<commit_before>var util = require("util");
var events = require("events");
var EventEmitter = events.EventEmitter;
var async = require("async");
var qtypes = require("qtypes");
var _ = require("lodash");
var norm = require("node-normalizer");
var requireDir = require("require-dir");
var debug = require("debug-levels")("SS:Script");
var facts = require("sfacts");
var gTopicsSystem = require("./lib/topics/index");
var Message = require("./lib/message");
var Users = require("./lib/users");
var getreply = require("./lib/getreply");
var Utils = require("./lib/utils");
var processHelpers = require("./lib/reply/common");
var mergex = require("deepmerge");

function SuperScript(options, callback) {
  EventEmitter.call(this);
  var mongoose;
  var self = this;
  options = options || {};

  // Create a new connection if non is provided.
  if (options.mongoose) {
    mongoose = options.mongoose;
  } else {
    mongoose = require("mongoose");
    mongoose.connect("mongodb://localhost/superscriptDB");
  }

  this._plugins = [];
  this.normalize = null;
  this.question = null;

  Utils.mkdirSync("./plugins");
  this.loadPlugins("./plugins");
  this.loadPlugins(process.cwd() + "/plugins");
  // this.intervalId = setInterval(this.check.bind(this), 500);

  this.factSystem = options.factSystem ? options.factSystem : facts.create("systemDB");
  this.topicSystem = gTopicsSystem(mongoose, this.factSystem);

  // This is a kill switch for filterBySeen which is useless in the editor.
  this.editMode = options.editMode || false;

  // We want a place to store bot related data
  this.memory = options.botfacts ? options.botfacts : this.factSystem.createUserDB("botfacts");

  this.scope = {};
  this.scope = _.extend(options.scope || {});
  this.scope.bot = this;
  this.scope.facts = this.factSystem;
  this.scope.topicSystem = this.topicSystem;
  this.scope.botfacts = this.memory;
  this.users = new Users(mongoose, this.factSystem);

  norm.loadData(function () {
    self.normalize = norm;
    new qtypes(function (question) {
      self.question = question;
      debug.verbose("System Loaded, waiting for replies");
      callback(null, self);
    });
  });
}

var messageItorHandle = function (user, system) {
  var messageItor = function (msg, next) {

    var options = {
      user: user,
      system: system,
      message: msg
    };

    processHelpers.getTopic(options.system.topicsSystem, system.topicName, function (err, topicData) {
      if (topicData) {
        options.aTopics = [];
        options.aTopics.push(topicData);
      }

      getreply(options, function (err, replyObj) {
        // Convert the reply into a message object too.

        var msgString = "";
        var messageOptions = {
          qtypes: system.question,
          norm: system.normalize,
          facts: system.facts
        };

        if (replyObj) {
          messageOptions.replyId = replyObj.replyId;
          msgString = replyObj.string;

          if (replyObj.clearConvo) {
            messageOptions.clearConvo = replyObj.clearConvo;
          }

        } else {
          replyObj = {};
        }

        new Message(msgString, messageOptions, function (replyMessageObject) {
          user.updateHistory(msg, replyMessageObject, replyObj, function(err, log) {

            // We send back a smaller message object to the clients.
            var clientObject = {
              replyId: replyObj.replyId,
              createdAt: replyMessageObject.createdAt || new Date(),
              string: msgString || "", // replyMessageObject.raw || "",
              topicName: replyObj.topicName,
              subReplies: replyObj.subReplies,
              debug: log
            };

            var newClientObject = mergex(clientObject, replyObj.props || {});

            user.save(function (err, res) {
              debug.verbose(err, res);
              // TODO - Seeing RangeError here. (investigate Mongoose 4.0)
              return next(null, newClientObject);
            });

          });
        });
      });
    });
  };

  return messageItor;
};

// This takes a message and breaks it into chucks to be passed though
// the sytem. We put them back together on the other end.
// FIXME: with chunking removed this is not needed.
var messageFactory = function (options, cb) {

  var rawMsg = options.msg;
  var normalize = options.normalize;
  var messageParts = [];

  var cleanMsg = normalize.clean(rawMsg).trim();
  debug.verbose("IN MessageFactory", cleanMsg);

  var messageOptions = {
    qtypes: options.question,
    norm: normalize,
    facts: options.factSystem,
    original: rawMsg
  };

  return new Message(cleanMsg, messageOptions, function (tmsg) {
    return cb(null, [tmsg]);
  });

  // messageParts.push(cleanMsg);
  // messageParts = Utils.cleanArray(messageParts);

  // var itor = function (messageChunk, nextcb) {
  //   var messageOptions = {
  //     qtypes: options.question,
  //     norm: normalize,
  //     facts: options.factSystem,
  //     original: rawMsg
  //   };

  //   new Message(messageChunk, messageOptions, function (tmsg) {
  //     nextcb(null, tmsg);
  //   });
  // };

  // return async.mapSeries(messageParts, itor, function (err, messageArray) {
  //   return cb(messageArray);
  // });
};

util.inherits(SuperScript, EventEmitter);

SuperScript.prototype.message = function (msgString, callback) {

  var messageOptions = {
    qtypes: this.question,
    norm: this.normalize,
    facts: this.factSystem
  };

  var message = new Message(msgString, messageOptions, function (msgObj) {
    callback(null, msgObj);
  });
};

// This is like doing a topicRedirect
SuperScript.prototype.directReply = function (userId, topic, msg, callback) {
  debug.log("[ New DirectReply - '" + userId + "']- " +  msg);
  var options = {
    userId: userId,
    topicName: topic,
    msgString: msg,
    extraScope: {}
  };

  this._reply(options, callback);

};

// Convert msg into message object, then check for a match
SuperScript.prototype.reply = function (userId, msg, callback, extraScope) {
  if (arguments.length === 2 && typeof msg === "function") {
    callback = msg;
    msg = userId;
    userId = Math.random().toString(36).substr(2, 5);
    extraScope = {};
  }

  debug.log("[ New Message - '" + userId + "']- " +  msg);
  var options = {
    userId: userId,
    msgString: msg,
    extraScope: extraScope
  };

  this._reply(options, callback);
};

SuperScript.prototype._reply = function(options, callback) {
  var self = this;

  // Ideally these will come from a cache, but self is a exercise for a rainy day
  var system = {

    // getReply
    topicsSystem: self.topicSystem,
    plugins: self._plugins,
    scope: self.scope,
    messageScope: options.extraScope,

    // Pass in the topic if it
    topicName: options.topicName || null,

    // Message
    question: self.question,
    normalize: self.normalize,
    facts: self.factSystem,
    editMode: self.editMode
  };

  var prop = {
    currentTopic: "random",
    status: 0,
    conversation: 0, volley: 0, rally: 0
  };

  this.users.findOrCreate({ id: options.userId }, prop, function (err1, user) {
    if (err1) {
      debug.error(err1);
    }

    var opt = {
      msg: options.msgString,
      question: self.question,
      normalize: self.normalize,
      factSystem: self.factSystem
    };

    messageFactory(opt, function (err, messages) {
      // FIXME: This will always be one now that we no longer chunk
      async.mapSeries(messages, messageItorHandle(user, system), function (err2, messageArray) {
        if (err2) {
          debug.error(err2);
        }

        var reply = {};
        messageArray = Utils.cleanArray(messageArray);

        if (_.isEmpty(messageArray)) {
          reply.string = "";
        } else if (messageArray.length === 1) {
          reply = messageArray[0];
        } else {
          // TODO - We will want to add some smarts on putting multiple
          // lines back together - check for tail grammar or drop bits.
          reply = messageArray[0];
          var messageReplies = [];
          reply.parts = [];
          for (var i = 0; i < messageArray.length; i++) {
            reply.parts[i] = {
              string: messageArray[i].string,
              threads: messageArray[i].threads,
              triggerId: messageArray[i].triggerId,
              topicName: messageArray[i].topicName
            };

            if (messageArray[i].string !== "") {
              messageReplies.push(messageArray[i].string);
            }

            for (var nprop in messageArray[i]) {
              if (nprop !== "createdAt" && nprop !== "string") {
                reply[nprop] = messageArray[i][nprop];
              }
            }
          }

          reply.string = messageReplies.join(" ");
        }

        debug.verbose("Update and Reply to user '" + user.id + "'", reply);
        debug.info("[ Final Reply - '" + user.id + "']- '" + reply.string + "'");

        // If we have a thread of messages, lets space them out.
        if (reply.subReplies) {

        }

        return callback(err2, reply);
      });
    });
  });
}

SuperScript.prototype.loadPlugins = function (path) {
  var plugins = requireDir(path);

  for (var file in plugins) {
    for (var func in plugins[file]) {
      debug.verbose("Loading Plugin", path, func);
      this._plugins[func] = plugins[file][func];
    }
  }
};

SuperScript.prototype.getPlugins = function () {
  return this._plugins;
};

SuperScript.prototype.getTopics = function () {
  return this.topics;
};

SuperScript.prototype.getUsers = function (cb) {
  this.users.find({}, "id", cb);
};

SuperScript.prototype.getUser = function (userId, cb) {
  this.users.findOne({id: userId}, function (err, usr) {
    cb(err, usr);
  });
};

SuperScript.prototype.findOrCreateUser = function (userId, callback) {
  var properties = { id: userId };
  var prop = {
    currentTopic: "random",
    status: 0,
    conversation: 0, volley: 0, rally: 0
  };

  this.users.findOrCreate(properties, prop, callback);
};

module.exports = SuperScript;
<commit_msg>Removed some dead code / comments<commit_after>var util = require("util");
var events = require("events");
var EventEmitter = events.EventEmitter;
var async = require("async");
var qtypes = require("qtypes");
var _ = require("lodash");
var norm = require("node-normalizer");
var requireDir = require("require-dir");
var debug = require("debug-levels")("SS:Script");
var facts = require("sfacts");
var gTopicsSystem = require("./lib/topics/index");
var Message = require("./lib/message");
var Users = require("./lib/users");
var getreply = require("./lib/getreply");
var Utils = require("./lib/utils");
var processHelpers = require("./lib/reply/common");
var mergex = require("deepmerge");

function SuperScript(options, callback) {
  EventEmitter.call(this);
  var mongoose;
  var self = this;
  options = options || {};

  // Create a new connection if non is provided.
  if (options.mongoose) {
    mongoose = options.mongoose;
  } else {
    mongoose = require("mongoose");
    mongoose.connect("mongodb://localhost/superscriptDB");
  }

  this._plugins = [];
  this.normalize = null;
  this.question = null;

  Utils.mkdirSync("./plugins");
  this.loadPlugins("./plugins");
  this.loadPlugins(process.cwd() + "/plugins");
  // this.intervalId = setInterval(this.check.bind(this), 500);

  this.factSystem = options.factSystem ? options.factSystem : facts.create("systemDB");
  this.topicSystem = gTopicsSystem(mongoose, this.factSystem);

  // This is a kill switch for filterBySeen which is useless in the editor.
  this.editMode = options.editMode || false;

  // We want a place to store bot related data
  this.memory = options.botfacts ? options.botfacts : this.factSystem.createUserDB("botfacts");

  this.scope = {};
  this.scope = _.extend(options.scope || {});
  this.scope.bot = this;
  this.scope.facts = this.factSystem;
  this.scope.topicSystem = this.topicSystem;
  this.scope.botfacts = this.memory;
  this.users = new Users(mongoose, this.factSystem);

  norm.loadData(function () {
    self.normalize = norm;
    new qtypes(function (question) {
      self.question = question;
      debug.verbose("System Loaded, waiting for replies");
      callback(null, self);
    });
  });
}

