<commit_before>// base svg chart, which auto resizes to fit containing element

define(['d3', 'lodash', 'baseChart', 'heatMap', 'legend'], function(d3, _, BaseChart, HeatMap, Legend) {return function($chartNode, customOptions, extendedEvents) {

  var ROW_COUNT = 7;
  var COL_COUNT = 24;
  var LEGEND_COUNT = 5;
  var LEGEND_HEIGHT = 30;
  var LEGEND_WIDTH = LEGEND_HEIGHT * LEGEND_COUNT;

  var model = null;
  var sensors = null;
  var localEvents = [];
  var localOptions = {};
  var dimensions = null;
  var width = null;
  var height = null;
  var svg = null;

  var baseChart = new BaseChart($chartNode, localOptions, localEvents);
  baseChart.visualize = visualize;
  baseChart.setOptions(customOptions);
  baseChart.on('chartResize', onResize);

  var margin = {top: 130, right: 20, bottom: 20, left: 20};
  var cityScale = d3.scale.ordinal();
  var sensorScale = d3.scale.ordinal();
  var colorScale = d3.scale.category10();
  var offset = 0;
  var cityOrder = {
	  'San Francisco': 0,
	  'Boston': 1,
	  'Rio de Janeiro': 2,
	  'Genève': 3,
	  'ಬೆಂಗಳೂರು': 4,
	  'Republik Singapura': 5,
	  '上海市': 6
  };

  function initialize() {

    baseChart.initialize();
    onResize(baseChart.getDimensions());

    svg = baseChart.getContainer()
      .append('g')
      .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  }

  function setData(data) {
    var cityMap = d3.nest()
      .key(function(d) { return d.city_name; })
      .map(data);

    var cityNames = Object.keys(cityMap).sort(function(a,b){
      return cityOrder[a] - cityOrder[b];
    });

    //cityNames = [cityNames[0]];

    cityScale.domain(cityNames);
    sensorScale.domain(SENSORS);

    sensors = SENSORS.map(function(sensor, i) {

      var extent = d3.extent(data, function(d) {return d[sensor];});
      var color = d3.scale.linear().range(['white', colorScale(sensor)]).domain(extent);
      var sensorGroup = svg.append('g').classed(sensor, true);

      var cities = cityNames.map(function(name) {
        var group = sensorGroup.append('g').classed(name, true);
        var details = CITY_DETAILS[name];
        var yFormat = function(d) {return details.format(new Date(d));};

        if (i == 0) {
          group.append('text')
            .classed('city-title', true).text(name)
            .attr('dy', '.9em');
        }

        var hours = d3.range(COL_COUNT);
        var xScale = d3.scale.ordinal().domain(hours);
        var yScale = d3.scale.ordinal();

        var options = {margin: {top: 40, bottom: 0, left: 48, right: 0}};
        var city = {
          name: name,
          group: group,
          map: new HeatMap(group, options),
          data: cityMap[name],
          xAxis: d3.svg.axis().scale(xScale).orient('top' ).tickValues(hours),
          yAxis: d3.svg.axis().scale(yScale).orient('left').tickPadding(10).tickFormat(yFormat)
        };

        return city;
      });

      var sensorPack = {
        name: sensor,
        extent: extent,
        color: color,
        group: sensorGroup,
        cities: cities
      };

      setSensorTitle(sensorPack);
      return sensorPack;
    });

    baseChart.setDimensions();
  }

  function sensorTitle(sensor) {
    return SENSOR_DETAILS[sensor].title + '  ' + SENSOR_DETAILS[sensor].unit + '';
  }

  function setSensorTitle(sensor) {
    sensor.legendG = sensor.group.append('g')
      .classed('legend', true);

    sensor.legend = new Legend(sensor.legendG)
      .color(sensor.color)
      .setData(sensor.extent, LEGEND_COUNT);

    sensor.title = sensor.group.append('text')
      .classed('type-title', true)
      .attr('text-anchor', 'middle')
      .attr('y', margin.top * -0.4)
      .attr('opacity', 0)
      .attr('dy', '-.2em');

    sensor.title
      .transition()
      .attr('opacity', 0)
      .transition()
      .duration(0)
      .text(sensorTitle(sensor.name))
      .transition()
      .duration(TRANSITION_DURATION / 3)
      .attr('opacity', 1);
  }

  var timeFormat = d3.time.format('%H');
  var dateFormat = d3.time.format('%e %b');

  function setFrame(date) {
    sensors.forEach(function(sensor){
        sensor.cities.forEach(function(city) {
          var yAxisValues = d3.range(ROW_COUNT).map(function(d, i) {
            return date.getTime() + i * MS_INA_DAY;
          });
          city.yAxis.scale().domain(yAxisValues);
          city.yAxis.tickValues(yAxisValues);

          city.map
            .color(function(d) {
              var value = d[sensor.name];
              return  value !== undefined && !isNaN(value) ? sensor.color(value) : NO_DATA_COLOR;
            })
            .setData(model.oneWeek(city.name, date), COL_COUNT, idAccess, city.xAxis, city.yAxis);
        });
    });

    visualize();
  }

  function idAccess(d) {
    return d.id;
  }

  function onResize(_dimensions) {
    dimensions = _dimensions;
    width = dimensions.width - (margin.left + margin.right);
    height = dimensions.height - (margin.top + margin.bottom);
    cityScale.rangeBands([0, height], 0.02, 0);
    sensorScale.rangeBands([0, width], 0, 0);

    if (!sensors) {return;}

    sensors.forEach(function(sensor) {
      sensor.title
        .attr('x', sensorScale.rangeBand() / 2);

      var legendPos = [(sensorScale.rangeBand() - LEGEND_WIDTH) / 2, -LEGEND_HEIGHT - 10];

      sensor.legendG.attr('transform', 'translate(' + legendPos + ')');
      sensor.legend.visualize(LEGEND_WIDTH, LEGEND_HEIGHT);
    });

    visualize();
  }

  function visualize() {
    if (!svg || !sensors) return;

    sensors.forEach(function(sensor) {
      sensor.group
        .transition()
        .duration(TRANSITION_DURATION)
        .attr('transform', 'translate(' + [sensorScale(sensor.name), 0] + ')');

      sensor.cities.forEach(function(city) {
        city.group
          .transition()
          .duration(TRANSITION_DURATION)
          .attr('transform', 'translate(0, ' + cityScale(city.name) + ')');
        city.map.visualize(sensorScale.rangeBand(), cityScale.rangeBand());
      });
    });
  }

  function setModel(_model) {
    model = _model;
  }

  // exports

  var exports = {
    setData: setData,
    setModel: setModel,
    setFrame: setFrame
  };

  initialize(CITIES);
  return $.extend(exports, baseChart);
};});
<commit_msg>refactor for speed<commit_after>// base svg chart, which auto resizes to fit containing element

define(['d3', 'lodash', 'baseChart', 'heatMap', 'legend'], function(d3, _, BaseChart, HeatMap, Legend) {return function($chartNode, customOptions, extendedEvents) {

  var ROW_COUNT = 7;
  var COL_COUNT = 24;
  var LEGEND_COUNT = 5;
  var LEGEND_HEIGHT = 30;
  var LEGEND_WIDTH = LEGEND_HEIGHT * LEGEND_COUNT;

  var model = null;
  var sensors = null;
  var localEvents = [];
  var localOptions = {};
  var dimensions = null;
  var width = null;
  var height = null;
  var svg = null;

  var baseChart = new BaseChart($chartNode, localOptions, localEvents);
  baseChart.visualize = visualize;
  baseChart.setOptions(customOptions);
  baseChart.on('chartResize', onResize);

  var margin = {top: 130, right: 20, bottom: 20, left: 20};
  var cityScale = d3.scale.ordinal();
  var sensorScale = d3.scale.ordinal();
  var colorScale = d3.scale.category10();
  var offset = 0;
  var cityOrder = {
	  'San Francisco': 0,
	  'Boston': 1,
	  'Rio de Janeiro': 2,
	  'Genève': 3,
	  'ಬೆಂಗಳೂರು': 4,
	  'Republik Singapura': 5,
	  '上海市': 6
  };

  function initialize() {

    baseChart.initialize();
    onResize(baseChart.getDimensions());

    svg = baseChart.getContainer()
      .append('g')
      .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  }

  function setData(data) {
    var cityMap = d3.nest()
      .key(function(d) { return d.city_name; })
      .map(data);

    var cityNames = Object.keys(cityMap).sort(function(a,b){
      return cityOrder[a] - cityOrder[b];
    });

    //cityNames = [cityNames[0]];

    cityScale.domain(cityNames);
    sensorScale.domain(SENSORS);

    sensors = SENSORS.map(function(sensor, i) {

      var extent = d3.extent(data, function(d) {return d[sensor];});
      var color = d3.scale.linear().range(['white', colorScale(sensor)]).domain(extent);
      var sensorGroup = svg.append('g').classed(sensor, true);

      var cities = cityNames.map(function(name) {
        var group = sensorGroup.append('g').classed(name, true);
        var details = CITY_DETAILS[name];
        var yFormat = function(d) {return details.format(new Date(d));};

        if (i == 0) {
          group.append('text')
            .classed('city-title', true).text(name)
            .attr('dy', '.9em');
        }

        var hours = d3.range(COL_COUNT);
        var xScale = d3.scale.ordinal().domain(hours);
        var yScale = d3.scale.ordinal();

        var options = {margin: {top: 40, bottom: 0, left: 48, right: 0}};
        var city = {
          name: name,
          group: group,
          heatmap: new HeatMap(group, options),
          data: cityMap[name],
          xAxis: d3.svg.axis().scale(xScale).orient('top' ).tickValues(hours),
          yAxis: d3.svg.axis().scale(yScale).orient('left').tickPadding(10).tickFormat(yFormat)
        };

        return city;
      });

      var sensorPack = {
        name: sensor,
        extent: extent,
        color: color,
        group: sensorGroup,
        cities: cities
      };

      setSensorTitle(sensorPack);
      return sensorPack;
    });

    baseChart.setDimensions();
  }

  function sensorTitle(sensor) {
    return SENSOR_DETAILS[sensor].title + '  ' + SENSOR_DETAILS[sensor].unit + '';
  }

  function setSensorTitle(sensor) {
    sensor.legendG = sensor.group.append('g')
      .classed('legend', true);

    sensor.legend = new Legend(sensor.legendG)
      .color(sensor.color)
      .setData(sensor.extent, LEGEND_COUNT);

    sensor.title = sensor.group.append('text')
      .classed('type-title', true)
      .attr('text-anchor', 'middle')
      .attr('y', margin.top * -0.4)
      .attr('opacity', 0)
      .attr('dy', '-.2em');

    sensor.title
      .transition()
      .attr('opacity', 0)
      .transition()
      .duration(0)
      .text(sensorTitle(sensor.name))
      .transition()
      .duration(TRANSITION_DURATION / 3)
      .attr('opacity', 1);
  }

  var timeFormat = d3.time.format('%H');
  var dateFormat = d3.time.format('%e %b');

  function setFrame(date) {
    sensors.forEach(function(sensor){
        sensor.cities.forEach(function(city) {
          var yAxisValues = d3.range(ROW_COUNT).map(function(d, i) {
            return date.getTime() + i * MS_INA_DAY;
          });
          city.yAxis.scale().domain(yAxisValues);
          city.yAxis.tickValues(yAxisValues);

          city.heatmap
            .color(function(d) {
              var value = d[sensor.name];
              return  value !== undefined && !isNaN(value) ? sensor.color(value) : NO_DATA_COLOR;
            })
            .setData(model.oneWeek(city.name, date), COL_COUNT, idAccess, city.xAxis, city.yAxis);
        });
    });

    visualize();
  }

  function idAccess(d) {
    return d.id;
  }

  function onResize(_dimensions) {
    dimensions = _dimensions;
    width = dimensions.width - (margin.left + margin.right);
    height = dimensions.height - (margin.top + margin.bottom);
    cityScale.rangeBands([0, height], 0.02, 0);
    sensorScale.rangeBands([0, width], 0, 0);

    if (!sensors) {return;}

    sensors.forEach(function(sensor) {
      sensor.title
        .attr('x', sensorScale.rangeBand() / 2);

      var legendPos = [(sensorScale.rangeBand() - LEGEND_WIDTH) / 2, -LEGEND_HEIGHT - 10];

      sensor.legendG.attr('transform', 'translate(' + legendPos + ')');
      sensor.legend.visualize(LEGEND_WIDTH, LEGEND_HEIGHT);
    });

    sensors.forEach(function(sensor) {
      sensor.group
        .transition()
        .duration(TRANSITION_DURATION)
        .attr('transform', 'translate(' + [sensorScale(sensor.name), 0] + ')');

      sensor.cities.forEach(function(city) {
        city.group
          .transition()
          .duration(TRANSITION_DURATION)
          .attr('transform', 'translate(0, ' + cityScale(city.name) + ')');
        city.heatmap.visualize(sensorScale.rangeBand(), cityScale.rangeBand());
      });
    });

    visualize();
  }

  function visualize() {
    if (!svg || !sensors) return;

    sensors.forEach(function(sensor) {
      sensor.cities.forEach(function(city) {
        city.heatmap.visualize(sensorScale.rangeBand(), cityScale.rangeBand());
      });
    });
  }

  function setModel(_model) {
    model = _model;
  }

  // exports

  var exports = {
    setData: setData,
    setModel: setModel,
    setFrame: setFrame
  };

  initialize(CITIES);
  return $.extend(exports, baseChart);
};});
<|endoftext|>


