<commit_before>
var GUID = require( '../guid' )

/**
 * Partition constructor
 * @param {Buffer} buffer
 */
function Partition( buffer ) {

  if( !(this instanceof Partition) )
    return new Partition( buffer )

  // Unique partition GUID
  this.GUID = new GUID(
    buffer.slice( 16, 32 )
  ).toString()

  // Partition type GUID
  this.type = new GUID(
    buffer.slice( 0, 16 )
  ).toString()

  this.info = Partition.TYPES[ this.type ] ||
    { OS: null, description: null }

  // Partition name (36 UTF-16LE code units)
  this.name = buffer.slice( 56, 128 )
  // Attribute flags
  this.attributes = buffer.slice( 48, 56 )

  // First LBA (little endian)
  // TODO: Read UInt64LE
  this.firstLBA = buffer.slice( 32, 40 )

  // Last LBA (inclusive, usually odd)
  this.lastLBA = buffer.slice( 40, 48 )

}

// Exports
module.exports = Partition

// GUID Partition Types
Partition.TYPES = require( './partition_types' )

/**
 * Partition prototype
 * @type {Object}
 */
Partition.prototype = {

  constructor: Partition

}
<commit_msg>Added string conversion on name in gpt/partition<commit_after>
var GUID = require( '../guid' )

/**
 * Partition constructor
 * @param {Buffer} buffer
 */
function Partition( buffer ) {

  if( !(this instanceof Partition) )
    return new Partition( buffer )

  // Unique partition GUID
  this.GUID = new GUID(
    buffer.slice( 16, 32 )
  ).toString()

  // Partition type GUID
  this.type = new GUID(
    buffer.slice( 0, 16 )
  ).toString()

  this.info = Partition.TYPES[ this.type ] ||
    { OS: null, description: null }

  // Partition name (36 UTF-16LE code units)
  this.name = buffer.slice( 56, 128 )
    .toString( 'ucs2' )
    .replace( /\x00/g, '' )

  // Attribute flags
  this.attributes = buffer.slice( 48, 56 )

  // First LBA (little endian)
  // TODO: Read UInt64LE
  this.firstLBA = buffer.slice( 32, 40 )

  // Last LBA (inclusive, usually odd)
  this.lastLBA = buffer.slice( 40, 48 )

}

// Exports
module.exports = Partition

// GUID Partition Types
Partition.TYPES = require( './partition_types' )

/**
 * Partition prototype
 * @type {Object}
 */
Partition.prototype = {

  constructor: Partition

}
<|endoftext|>


<commit_before>(function(global, undef) {
	$(function() {

		function objtoarr(obj) {
			var ret = [];
			for (var i in obj) {
				ret.push(obj[i]);
			}
			return ret;
		}

		window.snake = new Snake;

		snake.config({
			containerId: 'hehe'
		});

		var serverid;

		snake.init();

		var socket = io.connect('http://172.16.121.205:5566');
		//初始化房间信息- 剔除server id
		socket.on('open', function(data) {
			//console.log(data.roomstatus);
			//console.log(data.id + ' is in the room');
			serverid = data.id;
			socket.emit('serverinit', serverid);
			socket.emit('reopen');
			$('#number').text('当前房间人数0');
			var ret = '';
			var roomstatus = data.roomstatus;
			for (var i in roomstatus) {
				ret += i + ':' + (roomstatus[i].isready ? '已准备': '未准备') + '
';
			}
			$('#userstatus').html(ret);
		});

		snake.bind('died', 'room',function(data) {
           socket.emit('died',data.name);
        });

        snake.bind('gameover','room',function(data){
           socket.emit('gameover');
           location.reload();
        });

		socket.on('system', function(json) {
			if (json.type == 'new') {
				socket.emit('status', function(data) {
					var users = [];
					for (var i in data) {
						var user = data[i];
						users.push({
							name: user.id
						});
					}
					snake.addPlayers(users);
				});
				$('#number').text('当前房间人数' + objtoarr(json.data).length);
				var ret = '';
				var roomstatus = json.data;
				for (var i in roomstatus) {
					ret += i + ':' + (roomstatus[i].isready ? '已准备': '未准备') + '
';
				}
				$('#userstatus').html(ret);
			}
			if (json.type === 'allready') {
				var s = 5;
				$('#status').text('还有' + s + '秒,游戏即将开始');
				var T = setInterval(function() {
					s--;
					$('#status').text('还有' + s + '秒,游戏即将开始');
					if (s === 0) {
						clearInterval(T);
						snake.run();
					}
				},
				1000);
			}
			if (json.type === 'disconnect') {
				//判断全离线 初始化
				console.log('id ' + json.data.id + ' is out');
                snake.removePlayer(json.data.id);
                console.log('remove'+json.data.id);
				$('#number').text('当前房间人数' + objtoarr(json.data.roomstatus).length);
				//如果一个用户掉了，要remove掉蛇实例
			}
			if (json.type == 'top') {
				snake.setDirection(snake.players[json.data.id].snake, 'up');
			}
			if (json.type == 'right') {
				snake.setDirection(snake.players[json.data.id].snake, 'right');
			}
			if (json.type == 'down') {
				snake.setDirection(snake.players[json.data.id].snake, 'down');
			}
			if (json.type == 'left') {
				snake.setDirection(snake.players[json.data.id].snake, 'left');
			}
		});
	});
})(this);

<commit_msg>add scores<commit_after>(function(global, undef) {
	$(function() {

		function objtoarr(obj) {
			var ret = [];
			for (var i in obj) {
				ret.push(obj[i]);
			}
			return ret;
		}

		window.snake = new Snake;

		snake.config({
			containerId: 'hehe'
		});

		var serverid;

		snake.init();

		var socket = io.connect('http://172.16.121.205:5566');
		//初始化房间信息- 剔除server id
		socket.on('open', function(data) {
			//console.log(data.roomstatus);
			//console.log(data.id + ' is in the room');
			serverid = data.id;
			socket.emit('serverinit', serverid);
			socket.emit('reopen');
			$('#number').text('当前房间人数0');
			var ret = '';
			var roomstatus = data.roomstatus;
			for (var i in roomstatus) {
				ret += i + ':' + (roomstatus[i].isready ? '已准备': '未准备') + '
';
			}
			$('#userstatus').html(ret);
		});

		snake.bind('died', 'room',function(data) {
           socket.emit('died',data.name);
        });

        function showRank(){
            var ret ='';
            for(var i in snake.playerScores){
               var score = snake.playerScores[i].scores;
               ret += i +'：'+score+'
';
            }
            $('#currentrank').html(ret);
        }

        snake.bind('eat','room',function(){
           showRank();
        });

        snake.bind('gameover','room',function(data){
           socket.emit('gameover');
           setTimeout(function(){
             location.reload();
           },3000);
        });

		socket.on('system', function(json) {
			if (json.type == 'new') {
				socket.emit('status', function(data) {
					var users = [];
					for (var i in data) {
						var user = data[i];
						users.push({
							name: user.id
						});
					}
					snake.addPlayers(users);
				});
				$('#number').text('当前房间人数' + objtoarr(json.data).length);
				var ret = '';
				var roomstatus = json.data;
				for (var i in roomstatus) {
					ret += i + ':' + (roomstatus[i].isready ? '已准备': '未准备') + '
';
				}
				$('#userstatus').html(ret);
			}
			if (json.type === 'allready') {
				var s = 5;
				$('#status').text('还有' + s + '秒,游戏即将开始');
				var T = setInterval(function() {
					s--;
					$('#status').text('还有' + s + '秒,游戏即将开始');
					if (s === 0) {
						clearInterval(T);
						snake.run();
                        //显示分数
                        showRank();
					}
				},
				1000);
			}
			if (json.type === 'disconnect') {
				//判断全离线 初始化
				console.log('id ' + json.data.id + ' is out');
                snake.removePlayer(json.data.id);
                console.log('remove'+json.data.id);
				$('#number').text('当前房间人数' + objtoarr(json.data.roomstatus).length);
				//如果一个用户掉了，要remove掉蛇实例
			}
			if (json.type == 'top') {
				snake.setDirection(snake.players[json.data.id].snake, 'up');
			}
			if (json.type == 'right') {
				snake.setDirection(snake.players[json.data.id].snake, 'right');
			}
			if (json.type == 'down') {
				snake.setDirection(snake.players[json.data.id].snake, 'down');
			}
			if (json.type == 'left') {
				snake.setDirection(snake.players[json.data.id].snake, 'left');
			}
		});
	});
})(this);

<|endoftext|>


<commit_before>

var MergeRepeater = function(config) {

  //***** Private Methods *****//

  this.init_ = function(config) {

  };

  //***** Public Methods *****//

  /**
   * Converts this object into an easily serializeable form.
   *
   * @returns {Object} An Object containing all the data needed to recreate this Object.
   */
  this.toConfig = function() {

  };

  this.init_(config);
};

/** */
module.exports = MergeRepeater;
<commit_msg>Updated the fields needed for a repeated merge.<commit_after>

/**
 * The MergeRepeater handles storing data related to repeated merges. This doesn't actually create the trigger
 * or talk to the server. This Object can be easily serialized by calling toConfig or deserialized by passing that
 * config back into this contructor.
 *
 * @constructor
 * @param {Object} config The configuration Object used to define this MergeRepeater.
 * @param {Array<string>} config.triggers An Array of trigger IDs that can call this merge.
 * @param {string} config.owner The user that added the MergeRepeater.
 * @param {Array<string>} config.events A log of events that pertain to this MergeRepeater.
 */