var messageItorHandle = function (user, system) {
  var messageItor = function (msg, next) {

    var options = {
      user: user,
      system: system,
      message: msg
    };

    processHelpers.getTopic(options.system.topicsSystem, system.topicName, function (err, topicData) {
      if (topicData) {
        options.aTopics = [];
        options.aTopics.push(topicData);
      }

      getreply(options, function (err, replyObj) {
        // Convert the reply into a message object too.

        var msgString = "";
        var messageOptions = {
          qtypes: system.question,
          norm: system.normalize,
          facts: system.facts
        };

        if (replyObj) {
          messageOptions.replyId = replyObj.replyId;
          msgString = replyObj.string;

          if (replyObj.clearConvo) {
            messageOptions.clearConvo = replyObj.clearConvo;
          }

        } else {
          replyObj = {};
        }

        new Message(msgString, messageOptions, function (replyMessageObject) {
          user.updateHistory(msg, replyMessageObject, replyObj, function(err, log) {

            // We send back a smaller message object to the clients.
            var clientObject = {
              replyId: replyObj.replyId,
              createdAt: replyMessageObject.createdAt || new Date(),
              string: msgString || "", // replyMessageObject.raw || "",
              topicName: replyObj.topicName,
              subReplies: replyObj.subReplies,
              debug: log
            };

            var newClientObject = mergex(clientObject, replyObj.props || {});

            user.save(function (err, res) {
              debug.verbose(err, res);
              // TODO - Seeing RangeError here. (investigate Mongoose 4.0)
              return next(null, newClientObject);
            });
          });
        });
      });
    });
  };

  return messageItor;
};

// This takes a message and breaks it into chucks to be passed though
// the sytem. We put them back together on the other end.
// FIXME: with chunking removed this is not needed.
var messageFactory = function (options, cb) {

  var rawMsg = options.msg;
  var normalize = options.normalize;
  var messageParts = [];

  var cleanMsg = normalize.clean(rawMsg).trim();
  debug.verbose("IN MessageFactory", cleanMsg);

  var messageOptions = {
    qtypes: options.question,
    norm: normalize,
    facts: options.factSystem,
    original: rawMsg
  };

  return new Message(cleanMsg, messageOptions, function (tmsg) {
    return cb(null, [tmsg]);
  });
};

util.inherits(SuperScript, EventEmitter);

SuperScript.prototype.message = function (msgString, callback) {

  var messageOptions = {
    qtypes: this.question,
    norm: this.normalize,
    facts: this.factSystem
  };

  var message = new Message(msgString, messageOptions, function (msgObj) {
    callback(null, msgObj);
  });
};

// This is like doing a topicRedirect
SuperScript.prototype.directReply = function (userId, topic, msg, callback) {
  debug.log("[ New DirectReply - '" + userId + "']- " +  msg);
  var options = {
    userId: userId,
    topicName: topic,
    msgString: msg,
    extraScope: {}
  };

  this._reply(options, callback);

};

// Convert msg into message object, then check for a match
SuperScript.prototype.reply = function (userId, msg, callback, extraScope) {
  if (arguments.length === 2 && typeof msg === "function") {
    callback = msg;
    msg = userId;
    userId = Math.random().toString(36).substr(2, 5);
    extraScope = {};
  }

  debug.log("[ New Message - '" + userId + "']- " +  msg);
  var options = {
    userId: userId,
    msgString: msg,
    extraScope: extraScope
  };

  this._reply(options, callback);
};

SuperScript.prototype._reply = function(options, callback) {
  var self = this;

  // Ideally these will come from a cache, but self is a exercise for a rainy day
  var system = {

    // getReply
    topicsSystem: self.topicSystem,
    plugins: self._plugins,
    scope: self.scope,
    messageScope: options.extraScope,

    // Pass in the topic if it
    topicName: options.topicName || null,

    // Message
    question: self.question,
    normalize: self.normalize,
    facts: self.factSystem,
    editMode: self.editMode
  };

  var prop = {
    currentTopic: "random",
    status: 0,
    conversation: 0, volley: 0, rally: 0
  };

  this.users.findOrCreate({ id: options.userId }, prop, function (err1, user) {
    if (err1) {
      debug.error(err1);
    }

    var opt = {
      msg: options.msgString,
      question: self.question,
      normalize: self.normalize,
      factSystem: self.factSystem
    };

    messageFactory(opt, function (err, messages) {
      // FIXME: `messages` will always be one now that we no longer chunk
      async.mapSeries(messages, messageItorHandle(user, system), function (err2, messageArray) {
        if (err2) {
          debug.error(err2);
        }

        var reply = {};
        messageArray = Utils.cleanArray(messageArray);

        if (_.isEmpty(messageArray)) {
          reply.string = "";
        } else if (messageArray.length === 1) {
          reply = messageArray[0];
        } else {
          // TODO - We will want to add some smarts on putting multiple
          // lines back together - check for tail grammar or drop bits.
          reply = messageArray[0];
          var messageReplies = [];
          reply.parts = [];
          for (var i = 0; i < messageArray.length; i++) {
            reply.parts[i] = {
              string: messageArray[i].string,
              threads: messageArray[i].threads,
              triggerId: messageArray[i].triggerId,
              topicName: messageArray[i].topicName
            };

            if (messageArray[i].string !== "") {
              messageReplies.push(messageArray[i].string);
            }

            for (var nprop in messageArray[i]) {
              if (nprop !== "createdAt" && nprop !== "string") {
                reply[nprop] = messageArray[i][nprop];
              }
            }
          }

          reply.string = messageReplies.join(" ");
        }

        debug.verbose("Update and Reply to user '" + user.id + "'", reply);
        debug.info("[ Final Reply - '" + user.id + "']- '" + reply.string + "'");

        return callback(err2, reply);
      });
    });
  });
}

SuperScript.prototype.loadPlugins = function (path) {
  var plugins = requireDir(path);

  for (var file in plugins) {
    for (var func in plugins[file]) {
      debug.verbose("Loading Plugin", path, func);
      this._plugins[func] = plugins[file][func];
    }
  }
};

SuperScript.prototype.getPlugins = function () {
  return this._plugins;
};

SuperScript.prototype.getTopics = function () {
  return this.topics;
};

SuperScript.prototype.getUsers = function (cb) {
  this.users.find({}, "id", cb);
};

SuperScript.prototype.getUser = function (userId, cb) {
  this.users.findOne({id: userId}, function (err, usr) {
    cb(err, usr);
  });
};

SuperScript.prototype.findOrCreateUser = function (userId, callback) {
  var properties = { id: userId };
  var prop = {
    currentTopic: "random",
    status: 0,
    conversation: 0, volley: 0, rally: 0
  };

  this.users.findOrCreate(properties, prop, callback);
};

module.exports = SuperScript;
<|endoftext|>


<commit_before>function StayDown(target, interval, max, callback) {
    this.target = target;
    this.interval = interval;
    this.intend_down = true;
    this.max = max || 0;
    this.callback = callback;
    this.userScroll = true;

    var staydown = this;

    this.emit('lock');

    var wheelevent = "wheel";
    if (document.onmousewheel !== undefined) {
        wheelevent = 'mousewheel';
    }

    window.addEventListener('resize', function (event) {
        staydown.emit('windowresize');
        staydown.checkdown();
    });

    this.target.addEventListener('scroll', function (event) {
        if (staydown.userScroll) {
            if (staydown.intend_down && !staydown.isdown()) {
                staydown.intend_down = false;
                staydown.emit('release');
            } else if (!staydown.indend_down && staydown.isdown()) {
                staydown.intend_down = true;
                staydown.emit('lock');
            }
        }
        staydown.userScroll = true;
    });

    function onImageLoad(event) {
        //image loads later, and isn't a mutation
        staydown.emit('imageload');
        staydown.checkdown();
        event.target.removeEventListener(onImageLoad);
    }

    if (window.MutationObserver) {
        //private function for getting images recursively from dom

        //mutation observer for whenever the overflow element changes
        this.mo = new MutationObserver(function (mutations) {
            staydown.userScroll = false;
            //something changed, check scroll
            staydown.checkdown();
            //check to see if image was added, and add onload check
            for (var idx = 0; idx < mutations.length; idx++) {
                var mut = mutations[idx];
                for (var nidx = 0; nidx < mut.addedNodes.length; nidx++) {
                    var imgs = mut.addedNodes[nidx].getElementsByTagName('img');
                    for (var iidx = 0, ilen = imgs.length; iidx < ilen; i++) {
                        imgs[iidx].addEventListener('load', onImageLoad);
                    }
                }
            }
        });
        this.mo.observe(this.target, {attributes: true, childList: true, characterData: true, subtree: true});
    } else {
        var checkdown = function () {
            staydown.checkdown();
            window.setTimeout(checkdown, staydown.interval);
        };
        checkdown();
    }

}

(function () {

    this.isdown = function () {
        return (this.target.scrollTop + this.target.clientHeight == this.target.scrollHeight);
    };

    this.append = function (newel) {
        this.emit('append');
        this.target.appendChild(newel);
        if (this.intend_down) {
            this.target.scrollTop = this.target.scrollHeight;
            this.emit('scrolldown');
        }
        while (this.max !== 0 && this.target.children.length > this.max) {
            this.target.removeChild(this.target.children[0]);
            this.emit('removechild');
        }
    };

    this.emit = function (type, msg) {
        if (typeof this.callback === 'function') {
            this.callback(type, msg);
        }
    };

    this.checkdown = function () {
        if (this.intend_down &&
            this.target.scrollTop + this.target.clientHeight != this.target.scrollHeight) {
            this.target.scrollTop = this.target.scrollHeight;
            this.userScroll = false;
            this.emit('scrolldown');
        }
    };

}).call(StayDown.prototype);

