<commit_before>import React from 'react';
import Relay from 'react-relay';
import GCForm from './forms/GCForm';
import Form from 'react-formal';
import yup from 'yup';
import moment from 'moment';
import {Card, CardActions, CardExpandable, CardTitle, CardHeader, CardText, FlatButton, TextField, DropDownMenu, SelectField, DatePicker, TimePicker, Checkbox} from 'material-ui';
import {BernieText, BernieColors} from './styles/bernie-css';
import GCSelectField from './forms/GCSelectField'
import InfoHeader from './InfoHeader'

const momentWithOffset = (startDate, utcOffset) => {
  startDate = startDate * 1000
  return moment(startDate).utcOffset(utcOffset)
};

export default class EventPreview extends React.Component {
  constructor(props) {
    super(props);
    // this.handleKeyDown = this.handleKeyDown.bind(this);
    // document.addEventListener('keydown', this.handleKeyDown);
  }

  handleKeyDown(event){
    switch(event.keyIdentifier){
      case 'Down':
      case 'Right':
        // View next event
        this.props.onChangeEventIndex(1);
        break;
      case 'Up':
      case 'Left':
        // View previous event
        this.props.onChangeEventIndex(-1);
        break;
      case 'U+0041':
        // 'A' was pressed; approve and move to next event
        this.props.onEventConfirm([this.props.eventIndex]);
        break;
      case 'U+0045':
        // 'E' was pressed; open edit tab
        this.props.onTabRequest(this.props.eventIndex, 1);
        break;
      case 'U+0050':
        // 'P' was pressed; open preview tab
        this.props.onTabRequest(this.props.eventIndex, 0);
        break;
      case 'U+0044':
        // 'D' was pressed; delete this event
        this.props.onEventDelete([this.props.eventIndex]);
        break;
      default:
        //Statements executed when none of the values match the value of the expression
        console.log(event.keyIdentifier);
        break;
    }
  }

  componentWillUnmount(){
    document.removeEventListener('keydown', this.handleKeyDown);
  }

  render() {
    let event = this.props.event
    return (

        <CardText>

{event.name}

          <InfoHeader content='Event Type' />

{event.eventType.name}

          <InfoHeader content='Event Attendees' />

Venue Capacity: {(event.capacity) ? event.capacity : 'unlimited'}

Number of RSVPs: {event.attendeesCount}

          <InfoHeader content='Event Description' />

{event.description}

          <InfoHeader content='Event Date & Time' />

{momentWithOffset(event.startDate, event.localUTCOffset).format('LLLL')} {event.localTimezone} time

Duration: {Math.floor(event.duration / 60)} hours {event.duration % 60} minutes

          <InfoHeader content='Event Location' />

{event.venueName}

{event.venueAddr1} {event.venueAddr2}

{event.venueCity} {event.venueState}, {event.venueZip} ({event.venueCountry})

Capacity: {(event.capacity == 0) ? 'Unlimited' : event.capacity}

Directions: {(event.venueDirections) ? event.venueDirections : 'None'}

        </CardText>

    )
  }
}<commit_msg>Render html event descriptions in event preview pane<commit_after>import React from 'react';
import Relay from 'react-relay';
import GCForm from './forms/GCForm';
import Form from 'react-formal';
import yup from 'yup';
import moment from 'moment';
import {Card, CardActions, CardExpandable, CardTitle, CardHeader, CardText, FlatButton, TextField, DropDownMenu, SelectField, DatePicker, TimePicker, Checkbox} from 'material-ui';
import {BernieText, BernieColors} from './styles/bernie-css';
import GCSelectField from './forms/GCSelectField'
import InfoHeader from './InfoHeader'

const momentWithOffset = (startDate, utcOffset) => {
  startDate = startDate * 1000
  return moment(startDate).utcOffset(utcOffset)
};

export default class EventPreview extends React.Component {
  constructor(props) {
    super(props);
    // this.handleKeyDown = this.handleKeyDown.bind(this);
    // document.addEventListener('keydown', this.handleKeyDown);
  }

  handleKeyDown(event){
    switch(event.keyIdentifier){
      case 'Down':
      case 'Right':
        // View next event
        this.props.onChangeEventIndex(1);
        break;
      case 'Up':
      case 'Left':
        // View previous event
        this.props.onChangeEventIndex(-1);
        break;
      case 'U+0041':
        // 'A' was pressed; approve and move to next event
        this.props.onEventConfirm([this.props.eventIndex]);
        break;
      case 'U+0045':
        // 'E' was pressed; open edit tab
        this.props.onTabRequest(this.props.eventIndex, 1);
        break;
      case 'U+0050':
        // 'P' was pressed; open preview tab
        this.props.onTabRequest(this.props.eventIndex, 0);
        break;
      case 'U+0044':
        // 'D' was pressed; delete this event
        this.props.onEventDelete([this.props.eventIndex]);
        break;
      default:
        //Statements executed when none of the values match the value of the expression
        console.log(event.keyIdentifier);
        break;
    }
  }

  componentWillUnmount(){
    document.removeEventListener('keydown', this.handleKeyDown);
  }

  stripScripts = (s) => {
    let div = document.createElement('div');
    div.innerHTML = s;
    let scripts = div.getElementsByTagName('script');
    let i = scripts.length;
    while (i--) {
      scripts[i].parentNode.removeChild(scripts[i]);
    }
    return {__html: div.innerHTML}
  }

  render() {
    let event = this.props.event
    return (

        <CardText>

{event.name}

          <InfoHeader content='Event Type' />

{event.eventType.name}

          <InfoHeader content='Event Attendees' />

Venue Capacity: {(event.capacity) ? event.capacity : 'unlimited'}

Number of RSVPs: {event.attendeesCount}

          <InfoHeader content='Event Description' />

          <InfoHeader content='Event Date & Time' />

{momentWithOffset(event.startDate, event.localUTCOffset).format('LLLL')} {event.localTimezone} time

Duration: {Math.floor(event.duration / 60)} hours {event.duration % 60} minutes

          <InfoHeader content='Event Location' />

{event.venueName}

{event.venueAddr1} {event.venueAddr2}

{event.venueCity} {event.venueState}, {event.venueZip} ({event.venueCountry})

Capacity: {(event.capacity == 0) ? 'Unlimited' : event.capacity}

Directions: {(event.venueDirections) ? event.venueDirections : 'None'}

        </CardText>

    )
  }
}<|endoftext|>


<commit_before>var i18n = require('i18n');
var moment = require('moment');

var localization = function init(we) {
  i18n.configure (we.config.i18n);
  // set i18n middleware
  we.express.use(i18n.init);

  we.i18n = i18n;

  // set default moment locale
  moment.locale(we.config.i18n.defaultLocale);

  we.express.use(function setCurrentUserLocale(req, res, next) {
    if (req.user && req.user.language) {
      if (we.config.i18n.locales.indexOf(req.user.language) > -1) {
        req.setLocale(req.user.language);
      }
    }
    next();
  })

};

module.exports = localization;<commit_msg>update localization to set res.locals.locale<commit_after>var i18n = require('i18n');
var moment = require('moment');

var localization = function init(we) {
  i18n.configure (we.config.i18n);
  // set i18n middleware
  we.express.use(i18n.init);

  we.i18n = i18n;

  // set default moment locale
  moment.locale(we.config.i18n.defaultLocale);

  we.express.use(function setCurrentUserLocale(req, res, next) {
    if (req.user &&
      req.user.language &&
      we.config.i18n.locales.indexOf(req.user.language) > -1
    ) {
      // user locale
      req.setLocale(req.user.language);
    } else {
      // default
      req.setLocale(we.config.i18n.defaultLocale);
    }
    // set locale for views
    res.locals.locale = req.getLocale();

    next();
  })

};

module.exports = localization;<|endoftext|>


<commit_before>'use strict';

const noopConsole = require('noop-console');

/**
 * Utility function to mute the native console.
 * It adds a `restoreNativeConsole` method to
 * the Application instance `context`.
 *
 * @memberof core/Logger
 * @param {Application} context - Application context
 * @param {Object} config - Configuration object
 */
function muteConsole(context, config) {

    noopConsole(console);

    /**
     * Add a restore function to app.
     * This method is added to Application by
     * the `muteConsole`.
     *
     * @link core/Logger#muteConsole
     * @memberof Application
     * @return {void}
     */
    context.restoreNativeConsole = function(){
        console._restore();
        console.info('Restoring console...');
        console.info('console OK...');
    };
}

module.exports = muteConsole;
<commit_msg>udpate docs<commit_after>'use strict';

const noopConsole = require('noop-console');

/**
 * Utility function to mute the native console.
 * It adds a `restoreNativeConsole` method to
 * the Application instance `context`.
 *
 * @memberof core/logger
 * @param {Application} context - Application context
 * @param {Object} config - Configuration object
 */
function muteConsole(context, config) {

    noopConsole(console);

    /**
     * Add a restore function to app.
     * This method is added to Application by
     * the `muteConsole`.
     *
     * @link core/logger#muteConsole
     * @memberof Application
     * @return {void}
     */
    context.restoreNativeConsole = function(){
        console._restore();
        console.info('Restoring console...');
        console.info('console OK...');
    };
}

module.exports = muteConsole;
<|endoftext|>


<commit_before>var $ = require('jquery');
var Backbone = require('backbone');
var MapLayer = require('./map-layer');
var Layers = require('./layers');
var util = require('cdb/core/util');

var CartoDBLayerGroupBase = MapLayer.extend({

  defaults: {
    visible: true
  },

  initialize: function(attributes, options) {
    this.layers = new Backbone.Collection(options.layers);
  },

  isEqual: function() {
    return false;
  },

  getVisibleLayers: function() {
    return this.layers.filter(function(layer) {
      return layer.get('visible');
    });
  },

  getTileJSONFromTiles: function(layerIndex) {
    if (!this.get('urls')) {
      throw 'tileJSON for the layer cannot be calculated until urls are set';
    }

    // Layergroup
    var urls = this.get('urls');

    var index = this._getIndexOfVisibleLayer(layerIndex);

    // TODO: layerIndex should take into account the hidden layers.
    // For example, for a layergroup, if the layerIndex is 1 but layer 0 is hidden, this method should
    // use urls.grids[0]
    return {
      tilejson: '2.0.0',
      scheme: 'xyz',
      grids: urls.grids[index],
      tiles: urls.tiles,
      formatter: function(options, data) { return data; }
    };
  },

  // Returns the position of a visible layer in relation to all layers when the map is
  // an "Anonymous Map". For example, if there are two CartoDB layers and layer #0 is
  // hidden, this method would return -1 for #0 and 0 for layer #1.
  _getIndexOfVisibleLayer: function(layerIndex) {
    throw "_getIndexOfVisibleLayer must be implemented"
  },

  fetchAttributes: function(layer, featureID, callback) {
    if (!this.get('baseURL')) {
      throw 'Attributes cannot be fetched until baseURL is set';
    }

    var index = this._getIndexOfVisibleLayer(layer);
    var url = [
      this.get('baseURL'),
      index,
      'attributes',
      featureID
    ].join('/');

    $.ajax({
      dataType: 'jsonp',
      url: url,
      jsonpCallback: '_cdbi_layer_attributes_' + util.uniqueCallbackName(this.toJSON()),
      cache: true,
      success: function(data) {
        // loadingTime.end();
        callback(data);
      },
      error: function(data) {
        // loadingTime.end();
        // cartodb.core.Profiler.metric('cartodb-js.named_map.attributes.error').inc();
        callback(null);
      }
    });
  }
});

module.exports = CartoDBLayerGroupBase;
<commit_msg>Removed comment and simplified method<commit_after>var $ = require('jquery');
var Backbone = require('backbone');
var MapLayer = require('./map-layer');
var Layers = require('./layers');
var util = require('cdb/core/util');

