<commit_before>var http = require("http");
var qs = require('querystring');
var fs = require("fs");
var pg = require("pg");
var sha3 = require("js-sha3").sha3_512;
var mustache = require("mustache");

var config = require("./config");

var pattern = fs.readFileSync("./tpl/register.tpl", "utf-8");
var footer = fs.readFileSync("./tpl/footer.tpl", "utf-8");

var worker = function(request, response){

    //проверим action
    //если newuser - пришли данные на регистрацию
    console.log(request.post);
    switch(request.url){
        case "/newuser":
            //регистрируем новичка
            console.log(request.post);
            pg.connect(config.common.postgres, function (err, pgClient, done) {
	        if(err){
                    console.log(err);
                    response.end();
    	            return;
	        }
                var sql = "select adduser($1, $2, $3);"
                pgClient.query({
                    text: sql
	           ,values: [request.post.nickname, request.post.mailbox, sha3(request.post.sword)]
	        }, function(err, result){
                    done();
	            if(err){
		        console.log(err);
                        response.end();
		        return;
	            }
                    console.log(result);
                    var headers = {};

                    headers['Content-Type'] = 'text/html';
                    headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; //Дата в прошлом
                    headers['Cache-Control'] = ' no-cache, must-revalidate'; // HTTP/1.1
                    headers['Pragma'] = ' no-cache'; // HTTP/1.1
                    //headers['Last-Modified'] = ".gmdate("D, d M Y H:i:s")."GMT");

                    response.writeHead(200, "Ok", headers);
                    var output = mustache.render(pattern, {});
                    response.write(output);
	            //response.write(JSON.stringify(result.rows));
                    response.end();
                });
            });
            break;
        case "/":
            //если нет никаких action - просто выводим форму регистрации
            pg.connect(config.common.postgres, function (err, pgClient, done) {
	        if(err){
                    console.log(err);
                    response.end();
    	            return;
	        }

                var sql = ""
                pgClient.query({
                    text: sql
	            // ,values: argv
	        }, function(err, result){
                    done();
	            if(err){
		        console.log(err);
                        response.end();
		        return;
	            }

                    var headers = {};

                    headers['Content-Type'] = 'text/html';
                    headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; //Дата в прошлом
                    headers['Cache-Control'] = ' no-cache, must-revalidate'; // HTTP/1.1
                    headers['Pragma'] = ' no-cache'; // HTTP/1.1
                    //headers['Last-Modified'] = ".gmdate("D, d M Y H:i:s")."GMT");

                    response.writeHead(200, "Ok", headers);
                    var output = mustache.render(pattern, {});
                    response.write(output);
	            //response.write(JSON.stringify(result.rows));
                    response.end();
	        });
            });
            break;
    }

};
var starter = function (request, response) {
    if (request.method == 'POST') {
        var body = '';

        request.on('data', function (data) {
            body += data;

            // Too much POST data, kill the connection!
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6)
                request.connection.destroy();
        });

        request.on('end', function () {
            request.post = qs.parse(body);
            worker(request, response);
        });
    }else{
        request.post = {};
        worker(request, response);
    }
};

http.createServer(starter).listen(7502, "localhost");
console.log('views.server running at http://localhost:7502');
<commit_msg>start<commit_after>var http = require("http");
var qs = require('querystring');
var fs = require("fs");
var pg = require("pg");
var sha3 = require("js-sha3").sha3_512;
var mustache = require("mustache");

var config = require("./config");

var pattern = fs.readFileSync("./tpl/register.tpl", "utf-8");
var footer = fs.readFileSync("./tpl/footer.tpl", "utf-8");

var worker = function(request, response){

    //проверим action
    //если newuser - пришли данные на регистрацию
    console.log(request.post);
    switch(request.url){
        case "/newuser":
            //регистрируем новичка
            console.log(request.post);
            pg.connect(config.common.postgres, function (err, pgClient, done) {
	        if(err){
                    console.log(err);
                    response.end();
    	            return;
	        }
                var sql = "select * from adduser($1, $2, $3);"
                pgClient.query({
                    text: sql
	           ,values: [request.post.nickname, request.post.mailbox, sha3(request.post.sword)]
	        }, function(err, result){
                    done();
	            if(err){
		        console.log(err);
                        response.end();
		        return;
	            }
                    console.log(result);
                    var headers = {};

                    headers['Content-Type'] = 'text/html';
                    headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; //Дата в прошлом
                    headers['Cache-Control'] = ' no-cache, must-revalidate'; // HTTP/1.1
                    headers['Pragma'] = ' no-cache'; // HTTP/1.1
                    //headers['Last-Modified'] = ".gmdate("D, d M Y H:i:s")."GMT");

                    response.writeHead(200, "Ok", headers);
                    var output = mustache.render(pattern, {});
                    response.write(output);
	            //response.write(JSON.stringify(result.rows));
                    response.end();
                });
            });
            break;
        case "/":
            //если нет никаких action - просто выводим форму регистрации
            pg.connect(config.common.postgres, function (err, pgClient, done) {
	        if(err){
                    console.log(err);
                    response.end();
    	            return;
	        }

                var sql = ""
                pgClient.query({
                    text: sql
	            // ,values: argv
	        }, function(err, result){
                    done();
	            if(err){
		        console.log(err);
                        response.end();
		        return;
	            }

                    var headers = {};

                    headers['Content-Type'] = 'text/html';
                    headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; //Дата в прошлом
                    headers['Cache-Control'] = ' no-cache, must-revalidate'; // HTTP/1.1
                    headers['Pragma'] = ' no-cache'; // HTTP/1.1
                    //headers['Last-Modified'] = ".gmdate("D, d M Y H:i:s")."GMT");

                    response.writeHead(200, "Ok", headers);
                    var output = mustache.render(pattern, {});
                    response.write(output);
	            //response.write(JSON.stringify(result.rows));
                    response.end();
	        });
            });
            break;
    }

};
var starter = function (request, response) {
    if (request.method == 'POST') {
        var body = '';

        request.on('data', function (data) {
            body += data;

            // Too much POST data, kill the connection!
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6)
                request.connection.destroy();
        });

        request.on('end', function () {
            request.post = qs.parse(body);
            worker(request, response);
        });
    }else{
        request.post = {};
        worker(request, response);
    }
};

http.createServer(starter).listen(7502, "localhost");
console.log('views.server running at http://localhost:7502');
<|endoftext|>


<commit_before>"use strict";
//просто что бы видеть, какие модули используются
["http", "fs", "pg", "url", "mustache", "js-sha3", "querystring", "./bike", "./config"].forEach(cV => require(cV));

var fs = require("fs");
var http = require("http");

var patterns = {
    register       : fs.readFileSync("./tpl/register.tpl", "utf-8")
   ,footer         : fs.readFileSync("./tpl/footer.tpl", "utf-8")
   ,congratulations: fs.readFileSync("./tpl/congratulations.tpl", "utf-8")
};

var rndHex = function (len) {
    var id = '';
    var map = '0123456789abcdef';

    for (var $i = 0; $i < len; $i++) {
        id += map.charAt(Math.floor(Math.random() * 16));
    }

    return id;
};

var dispatcher = function(request, response){

    var fw = require("./bike");

         fw.prepare_headers({request, response})
   .then(fw.parse_post, fw.error)
   .then(fw.parse_cookies, fw.err)
   .then(fw.start_session, fw.err)
   .then(worker, fw.err)
   .then(fw.output, fw.err);
};

var worker = function(job){
    return new Promise(function(resolve, reject){
        var pg = require("pg");
        var config = require("./config");
        //проверим action
        //если newuser - пришли данные на регистрацию
        console.log(job.request.post);
        switch(job.request.url){
            case "/newuser":
                //регистрируем новичка
                console.log(job.request.post);
                pg.connect(config.common.postgres, function (err, pgClient, done) {
	            if(err){
                        console.log(err);
                        reject();
    	                return;
	            }
                    var sql = "select * from adduser($1, $2, $3, $4);"
                    var sid = rndHex(128);
                    pgClient.query({
                        text: sql
	               ,values: [job.request.post.nickname, job.request.post.mailbox, sha3(job.request.post.sword), sid]
	            }, function(err, result){
                        done();
	                if(err){
		            console.log(err);
                            reject();
		            return;
	                }
                        console.log(result);
                        // если все хорошо - выставляем куки и поздравляем с регистрацией
                        "data" in job.response.habr || (job.response.habr.data = {});
                        if(result.rows[0].adduser){
                            //куки авторизации
                            job.response.habr.headers["Set-Cookie"] = 'id=' + sid + '; path=/; HttpOnly;';
                            job.response.habr.data.user = {nickname: job.request.post.nickname};
                            job.response.habr.pattern = patterns.congratulations;
                            job.response.habr.patterns = patterns;
                            resolve(job);

                        }else{//что то пошло не так - просим повторить заново (логин либо почта уже есть в системе)
                            job.response.habr.pattern = patterns.register;
                            job.response.habr.patterns = patterns;
                            resolve(job);
                        }
                    });
                });
                break;
            case "/":
                "data" in job.response.habr || (job.response.habr.data = {});
                job.response.habr.pattern = patterns.register;
                job.response.habr.patterns = patterns;
                resolve(job);
                break;
        }
    }):
};

http.createServer(dispatcher).listen(7502, "localhost");
console.log('views.server running at http://localhost:7502');
<commit_msg>start<commit_after>"use strict";
//просто что бы видеть, какие модули используются
["http", "fs", "pg", "url", "mustache", "js-sha3", "querystring", "./bike", "./config"].forEach(cV => require(cV));

var fs = require("fs");
var http = require("http");

var patterns = {
    register       : fs.readFileSync("./tpl/register.tpl", "utf-8")
   ,footer         : fs.readFileSync("./tpl/footer.tpl", "utf-8")
   ,congratulations: fs.readFileSync("./tpl/congratulations.tpl", "utf-8")
};

var rndHex = function (len) {
    var id = '';
    var map = '0123456789abcdef';

    for (var $i = 0; $i < len; $i++) {
        id += map.charAt(Math.floor(Math.random() * 16));
    }

    return id;
};

var dispatcher = function(request, response){

    var fw = require("./bike");

         fw.prepare_headers({request, response})
   .then(fw.parse_post, fw.error)
   .then(fw.parse_cookies, fw.err)
   .then(fw.start_session, fw.err)
   .then(worker, fw.err)
   .then(fw.output, fw.err);
};

var worker = function(job){
    return new Promise(function(resolve, reject){
        var pg = require("pg");
        var config = require("./config");
        //проверим action
        //если newuser - пришли данные на регистрацию
        console.log(job.request.post);
        switch(job.request.url){
            case "/newuser":
                //регистрируем новичка
                console.log(job.request.post);
                pg.connect(config.common.postgres, function (err, pgClient, done) {
	            if(err){
                        console.log(err);
                        reject();
    	                return;
	            }
                    var sql = "select * from adduser($1, $2, $3, $4);"
                    var sid = rndHex(128);
                    pgClient.query({
                        text: sql
	               ,values: [job.request.post.nickname, job.request.post.mailbox, sha3(job.request.post.sword), sid]
	            }, function(err, result){
                        done();
	                if(err){
		            console.log(err);
                            reject();
		            return;
	                }
                        console.log(result);
                        // если все хорошо - выставляем куки и поздравляем с регистрацией
                        "data" in job.response.habr || (job.response.habr.data = {});
                        if(result.rows[0].adduser){
                            //куки авторизации
                            job.response.habr.headers["Set-Cookie"] = 'id=' + sid + '; path=/; HttpOnly;';
                            job.response.habr.data.user = {nickname: job.request.post.nickname};
                            job.response.habr.pattern = patterns.congratulations;
                            job.response.habr.patterns = patterns;
                            resolve(job);

                        }else{//что то пошло не так - просим повторить заново (логин либо почта уже есть в системе)
                            job.response.habr.pattern = patterns.register;
                            job.response.habr.patterns = patterns;
                            resolve(job);
                        }
                    });
                });
                break;
            case "/":
                "data" in job.response.habr || (job.response.habr.data = {});
                job.response.habr.pattern = patterns.register;
                job.response.habr.patterns = patterns;
                resolve(job);
                break;
        }
    });
};