module.exports = StayDown;
<commit_msg>Fix index<commit_after>function StayDown(target, interval, max, callback) {
    this.target = target;
    this.interval = interval;
    this.intend_down = true;
    this.max = max || 0;
    this.callback = callback;
    this.userScroll = true;

    var staydown = this;

    this.emit('lock');

    var wheelevent = "wheel";
    if (document.onmousewheel !== undefined) {
        wheelevent = 'mousewheel';
    }

    window.addEventListener('resize', function (event) {
        staydown.emit('windowresize');
        staydown.checkdown();
    });

    this.target.addEventListener('scroll', function (event) {
        if (staydown.userScroll) {
            if (staydown.intend_down && !staydown.isdown()) {
                staydown.intend_down = false;
                staydown.emit('release');
            } else if (!staydown.indend_down && staydown.isdown()) {
                staydown.intend_down = true;
                staydown.emit('lock');
            }
        }
        staydown.userScroll = true;
    });

    function onImageLoad(event) {
        //image loads later, and isn't a mutation
        staydown.emit('imageload');
        staydown.checkdown();
        event.target.removeEventListener(onImageLoad);
    }

    if (window.MutationObserver) {
        //private function for getting images recursively from dom

        //mutation observer for whenever the overflow element changes
        this.mo = new MutationObserver(function (mutations) {
            staydown.userScroll = false;
            //something changed, check scroll
            staydown.checkdown();
            //check to see if image was added, and add onload check
            for (var idx = 0; idx < mutations.length; idx++) {
                var mut = mutations[idx];
                for (var nidx = 0; nidx < mut.addedNodes.length; nidx++) {
                    var imgs = mut.addedNodes[nidx].getElementsByTagName('img');
                    for (var iidx = 0, ilen = imgs.length; iidx < ilen; iidx++) {
                        imgs[iidx].addEventListener('load', onImageLoad);
                    }
                }
            }
        });
        this.mo.observe(this.target, {attributes: true, childList: true, characterData: true, subtree: true});
    } else {
        var checkdown = function () {
            staydown.checkdown();
            window.setTimeout(checkdown, staydown.interval);
        };
        checkdown();
    }

}

(function () {

    this.isdown = function () {
        return (this.target.scrollTop + this.target.clientHeight == this.target.scrollHeight);
    };

    this.append = function (newel) {
        this.emit('append');
        this.target.appendChild(newel);
        if (this.intend_down) {
            this.target.scrollTop = this.target.scrollHeight;
            this.emit('scrolldown');
        }
        while (this.max !== 0 && this.target.children.length > this.max) {
            this.target.removeChild(this.target.children[0]);
            this.emit('removechild');
        }
    };

    this.emit = function (type, msg) {
        if (typeof this.callback === 'function') {
            this.callback(type, msg);
        }
    };

    this.checkdown = function () {
        if (this.intend_down &&
            this.target.scrollTop + this.target.clientHeight != this.target.scrollHeight) {
            this.target.scrollTop = this.target.scrollHeight;
            this.userScroll = false;
            this.emit('scrolldown');
        }
    };

}).call(StayDown.prototype);

module.exports = StayDown;
<|endoftext|>


<commit_before>var events = require('events');
var inherits = require('util').inherits;
var bopper = require('./vendor/bopper');
var ditty = require('./vendor/ditty');
var expr = require('dilla-expressions');
var memoize = require('meemo');

var checkValid = require('./lib/checkValid');
var positionHelper = require('./lib/positionHelper');

var loadTime = new Date().valueOf();

var memoSpacer = '//';

function Dilla (audioContext, options) {

  if (!(this instanceof Dilla)){
    return new Dilla(audioContext, options);
  }

  if (!audioContext || typeof audioContext !== 'object' || typeof audioContext.createScriptProcessor !== 'function') {
    throw new Error('Invalid arguments: cannot init without AudioContext');
  }

  events.EventEmitter.call(this);

  options = options || {};

  this.context = audioContext;
  this.clock = bopper(this.context);
  this.scheduler = ditty();

  this.expressions = expr;
  this.expandNote = options.expandNote;

  this.upstartWait = options.upstartWait || 250;
  this.setTempo(options.tempo || 120);
  this.setBeatsPerBar(options.beatsPerBar || 4);
  this.setLoopLength(options.loopLength || 2);

  this._position = '0.0.00';

  this.clock.on('data', this.updatePositionFromClock.bind(this));
  this.clock.pipe(this.scheduler).on('data', this.emitStep.bind(this));

  this._keepAlive = this._keepAlive.bind(this);
}

inherits(Dilla, events.EventEmitter);
var proto = Dilla.prototype;

proto.updatePositionFromClock = function updatePositionFromClock (step) {
  var position = this.getPositionFromTime(step.time);
  if (this._position !== position) {
    this._position = position;
    this.emit('tick', { 'position': this._position, 'context': this.context });
  }
};

proto.getPositionFromTime = function getPositionFromTime (time) {
  var offset = (this.clock._state.cycleLength * this.clock._state.preCycle) * 1;
  var position = this.clock.getPositionAt(time - offset);
  return this.getPositionFromClockPosition(position);
};

proto.getPositionFromClockPosition = function getPositionFromClockPosition (position) {
  checkValid.number('clockPosition', position);
  if (position < 0) {
    return '0.0.00';
  }
  var beatsPerLoop = this._loopLength * this._beatsPerBar;
  var loops = Math.floor(position / beatsPerLoop) || 0;
  position = position - (loops * beatsPerLoop);
  var bars = Math.floor(position / this._beatsPerBar);
  position = position - (bars * this._beatsPerBar);
  var beats = Math.floor(position);
  position = position - beats;
  var ticks = Math.floor(position * 96) + 1;
  if (ticks < 10) {
    ticks = '0' + ticks;
  }
  return (bars + 1) + '.' + (beats + 1) + '.' + ticks;
};

proto.getClockPositionFromPosition = memoize(function getClockPositionFromPosition (position, beatsPerBar) {
  var parts = position.split('.');
  var bars = parseInt(parts[0], 10) - 1;
  var beats = parseInt(parts[1], 10) - 1;
  var ticks = parseInt(parts[2], 10) - 1;
  return (bars * beatsPerBar) + beats + (ticks / 96);
});

proto.getPositionWithOffset = function getPositionWithOffset (position, offset) {
  return this.getPositionWithOffsetAndBeatsPerBar(position, offset, this.beatsPerBar());
};

proto.getPositionWithOffsetAndBeatsPerBar = memoize(function getPositionWithOffsetAndBeatsPerBar (position, offset, beatsPerBar) {
  if (!checkValid.positionString(position)) {
    throw new Error('Invalid argument: position is not a valid position string');
  }
  if (typeof offset !== 'number' || isNaN(offset) || offset % 1 !== 0) {
    throw new Error('Invalid argument: offset is not a valid number');
  }
  if (!offset) {
    return position;
  }
  var clockPosition = this.getClockPositionFromPosition(position, beatsPerBar);
  var clockOffset = offset / 96;
  return this.getPositionFromClockPosition(clockPosition + clockOffset);
}, function (position, offset) {
  return position + memoSpacer + offset;
});

proto.getDurationFromTicks = function getDurationFromTicks (ticks) {
  checkValid.positiveNumber('ticks', ticks);
  return (1 / 96) * ticks;
};

proto.emitStep = function emitStep (step) {
  var offset = step.offset = (this.clock._state.cycleLength * this.clock._state.preCycle) * 1;
  var note = step.args;
  step.time = step.time + offset;
  step.clockPosition = step.position;
  step.position = step.event === 'start' ? note.position : note.duration ?  this.getPositionWithOffsetAndBeatsPerBar(note.position, note.duration, this.beatsPerBar()) : note.position;
  if (step.event === 'stop'  && step.position === note.position) {
    return;
  }
  step.context = this.context;
  this.emit('step', step);
};

proto.notesForSet = memoize(function notesForSet (id, notes, beatsPerBar, loopLength) {

  var self = this;
  notes.forEach(function (note, index) {
    if (!Array.isArray(note) && typeof note === 'object' && !!note.position) {
      notes[index] = [note.position, note];
    }
  });

  notes = self.expressions(notes, {
    'beatsPerBar': beatsPerBar,
    'barsPerLoop': loopLength
  });

  var filtered = false;

  notes.forEach(function (note, index) {
    if (positionHelper.isPositionWithinBounds(note[0], loopLength, beatsPerBar)) {
      if (self.expandNote) {
        note = self.expandNote(note);
      }
      var normal = positionHelper.normalizeNote(note);
      notes[index] = [self.getClockPositionFromPosition(normal.position, beatsPerBar), self.getDurationFromTicks(normal.duration || 0), null, null, normal];
    }
    else {
      notes[index] = null;
      filtered = true;
    }
  });

  if (filtered) {
    return notes.filter(function (note) { return !!note; });
  }

  return notes;
}, function (id, notes, beatsPerBar, loopLength) {
  return id + memoSpacer + JSON.stringify(notes) + memoSpacer + beatsPerBar + memoSpacer + loopLength;
});

proto.set = function set (id, notes) {
  var self = this;
  if (typeof id !== 'string') {
    throw new Error('Invalid argument: id is not a valid string');
  }
  if (!notes || !Array.isArray(notes)) {
    throw new Error('Invalid argument: notes is not a valid array');
  }

  this.scheduler.set(id, this.notesForSet(id, notes, this.beatsPerBar(), this.loopLength()), this.beatsPerBar() * this.loopLength());
};

proto.get = function get (id) {
  if (typeof id !== 'string') {
    throw new Error('Invalid argument: id is not a valid string');
  }
  return (this.scheduler.get(id) || []).map(function (note) {
    return note[4];
  });
};

proto.channels = function channels () {
  return this.scheduler.getIds();
};

proto.clear = function clear (id) {
  var self = this;
  if (id) {
    if (typeof id !== 'string') {
      throw new Error('Invalid argument: id is not a valid string');
    }
    this.set(id, []);
  }
  else {
    this.scheduler.getIds().forEach(function (id) {
      self.clear(id);
    });
  }
};

proto._keepAlive = function _keepAlive () {
  if (this.clock._state.playing) {
    window.__lastDillaPosition = this._position;
    setTimeout(window.requestAnimationFrame.bind(null, this._keepAlive), 100);
  }
};

proto.start = function start () {
  var now = new Date().valueOf();
  var waited = now - loadTime;
  if (waited < this.upstartWait) {
    return setTimeout(start.bind(this), this.upstartWait - waited);
  }

  if (!this.clock._state.playing) {
    this.clock.start();
    this._keepAlive();
    this.emit('playing');
  }
};

proto.pause = function pause () {
  if (this.clock._state.playing) {
    this.clock.stop();
    this.emit('paused');
  }
};

proto.stop = function stop () {
  if (this.clock._state.playing) {
    this.clock.stop();
    this.emit('paused');
    this.clock.setPosition(0);
    this._position = '0.0.00';
  }
};

proto.position = function position () {
  return this._position;
};

proto.setPosition = function setPosition (position) {
  if (!positionHelper.isPositionWithinBounds(position, this.loopLength(), this.beatsPerBar())) {
    throw new Error('Invalid argument: position is not valid');
  }
  this._position = position;
  this.clock.setPosition(this.getClockPositionFromPosition(position, this.beatsPerBar()));
};

proto.tempo = function tempo () {
  return this.clock.getTempo();
};

proto.setTempo = function setTempo (tempo) {
  if (typeof tempo !== 'number' || tempo < 0 || isNaN(tempo)) {
    throw new Error('Invalid argument: tempo is not a valid number');
  }
  this.clock.setTempo(tempo);
};

proto.beatsPerBar = function beatsPerBar () {
  return this._beatsPerBar;
};

proto.setBeatsPerBar = function setBeatsPerBar (beats) {
  checkValid.positiveNumber('beats', beats);
  this._beatsPerBar = beats;
};

proto.loopLength = function loopLength () {
  return this._loopLength;
};

