<commit_before>/*eslint-disable max-params, no-unused-expressions, no-console, brace-style, no-shadow */
import React, { PropTypes } from 'react';
import $ from 'jquery';
import kendoConfigs from './constants';

if(window.location.href.indexOf('debug') !== -1) { console.log($.fn.jquery); }

const propsEqual = (current, next) => JSON.stringify(current) !== JSON.stringify(next);

const requireComponent = (component) => component.split(',').map((comp) => require(`kendo-ui-core/js/${comp}`));

const generateComponent = (kendoEl, options, composer, kendoComponentName) => {
  let component = $(kendoEl).data(composer);
  if (!component) {
    $(kendoEl)[composer](options);
    component = $(kendoEl).data(composer);
    options.generated && options.generated(component);
    options.debug && console.info(`${kendoComponentName} Generated`, kendoEl);
  }
  else {
    component.setOptions(options);
    options.rerendered && options.rerendered(component);
    options.debug && console.info(`${kendoComponentName} Rerendered`, kendoEl);
  }
};

export const component = (composer, adhocConfig) => {
  let config = adhocConfig;
  if(!adhocConfig) {
    for (let i = 0; i < kendoConfigs.length; i++) {
      if (kendoConfigs[i].composer === composer) {
        config = kendoConfigs[i];
      }
    }
  }

  const kendoComponent = class KendoComponent extends React.Component {

    componentWillMount() {
      requireComponent(config.namespace);
    }

    componentDidMount() {
      generateComponent(this.refs.kendoComponent, this.props, config.composer, config.name);
    }

    componentWillReceiveProps(nextProps) {
      if (!propsEqual(this.props, nextProps)) {
        generateComponent(this.refs.kendoComponent, nextProps, config.composer, config.name);
      }
    }

    render() {

      const opts = {
        children: this.props.children || [],
        className: this.props.className || config.composer,
        'data-id': config.composer,
        'data-kendo': 'true',
        ref: 'kendoComponent',
        style: this.props.style
      };

      let result;
      switch (config.root) {
      case 'button':
        result = (<button {...opts} {...config.defaultAttributes}>{this.props.text}</button>);
        break;
      case 'input':
        opts.children && delete opts.children;
        result = (<input {...opts} {...config.defaultAttributes} />);
        break;
      case 'textarea':
        opts.children && delete opts.children;
        result = (<textarea {...opts} {...config.defaultAttributes} />);
        break;
      case 'ul':
        result = (
{opts.children}
);
        break;
      case 'select':
        result = (<select {...opts} {...config.defaultAttributes}>{opts.children}</select>);
        break;
      default:
        result = (
);
        break;
      }
      return result;
    }

  };

  kendoComponent.propTypes = {
    children: PropTypes.instanceOf(Array),
    className: PropTypes.string,
    style: PropTypes.object,
    text: PropTypes.string
  };

  return kendoComponent;

};
<commit_msg>Spruced up demo<commit_after>/*eslint-disable max-params, no-unused-expressions, no-console, brace-style, no-shadow */
import React, { PropTypes } from 'react';
import $ from 'jquery.2';
import kendoConfigs from './constants';

if(window.location.href.indexOf('debug') !== -1) { console.log($.fn.jquery); }

const propsEqual = (current, next) => JSON.stringify(current) !== JSON.stringify(next);

const requireComponent = (component) => component.split(',').map((comp) => require(`kendo-ui-core/js/${comp}`));

const generateComponent = (kendoEl, options, composer, kendoComponentName) => {
  let component = $(kendoEl).data(composer);
  if (!component) {
    $(kendoEl)[composer](options);
    component = $(kendoEl).data(composer);
    options.generated && options.generated(component);
    options.debug && console.info(`${kendoComponentName} Generated`, kendoEl);
  }
  else {
    component.setOptions(options);
    options.rerendered && options.rerendered(component);
    options.debug && console.info(`${kendoComponentName} Rerendered`, kendoEl);
  }
};

export const component = (composer, adhocConfig) => {
  let config = adhocConfig;
  if(!adhocConfig) {
    for (let i = 0; i < kendoConfigs.length; i++) {
      if (kendoConfigs[i].composer === composer) {
        config = kendoConfigs[i];
      }
    }
  }

  const kendoComponent = class KendoComponent extends React.Component {

    componentWillMount() {
      requireComponent(config.namespace);
    }

    componentDidMount() {
      generateComponent(this.refs.kendoComponent, this.props, config.composer, config.name);
    }

    componentWillReceiveProps(nextProps) {
      if (!propsEqual(this.props, nextProps)) {
        generateComponent(this.refs.kendoComponent, nextProps, config.composer, config.name);
      }
    }

    render() {

      const opts = {
        children: this.props.children || [],
        className: this.props.className || config.composer,
        'data-id': config.composer,
        'data-kendo': 'true',
        ref: 'kendoComponent',
        style: this.props.style
      };

      let result;
      switch (config.root) {
      case 'button':
        result = (<button {...opts} {...config.defaultAttributes}>{this.props.text}</button>);
        break;
      case 'input':
        opts.children && delete opts.children;
        result = (<input {...opts} {...config.defaultAttributes} />);
        break;
      case 'textarea':
        opts.children && delete opts.children;
        result = (<textarea {...opts} {...config.defaultAttributes} />);
        break;
      case 'ul':
        result = (
{opts.children}
);
        break;
      case 'select':
        result = (<select {...opts} {...config.defaultAttributes}>{opts.children}</select>);
        break;
      default:
        result = (
);
        break;
      }
      return result;
    }

  };

  kendoComponent.propTypes = {
    children: PropTypes.instanceOf(Array),
    className: PropTypes.string,
    style: PropTypes.object,
    text: PropTypes.string
  };

  return kendoComponent;

};
<|endoftext|>


<commit_before>import serve from 'koa-static'
import logger from 'koa-logger'
import mount from 'koa-mount'
import views from 'koa-views'
import log4js from 'log4js'

export default (app) => {
    app.proxy = true

    app.use(logger())
    app.use(mount("/", serve(`${__dirname}/../public/`)))
    app.use(views(`${__dirname}/../views`, {extension: 'swig'}))
}
<commit_msg>history api fallback configured<commit_after>import serve from 'koa-static'
import logger from 'koa-logger'
import mount from 'koa-mount'
import views from 'koa-views'
import convert from 'koa-convert'
import historyApiFallback from 'koa-connect-history-api-fallback'
import log4js from 'log4js'

export default (app) => {
    app.proxy = true

    app.use(logger())
    app.use(mount("/", serve(`${__dirname}/../public/`)))
    app.use(views(`${__dirname}/../views`, {extension: 'swig'}))

    app.use(convert(historyApiFallback({
        index: '/'
    })))
}
<|endoftext|>


<commit_before>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure

//Declare and Initialize Variables
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume=1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume=1;
var description = "Error";
var i = 0;
var IdleStatus = 0;
var incoming_ONG = 0;
var KeepBlue = 0;
var NinjaAutoClickStatus = 0;
var RKAutoClickStatus = 0;
var RKAlertFrequency = 8;
var Time_to_ONG = 1800000;

//Beach Ball Startup
	//Set Settings
	IdleStatus = prompt("Set to idle? (1 = Yes, 0 = No)");
	RKAutoClickStatus = IdleStatus;
	NinjaAutoClickStatus = IdleStatus;
	if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

	//Create Menu
	$('#optionsItems').append('

RK Auto Click

');
	WriteOptionDescription('RKAutoClick',RKAutoClickStatus);

	Molpy.Notify('abc123', 1);

//Main Loop
setInterval(function() {
    RedundaKitty();
    Ninja();
}, 1800);

function Ninja() {
	//Ninja Warnings and Incoming ONG Warning
    Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
	if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
                $("#beach").css("border","4px solid blue");
                KeepBlue = 1;
            }
            else {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
        $("#beach").css("border","4px solid yellow");
            if (incoming_ONG == 0) {
                audio_Chime.play();
                incoming_ONG = 1;
            }
    }
    else if (KeepBlue == 0) {
        $("#beach").css("border","1px solid white");
	}
}

function RedundaKitty() {
	i = Molpy.redactedToggle - Molpy.redactedCountup;

	if (Molpy.redactedVisible > 0) {
		//Clicks if AutoClicker Enabled
		if (RKAutoClickStatus == 1) {
			Molpy.ClickRedacted();
		}

		else {
			//Redundakitty Notifications (Title Bar and Audio)
			document.title = "! kitten !";
			if (Math.floor(i % RKAlertFrequency) == 0) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = Molpy.redactedToggle-Molpy.redactedCountup;
		if (i != 0) { i = 0; }
	}
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 2) {RKAutoClickStatus = 0};
			status = RKAutoClickStatus;
		break;
	}
	WriteOptionDescription(option, status);
}

function WriteOptionDescription(option, status) {
	if (option == 'RKAutoClick') {
			switch (status) {
					case 1:
						description = "On";
						break;
					case 0:
						description = "Off";
						break;
			}
	}
	g(option + 'Desc').innerHTML = '
' + description;
}<commit_msg>Testing Option Description<commit_after>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure

//Declare and Initialize Variables
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume=1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume=1;
var description = "Error";
var i = 0;
var IdleStatus = 0;
var incoming_ONG = 0;
var KeepBlue = 0;
var NinjaAutoClickStatus = 0;
var RKAutoClickStatus = 0;
var RKAlertFrequency = 8;
var Time_to_ONG = 1800000;

//Beach Ball Startup
	//Set Settings
	IdleStatus = prompt("Set to idle? (1 = Yes, 0 = No)");
	RKAutoClickStatus = IdleStatus;
	NinjaAutoClickStatus = IdleStatus;
	if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

	//Create Menu
	$('#optionsItems').append('

RK Auto Click

');
	WriteOptionDescription('RKAutoClick',RKAutoClickStatus);

	Molpy.Notify('abc123', 1);

//Main Loop
setInterval(function() {
    RedundaKitty();
    Ninja();
	Molpy.Notify('abc321', 1);
}, 1800);

function Ninja() {
	//Ninja Warnings and Incoming ONG Warning
    Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
	if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
                $("#beach").css("border","4px solid blue");
                KeepBlue = 1;
            }
            else {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
        $("#beach").css("border","4px solid yellow");
            if (incoming_ONG == 0) {
                audio_Chime.play();
                incoming_ONG = 1;
            }
    }
    else if (KeepBlue == 0) {
        $("#beach").css("border","1px solid white");
	}
}

function RedundaKitty() {
	i = Molpy.redactedToggle - Molpy.redactedCountup;

	if (Molpy.redactedVisible > 0) {
		//Clicks if AutoClicker Enabled
		if (RKAutoClickStatus == 1) {
			Molpy.ClickRedacted();
		}

		else {
			//Redundakitty Notifications (Title Bar and Audio)
			document.title = "! kitten !";
			if (Math.floor(i % RKAlertFrequency) == 0) {
				audio_Bell.play();
			}
		}
	}
	else {
		document.title = Molpy.redactedToggle-Molpy.redactedCountup;
		if (i != 0) { i = 0; }
	}
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 2) {RKAutoClickStatus = 0};
			status = RKAutoClickStatus;
		break;
	}
	WriteOptionDescription(option, status);
}

function WriteOptionDescription(option, status) {
	if (option == 'RKAutoClick') {
			switch (status) {
					case 1:
						description = "On";
						break;
					case 0:
						description = "Off";
						break;
			}
	}
	g(option + 'Desc').innerHTML = '
' + description;
}<|endoftext|>