<commit_before>"use strict";

const Clutter = imports.gi.Clutter;
const ExtensionUtils = imports.misc.extensionUtils;
const Gio = imports.gi.Gio;
const GnomeDesktop = imports.gi.GnomeDesktop;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Main = imports.ui.main;
const Me = ExtensionUtils.getCurrentExtension();
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const St = imports.gi.St;

const Convenience = Me.imports.convenience;

let UTCClock = GObject.registerClass(
    class UTCCLock extends PanelMenu.Button {

        _init() {
            super._init(0, "UTCClock", false);

            // Label
            this.timeText = new St.Label({
                y_align: Clutter.ActorAlign.CENTER,
                text: "..."
            });

            let topBox = new St.BoxLayout();
            topBox.add_actor(this.timeText);
            this.add_actor(topBox);

            this.enable();
        }

        updateTime() {
            let now = new Date();
            let utc = new Date(
                now.getUTCFullYear(),
                now.getUTCMonth(),
                now.getUTCDate(),
                now.getUTCHours(),
                now.getUTCMinutes(),
                now.getUTCSeconds()
            );
            this.timeText.set_text(
                new Intl.DateTimeFormat(
                    "default", this.format_params
                ).format(utc) + " " + this.time_text
            );
        }

        setSecondsDisplayed() {
            let secondsDisplayed = this.settings.get_boolean("show-seconds");
            if (secondsDisplayed) {
                this.format_params["second"] = "2-digit";
            } else {
                delete this.format_params["second"];
            }
            this.updateTime();
        }

        setTimeText() {
            this.time_text = this.settings.get_string("time-text");
            this.updateTime();
        }

        setDateDisplayed() {
            let dateDisplayed = this.settings.get_boolean("show-date");
            if (dateDisplayed) {
                this.format_params["weekday"] = "short";
                this.format_params["month"] = "short";
                this.format_params["day"] = "numeric";
            } else {
                delete this.format_params["weekday"];
                delete this.format_params["month"];
                delete this.format_params["day"];
            }
            this.updateTime();
        }

        setLightOpacity() {
            this.timeText.opacity =
                this.settings.get_boolean("light-opacity") ? 200 : 255;
            this.updateTime();
        }

        buildMenu() {
            this.ClockMenuItemSeconds = new PopupMenu.PopupSwitchMenuItem(
                "Show seconds",
                this.settings.get_boolean("show-seconds"),
                { reactive: true }
            );
            this.menuSignal1 = this.ClockMenuItemSeconds.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("show-seconds", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemSeconds);

            this.ClockMenuItemText = new PopupMenu.PopupSubMenuMenuItem(
                "Time text to show"
            );
            this.PopupMenuItemUTC = new PopupMenu.PopupMenuItem("UTC");
            this.menuSignal2 = this.PopupMenuItemUTC.connect('activate', () => {
                this.settings.set_string("time-text", "UTC");
            });
            this.ClockMenuItemText.menu.addMenuItem(this.PopupMenuItemUTC);
            this.PopupMenuItemGMT = new PopupMenu.PopupMenuItem("GMT");
            this.menuSignal3 = this.PopupMenuItemGMT.connect('activate', () => {
                this.settings.set_string("time-text", "GMT");
            });
            this.ClockMenuItemText.menu.addMenuItem(this.PopupMenuItemGMT);
            this.PopupMenuItemZ = new PopupMenu.PopupMenuItem("Z");
            this.menuSignal4 = this.PopupMenuItemZ.connect('activate', () => {
                this.settings.set_string("time-text", "Z");
            });
            this.ClockMenuItemText.menu.addMenuItem(this.PopupMenuItemZ);
            this.menu.addMenuItem(this.ClockMenuItemText);

            this.ClockMenuItemDate = new PopupMenu.PopupSwitchMenuItem(
                "Show date",
                this.settings.get_boolean("show-date"),
                { reactive: true }
            );
            this.menuSignal5 = this.ClockMenuItemDate.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("show-date", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemDate);

            this.ClockMenuItemOpacity = new PopupMenu.PopupSwitchMenuItem(
                "Light opacity",
                this.settings.get_boolean("light-opacity"),
                { reactive: true }
            );
            this.menuSignal6 = this.ClockMenuItemOpacity.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("light-opacity", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemOpacity);
            this.menuSignal7 = this.connect(
                "button-press-event",
                Lang.bind(
                    this, function() {
                        if (this.gnomeSecondsSettings.get_boolean("clock-show-seconds"))
                            this.ClockMenuItemSeconds.set_reactive(true);
                        else {
                            this.ClockMenuItemSeconds._switch.state = false;
                            this.ClockMenuItemSeconds.set_reactive(false);
                        }
                    }
                )
            );
        }

        enable() {
            this.time_text = "UTC";

            this.format_params = {
                hour: "2-digit",
                minute: "2-digit",
                hour12: false
            }

            this.settings = Convenience.getSettings();
            this.gnomeSecondsSettings = Convenience.getSettings(
                "org.gnome.desktop.interface"
            );

            this.gnomeSecondsSignal =  this.gnomeSecondsSettings.connect(
                "changed::clock-show-seconds",
                Lang.bind(this, function() {
                    if (!this.gnomeSecondsSettings.get_boolean("clock-show-seconds")) {
                        this.settings.set_boolean("show-seconds", false);
                        this.setSecondsDisplayed();
                    }
                })
            );

            this.settingsSignals = [];

            this.clock = new GnomeDesktop.WallClock();
            this.clocksignal = this.clock.connect(
                "notify::clock",
                Lang.bind(this, this.updateTime)
            );

            if (!this.gnomeSecondsSettings.get_boolean("clock-show-seconds"))
                this.settings.set_boolean("show-seconds", false);
            this.setSecondsDisplayed();
            this.settingsSignals[0] = this.settings.connect(
                "changed::show-seconds",
                Lang.bind(this, this.setSecondsDisplayed)
            );

            this.setTimeText();
            this.settingsSignals[1] = this.settings.connect("changed::time-text",
                this.setTimeText.bind(this)
            );

            this.setDateDisplayed();
            this.settingsSignals[2] = this.settings.connect(
                "changed::show-date",
                Lang.bind(this, this.setDateDisplayed)
            );

            this.setLightOpacity();
            this.settingsSignals[3] = this.settings.connect(
                "changed::light-opacity",
                Lang.bind(this, this.setLightOpacity)
            );

            this.buildMenu();
        }

        disable() {
            this.clock.disconnect(this.clocksignal);
            this.gnomeSecondsSettings.disconnect(this.gnomeSecondsSignal);
            this.settings.disconnect(this.settingsSignals[0]);
            this.settings.disconnect(this.settingsSignals[1]);
            this.settings.disconnect(this.settingsSignals[2]);
            this.settings.disconnect(this.settingsSignals[3]);
            this.ClockMenuItemSeconds.disconnect(this.menuSignal1);
            this.PopupMenuItemUTC.disconnect(this.menuSignal2);
            this.PopupMenuItemGMT.disconnect(this.menuSignal3);
            this.PopupMenuItemZ.disconnect(this.menuSignal4);
            this.ClockMenuItemDate.disconnect(this.menuSignal5);
            this.ClockMenuItemOpacity.disconnect(this.menuSignal6);
            this.disconnect(this.menuSignal7);
        }
    }
);

let utcclock;

function init() {

}

function enable() {
    utcclock = new UTCClock();
    Main.panel._addToPanelBox("utcclock", utcclock, 1, Main.panel._centerBox);
}

function disable() {
    utcclock.disable();
    utcclock.destroy();
}<commit_msg>Removed Lang on seconds listener<commit_after>"use strict";

const Clutter = imports.gi.Clutter;
const ExtensionUtils = imports.misc.extensionUtils;
const Gio = imports.gi.Gio;
const GnomeDesktop = imports.gi.GnomeDesktop;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Main = imports.ui.main;
const Me = ExtensionUtils.getCurrentExtension();
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const St = imports.gi.St;

const Convenience = Me.imports.convenience;

