<commit_before>/* $Id$
 *
 * Include JS file for Tiki 7 Theme Generator
 */

$(document).ready( function() {
	// colorpicker for the colour swatches

	{	// closure for colorpicker code
		// expose options for event fns
		var colorSelector = ".colorSelector > div";
		var colorInput = "input.tgValue";

		var colorPickerListItem = null;		// still sort of globals really
		var colorPickerPreviews = null;		// need to know what was clicked from "inside" colorpicker

		var opts = {
			color: '#888',
			onBeforeShow: function () {
				colorPickerListItem = $(this).parent();	 // store for later (maybe there's a better way?)

				var c = $.trim($(colorInput, colorPickerListItem).val());
				var m = c.match(/^#([0-9A-F]{3})$/i);	// check for only 3 hex chars
				if (m) {
					c = c[0]+c[1]+c[1]+c[2]+c[2]+c[3]+c[3];	// double 'em
				}
				$(this).ColorPickerSetColor(c);

				if ($(".tgLivePreview:checked", $(colorPickerListItem).parent().parent()).length) {
					m = $(colorInput, colorPickerListItem).attr("name");
					m = m.match(/\[(.*?)\]/);	// colour type
					if (m) { m = m[1]; }
					if (m === "fgcolors") {
						m = ["color"];
					} else if (m === "bgcolors") {
						m = ["background-color"];
					} else if (m === "bordercolors") {
						m = ["border-top-color", "border-right-color", "border-bottom-color", "border-left-color", "border-color", "border"];
					}
					colorPickerPreviews = [];
					var zall = $(":visible");
					for (var t in m) {
						for (var i = 0; i < zall.length; i++) {
							var $el = $(zall[i]);
							if ($el.length && $el.css(m[t]) && $.Color($el.css(m[t])).toHEX() == c) {
								colorPickerPreviews.push( [ m[t], $el[0] ] );
							}
						}
					}
				} else {
					colorPickerPreviews = null;
				}
			},
			onShow: function (colpkr) {
				$(colpkr).fadeIn(500);
				return false;
			},
			onHide: function (colpkr) {
				colorPickerListItem = null;
				$(colpkr).fadeOut(500);
				return false;
			},
			onChange: function (hsb, hex, rgb) {
				if (colorSelector) {
					$(colorSelector, colorPickerListItem).css('backgroundColor', '#' + hex);
				}
				if (colorInput) {
					$(colorInput, colorPickerListItem).val('#' + hex);
				}
				$(colorPickerListItem).addClass('changed');

				if ($(".tgLivePreview:checked", $(colorPickerListItem).parent().parent()).length) {
					$(colorPickerPreviews).each(function () {
						$(this[1]).css( this[0], '#' + hex);
					});
				}
			}
		};	// end opts for colorpicker

		$(".tgItem > div", "#tg_section_colors").each(function() {
			var colorItem = this;
			$(this).ColorPicker(opts);
		});

	}

	// checkboxes to select items
	$(".tgItems :checkbox").click(function(e, flip) {
		if ($(this).attr("checked") && !flip) { // flip trickery to get trigger to toggle the right classes
			$(this).parent().addClass("selected");
		} else if ((!$(this).attr("checked") && !flip) || flip) {
			$(this).parent().removeClass("selected");
		}
	});

	// reset button fn
	$(".tgResetSection").click(function() {
		var container = $(this).parent().nextAll("ul");
		$(".tgItem :checkbox:checked", container).each(function() {
			$(this).parent().find("input.tgValue").val($(this).val());
			$(this).parent().find(".colorSelector > div").css("background-color", $(this).val());
			$(this).trigger("click", [true]);
			//$(this).parent().removeClass("selected");
		});
		return false;
	});

	// select modified colours
	$(".tgToggleChanged").click(function() {
		var container = $(this).parent().nextAll("ul");
		$(".tgItem", container).each(function() {
			if ($("input.tgValue", this).val() !== $("input[type=checkbox]", this).val()) {
				$(this).find("input[type=checkbox]").trigger("click", [true]);
			}
		});
	});

	// toggle selection
	$(".tgToggle").click(function() {
		var container = $(this).parent().nextAll("ul");
		$("input[type=checkbox]", container).trigger("click", [true]);
	});

	if (jqueryTiki.ui) {
		$(".themegenerator").tabs();
	}

	// disable for now
	$("input[type=checkbox].tgLivePreview", "#tg_section_typeography")
		.attr("checked", "")
		.attr("disabled", "disabled");

});
<commit_msg>[FIX] themegen: Add/remove selected toggle logic fix (can this be done in 2 clauses?)<commit_after>/* $Id$
 *
 * Include JS file for Tiki 7 Theme Generator
 */

$(document).ready( function() {
	// colorpicker for the colour swatches

	{	// closure for colorpicker code
		// expose options for event fns
		var colorSelector = ".colorSelector > div";
		var colorInput = "input.tgValue";

		var colorPickerListItem = null;		// still sort of globals really
		var colorPickerPreviews = null;		// need to know what was clicked from "inside" colorpicker

		var opts = {
			color: '#888',
			onBeforeShow: function () {
				colorPickerListItem = $(this).parent();	 // store for later (maybe there's a better way?)

				var c = $.trim($(colorInput, colorPickerListItem).val());
				var m = c.match(/^#([0-9A-F]{3})$/i);	// check for only 3 hex chars
				if (m) {
					c = c[0]+c[1]+c[1]+c[2]+c[2]+c[3]+c[3];	// double 'em
				}
				$(this).ColorPickerSetColor(c);

				if ($(".tgLivePreview:checked", $(colorPickerListItem).parent().parent()).length) {
					m = $(colorInput, colorPickerListItem).attr("name");
					m = m.match(/\[(.*?)\]/);	// colour type
					if (m) { m = m[1]; }
					if (m === "fgcolors") {
						m = ["color"];
					} else if (m === "bgcolors") {
						m = ["background-color"];
					} else if (m === "bordercolors") {
						m = ["border-top-color", "border-right-color", "border-bottom-color", "border-left-color", "border-color", "border"];
					}
					colorPickerPreviews = [];
					var zall = $(":visible");
					for (var t in m) {
						for (var i = 0; i < zall.length; i++) {
							var $el = $(zall[i]);
							if ($el.length && $el.css(m[t]) && $.Color($el.css(m[t])).toHEX() == c) {
								colorPickerPreviews.push( [ m[t], $el[0] ] );
							}
						}
					}
				} else {
					colorPickerPreviews = null;
				}
			},
			onShow: function (colpkr) {
				$(colpkr).fadeIn(500);
				return false;
			},
			onHide: function (colpkr) {
				colorPickerListItem = null;
				$(colpkr).fadeOut(500);
				return false;
			},
			onChange: function (hsb, hex, rgb) {
				if (colorSelector) {
					$(colorSelector, colorPickerListItem).css('backgroundColor', '#' + hex);
				}
				if (colorInput) {
					$(colorInput, colorPickerListItem).val('#' + hex);
				}
				$(colorPickerListItem).addClass('changed');

				if ($(".tgLivePreview:checked", $(colorPickerListItem).parent().parent()).length) {
					$(colorPickerPreviews).each(function () {
						$(this[1]).css( this[0], '#' + hex);
					});
				}
			}
		};	// end opts for colorpicker

		$(".tgItem > div", "#tg_section_colors").each(function() {
			var colorItem = this;
			$(this).ColorPicker(opts);
		});

	}

	// checkboxes to select items
	$(".tgItems :checkbox").click(function(e, flip) {
		if (flip) {
			if (!$(this).attr("checked")) { // flip trickery to get trigger to toggle the right classes
				$(this).parent().addClass("selected");
			} else {
				$(this).parent().removeClass("selected");
			}
		} else {
			if ($(this).attr("checked")) { // flip trickery to get trigger to toggle the right classes
				$(this).parent().addClass("selected");
			} else {
				$(this).parent().removeClass("selected");
			}
		}
	});

	// reset button fn
	$(".tgResetSection").click(function() {
		var container = $(this).parent().nextAll("ul");
		$(".tgItem :checkbox:checked", container).each(function() {
			$(this).parent().find("input.tgValue").val($(this).val());
			$(this).parent().find(".colorSelector > div").css("background-color", $(this).val());
			$(this).trigger("click", [true]);
			//$(this).parent().removeClass("selected");
		});
		return false;
	});

	// select modified colours
	$(".tgToggleChanged").click(function() {
		var container = $(this).parent().nextAll("ul");
		$(".tgItem", container).each(function() {
			if ($("input.tgValue", this).val() !== $("input[type=checkbox]", this).val()) {
				$(this).find("input[type=checkbox]").trigger("click", [true]);
			}
		});
	});

	// toggle selection
	$(".tgToggle").click(function() {
		var container = $(this).parent().nextAll("ul");
		$("input[type=checkbox]", container).trigger("click", [true]);
	});

	if (jqueryTiki.ui) {
		$(".themegenerator").tabs();
	}

	// disable for now
	$("input[type=checkbox].tgLivePreview", "#tg_section_typeography")
		.attr("checked", "")
		.attr("disabled", "disabled");

});
<|endoftext|>


<commit_before>/**
 * Created by Sebastian on 2016-08-24.
 */

document.addEventListener('DOMSubtreeModified', function(e) {
    if(document.getElementsByClassName("page-title__content__title__primary page-title__content__title__primary--text-transform-none")[0].textContent.length > 0){
        updateStats()
    }
});

function updateStats() {
    var statsFind = new XMLHttpRequest();
    statsFind.onload = function () {
        console.log("i statsFind");
        var json = JSON.parse(statsFind.responseText);
        var leagues = json.payload.leagues;

        var leagueOut = leagues[0].rank_label + " / " + leagues[1].rank_label;
        var rankOut = leagues[0].ladder.user_rank.rank + " / " + leagues[1].ladder.user_rank.rank;
        var pointsOut = leagues[0].ladder.user_rank.points + " / " + leagues[1].ladder.user_rank.points;

        var leaugeField = document.getElementsByClassName("stat__detail__value")[3].getElementsByTagName("span")[0];
        var rankField = document.getElementsByClassName("stat__detail__value")[4].getElementsByTagName("span")[0];
        var pointsField = document.getElementsByClassName("stat__detail__value")[5].getElementsByTagName("span")[0];

        leaugeField.innerHTML = leagueOut;
        rankField.innerHTML = rankOut;
        pointsField.innerHTML = pointsOut;

    };

    var userName = document.getElementsByClassName("page-title__content__title__primary page-title__content__title__primary--text-transform-none")[0].textContent;

    console.log("username: " + userName);

    var userFind = new XMLHttpRequest();
    userFind.onload = function () {

        var json = JSON.parse(userFind.responseText);
        console.log(json);
        json.payload.forEach(function (user) {

            if (user.name = userName) {
                var statsData = user.guid + "/games/csgo/league?region=EU";
                statsFind.open('GET', "https://api.faceit.com/api/users/" + statsData);
                statsFind.send();

            }
        });
    };

    var userData = "q=" + userName + "&rows=1&sortBy=nickname&start=0";
    userFind.open('GET', "https://api.faceit.com/search/v1/players?" + userData);
    console.log('Innan send: ' + "https://api.faceit.com/search/v1/players?" + userData);
    userFind.send();

};<commit_msg>remove prints<commit_after>/**
 * Created by Sebastian on 2016-08-24.
 */

document.addEventListener('DOMSubtreeModified', function(e) {
    if(document.getElementsByClassName("page-title__content__title__primary page-title__content__title__primary--text-transform-none")[0].textContent.length > 0){
        updateStats()
    }
});

function updateStats() {
    var statsFind = new XMLHttpRequest();
    statsFind.onload = function () {
        var json = JSON.parse(statsFind.responseText);
        var leagues = json.payload.leagues;

        var leagueOut = leagues[0].rank_label + " / " + leagues[1].rank_label;
        var rankOut = leagues[0].ladder.user_rank.rank + " / " + leagues[1].ladder.user_rank.rank;
        var pointsOut = leagues[0].ladder.user_rank.points + " / " + leagues[1].ladder.user_rank.points;

        var leaugeField = document.getElementsByClassName("stat__detail__value")[3].getElementsByTagName("span")[0];
        var rankField = document.getElementsByClassName("stat__detail__value")[4].getElementsByTagName("span")[0];
        var pointsField = document.getElementsByClassName("stat__detail__value")[5].getElementsByTagName("span")[0];

        leaugeField.innerHTML = leagueOut;
        rankField.innerHTML = rankOut;
        pointsField.innerHTML = pointsOut;

    };

    var userName = document.getElementsByClassName("page-title__content__title__primary page-title__content__title__primary--text-transform-none")[0].textContent;

    var userFind = new XMLHttpRequest();
    userFind.onload = function () {

        var json = JSON.parse(userFind.responseText);
        json.payload.forEach(function (user) {

            if (user.name = userName) {
                var statsData = user.guid + "/games/csgo/league?region=EU";
                statsFind.open('GET', "https://api.faceit.com/api/users/" + statsData);
                statsFind.send();

            }
        });
    };

    var userData = "q=" + userName + "&rows=1&sortBy=nickname&start=0";
    userFind.open('GET', "https://api.faceit.com/search/v1/players?" + userData);
    userFind.send();

};<|endoftext|>


<commit_before>Gather.Views.Select2View = Backbone.View.extend({

  initialize: function(options) {
    var self = this;
    this.options = options;
    this.options.extra_data = this.options.extra_data || {};

    this.$el.on('cocoon:after-insert', function(e, inserted) {
      console.log("after insert")
      self.setup_select2($(inserted).find("select[data-select2-src]"));
    });

    this.$('select[data-select2-src]').each(function() {
      self.setup_select2($(this));
    });
  },

  setup_select2: function(el) {
    var src = el.data("select2-src");
    var label_attr = el.data("select2-label-attr") || "name";
    var variable_width = !!el.data("select2-variable-width");
    var self = this;

    el.select2({
      ajax: {
        url: "/" + src,
        dataType: 'json',
        delay: 250,
        data: function (params) {
          return $.extend(self.options.extra_data, {
            search: params.term,
            page: params.page,
            context: el.data("select2-context")
          });
        },
        processResults: function (data, page) {
          return {
            results: data.results.map(function(u){ return {id: u.id, text: u[label_attr]}; }),
            pagination: { more: data.meta.more }
          }
        },
        cache: true
      },
      language: {
        inputTooShort: function() {
          return el.data("select2-prompt");
        }
      },
      minimumInputLength: 1,
      width: variable_width ? null : '100%'
    });
  }
});
<commit_msg>5138: Removed old console log<commit_after>Gather.Views.Select2View = Backbone.View.extend({

  initialize: function(options) {
    var self = this;
    this.options = options;
    this.options.extra_data = this.options.extra_data || {};

    this.$el.on('cocoon:after-insert', function(e, inserted) {
      self.setup_select2($(inserted).find("select[data-select2-src]"));
    });

    this.$('select[data-select2-src]').each(function() {
      self.setup_select2($(this));
    });
  },

  setup_select2: function(el) {
    var src = el.data("select2-src");
    var label_attr = el.data("select2-label-attr") || "name";
    var variable_width = !!el.data("select2-variable-width");
    var self = this;

    el.select2({
      ajax: {
        url: "/" + src,
        dataType: 'json',
        delay: 250,
        data: function (params) {
          return $.extend(self.options.extra_data, {
            search: params.term,
            page: params.page,
            context: el.data("select2-context")
          });
        },
        processResults: function (data, page) {
          return {
            results: data.results.map(function(u){ return {id: u.id, text: u[label_attr]}; }),
            pagination: { more: data.meta.more }
          }
        },
        cache: true
      },
      language: {
        inputTooShort: function() {
          return el.data("select2-prompt");
        }
      },
      minimumInputLength: 1,
      width: variable_width ? null : '100%'
    });
  }
});
<|endoftext|>


<commit_before>import React from "react";

import XYGraph from "../XYGraph";

import * as d3 from "d3";

import "./style.css";

import { properties } from "./default.config"

import { nest, nestStack, nestSum, limit } from "../../../utils/helpers"

// TODO split out this time interval log into a utility module.

// Time unit abbreviations from
// https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#time-units
// mapping onto D3 time intervals defined ad
// https://github.com/d3/d3-time#intervals
const timeAbbreviations = {
    "y": "utcYear",
    "M": "utcMonth",
    "w": "utcWeek",
    "d": "utcDay",
    "h": "utcHour",
    "m": "utcMinute",
    "s": "utcSecond",
    "ms": "utcMillisecond"
}

function computeBarWidth(interval, timeScale) {
    const step = +interval.substr(0, interval.length - 1);

    // TODO handle case of "ms"
    const abbreviation = interval.substr(interval.length - 1);
    const d3Interval = timeAbbreviations[abbreviation];

    // TODO validation and error handling
    const start = new Date(2000, 0, 0, 0, 0);
    const end = d3[d3Interval].offset(start, step);

    return timeScale(end) - timeScale(start);
}

export default class BarGraph extends XYGraph {

    constructor(props) {
        super(props, properties);
    }

    render() {

        const {
            data,
            width,
            height,
            onMarkClick
        } = this.props;

        if (!data || !data.length)
            return;

        const {
          chartHeightToPixel,
          chartWidthToPixel,
          circleToPixel,
          colorColumn,
          colors,
          dateHistogram,
          interval,
          legend,
          margin,
          orientation,
          padding,
          stroke,
          xColumn,
          xLabel,
          xTickFormat,
          xTickGrid,
          xTicks,
          xTickSizeInner,
          xTickSizeOuter,
          yColumn,
          yTickFormat,
          yTickGrid,
          yTicks,
          yTickSizeInner,
          yTickSizeOuter,
          otherOptions,
          stackColumn
        } = this.getConfiguredProperties();

        const vertical = orientation  === "vertical";

        let dimension, metric;

        if (vertical) {
          dimension = xColumn
          metric = yColumn
        } else {
          dimension = yColumn
          metric = xColumn
        }

        let stack = stackColumn || dimension

        let nestedData = nestStack({
            data: limit({
              data: nestSum({
                data: nest({
                    data,
                    key: dimension,
                    sortColumn: stack
                }),
                stackColumn: metric
              }),
              limitOption: Object.assign ({
                fields: [
                  {
                    type: 'array',
                    name: 'values',
                    groups: [stack],
                    metrics: metric
                  }
                ]}
                , otherOptions || {}
              )
            }),
            stackColumn: metric
        })

        const isVerticalLegend = legend.orientation === 'vertical';

        const xLabelFn         = (d) => d[xColumn];
        const yLabelFn         = (d) => d[yColumn];

        const stackLabelFn     = (d) => d[stack];

        const metricFn         = (d) => d.total
        const dimensionFn      = (d) => d.key

        const scale            = this.scaleColor(data, stack);

        const getColor         = (d) => scale ? scale(d[colorColumn || stack]) : colors[0];

        let xAxisHeight       = xLabel ? chartHeightToPixel : 0;

        let xAxisLabelWidth   = this.longestLabelLength(data, xLabelFn, xTickFormat) * chartWidthToPixel;
        let yAxisLabelWidth   = this.longestLabelLength(data, yLabelFn, yTickFormat) * chartWidthToPixel;

        let overAllAvailableWidth = width - (margin.left + margin.right);
        let maxWidthPercentage = 0.20;
        let trucatedYAxisWidth = ((overAllAvailableWidth * maxWidthPercentage) < yAxisLabelWidth ? (overAllAvailableWidth * maxWidthPercentage) : yAxisLabelWidth);

        let leftMargin        = margin.left + trucatedYAxisWidth;
        let availableWidth    = overAllAvailableWidth - trucatedYAxisWidth;
        let availableHeight   = height - (margin.top + margin.bottom + chartHeightToPixel + xAxisHeight);

        let legendWidth = this.longestLabelLength(data, stackLabelFn) * chartWidthToPixel;

        if (legend.show)
        {
            legend.width = legendWidth

            // Compute the available space considering a legend
            if (isVerticalLegend)
            {
                leftMargin      +=  legend.width;
                availableWidth  -=  legend.width;
            }
            else {
                const nbElementsPerLine  = parseInt(availableWidth / legend.width, 10);
                const nbLines            = parseInt(data.length / nbElementsPerLine, 10);
                availableHeight         -= nbLines * legend.circleSize * circleToPixel + chartHeightToPixel;
            }
        }

        let xScale, yScale;

        if (dateHistogram) {

            // Handle the case of a vertical date histogram.
            xScale = d3.scaleTime()
              .domain(d3.extent(nestedData, dimensionFn))

            yScale = d3.scaleLinear()
              .domain([0, d3.max(nestedData, metricFn)])

        } else if (vertical) {

            // Handle the case of a vertical bar chart.
            xScale = d3.scaleBand()
              .domain(nestedData.map(dimensionFn))
              .padding(padding)

            yScale = d3.scaleLinear()
              .domain([0, d3.max(nestedData, metricFn)])

        } else {
            // Handle the case of a horizontal bar chart.
            xScale = d3.scaleLinear()
              .domain([0, d3.max(nestedData, metricFn)])

            yScale = d3.scaleBand()
              .domain(nestedData.map(dimensionFn))
              .padding(padding)
        }

        xScale.range([0, availableWidth]);
        yScale.range([availableHeight, 0]);

        const xAxis = d3.axisBottom(xScale)
          .tickSizeInner(xTickGrid ? -availableHeight : xTickSizeInner)
          .tickSizeOuter(xTickSizeOuter);

        if(xTickFormat) {
            xAxis.tickFormat(d3.format(xTickFormat))
        }

        if(xTicks){
            xAxis.ticks(xTicks);
        }

        const yAxis = d3.axisLeft(yScale)
          .tickSizeInner(yTickGrid ? -availableWidth : yTickSizeInner)
          .tickSizeOuter(yTickSizeOuter);

        if(yTickFormat){
            yAxis.tickFormat(d3.format(yTickFormat));
        }

        if(yTicks){
            yAxis.ticks(yTicks);
        }

        let barWidth;

        if(dateHistogram){
            barWidth = computeBarWidth(interval, xScale);
        } else if(vertical){
            barWidth = xScale.bandwidth();
        }

        let xTitlePosition = {
            left: leftMargin + availableWidth / 2,
            top: margin.top + availableHeight + chartHeightToPixel + xAxisHeight
        }
        let yTitlePosition = {
            // We use chartWidthToPixel to compensate the rotation of the title
            left: margin.left + chartWidthToPixel + (isVerticalLegend ? legend.width : 0),
            top: margin.top + availableHeight / 2
        }

        let xAxisGraph = <g
            key="xAxis"
            ref={ (el) => vertical
                  ? d3.select(el).call(xAxis)
                      .selectAll(".tick text")
                      .call(this.wrapD3Text, barWidth)
                  : d3.select(el).call(xAxis)
                      .selectAll(".tick text")
                }
            transform={ `translate(0, ${availableHeight})` }
        />

        let yAxisGraph = <g
            key="yAxis"
            ref={ (el) => ( !vertical && !dateHistogram)
                  ? d3.select(el).call(yAxis)
                      .selectAll(".tick text")
                      .call(this.wrapD3Text, yAxisLabelWidth)
                  : d3.select(el).call(yAxis)
                }
        />

        return (
            <div className="bar-graph">
                {this.tooltip}
                <svg
                    style={{
                        width: width,
                        height: height
                    }}
                    >
                    {this.axisTitles(xTitlePosition, yTitlePosition)}
                    <g transform={ `translate(${leftMargin},${margin.top})` } >
                        { xAxisGraph }
                        { yAxisGraph }
                        {
                            nestedData.map((nest, i) => {
                                return nest.values.map((d, i) => {
                                    // Compute rectangle depending on orientation (vertical or horizontal).

                                    const {
                                        x,
                                        y,
                                        width,
                                        height
                                    } = (
                                        vertical ? {
                                            x: xScale(nest.key),
                                            y: yScale(d.y1),
                                            width: barWidth,
                                            height: yScale(d.y0) - yScale(d.y1)
                                        } : {
                                            x: xScale(d.y0),
                                            y: yScale(nest.key),
                                            width: xScale(d.y1) - xScale(d.y0),
                                            height: yScale.bandwidth()
                                        }
                                    );

                                // Set up clicking and cursor style.
                                const { onClick, style } = (

                                    // If an "onMarkClick" handler is registered,
                                    onMarkClick && (!otherOptions || d[dimension] !== otherOptions.label) ? {

                                        // set it up to be invoked, passing the current data row object.
                                        onClick: () => onMarkClick(d),

                                        // Make the cursor a pointer on hover, as an affordance for clickability.
                                        style: { cursor: "pointer" }

                                    } : {
                                        // Otherwise, set onClick and style to "undefined".
                                    }
                                );

                                return (
                                    <rect
                                        x={ x }
                                        y={ y }
                                        width={ width }
                                        height={ height }
                                        fill={ getColor(d) }
                                        onClick={ onClick }
                                        style={ style }
                                        key={ i }
                                        stroke={ stroke.color }
                                        strokeWidth={ stroke.width }
                                        { ...this.tooltipProps(d) }
                                    />
                                )
                            })
                        })}
                    </g>
                    {this.renderLegend(data, legend, getColor, stackLabelFn)}
                </svg>
            </div>
        );
    }
}
BarGraph.propTypes = {
  configuration: React.PropTypes.object,
  data: React.PropTypes.arrayOf(React.PropTypes.object),
};
<commit_msg>Handle negative value in bar graph<commit_after>import React from "react";

import XYGraph from "../XYGraph";

import * as d3 from "d3";

import "./style.css";

import { properties } from "./default.config"

import { nest, nestStack, nestSum, limit } from "../../../utils/helpers"

// TODO split out this time interval log into a utility module.

// Time unit abbreviations from
// https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#time-units
// mapping onto D3 time intervals defined ad
// https://github.com/d3/d3-time#intervals
const timeAbbreviations = {
    "y": "utcYear",
    "M": "utcMonth",
    "w": "utcWeek",
    "d": "utcDay",
    "h": "utcHour",
    "m": "utcMinute",
    "s": "utcSecond",
    "ms": "utcMillisecond"
}

function computeBarWidth(interval, timeScale) {
    const step = +interval.substr(0, interval.length - 1);

    // TODO handle case of "ms"
    const abbreviation = interval.substr(interval.length - 1);
    const d3Interval = timeAbbreviations[abbreviation];

    // TODO validation and error handling
    const start = new Date(2000, 0, 0, 0, 0);
    const end = d3[d3Interval].offset(start, step);

    return timeScale(end) - timeScale(start);
}

export default class BarGraph extends XYGraph {

    constructor(props) {
        super(props, properties);
    }

    render() {

        const {
            data,
            width,
            height,
            onMarkClick
        } = this.props;

        if (!data || !data.length)
            return;

        const {
          chartHeightToPixel,
          chartWidthToPixel,
          circleToPixel,
          colorColumn,
          colors,
          dateHistogram,
          interval,
          legend,
          margin,
          orientation,
          padding,
          stroke,
          xColumn,
          xLabel,
          xTickFormat,
          xTickGrid,
          xTicks,
          xTickSizeInner,
          xTickSizeOuter,
          yColumn,
          yTickFormat,
          yTickGrid,
          yTicks,
          yTickSizeInner,
          yTickSizeOuter,
          otherOptions,
          stackColumn
        } = this.getConfiguredProperties();

        const vertical = orientation  === "vertical";

        let dimension, metric;

        if (vertical) {
          dimension = xColumn
          metric = yColumn
        } else {
          dimension = yColumn
          metric = xColumn
        }

        let stack = stackColumn || dimension

        let nestedData = nestStack({
            data: limit({
              data: nestSum({
                data: nest({
                    data,
                    key: dimension,
                    sortColumn: stack
                }),
                stackColumn: metric
              }),
              limitOption: Object.assign ({
                fields: [
                  {
                    type: 'array',
                    name: 'values',
                    groups: [stack],
                    metrics: metric
                  }
                ]}
                , otherOptions || {}
              )
            }),
            stackColumn: metric
        })

        const isVerticalLegend = legend.orientation === 'vertical';

        const xLabelFn         = (d) => d[xColumn];
        const yLabelFn         = (d) => d[yColumn];

        const stackLabelFn     = (d) => d[stack];

        const metricFn         = (d) => d.total
        const dimensionFn      = (d) => d.key

        const scale            = this.scaleColor(data, stack);

        const getColor         = (d) => scale ? scale(d[colorColumn || stack]) : colors[0];

        let xAxisHeight       = xLabel ? chartHeightToPixel : 0;

        let xAxisLabelWidth   = this.longestLabelLength(data, xLabelFn, xTickFormat) * chartWidthToPixel;
        let yAxisLabelWidth   = this.longestLabelLength(data, yLabelFn, yTickFormat) * chartWidthToPixel;

        let overAllAvailableWidth = width - (margin.left + margin.right);
        let maxWidthPercentage = 0.20;
        let trucatedYAxisWidth = ((overAllAvailableWidth * maxWidthPercentage) < yAxisLabelWidth ? (overAllAvailableWidth * maxWidthPercentage) : yAxisLabelWidth);

        let leftMargin        = margin.left + trucatedYAxisWidth;
        let availableWidth    = overAllAvailableWidth - trucatedYAxisWidth;
        let availableHeight   = height - (margin.top + margin.bottom + chartHeightToPixel + xAxisHeight);

        let legendWidth = this.longestLabelLength(data, stackLabelFn) * chartWidthToPixel;

        if (legend.show)
        {
            legend.width = legendWidth

            // Compute the available space considering a legend
            if (isVerticalLegend)
            {
                leftMargin      +=  legend.width;
                availableWidth  -=  legend.width;
            }
            else {
                const nbElementsPerLine  = parseInt(availableWidth / legend.width, 10);
                const nbLines            = parseInt(data.length / nbElementsPerLine, 10);
                availableHeight         -= nbLines * legend.circleSize * circleToPixel + chartHeightToPixel;
            }
        }

        // calculate range and make starting point from zero
        let range = () => {
            let ext = d3.extent(nestedData, metricFn)
            if(ext[0] > 0)
                ext[0] = 0

            if(ext[1] < 0)
                ext[1] = 0

            return ext
        }

        let xScale, yScale;

        if (dateHistogram) {

            // Handle the case of a vertical date histogram.
            xScale = d3.scaleTime()
              .domain(d3.extent(nestedData, dimensionFn))

            yScale = d3.scaleLinear()
              .domain(range())

        } else if (vertical) {

            // Handle the case of a vertical bar chart.
            xScale = d3.scaleBand()
              .domain(nestedData.map(dimensionFn))
              .padding(padding)

            yScale = d3.scaleLinear()
              .domain(range())

        } else {
            // Handle the case of a horizontal bar chart.
            xScale = d3.scaleLinear()
              .domain(range())

            yScale = d3.scaleBand()
              .domain(nestedData.map(dimensionFn))
              .padding(padding)
        }

        xScale.range([0, availableWidth]);
        yScale.range([availableHeight, 0]);

        const xAxis = d3.axisBottom(xScale)
          .tickSizeInner(xTickGrid ? -availableHeight : xTickSizeInner)
          .tickSizeOuter(xTickSizeOuter);

        if(xTickFormat) {
            xAxis.tickFormat(d3.format(xTickFormat))
        }

        if(xTicks){
            xAxis.ticks(xTicks);
        }

        const yAxis = d3.axisLeft(yScale)
          .tickSizeInner(yTickGrid ? -availableWidth : yTickSizeInner)
          .tickSizeOuter(yTickSizeOuter);

        if(yTickFormat){
            yAxis.tickFormat(d3.format(yTickFormat));
        }

        if(yTicks){
            yAxis.ticks(yTicks);
        }

        let barWidth;

        if(dateHistogram){
            barWidth = computeBarWidth(interval, xScale);
        } else if(vertical){
            barWidth = xScale.bandwidth();
        }

        let xTitlePosition = {
            left: leftMargin + availableWidth / 2,
            top: margin.top + availableHeight + chartHeightToPixel + xAxisHeight
        }
        let yTitlePosition = {
            // We use chartWidthToPixel to compensate the rotation of the title
            left: margin.left + chartWidthToPixel + (isVerticalLegend ? legend.width : 0),
            top: margin.top + availableHeight / 2
        }

        let xAxisGraph = <g
            key="xAxis"
            ref={ (el) => vertical
                  ? d3.select(el).call(xAxis)
                      .selectAll(".tick text")
                      .call(this.wrapD3Text, barWidth)
                  : d3.select(el).call(xAxis)
                      .selectAll(".tick text")
                }
            transform={ `translate(0, ${availableHeight})` }
        />

        let yAxisGraph = <g
            key="yAxis"
            ref={ (el) => ( !vertical && !dateHistogram)
                  ? d3.select(el).call(yAxis)
                      .selectAll(".tick text")
                      .call(this.wrapD3Text, yAxisLabelWidth)
                  : d3.select(el).call(yAxis)
                }
        />

        let horizontalLine = (
            vertical ? <line
                x1="0"
                y1={yScale(0)}
                x2={availableWidth}
                y2={yScale(0)}
                stroke={"rgb(0,0,0)"}
                strokeWidth="0.7"
            /> :
            <line
                x1={xScale(0)}
                y1="0"
                x2={xScale(0)}
                y2={availableHeight}
                stroke={"rgb(0,0,0)"}
                strokeWidth="0.7"
            />
        )

        // calculate y axis coordinate to draw bar
        let yPosition = (d) => {
            if(vertical)
                return d.y1 >= 0 ? yScale(d.y1) : yScale(d.y0)

            return d.y1 >= 0 ? xScale(d.y0) : xScale(d.y1)
        }

        // calculate bar height
        let barHeight = (d) => {
            if(vertical)
              return d.y1 >= 0 ? yScale(d.y0) - yScale(d.y1) : yScale(d.y1) - yScale(d.y0)

            return d.y1 >= 0 ? xScale(d.y1) - xScale(d.y0) : xScale(d.y0) - xScale(d.y1)
        }

        return (
            <div className="bar-graph">
                {this.tooltip}
                <svg
                    style={{
                        width: width,
                        height: height
                    }}
                    >
                    {this.axisTitles(xTitlePosition, yTitlePosition)}
                    <g transform={ `translate(${leftMargin},${margin.top})` } >
                        { xAxisGraph }
                        { yAxisGraph }
                        { horizontalLine }
                        {
                            nestedData.map((nest, i) => {
                                return nest.values.map((d, i) => {
                                    // Compute rectangle depending on orientation (vertical or horizontal).

                                    const {
                                        x,
                                        y,
                                        width,
                                        height
                                    } = (
                                        vertical ? {
                                            x: xScale(nest.key),
                                            y: yPosition(d),
                                            width: barWidth,
                                            height: barHeight(d)
                                        } : {
                                            x: yPosition(d),
                                            y: yScale(nest.key),
                                            width: barHeight(d),
                                            height: yScale.bandwidth()
                                        }
                                    );

                                // Set up clicking and cursor style.
                                const { onClick, style } = (

                                    // If an "onMarkClick" handler is registered,
                                    onMarkClick && (!otherOptions || d[dimension] !== otherOptions.label) ? {

                                        // set it up to be invoked, passing the current data row object.
                                        onClick: () => onMarkClick(d),

                                        // Make the cursor a pointer on hover, as an affordance for clickability.
                                        style: { cursor: "pointer" }

                                    } : {
                                        // Otherwise, set onClick and style to "undefined".
                                    }
                                );

                                return (
                                    <rect
                                        x={ x }
                                        y={ y }
                                        width={ width }
                                        height={ height }
                                        fill={ getColor(d) }
                                        onClick={ onClick }
                                        style={ style }
                                        key={ i }
                                        stroke={ stroke.color }
                                        strokeWidth={ stroke.width }
                                        { ...this.tooltipProps(d) }
                                    />
                                )
                            })
                        })}
                    </g>
                    {this.renderLegend(data, legend, getColor, stackLabelFn)}
                </svg>
            </div>
        );
    }
}
BarGraph.propTypes = {
  configuration: React.PropTypes.object,
  data: React.PropTypes.arrayOf(React.PropTypes.object),
};
<|endoftext|>


<commit_before>/*
 * SimplyRead - makes webpages more readable
 *
 * See COPYING file for copyright, license and warranty details.
 */

if(window.content && window.content.document.simplyread_original === undefined) window.content.document.simplyread_original = false;

function simplyread()
{
	/* count the number of
 tags that are direct children of parenttag */
	function count_p(parenttag)
	{
		var n = 0;
		var c = parenttag.childNodes;
		for (var i = 0; i < c.length; i++) {
			if (c[i].tagName == "p" || c[i].tagName == "P")
				n++;
		}
		return n;
	}

	var doc;
	doc = (document.body === undefined)
	      ? window.content.document : document;

	/* if simplyread_original is set, then the simplyread version is currently active,
	 * so switch to the simplyread_original html */
	if (doc.simplyread_original) {
		doc.body.innerHTML = doc.simplyread_original;
		for (var i = 0; i < doc.styleSheets.length; i++)
			doc.styleSheets[i].disabled = false;
		doc.simplyread_original = false
		return 0;
	}

	doc.simplyread_original = doc.body.innerHTML;

	var biggest_num = 0;
	var biggest_tag;

	/* search for tag with most direct children
 tags */
	var t = doc.getElementsByTagName("*");
	for (var i = 0; i < t.length; i++) {
		var p_num = count_p(t[i]);
		if (p_num > biggest_num) {
			biggest_num = p_num;
			biggest_tag = t[i];
		}
	}

	if (biggest_num == 0) {
		alert("Can't find any content");
		return 1;
	}

	/* save and sanitise content of chosen tag */
	var fresh = doc.createElement("div");
	fresh.innerHTML = biggest_tag.innerHTML;
	fresh.innerHTML = fresh.innerHTML.replace(/<\/?font[^>]*>/g, "");
	fresh.innerHTML = fresh.innerHTML.replace(/style="[^"]*"/g, "");
	fresh.innerHTML = fresh.innerHTML.replace(/<\/?a[^>]*>/g, "");
	fresh.innerHTML = fresh.innerHTML.replace(/
/g, "
");

	for (var i = 0; i < doc.styleSheets.length; i++)
		doc.styleSheets[i].disabled = true;

	doc.body.innerHTML =
		"
" +
		"
" + doc.title + "
" +
		fresh.innerHTML + "
";

	return 0;
}
<commit_msg>Remove useless alert if no content found<commit_after>/*
 * SimplyRead - makes webpages more readable
 *
 * See COPYING file for copyright, license and warranty details.
 */

if(window.content && window.content.document.simplyread_original === undefined) window.content.document.simplyread_original = false;

function simplyread()
{
	/* count the number of
 tags that are direct children of parenttag */
	function count_p(parenttag)
	{
		var n = 0;
		var c = parenttag.childNodes;
		for (var i = 0; i < c.length; i++) {
			if (c[i].tagName == "p" || c[i].tagName == "P")
				n++;
		}
		return n;
	}

	var doc;
	doc = (document.body === undefined)
	      ? window.content.document : document;

	/* if simplyread_original is set, then the simplyread version is currently active,
	 * so switch to the simplyread_original html */
	if (doc.simplyread_original) {
		doc.body.innerHTML = doc.simplyread_original;
		for (var i = 0; i < doc.styleSheets.length; i++)
			doc.styleSheets[i].disabled = false;
		doc.simplyread_original = false
		return 0;
	}

	doc.simplyread_original = doc.body.innerHTML;

	var biggest_num = 0;
	var biggest_tag;

	/* search for tag with most direct children
 tags */
	var t = doc.getElementsByTagName("*");
	for (var i = 0; i < t.length; i++) {
		var p_num = count_p(t[i]);
		if (p_num > biggest_num) {
			biggest_num = p_num;
			biggest_tag = t[i];
		}
	}

	if (biggest_num == 0) return 1;

	/* save and sanitise content of chosen tag */
	var fresh = doc.createElement("div");
	fresh.innerHTML = biggest_tag.innerHTML;
	fresh.innerHTML = fresh.innerHTML.replace(/<\/?font[^>]*>/g, "");
	fresh.innerHTML = fresh.innerHTML.replace(/style="[^"]*"/g, "");
	fresh.innerHTML = fresh.innerHTML.replace(/<\/?a[^>]*>/g, "");
	fresh.innerHTML = fresh.innerHTML.replace(/
/g, "
");

	for (var i = 0; i < doc.styleSheets.length; i++)
		doc.styleSheets[i].disabled = true;

	doc.body.innerHTML =
		"
" +
		"
" + doc.title + "
" +
		fresh.innerHTML + "
";

	return 0;
}
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

var Viewport = function ( editor ) {

	var signals = editor.signals;

	var container = new UI.Panel();
	container.setId( 'viewport' );
	container.setPosition( 'absolute' );

	container.add( new Viewport.Camera( editor ) );
	container.add( new Viewport.Info( editor ) );

	//

	var renderer = null;

	var camera = editor.camera;
	var scene = editor.scene;
	var sceneHelpers = editor.sceneHelpers;

	var objects = [];

	// helpers

	var grid = new THREE.GridHelper( 30, 30, 0x444444, 0x888888 );
	sceneHelpers.add( grid );

	var array = grid.geometry.attributes.color.array;

	for ( var i = 0; i < array.length; i += 60 ) {

		for ( var j = 0; j < 12; j ++ ) {

			array[ i + j ] = 0.26;

		}

	}

	//

	var box = new THREE.Box3();

	var selectionBox = new THREE.BoxHelper();
	selectionBox.material.depthTest = false;
	selectionBox.material.transparent = true;
	selectionBox.visible = false;
	sceneHelpers.add( selectionBox );

	var objectPositionOnDown = null;
	var objectRotationOnDown = null;
	var objectScaleOnDown = null;

	var transformControls = new THREE.TransformControls( camera, container.dom );
	transformControls.addEventListener( 'change', function () {

		var object = transformControls.object;

		if ( object !== undefined ) {

			selectionBox.setFromObject( object );

			if ( editor.helpers[ object.id ] !== undefined ) {

				editor.helpers[ object.id ].update();

			}

			signals.refreshSidebarObject3D.dispatch( object );

		}

		render();

	} );
	transformControls.addEventListener( 'mouseDown', function () {

		var object = transformControls.object;

		objectPositionOnDown = object.position.clone();
		objectRotationOnDown = object.rotation.clone();
		objectScaleOnDown = object.scale.clone();

		controls.enabled = false;

	} );
	transformControls.addEventListener( 'mouseUp', function () {

		var object = transformControls.object;

		if ( object !== undefined ) {

			switch ( transformControls.getMode() ) {

				case 'translate':

					if ( ! objectPositionOnDown.equals( object.position ) ) {

						editor.execute( new SetPositionCommand( object, object.position, objectPositionOnDown ) );

					}

					break;

				case 'rotate':

					if ( ! objectRotationOnDown.equals( object.rotation ) ) {

						editor.execute( new SetRotationCommand( object, object.rotation, objectRotationOnDown ) );

					}

					break;

				case 'scale':

					if ( ! objectScaleOnDown.equals( object.scale ) ) {

						editor.execute( new SetScaleCommand( object, object.scale, objectScaleOnDown ) );

					}

					break;

			}

		}

		controls.enabled = true;

	} );

	sceneHelpers.add( transformControls );

	// object picking

	var raycaster = new THREE.Raycaster();
	var mouse = new THREE.Vector2();

	// events

	function getIntersects( point, objects ) {

		mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 );

		raycaster.setFromCamera( mouse, camera );

		return raycaster.intersectObjects( objects );

	}

	var onDownPosition = new THREE.Vector2();
	var onUpPosition = new THREE.Vector2();
	var onDoubleClickPosition = new THREE.Vector2();

	function getMousePosition( dom, x, y ) {

		var rect = dom.getBoundingClientRect();
		return [ ( x - rect.left ) / rect.width, ( y - rect.top ) / rect.height ];

	}

	function handleClick() {

		if ( onDownPosition.distanceTo( onUpPosition ) === 0 ) {

			var intersects = getIntersects( onUpPosition, objects );

			if ( intersects.length > 0 ) {

				var object = intersects[ 0 ].object;

				if ( object.userData.object !== undefined ) {

					// helper

					editor.select( object.userData.object );

				} else {

					editor.select( object );

				}

			} else {

				editor.select( null );

			}

			render();

		}

	}

	function onMouseDown( event ) {

		// event.preventDefault();

		var array = getMousePosition( container.dom, event.clientX, event.clientY );
		onDownPosition.fromArray( array );

		document.addEventListener( 'mouseup', onMouseUp, false );

	}

	function onMouseUp( event ) {

		var array = getMousePosition( container.dom, event.clientX, event.clientY );
		onUpPosition.fromArray( array );

		handleClick();

		document.removeEventListener( 'mouseup', onMouseUp, false );

	}

	function onTouchStart( event ) {

		var touch = event.changedTouches[ 0 ];

		var array = getMousePosition( container.dom, touch.clientX, touch.clientY );
		onDownPosition.fromArray( array );

		document.addEventListener( 'touchend', onTouchEnd, false );

	}

	function onTouchEnd( event ) {

		var touch = event.changedTouches[ 0 ];

		var array = getMousePosition( container.dom, touch.clientX, touch.clientY );
		onUpPosition.fromArray( array );

		handleClick();

		document.removeEventListener( 'touchend', onTouchEnd, false );

	}

	function onDoubleClick( event ) {

		var array = getMousePosition( container.dom, event.clientX, event.clientY );
		onDoubleClickPosition.fromArray( array );

		var intersects = getIntersects( onDoubleClickPosition, objects );

		if ( intersects.length > 0 ) {

			var intersect = intersects[ 0 ];

			signals.objectFocused.dispatch( intersect.object );

		}

	}

	container.dom.addEventListener( 'mousedown', onMouseDown, false );
	container.dom.addEventListener( 'touchstart', onTouchStart, false );
	container.dom.addEventListener( 'dblclick', onDoubleClick, false );

	// controls need to be added *after* main logic,
	// otherwise controls.enabled doesn't work.

	var controls = new THREE.EditorControls( camera, container.dom );
	controls.addEventListener( 'change', function () {

		signals.cameraChanged.dispatch( camera );

	} );

	// signals

	signals.editorCleared.add( function () {

		controls.center.set( 0, 0, 0 );
		render();

	} );

	signals.transformModeChanged.add( function ( mode ) {

		transformControls.setMode( mode );

	} );

	signals.snapChanged.add( function ( dist ) {

		transformControls.setTranslationSnap( dist );

	} );

	signals.spaceChanged.add( function ( space ) {

		transformControls.setSpace( space );

	} );

	signals.rendererChanged.add( function ( newRenderer ) {

		if ( renderer !== null ) {

			container.dom.removeChild( renderer.domElement );

		}

		renderer = newRenderer;

		renderer.autoClear = false;
		renderer.autoUpdateScene = false;
		renderer.gammaOutput = true;
		renderer.setPixelRatio( window.devicePixelRatio );
		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );

		container.dom.appendChild( renderer.domElement );

		render();

	} );

	signals.sceneGraphChanged.add( function () {

		render();

	} );

	signals.cameraChanged.add( function () {

		render();

	} );

	signals.objectSelected.add( function ( object ) {

		selectionBox.visible = false;
		transformControls.detach();

		if ( object !== null && object !== scene && object !== camera ) {

			box.setFromObject( object );

			if ( box.isEmpty() === false ) {

				selectionBox.setFromObject( object );
				selectionBox.visible = true;

			}

			transformControls.attach( object );

		}

		render();

	} );

	signals.objectFocused.add( function ( object ) {

		controls.focus( object );

	} );

	signals.geometryChanged.add( function ( object ) {

		if ( object !== undefined ) {

			selectionBox.setFromObject( object );

		}

		render();

	} );

	signals.objectAdded.add( function ( object ) {

		object.traverse( function ( child ) {

			objects.push( child );

		} );

	} );

	signals.objectChanged.add( function ( object ) {

		if ( editor.selected === object ) {

			selectionBox.setFromObject( object );

		}

		if ( object.isPerspectiveCamera ) {

			object.updateProjectionMatrix();

		}

		if ( editor.helpers[ object.id ] !== undefined ) {

			editor.helpers[ object.id ].update();

		}

		render();

	} );

	signals.objectRemoved.add( function ( object ) {

		controls.enabled = true;
		if ( object === transformControls.object ) {

			transformControls.detach();

		}

		object.traverse( function ( child ) {

			objects.splice( objects.indexOf( child ), 1 );

		} );

	} );

	signals.helperAdded.add( function ( object ) {

		objects.push( object.getObjectByName( 'picker' ) );

	} );

	signals.helperRemoved.add( function ( object ) {

		objects.splice( objects.indexOf( object.getObjectByName( 'picker' ) ), 1 );

	} );

	signals.materialChanged.add( function ( material ) {

		render();

	} );

	// fog

	signals.sceneBackgroundChanged.add( function ( backgroundColor ) {

		scene.background.setHex( backgroundColor );

		render();

	} );

	var currentFogType = null;

	signals.sceneFogChanged.add( function ( fogType, fogColor, fogNear, fogFar, fogDensity ) {

		if ( currentFogType !== fogType ) {

			switch ( fogType ) {

				case 'None':
					scene.fog = null;
					break;
				case 'Fog':
					scene.fog = new THREE.Fog();
					break;
				case 'FogExp2':
					scene.fog = new THREE.FogExp2();
					break;

			}

			currentFogType = fogType;

		}

		if ( scene.fog ) {

			if ( scene.fog.isFog ) {

				scene.fog.color.setHex( fogColor );
				scene.fog.near = fogNear;
				scene.fog.far = fogFar;

			} else if ( scene.fog.isFogExp2 ) {

				scene.fog.color.setHex( fogColor );
				scene.fog.density = fogDensity;

			}

		}

		render();

	} );

	signals.viewportCameraChanged.add( function ( viewportCamera ) {

		camera = viewportCamera;

		camera.aspect = editor.camera.aspect;
		camera.projectionMatrix.copy( editor.camera.projectionMatrix );

		render();

	} );

	//

	signals.windowResize.add( function () {

		// TODO: Move this out?

		editor.DEFAULT_CAMERA.aspect = container.dom.offsetWidth / container.dom.offsetHeight;
		editor.DEFAULT_CAMERA.updateProjectionMatrix();

		camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight;
		camera.updateProjectionMatrix();

		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );

		render();

	} );

	signals.showGridChanged.add( function ( showGrid ) {

		grid.visible = showGrid;
		render();

	} );

	// animations

	var prevTime = performance.now();

	function animate( time ) {

		requestAnimationFrame( animate );

		var mixer = editor.mixer;

		if ( mixer.stats.actions.inUse > 0 ) {

			mixer.update( ( time - prevTime ) / 1000 );
			render();

		}

		prevTime = time;

	}

	requestAnimationFrame( animate );

	//

	function render() {

		scene.updateMatrixWorld();
		renderer.render( scene, camera );

		if ( renderer instanceof THREE.RaytracingRenderer === false ) {

			if ( camera === editor.camera ) {

				sceneHelpers.updateMatrixWorld();
				renderer.render( sceneHelpers, camera );

			}

		}

	}

	return container;

};
<commit_msg>Add comment<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

var Viewport = function ( editor ) {

	var signals = editor.signals;

	var container = new UI.Panel();
	container.setId( 'viewport' );
	container.setPosition( 'absolute' );

	container.add( new Viewport.Camera( editor ) );
	container.add( new Viewport.Info( editor ) );

	//

	var renderer = null;

	var camera = editor.camera;
	var scene = editor.scene;
	var sceneHelpers = editor.sceneHelpers;

	var objects = [];

	// helpers

	var grid = new THREE.GridHelper( 30, 30, 0x444444, 0x888888 );
	sceneHelpers.add( grid );

	var array = grid.geometry.attributes.color.array;

	for ( var i = 0; i < array.length; i += 60 ) {

		for ( var j = 0; j < 12; j ++ ) {

			array[ i + j ] = 0.26;

		}

	}

	//

	var box = new THREE.Box3();

	var selectionBox = new THREE.BoxHelper();
	selectionBox.material.depthTest = false;
	selectionBox.material.transparent = true;
	selectionBox.visible = false;
	sceneHelpers.add( selectionBox );

	var objectPositionOnDown = null;
	var objectRotationOnDown = null;
	var objectScaleOnDown = null;

	var transformControls = new THREE.TransformControls( camera, container.dom );
	transformControls.addEventListener( 'change', function () {

		var object = transformControls.object;

		if ( object !== undefined ) {

			selectionBox.setFromObject( object );

			if ( editor.helpers[ object.id ] !== undefined ) {

				editor.helpers[ object.id ].update();

			}

			signals.refreshSidebarObject3D.dispatch( object );

		}

		render();

	} );
	transformControls.addEventListener( 'mouseDown', function () {

		var object = transformControls.object;

		objectPositionOnDown = object.position.clone();
		objectRotationOnDown = object.rotation.clone();
		objectScaleOnDown = object.scale.clone();

		controls.enabled = false;

	} );
	transformControls.addEventListener( 'mouseUp', function () {

		var object = transformControls.object;

		if ( object !== undefined ) {

			switch ( transformControls.getMode() ) {

				case 'translate':

					if ( ! objectPositionOnDown.equals( object.position ) ) {

						editor.execute( new SetPositionCommand( object, object.position, objectPositionOnDown ) );

					}

					break;

				case 'rotate':

					if ( ! objectRotationOnDown.equals( object.rotation ) ) {

						editor.execute( new SetRotationCommand( object, object.rotation, objectRotationOnDown ) );

					}

					break;

				case 'scale':

					if ( ! objectScaleOnDown.equals( object.scale ) ) {

						editor.execute( new SetScaleCommand( object, object.scale, objectScaleOnDown ) );

					}

					break;

			}

		}

		controls.enabled = true;

	} );

	sceneHelpers.add( transformControls );

	// object picking

	var raycaster = new THREE.Raycaster();
	var mouse = new THREE.Vector2();

	// events

	function getIntersects( point, objects ) {

		mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 );

		raycaster.setFromCamera( mouse, camera );

		return raycaster.intersectObjects( objects );

	}

	var onDownPosition = new THREE.Vector2();
	var onUpPosition = new THREE.Vector2();
	var onDoubleClickPosition = new THREE.Vector2();

	function getMousePosition( dom, x, y ) {

		var rect = dom.getBoundingClientRect();
		return [ ( x - rect.left ) / rect.width, ( y - rect.top ) / rect.height ];

	}

	function handleClick() {

		if ( onDownPosition.distanceTo( onUpPosition ) === 0 ) {

			var intersects = getIntersects( onUpPosition, objects );

			if ( intersects.length > 0 ) {

				var object = intersects[ 0 ].object;

				if ( object.userData.object !== undefined ) {

					// helper

					editor.select( object.userData.object );

				} else {

					editor.select( object );

				}

			} else {

				editor.select( null );

			}

			render();

		}

	}

	function onMouseDown( event ) {

		// event.preventDefault();

		var array = getMousePosition( container.dom, event.clientX, event.clientY );
		onDownPosition.fromArray( array );

		document.addEventListener( 'mouseup', onMouseUp, false );

	}

	function onMouseUp( event ) {

		var array = getMousePosition( container.dom, event.clientX, event.clientY );
		onUpPosition.fromArray( array );

		handleClick();

		document.removeEventListener( 'mouseup', onMouseUp, false );

	}

	function onTouchStart( event ) {

		var touch = event.changedTouches[ 0 ];

		var array = getMousePosition( container.dom, touch.clientX, touch.clientY );
		onDownPosition.fromArray( array );

		document.addEventListener( 'touchend', onTouchEnd, false );

	}

	function onTouchEnd( event ) {

		var touch = event.changedTouches[ 0 ];

		var array = getMousePosition( container.dom, touch.clientX, touch.clientY );
		onUpPosition.fromArray( array );

		handleClick();

		document.removeEventListener( 'touchend', onTouchEnd, false );

	}

	function onDoubleClick( event ) {

		var array = getMousePosition( container.dom, event.clientX, event.clientY );
		onDoubleClickPosition.fromArray( array );

		var intersects = getIntersects( onDoubleClickPosition, objects );

		if ( intersects.length > 0 ) {

			var intersect = intersects[ 0 ];

			signals.objectFocused.dispatch( intersect.object );

		}

	}

	container.dom.addEventListener( 'mousedown', onMouseDown, false );
	container.dom.addEventListener( 'touchstart', onTouchStart, false );
	container.dom.addEventListener( 'dblclick', onDoubleClick, false );

	// controls need to be added *after* main logic,
	// otherwise controls.enabled doesn't work.

	var controls = new THREE.EditorControls( camera, container.dom );
	controls.addEventListener( 'change', function () {

		signals.cameraChanged.dispatch( camera );

	} );

	// signals

	signals.editorCleared.add( function () {

		controls.center.set( 0, 0, 0 );
		render();

	} );

	signals.transformModeChanged.add( function ( mode ) {

		transformControls.setMode( mode );

	} );

	signals.snapChanged.add( function ( dist ) {

		transformControls.setTranslationSnap( dist );

	} );

	signals.spaceChanged.add( function ( space ) {

		transformControls.setSpace( space );

	} );

	signals.rendererChanged.add( function ( newRenderer ) {

		if ( renderer !== null ) {

			container.dom.removeChild( renderer.domElement );

		}

		renderer = newRenderer;

		renderer.autoClear = false;
		renderer.autoUpdateScene = false;
		renderer.gammaOutput = true;
		renderer.setPixelRatio( window.devicePixelRatio );
		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );

		container.dom.appendChild( renderer.domElement );

		render();

	} );

	signals.sceneGraphChanged.add( function () {

		render();

	} );

	signals.cameraChanged.add( function () {

		render();

	} );

	signals.objectSelected.add( function ( object ) {

		selectionBox.visible = false;
		transformControls.detach();

		if ( object !== null && object !== scene && object !== camera ) {

			box.setFromObject( object );

			if ( box.isEmpty() === false ) {

				selectionBox.setFromObject( object );
				selectionBox.visible = true;

			}

			transformControls.attach( object );

		}

		render();

	} );

	signals.objectFocused.add( function ( object ) {

		controls.focus( object );

	} );

	signals.geometryChanged.add( function ( object ) {

		if ( object !== undefined ) {

			selectionBox.setFromObject( object );

		}

		render();

	} );

	signals.objectAdded.add( function ( object ) {

		object.traverse( function ( child ) {

			objects.push( child );

		} );

	} );

	signals.objectChanged.add( function ( object ) {

		if ( editor.selected === object ) {

			selectionBox.setFromObject( object );

		}

		if ( object.isPerspectiveCamera ) {

			object.updateProjectionMatrix();

		}

		if ( editor.helpers[ object.id ] !== undefined ) {

			editor.helpers[ object.id ].update();

		}

		render();

	} );

	signals.objectRemoved.add( function ( object ) {

		controls.enabled = true; // see #14180
		if ( object === transformControls.object ) {

			transformControls.detach();

		}

		object.traverse( function ( child ) {

			objects.splice( objects.indexOf( child ), 1 );

		} );

	} );

	signals.helperAdded.add( function ( object ) {

		objects.push( object.getObjectByName( 'picker' ) );

	} );

	signals.helperRemoved.add( function ( object ) {

		objects.splice( objects.indexOf( object.getObjectByName( 'picker' ) ), 1 );

	} );

	signals.materialChanged.add( function ( material ) {

		render();

	} );

	// fog

	signals.sceneBackgroundChanged.add( function ( backgroundColor ) {

		scene.background.setHex( backgroundColor );

		render();

	} );

	var currentFogType = null;

	signals.sceneFogChanged.add( function ( fogType, fogColor, fogNear, fogFar, fogDensity ) {

		if ( currentFogType !== fogType ) {

			switch ( fogType ) {

				case 'None':
					scene.fog = null;
					break;
				case 'Fog':
					scene.fog = new THREE.Fog();
					break;
				case 'FogExp2':
					scene.fog = new THREE.FogExp2();
					break;

			}

			currentFogType = fogType;

		}

		if ( scene.fog ) {

			if ( scene.fog.isFog ) {

				scene.fog.color.setHex( fogColor );
				scene.fog.near = fogNear;
				scene.fog.far = fogFar;

			} else if ( scene.fog.isFogExp2 ) {

				scene.fog.color.setHex( fogColor );
				scene.fog.density = fogDensity;

			}

		}

		render();

	} );

	signals.viewportCameraChanged.add( function ( viewportCamera ) {

		camera = viewportCamera;

		camera.aspect = editor.camera.aspect;
		camera.projectionMatrix.copy( editor.camera.projectionMatrix );

		render();

	} );

	//

	signals.windowResize.add( function () {

		// TODO: Move this out?

		editor.DEFAULT_CAMERA.aspect = container.dom.offsetWidth / container.dom.offsetHeight;
		editor.DEFAULT_CAMERA.updateProjectionMatrix();

		camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight;
		camera.updateProjectionMatrix();

		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );

		render();

	} );

	signals.showGridChanged.add( function ( showGrid ) {

		grid.visible = showGrid;
		render();

	} );

	// animations

	var prevTime = performance.now();

	function animate( time ) {

		requestAnimationFrame( animate );

		var mixer = editor.mixer;

		if ( mixer.stats.actions.inUse > 0 ) {

			mixer.update( ( time - prevTime ) / 1000 );
			render();

		}

		prevTime = time;

	}

	requestAnimationFrame( animate );

	//

	function render() {

		scene.updateMatrixWorld();
		renderer.render( scene, camera );

		if ( renderer instanceof THREE.RaytracingRenderer === false ) {

			if ( camera === editor.camera ) {

				sceneHelpers.updateMatrixWorld();
				renderer.render( sceneHelpers, camera );

			}

		}

	}

	return container;

};
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