http.createServer(dispatcher).listen(7502, "localhost");
console.log('views.server running at http://localhost:7502');
<|endoftext|>


<commit_before>
/**
 * An implementation of Google Maps' MVCArray.
 * @see https://developers.google.com/maps/documentation/javascript/reference
 */

goog.provide('ol.Collection');
goog.provide('ol.CollectionEvent');
goog.provide('ol.CollectionEventType');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events.Event');
goog.require('ol.Object');

/**
 * @enum {string}
 */
ol.CollectionEventType = {
  ADD: 'add',
  INSERT_AT: 'insert_at',
  REMOVE: 'remove',
  REMOVE_AT: 'remove_at',
  SET_AT: 'set_at'
};

/**
 * @constructor
 * @extends {goog.events.Event}
 * @param {ol.CollectionEventType} type Type.
 * @param {*=} opt_elem Element.
 * @param {number=} opt_index Index.
 * @param {*=} opt_prev Value.
 * @param {Object=} opt_target Target.
 */
ol.CollectionEvent =
    function(type, opt_elem, opt_index, opt_prev, opt_target) {

  goog.base(this, type, opt_target);

  /**
   * @type {*}
   */
  this.elem = opt_elem;

  /**
   * @type {number|undefined}
   */
  this.index = opt_index;

  /**
   * @type {*}
   */
  this.prev = opt_prev;

};
goog.inherits(ol.CollectionEvent, goog.events.Event);

/**
 * @enum {string}
 */
ol.CollectionProperty = {
  LENGTH: 'length'
};

/**
 * @constructor
 * @extends {ol.Object}
 * @param {Array=} opt_array Array.
 */
ol.Collection = function(opt_array) {

  goog.base(this);

  /**
   * @private
   * @type {Array}
   */
  this.array_ = opt_array || [];

  this.updateLength_();

};
goog.inherits(ol.Collection, ol.Object);

/**
 * Remove all elements from the collection.
 */
ol.Collection.prototype.clear = function() {
  while (this[ol.CollectionProperty.LENGTH]) {
    this.pop();
  }
};

/**
 * @param {Function} f Function.
 * @param {Object=} opt_obj Object.
 */
ol.Collection.prototype.forEach = function(f, opt_obj) {
  goog.array.forEach(this.array_, f, opt_obj);
};

/**
 * @return {Array} Array.
 */
ol.Collection.prototype.getArray = function() {
  return this.array_;
};

/**
 * @param {number} index Index.
 * @return {*} Element.
 */
ol.Collection.prototype.getAt = function(index) {
  return this.array_[index];
};

/**
 * @return {number} Length.
 */
ol.Collection.prototype.getLength = function() {
  return /** @type {number} */ this.get(ol.CollectionProperty.LENGTH);
};

/**
 * @param {number} index Index.
 * @param {*} elem Element.
 */
ol.Collection.prototype.insertAt = function(index, elem) {
  goog.array.insertAt(this.array_, elem, index);
  this.updateLength_();
  this.dispatchEvent(new ol.CollectionEvent(
      ol.CollectionEventType.ADD, elem, undefined, undefined, this));
  this.dispatchEvent(new ol.CollectionEvent(
      ol.CollectionEventType.INSERT_AT, elem, index, undefined, this));
};

/**
 * @return {*} Element.
 */
ol.Collection.prototype.pop = function() {
  return this.removeAt(this.getLength() - 1);
};

/**
 * @param {*} elem Element.
 * @return {number} Length.
 */
ol.Collection.prototype.push = function(elem) {
  var n = this.array_.length;
  this.insertAt(n, elem);
  return n;
};

/**
 * @param {number} index Index.
 * @return {*} Value.
 */
ol.Collection.prototype.removeAt = function(index) {
  var prev = this.array_[index];
  goog.array.removeAt(this.array_, index);
  this.updateLength_();
  this.dispatchEvent(new ol.CollectionEvent(
      ol.CollectionEventType.REMOVE, prev, undefined, undefined, this));
  this.dispatchEvent(new ol.CollectionEvent(ol.CollectionEventType.REMOVE_AT,
      undefined, index, prev, this));
  return prev;
};

/**
 * @param {number} index Index.
 * @param {*} elem Element.
 */
ol.Collection.prototype.setAt = function(index, elem) {
  var n = this[ol.CollectionProperty.LENGTH];
  if (index < n) {
    var prev = this.array_[index];
    this.array_[index] = elem;
    this.dispatchEvent(new ol.CollectionEvent(ol.CollectionEventType.SET_AT,
        elem, index, prev, this));
    this.dispatchEvent(new ol.CollectionEvent(ol.CollectionEventType.REMOVE,
        prev, undefined, undefined, this));
    this.dispatchEvent(new ol.CollectionEvent(ol.CollectionEventType.ADD,
        elem, undefined, undefined, this));
  } else {
    var j;
    for (j = n; j < index; ++j) {
      this.insertAt(j, undefined);
    }
    this.insertAt(index, elem);
  }
};

/**
 * @private
 */
ol.Collection.prototype.updateLength_ = function() {
  this.set(ol.CollectionProperty.LENGTH, this.array_.length);
};
<commit_msg>Fix typecast in ol.Collection<commit_after>
/**
 * An implementation of Google Maps' MVCArray.
 * @see https://developers.google.com/maps/documentation/javascript/reference
 */

goog.provide('ol.Collection');
goog.provide('ol.CollectionEvent');
goog.provide('ol.CollectionEventType');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events.Event');
goog.require('ol.Object');

/**
 * @enum {string}
 */
ol.CollectionEventType = {
  ADD: 'add',
  INSERT_AT: 'insert_at',
  REMOVE: 'remove',
  REMOVE_AT: 'remove_at',
  SET_AT: 'set_at'
};

/**
 * @constructor
 * @extends {goog.events.Event}
 * @param {ol.CollectionEventType} type Type.
 * @param {*=} opt_elem Element.
 * @param {number=} opt_index Index.
 * @param {*=} opt_prev Value.
 * @param {Object=} opt_target Target.
 */
ol.CollectionEvent =
    function(type, opt_elem, opt_index, opt_prev, opt_target) {

  goog.base(this, type, opt_target);

  /**
   * @type {*}
   */
  this.elem = opt_elem;

  /**
   * @type {number|undefined}
   */
  this.index = opt_index;

  /**
   * @type {*}
   */
  this.prev = opt_prev;

};
goog.inherits(ol.CollectionEvent, goog.events.Event);

/**
 * @enum {string}
 */
ol.CollectionProperty = {
  LENGTH: 'length'
};

/**
 * @constructor
 * @extends {ol.Object}
 * @param {Array=} opt_array Array.
 */
ol.Collection = function(opt_array) {

  goog.base(this);

  /**
   * @private
   * @type {Array}
   */
  this.array_ = opt_array || [];

  this.updateLength_();

};
goog.inherits(ol.Collection, ol.Object);

/**
 * Remove all elements from the collection.
 */
ol.Collection.prototype.clear = function() {
  while (this[ol.CollectionProperty.LENGTH]) {
    this.pop();
  }
};

/**
 * @param {Function} f Function.
 * @param {Object=} opt_obj Object.
 */
ol.Collection.prototype.forEach = function(f, opt_obj) {
  goog.array.forEach(this.array_, f, opt_obj);
};

/**
 * @return {Array} Array.
 */
ol.Collection.prototype.getArray = function() {
  return this.array_;
};

/**
 * @param {number} index Index.
 * @return {*} Element.
 */
ol.Collection.prototype.getAt = function(index) {
  return this.array_[index];
};

/**
 * @return {number} Length.
 */
ol.Collection.prototype.getLength = function() {
  return /** @type {number} */ (this.get(ol.CollectionProperty.LENGTH));
};

/**
 * @param {number} index Index.
 * @param {*} elem Element.
 */
ol.Collection.prototype.insertAt = function(index, elem) {
  goog.array.insertAt(this.array_, elem, index);
  this.updateLength_();
  this.dispatchEvent(new ol.CollectionEvent(
      ol.CollectionEventType.ADD, elem, undefined, undefined, this));
  this.dispatchEvent(new ol.CollectionEvent(
      ol.CollectionEventType.INSERT_AT, elem, index, undefined, this));
};

/**
 * @return {*} Element.
 */
ol.Collection.prototype.pop = function() {
  return this.removeAt(this.getLength() - 1);
};

/**
 * @param {*} elem Element.
 * @return {number} Length.
 */
ol.Collection.prototype.push = function(elem) {
  var n = this.array_.length;
  this.insertAt(n, elem);
  return n;
};

/**
 * @param {number} index Index.
 * @return {*} Value.
 */
ol.Collection.prototype.removeAt = function(index) {
  var prev = this.array_[index];
  goog.array.removeAt(this.array_, index);
  this.updateLength_();
  this.dispatchEvent(new ol.CollectionEvent(
      ol.CollectionEventType.REMOVE, prev, undefined, undefined, this));
  this.dispatchEvent(new ol.CollectionEvent(ol.CollectionEventType.REMOVE_AT,
      undefined, index, prev, this));
  return prev;
};

/**
 * @param {number} index Index.
 * @param {*} elem Element.
 */
ol.Collection.prototype.setAt = function(index, elem) {
  var n = this[ol.CollectionProperty.LENGTH];
  if (index < n) {
    var prev = this.array_[index];
    this.array_[index] = elem;
    this.dispatchEvent(new ol.CollectionEvent(ol.CollectionEventType.SET_AT,
        elem, index, prev, this));
    this.dispatchEvent(new ol.CollectionEvent(ol.CollectionEventType.REMOVE,
        prev, undefined, undefined, this));
    this.dispatchEvent(new ol.CollectionEvent(ol.CollectionEventType.ADD,
        elem, undefined, undefined, this));
  } else {
    var j;
    for (j = n; j < index; ++j) {
      this.insertAt(j, undefined);
    }
    this.insertAt(index, elem);
  }
};

/**
 * @private
 */
ol.Collection.prototype.updateLength_ = function() {
  this.set(ol.CollectionProperty.LENGTH, this.array_.length);
};
<|endoftext|>


<commit_before>const persistence = require('./persistence');

function parseMod(mod) {
  let sum = 0;
  const translate = { '+': 1, '-': -1 };

  /* Find the total karma modifier by summing postive & negatives.
   * (ignore first character since @person+ doesn't do anything)
   */
  for (let i = 1; i < mod.length; i++) {
    sum += translate[mod.charAt(i)];
  }
  return sum;
}

function formatRanking(data, users) {
  let output = 'Karma Summary:\n```';

  for (let i = 0; i < data.length; i++) {
    const user = data[i];
    const username = users[user.id].username;
    const pos = i + 1;

    output += `\n${pos}. ${username} - ${user.karma} karma`;
  }
  output += '\n```';
  return output;
}

module.exports = {
  update(id, mod) {
    const diff = parseMod(mod);

    return persistence.addKarma(id, diff, () => {});
  },

  show(users) {
    return formatRanking(persistence.getKarma(), users);
  },
};
<commit_msg>Users who leave the server no longer break the !karma command<commit_after>const persistence = require('./persistence');