var CartoDBLayerGroupBase = MapLayer.extend({

  defaults: {
    visible: true
  },

  initialize: function(attributes, options) {
    this.layers = new Backbone.Collection(options.layers);
  },

  isEqual: function() {
    return false;
  },

  getVisibleLayers: function() {
    return this.layers.filter(function(layer) {
      return layer.get('visible');
    });
  },

  getTileJSONFromTiles: function(layerIndex) {
    var urls = this.get('urls');
    if (!urls) {
      throw 'tileJSON for the layer cannot be calculated until urls are set';
    }

    return {
      tilejson: '2.0.0',
      scheme: 'xyz',
      grids: urls.grids[this._getIndexOfVisibleLayer(layerIndex)],
      tiles: urls.tiles,
      formatter: function(options, data) { return data; }
    };
  },

  _getIndexOfVisibleLayer: function(layerIndex) {
    throw "_getIndexOfVisibleLayer must be implemented";
  },

  fetchAttributes: function(layer, featureID, callback) {
    if (!this.get('baseURL')) {
      throw 'Attributes cannot be fetched until baseURL is set';
    }

    var index = this._getIndexOfVisibleLayer(layer);
    var url = [
      this.get('baseURL'),
      index,
      'attributes',
      featureID
    ].join('/');

    $.ajax({
      dataType: 'jsonp',
      url: url,
      jsonpCallback: '_cdbi_layer_attributes_' + util.uniqueCallbackName(this.toJSON()),
      cache: true,
      success: function(data) {
        // loadingTime.end();
        callback(data);
      },
      error: function(data) {
        // loadingTime.end();
        // cartodb.core.Profiler.metric('cartodb-js.named_map.attributes.error').inc();
        callback(null);
      }
    });
  }
});

module.exports = CartoDBLayerGroupBase;
<|endoftext|>


<commit_before>/**
 * Asset Pipeline
 */
var
  helpers = require('../helpers'),
  mime            = require('mime'),
  prerender       = require('dssrv-prerender'),
  processAssets = function processAssets(req, res, next){

  var normalizedPath  = helpers.normalizeUrl(req.url)
  var priorityList    = prerender.helpers.buildPriorityList(normalizedPath)
  var sourceFile      = prerender.helpers.findFirstFile(req.setup.publicPath, priorityList)

  /**
   * We GTFO if we don't have a source file.
   */

  if(!sourceFile){
    if (path.basename(normalizedPath) === "index.html") {
      var pathAr = normalizedPath.split(path.sep); pathAr.pop() // Pop index.html off the list
      var prospectCleanPath       = pathAr.join("/")
      var prospectNormalizedPath  = helpers.normalizeUrl(prospectCleanPath)
      var prospectPriorityList    = prerender.helpers.buildPriorityList(prospectNormalizedPath)
      prospectPriorityList.push(path.basename(prospectNormalizedPath + ".html"))

      sourceFile = prerender.helpers.findFirstFile(req.setup.publicPath, prospectPriorityList)

      if (!sourceFile) {
        return next()
      } else {
        // 301 redirect
        res.statusCode = 301
        res.setHeader('Location', prospectCleanPath)
        res.end('Redirecting to ' + utilsEscape(prospectCleanPath))
      }

    } else {
      return next()
    }
  } else {

    /**
     * Now we let prerender handle the asset pipeline.
     */

    req.poly.render(sourceFile, function reqPolyRender(error, body){
      if(error){
        error.stack = helpers.stacktrace(error.stack, { lineno: error.lineno })

        var locals = {
          project: req.headers.host,
          error: error,
          pkg: pkg
        }
        if(prerender.helpers.outputType(sourceFile) == 'css'){
          var outputType = prerender.helpers.outputType(sourceFile)
          var mimeType   = helpers.mimeType(outputType)
          var charset    = mime.charsets.lookup(mimeType)
          var body       = helpers.cssError(locals)
          res.statusCode = 200
          // SetHeaders
          res.setHeader('Content-Type', mimeType + (charset ? '; charset=' + charset : ''))
          res.setHeader('Content-Length', Buffer.byteLength(body, charset));
          res.end(body)
        }else{

          // Make the paths relative but keep the root dir.
          // TODO: move to helper.
          //
          // var loc = req.projectPath.split(path.sep); loc.pop()
          // var loc = loc.join(path.sep) + path.sep
          // if(error.filename) error.filename = error.filename.replace(loc, "")

          prerender.root(__dirname + "/templates").render("error.jade", locals, function(err, body){
            var mimeType   = helpers.mimeType('html')
            var charset    = mime.charsets.lookup(mimeType)
            res.statusCode = 500
            res.setHeader('Content-Type', mimeType + (charset ? '; charset=' + charset : ''))
            res.setHeader('Content-Length', Buffer.byteLength(body, charset));
            res.end(body)
          })
        }
      }else{
        // 404
        if(!body) return next()

        var outputType = prerender.helpers.outputType(sourceFile)
        var mimeType   = helpers.mimeType(outputType)
        var charset    = mime.charsets.lookup(mimeType)
        res.statusCode = 200
        res.setHeader('Content-Type', mimeType + (charset ? '; charset=' + charset : ''))
        res.setHeader('Content-Length', Buffer.byteLength(body, charset));
        res.end(body);
      }
    })
  }

}

module.exports = processAssets;
<commit_msg>Fixes Path<commit_after>/**
 * Asset Pipeline
 */
var
  helpers = require('../helpers'),
  mime = require('mime'),
  prerender = require('dssrv-prerender'),
  path = require('path'),
  processAssets = function processAssets(req, res, next){

    var
      normalizedPath = helpers.normalizeUrl(req.url),
      priorityList = prerender.helpers.buildPriorityList(normalizedPath),
      sourceFile = prerender.helpers.findFirstFile(req.setup.publicPath, priorityList);

    /**
     * We GTFO if we don't have a source file.
     */

    if(!sourceFile){
      if (path.basename(normalizedPath) === "index.html") {
        var pathAr = normalizedPath.split(path.sep); pathAr.pop() // Pop index.html off the list
        var prospectCleanPath       = pathAr.join("/")
        var prospectNormalizedPath  = helpers.normalizeUrl(prospectCleanPath)
        var prospectPriorityList    = prerender.helpers.buildPriorityList(prospectNormalizedPath)
        prospectPriorityList.push(path.basename(prospectNormalizedPath + ".html"))

        sourceFile = prerender.helpers.findFirstFile(req.setup.publicPath, prospectPriorityList)

        if (!sourceFile) {
          return next()
        } else {
          // 301 redirect
          res.statusCode = 301
          res.setHeader('Location', prospectCleanPath)
          res.end('Redirecting to ' + utilsEscape(prospectCleanPath))
        }
      } else {
        return next()
      }

    } else {
      /**
       * Now we let prerender handle the asset pipeline.
       */

      req.poly.render(sourceFile, function reqPolyRender(error, body){
        if(error){
          error.stack = helpers.stacktrace(error.stack, { lineno: error.lineno })

          var locals = {
            project: req.headers.host,
            error: error,
            pkg: pkg
          }
          if(prerender.helpers.outputType(sourceFile) == 'css'){
            var outputType = prerender.helpers.outputType(sourceFile)
            var mimeType   = helpers.mimeType(outputType)
            var charset    = mime.charsets.lookup(mimeType)
            var body       = helpers.cssError(locals)
            res.statusCode = 200
            // SetHeaders
            res.setHeader('Content-Type', mimeType + (charset ? '; charset=' + charset : ''))
            res.setHeader('Content-Length', Buffer.byteLength(body, charset));
            res.end(body)
          }else{

            // Make the paths relative but keep the root dir.
            // TODO: move to helper.
            //
            // var loc = req.projectPath.split(path.sep); loc.pop()
            // var loc = loc.join(path.sep) + path.sep
            // if(error.filename) error.filename = error.filename.replace(loc, "")

            prerender.root(__dirname + "/templates").render("error.jade", locals, function(err, body){
              var mimeType   = helpers.mimeType('html')
              var charset    = mime.charsets.lookup(mimeType)
              res.statusCode = 500;
              res.setHeader('Content-Type', mimeType + (charset ? '; charset=' + charset : ''))
              res.setHeader('Content-Length', Buffer.byteLength(body, charset));
              res.end(body);
            })
          }
        }else{
          // 404
          if(!body) return next()

          var outputType = prerender.helpers.outputType(sourceFile);
          var mimeType   = helpers.mimeType(outputType);
          var charset    = mime.charsets.lookup(mimeType);
          res.statusCode = 200;
          res.setHeader('Content-Type', mimeType + (charset ? '; charset=' + charset : ''));
          res.setHeader('Content-Length', Buffer.byteLength(body, charset));
          res.end(body);
        }
      })
  }

}

module.exports = processAssets;
<|endoftext|>


<commit_before>var proto = Astro.BaseClass.prototype;

// Overloaded functions.

proto._getOne = function(fieldName, options) {
  var doc = this;
  var Class = doc.constructor;
  var event;

  // Trigger the "beforeGet" event handlers.
  event = new Astro.Event('beforeGet', {
    fieldName: fieldName
  });
  event.target = doc;
  Class.emitEvent(event);

  // If an event was prevented from the execution, then we stop here.
  if (event.defaultPrevented) {
    return;
  }

  // Set default options of the function. By default, we cast value being get
  // and get default value is none had been provided.
  options = _.extend({
    cast: true
  }, options);

  var fieldValue;
  Astro.utils.fields.traverseNestedDocs(
    doc,
    fieldName,
    function(nestedField, nestedFieldName, Class, field, index) {
      if (_.isUndefined(index)) {
        fieldValue = nestedField[nestedFieldName];
      } else {
        fieldValue = nestedField[nestedFieldName][index];
      }

      if (field) {
        if (options.cast) {
          // Try casting the value to the proper type.
          fieldValue = field.cast(fieldValue);
        } else {
          // Otherwise get a plain value.
          fieldValue = field.plain(fieldValue);
        }
      }

      // After casting value, set the casted value back into the field.
      if (_.isUndefined(index)) {
        nestedField[nestedFieldName] = fieldValue;
      } else {
        nestedField[nestedFieldName][index] = fieldValue;
      }
    }
  );

  // Trigger the "afterGet" event handlers.
  event = new Astro.Event('afterGet', {
    fieldName: fieldName
  });
  event.target = doc;
  Class.emitEvent(event);

  return fieldValue;
};

proto._getMany = function(fieldNames, options) {
  var doc = this;
  var values = {};

  _.each(fieldNames, function(fieldName) {
    var value = doc._getOne(fieldName, options);
    values[fieldName] = value;
  });

  return values;
};

proto._getAll = function(options) {
  var doc = this;
  var Class = doc.constructor;

  // Get list of fields and their values.
  return doc._getMany(Class.getFieldsNames(), options);
};

// Public.

proto.get = function(/* arguments */) {
  var doc = this;

  if (arguments.length === 0) {
    return doc._getAll();
  } else if (arguments.length === 1) {
    if (_.isArray(arguments[0])) {
      return doc._getMany(arguments[0]);
    } else if (_.isString(arguments[0])) {
      return doc._getOne(arguments[0]);
    }
  }
};
<commit_msg>Fix setting back casted value while getting value<commit_after>var proto = Astro.BaseClass.prototype;

// Overloaded functions.