var MergeRepeater = function(config) {

  var MAX_EVENTS = 10;

  var triggers;
  var owner;
  var events;

  //***** Private Methods *****//

  this.init_ = function(config) {
    events = [];

    this.update(config);
  };

  //***** Public Methods *****//

  this.update = function(config) {
    if (config.triggers != null) {
      triggers = config.triggers;
    }
    if (config.owner != null) {
      owner = config.owner;
    }
    if (config.events != null) {
      events = config.events;
    }
  }

  /**
   * Adds an event to this MergeRepeater. This can be used to determine what the trigger has been doing.
   * This ensures only MAX_EVENTS are recorded. Keep in mind, this is a client-side control, so it could easily be
   * circumvented.
   *
   * @param {string} event The event to log.
   */
  this.addEvent = function(event) {
    events.push(event);

    var tooMany = events.length - MAX_EVENTS;
    if (tooMany > 0) {
      events.splice(0, tooMany);
    }
  };

  /**
   * Converts this object into an easily serializeable form.
   *
   * @returns {Object} An Object containing all the data needed to recreate this Object.
   */
  this.toConfig = function() {
    triggers: triggers,
    owner: owner,
    events: events
  };

  this.init_(config);
};

/** */
module.exports = MergeRepeater;
<|endoftext|>


<commit_before>
var _           = require('lodash'),
    path        = require('path'),
    debug       = require('debug')('metalsmith-robotskirt'),
    Robotskirt  = require('robotskirt'),
    highlightjs = require('highlight.js');

/**
 * plugin expose function
 * @param  {object} options custom options
 * @return {function}       plugin function
 */
module.exports = function(options) {

    // default options
    var defaults = {
        extensions: {
            autolink: true,
            fenced_code: true,
            lax_spacing: true,
            no_intra_emphasis: true,
            space_headers: true,
            strikethrough: true,
            superscript: true,
            tables: true
        },
        htmlFlags: {
            skip_html: false,
            skip_style: false,
            skip_images: false,
            skip_links: false,
            safelink: false,
            toc: false,
            hard_wrap: false,
            use_xhtml: false,
            expand_tabs: false,
            escape: false
        },
        renderers: {
            blockcode: highlightCodeBlocks
        },
        smartypants: true
    };

    // create new object from merged options
    options = _.merge({}, defaults, options);

    // create robotskirt instances
    var renderFunctions = validateRenderFunctions(options.renderers);
        renderer = new Robotskirt.HtmlRenderer(convertConfigToRobotskirtFlags(options.htmlFlags, 'HTML'));
    _.forEach(renderFunctions, function(func, key) {
        renderer[key] = func;
    });
    var markdown = new Robotskirt.Markdown(renderer, convertConfigToRobotskirtFlags(options.extensions, 'EXT'));

    // main plugin function
    return function(files, metalsmith, done) {
        setImmediate(done);
        _.forEach(files, function(file, filename) {
            if (!isMarkdownFile(filename)) return;
            var dir = path.dirname(filename),
                html = path.basename(filename, path.extname(filename)) + '.html',
                contents = markdown.render(file.contents.toString());
            if (options.smartypants) {
                contents = Robotskirt.smartypantsHtml(contents);
            }
            file.contents = new Buffer(contents);
            if ('.' != dir) {
                html = dir + '/' + html;
            }
            delete files[filename];
            files[html] = file;
        });
    };

}

/**
 * checks if given file has a common markdown extension
 * @param  {string}  file filename or path
 * @return {Boolean}      test result
 */
function isMarkdownFile(file){
    return /\.md|\.markdown/.test(path.extname(file)) ? true : false;
}

/**
 * converts configuration object to an array of binary flags for robotskirt
 * @param  {object} configObj plain object
 * @param  {string} prefix    flag prefix
 * @return {array}            flags
 */
function convertConfigToRobotskirtFlags(configObj, prefix) {
    var robotskirtFlags = [];
    prefix = prefix ? prefix + '_' : '';
    _.forEach(configObj, function(value, key) {
        if (value) {
            robotskirtFlags.push(Robotskirt[prefix + key.toUpperCase()]);
        }
    });
    return robotskirtFlags;
}

/**
 * validates configuration object of render functions
 * @param  {object} configObj configuration object
 * @return {object}           validated object
 */
function validateRenderFunctions(configObj) {
    var robotskirtRenderFunctions = {};
    _.forEach(configObj, function(func, key) {
        if (_.isFunction(func)) {
            robotskirtRenderFunctions[key.toLowerCase()] = func;
        }
    });
    return robotskirtRenderFunctions;
}

/**
 * syntax highlighting for codeblocks using highlight.js
 * @param  {string} code content
 * @param  {string} lang language key
 * @return {string}      highlighted content
 */
function highlightCodeBlocks(code, lang) {
    var validLang = lang && highlightjs.getLanguage(lang.trim()),
        highlightedCode = validLang ? highlightjs.highlight(lang, code).value : highlightjs.highlightAuto(code).value,
        langClass = validLang ? ' class="lang-' + lang + '"' : '';
    return '
' + highlightedCode + '
';
}
<commit_msg>some smaller fixes<commit_after>
var _           = require('lodash'),
    path        = require('path'),
    debug       = require('debug')('metalsmith-robotskirt'),
    Robotskirt  = require('robotskirt'),
    highlightjs = require('highlight.js');

/**
 * plugin expose function
 * @param  {object} options custom options
 * @return {function}       plugin function
 */
module.exports = function(options) {

    // default options
    var defaults = {
        extensions: {
            autolink: true,
            fenced_code: true,
            lax_spacing: true,
            no_intra_emphasis: true,
            space_headers: true,
            strikethrough: true,
            superscript: true,
            tables: true
        },
        htmlFlags: {
            skip_html: false,
            skip_style: false,
            skip_images: false,
            skip_links: false,
            safelink: false,
            toc: false,
            hard_wrap: false,
            use_xhtml: false,
            expand_tabs: false,
            escape: false
        },
        renderers: {
            blockcode: highlightCodeBlocks
        },
        smartypants: true
    };

    // create new object from merged options
    options = _.merge({}, defaults, options);

    // create robotskirt instances
    var renderFunctions = validateRenderFunctions(options.renderers),
        renderer = new Robotskirt.HtmlRenderer(convertConfigToRobotskirtFlags(options.htmlFlags, 'HTML'));
    _.forEach(renderFunctions, function(func, key) {
        renderer[key] = func;
    });
    var markdown = new Robotskirt.Markdown(renderer, convertConfigToRobotskirtFlags(options.extensions, 'EXT'));

    // main plugin function
    return function(files, metalsmith, done) {
        setImmediate(done);
        _.forEach(files, function(file, filename) {
            if (!isMarkdownFile(filename)) {
                return;
            }
            var dir = path.dirname(filename),
                html = path.basename(filename, path.extname(filename)) + '.html',
                contents = markdown.render(file.contents.toString());
            if (options.smartypants) {
                contents = Robotskirt.smartypantsHtml(contents);
            }
            file.contents = new Buffer(contents);
            if ('.' !== dir) {
                html = dir + '/' + html;
            }
            delete files[filename];
            files[html] = file;
        });
    };

};

/**
 * checks if given file has a common markdown extension
 * @param  {string}  file filename or path
 * @return {Boolean}      test result
 */
function isMarkdownFile(file){
    return /\.md|\.markdown/.test(path.extname(file)) ? true : false;
}

/**
 * converts configuration object to an array of binary flags for robotskirt
 * @param  {object} configObj plain object
 * @param  {string} prefix    flag prefix
 * @return {array}            flags
 */
function convertConfigToRobotskirtFlags(configObj, prefix) {
    var robotskirtFlags = [];
    prefix = prefix ? prefix + '_' : '';
    _.forEach(configObj, function(value, key) {
        if (value) {
            robotskirtFlags.push(Robotskirt[prefix + key.toUpperCase()]);
        }
    });
    return robotskirtFlags;
}

/**
 * validates configuration object of render functions
 * @param  {object} configObj configuration object
 * @return {object}           validated object
 */
function validateRenderFunctions(configObj) {
    var robotskirtRenderFunctions = {};
    _.forEach(configObj, function(func, key) {
        if (_.isFunction(func)) {
            robotskirtRenderFunctions[key.toLowerCase()] = func;
        }
    });
    return robotskirtRenderFunctions;
}

/**
 * syntax highlighting for codeblocks using highlight.js
 * @param  {string} code content
 * @param  {string} lang language key
 * @return {string}      highlighted content
 */
function highlightCodeBlocks(code, lang) {
    var validLang = lang && highlightjs.getLanguage(lang.trim()),
        highlightedCode = validLang ? highlightjs.highlight(lang, code).value : highlightjs.highlightAuto(code).value,
        langClass = validLang ? ' class="lang-' + lang + '"' : '';
    return '
' + highlightedCode + '
';
}
<|endoftext|>


<commit_before>// A general purpose cache implementation for improved performance in all areas
// where results can be retained and reused temporarily. Any number of distinct cache
// objects can be created, identified by distinct names. The standard implementation
// is powered by a MongoDB collection, however it is straightforward to extend this
// module with a different implementation for some or all caches by overriding
// its `get` method.

var async = require('async');
var _ = require('lodash');
var Promise = require('bluebird');