function parseMod(mod) {
  let sum = 0;
  const translate = { '+': 1, '-': -1 };

  /* Find the total karma modifier by summing postive & negatives.
   * (ignore first character since @person+ doesn't do anything)
   */
  for (let i = 1; i < mod.length; i++) {
    sum += translate[mod.charAt(i)];
  }
  return sum;
}

function formatRanking(data, users) {
  let output = 'Karma Summary:\n```';

  for (let i = 0; i < data.length; i++) {
    const user = data[i];
    if (!users[user.id]) { continue; } // Skip missing users
    const username = users[user.id].username;
    const pos = i + 1;

    output += `\n${pos}. ${username}: ${user.karma} karma`;
  }
  output += '\n```';
  return output;
}

module.exports = {
  update(id, mod) {
    const diff = parseMod(mod);

    return persistence.addKarma(id, diff, () => {});
  },

  show(users) {
    return formatRanking(persistence.getKarma(), users);
  },
};
<|endoftext|>


<commit_before>import path from 'path';

import React from 'react';
import ReactDom from 'react-dom';
import PropTypes from 'prop-types';

import {Point} from 'atom';
import {Emitter} from 'event-kit';
import {autobind} from 'core-decorators';

import Switchboard from '../switchboard';
import FilePatchView from '../views/file-patch-view';
import ModelObserver from '../models/model-observer';
import FilePatch from '../models/file-patch';

export default class FilePatchController extends React.Component {
  static propTypes = {
    largeDiffLineThreshold: PropTypes.number,
    repository: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,
    filePath: PropTypes.string.isRequired,
    uri: PropTypes.string.isRequired,
    workingDirectoryPath: PropTypes.string.isRequired,
    lineNumber: PropTypes.number,
    stagingStatus: PropTypes.oneOf(['unstaged', 'staged']).isRequired,
    isAmending: PropTypes.bool.isRequired,
    discardLines: PropTypes.func.isRequired,
    didSurfaceFile: PropTypes.func.isRequired,
    quietlySelectItem: PropTypes.func.isRequired,
    undoLastDiscard: PropTypes.func.isRequired,
    openFiles: PropTypes.func.isRequired,
    getSelectedStagingViewItems: PropTypes.func.isRequired,
    switchboard: PropTypes.instanceOf(Switchboard),
  }

  static defaultProps = {
    largeDiffLineThreshold: 1000,
    switchboard: new Switchboard(),
  }

  static confirmedLargeFilePatches = new Set()

  static resetConfirmedLargeFilePatches() {
    this.confirmedLargeFilePatches = new Set();
  }

  constructor(props, context) {
    super(props, context);

    this.stagingOperationInProgress = false;
    this.emitter = new Emitter();

    this.state = {
      filePatch: null,
      stagingStatus: props.stagingStatus,
      isAmending: props.isAmending,
      isPartiallyStaged: false,
    };

    this.filePath = props.filePath;
    this.repository = props.repository;
    this.workingDirectoryPath = props.repository.getWorkingDirectoryPath();
    this.repositoryObserver = new ModelObserver({
      didUpdate: () => this.onRepoRefresh(),
    });
    this.repositoryObserver.setActiveModel(props.repository);

    this.onRepoRefresh();
  }

  getStagingStatus() {
    return this.state.stagingStatus;
  }

  getWorkingDirectory() {
    return this.workingDirectoryPath;
  }

  serialize() {
    return {
      deserializer: 'FilePatchControllerStub',
      uri: this.getURI(),
    };
  }

  getURI() {
    return this.props.uri;
  }

  @autobind
  async onRepoRefresh() {
    const repository = this.repository;
    const staged = this.state.stagingStatus === 'staged';
    const isPartiallyStaged = await repository.isPartiallyStaged(this.filePath);
    let filePatch = await repository.getFilePatchForPath(this.filePath, {staged, amending: staged && this.state.isAmending});
    if (filePatch) {
      if (!this.destroyed) { this.setState({filePatch, isPartiallyStaged}); }
    } else {
      // TODO: Prevent flicker after staging/unstaging
      const oldFilePatch = this.state.filePatch;
      if (oldFilePatch) {
        filePatch = new FilePatch(oldFilePatch.getOldPath(), oldFilePatch.getNewPath(), oldFilePatch.getStatus(), []);
        if (!this.destroyed) { this.setState({filePatch, isPartiallyStaged}); }
      }
    }
  }

  componentDidUpdate(prevProps) {
    if (this.getTitle(prevProps) !== this.getTitle()) {
      this.emitter.emit('did-change-title');
    }
  }

  goToDiffLine(lineNumber) {
    this.filePatchView.goToDiffLine(lineNumber);
  }

  componentWillUnmount() {
    this.destroy();
  }

  render() {
    const hunks = this.state.filePatch ? this.state.filePatch.getHunks() : [];
    if (!hunks.length) {
      return (

          File has no contents

      );
    } else if (!this.shouldDisplayLargeDiff(this.state.filePatch)) {
      return (

This is a large diff. For performance reasons, it is not rendered by default.

          <button className="btn btn-primary" onClick={this.handleShowDiffClick}>Show Diff</button>

      );
    } else {
      // NOTE: Outer div is required for etch to render elements correctly
      const hasUndoHistory = this.repository ? this.hasUndoHistory() : false;
      return (

          <FilePatchView
            ref={c => { this.filePatchView = c; }}
            commandRegistry={this.props.commandRegistry}
            tooltips={this.props.tooltips}
            hunks={hunks}
            filePath={this.filePath}
            filePatch={this.state.filePatch}
            workingDirectoryPath={this.props.workingDirectoryPath}
            stagingStatus={this.state.stagingStatus}
            isPartiallyStaged={this.state.isPartiallyStaged}
            getSelectedStagingViewItems={this.props.getSelectedStagingViewItems}
            attemptLineStageOperation={this.attemptLineStageOperation}
            attemptHunkStageOperation={this.attemptHunkStageOperation}
            didSurfaceFile={this.didSurfaceFile}
            didDiveIntoCorrespondingFilePatch={this.diveIntoCorrespondingFilePatch}
            switchboard={this.props.switchboard}
            openCurrentFile={this.openCurrentFile}
            discardLines={this.discardLines}
            undoLastDiscard={this.undoLastDiscard}
            hasUndoHistory={hasUndoHistory}
            lineNumber={this.props.lineNumber}
          />

      );
    }
  }

  async setAmendingState(isAmending) {
    const staged = this.state.stagingStatus === 'staged';
    const amending = staged && isAmending;
    const filePatch = await this.repository.getFilePatchForPath(this.filePath, {staged, amending});
    if (filePatch) { this.setState({filePatch, isAmending}); }
  }

  shouldDisplayLargeDiff(filePatch) {
    const fullPath = path.join(this.repository.getWorkingDirectoryPath(), this.filePath);
    if (FilePatchController.confirmedLargeFilePatches.has(fullPath)) {
      return true;
    }

    const lineCount = filePatch.getHunks().reduce((acc, hunk) => hunk.getLines().length, 0);
    return lineCount < this.props.largeDiffLineThreshold;
  }

  onDidChangeTitle(callback) {
    return this.emitter.on('did-change-title', callback);
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback);
  }

  @autobind
  handleShowDiffClick() {
    if (this.repository) {
      const fullPath = path.join(this.repository.getWorkingDirectoryPath(), this.filePath);
      FilePatchController.confirmedLargeFilePatches.add(fullPath);
      this.forceUpdate();
    }
  }

  async stageHunk(hunk) {
    this.props.switchboard.didBeginStageOperation({stage: true, hunk: true});

    await this.repository.applyPatchToIndex(
      this.state.filePatch.getStagePatchForHunk(hunk),
    );
    this.props.switchboard.didFinishStageOperation({stage: true, hunk: true});
  }

  async unstageHunk(hunk) {
    this.props.switchboard.didBeginStageOperation({unstage: true, hunk: true});

    await this.repository.applyPatchToIndex(
      this.state.filePatch.getUnstagePatchForHunk(hunk),
    );

    this.props.switchboard.didFinishStageOperation({unstage: true, hunk: true});
  }

  stageOrUnstageHunk(hunk) {
    const stagingStatus = this.state.stagingStatus;
    if (stagingStatus === 'unstaged') {
      return this.stageHunk(hunk);
    } else if (stagingStatus === 'staged') {
      return this.unstageHunk(hunk);
    } else {
      throw new Error(`Unknown stagingStatus: ${stagingStatus}`);
    }
  }

  @autobind
  attemptHunkStageOperation(hunk) {
    if (this.stagingOperationInProgress) {
      return;
    }

    this.stagingOperationInProgress = true;
    this.props.switchboard.getChangePatchPromise().then(() => {
      this.stagingOperationInProgress = false;
    });

    this.stageOrUnstageHunk(hunk);
  }

  async stageLines(lines) {
    this.props.switchboard.didBeginStageOperation({stage: true, line: true});

    await this.repository.applyPatchToIndex(
      this.state.filePatch.getStagePatchForLines(lines),
    );

    this.props.switchboard.didFinishStageOperation({stage: true, line: true});
  }

  async unstageLines(lines) {
    this.props.switchboard.didBeginStageOperation({unstage: true, line: true});

    await this.repository.applyPatchToIndex(
      this.state.filePatch.getUnstagePatchForLines(lines),
    );

    this.props.switchboard.didFinishStageOperation({unstage: true, line: true});
  }

  stageOrUnstageLines(lines) {
    const stagingStatus = this.state.stagingStatus;
    if (stagingStatus === 'unstaged') {
      return this.stageLines(lines);
    } else if (stagingStatus === 'staged') {
      return this.unstageLines(lines);
    } else {
      throw new Error(`Unknown stagingStatus: ${stagingStatus}`);
    }
  }

  @autobind
  attemptLineStageOperation(lines) {
    if (this.stagingOperationInProgress) {
      return;
    }

    this.stagingOperationInProgress = true;
    this.props.switchboard.getChangePatchPromise().then(() => {
      this.stagingOperationInProgress = false;
    });

    this.stageOrUnstageLines(lines);
  }

  getTitle() {
    let title = this.state.stagingStatus === 'staged' ? 'Staged' : 'Unstaged';
    title += ' Changes: ';
    title += this.filePath;
    return title;
  }

  @autobind
  didSurfaceFile() {
    if (this.props.didSurfaceFile) {
      this.props.didSurfaceFile(this.filePath, this.state.stagingStatus);
    }
  }

  @autobind
  async diveIntoCorrespondingFilePatch() {
    const stagingStatus = this.state.stagingStatus === 'staged' ? 'unstaged' : 'staged';
    const staged = stagingStatus === 'staged';
    const amending = staged && this.state.isAmending;
    const filePatch = await this.repository.getFilePatchForPath(this.filePath, {staged, amending});
    this.props.quietlySelectItem(this.filePath, stagingStatus);
    this.setState({filePatch, stagingStatus});
  }

  @autobind
  focus() {
    if (this.filePatchView) {
      this.filePatchView.focus();
    }
  }

  wasActivated() {
    process.nextTick(() => this.focus());
  }

  @autobind
  async openCurrentFile({lineNumber} = {}) {
    const [textEditor] = await this.props.openFiles([this.filePath]);
    const position = new Point(lineNumber ? lineNumber - 1 : 0, 0);
    textEditor.scrollToBufferPosition(position, {center: true});
    textEditor.setCursorBufferPosition(position);
    return textEditor;
  }

  @autobind
  discardLines(filePatch, lines) {
    return this.props.discardLines(filePatch, lines, this.props.repository);
  }

  @autobind
  undoLastDiscard() {
    return this.props.undoLastDiscard(this.filePath, this.props.repository);
  }

  @autobind
  hasUndoHistory() {
    return this.repository.hasDiscardHistory(this.filePath);
  }

  destroy() {
    this.destroyed = true;
    this.emitter.emit('did-destroy');
    this.repositoryObserver.destroy();
  }
}
<commit_msg>Check if filePatchView exists before calling goToDiffLine<commit_after>import path from 'path';