let UTCClock = GObject.registerClass(
    class UTCCLock extends PanelMenu.Button {

        _init() {
            super._init(0, "UTCClock", false);

            // Label
            this.timeText = new St.Label({
                y_align: Clutter.ActorAlign.CENTER,
                text: "..."
            });

            let topBox = new St.BoxLayout();
            topBox.add_actor(this.timeText);
            this.add_actor(topBox);

            this.enable();
        }

        updateTime() {
            let now = new Date();
            let utc = new Date(
                now.getUTCFullYear(),
                now.getUTCMonth(),
                now.getUTCDate(),
                now.getUTCHours(),
                now.getUTCMinutes(),
                now.getUTCSeconds()
            );
            this.timeText.set_text(
                new Intl.DateTimeFormat(
                    "default", this.format_params
                ).format(utc) + " " + this.time_text
            );
        }

        setSecondsDisplayed() {
            let secondsDisplayed = this.settings.get_boolean("show-seconds");
            if (secondsDisplayed) {
                this.format_params["second"] = "2-digit";
            } else {
                delete this.format_params["second"];
            }
            this.updateTime();
        }

        setTimeText() {
            this.time_text = this.settings.get_string("time-text");
            this.updateTime();
        }

        setDateDisplayed() {
            let dateDisplayed = this.settings.get_boolean("show-date");
            if (dateDisplayed) {
                this.format_params["weekday"] = "short";
                this.format_params["month"] = "short";
                this.format_params["day"] = "numeric";
            } else {
                delete this.format_params["weekday"];
                delete this.format_params["month"];
                delete this.format_params["day"];
            }
            this.updateTime();
        }

        setLightOpacity() {
            this.timeText.opacity =
                this.settings.get_boolean("light-opacity") ? 200 : 255;
            this.updateTime();
        }

        buildMenu() {
            this.ClockMenuItemSeconds = new PopupMenu.PopupSwitchMenuItem(
                "Show seconds",
                this.settings.get_boolean("show-seconds"),
                { reactive: true }
            );
            this.menuSignal1 = this.ClockMenuItemSeconds.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("show-seconds", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemSeconds);

            this.ClockMenuItemText = new PopupMenu.PopupSubMenuMenuItem(
                "Time text to show"
            );
            this.PopupMenuItemUTC = new PopupMenu.PopupMenuItem("UTC");
            this.menuSignal2 = this.PopupMenuItemUTC.connect('activate', () => {
                this.settings.set_string("time-text", "UTC");
            });
            this.ClockMenuItemText.menu.addMenuItem(this.PopupMenuItemUTC);
            this.PopupMenuItemGMT = new PopupMenu.PopupMenuItem("GMT");
            this.menuSignal3 = this.PopupMenuItemGMT.connect('activate', () => {
                this.settings.set_string("time-text", "GMT");
            });
            this.ClockMenuItemText.menu.addMenuItem(this.PopupMenuItemGMT);
            this.PopupMenuItemZ = new PopupMenu.PopupMenuItem("Z");
            this.menuSignal4 = this.PopupMenuItemZ.connect('activate', () => {
                this.settings.set_string("time-text", "Z");
            });
            this.ClockMenuItemText.menu.addMenuItem(this.PopupMenuItemZ);
            this.menu.addMenuItem(this.ClockMenuItemText);

            this.ClockMenuItemDate = new PopupMenu.PopupSwitchMenuItem(
                "Show date",
                this.settings.get_boolean("show-date"),
                { reactive: true }
            );
            this.menuSignal5 = this.ClockMenuItemDate.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("show-date", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemDate);

            this.ClockMenuItemOpacity = new PopupMenu.PopupSwitchMenuItem(
                "Light opacity",
                this.settings.get_boolean("light-opacity"),
                { reactive: true }
            );
            this.menuSignal6 = this.ClockMenuItemOpacity.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("light-opacity", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemOpacity);
            this.menuSignal7 = this.connect(
                "button-press-event",
                Lang.bind(
                    this, function() {
                        if (this.gnomeSecondsSettings.get_boolean("clock-show-seconds"))
                            this.ClockMenuItemSeconds.set_reactive(true);
                        else {
                            this.ClockMenuItemSeconds._switch.state = false;
                            this.ClockMenuItemSeconds.set_reactive(false);
                        }
                    }
                )
            );
        }

        enable() {
            this.time_text = "UTC";

            this.format_params = {
                hour: "2-digit",
                minute: "2-digit",
                hour12: false
            }

            this.settings = Convenience.getSettings();
            this.gnomeSecondsSettings = Convenience.getSettings(
                "org.gnome.desktop.interface"
            );

            this.gnomeSecondsSignal =  this.gnomeSecondsSettings.connect(
                "changed::clock-show-seconds",
                Lang.bind(this, function() {
                    if (!this.gnomeSecondsSettings.get_boolean("clock-show-seconds")) {
                        this.settings.set_boolean("show-seconds", false);
                        this.setSecondsDisplayed();
                    }
                })
            );

            this.settingsSignals = [];

            this.clock = new GnomeDesktop.WallClock();
            this.clockSignal = this.clock.connect(
                "notify::clock",
                this.updateTime.bind(this)
            );

            if (!this.gnomeSecondsSettings.get_boolean("clock-show-seconds"))
                this.settings.set_boolean("show-seconds", false);
            this.setSecondsDisplayed();
            this.settingsSignals[0] = this.settings.connect(
                "changed::show-seconds",
                Lang.bind(this, this.setSecondsDisplayed)
            );

            this.setTimeText();
            this.settingsSignals[1] = this.settings.connect("changed::time-text",
                this.setTimeText.bind(this)
            );

            this.setDateDisplayed();
            this.settingsSignals[2] = this.settings.connect(
                "changed::show-date",
                Lang.bind(this, this.setDateDisplayed)
            );

            this.setLightOpacity();
            this.settingsSignals[3] = this.settings.connect(
                "changed::light-opacity",
                Lang.bind(this, this.setLightOpacity)
            );

            this.buildMenu();
        }

        disable() {
            this.clock.disconnect(this.clockSignal);
            this.gnomeSecondsSettings.disconnect(this.gnomeSecondsSignal);
            this.settings.disconnect(this.settingsSignals[0]);
            this.settings.disconnect(this.settingsSignals[1]);
            this.settings.disconnect(this.settingsSignals[2]);
            this.settings.disconnect(this.settingsSignals[3]);
            this.ClockMenuItemSeconds.disconnect(this.menuSignal1);
            this.PopupMenuItemUTC.disconnect(this.menuSignal2);
            this.PopupMenuItemGMT.disconnect(this.menuSignal3);
            this.PopupMenuItemZ.disconnect(this.menuSignal4);
            this.ClockMenuItemDate.disconnect(this.menuSignal5);
            this.ClockMenuItemOpacity.disconnect(this.menuSignal6);
            this.disconnect(this.menuSignal7);
        }
    }
);

let utcclock;

function init() {

}

function enable() {
    utcclock = new UTCClock();
    Main.panel._addToPanelBox("utcclock", utcclock, 1, Main.panel._centerBox);
}

function disable() {
    utcclock.disable();
    utcclock.destroy();
}<|endoftext|>


<commit_before>describe 'Authored Scripts'

  before_each
    breadModel('clear');
    sparks.sparksSectionController.reset();
    sparks.sparksActivityController.reset();
  end

  describe 'Question Answers'

      it 'should be able to use scripts to define distractors'
        breadModel('insertComponent', 'resistor', {"UID": "r1", "connections": "a1,a2", "colors": "orange,black,brown,gold"});

        var jsonSection =
          {
            "pages":[
              {
                "questions": [
                  {
                    "prompt": "What is the resistance of R1?",
                    "correct_answer": "[if (r1.nominalResistance < 500) {'R1 is small'} else {'R1 is big'}]",
                    "correct_units": "ohms"
                  },
                  {
                    "prompt": "What is the resistance of R1?",
                    "correct_answer": "[if (r1.nominalResistance != 300) {'R1 is not 300'} else {'R1 is 300'}]",
                    "correct_units": "ohms"
                  }
                ]
              }
            ]
          };

          var ac = new sparks.ActivityConstructor(jsonSection);
          var section = sparks.sparksActivityController.currentSection;

          section.pages[0].questions.length.should.be 2
          section.pages[0].questions[0].correct_answer.should.be "R1 is small"
          section.pages[0].questions[1].correct_answer.should.be "R1 is 300"
      end

  end

  describe 'Question Grading'
    it 'should be able to grade student answers using simple scripts'
      var jsonSection =
        {
          "pages":[
            {
              "questions": [
                {
                    "prompt": "What is the resistance of R1?",
                    "points": 5,
                    "scoring": "if (question.answer == 10) {question.points_earned = 5} else {question.points_earned = 0}"
                },
                {
                    "prompt": "What is the resistance of R2?",
                    "points": 5,
                    "scoring": "if (question.answer == 20) {question.points_earned = 5} else {question.points_earned = 3}"
                }
              ]
            }
          ]
        };

      var ac = new sparks.ActivityConstructor(jsonSection);
      var section = sparks.sparksActivityController.currentSection;

      section.pages[0].questions[0].answer = "10"
      section.pages[0].questions[1].answer = "500"

      $.each(section.pages[0].questions, function(i, question){
        sparks.sparksQuestionController.gradeQuestion(question);
      });

      section.pages[0].questions[0].answerIsCorrect.should.be true
      section.pages[0].questions[0].points_earned.should.be 5
      section.pages[0].questions[1].answerIsCorrect.should.be false
      section.pages[0].questions[1].points_earned.should.be 3
    end

    it 'should be able to grade student answers using scripts with circuit variables'

      breadModel('insertComponent', 'resistor', {"UID": "r1", "resistance": "100"});
      breadModel('insertComponent', 'resistor', {"UID": "r2", "resistance": "200"});
      var jsonSection =
        {
          "pages":[
            {
              "questions": [
                {
                    "prompt": "What is the resistance of R1?",
                    "points": 5,
                    "scoring": "if (question.answer == r1.resistance) {question.points_earned = 5} else {question.points_earned = 0}"
                },
                {
                    "prompt": "What is the resistance of R2?",
                    "points": 5,
                    "scoring": "if (question.answer == r2.resistance) {question.points_earned = 5} else {question.points_earned = 0}"
                }
              ]
            }
          ]
        };

      var ac = new sparks.ActivityConstructor(jsonSection);
      var section = sparks.sparksActivityController.currentSection;

      section.pages[0].questions[0].answer = "100"
      section.pages[0].questions[1].answer = "500"

      $.each(section.pages[0].questions, function(i, question){
        sparks.sparksQuestionController.gradeQuestion(question);
      });

      section.pages[0].questions[0].answerIsCorrect.should.be true
      section.pages[0].questions[0].points_earned.should.be 5
      section.pages[0].questions[1].answerIsCorrect.should.be false
      section.pages[0].questions[1].points_earned.should.be 0
    end

    it 'should be able to find faults from within a script'

      breadModel('insertComponent', 'resistor', {"UID": "r1", "resistance": "100"});
      breadModel('insertComponent', 'resistor', {"UID": "r2", "resistance": "200", "open": true});
      var jsonSection =
        {
          "pages":[
            {
              "questions": [
                {
                    "prompt": "Which resistor is faulty?",
                    "points": 5,
                    "scoring": "console.log(breadboard.getFault().UID); if (question.answer == breadboard.getFault().UID) {question.points_earned = 5}"
                },
                {
                    "prompt": "List the faulty resistors in the feedback...",
                    "points": 5,
                    "scoring": "question.feedback = breadboard.getFaults()[0].UID"
                }
              ]
            }
          ]
        };

      var ac = new sparks.ActivityConstructor(jsonSection);
      var section = sparks.sparksActivityController.currentSection;

      section.pages[0].questions[0].answer = "r2"

      $.each(section.pages[0].questions, function(i, question){
        sparks.sparksQuestionController.gradeQuestion(question);
      });

      section.pages[0].questions[0].answerIsCorrect.should.be true
      section.pages[0].questions[0].points_earned.should.be 5
      section.pages[0].questions[1].answerIsCorrect.should.be false
      section.pages[0].questions[1].feedback.should.be "r2"
    end
  end