module.exports = {

  alias: 'caches',

  afterConstruct: function(self, callback) {
    self.addClearCacheTask();
    return self.getCollection(callback);
  },

  construct: function(self, options) {
    // *SLOW DOWN - READ CAREFULLY!*
    //
    // THIS IS NOT THE METHOD YOU CALL TO GET A VALUE - THIS IS
    // THE METHOD YOU CALL TO *GET A CACHE IN WHICH YOU CAN GET AND SET
    // VALUES. Call it with a name that uniquely identifies
    // your *entire cache*, like `weather-data` or similar. The
    // object it *returns* has `get` and `set` methods for actual data,
    // *as described below*.
    //
    // `get('cachename')` returns a cache object to store things in
    // temporarily. If you call `get` many times with the same cache name,
    // you get the same cache object each time.
    //
    // CACHES MUST NEVER BE RELIED UPON TO STORE INFORMATION. They are a
    // performance enhancement ONLY and data may DISAPPEAR at any time.
    //
    // HOW TO ACTUALLY CACHE DATA: *Every cache object has `.get(key, callback)` and
    // `.set(key, value, lifetime, callback)` methods to get
    // and store values in the cache.* If you call without a callback,
    // a promise is returned.
    //
    // Example (with promises):
    //
    // ```
    // // Get a cache for weather data, keyed by zip code
    // var myCache = self.apos.caches.get('weather-data');
    //
    // // Store something in the cache
    // `myCache.set('19147', { clouds: 'cumulus' }, 86400).then(function() { ... })`
    //
    // // Get a value from the cache
    // `myCache.get('19147').then(function(data) { ... })`
    //```
    //
    // The data to be stored must be representable as JSON for compatibility with
    // different implementations. You do NOT have to stringify it yourself.
    //
    // The `.get` method of each cache object invokes its callback with `(null, value)` in the event
    // of success. If the key does not exist in the cache, `value`
    // is `undefined`. This is *not* considered an error.
    //
    // The `lifetime` argument of `.set` is in seconds and may be omitted
    // entirely, in which case data is kept indefinitely.
    //
    // The default implementation is a single MongoDB collection with a
    // `name` property to keep the caches separate, but this
    // can be swapped out by overriding the `get` method.
    //
    // Caches also have a `clear()` method to clear the cache. If
    // no callback is passed, it returns a promise.
    //
    // CACHES MUST NEVER BE RELIED UPON TO STORE INFORMATION. They are a
    // performance enhancement ONLY and data may DISAPPEAR at any time.

    self.get = function(name) {
      if (!self.caches) {
        self.caches = {};
      }
      if (!self.caches[name]) {
        self.caches[name] = self.constructCache(name);
      }
      return self.caches[name];
    };

    self.constructCache = function(name) {
      return {
        // Fetch an item from the cache. If the item is in the
        // cache, the callback receives (null, item). If the
        // item is not in the cache the callback receives (null).
        // If an error occurs the callback receives (err).
        // If there is no callback a promise is returned.

        get: function(key, callback) {
          if (callback) {
            return body(callback);
          } else {
            return Promise.promisify(body)();
          }
          function body(callback) {
            return self.cacheCollection.findOne({
              name: name,
              key: key
            }, function(err, item) {
              if (err) {
                return callback(err);
              }
              if (!item) {
                return callback(null);
              }
              // MongoDB's expireAfterSeconds mechanism isn't instantaneous, so we
              // should still enforce this at get() time
              if (item.expires && (item.expires < (new Date()))) {
                return callback(null);
              }
              return callback(null, item.value);
            });
          }
        },

        // Store an item in the cache. `value` may be any JSON-friendly
        // value, including an object. `lifetime` is in seconds.
        //
        // The callback receives (err).
        //
        // You may also call with just three arguments:
        // key, value, callback. In that case there is no hard limit
        // on the lifetime, however NEVER use a cache for PERMANENT
        // storage of data. It might be cleared at any time.
        //
        // If there is no callback a promise is returned.

        set: function(key, value, lifetime, callback) {
          if (arguments.length === 2) {
            lifetime = 0;
            return Promise.promisify(body)();
          } else if (arguments.length === 3) {
            if (typeof(lifetime) === 'function') {
              callback = lifetime;
              lifetime = 0;
              return body(callback);
            } else {
              return Promise.promisify(body)();
            }
          } else {
            return body(callback);
          }
          function body(callback) {
            var action = {};
            var set = {
              name: name,
              key: key,
              value: value
            };
            action.$set = set;
            var unset = {};
            if (lifetime) {
              set.expires = new Date(new Date().getTime() + lifetime * 1000);
            } else {
              unset.expires = 1;
              action.$unset = unset;
            }
            return self.cacheCollection.update(
              {
                name: name,
                key: key
              },
              action,
              {
                upsert: true
              }, callback
            );
          }
        },

        // Empty the cache. If there is no callback a promise is returned.
        clear: function(callback) {
          if (callback) {
            return body(callback);
          } else {
            return Promise.promisify(body)();
          }
          function body(callback) {
            return self.cacheCollection.remove({
              name: name
            }, callback);
          }
        }
      };
    };

    self.getCollection = function(callback) {
      return self.apos.db.collection('aposCache', function(err, collection) {
        self.cacheCollection = collection;
        return async.series({
          keyIndex: function(callback) {
            return self.cacheCollection.ensureIndex({ key: 1, cache: 1 }, { unique: true }, callback);
          },
          expireIndex: function(callback) {
            return self.cacheCollection.ensureIndex({ expires: 1 }, { expireAfterSeconds: 0 }, callback);
          }
        }, callback);
      });
    };

    self.clearCacheTask = function(argv, callback) {
      var cacheNames = argv._.slice(1);
      if (!cacheNames.length) {
        return callback('A cache name or names must be given.');
      }
      return async.eachSeries(cacheNames, function(name, callback) {
        return self.get(name).clear(callback);
      }, callback);
    };

    self.addClearCacheTask = function() {
      self.apos.tasks.add('apostrophe-caches', 'clear',
        'Usage: node app apostrophe-caches:clear cachename cachename2...\n\n' +
        'Clears caches by name. If you are using apos.caches in your own code you will\n' +
        'know the cache name. Standard caches include "apostrophe-migrations",\n' +
        '"minify" and "oembed". Normally it is not necessary to clear them.',
        function(apos, argv, callback) {
          return self.clearCacheTask(argv, callback);
        }
      );
    };
  }
};
<commit_msg>doc tweaks<commit_after>// A general purpose cache implementation for improved performance in all areas
// where results can be retained and reused temporarily. Any number of distinct cache
// objects can be created, identified by distinct names. The standard implementation
// is powered by a MongoDB collection, however it is straightforward to extend this
// module with a different implementation for some or all caches by overriding
// its `get` method.

var async = require('async');
var _ = require('lodash');
var Promise = require('bluebird');