import React from 'react';
import ReactDom from 'react-dom';
import PropTypes from 'prop-types';

import {Point} from 'atom';
import {Emitter} from 'event-kit';
import {autobind} from 'core-decorators';

import Switchboard from '../switchboard';
import FilePatchView from '../views/file-patch-view';
import ModelObserver from '../models/model-observer';
import FilePatch from '../models/file-patch';

export default class FilePatchController extends React.Component {
  static propTypes = {
    largeDiffLineThreshold: PropTypes.number,
    repository: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,
    filePath: PropTypes.string.isRequired,
    uri: PropTypes.string.isRequired,
    workingDirectoryPath: PropTypes.string.isRequired,
    lineNumber: PropTypes.number,
    stagingStatus: PropTypes.oneOf(['unstaged', 'staged']).isRequired,
    isAmending: PropTypes.bool.isRequired,
    discardLines: PropTypes.func.isRequired,
    didSurfaceFile: PropTypes.func.isRequired,
    quietlySelectItem: PropTypes.func.isRequired,
    undoLastDiscard: PropTypes.func.isRequired,
    openFiles: PropTypes.func.isRequired,
    getSelectedStagingViewItems: PropTypes.func.isRequired,
    switchboard: PropTypes.instanceOf(Switchboard),
  }

  static defaultProps = {
    largeDiffLineThreshold: 1000,
    switchboard: new Switchboard(),
  }

  static confirmedLargeFilePatches = new Set()

  static resetConfirmedLargeFilePatches() {
    this.confirmedLargeFilePatches = new Set();
  }

  constructor(props, context) {
    super(props, context);

    this.stagingOperationInProgress = false;
    this.emitter = new Emitter();

    this.state = {
      filePatch: null,
      stagingStatus: props.stagingStatus,
      isAmending: props.isAmending,
      isPartiallyStaged: false,
    };

    this.filePath = props.filePath;
    this.repository = props.repository;
    this.workingDirectoryPath = props.repository.getWorkingDirectoryPath();
    this.repositoryObserver = new ModelObserver({
      didUpdate: () => this.onRepoRefresh(),
    });
    this.repositoryObserver.setActiveModel(props.repository);

    this.onRepoRefresh();
  }

  getStagingStatus() {
    return this.state.stagingStatus;
  }

  getWorkingDirectory() {
    return this.workingDirectoryPath;
  }

  serialize() {
    return {
      deserializer: 'FilePatchControllerStub',
      uri: this.getURI(),
    };
  }

  getURI() {
    return this.props.uri;
  }

  @autobind
  async onRepoRefresh() {
    const repository = this.repository;
    const staged = this.state.stagingStatus === 'staged';
    const isPartiallyStaged = await repository.isPartiallyStaged(this.filePath);
    let filePatch = await repository.getFilePatchForPath(this.filePath, {staged, amending: staged && this.state.isAmending});
    if (filePatch) {
      if (!this.destroyed) { this.setState({filePatch, isPartiallyStaged}); }
    } else {
      // TODO: Prevent flicker after staging/unstaging
      const oldFilePatch = this.state.filePatch;
      if (oldFilePatch) {
        filePatch = new FilePatch(oldFilePatch.getOldPath(), oldFilePatch.getNewPath(), oldFilePatch.getStatus(), []);
        if (!this.destroyed) { this.setState({filePatch, isPartiallyStaged}); }
      }
    }
  }

  componentDidUpdate(prevProps) {
    if (this.getTitle(prevProps) !== this.getTitle()) {
      this.emitter.emit('did-change-title');
    }
  }

  goToDiffLine(lineNumber) {
    if (this.filePatchView) {
      this.filePatchView.goToDiffLine(lineNumber);
    }
  }

  componentWillUnmount() {
    this.destroy();
  }

  render() {
    const hunks = this.state.filePatch ? this.state.filePatch.getHunks() : [];
    if (!hunks.length) {
      return (

          File has no contents

      );
    } else if (!this.shouldDisplayLargeDiff(this.state.filePatch)) {
      return (

This is a large diff. For performance reasons, it is not rendered by default.

          <button className="btn btn-primary" onClick={this.handleShowDiffClick}>Show Diff</button>

      );
    } else {
      // NOTE: Outer div is required for etch to render elements correctly
      const hasUndoHistory = this.repository ? this.hasUndoHistory() : false;
      return (

          <FilePatchView
            ref={c => { this.filePatchView = c; }}
            commandRegistry={this.props.commandRegistry}
            tooltips={this.props.tooltips}
            hunks={hunks}
            filePath={this.filePath}
            filePatch={this.state.filePatch}
            workingDirectoryPath={this.props.workingDirectoryPath}
            stagingStatus={this.state.stagingStatus}
            isPartiallyStaged={this.state.isPartiallyStaged}
            getSelectedStagingViewItems={this.props.getSelectedStagingViewItems}
            attemptLineStageOperation={this.attemptLineStageOperation}
            attemptHunkStageOperation={this.attemptHunkStageOperation}
            didSurfaceFile={this.didSurfaceFile}
            didDiveIntoCorrespondingFilePatch={this.diveIntoCorrespondingFilePatch}
            switchboard={this.props.switchboard}
            openCurrentFile={this.openCurrentFile}
            discardLines={this.discardLines}
            undoLastDiscard={this.undoLastDiscard}
            hasUndoHistory={hasUndoHistory}
            lineNumber={this.props.lineNumber}
          />

      );
    }
  }

  async setAmendingState(isAmending) {
    const staged = this.state.stagingStatus === 'staged';
    const amending = staged && isAmending;
    const filePatch = await this.repository.getFilePatchForPath(this.filePath, {staged, amending});
    if (filePatch) { this.setState({filePatch, isAmending}); }
  }

  shouldDisplayLargeDiff(filePatch) {
    const fullPath = path.join(this.repository.getWorkingDirectoryPath(), this.filePath);
    if (FilePatchController.confirmedLargeFilePatches.has(fullPath)) {
      return true;
    }

    const lineCount = filePatch.getHunks().reduce((acc, hunk) => hunk.getLines().length, 0);
    return lineCount < this.props.largeDiffLineThreshold;
  }

  onDidChangeTitle(callback) {
    return this.emitter.on('did-change-title', callback);
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback);
  }

  @autobind
  handleShowDiffClick() {
    if (this.repository) {
      const fullPath = path.join(this.repository.getWorkingDirectoryPath(), this.filePath);
      FilePatchController.confirmedLargeFilePatches.add(fullPath);
      this.forceUpdate();
    }
  }

  async stageHunk(hunk) {
    this.props.switchboard.didBeginStageOperation({stage: true, hunk: true});

    await this.repository.applyPatchToIndex(
      this.state.filePatch.getStagePatchForHunk(hunk),
    );
    this.props.switchboard.didFinishStageOperation({stage: true, hunk: true});
  }

  async unstageHunk(hunk) {
    this.props.switchboard.didBeginStageOperation({unstage: true, hunk: true});

    await this.repository.applyPatchToIndex(
      this.state.filePatch.getUnstagePatchForHunk(hunk),
    );

    this.props.switchboard.didFinishStageOperation({unstage: true, hunk: true});
  }

  stageOrUnstageHunk(hunk) {
    const stagingStatus = this.state.stagingStatus;
    if (stagingStatus === 'unstaged') {
      return this.stageHunk(hunk);
    } else if (stagingStatus === 'staged') {
      return this.unstageHunk(hunk);
    } else {
      throw new Error(`Unknown stagingStatus: ${stagingStatus}`);
    }
  }

  @autobind
  attemptHunkStageOperation(hunk) {
    if (this.stagingOperationInProgress) {
      return;
    }

    this.stagingOperationInProgress = true;
    this.props.switchboard.getChangePatchPromise().then(() => {
      this.stagingOperationInProgress = false;
    });

    this.stageOrUnstageHunk(hunk);
  }

  async stageLines(lines) {
    this.props.switchboard.didBeginStageOperation({stage: true, line: true});

    await this.repository.applyPatchToIndex(
      this.state.filePatch.getStagePatchForLines(lines),
    );

    this.props.switchboard.didFinishStageOperation({stage: true, line: true});
  }

  async unstageLines(lines) {
    this.props.switchboard.didBeginStageOperation({unstage: true, line: true});

    await this.repository.applyPatchToIndex(
      this.state.filePatch.getUnstagePatchForLines(lines),
    );

    this.props.switchboard.didFinishStageOperation({unstage: true, line: true});
  }

  stageOrUnstageLines(lines) {
    const stagingStatus = this.state.stagingStatus;
    if (stagingStatus === 'unstaged') {
      return this.stageLines(lines);
    } else if (stagingStatus === 'staged') {
      return this.unstageLines(lines);
    } else {
      throw new Error(`Unknown stagingStatus: ${stagingStatus}`);
    }
  }

  @autobind
  attemptLineStageOperation(lines) {
    if (this.stagingOperationInProgress) {
      return;
    }

    this.stagingOperationInProgress = true;
    this.props.switchboard.getChangePatchPromise().then(() => {
      this.stagingOperationInProgress = false;
    });

    this.stageOrUnstageLines(lines);
  }

  getTitle() {
    let title = this.state.stagingStatus === 'staged' ? 'Staged' : 'Unstaged';
    title += ' Changes: ';
    title += this.filePath;
    return title;
  }

  @autobind
  didSurfaceFile() {
    if (this.props.didSurfaceFile) {
      this.props.didSurfaceFile(this.filePath, this.state.stagingStatus);
    }
  }

  @autobind
  async diveIntoCorrespondingFilePatch() {
    const stagingStatus = this.state.stagingStatus === 'staged' ? 'unstaged' : 'staged';
    const staged = stagingStatus === 'staged';
    const amending = staged && this.state.isAmending;
    const filePatch = await this.repository.getFilePatchForPath(this.filePath, {staged, amending});
    this.props.quietlySelectItem(this.filePath, stagingStatus);
    this.setState({filePatch, stagingStatus});
  }

  @autobind
  focus() {
    if (this.filePatchView) {
      this.filePatchView.focus();
    }
  }

  wasActivated() {
    process.nextTick(() => this.focus());
  }

  @autobind
  async openCurrentFile({lineNumber} = {}) {
    const [textEditor] = await this.props.openFiles([this.filePath]);
    const position = new Point(lineNumber ? lineNumber - 1 : 0, 0);
    textEditor.scrollToBufferPosition(position, {center: true});
    textEditor.setCursorBufferPosition(position);
    return textEditor;
  }

  @autobind
  discardLines(filePatch, lines) {
    return this.props.discardLines(filePatch, lines, this.props.repository);
  }

  @autobind
  undoLastDiscard() {
    return this.props.undoLastDiscard(this.filePath, this.props.repository);
  }

  @autobind
  hasUndoHistory() {
    return this.repository.hasDiscardHistory(this.filePath);
  }

  destroy() {
    this.destroyed = true;
    this.emitter.emit('did-destroy');
    this.repositoryObserver.destroy();
  }
}
<|endoftext|>


<commit_before>'use strict';
var crypto = require('crypto');
var path = require('path');
var fs = require('fs');
var chalk = require('chalk');
var eachAsync = require('each-async');

