<commit_before>var graphs = []; // rickshaw objects
var datum = []; // metric data
var aliases = []; // alias strings

// minutes of data in the live feed
var period = (typeof period == 'undefined') ? 5 : period;

function constructWidgets() {
	graphElements = document.querySelectorAll('.graph');

    for (var i = 0; i < graphElements.length; i++) {
        aliases[i] = 'not important';
		datum[i] = [{ x:0, y:0 }];
		graphs[i] = new Rickshaw.Graph({
			element: graphElements[i],
			interpolation: 'step-after',
			series: [{
			color: '#afdab1',
			data: datum[i]
			}]
		});
		graphs[i].render();
	}
}

var currentUrl = ""
function constructUrl(period) {
	widgetElements = document.querySelectorAll('.widget');

	var targets = "";
	for (var i=0; i < widgetElements.length; i++) {
		if (i != 0) {
			targets += '&';
		}
		targets += ('target=' + encodeURI($.trim(widgetElements[i].id)));
	}
	currentUrl = '/render/?' + targets + '&from=-' + period + 'minutes&format=json';

	console.log(currentUrl);
}

// refresh the graph
function refreshData(immediately) {

	getData(function(values) {
		for (var i=0; i<graphs.length; i++) {
			for (var j=0; j<values[i].length; j++) {
				if (typeof values[i][j] !== "undefined") {
					datum[i][j] = values[i][j];
				}
			}

			// we want to render immediately, i.e.
			// as soon as ajax completes
			// used for time period / pause view
			if (immediately) {
				updateGraphs(i);
			}
		}

		values = null;
	});

	// we can wait until all data is gathered, i.e.
	// the live refresh should happen synchronously
	if (!immediately) {
		for (var i=0; i<graphs.length; i++) {
			updateGraphs(i);
		}
	}
}

// retrieve the data from Graphite
function getData(dataCallback) {
	var obtainedDatum = [];
	$.ajax({

		/*beforeSend: function(xhr) {
		  if (auth.length > 0) {
		  var bytes = Crypto.charenc.Binary.stringToBytes(auth);
		  var base64 = Crypto.util.bytesToBase64(bytes);
		  xhr.setRequestHeader("Authorization", "Basic " + base64);
		  }
		  },*/

		dataType: 'json',
		error: function(xhr, textStatus, errorThrown) {
			console.log("Error: " + xhr + " " + textStatus + " " + errorThrown);
		},
		url: currentUrl
	}).done(function(d) {
		if (d.length > 0) {
			for (var i=0; i<d.length; i++) {
				obtainedDatum[i] = [];
				obtainedDatum[i][0] = {
					x: d[i].datapoints[0][1],
	y: d[i].datapoints[0][0] || graphs[i].lastKnownValue || 0
				};
				for (var j=1; j<d[i].datapoints.length; j++) {
					obtainedDatum[i][j] = {
						x: d[i].datapoints[j][1],
	y: d[i].datapoints[j][0] || graphs[i].lastKnownValue
					};
					if (typeof d[i].datapoints[j][0] === "number") {
						graphs[i].lastKnownValue = d[i].datapoints[j][0];
					}
				}
			}
		}
		dataCallback(obtainedDatum);
	});
}

// perform the actual graph object and
// overlay name and number updates
function updateGraphs(i) {
	// update our graph
	graphs[i].update();
	if (datum[i][datum[i].length - 1] !== undefined) {
		var lastValue = datum[i][datum[i].length - 1].y;
		var lastValueDisplay;
		if ((typeof lastValue == 'number') && lastValue < 2.0) {
			lastValueDisplay = Math.round(lastValue*1000)/1000;
		} else {
			lastValueDisplay = parseInt(lastValue);
		}
	}
}

// build our graph objects
constructWidgets();

// set our last known value at invocation
Rickshaw.Graph.prototype.lastKnownValue = 0;

// build our url
constructUrl(period);

refreshData("now");

// define our refresh and start interval
var refreshInterval = (typeof refresh == 'undefined') ? 2000 : refresh;
var refreshId = setInterval(refreshData, refreshInterval);
<commit_msg>got rid of client side metric storage<commit_after>var graphs = []; // rickshaw objects
var datum = []; // metric data
var aliases = []; // alias strings

// minutes of data in the live feed
var period = (typeof period == 'undefined') ? 5 : period;

function constructWidgets() {
	graphElements = document.querySelectorAll('.graph');

    for (var i = 0; i < graphElements.length; i++) {
        aliases[i] = 'not important';
		datum[i] = [{ x:0, y:0 }];
		graphs[i] = new Rickshaw.Graph({
			element: graphElements[i],
			interpolation: 'step-after',
			series: [{
			color: '#afdab1',
			data: datum[i]
			}]
		});
		graphs[i].render();
	}
}

var currentUrl = ""
function constructUrl(period) {
	widgetElements = document.querySelectorAll('.widget');

	var targets = "";
	for (var i=0; i < widgetElements.length; i++) {
		if (i != 0) {
			targets += '&';
		}
		targets += ('target=' + encodeURI($.trim(widgetElements[i].id)));
	}
	currentUrl = '/render/?' + targets + '&from=-' + period + 'minutes&format=json';

	console.log(currentUrl);
}

// refresh the graph
function refreshData(immediately) {

	getData(function(values) {
		for (var i=0; i<graphs.length; i++) {
			for (var j=0; j<values[i].length; j++) {
				if (typeof values[i][j] !== "undefined") {
					datum[i][j] = values[i][j];
				}
			}

			// we want to render immediately, i.e.
			// as soon as ajax completes
			// used for time period / pause view
			if (immediately) {
				updateGraphs(i);
			}
		}

		values = null;
	});

	// we can wait until all data is gathered, i.e.
	// the live refresh should happen synchronously
	if (!immediately) {
		for (var i=0; i<graphs.length; i++) {
			updateGraphs(i);
		}
	}
}

// retrieve the data from Graphite
function getData(dataCallback) {
	var obtainedDatum = [];
	$.ajax({

		/*beforeSend: function(xhr) {
		  if (auth.length > 0) {
		  var bytes = Crypto.charenc.Binary.stringToBytes(auth);
		  var base64 = Crypto.util.bytesToBase64(bytes);
		  xhr.setRequestHeader("Authorization", "Basic " + base64);
		  }
		  },*/

		dataType: 'json',
		error: function(xhr, textStatus, errorThrown) {
			console.log("Error: " + xhr + " " + textStatus + " " + errorThrown);
		},
		url: currentUrl
	}).done(function(d) {
		if (d.length > 0) {
			for (var i=0; i<d.length; i++) {
				obtainedDatum[i] = [];
				obtainedDatum[i][0] = {
					x: d[i].datapoints[0][1],
	y: d[i].datapoints[0][0] || graphs[i].lastKnownValue || 0
				};
				for (var j=1; j<d[i].datapoints.length; j++) {
					obtainedDatum[i][j] = {
						x: d[i].datapoints[j][1],
	y: d[i].datapoints[j][0] || graphs[i].lastKnownValue
					};
					if (typeof d[i].datapoints[j][0] === "number") {
						graphs[i].lastKnownValue = d[i].datapoints[j][0];
					}
				}
			}
		}
		dataCallback(obtainedDatum);
	});
}

// perform the actual graph object and
// overlay name and number updates
function updateGraphs(i) {
	// update our graph
	graphs[i].update();
	if (datum[i][datum[i].length - 1] !== undefined) {
		var lastValue = datum[i][datum[i].length - 1].y;
		var lastValueDisplay;
		if ((typeof lastValue == 'number') && lastValue < 2.0) {
			lastValueDisplay = Math.round(lastValue*1000)/1000;
		} else {
			lastValueDisplay = parseInt(lastValue);
		}
	}
}

// build our graph objects
constructWidgets();

// build our url
constructUrl(period);

refreshData("now");

// define our refresh and start interval
var refreshInterval = (typeof refresh == 'undefined') ? 2000 : refresh;
var refreshId = setInterval(refreshData, refreshInterval);
<|endoftext|>


<commit_before>/**
 * Created by ndyumin on 06.12.2015.
 */

define(['bacon', '../util', './enemy', 'pf'], function(Bacon, util, enemy, pf) {
    'use strict';

    function addEnemy(enemies, enemy) {
        enemies.push(enemy);
        return enemies;
    }

    const tick_time = 500;
    const spawn_time = 1500;
    const enemiesL = util.lens('enemies');
    const mapL = util.lens('map');

    return function (map) {
        const grid = new pf.Grid(map.map(l=> l.map(x=>+(x === 5))));
        const finder = new pf.AStarFinder();

        function nextPosition(x, y) {
            const path = finder.findPath(x, y, 38, 28, grid.clone());
            return path.length  > 1 ? path[1] : [x, y];
        }

        function updatePositions(state) {
            state.enemies =  state.enemies.map(function(e) {
                e.position = nextPosition(e.position[0], e.position[1]);
                return e;
            });
            return state;
        }

        const enemyS = Bacon.interval(spawn_time)
            .flatMapLatest(enemy);

        const mapS = Bacon.constant(map);
        const enemiesS = Bacon.constant([])
            .combine(enemyS, addEnemy);

        return Bacon.interval(tick_time, {})
            .combine(enemiesS, enemiesL.set)
            .combine(Bacon.constant(), updatePositions)
            .combine(mapS, mapL.set);
    };
});<commit_msg>simplify enemy updates<commit_after>/**
 * Created by ndyumin on 06.12.2015.
 */

define(['bacon', '../util', './enemy', 'pf'], function(Bacon, util, enemy, pf) {
    'use strict';

    function addEnemy(enemies, enemy) {
        enemies.push(enemy);
        return enemies;
    }

    const tick_time = 500;
    const spawn_time = 1500;
    const mapL = util.lens('map');

    return function (map) {
        const grid = new pf.Grid(map.map(l=> l.map(x=>+(x === 5))));
        const finder = new pf.AStarFinder();

        function nextPosition(x, y) {
            const path = finder.findPath(x, y, 38, 28, grid.clone());
            return path.length  > 1 ? path[1] : [x, y];
        }

        function updatePositions(state, enemies) {
            state.enemies =  enemies.map(function(e) {
                e.position = nextPosition(e.position[0], e.position[1]);
                return e;
            });
            return state;
        }

        const enemyS = Bacon.interval(spawn_time)
            .flatMapLatest(enemy);

        const mapS = Bacon.constant(map);
        const enemiesS = Bacon.constant([])
            .combine(enemyS, addEnemy);

        return Bacon.interval(tick_time, {})
            .combine(enemiesS, updatePositions)
            .combine(mapS, mapL.set);
    };
});<|endoftext|>