proto.setLoopLength = function setLoopLength (bars) {
  checkValid.positiveNumber('bars', bars);
  this._loopLength = bars;
};

module.exports = Dilla;
<commit_msg>adds a resolver<commit_after>var events = require('events');
var inherits = require('util').inherits;
var bopper = require('./vendor/bopper');
var ditty = require('./vendor/ditty');
var expr = require('dilla-expressions');
var memoize = require('meemo');

var checkValid = require('./lib/checkValid');
var positionHelper = require('./lib/positionHelper');

var loadTime = new Date().valueOf();

var memoSpacer = '//';

function Dilla (audioContext, options) {

  if (!(this instanceof Dilla)){
    return new Dilla(audioContext, options);
  }

  if (!audioContext || typeof audioContext !== 'object' || typeof audioContext.createScriptProcessor !== 'function') {
    throw new Error('Invalid arguments: cannot init without AudioContext');
  }

  events.EventEmitter.call(this);

  options = options || {};

  this.context = audioContext;
  this.clock = bopper(this.context);
  this.scheduler = ditty();

  this.expressions = expr;
  this.expandNote = options.expandNote;

  this.upstartWait = options.upstartWait || 250;
  this.setTempo(options.tempo || 120);
  this.setBeatsPerBar(options.beatsPerBar || 4);
  this.setLoopLength(options.loopLength || 2);

  this._position = '0.0.00';

  this.clock.on('data', this.updatePositionFromClock.bind(this));
  this.clock.pipe(this.scheduler).on('data', this.emitStep.bind(this));

  this._keepAlive = this._keepAlive.bind(this);
}

inherits(Dilla, events.EventEmitter);
var proto = Dilla.prototype;

proto.updatePositionFromClock = function updatePositionFromClock (step) {
  var position = this.getPositionFromTime(step.time);
  if (this._position !== position) {
    this._position = position;
    this.emit('tick', { 'position': this._position, 'context': this.context });
  }
};

proto.getPositionFromTime = function getPositionFromTime (time) {
  var offset = (this.clock._state.cycleLength * this.clock._state.preCycle) * 1;
  var position = this.clock.getPositionAt(time - offset);
  return this.getPositionFromClockPosition(position);
};

proto.getPositionFromClockPosition = function getPositionFromClockPosition (position) {
  checkValid.number('clockPosition', position);
  if (position < 0) {
    return '0.0.00';
  }
  var beatsPerLoop = this._loopLength * this._beatsPerBar;
  var loops = Math.floor(position / beatsPerLoop) || 0;
  position = position - (loops * beatsPerLoop);
  var bars = Math.floor(position / this._beatsPerBar);
  position = position - (bars * this._beatsPerBar);
  var beats = Math.floor(position);
  position = position - beats;
  var ticks = Math.floor(position * 96) + 1;
  if (ticks < 10) {
    ticks = '0' + ticks;
  }
  return (bars + 1) + '.' + (beats + 1) + '.' + ticks;
};

proto.getClockPositionFromPosition = memoize(function getClockPositionFromPosition (position, beatsPerBar) {
  var parts = position.split('.');
  var bars = parseInt(parts[0], 10) - 1;
  var beats = parseInt(parts[1], 10) - 1;
  var ticks = parseInt(parts[2], 10) - 1;
  return (bars * beatsPerBar) + beats + (ticks / 96);
}, function(position, beatsPerBar){
  return position + memoSpacer + beatsPerBar;
});

proto.getPositionWithOffset = function getPositionWithOffset (position, offset) {
  return this.getPositionWithOffsetAndBeatsPerBar(position, offset, this.beatsPerBar());
};

proto.getPositionWithOffsetAndBeatsPerBar = memoize(function getPositionWithOffsetAndBeatsPerBar (position, offset, beatsPerBar) {
  if (!checkValid.positionString(position)) {
    throw new Error('Invalid argument: position is not a valid position string');
  }
  if (typeof offset !== 'number' || isNaN(offset) || offset % 1 !== 0) {
    throw new Error('Invalid argument: offset is not a valid number');
  }
  if (!offset) {
    return position;
  }
  var clockPosition = this.getClockPositionFromPosition(position, beatsPerBar);
  var clockOffset = offset / 96;
  return this.getPositionFromClockPosition(clockPosition + clockOffset);
}, function (position, offset) {
  return position + memoSpacer + offset;
});

proto.getDurationFromTicks = function getDurationFromTicks (ticks) {
  checkValid.positiveNumber('ticks', ticks);
  return (1 / 96) * ticks;
};

proto.emitStep = function emitStep (step) {
  var offset = step.offset = (this.clock._state.cycleLength * this.clock._state.preCycle) * 1;
  var note = step.args;
  step.time = step.time + offset;
  step.clockPosition = step.position;
  step.position = step.event === 'start' ? note.position : note.duration ?  this.getPositionWithOffsetAndBeatsPerBar(note.position, note.duration, this.beatsPerBar()) : note.position;
  if (step.event === 'stop'  && step.position === note.position) {
    return;
  }
  step.context = this.context;
  this.emit('step', step);
};

proto.notesForSet = memoize(function notesForSet (id, notes, beatsPerBar, loopLength) {

  var self = this;
  notes.forEach(function (note, index) {
    if (!Array.isArray(note) && typeof note === 'object' && !!note.position) {
      notes[index] = [note.position, note];
    }
  });

  notes = self.expressions(notes, {
    'beatsPerBar': beatsPerBar,
    'barsPerLoop': loopLength
  });

  var filtered = false;

  notes.forEach(function (note, index) {
    if (positionHelper.isPositionWithinBounds(note[0], loopLength, beatsPerBar)) {
      if (self.expandNote) {
        note = self.expandNote(note);
      }
      var normal = positionHelper.normalizeNote(note);
      notes[index] = [self.getClockPositionFromPosition(normal.position, beatsPerBar), self.getDurationFromTicks(normal.duration || 0), null, null, normal];
    }
    else {
      notes[index] = null;
      filtered = true;
    }
  });

  if (filtered) {
    return notes.filter(function (note) { return !!note; });
  }

  return notes;
}, function (id, notes, beatsPerBar, loopLength) {
  return id + memoSpacer + JSON.stringify(notes) + memoSpacer + beatsPerBar + memoSpacer + loopLength;
});

proto.set = function set (id, notes) {
  var self = this;
  if (typeof id !== 'string') {
    throw new Error('Invalid argument: id is not a valid string');
  }
  if (!notes || !Array.isArray(notes)) {
    throw new Error('Invalid argument: notes is not a valid array');
  }

  this.scheduler.set(id, this.notesForSet(id, notes, this.beatsPerBar(), this.loopLength()), this.beatsPerBar() * this.loopLength());
};

proto.get = function get (id) {
  if (typeof id !== 'string') {
    throw new Error('Invalid argument: id is not a valid string');
  }
  return (this.scheduler.get(id) || []).map(function (note) {
    return note[4];
  });
};

proto.channels = function channels () {
  return this.scheduler.getIds();
};

proto.clear = function clear (id) {
  var self = this;
  if (id) {
    if (typeof id !== 'string') {
      throw new Error('Invalid argument: id is not a valid string');
    }
    this.set(id, []);
  }
  else {
    this.scheduler.getIds().forEach(function (id) {
      self.clear(id);
    });
  }
};

proto._keepAlive = function _keepAlive () {
  if (this.clock._state.playing) {
    window.__lastDillaPosition = this._position;
    setTimeout(window.requestAnimationFrame.bind(null, this._keepAlive), 100);
  }
};

proto.start = function start () {
  var now = new Date().valueOf();
  var waited = now - loadTime;
  if (waited < this.upstartWait) {
    return setTimeout(start.bind(this), this.upstartWait - waited);
  }

  if (!this.clock._state.playing) {
    this.clock.start();
    this._keepAlive();
    this.emit('playing');
  }
};

proto.pause = function pause () {
  if (this.clock._state.playing) {
    this.clock.stop();
    this.emit('paused');
  }
};

proto.stop = function stop () {
  if (this.clock._state.playing) {
    this.clock.stop();
    this.emit('paused');
    this.clock.setPosition(0);
    this._position = '0.0.00';
  }
};

proto.position = function position () {
  return this._position;
};

proto.setPosition = function setPosition (position) {
  if (!positionHelper.isPositionWithinBounds(position, this.loopLength(), this.beatsPerBar())) {
    throw new Error('Invalid argument: position is not valid');
  }
  this._position = position;
  this.clock.setPosition(this.getClockPositionFromPosition(position, this.beatsPerBar()));
};

proto.tempo = function tempo () {
  return this.clock.getTempo();
};

proto.setTempo = function setTempo (tempo) {
  if (typeof tempo !== 'number' || tempo < 0 || isNaN(tempo)) {
    throw new Error('Invalid argument: tempo is not a valid number');
  }
  this.clock.setTempo(tempo);
};

proto.beatsPerBar = function beatsPerBar () {
  return this._beatsPerBar;
};

proto.setBeatsPerBar = function setBeatsPerBar (beats) {
  checkValid.positiveNumber('beats', beats);
  this._beatsPerBar = beats;
};

proto.loopLength = function loopLength () {
  return this._loopLength;
};

proto.setLoopLength = function setLoopLength (bars) {
  checkValid.positiveNumber('bars', bars);
  this._loopLength = bars;
};

module.exports = Dilla;
<|endoftext|>


<commit_before>var yargs = require('yargs');
var fs    = require('fs');
var http  = require('http');
var debug = require('debug')('word-counter:index');
var client_parse = require('./lib/client_parse.js');

var argv = yargs
    .option('c', {
      alias: 'client',
      type: 'array'
    })
    .option('s', {
      alias: 'search',
      type: 'string'
    })
    .option('f', {
      alias: 'file',
      type: 'string'
    })
    .argv;

var
  clients = argv.client,
  search = argv.search,
  filename = argv.file,
  fileArray = [],
  countArray = 0,
  ocurrences = 0,
  options = {
    host: 'localhost',
    port: 5050,
    method: 'POST',
    path: '/',
    headers: {
      'Content-Type': 'application/json'
    }
  },
  request = null;

// Lê o arquivo
fs.readFile(filename, 'utf8', function(err, data) {
  if (err) throw err;
  // Separa o arquivo em pedaços e guarda no array `fileArray`
  fileArray = data.match(/([^\s]+\s\s*){1,200}/g);

  mountOptions();
});

// Monta as opções de cada client para enviar
function mountOptions() {
  for (var i = 0; i < clients.length; i++) {
    var client = clients[i];
    var postData = getPostData();
    countArray++;

    if (postData) {
      sendRequest(client, postData);
    } else {
      debug('End of file reached');
    }
  }
};

function getPostData() {
  if(countArray < fileArray.length) {
    return JSON.stringify({
      'content': fileArray[countArray],
      'search': search
    });
  } else {
    return false;
  }
};

// Envia para o cliente um pedaço do texto e a palavra a ser buscada (Start dos requests)
function sendRequest(client, postData) {
  if(countArray <= fileArray.length) {
    var options = client_parse(client);
    var request = http.request(options, process_client.bind(null, client));

    request.on('error', function(e) {
      debug('Error processing request: ' + e.message);
    });

    request.write(postData);

    request.end();
  }
};