module.exports = function (grunt) {
  grunt.registerMultiTask('filever_replace', 'File revisioning based on content hashing', function () {
    var options = this.options({
      encoding: 'utf8',
      algorithm: 'md5',
      length: 8
    });
    var hash = crypto.createHash(options.algorithm).update(grunt.file.read(file), options.encoding).digest('hex');
    var suffix = hash.slice(0, options.length);
    var target = this.target;
    var filever_replace = grunt.filever_replace || {summary: {}};

    eachAsync(this.files, function (el, i, next) {
      var move = true;

      // If dest is furnished it should indicate a directory
      if (el.dest) {
        // When globbing is used, el.dest contains basename, we remove it
        if(el.orig.expand) {
          el.dest = path.dirname(el.dest);
        }

        try {
          var stat = fs.lstatSync(el.dest);
          if (stat && !stat.isDirectory()) {
            grunt.fail.fatal('Destination for target %s is not a directory', target);
          }
        } catch (err) {
          grunt.log.writeln('Destination dir ' + el.dest + ' does not exists for target ' + target + ': creating');
          grunt.file.mkdir(el.dest);
        }
        // We need to copy file as we now have a dest different from the src
        move = false;
      }

      el.src.forEach(function (file) {
        var dirname;
        var ext = path.extname(file);
        var newName = [path.basename(file, ext), suffix, ext.slice(1)].join('.');
        var resultPath;

        if (move) {
          dirname = path.dirname(file);
          resultPath = path.resolve(dirname, newName);
          fs.renameSync(file, resultPath);
        } else {
          dirname = el.dest;
          resultPath = path.resolve(dirname, newName);
          grunt.file.copy(file, resultPath);
        }

        filerev.summary[path.normalize(file)] = path.join(dirname, newName);
        grunt.log.writeln(chalk.green('✔ ') + file + chalk.gray(' changed to ') + newName);
      });
      next();
    }, this.async());

    grunt.filever_replace = filever_replace;
  });
};
<commit_msg>- some changes<commit_after>'use strict';
var crypto = require('crypto');
var path = require('path');
var fs = require('fs');
var chalk = require('chalk');
var eachAsync = require('each-async');

module.exports = function (grunt) {

  function reEscape(s) { // http://stackoverflow.com/a/18620139/899047
    return s.replace(/[$-\/?[-^{|}]/g, '\\$&');
  }

  function endsWith(s, suffix) { // http://stackoverflow.com/a/2548133/899047
    return s.indexOf(suffix, s.length - suffix.length) !== -1;
  }

  function replaceFirstGroup(s, pattern, replacement) {
    var match = pattern.exec(s);
    if (match) {
      return s.replace(pattern, match[0].replace(match[1] || match[0], replacement));
    } else {
      return s;
    }
  }

  grunt.registerMultiTask('filever_replace', 'File revisioning based on content hashing', function () {
    var options = this.options({
      encoding: 'utf8',
      algorithm: 'md5',
      length: 8
    });
    var hash = crypto.createHash(options.algorithm).digest('hex');
    var suffix = hash.slice(0, options.length);
    var target = this.target;
    var filever_replace = grunt.filever_replace || {summary: {}};
    var that = this;

    if (target === 'version') {
      eachAsync(this.files, function (el, i, next) {
        var move = true;

        // If dest is furnished it should indicate a directory
        if (el.dest) {
          // When globbing is used, el.dest contains basename, we remove it
          if(el.orig.expand) {
            el.dest = path.dirname(el.dest);
          }

          try {
            var stat = fs.lstatSync(el.dest);
            if (stat && !stat.isDirectory()) {
              grunt.fail.fatal('Destination for target %s is not a directory', target);
            }
          } catch (err) {
            grunt.log.writeln('Destination dir ' + el.dest + ' does not exists for target ' + target + ': creating');
            grunt.file.mkdir(el.dest);
          }
          // We need to copy file as we now have a dest different from the src
          move = false;
        }

        el.src.forEach(function (file) {
          var dirname;
          var ext = path.extname(file);
          var newName = [path.basename(file, ext), suffix, ext.slice(1)].join('.');
          var resultPath;

          if (move) {
            dirname = path.dirname(file);
            resultPath = path.resolve(dirname, newName);
            fs.renameSync(file, resultPath);
          } else {
            dirname = el.dest;
            resultPath = path.resolve(dirname, newName);
            grunt.file.copy(file, resultPath);
          }

          filever_replace.summary[path.normalize(file)] = path.join(dirname, newName);
          grunt.log.writeln(chalk.green('✔ ') + file + chalk.gray(' changed to ') + newName);
        });
        next();

      }, this.async());

    }

    if (target === 'replace') {

      // var path = require('path');
      var sep = '/';
      var options = this.options();
      var versioned = filever_replace.summary;

      if (versioned && path.sep !== sep) {
        var re = new RegExp(reEscape(path.sep), 'g');
        for (var assetpath in versioned) {
          versioned[assetpath.replace(re, sep)] = versioned[assetpath].replace(re, sep);
          delete versioned[assetpath];
        }
      }

      grunt.log.debug(this.nameArgs + ': ' + JSON.stringify(this.files, null, 4) +
        JSON.stringify(options, null, 4));
      grunt.log.debug('filerev.summary: ' + JSON.stringify(versioned, null, 4));

      if (versioned) {
        this.files.forEach(function(file) {
          file.src.filter(function(filepath) {
            if (!grunt.file.exists(filepath)) {
              grunt.log.warn('Source file "' + filepath + '" not found.');
              return false;
            } else {
              return true;
            }
          }).forEach(function(filepath) {
            var content = grunt.file.read(filepath);
            var updated = false;
            var replacement, lastLink, baseLink, hashLink;

            for (var label in options.patterns) {
              var pattern = options.patterns[label];
              var match = pattern.exec(content);
              console.log('MATCH ! ', match);
              if (match) {
                grunt.log.debug('Matching ' + [filepath, pattern, JSON.stringify(match)].join(': '));
                replacement = match[0];
                lastLink = match[1] || match[0];
                baseLink = options.hash ? replaceFirstGroup(lastLink, options.hash, '') : lastLink;
                for (var assetpath in versioned) {
                  if (endsWith(assetpath, baseLink)) {
                    if (!updated) {
                      grunt.log.writeln('Updating ' + filepath.cyan +
                        (file.dest ? ' -> ' + file.dest.cyan : '.'));
                    }
                    hashLink = versioned[assetpath].slice(assetpath.length - baseLink.length);
                    if (lastLink !== hashLink) {
                      grunt.log.writeln('Linking ' + label + ': ' + lastLink +
                        (baseLink !== lastLink ? ' -> ' + baseLink : '') + ' -> ' + hashLink.green);
                      replacement = replacement.replace(lastLink, hashLink);
                      content = content.replace(pattern, replacement);
                      updated = true;
                    } else {
                      grunt.log.writeln('Already linked ' + label + ': ' +
                        baseLink + ' -> ' + hashLink.green);
                    }
                    break;
                  } else {
                    grunt.log.debug('No match: ' + lastLink +
                      (baseLink !== lastLink ? ' -> ' + baseLink : '') + ' <> ' + assetpath);
                  }
                }
              } else {
                grunt.log.debug('Not matching ' + filepath + ': ' + pattern);
              }
            }
            if (updated) {
              grunt.file.write(file.dest || filepath, content);
            }
          });
        });
      }

    }

    grunt.filever_replace = filever_replace;
  });
};
<|endoftext|>


<commit_before>
// Graph object storage
var myGraph = {};

// Temporary gist data storage
var gistData = [];

// Select our active lineMode choice
var selectLineModeButton = function() {
  var index = $($('.line_mode.btn-group button.line_mode.btn[value="' + myLineMode + '"]')).attr('name');
  $('.line_mode.btn-group button.line_mode.btn.active').removeClass('active');
  $($('.line_mode.btn-group button.line_mode.btn')[index]).addClass('active');
};

// Select our active areaMode choice
var selectAreaModeButton = function() {
  var index = $($('.area_mode.btn-group button.area_mode.btn[value="' + myAreaMode + '"]')).attr('name');
  $('.area_mode.btn-group button.area_mode.btn.active').removeClass('active');
  $($('.area_mode.btn-group button.area_mode.btn')[index]).addClass('active');
};

// Select our active logMode choice
var selectLogModeButton = function() {
  var index = $($('.log_mode.btn-group button.log_mode.btn[value="' + myLogMode + '"]')).attr('name');
  $('.log_mode.btn-group button.log_mode.btn.active').removeClass('active');
  $($('.log_mode.btn-group button.log_mode.btn')[index || 1]).addClass('active');
};

// Select our active drawNullAsZero choice
var selectNullModeButton = function() {
  var index = $($('.null_mode.btn-group button.null_mode.btn[value="' + myNullMode + '"]')).attr('name');
  $('.null_mode.btn-group button.null_mode.btn.active').removeClass('active');
  $($('.null_mode.btn-group button.null_mode.btn')[index]).addClass('active');
};

// Store our updated settings
var updateGraph = function(cb) {
  var myUrl = window.location.pathname;
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {
      'overrides': {
        'lineMode': myLineMode,
        'areaMode': myAreaMode,
        'logBase': myLogMode,
        'drawNullAsZero': myNullMode,
        'target': myGraph.target
      }
    },
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'PUT',
    url: myUrl
  }).done(function(d) {
    console.log('Graph ' + window.location.pathname.split('/').pop() + ' successfully updated');
    cb();
  });
};

// Render the composer preview image and JSON editor
var renderComposerModal = function() {

  // construct our image config
  var composerImage = $.extend({}, myGraph.mergedConfig(), {
    height: 150,
    width: $('#composer_modal img#preview').width(),
    options: '&hideLegend=true',
    targets: myGraph.targets()
  });

  var composerImageUrl = constructGraphUrl(composerImage);

  $.ajax({
    beforeSend: function(xhr) {
      var creds = graphiteUser + ':' + graphitePass;
      if (creds.length > 1) {
        var bytes = Crypto.charenc.Binary.stringToBytes(creds);
        var base64 = Crypto.util.bytesToBase64(bytes);
        xhr.setRequestHeader('Authorization', 'Basic ' + base64);
      }
    },
    //error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'HEAD',
    url: composerImageUrl
  }).success(function() {
    // populate composer image and textarea
    $('#composer_modal img#preview').attr('src', composerImageUrl + '&height=' + composerImage.height + '&width=' + composerImage.width);
    $('#composer_modal textarea').text(JSON.stringify(myGraph.mergedConfig().target, null, "  "));
  });
};