"use strict";

const { Trace, TraceError } = require("firebug.sdk/lib/core/trace.js").get(module.id);
const { loadSheet, removeSheet } = require("sdk/stylesheet/utils");
const { Class } = require("sdk/core/heritage");
const { BaseOverlay } = require("../chrome/base-overlay.js");

/**
 * @overlay This object represents an overlay that is responsible
 * for customizing the 'Performance' panel.
 */
const PerformanceOverlay = Class(
/** @lends PerformanceOverlay */
{
  extends: BaseOverlay,

  overlayId: "performance",

  // Initialization

  initialize: function(options) {
    BaseOverlay.prototype.initialize.apply(this, arguments);
  },

  onReady: function(options) {
    BaseOverlay.prototype.onReady.apply(this, arguments);
  },

  destroy: function() {
  },

  onApplyTheme: function(win, oldTheme) {
    loadSheet(win, "chrome://firebug/skin/performance.css", "author");
  },

  onUnapplyTheme: function(win, newTheme) {
    removeSheet(win, "chrome://firebug/skin/performance.css", "author");
  },

  // Options

  /**
   * The performance panel uses the original popup menu already
   * populated with all options since its XUL structure is
   * wired with the JS logic. See: devtools/client/performance/performance.xul
   */
  getOptionsMenuPopup: function() {
    let doc = this.getPanelDocument();
    return doc.getElementById("performance-options-menupopup");
  },
});