module.exports = {

  alias: 'caches',

  afterConstruct: function(self, callback) {
    self.addClearCacheTask();
    return self.getCollection(callback);
  },

  construct: function(self, options) {
    // **SLOW DOWN - READ CAREFULLY!**
    //
    // THIS IS NOT THE METHOD YOU CALL TO GET A VALUE - THIS IS
    // THE METHOD YOU CALL TO **GET A CACHE IN WHICH YOU CAN GET AND SET
    // VALUES.** Call it with a name that uniquely identifies
    // your **entire cache**, like `weather-data` or similar. The
    // object it **returns** has `get` and `set` methods for actual data,
    // **as described below**.
    //
    // `get('cachename')` returns a cache object to store things in
    // temporarily. If you call `get` many times with the same cache name,
    // you get the same cache object each time.
    //
    // CACHES MUST NEVER BE RELIED UPON TO STORE INFORMATION. They are a
    // performance enhancement ONLY and data may DISAPPEAR at any time.
    //
    // HOW TO ACTUALLY CACHE DATA: **Every cache object has `.get(key, callback)` and
    // `.set(key, value, lifetime, callback)` methods to get
    // and store values in the cache.** If you call without a callback,
    // a promise is returned.
    //
    // Example (with promises):
    //
    // ```
    // // Get a cache for weather data, keyed by zip code
    // var myCache = self.apos.caches.get('weather-data');
    //
    // // Store something in the cache
    // myCache.set('19147', { clouds: 'cumulus' }, 86400).then(function() { ... })
    //
    // // Get a value from the cache
    // myCache.get('19147').then(function(data) { ... })
    //```
    //
    // The data to be stored must be representable as JSON for compatibility with
    // different implementations. You do NOT have to stringify it yourself.
    //
    // The `.get` method of each cache object invokes its callback with `(null, value)` in the event
    // of success. If the key does not exist in the cache, `value`
    // is `undefined`. This is *not* considered an error. If there is no callback
    // a promise is returned, which resolves to the cached value or `undefined`.
    //
    // The `lifetime` argument of `.set` is in seconds and may be omitted
    // entirely, in which case data is kept indefinitely (but NOT forever,
    // remember that caches can be erased at ANY time, they are not for permanent data storage).
    //
    // The default implementation is a single MongoDB collection with a
    // `name` property to keep the caches separate, but this
    // can be swapped out by overriding the `get` method.
    //
    // Caches also have a `clear()` method to clear the cache. If
    // no callback is passed, it returns a promise.
    //
    // CACHES MUST NEVER BE RELIED UPON TO STORE INFORMATION. They are a
    // performance enhancement ONLY and data may DISAPPEAR at any time.

    self.get = function(name) {
      if (!self.caches) {
        self.caches = {};
      }
      if (!self.caches[name]) {
        self.caches[name] = self.constructCache(name);
      }
      return self.caches[name];
    };

    self.constructCache = function(name) {
      return {
        // Fetch an item from the cache. If the item is in the
        // cache, the callback receives (null, item). If the
        // item is not in the cache the callback receives (null).
        // If an error occurs the callback receives (err).
        // If there is no callback a promise is returned.

        get: function(key, callback) {
          if (callback) {
            return body(callback);
          } else {
            return Promise.promisify(body)();
          }
          function body(callback) {
            return self.cacheCollection.findOne({
              name: name,
              key: key
            }, function(err, item) {
              if (err) {
                return callback(err);
              }
              if (!item) {
                return callback(null);
              }
              // MongoDB's expireAfterSeconds mechanism isn't instantaneous, so we
              // should still enforce this at get() time
              if (item.expires && (item.expires < (new Date()))) {
                return callback(null);
              }
              return callback(null, item.value);
            });
          }
        },

        // Store an item in the cache. `value` may be any JSON-friendly
        // value, including an object. `lifetime` is in seconds.
        //
        // The callback receives (err).
        //
        // You may also call with just three arguments:
        // key, value, callback. In that case there is no hard limit
        // on the lifetime, however NEVER use a cache for PERMANENT
        // storage of data. It might be cleared at any time.
        //
        // If there is no callback a promise is returned.

        set: function(key, value, lifetime, callback) {
          if (arguments.length === 2) {
            lifetime = 0;
            return Promise.promisify(body)();
          } else if (arguments.length === 3) {
            if (typeof(lifetime) === 'function') {
              callback = lifetime;
              lifetime = 0;
              return body(callback);
            } else {
              return Promise.promisify(body)();
            }
          } else {
            return body(callback);
          }
          function body(callback) {
            var action = {};
            var set = {
              name: name,
              key: key,
              value: value
            };
            action.$set = set;
            var unset = {};
            if (lifetime) {
              set.expires = new Date(new Date().getTime() + lifetime * 1000);
            } else {
              unset.expires = 1;
              action.$unset = unset;
            }
            return self.cacheCollection.update(
              {
                name: name,
                key: key
              },
              action,
              {
                upsert: true
              }, callback
            );
          }
        },

        // Empty the cache. If there is no callback a promise is returned.
        clear: function(callback) {
          if (callback) {
            return body(callback);
          } else {
            return Promise.promisify(body)();
          }
          function body(callback) {
            return self.cacheCollection.remove({
              name: name
            }, callback);
          }
        }
      };
    };

    self.getCollection = function(callback) {
      return self.apos.db.collection('aposCache', function(err, collection) {
        self.cacheCollection = collection;
        return async.series({
          keyIndex: function(callback) {
            return self.cacheCollection.ensureIndex({ key: 1, cache: 1 }, { unique: true }, callback);
          },
          expireIndex: function(callback) {
            return self.cacheCollection.ensureIndex({ expires: 1 }, { expireAfterSeconds: 0 }, callback);
          }
        }, callback);
      });
    };

    self.clearCacheTask = function(argv, callback) {
      var cacheNames = argv._.slice(1);
      if (!cacheNames.length) {
        return callback('A cache name or names must be given.');
      }
      return async.eachSeries(cacheNames, function(name, callback) {
        return self.get(name).clear(callback);
      }, callback);
    };

    self.addClearCacheTask = function() {
      self.apos.tasks.add('apostrophe-caches', 'clear',
        'Usage: node app apostrophe-caches:clear cachename cachename2...\n\n' +
        'Clears caches by name. If you are using apos.caches in your own code you will\n' +
        'know the cache name. Standard caches include "apostrophe-migrations",\n' +
        '"minify" and "oembed". Normally it is not necessary to clear them.',
        function(apos, argv, callback) {
          return self.clearCacheTask(argv, callback);
        }
      );
    };
  }
};
<|endoftext|>


<commit_before>/* @flow */

import Path from 'path'
import { CompositeDisposable, TextEditor } from 'atom'
import { exec, findCachedAsync } from 'atom-linter'
import { shouldTriggerAutocomplete } from 'atom-autocomplete'
import { INIT_MESSAGE, RECHECKING_MESSAGE, toLinterMessages, injectPosition, toAutocompleteSuggestions } from './helpers'
import CoverageView from './coverage-view'
import type { CoverageObject } from './coverage-view'

export default {
  activate() {
    // eslint-disable-next-line global-require
    require('atom-package-deps').install('flow-ide')

    this.subscriptions = new CompositeDisposable()
    this.subscriptions.add(atom.config.observe('flow-ide.executablePath', (executablePath) => {
      this.executablePath = executablePath
    }))
    this.subscriptions.add(atom.config.observe('flow-ide.onlyIfAppropriate', (onlyIfAppropriate) => {
      this.onlyIfAppropriate = onlyIfAppropriate
    }))
  },

  async getExecutablePath(fileDirectory: string): Promise<string> {
    return (
      await findCachedAsync(fileDirectory, 'node_modules/.bin/flow') ||
      this.executablePath ||
      'flow'
    )
  },

  deactivate() {
    this.subscriptions.dispose()
  },

  provideLinter(): Object {
    const linter = {
      name: 'Flow IDE',
      grammarScopes: ['source.js', 'source.js.jsx'],
      scope: 'project',
      lintOnFly: false,
      // eslint-disable-next-line arrow-parens
      lint: async (textEditor) => {
        const filePath = textEditor.getPath()
        const fileDirectory = Path.dirname(filePath)

        if (this.onlyIfAppropriate) {
          const configFile = await findCachedAsync(fileDirectory, '.flowconfig')
          if (!configFile) {
            return []
          }
        } else {
          return []
        }

        const executable = await this.getExecutablePath(fileDirectory)

        let result
        try {
          result = await exec(executable, ['status', '--json'], { cwd: fileDirectory, ignoreExitCode: true })
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return await linter.lint(textEditor)
          } else if (error.code === 'ENOENT') {
            throw new Error('Unable to find `flow` executable.')
          } else {
            throw error
          }
        }

        return toLinterMessages(result)
      },
    }
    return linter
  },

  provideAutocomplete(): Object {
    const provider = {
      selector: '.source.js, .source.js.jsx',
      disableForSelector: '.comment',
      inclusionPriority: 100,
      // eslint-disable-next-line arrow-parens
      getSuggestions: async (params) => {
        const { editor, bufferPosition, activatedManually } = params
        let prefix = params.prefix
        let filePath = editor.getPath()
        const fileDirectory = Path.dirname(filePath)
        const fileContents = injectPosition(editor.getText(), editor, bufferPosition)
        let flowOptions = ['autocomplete', '--json', filePath]

        const configFile = await findCachedAsync(fileDirectory, '.flowconfig')
        if (!configFile) {
          if (this.onlyIfAppropriate) {
            return []
          } else {
            const defaultFlowFile = Path.resolve(__dirname, '..', 'defaultflowconfig', '.flowconfig')
            flowOptions = ['autocomplete', '--root', defaultFlowFile, '--json', filePath]
          }
        }

        // NOTE: Fix for class properties autocompletion
        if (prefix === '.') {
          prefix = ''
        }

        if (!shouldTriggerAutocomplete({ activatedManually, bufferPosition, editor })) {
          return []
        }

        let result
        try {
          result = await exec(await this.getExecutablePath(fileDirectory), flowOptions, { cwd: fileDirectory, stdin: fileContents })
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return await provider.getSuggestions(params)
          }
          throw error
        }

        return toAutocompleteSuggestions(result, prefix)
      },
    }
    return provider
  },

  consumeStatusBar(statusBar: any): void {
    this.coverageView = new CoverageView()
    this.coverageView.initialize()
    this.statusBar = statusBar.addLeftTile({ item: this.coverageView, priority: 10 })

    this.subscriptions.add(atom.workspace.onDidChangeActivePaneItem((item: ?TextEditor): void => {
      if (item && item instanceof TextEditor) {
        this.updateCoverage(item)
      }
    }))
    this.subscriptions.add(atom.workspace.observeTextEditors((textEditor: TextEditor): void => {
      textEditor.onDidSave(() => this.updateCoverage(textEditor))
    }))
  },

  async updateCoverage(textEditor: TextEditor) {
    const filePath: string = textEditor.getPath()
    const fileDirectory: string = Path.dirname(filePath)

    const executable: string = await this.getExecutablePath(fileDirectory)
    try {
      const result: string = await exec(executable, ['coverage', filePath, '--json'], { cwd: fileDirectory, ignoreExitCode: true })

      if (result) {
        const coverage: CoverageObject = JSON.parse(result)
        this.coverageView.update(coverage)
      }
    } catch (error) {
      // Let the linter handle any flow errors.
    }
  },
}
<commit_msg>Fix console logging when project doesn't use flow<commit_after>/* @flow */

import Path from 'path'
import { CompositeDisposable, TextEditor } from 'atom'
import { exec, findCachedAsync } from 'atom-linter'
import { shouldTriggerAutocomplete } from 'atom-autocomplete'
import { INIT_MESSAGE, RECHECKING_MESSAGE, toLinterMessages, injectPosition, toAutocompleteSuggestions } from './helpers'
import CoverageView from './coverage-view'
import type { CoverageObject } from './coverage-view'