proto._getOne = function(fieldName, options) {
  var doc = this;
  var Class = doc.constructor;
  var event;

  // Trigger the "beforeGet" event handlers.
  event = new Astro.Event('beforeGet', {
    fieldName: fieldName
  });
  event.target = doc;
  Class.emitEvent(event);

  // If an event was prevented from the execution, then we stop here.
  if (event.defaultPrevented) {
    return;
  }

  // Set default options of the function. By default, we cast value being get
  // and get default value is none had been provided.
  options = _.extend({
    cast: true
  }, options);

  var fieldValue;
  Astro.utils.fields.traverseNestedDocs(
    doc,
    fieldName,
    function(nestedField, nestedFieldName, Class, field, index) {
      if (_.isUndefined(index)) {
        fieldValue = nestedField[nestedFieldName];
      } else {
        fieldValue = nestedField[nestedFieldName][index];
      }

      if (field) {
        if (options.cast) {
          // Try casting the value to the proper type.
          fieldValue = field.cast(fieldValue);

          // After casting value, set the casted value back into the field.
          if (_.isUndefined(index)) {
            nestedField[nestedFieldName] = fieldValue;
          } else {
            nestedField[nestedFieldName][index] = fieldValue;
          }
        } else {
          // Otherwise get a plain value.
          fieldValue = field.plain(fieldValue);
        }
      }
    }
  );

  // Trigger the "afterGet" event handlers.
  event = new Astro.Event('afterGet', {
    fieldName: fieldName
  });
  event.target = doc;
  Class.emitEvent(event);

  return fieldValue;
};

proto._getMany = function(fieldNames, options) {
  var doc = this;
  var values = {};

  _.each(fieldNames, function(fieldName) {
    var value = doc._getOne(fieldName, options);
    values[fieldName] = value;
  });

  return values;
};

proto._getAll = function(options) {
  var doc = this;
  var Class = doc.constructor;

  // Get list of fields and their values.
  return doc._getMany(Class.getFieldsNames(), options);
};

// Public.

proto.get = function(/* arguments */) {
  var doc = this;

  if (arguments.length === 0) {
    return doc._getAll();
  } else if (arguments.length === 1) {
    if (_.isArray(arguments[0])) {
      return doc._getMany(arguments[0]);
    } else if (_.isString(arguments[0])) {
      return doc._getOne(arguments[0]);
    }
  }
};
<|endoftext|>


<commit_before>/**
 * Validators for Mongoose.js utilising node-validate
 *
 */
var validator = require('validator'),
    defaultError = validator.defaultError,
    Validator = new validator.Validator();

Validator.error = function() {
    return false;
};

Validator.validate = function(method) {
    var args = Array.prototype.slice.call(arguments, 1),
        msg = defaultError[method];

    if (validator.validators[method]) {
        return {
            validator: function(val, next) {
                next( Validator.check(val)[method].apply(Validator, args) );
            },
            msg: msg
        }
    }

    throw new Error('Method ' +  method + ' does not exist on Validators.');
};

module.exports = Validator;<commit_msg>Tidy of spacing<commit_after>/**
 * Validators for Mongoose.js utilising node-validate
 *
 */
var validator = require('validator'),
    defaultError = validator.defaultError,
    Validator = new validator.Validator();

Validator.error = function() {
    return false;
};

Validator.validate = function(method) {
    var args = Array.prototype.slice.call(arguments, 1),
        msg = defaultError[method];

    if (validator.validators[method]) {
        return {
            validator: function(val, next) {
                next(Validator.check(val)[method].apply(Validator, args));
            },
            msg: msg
        }
    }

    throw new Error('Method ' +  method + ' does not exist on Validators.');
};

module.exports = Validator;<|endoftext|>


<commit_before>function changeMenuStyle(obj, new_style) {
  obj.className = new_style;
}

function showCursor(){
	document.body.style.cursor='hand'
}

function hideCursor(){
	document.body.style.cursor='default'
}

function confirmDelete(){
  if (confirm('Are you sure you want to delete?')){
    return true;
    }else{
    return false;
  }
}

<commit_msg>added ; at the end<commit_after>function changeMenuStyle(obj, new_style) {
  obj.className = new_style;
}

function showCursor(){
	document.body.style.cursor='hand';
}

function hideCursor(){
	document.body.style.cursor='default';
}

function confirmDelete(){
  if (confirm('Are you sure you want to delete?')){
    return true;
    }else{
    return false;
  }
}

<|endoftext|>


<commit_before>// Instance the tour
var executionTour = new Tour({  debug: true,
								orphan: true,
								backdrop: true,
								animation: false });
executionTour.addSteps([
  {
	element: "#tour-stop-1",
	title: "Snomed Release Service",
	content: "Content of first step",
	placement: "right",
	backdrop: false
  },
  {
	element: "#tour-stop-2",
	title: "In-page help text",
	content: "Content of second step",
	placement: "left",

  },
  {
	element: ".tour-stop-3",
	title: "List of Products",
	content: "Content of third step",
	placement: "right",

  },
  {
	element: "#tour-stop-4",
	title: "Starred Builds",
	content: "Content of fourth step",
	placement: "left",
	onNext: function () {
							window.location.hash = "/international/snomed_ct_international_edition/snomed_ct_release/1_20140731_international_release_build";
							recommence();
  						}
  },
  {
	element: "#tour-stop-5",
	title: "Product Build Screen",
	content: "Content of fifth step",
	placement: "right",
	backdrop: false
  },
  {
	element: "#tour-stop-6",
	title: "Packages",
	content: "Content of 6th step",
	placement: "right"
  },
  {
	element: "#tour-stop-7",
	title: "Execution History",
	content: "Content of 7th step",
	placement: "left"
  },
  {
	element: "#tour-stop-8",
	title: "Start an Execution",
	content: "Content of 8th step",
	placement: "right"
  },
]);

function startExecutionTour() {
	//Ensure user is at start of application and that this page has had a chance to
	//load fully before starting the tour.
	window.location.hash = "";
	window.setTimeout( function() {
		executionTour.init();
		executionTour.restart();
		console.log("Execution Tour underway!");
		} , 200 );
}

function recommence(){
	//Workaround for tour moving on to next step before the DOM is ready.
	//If it does that, we get the popup in the middle of the screen.
	//For now, we will end the tour, and the recommence 200ms later at nextStep
	var currentStep = executionTour.getCurrentStep();
	executionTour.end();
	window.setTimeout ( function() {
		executionTour.start(true);
		executionTour.goTo(currentStep + 1);
		} , 200 );
}

<commit_msg>Now correctly restarting from step 0 even if tour ended prematurely. Also showing entire screen without backgroup as first and last stops of each screen.<commit_after>// Instance the tour
var executionTour = new Tour({  debug: true,
								orphan: true,
								backdrop: true,
								animation: false });
executionTour.addSteps([
  {
	element: "#tour-stop-1",
	title: "Snomed Release Service",
	content: "Content of first step",
	placement: "right",
	backdrop: false
  },
  {
	element: "#tour-stop-2",
	title: "In-page help text",
	content: "Content of second step",
	placement: "left",

  },
  {
	element: ".tour-stop-3",
	title: "List of Products",
	content: "Content of third step",
	placement: "right",

  },
  {
	element: "#tour-stop-4",
	title: "Starred Builds",
	content: "Content of fourth step",
	placement: "left"
  },
  {
    //Going to show the whole page without a backdrop again, just before we move on.
	element: "#tour-stop-1",
	title: "Ready to move on",
	content: "Page overview before moving on to product build screen as if we'd clicked on Starred Build",
	placement: "right",
	backdrop: false,
	onNext: function () {
							window.location.hash = "/international/snomed_ct_international_edition/snomed_ct_release/1_20140731_international_release_build";
							recommence();
  						}
  },
  {
	element: "#tour-stop-5",
	title: "Product Build Screen",
	content: "Content of fifth step",
	placement: "right",
	backdrop: false
  },
  {
	element: "#tour-stop-6",
	title: "Packages",
	content: "Content of 6th step",
	placement: "right"
  },
  {
	element: "#tour-stop-7",
	title: "Execution History",
	content: "Content of 7th step",
	placement: "left"
  },
  {
	element: "#tour-stop-8",
	title: "Start an Execution",
	content: "Content of 8th step",
	placement: "right"
  },
  {
	element: "#tour-stop-5",
	title: "Product Build Screen",
	content: "Screen summary before moving on as if we'd clicked 'Create Execution and Review'",
	placement: "right",
	backdrop: false
  }
]);

function startExecutionTour() {
	//Ensure user is at start of application and that this page has had a chance to
	//load fully before starting the tour.
	window.location.hash = "";
	window.setTimeout( function() {
		executionTour.init();
		//We might have held onto a tour from last time - end if so.
		executionTour.end();
		executionTour.restart();  //Always restart at beginning.
		console.log("Execution Tour underway!");
		} , 200 );
}

function recommence(){
	//Workaround for tour moving on to next step before the DOM is ready.
	//If it does that, we get the popup in the middle of the screen.
	//For now, we will end the tour, and the recommence 200ms later at nextStep
	var currentStep = executionTour.getCurrentStep();
	executionTour.end();
	window.setTimeout ( function() {
		executionTour.start(true);
		executionTour.goTo(currentStep + 1);
		} , 200 );
}

<|endoftext|>


<commit_before>import {
  queryExpression as oqe
} from 'orbit/query/expression';
import {
  addRecordOperation,
  replaceRecordOperation,
  removeRecordOperation,
  replaceAttributeOperation,
  addToHasManyOperation,
  removeFromHasManyOperation,
  replaceHasOneOperation,
  replaceHasManyOperation,
  replaceKeyOperation
} from 'orbit-common/lib/operations';
import MemorySource from 'orbit-common/memory-source';
import Transform from 'orbit/transform';
import Evented from 'orbit/evented';
import Cache from 'orbit-common/cache';
import TransformBuilder from 'orbit-common/transform/builder';
import TransformTracker from 'orbit-common/transform/tracker';

export default class Store {
  constructor(opts) {
    Evented.extend(this);
    this.schema = opts.schema;
    this._transformBuilder = new TransformBuilder();
    this._transformTracker = new TransformTracker();
    this.cache = new Cache(opts.schema);
  }

  /////////////////////////////////////////////////////////////////////////////
  // Query helpers
  /////////////////////////////////////////////////////////////////////////////

  findRecordsOfType(type) {
    return this.query(oqe('recordsOfType', type))
      .then(records => {
        if (records) {
          return Object.keys(records).map(k => records[k]);
        } else {
          return [];
        }
      });
  }

  findRecord(type, id) {
    return this.query(oqe('record', type, id))
      .catch(e => undefined);
  }

  /////////////////////////////////////////////////////////////////////////////
  // Transform helpers
  /////////////////////////////////////////////////////////////////////////////

  addRecord(record) {
    return this
      .update(t => t.addRecord(this.schema.normalize(record)))
      .then(() => this.cache.get([record.type, record.id]));
  }

  replaceRecord(record) {
    return this
      .update(t => t.replaceRecord(this.schema.normalize(record)))
      .then(() => this.cache.get([record.type, record.id]));
  }

  removeRecord(record) {
    return this.update(t => t.removeRecord(record));
  }

  replaceKey(record, key, value) {
    return this.update(t => t.replaceKey(record, key, value));
  }

  replaceAttribute(record, attribute, value) {
    return this.update(t => t.replaceAttribute(record, attribute, value));
  }

  addToHasMany(record, relationship, value) {
    return this.update(t => t.addToHasMany(record, relationship, value));
  }

  removeFromHasMany(record, relationship, value) {
    return this.update(t => t.removeFromHasMany(record, relationship, value));
  }

  replaceHasMany(record, relationship, value) {
    return this.update(t => t.replaceHasMany(record, relationship, value));
  }

  replaceHasOne(record, relationship, value) {
    return this.update(t => t.replaceHasOne(record, relationship, value));
  }

  confirm(transform) {
    this.cache.transform(transform);
    this._transformTracker.confirm(transform);
  }

  deny(transform, error) {
    this._transformTracker.deny(transform, error);
  }

  update(transformSpecification) {
    const transform = Transform.from(transformSpecification, this._transformBuilder);
    const promisedResolution = this._transformTracker.add(transform);

    this.emit('transform', transform);

    return promisedResolution;
  }

  query(queryCallback) {
    return this
      .resolve('fetch', queryCallback)
      .then(transforms => {
        if (transforms.length === 0) { return; }
        return this._transformTracker.add(transforms.slice(-1)[0]);
      })
      .then(() => this.cache.query(queryCallback));
  }