// Grab configuration blob and construct our graph urls
var renderGraphs = function() {
  var myUrl = window.location.pathname;
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    url: myUrl
  }).done(function(d) {
    if (typeof d === 'undefined') {
      console.log('No graphs found');
    }

    myGraph = new Graph(d);
    var profileConfig = $.extend({}, myGraph.mergedConfig(), {height: 300, options: '&hideLegend=false'});

    updateLocalSettings(myGraph.mergedConfig());

    $('div.graphs').append('

');
    $('div.graphs div.row').append('

');
    $('div.graphs div.row div.graph').append('

');
    $('div.graph div.preview').append('');
    $('div.graph div.preview img').load(function() {
      // hide spinner on successful load
      $(this).parent('div.preview').css('background-image', 'none')
    }).error(function() {
      console.log('failed to load ' + $(this)[0].name);
      var broken_img = $(this);
      // hide spinner and show placeholder img
      broken_img.css('display', 'none');
      broken_img.parent('div.preview').css('background-image', 'url("/img/descartes-logo.png")').css('background-color', '#eee')
    });

    renderComposerModal();
    selectActiveIntervalButton();
    renderMetaInfo(d);
    renderDescription(d.description);
    renderTags();
    selectLineModeButton();
    selectAreaModeButton();
    selectLogModeButton();
    selectNullModeButton();
    $.ajax({
      accepts: {json: 'application/json'},
      cache: false,
      dataType: 'json',
      error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
      url: constructGraphUrl($.extend(profileConfig, {format: 'json'}))
    }).done(function(d) {
      gistData = d;
    });
  });
};

// Populate our info box
var renderMetaInfo = function(info) {
  $('span#owner').text(info.owner);
  $('span#created_at').text(info.created_at);
}

// Populate our description box
var renderDescription = function(description) {
  if ((typeof description === 'string') && (description.length > 0)) {
    myDescription = description;
    $('span#description').text(description);
  } else {
    $('span#description').html('Click here to add your own description of this graph.');
  }
};

// Reset description form
var resetDescriptionForm = function(desc) {
  $('div.description-wrapper span#description').removeClass('open').addClass('closed');
  $('div.description-wrapper span#description').children('textarea').remove();
  if ((typeof desc === 'string') && (desc.length > 0)) {
    $('div.description-wrapper span#description').text(desc);
  } else if (myDescription.length > 0) {
    $('div.description-wrapper span#description').text(myDescription);
  } else {
    $('div.description-wrapper span#description').append('Click here to add your own description of this graph.');
  }
  $('div.description-wrapper a').remove();
  return false;
};

// Populate our tags box
var renderTags = function() {
  gatherTags(function(tags) {
    $('div.tags-wrapper div.tags ul').remove();
    $('div.tags-wrapper div.tags span').remove();
    $('div.tags-wrapper div.tags').append('

');
    if ((typeof tags === 'object') && (tags.length > 0)) {
      for (var i in tags) {
        $('div.tags-wrapper div.tags ul').append('
 ' + tags[i].name + '
');
      }
    }
    $('div.tags-wrapper div.tags ul').append('
 Add a new tag...
');
  });
};

// Delete a tag
var deleteTag = function(id, cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'DELETE',
    url: window.location.pathname + '/tags/' + id
  }).done(function(d) {
    console.log('Tag ' + id + ' successfully deleted');
    cb();
  });
};

// Add a tag
var addTag = function(name, cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {'name': name},
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'POST',
    url: window.location.pathname + '/tags'
  }).done(function(d) {
    console.log('Tag ' + name + ' successfully added');
    cb();
  });
};

// Gather tags
var gatherTags = function(cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    url: window.location.pathname + '/tags'
  }).done(function(d) {
    cb(d);
  });
};

// Invert details button mode when activated
$(window).on('click', 'a.details.btn', function() {
  if ($('fieldset.in.collapse').length > 0) {
    resetFieldsetFormAndButtons($(this).attr('data-target'));
    $(this).text('Close Details').addClass('btn-inverse');
  } else {
    $(this).text('Details').removeClass('btn-inverse');
  }
});

// Convert description span into editable textarea
$('div.description-wrapper').on('click', 'span.closed#description', function() {
  $(this).unbind('click').removeClass('closed').addClass('open');
  $(this).html('<textarea class="description span4" rows="10">' + myDescription + '</textarea>');
  $(this).after('Update Description');
  $(this).after('Cancel');
  $(this).children('textarea').focus().select();
  return false;
});

// Reset description element on cancel
$('div.description-wrapper').on('click', 'a.description_cancel', resetDescriptionForm);

// Update description on submit
$('div.description-wrapper').on('click', 'a.description_submit', function() {
  var newDescription = $(this).parent().children('span#description').children('textarea').val();
  myDescription = newDescription;
  updateObjectAttributes({ 'description': newDescription }, function() {
    resetDescriptionForm(newDescription);
  });
  return false;
});

// Delete tag from list
$('div.tags-wrapper').on('click', 'a.tag_delete i', function() {
  var myTagId = $(this).parent().parent('li').attr('id');
  deleteTag(myTagId, function() {
    renderTags();
  });
  return false;
});

// Convert tag span into editable field
$('div.tags-wrapper').on('click', 'a.tag_add i', function() {
  $(this).parent('a').parent('li').children('span.tag_add').html('<input class="input-medium" type="text" name="new_tag"></input>');
  $(this).addClass('open');
  $('input[name="new_tag"]').focus();
});

// Add new tag
$('div.tags-wrapper div.tags').on('keypress', 'span.tag_add input[name="new_tag"]', function(e) {
  if (e.which === 13) {
    var myNewTag = $(this).val();
    addTag(myNewTag, function() {
      renderTags();
    });
    return false;
  }
});

// Reset tag input field on focusout
// XXX Potential race condition in that we call GET twice...
// XXX first after adding a tag (above), then here on focusout.
// XXX Not really a race condition per se, but a wasted call nonetheless.
$('div.tags-wrapper div.tags').on('focusout', 'span.tag_add input[name="new_tag"]', function() {
  renderTags();
});

// Update lineMode on selection
$('.line_mode.btn-group button.line_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myLineMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update areaMode on selection
$('.area_mode.btn-group button.area_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myAreaMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update logMode on selection
$('.log_mode.btn-group button.log_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myLogMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update drawNullAsZero on selection
$('.null_mode.btn-group button.null_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myNullMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// POST a new gist from profile
$('.tools.btn-group button.tools.btn.gist').click(function() {
  var graphUrl = $('.graph .preview img').attr('src');
  $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {'url': graphUrl, 'data': JSON.stringify(gistData)},
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'POST',
    url: window.location.pathname + '/gists'
  }).done(function(d) {
    $('div.header').before(
      '
' +
      '<button type="button" class="close" data-dismiss="alert">×</button>' +
      'Snapshot successfully created by ' + d.owner + ' on ' + d.created_at + '.'
    );
  }).fail(function(d, textStatus, errorThrown) {
    $('div.header').before(
      '
' +
      '<button type="button" class="close" data-dismiss="alert">×</button>' +
      'Unable to create snapshot: ' + errorThrown
    );
  });
  return false;
});

// Delete a graph
$('#destroy_modal .modal-footer button.delete').on('click', function() {
  deleteGraph($('div.graph div.preview img')[0].name, function() {
    console.log('deleted graph ' + $('div.graph div.preview img')[0].name);
    window.location.href = '/graphs';
  });
  return false;
});

// Bind composer textarea to edit and jsonlint
$('#composer_modal').on('input propertychange', 'textarea', function() {
  try {
    jsonlint.parse($(this).val());
    console.log('parses ok');
    myGraph.updateTargets(JSON.parse($(this).val()));
    renderComposerModal();
    $('#composer_modal button.targets_submit').removeClass('disabled');
  } catch(e) {
    console.log('parse failed');
    $('#composer_modal button.targets_submit').addClass('disabled');
  }
});

// Hidden key combo for composer modal
jwerty.key('alt+cmd+enter/alt+ctrl+enter', function() {
  $('#composer_modal').modal('toggle');
  $('textarea#targets_editor').focus();
});

// Activate composer modal
$('.tools.btn-group button.tools.btn.edit').on('click', function() {
  $('#composer_modal').modal('toggle');
});

// Edit graph targets
$('#composer_modal').on('click', 'button.targets_submit', function() {
  if ($(this).hasClass('disabled')) {
    console.log('broken JSON, unable to save changes');
  } else {
    updateGraph(function() {
      $('#composer_modal').modal('toggle');
      renderComposerModal();
      clearGraphs();
      renderGraphs();
    });
  }
});

// Not used in graph profile
var scrollNextPage = function() {
  return true;
}
<commit_msg>need to set creds for gist GET too<commit_after>
// Graph object storage
var myGraph = {};

// Temporary gist data storage
var gistData = [];

// Select our active lineMode choice
var selectLineModeButton = function() {
  var index = $($('.line_mode.btn-group button.line_mode.btn[value="' + myLineMode + '"]')).attr('name');
  $('.line_mode.btn-group button.line_mode.btn.active').removeClass('active');
  $($('.line_mode.btn-group button.line_mode.btn')[index]).addClass('active');
};

// Select our active areaMode choice
var selectAreaModeButton = function() {
  var index = $($('.area_mode.btn-group button.area_mode.btn[value="' + myAreaMode + '"]')).attr('name');
  $('.area_mode.btn-group button.area_mode.btn.active').removeClass('active');
  $($('.area_mode.btn-group button.area_mode.btn')[index]).addClass('active');
};

// Select our active logMode choice
var selectLogModeButton = function() {
  var index = $($('.log_mode.btn-group button.log_mode.btn[value="' + myLogMode + '"]')).attr('name');
  $('.log_mode.btn-group button.log_mode.btn.active').removeClass('active');
  $($('.log_mode.btn-group button.log_mode.btn')[index || 1]).addClass('active');
};

// Select our active drawNullAsZero choice
var selectNullModeButton = function() {
  var index = $($('.null_mode.btn-group button.null_mode.btn[value="' + myNullMode + '"]')).attr('name');
  $('.null_mode.btn-group button.null_mode.btn.active').removeClass('active');
  $($('.null_mode.btn-group button.null_mode.btn')[index]).addClass('active');
};

// Store our updated settings
var updateGraph = function(cb) {
  var myUrl = window.location.pathname;
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {
      'overrides': {
        'lineMode': myLineMode,
        'areaMode': myAreaMode,
        'logBase': myLogMode,
        'drawNullAsZero': myNullMode,
        'target': myGraph.target
      }
    },
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'PUT',
    url: myUrl
  }).done(function(d) {
    console.log('Graph ' + window.location.pathname.split('/').pop() + ' successfully updated');
    cb();
  });
};

// Render the composer preview image and JSON editor
var renderComposerModal = function() {

  // construct our image config
  var composerImage = $.extend({}, myGraph.mergedConfig(), {
    height: 150,
    width: $('#composer_modal img#preview').width(),
    options: '&hideLegend=true',
    targets: myGraph.targets()
  });

  var composerImageUrl = constructGraphUrl(composerImage);

  $.ajax({
    beforeSend: function(xhr) {
      var creds = graphiteUser + ':' + graphitePass;
      if (creds.length > 1) {
        var bytes = Crypto.charenc.Binary.stringToBytes(creds);
        var base64 = Crypto.util.bytesToBase64(bytes);
        xhr.setRequestHeader('Authorization', 'Basic ' + base64);
      }
    },
    //error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'HEAD',
    url: composerImageUrl
  }).success(function() {
    // populate composer image and textarea
    $('#composer_modal img#preview').attr('src', composerImageUrl + '&height=' + composerImage.height + '&width=' + composerImage.width);
    $('#composer_modal textarea').text(JSON.stringify(myGraph.mergedConfig().target, null, "  "));
  });
};