export default {
  activate() {
    // eslint-disable-next-line global-require
    require('atom-package-deps').install('flow-ide')

    this.subscriptions = new CompositeDisposable()
    this.subscriptions.add(atom.config.observe('flow-ide.executablePath', (executablePath) => {
      this.executablePath = executablePath
    }))
    this.subscriptions.add(atom.config.observe('flow-ide.onlyIfAppropriate', (onlyIfAppropriate) => {
      this.onlyIfAppropriate = onlyIfAppropriate
    }))
  },

  async getExecutablePath(fileDirectory: string): Promise<string> {
    return (
      await findCachedAsync(fileDirectory, 'node_modules/.bin/flow') ||
      this.executablePath ||
      'flow'
    )
  },

  deactivate() {
    this.subscriptions.dispose()
  },

  provideLinter(): Object {
    const linter = {
      name: 'Flow IDE',
      grammarScopes: ['source.js', 'source.js.jsx'],
      scope: 'project',
      lintOnFly: false,
      // eslint-disable-next-line arrow-parens
      lint: async (textEditor) => {
        const filePath = textEditor.getPath()
        const fileDirectory = Path.dirname(filePath)

        if (this.onlyIfAppropriate) {
          const configFile = await findCachedAsync(fileDirectory, '.flowconfig')
          if (!configFile) {
            return []
          }
        } else {
          return []
        }

        const executable = await this.getExecutablePath(fileDirectory)

        let result
        try {
          result = await exec(executable, ['status', '--json'], { cwd: fileDirectory, ignoreExitCode: true })
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return await linter.lint(textEditor)
          } else if (error.code === 'ENOENT') {
            throw new Error('Unable to find `flow` executable.')
          } else {
            throw error
          }
        }

        return toLinterMessages(result)
      },
    }
    return linter
  },

  provideAutocomplete(): Object {
    const provider = {
      selector: '.source.js, .source.js.jsx',
      disableForSelector: '.comment',
      inclusionPriority: 100,
      // eslint-disable-next-line arrow-parens
      getSuggestions: async (params) => {
        const { editor, bufferPosition, activatedManually } = params
        let prefix = params.prefix
        let filePath = editor.getPath()
        const fileDirectory = Path.dirname(filePath)
        const fileContents = injectPosition(editor.getText(), editor, bufferPosition)
        let flowOptions = ['autocomplete', '--json', filePath]

        const configFile = await findCachedAsync(fileDirectory, '.flowconfig')
        if (!configFile) {
          if (this.onlyIfAppropriate) {
            return []
          } else {
            const defaultFlowFile = Path.resolve(__dirname, '..', 'defaultflowconfig', '.flowconfig')
            flowOptions = ['autocomplete', '--root', defaultFlowFile, '--json', filePath]
          }
        }

        // NOTE: Fix for class properties autocompletion
        if (prefix === '.') {
          prefix = ''
        }

        if (!shouldTriggerAutocomplete({ activatedManually, bufferPosition, editor })) {
          return []
        }

        let result
        try {
          result = await exec(await this.getExecutablePath(fileDirectory), flowOptions, { cwd: fileDirectory, stdin: fileContents })
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return await provider.getSuggestions(params)
          }
          throw error
        }

        return toAutocompleteSuggestions(result, prefix)
      },
    }
    return provider
  },

  consumeStatusBar(statusBar: any): void {
    this.coverageView = new CoverageView()
    this.coverageView.initialize()
    this.statusBar = statusBar.addLeftTile({ item: this.coverageView, priority: 10 })

    this.subscriptions.add(atom.workspace.onDidChangeActivePaneItem((item: ?TextEditor): void => {
      if (item && item instanceof TextEditor) {
        this.updateCoverage(item)
      }
    }))
    this.subscriptions.add(atom.workspace.observeTextEditors((textEditor: TextEditor): void => {
      textEditor.onDidSave(() => this.updateCoverage(textEditor))
    }))
  },

  async updateCoverage(textEditor: TextEditor) {
    const filePath: string = textEditor.getPath()
    const fileDirectory: string = Path.dirname(filePath)

    const executable: string = await this.getExecutablePath(fileDirectory)
    try {
      const result: string = await exec(executable, ['coverage', filePath, '--json'], { cwd: fileDirectory, ignoreExitCode: true })
        .catch(() => {})

      if (result) {
        const coverage: CoverageObject = JSON.parse(result)
        this.coverageView.update(coverage)
      }
    } catch (error) {
      // Let the linter handle any flow errors.
    }
  },
}
<|endoftext|>


<commit_before>// console.log('Loading BoxView...')