end
<commit_msg>(m) fix a description of a test<commit_after>describe 'Authored Scripts'

  before_each
    breadModel('clear');
    sparks.sparksSectionController.reset();
    sparks.sparksActivityController.reset();
  end

  describe 'Question Answers'

      it 'should be able to use scripts to define correct answers'
        breadModel('insertComponent', 'resistor', {"UID": "r1", "connections": "a1,a2", "colors": "orange,black,brown,gold"});

        var jsonSection =
          {
            "pages":[
              {
                "questions": [
                  {
                    "prompt": "What is the resistance of R1?",
                    "correct_answer": "[if (r1.nominalResistance < 500) {'R1 is small'} else {'R1 is big'}]",
                    "correct_units": "ohms"
                  },
                  {
                    "prompt": "What is the resistance of R1?",
                    "correct_answer": "[if (r1.nominalResistance != 300) {'R1 is not 300'} else {'R1 is 300'}]",
                    "correct_units": "ohms"
                  }
                ]
              }
            ]
          };

          var ac = new sparks.ActivityConstructor(jsonSection);
          var section = sparks.sparksActivityController.currentSection;

          section.pages[0].questions.length.should.be 2
          section.pages[0].questions[0].correct_answer.should.be "R1 is small"
          section.pages[0].questions[1].correct_answer.should.be "R1 is 300"
      end

  end

  describe 'Question Grading'
    it 'should be able to grade student answers using simple scripts'
      var jsonSection =
        {
          "pages":[
            {
              "questions": [
                {
                    "prompt": "What is the resistance of R1?",
                    "points": 5,
                    "scoring": "if (question.answer == 10) {question.points_earned = 5} else {question.points_earned = 0}"
                },
                {
                    "prompt": "What is the resistance of R2?",
                    "points": 5,
                    "scoring": "if (question.answer == 20) {question.points_earned = 5} else {question.points_earned = 3}"
                }
              ]
            }
          ]
        };

      var ac = new sparks.ActivityConstructor(jsonSection);
      var section = sparks.sparksActivityController.currentSection;

      section.pages[0].questions[0].answer = "10"
      section.pages[0].questions[1].answer = "500"

      $.each(section.pages[0].questions, function(i, question){
        sparks.sparksQuestionController.gradeQuestion(question);
      });

      section.pages[0].questions[0].answerIsCorrect.should.be true
      section.pages[0].questions[0].points_earned.should.be 5
      section.pages[0].questions[1].answerIsCorrect.should.be false
      section.pages[0].questions[1].points_earned.should.be 3
    end

    it 'should be able to grade student answers using scripts with circuit variables'

      breadModel('insertComponent', 'resistor', {"UID": "r1", "resistance": "100"});
      breadModel('insertComponent', 'resistor', {"UID": "r2", "resistance": "200"});
      var jsonSection =
        {
          "pages":[
            {
              "questions": [
                {
                    "prompt": "What is the resistance of R1?",
                    "points": 5,
                    "scoring": "if (question.answer == r1.resistance) {question.points_earned = 5} else {question.points_earned = 0}"
                },
                {
                    "prompt": "What is the resistance of R2?",
                    "points": 5,
                    "scoring": "if (question.answer == r2.resistance) {question.points_earned = 5} else {question.points_earned = 0}"
                }
              ]
            }
          ]
        };

      var ac = new sparks.ActivityConstructor(jsonSection);
      var section = sparks.sparksActivityController.currentSection;

      section.pages[0].questions[0].answer = "100"
      section.pages[0].questions[1].answer = "500"

      $.each(section.pages[0].questions, function(i, question){
        sparks.sparksQuestionController.gradeQuestion(question);
      });

      section.pages[0].questions[0].answerIsCorrect.should.be true
      section.pages[0].questions[0].points_earned.should.be 5
      section.pages[0].questions[1].answerIsCorrect.should.be false
      section.pages[0].questions[1].points_earned.should.be 0
    end

    it 'should be able to find faults from within a script'

      breadModel('insertComponent', 'resistor', {"UID": "r1", "resistance": "100"});
      breadModel('insertComponent', 'resistor', {"UID": "r2", "resistance": "200", "open": true});
      var jsonSection =
        {
          "pages":[
            {
              "questions": [
                {
                    "prompt": "Which resistor is faulty?",
                    "points": 5,
                    "scoring": "console.log(breadboard.getFault().UID); if (question.answer == breadboard.getFault().UID) {question.points_earned = 5}"
                },
                {
                    "prompt": "List the faulty resistors in the feedback...",
                    "points": 5,
                    "scoring": "question.feedback = breadboard.getFaults()[0].UID"
                }
              ]
            }
          ]
        };

      var ac = new sparks.ActivityConstructor(jsonSection);
      var section = sparks.sparksActivityController.currentSection;

      section.pages[0].questions[0].answer = "r2"

      $.each(section.pages[0].questions, function(i, question){
        sparks.sparksQuestionController.gradeQuestion(question);
      });

      section.pages[0].questions[0].answerIsCorrect.should.be true
      section.pages[0].questions[0].points_earned.should.be 5
      section.pages[0].questions[1].answerIsCorrect.should.be false
      section.pages[0].questions[1].feedback.should.be "r2"
    end
  end

end
<|endoftext|>


<commit_before>var async         = require('async');
var cluster       = require('cluster');
var cookieParser  = require('cookie-parser')();
var fileServer    = require('node-static');
var forwarded     = require('forwarded-for');
var http          = require('http');
var microtime     = require('microtime-nodejs');
var querystring   = require('querystring');
var url           = require('url');
var fServer       = new fileServer.Server('/', { cache: 7800, serverInfo: 'OrangeBox'});

var statics       = [];
var staticPath    = [];
var aliases       = {};
var engines       = {swig: require('swig')};

String.prototype.hCapitalize = function () {
	return this.split('-').map(
		function (el, i) {
			return el.charAt(0).toUpperCase() + el.substring(1);
		}
	).join('-');
};

function processRequest (request) {
	var host = request.headers.host.split(':');
	if (host[0]) request.host = host[0];
	if (host[1]) request.port = host[1];

	var query = request.url.split('?');
	var path = query[0];
	query.splice(0,1);

	// request.ip = req.header('x-forwarded-for') || req.headers['X-Forwarded-For'] || req.client.remoteAddress;
	request.ip = forwarded(request, request.headers).ip;

	request.query = querystring.parse(query.join('?'));
	request.queryString = query.join('?');
	request.path = path;

	// aliases
	for (var a in aliases) {
		if (request.path.indexOf(a) === 0)  {
			request.originalUrl = request.url;
			request.url = request.path.replace(a, aliases[a]) + (request.queryString.length ? '?' + request.queryString : '');
		}
	}
}

function processPost (request, response, callback) {
	var queryData = '';
	if (typeof callback !== 'function') return;

	if (request.method == 'POST') {
		request.on('data', function(data) {
			queryData += data;
			if(queryData.length > 1e6) {
				queryData = '';
				response.writeHead(413, {'Content-Type': 'text/plain'}).end();
				request.connection.destroy();
			}
		});

		request.on('end', function() {
			request.body = querystring.parse(queryData);
			callback();
		});

	} else {
		request.body = {};
		callback();
	}
}