  liveQuery(expression) {
    return this.resolve('subscription').then(sourceObservable => {
      const cacheObservable = this.cache.liveQuery(expression);

      // Merge the two observables so they can be created/disposed together.
      // We only want events from the cacheObservable though so empty() is used
      // to ignore events from the sourceObservable.
      return sourceObservable.empty().merge(cacheObservable);
    });
  }
}
<commit_msg>Store can now use a query builder.<commit_after>import {
  queryExpression as oqe
} from 'orbit/query/expression';
import {
  addRecordOperation,
  replaceRecordOperation,
  removeRecordOperation,
  replaceAttributeOperation,
  addToHasManyOperation,
  removeFromHasManyOperation,
  replaceHasOneOperation,
  replaceHasManyOperation,
  replaceKeyOperation
} from 'orbit-common/lib/operations';
import MemorySource from 'orbit-common/memory-source';
import Query from 'orbit/query';
import Transform from 'orbit/transform';
import Evented from 'orbit/evented';
import Cache from 'orbit-common/cache';
import QueryBuilder from 'orbit-common/query/builder';
import TransformBuilder from 'orbit-common/transform/builder';
import TransformTracker from 'orbit-common/transform/tracker';

export default class Store {
  constructor(opts) {
    Evented.extend(this);
    this.schema = opts.schema;
    this._queryBuilder = new QueryBuilder();
    this._transformBuilder = new TransformBuilder();
    this._transformTracker = new TransformTracker();
    this.cache = new Cache(opts.schema);
  }

  /////////////////////////////////////////////////////////////////////////////
  // Query helpers
  /////////////////////////////////////////////////////////////////////////////

  findRecordsOfType(type) {
    return this.query(oqe('recordsOfType', type))
      .then(records => {
        if (records) {
          return Object.keys(records).map(k => records[k]);
        } else {
          return [];
        }
      });
  }

  findRecord(type, id) {
    return this.query(oqe('record', type, id))
      .catch(e => undefined);
  }

  /////////////////////////////////////////////////////////////////////////////
  // Transform helpers
  /////////////////////////////////////////////////////////////////////////////

  addRecord(record) {
    return this
      .update(t => t.addRecord(this.schema.normalize(record)))
      .then(() => this.cache.get([record.type, record.id]));
  }

  replaceRecord(record) {
    return this
      .update(t => t.replaceRecord(this.schema.normalize(record)))
      .then(() => this.cache.get([record.type, record.id]));
  }

  removeRecord(record) {
    return this.update(t => t.removeRecord(record));
  }

  replaceKey(record, key, value) {
    return this.update(t => t.replaceKey(record, key, value));
  }

  replaceAttribute(record, attribute, value) {
    return this.update(t => t.replaceAttribute(record, attribute, value));
  }

  addToHasMany(record, relationship, value) {
    return this.update(t => t.addToHasMany(record, relationship, value));
  }

  removeFromHasMany(record, relationship, value) {
    return this.update(t => t.removeFromHasMany(record, relationship, value));
  }

  replaceHasMany(record, relationship, value) {
    return this.update(t => t.replaceHasMany(record, relationship, value));
  }

  replaceHasOne(record, relationship, value) {
    return this.update(t => t.replaceHasOne(record, relationship, value));
  }

  confirm(transform) {
    this.cache.transform(transform);
    this._transformTracker.confirm(transform);
  }

  deny(transform, error) {
    this._transformTracker.deny(transform, error);
  }

  update(transformOrOperations) {
    const transform = Transform.from(transformOrOperations, this._transformBuilder);
    const promisedResolution = this._transformTracker.add(transform);

    this.emit('transform', transform);

    return promisedResolution;
  }

  query(queryOrExpression) {
    const query = Query.from(queryOrExpression, this._queryBuilder);

    return this
      .resolve('fetch', query)
      .then(transforms => {
        if (transforms.length === 0) { return; }
        return this._transformTracker.add(transforms.slice(-1)[0]);
      })
      .then(() => this.cache.query(query));
  }

