<commit_before>(function () {
  "use strict";

  var _ = require("lodash"),
      Marty = require("marty"),
      when = require('marty/when');

  var CohortFilterConstants = require("../constants/CohortFilterConstants"),
      LabKeyAPI = require("../lib/LabKeyAPI");

  class CohortFilterStore extends Marty.Store {
    constructor(options) {
      super(options);
      this.state = {
        cohortFilter: {}
      };
      this.handlers = {
        addCohortToFilter: CohortFilterConstants.COHORT_ADD,
        removeCohortFromFilter: CohortFilterConstants.COHORT_REMOVE
      };
    }

    addCohort(cohort) {
      this.state.cohorts.push(cohort);
      this.hasChanged();
    }

    /**
     * FILTER BY COHORT
     **/
    addCohortToFilter(cohort) {
      this.state.cohortFilter[cohort.rowid] = cohort;
      this.hasChanged();
    }

    removeCohortFromFilter(cohort) {
      delete this.state.cohortFilter[cohort.rowid];
      this.hasChanged();
    }

    getCohortFilter() {
      return this.state.cohortFilter || this.getCohorts();
    }

    /**
     * FILTER BY PARTICIPANT GROUP
     **/

    addParticipantGroupToFilter(cohort) {
      // TODO this.state.cohortFilter[cohort.rowid] = cohort;
      // TODO this.hasChanged();
    }

    removeParticipantGroupFromFilter(cohort) {
      // TODO delete this.state.cohortFilter[cohort.rowid];
      // TODO this.hasChanged();
    }

    getParticipantGroupFilter() {
      // TODO return this.state.cohortFilter || this.getCohorts();
    }

    getCohorts(){
      var that = this;
      return this.fetch('allCohorts',
        // local
        function(){
          return this.state.cohorts;
        },
        // remote
        function(){
          return LabKeyAPI.getCohorts().then(
            function(data) {
              that.state.cohorts = [];
              that.state.cohortFilter = {};
              data.rows.forEach(function(cohort) {
                that.addCohort(cohort);
                that.addCohortToFilter(cohort)
              });
            },
            function(error) {
              console.log("Sad times");
            });
        });
    }

    getParticipantGroups(){
      var that = this;
      return this.fetch('allParticipantGroups',
        // local
        function(){
          return this.state.allParticipantGroups;
        },
        // remote
        function(){
          return LabKeyAPI.getParticipantGroups().then(
            function(data) {
              that.state.allParticipantGroups = data.rows;
            },
            function(error) {
              console.log("Sad times");
            });
        });
    }

    getParticipants(){
      var that = this;
      return this.fetch('allParticipants',
        // local
        function(){
          return this.state.allParticipants;
        },
        // remote
        function(){
          return LabKeyAPI.getParticipants().then(
            function(data) {
              that.state.allParticipants = data.rows;
              that.hasChanged();
            },
            function(error) {
              console.log("Sad times");
            });
        });
    }

    getFilteredParticipants(){
      var that = this;
      var participants = this.state.allParticipants || [];
      var included = participants.filter(function(candidateParticipant) {
        return _.any(that.state.cohortFilter, 'rowid', candidateParticipant.InitialCohort);
      });
      return included;
    }
  }

  module.exports = Marty.register(CohortFilterStore);

}());
<commit_msg>:bug: Update participant filter to use `Cohort` rather than `InitialCohort`<commit_after>(function () {
  "use strict";

  var _ = require("lodash"),
      Marty = require("marty"),
      when = require('marty/when');

  var CohortFilterConstants = require("../constants/CohortFilterConstants"),
      LabKeyAPI = require("../lib/LabKeyAPI");

  class CohortFilterStore extends Marty.Store {
    constructor(options) {
      super(options);
      this.state = {
        cohortFilter: {}
      };
      this.handlers = {
        addCohortToFilter: CohortFilterConstants.COHORT_ADD,
        removeCohortFromFilter: CohortFilterConstants.COHORT_REMOVE
      };
    }

    addCohort(cohort) {
      this.state.cohorts.push(cohort);
      this.hasChanged();
    }

    /**
     * FILTER BY COHORT
     **/
    addCohortToFilter(cohort) {
      this.state.cohortFilter[cohort.rowid] = cohort;
      this.hasChanged();
    }

    removeCohortFromFilter(cohort) {
      delete this.state.cohortFilter[cohort.rowid];
      this.hasChanged();
    }

    getCohortFilter() {
      return this.state.cohortFilter || this.getCohorts();
    }

    /**
     * FILTER BY PARTICIPANT GROUP
     **/

    addParticipantGroupToFilter(cohort) {
      // TODO this.state.cohortFilter[cohort.rowid] = cohort;
      // TODO this.hasChanged();
    }

    removeParticipantGroupFromFilter(cohort) {
      // TODO delete this.state.cohortFilter[cohort.rowid];
      // TODO this.hasChanged();
    }

    getParticipantGroupFilter() {
      // TODO return this.state.cohortFilter || this.getCohorts();
    }

    getCohorts(){
      var that = this;
      return this.fetch('allCohorts',
        // local
        function(){
          return this.state.cohorts;
        },
        // remote
        function(){
          return LabKeyAPI.getCohorts().then(
            function(data) {
              that.state.cohorts = [];
              that.state.cohortFilter = {};
              data.rows.forEach(function(cohort) {
                that.addCohort(cohort);
                that.addCohortToFilter(cohort)
              });
            },
            function(error) {
              console.log("Sad times");
            });
        });
    }

    getParticipantGroups(){
      var that = this;
      return this.fetch('allParticipantGroups',
        // local
        function(){
          return this.state.allParticipantGroups;
        },
        // remote
        function(){
          return LabKeyAPI.getParticipantGroups().then(
            function(data) {
              that.state.allParticipantGroups = data.rows;
            },
            function(error) {
              console.log("Sad times");
            });
        });
    }

    getParticipants(){
      var that = this;
      return this.fetch('allParticipants',
        // local
        function(){
          return this.state.allParticipants;
        },
        // remote
        function(){
          return LabKeyAPI.getParticipants().then(
            function(data) {
              that.state.allParticipants = data.rows;
              that.hasChanged();
            },
            function(error) {
              console.log("Sad times");
            });
        });
    }

    getFilteredParticipants(){
      var that = this;
      var participants = this.state.allParticipants || [];

      var included = participants.filter(function(candidateParticipant) {
        return _.any(that.state.cohortFilter, 'rowid', candidateParticipant.Cohort);
      });
      return included;
    }
  }

  module.exports = Marty.register(CohortFilterStore);

}());
<|endoftext|>


<commit_before>MouseClickSystem.prototype = new EntityProcessingSystem();
MouseClickSystem.prototype.constructor = MouseClickSystem;

function MouseClickSystem(world, canvas) {

    EntityProcessingSystem.call(this);
    this.TID = 'MouseClickSystem';

    this.workOn(['MouseClickComponent']);
    this.setWorld(world);
    this.setCanvas(canvas);

};

MouseClickSystem.prototype.setCanvas = function (canvas) {

    this.canvas = canvas;
    return this;

};

MouseClickSystem.prototype.setWorld = function (world) {

    this.world = world;
    return this;

};

MouseClickSystem.prototype.processEvent = function (event) {

    if(event.type === 'click') {

        var x = event.x;
        var y = event.y;

        x -= this.canvas.offsetLeft + (Data.CELL_SIZE / 2);
        y -= this.canvas.offsetTop + (Data.CELL_SIZE / 2);

        var position = this.getSnappedPositionAt(x, y);

        var tower = EntityFactory.createTower(position.x, position.y);
        tower.addToWorld(this.world);

        var bullet = EntityFactory.createBullet(new PositionComponent(x, y), new AimingComponent(new PositionComponent(0, 0)));
        bullet.addToWorld(this.world);

//        var self = this;
//        setInterval(
//
//            function () {
//
//                var bullet = EntityFactory.createBullet(new PositionComponent(x, y), new AimingComponent(new PositionComponent(0, 0)));
//                bullet.addToWorld(self.world);
//
//            }
//
//        , 1000);

    }

    return this;

};

MouseClickSystem.prototype.getSnappedPositionAt = function (positionX, positionY) {

    return {
        x: this.getColumnIndexAt(positionX),
        y: this.getRowIndexAt(positionY)
    };

};

MouseClickSystem.prototype.getColumnIndexAt = function (positionX) {

    return Math.round(positionX / Data.CELL_SIZE) * Data.CELL_SIZE;

};

MouseClickSystem.prototype.getRowIndexAt = function (positionY) {

    return Math.round(positionY / Data.CELL_SIZE) * Data.CELL_SIZE;

};<commit_msg>Shooting more bullets<commit_after>MouseClickSystem.prototype = new EntityProcessingSystem();
MouseClickSystem.prototype.constructor = MouseClickSystem;

function MouseClickSystem(world, canvas) {

    EntityProcessingSystem.call(this);
    this.TID = 'MouseClickSystem';

    this.workOn(['MouseClickComponent']);
    this.setWorld(world);
    this.setCanvas(canvas);

};

MouseClickSystem.prototype.setCanvas = function (canvas) {

    this.canvas = canvas;
    return this;

};

MouseClickSystem.prototype.setWorld = function (world) {

    this.world = world;
    return this;

};

MouseClickSystem.prototype.processEvent = function (event) {

    if(event.type === 'click') {

        var x = event.x;
        var y = event.y;

        x -= this.canvas.offsetLeft + (Data.CELL_SIZE / 2);
        y -= this.canvas.offsetTop + (Data.CELL_SIZE / 2);

        var position = this.getSnappedPositionAt(x, y);

        var tower = EntityFactory.createTower(position.x, position.y);
        tower.addToWorld(this.world);

        var self = this;
        setInterval(

            function () {

                var bullet = EntityFactory.createBullet(new PositionComponent(position.x + (Data.CELL_SIZE / 2), position.y + (Data.CELL_SIZE / 2)), new AimingComponent(new PositionComponent(0, 0)));
                bullet.addToWorld(self.world);

            }

        , 1000);

    }

    return this;

};

MouseClickSystem.prototype.getSnappedPositionAt = function (positionX, positionY) {

    return {
        x: this.getColumnIndexAt(positionX),
        y: this.getRowIndexAt(positionY)
    };

};

MouseClickSystem.prototype.getColumnIndexAt = function (positionX) {

    return Math.round(positionX / Data.CELL_SIZE) * Data.CELL_SIZE;

};