function process_client(client, res) {
  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    var chunk = JSON.parse(chunk);
    debug('Client "%s" responded with %o', client, chunk);
    var searchReturned = chunk.search;
    var ocurrencesReturned = chunk.ocurrences;

    ocurrences += ocurrencesReturned;

    if(countArray < fileArray.length) {
      var postData = getPostData();
      countArray++;

      if (postData) {
        sendRequest(client, postData);
      } else {
        debug('End of file reached');
      }
    } else {
      debug('Found %d ocurrences of "%s" on file %s.', ocurrences, search, filename);
    }
  });
};
<commit_msg>The final output is to print on console always<commit_after>var yargs = require('yargs');
var fs    = require('fs');
var http  = require('http');
var debug = require('debug')('word-counter:index');
var client_parse = require('./lib/client_parse.js');

var argv = yargs
    .option('c', {
      alias: 'client',
      type: 'array'
    })
    .option('s', {
      alias: 'search',
      type: 'string'
    })
    .option('f', {
      alias: 'file',
      type: 'string'
    })
    .argv;

var
  clients = argv.client,
  search = argv.search,
  filename = argv.file,
  fileArray = [],
  countArray = 0,
  ocurrences = 0,
  options = {
    host: 'localhost',
    port: 5050,
    method: 'POST',
    path: '/',
    headers: {
      'Content-Type': 'application/json'
    }
  },
  request = null;

// Lê o arquivo
fs.readFile(filename, 'utf8', function(err, data) {
  if (err) throw err;
  // Separa o arquivo em pedaços e guarda no array `fileArray`
  fileArray = data.match(/([^\s]+\s\s*){1,200}/g);

  mountOptions();
});

// Monta as opções de cada client para enviar
function mountOptions() {
  for (var i = 0; i < clients.length; i++) {
    var client = clients[i];
    var postData = getPostData();
    countArray++;

    if (postData) {
      sendRequest(client, postData);
    } else {
      debug('End of file reached');
    }
  }
};

function getPostData() {
  if(countArray < fileArray.length) {
    return JSON.stringify({
      'content': fileArray[countArray],
      'search': search
    });
  } else {
    return false;
  }
};

// Envia para o cliente um pedaço do texto e a palavra a ser buscada (Start dos requests)
function sendRequest(client, postData) {
  if(countArray <= fileArray.length) {
    var options = client_parse(client);
    var request = http.request(options, process_client.bind(null, client));

    request.on('error', function(e) {
      debug('Error processing request: ' + e.message);
    });

    request.write(postData);

    request.end();
  }
};

function process_client(client, res) {
  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    var chunk = JSON.parse(chunk);
    debug('Client "%s" responded with %o', client, chunk);
    var searchReturned = chunk.search;
    var ocurrencesReturned = chunk.ocurrences;

    ocurrences += ocurrencesReturned;

    if(countArray < fileArray.length) {
      var postData = getPostData();
      countArray++;

      if (postData) {
        sendRequest(client, postData);
      } else {
        debug('End of file reached');
      }
    } else {
      console.log('Found %d ocurrences of "%s" on file %s.', ocurrences, search, filename);
    }
  });
};
<|endoftext|>


<commit_before>const BN = require('bn.js')
const fs = require('fs')
const cp = require('child_process')
const opcodes = require('./opcodes.js')

// map to track dependant WASM functions
const depMap = new Map([
  ['MOD', ['ISZERO_32', 'GTE']],
  ['SDIV', ['ISZERO_32', 'GTE']],
  ['SMOD', ['ISZERO_32', 'GTE']],
  ['DIV', ['ISZERO_32', 'GTE']],
  ['EXP', ['ISZERO_32', 'MUL_256']],
  ['MUL', ['MUL_256']]
])

exports.compile = function (evmCode) {
  const wast = exports.compileEVM(evmCode)
  return exports.compileWAST(wast)
}

exports.compileWAST = function (wast) {
  fs.writeFileSync('temp.wast', wast)
  cp.execSync(`${__dirname}/deps/sexpr-wasm-prototype/out/sexpr-wasm ./temp.wast -o ./temp.wasm`)
  return fs.readFileSync('./temp.wasm')
}

// compile segments
exports.compileEVM = function (evmCode) {
  const opcodesUsed = new Set()
  const opcodesIgnore = new Set(['JUMP', 'JUMPI', 'JUMPDEST', 'STOP'])
  const initCode = '(get_local $sp)'
  let wasmCode = initCode
  let opcodeCount = 0
  const segments = []
  let segNumber = 0
  let gasCount = 0

  for (let i = 0; i < evmCode.length; i++) {
    const op = opcodes(evmCode[i])
    gasCount += op.fee
    let bytes
    switch (op.name) {
      case 'JUMP':
        wasmCode = `(set_local $sp ${wasmCode})
                    (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))
                    (set_local $jump_dest (i64.load (get_local $sp)))
                    (br $loop)`
        break
      case 'JUMPI':
        wasmCode = `(set_local $sp ${wasmCode})
                    (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))
                    (set_local $jump_dest (i64.load (get_local $sp)))
                    (br_if $loop (i64.load (get_local $sp)))`
        break
      case 'JUMPDEST':
        addSegement()
        segNumber = i
        wasmCode = initCode
        break
      case 'LOG':
        bytes = evmCode.slice(i, i + op.number * 8)
        for (let i = 0; i < bytes.length; i += 8) {
          const int64 = bytes2int64(bytes.slice(i, i + 8))
          wasmCode = `(i64.const ${int64})` + wasmCode
        }
        i += op.number
        break
      case 'PUSH':
        i++
        bytes = evmCode.slice(i, i + op.number)
        let q = 0
        for (; q < bytes.length; q += 8) {
          const int64 = bytes2int64(bytes.slice(q, q + 8))
          wasmCode = `(i64.const ${int64})` + wasmCode
        }
        // padd the remaining of the word with 0
        for (; q < 32; q += 8) {
          wasmCode = '(i64.const 0)' + wasmCode
        }
        i += op.number - 1
        break
      case 'DUP':
        // adds the number on the stack to DUP
        wasmCode = `(i64.const ${op.number})` + wasmCode
        break
      case 'SWAP':
        // adds the number on the stack to SWAP
        wasmCode = `(i64.const ${op.number})` + wasmCode
        break
      case 'STOP':
        wasmCode = `${wasmCode} (br $done)`
        break
    }
    if (!opcodesIgnore.has(op.name)) {
      wasmCode = `(call $${op.name} ${wasmCode})`
      opcodesUsed.add(op.name)
    }
    opcodeCount++
  }
  if (wasmCode !== '') {
    addSegement()
  }
  const mainFunc = '(export "main" $main)' + assmebleSegments(segments)
  const funcMap = exports.resolveFunctions(opcodesUsed)
  funcMap.push(mainFunc)
  return exports.buildModule(funcMap)

  function addSegement (){
    wasmCode = `(call_import $useGas (i32.const ${gasCount})) ${wasmCode}`
    segments.push([wasmCode, segNumber])
  }
}

function assmebleSegments (segments) {
  let wasm = buildJumpMap(segments)

  segments.forEach((seg, index) => {
    wasm = `(block $${index + 1}
             ${wasm}
             ${seg[0]})`
  })
  return `(func $main
           (local $sp i32)
           (local $jump_dest i64)
           (loop $done $loop
            ${wasm}))`
}

function buildJumpMap (segments) {
  let wasm = '(unreachable)'
  let brTable = '(block $0 (br_table'

  segments.forEach((seg, index) => {
    brTable += ' $' + index
    wasm = `(if (i64.eq (get_local $jump_dest) (i64.const ${seg[1]}))
                (then (i32.const ${index}))
                (else ${wasm}))`
  })

  brTable += wasm + '))'
  return brTable
}

// converts 8 bytes into a int 64
function bytes2int64 (bytes) {
  return new BN(bytes).fromTwos(64).toString()
}

exports.resolveFunctions = function resolveFunctions (funcSet, dir = '/wasm/') {
  let funcs = []
  for (let func of funcSet) {
    const wastPath = __dirname + dir + func + '.wast'
    const wast = fs.readFileSync(wastPath)
    funcs.push(wast.toString())
    const depFuncs = depMap.get(func)
    if (depFuncs) {
      funcs = funcs.concat(resolveFunctions(depFuncs, dir))
    }
  }
  return funcs
}

exports.buildModule = function buildModule (funcs, imports=[], exports=[]) {
  let funcStr = ''
  for (let func of funcs) {
    funcStr += func
  }
  for (let exprt of exports) {
    funcStr += `(export "${exprt}" $${exprt})`
  }
  return `(module
          (import $sstore  "ethereum" "sstore"  (param i32 i32))
          (import $useGas  "ethereum" "useGas"  (param i32))
          (memory 1 1)
          (export "a" memory)
           ${funcStr}
          )`
}

// remap code hashes
// pull original code; if code is not wasm try to convert it. Transpiler will
// need to be written in wasm
// TRADE OFF
//  if you have polifilly
//
// transcompiling create code; can be done at runtime.
// how to store old code? just use prefix
// store the old code in mem storage.
//  how to protect?
//   use a longer or shorter path then the current contracts have access to
//   transcompiler contract
//    which then get the code and run its
//    extra cost first time calling it
<commit_msg>Ensure that dependencies are only imported once<commit_after>const BN = require('bn.js')
const fs = require('fs')
const cp = require('child_process')
const opcodes = require('./opcodes.js')

// map to track dependant WASM functions
const depMap = new Map([
  ['MOD', ['ISZERO_32', 'GTE']],
  ['SDIV', ['ISZERO_32', 'GTE']],
  ['SMOD', ['ISZERO_32', 'GTE']],
  ['DIV', ['ISZERO_32', 'GTE']],
  ['EXP', ['ISZERO_32', 'MUL_256']],
  ['MUL', ['MUL_256']]
])

exports.compile = function (evmCode) {
  const wast = exports.compileEVM(evmCode)
  return exports.compileWAST(wast)
}

exports.compileWAST = function (wast) {
  fs.writeFileSync('temp.wast', wast)
  cp.execSync(`${__dirname}/deps/sexpr-wasm-prototype/out/sexpr-wasm ./temp.wast -o ./temp.wasm`)
  return fs.readFileSync('./temp.wasm')
}