// Exports from this module
exports.PerformanceOverlay = PerformanceOverlay;
<commit_msg>Use proper base object for Performance panel overlay<commit_after>/* See license.txt for terms of usage */

"use strict";

// Add-on SDK
const { loadSheet, removeSheet } = require("sdk/stylesheet/utils");
const { Class } = require("sdk/core/heritage");

// Firebug.SDK
const { Trace, TraceError } = require("firebug.sdk/lib/core/trace.js").get(module.id);
const { PanelOverlay } = require("firebug.sdk/lib/panel-overlay.js");

/**
 * @overlay This object represents an overlay that is responsible
 * for customizing the 'Performance' panel.
 */
const PerformanceOverlay = Class(
/** @lends PerformanceOverlay */
{
  extends: PanelOverlay,

  overlayId: "performance",

  onApplyTheme: function(win, oldTheme) {
    loadSheet(win, "chrome://firebug/skin/performance.css", "author");
  },

  onUnapplyTheme: function(win, newTheme) {
    removeSheet(win, "chrome://firebug/skin/performance.css", "author");
  },

  // Options

  /**
   * The performance panel uses the original popup menu already
   * populated with all options since its XUL structure is
   * wired with the JS logic. See: devtools/client/performance/performance.xul
   */
  getOptionsMenuPopup: function() {
    let doc = this.getPanelDocument();
    return doc.getElementById("performance-options-menupopup");
  },
});