  liveQuery(expression) {
    return this.resolve('subscription').then(sourceObservable => {
      const cacheObservable = this.cache.liveQuery(expression);

      // Merge the two observables so they can be created/disposed together.
      // We only want events from the cacheObservable though so empty() is used
      // to ignore events from the sourceObservable.
      return sourceObservable.empty().merge(cacheObservable);
    });
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'

import './Header.css'

import logo from './logo.svg'

class Header extends Component {
  render() {
    return (

                <input type="text" className="uk-input re-navbar-search" placeholder="Quick search" />

    )
  }
}

export default Header
<commit_msg>Add dropdown menu<commit_after>import React, { Component } from 'react'

import './Header.css'

import logo from './logo.svg'

class Header extends Component {
  render() {
    return (

                  <input type="text" className="uk-input re-navbar-search" placeholder="Quick search" />

Help & support

Settings

Sign out

    )
  }
}

export default Header
<|endoftext|>


<commit_before>'use strict';

const parser = require('../parser');

function InMemory(partials) {
	this.partials = partials;
	this.compiledPartials = {};
}

InMemory.prototype.get = function (id) {
	if (this.compiledPartials.hasOwnProperty(id)) return this.compiledPartials[id];
	if (this.partials.hasOwnProperty(id)) {
		return this.compiledPartials[id] = parser(this.partials[id]);
	}
	return null;
};

module.exports = InMemory;
<commit_msg>Update InMemory partials resolved to resolve compiled templates. This makes unit tests work again<commit_after>'use strict';

const parser = require('../parser');

function InMemory(partials) {
	this.partials = partials;
	this.compiledPartials = {};
}

InMemory.prototype.get = function (id) {
	const compileTemplate = require('../../').compileTemplate;

	if (this.compiledPartials.hasOwnProperty(id)) return this.compiledPartials[id];
	if (this.partials.hasOwnProperty(id)) {
		return this.compiledPartials[id] = compileTemplate(parser(this.partials[id]));
	}
	return null;
};

module.exports = InMemory;
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2018 The FOAM Authors. 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.
 */

/*
  Accessible through browser at location path static/foam2/src/foam/nanos/controller/index.html
  Available on browser console as ctrl. (exports axiom)
*/
foam.CLASS({
  package: 'foam.nanos.controller',
  name: 'ApplicationController',
  extends: 'foam.u2.Element',

  documentation: 'FOAM Application Controller.',

  implements: [
    'foam.box.Context',
    'foam.nanos.controller.AppStyles'
  ],

  requires: [
    'foam.nanos.client.ClientBuilder',
    'foam.nanos.auth.Group',
    'foam.nanos.auth.ResendVerificationEmail',
    'foam.nanos.auth.SignInView',
    'foam.nanos.auth.User',
    'foam.nanos.auth.resetPassword.ResetView',
    'foam.nanos.u2.navigation.TopNavigation',
    'foam.nanos.u2.navigation.FooterView',
    'foam.u2.stack.Stack',
    'foam.u2.stack.StackView'
  ],

  imports: [
    'installCSS',
    'sessionSuccess',
    'window'
  ],

  exports: [
    'as ctrl',
    'group',
    'loginSuccess',
    'logo',
    'requestLogin',
    'signUpEnabled',
    'stack',
    'currentMenu',
    'lastMenuLaunched',
    'menuListener',
    'lastMenuLaunchedListener',
    'user',
    'webApp',
    'wrapCSS as installCSS'
  ],

  constants: {
    MACROS: [ 'primaryColor', 'secondaryColor', 'tableColor', 'tableHoverColor', 'accentColor', 'secondaryHoverColor', 'groupCSS' ]
  },

  css: `
    body {
      font-family: 'Roboto', sans-serif;
      font-size: 14px;
      letter-spacing: 0.2px;
      color: #373a3c;
      background: #edf0f5;
      margin: 0;
    }
    .foam-u2-UnstyledActionView-signIn {
      margin-left: 25px !important;
    }
    .stack-wrapper {
      margin-bottom: -10px;
      min-height: calc(80% - 60px);
    }
    .stack-wrapper:after {
      content: "";
      display: block;
    }
    .foam-u2-UnstyledActionView:focus{
      outline: none;
    }
  `,

  properties: [
    {
      name: 'clientPromise',
      factory: function() {
        var self = this;
        return self.ClientBuilder.create().promise.then(function(cls) {
          self.client = cls.create(null, self);
          return self.client;
        });
      },
    },
    {
      name: 'client',
    },
    {
      name: 'stack',
      factory: function() { return this.Stack.create(); }
    },
    {
      class: 'foam.core.FObjectProperty',
      of: 'foam.nanos.auth.User',
      name: 'user',
      factory: function() { return this.User.create(); }
    },
    {
      class: 'foam.core.FObjectProperty',
      of: 'foam.nanos.auth.Group',
      name: 'group',
      factory: function() { return this.Group.create(); }
    },
    {
      class: 'Boolean',
      name: 'signUpEnabled',
      adapt: function(_, v) {
        return foam.String.isInstance(v) ? v !== 'false' : v;
      }
    },
    {
      class: 'Boolean',
      name: 'loginSuccess'
    },
    { class: 'URL', name: 'logo' },
    'currentMenu',
    'lastMenuLaunched',
    'webApp',
    'primaryColor',
    'secondaryColor',
    'secondaryHoverColor',
    'tableColor',
    'tableHoverColor',
    'accentColor',
    'groupCSS',
    'topNavigation_',
    'footerView_'
  ],

  methods: [
    function init() {
      this.SUPER();
      var self = this;
      self.clientPromise.then(function(client) {
        self.setPrivate_('__subContext__', client.__subContext__);
        foam.__context__.register(foam.u2.UnstyledActionView, 'foam.u2.ActionView');
        self.getCurrentUser();

        window.onpopstate = function(event) {
          if ( location.hash != null ) {
            var hid = location.hash.substr(1);

            hid && self.client.menuDAO.find(hid).then(function(menu) {
              menu && menu.launch(this, null);
            });
          }
        };

        window.onpopstate();
      });
    },

    function initE() {
      var self = this;
      self.clientPromise.then(function() {
        self
          .addClass(self.myClass())
          .start('div', null, self.topNavigation_$).end()
          .start('div').addClass('stack-wrapper')
            .tag({class: 'foam.u2.stack.StackView', data: self.stack, showActions: false})
          .end()
          .start('div', null, self.footerView_$).end();

          // Sets up application view
          self.topNavigation_.add(self.TopNavigation.create());
          self.footerView_.add(self.FooterView.create());
      });
    },

    function setPortalView(group) {
      // Replaces contents of top navigation and footer view with group views
      this.topNavigation_ && this.topNavigation_.replaceChild(
        foam.lookup(group.topNavigation).create(null, this),
        this.topNavigation_.children[0]
      );

      this.footerView_ && this.footerView_.replaceChild(
        foam.lookup(group.footerView).create(null, this),
        this.footerView_.children[0]
      );
    },

    async function setDefaultMenu() {
      var group = await this.client.groupDAO.find(this.user.group);
      this.group.copyFrom(group);
      this.setPortalView(group);

      for ( var i = 0; i < this.MACROS.length; i++ ) {
        var m = this.MACROS[i];
        if ( group[m] ) this[m] = group[m];
      }

      // Don't select default if menu already set
      if ( this.window.location.hash || ! this.user.group ) return;

      if ( group && ! this.window.location.hash ) {
        this.window.location.hash = group.defaultMenu;
      }
    },

    function getCurrentUser() {
      var self = this;

      // get current user, else show login
      this.client.auth.getCurrentUser(null).then(function (result) {
        self.loginSuccess = !! result;
        if ( result ) {
          self.user.copyFrom(result);
          if ( ! self.user.emailVerified ) {
            self.stack.push({ class: 'foam.nanos.auth.ResendVerificationEmail' });
            return;
          }
          self.onUserUpdate();
        }
      })
      .catch(function (err) {
        self.requestLogin().then(function() {
          self.getCurrentUser();
        });
      });
    },

    function expandShortFormMacro(css, m) {
      /* A short-form macros is of the form %PRIMARY_COLOR%. */
      var M = m.toUpperCase();

      return css.replace(
        new RegExp("%" + M + "%", 'g'),
        '/*%' + M + '%*/ ' + this[m]);
    },

    function expandLongFormMacro(css, m) {
      // A long-form macros is of the form "/*%PRIMARY_COLOR%*/ blue".
      var M = m.toUpperCase();

      return css.replace(
        new RegExp('/\\*%' + M + '%\\*/[^;]*', 'g'),
        '/*%' + M + '%*/ ' + this[m]);
    },

    // CSS preprocessor, works on classes instantiated in subContext
    function wrapCSS(text, id) {
      if ( text ) {
        if ( ! this.accentColor ) {
          var self = this;

          this.accentColor$.sub(function(s) {
            self.wrapCSS(text, id);
            s.detach();
          });
        }

        let eid = foam.u2.Element.NEXT_ID();

        for ( var i = 0 ; i < this.MACROS.length ; i++ ) {
          let m     = this.MACROS[i];
          var text2 = this.expandShortFormMacro(this.expandLongFormMacro(text, m), m);

            // If the macro was found, then listen for changes to the property
            // and update the CSS if it changes.
            if ( text != text2 ) {
              text = text2;
              this.slot(m).sub(function() {
                var el = this.getElementById(eid);
                el.innerText = this.expandLongFormMacro(el.innerText, m);
              }.bind(this));
            }
        }

        this.installCSS(text, id, eid);
      }
    },

    function requestLogin() {
      var self = this;

      // don't go to log in screen if going to reset password screen
      if ( location.hash != null && location.hash === '#reset')
        return new Promise(function (resolve, reject) {
          self.stack.push({ class: 'foam.nanos.auth.resetPassword.ResetView' });
          self.loginSuccess$.sub(resolve);
        });

      return new Promise(function(resolve, reject) {
        self.stack.push({ class: 'foam.nanos.auth.SignInView' });
        self.loginSuccess$.sub(resolve);
      });
    }
  ],

  listeners: [
    function onUserUpdate() {
      this.setDefaultMenu();
    },

    // This listener should be triggered when a Menu item has been launched AND
    // navigates to a new screen.
    function menuListener(m) {
      this.currentMenu = m;
    },

    // This listener should be triggered when a Menu has been launched but does
    // not navigate to a new screen. Typically for SubMenus
    function lastMenuLaunchedListener(m) {
      this.lastMenuLaunched = m;
    }
  ]
});
<commit_msg>Fix hash update on login.<commit_after>/**
 * @license
 * Copyright 2018 The FOAM Authors. 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.
 */

/*
  Accessible through browser at location path static/foam2/src/foam/nanos/controller/index.html
  Available on browser console as ctrl. (exports axiom)
*/
foam.CLASS({
  package: 'foam.nanos.controller',
  name: 'ApplicationController',
  extends: 'foam.u2.Element',

  documentation: 'FOAM Application Controller.',

  implements: [
    'foam.box.Context',
    'foam.nanos.controller.AppStyles'
  ],

  requires: [
    'foam.nanos.client.ClientBuilder',
    'foam.nanos.auth.Group',
    'foam.nanos.auth.ResendVerificationEmail',
    'foam.nanos.auth.SignInView',
    'foam.nanos.auth.User',
    'foam.nanos.auth.resetPassword.ResetView',
    'foam.nanos.u2.navigation.TopNavigation',
    'foam.nanos.u2.navigation.FooterView',
    'foam.u2.stack.Stack',
    'foam.u2.stack.StackView'
  ],

  imports: [
    'installCSS',
    'sessionSuccess',
    'window'
  ],

  exports: [
    'as ctrl',
    'group',
    'loginSuccess',
    'logo',
    'requestLogin',
    'signUpEnabled',
    'stack',
    'currentMenu',
    'lastMenuLaunched',
    'menuListener',
    'lastMenuLaunchedListener',
    'user',
    'webApp',
    'wrapCSS as installCSS'
  ],

  constants: {
    MACROS: [ 'primaryColor', 'secondaryColor', 'tableColor', 'tableHoverColor', 'accentColor', 'secondaryHoverColor', 'groupCSS' ]
  },

  css: `
    body {
      font-family: 'Roboto', sans-serif;
      font-size: 14px;
      letter-spacing: 0.2px;
      color: #373a3c;
      background: #edf0f5;
      margin: 0;
    }
    .foam-u2-UnstyledActionView-signIn {
      margin-left: 25px !important;
    }
    .stack-wrapper {
      margin-bottom: -10px;
      min-height: calc(80% - 60px);
    }
    .stack-wrapper:after {
      content: "";
      display: block;
    }
    .foam-u2-UnstyledActionView:focus{
      outline: none;
    }
  `,

  properties: [
    {
      name: 'clientPromise',
      factory: function() {
        var self = this;
        return self.ClientBuilder.create().promise.then(function(cls) {
          self.client = cls.create(null, self);
          return self.client;
        });
      },
    },
    {
      name: 'client',
    },
    {
      name: 'stack',
      factory: function() { return this.Stack.create(); }
    },
    {
      class: 'foam.core.FObjectProperty',
      of: 'foam.nanos.auth.User',
      name: 'user',
      factory: function() { return this.User.create(); }
    },
    {
      class: 'foam.core.FObjectProperty',
      of: 'foam.nanos.auth.Group',
      name: 'group',
      factory: function() { return this.Group.create(); }
    },
    {
      class: 'Boolean',
      name: 'signUpEnabled',
      adapt: function(_, v) {
        return foam.String.isInstance(v) ? v !== 'false' : v;
      }
    },
    {
      class: 'Boolean',
      name: 'loginSuccess'
    },
    { class: 'URL', name: 'logo' },
    'currentMenu',
    'lastMenuLaunched',
    'webApp',
    'primaryColor',
    'secondaryColor',
    'secondaryHoverColor',
    'tableColor',
    'tableHoverColor',
    'accentColor',
    'groupCSS',
    'topNavigation_',
    'footerView_'
  ],

  methods: [
    function init() {
      this.SUPER();
      var self = this;
      self.clientPromise.then(function(client) {
        self.setPrivate_('__subContext__', client.__subContext__);
        foam.__context__.register(foam.u2.UnstyledActionView, 'foam.u2.ActionView');
        self.getCurrentUser();

        window.onpopstate = function(event) {
          if ( location.hash != null ) {
            var hid = location.hash.substr(1);

            hid && self.client.menuDAO.find(hid).then(function(menu) {
              menu && menu.launch(this, null);
            });
          }
        };

        window.onpopstate();
      });
    },

    function initE() {
      var self = this;
      self.clientPromise.then(function() {
        self
          .addClass(self.myClass())
          .start('div', null, self.topNavigation_$).end()
          .start('div').addClass('stack-wrapper')
            .tag({class: 'foam.u2.stack.StackView', data: self.stack, showActions: false})
          .end()
          .start('div', null, self.footerView_$).end();

          // Sets up application view
          self.topNavigation_.add(self.TopNavigation.create());
          self.footerView_.add(self.FooterView.create());
      });
    },

    function setPortalView(group) {
      // Replaces contents of top navigation and footer view with group views
      this.topNavigation_ && this.topNavigation_.replaceChild(
        foam.lookup(group.topNavigation).create(null, this),
        this.topNavigation_.children[0]
      );

      this.footerView_ && this.footerView_.replaceChild(
        foam.lookup(group.footerView).create(null, this),
        this.footerView_.children[0]
      );
    },

    async function setDefaultMenu() {
      var group = await this.client.groupDAO.find(this.user.group);
      this.group.copyFrom(group);
      this.setPortalView(group);

      for ( var i = 0; i < this.MACROS.length; i++ ) {
        var m = this.MACROS[i];
        if ( group[m] ) this[m] = group[m];
      }

      var hash = this.window.location.hash;
      this.window.location.hash = '';

      if ( group ) {
        this.window.location.hash = group.defaultMenu;
      } else {
        this.window.location.hash = hash;
      }
    },

    function getCurrentUser() {
      var self = this;

      // get current user, else show login
      this.client.auth.getCurrentUser(null).then(function (result) {
        self.loginSuccess = !! result;
        if ( result ) {
          self.user.copyFrom(result);
          if ( ! self.user.emailVerified ) {
            self.stack.push({ class: 'foam.nanos.auth.ResendVerificationEmail' });
            return;
          }
          self.onUserUpdate();
        }
      })
      .catch(function (err) {
        self.requestLogin().then(function() {
          self.getCurrentUser();
        });
      });
    },

    function expandShortFormMacro(css, m) {
      /* A short-form macros is of the form %PRIMARY_COLOR%. */
      var M = m.toUpperCase();

      return css.replace(
        new RegExp("%" + M + "%", 'g'),
        '/*%' + M + '%*/ ' + this[m]);
    },

    function expandLongFormMacro(css, m) {
      // A long-form macros is of the form "/*%PRIMARY_COLOR%*/ blue".
      var M = m.toUpperCase();

      return css.replace(
        new RegExp('/\\*%' + M + '%\\*/[^;]*', 'g'),
        '/*%' + M + '%*/ ' + this[m]);
    },

    // CSS preprocessor, works on classes instantiated in subContext
    function wrapCSS(text, id) {
      if ( text ) {
        if ( ! this.accentColor ) {
          var self = this;

          this.accentColor$.sub(function(s) {
            self.wrapCSS(text, id);
            s.detach();
          });
        }

        let eid = foam.u2.Element.NEXT_ID();

        for ( var i = 0 ; i < this.MACROS.length ; i++ ) {
          let m     = this.MACROS[i];
          var text2 = this.expandShortFormMacro(this.expandLongFormMacro(text, m), m);

            // If the macro was found, then listen for changes to the property
            // and update the CSS if it changes.
            if ( text != text2 ) {
              text = text2;
              this.slot(m).sub(function() {
                var el = this.getElementById(eid);
                el.innerText = this.expandLongFormMacro(el.innerText, m);
              }.bind(this));
            }
        }

        this.installCSS(text, id, eid);
      }
    },

    function requestLogin() {
      var self = this;

      // don't go to log in screen if going to reset password screen
      if ( location.hash != null && location.hash === '#reset')
        return new Promise(function (resolve, reject) {
          self.stack.push({ class: 'foam.nanos.auth.resetPassword.ResetView' });
          self.loginSuccess$.sub(resolve);
        });

      return new Promise(function(resolve, reject) {
        self.stack.push({ class: 'foam.nanos.auth.SignInView' });
        self.loginSuccess$.sub(resolve);
      });
    }
  ],

  listeners: [
    function onUserUpdate() {
      this.setDefaultMenu();
    },

    // This listener should be triggered when a Menu item has been launched AND
    // navigates to a new screen.
    function menuListener(m) {
      this.currentMenu = m;
    },

    // This listener should be triggered when a Menu has been launched but does
    // not navigate to a new screen. Typically for SubMenus
    function lastMenuLaunchedListener(m) {
      this.lastMenuLaunched = m;
    }
  ]
});
<|endoftext|>


<commit_before>import fetch from 'lets-fetch'
import cheerio from 'cheerio'
import flow from 'promise-control-flow'

// Get the cost to level crafting professions
export default async function craftingProfessionCost () {
  const promises = {
    armorsmith: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/armorcraft.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/armorcraft_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    artificer: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/artificing.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/artificing_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    chef: async () => {
      let baseCraft = await getProfessionTotalCost('http://gw2crafts.net/cooking_karma_light.html')
      return { 400: baseCraft }
    },
    huntsman: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/huntsman.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/huntsman_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    jeweler: async () => {
      return getProfessionParts('http://gw2crafts.net/jewelcraft.html')
    },
    leatherworker: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/leatherworking.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/leatherworking_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    scribe: async () => {
      return getProfessionParts('http://gw2crafts.net/scribe.html')
    },
    tailor: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/tailor.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/tailor_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    weaponsmith: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/weaponcraft.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/weaponcraft_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    }
  }

  // Return an array of all crafting professions
  return flow.parallel(promises)
}

// Get partial data, one per segment
async function getProfessionParts (url) {
  let content = await fetch.single(url, { type: 'text' })
  let $ = cheerio.load(content)
  let costs = []

  // Go through the headings, since that is where
  // the cost is defined in
  $('h4').map((i, element) => {
    let html = $(element).html()

    // Only take "cost" headlines
    if (!html.match(/^Cost:/)) {
      return
    }

    // Rip the rolling total only
    html = html.replace(/.+ \(Rolling Total: (.+)\)$/, '$1')

    // Replace and split the icons for gold, silver and copper
    html = html.replace(/<span.+?<\/span>/g, '###')
    html = html.split('###')

    // Get a copper cost and push it into our list
    let goldCost = cleanGoldArray(html)
    costs.push(goldCost)
  })

  // Get a nice, clean array with costs per level
  return {
    75: costs[0],
    150: costs[1],
    225: costs[2],
    300: costs[3],
    400: costs[4]
  }
}

// Get the total cost of a profession
async function getProfessionTotalCost (url) {
  let content = await fetch.single(url, { type: 'text' })
  let $ = cheerio.load(content)

  // Get the first defined cost, that's the total cost
  let html = $('dd').eq(2).html()

  // Replace and split the icons for gold, silver and copper
  html = html.replace(/<span.+?<\/span>/g, '###')
  html = html.split('###')

  // Get a copper cost and return it
  return cleanGoldArray(html)
}

// Get a clean "copper" number from an array of money
function cleanGoldArray (array) {
  array = array.filter(x => x !== '').map(x => parseInt(x, 10))

  // Copper
  if (array.length === 1) {
    return array[0]
  }

  // Copper + Silver
  if (array.length === 2) {
    return array[0] * 100 + array[1]
  }

  // Copper, Silver + Gold
  return array[0] * 10000 + array[1] * 100 + array[2]
}
<commit_msg>Sanity check for crafting price parsing<commit_after>import fetch from 'lets-fetch'
import cheerio from 'cheerio'
import flow from 'promise-control-flow'

// Get the cost to level crafting professions
export default async function craftingProfessionCost () {
  const promises = {
    armorsmith: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/armorcraft.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/armorcraft_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    artificer: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/artificing.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/artificing_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    chef: async () => {
      let baseCraft = await getProfessionTotalCost('http://gw2crafts.net/cooking_karma_light.html')
      return { 400: baseCraft }
    },
    huntsman: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/huntsman.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/huntsman_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    jeweler: async () => {
      return getProfessionParts('http://gw2crafts.net/jewelcraft.html')
    },
    leatherworker: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/leatherworking.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/leatherworking_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    scribe: async () => {
      return getProfessionParts('http://gw2crafts.net/scribe.html')
    },
    tailor: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/tailor.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/tailor_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    },
    weaponsmith: async () => {
      let baseCraft = await getProfessionParts('http://gw2crafts.net/weaponcraft.html')
      let maxCraft = await getProfessionTotalCost('http://gw2crafts.net/weaponcraft_400.html')
      return { ...baseCraft, 500: maxCraft + baseCraft[400] }
    }
  }