// Grab configuration blob and construct our graph urls
var renderGraphs = function() {
  var myUrl = window.location.pathname;
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    url: myUrl
  }).done(function(d) {
    if (typeof d === 'undefined') {
      console.log('No graphs found');
    }

    myGraph = new Graph(d);
    var profileConfig = $.extend({}, myGraph.mergedConfig(), {height: 300, options: '&hideLegend=false'});

    updateLocalSettings(myGraph.mergedConfig());

    $('div.graphs').append('

');
    $('div.graphs div.row').append('

');
    $('div.graphs div.row div.graph').append('

');
    $('div.graph div.preview').append('');
    $('div.graph div.preview img').load(function() {
      // hide spinner on successful load
      $(this).parent('div.preview').css('background-image', 'none')
    }).error(function() {
      console.log('failed to load ' + $(this)[0].name);
      var broken_img = $(this);
      // hide spinner and show placeholder img
      broken_img.css('display', 'none');
      broken_img.parent('div.preview').css('background-image', 'url("/img/descartes-logo.png")').css('background-color', '#eee')
    });

    renderComposerModal();
    selectActiveIntervalButton();
    renderMetaInfo(d);
    renderDescription(d.description);
    renderTags();
    selectLineModeButton();
    selectAreaModeButton();
    selectLogModeButton();
    selectNullModeButton();
    $.ajax({
      accepts: {json: 'application/json'},
      beforeSend: function(xhr) {
        var creds = graphiteUser + ':' + graphitePass;
        if (creds.length > 1) {
          var bytes = Crypto.charenc.Binary.stringToBytes(creds);
          var base64 = Crypto.util.bytesToBase64(bytes);
          xhr.setRequestHeader('Authorization', 'Basic ' + base64);
        }
      },
      cache: false,
      dataType: 'json',
      error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
      url: constructGraphUrl($.extend(profileConfig, {format: 'json'}))
    }).done(function(d) {
      gistData = d;
    });
  });
};

// Populate our info box
var renderMetaInfo = function(info) {
  $('span#owner').text(info.owner);
  $('span#created_at').text(info.created_at);
}

// Populate our description box
var renderDescription = function(description) {
  if ((typeof description === 'string') && (description.length > 0)) {
    myDescription = description;
    $('span#description').text(description);
  } else {
    $('span#description').html('Click here to add your own description of this graph.');
  }
};

// Reset description form
var resetDescriptionForm = function(desc) {
  $('div.description-wrapper span#description').removeClass('open').addClass('closed');
  $('div.description-wrapper span#description').children('textarea').remove();
  if ((typeof desc === 'string') && (desc.length > 0)) {
    $('div.description-wrapper span#description').text(desc);
  } else if (myDescription.length > 0) {
    $('div.description-wrapper span#description').text(myDescription);
  } else {
    $('div.description-wrapper span#description').append('Click here to add your own description of this graph.');
  }
  $('div.description-wrapper a').remove();
  return false;
};

// Populate our tags box
var renderTags = function() {
  gatherTags(function(tags) {
    $('div.tags-wrapper div.tags ul').remove();
    $('div.tags-wrapper div.tags span').remove();
    $('div.tags-wrapper div.tags').append('

');
    if ((typeof tags === 'object') && (tags.length > 0)) {
      for (var i in tags) {
        $('div.tags-wrapper div.tags ul').append('
 ' + tags[i].name + '
');
      }
    }
    $('div.tags-wrapper div.tags ul').append('
 Add a new tag...
');
  });
};

// Delete a tag
var deleteTag = function(id, cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'DELETE',
    url: window.location.pathname + '/tags/' + id
  }).done(function(d) {
    console.log('Tag ' + id + ' successfully deleted');
    cb();
  });
};

// Add a tag
var addTag = function(name, cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {'name': name},
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'POST',
    url: window.location.pathname + '/tags'
  }).done(function(d) {
    console.log('Tag ' + name + ' successfully added');
    cb();
  });
};

// Gather tags
var gatherTags = function(cb) {
  return $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    url: window.location.pathname + '/tags'
  }).done(function(d) {
    cb(d);
  });
};

// Invert details button mode when activated
$(window).on('click', 'a.details.btn', function() {
  if ($('fieldset.in.collapse').length > 0) {
    resetFieldsetFormAndButtons($(this).attr('data-target'));
    $(this).text('Close Details').addClass('btn-inverse');
  } else {
    $(this).text('Details').removeClass('btn-inverse');
  }
});

// Convert description span into editable textarea
$('div.description-wrapper').on('click', 'span.closed#description', function() {
  $(this).unbind('click').removeClass('closed').addClass('open');
  $(this).html('<textarea class="description span4" rows="10">' + myDescription + '</textarea>');
  $(this).after('Update Description');
  $(this).after('Cancel');
  $(this).children('textarea').focus().select();
  return false;
});

// Reset description element on cancel
$('div.description-wrapper').on('click', 'a.description_cancel', resetDescriptionForm);

// Update description on submit
$('div.description-wrapper').on('click', 'a.description_submit', function() {
  var newDescription = $(this).parent().children('span#description').children('textarea').val();
  myDescription = newDescription;
  updateObjectAttributes({ 'description': newDescription }, function() {
    resetDescriptionForm(newDescription);
  });
  return false;
});

// Delete tag from list
$('div.tags-wrapper').on('click', 'a.tag_delete i', function() {
  var myTagId = $(this).parent().parent('li').attr('id');
  deleteTag(myTagId, function() {
    renderTags();
  });
  return false;
});

// Convert tag span into editable field
$('div.tags-wrapper').on('click', 'a.tag_add i', function() {
  $(this).parent('a').parent('li').children('span.tag_add').html('<input class="input-medium" type="text" name="new_tag"></input>');
  $(this).addClass('open');
  $('input[name="new_tag"]').focus();
});

// Add new tag
$('div.tags-wrapper div.tags').on('keypress', 'span.tag_add input[name="new_tag"]', function(e) {
  if (e.which === 13) {
    var myNewTag = $(this).val();
    addTag(myNewTag, function() {
      renderTags();
    });
    return false;
  }
});

// Reset tag input field on focusout
// XXX Potential race condition in that we call GET twice...
// XXX first after adding a tag (above), then here on focusout.
// XXX Not really a race condition per se, but a wasted call nonetheless.
$('div.tags-wrapper div.tags').on('focusout', 'span.tag_add input[name="new_tag"]', function() {
  renderTags();
});