// compile segments
exports.compileEVM = function (evmCode) {
  const opcodesUsed = new Set()
  const opcodesIgnore = new Set(['JUMP', 'JUMPI', 'JUMPDEST', 'STOP'])
  const initCode = '(get_local $sp)'
  let wasmCode = initCode
  let opcodeCount = 0
  const segments = []
  let segNumber = 0
  let gasCount = 0

  for (let i = 0; i < evmCode.length; i++) {
    const op = opcodes(evmCode[i])
    gasCount += op.fee
    let bytes
    switch (op.name) {
      case 'JUMP':
        wasmCode = `(set_local $sp ${wasmCode})
                    (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))
                    (set_local $jump_dest (i64.load (get_local $sp)))
                    (br $loop)`
        break
      case 'JUMPI':
        wasmCode = `(set_local $sp ${wasmCode})
                    (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))
                    (set_local $jump_dest (i64.load (get_local $sp)))
                    (br_if $loop (i64.load (get_local $sp)))`
        break
      case 'JUMPDEST':
        addSegement()
        segNumber = i
        wasmCode = initCode
        break
      case 'LOG':
        bytes = evmCode.slice(i, i + op.number * 8)
        for (let i = 0; i < bytes.length; i += 8) {
          const int64 = bytes2int64(bytes.slice(i, i + 8))
          wasmCode = `(i64.const ${int64})` + wasmCode
        }
        i += op.number
        break
      case 'PUSH':
        i++
        bytes = evmCode.slice(i, i + op.number)
        let q = 0
        for (; q < bytes.length; q += 8) {
          const int64 = bytes2int64(bytes.slice(q, q + 8))
          wasmCode = `(i64.const ${int64})` + wasmCode
        }
        // padd the remaining of the word with 0
        for (; q < 32; q += 8) {
          wasmCode = '(i64.const 0)' + wasmCode
        }
        i += op.number - 1
        break
      case 'DUP':
        // adds the number on the stack to DUP
        wasmCode = `(i64.const ${op.number})` + wasmCode
        break
      case 'SWAP':
        // adds the number on the stack to SWAP
        wasmCode = `(i64.const ${op.number})` + wasmCode
        break
      case 'STOP':
        wasmCode = `${wasmCode} (br $done)`
        break
    }
    if (!opcodesIgnore.has(op.name)) {
      wasmCode = `(call $${op.name} ${wasmCode})`
      opcodesUsed.add(op.name)
    }
    opcodeCount++
  }
  if (wasmCode !== '') {
    addSegement()
  }
  const mainFunc = '(export "main" $main)' + assmebleSegments(segments)
  const funcMap = exports.resolveFunctions(opcodesUsed)
  funcMap.push(mainFunc)
  return exports.buildModule(funcMap)

  function addSegement (){
    wasmCode = `(call_import $useGas (i32.const ${gasCount})) ${wasmCode}`
    segments.push([wasmCode, segNumber])
  }
}

function assmebleSegments (segments) {
  let wasm = buildJumpMap(segments)

  segments.forEach((seg, index) => {
    wasm = `(block $${index + 1}
             ${wasm}
             ${seg[0]})`
  })
  return `(func $main
           (local $sp i32)
           (local $jump_dest i64)
           (loop $done $loop
            ${wasm}))`
}

function buildJumpMap (segments) {
  let wasm = '(unreachable)'
  let brTable = '(block $0 (br_table'

  segments.forEach((seg, index) => {
    brTable += ' $' + index
    wasm = `(if (i64.eq (get_local $jump_dest) (i64.const ${seg[1]}))
                (then (i32.const ${index}))
                (else ${wasm}))`
  })

  brTable += wasm + '))'
  return brTable
}

// converts 8 bytes into a int 64
function bytes2int64 (bytes) {
  return new BN(bytes).fromTwos(64).toString()
}

// Ensure that dependencies are only imported once (use the Set)
exports.resolveFunctionDeps = function resolveFunctionDeps (funcSet) {
  let funcs = funcSet
  for (let func of funcSet) {
    const deps = depMap.get(func)
    if (deps) {
      for (var dep of deps) {
        funcs.add(dep)
      }
    }
  }
  return funcs
}

exports.resolveFunctions = function resolveFunctions (funcSet, dir='/wasm/') {
  let funcs = []
  for (let func of exports.resolveFunctionDeps(funcSet)) {
    const wastPath = __dirname + dir + func + '.wast'
    const wast = fs.readFileSync(wastPath)
    funcs.push(wast.toString())
  }
  return funcs
}

exports.buildModule = function buildModule (funcs, imports=[], exports=[]) {
  let funcStr = ''
  for (let func of funcs) {
    funcStr += func
  }
  for (let exprt of exports) {
    funcStr += `(export "${exprt}" $${exprt})`
  }
  return `(module
          (import $sstore  "ethereum" "sstore"  (param i32 i32))
          (import $useGas  "ethereum" "useGas"  (param i32))
          (memory 1 1)
          (export "a" memory)
           ${funcStr}
          )`
}

// remap code hashes
// pull original code; if code is not wasm try to convert it. Transpiler will
// need to be written in wasm
// TRADE OFF
//  if you have polifilly
//
// transcompiling create code; can be done at runtime.
// how to store old code? just use prefix
// store the old code in mem storage.
//  how to protect?
//   use a longer or shorter path then the current contracts have access to
//   transcompiler contract
//    which then get the code and run its
//    extra cost first time calling it
<|endoftext|>


<commit_before>var debug = require('debug')('oa-graphs')
var inherits = require('inherits');
var Map = require('es6-map');

var Graph = require('oa-graph');

function Graphs (options) {
  options = options || {};
  debug("constructor", options);
  // call new constructor if not already
  if (!(this instanceof Graphs)) {
    return new Graphs(options);
  }

  // call Map constructor on this
  Map.call(this);

  // setup graph db
  var level = options.db;
  delete options.db;

  this.db = require('levelgraph-jsonld')(
    require('levelgraph')(level, options)
  , options);

  // setup type registry
  if (options.types) {
    this.types = options.types;
  } else {
    this.types = require('oa-types')();
  }

  // use any given graphs
  if (options.graphs) {
    for (var id in options.graphs) {
      debug("use-ing", options.graphs[id]);
      this.use(options.graphs[id]);
    }
  }
}
inherits(Graphs, Map);

Graphs.prototype.use = function (graph) {
  debug("use", graph);

  // if not instanceof Graph, assume it is type
  if (!(graph instanceof Graph)) {
    graph = new Graph({
      db: graph.db || this.db,
      types: graph.types || this.types,
      type: graph.type,
      id: graph.id,
    });
  }

  debug("set", graph.id, graph);
  this.set(graph.id, graph);

  return graph;
};

module.exports = Graphs;
<commit_msg>add graphs property<commit_after>var debug = require('debug')('oa-graphs')
var inherits = require('inherits');
var Map = require('es6-map');

var Graph = require('oa-graph');

function Graphs (options) {
  options = options || {};
  debug("constructor", options);
  // call new constructor if not already
  if (!(this instanceof Graphs)) {
    return new Graphs(options);
  }

  // call Map constructor on this
  Map.call(this);

  // setup graph db
  var level = options.db;
  delete options.db;

  this.db = require('levelgraph-jsonld')(
    require('levelgraph')(level, options)
  , options);

  // setup type registry
  if (options.types) {
    this.types = options.types;
  } else {
    this.types = require('oa-types')();
  }

  // use any given graphs
  if (options.graphs) {
    for (var id in options.graphs) {
      debug("use-ing", options.graphs[id]);
      this.use(options.graphs[id]);
    }
  }
}
inherits(Graphs, Map);

Graphs.prototype.use = function (graph) {
  debug("use", graph);

  // if not instanceof Graph, assume it is type
  if (!(graph instanceof Graph)) {
    graph = new Graph({
      db: graph.db || this.db,
      types: graph.types || this.types,
      type: graph.type,
      id: graph.id,
      graphs: this,
    });
  }

  debug("set", graph.id, graph);
  this.set(graph.id, graph);

  return graph;
};

module.exports = Graphs;
<|endoftext|>


<commit_before>// NOTES

class PaymentAddress {
  constructor(
    country,
    addressLine,
    region=null,
    city=null,
    dependentLocality=null,
    postalCode=null,
    sortingCode=null,
    languageCode=null,
    organization=null,
    recipient=null,
    phone=null,
  ) {
    this.country = country;
    this.addressLine = addressLine;
    this.region = region;
    this.city = city;
    this.dependentLocality = dependentLocality;
    this.postalCode = postalCode;
    this.sortingCode = sortingCode;
    this.languageCode = languageCode;
    this.organization = organization;
    this.recipient = recipient;
    this.phone = phone;
  }

  static get country() {
    return this.country;
  }
  static set country(value) {
    throw new DOMException('The country property is read-only');
  }

  static get addressLine() {
    return this.addressLine;
  }
  static set addressLine(value) {
    throw new DOMException('The addressLine property is read-only');
  }

  static get region() {
    return this.region;
  }
  static set region(value) {
    throw new DOMException('The region property is read-only');
  }

  static get city() {
    return this.city;
  }
  static set city(value) {
    throw new DOMException('The city property is read-only');
  }

  static get dependentLocality() {
    return this.dependentLocality;
  }
  static set dependentLocality(value) {
    throw new DOMException('The dependentLocality property is read-only');
  }

  static get postalCode() {
    return this.postalCode;
  }
  static set postalCode(value) {
    throw new DOMException('The postalCode property is read-only');
  }

  static get sortingCode() {
    return this.sortingCode;
  }
  static set sortingCode(value) {
    throw new DOMException('The sortingCode property is read-only');
  }

  static get languageCode() {
    return this.languageCode;
  }
  static set languageCode(value) {
    throw new DOMException('The languageCode property is read-only');
  }

  static get organization() {
    return this.organization;
  }
  static set organization(value) {
    throw new DOMException('The organization property is read-only');
  }

  static get recipient() {
    return this.recipient;
  }
  static set recipient(value) {
    throw new DOMException('The recipient property is read-only');
  }

  static get phone() {
    return this.phone;
  }
  static set phone(value) {
    throw new DOMException('The phone property is read-only');
  }
}

const PaymentShippingType = {
  SHIPPING: Symbol('shipping'),
  DELIVERY: Symbol('delivery'),
  PICKUP: Symbol('pickup'),
};

const PaymentRequestState = {
  CREATED: Symbol('created'),
  INTERACTIVE: Symbol('interactive'),
  CLOSED: Symbol('closed'),
};

class PaymentRequest {