  // Generate an array of all crafting professions
  const professions = await flow.parallel(promises)

  // Sanity check that we parsed the prices correctly, so we don't accidentally assume
  // leveling Scribe to 500 takes 6 million gold.
  for (const profession of Object.keys(professions)) {
    for (const level of Object.keys(professions[profession])) {
      const value = professions[profession][level]

      if (value > 2500000) {
        throw new Error(`Failed parsing price for ${profession} ${level}: ${value}`)
      }
    }
  }

  return professions
}

// Get partial data, one per segment
async function getProfessionParts (url) {
  let content = await fetch.single(url, { type: 'text' })
  let $ = cheerio.load(content)
  let costs = []

  // Go through the headings, since that is where
  // the cost is defined in
  $('h4').map((i, element) => {
    let html = $(element).html()

    // Only take "cost" headlines
    if (!html.match(/^Cost:/)) {
      return
    }

    // Rip the rolling total only
    html = html.replace(/.+ \(Rolling Total: (.+)\)$/, '$1')

    // Replace and split the icons for gold, silver and copper
    html = html.replace(/<span.+?<\/span>/g, '###')
    html = html.split('###')

    // Get a copper cost and push it into our list
    let goldCost = cleanGoldArray(html)
    costs.push(goldCost)
  })

  // Get a nice, clean array with costs per level
  return {
    75: costs[0],
    150: costs[1],
    225: costs[2],
    300: costs[3],
    400: costs[4]
  }
}

// Get the total cost of a profession
async function getProfessionTotalCost (url) {
  let content = await fetch.single(url, { type: 'text' })
  let $ = cheerio.load(content)

  // Get the first defined cost, that's the total cost
  let html = $('dd').eq(2).html()

  // Replace and split the icons for gold, silver and copper
  html = html.replace(/<span.+?<\/span>/g, '###')
  html = html.split('###')

  // Get a copper cost and return it
  return cleanGoldArray(html)
}

// Get a clean "copper" number from an array of money
function cleanGoldArray (array) {
  array = array.filter(x => x !== '').map(x => parseInt(x, 10))

  // Copper
  if (array.length === 1) {
    return array[0]
  }

  // Copper + Silver
  if (array.length === 2) {
    return array[0] * 100 + array[1]
  }

  // Copper, Silver + Gold
  return array[0] * 10000 + array[1] * 100 + array[2]
}
<|endoftext|>


<commit_before>import { Mongo } from 'meteor/mongo';
import { Session } from 'meteor/session';
import { BigNumber } from 'meteor/ethereum:web3';
import { Dapple, web3 } from 'meteor/makerotc:dapple';
import { _ } from 'meteor/underscore';
import { $ } from 'meteor/jquery';

import Transactions from '/imports/api/transactions';
import { formatError } from '/imports/utils/functions';

import { convertToTokenPrecision, convertTo18Precision } from '/imports/utils/conversion';

const Offers = new Mongo.Collection(null);
const Trades = new Mongo.Collection(null);

const Status = {
  PENDING: 'pending',
  CONFIRMED: 'confirmed',
  CANCELLED: 'cancelled',
  BOUGHT: 'bought',
};

const OFFER_GAS = 1000000;
const BUY_GAS = 1000000;
const CANCEL_GAS = 1000000;

const TRADES_LIMIT = 7;
Session.set('lastTradesLimit', TRADES_LIMIT);

const OFFER_LIMIT = 7;
Session.set('orderBookLimit', OFFER_LIMIT);

const helpers = {
  volume(currency) {
    let volume = '0';
    if (this.buyWhichToken === currency) {
      volume = this.buyHowMuch;
    } else if (this.sellWhichToken === currency) {
      volume = this.sellHowMuch;
    }
    return volume;
  },
  type() {
    const baseCurrency = Session.get('baseCurrency');
    let type = '';
    if (this.buyWhichToken === baseCurrency) {
      type = 'bid';
    } else if (this.sellWhichToken === baseCurrency) {
      type = 'ask';
    }
    return type;
  },
  price() {
    const quoteCurrency = Session.get('quoteCurrency');
    const baseCurrency = Session.get('baseCurrency');
    let price = '0';
    if (this.buyWhichToken === quoteCurrency && this.sellWhichToken === baseCurrency) {
      price = new BigNumber(this.buyHowMuch).div(new BigNumber(this.sellHowMuch));
    } else if (this.buyWhichToken === baseCurrency && this.sellWhichToken === quoteCurrency) {
      price = new BigNumber(this.sellHowMuch).div(new BigNumber(this.buyHowMuch));
    }
    return price;
  },
};

Offers.syncedOffers = [];

Offers.helpers(_.extend(helpers, {
  canCancel() {
    const marketOpen = Session.get('market_open');
    const address = Session.get('address');
    return this.status === Status.CONFIRMED && (!marketOpen || address === this.owner);
  },
}));

Trades.helpers(helpers);

/**
 * Get if market is open
 */
Offers.checkMarketOpen = () => {
   // Fetch the market close time
  Dapple['maker-otc'].objects.otc.close_time((error, t) => {
    if (!error) {
      const closeTime = t.toNumber();
      Session.set('close_time', closeTime);
      Session.set('market_open', closeTime > (new Date() / 1000));
    }
  });
};

/**
 * Syncs up all offers and trades
 */
Offers.sync = () => {
  Offers.remove({});

  // Watch ItemUpdate Event
  /* eslint new-cap: ["error", { "capIsNewExceptions": ["ItemUpdate", "Trade"] }] */
  Dapple['maker-otc'].objects.otc.ItemUpdate((error, result) => {
    if (!error) {
      const id = result.args.id.toNumber();
      Offers.syncOffer(id);
      Offers.remove(result.transactionHash);
      if (Session.equals('selectedOffer', result.transactionHash)) {
        Session.set('selectedOffer', id.toString());
      }
    }
  });

  Offers.checkMarketOpen();

  // Sync all past offers
  Dapple['maker-otc'].objects.otc.last_offer_id((error, n) => {
    if (!error) {
      const lastOfferId = n.toNumber();
      console.log('last_offer_id', lastOfferId);
      if (lastOfferId > 0) {
        Session.set('loading', true);
        Session.set('loadingProgress', 0);
        for (let i = lastOfferId; i >= 1; i--) {
          Offers.syncOffer(i, lastOfferId);
        }
      } else {
        Session.set('loading', false);
        Session.set('loadingProgress', 100);
      }
    }
  });

  // Watch Trade events
  Dapple['maker-otc'].objects.otc.Trade({}, { fromBlock: Dapple.getFirstContractBlock() }).get((error, trades) => {
    if (!error) {
      let trade = null;
      let buyWhichToken = null;
      let sellWhichToken = null;
      let args = {};
      const promises = [];
      let block = null;

      if (trades.length > 0) {
        for (let i = 0; i < trades.length; i++) {
          promises.push(Offers.getBlock(trades[i].blockNumber));
        }

        Promise.all(promises).then((resultProm) => {
          for (let i = 0; i < trades.length; i++) {
            trade = trades[i];
            buyWhichToken = Dapple.getTokenByAddress(trade.args.buy_which_token);
            sellWhichToken = Dapple.getTokenByAddress(trade.args.sell_which_token);

            // Transform arguments
            args = {
              buyWhichToken_address: trade.args.buy_which_token,
              buyWhichToken,
              sellWhichToken_address: trade.args.sell_which_token,
              sellWhichToken,
              buyHowMuch: convertTo18Precision(trade.args.buy_how_much.toString(10), buyWhichToken),
              sellHowMuch: convertTo18Precision(trade.args.sell_how_much.toString(10), sellWhichToken),
            };

            block = resultProm[i];

            Trades.upsert(trade.transactionHash, _.extend(block, trade, args));
            Session.set('loadingTradeHistory', false);
          }
        });
      } else {
        Session.set('loadingTradeHistory', false);
      }
    }
  });
};

Offers.getBlock = function getBlock(blockNumber) {
  const p = new Promise((resolve, reject) => {
    web3.eth.getBlock(blockNumber, (blockError, block) => {
      if (!blockError) {
        resolve(block);
      } else {
        reject(blockError);
      }
    });
  });
  return p;
};

/**
 * Syncs up a single offer
 */