Spontaneous.Views.BoxView = (function($, S) {
	'use strict';
	var dom = S.Dom;

	var BoxView = new JS.Class(Spontaneous.Views.View, {
		include: Spontaneous.Properties,

		initialize: function(box, dom_container) {
			this.callSuper(box);
			this.box = box;
			this.dom_container = dom_container;
			this.box.bind('entry_added', this.insert_entry.bind(this));
			this.box.bind('entry_removed', this.remove_entry.bind(this));
			this._isAttached = false;
		},

		name: function() {
			return this.box.name();
		},
		schema_id: function() {
			return this.box.schema_id();
		},

		activate: function() {
			$('> .slot-content', this.dom_container).hide();
			this.panel().show();
		},

		mouseover: function() {
			if (this.fields_preview) {
				this.fields_preview.addClass('hover');
			}
		},
		mouseout: function() {
			if (this.fields_preview) {
				this.fields_preview.removeClass('hover');
			}
		},

		panel: function() {
			if (!this._panel) {
				// var panel = $(dom.div, {'class': 'slot-content'});
				var panel = dom.div('.slot-content');
				panel.addClass('empty');
				if (this.box.has_fields()) {
					var w = dom.div('.box-fields');
					var fields = new Spontaneous.FieldPreview(this, '');
					this._subviews.push(fields);
					var fields_preview = fields.panel();
					fields_preview.prepend(dom.div('.overlay'));
					var preview_area = this.create_edit_wrapper(fields_preview);

					w.append(preview_area);
					panel.append(w);
					this.fields_preview = fields_preview;
				}

				panel.append(this.add_allowed_types_bar('top', 0));
				var entries = dom.div('.slot-entries');
				panel.append(entries);
				this.dom_container.append(panel);
				var instructions = dom.div('.slot-instructions').text('Add items using the buttons above');
				entries.append(instructions);
				if (this._isAttached) {
					this.appendEntries(entries);
				}
				entries.sortable({
					items:'> .'+this.entry_class(),
					// handle: '.title-bar',
					axis:'y',
					distance: 5,
					tolerance: 'pointer',
					helper: 'clone',
					// tolerance: 'intersect',
					scrollSpeed: 40,
					containment: 'parent',
					cursor: 'move',
					stop: function(event, ui) {
						this.re_sort(ui.item);
					}.bind(this)
				});
				panel.hide();
				this._panel = panel;
				this._entry_container = entries;
				// this._bottom_add_bar = _bottom_add_bar;
			}
			this.check_if_empty();
			return this._panel;
		},
		// relies on this view being attached to the dom
		// fills the box until all the entries have been added or the last entry
		// is at the bottom of the screen, whichever comes first.
		appendEntries: function(entries) {
			var entry_total = this.entries().length, attached = 0;
			var availableHeight = S.ContentArea.height() - entries.position().top;
			for (var i = 0, ee = this.entries(), ii = entry_total;i < ii; i++) {
				var entry = ee[i];
				entries.append(this.claim_entry(entry));
				attached++;
				var contentHeight = entries.height(), gap = availableHeight - contentHeight;
				if (gap < 0) { // wait until there's an overlap so we see a scrollbar
					break;
				}
			}
			if (attached < entry_total) {
				var scrollLoad = function(view, loadedCount, entries, container) {
					var position = loadedCount, increment = 3, total = entries.length;
					return function() {
						if (position >= total) { return; }
						var availableHeight = S.ContentArea.height() - container.position().top;
						var added = 0;
						for (var i = position, ii = total; i < ii; i++) {
							container.append(view.claim_entry(entries[i]));
							added++;
							var contentHeight = container.height(), gap = availableHeight - contentHeight;
							if (gap < 0) { // wait until there's an overlap so we see a scrollbar
								break;
							}
						}
						position += added;
						if (position >= total) {
							container.addClass('entries-loaded');
						}
					};
				}(this, attached, this.entries(), entries);
				this.watchOther(S.ContentArea, 'scroll_bottom', scrollLoad);
			} else {
				entries.addClass('entries-loaded');
			}
		},
		attachView: function() {
			this._isAttached = true;
			var entries = this._entry_container;
			if (!entries) { return; }
			this.appendEntries(entries);
		},
		check_if_empty: function() {
			var _view = this, _panel = this._panel;
			if (_view.box.entries().length === 0) {
				_panel.addClass('empty');
				// _view._bottom_add_bar.velocity('fadeOut', $.fn.appear.height_change_duration/2, function() {
				// })
			} else {
				_panel.removeClass('empty');
				// _view._bottom_add_bar.velocity('fadeIn', function() {
				// })
			}
		},
		add_allowed_types_bar: function(position, insert_at) {
			var allowed = this.box.allowed_types();
			if (allowed.length === 0) { return ''; }
			var _box = this
, allowed_bar = dom.div('.slot-addable')
			, inner = dom.div('.addable-inner')
			, dropper = allowed_bar
, drop = function(event) {
				dropper.removeClass('drop-active').addClass('uploading');
				// var progress_outer = $(dom.div, {'class':'drop-upload-outer'});
				// var progress_inner = $(dom.div, {'class':'drop-upload-inner'}).css('width', 0);
				// progress_outer.append(progress_inner);
				// dropper.append(progress_outer);
				// this.progress_bar = progress_inner;
				event.stopPropagation();
				event.preventDefault();
				var files = event.dataTransfer.files;
				if (files.length > 0) {
					S.UploadManager.wrap(this, files, insert_at);
				}
				return false;
			}.bind(this)

			, drag_enter = function(event) {
				// var files = event.originalEvent.dataTransfer.files;
				$(this).addClass('drop-active');
				event.stopPropagation();
				event.preventDefault();
				return false;
			}.bind(dropper)

			, drag_over = function(event) {
				event.stopPropagation();
				event.preventDefault();
				return false;
			}.bind(dropper)

			, drag_leave = function(event) {
				$(this).removeClass('drop-active');
				event.stopPropagation();
				event.preventDefault();
				return false;
			}.bind(dropper);

			allowed_bar.addClass(position);
			dropper.get(0).addEventListener('drop', drop, true);
			dropper.bind('dragenter', drag_enter).bind('dragover', drag_over).bind('dragleave', drag_leave);

			$.each(allowed, function(i, allow) {
				var type = allow.type, as = allow.as || type.title;
				var a = dom.a().append(dom.span().text(as)), add_allowed;
				if (type.is_alias()) {
					a.addClass('alias');
					add_allowed = function(type) {
						var d = new Spontaneous.AddAliasDialogue(_box, type, insert_at);
						d.open();
					}.bind(_box, type);
				} else {
					add_allowed = function(type) {
						this.add_content(type, insert_at);
					}.bind(_box, type);
				}
				a.click(add_allowed);
				inner.append(a);
			});
			allowed_bar.data('allowed-count', allowed.length);
			allowed_bar.append(inner, dom.span('.down'));

			return allowed_bar;
		},
		re_sort: function(item) {
			var entries = this.entries(), order = this._entry_container.sortable('toArray'), css_id = item.attr('id'), new_position = 0;
			for (var i = 0, ii = order.length; i < ii; i++) {
				if (order[i] === css_id) { new_position = i; break; }
			}
			var id = css_id.split('-')[1], entry, old_position = 0;

			for (i = 0, ii = entries.length; i < ii; i++) {
				if (entries[i].id() == id) {
					old_position = i;
					entry = entries[i];
					break;
				}
			}
			// move entry inside the array so that we can reliably find its position
			entries.splice(old_position, 1);
			entries.splice(new_position, 0, entry);
			entry.reposition(new_position, function(entry) {
				this.sorted(entry);
			}.bind(this));
		},
		sorted: function(entry) {
		},
		upload_complete: function(values) {
			this.box.entry_added(values);
		},
		upload_progress: function(position, total) {
		},
		entries: function() {
			var entries = [];
			for (var i = 0, ee = this.box.entries(), ii = ee.length;i < ii; i++) {
				var entry = ee[i];
				entries.push(this.view_for_entry(entry));
			}
			return entries;
		}.cache(),

		view_for_entry: function(entry) {
			var view_class = S.Views.PieceView, view, panel;
			if (entry.is_page()) {
				view_class = S.Views.PagePieceView;
			}
			view = new view_class(entry, this); // jshint ignore:line
			return view;
		},
		claim_entry: function(entry) {
			this._subviews.push(entry);
			var div = entry.panel();
			entry.bind('removed', this.entry_removed.bind(this));
			return div.attr('id', this.entry_id(entry)).addClass(this.entry_class());
		},

		entry_id: function(entry) {
			return 'entry-' + entry.content.id();
		},

		entry_class: function() {
			return 'container-'+this.box.schema_id();
		},

		save_path: function() {
			return ['/content', this.id()].join('/');
		},

		add_content: function(content_type, position) {
			this.box.add_entry(content_type, position);
		},

		add_alias: function(target_ids, type, position) {
			this.box.add_alias(target_ids, type, position);
		},

		insert_entry: function(entry, position) {
			this.trigger('entry_added', entry, position);
			var entries = this.entries()
			, w = this.entry_wrappers()
			, e = this.view_for_entry(entry)
			, h = this.claim_entry(e)
			, view = this;
			if (position === -1) {
				entries.push(e);
			} else {
				entries.splice(position, 0, e);
			}
			if (position === -1 || w.length === 0) {
				this._entry_container.append(h);
			} else if (position === 0) {
				this._entry_container.prepend(h);
			} else {
				this.entry_wrappers().slice(position-1, position).after(h);
			}
			if (position === -1) {
				S.ContentArea.scroll_to_bottom($.fn.appear.height_change_duration);
			}
			view.check_if_empty();
			h.hide().appear(function() {
				if (e.content.has_fields()) {
					e.edit();
				}
			});
		},

		remove_entry: function(entry) {
		},
		entry_removed: function(entry) {
			var entries = this.entries();
			for (var i = 0, ii = entries.length; i < ii; i++) {
				if (entries[i] === entry) {
					entries.splice(i, 1);
				}
			}
			this.check_if_empty();
		},
		entry_wrappers: function() {
			return this._entry_container.find('> .'+this.entry_class());
		},
		show_add_after: function(entry, entry_spacer) {
			var bar, position = 0;
			for (var i = 0, entries = this.entries(), ii = entries.length; i < ii; i++) {
				if (entries[i] === entry) {
					position = i;
					break;
				}
			}
			bar = this.add_allowed_types_bar('floating', position + 1);
			if (bar && bar.data('allowed-count') > 0) {
				entry_spacer.addClass('add-entry').append(bar.show());
				if (!entry_spacer.data('auto-height')) {
					entry_spacer.data('auto-height', entry_spacer.height());
				}
				var newHeight = bar.find('.addable-inner').outerHeight() + 11, currentHeight = entry_spacer.outerHeight();
				newHeight = Math.max(newHeight, currentHeight);
				entry_spacer.velocity({height:newHeight}, 200);
			}
		},
		hide_add_after: function(entry, entry_spacer) {
			if (entry_spacer.data('auto-height')) {
				entry_spacer.empty();
				entry_spacer.removeClass('add-entry').velocity({height: entry_spacer.data('auto-height')}, 200);
			}
		}
	});

	return BoxView;

})(jQuery, Spontaneous);

<commit_msg>Look up entry position dynamically when inserting<commit_after>// console.log('Loading BoxView...')