MouseClickSystem.prototype.getRowIndexAt = function (positionY) {

    return Math.round(positionY / Data.CELL_SIZE) * Data.CELL_SIZE;

};<|endoftext|>


<commit_before>'use strict';

var __ = require('underscore'),
    Backbone = require('backbone'),
    $ = require('jquery'),
    is = require('is_js'),
    loadTemplate = require('../utils/loadTemplate'),
    saveToAPI = require('../utils/saveToAPI'),
    orderModel = require('../models/orderMd'),
    getBTPrice = require('../utils/getBitcoinPrice'),
    baseVw = require('./baseVw'),
    chatMessageView = require('./chatMessageVw'),
    qr = require('qr-encode'),
    messageModal = require('../utils/messageModal'),
    discussionCl = require('../collections/discussionCl'),
    clipboard = require('clipboard');

module.exports = baseVw.extend({

  className: "modal modal-opaque js-transactionModal",

  events: {
    'click .js-transactionModal': 'blockClicks',
    'click .js-closeModal': 'closeModal',
    'click .js-summaryTab': 'clickSummaryTab',
    'click .js-shippingTab': 'clickShippingTab',
    'click .js-fundsTab': 'clickFundsTab',
    'click .js-discussionTab': 'clickDiscussionTab',
    'click .js-showConfirmForm': 'showConfirmForm',
    'click .js-showCompleteForm': 'showCompleteForm',
    'click .js-confirmOrder': 'confirmOrder',
    'click .js-completeOrder': 'completeOrder',
    'click .js-copyIncommingTx': 'copyTx',
    'click .js-copyOutgoingTx': 'copyTx',
    'click .js-closeOrderForm': 'closeOrderForm',
    'click .js-showFundOrder': 'showFundOrder',
    'click .js-transactionPayCheck':'checkPayment',
    'click .js-startDispute': 'startDispute',
    'click .js-confirmDispute': 'confirmDispute',
    'click .js-sendDiscussionMessage': 'sendDiscussionMessageClick',
    'blur input': 'validateInput',
    'blur textarea': 'validateInput'
  },

  initialize: function (options) {

    var self = this;

    this.orderID = options.orderID;
    this.status = options.status;
    this.transactionType = options.transactionType;
    this.parentEl = options.parentEl;
    this.countriesArray = options.countriesArray;
    this.cCode = options.cCode;
    this.btAve = options.btAve; //average price in bitcoin for one unit of the user's currency
    this.bitcoinValidationRegex = options.bitcoinValidationRegex;
    this.pageState = options.state; //state of the parent view
    this.tabState = options.tabState ;//active tab
    this.socketView = options.socketView;
    this.userModel = options.userModel;
    this.serverUrl = this.userModel.get('serverUrl');
    this.userProfile = options.userProfile;
    this.lastTab = "summary";
    this.discussionCount = 0;
    this.discussionCol = new discussionCl();
    this.discussionCol.url = this.serverUrl + "get_dispute_messages";

    if(this.userProfile.get('avatar_hash')){
      this.avatarURL = this.userModel.get('serverUrl') + "get_image?hash=" + this.userProfile.get('avatar_hash');
    }

    this.listenTo(window.obEventBus, "socketMessageReceived", this.handleSocketMessage);

    this.listenTo(this.discussionCol, "add", this.addDiscussionMessage);

    this.model = new orderModel({
      cCode: this.cCode,
      btAve: this.btAve,
      serverUrl: this.serverUrl,
      status: this.status,
      transactionType: this.transactionType,
      bitcoinValidationRegex: this.bitcoinValidationRegex,
      avatarURL: this.avatarURL
    });
    this.model.urlRoot = options.serverUrl + "get_order";
    this.listenTo(this.model, 'change:priceSet', this.render);
    this.getData();
  },

  getData: function(){
    var self = this;
    this.model.fetch({
      data: $.param({'order_id': self.orderID}),
      timeout: 4000,
      dataType: 'json',
      success: function (model, response, options) {
        self.model.updateAttributes();
      },
      error: function (jqXHR, status, errorThrown) {
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        $('.js-loadingModal').addClass("hide");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  render: function () {
    var self = this;
    $('.js-loadingModal').addClass("hide");
    this.model.set('status', this.status);

    loadTemplate('./js/templates/transactionModal.html', function(loadedTemplate) {
      //hide the modal when it first loads
      self.parentEl.html(self.$el);
      self.$el.html(loadedTemplate(self.model.toJSON()));
      self.delegateEvents(); //reapply events if this is a second render
      self.$el.parent().fadeIn(300);
      self.setState(self.tabState);
      if(self.status == 0){
        self.showPayment();
      }
      self.getDiscussion();
      self.discussionScroller = self.$('.js-discussionScroller');
    });
  },

  handleSocketMessage: function(response) {
    var data = JSON.parse(response.data);
    if(data.notification && data.notification.order_id == this.orderID && data.notification.type == "payment received" && this.status == 0){
      this.status = 1;
      this.getData();
    } else if(data.message && data.message.subject == this.orderID){
      var messageModel = new Backbone.Model(data.message);
      //this.addDiscussionMessage(messageModel);
      this.discussionCol.add(messageModel);
    }
  },

  showPayment: function(){
    var totalBTCPrice = 0,
        payHREF,
        dataURI;
    if(this.model.get('buyer_order')){
      payHREF = "bitcoin:" + this.model.get('buyer_order').order.payment.address + "?amount=" + this.model.get('buyer_order').order.payment.amount + "&message=" + this.model.get('vendor_offer').listing.item.title;
      dataURI = qr(payHREF, {type: 10, size: 10, level: 'M'});
      this.$el.find('.js-transactionPayQRCode').attr('src', dataURI);
    } else {
      messageModal.show(window.polyglot.t('errorMessages.getError'), window.polyglot.t('errorMessages.serverError'));
    }
  },

  setState: function(state){
    if(!state){
      state = "summary";
    }
    this.$el.find('.js-main').addClass('hide');
    this.$el.find('.js-tab').removeClass('active');
    this.$el.find('.js-' + state).removeClass('hide');
    this.$el.find('.js-' + state + 'Tab').addClass('active').removeClass('hide');

    if(state == "discussion"){
      this.discussionScroller[0].scrollTop = this.discussionScroller[0].scrollHeight;
    }

    this.lastTab = this.state;
    this.state = state;
  },

  validateInput: function(e) {
    e.target.checkValidity();
    $(e.target).closest('.flexRow').addClass('formChecked');
  },

  clickSummaryTab: function(){
    this.setState("summary");
  },

  clickShippingTab: function(){
    this.setState("shipping");
  },

  clickFundsTab: function(){
    this.setState("funds");
  },

  clickDiscussionTab: function(){
    this.setState("discussion");
  },

  showConfirmForm: function(){
    this.setState("confirm");
  },

  showCompleteForm: function(){
    this.setState("complete");
  },

  confirmOrder: function(e){
    var self = this,
        targetForm = this.$el.find('#transactionConfirmForm'),
        confirmData = {};

    confirmData.id = this.orderID;
    this.$el.find('.js-transactionSpinner').removeClass('hide');

    saveToAPI(targetForm, '', this.serverUrl + "confirm_order", function(data){
      self.status = 2;
      self.tabState = "summary";
      self.getData();
      }, '', confirmData);
  },

  completeOrder: function(e){
    var self = this,
        targetForm = this.$el.find('#transactionCompleteForm'),
        completeData = {};

    completeData.id = this.orderID;
    this.$el.find('.js-transactionSpinner').removeClass('hide');

    saveToAPI(targetForm, '', this.serverUrl + "complete_order",
        function(data){
          self.status = 3;
          self.tabState = "summary";
          self.getData();
        },
        function(data){
          messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        },
        completeData);
  },

  checkPayment: function(){
    var self = this,
        formData = new FormData();

    formData.append("order_id", this.orderID);
    $.ajax({ //this only triggers the server to send a new socket message
      type: "POST",
      url: self.model.get('serverUrl') + "check_for_payment",
      contentType: false,
      processData: false,
      data: formData,
      dataType: "json"
    });
  },

  getDiscussion: function(){
    var self = this;
    this.discussionCount = 0;

    this.discussionCol.fetch({
      data: $.param({'order_id': self.orderID}),
      timeout: 4000,
      dataType: 'json',
      reset: true,
      success: function (collection, response, options) {
        self.addAllDiscussionMessages();
      },
      error: function (jqXHR, status, errorThrown) {
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  addDiscussionMessage: function(message){
    var avatarURL = message.get('outgoing')
        ? this.avatarURL
        : this.serverUrl + "get_image?hash=" + message.get('avatar_hash') + "&guid=" + message.get('guid'),
        wrapper = this.$('.js-discussionWrapper');

    message.set('avatarURL', avatarURL);
    var discussionMessage = new chatMessageView({
      model: message
    });
    wrapper.append(discussionMessage.el);
    this.discussionCount++;
    this.$('.js-discussionCount').text(this.discussionCount);
    this.discussionScroller[0].scrollTop = this.discussionScroller[0].scrollHeight;
    this.$('.js-discussionForm').removeClass('disabled');
  },

  addAllDiscussionMessages: function(){
    var self = this;
    if(this.discussionCol.length > 0){
      this.$('.js-discussionWrapper').html('');
      this.$('.js-discussionNotStarted').addClass('hide');
      this.$('.js-discussionStarted').removeClass('hide');
    }
    this.discussionCol.each(function(model, i){
      self.addDiscussionMessage(model);
    });
  },

  sendDiscussionMessageClick: function(){
    var guid,
        rKey;
    console.log(this.model.attributes)
    if(this.transactionType == "purchases"){
      guid = this.model.get('vendor_offer').listing.id.guid;
      rKey = this.model.get('vendor_offer').listing.id.pubkeys.encryption;
    } else if(this.transactionType == "sales"){
      guid = this.model.get('buyer_order').order.id.guid;
      rKey = this.model.get('buyer_order').order.id.pubkeys.encryption;
    }
    this.sendDiscussionMessage(guid, rKey);
    this.sendDiscussionMessage(this.model.get('displayModerator').guid, rKey);
  },

  sendDiscussionMessage: function(guid, rKey){
    var messageInput = this.$('#transactionDiscussionSendText');
    var messageText = messageInput.val();
    if (messageText) {
      var socketMessageId = Math.random().toString(36).slice(2);
      console.log(guid)
      console.log(rKey)

      var chatMessage = {
        "request": {
          "api": "v1",
          "id": socketMessageId,
          "command": "send_message",
          "guid": guid,
          "handle": "",
          "message": messageText,
          "subject": this.orderID,
          "message_type": "DISPUTE",
          "public_key": rKey
        }
      };
      this.socketView.sendMessage(JSON.stringify(chatMessage));
      messageInput.val('');
      messageInput.closest('.flexRow').removeClass('formChecked');
      this.getDiscussion();
    }
  },

  copyTx: function(e){

    var tx = $(e.target).data('tx');
    clipboard.writeText(tx);
  },

  startDispute: function(){
    this.setState("discussion");
  },

  confirmDispute: function(){
    var self = this,
        targetForm = this.$('#transactionDiscussionForm'),
        discussionData = {};

    discussionData.order_id = this.orderID;

    saveToAPI(targetForm, '', this.serverUrl + "dispute_contract", function(data){
      self.status = 4;
      self.tabState = "discussion";
      self.getData();
    }, '', discussionData);
  },

  closeOrderForm: function(e){
    this.setState(this.lastTab);
  },

  blockClicks: function(e) {
    "use strict";
    if(!$(e.target).hasClass('js-externalLink')){
      e.stopPropagation();
    }
  },

  closeModal: function(){
    this.trigger("closed");
    this.$el.parent().fadeOut(300);
  }
});<commit_msg>fix keys<commit_after>'use strict';

var __ = require('underscore'),
    Backbone = require('backbone'),
    $ = require('jquery'),
    is = require('is_js'),
    loadTemplate = require('../utils/loadTemplate'),
    saveToAPI = require('../utils/saveToAPI'),
    orderModel = require('../models/orderMd'),
    getBTPrice = require('../utils/getBitcoinPrice'),
    baseVw = require('./baseVw'),
    chatMessageView = require('./chatMessageVw'),
    qr = require('qr-encode'),
    messageModal = require('../utils/messageModal'),
    discussionCl = require('../collections/discussionCl'),
    clipboard = require('clipboard');

module.exports = baseVw.extend({

  className: "modal modal-opaque js-transactionModal",

  events: {
    'click .js-transactionModal': 'blockClicks',
    'click .js-closeModal': 'closeModal',
    'click .js-summaryTab': 'clickSummaryTab',
    'click .js-shippingTab': 'clickShippingTab',
    'click .js-fundsTab': 'clickFundsTab',
    'click .js-discussionTab': 'clickDiscussionTab',
    'click .js-showConfirmForm': 'showConfirmForm',
    'click .js-showCompleteForm': 'showCompleteForm',
    'click .js-confirmOrder': 'confirmOrder',
    'click .js-completeOrder': 'completeOrder',
    'click .js-copyIncommingTx': 'copyTx',
    'click .js-copyOutgoingTx': 'copyTx',
    'click .js-closeOrderForm': 'closeOrderForm',
    'click .js-showFundOrder': 'showFundOrder',
    'click .js-transactionPayCheck':'checkPayment',
    'click .js-startDispute': 'startDispute',
    'click .js-confirmDispute': 'confirmDispute',
    'click .js-sendDiscussionMessage': 'sendDiscussionMessageClick',
    'blur input': 'validateInput',
    'blur textarea': 'validateInput'
  },

  initialize: function (options) {

    var self = this;

    this.orderID = options.orderID;
    this.status = options.status;
    this.transactionType = options.transactionType;
    this.parentEl = options.parentEl;
    this.countriesArray = options.countriesArray;
    this.cCode = options.cCode;
    this.btAve = options.btAve; //average price in bitcoin for one unit of the user's currency
    this.bitcoinValidationRegex = options.bitcoinValidationRegex;
    this.pageState = options.state; //state of the parent view
    this.tabState = options.tabState ;//active tab
    this.socketView = options.socketView;
    this.userModel = options.userModel;
    this.serverUrl = this.userModel.get('serverUrl');
    this.userProfile = options.userProfile;
    this.lastTab = "summary";
    this.discussionCount = 0;
    this.discussionCol = new discussionCl();
    this.discussionCol.url = this.serverUrl + "get_dispute_messages";

    if(this.userProfile.get('avatar_hash')){
      this.avatarURL = this.userModel.get('serverUrl') + "get_image?hash=" + this.userProfile.get('avatar_hash');
    }

    this.listenTo(window.obEventBus, "socketMessageReceived", this.handleSocketMessage);

    this.listenTo(this.discussionCol, "add", this.addDiscussionMessage);

    this.model = new orderModel({
      cCode: this.cCode,
      btAve: this.btAve,
      serverUrl: this.serverUrl,
      status: this.status,
      transactionType: this.transactionType,
      bitcoinValidationRegex: this.bitcoinValidationRegex,
      avatarURL: this.avatarURL
    });
    this.model.urlRoot = options.serverUrl + "get_order";
    this.listenTo(this.model, 'change:priceSet', this.render);
    this.getData();
  },

  getData: function(){
    var self = this;
    this.model.fetch({
      data: $.param({'order_id': self.orderID}),
      timeout: 4000,
      dataType: 'json',
      success: function (model, response, options) {
        self.model.updateAttributes();
      },
      error: function (jqXHR, status, errorThrown) {
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        $('.js-loadingModal').addClass("hide");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  render: function () {
    var self = this;
    $('.js-loadingModal').addClass("hide");
    this.model.set('status', this.status);

    loadTemplate('./js/templates/transactionModal.html', function(loadedTemplate) {
      //hide the modal when it first loads
      self.parentEl.html(self.$el);
      self.$el.html(loadedTemplate(self.model.toJSON()));
      self.delegateEvents(); //reapply events if this is a second render
      self.$el.parent().fadeIn(300);
      self.setState(self.tabState);
      if(self.status == 0){
        self.showPayment();
      }
      self.getDiscussion();
      self.discussionScroller = self.$('.js-discussionScroller');
    });
  },

  handleSocketMessage: function(response) {
    var data = JSON.parse(response.data);
    if(data.notification && data.notification.order_id == this.orderID && data.notification.type == "payment received" && this.status == 0){
      this.status = 1;
      this.getData();
    } else if(data.message && data.message.subject == this.orderID){
      var messageModel = new Backbone.Model(data.message);
      //this.addDiscussionMessage(messageModel);
      this.discussionCol.add(messageModel);
    }
  },

  showPayment: function(){
    var totalBTCPrice = 0,
        payHREF,
        dataURI;
    if(this.model.get('buyer_order')){
      payHREF = "bitcoin:" + this.model.get('buyer_order').order.payment.address + "?amount=" + this.model.get('buyer_order').order.payment.amount + "&message=" + this.model.get('vendor_offer').listing.item.title;
      dataURI = qr(payHREF, {type: 10, size: 10, level: 'M'});
      this.$el.find('.js-transactionPayQRCode').attr('src', dataURI);
    } else {
      messageModal.show(window.polyglot.t('errorMessages.getError'), window.polyglot.t('errorMessages.serverError'));
    }
  },

  setState: function(state){
    if(!state){
      state = "summary";
    }
    this.$el.find('.js-main').addClass('hide');
    this.$el.find('.js-tab').removeClass('active');
    this.$el.find('.js-' + state).removeClass('hide');
    this.$el.find('.js-' + state + 'Tab').addClass('active').removeClass('hide');

    if(state == "discussion"){
      this.discussionScroller[0].scrollTop = this.discussionScroller[0].scrollHeight;
    }

    this.lastTab = this.state;
    this.state = state;
  },

  validateInput: function(e) {
    e.target.checkValidity();
    $(e.target).closest('.flexRow').addClass('formChecked');
  },

  clickSummaryTab: function(){
    this.setState("summary");
  },

  clickShippingTab: function(){
    this.setState("shipping");
  },

  clickFundsTab: function(){
    this.setState("funds");
  },

  clickDiscussionTab: function(){
    this.setState("discussion");
  },

  showConfirmForm: function(){
    this.setState("confirm");
  },

  showCompleteForm: function(){
    this.setState("complete");
  },

  confirmOrder: function(e){
    var self = this,
        targetForm = this.$el.find('#transactionConfirmForm'),
        confirmData = {};

    confirmData.id = this.orderID;
    this.$el.find('.js-transactionSpinner').removeClass('hide');

    saveToAPI(targetForm, '', this.serverUrl + "confirm_order", function(data){
      self.status = 2;
      self.tabState = "summary";
      self.getData();
      }, '', confirmData);
  },

  completeOrder: function(e){
    var self = this,
        targetForm = this.$el.find('#transactionCompleteForm'),
        completeData = {};

    completeData.id = this.orderID;
    this.$el.find('.js-transactionSpinner').removeClass('hide');

    saveToAPI(targetForm, '', this.serverUrl + "complete_order",
        function(data){
          self.status = 3;
          self.tabState = "summary";
          self.getData();
        },
        function(data){
          messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        },
        completeData);
  },

  checkPayment: function(){
    var self = this,
        formData = new FormData();

    formData.append("order_id", this.orderID);
    $.ajax({ //this only triggers the server to send a new socket message
      type: "POST",
      url: self.model.get('serverUrl') + "check_for_payment",
      contentType: false,
      processData: false,
      data: formData,
      dataType: "json"
    });
  },

  getDiscussion: function(){
    var self = this;
    this.discussionCount = 0;

    this.discussionCol.fetch({
      data: $.param({'order_id': self.orderID}),
      timeout: 4000,
      dataType: 'json',
      reset: true,
      success: function (collection, response, options) {
        self.addAllDiscussionMessages();
      },
      error: function (jqXHR, status, errorThrown) {
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  addDiscussionMessage: function(message){
    var avatarURL = message.get('outgoing')
        ? this.avatarURL
        : this.serverUrl + "get_image?hash=" + message.get('avatar_hash') + "&guid=" + message.get('guid'),
        wrapper = this.$('.js-discussionWrapper');

    message.set('avatarURL', avatarURL);
    var discussionMessage = new chatMessageView({
      model: message
    });
    wrapper.append(discussionMessage.el);
    this.discussionCount++;
    this.$('.js-discussionCount').text(this.discussionCount);
    this.discussionScroller[0].scrollTop = this.discussionScroller[0].scrollHeight;
    this.$('.js-discussionForm').removeClass('disabled');
  },

  addAllDiscussionMessages: function(){
    var self = this;
    if(this.discussionCol.length > 0){
      this.$('.js-discussionWrapper').html('');
      this.$('.js-discussionNotStarted').addClass('hide');
      this.$('.js-discussionStarted').removeClass('hide');
    }
    this.discussionCol.each(function(model, i){
      self.addDiscussionMessage(model);
    });
  },

  sendDiscussionMessageClick: function(){
    var guid,
        rKey;
    if(this.transactionType == "purchases"){
      guid = this.model.get('vendor_offer').listing.id.guid;
      rKey = this.model.get('vendor_offer').listing.id.pubkeys.guid;
    } else if(this.transactionType == "sales"){
      guid = this.model.get('buyer_order').order.id.guid;
      rKey = this.model.get('buyer_order').order.id.pubkeys.guid;
    }
    this.sendDiscussionMessage(guid, rKey);
    this.sendDiscussionMessage(this.model.get('displayModerator').guid, rKey);
  },

  sendDiscussionMessage: function(guid, rKey){
    var messageInput = this.$('#transactionDiscussionSendText');
    var messageText = messageInput.val();
    if (messageText) {
      var socketMessageId = Math.random().toString(36).slice(2);

      var chatMessage = {
        "request": {
          "api": "v1",
          "id": socketMessageId,
          "command": "send_message",
          "guid": guid,
          "handle": "",
          "message": messageText,
          "subject": this.orderID,
          "message_type": "DISPUTE",
          "public_key": rKey
        }
      };
      this.socketView.sendMessage(JSON.stringify(chatMessage));
      messageInput.val('');
      messageInput.closest('.flexRow').removeClass('formChecked');
      this.getDiscussion();
    }
  },

  copyTx: function(e){

    var tx = $(e.target).data('tx');
    clipboard.writeText(tx);
  },

  startDispute: function(){
    this.setState("discussion");
  },

  confirmDispute: function(){
    var self = this,
        targetForm = this.$('#transactionDiscussionForm'),
        discussionData = {};

    discussionData.order_id = this.orderID;

    saveToAPI(targetForm, '', this.serverUrl + "dispute_contract", function(data){
      self.status = 4;
      self.tabState = "discussion";
      self.getData();
    }, '', discussionData);
  },

  closeOrderForm: function(e){
    this.setState(this.lastTab);
  },

  blockClicks: function(e) {
    "use strict";
    if(!$(e.target).hasClass('js-externalLink')){
      e.stopPropagation();
    }
  },

  closeModal: function(){
    this.trigger("closed");
    this.$el.parent().fadeOut(300);
  }
});<|endoftext|>


<commit_before>function getResult(callback, parameters) {

    var action_module = require('./Google_Geocoding_App.js');
    action_module.getResult(function(newParameters) {
        console.log("Weather -> Geocode : " + newParameters);
        console.log("Weather -> Geocode lat : " + newParameters.lat);

        if(newParameters){
            console.log("Weather all : " + newParameters);
            console.log("Weather lat : " + newParameters.lat);
             console.log("Weather lng : " + newParameters.lng);
        //Put your action here
        require('request')('https://api.forecast.io/forecast/5fe274f52b8b66a83b716c68ff4da61f/'+newParameters.lat+','+newParameters.lng, function (error, response, body) {
            if (!error && response.statusCode == 200) {
              var info = JSON.parse(body);
              callback(JSON.stringify(info.currently.temperature));
            }else{
                callback("the request failed");
            }
          });

        }else{
                console.log("Weather : erro" + newParameters);
            callback("parameters are missing");
        }
    },parameters);

}

exports.getResult = getResult;
<commit_msg>Update Weather_App.js<commit_after>function getResult(callback, parameters) {

    var action_module = require('./Google_Geocoding_App.js');
    action_module.getResult(function(newParameters) {
        console.log("Weather -> Geocode : " + newParameters);
        console.log("Weather -> Geocode lat : " + newParameters.lat);

        if(newParameters){
            console.log("Weather all : " + newParameters);
            console.log("Weather lat : " + newParameters.lat);
             console.log("Weather lng : " + newParameters.lng);
        //Put your action here
        require('request')('https://api.forecast.io/forecast/5fe274f52b8b66a83b716c68ff4da61f/'+newParameters.lat+','+newParameters.lng, function (error, response, body) {
            if (!error && response.statusCode == 200) {
              var info = JSON.parse(body);
              callback(JSON.stringify(info.hourly.summary));
            }else{
                callback("the request failed");
            }
          });

        }else{
                console.log("Weather : erro" + newParameters);
            callback("parameters are missing");
        }
    },parameters);

}

exports.getResult = getResult;
<|endoftext|>


<commit_before>'use strict';

var __ = require('underscore'),
    Backbone = require('backbone'),
    $ = require('jquery'),
    is = require('is_js'),
    loadTemplate = require('../utils/loadTemplate'),
    saveToAPI = require('../utils/saveToAPI'),
    orderModel = require('../models/orderMd'),
    getBTPrice = require('../utils/getBitcoinPrice'),
    baseVw = require('./baseVw'),
    chatMessageView = require('./chatMessageVw'),
    qr = require('qr-encode'),
    messageModal = require('../utils/messageModal'),
    discussionCl = require('../collections/discussionCl'),
    clipboard = require('clipboard');

module.exports = baseVw.extend({

  className: "modal modal-opaque js-transactionModal",

  events: {
    'click .js-transactionModal': 'blockClicks',
    'click .js-closeModal': 'closeModal',
    'click .js-summaryTab': 'clickSummaryTab',
    'click .js-shippingTab': 'clickShippingTab',
    'click .js-fundsTab': 'clickFundsTab',
    'click .js-discussionTab': 'clickDiscussionTab',
    'click .js-showConfirmForm': 'showConfirmForm',
    'click .js-showCompleteForm': 'showCompleteForm',
    'click .js-confirmOrder': 'confirmOrder',
    'click .js-completeOrder': 'completeOrder',
    'click .js-copyIncommingTx': 'copyTx',
    'click .js-copyOutgoingTx': 'copyTx',
    'click .js-closeOrderForm': 'closeOrderForm',
    'click .js-showFundOrder': 'showFundOrder',
    'click .js-transactionPayCheck':'checkPayment',
    'click .js-startDispute': 'startDispute',
    'click .js-confirmDispute': 'confirmDispute',
    'click .js-sendDiscussionMessage': 'sendDiscussionMessageClick',
    'blur input': 'validateInput',
    'blur textarea': 'validateInput'
  },

  initialize: function (options) {

    var self = this;

    this.orderID = options.orderID;
    this.status = options.status;
    this.transactionType = options.transactionType;
    this.parentEl = options.parentEl;
    this.countriesArray = options.countriesArray;
    this.cCode = options.cCode;
    this.btAve = options.btAve; //average price in bitcoin for one unit of the user's currency
    this.bitcoinValidationRegex = options.bitcoinValidationRegex;
    this.pageState = options.state; //state of the parent view
    this.tabState = options.tabState ;//active tab
    this.socketView = options.socketView;
    this.userModel = options.userModel;
    this.serverUrl = this.userModel.get('serverUrl');
    this.userProfile = options.userProfile;
    this.lastTab = "summary";
    this.discussionCount = 0;

    if(this.userProfile.get('avatar_hash')){
      this.avatarURL = this.userModel.get('serverUrl') + "get_image?hash=" + this.userProfile.get('avatar_hash');
    }

    this.listenTo(window.obEventBus, "socketMessageReceived", function(response){
      this.handleSocketMessage(response);
    });

    this.model = new orderModel({
      cCode: this.cCode,
      btAve: this.btAve,
      serverUrl: this.serverUrl,
      status: this.status,
      transactionType: this.transactionType,
      bitcoinValidationRegex: this.bitcoinValidationRegex,
      avatarURL: this.avatarURL
    });
    this.model.urlRoot = options.serverUrl + "get_order";
    this.listenTo(this.model, 'change:priceSet', this.render);
    this.getData();
  },

  getData: function(){
    var self = this;
    this.model.fetch({
      data: $.param({'order_id': self.orderID}),
      timeout: 4000,
      dataType: 'json',
      success: function (model, response, options) {
        self.model.updateAttributes();
      },
      error: function (jqXHR, status, errorThrown) {
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        $('.js-loadingModal').addClass("hide");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  render: function () {
    var self = this;
    $('.js-loadingModal').addClass("hide");
    this.model.set('status', this.status);

    loadTemplate('./js/templates/transactionModal.html', function(loadedTemplate) {
      //hide the modal when it first loads
      self.parentEl.html(self.$el);
      self.$el.html(loadedTemplate(self.model.toJSON()));
      self.delegateEvents(); //reapply events if this is a second render
      self.$el.parent().fadeIn(300);
      self.setState(self.tabState);
      if(self.status == 0){
        self.showPayment();
      }
      self.getDiscussion();
      self.discussionScroller = self.$('.js-discussionScroller');
    });
  },

  handleSocketMessage: function(response) {
    var data = JSON.parse(response.data);
    if(data.notification && data.notification.order_id == this.orderID && data.notification.type == "payment received" && this.status == 0){
      this.status = 1;
      this.getData();
    } else if(data.message && data.message.subject == this.orderID){
      var messageModel = new Backbone.Model(data.message);
      this.addDiscussionMessage(messageModel);
    }
  },

  showPayment: function(){
    var totalBTCPrice = 0,
        payHREF,
        dataURI;
    if(this.model.get('buyer_order')){
      payHREF = "bitcoin:" + this.model.get('buyer_order').order.payment.address + "?amount=" + this.model.get('buyer_order').order.payment.amount + "&message=" + this.model.get('vendor_offer').listing.item.title;
      dataURI = qr(payHREF, {type: 10, size: 10, level: 'M'});
      this.$el.find('.js-transactionPayQRCode').attr('src', dataURI);
    } else {
      messageModal.show(window.polyglot.t('errorMessages.getError'), window.polyglot.t('errorMessages.serverError'));
    }
  },

  setState: function(state){
    if(!state){
      state = "summary";
    }
    this.$el.find('.js-main').addClass('hide');
    this.$el.find('.js-tab').removeClass('active');
    this.$el.find('.js-' + state).removeClass('hide');
    this.$el.find('.js-' + state + 'Tab').addClass('active').removeClass('hide');

    if(state == "discussion"){
      this.discussionScroller[0].scrollTop = this.discussionScroller[0].scrollHeight;
    }

    this.lastTab = this.state;
    this.state = state;
  },

  validateInput: function(e) {
    e.target.checkValidity();
    $(e.target).closest('.flexRow').addClass('formChecked');
  },

  clickSummaryTab: function(){
    this.setState("summary");
  },

  clickShippingTab: function(){
    this.setState("shipping");
  },

  clickFundsTab: function(){
    this.setState("funds");
  },

  clickDiscussionTab: function(){
    this.setState("discussion");
  },

  showConfirmForm: function(){
    this.setState("confirm");
  },

  showCompleteForm: function(){
    this.setState("complete");
  },

  confirmOrder: function(e){
    var self = this,
        targetForm = this.$el.find('#transactionConfirmForm'),
        confirmData = {};

    confirmData.id = this.orderID;
    this.$el.find('.js-transactionSpinner').removeClass('hide');

    saveToAPI(targetForm, '', this.serverUrl + "confirm_order", function(data){
      self.status = 2;
      self.tabState = "summary";
      self.getData();
      }, '', confirmData);
  },

  completeOrder: function(e){
    var self = this,
        targetForm = this.$el.find('#transactionCompleteForm'),
        completeData = {};

    completeData.id = this.orderID;
    this.$el.find('.js-transactionSpinner').removeClass('hide');

    saveToAPI(targetForm, '', this.serverUrl + "complete_order",
        function(data){
          self.status = 3;
          self.tabState = "summary";
          self.getData();
        },
        function(data){
          messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        },
        completeData);
  },

  checkPayment: function(){
    var self = this,
        formData = new FormData();

    formData.append("order_id", this.orderID);
    $.ajax({ //this only triggers the server to send a new socket message
      type: "POST",
      url: self.model.get('serverUrl') + "check_for_payment",
      contentType: false,
      processData: false,
      data: formData,
      dataType: "json"
    });
  },

  getDiscussion: function(){
    var self = this;
    this.discussionCount = 0;
    this.discussionCol = new discussionCl();
    this.discussionCol.url = this.serverUrl + "get_dispute_messages";

    this.discussionCol.fetch({
      data: $.param({'order_id': self.orderID}),
      timeout: 4000,
      dataType: 'json',
      reset: true,
      success: function (collection, response, options) {
        self.addAllDiscussionMessages();
      },
      error: function (jqXHR, status, errorThrown) {
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  addDiscussionMessage: function(message){
    var avatarURL = message.outgoing ? this.serverUrl + "get_image?hash=" + message.avatar_hash + "&guid=" + message.guid : this.avatarURL,
        wrapper = this.$('.js-discussionWrapper');

    message.set('avatarURL', avatarURL);
    var discussionMessage = new chatMessageView({
      model: message
    });
    wrapper.append(discussionMessage.el);
    this.discussionCount++;
    this.$('.js-discussionCount').text(this.discussionCount);
    this.discussionScroller[0].scrollTop = this.discussionScroller[0].scrollHeight;
    this.$('.js-discussionForm').removeClass('disabled');
  },

  addAllDiscussionMessages: function(){
    var self = this;
    if(this.discussionCol.length > 0){
      this.$('.js-discussionWrapper').html('');
      this.$('.js-discussionNotStarted').addClass('hide');
      this.$('.js-discussionStarted').removeClass('hide');
    }
    this.discussionCol.each(function(model, i){
      self.addDiscussionMessage(model);
    });
  },

  sendDiscussionMessageClick: function(){
    var guid;
    if(this.transactionType == "purchase"){
      guid = this.model.get('vendor_offer').listing.id.guid;
    } else if(this.transactionType == "sale"){
      guid = this.model.get('buyer_order').order.id.guid;
    }
    this.sendDiscussionMessage(guid);
    this.sendDiscussionMessage(this.model.get('displayModerator').guid);
  },

  sendDiscussionMessage: function(guid){
    var messageInput = this.$('#transactionDiscussionSendText');
    var messageText = messageInput.val();
    if (messageText) {
      var socketMessageId = Math.random().toString(36).slice(2);

      var chatMessage = {
        "request": {
          "api": "v1",
          "id": socketMessageId,
          "command": "send_message",
          "guid": guid,
          "handle": "",
          "message": messageText,
          "subject": this.orderID,
          "message_type": "DISPUTE",
          "recipient_key": this.model.get('vendor_offer').listing.id.pubkeys.encryption
        }
      };
      this.socketView.sendMessage(JSON.stringify(chatMessage));
      messageInput.val('');
      messageInput.closest('.flexRow').removeClass('formChecked');
      this.getDiscussion();
    }
  },

  copyTx: function(e){

    var tx = $(e.target).data('tx');
    clipboard.writeText(tx);
  },

  startDispute: function(){
    this.setState("discussion");
  },

  confirmDispute: function(){
    var self = this,
        targetForm = this.$('#transactionDiscussionForm'),
        discussionData = {};

    discussionData.order_id = this.orderID;

    saveToAPI(targetForm, '', this.serverUrl + "dispute_contract", function(data){
      self.status = 4;
      self.tabState = "discussion";
      self.getData();
    }, '', discussionData);
  },

  closeOrderForm: function(e){
    this.setState(this.lastTab);
  },

  blockClicks: function(e) {
    e.stopPropagation();
  },

  closeModal: function(){
    this.trigger("closed");
    this.$el.parent().fadeOut(300);
  }
});<commit_msg>fix recipient key<commit_after>'use strict';

var __ = require('underscore'),
    Backbone = require('backbone'),
    $ = require('jquery'),
    is = require('is_js'),
    loadTemplate = require('../utils/loadTemplate'),
    saveToAPI = require('../utils/saveToAPI'),
    orderModel = require('../models/orderMd'),
    getBTPrice = require('../utils/getBitcoinPrice'),
    baseVw = require('./baseVw'),
    chatMessageView = require('./chatMessageVw'),
    qr = require('qr-encode'),
    messageModal = require('../utils/messageModal'),
    discussionCl = require('../collections/discussionCl'),
    clipboard = require('clipboard');

module.exports = baseVw.extend({

  className: "modal modal-opaque js-transactionModal",

  events: {
    'click .js-transactionModal': 'blockClicks',
    'click .js-closeModal': 'closeModal',
    'click .js-summaryTab': 'clickSummaryTab',
    'click .js-shippingTab': 'clickShippingTab',
    'click .js-fundsTab': 'clickFundsTab',
    'click .js-discussionTab': 'clickDiscussionTab',
    'click .js-showConfirmForm': 'showConfirmForm',
    'click .js-showCompleteForm': 'showCompleteForm',
    'click .js-confirmOrder': 'confirmOrder',
    'click .js-completeOrder': 'completeOrder',
    'click .js-copyIncommingTx': 'copyTx',
    'click .js-copyOutgoingTx': 'copyTx',
    'click .js-closeOrderForm': 'closeOrderForm',
    'click .js-showFundOrder': 'showFundOrder',
    'click .js-transactionPayCheck':'checkPayment',
    'click .js-startDispute': 'startDispute',
    'click .js-confirmDispute': 'confirmDispute',
    'click .js-sendDiscussionMessage': 'sendDiscussionMessageClick',
    'blur input': 'validateInput',
    'blur textarea': 'validateInput'
  },

  initialize: function (options) {

    var self = this;

    this.orderID = options.orderID;
    this.status = options.status;
    this.transactionType = options.transactionType;
    this.parentEl = options.parentEl;
    this.countriesArray = options.countriesArray;
    this.cCode = options.cCode;
    this.btAve = options.btAve; //average price in bitcoin for one unit of the user's currency
    this.bitcoinValidationRegex = options.bitcoinValidationRegex;
    this.pageState = options.state; //state of the parent view
    this.tabState = options.tabState ;//active tab
    this.socketView = options.socketView;
    this.userModel = options.userModel;
    this.serverUrl = this.userModel.get('serverUrl');
    this.userProfile = options.userProfile;
    this.lastTab = "summary";
    this.discussionCount = 0;

    if(this.userProfile.get('avatar_hash')){
      this.avatarURL = this.userModel.get('serverUrl') + "get_image?hash=" + this.userProfile.get('avatar_hash');
    }

    this.listenTo(window.obEventBus, "socketMessageReceived", function(response){
      this.handleSocketMessage(response);
    });

    this.model = new orderModel({
      cCode: this.cCode,
      btAve: this.btAve,
      serverUrl: this.serverUrl,
      status: this.status,
      transactionType: this.transactionType,
      bitcoinValidationRegex: this.bitcoinValidationRegex,
      avatarURL: this.avatarURL
    });
    this.model.urlRoot = options.serverUrl + "get_order";
    this.listenTo(this.model, 'change:priceSet', this.render);
    this.getData();
  },

  getData: function(){
    var self = this;
    this.model.fetch({
      data: $.param({'order_id': self.orderID}),
      timeout: 4000,
      dataType: 'json',
      success: function (model, response, options) {
        self.model.updateAttributes();
      },
      error: function (jqXHR, status, errorThrown) {
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        $('.js-loadingModal').addClass("hide");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  render: function () {
    var self = this;
    $('.js-loadingModal').addClass("hide");
    this.model.set('status', this.status);

    loadTemplate('./js/templates/transactionModal.html', function(loadedTemplate) {
      //hide the modal when it first loads
      self.parentEl.html(self.$el);
      self.$el.html(loadedTemplate(self.model.toJSON()));
      self.delegateEvents(); //reapply events if this is a second render
      self.$el.parent().fadeIn(300);
      self.setState(self.tabState);
      if(self.status == 0){
        self.showPayment();
      }
      self.getDiscussion();
      self.discussionScroller = self.$('.js-discussionScroller');
    });
  },

  handleSocketMessage: function(response) {
    var data = JSON.parse(response.data);
    if(data.notification && data.notification.order_id == this.orderID && data.notification.type == "payment received" && this.status == 0){
      this.status = 1;
      this.getData();
    } else if(data.message && data.message.subject == this.orderID){
      var messageModel = new Backbone.Model(data.message);
      this.addDiscussionMessage(messageModel);
    }
  },

  showPayment: function(){
    var totalBTCPrice = 0,
        payHREF,
        dataURI;
    if(this.model.get('buyer_order')){
      payHREF = "bitcoin:" + this.model.get('buyer_order').order.payment.address + "?amount=" + this.model.get('buyer_order').order.payment.amount + "&message=" + this.model.get('vendor_offer').listing.item.title;
      dataURI = qr(payHREF, {type: 10, size: 10, level: 'M'});
      this.$el.find('.js-transactionPayQRCode').attr('src', dataURI);
    } else {
      messageModal.show(window.polyglot.t('errorMessages.getError'), window.polyglot.t('errorMessages.serverError'));
    }
  },

  setState: function(state){
    if(!state){
      state = "summary";
    }
    this.$el.find('.js-main').addClass('hide');
    this.$el.find('.js-tab').removeClass('active');
    this.$el.find('.js-' + state).removeClass('hide');
    this.$el.find('.js-' + state + 'Tab').addClass('active').removeClass('hide');

    if(state == "discussion"){
      this.discussionScroller[0].scrollTop = this.discussionScroller[0].scrollHeight;
    }

    this.lastTab = this.state;
    this.state = state;
  },

  validateInput: function(e) {
    e.target.checkValidity();
    $(e.target).closest('.flexRow').addClass('formChecked');
  },

  clickSummaryTab: function(){
    this.setState("summary");
  },

  clickShippingTab: function(){
    this.setState("shipping");
  },

  clickFundsTab: function(){
    this.setState("funds");
  },

  clickDiscussionTab: function(){
    this.setState("discussion");
  },

  showConfirmForm: function(){
    this.setState("confirm");
  },

  showCompleteForm: function(){
    this.setState("complete");
  },

  confirmOrder: function(e){
    var self = this,
        targetForm = this.$el.find('#transactionConfirmForm'),
        confirmData = {};

    confirmData.id = this.orderID;
    this.$el.find('.js-transactionSpinner').removeClass('hide');

    saveToAPI(targetForm, '', this.serverUrl + "confirm_order", function(data){
      self.status = 2;
      self.tabState = "summary";
      self.getData();
      }, '', confirmData);
  },

  completeOrder: function(e){
    var self = this,
        targetForm = this.$el.find('#transactionCompleteForm'),
        completeData = {};

    completeData.id = this.orderID;
    this.$el.find('.js-transactionSpinner').removeClass('hide');

    saveToAPI(targetForm, '', this.serverUrl + "complete_order",
        function(data){
          self.status = 3;
          self.tabState = "summary";
          self.getData();
        },
        function(data){
          messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        },
        completeData);
  },

  checkPayment: function(){
    var self = this,
        formData = new FormData();

    formData.append("order_id", this.orderID);
    $.ajax({ //this only triggers the server to send a new socket message
      type: "POST",
      url: self.model.get('serverUrl') + "check_for_payment",
      contentType: false,
      processData: false,
      data: formData,
      dataType: "json"
    });
  },

  getDiscussion: function(){
    var self = this;
    this.discussionCount = 0;
    this.discussionCol = new discussionCl();
    this.discussionCol.url = this.serverUrl + "get_dispute_messages";

    this.discussionCol.fetch({
      data: $.param({'order_id': self.orderID}),
      timeout: 4000,
      dataType: 'json',
      reset: true,
      success: function (collection, response, options) {
        self.addAllDiscussionMessages();
      },
      error: function (jqXHR, status, errorThrown) {
        messageModal.show(window.polyglot.t('errorMessages.getError'), "" + errorThrown + "");
        console.log(jqXHR);
        console.log(status);
        console.log(errorThrown);
      }
    });
  },

  addDiscussionMessage: function(message){
    var avatarURL = message.outgoing ? this.serverUrl + "get_image?hash=" + message.avatar_hash + "&guid=" + message.guid : this.avatarURL,
        wrapper = this.$('.js-discussionWrapper');

    message.set('avatarURL', avatarURL);
    var discussionMessage = new chatMessageView({
      model: message
    });
    wrapper.append(discussionMessage.el);
    this.discussionCount++;
    this.$('.js-discussionCount').text(this.discussionCount);
    this.discussionScroller[0].scrollTop = this.discussionScroller[0].scrollHeight;
    this.$('.js-discussionForm').removeClass('disabled');
  },

  addAllDiscussionMessages: function(){
    var self = this;
    if(this.discussionCol.length > 0){
      this.$('.js-discussionWrapper').html('');
      this.$('.js-discussionNotStarted').addClass('hide');
      this.$('.js-discussionStarted').removeClass('hide');
    }
    this.discussionCol.each(function(model, i){
      self.addDiscussionMessage(model);
    });
  },

  sendDiscussionMessageClick: function(){
    var guid,
        rKey;
    if(this.transactionType == "purchase"){
      guid = this.model.get('vendor_offer').listing.id.guid;
      rKey = this.model.get('vendor_offer').listing.id.pubkeys.encryption;
    } else if(this.transactionType == "sale"){
      guid = this.model.get('buyer_order').order.id.guid;
      rKey = this.model.get('buyer_order').order.id.pubkeys.encryption;
    }
    this.sendDiscussionMessage(guid);
    this.sendDiscussionMessage(this.model.get('displayModerator').guid);
  },

  sendDiscussionMessage: function(guid, rKey){
    var messageInput = this.$('#transactionDiscussionSendText');
    var messageText = messageInput.val();
    if (messageText) {
      var socketMessageId = Math.random().toString(36).slice(2);

      var chatMessage = {
        "request": {
          "api": "v1",
          "id": socketMessageId,
          "command": "send_message",
          "guid": guid,
          "handle": "",
          "message": messageText,
          "subject": this.orderID,
          "message_type": "DISPUTE",
          "recipient_key": rKey
        }
      };
      this.socketView.sendMessage(JSON.stringify(chatMessage));
      messageInput.val('');
      messageInput.closest('.flexRow').removeClass('formChecked');
      this.getDiscussion();
    }
  },

  copyTx: function(e){

    var tx = $(e.target).data('tx');
    clipboard.writeText(tx);
  },

  startDispute: function(){
    this.setState("discussion");
  },

  confirmDispute: function(){
    var self = this,
        targetForm = this.$('#transactionDiscussionForm'),
        discussionData = {};

    discussionData.order_id = this.orderID;

    saveToAPI(targetForm, '', this.serverUrl + "dispute_contract", function(data){
      self.status = 4;
      self.tabState = "discussion";
      self.getData();
    }, '', discussionData);
  },

  closeOrderForm: function(e){
    this.setState(this.lastTab);
  },

  blockClicks: function(e) {
    e.stopPropagation();
  },

  closeModal: function(){
    this.trigger("closed");
    this.$el.parent().fadeOut(300);
  }
});<|endoftext|>


<commit_before>import {basename, dirname, normalize as _normalize, resolve} from "path";
import FSWatcher from "./FSWatcher";
const errors = require("errno");
const node_modules = 'node_modules';
let normalize = (_path) => resolve('/', _normalize(_path));

class XFileSystemError extends Error {
  constructor(err, path) {
    super();
    Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
    this.code = err.code;
    this.errno = err.errno;
    this.message = err.description;
    this.path = path;
  }
}
// directory is an object with '' prop, {'':true}(normal dir) {'':null}(remote dir)
function isDir(item) {
  return item && typeof item == "object" && ('' in item);
}

// File is Buffer or null(from remote)
function isFile(item) {
  return item instanceof Buffer
}

function exists(item) {
  return item != undefined;
}
function pathToArray(abspath) {
  let path = normalize(abspath).substr(1).split("/");
  if (path.length > 0 && !path[path.length - 1]) path.pop();
  return path;
}

const trueFn = () => true;
const falseFn = () => false;

function isReservePath(abspath) {
  return abspath == '/' || abspath == `/${node_modules}`;
}
function NotImplemented() {
  throw new XFileSystemError(errors.code.ENOSYS);
}
export function inLib(path) {
  return normalize(path).indexOf(node_modules) == 1;
}
const libPrefixLength = node_modules.length + 1;

export default class XFileSystem {
  data = {'': true};
  _stats = {'/': {birthtime: new Date(), mode: 16877, atime: new Date(), mtime: new Date(), ctime: new Date()}};
  _watcher = {};
  _fetch;

  constructor(fetch) {
    this._fetch = fetch;
    this.mkdirSync(node_modules);
    this.data.node_modules[''] = null;
  }

  /**
   * helper method
   * @param abspath
   * @returns {*}
   */
  _meta(abspath) {
    const path = pathToArray(abspath);
    let current = this.data;
    for (let token of path) {
      if (!isDir(current))
        return;
      current = current[token];
    }
    return current;
  }

  _syncToCb = (fn) => {
    let fs = this;
    return function () {
      let path = arguments[0];
      let args = Array.prototype.slice.call(arguments, 1, arguments.length - 1);
      let callback = arguments[arguments.length - 1];
      if (typeof path != 'string') {
        return callback(new TypeError('path must be a string'));
      }
      if (typeof callback != 'function') {
        args.push(callback);
        callback = falseFn;
      }
      let result;
      try {
        result = fs[fn + "Sync"](path, ...args);
      } catch (e) {
        callback(e);
        return;
      }
      callback(null, result);
    }
  };
  _remote = (fn, shouldBeDir) => {
    let fs = this;
    return function () {
      let path = arguments[0];
      let args = Array.prototype.slice.call(arguments, 1, arguments.length - 1);
      let callback = arguments[arguments.length - 1];
      if (!path || !(typeof path == 'string')) {
        throw new TypeError('path must be a string');
      }
      if (typeof callback != 'function') {
        args.push(callback);
        callback = falseFn;
      }
      let abspath = normalize(path);
      let result;
      try {
        result = fs[fn + 'Sync'](abspath, ...args);
      } catch (e) {

        if (!inLib(abspath)) return callback(e);
        fs._fetch(abspath.substr(libPrefixLength), shouldBeDir)
          .then((textOrArray) => {
            if (shouldBeDir) {
              let dir = fs.mkdirpSync(abspath);
              dir[''] = true;
              for (let sub of textOrArray) {
                if (sub[sub.length - 1] == '/') { // dir
                  sub = sub.substr(0, sub.length - 1);
                  if (dir[sub]) {
                    if (!isDir(dir[sub])) {
                      return callback(new XFileSystemError(errors.code.EEXIST, abspath + '/' + sub))
                    }
                  } else {
                    this._write(dir, abspath + '/' + sub, {'': null});
                  }
                } else { // remote file
                  this._write(dir, abspath + '/' + sub, null);
                }
              }
            } else {
              fs.writeFileSync(abspath, textOrArray);
            }
            try {
              result = fs[fn + 'Sync'](abspath, ...args)
            } catch (e) {
              callback(e);
              return;
            }
            callback(null, result);
          })
          .catch((e2) => callback(e));
        return;
      }
      callback(null, result)
    }
  };

  _emit(abspath, dirpath, filename, type) {
    this._watcher[dirpath] && this._watcher[dirpath].emit('watch', type, filename);
    this._watcher[abspath] && this._watcher[abspath].emit('watch', type, filename);
  }

  _write(current, abspath, content) {
    let dirpath = dirname(abspath);
    let filename = basename(abspath);
    current[filename] = content;

    let createNew = !this._stats[abspath];
    let stats = createNew
      ? {
        birthtime: new Date(),
        mode: isDir(content) ? 16877 /* Oct 40755 */ : 33188 /* Oct 100644 */
      }
      : this._stats[abspath];

    this._stats[abspath] = {
      ...stats,
      atime: new Date(),
      mtime: new Date(),
      ctime: new Date(),
    };
    this._emit(abspath, dirpath, filename, createNew ? 'rename' : 'change');
    return content;
  }

  _remove(_path, testFn) {
    let abspath = normalize(_path);

    if (isReservePath(abspath)) {
      throw new XFileSystemError(errors.code.EPERM, abspath);
    }
    let dirpath = dirname(abspath);
    let dir = this._meta(dirpath);
    let filename = basename(abspath);
    if (!isDir(dir) || !(filename in dir) || !testFn(dir[filename])) {
      throw new XFileSystemError(errors.code.ENOENT, abspath);
    }
    delete dir[filename];
    delete this._stats[abspath];
    this._emit(abspath, dirpath, filename, 'rename');
  }

  access = this._syncToCb('access');
  accessSync = NotImplemented;
  appendFile = this._syncToCb('appendFile');
  appendFileSync = NotImplemented;
  chmod = this._syncToCb('chmod');
  chmodSync = NotImplemented;
  chown = this._syncToCb('chown');
  chownSync = NotImplemented;
  close = this._syncToCb('close');
  closeSync = NotImplemented;

  get constants() {
    NotImplemented();
  }

  createReadStream = NotImplemented;
  createWriteStream = NotImplemented;
  exists = NotImplemented;
  existsSync = (p) => exists(this._meta(p));
  fchmod = this._syncToCb('fchmod');
  fchmodSync = NotImplemented;
  fchown = this._syncToCb('fchown');
  fchownSync = NotImplemented;
  fdatasync = this._syncToCb('fdatasync');
  fdatasyncSync = NotImplemented;
  fstat = this._syncToCb('fstat');
  fstatSync = NotImplemented;
  fsync = this._syncToCb('fsync');
  fsyncSync = NotImplemented;
  ftruncate = this._syncToCb('ftruncate');
  ftruncateSync = NotImplemented;
  futimes = this._syncToCb('futimes');
  futimesSync = NotImplemented;
  lchmod = this._syncToCb('lchmod');
  lchmodSync = NotImplemented;
  lchown = this._syncToCb('lchown');
  lchownSync = NotImplemented;
  link = this._syncToCb('link');
  linkSync = NotImplemented;
  lstat = this._syncToCb('lstat');

  lstatSync(_path) {
    let abspath = normalize(_path);
    let current = this._meta(abspath);
    if (!isDir(current) && !isFile(current)) {
      throw new XFileSystemError(errors.code.ENOENT, _path);
    }
    let stats = {
      isFile: falseFn,
      isDirectory: falseFn,
      isBlockDevice: falseFn,
      isCharacterDevice: falseFn,
      isSymbolicLink: falseFn,
      isFIFO: falseFn,
      isSocket: falseFn,
      ...this._stats[abspath]
    };
    stats[isDir(current) ? 'isDirectory' : 'isFile'] = trueFn;
    return stats;
  };

  mkdir = this._syncToCb('mkdir');

  mkdirSync(_path) {
    const abspath = normalize(_path);
    const path = pathToArray(abspath);
    if (path.length === 0) {
      throw new XFileSystemError(errors.code.EEXIST, abspath);
    }
    let current = this.data;
    let i;
    for (i = 0; i < path.length - 1; i++) {
      if (!isDir(current[path[i]]))
        throw new XFileSystemError(errors.code.ENOENT, abspath);
      current = current[path[i]];
    }
    if (isDir(current[path[i]])) {
      throw new XFileSystemError(errors.code.EEXIST, abspath);
    } else if (isFile(current[path[i]])) {
      throw new XFileSystemError(errors.code.ENOTDIR, abspath);
    }
    let local = path[0] != node_modules ? true : null;

    this._write(current, abspath, {'': local});
  }

  mkdirp = this._syncToCb('mkdirp');

  mkdirpSync(_path) {
    const abspath = normalize(_path);
    const path = pathToArray(abspath);
    let current = this.data;
    let currentPath = '/';
    let local = path[0] != node_modules ? true : null;
    for (let token of path) {
      if (isFile(current[token])) {
        throw new XFileSystemError(errors.code.ENOTDIR, abspath);
      } else if (isDir(current[token])) {
        current = current[token];
      } else {
        if (currentPath != '/') {
          currentPath += '/';
        }
        currentPath += token;
        current = this._write(current, currentPath, {'': local});
      }
    }
    return current;
  }

  mkdtemp = this._syncToCb('mkdtemp');
  mkdtempSync = NotImplemented;
  open = this._syncToCb('open');
  openSync = NotImplemented;
  read = this._syncToCb('read');
  readdir = this._remote('readdir', true);

  readdirSync(path) {
    let abspath = normalize(path);
    let current = this._meta(abspath);
    if (!isDir(current)) {
      throw new XFileSystemError(errors.code[isFile(current) ? 'ENOTDIR' : 'ENOENT'], abspath);
    }
    return Object.keys(current).filter(Boolean);
  };

  readFile = this._remote('readFile', false);

  readFileSync(_path, options) {
    let encoding = typeof options == 'object' ? options.encoding : options;
    const abspath = normalize(_path);
    let current = this._meta(abspath);
    if (!isFile(current)) {
      throw new XFileSystemError(errors.code[isDir(current) ? 'EISDIR' : 'ENOENT'], abspath);
    }
    return encoding ? current.toString(encoding) : current;
  }
  readlink = this._syncToCb('readlink');
  readlinkSync = NotImplemented;
  readSync = NotImplemented;
  realpath = this._syncToCb('realpath');
  realpathSync = normalize;
  rename = this._syncToCb('rename');
  renameSync = NotImplemented;
  rmdir = this._syncToCb('rmdir');
  rmdirSync = (path) => this._remove(path, isDir);
  stat = this._syncToCb('stat');
  statSync = this.lstatSync;
  symlink = this._syncToCb('symlink');
  symlinkSync = NotImplemented;
  truncate = this._syncToCb('truncate');
  truncateSync = NotImplemented;
  unlink = this._syncToCb('unlink');
  unlinkSync = (path) => this._remove(path, isFile);
  unwatchFile = NotImplemented;
  utimes = this._syncToCb('utimes');
  utimesSync = NotImplemented;

  watch(filename, options, listener) {
    options = options || {};
    if (typeof options === 'function') {
      listener = options;
      options = {};
    } else if (typeof options === 'string') {
      options = {encoding: options};
    }
    if (typeof options !== 'object')
      throw new TypeError('"options" must be a string or an object');

    const watcher = new FSWatcher(this);
    watcher.start(normalize(filename), options.encoding);
    if (listener) {
      watcher.addListener('change', listener);
    }
    return watcher;
  }

  watchFile = this.watch;
  write = NotImplemented;
  writeFile = this._syncToCb('writeFile');

  writeFileSync(_path, content, options) {
    let abspath = normalize(_path);
    let encoding = typeof options == 'object' ? options.encoding : options;
    let path = pathToArray(abspath);
    if (path.length === 0) {
      throw new XFileSystemError(errors.code.EISDIR, abspath);
    }
    let local = path[0] != node_modules ? true : null;
    let current = this.data;
    for (let i = 0; i < path.length - 1; i++) {
      if (isFile(current[path[i]])) {
        throw new XFileSystemError(errors.code.EEXIST, abspath);
      } else if (isDir(current[path[i]])) {
        current = current[path[i]];
      } else {
        current[path[i]] = {'': local};
        current = current[path[i]];
      }
    }
    if (isDir(current[path[path.length - 1]])) {
      throw new XFileSystemError(errors.code.EISDIR, abspath);
    }
    this._write(current, abspath, encoding || typeof content === "string" ? new Buffer(content, encoding) : content)
  }

  writeSync = NotImplemented;
}

XFileSystem.FSWatch = FSWatcher;
XFileSystem.ReadStream = NotImplemented;
XFileSystem.WriteStream = NotImplemented;
<commit_msg>callback should be in next tick<commit_after>import {basename, dirname, normalize as _normalize, resolve} from "path";
import FSWatcher from "./FSWatcher";
const errors = require("errno");
const node_modules = 'node_modules';
let normalize = (_path) => resolve('/', _normalize(_path));

class XFileSystemError extends Error {
  constructor(err, path) {
    super();
    Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
    this.code = err.code;
    this.errno = err.errno;
    this.message = err.description;
    this.path = path;
  }
}
// directory is an object with '' prop, {'':true}(normal dir) {'':null}(remote dir)
function isDir(item) {
  return item && typeof item == "object" && ('' in item);
}

// File is Buffer or null(from remote)
function isFile(item) {
  return item instanceof Buffer
}

function exists(item) {
  return item != undefined;
}
function pathToArray(abspath) {
  let path = normalize(abspath).substr(1).split("/");
  if (path.length > 0 && !path[path.length - 1]) path.pop();
  return path;
}

const trueFn = () => true;
const falseFn = () => false;

function isReservePath(abspath) {
  return abspath == '/' || abspath == `/${node_modules}`;
}
function NotImplemented() {
  throw new XFileSystemError(errors.code.ENOSYS);
}
export function inLib(path) {
  return normalize(path).indexOf(node_modules) == 1;
}
const libPrefixLength = node_modules.length + 1;

export default class XFileSystem {
  data = {'': true};
  _stats = {'/': {birthtime: new Date(), mode: 16877, atime: new Date(), mtime: new Date(), ctime: new Date()}};
  _watcher = {};
  _fetch;

  constructor(fetch) {
    this._fetch = fetch;
    this.mkdirSync(node_modules);
    this.data.node_modules[''] = null;
  }

  /**
   * helper method
   * @param abspath
   * @returns {*}
   */
  _meta(abspath) {
    const path = pathToArray(abspath);
    let current = this.data;
    for (let token of path) {
      if (!isDir(current))
        return;
      current = current[token];
    }
    return current;
  }

  _syncToCb = (fn) => {
    let fs = this;
    return function () {
      let path = arguments[0];
      let args = Array.prototype.slice.call(arguments, 1, arguments.length - 1);
      let callback = arguments[arguments.length - 1];
      if (typeof path != 'string') {
        setImmediate(() => callback(new TypeError('path must be a string')));
        return
      }
      if (typeof callback != 'function') {
        args.push(callback);
        callback = falseFn;
      }
      let result;
      try {
        result = fs[fn + "Sync"](path, ...args);
      } catch (e) {
        setImmediate(() => callback(e));
        return;
      }
      setImmediate(() => callback(null, result));
    }
  };
  _remote = (fn, shouldBeDir) => {
    let fs = this;
    return function () {
      let path = arguments[0];
      let args = Array.prototype.slice.call(arguments, 1, arguments.length - 1);
      let callback = arguments[arguments.length - 1];
      if (!path || !(typeof path == 'string')) {
        throw new TypeError('path must be a string');
      }
      if (typeof callback != 'function') {
        args.push(callback);
        callback = falseFn;
      }
      let abspath = normalize(path);
      let result;
      try {
        result = fs[fn + 'Sync'](abspath, ...args);
      } catch (e) {

        if (!inLib(abspath)) {
          setImmediate(() => callback(e));
          return;
        }
        fs._fetch(abspath.substr(libPrefixLength), shouldBeDir)
          .then((textOrArray) => {
            if (shouldBeDir) {
              let dir = fs.mkdirpSync(abspath);
              dir[''] = true;
              for (let sub of textOrArray) {
                if (sub[sub.length - 1] == '/') { // dir
                  sub = sub.substr(0, sub.length - 1);
                  if (dir[sub]) {
                    if (!isDir(dir[sub])) {
                      return callback(new XFileSystemError(errors.code.EEXIST, abspath + '/' + sub))
                    }
                  } else {
                    this._write(dir, abspath + '/' + sub, {'': null});
                  }
                } else { // remote file
                  this._write(dir, abspath + '/' + sub, null);
                }
              }
            } else {
              fs.writeFileSync(abspath, textOrArray);
            }
            try {
              result = fs[fn + 'Sync'](abspath, ...args)
            } catch (e) {
              callback(e);
              return;
            }
            callback(null, result);
          })
          .catch((e2) => callback(e));
        return;
      }
      setImmediate(() => callback(null, result));
    }
  };

  _emit(abspath, dirpath, filename, type) {
    this._watcher[dirpath] && this._watcher[dirpath].emit('watch', type, filename);
    this._watcher[abspath] && this._watcher[abspath].emit('watch', type, filename);
  }

  _write(current, abspath, content) {
    let dirpath = dirname(abspath);
    let filename = basename(abspath);
    current[filename] = content;

    let createNew = !this._stats[abspath];
    let stats = createNew
      ? {
        birthtime: new Date(),
        mode: isDir(content) ? 16877 /* Oct 40755 */ : 33188 /* Oct 100644 */
      }
      : this._stats[abspath];

    this._stats[abspath] = {
      ...stats,
      atime: new Date(),
      mtime: new Date(),
      ctime: new Date(),
    };
    this._emit(abspath, dirpath, filename, createNew ? 'rename' : 'change');
    return content;
  }

  _remove(_path, testFn) {
    let abspath = normalize(_path);

    if (isReservePath(abspath)) {
      throw new XFileSystemError(errors.code.EPERM, abspath);
    }
    let dirpath = dirname(abspath);
    let dir = this._meta(dirpath);
    let filename = basename(abspath);
    if (!isDir(dir) || !(filename in dir) || !testFn(dir[filename])) {
      throw new XFileSystemError(errors.code.ENOENT, abspath);
    }
    delete dir[filename];
    delete this._stats[abspath];
    this._emit(abspath, dirpath, filename, 'rename');
  }

  access = this._syncToCb('access');
  accessSync = NotImplemented;
  appendFile = this._syncToCb('appendFile');
  appendFileSync = NotImplemented;
  chmod = this._syncToCb('chmod');
  chmodSync = NotImplemented;
  chown = this._syncToCb('chown');
  chownSync = NotImplemented;
  close = this._syncToCb('close');
  closeSync = NotImplemented;

  get constants() {
    NotImplemented();
  }

  createReadStream = NotImplemented;
  createWriteStream = NotImplemented;
  exists = NotImplemented;
  existsSync = (p) => exists(this._meta(p));
  fchmod = this._syncToCb('fchmod');
  fchmodSync = NotImplemented;
  fchown = this._syncToCb('fchown');
  fchownSync = NotImplemented;
  fdatasync = this._syncToCb('fdatasync');
  fdatasyncSync = NotImplemented;
  fstat = this._syncToCb('fstat');
  fstatSync = NotImplemented;
  fsync = this._syncToCb('fsync');
  fsyncSync = NotImplemented;
  ftruncate = this._syncToCb('ftruncate');
  ftruncateSync = NotImplemented;
  futimes = this._syncToCb('futimes');
  futimesSync = NotImplemented;
  lchmod = this._syncToCb('lchmod');
  lchmodSync = NotImplemented;
  lchown = this._syncToCb('lchown');
  lchownSync = NotImplemented;
  link = this._syncToCb('link');
  linkSync = NotImplemented;
  lstat = this._syncToCb('lstat');

  lstatSync(_path) {
    let abspath = normalize(_path);
    let current = this._meta(abspath);
    if (!isDir(current) && !isFile(current)) {
      throw new XFileSystemError(errors.code.ENOENT, _path);
    }
    let stats = {
      isFile: falseFn,
      isDirectory: falseFn,
      isBlockDevice: falseFn,
      isCharacterDevice: falseFn,
      isSymbolicLink: falseFn,
      isFIFO: falseFn,
      isSocket: falseFn,
      ...this._stats[abspath]
    };
    stats[isDir(current) ? 'isDirectory' : 'isFile'] = trueFn;
    return stats;
  };

  mkdir = this._syncToCb('mkdir');

  mkdirSync(_path) {
    const abspath = normalize(_path);
    const path = pathToArray(abspath);
    if (path.length === 0) {
      throw new XFileSystemError(errors.code.EEXIST, abspath);
    }
    let current = this.data;
    let i;
    for (i = 0; i < path.length - 1; i++) {
      if (!isDir(current[path[i]]))
        throw new XFileSystemError(errors.code.ENOENT, abspath);
      current = current[path[i]];
    }
    if (isDir(current[path[i]])) {
      throw new XFileSystemError(errors.code.EEXIST, abspath);
    } else if (isFile(current[path[i]])) {
      throw new XFileSystemError(errors.code.ENOTDIR, abspath);
    }
    let local = path[0] != node_modules ? true : null;

    this._write(current, abspath, {'': local});
  }

  mkdirp = this._syncToCb('mkdirp');

  mkdirpSync(_path) {
    const abspath = normalize(_path);
    const path = pathToArray(abspath);
    let current = this.data;
    let currentPath = '/';
    let local = path[0] != node_modules ? true : null;
    for (let token of path) {
      if (isFile(current[token])) {
        throw new XFileSystemError(errors.code.ENOTDIR, abspath);
      } else if (isDir(current[token])) {
        current = current[token];
      } else {
        if (currentPath != '/') {
          currentPath += '/';
        }
        currentPath += token;
        current = this._write(current, currentPath, {'': local});
      }
    }
    return current;
  }

  mkdtemp = this._syncToCb('mkdtemp');
  mkdtempSync = NotImplemented;
  open = this._syncToCb('open');
  openSync = NotImplemented;
  read = this._syncToCb('read');
  readdir = this._remote('readdir', true);

  readdirSync(path) {
    let abspath = normalize(path);
    let current = this._meta(abspath);
    if (!isDir(current)) {
      throw new XFileSystemError(errors.code[isFile(current) ? 'ENOTDIR' : 'ENOENT'], abspath);
    }
    return Object.keys(current).filter(Boolean);
  };

  readFile = this._remote('readFile', false);

  readFileSync(_path, options) {
    let encoding = typeof options == 'object' ? options.encoding : options;
    const abspath = normalize(_path);
    let current = this._meta(abspath);
    if (!isFile(current)) {
      throw new XFileSystemError(errors.code[isDir(current) ? 'EISDIR' : 'ENOENT'], abspath);
    }
    return encoding ? current.toString(encoding) : current;
  }

  readlink = this._syncToCb('readlink');
  readlinkSync = NotImplemented;
  readSync = NotImplemented;
  realpath = this._syncToCb('realpath');
  realpathSync = normalize;
  rename = this._syncToCb('rename');
  renameSync = NotImplemented;
  rmdir = this._syncToCb('rmdir');
  rmdirSync = (path) => this._remove(path, isDir);
  stat = this._syncToCb('stat');
  statSync = this.lstatSync;
  symlink = this._syncToCb('symlink');
  symlinkSync = NotImplemented;
  truncate = this._syncToCb('truncate');
  truncateSync = NotImplemented;
  unlink = this._syncToCb('unlink');
  unlinkSync = (path) => this._remove(path, isFile);
  unwatchFile = NotImplemented;
  utimes = this._syncToCb('utimes');
  utimesSync = NotImplemented;

  watch(filename, options, listener) {
    options = options || {};
    if (typeof options === 'function') {
      listener = options;
      options = {};
    } else if (typeof options === 'string') {
      options = {encoding: options};
    }
    if (typeof options !== 'object')
      throw new TypeError('"options" must be a string or an object');

    const watcher = new FSWatcher(this);
    watcher.start(normalize(filename), options.encoding);
    if (listener) {
      watcher.addListener('change', listener);
    }
    return watcher;
  }

  watchFile = this.watch;
  write = NotImplemented;
  writeFile = this._syncToCb('writeFile');

  writeFileSync(_path, content, options) {
    let abspath = normalize(_path);
    let encoding = typeof options == 'object' ? options.encoding : options;
    let path = pathToArray(abspath);
    if (path.length === 0) {
      throw new XFileSystemError(errors.code.EISDIR, abspath);
    }
    let local = path[0] != node_modules ? true : null;
    let current = this.data;
    for (let i = 0; i < path.length - 1; i++) {
      if (isFile(current[path[i]])) {
        throw new XFileSystemError(errors.code.EEXIST, abspath);
      } else if (isDir(current[path[i]])) {
        current = current[path[i]];
      } else {
        current[path[i]] = {'': local};
        current = current[path[i]];
      }
    }
    if (isDir(current[path[path.length - 1]])) {
      throw new XFileSystemError(errors.code.EISDIR, abspath);
    }
    this._write(current, abspath, encoding || typeof content === "string" ? new Buffer(content, encoding) : content)
  }

  writeSync = NotImplemented;
}

XFileSystem.FSWatch = FSWatcher;
XFileSystem.ReadStream = NotImplemented;
XFileSystem.WriteStream = NotImplemented;
<|endoftext|>