Offers.syncOffer = (id, max = 0) => {
  Dapple['maker-otc'].objects.otc.offers(id, (error, data) => {
    if (!error) {
      const idx = id.toString();
      const [sellHowMuch, sellWhichTokenAddress, buyHowMuch, buyWhichTokenAddress, owner, active] = data;

      if (active) {
        Offers.updateOffer(idx, sellHowMuch, sellWhichTokenAddress, buyHowMuch, buyWhichTokenAddress,
                           owner, Status.CONFIRMED);
      } else {
        Offers.remove(idx);
        if (Session.equals('selectedOffer', idx)) {
          $('#offerModal').modal('hide');
        }
      }
      Offers.syncedOffers.push(id);

      if (max > 0 && id > 1) {
        Session.set('loadingProgress', Math.round(100 * (Offers.syncedOffers.length / max)));
      } else {
        Session.set('loading', false);
        Session.set('loadingProgress', 100);
      }
    }
  });
};

Offers.updateOffer = (idx, sellHowMuch, sellWhichTokenAddress, buyHowMuch, buyWhichTokenAddress, owner, status) => {
  const sellToken = Dapple.getTokenByAddress(sellWhichTokenAddress);
  const buyToken = Dapple.getTokenByAddress(buyWhichTokenAddress);

  let sellHowMuchValue = convertTo18Precision(sellHowMuch, sellToken);
  let buyHowMuchValue = convertTo18Precision(buyHowMuch, buyToken);
  if (!(sellHowMuchValue instanceof BigNumber)) {
    sellHowMuchValue = new BigNumber(sellHowMuchValue);
  }
  if (!(buyHowMuchValue instanceof BigNumber)) {
    buyHowMuchValue = new BigNumber(buyHowMuchValue);
  }

  const offer = {
    owner,
    status,
    helper: status === Status.PENDING ? 'Your new order is being placed...' : '',
    buyWhichTokenAddress,
    buyWhichToken: buyToken,
    sellWhichTokenAddress,
    sellWhichToken: sellToken,
    buyHowMuch: buyHowMuchValue.toString(10),
    sellHowMuch: sellHowMuchValue.toString(10),
    ask_price: buyHowMuchValue.div(sellHowMuchValue).toNumber(),
    bid_price: sellHowMuchValue.div(buyHowMuchValue).toNumber(),
  };

  Offers.upsert(idx, { $set: offer });
};

Offers.newOffer = (sellHowMuch, sellWhichToken, buyHowMuch, buyWhichToken, callback) => {
  const sellWhichTokenAddress = Dapple.getTokenAddress(sellWhichToken);
  const buyWhichTokenAddress = Dapple.getTokenAddress(buyWhichToken);

  const sellHowMuchAbsolute = convertToTokenPrecision(sellHowMuch, sellWhichToken);
  const buyHowMuchAbsolute = convertToTokenPrecision(buyHowMuch, buyWhichToken);

  Dapple['maker-otc'].objects.otc.offer(sellHowMuchAbsolute, sellWhichTokenAddress,
                                        buyHowMuchAbsolute, buyWhichTokenAddress,
    { gas: OFFER_GAS }, (error, tx) => {
      callback(error, tx);
      if (!error) {
        Offers.updateOffer(tx, sellHowMuchAbsolute, sellWhichTokenAddress, buyHowMuchAbsolute, buyWhichTokenAddress,
                           web3.eth.defaultAccount, Status.PENDING);
        Transactions.add('offer', tx, { id: tx, status: Status.PENDING });
      }
    });
};

Offers.buyOffer = (_id, _quantity, _token) => {
  const id = parseInt(_id, 10);

  const quantityAbsolute = convertToTokenPrecision(_quantity, _token);

  Offers.update(_id, { $unset: { helper: '' } });
  Dapple['maker-otc'].objects.otc.buy(id.toString(10), quantityAbsolute, { gas: BUY_GAS }, (error, tx) => {
    if (!error) {
      Transactions.add('offer', tx, { id: _id, status: Status.BOUGHT });
      Offers.update(_id, { $set: {
        tx, status: Status.BOUGHT, helper: 'Your buy / sell order is being processed...' } });
    } else {
      Offers.update(_id, { $set: { helper: formatError(error) } });
    }
  });
};

Offers.cancelOffer = (idx) => {
  const id = parseInt(idx, 10);
  Offers.update(idx, { $unset: { helper: '' } });
  Dapple['maker-otc'].objects.otc.cancel(id, { gas: CANCEL_GAS }, (error, tx) => {
    if (!error) {
      Transactions.add('offer', tx, { id: idx, status: Status.CANCELLED });
      Offers.update(idx, { $set: { tx, status: Status.CANCELLED, helper: 'Your order is being cancelled...' } });
    } else {
      Offers.update(idx, { $set: { helper: formatError(error) } });
    }
  });
};

export { Offers, Trades, Status };
<commit_msg>Show all trades and offers<commit_after>import { Mongo } from 'meteor/mongo';
import { Session } from 'meteor/session';
import { BigNumber } from 'meteor/ethereum:web3';
import { Dapple, web3 } from 'meteor/makerotc:dapple';
import { _ } from 'meteor/underscore';
import { $ } from 'meteor/jquery';

import Transactions from '/imports/api/transactions';
import { formatError } from '/imports/utils/functions';

import { convertToTokenPrecision, convertTo18Precision } from '/imports/utils/conversion';

const Offers = new Mongo.Collection(null);
const Trades = new Mongo.Collection(null);

const Status = {
  PENDING: 'pending',
  CONFIRMED: 'confirmed',
  CANCELLED: 'cancelled',
  BOUGHT: 'bought',
};

const OFFER_GAS = 1000000;
const BUY_GAS = 1000000;
const CANCEL_GAS = 1000000;

const TRADES_LIMIT = 0;
Session.set('lastTradesLimit', TRADES_LIMIT);

const OFFER_LIMIT = 0;
Session.set('orderBookLimit', OFFER_LIMIT);

const helpers = {
  volume(currency) {
    let volume = '0';
    if (this.buyWhichToken === currency) {
      volume = this.buyHowMuch;
    } else if (this.sellWhichToken === currency) {
      volume = this.sellHowMuch;
    }
    return volume;
  },
  type() {
    const baseCurrency = Session.get('baseCurrency');
    let type = '';
    if (this.buyWhichToken === baseCurrency) {
      type = 'bid';
    } else if (this.sellWhichToken === baseCurrency) {
      type = 'ask';
    }
    return type;
  },
  price() {
    const quoteCurrency = Session.get('quoteCurrency');
    const baseCurrency = Session.get('baseCurrency');
    let price = '0';
    if (this.buyWhichToken === quoteCurrency && this.sellWhichToken === baseCurrency) {
      price = new BigNumber(this.buyHowMuch).div(new BigNumber(this.sellHowMuch));
    } else if (this.buyWhichToken === baseCurrency && this.sellWhichToken === quoteCurrency) {
      price = new BigNumber(this.sellHowMuch).div(new BigNumber(this.buyHowMuch));
    }
    return price;
  },
};

Offers.syncedOffers = [];

Offers.helpers(_.extend(helpers, {
  canCancel() {
    const marketOpen = Session.get('market_open');
    const address = Session.get('address');
    return this.status === Status.CONFIRMED && (!marketOpen || address === this.owner);
  },
}));

Trades.helpers(helpers);

/**
 * Get if market is open
 */
Offers.checkMarketOpen = () => {
   // Fetch the market close time
  Dapple['maker-otc'].objects.otc.close_time((error, t) => {
    if (!error) {
      const closeTime = t.toNumber();
      Session.set('close_time', closeTime);
      Session.set('market_open', closeTime > (new Date() / 1000));
    }
  });
};

/**
 * Syncs up all offers and trades
 */
Offers.sync = () => {
  Offers.remove({});

  // Watch ItemUpdate Event
  /* eslint new-cap: ["error", { "capIsNewExceptions": ["ItemUpdate", "Trade"] }] */
  Dapple['maker-otc'].objects.otc.ItemUpdate((error, result) => {
    if (!error) {
      const id = result.args.id.toNumber();
      Offers.syncOffer(id);
      Offers.remove(result.transactionHash);
      if (Session.equals('selectedOffer', result.transactionHash)) {
        Session.set('selectedOffer', id.toString());
      }
    }
  });

  Offers.checkMarketOpen();

  // Sync all past offers
  Dapple['maker-otc'].objects.otc.last_offer_id((error, n) => {
    if (!error) {
      const lastOfferId = n.toNumber();
      console.log('last_offer_id', lastOfferId);
      if (lastOfferId > 0) {
        Session.set('loading', true);
        Session.set('loadingProgress', 0);
        for (let i = lastOfferId; i >= 1; i--) {
          Offers.syncOffer(i, lastOfferId);
        }
      } else {
        Session.set('loading', false);
        Session.set('loadingProgress', 100);
      }
    }
  });

  // Watch Trade events
  Dapple['maker-otc'].objects.otc.Trade({}, { fromBlock: Dapple.getFirstContractBlock() }).get((error, trades) => {
    if (!error) {
      let trade = null;
      let buyWhichToken = null;
      let sellWhichToken = null;
      let args = {};
      const promises = [];
      let block = null;

      if (trades.length > 0) {
        for (let i = 0; i < trades.length; i++) {
          promises.push(Offers.getBlock(trades[i].blockNumber));
        }

        Promise.all(promises).then((resultProm) => {
          for (let i = 0; i < trades.length; i++) {
            trade = trades[i];
            buyWhichToken = Dapple.getTokenByAddress(trade.args.buy_which_token);
            sellWhichToken = Dapple.getTokenByAddress(trade.args.sell_which_token);

            // Transform arguments
            args = {
              buyWhichToken_address: trade.args.buy_which_token,
              buyWhichToken,
              sellWhichToken_address: trade.args.sell_which_token,
              sellWhichToken,
              buyHowMuch: convertTo18Precision(trade.args.buy_how_much.toString(10), buyWhichToken),
              sellHowMuch: convertTo18Precision(trade.args.sell_how_much.toString(10), sellWhichToken),
            };

            block = resultProm[i];

            Trades.upsert(trade.transactionHash, _.extend(block, trade, args));
            Session.set('loadingTradeHistory', false);
          }
        });
      } else {
        Session.set('loadingTradeHistory', false);
      }
    }
  });
};

Offers.getBlock = function getBlock(blockNumber) {
  const p = new Promise((resolve, reject) => {
    web3.eth.getBlock(blockNumber, (blockError, block) => {
      if (!blockError) {
        resolve(block);
      } else {
        reject(blockError);
      }
    });
  });
  return p;
};

/**
 * Syncs up a single offer
 */
Offers.syncOffer = (id, max = 0) => {
  Dapple['maker-otc'].objects.otc.offers(id, (error, data) => {
    if (!error) {
      const idx = id.toString();
      const [sellHowMuch, sellWhichTokenAddress, buyHowMuch, buyWhichTokenAddress, owner, active] = data;

      if (active) {
        Offers.updateOffer(idx, sellHowMuch, sellWhichTokenAddress, buyHowMuch, buyWhichTokenAddress,
                           owner, Status.CONFIRMED);
      } else {
        Offers.remove(idx);
        if (Session.equals('selectedOffer', idx)) {
          $('#offerModal').modal('hide');
        }
      }
      Offers.syncedOffers.push(id);

      if (max > 0 && id > 1) {
        Session.set('loadingProgress', Math.round(100 * (Offers.syncedOffers.length / max)));
      } else {
        Session.set('loading', false);
        Session.set('loadingProgress', 100);
      }
    }
  });
};

Offers.updateOffer = (idx, sellHowMuch, sellWhichTokenAddress, buyHowMuch, buyWhichTokenAddress, owner, status) => {
  const sellToken = Dapple.getTokenByAddress(sellWhichTokenAddress);
  const buyToken = Dapple.getTokenByAddress(buyWhichTokenAddress);

  let sellHowMuchValue = convertTo18Precision(sellHowMuch, sellToken);
  let buyHowMuchValue = convertTo18Precision(buyHowMuch, buyToken);
  if (!(sellHowMuchValue instanceof BigNumber)) {
    sellHowMuchValue = new BigNumber(sellHowMuchValue);
  }
  if (!(buyHowMuchValue instanceof BigNumber)) {
    buyHowMuchValue = new BigNumber(buyHowMuchValue);
  }

  const offer = {
    owner,
    status,
    helper: status === Status.PENDING ? 'Your new order is being placed...' : '',
    buyWhichTokenAddress,
    buyWhichToken: buyToken,
    sellWhichTokenAddress,
    sellWhichToken: sellToken,
    buyHowMuch: buyHowMuchValue.toString(10),
    sellHowMuch: sellHowMuchValue.toString(10),
    ask_price: buyHowMuchValue.div(sellHowMuchValue).toNumber(),
    bid_price: sellHowMuchValue.div(buyHowMuchValue).toNumber(),
  };

  Offers.upsert(idx, { $set: offer });
};