<commit_before>(function($) {
  var config = {
    environment: $('.environment').eq(0).data('id'),
    urls: {
      pivotal: {
        api: 'https://www.pivotaltracker.com/services/v5',
      }
    }
  };

  /**
   * removeDupesFromArray returns an array without dupes
   * @param  {Array} arr Any array
   * @return {Array}     Array without dups
   */
  function removeDupesFromArray(arr) {
    return arr.filter(function(elem, i) {
      return arr.indexOf(elem) == i;
    });
  }

  /**
   * isStringInArray return a boolean if item exists in an Array
   * @param  {String}  value  Some string
   * @param  {Array}   array  Array of strings
   * @return {Boolean}
   */
  function isStringInArray(value, array) {
    return array.indexOf(value) > -1;
  }

  /**
   * mapStatusLabelClass returns label class type (as of Twitter Bootstrap 3)
   * @param  {string} status Pivotal story status
   * @return {string}        Bootstrap class name
   */
  function mapStatusLabelClass(status) {
    switch(status) {
      case 'rejected':
        return 'danger';
      case 'accepted':
        return 'success';
      case 'delivered':
        return 'warning';
      case 'finished':
        return 'primary';
      case 'started':
        return 'info';
      default:
        return 'default';
    }
  }

  /**
   * getProjectDiffs return an Object, project name as the key and github diff URLs
   * as the value
   * @return {Object} {project_name: diff_url}
   */
  function getProjectDiffs() {
    var diffURLs = {};

    $('.project').each(function() {
      var $this = $(this);
      var project = $this.data('id');
      var url = $this.find('.GitHubDiffURL').attr('href');

      if (url) {
        diffURLs[project] = url;
      }
    });

    return diffURLs;
  }

  /**
   * getGithubCommits returns Github commits for a given repository
   * @param  {String}   github_token Github token
   * @param  {String}   repo         Github repository name
   * @param  {String}   commitHashe  Current and Latest commit hash
   * @param  {Function} callback
   */
  function getGithubCommits(github_token, repo, commitHashe, callback) {
    $.ajax({
      url: 'https://api.github.com/repos/gengo/'+ repo +'/compare/'+ commitHashe,
      type: 'GET',
      headers: {
        'Authorization': 'token '+ github_token
      },
      success: function(data) {
        callback(data.commits);
      },
      error: function(err) {
        console.error(err);
      }
    });
  }

  /**
   * getPivotalStoryIDs return an array of Pivotal story IDs from array of messages
   * @param  {Array} msgs Array of string messages
   * @return {Array}      Array of pivotal IDs
   */
  function getPivotalStoryIDs(msgs) {
    var reg = /\[#(\d+)\]/; // Pivotal story ID, ex) [#12345]
    var storyIDs = msgs
      .filter(function(str) {
        return reg.test(str);
      })
      .map(function(str) {
        return parseInt(str.match(reg)[1], 10);
      });

    return removeDupesFromArray(storyIDs);
  }

  /**
   * getPivotalStoryInfo return pivotal story data
   * @param  {string}   pt_token Pivotal token
   * @param  {number}   story_id Story id
   * @param  {Function} callback
   */
  function getPivotalStoryInfo(pt_token, story_id, callback) {
    $.ajax({
      url: config.urls.pivotal.api + '/stories/' + story_id,
      type: 'GET',
      headers: {
        'X-TrackerToken': pt_token
      },
      success: function(data) {
        getRepoDependencies(pt_token, data.project_id, story_id, function(list) {
          callback({
            id: story_id,
            url: data.url,
            status: data.current_state,
            dependencies: list
          });
        });
      }
    });
  }

  /**
   * getRepoDependencies return a list of dependencies for stroy in a project
   * @param  {String}   pt_token   Pivotal token
   * @param  {number}   project_id Project ID
   * @param  {number}   story_id   Story ID
   * @param  {Function} callback   Returns Pivotal story ID list
   */
  function getRepoDependencies(pt_token, project_id, story_id, callback) {
    $.ajax({
      url: config.urls.pivotal.api + '/projects/' + project_id + '/stories/' + story_id + '/comments',
      type: 'GET',
      headers: {
        'X-TrackerToken': pt_token
      },
      success: function(data) {
        var PULL_REQEST_REGEX = /Merge pull request/;
        var COMMIT_REPO_REGEX = /https:\/\/github.com\/gengo\/(.+)\/commit\//;
        var DEPLOY_REPO_REGEX = new RegExp('Deployed (.+) to '+ config.environment +': ');

        var list = data.filter(function(activity) {
          return activity.commit_type === 'github' || DEPLOY_REPO_REGEX.test(activity.text);
        }).reverse();

        var dependencies = [];
        var deployed = [];
        var notDeployed = [];

        for (var i = 0; i < list.length; i++) {
          var activity = list[i];

          // Deployed repos
          if (DEPLOY_REPO_REGEX.test(activity.text)) {
            var deployedRepo = activity.text.match(DEPLOY_REPO_REGEX)[1];

            if (!isStringInArray(deployedRepo, deployed)) {
              deployed.push(deployedRepo);
            }
          }

          // Merged repos
          if (PULL_REQEST_REGEX.test(activity.text)) {
            var mergedRepo = activity.text.match(COMMIT_REPO_REGEX)[1];

            if (!isStringInArray(mergedRepo, deployed) && !isStringInArray(mergedRepo, notDeployed)) {
              notDeployed.push(mergedRepo);
            }
            if (!isStringInArray(mergedRepo, dependencies)) {
              dependencies.push(mergedRepo);
            }
          }
          // Active repos
          else if (COMMIT_REPO_REGEX.test(activity.text)) {
            var activeRepo = activity.text.match(COMMIT_REPO_REGEX)[1];

            if (!isStringInArray(activeRepo, dependencies)) {
              dependencies.push(activeRepo);
            }
          }
        }

        callback({ 'all': dependencies, 'deployed': deployed, 'not_deployed': notDeployed });
      }
    });
  }

  /**
   * getPopoverHTML return a HTML string
   * @param  {Array} list Array of strings
   * @return {String}     HTML text string
   */
  function getPopoverHTML(dependencies) {
    var d = dependencies.deployed.map(function(repo) {
      return '
<s>'+ repo +'</s>
';
    }).join('');

    var n = dependencies.not_deployed.map(function(repo) {
      return '
'+ repo +'
';
    }).join('');

    var p = dependencies.all.map(function(repo) {
      if (!isStringInArray(repo, dependencies.deployed) && !isStringInArray(repo, dependencies.not_deployed)) {
        return '
'+ repo +'
';
      }
    }).join('');

    return p + n + d;
  }

  /**
   * onGetPivotalStoryInfoComplete is triggered when pitotal info loading completted,
   * and building up HTML to insert into the Story block.
   * @param  {String} project   GitHub project name
   * @param  {Array} storyList  Pivotal story info array
   */
  function onGetPivotalStoryInfoComplete(project, storyList) {
    var html = storyList.map(function(story) {
      return '
 \
                #'+ story.id +' \
                  \
                '+ story.status +' \
                  \
                '+ story.dependencies.all.length +' \

';
    });

    $('.project[data-id="'+ project +'"]')
      .find('.story')
        .html(html)
      .find('[data-toggle="popover"]')
        .popover({
          html: true,
          trigger: 'hover',
          placement: 'top'
        });
  }

  /**
   * showNoStoriesMessage
   * @param  {jQuery} $target jQuery button object
   */
  function showNoStoriesMessage($target) {
    $target.closest('.story').text('No stories found.');
  }

  $(document).ready(function() {
    // add button to story columns
    var button = '<button class="btn btn-default getStories">Get stories</button>Loading...';
    $('.project .story').each(function() {
      $(this).html(button);
    });

    // When reset button clicked add Get stories button
    $('.refresh').click(function() {
      $(this).closest('.project').find('.story').html(button);
    });

    $('.project').on('click', '.getStories', function(e) {
      e.preventDefault();

      var $this_button = $(e.currentTarget);
      var project = $this_button.parents('.project').data('id');
      var diffs = getProjectDiffs();

      $this_button.hide();

      if (project in diffs) {
        $this_button.siblings('.loading').show();

        var url = diffs[project];
        // hashes: currentCommit...latestCommit
        var commitHashe = url.substr(url.lastIndexOf('/') + 1);
        var repositoryName = url.match(/.*\/(.*)\/compare/)[1];

        getGithubCommits(GITHUB_TOKEN, repositoryName, commitHashe, function(commits) {
          // Array of comitt messages
          var messages = commits.map(function(obj) {
            return obj.commit.message;
          });
          // Array of pivotal story IDs
          var pivotal_ids = getPivotalStoryIDs(messages);
          if (pivotal_ids.length === 0) {
            showNoStoriesMessage($this_button);
            return;
          };

          var storyList = [];
          for (var i = 0, imax = pivotal_ids.length; i < imax; i++) {
            getPivotalStoryInfo(PIVOTAL_TOKEN, pivotal_ids[i], function(info) {
              storyList.push(info);

              if (storyList.length === imax) {
                $this_button.siblings('.loading').hide();
                onGetPivotalStoryInfoComplete(project, storyList);
              }
            });
          }
        });
      }
      else {
        showNoStoriesMessage($this_button);
      }
    });

  });
}(jQuery));
<commit_msg>fix typo on feedback<commit_after>(function($) {
  var config = {
    environment: $('.environment').eq(0).data('id'),
    urls: {
      pivotal: {
        api: 'https://www.pivotaltracker.com/services/v5',
      }
    }
  };

  /**
   * removeDupesFromArray returns an array without dupes
   * @param  {Array} arr Any array
   * @return {Array}     Array without dups
   */
  function removeDupesFromArray(arr) {
    return arr.filter(function(elem, i) {
      return arr.indexOf(elem) == i;
    });
  }

  /**
   * isStringInArray return a boolean if item exists in an Array
   * @param  {String}  value  Some string
   * @param  {Array}   array  Array of strings
   * @return {Boolean}
   */
  function isStringInArray(value, array) {
    return array.indexOf(value) > -1;
  }

  /**
   * mapStatusLabelClass returns label class type (as of Twitter Bootstrap 3)
   * @param  {string} status Pivotal story status
   * @return {string}        Bootstrap class name
   */
  function mapStatusLabelClass(status) {
    switch(status) {
      case 'rejected':
        return 'danger';
      case 'accepted':
        return 'success';
      case 'delivered':
        return 'warning';
      case 'finished':
        return 'primary';
      case 'started':
        return 'info';
      default:
        return 'default';
    }
  }

  /**
   * getProjectDiffs return an Object, project name as the key and github diff URLs
   * as the value
   * @return {Object} {project_name: diff_url}
   */
  function getProjectDiffs() {
    var diffURLs = {};

    $('.project').each(function() {
      var $this = $(this);
      var project = $this.data('id');
      var url = $this.find('.GitHubDiffURL').attr('href');

      if (url) {
        diffURLs[project] = url;
      }
    });

    return diffURLs;
  }

  /**
   * getGithubCommits returns Github commits for a given repository
   * @param  {String}   github_token Github token
   * @param  {String}   repo         Github repository name
   * @param  {String}   commitHashe  Current and Latest commit hash
   * @param  {Function} callback
   */
  function getGithubCommits(github_token, repo, commitHashe, callback) {
    $.ajax({
      url: 'https://api.github.com/repos/gengo/'+ repo +'/compare/'+ commitHashe,
      type: 'GET',
      headers: {
        'Authorization': 'token '+ github_token
      },
      success: function(data) {
        callback(data.commits);
      },
      error: function(err) {
        console.error(err);
      }
    });
  }

  /**
   * getPivotalStoryIDs return an array of Pivotal story IDs from array of messages
   * @param  {Array} msgs Array of string messages
   * @return {Array}      Array of pivotal IDs
   */
  function getPivotalStoryIDs(msgs) {
    var reg = /\[#(\d+)\]/; // Pivotal story ID, ex) [#12345]
    var storyIDs = msgs
      .filter(function(str) {
        return reg.test(str);
      })
      .map(function(str) {
        return parseInt(str.match(reg)[1], 10);
      });

    return removeDupesFromArray(storyIDs);
  }

  /**
   * getPivotalStoryInfo return pivotal story data
   * @param  {string}   pt_token Pivotal token
   * @param  {number}   story_id Story id
   * @param  {Function} callback
   */
  function getPivotalStoryInfo(pt_token, story_id, callback) {
    $.ajax({
      url: config.urls.pivotal.api + '/stories/' + story_id,
      type: 'GET',
      headers: {
        'X-TrackerToken': pt_token
      },
      success: function(data) {
        getRepoDependencies(pt_token, data.project_id, story_id, function(list) {
          callback({
            id: story_id,
            url: data.url,
            status: data.current_state,
            dependencies: list
          });
        });
      }
    });
  }

  /**
   * getRepoDependencies return a list of dependencies for stroy in a project
   * @param  {String}   pt_token   Pivotal token
   * @param  {number}   project_id Project ID
   * @param  {number}   story_id   Story ID
   * @param  {Function} callback   Returns Pivotal story ID list
   */
  function getRepoDependencies(pt_token, project_id, story_id, callback) {
    $.ajax({
      url: config.urls.pivotal.api + '/projects/' + project_id + '/stories/' + story_id + '/comments',
      type: 'GET',
      headers: {
        'X-TrackerToken': pt_token
      },
      success: function(data) {
        var PULL_REQUEST_REGEX = /Merge pull request/;
        var COMMIT_REPO_REGEX = /https:\/\/github.com\/gengo\/(.+)\/commit\//;
        var DEPLOY_REPO_REGEX = new RegExp('Deployed (.+) to '+ config.environment +': ');

        var list = data.filter(function(activity) {
          return activity.commit_type === 'github' || DEPLOY_REPO_REGEX.test(activity.text);
        }).reverse();

        var dependencies = [];
        var deployed = [];
        var notDeployed = [];

        for (var i = 0; i < list.length; i++) {
          var activity = list[i];

          // Deployed repos
          if (DEPLOY_REPO_REGEX.test(activity.text)) {
            var deployedRepo = activity.text.match(DEPLOY_REPO_REGEX)[1];

            if (!isStringInArray(deployedRepo, deployed)) {
              deployed.push(deployedRepo);
            }
          }

          // Merged repos
          if (PULL_REQUEST_REGEX.test(activity.text)) {
            var mergedRepo = activity.text.match(COMMIT_REPO_REGEX)[1];

            if (!isStringInArray(mergedRepo, deployed) && !isStringInArray(mergedRepo, notDeployed)) {
              notDeployed.push(mergedRepo);
            }
            if (!isStringInArray(mergedRepo, dependencies)) {
              dependencies.push(mergedRepo);
            }
          }
          // Active repos
          else if (COMMIT_REPO_REGEX.test(activity.text)) {
            var activeRepo = activity.text.match(COMMIT_REPO_REGEX)[1];

            if (!isStringInArray(activeRepo, dependencies)) {
              dependencies.push(activeRepo);
            }
          }
        }

        callback({ 'all': dependencies, 'deployed': deployed, 'not_deployed': notDeployed });
      }
    });
  }

  /**
   * getPopoverHTML return a HTML string
   * @param  {Array} list Array of strings
   * @return {String}     HTML text string
   */
  function getPopoverHTML(dependencies) {
    var d = dependencies.deployed.map(function(repo) {
      return '
<s>'+ repo +'</s>
';
    }).join('');

    var n = dependencies.not_deployed.map(function(repo) {
      return '
'+ repo +'
';
    }).join('');

    var p = dependencies.all.map(function(repo) {
      if (!isStringInArray(repo, dependencies.deployed) && !isStringInArray(repo, dependencies.not_deployed)) {
        return '
'+ repo +'
';
      }
    }).join('');

    return p + n + d;
  }

  /**
   * onGetPivotalStoryInfoComplete is triggered when pitotal info loading completted,
   * and building up HTML to insert into the Story block.
   * @param  {String} project   GitHub project name
   * @param  {Array} storyList  Pivotal story info array
   */
  function onGetPivotalStoryInfoComplete(project, storyList) {
    var html = storyList.map(function(story) {
      return '
 \
                #'+ story.id +' \
                  \
                '+ story.status +' \
                  \
                '+ story.dependencies.all.length +' \

';
    });

    $('.project[data-id="'+ project +'"]')
      .find('.story')
        .html(html)
      .find('[data-toggle="popover"]')
        .popover({
          html: true,
          trigger: 'hover',
          placement: 'top'
        });
  }

  /**
   * showNoStoriesMessage
   * @param  {jQuery} $target jQuery button object
   */
  function showNoStoriesMessage($target) {
    $target.closest('.story').text('No stories found.');
  }

  $(document).ready(function() {
    // add button to story columns
    var button = '<button class="btn btn-default getStories">Get stories</button>Loading...';
    $('.project .story').each(function() {
      $(this).html(button);
    });

    // When reset button clicked add Get stories button
    $('.refresh').click(function() {
      $(this).closest('.project').find('.story').html(button);
    });

    $('.project').on('click', '.getStories', function(e) {
      e.preventDefault();

      var $this_button = $(e.currentTarget);
      var project = $this_button.parents('.project').data('id');
      var diffs = getProjectDiffs();

      $this_button.hide();

      if (project in diffs) {
        $this_button.siblings('.loading').show();

        var url = diffs[project];
        // hashes: currentCommit...latestCommit
        var commitHashe = url.substr(url.lastIndexOf('/') + 1);
        var repositoryName = url.match(/.*\/(.*)\/compare/)[1];

        getGithubCommits(GITHUB_TOKEN, repositoryName, commitHashe, function(commits) {
          // Array of comitt messages
          var messages = commits.map(function(obj) {
            return obj.commit.message;
          });
          // Array of pivotal story IDs
          var pivotal_ids = getPivotalStoryIDs(messages);
          if (pivotal_ids.length === 0) {
            showNoStoriesMessage($this_button);
            return;
          };

          var storyList = [];
          for (var i = 0, imax = pivotal_ids.length; i < imax; i++) {
            getPivotalStoryInfo(PIVOTAL_TOKEN, pivotal_ids[i], function(info) {
              storyList.push(info);

              if (storyList.length === imax) {
                $this_button.siblings('.loading').hide();
                onGetPivotalStoryInfoComplete(project, storyList);
              }
            });
          }
        });
      }
      else {
        showNoStoriesMessage($this_button);
      }
    });

  });
}(jQuery));
<|endoftext|>


<commit_before>var map;
var polylines = [];

function initMap() {
    var $mapDiv = $('#map');
    map = new google.maps.Map($mapDiv, {
      center: {lat: 48.428611, lng: -123.365556},
      zoom: 14
    });

    google.maps.event.addListener(map, 'click', function(event) {
        var geocoder = new google.maps.Geocoder();
        console.log(event);
        latlngobj = event.latLng;
        var latlng = {lat: parseFloat(latlngobj.lat()), lng: parseFloat(latlngobj.lng())};
        geocoder.geocode({'location': latlng}, function(event, result){
            if(!!event){
                var address = event[0].formatted_address;
                $("#mapLoc").text(address);
            }
        });
    });
}

function mapRoute(routes) {
    for(var j = 0; j < routes.length; j++){
        latlngPoints = [];
        for(var i = 0; i < routes[j][2].length; i++) {
            latlngPoints.push({lat: routes[j][2][i][0], lng: routes[j][2][i][1]});
        }
        var strokeColor = '#00FF00';
        var strokeWeight = 3;
        if(j >= 1){
            strokeColor = '#0000FF';
            strokeWeight = 1;
        }

        var polyline = new google.maps.Polyline({
            path: latlngPoints,
            geodesic: true,
            strokeColor: strokeColor,
            strokeOpacity: 0.5,
            strokeWeight: strokeWeight
        });

        polyline.setMap(map);
        polylines.push(polyline);
    }

    $("#info-text").text("Best route found with " + routes[0][0] + " street lights");
    $("#info").show();
}

function getRoutes(starting_point, ending_point) {
    $("#error").hide();
    $("#info").hide();
    $("#spinner").show();
    $.ajax({
      url: '/route',
      type: 'POST',
      data: { start: starting_point, end: ending_point},
      success: function(data) {
          routes = JSON.parse(data);
          mapRoute(routes);
      },
      error: function() {
          $("#error").show();
      }
  }).always(function() {
        $("#mapLoc").text("");
        $("#spinner").hide();
    });
}

$("#bttn").click(function() {
    starting_point = $("#starting_point").val();
    ending_point = $("#ending_point").val();
    // Remove current path
    for(var i = 0; i < polylines.length; i++) {
        polylines[i].setMap(null);
    }

    routes = getRoutes(starting_point, ending_point);
});
<commit_msg>use elemnt instead of jquery<commit_after>var map;
var polylines = [];

function initMap() {
    var $mapDiv = $('#map');
    map = new google.maps.Map($mapDiv[0], {
      center: {lat: 48.428611, lng: -123.365556},
      zoom: 14
    });

    google.maps.event.addListener(map, 'click', function(event) {
        var geocoder = new google.maps.Geocoder();
        console.log(event);
        latlngobj = event.latLng;
        var latlng = {lat: parseFloat(latlngobj.lat()), lng: parseFloat(latlngobj.lng())};
        geocoder.geocode({'location': latlng}, function(event, result){
            if(!!event){
                var address = event[0].formatted_address;
                $("#mapLoc").text(address);
            }
        });
    });
}

function mapRoute(routes) {
    for(var j = 0; j < routes.length; j++){
        latlngPoints = [];
        for(var i = 0; i < routes[j][2].length; i++) {
            latlngPoints.push({lat: routes[j][2][i][0], lng: routes[j][2][i][1]});
        }
        var strokeColor = '#00FF00';
        var strokeWeight = 3;
        if(j >= 1){
            strokeColor = '#0000FF';
            strokeWeight = 1;
        }

        var polyline = new google.maps.Polyline({
            path: latlngPoints,
            geodesic: true,
            strokeColor: strokeColor,
            strokeOpacity: 0.5,
            strokeWeight: strokeWeight
        });

        polyline.setMap(map);
        polylines.push(polyline);
    }

    $("#info-text").text("Best route found with " + routes[0][0] + " street lights");
    $("#info").show();
}

function getRoutes(starting_point, ending_point) {
    $("#error").hide();
    $("#info").hide();
    $("#spinner").show();
    $.ajax({
      url: '/route',
      type: 'POST',
      data: { start: starting_point, end: ending_point},
      success: function(data) {
          routes = JSON.parse(data);
          mapRoute(routes);
      },
      error: function() {
          $("#error").show();
      }
  }).always(function() {
        $("#mapLoc").text("");
        $("#spinner").hide();
    });
}

$("#bttn").click(function() {
    starting_point = $("#starting_point").val();
    ending_point = $("#ending_point").val();
    // Remove current path
    for(var i = 0; i < polylines.length; i++) {
        polylines[i].setMap(null);
    }

    routes = getRoutes(starting_point, ending_point);
});
<|endoftext|>


<commit_before>/* knod 02/28/14
* texteditor.js
* Manages the changing inputs of the visualizer's editor
*
* ToDo:
* - FIGURE OUT WHY A TEXTAREA HAS AN EXTRA SPACE AT THE
* BOTTOM AND HOW TO GET RID OF IT.
* - Figure out why .num-row height doesn't change when
* pasting text.
* - Figure out why height of .text-row changes so that
* we don't have to cycle through all the .text-rows to
* get the right height.
* - Do we want the bottom line of the editor to remain
* blank for the evaluate button
*
* DONE:
* [DONE] - The first text input does not have row one
* as it's data value
*
*/

var textEditor = {
	/* Enclosure for text editor functions */

	// The colors for an activated row
	activeNumRow: "#dcdcdc",
	activeTextRow: "#f0f0f0",

	firstRow: function () {
		/* (None) -> None

		Creates the first text editor row. Why here?
		Because we want to have the .num-row and the
		.text-row paired.
		*/

		// Create the .num-row div
		var $newNumRow = $("

");
		// Create the .text-row input
		var $newTextRow = $("<textarea class='text-row'></textarea>")
		// Store the .num-row as the .text-row's data value
		.data("numRow", $newNumRow);

		// Append them as the first in their divs
		$("#text-areas").append($newTextRow);
		$("#num-gutter").append($newNumRow);

		// Make sure .num-row height matches .text-row height
		$newNumRow.outerHeight($newTextRow.outerHeight());

		// Do we want to focus the mouse here at the start?
		$newTextRow.focus();
	},

	keyFilter: function (key, $textRow) {
		/* (int) -> None

		Calls further function depending on
		value of key.
		*/

		// Always resize this .num-row to match this .text-row
		// This only matters if we make text areas work
		// HOW THE HELL DO WE GET RID OF THE LINE AT THE END
		$textRow.data("numRow").outerHeight($textRow.outerHeight());

		// Expands the input textarea size to show all text
		$textRow.autosize();

		// If the enter key was pressled
		if (key.keyCode == 13) {
			// Will probably need to stop propagation and
			// default

			// Add a line and updates the row numbers
			textEditor.addRow($textRow);
		}

		// If the delete key was pressed
		else if (key.keyCode == 8) {
			// Will probably need to stop propagation and
			// default

			// Do not remove the first row
			if ($(".text-row").length - 1) {
				// If there's no text in the row
				if (!$textRow.val()) {
					// Run a function in texteditor.js that removes a
					textEditor.removeRow($textRow);
					// line and updates the row numbers
				}
			}
		}

		// If the up arrow key was pressed
		// If the down arrow key was pressed

	},

	addRow: function ($textRow) {
		/* (element) -> None

		Adds divs below current input, one for the
		rows, one for the text, then numbers the
		rows appropriately. Moves curosr to the new
		input field
		*/

		// Create the .num-row div
		var $newNumRow = $("

");
		// Create the .text-row input
		var $newTextRow = $("<textarea class='text-row'></textarea>")
		// Store the .num-row as the .text-row's data value
		.data("numRow", $newNumRow);

		// Append new text input under this text input
		$textRow.after($newTextRow);
		// Append new .num-row using the current .text-row's data
		$textRow.data("numRow").after($newNumRow);

		// XMake newnumRow height same as newTextRow
		// !!! WHY IS SOMETHING STILL GETTING EXTRA PADDING?!!
		// Not padding, size of .text-row changes after creation
		// for some reason. So here we will resize everything on
		// new row creation so that it isn't done with every keydown
		$(".text-row").each(function () {
			$this = $(this);
			$this.data("numRow").outerHeight($this.outerHeight());
		});

		// Move the cursor to the new .text-row input
		$newTextRow.focus();

		// Re-number the rows
		textEditor.updateNums();
	},

	removeRow: function ($textRow) {
		/* (element) -> None

		Deletes this input and it's matching .num-row,
		then numbers the rows appropriately. Moves curosr
		to the previous input field.
		*/

		// Move the cursor to the previous input field
		$textRow.prev().focus();
		// Remove the .num-row in this .text-row's data value
		$textRow.data("numRow").remove();
		// Remove this .text-row
		$textRow.remove();
		// Update the row numbers
		textEditor.updateNums();
	},

	updateNums: function () {
		/* (None) -> None

		Cycles through all the .num-row rows and
		numbers them in order
		*/

		$(".num-row").each(
			function (thisIndex) {
				$(this).text(thisIndex + 1);
			});
	},

	activateRow: function ($textRow) {
		/* (element) -> None

		Change the colors of $textRow to the
		active colors.
		*/

		// Change $textRow's color
		$textRow.css("background", this.activeTextRow);
		// Change color of $textRow's numRow data value
		$textRow.data("numRow").css("background", this.activeNumRow);
	},

	deactivateRow: function ($textRow) {
		/* (element) -> None

		Remove the colors of $textRow.
		*/

		// Remove $textRow's color
		$textRow.css("background", "");
		// Remove color of $textRow's numRow data value
		$textRow.data("numRow").css("background", "");
	},
}<commit_msg>Note on row deletion<commit_after>/* knod 02/28/14
* texteditor.js
* Manages the changing inputs of the visualizer's editor
*
* ToDo:
* - FIGURE OUT WHY A TEXTAREA HAS AN EXTRA SPACE AT THE
* BOTTOM AND HOW TO GET RID OF IT.
* - Make textareas empty on creation so that you don't
* have to delete twice to delete an area you click into,
* though this should be better once we make the initial
* textarea just one line high. .val("") doesn't work.
* - Figure out why .num-row height doesn't change when
* pasting text.
* - Figure out why height of .text-row changes so that
* we don't have to cycle through all the .text-rows to
* get the right height.
* - Do we want the bottom line of the editor to remain
* blank for the evaluate button
*
* DONE:
* [DONE] - The first text input does not have row one
* as it's data value
*
*/

var textEditor = {
	/* Enclosure for text editor functions */

	// The colors for an activated row
	activeNumRow: "#dcdcdc",
	activeTextRow: "#f0f0f0",

	firstRow: function () {
		/* (None) -> None

		Creates the first text editor row. Why here?
		Because we want to have the .num-row and the
		.text-row paired.
		*/

		// Create the .num-row div
		var $newNumRow = $("

");
		// Create the .text-row input
		var $newTextRow = $("<textarea class='text-row'></textarea>")
		// Store the .num-row as the .text-row's data value
		.data("numRow", $newNumRow);

		// Append them as the first in their divs
		$("#text-areas").append($newTextRow);
		$("#num-gutter").append($newNumRow);

		// Make sure .num-row height matches .text-row height
		$newNumRow.outerHeight($newTextRow.outerHeight());

		// Do we want to focus the mouse here at the start?
		$newTextRow.focus();
	},

	keyFilter: function (key, $textRow) {
		/* (int) -> None

		Calls further function depending on
		value of key.
		*/

		// Always resize this .num-row to match this .text-row
		// This only matters if we make text areas work
		// HOW THE HELL DO WE GET RID OF THE LINE AT THE END
		$textRow.data("numRow").outerHeight($textRow.outerHeight());

		// Expands the input textarea size to show all text
		$textRow.autosize();

		// If the enter key was pressled
		if (key.keyCode == 13) {
			// Will probably need to stop propagation and
			// default

			// Add a line and updates the row numbers
			textEditor.addRow($textRow);
		}

		// If the delete key was pressed
		else if (key.keyCode == 8) {
			// Will probably need to stop propagation and
			// default

			// Do not remove the first row
			if ($(".text-row").length - 1) {
				// If there's no text in the row
				if (!$textRow.val()) {
					// Run a function in texteditor.js that removes a
					textEditor.removeRow($textRow);
					// line and updates the row numbers
				}
			}
		}

		// If the up arrow key was pressed
		// If the down arrow key was pressed

	},

	addRow: function ($textRow) {
		/* (element) -> None

		Adds divs below current input, one for the
		rows, one for the text, then numbers the
		rows appropriately. Moves curosr to the new
		input field
		*/

		// Create the .num-row div
		var $newNumRow = $("

");
		// Create the .text-row input
		var $newTextRow = $("<textarea class='text-row'></textarea>")
		// Store the .num-row as the .text-row's data value
		.data("numRow", $newNumRow);

		// Append new text input under this text input
		$textRow.after($newTextRow);
		// Append new .num-row using the current .text-row's data
		$textRow.data("numRow").after($newNumRow);

		// XMake newnumRow height same as newTextRow
		// !!! WHY IS SOMETHING STILL GETTING EXTRA PADDING?!!
		// Not padding, size of .text-row changes after creation
		// for some reason. So here we will resize everything on
		// new row creation so that it isn't done with every keydown
		$(".text-row").each(function () {
			$this = $(this);
			$this.data("numRow").outerHeight($this.outerHeight());
		});

		// Move the cursor to the new .text-row input
		$newTextRow.focus();

		// Re-number the rows
		textEditor.updateNums();
	},

	removeRow: function ($textRow) {
		/* (element) -> None

		Deletes this input and it's matching .num-row,
		then numbers the rows appropriately. Moves curosr
		to the previous input field.
		*/

		// Move the cursor to the previous input field
		$textRow.prev().focus();
		// Remove the .num-row in this .text-row's data value
		$textRow.data("numRow").remove();
		// Remove this .text-row
		$textRow.remove();
		// Update the row numbers
		textEditor.updateNums();
	},

	updateNums: function () {
		/* (None) -> None

		Cycles through all the .num-row rows and
		numbers them in order
		*/

		$(".num-row").each(
			function (thisIndex) {
				$(this).text(thisIndex + 1);
			});
	},

	activateRow: function ($textRow) {
		/* (element) -> None

		Change the colors of $textRow to the
		active colors.
		*/

		// Change $textRow's color
		$textRow.css("background", this.activeTextRow);
		// Change color of $textRow's numRow data value
		$textRow.data("numRow").css("background", this.activeNumRow);
	},

	deactivateRow: function ($textRow) {
		/* (element) -> None

		Remove the colors of $textRow.
		*/

		// Remove $textRow's color
		$textRow.css("background", "");
		// Remove color of $textRow's numRow data value
		$textRow.data("numRow").css("background", "");
	},
}<|endoftext|>


<commit_before>import path from 'path';
import fs from 'fs';
import core from 'babel-runtime/core-js';
const { lpad } = core.String.prototype;
import { promisify, promisifyAll, fromNode as promiseFromNode } from 'bluebird';
import nunjucks from 'nunjucks';
import permalinks from 'permalinks';
import MkMeta from 'marked-metadata';
import mkdirp from 'mkdirp';
import { ncp } from 'ncp';
import rimraf from 'rimraf';
import stylus from 'stylus';
import less from 'less';
import { rootdir, postspath, pagespath } from './config';
import { cliColor, getConfig, getFileName, getStructure } from './helpers';
import Theme from './theme';
promisifyAll(fs);
const mkdirpAsync = promisify(mkdirp);
const ncpAsync = promisify(ncp);
const rimrafAsync = promisify(rimraf);

const clc = cliColor();
const rMarkdownExt = /\.(?:md|markdown)$/;

const Helper = {

    sort(a, b) {
        return new Date(b.date) - new Date(a.date);
    },

    sortPosts(posts) {
        Object.values(posts).forEach((postsArray) => postsArray.sort(Helper.sort));
        return posts;
    },

    normalizeMetaData(data) {
        data.categories = (data.categories || '').split(',').map((category) => category.trim());

        if (data.date) {
            data.date = new Date(data.date);
        }

        // FIXME why is this here? The template should do the escaping, not `normalizeMetaData`
        data.title = data.title.replace(/\"/g, '');

        return data;
    }
};

export default class Harmonic {
    /*eslint-disable camelcase*/

    constructor(sitePath, { quiet = true } = {}) {
        this.sitePath = path.resolve(sitePath);
        this.quiet = !!quiet;

        const config = Object.assign({
            index_posts: 10
        }, getConfig(this.sitePath));
        this.theme = new Theme(config.theme, this.sitePath);

        if (fs.existsSync(path.join(this.theme.themePath, 'config.json'))) {
            Object.assign(config, JSON.parse(this.theme.getFileContents('config.json')));
        }

        this.config = config;
        this.nunjucksEnv = nunjucks.configure(this.theme.themePath, { watch: false });
    }

    async clean() {
        console.log(clc.warn('Cleaning up...'));
        await rimrafAsync(path.join(this.sitePath, 'public'), { maxBusyTries: 20 });
    }

    async compileCSS() {
        const currentCSSCompiler = this.config.preprocessor;
        if (!currentCSSCompiler) {
            return;
        }

        const compiler = {

            less: async () => {
                const lessIndexPath = path.join(this.theme.themePath, 'resources/_less/index.less');
                const cssDir = path.join(this.sitePath, 'public/css');

                const lessInput = await fs.readFileAsync(lessIndexPath, { encoding: 'utf8' });
                const { css } = await less.render(lessInput, { filename: lessIndexPath });

                await mkdirpAsync(cssDir);
                await fs.writeFileAsync(path.join(cssDir, 'main.css'), css);

                console.log(clc.info('Successfully generated CSS with LESS preprocessor'));
            },

            stylus: async () => {
                const stylDir = path.join(this.theme.themePath, 'resources/_stylus');
                const stylIndexPath = path.join(stylDir, 'index.styl');
                const cssDir = path.join(this.sitePath, 'public/css');

                const stylInput = await fs.readFileAsync(stylIndexPath, { encoding: 'utf8' });
                const css = await promiseFromNode((cb) => {
                    stylus(stylInput)
                        .set('filename', stylIndexPath)
                        .set('paths', [path.join(stylDir, 'engine'), path.join(stylDir, 'partials')])
                        .render(cb);
                });

                await mkdirpAsync(cssDir);
                await fs.writeFileAsync(path.join(cssDir, 'main.css'), css);

                console.log(clc.info('Successfully generated CSS with Stylus preprocessor'));
            }
        };

        if (!compiler.hasOwnProperty(currentCSSCompiler)) {
            throw new Error(`Unsupported CSS preprocessor: ${currentCSSCompiler}`);
        }

        await compiler[currentCSSCompiler]();
    }

    async compileJS(postsMetadata, pagesMetadata) {
        const harmonicClient = (await fs.readFileAsync(`${rootdir}/bin/client/harmonic-client.js`, { encoding: 'utf8' }))
            .replace(/__HARMONIC\.POSTS__/g, JSON.stringify(postsMetadata))
            .replace(/__HARMONIC\.PAGES__/g, JSON.stringify(pagesMetadata))
            .replace(/__HARMONIC\.CONFIG__/g, JSON.stringify(this.config));

        await fs.writeFileAsync(path.join(this.sitePath, 'public/harmonic.js'), harmonicClient);
    }

    async generateTagsPages(postsMetadata) {
        const tagTemplateNJ = nunjucks.compile(this.theme.getFileContents('index.html'), this.nunjucksEnv);
        const config = this.config;

        await* [].concat(...Object.entries(postsMetadata).map(([lang, langPosts]) => {
            const postsByTag = {};
            langPosts.forEach((post) => {
                post.categories.forEach((category) => {
                    // TODO replace with kebabCase?
                    const tag = category.toLowerCase().trim().split(' ').join('-');
                    postsByTag[tag] = postsByTag[tag] || [];
                    postsByTag[tag].push(post);
                });
            });

            return Object.entries(postsByTag).map(async ([tag, tagPosts]) => {
                const tagContent = tagTemplateNJ.render({
                    posts: tagPosts,
                    config,
                    category: tag
                });

                const tagPath = path.join(this.sitePath, 'public/categories', ...(config.i18n.default === lang ? [] : [lang]), tag);
                await mkdirpAsync(tagPath);
                await fs.writeFileAsync(path.join(tagPath, 'index.html'), tagContent);
                console.log(clc.info(`Successfully generated tag[${tag}] archive html file`));
            });
        }));
    }

    async generateIndex(postsMetadata, pagesMetadata) {
        const indexTemplateNJ = nunjucks.compile(this.theme.getFileContents('index.html'), this.nunjucksEnv);
        const config = this.config;

        await* Object.entries(postsMetadata).map(async ([lang, langPosts]) => {
            const posts = langPosts.slice(0, config.index_posts);
            const pages = pagesMetadata[lang] || [];

            const indexContent = indexTemplateNJ.render({
                posts,
                pages,
                config
            });

            const indexPath = path.join(this.sitePath, 'public', ...(config.i18n.default === lang ? [] : [lang]));
            await mkdirpAsync(indexPath);
            await fs.writeFileAsync(path.join(indexPath, 'index.html'), indexContent);
            console.log(clc.info(`${lang}/index file successfully created`));
        });
    }

    async copyThemeResources() {
        await ncpAsync(path.join(this.theme.themePath, 'resources'), path.join(this.sitePath, 'public'), { stopOnErr: true });
        console.log(clc.info('Theme resources copied'));
    }

    async copyUserResources() {
        const userResourcesPath = path.join(this.sitePath, 'resources');
        await mkdirpAsync(userResourcesPath);
        await ncpAsync(userResourcesPath, path.join(this.sitePath, 'public'), { stopOnErr: true });
        console.log(clc.info(`User resources copied`));
    }

    async generatePosts(files) {
        const langs = Object.keys(files);
        const config = this.config;
        const posts = {};
        const currentDate = new Date();
        const nunjucksEnv = this.nunjucksEnv;
        const postTemplates = {};
        const tokens = config.header_tokens || ['<!--', '-->'];

        await* [].concat(...langs.map((lang) => files[lang].map(async (file) => {
            const md = new MkMeta(path.join(this.sitePath, postspath, lang, file));
            md.defineTokens(tokens[0], tokens[1]);

            const metadata = Helper.normalizeMetaData(md.metadata());
            metadata.content = md.markdown({
                crop: '<!--more-->'
            });

            const layoutName = metadata.layout ? metadata.layout + '.html' : 'post.html';
            if(!postTemplates[layoutName]){
                let templateFile = this.theme.getFileContents(layoutName);
                postTemplates[layoutName] = nunjucks.compile(templateFile, nunjucksEnv);
            }

            const filename = getFileName(file);

            const postPath = permalinks({
                replacements: [{
                    pattern: ':year',
                    replacement: metadata.date.getFullYear()
                },
                {
                    pattern: ':month',
                    replacement: (metadata.date.getMonth() + 1)::lpad(2, '0')
                },
                {
                    pattern: ':title',
                    replacement: filename
                },
                {
                    pattern: ':language',
                    replacement: lang
                }],
                structure: getStructure(config.i18n.default, lang, config.posts_permalink)
            });

            metadata.file = postspath + file;
            metadata.filename = filename;
            metadata.link = postPath;
            metadata.lang = lang;
            metadata.default_lang = config.i18n.default !== lang; // FIXME https://github.com/JSRocksHQ/harmonic/issues/169

            const postHTMLFile = postTemplates[layoutName]
                .render({
                    post: {
                        content: md.markdown(),
                        metadata: metadata
                    },
                    config: config
                })
                .replace(/<!--[\s\S]*?-->/g, '');

            if (metadata.published && metadata.published === 'false') {
                return;
            }

            if (metadata.date && metadata.date > currentDate) {
                console.log(clc.info(`Skipping future post ${metadata.filename}`));
                return;
            }

            const postDirPath = path.join(this.sitePath, 'public', postPath);
            const postFilePath = path.join(postDirPath, 'index.html');
            await mkdirpAsync(postDirPath);

            // write post html file
            await fs.writeFileAsync(postFilePath, postHTMLFile);
            console.log(clc.info(`Successfully generated post ${postPath}`));

            posts[lang] = posts[lang] || [];
            posts[lang].push(metadata);
        })));
        return Helper.sortPosts(posts);
    }

    async generatePages(files) {
        const langs = Object.keys(files);
        const config = this.config;
        const pages = {};
        const nunjucksEnv = this.nunjucksEnv;
        const pageTemplates = {};
        const tokens = config.header_tokens || ['<!--', '-->'];

        await* [].concat(...langs.map((lang) => files[lang].map(async (file) => {
            const md = new MkMeta(path.join(this.sitePath, pagespath, lang, file));
            md.defineTokens(tokens[0], tokens[1]);

            const metadata = Helper.normalizeMetaData(md.metadata());

            const layoutName = metadata.layout ? metadata.layout + '.html' : 'page.html';
            if(!pageTemplates[layoutName]){
                let templateFile = this.theme.getFileContents(layoutName);
                pageTemplates[layoutName] = nunjucks.compile(templateFile, nunjucksEnv);
            }

            const filename = getFileName(file);

            const pagePath = permalinks({
                replacements: [{
                    pattern: ':title',
                    replacement: filename
                },
                {
                    pattern: ':language',
                    replacement: lang
                }],
                structure: getStructure(config.i18n.default, lang, config.pages_permalink)
            });

            const pageHTMLFile = pageTemplates[layoutName]
                .render({
                    page: {
                        content: md.markdown(),
                        metadata: metadata
                    },
                    config: config
                })
                .replace(/<!--[\s\S]*?-->/g, '');

            metadata.content = pageHTMLFile;
            metadata.file = postspath + file;
            metadata.filename = filename;
            metadata.link = pagePath;
            metadata.lang = lang;
            metadata.default_lang = config.i18n.default !== lang; // FIXME https://github.com/JSRocksHQ/harmonic/issues/169

            const pageDirPath = path.join(this.sitePath, 'public', pagePath);
            const pageFilePath = path.join(pageDirPath, 'index.html');
            await mkdirpAsync(pageDirPath);

            // write page html file
            await fs.writeFileAsync(pageFilePath, pageHTMLFile);
            console.log(clc.info(`Successfully generated page ${pagePath}`));

            pages[lang] = pages[lang] || [];
            pages[lang].push(metadata);
        })));
        return pages;
    }

    async getPostFiles() {
        const files = {};

        await* this.config.i18n.languages.map(async (lang) => {
            files[lang] = (await fs.readdirAsync(path.join(this.sitePath, postspath, lang)))
                .filter((p) => rMarkdownExt.test(p));
        });

        return files;
    }

    async getPageFiles() {
        const files = {};

        await* this.config.i18n.languages.map(async (lang) => {
            const langPath = path.join(this.sitePath, pagespath, lang);
            await mkdirpAsync(langPath);
            files[lang] = (await fs.readdirAsync(langPath)).filter((p) => rMarkdownExt.test(p));
        });

        return files;
    }

    async generateRSS(postsMetadata, pagesMetadata) {
        const rssTemplate = await fs.readFileAsync(path.join(__dirname, 'resources/rss.xml'), { encoding: 'utf8' });
        const rssTemplateNJ = nunjucks.compile(rssTemplate, this.nunjucksEnv);
        const config = this.config;
        const rssAuthor = config.author_email ? `${config.author_email} ( ${config.author} )` : config.author;

        await* Object.entries(postsMetadata).map(async ([lang, langPosts]) => {
            const posts = langPosts.slice(0, config.index_posts);
            const isDefaultLang = config.i18n.default === lang;
            const rssPath = path.join(this.sitePath, 'public', ...(isDefaultLang ? [] : [lang]));
            const rssLink = `${config.domain}${isDefaultLang ? '' : '/' + lang}/rss.xml`;

            const rssContent = rssTemplateNJ.render({
                rss: {
                    date: new Date().toUTCString(),
                    link: rssLink,
                    author: rssAuthor,
                    lang: lang
                },
                posts,
                config,
                pages: pagesMetadata
            });

            await mkdirpAsync(rssPath);
            await fs.writeFileAsync(`${rssPath}/rss.xml`, rssContent);
            console.log(clc.info(`${lang}/rss.xml file successfully created`));
        });
    }
}
<commit_msg>crated metadataDefaults<commit_after>import path from 'path';
import fs from 'fs';
import core from 'babel-runtime/core-js';
const { lpad } = core.String.prototype;
import { promisify, promisifyAll, fromNode as promiseFromNode } from 'bluebird';
import nunjucks from 'nunjucks';
import permalinks from 'permalinks';
import MkMeta from 'marked-metadata';
import mkdirp from 'mkdirp';
import { ncp } from 'ncp';
import rimraf from 'rimraf';
import stylus from 'stylus';
import less from 'less';
import { rootdir, postspath, pagespath } from './config';
import { cliColor, getConfig, getFileName, getStructure } from './helpers';
import Theme from './theme';
promisifyAll(fs);
const mkdirpAsync = promisify(mkdirp);
const ncpAsync = promisify(ncp);
const rimrafAsync = promisify(rimraf);

const clc = cliColor();
const rMarkdownExt = /\.(?:md|markdown)$/;

const Helper = {

    sort(a, b) {
        return new Date(b.date) - new Date(a.date);
    },

    sortPosts(posts) {
        Object.values(posts).forEach((postsArray) => postsArray.sort(Helper.sort));
        return posts;
    },

    normalizeMetaData(data, defaults) {
        data.categories = (data.categories || '').split(',').map((category) => category.trim());

        if (data.date) {
            data.date = new Date(data.date);
        }

        // FIXME why is this here? The template should do the escaping, not `normalizeMetaData`
        data.title = data.title.replace(/\"/g, '');
        data.layout = data.layout ? data.layout + '.html' : defaults.layout;

        return data;
    }
};

export default class Harmonic {
    /*eslint-disable camelcase*/

    constructor(sitePath, { quiet = true } = {}) {
        this.sitePath = path.resolve(sitePath);
        this.quiet = !!quiet;

        const config = Object.assign({
            index_posts: 10
        }, getConfig(this.sitePath));
        this.theme = new Theme(config.theme, this.sitePath);

        if (fs.existsSync(path.join(this.theme.themePath, 'config.json'))) {
            Object.assign(config, JSON.parse(this.theme.getFileContents('config.json')));
        }

        this.config = config;
        this.nunjucksEnv = nunjucks.configure(this.theme.themePath, { watch: false });
    }

    async clean() {
        console.log(clc.warn('Cleaning up...'));
        await rimrafAsync(path.join(this.sitePath, 'public'), { maxBusyTries: 20 });
    }

    async compileCSS() {
        const currentCSSCompiler = this.config.preprocessor;
        if (!currentCSSCompiler) {
            return;
        }

        const compiler = {

            less: async () => {
                const lessIndexPath = path.join(this.theme.themePath, 'resources/_less/index.less');
                const cssDir = path.join(this.sitePath, 'public/css');

                const lessInput = await fs.readFileAsync(lessIndexPath, { encoding: 'utf8' });
                const { css } = await less.render(lessInput, { filename: lessIndexPath });

                await mkdirpAsync(cssDir);
                await fs.writeFileAsync(path.join(cssDir, 'main.css'), css);

                console.log(clc.info('Successfully generated CSS with LESS preprocessor'));
            },

            stylus: async () => {
                const stylDir = path.join(this.theme.themePath, 'resources/_stylus');
                const stylIndexPath = path.join(stylDir, 'index.styl');
                const cssDir = path.join(this.sitePath, 'public/css');

                const stylInput = await fs.readFileAsync(stylIndexPath, { encoding: 'utf8' });
                const css = await promiseFromNode((cb) => {
                    stylus(stylInput)
                        .set('filename', stylIndexPath)
                        .set('paths', [path.join(stylDir, 'engine'), path.join(stylDir, 'partials')])
                        .render(cb);
                });

                await mkdirpAsync(cssDir);
                await fs.writeFileAsync(path.join(cssDir, 'main.css'), css);

                console.log(clc.info('Successfully generated CSS with Stylus preprocessor'));
            }
        };

        if (!compiler.hasOwnProperty(currentCSSCompiler)) {
            throw new Error(`Unsupported CSS preprocessor: ${currentCSSCompiler}`);
        }

        await compiler[currentCSSCompiler]();
    }

    async compileJS(postsMetadata, pagesMetadata) {
        const harmonicClient = (await fs.readFileAsync(`${rootdir}/bin/client/harmonic-client.js`, { encoding: 'utf8' }))
            .replace(/__HARMONIC\.POSTS__/g, JSON.stringify(postsMetadata))
            .replace(/__HARMONIC\.PAGES__/g, JSON.stringify(pagesMetadata))
            .replace(/__HARMONIC\.CONFIG__/g, JSON.stringify(this.config));

        await fs.writeFileAsync(path.join(this.sitePath, 'public/harmonic.js'), harmonicClient);
    }

    async generateTagsPages(postsMetadata) {
        const tagTemplateNJ = nunjucks.compile(this.theme.getFileContents('index.html'), this.nunjucksEnv);
        const config = this.config;

        await* [].concat(...Object.entries(postsMetadata).map(([lang, langPosts]) => {
            const postsByTag = {};
            langPosts.forEach((post) => {
                post.categories.forEach((category) => {
                    // TODO replace with kebabCase?
                    const tag = category.toLowerCase().trim().split(' ').join('-');
                    postsByTag[tag] = postsByTag[tag] || [];
                    postsByTag[tag].push(post);
                });
            });

            return Object.entries(postsByTag).map(async ([tag, tagPosts]) => {
                const tagContent = tagTemplateNJ.render({
                    posts: tagPosts,
                    config,
                    category: tag
                });

                const tagPath = path.join(this.sitePath, 'public/categories', ...(config.i18n.default === lang ? [] : [lang]), tag);
                await mkdirpAsync(tagPath);
                await fs.writeFileAsync(path.join(tagPath, 'index.html'), tagContent);
                console.log(clc.info(`Successfully generated tag[${tag}] archive html file`));
            });
        }));
    }

    async generateIndex(postsMetadata, pagesMetadata) {
        const indexTemplateNJ = nunjucks.compile(this.theme.getFileContents('index.html'), this.nunjucksEnv);
        const config = this.config;

        await* Object.entries(postsMetadata).map(async ([lang, langPosts]) => {
            const posts = langPosts.slice(0, config.index_posts);
            const pages = pagesMetadata[lang] || [];

            const indexContent = indexTemplateNJ.render({
                posts,
                pages,
                config
            });

            const indexPath = path.join(this.sitePath, 'public', ...(config.i18n.default === lang ? [] : [lang]));
            await mkdirpAsync(indexPath);
            await fs.writeFileAsync(path.join(indexPath, 'index.html'), indexContent);
            console.log(clc.info(`${lang}/index file successfully created`));
        });
    }

    async copyThemeResources() {
        await ncpAsync(path.join(this.theme.themePath, 'resources'), path.join(this.sitePath, 'public'), { stopOnErr: true });
        console.log(clc.info('Theme resources copied'));
    }

    async copyUserResources() {
        const userResourcesPath = path.join(this.sitePath, 'resources');
        await mkdirpAsync(userResourcesPath);
        await ncpAsync(userResourcesPath, path.join(this.sitePath, 'public'), { stopOnErr: true });
        console.log(clc.info(`User resources copied`));
    }

    async generatePosts(files) {
        const langs = Object.keys(files);
        const config = this.config;
        const posts = {};
        const currentDate = new Date();
        const nunjucksEnv = this.nunjucksEnv;
        const postTemplates = {};
        const tokens = config.header_tokens || ['<!--', '-->'];
        const metadataDefaults = {
            layout: 'post.html'
        };

        await* [].concat(...langs.map((lang) => files[lang].map(async (file) => {
            const md = new MkMeta(path.join(this.sitePath, postspath, lang, file));
            md.defineTokens(tokens[0], tokens[1]);

            const metadata = Helper.normalizeMetaData(md.metadata(), metadataDefaults);
            metadata.content = md.markdown({
                crop: '<!--more-->'
            });

            if(!postTemplates[metadata.layout]){
                let templateFile = this.theme.getFileContents(metadata.layout);
                postTemplates[metadata.layout] = nunjucks.compile(templateFile, nunjucksEnv);
            }

            const filename = getFileName(file);

            const postPath = permalinks({
                replacements: [{
                    pattern: ':year',
                    replacement: metadata.date.getFullYear()
                },
                {
                    pattern: ':month',
                    replacement: (metadata.date.getMonth() + 1)::lpad(2, '0')
                },
                {
                    pattern: ':title',
                    replacement: filename
                },
                {
                    pattern: ':language',
                    replacement: lang
                }],
                structure: getStructure(config.i18n.default, lang, config.posts_permalink)
            });

            metadata.file = postspath + file;
            metadata.filename = filename;
            metadata.link = postPath;
            metadata.lang = lang;
            metadata.default_lang = config.i18n.default !== lang; // FIXME https://github.com/JSRocksHQ/harmonic/issues/169

            const postHTMLFile = postTemplates[metadata.layout]
                .render({
                    post: {
                        content: md.markdown(),
                        metadata: metadata
                    },
                    config: config
                })
                .replace(/<!--[\s\S]*?-->/g, '');

            if (metadata.published && metadata.published === 'false') {
                return;
            }

            if (metadata.date && metadata.date > currentDate) {
                console.log(clc.info(`Skipping future post ${metadata.filename}`));
                return;
            }

            const postDirPath = path.join(this.sitePath, 'public', postPath);
            const postFilePath = path.join(postDirPath, 'index.html');
            await mkdirpAsync(postDirPath);

            // write post html file
            await fs.writeFileAsync(postFilePath, postHTMLFile);
            console.log(clc.info(`Successfully generated post ${postPath}`));

            posts[lang] = posts[lang] || [];
            posts[lang].push(metadata);
        })));
        return Helper.sortPosts(posts);
    }

    async generatePages(files) {
        const langs = Object.keys(files);
        const config = this.config;
        const pages = {};
        const nunjucksEnv = this.nunjucksEnv;
        const pageTemplates = {};
        const tokens = config.header_tokens || ['<!--', '-->'];
        const metadataDefaults = {
            layout: 'page.html'
        };

        await* [].concat(...langs.map((lang) => files[lang].map(async (file) => {
            const md = new MkMeta(path.join(this.sitePath, pagespath, lang, file));
            md.defineTokens(tokens[0], tokens[1]);

            const metadata = Helper.normalizeMetaData(md.metadata(), metadataDefaults);
            if(!pageTemplates[metadata.layout]){
                let templateFile = this.theme.getFileContents(metadata.layout);
                pageTemplates[metadata.layout] = nunjucks.compile(templateFile, nunjucksEnv);
            }

            const filename = getFileName(file);

            const pagePath = permalinks({
                replacements: [{
                    pattern: ':title',
                    replacement: filename
                },
                {
                    pattern: ':language',
                    replacement: lang
                }],
                structure: getStructure(config.i18n.default, lang, config.pages_permalink)
            });

            const pageHTMLFile = pageTemplates[metadata.layout]
                .render({
                    page: {
                        content: md.markdown(),
                        metadata: metadata
                    },
                    config: config
                })
                .replace(/<!--[\s\S]*?-->/g, '');

            metadata.content = pageHTMLFile;
            metadata.file = postspath + file;
            metadata.filename = filename;
            metadata.link = pagePath;
            metadata.lang = lang;
            metadata.default_lang = config.i18n.default !== lang; // FIXME https://github.com/JSRocksHQ/harmonic/issues/169

            const pageDirPath = path.join(this.sitePath, 'public', pagePath);
            const pageFilePath = path.join(pageDirPath, 'index.html');
            await mkdirpAsync(pageDirPath);

            // write page html file
            await fs.writeFileAsync(pageFilePath, pageHTMLFile);
            console.log(clc.info(`Successfully generated page ${pagePath}`));

            pages[lang] = pages[lang] || [];
            pages[lang].push(metadata);
        })));
        return pages;
    }

    async getPostFiles() {
        const files = {};

        await* this.config.i18n.languages.map(async (lang) => {
            files[lang] = (await fs.readdirAsync(path.join(this.sitePath, postspath, lang)))
                .filter((p) => rMarkdownExt.test(p));
        });

        return files;
    }

    async getPageFiles() {
        const files = {};

        await* this.config.i18n.languages.map(async (lang) => {
            const langPath = path.join(this.sitePath, pagespath, lang);
            await mkdirpAsync(langPath);
            files[lang] = (await fs.readdirAsync(langPath)).filter((p) => rMarkdownExt.test(p));
        });

        return files;
    }

    async generateRSS(postsMetadata, pagesMetadata) {
        const rssTemplate = await fs.readFileAsync(path.join(__dirname, 'resources/rss.xml'), { encoding: 'utf8' });
        const rssTemplateNJ = nunjucks.compile(rssTemplate, this.nunjucksEnv);
        const config = this.config;
        const rssAuthor = config.author_email ? `${config.author_email} ( ${config.author} )` : config.author;

        await* Object.entries(postsMetadata).map(async ([lang, langPosts]) => {
            const posts = langPosts.slice(0, config.index_posts);
            const isDefaultLang = config.i18n.default === lang;
            const rssPath = path.join(this.sitePath, 'public', ...(isDefaultLang ? [] : [lang]));
            const rssLink = `${config.domain}${isDefaultLang ? '' : '/' + lang}/rss.xml`;

            const rssContent = rssTemplateNJ.render({
                rss: {
                    date: new Date().toUTCString(),
                    link: rssLink,
                    author: rssAuthor,
                    lang: lang
                },
                posts,
                config,
                pages: pagesMetadata
            });

            await mkdirpAsync(rssPath);
            await fs.writeFileAsync(`${rssPath}/rss.xml`, rssContent);
            console.log(clc.info(`${lang}/rss.xml file successfully created`));
        });
    }
}
<|endoftext|>


<commit_before>"use strict";

var utils = require('../utils/utils.js'),
	calc = require('../utils/calc.js'),
	isPriority = function (key) {
    	var prioritys = ['current', 'from', 'to', 'start'];
    	return (prioritys.indexOf(key) > -1);
	},
	parse = function (value, data, current) {
	    return (utils.isFunc(value)) ? value(data, current) : value;
	},
	Value = function (value, action) {
		this.update(value, action, true);
	},
	defaults = {
	    // Actual value
    	current: 0,
    	start: 0,

    	// Current range for value
    	from: 0,
    	to: 1,

    	// Maximum range for value (TODO - has no current effect)
    	min: null,
    	max: null,

    	// Speed for .move(), in xps
    	speed: 0,
    	friction: 0,
    	thrust: 0,

    	// Options
    	duration: 400,
    	delay: 0,
    	ease: 'ease-in-out',
    	link: null, // use the progress of this value
    	math: null,
    	steps: 0,

    	// Amp for inside and outside range (ie value * amp)
    	amp: 0,
    	escapeAmp: 0
	};

/*
	Update the value properties

	@param [object || number]: User-defined value
	@param [object]: Action this value belongs to
	@param [boolean] (optional): Is this a new value construct
*/
Value.prototype.update = function (value, action, isNewValue) {
	var data = (action) ? action.data : {};

	// If value is just a number
	if (utils.isNum(value) || utils.isFunc(value)) {
	    this.from = (isNewValue) ? 0 : this.from;
	    this.current = (isNewValue) ? this.from : this.current;
		this.to = parse(value, data, this.current);

	// Or if it is an object
	} else {

	    // Deal with our priorities
	    // TODO: See if this badass if statement (emphasis on ass) can be refactored
	    if (isNewValue && value.hasOwnProperty('speed')) {
		    value.current = parse(value.start, data);
	    }

	    // If user has defined a new current, but not a from
	    if (value.hasOwnProperty('current') && !value.hasOwnProperty('from')) {
    	    this.current = parse(value.current, data);
    	    this.from = this.current;

	    // Or if user has defined a from, but not a current
	    } else if (!value.hasOwnProperty('current') && value.hasOwnProperty('from')) {
    	    this.from = isNewValue ? parse(value.from, data) : this.current;
    	    this.current = isNewValue ? this.from : this.current;

        // Or they've defined both
	    } else if (value.hasOwnProperty('current') && value.hasOwnProperty('from')) {
    	    this.current = parse(value.current, data);
    	    this.from = isNewValue ? parse(value.from, data) : this.current;

        // Or they've defined neither
	    } else {
    	    this.current = isNewValue ? defaults.current : this.current;
    	    this.from = isNewValue ? defaults.from : this.current;
	    }

		this.to = parse(value.to, data, this.current);
	}

    // Loop through permitted values
    for (var key in defaults) {
	    if (defaults.hasOwnProperty(key) && !isPriority(key)) {

		    // If user has submitted a property
		    if (utils.isObj(value) && value.hasOwnProperty(key)) {
                this[key] = parse(value[key], data, this.current);

            // Or there's a default set on the action
		    } else if (utils.isObj(action) && action.hasOwnProperty(key)) {
                this[key] = parse(action[key], data, this.current);

            // Otherwise, if this is our first time (honest judge), set as the default.
		    } else if (isNewValue) {
    		    this[key] = defaults[key];
		    }

	    }
    }
};

module.exports = Value;<commit_msg>fixing start value<commit_after>"use strict";

var utils = require('../utils/utils.js'),
	calc = require('../utils/calc.js'),
	isPriority = function (key) {
    	var prioritys = ['current', 'from', 'to', 'start'];
    	return (prioritys.indexOf(key) > -1);
	},
	parse = function (value, data, current) {
	    return (utils.isFunc(value)) ? value(data, current) : value;
	},
	Value = function (value, action) {
		this.update(value, action, true);
	},
	defaults = {
	    // Actual value
    	current: 0,
    	start: 0,

    	// Current range for value
    	from: 0,
    	to: 1,

    	// Maximum range for value (TODO - has no current effect)
    	min: null,
    	max: null,

    	// Speed for .move(), in xps
    	speed: 0,
    	friction: 0,
    	thrust: 0,

    	// Options
    	duration: 400,
    	delay: 0,
    	ease: 'ease-in-out',
    	link: null, // use the progress of this value
    	math: null,
    	steps: 0,

    	// Amp for inside and outside range (ie value * amp)
    	amp: 0,
    	escapeAmp: 0
	};

/*
	Update the value properties

	@param [object || number]: User-defined value
	@param [object]: Action this value belongs to
	@param [boolean] (optional): Is this a new value construct
*/
Value.prototype.update = function (value, action, isNewValue) {
	var data = (action) ? action.data : {};

	// If value is just a number
	if (utils.isNum(value) || utils.isFunc(value)) {
	    this.from = (isNewValue) ? 0 : this.from;
	    this.current = (isNewValue) ? this.from : this.current;
		this.to = parse(value, data, this.current);

	// Or if it is an object
	} else {

	    // Deal with our priorities
	    // TODO: See if this badass if statement (emphasis on ass) can be refactored
	    if (isNewValue && value.hasOwnProperty('start')) {
		    value.current = parse(value.start, data);
	    }

	    // If user has defined a new current, but not a from
	    if (value.hasOwnProperty('current') && !value.hasOwnProperty('from')) {
    	    this.current = parse(value.current, data);
    	    this.from = this.current;

	    // Or if user has defined a from, but not a current
	    } else if (!value.hasOwnProperty('current') && value.hasOwnProperty('from')) {
    	    this.from = isNewValue ? parse(value.from, data) : this.current;
    	    this.current = isNewValue ? this.from : this.current;

        // Or they've defined both
	    } else if (value.hasOwnProperty('current') && value.hasOwnProperty('from')) {
    	    this.current = parse(value.current, data);
    	    this.from = isNewValue ? parse(value.from, data) : this.current;

        // Or they've defined neither
	    } else {
    	    this.current = isNewValue ? defaults.current : this.current;
    	    this.from = isNewValue ? defaults.from : this.current;
	    }

		this.to = parse(value.to, data, this.current);
	}

    // Loop through permitted values
    for (var key in defaults) {
	    if (defaults.hasOwnProperty(key) && !isPriority(key)) {

		    // If user has submitted a property
		    if (utils.isObj(value) && value.hasOwnProperty(key)) {
                this[key] = parse(value[key], data, this.current);

            // Or there's a default set on the action
		    } else if (utils.isObj(action) && action.hasOwnProperty(key)) {
                this[key] = parse(action[key], data, this.current);

            // Otherwise, if this is our first time (honest judge), set as the default.
		    } else if (isNewValue) {
    		    this[key] = defaults[key];
		    }

	    }
    }
};

module.exports = Value;<|endoftext|>


<commit_before>
(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(["sig-js","drainpipe","gibberish-dsp"], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('sig-js'), require('drainpipe'), require('gibberish-dsp'));
  } else {
    root.wired = factory(root.sig, root.v, root.Gibberish);
  }
}(this, function(sig, v, Gibberish) {

var wired = {}

wired.utils = function() {
  function is(x, type) {
    if (typeof type == 'function') return x instanceof type
    if (type === 'array') return Array.isArray(x, type)
    if (type === 'null') return x === null
    if (x === null && type === 'object') return false

    return (x || 0).type
      ? x.type === type
      : typeof x == type
  }

  return {
    is: is
  }
}()

wired.attach = function(conf) {
  var define = wired.ugens.define
  wired.gib = conf.gib
  wired.master = wired.gib[conf.master]

  conf.meta.forEach(function(ugen) {
    wired[ugen.exportName] = define(ugen)
  })
}

wired.ugens = {}

wired.ugens.meta = [{
  exportName: 'sine',
  name: 'Sine',
  paramNames: [
    'frequency',
    'amp',
    'sync'
  ]
}, {
  exportName: 'bus',
  name: 'Bus',
  paramNames: [
    'inputs',
    'amp'
  ]
}, {
  exportName: 'bus2',
  name: 'Bus2',
  paramNames: [
    'inputs',
    'amp',
    'pan'
  ]
}]

wired.ugens.make = function() {
  var u = wired.utils

  function make(ugen, args) {
    var out = sig()
    var params = makeParams(ugen, args)

    v(params)
     (sig.all)
     (sig.then, function(params0) {
       var gibUgen = new wired.gib[ugen.name](params0)

       v(params)
        (sig.any)
        (sig.map, sig.spread(function(v, k) { gibUgen[k] = v }))
        (sig.depend, out)

       sig.push(out, gibUgen)
     })
     (sig.depend, out)

    return out
  }

  function makeParams(ugen, args) {
    var params = args[args.length - 1]

    if (u.is(params, 'object')) args = args.slice(0, -1)
    else params = {}

    return setProps(params, ugen.paramNames, args)
  }

  function setProps(props, names, values) {
    var i = -1
    var n = values.length
    while (++i < n) props[names[i]] = values[i]
    return props
  }

  return make
}()

wired.ugens.define = function() {
  var make = wired.ugens.make

  function define(ugen) {
    return function() {
      return make(ugen, Array.prototype.slice.call(arguments))
    }
  }

  return define
}()

wired.out = function() {
  function out(ugen, bus) {
    return v([ugen, bus || wired.master])
      (sig.all)
      (sig.then, sig.spread(function(ugen, bus) {
        ugen.connect(bus)
        return ugen
      }))
      ()
  }

  return out
}()

wired.stop = function() {
  function stop(ugen, bus) {
    return v([ugen, bus])
      (sig.all)
      (sig.then, sig.spread(function(ugen, bus) {
        if (!bus) ugen.disconnect()
        else ugen.disconnect(bus)
        return ugen
      }))
      ()
  }

  return stop
}()

;(function() {
  Gibberish.init()

  wired.attach({
    gib: Gibberish,
    master: 'out',
    meta: wired.ugens.meta
  })
})()

return wired;

}));
<commit_msg>rebuild<commit_after>
(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(["sig-js","drainpipe","gibberish-dsp"], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('sig-js'), require('drainpipe'), require('gibberish-dsp'));
  } else {
    root.wired = factory(root.sig, root.v, root.Gibberish);
  }
}(this, function(sig, v, Gibberish) {

var wired = {}

wired.utils = function() {
  function is(x, type) {
    if (typeof type == 'function') return x instanceof type
    if (type === 'array') return Array.isArray(x, type)
    if (type === 'null') return x === null
    if (x === null && type === 'object') return false

    return (x || 0).type
      ? x.type === type
      : typeof x == type
  }

  return {
    is: is
  }
}()

wired.attach = function(conf) {
  var define = wired.ugens.define
  wired.gib = conf.gib
  wired.master = wired.gib[conf.master]

  conf.meta.forEach(function(ugen) {
    wired[ugen.exportName] = define(ugen)
  })
}

wired.ugens = {}

wired.ugens.meta = [{
  exportName: 'sine',
  name: 'Sine',
  paramNames: [
    'frequency',
    'amp',
    'sync'
  ]
}, {
  exportName: 'bus',
  name: 'Bus',
  paramNames: [
    'inputs',
    'amp'
  ]
}, {
  exportName: 'bus2',
  name: 'Bus2',
  paramNames: [
    'inputs',
    'amp',
    'pan'
  ]
}]

wired.ugens.make = function() {
  var u = wired.utils

  function make(ugen, args) {
    var out = sig()
    var params = makeParams(ugen, args)

    vv(params)
      (sig.all)
      (sig.then, function(params0) {
        var gibUgen = new wired.gib[ugen.name](params0)

        vv(params)
          (sig.any)
          (sig.map, sig.spread(function(v, k) { gibUgen[k] = v }))
          (sig.depend, out)

        sig.push(out, gibUgen)
      })
      (sig.depend, out)

      return out
  }

  function makeParams(ugen, args) {
    var params = args[args.length - 1]

    if (u.is(params, 'object')) args = args.slice(0, -1)
    else params = {}

    return setProps(params, ugen.paramNames, args)
  }

  function setProps(props, names, values) {
    var i = -1
    var n = values.length
    while (++i < n) props[names[i]] = values[i]
    return props
  }

  return make
}()

wired.ugens.define = function() {
  var make = wired.ugens.make

  function define(ugen) {
    return function() {
      return make(ugen, Array.prototype.slice.call(arguments))
    }
  }

  return define
}()

wired.out = function() {
  function out(ugen, bus) {
    return vv([ugen, bus || wired.master])
      (sig.all)
      (sig.then, sig.spread(function(ugen, bus) {
        ugen.connect(bus)
        return ugen
      }))
      ()
  }

  return out
}()

wired.stop = function() {
  function stop(ugen, bus) {
    return vv([ugen, bus])
      (sig.all)
      (sig.then, sig.spread(function(ugen, bus) {
        if (!bus) ugen.disconnect()
        else ugen.disconnect(bus)
        return ugen
      }))
      ()
  }

  return stop
}()

;(function() {
  Gibberish.init()

  wired.attach({
    gib: Gibberish,
    master: 'out',
    meta: wired.ugens.meta
  })
})()

return wired;

}));
<|endoftext|>


<commit_before>var $ = (function(d) {
  var slice = [].slice, k,
    CN = "className", AEL = "addEventListener", PN = "parentNode", QSA = "querySelectorAll",
    ADJ_OPS = {append: 'beforeEnd', prepend: 'afterBegin', before: 'beforeBegin', after: 'afterEnd'};

  function $(_, context){
    if(context !== void 0) return $(context).find(_);
    function fn(_){ return fn.dom.forEach(_), fn }
    fn.dom = ((typeof _ == 'function' && 'dom' in _) ?
      _.dom : (_ instanceof Array ? _ :
        (_ instanceof Element ? [_] :
          slice.call(d[QSA](fn.selector = _))))).filter(function(el){
            return el !== void 0 && el !== null;
          });
    for(k in $.fn) fn[k] = $.fn[k];
    return fn;
  }

  function classRE(name){ return new RegExp("(^|\\s)"+name+"(\\s|$)") }
  function elSelect(el, selector){ return slice.call(el[QSA](selector)) }

  $.fn = {
    get: function(idx){ return idx === void 0 ? this.dom : this.dom[idx] },
    remove: function(){
      return this(function(el){ el[PN].removeChild(el) });
    },
    each: function(callback){
      return this(function(e){ callback(e) });
    },
    find: function(selector){
      return $(this.dom.map(function(el){ return elSelect(el, selector) }).reduce(function(a,b){ return a.concat(b) }, []));
    },
    closest: function(selector){
      var el = this.dom[0][PN], nodes = elSelect(d, selector);
      while(el && nodes.indexOf(el)<0) el = el[PN];
      return $(el && !(el===d) ? el : []);
    },
    show: function(){ return this.css('display:block') },
    hide: function(){ return this.css('display:none') },
    prev: function(){ return $(this.dom.map(function(el){ return el.previousElementSibling })) },
    next: function(){ return $(this.dom.map(function(el){ return el.nextElementSibling })) },
    html: function(html){
      return html === void 0 ? (this.dom.length>0 ? this.dom[0].innerHTML : null) : this(function(el){ el.innerHTML = html });
    },
    attr: function(name,value){
      return (typeof name == 'string' && value === void 0) ? (this.dom.length>0 ? this.dom[0].getAttribute(name) || undefined : null) :
        this(function(el){
          if (typeof name == 'object') for(k in name) el.setAttribute(k, name[k])
          else el.setAttribute(name,value);
        });
    },
    offset: function(){
      var obj = this.dom[0].getBoundingClientRect();
      return { left: obj.left+d.body.scrollLeft, top: obj.top+d.body.scrollTop, width: obj.width, height: obj.height };
    },
    css: function(style){
      return this(function(el){ el.style.cssText += ';'+style });
    },
    index: function(target){
      return this.dom.indexOf($(target).get(0));
    },
    anim: function(transform, opacity, dur){
      return this.css('-webkit-transition:all '+(dur||0.5)+'s;'+
        '-webkit-transform:'+transform+';opacity:'+(opacity===0?0:opacity||1));
    },
    bind: function(event, callback){
      return this(function(el){
        event.split(/\s/).forEach(function(event){ el[AEL](event, callback, false); });
      });
    },
    delegate: function(selector, event, callback){
      return this(function(el){
        el[AEL](event, function(event){
          var target = event.target, nodes = elSelect(el, selector);
          while(target && nodes.indexOf(target)<0) target = target[PN];
          if(target && !(target===el) && !(target===d)) callback.call(target, event);
        }, false);
      });
    },
    addClass: function(name){
      return this(function(el){
        !classRE(name).test(el[CN]) && (el[CN] += (el[CN] ? ' ' : '') + name);
      });
    },
    removeClass: function(name){
      return this(function(el){
        el[CN] = el[CN].replace(classRE(name), ' ').replace(/^\s+|\s+$/g, '');
      });
    }
  };

  ['width','height'].forEach(function(m){ $.fn[m] = function(){ return this.offset()[m] }});

  for(k in ADJ_OPS)
    $.fn[k] = (function(op){
      return function(html){ return this(function(el){
        el['insertAdjacent' + (html instanceof Element ? 'Element' : 'HTML')](op,html)
      })};
    })(ADJ_OPS[k]);

  ['swipe', 'doubleTap', 'tap'].forEach(function(m){
    $.fn[m] = function(callback){ return this.bind(m, callback) }
  });

  function dispatch(event, target) {
    var e = d.createEvent('Events');
    e.initEvent(event, true, false);
    target.dispatchEvent(e);
  }

  d.ontouchstart = function(e) {
    var now = Date.now(), t = e.touches[0].target, delta = now - (t.last || now);
    t.x1 = e.touches[0].pageX;
    if (delta > 0 && delta <= 800) {
      dispatch('doubleTap', t);
      t.last = 0;
    } else t.last = now;
  }

  d.ontouchmove = function(e) {
    e.touches[0].target.x2 = e.touches[0].pageX;
  }

  d.ontouchend = function(e) {
    var t = e.target;
    if (t.x2 > 0) {
      t.x1 - t.x2 > 30 && dispatch('swipe', t);
      t.x1 - t.x2 < -30 && dispatch('swipe', t);
      t.x1 = t.x2 = t.last = 0;
    } else if (t.last != 0) {
      dispatch('tap', t);
    }
  }

  function ajax(method, url, success){
    var r = new XMLHttpRequest();
    r.onreadystatechange = function(){
      if(r.readyState==4 && (r.status==200 || r.status==0))
        success(r.responseText);
    };
    r.open(method,url,true);
    r.setRequestHeader('X-Requested-With','XMLHttpRequest');
    r.send(null);
  }

  $.get = function(url, success){ ajax('GET', url, success); };
  $.post = function(url, success){ ajax('POST', url, success); };
  $.getJSON = function(url, success){
    $.get(url, function(json){ success(JSON.parse(json)) });
  };

  return $;
})(document);
<commit_msg>Use a delay of 250ms to decide between single/double taps. Don't pollute elements with temporary data.<commit_after>var $ = (function(d) {
  var slice = [].slice, k,
    CN = "className", AEL = "addEventListener", PN = "parentNode", QSA = "querySelectorAll",
    ADJ_OPS = {append: 'beforeEnd', prepend: 'afterBegin', before: 'beforeBegin', after: 'afterEnd'},
    touch = {}, touchTimeout, e;

  function $(_, context){
    if(context !== void 0) return $(context).find(_);
    function fn(_){ return fn.dom.forEach(_), fn }
    fn.dom = ((typeof _ == 'function' && 'dom' in _) ?
      _.dom : (_ instanceof Array ? _ :
        (_ instanceof Element ? [_] :
          slice.call(d[QSA](fn.selector = _))))).filter(function(el){
            return el !== void 0 && el !== null;
          });
    for(k in $.fn) fn[k] = $.fn[k];
    return fn;
  }

  function classRE(name){ return new RegExp("(^|\\s)"+name+"(\\s|$)") }
  function elSelect(el, selector){ return slice.call(el[QSA](selector)) }

  $.fn = {
    get: function(idx){ return idx === void 0 ? this.dom : this.dom[idx] },
    remove: function(){
      return this(function(el){ el[PN].removeChild(el) });
    },
    each: function(callback){
      return this(function(e){ callback(e) });
    },
    find: function(selector){
      return $(this.dom.map(function(el){ return elSelect(el, selector) }).reduce(function(a,b){ return a.concat(b) }, []));
    },
    closest: function(selector){
      var el = this.dom[0][PN], nodes = elSelect(d, selector);
      while(el && nodes.indexOf(el)<0) el = el[PN];
      return $(el && !(el===d) ? el : []);
    },
    show: function(){ return this.css('display:block') },
    hide: function(){ return this.css('display:none') },
    prev: function(){ return $(this.dom.map(function(el){ return el.previousElementSibling })) },
    next: function(){ return $(this.dom.map(function(el){ return el.nextElementSibling })) },
    html: function(html){
      return html === void 0 ? (this.dom.length>0 ? this.dom[0].innerHTML : null) : this(function(el){ el.innerHTML = html });
    },
    attr: function(name,value){
      return (typeof name == 'string' && value === void 0) ? (this.dom.length>0 ? this.dom[0].getAttribute(name) || undefined : null) :
        this(function(el){
          if (typeof name == 'object') for(k in name) el.setAttribute(k, name[k])
          else el.setAttribute(name,value);
        });
    },
    offset: function(){
      var obj = this.dom[0].getBoundingClientRect();
      return { left: obj.left+d.body.scrollLeft, top: obj.top+d.body.scrollTop, width: obj.width, height: obj.height };
    },
    css: function(style){
      return this(function(el){ el.style.cssText += ';'+style });
    },
    index: function(target){
      return this.dom.indexOf($(target).get(0));
    },
    anim: function(transform, opacity, dur){
      return this.css('-webkit-transition:all '+(dur||0.5)+'s;'+
        '-webkit-transform:'+transform+';opacity:'+(opacity===0?0:opacity||1));
    },
    bind: function(event, callback){
      return this(function(el){
        event.split(/\s/).forEach(function(event){ el[AEL](event, callback, false); });
      });
    },
    delegate: function(selector, event, callback){
      return this(function(el){
        el[AEL](event, function(event){
          var target = event.target, nodes = elSelect(el, selector);
          while(target && nodes.indexOf(target)<0) target = target[PN];
          if(target && !(target===el) && !(target===d)) callback.call(target, event);
        }, false);
      });
    },
    addClass: function(name){
      return this(function(el){
        !classRE(name).test(el[CN]) && (el[CN] += (el[CN] ? ' ' : '') + name);
      });
    },
    removeClass: function(name){
      return this(function(el){
        el[CN] = el[CN].replace(classRE(name), ' ').replace(/^\s+|\s+$/g, '');
      });
    }
  };

  ['width','height'].forEach(function(m){ $.fn[m] = function(){ return this.offset()[m] }});

  for(k in ADJ_OPS)
    $.fn[k] = (function(op){
      return function(html){ return this(function(el){
        el['insertAdjacent' + (html instanceof Element ? 'Element' : 'HTML')](op,html)
      })};
    })(ADJ_OPS[k]);

  ['swipe', 'doubleTap', 'tap'].forEach(function(m){
    $.fn[m] = function(callback){ return this.bind(m, callback) }
  });

  function dispatch(event, target) {
    target.dispatchEvent(e = d.createEvent('Events'), e.initEvent(event, true, false));
  }

  d.ontouchstart = function(e) {
    var now = Date.now(), delta = now-(touch.last || now);
    touch.target = e.touches[0].target;
    if(touchTimeout) clearTimeout(touchTimeout);
    touch.x1 = e.touches[0].pageX;
    if (delta > 0 && delta <= 250) {
      dispatch('doubleTap', touch.target);
      touch = {};
    } else touch.last = now;
  }

  d.ontouchmove = function(e) { touch.x2 = e.touches[0].pageX }

  d.ontouchend = function(e) {
    if (touch.x2 > 0) {
      touch.x1 - touch.x2 > 30 && dispatch('swipe', touch.target);
      touch.x1 - touch.x2 < -30 && dispatch('swipe', touch.target);
      touch.x1 = touch.x2 = touch.last = 0;
    } else if ('last' in touch) {
      touchTimeout = setTimeout(function(){
        touchTimeout = null;
        dispatch('tap', touch.target);
        touch = {};
      }, 250);
    }
  }

  function ajax(method, url, success){
    var r = new XMLHttpRequest();
    r.onreadystatechange = function(){
      if(r.readyState==4 && (r.status==200 || r.status==0))
        success(r.responseText);
    };
    r.open(method,url,true);
    r.setRequestHeader('X-Requested-With','XMLHttpRequest');
    r.send(null);
  }

  $.get = function(url, success){ ajax('GET', url, success); };
  $.post = function(url, success){ ajax('POST', url, success); };
  $.getJSON = function(url, success){
    $.get(url, function(json){ success(JSON.parse(json)) });
  };

  return $;
})(document);
<|endoftext|>