// Update lineMode on selection
$('.line_mode.btn-group button.line_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myLineMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update areaMode on selection
$('.area_mode.btn-group button.area_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myAreaMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update logMode on selection
$('.log_mode.btn-group button.log_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myLogMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// Update drawNullAsZero on selection
$('.null_mode.btn-group button.null_mode.btn').click(function() {
  if ($(this).attr('value').length > 0) {
    myNullMode = $(this).attr('value');
    updateGraph(function() {
      clearGraphs();
      renderGraphs();
    });
  }
});

// POST a new gist from profile
$('.tools.btn-group button.tools.btn.gist').click(function() {
  var graphUrl = $('.graph .preview img').attr('src');
  $.ajax({
    accepts: {json: 'application/json'},
    cache: false,
    data: {'url': graphUrl, 'data': JSON.stringify(gistData)},
    dataType: 'json',
    error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); },
    type: 'POST',
    url: window.location.pathname + '/gists'
  }).done(function(d) {
    $('div.header').before(
      '
' +
      '<button type="button" class="close" data-dismiss="alert">×</button>' +
      'Snapshot successfully created by ' + d.owner + ' on ' + d.created_at + '.'
    );
  }).fail(function(d, textStatus, errorThrown) {
    $('div.header').before(
      '
' +
      '<button type="button" class="close" data-dismiss="alert">×</button>' +
      'Unable to create snapshot: ' + errorThrown
    );
  });
  return false;
});

// Delete a graph
$('#destroy_modal .modal-footer button.delete').on('click', function() {
  deleteGraph($('div.graph div.preview img')[0].name, function() {
    console.log('deleted graph ' + $('div.graph div.preview img')[0].name);
    window.location.href = '/graphs';
  });
  return false;
});

// Bind composer textarea to edit and jsonlint
$('#composer_modal').on('input propertychange', 'textarea', function() {
  try {
    jsonlint.parse($(this).val());
    console.log('parses ok');
    myGraph.updateTargets(JSON.parse($(this).val()));
    renderComposerModal();
    $('#composer_modal button.targets_submit').removeClass('disabled');
  } catch(e) {
    console.log('parse failed');
    $('#composer_modal button.targets_submit').addClass('disabled');
  }
});

// Hidden key combo for composer modal
jwerty.key('alt+cmd+enter/alt+ctrl+enter', function() {
  $('#composer_modal').modal('toggle');
  $('textarea#targets_editor').focus();
});

// Activate composer modal
$('.tools.btn-group button.tools.btn.edit').on('click', function() {
  $('#composer_modal').modal('toggle');
});

// Edit graph targets
$('#composer_modal').on('click', 'button.targets_submit', function() {
  if ($(this).hasClass('disabled')) {
    console.log('broken JSON, unable to save changes');
  } else {
    updateGraph(function() {
      $('#composer_modal').modal('toggle');
      renderComposerModal();
      clearGraphs();
      renderGraphs();
    });
  }
});

// Not used in graph profile
var scrollNextPage = function() {
  return true;
}
<|endoftext|>


<commit_before>'use strict';

var util = require('../../../utils/index');

var object = util.object;

function factory (type, config, load, typed) {

  var matrix = load(require('../../../type/matrix/function/matrix'));
  var zeros = load(require('../../matrix/zeros'));
  var eye = load(require('../../matrix/eye'));
  var clone = load(require('../../utils/clone'));

  var isZero = load(require('../../utils/isZero'));
  var isPositive = load(require('../../utils/isPositive'));
  var unequal = load(require('../../relational/unequal'));

  var abs = load(require('../../arithmetic/abs'));
  var sign = load(require('../../arithmetic/sign'));
  var hypot = load(require('../../arithmetic/hypot'));
  var conj = load(require('../../complex/conj'));

  var unaryMinus = load(require('../../arithmetic/unaryMinus'));
  var addScalar = load(require('../../arithmetic/addScalar'));
  var divideScalar = load(require('../../arithmetic/divideScalar'));
  var multiplyScalar = load(require('../../arithmetic/multiplyScalar'));
  var subtract = load(require('../../arithmetic/subtract'));

  /**
   * Calculate the Matrix QR decomposition. Matrix `A` is decomposed in two matrices (`Q`, `R`) where `Q` is an
   * orthoganal matrix and `R` is an upper triangular matrix.
   *
   * Syntax:
   *
   *    math.qr(A);
   *
   * Example:
   *
   *    var m = [
   *      [1, -1,  4],
   *      [1,  4, -2],
   *      [1,  4,  2],
   *      [1,  -1, 0]
   *    ];
   *    var result = math.qr(m);
   *    // r = {
   *    //   Q: [
   *    //     [0.5, -0.5,   0.5],
   *    //     [0.5,  0.5,  -0.5],
   *    //     [0.5,  0.5,   0.5],
   *    //     [0.5, -0.5,  -0.5],
   *    //   ],
   *    //   R: [
   *    //     [2, 3,  2],
   *    //     [0, 5, -2],
   *    //     [0, 0,  4]
   *    //   ]
   *    // }
   *
   * See also:
   *
   *    TODO!!
   *
   * @param {Matrix | Array} A    A two dimensional matrix or array for which to get the QR decomposition.
   *
   * @return {{Q: Array | Matrix, R: Array | Matrix}} Q: the orthoganal matrix and R: the upper triangular matrix
   */
  var qr = typed('qr', {

    'DenseMatrix': function (m) {
      return _denseQR(m);
    },

    'SparseMatrix': function (m) {
      return _sparseQR(m);
    },

    'Array': function (a) {
      // create dense matrix from array
      var m = matrix(a);
      // lup, use matrix implementation
      var r = _denseQR(m);
      // result
      return {
        Q: r.Q.valueOf(),
        R: r.R.valueOf(),
      };
    }
  });

  var _denseQR = function (m) {

    // rows & columns (m x n)
    var rows = m._size[0]; // m
    var cols = m._size[1]; // n

    var Q = eye([rows], 'dense');
    var Qdata = Q._data;

    var R = m.clone();
    var Rdata = R._data;

    // vars
    var i, j, k;

    var w = zeros([rows], '');

    for (k = 0; k < Math.min(cols, rows); ++k) {

      /*
       * **k-th Household matrix**
       *
       * The matrix I - 2*v*transpose(v)
       * x     = first column of A
       * x1    = first element of x
       * alpha = x1 / |x1| * |x|
       * e1    = tranpose([1, 0, 0, ...])
       * u     = x - alpha * e1
       * v     = u / |u|
       *
       * Household matrix = I - 2 * v * tranpose(v)
       *
       *  * Initially Q = I and R = A.
       *  * Household matrix is a reflection in a plane normal to v which will zero
       *    out all but the top right element in R.
       *  * Appplying reflection to both Q and R will not change product.
       *  * Repeat this process on the (1,1) minor to get R as an upper triangular matrix.
       *  * Reflections leave the magnitude of the columns of Q unchanged so Q remains othoganal.
       *
       */

      // TODO what is the best way to find modulus of a potentialy complex vector
      var alpha = 0.0;
      for (i = k; i < rows; i++) {
        alpha = hypot(alpha,abs(Rdata[i][k]));
      }

      var pivot = Rdata[k][k];

      var sgn = unaryMinus(sign(pivot));
      var conjSgn = conj(sgn);

      alpha = multiplyScalar(sgn, alpha);

      if (!isZero(alpha)) {

        // first element in vector u
        var u1 = subtract(pivot, alpha);

        // w = v * u1 / |u|    (only elements k to (rows-1) are used)
        w[k] = 1;

        for (i = k+1; i < rows; i++) {
          w[i] = divideScalar(Rdata[i][k], u1);
        }

        // tau = - conj(u1 / alpha)
        var tau = unaryMinus(conj(divideScalar(u1, alpha)));

        /*
         * tau and w have been choosen so that
         *
         * 2 * v * tranpose(v) = tau * w * tranpose(w)
         */

        /*
         * -- calculate R = R - tau * w * tranpose(w) * R --
         * Only do calculation with rows k to (rows-1)
         * Additionally columns 0 to (k-1) will not be changed by this
         *   multiplication so do not bother recalculating them
         */
        for (j = k; j < cols; j++) {
          var s = 0.0;

          // calculate jth element of [tranpose(w) * R]
          for (i = k; i < rows; i++) {
            s = addScalar(s, multiplyScalar(conj(w[i]), Rdata[i][j]));
          }

          // calculate the jth element of [tau * transpose(w) * R]
          s = multiplyScalar(s, tau);

          for (i = k; i < rows; i++) {
            Rdata[i][j] = multiplyScalar(subtract(Rdata[i][j], multiplyScalar(w[i], s)), conjSgn);
          }
        }
        /*
         * -- calculate Q = Q - tau * Q * w * transpose(w) --
         * Q is a square matrix (rows x rows)
         * Only do calculation with columns k to (rows-1)
         * Additionally rows 0 to (k-1) will not be changed by this
         *   multiplication so do not bother recalculating them
         */
        for (i = 0; i < rows; i++) {
          var s = 0.0;

          // calculate ith element of [Q * w]
          for (j = k; j < rows; j++) {
            s = addScalar(s, multiplyScalar(Qdata[i][j], w[j]));
          }

          // calculate the ith element of [tau * Q * w]
          s = multiplyScalar(s, tau);

          for (j = k; j < rows; ++j) {
            Qdata[i][j] = divideScalar(subtract(Qdata[i][j], multiplyScalar(s, conj(w[j]))), conjSgn);
          }

        }
      }

    }

    // coerse almost zero elements to zero
    // TODO I feel uneasy just zeroing these values
    for (i = 0; i < rows; ++i) {
      for (j = 0; j < i && j < cols; ++j) {
        if (unequal(0, divideScalar(Rdata[i][j], 1e5))) {
          throw new Error('math.qr(): unknown error - R is not lower triangular (element (' + i + ', ' + j + ')  = ' + Rdata[i][j] + ')');
        }
        Rdata[i][j] = multiplyScalar(Rdata[i][j], 0);
      }
    }

    // return matrices
    return {
      Q: Q,
      R: R,
      toString: function () {
        return 'Q: ' + this.Q.toString() + '\nR: ' + this.R.toString();
      }
    };
  };

  var _sparseQR = function (m) {

    throw new Error('qr not implemented for sparse matrices yet');

    // return matrices
    return {
      Q: new SparseMatrix({
        values: Qdata,
        index: Qindex,
        ptr: Qptr,
        size: Qsize
      }),
      R: new SparseMatrix({
        values: Rdata,
        index: Rindex,
        ptr: Rptr,
        size: Rsize
      }),
      toString: function () {
        return 'Q: ' + this.Q.toString() + '\nR: ' + this.R.toString();
      }
    };
  };

  return qr;
}

exports.name = 'qr';
exports.factory = factory;
<commit_msg>qr.js conforms to node-style-guide<commit_after>'use strict';

var util = require('../../../utils/index');

var object = util.object;

function factory (type, config, load, typed) {

  var matrix = load(require('../../../type/matrix/function/matrix'));
  var zeros = load(require('../../matrix/zeros'));
  var eye = load(require('../../matrix/eye'));
  var clone = load(require('../../utils/clone'));

  var isZero = load(require('../../utils/isZero'));
  var isPositive = load(require('../../utils/isPositive'));
  var unequal = load(require('../../relational/unequal'));

  var abs = load(require('../../arithmetic/abs'));
  var sign = load(require('../../arithmetic/sign'));
  var hypot = load(require('../../arithmetic/hypot'));
  var conj = load(require('../../complex/conj'));

  var unaryMinus = load(require('../../arithmetic/unaryMinus'));
  var addScalar = load(require('../../arithmetic/addScalar'));
  var divideScalar = load(require('../../arithmetic/divideScalar'));
  var multiplyScalar = load(require('../../arithmetic/multiplyScalar'));
  var subtract = load(require('../../arithmetic/subtract'));

  /**
   * Calculate the Matrix QR decomposition. Matrix `A` is decomposed in
   * two matrices (`Q`, `R`) where `Q` is an
   * orthoganal matrix and `R` is an upper triangular matrix.
   *
   * Syntax:
   *
   *    math.qr(A);
   *
   * Example:
   *
   *    var m = [
   *      [1, -1,  4],
   *      [1,  4, -2],
   *      [1,  4,  2],
   *      [1,  -1, 0]
   *    ];
   *    var result = math.qr(m);
   *    // r = {
   *    //   Q: [
   *    //     [0.5, -0.5,   0.5],
   *    //     [0.5,  0.5,  -0.5],
   *    //     [0.5,  0.5,   0.5],
   *    //     [0.5, -0.5,  -0.5],
   *    //   ],
   *    //   R: [
   *    //     [2, 3,  2],
   *    //     [0, 5, -2],
   *    //     [0, 0,  4]
   *    //   ]
   *    // }
   *
   * See also:
   *
   *    lu
   *
   * @param {Matrix | Array} A    A two dimensional matrix or array
   * for which to get the QR decomposition.
   *
   * @return {{Q: Array | Matrix, R: Array | Matrix}} Q: the orthoganal
   * matrix and R: the upper triangular matrix
   */
  var qr = typed('qr', {

    'DenseMatrix': function (m) {
      return _denseQR(m);
    },

    'SparseMatrix': function (m) {
      return _sparseQR(m);
    },

    'Array': function (a) {
      // create dense matrix from array
      var m = matrix(a);
      // lup, use matrix implementation
      var r = _denseQR(m);
      // result
      return {
        Q: r.Q.valueOf(),
        R: r.R.valueOf(),
      };
    }
  });

  var _denseQR = function (m) {

    // rows & columns (m x n)
    var rows = m._size[0]; // m
    var cols = m._size[1]; // n

    var Q = eye([rows], 'dense');
    var Qdata = Q._data;

    var R = m.clone();
    var Rdata = R._data;

    // vars
    var i, j, k;

    var w = zeros([rows], '');

    for (k = 0; k < Math.min(cols, rows); ++k) {

      /*
       * **k-th Household matrix**
       *
       * The matrix I - 2*v*transpose(v)
       * x     = first column of A
       * x1    = first element of x
       * alpha = x1 / |x1| * |x|
       * e1    = tranpose([1, 0, 0, ...])
       * u     = x - alpha * e1
       * v     = u / |u|
       *
       * Household matrix = I - 2 * v * tranpose(v)
       *
       *  * Initially Q = I and R = A.
       *  * Household matrix is a reflection in a plane normal to v which
       *    will zero out all but the top right element in R.
       *  * Appplying reflection to both Q and R will not change product.
       *  * Repeat this process on the (1,1) minor to get R as an upper
       *    triangular matrix.
       *  * Reflections leave the magnitude of the columns of Q unchanged
       *    so Q remains othoganal.
       *
       */

      // TODO what is the best way to find modulus of a
      // potentialy complex vector
      var alpha = 0.0;
      for (i = k; i < rows; i++) {
        alpha = hypot(alpha,abs(Rdata[i][k]));
      }

      var pivot = Rdata[k][k];

      var sgn = unaryMinus(sign(pivot));
      var conjSgn = conj(sgn);

      alpha = multiplyScalar(sgn, alpha);

      if (!isZero(alpha)) {

        // first element in vector u
        var u1 = subtract(pivot, alpha);

        // w = v * u1 / |u|    (only elements k to (rows-1) are used)
        w[k] = 1;

        for (i = k+1; i < rows; i++) {
          w[i] = divideScalar(Rdata[i][k], u1);
        }

        // tau = - conj(u1 / alpha)
        var tau = unaryMinus(conj(divideScalar(u1, alpha)));

        var s;

        /*
         * tau and w have been choosen so that
         *
         * 2 * v * tranpose(v) = tau * w * tranpose(w)
         */

        /*
         * -- calculate R = R - tau * w * tranpose(w) * R --
         * Only do calculation with rows k to (rows-1)
         * Additionally columns 0 to (k-1) will not be changed by this
         *   multiplication so do not bother recalculating them
         */
        for (j = k; j < cols; j++) {
          s = 0.0;

          // calculate jth element of [tranpose(w) * R]
          for (i = k; i < rows; i++) {
            s = addScalar(s, multiplyScalar(conj(w[i]), Rdata[i][j]));
          }

          // calculate the jth element of [tau * transpose(w) * R]
          s = multiplyScalar(s, tau);

          for (i = k; i < rows; i++) {
            Rdata[i][j] = multiplyScalar(
              subtract(Rdata[i][j], multiplyScalar(w[i], s)),
              conjSgn
            );
          }
        }
        /*
         * -- calculate Q = Q - tau * Q * w * transpose(w) --
         * Q is a square matrix (rows x rows)
         * Only do calculation with columns k to (rows-1)
         * Additionally rows 0 to (k-1) will not be changed by this
         *   multiplication so do not bother recalculating them
         */
        for (i = 0; i < rows; i++) {
          s = 0.0;

          // calculate ith element of [Q * w]
          for (j = k; j < rows; j++) {
            s = addScalar(s, multiplyScalar(Qdata[i][j], w[j]));
          }

          // calculate the ith element of [tau * Q * w]
          s = multiplyScalar(s, tau);

          for (j = k; j < rows; ++j) {
            Qdata[i][j] = divideScalar(
              subtract(Qdata[i][j], multiplyScalar(s, conj(w[j]))),
              conjSgn
            );
          }

        }
      }

    }

    // coerse almost zero elements to zero
    // TODO I feel uneasy just zeroing these values
    for (i = 0; i < rows; ++i) {
      for (j = 0; j < i && j < cols; ++j) {
        if (unequal(0, divideScalar(Rdata[i][j], 1e5))) {
          throw new Error('math.qr(): unknown error - ' +
           'R is not lower triangular (element (' +
            i + ', ' + j + ')  = ' + Rdata[i][j] + ')'
          );
        }
        Rdata[i][j] = multiplyScalar(Rdata[i][j], 0);
      }
    }

    // return matrices
    return {
      Q: Q,
      R: R,
      toString: function () {
        return 'Q: ' + this.Q.toString() + '\nR: ' + this.R.toString();
      }
    };
  };

  var _sparseQR = function (m) {

    throw new Error('qr not implemented for sparse matrices yet');

  };
}

exports.name = 'qr';
exports.factory = factory;
<|endoftext|>