  constructor(
    methodData,
    details,
    options,
  ) {
    // 1. If a paymentRequestId was not provided during construction, generate
    //    a paymentRequestId.
    this.id = this.details['id'] || 'dummy_payment_request_id';

    // 2. If the current settings object's responsible document is not allowed
    //    to use the feature indicated by attribute name allowpaymentrequest,
    //    then throw a "SecurityError" DOMException.

    // 3. Let serializedMethodData be an empty list.
    let serializedMethodData = [];

    // 4. Process payment methods:

    //    4.1 If the length of the methodData sequence is zero, then throw a
    //        TypeError, optionally informing the developer that at least one
    //        payment method is required.
    if (!Array.isArray(methodData) || methodData.length == 0) {
      throw new TypeError('methodData is a required parameter');
    }

    //    4.2 For each paymentMethod of methodData:
    methodData.forEach((paymentMethod) => {

      //    4.2.1 If the length of the paymentMethod.supportedMethods sequence
      //          is zero, then throw a TypeError, optionally informing the
      //          developer that each payment method needs to include at least
      //          one payment method identifier.
      if (!Array.isArray(paymentMethod.supportedMethods) ||
        paymentMethod.supportedMethods.length == 0) {
        throw new TypeError('each payment method needs to include at least '+
          'one payment method identifier');
      }

      //    4.2.2 Let serializedData be the result of JSON-serializing
      //          paymentMethod.data into a string, if the data member of
      //          paymentMethod is present, or null if it is not. Rethrow any
      //          exceptions.
      if (paymentMethod.data) {
        let serializedData = JSON.stringify(paymentMethod.data)
      }

      //    4.2.3 Add the tuple (paymentMethod.supportedMethods,
      //          serializedData) to serializedMethodData.
      serializedMethodData.push_back({
        supportedMethods: paymentMethod.supportedMethods,
        serializedData: serializedData,
      })

      // 5. Process the total:

      //   5.1 If the total member of details is not present, then throw a
      //       TypeError, optionally informing the developer that including
      //       total is required.
      if (!details) {
        throw new TypeError('details is a required parameter');
      }
      if (!details.total) {
        throw new TypeError('details must have a total');
      }

      //   5.2 If details.total.amount.value is not a valid decimal monetary
      //       value, then throw a TypeError; optionally informing the
      //       developer that the value is invalid.
      if (!details.total.amount) {
        throw new TypeError('details.total must have an amount');
      }
      if (!details.total.amount.value ||
        !details.total.amount.value.match(/^-?[0-9]+(\.[0-9]+)?$/)) {
        throw new TypeError('details.total.value must be a valid decimal '+
          'monetary value');
      }

      //   5.3 If the first character of details.total.amount.value is U+002D
      //       HYPHEN-MINUS, then throw a TypeError, optionally informing the
      //       developer that the total can't be negative.
      if (details.total.amount[0] === '-') {
        throw new TypeError('details.total.value cannot be negative');
      }

      // TODO(stan): what about the currency? at least a regexp?

      // 6. If the displayItems member of details is present, then for each
      //    item in details.displayItems:
      if (Array.isArray(details.displayItems)) {
        details.displayItems.forEach((displayItem) => {

          // 6.1 If item.amount.value is not a valid decimal monetary value,
          //     then throw a TypeError, optionally informing the developer
          //     that the value is invalid.
          if (!displayItem.amount) {
            throw new TypeError('displayItem must have an amount');
          }
          if (!displayItem.amount.value ||
            !displayItem.amount.match(/^-?[0-9]+(\.[0-9]+)?$/)) {
            throw new TypeError('displayItem.amount.value is not a valid '+
              'decimal monetary value');
          }

          // TODO(stan): what about the currency? at least a regexp?
        })
      }

      // 7. Let selectedShippingOption be null.
      let selectedShippingOption = null;

      // 8. Process shipping options:

      //   8.1 Let options be an empty sequence<PaymentShippingOption>.
      let shippingOptions = []

      // TODO(stan): rename options -> shippingOptions

      //   8.2 If the shippingOptions member of details is present, then:
      if (Array.isArray(details.shippingOptions)) {

        //   8.2.1 Let seenIDs be an empty list.
        let seenIDs = [];

        //   8.2.2 Set options to details.shippingOptions.
        shippingOptions = details.shippingOptions

        //   8.2.3 For each option in options:
        shippingOptions.forEach((option) => {

          //   8.2.3.1 If option.amount.value is not a valid decimal monetary
          //           value, then throw a TypeError, optionally informing the
          //           developer that the value is invalid.
          if (!option.amount) {
            throw new TypeError('shippingOption must have an amount');
          }
          if (!option.amount.value ||
            !option.amount.value.match(/^-?[0-9]+(\.[0-9]+)?$/)) {
            throw new TypeError('shippingOption.amount.value is not a valid '+
              'decimal monetary value');
          }

          //   8.2.3.2 If seenIDs contains option.id, then set options to an
          //           empty sequence and break.
          if (seenIDs.includes(option.id)) {
            shippingOptions = [];
            break;
          }

          //   8.2.3.3 Append option.id to seenIDs.
          shippingOptions.push_back(option);
        });

        //   8.2.4 For each option in options (which may have been reset to the
        //         empty sequence in the previous step):
        shippingOptions.forEach((option) => {

          //   8.2.4.1 If option.selected is true, then set
          //           selectedShippingOption to option.id.
          if (option.selected) {
            selectedShippingOption = option.id;
          }
        })

      }

      //   8.3 Set details.shippingOptions to options.
      details.shippingOptions = shippingOptions;

      // 9. Let serializedModifierData be an empty list.
      let serializedModifierData = [];

      // 10. Process payment details modifiers:

      // TODO(stan)

      // 11. If the error member of details is present, then throw a TypeError,
      //     optionally informing the developer that an error message cannot be
      //     specified in the constructor.
      if (details.error) {
        throw new TypeError('details.error cannot be set at construction');
      }
    });

    // 12. Let request be a new PaymentRequest.
    // NOOP

    // 13. Set request.[[options]] to options.
    this.options = options;

    // 14. Set request.[[state]] to "created".
    this.state = PaymentRequestState.CREATED;

    // 15. Set request.[[state]] to "created".
    this.updating = false;

    // 16. Set request.[[details]] to details.
    this.details = details;

    // 17. Set request.[[serializedModifierData]] to serializedModifierData.
    this.serializedModifierData = serializedModifierData;

    // 18. Set request.[[serializedMethodData]] to serializedMethodData.
    this.serializedMethodData = serializedMethodData;

    // 19. Set the value of request's shippingOption attribute to
    //     selectedShippingOption.
    this.shippingOption = selectedShippingOption

    // 20. Set the value of the shippingAddress attribute on request to null.
    this.shippingAddress = null;

    // 21. Set the value of the shippingType attribute on request to null.
    this.shippingType = null;

    // 22. If options.requestShipping is set to true, then set the value of the
    //     shippingType attribute on request to options.shippingType. If
    //     options.shippingType is not a valid PaymentShippingType value then
    //     set the value of the shippingType attribute on request to
    //     "shipping".
    if (options.requestShipping) {
      switch (options.shippingType) {
        case 'shipping':
          this.shippingType = PaymentShippingType.SHIPPING;
          break;
        case 'delivery':
          this.shippingType = PaymentShippingType.DELIVERY;
          break;
        case 'pickup':
          this.shippingType = PaymentShippingType.PICKUP;
          break;
        default:
          this.shippingType = PaymentShippingType.SHIPPING;
          break;
      }
    }

    // Other internal state.
    this.acceptPromise = null;
    this.onshippingaddresschange = []
    this.onshippingoptionchange = []
  }

  static get id() {
    return 'foo';
  }
  static set id(value) {
    throw new DOMException('The id property is read-only');
  }

  static get shippingAddress() {
    return this.shippintAddress;
  }
  static set shippintAddress(value) {
    throw new DOMException('The shippingAddress property is read-only');
  }

  static get shippingOption() {
    return this.shippintOption;
  }
  static set shippintOption(value) {
    throw new DOMException('The shippingOption property is read-only');
  }

  static get shippingType() {
    return this.shippintType;
  }
  static set shippintType(value) {
    throw new DOMException('The shippingType property is read-only');
  }

  addEventListener(event, handler) {
    switch(event) {
      case 'shippingaddresschange':
        this.onshippingaddresschange.push_back(handler);
        break;
      case 'shippingoptionchange':
        this.onshippingoptionchange.push_back(handler);
        break;
    }
  }

  show() {
    this.acceptPromise = new Promise((resolve, reject) => {
      this.showResolve = resolve;
      this.showReject = reject;
    });
    // TODO show something
    return this.acceptPromise;
  }
}
<commit_msg>Typo fix<commit_after>class PaymentAddress {
  constructor(
    country,
    addressLine,
    region=null,
    city=null,
    dependentLocality=null,
    postalCode=null,
    sortingCode=null,
    languageCode=null,
    organization=null,
    recipient=null,
    phone=null,
  ) {
    this.country = country;
    this.addressLine = addressLine;
    this.region = region;
    this.city = city;
    this.dependentLocality = dependentLocality;
    this.postalCode = postalCode;
    this.sortingCode = sortingCode;
    this.languageCode = languageCode;
    this.organization = organization;
    this.recipient = recipient;
    this.phone = phone;
  }

  static get country() {
    return this.country;
  }
  static set country(value) {
    throw new DOMException('The country property is read-only');
  }

  static get addressLine() {
    return this.addressLine;
  }
  static set addressLine(value) {
    throw new DOMException('The addressLine property is read-only');
  }

  static get region() {
    return this.region;
  }
  static set region(value) {
    throw new DOMException('The region property is read-only');
  }

  static get city() {
    return this.city;
  }
  static set city(value) {
    throw new DOMException('The city property is read-only');
  }

  static get dependentLocality() {
    return this.dependentLocality;
  }
  static set dependentLocality(value) {
    throw new DOMException('The dependentLocality property is read-only');
  }

  static get postalCode() {
    return this.postalCode;
  }
  static set postalCode(value) {
    throw new DOMException('The postalCode property is read-only');
  }

  static get sortingCode() {
    return this.sortingCode;
  }
  static set sortingCode(value) {
    throw new DOMException('The sortingCode property is read-only');
  }

  static get languageCode() {
    return this.languageCode;
  }
  static set languageCode(value) {
    throw new DOMException('The languageCode property is read-only');
  }

  static get organization() {
    return this.organization;
  }
  static set organization(value) {
    throw new DOMException('The organization property is read-only');
  }

  static get recipient() {
    return this.recipient;
  }
  static set recipient(value) {
    throw new DOMException('The recipient property is read-only');
  }

  static get phone() {
    return this.phone;
  }
  static set phone(value) {
    throw new DOMException('The phone property is read-only');
  }
}

const PaymentShippingType = {
  SHIPPING: Symbol('shipping'),
  DELIVERY: Symbol('delivery'),
  PICKUP: Symbol('pickup'),
};

const PaymentRequestState = {
  CREATED: Symbol('created'),
  INTERACTIVE: Symbol('interactive'),
  CLOSED: Symbol('closed'),
};

class PaymentRequest {

