<commit_before>$(function() {

  // Before submitting the form
  $('form').submit(function (e) {
    // Update locales
    var arr = [];
    $("#selected").parent().siblings('ul').find('li:not(".no-match")').each(function() {
      arr.push($(this).data('id'));
    });
    $('#id_locales').val(arr);

    // Update form action
    var slug = $('#id_slug').val();
    if (slug.length > 0) {
      slug += '/';
    }
    $('form').attr('action', $('form').attr('action').split('/projects/')[0] + '/projects/' + slug);
  });

  // Submit form with Enter
  $('html').unbind("keydown.pontoon").bind("keydown.pontoon", function (e) {
    if ($('input[type=text]:not("input[type=search], #id_transifex_username, #id_transifex_password"):focus').length > 0) {
      var key = e.keyCode || e.which;
      if (key === 13) { // Enter
        // A short delay to allow digest of autocomplete before submit
        setTimeout(function() {
          $('form').submit();
        }, 1);
        return false;
      }
    }
  });

  // Suggest slugified name for new projects
  $('#id_name').blur(function() {
    if ($('input[name=pk]').length > 0 || !$('#id_name').val()) {
      return;
    }
    $('#id_slug').attr('placeholder', 'Retrieving...');
    $.ajax({
      url: '/admin/get-slug/',
      data: {
        name: $('#id_name').val()
      },
      success: function(data) {
        var value = (data === "error") ? "" : data;
        $('#id_slug').val(value);
      },
      error: function() {
        $('#id_slug').attr('placeholder', '');
      }
    });
  });

  // Choose locales
  $('.locale.select').on('click.pontoon', 'li', function (e) {
    var target = $(this).parents('.locale.select').siblings('.locale.select').find('ul'),
        clone = $(this).remove();
    target.prepend(clone);
  });

  // Choose/remove all locales
  $('.choose-all, .remove-all').click(function (e) {
    e.preventDefault();
    var ls = $(this).parents('.locale.select'),
        target = ls.siblings('.locale.select').find('ul'),
        items = ls.find('li:visible:not(".no-match")').remove();
    target.prepend(items);
  });

  // Select repository type
  $('body').click(function () {
    $('.repository')
      .find('.menu').hide().end()
      .find('.select').removeClass('opened');
  });
  $('.repository .type li').click(function () {
    var selected = $(this).html(),
        selected_lower = selected.toLowerCase();
    $(this).parents('.select').find('.title').html(selected);
    $('#id_repository_type').val(selected_lower);
    $('.details-wrapper').attr('data-repository-type', selected_lower);
  });
  // Show human-readable value
  $('.repository .type li[data-type=' + $('#id_repository_type').val() + ']').click();

  // Update from repository
  $('.repository .update:not(".disabled"), .transifex .update:not(".disabled")').unbind('click.pontoon').bind('click.pontoon', function (e) {
    e.preventDefault();
    $(this).addClass('disabled');

    var source = $(this).data('source'),
        icon = $(this).find('span').attr('class', 'fa fa-refresh fa-spin'),
        params = {
          pk: $('input[name=pk]').val(),
          csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val()
        };

    if (source === 'transifex') {
      if ($(this).parents('.popup').length === 0) {
        project = $('.transifex input#id_transifex_project');
        resource = $('.transifex input#id_transifex_resource');
        params[project.attr('name')] = project.val();
        params[resource.attr('name')] = resource.val();
      } else {
        $('.transifex input').each(function() {
          var val = $(this).val();
          if (val) {
            if ($(this).attr('name') === 'remember') {
              params[$(this).attr('name')] = ($(this).is(':checked')) ? "on" : "off";
            } else {
              params[$(this).attr('name')] = val;
            }
          }
        });
      }
    }

    $.ajax({
      url: '/admin/' + source + '/',
      type: 'POST',
      data: params,
      success: function(data) {
        if (data === "200") {
          icon.attr('class', 'fa fa-check');
          $('.repository').removeClass('authenticate')
            .find('.errorlist').remove();
          $('.warning').animate({opacity: 0});
          $('.links .translate').removeClass('hidden');
        } else if (data === "authenticate") {
          icon.attr('class', 'fa fa-refresh');
          $('.repository').addClass('authenticate');
        } else if (data.type === "error") {
          icon.attr('class', 'fa fa-warning');
          $('.repository')
            .find('.errorlist').remove().end()
          .append(
            '

' + data.message + '

');
        }
      },
      error: function() {
        icon.attr('class', 'fa fa-warning');
      }
    }).complete(function() {
      icon.parent().removeClass('disabled');
      setTimeout(function() {
        icon.attr('class', 'fa fa-refresh');
      }, 5000);
    });
  });

  // Delete subpage
  $('body').on('click.pontoon', '.delete-subpage', function (e) {
    e.preventDefault();
    $(this).parent().toggleClass('delete');
    $(this).next().prop('checked', !$(this).next().prop('checked'));
  });
  $('.subpages [checked]').click().prev().click();

  // Add subpage
  var count = $('.subpages:last').data('count');
  $('.add-subpage').click(function(e) {
    e.preventDefault();
    var form = $('.subpages:last').html().replace(/__prefix__/g, count);
    $('.subpages:last').before('
' + form + '
');
    count++;
    $('#id_subpage_set-TOTAL_FORMS').val(count);
  });

  // Delete project
  $('.delete-project').click(function (e) {
    e.preventDefault();
    if ($(this).is('.clicked')) {
      window.location = '/admin/delete/' + $('input[name=pk]').val();
    } else {
      $(this).addClass('clicked').html('Are you sure?');
    }
  });

});
<commit_msg>Bugfix: Prevent multiple update requests on project admin<commit_after>$(function() {

  // Before submitting the form
  $('form').submit(function (e) {
    // Update locales
    var arr = [];
    $("#selected").parent().siblings('ul').find('li:not(".no-match")').each(function() {
      arr.push($(this).data('id'));
    });
    $('#id_locales').val(arr);

    // Update form action
    var slug = $('#id_slug').val();
    if (slug.length > 0) {
      slug += '/';
    }
    $('form').attr('action', $('form').attr('action').split('/projects/')[0] + '/projects/' + slug);
  });

  // Submit form with Enter
  $('html').unbind("keydown.pontoon").bind("keydown.pontoon", function (e) {
    if ($('input[type=text]:not("input[type=search], #id_transifex_username, #id_transifex_password"):focus').length > 0) {
      var key = e.keyCode || e.which;
      if (key === 13) { // Enter
        // A short delay to allow digest of autocomplete before submit
        setTimeout(function() {
          $('form').submit();
        }, 1);
        return false;
      }
    }
  });

  // Suggest slugified name for new projects
  $('#id_name').blur(function() {
    if ($('input[name=pk]').length > 0 || !$('#id_name').val()) {
      return;
    }
    $('#id_slug').attr('placeholder', 'Retrieving...');
    $.ajax({
      url: '/admin/get-slug/',
      data: {
        name: $('#id_name').val()
      },
      success: function(data) {
        var value = (data === "error") ? "" : data;
        $('#id_slug').val(value);
      },
      error: function() {
        $('#id_slug').attr('placeholder', '');
      }
    });
  });

  // Choose locales
  $('.locale.select').on('click.pontoon', 'li', function (e) {
    var target = $(this).parents('.locale.select').siblings('.locale.select').find('ul'),
        clone = $(this).remove();
    target.prepend(clone);
  });

  // Choose/remove all locales
  $('.choose-all, .remove-all').click(function (e) {
    e.preventDefault();
    var ls = $(this).parents('.locale.select'),
        target = ls.siblings('.locale.select').find('ul'),
        items = ls.find('li:visible:not(".no-match")').remove();
    target.prepend(items);
  });

  // Select repository type
  $('body').click(function () {
    $('.repository')
      .find('.menu').hide().end()
      .find('.select').removeClass('opened');
  });
  $('.repository .type li').click(function () {
    var selected = $(this).html(),
        selected_lower = selected.toLowerCase();
    $(this).parents('.select').find('.title').html(selected);
    $('#id_repository_type').val(selected_lower);
    $('.details-wrapper').attr('data-repository-type', selected_lower);
  });
  // Show human-readable value
  $('.repository .type li[data-type=' + $('#id_repository_type').val() + ']').click();

  // Update from repository
  $('.repository, .transifex').on('click', '.update', function (e) {
    e.preventDefault();
    if ($(this).is('.disabled')) {
      return;
    }
    $(this).addClass('disabled');

    var source = $(this).data('source'),
        icon = $(this).find('span').attr('class', 'fa fa-refresh fa-spin'),
        params = {
          pk: $('input[name=pk]').val(),
          csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val()
        };

    if (source === 'transifex') {
      if ($(this).parents('.popup').length === 0) {
        project = $('.transifex input#id_transifex_project');
        resource = $('.transifex input#id_transifex_resource');
        params[project.attr('name')] = project.val();
        params[resource.attr('name')] = resource.val();
      } else {
        $('.transifex input').each(function() {
          var val = $(this).val();
          if (val) {
            if ($(this).attr('name') === 'remember') {
              params[$(this).attr('name')] = ($(this).is(':checked')) ? "on" : "off";
            } else {
              params[$(this).attr('name')] = val;
            }
          }
        });
      }
    }

    $.ajax({
      url: '/admin/' + source + '/',
      type: 'POST',
      data: params,
      success: function(data) {
        if (data === "200") {
          icon.attr('class', 'fa fa-check');
          $('.repository').removeClass('authenticate')
            .find('.errorlist').remove();
          $('.warning').animate({opacity: 0});
          $('.links .translate').removeClass('hidden');
        } else if (data === "authenticate") {
          icon.attr('class', 'fa fa-refresh');
          $('.repository').addClass('authenticate');
        } else if (data.type === "error") {
          icon.attr('class', 'fa fa-warning');
          $('.repository')
            .find('.errorlist').remove().end()
          .append(
            '

' + data.message + '

');
        }
      },
      error: function() {
        icon.attr('class', 'fa fa-warning');
      }
    }).complete(function() {
      icon.parent().removeClass('disabled');
      setTimeout(function() {
        icon.attr('class', 'fa fa-refresh');
      }, 5000);
    });
  });

  // Delete subpage
  $('body').on('click.pontoon', '.delete-subpage', function (e) {
    e.preventDefault();
    $(this).parent().toggleClass('delete');
    $(this).next().prop('checked', !$(this).next().prop('checked'));
  });
  $('.subpages [checked]').click().prev().click();

  // Add subpage
  var count = $('.subpages:last').data('count');
  $('.add-subpage').click(function(e) {
    e.preventDefault();
    var form = $('.subpages:last').html().replace(/__prefix__/g, count);
    $('.subpages:last').before('
' + form + '
');
    count++;
    $('#id_subpage_set-TOTAL_FORMS').val(count);
  });

  // Delete project
  $('.delete-project').click(function (e) {
    e.preventDefault();
    if ($(this).is('.clicked')) {
      window.location = '/admin/delete/' + $('input[name=pk]').val();
    } else {
      $(this).addClass('clicked').html('Are you sure?');
    }
  });

});
<|endoftext|>


<commit_before>NCI.nciHistogram = (function(){
	var me = $('#nciHistogram');

	var internalEndpointsCheckbox = $('#histogramDetailsInternal');
	var barWidth = 4;
	var chart = d3.select("#nciHistogram");
	var chartDetails = d3.select("#nciHistogramDetails");
	var margin = {top: 40, right: 60, bottom: 40, left:40},
	    width = 600,
	    height = 350;
	var color = d3.scale.category10();
	var notNetworkColor = "#000000";
	var detailsGraphForce;
	var force;

	me.show = function(){
		chart.text("");
		var endpointsMax = d3.max(NCI.Communities, function(d) { return d.Size; });
		var endpointsMin;
		var endpointsScale;
		if (endpointsMax > 100) {
			endpointsMin = 0.5;
			endpointsScale = d3.scale.log();
		} else {
			endpointsMin = 0;
			endpointsScale = d3.scale.linear();
		}
		endpointsScale.domain([endpointsMax, endpointsMin])
				.range([0, height - margin.top - margin.bottom]);

		var activitiesScale = d3.scale.linear();
		var activitiesMin = 0;
		if (NCI.Communities.length < 800){
			activitiesScale = d3.scale.linear();
			activitiesMin = 0;
		} else{
			activitiesScale = d3.scale.log();
			activitiesMin = 0.5;
		};
		activitiesScale.domain([NCI.Communities.length + 1, activitiesMin])
					    .range([width - margin.right - margin.left, margin.left]);

		var activitiesAxis = d3.svg.axis()
		    .scale(activitiesScale)
		    .orient('bottom')
		    .tickSize(0)
			.ticks(Math.min(NCI.Communities.length + 2, 10),  d3.format("d"))
		    .tickPadding(8);

		var endpointsAxis = d3.svg.axis()
		    .scale(endpointsScale)
		    .orient('left')
			.tickSize(0)
			.ticks(10,  d3.format("d"))
		    .tickPadding(10);

		var barChartSvg = chart.append('svg')
		    .attr('width', width)
		    .attr('height', height)
		    .append('g')
		    .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

        //draw bars
        var index = 0;
		barChartSvg.selectAll('g')
		    .data(NCI.Communities)
		    .enter().append('rect')
		    .attr('x', function(d) { return activitiesScale(NCI.Communities.length - index++) - barWidth/2})
		    .attr('y', function(d) { return endpointsScale(d.Size)}) //- selfwidth
		    .attr('width', function(d) { return barWidth})
		    .attr('height',function(d) { return height - margin.top - margin.bottom - endpointsScale(d.Size) })
			.on("click", function(d) {
				if (NCI.nciHistogram.selectedBar)
				NCI.nciHistogram.selectedBar.setAttribute("fill", "red");
				NCI.nciHistogram.selectedBar = this;
				this.setAttribute("fill", "red");
				me.showDetails();
			 });

		barChartSvg.append("circle").attr("cy", endpointsScale(NCI.timestampNCI))
		    .attr("cx", activitiesScale(NCI.timestampNCI) ).style("fill", "red").attr("r", 6);
	    barChartSvg.append("circle").attr("cy", endpointsScale(endpointsMin))
		    .attr("cx", activitiesScale(NCI.timestampNCI) ).style("fill", "red").attr("r", 4);
		barChartSvg.append("circle").attr("cy", endpointsScale(NCI.timestampNCI))
		    .attr("cx", activitiesScale(activitiesMin) ).style("fill", "red").attr("r", 4);
		//draw axis
		barChartSvg.append('g')
		    .attr('class', 'x axis')
			.attr('transform', 'translate(0,' + (height - margin.top - margin.bottom) + ')')
			.call(activitiesAxis);
		barChartSvg.append('g')
			.attr('class', 'y axis')
			.attr('transform', 'translate(' + margin.left + ')')
			.call(endpointsAxis);
		//draw axis labels
		barChartSvg.append('text').
		attr('style', 'font-weight:bold').
		html('Activities Sorted by Size     j').attr('x', width/2 - 100).attr('y', height - 45);
		barChartSvg.append('text').
		attr('style', 'font-weight:bold').
		html('Number of Endpoints per Activity      X[j]').attr('x', -height/2 - 70).attr('y', -10)
		.attr('transform', 'rotate(-90)');

	};

	me.showDetails = function(d){
		chartDetails.text("");
		if (d.Size > 300)
		return;
		var detailsDim = 320;
		var activityDetails = chartDetails.append('svg')
			.attr('width',  $("#nciHistogramDetails").width())
		    .attr('height', detailsDim);

	    var graph = NCI.prepareDataForForceGraph([d]);

		force = d3.layout.force()
			.charge(-60)
			.linkDistance(30)
			.size([detailsDim, detailsDim])
			.linkStrength(1).nodes(graph.nodes).links(graph.links).start();

		var link = activityDetails.selectAll(".link")
		    .data(graph.links)
			.enter().append("line")
			.attr("class", "activities_link")
			.style("stroke-width", function(d) { return Math.sqrt(d.value); });

		chartDetails.node = activityDetails.selectAll(".node")
		    .data(graph.nodes)
		    .enter().append("circle")
			.call(force.drag)
		    .attr("r", 5)
			.style("fill", function(d) {
				return me.colorifyEndpoint(internalEndpointsCheckbox[0].checked, d);
			 });

		chartDetails.node.append("title").html(function(d) {
			var info = d.name;
			if (d.external){
				info += "
doesn't belong activity";
			};
			info += "
" + d.connections + " connections";
			return info;
		});

		force.on("tick", function() {
			link.attr("x1", function(d) { return d.source.x; })
			    .attr("y1", function(d) { return d.source.y; })
				.attr("x2", function(d) { return d.target.x; })
				.attr("y2", function(d) { return d.target.y; });

			chartDetails.node.attr("cx", function(d) { return d.x; })
			    .attr("cy", function(d) { return d.y; });
		});
	};

	me.colorifyEndpoint = function(devided, endpoint){
		if (endpoint.external)
		    return "#ff0000";
		if ( devided && !endpoint.name.indexOf("10.") == 0 && !name.indexOf("192.168") == 0){
			return notNetworkColor;
		}
		return color(0);
	};

	me.clean = function(){
		chartDetails.text("");
		chart.text("");
	};

	internalEndpointsCheckbox.on('click', function(event){
		var checked = this.checked;
		chartDetails.node.style("fill", function(d) {
			return me.colorifyEndpoint(checked, d);
		});
	});

	return me;
}());
<commit_msg>Fix xistogram details<commit_after>NCI.nciHistogram = (function(){
	var me = $('#nciHistogram');

	var internalEndpointsCheckbox = $('#histogramDetailsInternal');
	var barWidth = 4;
	var chart = d3.select("#nciHistogram");
	var chartDetails = d3.select("#nciHistogramDetails");
	var margin = {top: 40, right: 60, bottom: 40, left:40},
	    width = 600,
	    height = 350;
	var color = d3.scale.category10();
	var notNetworkColor = "#000000";
	var detailsGraphForce;
	var force;

	me.show = function(){
		chart.text("");
		var endpointsMax = d3.max(NCI.Communities, function(d) { return d.Size; });
		var endpointsMin;
		var endpointsScale;
		if (endpointsMax > 100) {
			endpointsMin = 0.5;
			endpointsScale = d3.scale.log();
		} else {
			endpointsMin = 0;
			endpointsScale = d3.scale.linear();
		}
		endpointsScale.domain([endpointsMax, endpointsMin])
				.range([0, height - margin.top - margin.bottom]);

		var activitiesScale = d3.scale.linear();
		var activitiesMin = 0;
		if (NCI.Communities.length < 800){
			activitiesScale = d3.scale.linear();
			activitiesMin = 0;
		} else{
			activitiesScale = d3.scale.log();
			activitiesMin = 0.5;
		};
		activitiesScale.domain([NCI.Communities.length + 1, activitiesMin])
					    .range([width - margin.right - margin.left, margin.left]);

		var activitiesAxis = d3.svg.axis()
		    .scale(activitiesScale)
		    .orient('bottom')
		    .tickSize(0)
			.ticks(Math.min(NCI.Communities.length + 2, 10),  d3.format("d"))
		    .tickPadding(8);

		var endpointsAxis = d3.svg.axis()
		    .scale(endpointsScale)
		    .orient('left')
			.tickSize(0)
			.ticks(10,  d3.format("d"))
		    .tickPadding(10);

		var barChartSvg = chart.append('svg')
		    .attr('width', width)
		    .attr('height', height)
		    .append('g')
		    .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

        //draw bars
        var index = 0;
		barChartSvg.selectAll('g')
		    .data(NCI.Communities)
		    .enter().append('rect')
		    .attr('x', function(d) { return activitiesScale(NCI.Communities.length - index++) - barWidth/2})
		    .attr('y', function(d) { return endpointsScale(d.Size)}) //- selfwidth
		    .attr('width', function(d) { return barWidth})
		    .attr('height',function(d) { return height - margin.top - margin.bottom - endpointsScale(d.Size) })
			.on("click", function(d) {
				if (NCI.nciHistogram.selectedBar)
				NCI.nciHistogram.selectedBar.setAttribute("fill", "black");
				NCI.nciHistogram.selectedBar = this;
				this.setAttribute("fill", "rgb(31, 119, 180)");
				me.showDetails(d);
			 });

		barChartSvg.append("circle").attr("cy", endpointsScale(NCI.timestampNCI))
		    .attr("cx", activitiesScale(NCI.timestampNCI) ).style("fill", "red").attr("r", 6);
	    barChartSvg.append("circle").attr("cy", endpointsScale(endpointsMin))
		    .attr("cx", activitiesScale(NCI.timestampNCI) ).style("fill", "red").attr("r", 4);
		barChartSvg.append("circle").attr("cy", endpointsScale(NCI.timestampNCI))
		    .attr("cx", activitiesScale(activitiesMin) ).style("fill", "red").attr("r", 4);
		//draw axis
		barChartSvg.append('g')
		    .attr('class', 'x axis')
			.attr('transform', 'translate(0,' + (height - margin.top - margin.bottom) + ')')
			.call(activitiesAxis);
		barChartSvg.append('g')
			.attr('class', 'y axis')
			.attr('transform', 'translate(' + margin.left + ')')
			.call(endpointsAxis);
		//draw axis labels
		barChartSvg.append('text').
		attr('style', 'font-weight:bold').
		html('Activities Sorted by Size     j').attr('x', width/2 - 100).attr('y', height - 45);
		barChartSvg.append('text').
		attr('style', 'font-weight:bold').
		html('Number of Endpoints per Activity      X[j]').attr('x', -height/2 - 70).attr('y', -10)
		.attr('transform', 'rotate(-90)');

	};

	me.showDetails = function(d){
		chartDetails.text("");
		var detailsDim = 320;
		var activityDetails = chartDetails.append('svg')
			.attr('width',  $("#nciHistogramDetails").width())
		    .attr('height', detailsDim);

	    var graph = NCI.prepareDataForForceGraph([d]);

		force = d3.layout.force()
			.charge(-60)
			.linkDistance(30)
			.size([detailsDim, detailsDim])
			.linkStrength(1).nodes(graph.nodes).links(graph.links).start();

		var link = activityDetails.selectAll(".link")
		    .data(graph.links)
			.enter().append("line")
			.attr("class", "activities_link")
			.style("stroke-width", function(d) { return Math.sqrt(d.value); });

		chartDetails.node = activityDetails.selectAll(".node")
		    .data(graph.nodes)
		    .enter().append("circle")
			.call(force.drag)
		    .attr("r", 5)
			.style("fill", function(d) {
				return me.colorifyEndpoint(internalEndpointsCheckbox[0].checked, d);
			 });

		chartDetails.node.append("title").html(function(d) {
			var info = d.name;
			if (d.external){
				info += "
doesn't belong activity";
			};
			info += "
" + d.connections + " connections";
			return info;
		});

		force.on("tick", function() {
			link.attr("x1", function(d) { return d.source.x; })
			    .attr("y1", function(d) { return d.source.y; })
				.attr("x2", function(d) { return d.target.x; })
				.attr("y2", function(d) { return d.target.y; });

			chartDetails.node.attr("cx", function(d) { return d.x; })
			    .attr("cy", function(d) { return d.y; });
		});
	};

	me.colorifyEndpoint = function(devided, endpoint){
		if (endpoint.external)
		    return "#ff0000";
		if ( devided && !endpoint.name.indexOf("10.") == 0 && !name.indexOf("192.168") == 0){
			return notNetworkColor;
		}
		return color(0);
	};

	me.clean = function(){
		chartDetails.text("");
		chart.text("");
	};

	internalEndpointsCheckbox.on('click', function(event){
		var checked = this.checked;
		chartDetails.node.style("fill", function(d) {
			return me.colorifyEndpoint(checked, d);
		});
	});

	return me;
}());
<|endoftext|>


<commit_before>const contributorVoices = [
  {
    label: 'Anything you want',
    image: 'https://upload.wikimedia.org/wikipedia/commons/3/33/White_square_with_question_mark.png',
    heading: 'Your Name Here',
    githubUrl: 'https://github.com/udacityalumni',
    description: 'There surely is something you can do to make this better! : )',
  },
  {
    label: 'FE Coder',
    image: 'https://avatars0.githubusercontent.com/u/10746052?v=3&s=400',
    heading: 'Treefish Zhang',
    githubUrl: 'https://github.com/zhangtreefish',
    description: 'The project is about learning React and practice collaborative development with friendly fellow Udacians.',
  },
  {
    label: 'Manager and FS Coder',
    image: 'https://avatars2.githubusercontent.com/u/13810084?v=3&s=400',
    heading: 'Ryan C. Collins',
    githubUrl: 'https://github.com/udacityalumni',
    description: 'Above all else, this project has connected me with an outstanding group of people, all of whom share my passion for education.',
  },
  {
    label: 'FE Coder',
    image: 'https://avatars1.githubusercontent.com/u/2024584?v=3&s=400',
    heading: 'Kelli Blalock',
    githubUrl: 'https://github.com/kellim',
    description: "Helping out with the Udacity Alumni Web App is a great way to learn new skills and how to collaborate on a coding project with a team! I didn't know how hard it would actually be to learn a professional web development stack, but with help from the team, I am contributing code, testing the app, and finding and fixing issues. It also feels pretty awesome to help with the app because Udacity has been the best learning experience I've had as far as getting job ready skills to become a web developer, and I believe this app can help alumni take their skills to the next level! Alumni can contribute to this app, find projects to collaborate on with other alumni, and perhaps find a mentor or meetup.",
  },
  {
    label: 'Premium Poster',
    image: 'https://s-media-cache-ak0.pinimg.com/236x/75/93/83/759383c1c4e98c15c06c9af43fc84552.jpg',
    heading: 'SadlyFake Demo-User',
    githubUrl: 'https://github.com/udacityalumni',
    description: 'I love blogging! I also break hearts.',
  },
  {
    label: 'FE Coder',
    image: 'https://avatars1.githubusercontent.com/u/12371494?v=3&s=400',
    heading: 'Martin Breuss',
    githubUrl: 'https://github.com/martin-martin',
    description: "Contributing to the Alumni-Webapp taught me a lot about the joys and troubles of real-life collaborative Web-Development. Working with other Alumni is beautiful and there is a lot of positive support oozing out in all directions. Personally I wish that this webapp will further the possibilities to connect with each other and work on big useful projects as well as tiny playful ideas. : ) I hope that it will be a place to talk things over, get and give support, and simply appreciate each other's life and work.",
  },
  {
    label: '',
    image: 'https://avatars2.githubusercontent.com/u/14373007?v=3&s=400',
    heading: 'Ben Lewis',
    githubUrl: 'https://github.com/BenGoBlue05',
    description: 'A chance to become involved in the Udacity alumni community by making connections, learning about development opportunities, and staying up-to-date with the latest news.',
  },
  {
    label: 'Anything you want',
    image: 'https://upload.wikimedia.org/wikipedia/commons/3/33/White_square_with_question_mark.png',
    heading: 'Your Name Here',
    githubUrl: 'https://github.com/udacityalumni',
    description: 'Excited to build something? Click the link!',
  },
];

export default contributorVoices;<commit_msg>Feat: mb add 2 new contributor voices. Yay<commit_after>const contributorVoices = [
  {
    label: 'Anything you want',
    image: 'https://upload.wikimedia.org/wikipedia/commons/3/33/White_square_with_question_mark.png',
    heading: 'Your Name Here',
    githubUrl: 'https://github.com/udacityalumni',
    description: 'There surely is something you can do to make this better! : )',
  },
  {
    label: 'FE Coder',
    image: 'https://avatars0.githubusercontent.com/u/10746052?v=3&s=400',
    heading: 'Treefish Zhang',
    githubUrl: 'https://github.com/zhangtreefish',
    description: 'The project is about learning React and practice collaborative development with friendly fellow Udacians.',
  },
  {
    label: 'Manager and FS Coder',
    image: 'https://avatars2.githubusercontent.com/u/13810084?v=3&s=400',
    heading: 'Ryan C. Collins',
    githubUrl: 'https://github.com/udacityalumni',
    description: 'Above all else, this project has connected me with an outstanding group of people, all of whom share my passion for education.',
  },
  {
    label: 'FE Coder',
    image: 'https://avatars1.githubusercontent.com/u/2024584?v=3&s=400',
    heading: 'Kelli Blalock',
    githubUrl: 'https://github.com/kellim',
    description: "Helping out with the Udacity Alumni Web App is a great way to learn new skills and how to collaborate on a coding project with a team! I didn't know how hard it would actually be to learn a professional web development stack, but with help from the team, I am contributing code, testing the app, and finding and fixing issues. It also feels pretty awesome to help with the app because Udacity has been the best learning experience I've had as far as getting job ready skills to become a web developer, and I believe this app can help alumni take their skills to the next level! Alumni can contribute to this app, find projects to collaborate on with other alumni, and perhaps find a mentor or meetup.",
  },
  {
    label: 'Premium Poster',
    image: 'https://s-media-cache-ak0.pinimg.com/236x/75/93/83/759383c1c4e98c15c06c9af43fc84552.jpg',
    heading: 'SadlyFake Demo-User',
    githubUrl: 'https://github.com/udacityalumni',
    description: 'I love blogging! I also break hearts.',
  },
  {
    label: 'FE Coder',
    image: 'https://avatars1.githubusercontent.com/u/12371494?v=3&s=400',
    heading: 'Martin Breuss',
    githubUrl: 'https://github.com/martin-martin',
    description: "Contributing to the Alumni-Webapp taught me a lot about the joys and troubles of real-life collaborative Web-Development. Working with other Alumni is beautiful and there is a lot of positive support oozing out in all directions. Personally I wish that this webapp will further the possibilities to connect with each other and work on big useful projects as well as tiny playful ideas. : ) I hope that it will be a place to talk things over, get and give support, and simply appreciate each other's life and work.",
  },
  {
    label: '',
    image: 'https://avatars2.githubusercontent.com/u/14373007?v=3&s=400',
    heading: 'Ben Lewis',
    githubUrl: 'https://github.com/BenGoBlue05',
    description: 'A chance to become involved in the Udacity alumni community by making connections, learning about development opportunities, and staying up-to-date with the latest news.',
  },
  {
    label: 'Anything you want',
    image: 'https://upload.wikimedia.org/wikipedia/commons/3/33/White_square_with_question_mark.png',
    heading: 'Your Name Here',
    githubUrl: 'https://github.com/udacityalumni',
    description: 'Excited to build something? Click the link!',
  },
  {
    label: '',
    image: 'https://avatars2.githubusercontent.com/u/10888441?v=3&s=400',
    heading: 'James Ives',
    githubUrl: 'https://github.com/JamesIves',
    description: 'Excited to build something? Click the link!',
  },
  {
    label: '',
    image: 'https://avatars1.githubusercontent.com/u/15236109?v=3&s=400',
    heading: 'James Gallagher',
    githubUrl: 'https://github.com/James-Gallagher',
    description: 'The Udacity Alumni Web App project was a key opportunity to collaborate with experienced programmers on a project which would benefit the whole Alumni Community. Implementing features, delegating tasks, collaborating on ideas - all parts of the project in which turned the project, into a true community of developers. The project expresses the work, thoughts and opinions of Udacity Alumni and was a very time consuming, yet well executed project - with development never ending considering there is always a new idea which is pending to be implemented.',
  },
];

export default contributorVoices;<|endoftext|>


<commit_before>/*
  lazyload.js: Image lazy loading

  Copyright (c) 2012 Vincent Voyer, Stéphane Rios

  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/

(function(window, document){

  var
    docElem = document.documentElement || document.body,
    // Vertical offset in px. Used for preloading images while scrolling
    offset = 200,
    //where to get real src
    lazyAttr = 'data-src',
    // Window height
    winH,
    // Self-populated page images array, we do not getElementsByTagName
    imgs = [],
    pageHasLoaded,

    // throttled functions, so that we do not call them too much
    saveWindowHeightT = throttle(saveWindowHeight, 20),
    showImagesT = throttle(showImages, 20);

  // Called from every lazy <img> onload event
  window['lzld'] = onFakeImgLoad;

  // Bind events
  saveWindowHeight();
  addEvent(window, 'resize', saveWindowHeightT);
  addEvent(window, 'scroll', showImagesT);
  addEvent(document, 'DOMContentLoaded', onDomReady);
  addEvent(window, 'load', onLoad);

  function onFakeImgLoad(img) {
    // To avoid onload being called and called and called ...
    // This is what prevents pagespeed's lazyload to work on IE!
    img.onload = null;

    showIfVisible(img, imgs.push(img) - 1);
  }

  function onDomReady() {
    showImagesT();
    setTimeout(showImagesT, 20);
  }

  function onLoad() {
    pageHasLoaded = true;
    // if page height changes (hiding elements at start)
    // we should recheck for new in viewport images that need to be shown
    // see onload test
    showImagesT();
    // we are the first to be notified about onload, so let others event handlers
    // pass and then try again
    setTimeout(showImagesT, 20);
  }

  function throttle(fn, minDelay) {
    var lastCall = 0;
    return function() {
      var now = +new Date;
      if (now - lastCall < minDelay) {
        return;
      }
      lastCall = now;
      // we do not return anything as
      // https://github.com/documentcloud/underscore/issues/387
      fn.apply(this, arguments);
    }
  }

  // cross browser event add
  function addEvent( el, type, fn ) {
    if (el.attachEvent) {
      el.attachEvent && el.attachEvent( 'on' + type, fn );
    } else {
      el.addEventListener( type, fn, false );
    }
  }

  // cross browser event remove
  function removeEvent( el, type, fn ) {
    if (el.detachEvent) {
      el.detachEvent && el.detachEvent( 'on' + type, fn );
    } else {
      el.removeEventListener( type, fn, false );
    }
  }

  // img = dom element
  // index = imgs array index
  function showIfVisible(img, index) {
    if (img.getBoundingClientRect().top < winH + offset) {
      img.src = img.getAttribute(lazyAttr);
      img.removeAttribute(lazyAttr);
      imgs[index] = null;
      return true; // img shown
    } else {
      return false; // img to be shown
    }
  }

  // cross browser window height
  function saveWindowHeight() {
    // if window height 0 then we will load all images
    return winH = window.innerHeight || docElem.clientHeight || 10000;
  }

  // Loop through images array to find to-be-shown images
  function showImages() {
    var
      last = imgs.length,
      current,
      allImagesDone = true;

    for (current = 0; current < last; current++) {
      var img = imgs[current];
      // if showIfVisible is false, it means we have some waiting images to be
      // shown
      if(img !== null && !showIfVisible(img, current)) {
        allImagesDone = false;
      }
    }

    if (allImagesDone && pageHasLoaded) {
      unsubscribe();
    }
  }

  // remove all event listeners
  function unsubscribe() {
    removeEvent(window, 'resize', saveWindowHeightT);
    removeEvent(window, 'scroll', showImagesT);
    removeEvent(window, 'load', onLoad);
    removeEvent(document, 'DOMContentLoaded', onDomReady);
  }

})(this, document)
<commit_msg>small refactor better viewport computing<commit_after>/*
  lazyload.js: Image lazy loading

  Copyright (c) 2012 Vincent Voyer, Stéphane Rios

  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/

(function(window, document){

  var
    // Vertical offset in px. Used for preloading images while scrolling
    offset = 200,
    //where to get real src
    lazyAttr = 'data-src',
    // Window height
    winH = viewport(),
    // Self-populated page images array, we do not getElementsByTagName
    imgs = [],
    pageHasLoaded,

    // throttled functions, so that we do not call them too much
    saveViewportT = throttle(viewport, 20),
    showImagesT = throttle(showImages, 20);

  // Called from every lazy <img> onload event
  window['lzld'] = onDataSrcImgLoad;

  // Bind events
  addEvent(window, 'resize', saveViewportT);
  addEvent(window, 'scroll', showImagesT);
  addEvent(document, 'DOMContentLoaded', onDomReady);
  addEvent(window, 'load', onLoad);

  function onDataSrcImgLoad(img) {
    // To avoid onload being called and called and called ...
    // This is what prevents pagespeed's lazyload to work on IE!
    img.onload = null;

    showIfVisible(img, imgs.push(img) - 1);
  }

  function onDomReady() {
    showImagesT();
    setTimeout(showImagesT, 25);
  }

  function onLoad() {
    pageHasLoaded = true;
    // if page height changes (hiding elements at start)
    // we should recheck for new in viewport images that need to be shown
    // see onload test
    showImagesT();
    // we could be the first to be notified about onload, so let others event handlers
    // pass and then try again
    // because they could change things on images
    setTimeout(showImagesT, 25);
  }

  function throttle(fn, minDelay) {
    var lastCall = 0;
    return function() {
      var now = +new Date;
      if (now - lastCall < minDelay) {
        return;
      }
      lastCall = now;
      // we do not return anything as
      // https://github.com/documentcloud/underscore/issues/387
      fn.apply(this, arguments);
    }
  }

  // X-browser
  function addEvent( el, type, fn ) {
    if (el.attachEvent) {
      el.attachEvent && el.attachEvent( 'on' + type, fn );
    } else {
      el.addEventListener( type, fn, false );
    }
  }

  // X-browser
  function removeEvent( el, type, fn ) {
    if (el.detachEvent) {
      el.detachEvent && el.detachEvent( 'on' + type, fn );
    } else {
      el.removeEventListener( type, fn, false );
    }
  }

  // img = dom element
  // index = imgs array index
  function showIfVisible(img, index) {
    if (img.getBoundingClientRect().top < winH + offset) {
      img.src = img.getAttribute(lazyAttr);
      img.removeAttribute(lazyAttr);
      imgs[index] = null;
      return true; // img shown
    } else {
      return false; // img to be shown
    }
  }

  // cross browser viewport calculation
  function viewport() {
    if (document.documentElement.clientHeight >= 0) {
      return document.documentElement.clientHeight;
    } else if (document.body && document.body.clientHeight >= 0) {
      return document.body.clientHeight
    } else if (window.innerHeight >= 0) {
      return window.innerHeight;
    } else {
      return 0;
    }
  }

  function saveViewport() {
    winH = viewport();
  }

  // Loop through images array to find to-be-shown images
  function showImages() {
    var
      last = imgs.length,
      current,
      allImagesDone = true;

    for (current = 0; current < last; current++) {
      var img = imgs[current];
      // if showIfVisible is false, it means we have some waiting images to be
      // shown
      if(img !== null && !showIfVisible(img, current)) {
        allImagesDone = false;
      }
    }

    if (allImagesDone && pageHasLoaded) {
      unsubscribe();
    }
  }

  // remove all event listeners
  function unsubscribe() {
    removeEvent(window, 'resize', saveViewportT);
    removeEvent(window, 'scroll', showImagesT);
    removeEvent(window, 'load', onLoad);
    removeEvent(document, 'DOMContentLoaded', onDomReady);
  }

})(this, document)
<|endoftext|>


<commit_before>/**
 * Shopware 4.0
 * Copyright © 2012 shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 *
 * @category   Shopware
 * @package    Article
 * @subpackage Variants
 * @copyright  Copyright (c) 2012, shopware AG (http://www.shopware.de)
 * @version    $Id$
 * @author shopware AG
 */

/**
 * Shopware UI - Article detail page
 * The variant list component is the listing component for the created article variants.
 */
//{namespace name=backend/article/view/main}
//{block name="backend/article/view/variant/list"}
Ext.define('Shopware.apps.Article.view.variant.List', {

    /**
     * Extend from the standard ExtJS 4
     * @string
     */
    extend:'Ext.grid.Panel',

    /**
     * List of short aliases for class names. Most useful for defining xtypes for widgets.
     * @string
    */
    alias:'widget.article-variant-list',

    /**
     * Set css class
     * @string
     */
    cls:Ext.baseCSSPrefix + 'article-variant-list',

    /**
     * The view needs to be scrollable
     * @string
     */
    autoScroll:true,

    /**
     * Contains all snippets for the view component
     * @object
     */
    snippets:{
        regexNumberValidation: '{s name=detail/base/regex_number_validation}The inserted article number contains illegal characters!{/s}',
        columns:{
            number:'{s name=variant/list/column/number}Order number{/s}',
            stock:'{s name=variant/list/column/stock}Stock{/s}',
            price: {
                header: '{s name=variant/list/column/price}Price{/s}',
                undefined: '{s name=variant/list/column/price_undefined}Undefined{/s}',
                from: '{s name=variant/list/column/price_from}From{/s}'
            },
            standard: '{s name=variant/list/column/standard}Preselection{/s}',
            active: '{s name=variant/list/column/active}Active{/s}',
            remove: '{s name=variant/list/column/remove}Remove variant{/s}',
            edit: '{s name=variant/list/column/edit}Edit variant{/s}'
        },
        toolbar:{
            add:'{s name=variant/list/toolbar/button_add}Add{/s}',
            remove:'{s name=variant/list/toolbar/button_delete}Delete all selected{/s}',
            search:'{s name=variant/list/toolbar/search_empty_text}Search...{/s}',
            data:'{s name=variant/list/toolbar/data}Apply standard data{/s}',
            save:'{s name=variant/list/toolbar/save}Save changes{/s}',
            orderNumber: {
                field: '{s name=variant/list/toolbar/order_field}Apply standard prices{/s}',
                button: '{s name=variant/list/toolbar/order_button}Regenerate order numbers{/s}',
                empty: '{s name=variant/list/toolbar/order_empty}mainDetail.number{/s}'
            }
        },
        saved: {
            errorMessage: '{s name=article_saved/error_message}An error has occurred while saving the article:{/s}',
            errorTitle: '{s name=article_saved/error_title}Error{/s}',
        }
    },

    /**
     * Initialize the Shopware.apps.Article.view.variant.List and defines the necessary default configuration
     * @return void
     */
    initComponent:function () {
        var me = this;

        me.registerEvents();
        me.selModel = me.getGridSelModel();
        me.columns = me.getColumns();
        me.toolbar = me.getToolbar();
        me.pagingbar = me.getPagingBar();
        me.plugins = [ me.createCellEditor() ];
        me.dockedItems = [ me.toolbar, me.pagingbar ];
        me.callParent(arguments);
    },

    /**
     * Creates the cell editor the grid panel.
     *
     * @public
     * @return [object] Ext.grid.plugin.CellEditing
     */
    createCellEditor: function() {
        var me = this;

        me.cellEditor = Ext.create('Ext.grid.plugin.CellEditing', {
            clicksToMoveEditor: 1,
            autoCancel: true
        });

        //register listener on the edit event to save the record and convert the price value. Without
        //this listener the insert price "10,55" would be become "1055"
        me.cellEditor.on('edit', function(editor, e) {
            if (e.value && e.field === 'price') {
                var newPrice = Ext.Number.from(e.value);
                newPrice = Ext.Number.toFixed(newPrice, 2);

                var oldPrice = Ext.Number.from(e.originalValue);
                oldPrice = Ext.Number.toFixed(oldPrice, 2);

                if (newPrice != oldPrice) {
                    me.fireEvent('editVariantPrice', e.record, newPrice);
                }
            } else {
                var oldNumber = e.record.get('number');

                // Map the ordernumber and save the model to the server side
                console.dir(e.record.data);
                e.record.set('number', e.record.get('details.number'));
                e.record.save({

                    // Rollback changes if an error occurs
                    failure: function(record) {
                        var rawData = record.getProxy().getReader().rawData,
                            message = rawData.message;

                        e.record.set('number', oldNumber);
                        e.record.set('details.number', oldNumber);
                        Shopware.Notification.createGrowlMessage(me.snippets.saved.errorTitle, me.snippets.saved.errorMessage + message, me.snippets.growlMessage);
                    }
                });
            }
        });

        /**
         * Event listener which filters the html tags from the number value.
         */
        me.cellEditor.on('beforeedit', function(editor, e) {
            if(e.field === 'details.number') {

                // We need to defer the function call to make sure that the editor is rendered
                // and the value is loaded.
                Ext.defer(function() {

                    editor.editors.each(function(ed) {
                        ed.validationRequestParam = e.record.get('id');
                        ed.setValue(e.record.get('number'));
                    });
                }, 50);
            }
        }, me);

        return me.cellEditor;
    },

    /**
     * Called when the user creates the variants. This function recreates the grid columns.
     */
    refreshColumns: function() {
        var me = this;
        me.getSelectionModel().deselectAll();
        me.reconfigure(me.getStore(), me.getColumns());
    },

    /**
     * Defines additional events which will be fired from the component
     *
     * @return void
     */
    registerEvents:function () {
        this.addEvents(
            /**
             * Event will be fired when the user clicks the delete button in the toolbar or
             * use the action column of the grid to remove one or multiple variants
             * @event deleteVariant
             * @param [array] Record - The selected records
             */
            'deleteVariant',

            /**
             * @event saveVariant
             */
            'saveVariant',

            /**
             * Event will be fired when the user insert a value into the search field of the toolbar
             * to filter the listing.
             * @event searchVariants
             */
            'searchVariants',

            /**
             * Event will be fired when the user clicks on the edit action column of the
             * grid, to edit a single variant.
             * @event editVariant
             * @param [Ext.data.Model] Record - The selected record
             */
            'editVariant',

            /**
             * Event will be fired when the user clicks the "generate order numbers" button in the
             * toolbar to create new article order numbers.
             * @event generateOrderNumbers
             */
            'generateOrderNumbers',

            /**
             * Event will be fired when the user clicks the "apply standard prices" button in the toolbar
             * to apply the standard prices for all article variants.
             * @event applyPrices
             */
            'applyData',

            /**
             * Event will be fired over the row editor update button.
             * @event saveVariants
             */
            'editVariantPrice',

            /**
             * Event will be fired over the save button if the user is on the configurator tab.
             * Fired from the detail.window component
             * @event createVariants
             */
            'createVariants',

            /**
             * Event will be fired over the save button if the user is on the settings tab.
             * Fired from the detail.window component
             * @event saveSettings
             */
            'saveSettings'
        );
    },

    /**
     * Creates the grid columns
     *
     * @return [array] grid columns
     */
    getColumns: function () {
        var me = this, standardColumns, columns = [];

        standardColumns = [
            {
                header: me.snippets.columns.stock,
                dataIndex: 'inStock',
                sortable: false,
                flex: 1,
                renderer: me.stockColumnRenderer,
                editor: {
                    xtype: 'numberfield',
                    allowBlank: true,
                    allowDecimals: false
                }
            } ,{
                header: me.snippets.columns.price.header,
                dataIndex: 'price',
                sortable: false,
                flex: 1,
                renderer: me.priceColumnRenderer,
                editor: {
                    xtype: 'numberfield',
                    allowBlank: false,
                    decimalSeparator: ',',
                    decimalPrecision: 2
                }
            } , {
                header: me.snippets.columns.standard,
                dataIndex: 'standard',
                sortable: false,
                flex: 1,
                editor: {
                    xtype: 'checkbox',
                    inputValue: true,
                    uncheckedValue: false
                }
            } , {
                header: me.snippets.columns.active,
                dataIndex: 'active',
                sortable: false,
                flex: 1,
                editor: {
                    xtype: 'checkbox',
                    inputValue: true,
                    uncheckedValue: false
                }
            } ,
            {
                /**
                 * Special column type which provides clickable icons in each row
                 */
                xtype:'actioncolumn',
                width:70,
                items:[
                    {
                        iconCls:'sprite-minus-circle-frame',
                        action:'deleteVariant',
                        tooltip:me.snippets.columns.remove,
                        handler: function (view, rowIndex, colIndex, item, opts, record) {
                            var records = [ record ];
                            me.fireEvent('deleteVariant', records);
                        }
                    } , {
                        iconCls:'sprite-pencil',
                        action:'editVariant',
                        tooltip:me.snippets.columns.edit,
                        handler:function (view, rowIndex, colIndex, item, opts, record) {
                            me.fireEvent('editVariant', record);
                        }
                    }
                ]
            }
        ];

        columns.push({
            header: me.snippets.columns.number,
            dataIndex: 'details.number',
            sortable: true,
            flex:1,
            align: 'left',
            renderer: me.numberColumnRenderer,
            editor: {
                allowBlank: false
            }
        });
        columns = columns.concat(me.createDynamicColumns());
        columns = columns.concat(standardColumns);
        return columns;
    },

    /**
     * Creates the grid columns for the dynamic configurator groups.
     * @return [array] An array of column objects.
     */
    createDynamicColumns: function() {
        var me = this, columns = [], column;

        me.configuratorGroupStore.each(function(group) {
            if (group.get('active')) {
                columns.push(
                    {
                        header: group.get('name'),
                        dataIndex: 'configuratorOptions.name',
                        sortable: false,
                        flex: 1,
                        configuratorGroup: group,
                        renderer: me.configuratorGroupColumnRenderer
                    }
                );
            }
        });

        return columns;
    },

    /**
     * Renderer function of the price column. If a scale price defined, the function returns the first price value
     * with an additional flag "from*" to display the user that this variant has scale prices.
     * @param value
     * @param metaData
     * @param record
     */
    priceColumnRenderer: function(value, metaData, record) {
        var me = this,
            prices = record.getPrice();

        if (prices.getCount() === 0) {
            return me.snippets.columns.price.undefined;
        } else {
            var firstPrice = prices.first();
            if (prices.getCount() === 1) {
                return Ext.util.Format.currency(firstPrice.get('price'));
            } else {
                return me.snippets.columns.price.from + ' ' + Ext.util.Format.currency(firstPrice.get('price'));
            }
        }
    },

    /**
     * Renderer function of the number column.
     * @param value
     * @param metaData
     * @param record
     */
    numberColumnRenderer: function(value, metaData, record) {
        if (record) {
            return record.get('number');
        } else {
            return '';
        }
    },
    /**
     * Renderer function of the stock column.
     * @param value
     * @param metaData
     * @param record
     */
    stockColumnRenderer: function(value, metaData, record) {
        if (record) {
            return record.get('inStock');
        } else {
            return '';
        }
    },

    /**
     * Renderer function for each configurator group column
     */
    configuratorGroupColumnRenderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
        var me = this;
        var column = me.columns[colIndex];
        var options = record.getConfiguratorOptions();

        if (column && options) {
            var configuratorGroup = column.configuratorGroup;
            var currentOption = null;
            options.each(function(option) {
                if (option.get('groupId') === configuratorGroup.get('id')) {
                    currentOption = option;
                    return;
                }
            });
            if (currentOption !== null) {
                return currentOption.get('name');
            }
        }
        return '';
    },

    /**
     * Creates the grid selection model for checkboxes
     *
     * @return [Ext.selection.CheckboxModel] grid selection model
     */
    getGridSelModel:function () {
        var me = this;

        return Ext.create('Ext.selection.CellModel');
    },

    /**
     * Creates the grid toolbar with the different buttons.
     * @return [Ext.toolbar.Toolbar] grid toolbar
     */
    getToolbar:function () {
        var me = this;

        //creates the price button to apply the standard prices of the main article on all variants.
        me.applyDataButton = Ext.create('Ext.button.Button', {
            iconCls:'sprite-money--arrow',
            text: me.snippets.toolbar.data,
            action: 'applyData',
            handler: function() {
                me.fireEvent('applyData');
            }
        });

        //creates the text field for the order number syntax.
        me.orderNumberField = Ext.create('Ext.form.field.Text', {
            emptyText: me.snippets.toolbar.orderNumber.empty,
            fieldLabel: me.snippets.toolbar.orderNumber.label,
            flex: 1,
            name: 'numberSyntax'
        });

        //creates the button to regenerate all order numbers for the article variants.
        me.orderNumberButton = Ext.create('Ext.button.Button', {
            iconCls: 'sprite-key--arrow',
            text: me.snippets.toolbar.orderNumber.button,
            action: 'generateOrderNumbers',
            handler: function() {
                me.fireEvent('generateOrderNumbers', me.orderNumberField);
            }
        });

        //creates the search field to filter the listing.
        me.searchField = Ext.create('Ext.form.field.Text', {
            name:'searchfield',
            cls:'searchfield',
            width:170,
            emptyText:me.snippets.toolbar.search,
            enableKeyEvents:true,
            checkChangeBuffer:500,
            listeners: {
                change: function(field, value) {
                    me.fireEvent('searchVariants', value);
                }
            }
        });

        return Ext.create('Ext.toolbar.Toolbar', {
            dock:'top',
            ui: 'shopware-ui',
            cls: 'shopware-toolbar',
            items:[
                me.applyDataButton,
                { xtype:'tbspacer', width: 6 },
                { xtype: 'tbseparator' },
                { xtype:'tbspacer', width: 6 },
                me.orderNumberField,
                { xtype:'tbspacer', width: 6 },
                me.orderNumberButton,
                '->',
                me.searchField,
                { xtype:'tbspacer', width:6 }
            ]
        });
    },

    /**
     * Creates the paging toolbar for the grid to allow store paging. The paging toolbar uses the same store as the Grid
     *
     * @return Ext.toolbar.Paging The paging toolbar for the customer grid
     */
    getPagingBar:function () {
        var me = this;

        return Ext.create('Ext.toolbar.Paging', {
            store: me.store,
            dock:'bottom',
            displayInfo:true
        });
    }

});
//{/block}

<commit_msg>#NTR - Remove debug output<commit_after>/**
 * Shopware 4.0
 * Copyright © 2012 shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 *
 * @category   Shopware
 * @package    Article
 * @subpackage Variants
 * @copyright  Copyright (c) 2012, shopware AG (http://www.shopware.de)
 * @version    $Id$
 * @author shopware AG
 */

/**
 * Shopware UI - Article detail page
 * The variant list component is the listing component for the created article variants.
 */
//{namespace name=backend/article/view/main}
//{block name="backend/article/view/variant/list"}
Ext.define('Shopware.apps.Article.view.variant.List', {

    /**
     * Extend from the standard ExtJS 4
     * @string
     */
    extend:'Ext.grid.Panel',

    /**
     * List of short aliases for class names. Most useful for defining xtypes for widgets.
     * @string
    */
    alias:'widget.article-variant-list',

    /**
     * Set css class
     * @string
     */
    cls:Ext.baseCSSPrefix + 'article-variant-list',

    /**
     * The view needs to be scrollable
     * @string
     */
    autoScroll:true,

    /**
     * Contains all snippets for the view component
     * @object
     */
    snippets:{
        regexNumberValidation: '{s name=detail/base/regex_number_validation}The inserted article number contains illegal characters!{/s}',
        columns:{
            number:'{s name=variant/list/column/number}Order number{/s}',
            stock:'{s name=variant/list/column/stock}Stock{/s}',
            price: {
                header: '{s name=variant/list/column/price}Price{/s}',
                undefined: '{s name=variant/list/column/price_undefined}Undefined{/s}',
                from: '{s name=variant/list/column/price_from}From{/s}'
            },
            standard: '{s name=variant/list/column/standard}Preselection{/s}',
            active: '{s name=variant/list/column/active}Active{/s}',
            remove: '{s name=variant/list/column/remove}Remove variant{/s}',
            edit: '{s name=variant/list/column/edit}Edit variant{/s}'
        },
        toolbar:{
            add:'{s name=variant/list/toolbar/button_add}Add{/s}',
            remove:'{s name=variant/list/toolbar/button_delete}Delete all selected{/s}',
            search:'{s name=variant/list/toolbar/search_empty_text}Search...{/s}',
            data:'{s name=variant/list/toolbar/data}Apply standard data{/s}',
            save:'{s name=variant/list/toolbar/save}Save changes{/s}',
            orderNumber: {
                field: '{s name=variant/list/toolbar/order_field}Apply standard prices{/s}',
                button: '{s name=variant/list/toolbar/order_button}Regenerate order numbers{/s}',
                empty: '{s name=variant/list/toolbar/order_empty}mainDetail.number{/s}'
            }
        },
        saved: {
            errorMessage: '{s name=article_saved/error_message}An error has occurred while saving the article:{/s}',
            errorTitle: '{s name=article_saved/error_title}Error{/s}',
        }
    },

    /**
     * Initialize the Shopware.apps.Article.view.variant.List and defines the necessary default configuration
     * @return void
     */
    initComponent:function () {
        var me = this;

        me.registerEvents();
        me.selModel = me.getGridSelModel();
        me.columns = me.getColumns();
        me.toolbar = me.getToolbar();
        me.pagingbar = me.getPagingBar();
        me.plugins = [ me.createCellEditor() ];
        me.dockedItems = [ me.toolbar, me.pagingbar ];
        me.callParent(arguments);
    },

    /**
     * Creates the cell editor the grid panel.
     *
     * @public
     * @return [object] Ext.grid.plugin.CellEditing
     */
    createCellEditor: function() {
        var me = this;

        me.cellEditor = Ext.create('Ext.grid.plugin.CellEditing', {
            clicksToMoveEditor: 1,
            autoCancel: true
        });

        //register listener on the edit event to save the record and convert the price value. Without
        //this listener the insert price "10,55" would be become "1055"
        me.cellEditor.on('edit', function(editor, e) {
            if (e.value && e.field === 'price') {
                var newPrice = Ext.Number.from(e.value);
                newPrice = Ext.Number.toFixed(newPrice, 2);

                var oldPrice = Ext.Number.from(e.originalValue);
                oldPrice = Ext.Number.toFixed(oldPrice, 2);

                if (newPrice != oldPrice) {
                    me.fireEvent('editVariantPrice', e.record, newPrice);
                }
            } else {
                var oldNumber = e.record.get('number');

                // Map the ordernumber and save the model to the server side
                e.record.set('number', e.record.get('details.number'));
                e.record.save({

                    // Rollback changes if an error occurs
                    failure: function(record) {
                        var rawData = record.getProxy().getReader().rawData,
                            message = rawData.message;

                        e.record.set('number', oldNumber);
                        e.record.set('details.number', oldNumber);
                        Shopware.Notification.createGrowlMessage(me.snippets.saved.errorTitle, me.snippets.saved.errorMessage + message, me.snippets.growlMessage);
                    }
                });
            }
        });

        /**
         * Event listener which filters the html tags from the number value.
         */
        me.cellEditor.on('beforeedit', function(editor, e) {
            if(e.field === 'details.number') {

                // We need to defer the function call to make sure that the editor is rendered
                // and the value is loaded.
                Ext.defer(function() {

                    editor.editors.each(function(ed) {
                        ed.validationRequestParam = e.record.get('id');
                        ed.setValue(e.record.get('number'));
                    });
                }, 50);
            }
        }, me);

        return me.cellEditor;
    },

    /**
     * Called when the user creates the variants. This function recreates the grid columns.
     */
    refreshColumns: function() {
        var me = this;
        me.getSelectionModel().deselectAll();
        me.reconfigure(me.getStore(), me.getColumns());
    },

    /**
     * Defines additional events which will be fired from the component
     *
     * @return void
     */
    registerEvents:function () {
        this.addEvents(
            /**
             * Event will be fired when the user clicks the delete button in the toolbar or
             * use the action column of the grid to remove one or multiple variants
             * @event deleteVariant
             * @param [array] Record - The selected records
             */
            'deleteVariant',

            /**
             * @event saveVariant
             */
            'saveVariant',

            /**
             * Event will be fired when the user insert a value into the search field of the toolbar
             * to filter the listing.
             * @event searchVariants
             */
            'searchVariants',

            /**
             * Event will be fired when the user clicks on the edit action column of the
             * grid, to edit a single variant.
             * @event editVariant
             * @param [Ext.data.Model] Record - The selected record
             */
            'editVariant',

            /**
             * Event will be fired when the user clicks the "generate order numbers" button in the
             * toolbar to create new article order numbers.
             * @event generateOrderNumbers
             */
            'generateOrderNumbers',

            /**
             * Event will be fired when the user clicks the "apply standard prices" button in the toolbar
             * to apply the standard prices for all article variants.
             * @event applyPrices
             */
            'applyData',

            /**
             * Event will be fired over the row editor update button.
             * @event saveVariants
             */
            'editVariantPrice',

            /**
             * Event will be fired over the save button if the user is on the configurator tab.
             * Fired from the detail.window component
             * @event createVariants
             */
            'createVariants',

            /**
             * Event will be fired over the save button if the user is on the settings tab.
             * Fired from the detail.window component
             * @event saveSettings
             */
            'saveSettings'
        );
    },

    /**
     * Creates the grid columns
     *
     * @return [array] grid columns
     */
    getColumns: function () {
        var me = this, standardColumns, columns = [];

        standardColumns = [
            {
                header: me.snippets.columns.stock,
                dataIndex: 'inStock',
                sortable: false,
                flex: 1,
                renderer: me.stockColumnRenderer,
                editor: {
                    xtype: 'numberfield',
                    allowBlank: true,
                    allowDecimals: false
                }
            } ,{
                header: me.snippets.columns.price.header,
                dataIndex: 'price',
                sortable: false,
                flex: 1,
                renderer: me.priceColumnRenderer,
                editor: {
                    xtype: 'numberfield',
                    allowBlank: false,
                    decimalSeparator: ',',
                    decimalPrecision: 2
                }
            } , {
                header: me.snippets.columns.standard,
                dataIndex: 'standard',
                sortable: false,
                flex: 1,
                editor: {
                    xtype: 'checkbox',
                    inputValue: true,
                    uncheckedValue: false
                }
            } , {
                header: me.snippets.columns.active,
                dataIndex: 'active',
                sortable: false,
                flex: 1,
                editor: {
                    xtype: 'checkbox',
                    inputValue: true,
                    uncheckedValue: false
                }
            } ,
            {
                /**
                 * Special column type which provides clickable icons in each row
                 */
                xtype:'actioncolumn',
                width:70,
                items:[
                    {
                        iconCls:'sprite-minus-circle-frame',
                        action:'deleteVariant',
                        tooltip:me.snippets.columns.remove,
                        handler: function (view, rowIndex, colIndex, item, opts, record) {
                            var records = [ record ];
                            me.fireEvent('deleteVariant', records);
                        }
                    } , {
                        iconCls:'sprite-pencil',
                        action:'editVariant',
                        tooltip:me.snippets.columns.edit,
                        handler:function (view, rowIndex, colIndex, item, opts, record) {
                            me.fireEvent('editVariant', record);
                        }
                    }
                ]
            }
        ];

        columns.push({
            header: me.snippets.columns.number,
            dataIndex: 'details.number',
            sortable: true,
            flex:1,
            align: 'left',
            renderer: me.numberColumnRenderer,
            editor: {
                allowBlank: false
            }
        });
        columns = columns.concat(me.createDynamicColumns());
        columns = columns.concat(standardColumns);
        return columns;
    },

    /**
     * Creates the grid columns for the dynamic configurator groups.
     * @return [array] An array of column objects.
     */
    createDynamicColumns: function() {
        var me = this, columns = [], column;

        me.configuratorGroupStore.each(function(group) {
            if (group.get('active')) {
                columns.push(
                    {
                        header: group.get('name'),
                        dataIndex: 'configuratorOptions.name',
                        sortable: false,
                        flex: 1,
                        configuratorGroup: group,
                        renderer: me.configuratorGroupColumnRenderer
                    }
                );
            }
        });

        return columns;
    },

    /**
     * Renderer function of the price column. If a scale price defined, the function returns the first price value
     * with an additional flag "from*" to display the user that this variant has scale prices.
     * @param value
     * @param metaData
     * @param record
     */
    priceColumnRenderer: function(value, metaData, record) {
        var me = this,
            prices = record.getPrice();

        if (prices.getCount() === 0) {
            return me.snippets.columns.price.undefined;
        } else {
            var firstPrice = prices.first();
            if (prices.getCount() === 1) {
                return Ext.util.Format.currency(firstPrice.get('price'));
            } else {
                return me.snippets.columns.price.from + ' ' + Ext.util.Format.currency(firstPrice.get('price'));
            }
        }
    },

    /**
     * Renderer function of the number column.
     * @param value
     * @param metaData
     * @param record
     */
    numberColumnRenderer: function(value, metaData, record) {
        if (record) {
            return record.get('number');
        } else {
            return '';
        }
    },
    /**
     * Renderer function of the stock column.
     * @param value
     * @param metaData
     * @param record
     */
    stockColumnRenderer: function(value, metaData, record) {
        if (record) {
            return record.get('inStock');
        } else {
            return '';
        }
    },

    /**
     * Renderer function for each configurator group column
     */
    configuratorGroupColumnRenderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
        var me = this;
        var column = me.columns[colIndex];
        var options = record.getConfiguratorOptions();

        if (column && options) {
            var configuratorGroup = column.configuratorGroup;
            var currentOption = null;
            options.each(function(option) {
                if (option.get('groupId') === configuratorGroup.get('id')) {
                    currentOption = option;
                    return;
                }
            });
            if (currentOption !== null) {
                return currentOption.get('name');
            }
        }
        return '';
    },

    /**
     * Creates the grid selection model for checkboxes
     *
     * @return [Ext.selection.CheckboxModel] grid selection model
     */
    getGridSelModel:function () {
        var me = this;

        return Ext.create('Ext.selection.CellModel');
    },

    /**
     * Creates the grid toolbar with the different buttons.
     * @return [Ext.toolbar.Toolbar] grid toolbar
     */
    getToolbar:function () {
        var me = this;

        //creates the price button to apply the standard prices of the main article on all variants.
        me.applyDataButton = Ext.create('Ext.button.Button', {
            iconCls:'sprite-money--arrow',
            text: me.snippets.toolbar.data,
            action: 'applyData',
            handler: function() {
                me.fireEvent('applyData');
            }
        });

        //creates the text field for the order number syntax.
        me.orderNumberField = Ext.create('Ext.form.field.Text', {
            emptyText: me.snippets.toolbar.orderNumber.empty,
            fieldLabel: me.snippets.toolbar.orderNumber.label,
            flex: 1,
            name: 'numberSyntax'
        });

        //creates the button to regenerate all order numbers for the article variants.
        me.orderNumberButton = Ext.create('Ext.button.Button', {
            iconCls: 'sprite-key--arrow',
            text: me.snippets.toolbar.orderNumber.button,
            action: 'generateOrderNumbers',
            handler: function() {
                me.fireEvent('generateOrderNumbers', me.orderNumberField);
            }
        });

        //creates the search field to filter the listing.
        me.searchField = Ext.create('Ext.form.field.Text', {
            name:'searchfield',
            cls:'searchfield',
            width:170,
            emptyText:me.snippets.toolbar.search,
            enableKeyEvents:true,
            checkChangeBuffer:500,
            listeners: {
                change: function(field, value) {
                    me.fireEvent('searchVariants', value);
                }
            }
        });

        return Ext.create('Ext.toolbar.Toolbar', {
            dock:'top',
            ui: 'shopware-ui',
            cls: 'shopware-toolbar',
            items:[
                me.applyDataButton,
                { xtype:'tbspacer', width: 6 },
                { xtype: 'tbseparator' },
                { xtype:'tbspacer', width: 6 },
                me.orderNumberField,
                { xtype:'tbspacer', width: 6 },
                me.orderNumberButton,
                '->',
                me.searchField,
                { xtype:'tbspacer', width:6 }
            ]
        });
    },

    /**
     * Creates the paging toolbar for the grid to allow store paging. The paging toolbar uses the same store as the Grid
     *
     * @return Ext.toolbar.Paging The paging toolbar for the customer grid
     */
    getPagingBar:function () {
        var me = this;

        return Ext.create('Ext.toolbar.Paging', {
            store: me.store,
            dock:'bottom',
            displayInfo:true
        });
    }

});
//{/block}

<|endoftext|>


<commit_before>/**
 * Results formatter
 */
module.exports = function(results, format) {
	function render() {
		switch(format) {
			case 'json':
				return formatJson();

			case 'csv':
				return formatCsv();

			default:
			case 'plain':
				return formatPlain();
		}
	}

	function formatJson() {
		return JSON.stringify(results);
	}

	function formatCsv() {
		var obj = results.metrics,
			key,
			keys = [],
			values = [];

		for (key in obj) {
			keys.push(key);
			values.push(obj[key]);
		}

		return keys.join(',') + "\n" + values.join(',');
	}

	function formatPlain() {
		var colors = require('ansicolors'),
			res = '',
			metrics = results.metrics;

		// header
		res += 'phantomas metrics for <' + results.url + '>:\n\n';

		// metrics
		Object.keys(metrics).forEach(function(metric) {
			res += '* ' + metric + ': ' + metrics[metric]+ '\n';
		});

		res += '\n';

		// notices
		results.notices.forEach(function(msg) {
			msg = msg.
				// color labels
				replace(/^[^ <][^:<]+:/, colors.brightGreen).
				// color URLs
				replace(/<[^>]+>/, colors.brightBlue);

			// add a notice
			res += msg + "\n";
		});

		res += '\n';

		// errors
		results.jsErrors.forEach(function(msg) {
			msg = msg.replace(/^[^ <].*/, colors.brightRed);
			res += msg + "\n";
		});

		res += '\n';

		return res.trim();
	}

	// public interface
	this.render = render;
};
<commit_msg>formatter: support multiple URLs<commit_after>/**
 * Results formatter
 */
module.exports = function(results, format) {
	function render() {
		switch(format) {
			case 'json':
				return formatJson();

			case 'csv':
				return formatCsv();

			default:
			case 'plain':
				return formatPlain();
		}
	}

	function formatJson() {
		return JSON.stringify(results);
	}

	function formatCsv() {
		var obj = results.metrics,
			key,
			keys = [],
			values = [];

		for (key in obj) {
			keys.push(key);
			values.push(obj[key]);
		}

		return keys.join(',') + "\n" + values.join(',');
	}

	function formatPlain() {
		var colors = require('ansicolors'),
			res = '',
			metrics = results.metrics;

		// header
		res += 'phantomas metrics for <' + results.url + '>:\n\n';

		// metrics
		Object.keys(metrics).forEach(function(metric) {
			res += '* ' + metric + ': ' + metrics[metric]+ '\n';
		});

		res += '\n';

		// notices
		results.notices.forEach(function(msg) {
			msg = msg.
				// color labels
				replace(/^[^ <][^:<]+:/, colors.brightGreen).
				// color URLs
				replace(/<[^>]+>/g, colors.brightBlue);

			// add a notice
			res += msg + "\n";
		});

		res += '\n';

		// errors
		results.jsErrors.forEach(function(msg) {
			msg = msg.replace(/^[^ <].*/, colors.brightRed);
			res += msg + "\n";
		});

		res += '\n';

		return res.trim();
	}

	// public interface
	this.render = render;
};
<|endoftext|>


<commit_before>/**
Name : NodeJS Custom CLI Module - Project Generator Template
Author:  Dilusha Gonagala
License : MIT
Version : 1.0
**/

//Module Dependencies
var fs = require('fs-extra');
var child_process = require('child_process');
var path = require("path");
var packages = require("./packages");

module.exports = {

  generate: function(projecttype, projectname) {

    if (!projecttype == undefined || !projecttype == "" && !projectname == undefined || !projectname == "") {

      //AngularSimple Generator
      if (projecttype == "angularsimple") {

        //Create directory with the user's given project name on the current cli path
        fs.mkdirs('./' + projectname + '', function(err) {
          if (err) {
            // console.error(err);
          } else {

            fs.writeFile("./" + projectname + "/README.MD", "Generated By GenSimple", function(err) {
              if (err) {
                // console.log(err);
              }
              // We now know that evrything is smooth
              else {
                // console.log(__dirname);
                var dirname = path.resolve(__dirname);
                // console.log(path.resolve(__dirname))

                var dirstr = dirname.substr(dirname.lastIndexOf('/') + 1) + '$',
                  fixedurl = dirname.replace(new RegExp(dirstr), '');

                fs.copy(fixedurl + '/templates/angularsimple/', "./" + projectname + "", function(err) {
                  if (err) {
                    console.error(err)
                  } else {

                    var currentDir = process.cwd(), totdalPackageCount =packages.angularsimple.packages.length,
                    installedPackageCount=0 ;

                    for (var i = 0; i < packages.angularsimple.packages.length; i++) {

                      var packagenpm = packages.angularsimple.packages[i];
                      console.log("Installing Dependencies..." + packagenpm);
                      child_process.exec(["npm install --prefix ./" + projectname + " " + packagenpm + ""], function(err, out, code) {
                        if (err instanceof Error) {
                          throw err;
                        } else {
                          installedPackageCount ++;
                          if(totdalPackageCount == installedPackageCount){

                            console.log("Success ! Your AngularSimple App Is up And Running on http://localhost:5000");
                            child_process.exec(["node ./" + projectname + "/server.js"], function(err, out, code) {
                              if (err instanceof Error) {
                                console.log(err);
                                throw err;
                              }

                            });
                          }
                        }

                      });

                    }

                  }

                });

              }

            });

          }

        });

      }

    }

  }

}
<commit_msg>Express Commit<commit_after>/**
Name : NodeJS Custom CLI Module - Project Generator Template
Author:  Dilusha Gonagala
License : MIT
Version : 1.0
**/

//Module Dependencies
var fs = require('fs-extra');
var child_process = require('child_process');
var path = require("path");
var packages = require("./packages");

module.exports = {

  generate: function(projecttype, projectname) {

    if (!projecttype == undefined || !projecttype == "" && !projectname == undefined || !projectname == "") {

      //AngularSimple Generator
      if (projecttype == "angularsimple") {

        //Create directory with the user's given project name on the current cli path
        fs.mkdirs('./' + projectname + '', function(err) {
          if (err) {
            // console.error(err);
          } else {

            fs.writeFile("./" + projectname + "/README.MD", "Generated By GenSimple", function(err) {
              if (err) {
                // console.log(err);
              }
              // We now know that evrything is smooth
              else {
                //  console.log(__dirname);
                //  console.log(__filename);
                var dirname = path.resolve(__dirname);
                // console.log(path.resolve(__dirname))

                var dirstr = dirname.substr(dirname.lastIndexOf('/') + 1) + '$',
                  fixedurl = dirname.replace(new RegExp(dirstr), '');

                fs.copy(fixedurl + '/templates/angularsimple/', "./" + projectname + "", function(err) {
                  if (err) {
                    console.error(err)
                  } else {

                    var currentDir = process.cwd(), totdalPackageCount =packages.angularsimple.packages.length,
                    installedPackageCount=0 ;

                    for (var i = 0; i < packages.angularsimple.packages.length; i++) {

                      var packagenpm = packages.angularsimple.packages[i];
                      console.log("Installing Dependency..." + packagenpm);
                      child_process.exec(["npm install --prefix ./" + projectname + " " + packagenpm + ""], function(err, out, code) {
                        if (err instanceof Error) {
                          throw err;
                        } else {
                          installedPackageCount ++;
                          if(totdalPackageCount == installedPackageCount){

                            console.log("Success ! Your AngularSimple App Is up And Running on http://localhost:5000");
                            child_process.exec(["node ./" + projectname + "/server.js"], function(err, out, code) {
                              if (err instanceof Error) {
                                console.log(err);
                                throw err;
                              }

                            });
                          }
                        }

                      });

                    }

                  }

                });

              }

            });

          }

        });

      }

    }

  }

}
<|endoftext|>