Spontaneous.Views.BoxView = (function($, S) {
	'use strict';
	var dom = S.Dom;

	var BoxView = new JS.Class(Spontaneous.Views.View, {
		include: Spontaneous.Properties,

		initialize: function(box, dom_container) {
			this.callSuper(box);
			this.box = box;
			this.dom_container = dom_container;
			this.box.bind('entry_added', this.insert_entry.bind(this));
			this.box.bind('entry_removed', this.remove_entry.bind(this));
			this._isAttached = false;
		},

		name: function() {
			return this.box.name();
		},
		schema_id: function() {
			return this.box.schema_id();
		},

		activate: function() {
			$('> .slot-content', this.dom_container).hide();
			this.panel().show();
		},

		mouseover: function() {
			if (this.fields_preview) {
				this.fields_preview.addClass('hover');
			}
		},
		mouseout: function() {
			if (this.fields_preview) {
				this.fields_preview.removeClass('hover');
			}
		},

		panel: function() {
			if (!this._panel) {
				// var panel = $(dom.div, {'class': 'slot-content'});
				var panel = dom.div('.slot-content');
				panel.addClass('empty');
				if (this.box.has_fields()) {
					var w = dom.div('.box-fields');
					var fields = new Spontaneous.FieldPreview(this, '');
					this._subviews.push(fields);
					var fields_preview = fields.panel();
					fields_preview.prepend(dom.div('.overlay'));
					var preview_area = this.create_edit_wrapper(fields_preview);

					w.append(preview_area);
					panel.append(w);
					this.fields_preview = fields_preview;
				}
				var firstPosition = function() { return 0; };
				panel.append(this.add_allowed_types_bar('top', firstPosition));
				var entries = dom.div('.slot-entries');
				panel.append(entries);
				this.dom_container.append(panel);
				var instructions = dom.div('.slot-instructions').text('Add items using the buttons above');
				entries.append(instructions);
				if (this._isAttached) {
					this.appendEntries(entries);
				}
				entries.sortable({
					items:'> .'+this.entry_class(),
					// handle: '.title-bar',
					axis:'y',
					distance: 5,
					tolerance: 'pointer',
					helper: 'clone',
					// tolerance: 'intersect',
					scrollSpeed: 40,
					containment: 'parent',
					cursor: 'move',
					stop: function(event, ui) {
						this.re_sort(ui.item);
					}.bind(this)
				});
				panel.hide();
				this._panel = panel;
				this._entry_container = entries;
				// this._bottom_add_bar = _bottom_add_bar;
			}
			this.check_if_empty();
			return this._panel;
		},
		// relies on this view being attached to the dom
		// fills the box until all the entries have been added or the last entry
		// is at the bottom of the screen, whichever comes first.
		appendEntries: function(entries) {
			var entry_total = this.entries().length, attached = 0;
			var availableHeight = S.ContentArea.height() - entries.position().top;
			for (var i = 0, ee = this.entries(), ii = entry_total;i < ii; i++) {
				var entry = ee[i];
				entries.append(this.claim_entry(entry));
				attached++;
				var contentHeight = entries.height(), gap = availableHeight - contentHeight;
				if (gap < 0) { // wait until there's an overlap so we see a scrollbar
					break;
				}
			}
			if (attached < entry_total) {
				var scrollLoad = function(view, loadedCount, entries, container) {
					var position = loadedCount, increment = 3, total = entries.length;
					return function() {
						if (position >= total) { return; }
						var availableHeight = S.ContentArea.height() - container.position().top;
						var added = 0;
						for (var i = position, ii = total; i < ii; i++) {
							container.append(view.claim_entry(entries[i]));
							added++;
							var contentHeight = container.height(), gap = availableHeight - contentHeight;
							if (gap < 0) { // wait until there's an overlap so we see a scrollbar
								break;
							}
						}
						position += added;
						if (position >= total) {
							container.addClass('entries-loaded');
						}
					};
				}(this, attached, this.entries(), entries);
				this.watchOther(S.ContentArea, 'scroll_bottom', scrollLoad);
			} else {
				entries.addClass('entries-loaded');
			}
		},
		attachView: function() {
			this._isAttached = true;
			var entries = this._entry_container;
			if (!entries) { return; }
			this.appendEntries(entries);
		},
		check_if_empty: function() {
			var _view = this, _panel = this._panel;
			if (_view.box.entries().length === 0) {
				_panel.addClass('empty');
				// _view._bottom_add_bar.velocity('fadeOut', $.fn.appear.height_change_duration/2, function() {
				// })
			} else {
				_panel.removeClass('empty');
				// _view._bottom_add_bar.velocity('fadeIn', function() {
				// })
			}
		},
		add_allowed_types_bar: function(position, insert_at) {
			var allowed = this.box.allowed_types();
			if (allowed.length === 0) { return ''; }
			var _box = this
, allowed_bar = dom.div('.slot-addable')
			, inner = dom.div('.addable-inner')
			, dropper = allowed_bar
, drop = function(event) {
				dropper.removeClass('drop-active').addClass('uploading');
				// var progress_outer = $(dom.div, {'class':'drop-upload-outer'});
				// var progress_inner = $(dom.div, {'class':'drop-upload-inner'}).css('width', 0);
				// progress_outer.append(progress_inner);
				// dropper.append(progress_outer);
				// this.progress_bar = progress_inner;
				event.stopPropagation();
				event.preventDefault();
				var files = event.dataTransfer.files;
				if (files.length > 0) {
					S.UploadManager.wrap(this, files, insert_at());
				}
				return false;
			}.bind(this)

			, drag_enter = function(event) {
				// var files = event.originalEvent.dataTransfer.files;
				$(this).addClass('drop-active');
				event.stopPropagation();
				event.preventDefault();
				return false;
			}.bind(dropper)

			, drag_over = function(event) {
				event.stopPropagation();
				event.preventDefault();
				return false;
			}.bind(dropper)

			, drag_leave = function(event) {
				$(this).removeClass('drop-active');
				event.stopPropagation();
				event.preventDefault();
				return false;
			}.bind(dropper);

			allowed_bar.addClass(position);
			dropper.get(0).addEventListener('drop', drop, true);
			dropper.bind('dragenter', drag_enter).bind('dragover', drag_over).bind('dragleave', drag_leave);

			$.each(allowed, function(i, allow) {
				var type = allow.type, as = allow.as || type.title;
				var a = dom.a().append(dom.span().text(as)), add_allowed;
				if (type.is_alias()) {
					a.addClass('alias');
					add_allowed = function(type) {
						var d = new Spontaneous.AddAliasDialogue(_box, type, insert_at());
						d.open();
					}.bind(_box, type);
				} else {
					add_allowed = function(type) {
						this.add_content(type, insert_at());
					}.bind(_box, type);
				}
				a.click(add_allowed);
				inner.append(a);
			});
			allowed_bar.data('allowed-count', allowed.length);
			allowed_bar.append(inner, dom.span('.down'));

			return allowed_bar;
		},
		re_sort: function(item) {
			var entries = this.entries(), order = this._entry_container.sortable('toArray'), css_id = item.attr('id'), new_position = 0;
			for (var i = 0, ii = order.length; i < ii; i++) {
				if (order[i] === css_id) { new_position = i; break; }
			}
			var id = css_id.split('-')[1], entry, old_position = 0;

			for (i = 0, ii = entries.length; i < ii; i++) {
				if (entries[i].id() == id) {
					old_position = i;
					entry = entries[i];
					break;
				}
			}
			// move entry inside the array so that we can reliably find its position
			entries.splice(old_position, 1);
			entries.splice(new_position, 0, entry);
			entry.reposition(new_position, function(entry) {
				this.sorted(entry);
			}.bind(this));
		},
		sorted: function(entry) {
		},
		upload_complete: function(values) {
			this.box.entry_added(values);
		},
		upload_progress: function(position, total) {
		},
		entries: function() {
			var entries = [];
			for (var i = 0, ee = this.box.entries(), ii = ee.length;i < ii; i++) {
				var entry = ee[i];
				entries.push(this.view_for_entry(entry));
			}
			return entries;
		}.cache(),

		view_for_entry: function(entry) {
			var view_class = S.Views.PieceView, view, panel;
			if (entry.is_page()) {
				view_class = S.Views.PagePieceView;
			}
			view = new view_class(entry, this); // jshint ignore:line
			return view;
		},
		claim_entry: function(entry) {
			this._subviews.push(entry);
			var div = entry.panel();
			entry.bind('removed', this.entry_removed.bind(this));
			return div.attr('id', this.entry_id(entry)).addClass(this.entry_class());
		},

		entry_id: function(entry) {
			return 'entry-' + entry.content.id();
		},

		entry_class: function() {
			return 'container-'+this.box.schema_id();
		},

		save_path: function() {
			return ['/content', this.id()].join('/');
		},

		add_content: function(content_type, position) {
			this.box.add_entry(content_type, position);
		},

		add_alias: function(target_ids, type, position) {
			this.box.add_alias(target_ids, type, position);
		},

		insert_entry: function(entry, position) {
			this.trigger('entry_added', entry, position);
			var entries = this.entries()
			, w = this.entry_wrappers()
			, e = this.view_for_entry(entry)
			, h = this.claim_entry(e)
			, view = this;
			if (position === -1) {
				entries.push(e);
			} else {
				entries.splice(position, 0, e);
			}
			if (position === -1 || w.length === 0) {
				this._entry_container.append(h);
			} else if (position === 0) {
				this._entry_container.prepend(h);
			} else {
				this.entry_wrappers().slice(position-1, position).after(h);
			}
			if (position === -1) {
				S.ContentArea.scroll_to_bottom($.fn.appear.height_change_duration);
			}
			view.check_if_empty();
			h.hide().appear(function() {
				if (e.content.has_fields()) {
					e.edit();
				}
			});
		},

		remove_entry: function(entry) {
		},
		entry_removed: function(entry) {
			var entries = this.entries();
			for (var i = 0, ii = entries.length; i < ii; i++) {
				if (entries[i] === entry) {
					entries.splice(i, 1);
				}
			}
			this.check_if_empty();
		},
		entry_wrappers: function() {
			return this._entry_container.find('> .'+this.entry_class());
		},
		currentEntryPosition: function(entry) {
			for (var i = 0, entries = this.entries(), ii = entries.length; i < ii; i++) {
				if (entries[i] === entry) {
					return i;
				}
			}
			return false;
		},
		show_add_after: function(entry, entry_spacer) {
			var bar, entryPosition = this.currentEntryPosition.bind(this);
			var position = function() {
				return entryPosition(entry) + 1;
			};

			bar = this.add_allowed_types_bar('floating', position);
			if (bar && bar.data('allowed-count') > 0) {
				entry_spacer.addClass('add-entry').append(bar.show());
				if (!entry_spacer.data('auto-height')) {
					entry_spacer.data('auto-height', entry_spacer.height());
				}
				var newHeight = bar.find('.addable-inner').outerHeight() + 11, currentHeight = entry_spacer.outerHeight();
				newHeight = Math.max(newHeight, currentHeight);
				entry_spacer.velocity({height:newHeight}, 200);
			}
		},
		hide_add_after: function(entry, entry_spacer) {
			if (entry_spacer.data('auto-height')) {
				entry_spacer.empty();
				entry_spacer.removeClass('add-entry').velocity({height: entry_spacer.data('auto-height')}, 200);
			}
		}
	});

	return BoxView;

})(jQuery, Spontaneous);

<|endoftext|>


<commit_before>'use strict';

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// STDMATH //

var stdmath = {};
setReadOnly( stdmath, 'base', {} );

// Constants:
setReadOnly( stdmath, 'PI', require( '@stdlib/math/constants/float64-pi' ) );
setReadOnly( stdmath, 'TWO_PI', require( '@stdlib/math/constants/float64-two-pi' ) );
setReadOnly( stdmath, 'E', require( '@stdlib/math/constants/float64-e' ) );
setReadOnly( stdmath, 'EULERGAMMA', require( '@stdlib/math/constants/float64-eulergamma' ) );
setReadOnly( stdmath, 'GLAISHER', require( '@stdlib/math/constants/float64-glaisher-kinkelin' ) );

setReadOnly( stdmath, 'PINF', require( '@stdlib/math/constants/float64-pinf' ) );
setReadOnly( stdmath, 'NINF', require( '@stdlib/math/constants/float64-ninf' ) );
setReadOnly( stdmath, 'FLOAT32_PINF', require( '@stdlib/math/constants/float32-pinf' ) );
setReadOnly( stdmath, 'FLOAT32_NINF', require( '@stdlib/math/constants/float32-ninf' ) );

setReadOnly( stdmath, 'INT32_MAX', require( '@stdlib/math/constants/int32-max' ) );
setReadOnly( stdmath, 'INT32_MIN', require( '@stdlib/math/constants/int32-min' ) );
setReadOnly( stdmath, 'UINT32_MAX', require( '@stdlib/math/constants/uint32-max' ) );

setReadOnly( stdmath, 'FLOAT64_EPSILON', require( '@stdlib/math/constants/float64-eps' ) );