  constructor(
    methodData,
    details,
    options,
  ) {
    // 1. If a paymentRequestId was not provided during construction, generate
    //    a paymentRequestId.
    let id = details['id'] || 'dummy_payment_request_id';

    // 2. If the current settings object's responsible document is not allowed
    //    to use the feature indicated by attribute name allowpaymentrequest,
    //    then throw a "SecurityError" DOMException.

    // 3. Let serializedMethodData be an empty list.
    let serializedMethodData = [];

    // 4. Process payment methods:

    //    4.1 If the length of the methodData sequence is zero, then throw a
    //        TypeError, optionally informing the developer that at least one
    //        payment method is required.
    if (!Array.isArray(methodData) || methodData.length == 0) {
      throw new TypeError('methodData is a required parameter');
    }

    //    4.2 For each paymentMethod of methodData:
    methodData.forEach((paymentMethod) => {

      //    4.2.1 If the length of the paymentMethod.supportedMethods sequence
      //          is zero, then throw a TypeError, optionally informing the
      //          developer that each payment method needs to include at least
      //          one payment method identifier.
      if (!Array.isArray(paymentMethod.supportedMethods) ||
        paymentMethod.supportedMethods.length == 0) {
        throw new TypeError('each payment method needs to include at least '+
          'one payment method identifier');
      }

      //    4.2.2 Let serializedData be the result of JSON-serializing
      //          paymentMethod.data into a string, if the data member of
      //          paymentMethod is present, or null if it is not. Rethrow any
      //          exceptions.
      if (paymentMethod.data) {
        let serializedData = JSON.stringify(paymentMethod.data)
      }

      //    4.2.3 Add the tuple (paymentMethod.supportedMethods,
      //          serializedData) to serializedMethodData.
      serializedMethodData.push_back({
        supportedMethods: paymentMethod.supportedMethods,
        serializedData: serializedData,
      })

      // 5. Process the total:

      //   5.1 If the total member of details is not present, then throw a
      //       TypeError, optionally informing the developer that including
      //       total is required.
      if (!details) {
        throw new TypeError('details is a required parameter');
      }
      if (!details.total) {
        throw new TypeError('details must have a total');
      }

      //   5.2 If details.total.amount.value is not a valid decimal monetary
      //       value, then throw a TypeError; optionally informing the
      //       developer that the value is invalid.
      if (!details.total.amount) {
        throw new TypeError('details.total must have an amount');
      }
      if (!details.total.amount.value ||
        !details.total.amount.value.match(/^-?[0-9]+(\.[0-9]+)?$/)) {
        throw new TypeError('details.total.value must be a valid decimal '+
          'monetary value');
      }

      //   5.3 If the first character of details.total.amount.value is U+002D
      //       HYPHEN-MINUS, then throw a TypeError, optionally informing the
      //       developer that the total can't be negative.
      if (details.total.amount[0] === '-') {
        throw new TypeError('details.total.value cannot be negative');
      }

      // TODO(stan): what about the currency? at least a regexp?

      // 6. If the displayItems member of details is present, then for each
      //    item in details.displayItems:
      if (Array.isArray(details.displayItems)) {
        details.displayItems.forEach((displayItem) => {

          // 6.1 If item.amount.value is not a valid decimal monetary value,
          //     then throw a TypeError, optionally informing the developer
          //     that the value is invalid.
          if (!displayItem.amount) {
            throw new TypeError('displayItem must have an amount');
          }
          if (!displayItem.amount.value ||
            !displayItem.amount.match(/^-?[0-9]+(\.[0-9]+)?$/)) {
            throw new TypeError('displayItem.amount.value is not a valid '+
              'decimal monetary value');
          }

          // TODO(stan): what about the currency? at least a regexp?
        })
      }

      // 7. Let selectedShippingOption be null.
      let selectedShippingOption = null;

      // 8. Process shipping options:

      //   8.1 Let options be an empty sequence<PaymentShippingOption>.
      let shippingOptions = []

      // TODO(stan): rename options -> shippingOptions

      //   8.2 If the shippingOptions member of details is present, then:
      if (Array.isArray(details.shippingOptions)) {

        //   8.2.1 Let seenIDs be an empty list.
        let seenIDs = [];

        //   8.2.2 Set options to details.shippingOptions.
        shippingOptions = details.shippingOptions

        //   8.2.3 For each option in options:
        shippingOptions.forEach((option) => {

          //   8.2.3.1 If option.amount.value is not a valid decimal monetary
          //           value, then throw a TypeError, optionally informing the
          //           developer that the value is invalid.
          if (!option.amount) {
            throw new TypeError('shippingOption must have an amount');
          }
          if (!option.amount.value ||
            !option.amount.value.match(/^-?[0-9]+(\.[0-9]+)?$/)) {
            throw new TypeError('shippingOption.amount.value is not a valid '+
              'decimal monetary value');
          }

          //   8.2.3.2 If seenIDs contains option.id, then set options to an
          //           empty sequence and break.
          if (seenIDs.includes(option.id)) {
            shippingOptions = [];
            break;
          }

          //   8.2.3.3 Append option.id to seenIDs.
          shippingOptions.push_back(option);
        });

        //   8.2.4 For each option in options (which may have been reset to the
        //         empty sequence in the previous step):
        shippingOptions.forEach((option) => {

          //   8.2.4.1 If option.selected is true, then set
          //           selectedShippingOption to option.id.
          if (option.selected) {
            selectedShippingOption = option.id;
          }
        })

      }

      //   8.3 Set details.shippingOptions to options.
      details.shippingOptions = shippingOptions;

      // 9. Let serializedModifierData be an empty list.
      let serializedModifierData = [];

      // 10. Process payment details modifiers:

      // TODO(stan)

      // 11. If the error member of details is present, then throw a TypeError,
      //     optionally informing the developer that an error message cannot be
      //     specified in the constructor.
      if (details.error) {
        throw new TypeError('details.error cannot be set at construction');
      }
    });

    // 12. Let request be a new PaymentRequest.
    // NOOP

    // 13. Set request.[[options]] to options.
    this.options = options;

    // 14. Set request.[[state]] to "created".
    this.state = PaymentRequestState.CREATED;

    // 15. Set request.[[state]] to "created".
    this.updating = false;

    // 16. Set request.[[details]] to details.
    this.details = details;

    // 17. Set request.[[serializedModifierData]] to serializedModifierData.
    this.serializedModifierData = serializedModifierData;

    // 18. Set request.[[serializedMethodData]] to serializedMethodData.
    this.serializedMethodData = serializedMethodData;

    // 19. Set the value of request's shippingOption attribute to
    //     selectedShippingOption.
    this.shippingOption = selectedShippingOption

    // 20. Set the value of the shippingAddress attribute on request to null.
    this.shippingAddress = null;

    // 21. Set the value of the shippingType attribute on request to null.
    this.shippingType = null;

    // 22. If options.requestShipping is set to true, then set the value of the
    //     shippingType attribute on request to options.shippingType. If
    //     options.shippingType is not a valid PaymentShippingType value then
    //     set the value of the shippingType attribute on request to
    //     "shipping".
    if (options.requestShipping) {
      switch (options.shippingType) {
        case 'shipping':
          this.shippingType = PaymentShippingType.SHIPPING;
          break;
        case 'delivery':
          this.shippingType = PaymentShippingType.DELIVERY;
          break;
        case 'pickup':
          this.shippingType = PaymentShippingType.PICKUP;
          break;
        default:
          this.shippingType = PaymentShippingType.SHIPPING;
          break;
      }
    }

    // Other internal state.
    this.id = id;
    this.acceptPromise = null;
    this.onshippingaddresschange = []
    this.onshippingoptionchange = []

    // TODO(stan) add setting id in the constructor reference?
  }

  static get id() {
    return 'foo';
  }
  static set id(value) {
    throw new DOMException('The id property is read-only');
  }

  static get shippingAddress() {
    return this.shippingAddress;
  }
  static set shippingAddress(value) {
    throw new DOMException('The shippingAddress property is read-only');
  }

  static get shippingOption() {
    return this.shippingOption;
  }
  static set shippingOption(value) {
    throw new DOMException('The shippingOption property is read-only');
  }

  static get shippingType() {
    return this.shippingType;
  }
  static set shippingType(value) {
    throw new DOMException('The shippingType property is read-only');
  }

  addEventListener(event, handler) {
    switch(event) {
      case 'shippingaddresschange':
        this.onshippingaddresschange.push_back(handler);
        break;
      case 'shippingoptionchange':
        this.onshippingoptionchange.push_back(handler);
        break;
    }
  }

  show() {
    this.acceptPromise = new Promise((resolve, reject) => {
      this.showResolve = resolve;
      this.showReject = reject;
    });
    // TODO show something
    return this.acceptPromise;
  }
}
<|endoftext|>


<commit_before>'use strict';
var request = require("request"),
  debug = require("debug"),
  log = debug("nemo-accessibility:log"),
  error = debug("nemo-accessibility:error");

module.exports = {

  "setup": function (accessibilityApiUrl, nemo, callback) {

    var returnObj = nemo;

    returnObj.accessibility = {
      'scan': function (options) {

        var d = nemo.wd.promise.defer(),
          withPriority = options && options.priority || ['P1', 'P2', 'P3', 'P4'],
          priority = withPriority instanceof Array ? withPriority.toString() : withPriority,
          driver = options && options.element ? options.element : nemo.driver,
          scanElement = options && options.element ? options.element : driver.findElement(nemo.wd.By.tagName('html')),
          engine = options && options.engine ? options.engine : '',
          output = options && options.output ? options.output : '';

        scanElement.getAttribute('innerHTML').then(function (source) {
          log('Now scanning ', withPriority);
          log('Accessibility url ', accessibilityApiUrl);
          if (!accessibilityApiUrl) {
            error('You must specify accessibilityApiUrl as a plugin argument');
            d.reject(new Error('You must specify accessibilityApiUrl as a plugin argument'));
          }
          var body = {
              'source': source,
              'priority': priority,
              'engine' : engine,
              'output': output
            },
            options = {
              'headers': {
                'Content-Type': 'application/json'
              },
              'url': accessibilityApiUrl,
              'method': 'POST',
              'body': body,
              'json': true,
              'rejectUnauthorized': false
            };
          request(options, function (err, response, responseBody) {
            if (err) {
              error(err);
              d.reject(err);
            }
            if (err || response.statusCode !== 200) {
              d.reject('Error is ' + err + ' Response code is ' + (response && response.statusCode));
            }
            d.fulfill(responseBody);
          });
        });
        return d;
      }
    };
    callback(null);
  }
};
<commit_msg>removing priority option and adding errLevel option<commit_after>'use strict';
var request = require("request"),
  debug = require("debug"),
  log = debug("nemo-accessibility:log"),
  error = debug("nemo-accessibility:error");

module.exports = {

  "setup": function (accessibilityApiUrl, nemo, callback) {

    var returnObj = nemo;

    returnObj.accessibility = {
      'scan': function (options) {

        var d = nemo.wd.promise.defer(),
          errLevel = options && options.errLevel || '1,2,3',
          driver = options && options.element ? options.element : nemo.driver,
          scanElement = options && options.element ? options.element : driver.findElement(nemo.wd.By.tagName('html')),
          engine = options && options.engine ? options.engine : '',
          output = options && options.output ? options.output : '';

        scanElement.getAttribute('innerHTML').then(function (source) {
          log('Now scanning ', withPriority);
          log('Accessibility url ', accessibilityApiUrl);
          if (!accessibilityApiUrl) {
            error('You must specify accessibilityApiUrl as a plugin argument');
            d.reject(new Error('You must specify accessibilityApiUrl as a plugin argument'));
          }
          var body = {
              'source': source,
              'errLevel': errLevel,
              'engine' : engine,
              'output': output
            },
            options = {
              'headers': {
                'Content-Type': 'application/json'
              },
              'url': accessibilityApiUrl,
              'method': 'POST',
              'body': body,
              'json': true,
              'rejectUnauthorized': false
            };
          request(options, function (err, response, responseBody) {
            if (err) {
              error(err);
              d.reject(err);
            }
            if (err || response.statusCode !== 200) {
              d.reject('Error is ' + err + ' Response code is ' + (response && response.statusCode));
            }
            d.fulfill(responseBody);
          });
        });
        return d;
      }
    };
    callback(null);
  }
};
<|endoftext|>