// Exports from this module
exports.PerformanceOverlay = PerformanceOverlay;
<|endoftext|>


<commit_before>[
  {
    "name": "Rise Ui",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/RiseUi.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/RiseUi.png"
  },
  {
    "name": "Ace",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Ace.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Ace.png"
  },
  {
    "name": "Arena",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Arena.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Arena.png"
  },
  {
    "name": "Arena1",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Arena1.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Arena1.png"
  },
  {
    "name": "Weyo",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Weyo.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Weyo.png"
  },
  {
    "name": "Ascend",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Ascend.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Ascend.png"
  },
  {
    "name": "Eco",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Eco.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Eco.png"
  },
  {
    "name": "Prime",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Prime.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Prime.png"
  },
  {
    "name": "Radiant",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Radiant.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Radiant.png"
  }
]
<commit_msg>Update Pattern.js<commit_after>[
  {
			"name": "Magic_mix",
			"author": "Hiten Soni",
			"url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Magic_mix.png",
			"thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Thumb/Magic_mix.png"
	},
  {
    "name": "Rise Ui",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/RiseUi.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/RiseUi.png"
  },
  {
    "name": "Ace",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Ace.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Ace.png"
  },
  {
    "name": "Arena",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Arena.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Arena.png"
  },
  {
    "name": "Arena1",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Arena1.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Arena1.png"
  },
  {
    "name": "Weyo",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Weyo.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Weyo.png"
  },
  {
    "name": "Ascend",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Ascend.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Ascend.png"
  },
  {
    "name": "Eco",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Eco.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Eco.png"
  },
  {
    "name": "Prime",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Prime.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Prime.png"
  },
  {
    "name": "Radiant",
    "author": "Hiten Soni",
    "url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/StripesandPatterns/Radiant.png",
    "thumb_url": "https://raw.githubusercontent.com/hiten1985/Backgrounds/master/Walls/Thumbs/Radiant.png"
  }
]
<|endoftext|>