setReadOnly( stdmath, 'FLOAT16_PRECISION', require( '@stdlib/math/constants/float16-precision' ) );
setReadOnly( stdmath, 'FLOAT32_PRECISION', require( '@stdlib/math/constants/float32-precision' ) );
setReadOnly( stdmath, 'FLOAT64_PRECISION', require( '@stdlib/math/constants/float64-precision' ) );

// Special functions (base):
setReadOnly( stdmath.base, 'round', require( '@stdlib/math/base/special/round' ) );
setReadOnly( stdmath.base, 'roundn', require( '@stdlib/math/base/special/roundn' ) );
setReadOnly( stdmath.base, 'floor', require( '@stdlib/math/base/special/floor' ) );
setReadOnly( stdmath.base, 'ceil', require( '@stdlib/math/base/special/ceil' ) );
setReadOnly( stdmath.base, 'abs', require( '@stdlib/math/base/special/abs' ) );
setReadOnly( stdmath.base, 'pow', require( '@stdlib/math/base/special/pow' ) );
setReadOnly( stdmath.base, 'ln', require( '@stdlib/math/base/special/ln' ) );
setReadOnly( stdmath.base, 'signum', require( '@stdlib/math/base/special/signum' ) );
setReadOnly( stdmath.base, 'truncate', require( '@stdlib/math/base/special/truncate' ) );

// Utilities (base):
setReadOnly( stdmath.base, 'isNaN', require( '@stdlib/math/base/utils/is-nan' ) );
setReadOnly( stdmath.base, 'isInfinite', require( '@stdlib/math/base/utils/is-infinite' ) );
setReadOnly( stdmath.base, 'isNegativeZero', require( '@stdlib/math/base/utils/is-negative-zero' ) );
setReadOnly( stdmath.base, 'isPositiveZero', require( '@stdlib/math/base/utils/is-positive-zero' ) );
setReadOnly( stdmath.base, 'isInteger', require( '@stdlib/math/base/utils/is-integer' ) );
setReadOnly( stdmath.base, 'absoluteDifference', require( '@stdlib/math/base/utils/absolute-difference' ) );

// Utilities (generics):
setReadOnly( stdmath, 'linspace', require( '@stdlib/math/generics/utils/linspace' ) );
setReadOnly( stdmath, 'logspace', require( '@stdlib/math/generics/utils/logspace' ) );
setReadOnly( stdmath, 'incrspace', require( '@stdlib/math/generics/utils/incrspace' ) );

// EXPORTS //

module.exports = stdmath;
<commit_msg>Export float64 max safe integer constant<commit_after>'use strict';

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// STDMATH //

var stdmath = {};
setReadOnly( stdmath, 'base', {} );

// Constants:
setReadOnly( stdmath, 'PI', require( '@stdlib/math/constants/float64-pi' ) );
setReadOnly( stdmath, 'TWO_PI', require( '@stdlib/math/constants/float64-two-pi' ) );
setReadOnly( stdmath, 'E', require( '@stdlib/math/constants/float64-e' ) );
setReadOnly( stdmath, 'EULERGAMMA', require( '@stdlib/math/constants/float64-eulergamma' ) );
setReadOnly( stdmath, 'GLAISHER', require( '@stdlib/math/constants/float64-glaisher-kinkelin' ) );

setReadOnly( stdmath, 'PINF', require( '@stdlib/math/constants/float64-pinf' ) );
setReadOnly( stdmath, 'NINF', require( '@stdlib/math/constants/float64-ninf' ) );
setReadOnly( stdmath, 'FLOAT32_PINF', require( '@stdlib/math/constants/float32-pinf' ) );
setReadOnly( stdmath, 'FLOAT32_NINF', require( '@stdlib/math/constants/float32-ninf' ) );

setReadOnly( stdmath, 'INT32_MAX', require( '@stdlib/math/constants/int32-max' ) );
setReadOnly( stdmath, 'INT32_MIN', require( '@stdlib/math/constants/int32-min' ) );
setReadOnly( stdmath, 'UINT32_MAX', require( '@stdlib/math/constants/uint32-max' ) );
setReadOnly( stdmath, 'FLOAT64_MAX_SAFE_INTEGER', require( '@stdlib/math/constants/float64-max-safe-integer' ) );

setReadOnly( stdmath, 'FLOAT64_EPSILON', require( '@stdlib/math/constants/float64-eps' ) );

setReadOnly( stdmath, 'FLOAT16_PRECISION', require( '@stdlib/math/constants/float16-precision' ) );
setReadOnly( stdmath, 'FLOAT32_PRECISION', require( '@stdlib/math/constants/float32-precision' ) );
setReadOnly( stdmath, 'FLOAT64_PRECISION', require( '@stdlib/math/constants/float64-precision' ) );

// Special functions (base):
setReadOnly( stdmath.base, 'round', require( '@stdlib/math/base/special/round' ) );
setReadOnly( stdmath.base, 'roundn', require( '@stdlib/math/base/special/roundn' ) );
setReadOnly( stdmath.base, 'floor', require( '@stdlib/math/base/special/floor' ) );
setReadOnly( stdmath.base, 'ceil', require( '@stdlib/math/base/special/ceil' ) );
setReadOnly( stdmath.base, 'abs', require( '@stdlib/math/base/special/abs' ) );
setReadOnly( stdmath.base, 'pow', require( '@stdlib/math/base/special/pow' ) );
setReadOnly( stdmath.base, 'ln', require( '@stdlib/math/base/special/ln' ) );
setReadOnly( stdmath.base, 'signum', require( '@stdlib/math/base/special/signum' ) );
setReadOnly( stdmath.base, 'truncate', require( '@stdlib/math/base/special/truncate' ) );

// Utilities (base):
setReadOnly( stdmath.base, 'isNaN', require( '@stdlib/math/base/utils/is-nan' ) );
setReadOnly( stdmath.base, 'isInfinite', require( '@stdlib/math/base/utils/is-infinite' ) );
setReadOnly( stdmath.base, 'isNegativeZero', require( '@stdlib/math/base/utils/is-negative-zero' ) );
setReadOnly( stdmath.base, 'isPositiveZero', require( '@stdlib/math/base/utils/is-positive-zero' ) );
setReadOnly( stdmath.base, 'isInteger', require( '@stdlib/math/base/utils/is-integer' ) );
setReadOnly( stdmath.base, 'absoluteDifference', require( '@stdlib/math/base/utils/absolute-difference' ) );

// Utilities (generics):
setReadOnly( stdmath, 'linspace', require( '@stdlib/math/generics/utils/linspace' ) );
setReadOnly( stdmath, 'logspace', require( '@stdlib/math/generics/utils/logspace' ) );
setReadOnly( stdmath, 'incrspace', require( '@stdlib/math/generics/utils/incrspace' ) );

// EXPORTS //

module.exports = stdmath;
<|endoftext|>


<commit_before>
var Transform = require('../Transform');
var isType = require('../helper/isType');
var Handlebars = require('handlebars');
var path = require('path');

function precompileHandlebarsAsset(asset, callback) {
	var startTime = new Date();

	var partialName = path.basename(
		asset.path.replace(/\.(?:hbs|handlebars)$/, '')
	).replace(/\W+/g, '_').replace(/^([0-9])/, '_$1');

	var javaScript = (
		'// Pre-compiled Handlebars template: ' + asset.path + '\n' +
		'\n' +
		'var Handlebars = require(\'handlebars-runtime\');\n' +
		'\n' +
		'module.exports = Handlebars.partials.' + partialName + ' = ' +
		'Handlebars.template(' + Handlebars.precompile(asset.content.data) + ');\n'
	);

	var endTime = new Date();
	var transformedAsset = {
		event: 'update',
		path: asset.path + '.js',
		content: {
			type: 'application/javascript',
			data: javaScript
		},
		transforms: (asset.transforms || []).concat({
			name: 'precompileHandlebars',
			time: endTime - startTime
		})
	};

	callback(null, transformedAsset);
}

module.exports = Transform.create(function() {
	return function(asset, callback) {
		callback(null, asset);

		if (asset.event === 'update' && isType.handlebars(asset)) {
			precompileHandlebarsAsset(asset, callback);
		}
	};
});
<commit_msg>Bugfix in partial naming convention.<commit_after>
var Transform = require('../Transform');
var isType = require('../helper/isType');
var Handlebars = require('handlebars');
var path = require('path');

function precompileHandlebarsAsset(asset, callback) {
	var startTime = new Date();

	var partialName = path.basename(
		asset.path.replace(/\.(?:hbs|handlebars)$/, '')
	);

	var javaScript = (
		'// Pre-compiled Handlebars template: ' + asset.path + '\n' +
		'\n' +
		'var Handlebars = require(\'handlebars-runtime\');\n' +
		'\n' +
		'module.exports = Handlebars.partials[' + JSON.stringify(partialName) + '] = ' +
		'Handlebars.template(' + Handlebars.precompile(asset.content.data) + ');\n'
	);

	var endTime = new Date();
	var transformedAsset = {
		event: 'update',
		path: asset.path + '.js',
		content: {
			type: 'application/javascript',
			data: javaScript
		},
		transforms: (asset.transforms || []).concat({
			name: 'precompileHandlebars',
			time: endTime - startTime
		})
	};

	callback(null, transformedAsset);
}

module.exports = Transform.create(function() {
	return function(asset, callback) {
		callback(null, asset);

		if (asset.event === 'update' && isType.handlebars(asset)) {
			precompileHandlebarsAsset(asset, callback);
		}
	};
});
<|endoftext|>