Offers.newOffer = (sellHowMuch, sellWhichToken, buyHowMuch, buyWhichToken, callback) => {
  const sellWhichTokenAddress = Dapple.getTokenAddress(sellWhichToken);
  const buyWhichTokenAddress = Dapple.getTokenAddress(buyWhichToken);

  const sellHowMuchAbsolute = convertToTokenPrecision(sellHowMuch, sellWhichToken);
  const buyHowMuchAbsolute = convertToTokenPrecision(buyHowMuch, buyWhichToken);

  Dapple['maker-otc'].objects.otc.offer(sellHowMuchAbsolute, sellWhichTokenAddress,
                                        buyHowMuchAbsolute, buyWhichTokenAddress,
    { gas: OFFER_GAS }, (error, tx) => {
      callback(error, tx);
      if (!error) {
        Offers.updateOffer(tx, sellHowMuchAbsolute, sellWhichTokenAddress, buyHowMuchAbsolute, buyWhichTokenAddress,
                           web3.eth.defaultAccount, Status.PENDING);
        Transactions.add('offer', tx, { id: tx, status: Status.PENDING });
      }
    });
};

Offers.buyOffer = (_id, _quantity, _token) => {
  const id = parseInt(_id, 10);

  const quantityAbsolute = convertToTokenPrecision(_quantity, _token);

  Offers.update(_id, { $unset: { helper: '' } });
  Dapple['maker-otc'].objects.otc.buy(id.toString(10), quantityAbsolute, { gas: BUY_GAS }, (error, tx) => {
    if (!error) {
      Transactions.add('offer', tx, { id: _id, status: Status.BOUGHT });
      Offers.update(_id, { $set: {
        tx, status: Status.BOUGHT, helper: 'Your buy / sell order is being processed...' } });
    } else {
      Offers.update(_id, { $set: { helper: formatError(error) } });
    }
  });
};

Offers.cancelOffer = (idx) => {
  const id = parseInt(idx, 10);
  Offers.update(idx, { $unset: { helper: '' } });
  Dapple['maker-otc'].objects.otc.cancel(id, { gas: CANCEL_GAS }, (error, tx) => {
    if (!error) {
      Transactions.add('offer', tx, { id: idx, status: Status.CANCELLED });
      Offers.update(idx, { $set: { tx, status: Status.CANCELLED, helper: 'Your order is being cancelled...' } });
    } else {
      Offers.update(idx, { $set: { helper: formatError(error) } });
    }
  });
};

export { Offers, Trades, Status };
<|endoftext|>


<commit_before>'use strict';

const apiResult = require('../apiResult');
const type = require('../type');
const Application = require('../../documentModels/application');
const ApplicationAccess = require('../../documentModels/applicationAccess');

module.exports = (request, response, next) => {
	request.checkRequestAsync = async (routeConfig) => {
		try {
			if (routeConfig == null)
				routeConfig = {};

			// parameters
			if (routeConfig.params == null)
				routeConfig.params = [];

			for(const param of routeConfig.params) {
				if (param.type == null || param.name == null) {
					throw new Error('extentions.params elements are missing');
				}

				const paramType = param.type;
				const paramName = param.name;
				const isRequire = param.require != null ? param.require === true : true; // requireにtrueが設定されている場合は必須項目になる。デフォルトでtrue

				if (isRequire) {
					if (request.body[paramName] == null) {
						throw new apiResult(400, `parameter '${paramName}' is require`);
					}

					if (type(request.body[paramName]).toLowerCase() !== paramType.toLowerCase()) {
						throw new apiResult(400, `type of parameter '${paramName}' is invalid`);
					}
				}
			}

			// query strings
			if (routeConfig.queries == null)
				routeConfig.queries = [];

			for(const query of routeConfig.queries) {
				if (query.type == null || query.name == null) {
					throw new Error('extentions.queries elements are missing');
				}

				const queryType = query.type;
				const queryName = query.name;
				const isRequire = query.require != null ? query.require === true : true; // requireにtrueが設定されている場合は必須項目になる。デフォルトでtrue

				if (isRequire) {
					if (request.query[queryName] == null) {
						throw new apiResult(400, `query '${queryName}' is require`);
					}

					if (type(request.query[queryName]).toLowerCase() !== queryType.toLowerCase()) {
						throw new apiResult(400, `type of query '${queryName}' is invalid`);
					}
				}
			}

			// permissions
			if (routeConfig.permissions == null)
				routeConfig.permissions = [];

			if (routeConfig.permissions.length !== 0) {
				const applicationKey = request.get('X-Application-Key');
				const accessKey = request.get('X-Access-Key');

				if (applicationKey == null) {
					throw new apiResult(400, 'X-Application-Key header is empty');
				}

				if (accessKey == null) {
					throw new apiResult(400, 'X-Access-Key header is empty');
				}

				if (!await Application.verifyKeyAsync(applicationKey, request.db, request.config)) {
					throw new apiResult(400, 'X-Application-Key header is invalid');
				}

				if (!await ApplicationAccess.verifyKeyAsync(accessKey, request.db, request.config)) {
					throw new apiResult(400, 'X-Access-Key header is invalid');
				}

				const applicationId = Application.splitKey(applicationKey, request.db, request.config).applicationId;
				const userId = ApplicationAccess.splitKey(accessKey, request.db, request.config).userId;

				request.application = (await request.db.applications.findByIdAsync(applicationId));
				request.user = (await request.db.users.findByIdAsync(userId));

				const hasPermissions = routeConfig.permissions.every(p => request.application.hasPermission(p));
				if (!hasPermissions) {
					throw new apiResult(403, 'you do not have any permissions');
				}
			}

			// headers
			if (routeConfig.headers == null)
				routeConfig.headers = [];

			if (routeConfig.headers.indexOf('X-Api-Version') == -1)
				routeConfig.headers.push('X-Api-Version');

			for(const header of routeConfig.headers) {
				if (header == null) {
					throw new Error('extentions.headers elements are missing');
				}

				if (request.get(header) == null) {
					throw new apiResult(400, `${header} header is empty`);
				}
			}

			return null;
		}
		catch(e) {
			if (e instanceof Error) {
				console.log(`checkRequest failed: ${e.trace}`);
				throw e;
			}
			else {
				return e;
			}
		}
	};

	next();
};
<commit_msg>support for using as non-middleware<commit_after>'use strict';

const apiResult = require('../apiResult');
const type = require('../type');
const Application = require('../../documentModels/application');
const ApplicationAccess = require('../../documentModels/applicationAccess');

module.exports = (request, response, next) => {
	const isMiddleware = next != null;

	request.checkRequestAsync = async (routeConfig) => {
		try {
			if (routeConfig == null)
				routeConfig = {};

			// parameters
			if (routeConfig.params == null)
				routeConfig.params = [];

			for(const param of routeConfig.params) {
				if (param.type == null || param.name == null) {
					throw new Error('extentions.params elements are missing');
				}

				const paramType = param.type;
				const paramName = param.name;
				const isRequire = param.require != null ? param.require === true : true; // requireにtrueが設定されている場合は必須項目になる。デフォルトでtrue

				if (isRequire) {
					if (request.params[paramName] == null) {
						throw new apiResult(400, `parameter '${paramName}' is require`);
					}

					if (type(request.params[paramName]).toLowerCase() !== paramType.toLowerCase()) {
						throw new apiResult(400, `type of parameter '${paramName}' is invalid`);
					}
				}
			}

			// body
			if (routeConfig.body == null)
				routeConfig.body = [];

			for(const param of routeConfig.body) {
				if (param.type == null || param.name == null) {
					throw new Error('extentions.body elements are missing');
				}

				const paramType = param.type;
				const paramName = param.name;
				const isRequire = param.require != null ? param.require === true : true; // requireにtrueが設定されている場合は必須項目になる。デフォルトでtrue

				if (isRequire) {
					if (request.body[paramName] == null) {
						throw new apiResult(400, `body parameter '${paramName}' is require`);
					}

					if (type(request.body[paramName]).toLowerCase() !== paramType.toLowerCase()) {
						throw new apiResult(400, `type of body parameter '${paramName}' is invalid`);
					}
				}
			}

			// query strings
			if (routeConfig.queries == null)
				routeConfig.queries = [];

			for(const query of routeConfig.queries) {
				if (query.type == null || query.name == null) {
					throw new Error('extentions.queries elements are missing');
				}

				const queryType = query.type;
				const queryName = query.name;
				const isRequire = query.require != null ? query.require === true : true; // requireにtrueが設定されている場合は必須項目になる。デフォルトでtrue

				if (isRequire) {
					let requestQuery = null;
					try {
						requestQuery = request.query[queryName];
					}
					catch(e) {
						/* noop */
					}
					if (requestQuery == null) {
						throw new apiResult(400, `query '${queryName}' is require`);
					}

					if (type(requestQuery).toLowerCase() !== queryType.toLowerCase()) {
						throw new apiResult(400, `type of query '${queryName}' is invalid`);
					}
				}
			}

			// permissions
			if (routeConfig.permissions == null)
				routeConfig.permissions = [];

			if (routeConfig.permissions.length !== 0) {
				if (isMiddleware) {
					const applicationKey = request.get('X-Application-Key');
					const accessKey = request.get('X-Access-Key');

					if (applicationKey == null) {
						throw new apiResult(400, 'X-Application-Key header is empty');
					}

					if (accessKey == null) {
						throw new apiResult(400, 'X-Access-Key header is empty');
					}

					if (!await Application.verifyKeyAsync(applicationKey, request.db, request.config)) {
						throw new apiResult(400, 'X-Application-Key header is invalid');
					}

					if (!await ApplicationAccess.verifyKeyAsync(accessKey, request.db, request.config)) {
						throw new apiResult(400, 'X-Access-Key header is invalid');
					}

					const applicationId = Application.splitKey(applicationKey, request.db, request.config).applicationId;
					const userId = ApplicationAccess.splitKey(accessKey, request.db, request.config).userId;

					request.application = (await request.db.applications.findByIdAsync(applicationId));
					request.user = (await request.db.users.findByIdAsync(userId));
				}

				const hasPermissions = routeConfig.permissions.every(p => request.application.hasPermission(p));
				if (!hasPermissions) {
					throw new apiResult(403, 'you do not have any permissions');
				}
			}

			// headers
			if (routeConfig.headers == null)
				routeConfig.headers = [];

			if (request.headers == null)
				request.headers = [];

			if (routeConfig.headers.indexOf('X-Api-Version') == -1)
				routeConfig.headers.push('X-Api-Version');

			for(const header of routeConfig.headers) {
				if (header == null) {
					throw new Error('extentions.headers elements are missing');
				}

				if (isMiddleware) {
					if (request.get(header) == null) {
						throw new apiResult(400, `${header} header is empty`);
					}
				}
				else {
					let requestHeader = null;
					try {
						requestHeader = request.headers[header.toLowerCase()];
					}
					catch(e) {
						/* noop */
					}

					if (requestHeader == null) {
						throw new apiResult(400, `${header} header is empty`);
					}
				}

			}

			return null;
		}
		catch(e) {
			if (e instanceof Error) {
				console.log(`checkRequest failed: ${e}`);
				throw e;
			}
			else {
				return e;
			}
		}
	};

	if (isMiddleware)
		next();
};
<|endoftext|>