<commit_before>/*
 * Copyright 2014, Gregg Tavares.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Gregg Tavares. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
"use strict";

var ZipWriter = require("moxie-zip").ZipWriter;
var JSZip = require('jszip');
var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var gameInfo = require('../server/gameinfo');
var gameDB = require('../server/gamedb');
var games = require('../management/games');
var config = require('../server/config');
var strings = require('../server/strings');

var ReleaseManager = function() {

  var readDirTreeSync = function(filePath, options) {
    options = options || {};

    var filter = options.filter;
    if (filter === undefined) {
      filter = function() { return true; };
    } else if (filter instanceof RegExp) {
      filter = function(filter) {
        return function(filename) {
          return filter.test(filename);
        }
      }(filter);
    }

    var fileNames = fs.readdirSync(filePath).filter(filter).map(function(fileName) {
      return path.join(filePath, fileName);
    });

    var subdirFilenames = [];
    fileNames.forEach(function(fileName) {
      var stat = fs.statSync(fileName);
      if (stat.isDirectory()) {
        subdirFilenames.push(readDirTreeSync(fileName));
      }
    });

    subdirFilenames.forEach(function(subNames) {
      fileNames = fileNames.concat(subNames);
    });

    return fileNames;
  };

  // Remove this if Zip adds the filter.
//  var addLocalFolder = (function() {
//    var Utils = require('../node_modules/adm-zip/util/utils.js');
//    return function(zip, /*String*/localPath, /*String*/zipPath, /*RegExp|Function*/filter) {
//      if (filter === undefined) {
//        filter = function() { return true; };
//      } else if (filter instanceof RegExp) {
//        filter = function(filter) {
//          return function(filename) {
//            return filter.test(filename);
//          }
//        }(filter);
//      }
//
//      if(zipPath){
//          zipPath=zipPath.split("\\").join("/");
//          if(zipPath.charAt(zipPath.length - 1) != "/"){
//              zipPath += "/";
//          }
//      }else{
//          zipPath="";
//      }
//      localPath = localPath.split("\\").join("/"); //windows fix
//      if (localPath.charAt(localPath.length - 1) != "/")
//          localPath += "/";
//
//      if (fs.existsSync(localPath)) {
//
//          var items = Utils.findFiles(localPath);
//          if (items.length) {
//              items.forEach(function(path) {
//                  var p = path.split("\\").join("/").replace(localPath, ""); //windows fix
//                  if (filter(p)) {
//                      if (p.charAt(p.length - 1) !== "/") {
//                          zip.addFile(zipPath+p, fs.readFileSync(path), "", 0)
//                      } else {
//                          zip.addFile(zipPath+p, new Buffer(0), "", 0)
//                      }
//                  }
//              });
//          }
//      } else {
//          throw Utils.Errors.FILE_NOT_FOUND.replace("%s", localPath);
//      }
//    };
//  }());

  /**
   * Makes a release.
   *
   * I'm not sure this belongs here but since installing a release
   * belongs here then it seems prudent to keep the 2 together
   * since they need to match.
   *
   * @param {string} gamePath path to folder of game
   * @param {stirng} destPath path to save zip file.
   */
  var make = function(gamePath, destPath, callback) {
    // Make sure it's a game!
    var info = gameInfo.readGameInfo(gamePath);
    if (!info) {
      return false;
    }

    switch (info.happyFunTimes.gameType) {
      case 'html':
        break;
      default:
        console.error("unsupported gametype: " + info.happyFunTimes.gameType)
        break;
    }

    var fileNames = readDirTreeSync(gamePath, {filter: /^(?!\.)/});
    var zip = new ZipWriter();
    fileNames.forEach(function(fileName) {
      var zipName = path.join(info.happyFunTimes.gameId, fileName.substring(gamePath.length)).replace(/\\/g, '/');
      var stat = fs.statSync(fileName);
      if (stat.isDirectory()) {
        zip.addDir(zipName);
      } else {
        var buffer = fs.readFileSync(fileName);
        zip.addData(zipName, buffer);
      }
    });
    zip.saveAs(destPath, callback);
  };

  /**
   * @typedef {Object} Install~Options
   * @property {boolean?} overwrite default false. Install even if
   *           already installed. (not implemented)
   * @property {boolean?} verbose print extra info
   * @property {boolean?} dryRun true = don't write any files or
   *           make any folders.
   */

  /**
   * Installs a release.
   *
   * @param {string} releasePath path to zip file
   * @param {string?} opt_destPath path to where to install. If
   *        not provided default games path is used.
   * @param {Install~Options?} opt_options
   */
  var install = function(releasePath, opt_destPath, opt_options) {
    var options = opt_options || {};
    var log = options.verbose ? console.log.bind(console) : function() {};

    if (!strings.endsWith(releasePath, ".zip")) {
      // ToDo: Should we handle URLs? What about ids?
      console.error("Can't handle non zip files yet");
      return false;
    }

    var zip = new JSZip();
    zip.load(fs.readFileSync(releasePath));
    var entries = Object.keys(zip.files).sort().map(function(key) { return zip.files[key]; });
    var info;
    var packageBasePath;

    try {
      // Find the packageInfo
      for (var ii = 0; ii < entries.length; ++ii) {
        var entry = entries[ii];
        var baseName = path.basename(entry.name);
        var dirName = path.dirname(entry.name);
        if (dirName.indexOf("/") < 0 && baseName == "package.json") {
          info = gameInfo.parseGameInfo(entry.asText(), path.join(releasePath, entry.name));
          packageBasePath = dirName;
          break;
        }
      }
    } catch (e) {
      console.error("error " + e + ": could not parse package.json. Maybe this is not a HappyFunTimes game?");
      return false;
    }

    var hftInfo = info.happyFunTimes;
    var gameId = hftInfo.gameId;
    var destBasePath;

    // is it already installed?
    var installedGame = gameDB.getGameById(gameId);
    if (installedGame) {
      if (!options.overwrite) {
        console.error("game " + gameId + " already installed at: " + installedGame.happyFunTimes.basePath);
        return false;
      }
      destBasePath = installedGame.happyFunTimes.basePath
    } else {
      // make the dir after we're sure we're ready to install
      destBasePath = path.join(config.getConfig().gamesDir, info.happyFunTimes.gameId);
    }

    destBasePath = opt_destPath ? opt_destPath : destBasePath;

    console.log("installing to: " + destBasePath);
    if (!options.dryRun) {
      mkdirp.sync(destBasePath);
    }

    entries.forEach(function(entry) {
      var filePath = entry.name.substring(packageBasePath.length + 1);
      var destPath = path.join(destBasePath, filePath);
      if (entry.dir) {
        log("mkdir  : " + destPath);
        if (!options.dryRun) {
          mkdirp.sync(destPath);
        }
      } else {
        log("install: " + entry.name + " -> " + destPath);
        if (!options.dryRun) {
          fs.writeFileSync(destPath, entry.asNodeBuffer());
        }
      };
    });

    log("add: " + destBasePath);
    if (!options.dryRun) {
      games.add(destBasePath);
    }
  };

  /**
   * @typedef {Object} Download~Options
   * @property {boolean?} overwrite default false. Install even if
   *           already installed.
   * @property {boolean?} verbose print extra info
   * @property {boolean?} dryRun true = don't write any files or
   *           make any folders.
   * @property {string?} gamesUrl URL to get game info from.
   * @property {string?} version version of game to download?
   *           (not implemented)
   */

  /**
   * Downloads and installs a game by gameId
   * @param {string} gameId the gameId for the game
   * @param {string?} opt_destPath path to install game.
   * @param {Download~Options?) options
   */
  var download = function(gameId, opt_destPath, options) {
    // get game
    url = options.gamesUrl || config.getSettings().gamesUrl;
  };

  this.download = download.bind(this);
  this.install = install.bind(this);
  this.make = make.bind(this);
};