if (!cluster.isMaster) {

	// Worker processes have a http server.
	var server = http.Server(function(request, response) {
		var saveStart = microtime.nowDouble();
		processRequest(request);

		function notFile(){
			processPost(request, response, function() {

				var reqId = Math.random().toString(36).substring(2,16);

				process.once('ok_' + reqId, function(ret) {
					ret._headers['x-time'] = (microtime.nowDouble() - saveStart).toFixed(6);
					if (204 == ret.statusCode || 304 == ret.statusCode) {
						if (ret._headers['content-type']) delete ret._headers['content-type'];
						if (ret._headers['content-length']) delete ret._headers['content-length'];
						if (ret._headers['transfer-encoding']) delete ret._headers['transfer-encoding'];
						ret.data = '';
					}

					var headers = ret.subHeaders || {};
					Object.keys(ret._headers).forEach(function(el) {
						headers[el.hCapitalize()] = ret._headers[el];
					});

					if (ret.sendFile && ret.filePath) {
						ret.data = '';
						var r = fServer.serveFile(ret.filePath, ret.statusCode, headers, request, response);
						fServer.root='/';
						r.on("error", function(err) {
							response.writeHead(404, {'Content-Type': 'text/html'});
							response.end('
404 Not Found
Requested resource could not be found.');
							r.removeAllListeners();
						}).on("success", function(err) {
							r.removeAllListeners();
						});
					} else {
						response.writeHead(ret.statusCode, headers);
						if (ret.Type == 'Buffer') {
							ret.data = new Buffer(ret.data, 'base64');
						}
						response.end(ret.data);
					}

				});

				cookieParser(request, response, function() {
					process.send({
						headers          : request.headers,
						orangebox        : '0.1.5',
						url              : request.url,
						originalUrl      : request.url + '?' + request.queryString,
						host             : request.host,
						hostname         : request.host,
						port             : request.port,
						path             : request.path,
						baseUrl          : request.path,
						httpVersionMajor : request.httpVersionMajor,
						httpVersionMinor : request.httpVersionMinor,
						trailers         : request.trailers,
						httpVersion      : request.httpVersion,
						method           : request.method,
						body             : request.body,
						protocol         : request.protocol,
						secure           : 'https' == request.protocol,
						post             : request.post,
						query            : request.query,
						queryString      : request.queryString,
						ip               : request.ip,
						cookies          : request.cookies,
						signedCookies    : request.signedCookies,
						reqId            : reqId,
						pid              : process.pid,
						connection       : {
							encrypted     : request.connection.encrypted,
							readable      : request.connection.readable,
							writable      : request.connection.writable,
							destroyed     : request.connection.destroyed,
							allowHalfOpen : request.connection.allowHalfOpen,
							bytesRead     : request.connection.bytesRead
						}
					});
				});

			});
		}
		if (statics.length) {
			var pathname = url.parse(request.url).pathname;
			var aFlr = statics.filter(function(el,i){
				return pathname !== '' && pathname.indexOf(staticPath[i]) === 0;
			});
			if (!aFlr.length) {
				aFlr = statics.filter(function(){
					return pathname === '';
				});
			}
			async.eachSeries(aFlr, function(el, callback) {
				el.serve(request, response, function (e, res) {
					if (!e || e.status !== 404)
						callback(true);
					else
						callback(null);
				});
			}, function(err){
				if (!err) notFile();
			});
		} else {
			notFile();
		}
	});

	process.on('message', function(ret) {
		if (ret.cmd) {

			switch (ret.cmd) {

				case 'send':
					process.emit('ok_' + ret.response.reqId, ret.response);
					break;

				case 'sendFile':
					if (ret.options) {
						if (ret.options.root) {
							fServer.root = ret.options.root;
						}
						if (ret.options.headers) {
							ret.response.subHeaders = ret.options.headers;
						}
					}
					ret.response.sendFile = true;
					process.emit('ok_' + ret.response.reqId, ret.response);
					break;

				case 'sendRender':

					if (ret.engine == 'swig') {
						engines['swig'].setDefaults({ autoescape: ret.response.variables['view autoescape'] });
						engines['swig'].setDefaultTZOffset(ret.response.variables['view timezone']);
					}

					engines[ret.engine].renderFile(ret.viewsPath + '/' + ret.view + '.html' , ret.data || {}, function (err, output) {
						if (err) {
							console.error(err);
							ret.response.statusCode = 500;
						} else {
							ret.response.data = output;
						}
						process.emit('ok_' + ret.response.reqId, ret.response);
					});
					break;

				case 'listen':
					var _listen = function() { process.send({'cmd': 'listen'}); };
					if (ret.listen.host) {
						server.listen(ret.listen.port, ret.listen.host, _listen);
					} else {
						server.listen(ret.listen.port, _listen);
					}
					break;

				case 'fileServer':
					statics.push(new fileServer.Server(ret.path, { cache: 7800, serverInfo: 'OrangeBox'}));
					staticPath.push(ret.routePath);
					break;

				case 'alias':
					aliases[ret.alias] = ret.path;
					break;

				default:
					console.warn('Undefined message' + ret);
					break;

			}
		}
	});

	function gracefulExit() {
		server.removeAllListeners();
	}
	process.once('SIGINT', gracefulExit).once('SIGTERM', gracefulExit);
}

<commit_msg>Added file upload support.<commit_after>var async         = require('async');
var cluster       = require('cluster');
var cookieParser  = require('cookie-parser')();
var fileServer    = require('node-static');
var forwarded     = require('forwarded-for');
var http          = require('http');
var microtime     = require('microtime-nodejs');
var multiparty    = require('multiparty');
var querystring   = require('querystring');
var url           = require('url');
var fServer       = new fileServer.Server('/', { cache: 7800, serverInfo: 'OrangeBox'});

var statics       = [];
var staticPath    = [];
var aliases       = {};
var engines       = {swig: require('swig')};

String.prototype.hCapitalize = function () {
	return this.split('-').map(
		function (el, i) {
			return el.charAt(0).toUpperCase() + el.substring(1);
		}
	).join('-');
};

function processRequest (request) {
	var host = request.headers.host.split(':');
	if (host[0]) request.host = host[0];
	if (host[1]) request.port = host[1];

	var query = request.url.split('?');
	var path = query[0];
	query.splice(0,1);

	// request.ip = req.header('x-forwarded-for') || req.headers['X-Forwarded-For'] || req.client.remoteAddress;
	request.ip = forwarded(request, request.headers).ip;

	request.query = querystring.parse(query.join('?'));
	request.queryString = query.join('?');
	request.path = path;

	// aliases
	for (var a in aliases) {
		if (request.path.indexOf(a) === 0)  {
			request.originalUrl = request.url;
			request.url = request.path.replace(a, aliases[a]) + (request.queryString.length ? '?' + request.queryString : '');
		}
	}
}

function processPost (request, response, callback) {
	var queryData = '';
	if (typeof callback !== 'function') return;

	if (request.method == 'POST') {
		var mpart = false;
		if (typeof request.headers["content-type"] === 'string' &&
		 request.headers["content-type"].indexOf('multipart/form-data') !== -1) {
			var form = new multiparty.Form();
			form.parse(request, function(err, body, files) {
				request.body = body;
				request.files = files;
				callback();
			});
		} else {
			request.on('data', function(data) {
				queryData += data;
				if(queryData.length > 1e6) {
					queryData = '';
					response.writeHead(413, {'Content-Type': 'text/plain'}).end();
					request.connection.destroy();
				}
			});

			request.on('end', function() {
				request.body = querystring.parse(queryData);
				callback();
			});
		}
	} else {
		request.body = {};
		callback();
	}
}

if (!cluster.isMaster) {

	// Worker processes have a http server.
	var server = http.Server(function(request, response) {
		var saveStart = microtime.nowDouble();
		processRequest(request);

		function notFile(){
			processPost(request, response, function() {

				var reqId = Math.random().toString(36).substring(2,16);

				process.once('ok_' + reqId, function(ret) {
					ret._headers['x-time'] = (microtime.nowDouble() - saveStart).toFixed(6);
					if (204 == ret.statusCode || 304 == ret.statusCode) {
						if (ret._headers['content-type']) delete ret._headers['content-type'];
						if (ret._headers['content-length']) delete ret._headers['content-length'];
						if (ret._headers['transfer-encoding']) delete ret._headers['transfer-encoding'];
						ret.data = '';
					}

					var headers = ret.subHeaders || {};
					Object.keys(ret._headers).forEach(function(el) {
						headers[el.hCapitalize()] = ret._headers[el];
					});

					if (ret.sendFile && ret.filePath) {
						ret.data = '';
						var r = fServer.serveFile(ret.filePath, ret.statusCode, headers, request, response);
						fServer.root='/';
						r.on("error", function(err) {
							response.writeHead(404, {'Content-Type': 'text/html'});
							response.end('
404 Not Found
Requested resource could not be found.');
							r.removeAllListeners();
						}).on("success", function(err) {
							r.removeAllListeners();
						});
					} else {
						response.writeHead(ret.statusCode, headers);
						if (ret.Type == 'Buffer') {
							ret.data = new Buffer(ret.data, 'base64');
						}
						response.end(ret.data);
					}

				});

				cookieParser(request, response, function() {
					process.send({
						headers          : request.headers,
						orangebox        : '0.1.6',
						url              : request.url,
						originalUrl      : request.url + '?' + request.queryString,
						host             : request.host,
						hostname         : request.host,
						port             : request.port,
						path             : request.path,
						baseUrl          : request.path,
						httpVersionMajor : request.httpVersionMajor,
						httpVersionMinor : request.httpVersionMinor,
						trailers         : request.trailers,
						httpVersion      : request.httpVersion,
						method           : request.method,
						body             : request.body,
						protocol         : request.protocol,
						secure           : 'https' == request.protocol,
						post             : request.post,
						query            : request.query,
						queryString      : request.queryString,
						ip               : request.ip,
						cookies          : request.cookies,
						signedCookies    : request.signedCookies,
						reqId            : reqId,
						pid              : process.pid,
						connection       : {
							encrypted     : request.connection.encrypted,
							readable      : request.connection.readable,
							writable      : request.connection.writable,
							destroyed     : request.connection.destroyed,
							allowHalfOpen : request.connection.allowHalfOpen,
							bytesRead     : request.connection.bytesRead
						}
					});
				});

			});
		}
		if (statics.length) {
			var pathname = url.parse(request.url).pathname;
			var aFlr = statics.filter(function(el,i){
				return pathname !== '' && pathname.indexOf(staticPath[i]) === 0;
			});
			if (!aFlr.length) {
				aFlr = statics.filter(function(){
					return pathname === '';
				});
			}
			async.eachSeries(aFlr, function(el, callback) {
				el.serve(request, response, function (e, res) {
					if (!e || e.status !== 404)
						callback(true);
					else
						callback(null);
				});
			}, function(err){
				if (!err) notFile();
			});
		} else {
			notFile();
		}
	});

	process.on('message', function(ret) {
		if (ret.cmd) {

			switch (ret.cmd) {

				case 'send':
					process.emit('ok_' + ret.response.reqId, ret.response);
					break;

				case 'sendFile':
					if (ret.options) {
						if (ret.options.root) {
							fServer.root = ret.options.root;
						}
						if (ret.options.headers) {
							ret.response.subHeaders = ret.options.headers;
						}
					}
					ret.response.sendFile = true;
					process.emit('ok_' + ret.response.reqId, ret.response);
					break;

				case 'sendRender':

					if (ret.engine == 'swig') {
						engines['swig'].setDefaults({ autoescape: ret.response.variables['view autoescape'] });
						engines['swig'].setDefaultTZOffset(ret.response.variables['view timezone']);
					}

					engines[ret.engine].renderFile(ret.viewsPath + '/' + ret.view + '.html' , ret.data || {}, function (err, output) {
						if (err) {
							console.error(err);
							ret.response.statusCode = 500;
						} else {
							ret.response.data = output;
						}
						process.emit('ok_' + ret.response.reqId, ret.response);
					});
					break;

				case 'listen':
					var _listen = function() { process.send({'cmd': 'listen'}); };
					if (ret.listen.host) {
						server.listen(ret.listen.port, ret.listen.host, _listen);
					} else {
						server.listen(ret.listen.port, _listen);
					}
					break;

				case 'fileServer':
					statics.push(new fileServer.Server(ret.path, { cache: 7800, serverInfo: 'OrangeBox'}));
					staticPath.push(ret.routePath);
					break;

				case 'alias':
					aliases[ret.alias] = ret.path;
					break;

				default:
					console.warn('Undefined message' + ret);
					break;

			}
		}
	});

	function gracefulExit() {
		server.removeAllListeners();
	}
	process.once('SIGINT', gracefulExit).once('SIGTERM', gracefulExit);
}

<|endoftext|>


<commit_before>
document.getElementById('close').onmousedown = function(e) {
  e.preventDefault();
  document.getElementById('info').style.display = 'none';
  return false;
};

// settings

var physics_accuracy  = 3,
    mouse_influence   = 20,
    mouse_cut         = 5,
    gravity           = 1200,
    cloth_height      = 30,
    cloth_width       = 50,
    start_y           = 20,
    spacing           = 7,
    tear_distance     = 60;

window.requestAnimFrame =
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function (callback) {
        window.setTimeout(callback, 1000 / 60);
};

var canvas,
    ctx,
    cloth,
    boundsx,
    boundsy,
    mouse = {
        down: false,
        button: 1,
        x: 0,
        y: 0,
        px: 0,
        py: 0
    };

var Point = function (x, y) {

    this.x      = x;
    this.y      = y;
    this.px     = x;
    this.py     = y;
    this.vx     = 0;
    this.vy     = 0;
    this.pin_x  = null;
    this.pin_y  = null;

    this.constraints = [];
};

Point.prototype.update = function (delta) {

    if (mouse.down) {

        var diff_x = this.x - mouse.x,
            diff_y = this.y - mouse.y,
            dist = Math.sqrt(diff_x * diff_x + diff_y * diff_y);

        if (mouse.button == 1) {

            if (dist < mouse_influence) {
                this.px = this.x - (mouse.x - mouse.px) * 1.8;
                this.py = this.y - (mouse.y - mouse.py) * 1.8;
            }

        } else if (dist < mouse_cut) this.constraints = [];
    }

    this.add_force(0, gravity);

    delta *= delta;
    nx = this.x + ((this.x - this.px) * .99) + ((this.vx / 2) * delta);
    ny = this.y + ((this.y - this.py) * .99) + ((this.vy / 2) * delta);

    this.px = this.x;
    this.py = this.y;

    this.x = nx;
    this.y = ny;

    this.vy = this.vx = 0
};

Point.prototype.draw = function () {

    if (!this.constraints.length) return;

    var i = this.constraints.length;
    while (i--) this.constraints[i].draw();
};

Point.prototype.resolve_constraints = function () {

    if (this.pin_x != null && this.pin_y != null) {

        this.x = this.pin_x;
        this.y = this.pin_y;
        return;
    }

    var i = this.constraints.length;
    while (i--) this.constraints[i].resolve();

    this.x > boundsx ? this.x = 2 * boundsx - this.x : 1 > this.x && (this.x = 2 - this.x);
    this.y < 1 ? this.y = 2 - this.y : this.y > boundsy && (this.y = 2 * boundsy - this.y);
};

Point.prototype.attach = function (point) {

    this.constraints.push(
        new Constraint(this, point)
    );
};

Point.prototype.remove_constraint = function (constraint) {

    this.constraints.splice(this.constraints.indexOf(constraint), 1);
};

Point.prototype.add_force = function (x, y) {

    this.vx += x;
    this.vy += y;
};

Point.prototype.pin = function (pinx, piny) {
    this.pin_x = pinx;
    this.pin_y = piny;
};

var Constraint = function (p1, p2) {

    this.p1     = p1;
    this.p2     = p2;
    this.length = spacing;
};

Constraint.prototype.resolve = function () {

    var diff_x  = this.p1.x - this.p2.x,
        diff_y  = this.p1.y - this.p2.y,
        dist    = Math.sqrt(diff_x * diff_x + diff_y * diff_y),
        diff    = (this.length - dist) / dist;

    if (dist > tear_distance) this.p1.remove_constraint(this);

    var px = diff_x * diff * 0.5;
    var py = diff_y * diff * 0.5;

    this.p1.x += px;
    this.p1.y += py;
    this.p2.x -= px;
    this.p2.y -= py;
};

Constraint.prototype.draw = function () {

    ctx.moveTo(this.p1.x, this.p1.y);
    ctx.lineTo(this.p2.x, this.p2.y);
};

var Cloth = function () {

    this.points = [];

    var start_x = canvas.width / 2 - cloth_width * spacing / 2;

    for (var y = 0; y <= cloth_height; y++) {

        for (var x = 0; x <= cloth_width; x++) {

            var p = new Point(start_x + x * spacing, start_y + y * spacing);

            x != 0 && p.attach(this.points[this.points.length - 1]);
            y == 0 && p.pin(p.x, p.y);
            y != 0 && p.attach(this.points[x + (y - 1) * (cloth_width + 1)])

            this.points.push(p);
        }
    }
};

Cloth.prototype.update = function () {

    var i = physics_accuracy;

    while (i--) {
        var p = this.points.length;
        while (p--) this.points[p].resolve_constraints();
    }

    i = this.points.length;
    while (i--) this.points[i].update(.016);
};

Cloth.prototype.draw = function () {

    ctx.beginPath();

    var i = cloth.points.length;
    while (i--) cloth.points[i].draw();

    ctx.stroke();
};

function update() {

    ctx.clearRect(0, 0, canvas.width, canvas.height);

    cloth.update();
    cloth.draw();

    requestAnimFrame(update);
}

function start() {

    canvas.onmousedown = function (e) {
        mouse.button  = e.which;
        mouse.px      = mouse.x;
        mouse.py      = mouse.y;
        var rect      = canvas.getBoundingClientRect();
        mouse.x       = e.clientX - rect.left,
        mouse.y       = e.clientY - rect.top,
        mouse.down    = true;
        e.preventDefault();
    };

    canvas.onmouseup = function (e) {
        mouse.down = false;
        e.preventDefault();
    };

    canvas.onmousemove = function (e) {
        mouse.px  = mouse.x;
        mouse.py  = mouse.y;
        var rect  = canvas.getBoundingClientRect();
        mouse.x   = e.clientX - rect.left,
        mouse.y   = e.clientY - rect.top,
        e.preventDefault();
    };

    canvas.oncontextmenu = function (e) {
        e.preventDefault();
    };

    boundsx = canvas.width - 1;
    boundsy = canvas.height - 1;

    ctx.strokeStyle = '#888';

    cloth = new Cloth();

    update();
}

window.onload = function () {

    canvas  = document.getElementById('c');
    ctx     = canvas.getContext('2d');

    canvas.width  = 560;
    canvas.height = 350;

    start();
};
<commit_msg>Delete cloth.js<commit_after><|endoftext|>


<commit_before>/**
 * Descriptor may have the following attributes:
 *   - constructor
 *   - template
 *   - interactive_properties
 *   - data_handler
 *   - icon
 *   - display_name
 *   - category
 */
ds.register_dashboard_item = function(item_type, descriptor) {
  ds.models[item_type] = descriptor
  if (descriptor.template && (typeof(descriptor.template) === 'string')) {
    descriptor.template = Handlebars.compile(descriptor.template)
  }

  if (descriptor.actions && descriptor.actions.length) {
    ds.actions.register(item_type, descriptor.actions)
  }

  var props = (descriptor.interactive_properties || []).map(function(p) {
                if (typeof(p) === 'string') {
                  var prop = ds.property.get(p)
                  return prop || ds.property({id: p})
                } else if (p.is_property) {
                  return p
                } else {
                  return ds.property(p)
                }
              })

  props.sort(function(p1, p2) {
    if (p1.category === p2.category) {
      return p1.name.localeCompare(p2.name)
    } else {
      return (p1.category || '').localeCompare(p2.category || '')
    }
  })

  descriptor.interactive_properties = props

  var new_item_action = ds.action({
    name:     item_type,
    display:  'Add new ' + (descriptor.display_name || item_type),
    icon:     descriptor.icon || '',
    category: descriptor.category ? 'new-item-' + descriptor.category : 'new-item',
    handler:  function(action, container) {
      container.add(item_type)
    }
  })

  ds.actions.register(new_item_action.category, new_item_action)

  return ds
}

ds.models.factory = function(data) {
  var item_type = null
    , item = null

  if (typeof(data) === 'string' && ds.models[data]) {
    item_type = ds.models[data]
    item = ( item_type.constructor ) ? item_type.constructor() : item_type()
  } else if (data.is_dashboard_item) {
    item = data;
  } else if (data.item_type && ds.models[data.item_type]) {
    item_type = ds.models[data.item_type]
    if (item_type instanceof Function) {
      item = item_type(data)
    } else if (item_type.constructor) {
      item = item_type.constructor(data)
    }
  }
  if (item) {
    if (item_type) {
      item.interactive_properties = item_type.interactive_properties
    }
    return item
  }
  console.log('Unknown type');
  console.log(data);
  return null;
}

ds.models.make = ds.models.factory
<commit_msg>Left out action class (needed for menu event handler)<commit_after>/**
 * Descriptor may have the following attributes:
 *   - constructor
 *   - template
 *   - interactive_properties
 *   - data_handler
 *   - icon
 *   - display_name
 *   - category
 */
ds.register_dashboard_item = function(item_type, descriptor) {
  ds.models[item_type] = descriptor
  if (descriptor.template && (typeof(descriptor.template) === 'string')) {
    descriptor.template = Handlebars.compile(descriptor.template)
  }

  if (descriptor.actions && descriptor.actions.length) {
    ds.actions.register(item_type, descriptor.actions)
  }

  var props = (descriptor.interactive_properties || []).map(function(p) {
                if (typeof(p) === 'string') {
                  var prop = ds.property.get(p)
                  return prop || ds.property({id: p})
                } else if (p.is_property) {
                  return p
                } else {
                  return ds.property(p)
                }
              })

  props.sort(function(p1, p2) {
    if (p1.category === p2.category) {
      return p1.name.localeCompare(p2.name)
    } else {
      return (p1.category || '').localeCompare(p2.category || '')
    }
  })

  descriptor.interactive_properties = props

  var category = descriptor.category ? 'new-item-' + descriptor.category : 'new-item'

  ds.actions.register(category, {
    name:     item_type,
    display:  'Add new ' + (descriptor.display_name || item_type),
    icon:     descriptor.icon || '',
    category: category,
    class:   'new-item',
    handler:  function(action, container) {
      console.log('Add new ' + item_type)
      container.add(item_type)
    }
  })

  return ds
}

ds.models.factory = function(data) {
  var item_type = null
    , item = null

  if (typeof(data) === 'string' && ds.models[data]) {
    item_type = ds.models[data]
    item = ( item_type.constructor ) ? item_type.constructor() : item_type()
  } else if (data.is_dashboard_item) {
    item = data;
  } else if (data.item_type && ds.models[data.item_type]) {
    item_type = ds.models[data.item_type]
    if (item_type instanceof Function) {
      item = item_type(data)
    } else if (item_type.constructor) {
      item = item_type.constructor(data)
    }
  }
  if (item) {
    if (item_type) {
      item.interactive_properties = item_type.interactive_properties
    }
    return item
  }
  console.log('Unknown type');
  console.log(data);
  return null;
}

ds.models.make = ds.models.factory
<|endoftext|>


<commit_before>/*******************************************
* js-cgi.js
* Copyright (c) 2015, Darrel Kathan
* Licensed under the MIT license.
*
* A current version and some documentation is available at
*    https://github.com/kathan/js-cgi
*
* @summary     Javascript CGI process manager
* @description js-cgi is a javascript CGI process manager, similar to php-fpm, for executing node.js/io.js compatible scripts behind NGINX or Apache.
* @file        js-cgi.js
* @version     0.1.0
* @author      Darrel Kathan
* @license     MIT
*******************************************/
'use strict';

var cluster = require('cluster'),
	url = require('url'),
	//fs = require('fs'),
	fs = require('graceful-fs'),
	vm = require('vm'),
	os = require('os'),
	util = require('util'),
	path = require('path'),
	express = require('express'),
	cookieParser = require('cookie-parser'),
	app = express(),
	config_name = 'js-cgi.config',
	config = {};

/*******************************************
* Funnel console.log and console.error
* input to log file.
*******************************************/
console.log = function(){
	var d = new Date(),
		log_msg = d.toString()+' - ('+process.pid+'): ',
		stack = new Error().stack;

	this._stdout.write(log_msg + util.format.apply(this, arguments) + stack + '\n');
	if(config.output_log){
		fs.appendFile(config.output_log, log_msg + util.format.apply(this, arguments) + '\n', function(){return;});
	}
};

console.error = function(err){
	var d = new Date(),
		log_msg = d.toString()+' - ('+process.pid+'): '+err.toString();
	util.error(log_msg, err.stack);
	if(config.output_log){
		fs.appendFile(config.output_log, log_msg+'\n', function(){return;});
		fs.appendFile(config.output_log, err.stack+'\n', function(){return;});
	}
};

/*******************************************
* Prepare web server to handle cookies and
* format JSON.
*******************************************/
app.use(cookieParser());
app.set('json spaces', 4);

config.output_log = path.dirname(process.argv[1])+'/js-cgi.log';
//console.log(config.output_log);
if(fs.existsSync(path.join(__dirname, config_name))){
	//Load the congfig file
	console.log('Loading '+config_name+'...');
	config = require('./'+config_name);
}else{
	//Use the default congfig
	console.log('Loading default config...');
	config.port = 3000;
	config.localhostOnly = true;
	//config.workers = 2;
	config.timeout = 30000;
	config.workers = (os.cpus().length/2)-1;//For some reason cpus.length is reports twice as many cores than actual.
}

/*******************************************
* Override the "require" function to watch
* if required files have change and expire
* them from cache when they do.
*******************************************/
var assert = require('assert').ok,
	Module = require('module');
if(typeof Module._watching !== 'object'){
	Module._watching = {};
}
function watchRequired(fn){
	/*var fs = require('fs')
		console = console;*/
	//console.log(fn);
	if(Module._watching && !Module._watching.hasOwnProperty(fn)){
		if(fs.existsSync(fn) && !Module._watching.hasOwnProperty(fn)){
			console.log('Watching '+fn);
			Module._watching[fn] = fs.watch(fn, function(event,f){
			//Module._watching[fn] = fs.watchFile(fn, function(curr, prev){
				console.log(fn, event);

				if(Module._cache.hasOwnProperty(fn)){
					console.log('Expiring '+fn);
					//fs.unwatch(fn, function(){return;});
					return delete Module._cache[fn];
				}
				return;
			});
		}
	}
}

Module.prototype.require = function(path) {
  assert(path, 'missing path');
  assert((typeof path === 'string'), 'path must be a string');
  watchRequired(Module._resolveFilename(path, this));
  return Module._load(path, this);
};

/*******************************************
* Start up the server node.
*******************************************/
if (cluster.isMaster) {
	cluster.globals = {};
	cluster.fork();//At least one worker is required.

	for(var w = 2; w <= config.workers;w++){
		cluster.fork().on('error', console.error);
	}

	cluster.on('disconnect', function(worker) {
		var e = new Error('disconnect!');
		//console.error(e);
		cluster.fork().on('error', console.error);
	});
} else {
	// the worker
	var domain = require('domain'),
		server,
		d = domain.create();

	d.on('error', function(er) {
		console.error(er);
		try {
			// make sure we close down if it times out
			var killtimer = setTimeout(function() {
				var err = new Error('Killing process. Timeout expired ('+config.timeout+' ms)')
				console.error(err);
				return process.exit(1);
			}, config.timeout);
			// But don't keep the process open just for that!
			killtimer.unref();

			// stop taking new requests.
			server.close();

			// Let the master know we're dead.  This will trigger a
			// 'disconnect' in the cluster master, and then it will fork
			// a new worker.
			cluster.worker.disconnect();
		} catch (er2) {
			// oh well, not much we can do at this point.
			console.error(er2);
		}
	});

    /*******************************************
    * Now run the handler function in the domain.
    *******************************************/
    d.run(function() {
		console.log('Listening on '+config.port);

		server = app.listen(config.port);

		app.all('*', function(req, res){
			//console.log('req');
			return handleRequest(req, res);
		});
	});
}

function setRequiredCacheTimestamp(name){
	if(require.cache[process.execPath][name]){
		return require.cache[process.execPath][name];
	}
}

/*******************************************
* This is where all of the web requests are
* handled.
*******************************************/
function handleRequest(req, res) {
	var url_obj = url.parse(req.url, true),
		file_path;
	/*if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
		//res.writeHead(401);
		res.end(401);
	}*/

	if(req.headers.path_translated && url_obj.pathname){
		file_path = req.headers.path_translated+url_obj.pathname;
	}else{
		file_path = url_obj.pathname;
	}

	//console.log('file_path:'+file_path);
	function resolveModule(module) {
		if (module.charAt(0) !== '.'){
			//console.log('No need to resolve '+module);
			return module;
		}
		//console.log('Resolved '+module+' to '+path.resolve(path.dirname(file_path), module));
		return path.resolve(path.dirname(file_path), module);
	}

	//If the requested file exists...
	fs.exists(file_path, function(exists){
		if(exists){
			fs.readFile(file_path, function (err, source) {
				if(err){
					//Error reading file
					console.error(err);
					res.writeHead(500, err);
					return res.send(err.toString());
				}
				try{
					console.log('Request: '+file_path);
					//console.log(require.cache);
					var sandbox = {
						//globals: globals,
						console: console,
						setImmediate: setImmediate,
						require: function(name) {
							var mod_path = resolveModule(name);
							//watchRequired(mod_path);
							return require(mod_path);
						},
						req: req,
						res: res,
						process: process
					};
					var c = vm.createContext(sandbox);
            		//return vm.runInContext(source, c, {displayErrors: true});
					return vm.runInContext('(function(){try{'+source+'}catch(e){console.error(e);res.status(500).send({err: e.toString(), stack: e.stack});}})();', c, {displayErrors: true});
					//return vm.runInContext('function runInContext() {try{'+source+'}catch(e){console.error(e);res.status(500).send({err: e.toString(), stack: e.stack});}} runInContext();', c, {displayErrors: true});
				}catch(err){
					console.error(err);
					//res.writeHead(500);
					return res.status(500).send(err.toString());
				}
			});
		}else{
			//File does not exist
			//res.writeHead(404, 'File not found.');
			return res.status(404).send('File not found.');
		}
	});
}

/*******************************************
* The following handleRequest options were
* less successful.
*******************************************/
function handleRequestScript(req, res) {
  var url_obj = url.parse(req.url, true);
  /*if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
    //res.writeHead(401);
    res.end(401);
  }*/

  var file_path;
  if(req.headers.path_translated && url_obj.pathname){
    file_path = req.headers.path_translated+url_obj.pathname;
  }else{
    file_path = url_obj.pathname;
  }

  function resolveModule(module) {
    if (module.charAt(0) !== '.'){
      //console.log('No need to resolve '+module);
      return module;
    }
    //console.log('Resolved '+module+' to '+path.resolve(path.dirname(file_path), module));
    return path.resolve(path.dirname(file_path), module);
  }

  function myRequire(name) {
    return require(resolveModule(name));
  }

  //If the requested file exists...
  fs.exists(file_path, function(exists){
    if(exists){
    	fs.readFile(file_path, function(err, content){
	      try{
	      	var path_dir = file_path.split("/");
	      	path_dir.pop();
	      	path_dir = path_dir.join('/');
	      	//console.log(path_dir);
	      	process.chdir(path_dir);
	      	//console.log(process.cwd());
	      	var script = Function('req', 'res', 'globals', 'require', content);
	      	//console.log(script.toString());
	      	console.log(file_path);
	      	script(req, res, cluster.globals, myRequire);

	      }catch(err){
	      	res.writeHead(500);
	      	console.error(err)
	      	res.end(err+' in '+file_path);
	      }
	    });
    }else{
      //File does not exist
      res.writeHead(404, 'File not found.');
      res.end('File '+file_path+' not found.');
    }
  });
}

function handleRequestRequire(req, res) {
  var url_obj = url.parse(req.url, true);
  /*if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
    //res.writeHead(401);
    res.end(401);
  }*/

  var file_path;
  if(req.headers.path_translated && url_obj.pathname){
    file_path = req.headers.path_translated+url_obj.pathname;
  }else{
    file_path = url_obj.pathname;
  }

  //If the requested file exists...
  fs.exists(file_path, function(exists){
    if(exists){
      var script = require(file_path);
      if(typeof script === 'function'){
      	script(req, res, cluster.globals);
      }else{
      	res.writeHead(500);
      	return res.send('Script is not configured correctly.');
      }
    }else{
      //File does not exist
      res.writeHead(404, 'File not found.');
      return res.send('File '+file_path+' not found.');
    }
  });
}

function handleRequestRIC(req, res) {
  var url_obj = url.parse(req.url, true);
  /*if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
    //res.writeHead(401);
    res.end(401);
  }*/

  var file_path;
  if(req.headers.path_translated && url_obj.pathname){
    file_path = req.headers.path_translated+url_obj.pathname;
  }else{
    file_path = url_obj.pathname;
  }
  //console.log('file_path:'+file_path);
  function resolveModule(module) {
    if (module.charAt(0) !== '.'){
      //console.log('No need to resolve '+module);
      return module;
    }
    //console.log('Resolved '+module+' to '+path.resolve(path.dirname(file_path), module));
    return path.resolve(path.dirname(file_path), module);
  }
  //If the requested file exists...
  fs.exists(file_path, function(exists){
    if(exists){
      fs.readFile(file_path, function (err, source) {
        if(err){
          //Error reading file
          console.error(err);
          res.writeHead(500, err);
          return res.send(err.toString());
        }
        try{
          //console.log('filename:'+file_path);

          //var script = vm.createScript('try{\n'+source+'\n}catch(err){console.error(err);res.writeHead(500);res.end(err.toString());}');
          var script = vm.createScript(source);
          //console.log('pre execute:'+g);
          var sandbox = {
                  //globals: globals,
                  console: console,
                  require: function(name) {
                           return require(resolveModule(name));
                       },
                req: req,
                res: res,
                displayErrors: true
            };

          return script.runInNewContext(sandbox);

        }catch(err){
          console.error(err);
          res.writeHead(500);
          return res.send(err.toString());
        }
      });
    }else{
      //File does not exist
      res.writeHead(404, 'File not found.');
      return res.send('File not found.');
    }
  });
}<commit_msg>added watch_required config option<commit_after>/*******************************************
* js-cgi.js
* Copyright (c) 2015, Darrel Kathan
* Licensed under the MIT license.
*
* A current version and some documentation is available at
*    https://github.com/kathan/js-cgi
*
* @summary     Javascript CGI process manager
* @description js-cgi is a javascript CGI process manager, similar to php-fpm, for executing node.js/io.js compatible scripts behind NGINX or Apache.
* @file        js-cgi.js
* @version     0.1.0
* @author      Darrel Kathan
* @license     MIT
*******************************************/
'use strict';

var cluster = require('cluster'),
	url = require('url'),
	//fs = require('fs'),
	fs = require('graceful-fs'),
	vm = require('vm'),
	os = require('os'),
	util = require('util'),
	path = require('path'),
	express = require('express'),
	cookieParser = require('cookie-parser'),
	app = express(),
	config_name = 'js-cgi.config',
	config = {};

/*******************************************
* Funnel console.log and console.error
* input to log file.
*******************************************/
console.log = function(){
	var d = new Date(),
		log_msg = d.toString()+' - ('+process.pid+'): ',
		stack = new Error().stack;

	this._stdout.write(log_msg + util.format.apply(this, arguments) + stack + '\n');
	if(config.output_log){
		fs.appendFile(config.output_log, log_msg + util.format.apply(this, arguments) + '\n', function(){return;});
	}
};

console.error = function(err){
	var d = new Date(),
		log_msg = d.toString()+' - ('+process.pid+'): '+err.toString();
	util.error(log_msg, err.stack);
	if(config.output_log){
		fs.appendFile(config.output_log, log_msg+'\n', function(){return;});
		fs.appendFile(config.output_log, err.stack+'\n', function(){return;});
	}
};

/*******************************************
* Prepare web server to handle cookies and
* format JSON.
*******************************************/
app.use(cookieParser());
app.set('json spaces', 4);

config.output_log = path.dirname(process.argv[1])+'/js-cgi.log';
//console.log(config.output_log);
if(fs.existsSync(path.join(__dirname, config_name))){
	//Load the congfig file
	console.log('Loading '+config_name+'...');
	config = require('./'+config_name);
}else{
	//Use the default congfig
	console.log('Loading default config...');
	config.port = 3000;
	config.localhostOnly = true;
	//config.workers = 2;
	config.timeout = 30000;
	config.workers = (os.cpus().length/2)-1;//For some reason cpus.length is reports twice as many cores than actual.
	config.watch_required = false;
}

/*******************************************
* Override the "require" function to watch
* if required files have change and expire
* them from cache when they do.
*******************************************/
var assert = require('assert').ok,
	Module = require('module');
if(typeof Module._watching !== 'object'){
	Module._watching = {};
}
function watchRequired(fn){
	/*var fs = require('fs')
		console = console;*/
	//console.log(fn);
	if(Module._watching && !Module._watching.hasOwnProperty(fn)){
		if(fs.existsSync(fn) && !Module._watching.hasOwnProperty(fn)){
			console.log('Watching '+fn);
			Module._watching[fn] = fs.watch(fn, function(event,f){
			//Module._watching[fn] = fs.watchFile(fn, function(curr, prev){
				console.log(fn, event);

				if(Module._cache.hasOwnProperty(fn)){
					console.log('Expiring '+fn);
					//fs.unwatch(fn, function(){return;});
					return delete Module._cache[fn];
				}
				return;
			});
		}
	}
}

Module.prototype.require = function(path) {
  assert(path, 'missing path');
  assert((typeof path === 'string'), 'path must be a string');
  if(config.watch_required){
	  watchRequired(Module._resolveFilename(path, this));
  }
  return Module._load(path, this);
};

/*******************************************
* Start up the server node.
*******************************************/
if (cluster.isMaster) {
	cluster.globals = {};
	cluster.fork();//At least one worker is required.

	for(var w = 2; w <= config.workers;w++){
		cluster.fork().on('error', console.error);
	}

	cluster.on('disconnect', function(worker) {
		var e = new Error('disconnect!');
		//console.error(e);
		cluster.fork().on('error', console.error);
	});
} else {
	// the worker
	var domain = require('domain'),
		server,
		d = domain.create();

	d.on('error', function(er) {
		console.error(er);
		try {
			// make sure we close down if it times out
			var killtimer = setTimeout(function() {
				var err = new Error('Killing process. Timeout expired ('+config.timeout+' ms)')
				console.error(err);
				return process.exit(1);
			}, config.timeout);
			// But don't keep the process open just for that!
			killtimer.unref();

			// stop taking new requests.
			server.close();

			// Let the master know we're dead.  This will trigger a
			// 'disconnect' in the cluster master, and then it will fork
			// a new worker.
			cluster.worker.disconnect();
		} catch (er2) {
			// oh well, not much we can do at this point.
			console.error(er2);
		}
	});

    /*******************************************
    * Now run the handler function in the domain.
    *******************************************/
    d.run(function() {
		console.log('Listening on '+config.port);

		server = app.listen(config.port);

		app.all('*', function(req, res){
			//console.log('req');
			return handleRequest(req, res);
		});
	});
}

function setRequiredCacheTimestamp(name){
	if(require.cache[process.execPath][name]){
		return require.cache[process.execPath][name];
	}
}

/*******************************************
* This is where all of the web requests are
* handled.
*******************************************/
function handleRequest(req, res) {
	var url_obj = url.parse(req.url, true),
		file_path;
	/*if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
		//res.writeHead(401);
		res.end(401);
	}*/

	if(req.headers.path_translated && url_obj.pathname){
		file_path = req.headers.path_translated+url_obj.pathname;
	}else{
		file_path = url_obj.pathname;
	}

	//console.log('file_path:'+file_path);
	function resolveModule(module) {
		if (module.charAt(0) !== '.'){
			//console.log('No need to resolve '+module);
			return module;
		}
		//console.log('Resolved '+module+' to '+path.resolve(path.dirname(file_path), module));
		return path.resolve(path.dirname(file_path), module);
	}

	//If the requested file exists...
	fs.exists(file_path, function(exists){
		if(exists){
			fs.readFile(file_path, function (err, source) {
				if(err){
					//Error reading file
					console.error(err);
					res.writeHead(500, err);
					return res.send(err.toString());
				}
				try{
					console.log('Request: '+file_path);
					//console.log(require.cache);
					var sandbox = {
						//globals: globals,
						console: console,
						setImmediate: setImmediate,
						require: function(name) {
							var mod_path = resolveModule(name);
							//watchRequired(mod_path);
							return require(mod_path);
						},
						req: req,
						res: res,
						process: process
					};
					var c = vm.createContext(sandbox);
            		//return vm.runInContext(source, c, {displayErrors: true});
					return vm.runInContext('(function(){try{'+source+'}catch(e){console.error(e);res.status(500).send({err: e.toString(), stack: e.stack});}})();', c, {displayErrors: true});
					//return vm.runInContext('function runInContext() {try{'+source+'}catch(e){console.error(e);res.status(500).send({err: e.toString(), stack: e.stack});}} runInContext();', c, {displayErrors: true});
				}catch(err){
					console.error(err);
					//res.writeHead(500);
					return res.status(500).send(err.toString());
				}
			});
		}else{
			//File does not exist
			//res.writeHead(404, 'File not found.');
			return res.status(404).send('File not found.');
		}
	});
}

/*******************************************
* The following handleRequest options were
* less successful.
*******************************************/
function handleRequestScript(req, res) {
  var url_obj = url.parse(req.url, true);
  /*if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
    //res.writeHead(401);
    res.end(401);
  }*/

  var file_path;
  if(req.headers.path_translated && url_obj.pathname){
    file_path = req.headers.path_translated+url_obj.pathname;
  }else{
    file_path = url_obj.pathname;
  }

  function resolveModule(module) {
    if (module.charAt(0) !== '.'){
      //console.log('No need to resolve '+module);
      return module;
    }
    //console.log('Resolved '+module+' to '+path.resolve(path.dirname(file_path), module));
    return path.resolve(path.dirname(file_path), module);
  }

  function myRequire(name) {
    return require(resolveModule(name));
  }

  //If the requested file exists...
  fs.exists(file_path, function(exists){
    if(exists){
    	fs.readFile(file_path, function(err, content){
	      try{
	      	var path_dir = file_path.split("/");
	      	path_dir.pop();
	      	path_dir = path_dir.join('/');
	      	//console.log(path_dir);
	      	process.chdir(path_dir);
	      	//console.log(process.cwd());
	      	var script = Function('req', 'res', 'globals', 'require', content);
	      	//console.log(script.toString());
	      	console.log(file_path);
	      	script(req, res, cluster.globals, myRequire);

	      }catch(err){
	      	res.writeHead(500);
	      	console.error(err)
	      	res.end(err+' in '+file_path);
	      }
	    });
    }else{
      //File does not exist
      res.writeHead(404, 'File not found.');
      res.end('File '+file_path+' not found.');
    }
  });
}

function handleRequestRequire(req, res) {
  var url_obj = url.parse(req.url, true);
  /*if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
    //res.writeHead(401);
    res.end(401);
  }*/

  var file_path;
  if(req.headers.path_translated && url_obj.pathname){
    file_path = req.headers.path_translated+url_obj.pathname;
  }else{
    file_path = url_obj.pathname;
  }

  //If the requested file exists...
  fs.exists(file_path, function(exists){
    if(exists){
      var script = require(file_path);
      if(typeof script === 'function'){
      	script(req, res, cluster.globals);
      }else{
      	res.writeHead(500);
      	return res.send('Script is not configured correctly.');
      }
    }else{
      //File does not exist
      res.writeHead(404, 'File not found.');
      return res.send('File '+file_path+' not found.');
    }
  });
}

function handleRequestRIC(req, res) {
  var url_obj = url.parse(req.url, true);
  /*if(config.localhostOnly && req.connection.remoteAddress !== '127.0.0.1'){
    //res.writeHead(401);
    res.end(401);
  }*/

  var file_path;
  if(req.headers.path_translated && url_obj.pathname){
    file_path = req.headers.path_translated+url_obj.pathname;
  }else{
    file_path = url_obj.pathname;
  }
  //console.log('file_path:'+file_path);
  function resolveModule(module) {
    if (module.charAt(0) !== '.'){
      //console.log('No need to resolve '+module);
      return module;
    }
    //console.log('Resolved '+module+' to '+path.resolve(path.dirname(file_path), module));
    return path.resolve(path.dirname(file_path), module);
  }
  //If the requested file exists...
  fs.exists(file_path, function(exists){
    if(exists){
      fs.readFile(file_path, function (err, source) {
        if(err){
          //Error reading file
          console.error(err);
          res.writeHead(500, err);
          return res.send(err.toString());
        }
        try{
          //console.log('filename:'+file_path);

          //var script = vm.createScript('try{\n'+source+'\n}catch(err){console.error(err);res.writeHead(500);res.end(err.toString());}');
          var script = vm.createScript(source);
          //console.log('pre execute:'+g);
          var sandbox = {
                  //globals: globals,
                  console: console,
                  require: function(name) {
                           return require(resolveModule(name));
                       },
                req: req,
                res: res,
                displayErrors: true
            };

          return script.runInNewContext(sandbox);

        }catch(err){
          console.error(err);
          res.writeHead(500);
          return res.send(err.toString());
        }
      });
    }else{
      //File does not exist
      res.writeHead(404, 'File not found.');
      return res.send('File not found.');
    }
  });
}<|endoftext|>