<commit_before>angular.module('Ventolone.controllers', [])
  .controller('NewAnemometerCtrl', function($scope, Anemometer, $location) {
    $scope.anemometer = {}
    $scope.submit = function() {
      Anemometer.save($scope.anemometer).$promise.then(function(response) {
        $location.path($scope.h.anemometerUploadRoute(response.id))
      })
    }
  })
  .controller('EditAnemometerCtrl', function($scope, Anemometer, anemometer) {
    $scope.anemometer = anemometer
    $scope.submit = function() {
      Anemometer.save($scope.anemometer)
    }
  })
  .controller('AnemometerListCtrl', function($scope, Anemometer, $route) {
    $scope.options = {
      width: 400,
      height: 120,
      redFrom: 90,
      redTo: 100,
      yellowFrom: 75,
      yellowTo: 90,
      minorTicks: 5
    };

    Anemometer.query().$promise.then(function(anemometers) {
      $scope.anemometers = anemometers
    })

    $scope.delete = function(anemometer) {
      Anemometer.delete({
        id: anemometer._id,
        rev: anemometer._rev
      }, function() {
        $route.reload()
      })
    }
  })
  .controller('AnemometerCtrl', function($scope, anemometer, Sample, $q, $interpolate, $filter, params, TimeChartsData, timeFilter, frequencyTimeFilter, FrequencyChartsData) {
    $scope.anemometer = anemometer

    params.then(function(p) {
      $scope.options = p.intervalsGroupLevels
    })

    $scope.dataFrequency = 4

    var statistics = Sample.statistics({
      startkey: JSON.stringify([anemometer._id]),
      endkey: JSON.stringify([anemometer._id, {}]),
    }, function(statistics) {
      if (statistics.time) {
        $scope.timeSpan = {
          from: $filter('date')(new Date(statistics.time.min * 1000), 'yyyy-MM-dd'),
          to: $filter('date')(new Date(statistics.time.max * 1000), 'yyyy-MM-dd')
        }

        $scope.$watch('dataFrequency', updateTimeCharts)
        $scope.$watch('timeSpan.to', updateTimeCharts)
        $scope.$watch('timeSpan.from', updateTimeCharts)

        $scope.$watch('dataFrequency', updateFrequencyCharts)
        $scope.$watch('timeSpan.to', updateFrequencyCharts)
        $scope.$watch('timeSpan.from', updateFrequencyCharts)
      }
    })

    var tooltip = $interpolate('{{date | date:"dd/MM/yyyy - hh:mm"}}
 {{label}}: {{value|number}}');

    function updateTimeCharts() {
      $scope.showOverlay = true
      var dataFrequency = $scope.dataFrequency
      if (dataFrequency && anemometer._id) {
        var samples = Sample.time({
          group_level: dataFrequency,
          startkey: JSON.stringify([anemometer._id].concat(timeFilter(dataFrequency, $scope.timeSpan.from))),
          endkey: JSON.stringify([anemometer._id].concat(timeFilter(dataFrequency, $scope.timeSpan.to)).concat({}))
        })

        TimeChartsData(samples.$promise, tooltip).then(function(data) {
          $scope.data = data.speed
          $scope.dataBattery = data.battery
          $scope.showOverlay = false
        })
      }
    }

    function updateFrequencyCharts() {
      var dataFrequency = $scope.dataFrequency,
        group_level = (dataFrequency - 1) * 2 + 1,
        frequency = Sample.frequency({
          group_level: group_level,
          startkey: JSON.stringify([anemometer._id].concat(frequencyTimeFilter(dataFrequency, $scope.timeSpan.from, -100))),
          endkey: JSON.stringify([anemometer._id].concat(frequencyTimeFilter(dataFrequency, $scope.timeSpan.to, 100)))
        })

        $q.all({
          statistics: statistics.$promise,
          frequency: frequency.$promise
        }).then(function(data) {
          $scope.frequency = FrequencyChartsData(data.frequency, angular.noop, group_level, data.statistics.count)
        })
    }

  })
  .controller('AnemometerUploadCtrl', function($scope, readFile, csvReader, upload, anemometer, anemometerStatistics, Sample, anemometerStats) {
    $scope.anemometer = anemometer
    var iterator
    $scope.$watch('importFile', function(file) {
      if (file) {
        readFile(file).then(function(csv) {
          iterator = csvReader(csv)
          $scope.numberOfLines = iterator.size()
        })
      }
    })

    $scope.submit = function() {
      $scope.uploads = 0
      $scope.uploadErrors = 0
      $scope.uploadsActive = true
      $scope.uploadsComplete = false
      $scope.uploadErrorsProgress = 0

      var up = upload(anemometer, iterator)
      up.promise.then(
        function() {
          $scope.uploadsActive = false
          $scope.uploadsComplete = true
          $scope.importFile = null
          $scope.numberOfLines = null

          anemometerStats(anemometer).then(function() {
            $scope.uploadsComplete = false
            $scope.processingComplete = true
          })
        },
        function() {
          $scope.uploadErrors++
          $scope.uploadErrorsProgress = $scope.uploadErrors / up.numberOfUploads
        },
        function(val) {
          $scope.uploads++
          $scope.uploadsProgress = $scope.uploads / up.numberOfUploads
          $scope.uploadsPercent = $scope.uploads / up.numberOfUploads * 100
        }
      )
    }
  })
<commit_msg>cleanup<commit_after>angular.module('Ventolone.controllers', [])
  .controller('NewAnemometerCtrl', function($scope, Anemometer, $location) {
    $scope.anemometer = {}
    $scope.submit = function() {
      Anemometer.save($scope.anemometer).$promise.then(function(response) {
        $location.path($scope.h.anemometerUploadRoute(response.id))
      })
    }
  })
  .controller('EditAnemometerCtrl', function($scope, Anemometer, anemometer) {
    $scope.anemometer = anemometer
    $scope.submit = function() {
      Anemometer.save($scope.anemometer)
    }
  })
  .controller('AnemometerListCtrl', function($scope, Anemometer, $route) {

    Anemometer.query().$promise.then(function(anemometers) {
      $scope.anemometers = anemometers
    })

    $scope.delete = function(anemometer) {
      Anemometer.delete({
        id: anemometer._id,
        rev: anemometer._rev
      }, function() {
        $route.reload()
      })
    }
  })
  .controller('AnemometerCtrl', function($scope, anemometer, Sample, $q, $interpolate, $filter, params, TimeChartsData, timeFilter, frequencyTimeFilter, FrequencyChartsData) {
    $scope.anemometer = anemometer

    params.then(function(p) {
      $scope.options = p.intervalsGroupLevels
    })

    $scope.dataFrequency = 4

    var statistics = Sample.statistics({
      startkey: JSON.stringify([anemometer._id]),
      endkey: JSON.stringify([anemometer._id, {}]),
    }, function(statistics) {
      if (statistics.time) {
        $scope.timeSpan = {
          from: $filter('date')(new Date(statistics.time.min * 1000), 'yyyy-MM-dd'),
          to: $filter('date')(new Date(statistics.time.max * 1000), 'yyyy-MM-dd')
        }

        $scope.$watch('dataFrequency', updateTimeCharts)
        $scope.$watch('timeSpan.to', updateTimeCharts)
        $scope.$watch('timeSpan.from', updateTimeCharts)

        $scope.$watch('dataFrequency', updateFrequencyCharts)
        $scope.$watch('timeSpan.to', updateFrequencyCharts)
        $scope.$watch('timeSpan.from', updateFrequencyCharts)
      }
    })

    var tooltip = $interpolate('{{date | date:"dd/MM/yyyy - hh:mm"}}
 {{label}}: {{value|number}}');

    function updateTimeCharts() {
      $scope.showOverlay = true
      var dataFrequency = $scope.dataFrequency
      if (dataFrequency && anemometer._id) {
        var samples = Sample.time({
          group_level: dataFrequency,
          startkey: JSON.stringify([anemometer._id].concat(timeFilter(dataFrequency, $scope.timeSpan.from))),
          endkey: JSON.stringify([anemometer._id].concat(timeFilter(dataFrequency, $scope.timeSpan.to)).concat({}))
        })

        TimeChartsData(samples.$promise, tooltip).then(function(data) {
          $scope.data = data.speed
          $scope.dataBattery = data.battery
          $scope.showOverlay = false
        })
      }
    }

    function updateFrequencyCharts() {
      var dataFrequency = $scope.dataFrequency,
        group_level = (dataFrequency - 1) * 2 + 1,
        frequency = Sample.frequency({
          group_level: group_level,
          startkey: JSON.stringify([anemometer._id].concat(frequencyTimeFilter(dataFrequency, $scope.timeSpan.from, -100))),
          endkey: JSON.stringify([anemometer._id].concat(frequencyTimeFilter(dataFrequency, $scope.timeSpan.to, 100)))
        })

        $q.all({
          statistics: statistics.$promise,
          frequency: frequency.$promise
        }).then(function(data) {
          $scope.frequency = FrequencyChartsData(data.frequency, angular.noop, group_level, data.statistics.count)
        })
    }

  })
  .controller('AnemometerUploadCtrl', function($scope, readFile, csvReader, upload, anemometer, anemometerStatistics, Sample, anemometerStats) {
    $scope.anemometer = anemometer
    var iterator
    $scope.$watch('importFile', function(file) {
      if (file) {
        readFile(file).then(function(csv) {
          iterator = csvReader(csv)
          $scope.numberOfLines = iterator.size()
        })
      }
    })

    $scope.submit = function() {
      $scope.uploads = 0
      $scope.uploadErrors = 0
      $scope.uploadsActive = true
      $scope.uploadsComplete = false
      $scope.uploadErrorsProgress = 0

      var up = upload(anemometer, iterator)
      up.promise.then(
        function() {
          $scope.uploadsActive = false
          $scope.uploadsComplete = true
          $scope.importFile = null
          $scope.numberOfLines = null

          anemometerStats(anemometer).then(function() {
            $scope.uploadsComplete = false
            $scope.processingComplete = true
          })
        },
        function() {
          $scope.uploadErrors++
          $scope.uploadErrorsProgress = $scope.uploadErrors / up.numberOfUploads
        },
        function(val) {
          $scope.uploads++
          $scope.uploadsProgress = $scope.uploads / up.numberOfUploads
          $scope.uploadsPercent = $scope.uploads / up.numberOfUploads * 100
        }
      )
    }
  })
<|endoftext|>


<commit_before>/* --------------------------------------- *
* Guerrilla UI                             *
* @module: Broker pub / sub implemntation  *
* ---------------------------------------- */
var Broker;

Broker = (function() {

    function Broker(obj, cascade) {

        this.cascade = (cascade) ? true : false;

        this.channels = {};

        if (utils.isObj(obj)) {
            this.install(obj);

        } else if (obj === true) {
            this.cascade = true;
        }
    }

    Broker.prototype.bind = function(fn, me) {
        return function() {
            return fn.apply(me, arguments);
        };
    };

    Broker.prototype.add = function(channel, fn, context) {
        var subscription, _this = this;

        if (!context || context === null) {
            context = this;
        }

        if (!this.channels[channel]){
            this.channels[channel] = [];
        }

        subscription = {
            event: channel,
            context: context,
            callback: fn || function(){}
        };

        return {
            listen: function() {
                _this.channels[channel].push(subscription);
                return this;
            },
            ignore: function() {
                _this.remove(channel);
                return this;
            }
        }.listen();
    };

    Broker.prototype.remove = function(channel, cb) {
        var id;

        switch (typeof channel) {

            case "string":
                if (typeof cb === "function") {
                    Broker._delete(this, ch, cb);
                }

                if (typeof cb === "undefined") {
                    Broker._delete(this, ch);
                }
                break;

            case "function":
                for (id in this.channels) {
                    Broker._delete(this, id, ch);
                }
                break;

            case "undefined":
                for (id in this.channels) {
                    Broker._delete(this, id);
                }
                break;

            case "object":
                for (id in this.channels) {
                    Broker._delete(this, id, null, ch);
                }
        }

        return this;
    };

    Broker.prototype.fire = function(channel, data, cb) {
        var tasks;

        if (!cb || cb === null) {
            cb = function() {};
        }

        if (typeof data === "function") {
            cb = data;
            data = void 0;
        }

        if (typeof channel !== "string") {
            return false;
        }

        tasks = this._setup(data, channel, channel, this);

        utils.run.first(tasks, (function(errors, result) {
            var e, x;

            if (errors) {

                e = new Error(((function() {
                    var i, len, results1;

                    results1 = [];

                    for (i = 0, len = errors.length; i < len; i++) {
                        x = errors[i];

                        if (x !== null) {
                            results1.push(x.message);
                        }
                    }

                    return results1;

                })()).join('; '));

                return cb(e);

            } else {

                return cb(null, result);
            }
        }), true);

        return this;
    };

    Broker.prototype.emit = function(channel, data, cb, origin) {
        var o, e, x, chnls;

        if (!cb || cb === null) {
            cb = (function() {});
        }

        if (!origin || origin === null) {
            origin = channel;
        }

        if (data && utils.isFunc(data)) {
            cb = data;
        }

        data = void 0;

        if (typeof channel !== "string") {
            return false;
        }

        tasks = this._setup(data, channel, origin, this);

        utils.run.series(tasks, (function(errors, series) {
            if (errors) {

                e = new Error(((function() {
                    var i, len, results;

                    results = [];

                    for (i = 0, len = errors.length; i < len; i++) {
                        x = errors[i];

                        if (x !== null) {
                            results.push(x.message);
                        }
                    }

                    return results;

                })()).join('; '));

                return e;
            }
        }, cb(e)), true);

        if (this.cascade && (chnls = channel.split('/')).length > 1) {

            if (this.fireOrigin) {
                o = origin;
            }

            this.fire(chnls.slice(0, -1).join('/'), data, cb, o);
        }

        return this;
    };

    Broker.prototype.install = function(obj, forced) {
        var key, value;

        if (utils.isObj(obj)) {

            for (key in this) {

                value = this[key];

                if (forced) {
                    obj[key] = value;
                } else {

                    if (!obj[key]) {
                        obj[key] = value;
                    }
                }
            }
        }

        return this;
    };

    Broker.prototype._delete = function(obj, channel, cb, context) {
        var s;

        if (obj.channels[channel] === null) {

            obj.channels[channel] = (function() {
                var i, len, ref, results;

                ref = obj.channels[ch];
                results = [];

                for (i = 0, len = ref.length; i < len; i++) {
                    s = ref[i];

                    if ((typeof cb !== "undefined" && cb !== null ? s.callback !== cb : typeof context !== "undefined" && context !== null ? s.context !== context : s.context !== obj)) {

                        results.push(s);
                    }
                }

                return results;

            })();

            return obj.channels[channel];
        }
    };

    Broker.prototype._setup = function(data, channel, origin, context) {
        var i = 0, len, results = [], sub, subscribers;

        subscribers = context.channels[channel] || [];
        len = subscribers.length;

        do {
            sub = subscribers[i];

            results.push((function(sub) {

                return function(next) {
                    var e;

                    try {

                        if (utils.hasArgs(sub.callback, 3)) {

                            return sub.callback.apply(sub.context, [data, origin, next]);

                        } else {

                            return next(null, sub.callback.apply(sub.context, [data, origin]));
                        }
                    } catch (_error) {
                        e = _error;

                        return next(e);
                    }
                };
            })(sub));

            i++;
        } while(--len);

        return results;
    };

    Broker.prototype.pipe = function(src, target, broker) {
        if (target instanceof Broker) {
            mediator = target;
            target = src;
        }

        if (broker === null) {
            return this.pipe(src, target, this);
        }

        if (broker === this && src === target) {
            return this;
        }

        this.add(src, function() {

            return broker.fire.apply(broker, [target].concat(slice.call(arguments)));
        });

        return this;
    };

    return Broker;

})(this);
<commit_msg>--update local _this reference to $this<commit_after>/* --------------------------------------- *
* Guerrilla UI                             *
* @module: Broker pub / sub implemntation  *
* ---------------------------------------- */
var Broker;

Broker = (function() {

    function Broker(obj, cascade) {

        this.cascade = (cascade) ? true : false;

        this.channels = {};

        if (utils.isObj(obj)) {
            this.install(obj);

        } else if (obj === true) {
            this.cascade = true;
        }
    }

    Broker.prototype.bind = function(fn, me) {
        return function() {
            return fn.apply(me, arguments);
        };
    };

    Broker.prototype.add = function(channel, fn, context) {
        var subscription, $this = this;

        if (!context || context === null) {
            context = this;
        }

        if (!this.channels[channel]){
            this.channels[channel] = [];
        }

        subscription = {
            event: channel,
            context: context,
            callback: fn || function(){}
        };

        return {
            listen: function() {
                $this.channels[channel].push(subscription);
                return this;
            },
            ignore: function() {
                $this.remove(channel);
                return this;
            }
        }.listen();
    };

    Broker.prototype.remove = function(channel, cb) {
        var id;

        switch (typeof channel) {

            case "string":
                if (typeof cb === "function") {
                    Broker._delete(this, ch, cb);
                }

                if (typeof cb === "undefined") {
                    Broker._delete(this, ch);
                }
                break;

            case "function":
                for (id in this.channels) {
                    Broker._delete(this, id, ch);
                }
                break;

            case "undefined":
                for (id in this.channels) {
                    Broker._delete(this, id);
                }
                break;

            case "object":
                for (id in this.channels) {
                    Broker._delete(this, id, null, ch);
                }
        }

        return this;
    };

    Broker.prototype.fire = function(channel, data, cb) {
        var tasks;

        if (!cb || cb === null) {
            cb = function() {};
        }

        if (typeof data === "function") {
            cb = data;
            data = void 0;
        }

        if (typeof channel !== "string") {
            return false;
        }

        tasks = this._setup(data, channel, channel, this);

        utils.run.first(tasks, (function(errors, result) {
            var e, x;

            if (errors) {

                e = new Error(((function() {
                    var i, len, results1;

                    results1 = [];

                    for (i = 0, len = errors.length; i < len; i++) {
                        x = errors[i];

                        if (x !== null) {
                            results1.push(x.message);
                        }
                    }

                    return results1;

                })()).join('; '));

                return cb(e);

            } else {

                return cb(null, result);
            }
        }), true);

        return this;
    };

    Broker.prototype.emit = function(channel, data, cb, origin) {
        var o, e, x, chnls;

        if (!cb || cb === null) {
            cb = (function() {});
        }

        if (!origin || origin === null) {
            origin = channel;
        }

        if (data && utils.isFunc(data)) {
            cb = data;
        }

        data = void 0;

        if (typeof channel !== "string") {
            return false;
        }

        tasks = this._setup(data, channel, origin, this);

        utils.run.series(tasks, (function(errors, series) {
            if (errors) {

                e = new Error(((function() {
                    var i, len, results;

                    results = [];

                    for (i = 0, len = errors.length; i < len; i++) {
                        x = errors[i];

                        if (x !== null) {
                            results.push(x.message);
                        }
                    }

                    return results;

                })()).join('; '));

                return e;
            }
        }, cb(e)), true);

        if (this.cascade && (chnls = channel.split('/')).length > 1) {

            if (this.fireOrigin) {
                o = origin;
            }

            this.fire(chnls.slice(0, -1).join('/'), data, cb, o);
        }

        return this;
    };

    Broker.prototype.install = function(obj, forced) {
        var key, value;

        if (utils.isObj(obj)) {

            for (key in this) {

                value = this[key];

                if (forced) {
                    obj[key] = value;
                } else {

                    if (!obj[key]) {
                        obj[key] = value;
                    }
                }
            }
        }

        return this;
    };

    Broker.prototype._delete = function(obj, channel, cb, context) {
        var s;

        if (obj.channels[channel] === null) {

            obj.channels[channel] = (function() {
                var i, len, ref, results;

                ref = obj.channels[ch];
                results = [];

                for (i = 0, len = ref.length; i < len; i++) {
                    s = ref[i];

                    if ((typeof cb !== "undefined" && cb !== null ? s.callback !== cb : typeof context !== "undefined" && context !== null ? s.context !== context : s.context !== obj)) {

                        results.push(s);
                    }
                }

                return results;

            })();

            return obj.channels[channel];
        }
    };

    Broker.prototype._setup = function(data, channel, origin, context) {
        var i = 0, len, results = [], sub, subscribers;

        subscribers = context.channels[channel] || [];
        len = subscribers.length;

        do {
            sub = subscribers[i];

            results.push((function(sub) {

                return function(next) {
                    var e;

                    try {

                        if (utils.hasArgs(sub.callback, 3)) {

                            return sub.callback.apply(sub.context, [data, origin, next]);

                        } else {

                            return next(null, sub.callback.apply(sub.context, [data, origin]));
                        }
                    } catch (_error) {
                        e = _error;

                        return next(e);
                    }
                };
            })(sub));

            i++;
        } while(--len);

        return results;
    };

    Broker.prototype.pipe = function(src, target, broker) {
        if (target instanceof Broker) {
            mediator = target;
            target = src;
        }

        if (broker === null) {
            return this.pipe(src, target, this);
        }

        if (broker === this && src === target) {
            return this;
        }

        this.add(src, function() {

            return broker.fire.apply(broker, [target].concat(slice.call(arguments)));
        });

        return this;
    };

    return Broker;

})(this);
<|endoftext|>


<commit_before>const listen = (dispatch) => {
  const layout = {};

  const vdom = require('virtual-dom');
  const main = require('main-loop');
  const hyperx = require('hyperx');
  const hx = hyperx(vdom.h);

  const onMessage = (msg) => {
    console.log(msg);
    const { data, component, componentId } = msg;

    switch (data) {
      case 'scene/dashboard':
        changeScene('dashboard');
        break;
      case 'scene/login':
        changeScene('login');
        break;
      case 'scene/cacheComponent':
        cacheComponent(componentId, component);
        break;
      default:
        changeScene('default');
        break;
    }
  };

  function cacheComponent(componentId, component) {
    layout[componentId] = component;
  }

  function render(state) {
    const cmp = layout[state.sceneKey];
    console.log('render', state);
    console.log('component', cmp);
    return cmp || hx`<span>default</span>`;
  }

  const loop = main({ sceneKey: 'default' }, render, vdom);
  document.querySelector('.scene').appendChild(loop.target);

  const changeScene = (name) => {
    console.log('change scene', name);
    loop.update({ sceneKey: name });
  };

  return onMessage;
};

export default listen;
<commit_msg>+ eslint errors fix<commit_after>const vdom = require('virtual-dom');
const main = require('main-loop');
const hyperx = require('hyperx');

const listen = (dispatch) => {
  const layout = {};
  const hx = hyperx(vdom.h);

  const onMessage = (msg) => {
    console.log(msg);
    const { data, component, componentId } = msg;

    switch (data) {
      case 'scene/dashboard':
        changeScene('dashboard');
        break;
      case 'scene/login':
        changeScene('login');
        break;
      case 'scene/cacheComponent':
        cacheComponent(componentId, component);
        break;
      default:
        changeScene('default');
        break;
    }
  };

  function cacheComponent(componentId, component) {
    layout[componentId] = component;
  }

  function render(state) {
    const cmp = layout[state.sceneKey];
    console.log('render', state);
    console.log('component', cmp);
    return cmp || hx`<span>default</span>`;
  }

  const loop = main({ sceneKey: 'default' }, render, vdom);
  document.querySelector('.scene').appendChild(loop.target);

  function changeScene(name) {
    console.log('change scene', name);
    loop.update({ sceneKey: name });
  }

  return onMessage;
};

export default listen;
<|endoftext|>


<commit_before>import Endpoint from './endpoint';

/**
 * Creates an endpoint hash.
 * The hash is a combination of the url and the method parameters. Guarantees uniqueness
 * for distinct inputs.
 *
 * @param  {String} url    The url to hash.
 * @param  {String} method The method to hash.
 * @return {String}        Returned unique hash.
 */
function createEndpointHash(url, method) {
  return `url:${url}|method:${method}`;
}

/**
 * This class represents a fake server. The server serves endpoints registered with it.
 *
 * @class PseudoServer
 */
export default class Server {

  /**
   * Constructor.
   *
   * Takes a config-parameter which is the config of the server.
   *
   * @param  {Object} config A url-config associated with this pseudo-server.
   */
  constructor(config) {
    this.config = config;
    this.paths = {};
  }

  /**
   * Registers a new route with the server. The method simply creates a new
   * PseudoEndpoint-instance, and adds it to the paths-dict of this server.
   *
   * @param  {String} url     The url of the endpoint.
   * @param  {String} method  The method it accepts requests to. Typically GET/POST etc.
   * @return {PseudoEndpoint} The resulting endpoint.
   */
  route(url, method) {
    const endpoint = new PseudoEndpoint(url, method);
    const hash = createEndpointHash(url, method);
    if (hash in this.paths) {
      console.warn(`Overwriting ${hash}`);
    }

    this.paths[createEndpointHash(url, method)] = endpoint;
    return endpoint;
  }

  /**
   * Alias for route(url, 'GET').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {PseudoEndpoint} The resulting endpoint.
   */
  get(url) {
    return route(url, 'GET');
  }

  /**
   * Alias for route(url, 'POSt').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {PseudoEndpoint} The resulting endpoint.
   */
  post(url) {
    return route(url, 'POST');
  }

  /**
   * Alias for route(url, 'PATCH').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {PseudoEndpoint} The resulting endpoint.
   */
  patch(url) {
    return route(url, 'PATCH');
  }

  /**
   * Alias for route(url, 'PUT').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {PseudoEndpoint} The resulting endpoint.
   */
  put(url) {
    return route(url, 'PUT');
  }

  /**
   * Alias for route(url, 'DELETE').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {PseudoEndpoint} The resulting endpoint.
   */
  delete(url) {
    return route(url, 'DELETE');
  }

  /**
   * Alias for route(url, 'OPTIONS').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {PseudoEndpoint} The resulting endpoint.
   */
  options(url) {
    return route(url, 'OPTIONS');
  }

  /**
   * Alias for route(url, 'HEAD').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {PseudoEndpoint} The resulting endpoint.
   */
  head(url) {
  _call(url='', config={}) {
    const endpointHash = createEndpointHash(url, config.method || 'GET');
    const endpoint = this.endpoints[endpointHash];
    if (!endpoint) {
      return new Promise((resolve, reject) => {
        reject(new Response({status: 404}));
      });
    }
    return endpoint._call(url, config);
  }
}
<commit_msg>Fixed a few bugs in server<commit_after>import Endpoint from './endpoint';
import Response from './response';

/**
 * Creates an endpoint hash.
 * The hash is a combination of the url and the method parameters. Guarantees uniqueness
 * for distinct inputs.
 *
 * @param  {String} url    The url to hash.
 * @param  {String} method The method to hash.
 * @return {String}        Returned unique hash.
 */
function createEndpointHash(url, method) {
  return `url:${url}|method:${method}`;
}

/**
 * This class represents a fake server. The server serves endpoints registered with it.
 *
 * @class PseudoServer
 */
export default class Server {

  /**
   * Constructor.
   *
   * Takes a config-parameter which is the config of the server.
   *
   * @param  {Object} config A url-config associated with this pseudo-server.
   */
  constructor(config) {
    this.config = config;
    this.endpoints = {};
  }

  /**
   * Registers a new route with the server. The method simply creates a new
   * Endpoint-instance, and adds it to the endpoints-dict of this server.
   *
   * @param  {String} url     The url of the endpoint.
   * @param  {String} method  The method it accepts requests to. Typically GET/POST etc.
   * @return {Endpoint} The resulting endpoint.
   */
  route(url='', method='GET') {
    const endpoint = new Endpoint(url, method);
    const hash = createEndpointHash(url, method);
    if (hash in this.endpoints) {
      console.warn(`Overwriting ${hash}`);
    }

    this.endpoints[createEndpointHash(url, method)] = endpoint;
    return endpoint;
  }

  /**
   * Alias for route(url, 'GET').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {Endpoint} The resulting endpoint.
   */
  get(url) {
    return this.route(url, 'GET');
  }

  /**
   * Alias for route(url, 'POSt').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {Endpoint} The resulting endpoint.
   */
  post(url) {
    return this.route(url, 'POST');
  }

  /**
   * Alias for route(url, 'PATCH').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {Endpoint} The resulting endpoint.
   */
  patch(url) {
    return this.route(url, 'PATCH');
  }

  /**
   * Alias for route(url, 'PUT').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {Endpoint} The resulting endpoint.
   */
  put(url) {
    return this.route(url, 'PUT');
  }

  /**
   * Alias for route(url, 'DELETE').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {Endpoint} The resulting endpoint.
   */
  delete(url) {
    return this.route(url, 'DELETE');
  }

  /**
   * Alias for route(url, 'OPTIONS').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {Endpoint} The resulting endpoint.
   */
  options(url) {
    return this.route(url, 'OPTIONS');
  }

  /**
   * Alias for route(url, 'HEAD').
   *
   * @param  {String} url     The url of the endpoint.
   * @return {Endpoint} The resulting endpoint.
   */
  head(url) {
    return this.route(url, 'HEAD');
  }

  _call(url='', config={}) {
    const endpointHash = createEndpointHash(url, config.method || 'GET');
    const endpoint = this.endpoints[endpointHash];
    if (!endpoint) {
      return new Promise((resolve, reject) => {
        reject(new Response({status: 404}));
      });
    }
    return endpoint._call(url, config);
  }
}
<|endoftext|>


<commit_before>import fs from 'fs'
import http from 'http';
import path from 'path';

import axios from 'axios';
//import db from './db';
import express from 'express';
//import Sequelize from 'sequelize';
import Promise from 'bluebird';
import React from 'react';
import WebpackDevServer from 'webpack-dev-server';
import webpack from 'webpack';

import Structure from './Structure';
import defaultData from './data';
import Html from './components/Html';
import Layout from './components/Layout';
import routes, {actions} from './routes';
import marshall from './marshall';
import settings from './settings';

const app = express();
const statsJsonPath = path.join(path.dirname(process.argv[1]), '..', 'build', '_stats.json');
const debug = require('debug')('rjanko:server');

function renderHtml(res, data, webpackAssets) {
  const cursor = data.cursor();
  const markup = React.renderToString(<Layout data={cursor} />);
  const html = React.renderToStaticMarkup();
  res.send(`<!doctype html>\n${html}`);
}

async function renderApp(req, res, next, webpackAssets) {
  let route = routes.getRoute(req.path);

  //let manifestRequestHeaders = {};
  //if (req.headers.cookie) {
  //  manifestRequestHeaders.Cookie = req.headers.cookie;
  //}
  //let manifestResponse = await axios({
  //  url: `${settings.apiHost()}/api/manifest/`,
  //  headers: manifestRequestHeaders
  //});

  const data = new Structure(defaultData, false);

  //data.setIn('user', manifestResponse.data.user);

  if (!route) {
    route = routes.getRoute('/404');
  }

  data.setIn('route', {
    name: route.name,
    params: route.params,
    query: req.query
  });

  const actionPromise = actions[route.name]
      ? actions[route.name](data, route.params, req.query)
      : new Promise(resolve => resolve());

  actionPromise.then(function() {
    renderHtml(res, data, webpackAssets);
  }).catch((e) => {
    //throw e;
    route = routes.getRoute('/500');
    data.setIn('route', {name: route.name, params: route.params});
    renderHtml(res, data, webpackAssets);
    next();
  });
}

if (process.env.NODE_ENV === 'production') {

  const webpackAssets = JSON.parse(fs.readFileSync(statsJsonPath));

  app.get('/_webpack_stats.json', function (req, res, next) {
    res.send(webpackAssets)
  });

  app.use('/build', express.static(path.join(__dirname, 'build')));

  app.use(function(req, res, next) {
    renderApp(req, res, next, webpackAssets).catch(next)
  });

  app.use(function(err, req, res, next) {
    if (err) {
      debug(err.stack);
      res.send('internal error ;(');
    }
  });

} else {

  var webpackServer = new WebpackDevServer(webpack(require(
      path.join(path.dirname(process.argv[1]), '../webpack.config')
  )), {
    publicPath: 'http://0.0.0.0:3001/build/',
    watchDelay: 0,
    hot: true,
    stats: {
      colors: true,
      assets: true,
      timings: true,
      chunks: false,
      chunkModules: false,
      modules: false,
      children: false
    }
  });

  webpackServer.listen(3001, '0.0.0.0', function (err, result) {
    if (err) {
      debug(err);
    } else {
      debug('webpack server listening on 3001');
    }
  });

  //app.use(favicon(path.join(__dirname, 'favicon.ico')));

  app.get('/_webpack_stats.json', function(req, res, next) {
    const webpackAssets = JSON.parse(webpackServer.middleware.fileSystem.readFileSync(statsJsonPath));
    res.send(webpackAssets);
  });

  app.use(function(req, res, next) {
    const webpackAssets = JSON.parse(webpackServer.middleware.fileSystem.readFileSync(statsJsonPath));
    renderApp(req, res, next, webpackAssets).catch(next);
  });

  app.use(function(err, req, res, next) {
    if (err) {
      debug(err.stack);
      res.send('
' + err.stack + '
');
    }
  });

}

const port = process.env.PORT || 3000;
const server = http.Server(app);

async function makeApiRequest(socket, payload) {
  const {status, data, headers} = await axios({
    url: `${settings.apiHost()}${payload.url}`,
    method: payload.method,
    data: payload.data,
    responseType: 'text',
    headers: {
      'content-type': 'application/json',
      cookie: payload.cookies
    },
    transformResponse: [function(responseData) {
      try {
        return JSON.parse(responseData);
      } catch(e) {
        return undefined;
      }
    }]
  });
  socket.emit('apiResponse', {
    requestId: payload.requestId,
    status,
    data,
    cookies: headers['set-cookie']
  });
}

var io = require('socket.io')(server);
io.on('connection', function(socket){
  socket.on('apiRequest', payload => makeApiRequest(socket, payload));
});

server.listen(port, function(err, result) {
  if (err) {
    debug(err);
  }
  debug(`express listening on ${port}`);
});

//app.get('/admin', (req, res) => {
//  res.send('Welcome to admin of <%= rjanko.name %>')
//});
//
//app.get('/', (req, res) => {
//  res.send(`Hello World, <%= rjanko.name %>!`);
//});

//app.post('/users', (req, res) => {
//
//  var User = db.define('user', {
//    firstName: {
//      type: Sequelize.STRING,
//      field: 'first_name'
//    },
//    lastName: {
//      type: Sequelize.STRING
//    }
//  }, {
//    freezeTableName: true
//  });
//
//
//  User.sync({force: true}).then(function () {
//    // Table created
//    return User.create({
//      firstName: 'Антон',
//      lastName: 'Федченко'
//    });
//  });
//
//  res.send(`Post users`);
//});
//
//app.get('/users', (req, res) => {
//  res.send(`Get users`);
//});

//const server = app.listen(3000, () => {
//
//  const host = server.address().address;
//  const port = server.address().port;
//
//  console.log('Example app listening at http://%s:%s', host, port);
//
//});
<commit_msg>Better path joining.<commit_after>import fs from 'fs'
import http from 'http';
import path from 'path';

import axios from 'axios';
//import db from './db';
import express from 'express';
//import Sequelize from 'sequelize';
import Promise from 'bluebird';
import React from 'react';
import WebpackDevServer from 'webpack-dev-server';
import webpack from 'webpack';

import Structure from './Structure';
import defaultData from './data';
import Html from './components/Html';
import Layout from './components/Layout';
import routes, {actions} from './routes';
import marshall from './marshall';
import settings from './settings';

const app = express();
const statsJsonPath = path.join(path.dirname(process.argv[1]), '..', 'build', '_stats.json');
const debug = require('debug')('rjanko:server');

function renderHtml(res, data, webpackAssets) {
  const cursor = data.cursor();
  const markup = React.renderToString(<Layout data={cursor} />);
  const html = React.renderToStaticMarkup();
  res.send(`<!doctype html>\n${html}`);
}

async function renderApp(req, res, next, webpackAssets) {
  let route = routes.getRoute(req.path);

  //let manifestRequestHeaders = {};
  //if (req.headers.cookie) {
  //  manifestRequestHeaders.Cookie = req.headers.cookie;
  //}
  //let manifestResponse = await axios({
  //  url: `${settings.apiHost()}/api/manifest/`,
  //  headers: manifestRequestHeaders
  //});

  const data = new Structure(defaultData, false);

  //data.setIn('user', manifestResponse.data.user);

  if (!route) {
    route = routes.getRoute('/404');
  }

  data.setIn('route', {
    name: route.name,
    params: route.params,
    query: req.query
  });

  const actionPromise = actions[route.name]
      ? actions[route.name](data, route.params, req.query)
      : new Promise(resolve => resolve());

  actionPromise.then(function() {
    renderHtml(res, data, webpackAssets);
  }).catch((e) => {
    //throw e;
    route = routes.getRoute('/500');
    data.setIn('route', {name: route.name, params: route.params});
    renderHtml(res, data, webpackAssets);
    next();
  });
}

if (process.env.NODE_ENV === 'production') {

  const webpackAssets = JSON.parse(fs.readFileSync(statsJsonPath));

  app.get('/_webpack_stats.json', function (req, res, next) {
    res.send(webpackAssets)
  });

  app.use('/build', express.static(path.join(__dirname, 'build')));

  app.use(function(req, res, next) {
    renderApp(req, res, next, webpackAssets).catch(next)
  });

  app.use(function(err, req, res, next) {
    if (err) {
      debug(err.stack);
      res.send('internal error ;(');
    }
  });

} else {

  var webpackServer = new WebpackDevServer(webpack(require(
      path.join(path.dirname(process.argv[1]), '..', 'webpack.config')
  )), {
    publicPath: 'http://0.0.0.0:3001/build/',
    watchDelay: 0,
    hot: true,
    stats: {
      colors: true,
      assets: true,
      timings: true,
      chunks: false,
      chunkModules: false,
      modules: false,
      children: false
    }
  });

  webpackServer.listen(3001, '0.0.0.0', function (err, result) {
    if (err) {
      debug(err);
    } else {
      debug('webpack server listening on 3001');
    }
  });

  //app.use(favicon(path.join(__dirname, 'favicon.ico')));

  app.get('/_webpack_stats.json', function(req, res, next) {
    const webpackAssets = JSON.parse(webpackServer.middleware.fileSystem.readFileSync(statsJsonPath));
    res.send(webpackAssets);
  });

  app.use(function(req, res, next) {
    const webpackAssets = JSON.parse(webpackServer.middleware.fileSystem.readFileSync(statsJsonPath));
    renderApp(req, res, next, webpackAssets).catch(next);
  });

  app.use(function(err, req, res, next) {
    if (err) {
      debug(err.stack);
      res.send('
' + err.stack + '
');
    }
  });

}

const port = process.env.PORT || 3000;
const server = http.Server(app);

async function makeApiRequest(socket, payload) {
  const {status, data, headers} = await axios({
    url: `${settings.apiHost()}${payload.url}`,
    method: payload.method,
    data: payload.data,
    responseType: 'text',
    headers: {
      'content-type': 'application/json',
      cookie: payload.cookies
    },
    transformResponse: [function(responseData) {
      try {
        return JSON.parse(responseData);
      } catch(e) {
        return undefined;
      }
    }]
  });
  socket.emit('apiResponse', {
    requestId: payload.requestId,
    status,
    data,
    cookies: headers['set-cookie']
  });
}

var io = require('socket.io')(server);
io.on('connection', function(socket){
  socket.on('apiRequest', payload => makeApiRequest(socket, payload));
});

server.listen(port, function(err, result) {
  if (err) {
    debug(err);
  }
  debug(`express listening on ${port}`);
});

//app.get('/admin', (req, res) => {
//  res.send('Welcome to admin of <%= rjanko.name %>')
//});
//
//app.get('/', (req, res) => {
//  res.send(`Hello World, <%= rjanko.name %>!`);
//});

//app.post('/users', (req, res) => {
//
//  var User = db.define('user', {
//    firstName: {
//      type: Sequelize.STRING,
//      field: 'first_name'
//    },
//    lastName: {
//      type: Sequelize.STRING
//    }
//  }, {
//    freezeTableName: true
//  });
//
//
//  User.sync({force: true}).then(function () {
//    // Table created
//    return User.create({
//      firstName: 'Антон',
//      lastName: 'Федченко'
//    });
//  });
//
//  res.send(`Post users`);
//});
//
//app.get('/users', (req, res) => {
//  res.send(`Get users`);
//});

//const server = app.listen(3000, () => {
//
//  const host = server.address().address;
//  const port = server.address().port;
//
//  console.log('Example app listening at http://%s:%s', host, port);
//
//});
<|endoftext|>


<commit_before>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Top-Level of foam package
 */
foam = {
  isServer: typeof process === 'object',
  core:     {},
  Array:    Array.prototype,
  Function: Function.prototype,
  Number:   Number.prototype,
  Object:   Object.prototype,
  String:   String.prototype,
  Date:     Date.prototype,
};

/** Setup nodejs-like 'global' on web */
if ( ! foam.isServer ) global = this;

/**
 * Creates a small library in the foam package. A LIB is a collection of static constants,
 * properties and functions. It can also add properties to a core javascript
 * object when you specify name: 'Array', 'Function', 'Number', 'Object',
 * 'String', or 'Date'.
 *

foam.LIB({
  name: 'network',
  properties: [ { name: 'packets' } ],
  methods: [ function sendPacket() { ... }  ]
});

Produces foam.network:

foam.network.packets = 4;
foam.network.sendPacket();

Or add methods and properties to built-in types (avoid this usage if you can):

foam.LIB({
  name: 'Number',
  methods: [ function plusOne() { this += 1; } ]
});
console.assert(9.plusOne() == 10, "It works!");

 * @method LIB
 * @memberof module:foam
 */
foam.LIB = function LIB(model) {
  var proto;

  function defineProperty(proto, key, map) {
    if ( ! map.value || proto === Object.prototype || proto === Array.prototype )
      Object.defineProperty.apply(this, arguments);
    else
      proto[key] = map.value;
  }

  proto = model.name ? foam[model.name] || ( foam[model.name] = {} ) : foam;

  if ( model.properties ) for ( var i = 0 ; i < model.properties.length ; i++ ) {
    var p = model.properties[i];
    defineProperty(
      proto,
      p.name,
      { get: p.getter, enumerable: false });
  }

  for ( key in model.constants )
    defineProperty(
      proto,
      key,
      { value: model.constants[key], writable: true, enumerable: false });

  if ( model.methods ) for ( var i = 0 ; i < model.methods.length ; i++ ) {
    var m = model.methods[i];
    defineProperty(
      proto,
      m.name,
      { value: m.code || m, writable: true, enumerable: false });
  }
};

/** Object prototype additions. */
foam.LIB({
  name: 'Object',

  properties: [
    {
      /**
       * Add Unique Identifiers (UIDs) to all Objects.
       * UID's are created when first accessed.
       */
      name: '$UID',
      getter: (function() {
        var id = 1;
        return function() {
          if ( Object.hasOwnProperty.call(this, '$UID__') ) return this.$UID__;
          Object.defineProperty(this, '$UID__', {value: id, enumerable: false});
          id++;
          return this.$UID__;
        };
      })()
    }
  ]
});

/** Number prototype additions. */
foam.LIB({
  name: 'Number',

  methods: [
    function compareTo(o) { return ( o == this ) ? 0 : this < o ? -1 : 1; },
  ]
});

/** String prototype additions. */
foam.LIB({
  name: 'String',

  methods: [
    function compareTo(o) { return ( o == this ) ? 0 : this < o ? -1 : 1; },

    /** Adds hashCode functionality to all strings. */
    function hashCode() {
      var hash = 0;
      if ( this.length == 0 ) return hash;

      for (i = 0; i < this.length; i++) {
        var code = this.charCodeAt(i);
        hash = ((hash << 5) - hash) + code;
        hash &= hash;
      }

      return hash;
    }
  ]
});

/** Array prototype additions. */
foam.LIB({
  name: 'Array',
  methods: [
    function diff(other) {
      /** Finds elements added (found in other, not in this) and removed
          (found in this, not in other). Repeated values are treated
          as separate elements, but ordering changes are ignored. */
      var added = other.slice(0);
      var removed = [];
      for ( var i = 0 ; i < this.length ; i++ ) {
        for ( var j = 0 ; j < added.length ; j++ ) {
          if ( this[i].compareTo(added[j]) == 0 ) {
            added.splice(j, 1);
            j--;
            break;
          }
        }
        if ( j == added.length ) removed.push(this[i]);
      }
      return { added: added, removed: removed };
    },
    function clone() {
      /** Returns a deep copy of this array and its contents. */
      var ret = new Array(this.length);
      for ( var i = 0; i < this.length; i++ ) {
        ret[i] = ( this[i].clone ) ? this[i].clone() : this[i];
      }
      return ret;
    },
    function shallowClone() {
      /** Returns a new array containing the same elements as this. */
      return this.slice();
    }
  ]
});

/** Date prototype additions. */
foam.LIB({
  name: 'Date',
  methods: [
    function toRelativeDateString(){
      // TODO i18n: make this translatable
      var seconds = Math.floor((Date.now() - this.getTime())/1000);

      if ( seconds < 60 ) return 'moments ago';

      var minutes = Math.floor((seconds)/60);

      if ( minutes == 1 ) return '1 minute ago';

      if ( minutes < 60 ) return minutes + ' minutes ago';

      var hours = Math.floor(minutes/60);
      if ( hours == 1 ) return '1 hour ago';

      if ( hours < 24 ) return hours + ' hours ago';

      var days = Math.floor(hours / 24);
      if ( days == 1 ) return '1 day ago';

      if ( days < 7 ) return days + ' days ago';

      if ( days < 365 ) {
        var year = 1900+this.getYear();
        var noyear = this.toDateString().replace(' ' + year, '');
        return noyear.substring(4);
      }

      return this.toDateString().substring(4);
    },

    function equals(o) {
      if ( ! o ) return false;
      if ( ! o.getTime ) return false;
      return this.getTime() === o.getTime();
    },

    function compareTo(o){
      if ( o === this ) return 0;
      if ( ! o ) return 1;
      var d = this.getTime() - o.getTime();
      return d == 0 ? 0 : d > 0 ? 1 : -1;
    }
  ]
});

foam.LIB({
  name: 'array',

  methods: [
    function argsToArray(args) {
      /** convenience method to turn 'arguments' into a real array */
      return foam.fn.appendArguments([], args, 0);
    }
  ]
});

foam.LIB({
  name: 'events',

  methods: [
    function oneTime(listener) {
      /** Create a "one-time" listener which unsubscribes itself after its first invocation. **/
      return function(subscription) {
        listener.apply(this, foam.array.argsToArray(arguments));
        subscription.destroy();
      };
    },

    function consoleLog(listener) {
      /** Log all listener invocations to console. **/
      return function() {
        var args = foam.array.argsToArray(arguments);
        console.log(args);
        listener && listener.apply(this, args);
      };
    }
  ]
});

foam.LIB({
  name: 'util',
  methods: [
    function equals(a, b) {
      if ( a === b ) return true;
      if ( ! a || ! b ) return false;
      if ( a.equals ) return a.equals(b);
      return a == b;
    }
  ]
});

foam.LIB({
  name: 'fn',

  methods: [
    /** Faster version of memoize() when only dealing with one argument. */
    function memoize1(f) {
      var cache = {};
      var g = function(arg) {
        console.assert(arguments.length == 1, "Memoize1'ed functions must take exactly one argument.");
        var key = arg ? arg.toString() : '';
        if ( ! cache.hasOwnProperty(key) ) cache[key] = f.call(this, arg);
        return cache[key];
      };
      foam.fn.setName(g, 'memoize1(' + f.name + ')');
      return g;
    },

    function setName(f, name) {
      /** Set a function's name for improved debugging and profiling **/
      Object.defineProperty(f, 'name', {value: name, configurable: true});
    },

    function appendArguments(a, args, start) {
      /** Convenience method to append 'arguments' onto a real array **/
      for ( var i = start ; i < args.length ; i++ ) a.push(args[i]);
      return a;
    },

    function argsStr(f) {
      /** Finds the function(...) declaration arguments part. Strips newlines. */
      return f.toString().replace(/(\r\n|\n|\r)/gm,"").match(/^function(\s+[_$\w]+|\s*)\((.*?)\)/)[2] || '';
    },

    function argsArray(f) {
      /**
       * Return a function's arguments as an array.
       * Ex. args(function(a,b) {...}) == ['a', 'b']
       **/
      var args = foam.fn.argsStr(f);
      if ( ! args ) return [];
      args += ',';

      var ret = [];
      // [ ws /* anything */ ] ws arg_name ws [ /* anything */ ],
      var argMatcher = /(\s*\/\*.*?\*\/)?\s*([\w_$]+)\s*(\/\*.*?\*\/)?\s*\,+/g;
      var typeMatch;
      while ((typeMatch = argMatcher.exec(args)) !== null) {
        ret.push(typeMatch[2]);
      }
      return ret;
    },

    // ???: Is this needed?
    /*
    function passProperties(args, f) {
      return function passProperties() {
        var self = this;
        return f.apply(this, args.map(function(arg) { return self[arg]; }));
      };
    }
    */
  ]
});

(function() {
  // Disable setName if not supported on this platform.
  try {
    foam.fn.setName(function() {}, '');
  } catch (x) {
    /**
      @class fn
      @ignore */
    foam.LIB({
      name: 'fn',
      methods: [ function setName() { /* NOP */ } ]
    });
  }
})();

foam.LIB({
  name: 'string',

  methods: [
    {
      name: 'constantize',
      code: foam.fn.memoize1(function(str) {
        // switchFromCamelCaseToConstantFormat to SWITCH_FROM_CAMEL_CASE_TO_CONSTANT_FORMAT
        return str.replace(/[a-z][^0-9a-z_]/g, function(a) {
          return a.substring(0,1) + '_' + a.substring(1,2);
        }).toUpperCase();
      })
    },

    {
      name: 'labelize',
      code: foam.fn.memoize1(function(str) {
        if ( ! str || str === '' ) return str;
        return this.capitalize(str.replace(/[a-z][A-Z]/g, function (a) { return a.charAt(0) + ' ' + a.charAt(1); }));
      })
    },

    {
      name: 'capitalize',
      code: foam.fn.memoize1(function(str) {
        // switchFromProperyName to //SwitchFromPropertyName
        return str[0].toUpperCase() + str.substring(1);
      })
    },

    function pad(str, size) {
      // Right pads to size if size > 0, Left pads to -size if size < 0
      return size < 0 ?
        (new Array(-size).join(' ') + str).slice(size)       :
        (str + new Array(size).join(' ')).substring(0, size) ;
    },

    function multiline(f) {
      // Function for returning multi-line strings from commented functions.
      // Ex. var str = multiline(function() { /* multi-line string here */ });
      if ( typeof f === 'string' ) return f;
      var s = f.toString();
      var start = s.indexOf('/*');
      var end   = s.lastIndexOf('*/');
      return s.substring(start+2, end);
    }
  ]
});

(function() {

  function set(X, key, value) {
    /* Update a Context binding. */
    X[key] = value;

    // TODO:
    // if ( GLOBAL.SimpleReadOnlyValue && key !== '$' && key !== '$$' )
    // X[key + '$'] = SimpleReadOnlyValue.create({value: value});
  }

  function setDynamic(X, key, dValue) {
    Object.defineProperty(
      X,
      key,
      {
        get: function() { return dValue.get(); },
        configurable: true
      }
    );

    if ( key !== '$' && key !== '$$' ) X[key + '$'] = dValue;
  }

  var ROOT = global;

  var lookup_ = function lookup_(id) {
    var a = foam.core[id];
    if ( a ) return a;
    var path = id.split('.');
    var root = ROOT;
    for ( var i = 0 ; root && i < path.length ; i++ )
      root = root[path[i]];
    return root;
  };

  var cache = {};

  var X = {
    lookup: function(id) {
      return id && ( cache[id] || ( cache[id] = lookup_(id) ) );
    },

    register: function(cls) {
      cache[cls.id] = cls;
      if ( cls.package === 'foam.core' )
        cache[cls.name] = cls;
      var path = cls.id.split('.');
      var root = ROOT;
      for ( var i = 0 ; i < path.length-1 ; i++ ) {
        root = root[path[i]] || ( root[path[i]] = {} );
      }
      root[path[path.length-1]] = cls;
    },

    sub: function sub(opt_args, opt_name) {
      var sub = Object.create(this);

      if ( opt_args ) for ( var key in opt_args ) {
        if ( opt_args.hasOwnProperty(key) ) {
          var asDyn = key !== '$' && key != '$$' && key.charAt(key.length-1) == '$';
          if ( asDyn ) {
            setDynamic(sub, key.substring(0, key.length-1), opt_args[key]);
          } else {
            set(sub, key, opt_args[key]);
          }
        }
      }

      if ( opt_name )
        Object.defineProperty(sub, 'NAME', {value: opt_name, enumerable: false});

      return sub;
    }
  };

  foam.X = X;

  for ( var key in X ) foam[key] = X[key].bind(X);
})();
<commit_msg>Add a foam.util.compare alongside foam.util.equals<commit_after>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Top-Level of foam package
 */
foam = {
  isServer: typeof process === 'object',
  core:     {},
  Array:    Array.prototype,
  Function: Function.prototype,
  Number:   Number.prototype,
  Object:   Object.prototype,
  String:   String.prototype,
  Date:     Date.prototype,
};

/** Setup nodejs-like 'global' on web */
if ( ! foam.isServer ) global = this;

/**
 * Creates a small library in the foam package. A LIB is a collection of static constants,
 * properties and functions. It can also add properties to a core javascript
 * object when you specify name: 'Array', 'Function', 'Number', 'Object',
 * 'String', or 'Date'.
 *

foam.LIB({
  name: 'network',
  properties: [ { name: 'packets' } ],
  methods: [ function sendPacket() { ... }  ]
});

Produces foam.network:

foam.network.packets = 4;
foam.network.sendPacket();

Or add methods and properties to built-in types (avoid this usage if you can):

foam.LIB({
  name: 'Number',
  methods: [ function plusOne() { this += 1; } ]
});
console.assert(9.plusOne() == 10, "It works!");

 * @method LIB
 * @memberof module:foam
 */
foam.LIB = function LIB(model) {
  var proto;

  function defineProperty(proto, key, map) {
    if ( ! map.value || proto === Object.prototype || proto === Array.prototype )
      Object.defineProperty.apply(this, arguments);
    else
      proto[key] = map.value;
  }

  proto = model.name ? foam[model.name] || ( foam[model.name] = {} ) : foam;

  if ( model.properties ) for ( var i = 0 ; i < model.properties.length ; i++ ) {
    var p = model.properties[i];
    defineProperty(
      proto,
      p.name,
      { get: p.getter, enumerable: false });
  }

  for ( key in model.constants )
    defineProperty(
      proto,
      key,
      { value: model.constants[key], writable: true, enumerable: false });

  if ( model.methods ) for ( var i = 0 ; i < model.methods.length ; i++ ) {
    var m = model.methods[i];
    defineProperty(
      proto,
      m.name,
      { value: m.code || m, writable: true, enumerable: false });
  }
};

/** Object prototype additions. */
foam.LIB({
  name: 'Object',

  properties: [
    {
      /**
       * Add Unique Identifiers (UIDs) to all Objects.
       * UID's are created when first accessed.
       */
      name: '$UID',
      getter: (function() {
        var id = 1;
        return function() {
          if ( Object.hasOwnProperty.call(this, '$UID__') ) return this.$UID__;
          Object.defineProperty(this, '$UID__', {value: id, enumerable: false});
          id++;
          return this.$UID__;
        };
      })()
    }
  ]
});

/** Number prototype additions. */
foam.LIB({
  name: 'Number',

  methods: [
    function compareTo(o) { return ( o == this ) ? 0 : this < o ? -1 : 1; },
  ]
});

/** String prototype additions. */
foam.LIB({
  name: 'String',

  methods: [
    function compareTo(o) { return ( o == this ) ? 0 : this < o ? -1 : 1; },

    /** Adds hashCode functionality to all strings. */
    function hashCode() {
      var hash = 0;
      if ( this.length == 0 ) return hash;

      for (i = 0; i < this.length; i++) {
        var code = this.charCodeAt(i);
        hash = ((hash << 5) - hash) + code;
        hash &= hash;
      }

      return hash;
    }
  ]
});

/** Array prototype additions. */
foam.LIB({
  name: 'Array',
  methods: [
    function diff(other) {
      /** Finds elements added (found in other, not in this) and removed
          (found in this, not in other). Repeated values are treated
          as separate elements, but ordering changes are ignored. */
      var added = other.slice(0);
      var removed = [];
      for ( var i = 0 ; i < this.length ; i++ ) {
        for ( var j = 0 ; j < added.length ; j++ ) {
          if ( this[i].compareTo(added[j]) == 0 ) {
            added.splice(j, 1);
            j--;
            break;
          }
        }
        if ( j == added.length ) removed.push(this[i]);
      }
      return { added: added, removed: removed };
    },
    function clone() {
      /** Returns a deep copy of this array and its contents. */
      var ret = new Array(this.length);
      for ( var i = 0; i < this.length; i++ ) {
        ret[i] = ( this[i].clone ) ? this[i].clone() : this[i];
      }
      return ret;
    },
    function shallowClone() {
      /** Returns a new array containing the same elements as this. */
      return this.slice();
    }
  ]
});

/** Date prototype additions. */
foam.LIB({
  name: 'Date',
  methods: [
    function toRelativeDateString(){
      // TODO i18n: make this translatable
      var seconds = Math.floor((Date.now() - this.getTime())/1000);

      if ( seconds < 60 ) return 'moments ago';

      var minutes = Math.floor((seconds)/60);

      if ( minutes == 1 ) return '1 minute ago';

      if ( minutes < 60 ) return minutes + ' minutes ago';

      var hours = Math.floor(minutes/60);
      if ( hours == 1 ) return '1 hour ago';

      if ( hours < 24 ) return hours + ' hours ago';

      var days = Math.floor(hours / 24);
      if ( days == 1 ) return '1 day ago';

      if ( days < 7 ) return days + ' days ago';

      if ( days < 365 ) {
        var year = 1900+this.getYear();
        var noyear = this.toDateString().replace(' ' + year, '');
        return noyear.substring(4);
      }

      return this.toDateString().substring(4);
    },

    function equals(o) {
      if ( ! o ) return false;
      if ( ! o.getTime ) return false;
      return this.getTime() === o.getTime();
    },

    function compareTo(o){
      if ( o === this ) return 0;
      if ( ! o ) return 1;
      var d = this.getTime() - o.getTime();
      return d == 0 ? 0 : d > 0 ? 1 : -1;
    }
  ]
});

foam.LIB({
  name: 'array',

  methods: [
    function argsToArray(args) {
      /** convenience method to turn 'arguments' into a real array */
      return foam.fn.appendArguments([], args, 0);
    }
  ]
});

foam.LIB({
  name: 'events',

  methods: [
    function oneTime(listener) {
      /** Create a "one-time" listener which unsubscribes itself after its first invocation. **/
      return function(subscription) {
        listener.apply(this, foam.array.argsToArray(arguments));
        subscription.destroy();
      };
    },

    function consoleLog(listener) {
      /** Log all listener invocations to console. **/
      return function() {
        var args = foam.array.argsToArray(arguments);
        console.log(args);
        listener && listener.apply(this, args);
      };
    }
  ]
});

foam.LIB({
  name: 'util',
  methods: [
    function equals(a, b) {
      if ( a === b ) return true;
      if ( ! a || ! b ) return false;
      if ( a.equals ) return a.equals(b);
      return a == b;
    },
    function compare(a, b) {
      if ( a.compareTo ) return a.compareTo(b);
      if ( b.compareTo ) return - b.compareTo(a);
      if ( foam.util.equals(a, b) ) return 0;
      return a.$UID.compareTo(b.$UID);
    }
  ]
});

foam.LIB({
  name: 'fn',

  methods: [
    /** Faster version of memoize() when only dealing with one argument. */
    function memoize1(f) {
      var cache = {};
      var g = function(arg) {
        console.assert(arguments.length == 1, "Memoize1'ed functions must take exactly one argument.");
        var key = arg ? arg.toString() : '';
        if ( ! cache.hasOwnProperty(key) ) cache[key] = f.call(this, arg);
        return cache[key];
      };
      foam.fn.setName(g, 'memoize1(' + f.name + ')');
      return g;
    },

    function setName(f, name) {
      /** Set a function's name for improved debugging and profiling **/
      Object.defineProperty(f, 'name', {value: name, configurable: true});
    },

    function appendArguments(a, args, start) {
      /** Convenience method to append 'arguments' onto a real array **/
      for ( var i = start ; i < args.length ; i++ ) a.push(args[i]);
      return a;
    },

    function argsStr(f) {
      /** Finds the function(...) declaration arguments part. Strips newlines. */
      return f.toString().replace(/(\r\n|\n|\r)/gm,"").match(/^function(\s+[_$\w]+|\s*)\((.*?)\)/)[2] || '';
    },

    function argsArray(f) {
      /**
       * Return a function's arguments as an array.
       * Ex. args(function(a,b) {...}) == ['a', 'b']
       **/
      var args = foam.fn.argsStr(f);
      if ( ! args ) return [];
      args += ',';

      var ret = [];
      // [ ws /* anything */ ] ws arg_name ws [ /* anything */ ],
      var argMatcher = /(\s*\/\*.*?\*\/)?\s*([\w_$]+)\s*(\/\*.*?\*\/)?\s*\,+/g;
      var typeMatch;
      while ((typeMatch = argMatcher.exec(args)) !== null) {
        ret.push(typeMatch[2]);
      }
      return ret;
    },

    // ???: Is this needed?
    /*
    function passProperties(args, f) {
      return function passProperties() {
        var self = this;
        return f.apply(this, args.map(function(arg) { return self[arg]; }));
      };
    }
    */
  ]
});

(function() {
  // Disable setName if not supported on this platform.
  try {
    foam.fn.setName(function() {}, '');
  } catch (x) {
    /**
      @class fn
      @ignore */
    foam.LIB({
      name: 'fn',
      methods: [ function setName() { /* NOP */ } ]
    });
  }
})();

foam.LIB({
  name: 'string',

  methods: [
    {
      name: 'constantize',
      code: foam.fn.memoize1(function(str) {
        // switchFromCamelCaseToConstantFormat to SWITCH_FROM_CAMEL_CASE_TO_CONSTANT_FORMAT
        return str.replace(/[a-z][^0-9a-z_]/g, function(a) {
          return a.substring(0,1) + '_' + a.substring(1,2);
        }).toUpperCase();
      })
    },

    {
      name: 'labelize',
      code: foam.fn.memoize1(function(str) {
        if ( ! str || str === '' ) return str;
        return this.capitalize(str.replace(/[a-z][A-Z]/g, function (a) { return a.charAt(0) + ' ' + a.charAt(1); }));
      })
    },

    {
      name: 'capitalize',
      code: foam.fn.memoize1(function(str) {
        // switchFromProperyName to //SwitchFromPropertyName
        return str[0].toUpperCase() + str.substring(1);
      })
    },

    function pad(str, size) {
      // Right pads to size if size > 0, Left pads to -size if size < 0
      return size < 0 ?
        (new Array(-size).join(' ') + str).slice(size)       :
        (str + new Array(size).join(' ')).substring(0, size) ;
    },

    function multiline(f) {
      // Function for returning multi-line strings from commented functions.
      // Ex. var str = multiline(function() { /* multi-line string here */ });
      if ( typeof f === 'string' ) return f;
      var s = f.toString();
      var start = s.indexOf('/*');
      var end   = s.lastIndexOf('*/');
      return s.substring(start+2, end);
    }
  ]
});

(function() {

  function set(X, key, value) {
    /* Update a Context binding. */
    X[key] = value;

    // TODO:
    // if ( GLOBAL.SimpleReadOnlyValue && key !== '$' && key !== '$$' )
    // X[key + '$'] = SimpleReadOnlyValue.create({value: value});
  }

  function setDynamic(X, key, dValue) {
    Object.defineProperty(
      X,
      key,
      {
        get: function() { return dValue.get(); },
        configurable: true
      }
    );

    if ( key !== '$' && key !== '$$' ) X[key + '$'] = dValue;
  }

  var ROOT = global;

  var lookup_ = function lookup_(id) {
    var a = foam.core[id];
    if ( a ) return a;
    var path = id.split('.');
    var root = ROOT;
    for ( var i = 0 ; root && i < path.length ; i++ )
      root = root[path[i]];
    return root;
  };

  var cache = {};

  var X = {
    lookup: function(id) {
      return id && ( cache[id] || ( cache[id] = lookup_(id) ) );
    },

    register: function(cls) {
      cache[cls.id] = cls;
      if ( cls.package === 'foam.core' )
        cache[cls.name] = cls;
      var path = cls.id.split('.');
      var root = ROOT;
      for ( var i = 0 ; i < path.length-1 ; i++ ) {
        root = root[path[i]] || ( root[path[i]] = {} );
      }
      root[path[path.length-1]] = cls;
    },

    sub: function sub(opt_args, opt_name) {
      var sub = Object.create(this);

      if ( opt_args ) for ( var key in opt_args ) {
        if ( opt_args.hasOwnProperty(key) ) {
          var asDyn = key !== '$' && key != '$$' && key.charAt(key.length-1) == '$';
          if ( asDyn ) {
            setDynamic(sub, key.substring(0, key.length-1), opt_args[key]);
          } else {
            set(sub, key, opt_args[key]);
          }
        }
      }

      if ( opt_name )
        Object.defineProperty(sub, 'NAME', {value: opt_name, enumerable: false});

      return sub;
    }
  };

  foam.X = X;

  for ( var key in X ) foam[key] = X[key].bind(X);
})();
<|endoftext|>


<commit_before>
var {Button, Grid, Row, Col} = ReactBootstrap;

// source: https://www.gamefaqs.com/pc/574556-castle-of-the-winds-1-a-question-of-vengeance/faqs/2405
// fieldName: [offset, numberOfBytes (littleEndian)]
const FIELDS = {
	// green bars, base value
	strBase: [0x80, 1],
	intBase: [0x81, 1],
	conBase: [0x82, 1],
	dexBase: [0x83, 1],
	// blue bars, affected by items
	str: [0x84, 1],
	int: [0x85, 1],
	con: [0x86, 1],
	dex: [0x87, 1],

	strPenalty: [0x88, 1],
	intPenalty: [0x89, 1],
	conPenalty: [0x8A, 1],
	dexPenalty: [0x8B, 1],
	strBonus: [0x90, 1],
	intBonus: [0x91, 1],
	conBonus: [0x92, 1],
	dexBonus: [0x93, 1],

	hp: [0x94, 2],
	maxHp: [0x96, 2],
	mp: [0x98, 2],
	maxMp: [0x9A, 2],
	level: [0x9C, 2],
	armorClass: [0xA6, 2],

	exp: [0x9E, 4],
	expAlt: [0xA2, 4],

	bonusHit: [0xA8, 2],
	bonusDamage: [0xAA, 2],

	gender: [0xBA, 1],

	resistFire: [0x150, 2],
	resistCold: [0x152, 2],
	resistLightning: [0x154, 2],
	resistAcid: [0x156, 2],
	resistFear: [0x158, 2],
	resistDrainLife: [0x15A, 2],

	weight: [0x3FE, 4],
	bulk: [0x402, 4],
	maxWeight: [0x406, 4],
	maxBulk: [0x40A, 4],
};

const SPELLS = {
	healMinorWounds: 0x1B2,
	fireBall: 0x31A
};

const SPELL_SLOTS = [0x38E, 0x390, 0x392, 0x394, 0x396, 0x398, 0x39A, 0x39C, 0x39E, 0x3A0];

var FileInput = React.createClass({
	propTypes: {
		onChange: React.PropTypes.func.isRequired,
		loaded: React.PropTypes.bool.isRequired,
	},
	render() {
		return (
			<fieldset>
				<legend>Savegame file</legend>
				<input type='file' id='file' onChange={this.props.onChange} />
				<Button bsStyle="primary" disabled={!this.props.loaded} onClick={this.props.onDownloadFile}>Download savegame</Button>
			</fieldset>
		);
	}
});

var CharacterAttribute = React.createClass({
	render() {
		return (
			<Row>
				<Col md={1}>{this.props.name}:</Col>
				<Col md={1}><input type="number" min="0" max={this.props.max} value={this.props.value} onChange={(e) => this.props.onChange(this.props.var, e)}/></Col>
			</Row>
		);
	}
});

var CharacterProfile = React.createClass({
	render() {
		return (
			<fieldset>
				<legend>Character</legend>

HP: {this.props.hp} / {this.props.maxHp}

Mana: {this.props.mp} / {this.props.maxMp}

Armor Class: {this.props.armorClass}

				<CharacterAttribute name="Experience" var="exp" value={this.props.exp} max="99999" onChange={this.props.handleChange}/>
				<CharacterAttribute name="Strength" var="str" value={this.props.str} max="100" onChange={this.props.handleChange}/>
				<CharacterAttribute name="Intelligence" var="int" value={this.props.int} max="100" onChange={this.props.handleChange}/>
				<CharacterAttribute name="Constitution" var="con" value={this.props.con} max="100" onChange={this.props.handleChange}/>
				<CharacterAttribute name="Dextery" var="dex" value={this.props.dex} max="100" onChange={this.props.handleChange}/>

Bulk: {this.props.bulk} / {this.props.maxBulk}

Weight: {this.props.weight} / {this.props.maxWeight}

			</fieldset>
		);
	}
});

var MainEditor = React.createClass({
	getInitialState() {
		return {};
	},
	savefileSelected(e) {
		var reader = new FileReader();
		reader.onload = (() => {
			var dataView = new DataView(reader.result);
			var state = {spellBook: {}, rawFile: reader.result};
			var readInt = function(_dataView, _offset, _numBytes){
				// TODO signed or unsigned?
				if (_numBytes === 1){
					return _dataView.getInt8(_offset);
				} else if (_numBytes === 2){
					return _dataView.getInt16(_offset, true);
				} else if (_numBytes === 4){
					return _dataView.getInt32(_offset, true);
				}
			};
			for(let property in FIELDS){
				if(FIELDS.hasOwnProperty(property)){
					let [offset, numBytes] = FIELDS[property];
					state[property] = readInt(dataView, offset, numBytes);
				}
			}

			for(let property in SPELLS){
				if(SPELLS.hasOwnProperty(property)){
					let offset = SPELLS[property];
					state.spellBook[property] = readInt(dataView, offset, 1);
				}
			}

			state.spellSlots = SPELL_SLOTS.map((offset) => readInt(dataView, offset, 2));
			this.setState(state);
		});
		reader.readAsArrayBuffer(e.target.files[0]);
	},
	downloadSavefile() {
		let dataView = new DataView(this.state.rawFile);
		let writeInt = function(_dataView, _offset, _value, _numBytes){
			// TODO signed or unsigned?
			if (_numBytes === 1){
				return _dataView.setInt8(_offset, _value);
			} else if (_numBytes === 2){
				return _dataView.setInt16(_offset, _value, true);
			} else if (_numBytes === 4){
				return _dataView.setInt32(_offset, _value, true);
			}
		};
		for(let property in FIELDS){
			if(FIELDS.hasOwnProperty(property)){
				let [offset, numBytes] = FIELDS[property];
				writeInt(dataView, offset, this.state[property], numBytes);
			}
		}
		// TODO spells, spellsSlots
		let blob = new Blob([dataView]);
		saveAs(blob, 'savegame.cwg');
	},
	handleChange(attribute, event) {
		this.setState({[attribute]: +event.target.value});
	},
	isLoaded() {
		return !!this.state.level;
	},
	render() {
		return (
			<Grid>

Castle of the Winds Editor

				<FileInput loaded={this.isLoaded()} onChange={this.savefileSelected} onDownloadFile={this.downloadSavefile} />
				<CharacterProfile
					str={this.state.str} int={this.state.int} con={this.state.con} dex={this.state.dex}
					hp={this.state.hp} maxHp={this.state.maxHp}
					mp={this.state.mp} maxMp={this.state.maxMp}
					exp={this.state.exp} armorClass={this.state.armorClass}
					bulk={this.state.bulk} maxBulk={this.state.maxBulk}
					weight={this.state.weight} maxWeight={this.state.maxWeight} gender={this.state.gender}
					handleChange={this.handleChange}
					/>
			</Grid>
		);
	}
});

ReactDOM.render(<MainEditor />, document.getElementById('react-app'));<commit_msg>Show all spells<commit_after>
var {Button, Grid, Row, Col} = ReactBootstrap;

// source: https://www.gamefaqs.com/pc/574556-castle-of-the-winds-1-a-question-of-vengeance/faqs/2405
// fieldName: [offset, numberOfBytes (littleEndian)]
const FIELDS = {
	// green bars, base value
	strBase: [0x80, 1],
	intBase: [0x81, 1],
	conBase: [0x82, 1],
	dexBase: [0x83, 1],
	// blue bars, affected by items
	str: [0x84, 1],
	int: [0x85, 1],
	con: [0x86, 1],
	dex: [0x87, 1],

	strPenalty: [0x88, 1],
	intPenalty: [0x89, 1],
	conPenalty: [0x8A, 1],
	dexPenalty: [0x8B, 1],
	strBonus: [0x90, 1],
	intBonus: [0x91, 1],
	conBonus: [0x92, 1],
	dexBonus: [0x93, 1],

	hp: [0x94, 2],
	maxHp: [0x96, 2],
	mp: [0x98, 2],
	maxMp: [0x9A, 2],
	level: [0x9C, 2],
	armorClass: [0xA6, 2],

	exp: [0x9E, 4],
	expAlt: [0xA2, 4],

	bonusHit: [0xA8, 2],
	bonusDamage: [0xAA, 2],

	gender: [0xBA, 1],

	resistFire: [0x150, 2],
	resistCold: [0x152, 2],
	resistLightning: [0x154, 2],
	resistAcid: [0x156, 2],
	resistFear: [0x158, 2],
	resistDrainLife: [0x15A, 2],

	weight: [0x3FE, 4],
	bulk: [0x402, 4],
	maxWeight: [0x406, 4],
	maxBulk: [0x40A, 4],
};

const SPELLS = {
	healMinorWounds: 0x1B2,
	detectObjects: 0x1BE,
	light: 0x1CA,
	magicArrow: 0x1D6,
	phaseDoor: 0x1E2,
	shield: 0x1EE,
	clairvoyance: 0x1FA,
	coldBolt: 0x206,
	detectMonsters: 0x212,
	detectTraps: 0x21E,
	identify: 0x22A,
	levitation: 0x236,
	neutralizePoison: 0x242,
	coldBall: 0x24E,
	healMediumWounds: 0x25A,
	fireBolt: 0x266,
	lightningBolt: 0x272,
	removeCurse: 0x27E,
	resistFire: 0x28A,
	resistCold: 0x296,
	resistLightning: 0x2A2,
	resistAcid: 0x2AE,
	resistFear: 0x2BA,
	sleepMonster: 0x2C6,
	slowMonster: 0x2D2,
	teleport: 0x2DE,
	runeOfReturn: 0x2EA,
	healMajorWounds: 0x2F6,
	fireball: 0x302,
	ballLightning: 0x30E,
	healing: 0x31A,
	transmogrifyMonster: 0x326,
	createTraps: 0x332,
	hasteMonster: 0x33E,
	teleportAway: 0x34A,
	cloneMonster: 0x356
};

const SPELL_SLOTS = [0x38E, 0x390, 0x392, 0x394, 0x396, 0x398, 0x39A, 0x39C, 0x39E, 0x3A0];

var FileInput = React.createClass({
	propTypes: {
		onChange: React.PropTypes.func.isRequired,
		loaded: React.PropTypes.bool.isRequired,
	},
	render() {
		return (
			<fieldset>
				<legend>Savegame file</legend>
				<input type='file' id='file' onChange={this.props.onChange} />
				<Button bsStyle="primary" disabled={!this.props.loaded} onClick={this.props.onDownloadFile}>Download savegame</Button>
			</fieldset>
		);
	}
});

var CharacterAttribute = React.createClass({
	render() {
		return (
			<Row>
				<Col md={1}>{this.props.name}:</Col>
				<Col md={1}><input type="number" min="0" max={this.props.max} value={this.props.value} onChange={(e) => this.props.onChange(this.props.var, e)}/></Col>
			</Row>
		);
	}
});

var CharacterProfile = React.createClass({
	render() {
		return (
			<fieldset>
				<legend>Character</legend>

HP: {this.props.hp} / {this.props.maxHp}

Mana: {this.props.mp} / {this.props.maxMp}

Armor Class: {this.props.armorClass}

				<CharacterAttribute name="Experience" var="exp" value={this.props.exp} max="99999" onChange={this.props.handleChange}/>
				<CharacterAttribute name="Strength" var="str" value={this.props.str} max="100" onChange={this.props.handleChange}/>
				<CharacterAttribute name="Intelligence" var="int" value={this.props.int} max="100" onChange={this.props.handleChange}/>
				<CharacterAttribute name="Constitution" var="con" value={this.props.con} max="100" onChange={this.props.handleChange}/>
				<CharacterAttribute name="Dextery" var="dex" value={this.props.dex} max="100" onChange={this.props.handleChange}/>

Bulk: {this.props.bulk} / {this.props.maxBulk}

Weight: {this.props.weight} / {this.props.maxWeight}

			</fieldset>
		);
	}
});

var Spellbook = React.createClass({
	getInitialState() {
		return {spells: {}};
	},
	render() {
		const spells = Object.keys(this.props.spells).map((spellName) => {
			let value = this.props.spells[spellName];
			return
{spellName}: {value}
;
		});
		return (
			<fieldset>
				<legend>Spellbook</legend>

					{spells}

			</fieldset>
		);
	}
});

var MainEditor = React.createClass({
	getInitialState() {
		return {spellBook: {}};
	},
	savefileSelected(e) {
		var reader = new FileReader();
		reader.onload = (() => {
			var dataView = new DataView(reader.result);
			var state = {spellBook: {}, rawFile: reader.result};
			var readInt = function(_dataView, _offset, _numBytes){
				// TODO signed or unsigned?
				if (_numBytes === 1){
					return _dataView.getInt8(_offset);
				} else if (_numBytes === 2){
					return _dataView.getInt16(_offset, true);
				} else if (_numBytes === 4){
					return _dataView.getInt32(_offset, true);
				}
			};
			for(let property in FIELDS){
				if(FIELDS.hasOwnProperty(property)){
					let [offset, numBytes] = FIELDS[property];
					state[property] = readInt(dataView, offset, numBytes);
				}
			}

			for(let property in SPELLS){
				if(SPELLS.hasOwnProperty(property)){
					let offset = SPELLS[property];
					state.spellBook[property] = readInt(dataView, offset, 1);
				}
			}

			state.spellSlots = SPELL_SLOTS.map((offset) => readInt(dataView, offset, 2));
			this.setState(state);
		});
		reader.readAsArrayBuffer(e.target.files[0]);
	},
	downloadSavefile() {
		let dataView = new DataView(this.state.rawFile);
		let writeInt = function(_dataView, _offset, _value, _numBytes){
			// TODO signed or unsigned?
			if (_numBytes === 1){
				return _dataView.setInt8(_offset, _value);
			} else if (_numBytes === 2){
				return _dataView.setInt16(_offset, _value, true);
			} else if (_numBytes === 4){
				return _dataView.setInt32(_offset, _value, true);
			}
		};
		for(let property in FIELDS){
			if(FIELDS.hasOwnProperty(property)){
				let [offset, numBytes] = FIELDS[property];
				writeInt(dataView, offset, this.state[property], numBytes);
			}
		}
		// TODO spells, spellsSlots
		let blob = new Blob([dataView]);
		saveAs(blob, 'savegame.cwg');
	},
	handleChange(attribute, event) {
		this.setState({[attribute]: +event.target.value});
	},
	isLoaded() {
		return !!this.state.level;
	},
	render() {
		return (
			<Grid>

Castle of the Winds Editor

				<FileInput loaded={this.isLoaded()} onChange={this.savefileSelected} onDownloadFile={this.downloadSavefile} />
				<CharacterProfile
					str={this.state.str} int={this.state.int} con={this.state.con} dex={this.state.dex}
					hp={this.state.hp} maxHp={this.state.maxHp}
					mp={this.state.mp} maxMp={this.state.maxMp}
					exp={this.state.exp} armorClass={this.state.armorClass}
					bulk={this.state.bulk} maxBulk={this.state.maxBulk}
					weight={this.state.weight} maxWeight={this.state.maxWeight} gender={this.state.gender}
					handleChange={this.handleChange}
					/>
				<Spellbook spells={this.state.spellBook}/>
			</Grid>
		);
	}
});

ReactDOM.render(<MainEditor />, document.getElementById('react-app'));<|endoftext|>