module.exports = new ReleaseManager();

<commit_msg>add file downloader<commit_after>/*
 * Copyright 2014, Gregg Tavares.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Gregg Tavares. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
"use strict";

var debug = require('debug')('release');
var ZipWriter = require("moxie-zip").ZipWriter;
var JSZip = require('jszip');
var events = require('events');
var fs = require('fs');
var path = require('path');
var http = require('http');
var https = require('https');
var url = require('url');
var mkdirp = require('mkdirp');
var gameInfo = require('../server/gameinfo');
var gameDB = require('../server/gamedb');
var games = require('../management/games');
var config = require('../server/config');
var strings = require('../server/strings');

var ReleaseManager = function() {

  var readDirTreeSync = function(filePath, options) {
    options = options || {};

    var filter = options.filter;
    if (filter === undefined) {
      filter = function() { return true; };
    } else if (filter instanceof RegExp) {
      filter = function(filter) {
        return function(filename) {
          return filter.test(filename);
        }
      }(filter);
    }

    var fileNames = fs.readdirSync(filePath).filter(filter).map(function(fileName) {
      return path.join(filePath, fileName);
    });

    var subdirFilenames = [];
    fileNames.forEach(function(fileName) {
      var stat = fs.statSync(fileName);
      if (stat.isDirectory()) {
        subdirFilenames.push(readDirTreeSync(fileName));
      }
    });

    subdirFilenames.forEach(function(subNames) {
      fileNames = fileNames.concat(subNames);
    });

    return fileNames;
  };

  // Remove this if Zip adds the filter.
//  var addLocalFolder = (function() {
//    var Utils = require('../node_modules/adm-zip/util/utils.js');
//    return function(zip, /*String*/localPath, /*String*/zipPath, /*RegExp|Function*/filter) {
//      if (filter === undefined) {
//        filter = function() { return true; };
//      } else if (filter instanceof RegExp) {
//        filter = function(filter) {
//          return function(filename) {
//            return filter.test(filename);
//          }
//        }(filter);
//      }
//
//      if(zipPath){
//          zipPath=zipPath.split("\\").join("/");
//          if(zipPath.charAt(zipPath.length - 1) != "/"){
//              zipPath += "/";
//          }
//      }else{
//          zipPath="";
//      }
//      localPath = localPath.split("\\").join("/"); //windows fix
//      if (localPath.charAt(localPath.length - 1) != "/")
//          localPath += "/";
//
//      if (fs.existsSync(localPath)) {
//
//          var items = Utils.findFiles(localPath);
//          if (items.length) {
//              items.forEach(function(path) {
//                  var p = path.split("\\").join("/").replace(localPath, ""); //windows fix
//                  if (filter(p)) {
//                      if (p.charAt(p.length - 1) !== "/") {
//                          zip.addFile(zipPath+p, fs.readFileSync(path), "", 0)
//                      } else {
//                          zip.addFile(zipPath+p, new Buffer(0), "", 0)
//                      }
//                  }
//              });
//          }
//      } else {
//          throw Utils.Errors.FILE_NOT_FOUND.replace("%s", localPath);
//      }
//    };
//  }());

  /**
   * Makes a release.
   *
   * I'm not sure this belongs here but since installing a release
   * belongs here then it seems prudent to keep the 2 together
   * since they need to match.
   *
   * @param {string} gamePath path to folder of game
   * @param {stirng} destPath path to save zip file.
   */
  var make = function(gamePath, destPath, callback) {
    // Make sure it's a game!
    var info = gameInfo.readGameInfo(gamePath);
    if (!info) {
      return false;
    }

    switch (info.happyFunTimes.gameType) {
      case 'html':
        break;
      default:
        console.error("unsupported gametype: " + info.happyFunTimes.gameType)
        break;
    }

    var fileNames = readDirTreeSync(gamePath, {filter: /^(?!\.)/});
    var zip = new ZipWriter();
    fileNames.forEach(function(fileName) {
      var zipName = path.join(info.happyFunTimes.gameId, fileName.substring(gamePath.length)).replace(/\\/g, '/');
      var stat = fs.statSync(fileName);
      if (stat.isDirectory()) {
        zip.addDir(zipName);
      } else {
        var buffer = fs.readFileSync(fileName);
        zip.addData(zipName, buffer);
      }
    });
    zip.saveAs(destPath, callback);
  };

  /**
   * @typedef {Object} Install~Options
   * @property {boolean?} overwrite default false. Install even if
   *           already installed. (not implemented)
   * @property {boolean?} verbose print extra info
   * @property {boolean?} dryRun true = don't write any files or
   *           make any folders.
   */

  /**
   * Installs a release.
   *
   * @param {string} releasePath path to zip file
   * @param {string?} opt_destPath path to where to install. If
   *        not provided default games path is used.
   * @param {Install~Options?} opt_options
   */
  var install = function(releasePath, opt_destPath, opt_options) {
    var options = opt_options || {};
    var log = options.verbose ? console.log.bind(console) : function() {};

    if (!strings.endsWith(releasePath, ".zip")) {
      // ToDo: Should we handle URLs? What about ids?
      console.error("Can't handle non zip files yet");
      return false;
    }

    var zip = new JSZip();
    zip.load(fs.readFileSync(releasePath));
    var entries = Object.keys(zip.files).sort().map(function(key) { return zip.files[key]; });
    var info;
    var packageBasePath;

    try {
      // Find the packageInfo
      for (var ii = 0; ii < entries.length; ++ii) {
        var entry = entries[ii];
        var baseName = path.basename(entry.name);
        var dirName = path.dirname(entry.name);
        if (dirName.indexOf("/") < 0 && baseName == "package.json") {
          info = gameInfo.parseGameInfo(entry.asText(), path.join(releasePath, entry.name));
          packageBasePath = dirName;
          break;
        }
      }
    } catch (e) {
      console.error("error " + e + ": could not parse package.json. Maybe this is not a HappyFunTimes game?");
      return false;
    }

    var hftInfo = info.happyFunTimes;
    var gameId = hftInfo.gameId;
    var destBasePath;

    // is it already installed?
    var installedGame = gameDB.getGameById(gameId);
    if (installedGame) {
      if (!options.overwrite) {
        console.error("game " + gameId + " already installed at: " + installedGame.happyFunTimes.basePath);
        return false;
      }
      destBasePath = installedGame.happyFunTimes.basePath
    } else {
      // make the dir after we're sure we're ready to install
      destBasePath = path.join(config.getConfig().gamesDir, info.happyFunTimes.gameId);
    }

    destBasePath = opt_destPath ? opt_destPath : destBasePath;

    console.log("installing to: " + destBasePath);
    if (!options.dryRun) {
      mkdirp.sync(destBasePath);
    }

    entries.forEach(function(entry) {
      var filePath = entry.name.substring(packageBasePath.length + 1);
      var destPath = path.join(destBasePath, filePath);
      if (entry.dir) {
        log("mkdir  : " + destPath);
        if (!options.dryRun) {
          mkdirp.sync(destPath);
        }
      } else {
        log("install: " + entry.name + " -> " + destPath);
        if (!options.dryRun) {
          fs.writeFileSync(destPath, entry.asNodeBuffer());
        }
      };
    });

    log("add: " + destBasePath);
    if (!options.dryRun) {
      games.add(destBasePath);
    }
  };

  /**
   * @typedef {Object} Download~Options
   * @property {boolean?} overwrite default false. Install even if
   *           already installed.
   * @property {boolean?} verbose print extra info
   * @property {boolean?} dryRun true = don't write any files or
   *           make any folders.
   * @property {string?} gamesUrl URL to get game info from.
   * @property {string?} version version of game to download?
   *           (not implemented)
   */

  /**
   * Downloads and installs a game by gameId
   * @param {string} gameId the gameId for the game
   * @param {string?} opt_destPath path to install game.
   * @param {Download~Options?) options
   */
  var download = function(gameId, opt_destPath, options) {
    // get game
    var url = options.gamesUrl || config.getSettings().gamesUrl;
  };

  /**
   * Downloads a url to the specified path
   * @param {string} srcUrl url to download
   * @param {string} destPath path to store file
   * @returns {EventEmitter} emitter for events.
   *
   * Events are:
   *   'start': {size: number, bytesDownloaded: number},
   *   'progress': {size: number, bytesDownloaded: number},
   *   'end': {size: number, bytesDownloaded: number},
   *   'error': ??,
   */
  var downloadFile = function(srcUrl, destPath) {
    var depth = 0;

    var doDownload = function(srcUrl, destPath, eventEmitter) {
      debug("DL: " + srcUrl);
      eventEmitter = eventEmitter || new events.EventEmitter();

      ++depth;
      if (depth > 5) {
        eventEmitter.emit('error', "too many redirects");
        return eventEmitter;
      }

      var parsedUrl = url.parse(srcUrl);

      var requestType;
      switch (parsedUrl.protocol) {
        case 'http:':
          requestType = http.request.bind(http);
          break;
        case 'https:':
          requestType = https.request.bind(http);
          break;
        default:
          // Need to use setTimeout in case this is the first time in here otherwise
          // we'd call the event before the user has a chance to register listeners.
          setTimeout(function() {
            eventEmitter.emit('error', "unhandled protocol: " + parsedUrl.protocol);
          }, 0);
          return eventEmitter;
      }

      var request = requestType({
        hostname: parsedUrl.hostname,
        port: parsedUrl.port,
        path: parsedUrl.pathname,
      });

      var stream;

      request.on('response', function (response) {
        switch (response.statusCode) {
          case 200:
            break;
          case 301:
          case 302:
          case 307:
          case 308:
            doDownload(response.headers["location"].toString(), destPath, eventEmitter);
            return;
          case 404:
            eventEmitter.emit('error', "url not found:" + srcUrl);
            return;
          default:
            eventEmitter.emit('error', "unhandled status code:" + response.statusCode);
            debug(JSON.stringify(response.headers, undefined, "  "));
            return;
        }
        var bytesDownloaded = 0;
        var totalBytes = response.headers['content-length'];
        stream = fs.createWriteStream(destPath);
        stream.on('error', function(e) {
          eventEmitter.emit('error', "error writing to file: " + destPath + "\n" + e);
          request.abort();
        });

        eventEmitter.emit('start', {size: totalBytes, bytesDownloaded: bytesDownloaded});
        response.on('data', function (chunk) {
          bytesDownloaded += chunk.length;
          eventEmitter.emit('progress', {size: totalBytes, bytesDownloaded: bytesDownloaded});
          stream.write(chunk);
        });

        response.on('end', function() {
          eventEmitter.emit('progress', {size: totalBytes, bytesDownloaded: bytesDownloaded});
          stream.end(undefined, undefined, function() {
            eventEmitter.emit('end', {size: totalBytes, bytesDownloaded: bytesDownloaded});
          });
        });

      });

      request.on('error', function(err) {
        if (stream) {
          stream.end();
          fs.unlinkSync(destPath);
        }
        eventEmitter.emit('error', err);
      });

      request.end();
      return eventEmitter;
    }

    return doDownload.apply(this, arguments);
  };

  this.download = download.bind(this);
  this.downloadFile = downloadFile.bind(this);
  this.install = install.bind(this);
  this.make = make.bind(this);
};

module.exports = new ReleaseManager();

<|endoftext|>