<commit_before>App.DcController = Ember.Controller.extend({
  // Whether or not the dropdown menu can be seen
  isDropdownVisible: false,

  datacenter: function() {
    return this.get('content')
  }.property('Content'),

  checks: function() {
    var nodes = this.get('nodes');
    var checks = Ember.A()

    // Combine the checks from all of our nodes
    // into one.
    nodes.forEach(function(item) {
      checks = checks.concat(item.Checks)
    });

    return checks
  }.property('nodes'),

  // Returns the total number of failing checks.
  //
  // We treat any non-passing checks as failing
  //
  totalChecksFailing: function() {
    var checks = this.get('checks')
    return (checks.filterBy('Status', 'critical').get('length') +
      checks.filterBy('Status', 'warning').get('length'))
  }.property('nodes'),

  //
  // Returns the human formatted message for the button state
  //
  checkMessage: function() {
    var checks = this.get('checks')
    var failingChecks = this.get('totalChecksFailing');
    var passingChecks = checks.filterBy('Status', 'passing').get('length');

    if (this.get('hasFailingChecks') == true) {
      return  failingChecks + ' checks failing';
    } else {
      return  passingChecks + ' checks passing';
    }

  }.property('nodes'),

  //
  // Boolean if the datacenter has any failing checks.
  //
  hasFailingChecks: function() {
    var checks = this.get('checks')
    return (checks.filterBy('Status', 'critical').get('length') +
      checks.filterBy('Status', 'warning').get('length'));
  }.property('nodes'),

  actions: {
    // Hide and show the dropdown menu
    toggle: function(item){
      this.toggleProperty('isDropdownVisible');
    },
    // Just hide the dropdown menu
    hideDrop: function(item){
      this.set('isDropdownVisible', false);
    }
  }
})

// Add mixins
App.KvShowController = Ember.ObjectController.extend(Ember.Validations.Mixin);

App.KvShowController.reopen({
  needs: ["dc"],
  dc: Ember.computed.alias("controllers.dc"),
  isLoading: false,

  actions: {
    // Creates the key from the newKey model
    // set on the route.
    createKey: function() {
      this.set('isLoading', true);

      var newKey = this.get('newKey');
      var parentKey = this.get('parentKey');
      var grandParentKey = this.get('grandParentKey');
      var controller = this;
      var dc = this.get('dc').get('datacenter');

      // If we don't have a previous model to base
      // on our parent, or we're not at the root level,
      // add the prefix
      if (parentKey != undefined && parentKey != "/") {
        newKey.set('Key', (parentKey + newKey.get('Key')));
      }

      // Put the Key and the Value retrieved from the form
      Ember.$.ajax({
          url: ("/v1/kv/" + newKey.get('Key') + '?dc=' + dc),
          type: 'PUT',
          data: newKey.get('Value')
      }).then(function(response) {
        // transition to the right place
        if (newKey.get('isFolder') == true) {
          controller.transitionToRoute('kv.show', newKey.get('urlSafeKey'));
        } else {
          controller.transitionToRoute('kv.edit', newKey.get('urlSafeKey'));
        }
        controller.set('isLoading', false)
      }).fail(function(response) {
        // Render the error message on the form if the request failed
        controller.set('errorMessage', 'Received error while processing: ' + response.statusText)
      });

    }
  }
});

App.KvEditController = Ember.Controller.extend({
  isLoading: false,
  needs: ["dc"],
  dc: Ember.computed.alias("controllers.dc"),

  actions: {
    // Updates the key set as the model on the route.
    updateKey: function() {
      this.set('isLoading', true);

      var dc = this.get('dc').get('datacenter');
      var key = this.get("model");
      var controller = this;

      // Put the key and the decoded (plain text) value
      // from the form.
      Ember.$.ajax({
          url: ("/v1/kv/" + key.get('Key') + '?dc=' + dc),
          type: 'PUT',
          data: key.get('valueDecoded')
      }).then(function(response) {
        // If success, just reset the loading state.
        controller.set('isLoading', false)
      }).fail(function(response) {
        // Render the error message on the form if the request failed
        controller.set('errorMessage', 'Received error while processing: ' + response.statusText)
      })
    },

    deleteKey: function() {
      this.set('isLoading', true);
      var key = this.get("model");
      var controller = this;
      var dc = this.get('dc').get('datacenter');

      // Get the parent for the transition back up a level
      // after the delete
      var parent = key.get('urlSafeParentKey');

      // Delete the key
      Ember.$.ajax({
          url: ("/v1/kv/" + key.get('Key') + '?dc=' + dc),
          type: 'DELETE'
      }).then(function(response) {
        // Tranisiton back up a level
        controller.transitionToRoute('kv.show', parent);
        controller.set('isLoading', false);
      }).fail(function(response) {
        // Render the error message on the form if the request failed
        controller.set('errorMessage', 'Received error while processing: ' + response.statusText)
      })

    }
  }

});
<commit_msg>ui: fix dc # of failing checks<commit_after>App.DcController = Ember.Controller.extend({
  // Whether or not the dropdown menu can be seen
  isDropdownVisible: false,

  datacenter: function() {
    return this.get('content')
  }.property('Content'),

  checks: function() {
    var nodes = this.get('nodes');
    var checks = Ember.A()

    // Combine the checks from all of our nodes
    // into one.
    nodes.forEach(function(item) {
      checks = checks.concat(item.Checks)
    });

    return checks
  }.property('nodes'),

  // Returns the total number of failing checks.
  //
  // We treat any non-passing checks as failing
  //
  totalChecksFailing: function() {
    var checks = this.get('checks')
    return (checks.filterBy('Status', 'critical').get('length') +
      checks.filterBy('Status', 'warning').get('length'))
  }.property('nodes'),

  //
  // Returns the human formatted message for the button state
  //
  checkMessage: function() {
    var checks = this.get('checks')
    var failingChecks = this.get('totalChecksFailing');
    var passingChecks = checks.filterBy('Status', 'passing').get('length');

    if (this.get('hasFailingChecks') == true) {
      return  failingChecks + ' checks failing';
    } else {
      return  passingChecks + ' checks passing';
    }

  }.property('nodes'),

  //
  // Boolean if the datacenter has any failing checks.
  //
  hasFailingChecks: function() {
    var failingChecks = this.get('totalChecksFailing')
    return (failingChecks > 0);
  }.property('nodes'),

  actions: {
    // Hide and show the dropdown menu
    toggle: function(item){
      this.toggleProperty('isDropdownVisible');
    },
    // Just hide the dropdown menu
    hideDrop: function(item){
      this.set('isDropdownVisible', false);
    }
  }
})

// Add mixins
App.KvShowController = Ember.ObjectController.extend(Ember.Validations.Mixin);

App.KvShowController.reopen({
  needs: ["dc"],
  dc: Ember.computed.alias("controllers.dc"),
  isLoading: false,

  actions: {
    // Creates the key from the newKey model
    // set on the route.
    createKey: function() {
      this.set('isLoading', true);

      var newKey = this.get('newKey');
      var parentKey = this.get('parentKey');
      var grandParentKey = this.get('grandParentKey');
      var controller = this;
      var dc = this.get('dc').get('datacenter');

      // If we don't have a previous model to base
      // on our parent, or we're not at the root level,
      // add the prefix
      if (parentKey != undefined && parentKey != "/") {
        newKey.set('Key', (parentKey + newKey.get('Key')));
      }

      // Put the Key and the Value retrieved from the form
      Ember.$.ajax({
          url: ("/v1/kv/" + newKey.get('Key') + '?dc=' + dc),
          type: 'PUT',
          data: newKey.get('Value')
      }).then(function(response) {
        // transition to the right place
        if (newKey.get('isFolder') == true) {
          controller.transitionToRoute('kv.show', newKey.get('urlSafeKey'));
        } else {
          controller.transitionToRoute('kv.edit', newKey.get('urlSafeKey'));
        }
        controller.set('isLoading', false)
      }).fail(function(response) {
        // Render the error message on the form if the request failed
        controller.set('errorMessage', 'Received error while processing: ' + response.statusText)
      });

    }
  }
});

App.KvEditController = Ember.Controller.extend({
  isLoading: false,
  needs: ["dc"],
  dc: Ember.computed.alias("controllers.dc"),

  actions: {
    // Updates the key set as the model on the route.
    updateKey: function() {
      this.set('isLoading', true);

      var dc = this.get('dc').get('datacenter');
      var key = this.get("model");
      var controller = this;

      // Put the key and the decoded (plain text) value
      // from the form.
      Ember.$.ajax({
          url: ("/v1/kv/" + key.get('Key') + '?dc=' + dc),
          type: 'PUT',
          data: key.get('valueDecoded')
      }).then(function(response) {
        // If success, just reset the loading state.
        controller.set('isLoading', false)
      }).fail(function(response) {
        // Render the error message on the form if the request failed
        controller.set('errorMessage', 'Received error while processing: ' + response.statusText)
      })
    },

    deleteKey: function() {
      this.set('isLoading', true);
      var key = this.get("model");
      var controller = this;
      var dc = this.get('dc').get('datacenter');

      // Get the parent for the transition back up a level
      // after the delete
      var parent = key.get('urlSafeParentKey');

      // Delete the key
      Ember.$.ajax({
          url: ("/v1/kv/" + key.get('Key') + '?dc=' + dc),
          type: 'DELETE'
      }).then(function(response) {
        // Tranisiton back up a level
        controller.transitionToRoute('kv.show', parent);
        controller.set('isLoading', false);
      }).fail(function(response) {
        // Render the error message on the form if the request failed
        controller.set('errorMessage', 'Received error while processing: ' + response.statusText)
      })

    }
  }

});
<|endoftext|>


<commit_before>var _          = require('lodash');
var async      = require('async');
var ripple     = require('ripple-lib');
var server_lib = require('../lib/server-lib');
var validator  = require('../lib/schema-validator');
var remote     = require(__dirname+'/../lib/remote.js');
var dbinterface = require(__dirname+'/../lib/db-interface.js');

module.exports = {
  DEFAULT_RESULTS_PER_PAGE: 10,
  NUM_TRANSACTION_TYPES: 5,
  DEFAULT_LEDGER_BUFFER: 6,
  submit: submitTransaction,
  get: getTransaction,
  getTransactionHelper: getTransactionHelper,
  getAccountTransactions: getAccountTransactions
};

/**
 *  Submit a normal ripple-lib transaction, blocking duplicates
 *  for payments and orders.
 *
 *  @param {Remote} remote
 *  @param {/lib/db-interface} dbinterface
 *  @param {Transaction} data.transaction
 *  @param {String} data.secret
 *  @param {String} data.client_resource_id
 *  @param {Express.js Response} res Used to send error messages directly to the client
 *  @param {Function} callback
 *
 *  @callback
 *  @param {Error} error Submission Error
 *  @param {submission response} response The response received from the 'proposed' event
 */
function submitTransaction(data, response, callback) {

  function ensureConnected(async_callback) {
    server_lib.ensureConnected(remote, function(error, connected) {
      if (connected) {
        async_callback();
      } else if (error) {
        response.json(500, {
          success: false,
          message: error.message
        });
      } else {
        response.json(500, {
          success: false,
          message: 'No connection to rippled'
        });
      }
    });
  };

  function prepareTransaction(async_callback) {
    data.transaction.secret(data.secret);
    data.transaction.clientID(data.client_resource_id);
    async_callback(null, data.transaction);
  };

  function blockDuplicates(transaction, async_callback) {
    var type = transaction.tx_json.TransactionType;
    if (type !== 'Payment' && type !== 'OfferCreate' && type !== 'OfferCancel') {
      return async_callback(null, transaction);
    }
    dbinterface.getTransaction({
      source_account: transaction.tx_json.Account,
      client_resource_id: data.client_resource_id,
      type: transaction.tx_json.TransactionType.toLowerCase()
    }, function(error, db_record) {
        if (error) {
          return async_callback(error);
        }
        if (db_record && db_record.state !== 'failed') {
          response.json(500, {
            success: false,
            message: 'Duplicate Transaction. ' +
            'A record already exists in the database for a transaction of this type ' +
            'with the same client_resource_id. If this was not an accidental resubmission ' +
            'please submit the transaction again with a unique client_resource_id'
          });
        } else {
          async_callback(null, transaction);
        }
    });
  };

  function submitTransaction(transaction, async_callback) {
    transaction.remote = remote;
    transaction.lastLedger(Number(remote._ledger_current_index) + module.exports.DEFAULT_LEDGER_BUFFER);
    transaction.once('error', async_callback);
    transaction.once('proposed', function() {
      transaction.removeListener('error', async_callback);
      async_callback(null, transaction._clientID);
    });
    transaction.submit();
  };

  var steps = [
    ensureConnected,
    prepareTransaction,
    blockDuplicates,
    submitTransaction
  ];
  async.waterfall(steps, callback);
};

/**
 *  Wrapper around getTransactionHelper function that is
 *  meant to be used directly as a client-facing function.
 *  Unlike getTransactionHelper, it will call next with any errors
 *  and send a JSON response to the client on success.
 *
 *  See getTransactionHelper for parameter details
 */
function getTransaction(request, response, next) {
  getTransactionHelper(request, response, function(error, transaction) {
    if (error) {
      next(error);
    } else {
      response.json(200, {
        success: true,
        transaction: transaction
      });
    }
  });
};

/**
 *  Retrieve a transaction from the Remote and local database
 *  based on the account and either hash or client_resource_id.
 *
 *  Note that if any errors are encountered while executing this function
 *  they will be sent back to the client through the res. If the query is
 *  successful it will be passed to the callback function which can either
 *  send the transaction directly back to the client (e.g. in the case of
 *  getTransaction) or can process the transaction more (e.g. in the case
 *  of the Notification or Payment related functions).
 *
 *  @param {Remote} remote
 *  @param {/lib/db-interface} dbinterface
 *  @param {RippleAddress} req.params.account
 *  @param {Hex-encoded String|ASCII printable character String} req.params.identifier
 *  @param {Express.js Response} res
 *  @param {Function} callback
 *
 *  @callback
 *  @param {Error} error
 *  @param {Transaction} transaction
 */
function getTransactionHelper(request, response, callback) {
  var options = {
    account: request.params.account,
    identifier: request.params.identifier
  };

  var steps = [
    validateOptions,
    ensureConnected,
    queryTransaction,
    checkIfRelatedToAccount,
    attachResourceID,
    attachDate
  ];

  async.waterfall(steps, callback);

  function validateOptions(async_callback) {
    if (options.account && !validator.isValid(options.account, 'RippleAddress')) {
      return response.json(400, {
        success: false,
        message: 'Invalid parameter: account. Must be a valid Ripple Address'
      });
    }

    if (!options.identifier) {
      return response.json(400, {
        success: false,
        message: 'Missing parameter: identifier'
      });
    }

    if (validator.isValid(options.identifier, 'Hash256')) {
      options.hash = options.identifier;
      async_callback();
    } else if (validator.isValid(options.identifier, 'ResourceId')) {
      options.client_resource_id = options.identifier;
      async_callback();
    } else {
      response.json(400, {
        success: false,
        message: 'Parameter not a valid transaction hash or client_resource_id: identifier'
      });
    }
  };

  function ensureConnected(async_callback) {
    server_lib.ensureConnected(remote, function(error, connected){
      if (connected) {
        async_callback();
      } else if (error) {
        response.json(500, {
          success: false,
          message: error.message
        });
      } else {
        response.json(500, {
          success: false,
          message: 'No connection to rippled'
        });
      }
    });
  };

  function queryTransaction(async_callback) {
    dbinterface.getTransaction(options, function(error, entry) {
      if (error) {
        return response.json(500, {
          success: false,
          message: 'Error querying transaction'
        });
      }

      if (!(entry || options.hash)) {
        // Need transaction hash
        return response.json(404, {
          success: false,
          message: 'Transaction not found'
        });
      }

      if (options.hash && entry) {
        // Verify that transaction hashes match
        if (options.hash !== entry.transaction.hash) {
          return response.json(404, {
            success: false,
            message: 'Transaction not found'
          });
        }
      }

      var transactionHash = options.hash || entry.transaction.hash;

      remote.requestTx(transactionHash, function(error, transaction) {
        if (entry && transaction) {
          transaction.client_resource_id = entry.client_resource_id;
        }
        async_callback(error, transaction);
      });
    });
  };

  function checkIfRelatedToAccount(transaction, async_callback) {
    if (options.account) {
      var transaction_string = JSON.stringify(transaction);
      var account_regex = new RegExp(options.account);
      if (!account_regex.test(transaction_string)) {
        return response.json(400, {
          success: false,
          message: 'Transaction specified did not affect the given account'
        });
      }
    }

    async_callback(null, transaction);
  };

  function attachResourceID(transaction, async_callback) {
    if (transaction && options.client_resource_id) {
      transaction.client_resource_id = options.client_resource_id;
    }
    async_callback(null, transaction);
  };

  function attachDate(transaction, async_callback) {
    if (!transaction || transaction.date || !transaction.ledger_index) {
      return async_callback(null, transaction);
    }

    remote.requestLedger(transaction.ledger_index, function(error, ledger_res) {
      if (error) {
        return response.json(404, {
          success: false,
          message: 'Transaction ledger not found'
        });
      }

      if (typeof ledger_res.ledger.close_time === 'number') {
        transaction.date = ledger_res.ledger.close_time;
      }

      async_callback(null, transaction);
    });
  };

};

/**
 *  Recursively get transactions for the specified account from
 *  the Remote and local database. If options.min is set, this will
 *  recurse until it has retrieved that number of transactions or
 *  it has reached the end of the account's transaction history.
 *
 *  @param {Remote} remote
 *  @param {/lib/db-interface} dbinterface
 *  @param {RippleAddress} options.account
 *  @param {Number} [-1] options.ledger_index_min
 *  @param {Number} [-1] options.ledger_index_max
 *  @param {Boolean} [false] options.earliest_first
 *  @param {Boolean} [false] options.binary
 *  @param {Boolean} [false] options.exclude_failed
 *  @param {Number} [DEFAULT_RESULTS_PER_PAGE] options.min
 *  @param {Number} [DEFAULT_RESULTS_PER_PAGE] options.max
 *  @param {Array of Strings} options.types Possible values are "payment", "offercreate", "offercancel", "trustset", "accountset"
 *  @param {opaque value} options.marker
 *  @param {Array of Transactions} options.previous_transactions Included automatically when this function is called recursively
 *  @param {Express.js Response} res
 *  @param {Function} callback
 *
 *  @callback
 *  @param {Error} error
 *  @param {Array of transactions in JSON format} transactions
 */
function getAccountTransactions(options, response, callback) {
  var steps = [
    validateOptions,
    ensureConnected,
    queryTransactions,
    filterTransactions,
    sortTransactions,
    mergeAndTruncateResults
  ];
  async.waterfall(steps, asyncWaterfallCallback);
  if (!options.min) {
    options.min = module.exports.DEFAULT_RESULTS_PER_PAGE;
  }
  if (!options.max) {
    options.max = Math.max(options.min, module.exports.DEFAULT_RESULTS_PER_PAGE);
  }
  if (!options.limit) {
    options.limit = Math.max(options.max, module.exports.DEFAULT_RESULTS_PER_PAGE);
  }

  function validateOptions(async_callback) {
    if (!options.account) {
      return response.json(400, {
        success: false,
        message: 'Missing parameter: account. ' +
        'Must supply a valid Ripple Address to query account transactions'
      });
    }
    if (!validator.isValid(options.account, 'RippleAddress')) {
      return response.json(400, {
        success: false,
        message: 'Invalid parameter: account. ' +
        'Must supply a valid Ripple Address to query account transactions'
      });
    }
    async_callback();
  };

  function ensureConnected(async_callback) {
    server_lib.ensureConnected(remote, function(error, connected){
      if (connected) {
        async_callback();
      } else if (error) {
        response.json(500, {
          success: false,
          message: error.message
        });
      } else {
        response.json(500, {
          success: false,
          message: 'No connection to rippled'
        });
      }
    });
  };

  function queryTransactions(async_callback) {
    getLocalAndRemoteTransactions(options, async_callback);
  };

  function filterTransactions(transactions, async_callback) {
    async_callback(null, transactionFilter(transactions, options));
  };

  function sortTransactions(transactions, async_callback) {
    transactions.sort(function(first, second) {
      return compareTransactions(first, second, options.earliest_first);
    });
    async_callback(null, transactions);
  };

  function mergeAndTruncateResults(transactions, async_callback) {
    if (options.previous_transactions && options.previous_transactions.length > 0) {
      transactions = options.previous_transactions.concat(transactions);
    }
    if (options.offset && options.offset > 0) {
      var offset_remaining = options.offset - transactions.length;
      transactions = transactions.slice(options.offset);
      options.offset = offset_remaining;
    }
    if (transactions.length > options.max) {
      transactions = transactions.slice(0, options.max);
    }
    async_callback(null, transactions);
  };

  function asyncWaterfallCallback(error, transactions) {
    if (error) {
      return callback(error);
    }
    if (!options.min || transactions.length >= options.min || !options.marker) {
      callback(null, transactions);
    } else {
      options.previous_transactions = transactions;
      setImmediate(function() {
        getAccountTransactions(options, response, callback);
      });
    }
  };
};

/**
 *  Retrieve transactions from the Remote as well as the local database.
 *
 *  @param {Remote} remote
 *  @param {/lib/db-interface} dbinterface
 *  @param {RippleAddress} options.account
 *  @param {Number} [-1] options.ledger_index_min
 *  @param {Number} [-1] options.ledger_index_max
 *  @param {Boolean} [false] options.earliest_first
 *  @param {Boolean} [false] options.binary
 *  @param {Boolean} [false] options.exclude_failed
 *  @param {opaque value} options.marker
 *  @param {Function} callback
 *
 *  @callback
 *  @param {Error} error
 *  @param {Array of transactions in JSON format} transactions
 */
function getLocalAndRemoteTransactions(options, callback) {

  function queryRippled(callback) {
    getAccountTx(remote, options, function(error, results) {
      if (error) {
        callback(error);
      } else {
        // Set marker so that when this function is called again
        // recursively it starts from the last place it left off
        options.marker = results.marker;

        callback(null, results.transactions);
      }
    });
  };

  function queryDB(callback) {
    if (options.exclude_failed) {
      callback(null, []);
    } else {
      dbinterface.getFailedTransactions(options, callback);
    }
  };
  var transaction_sources = [
    queryRippled,
    queryDB
  ];
  async.parallel(transaction_sources, function(error, source_results) {
    if (error) {
      return callback(error);
    }
    var results = source_results[0].concat(source_results[1]);
    var transactions = _.uniq(results, function(tx) {
      return tx.hash;
    });
    callback(null, transactions);
  });
};

/**
 *  Filter transactions based on the given set of options.
 *
 *  @param {Array of transactions in JSON format} transactions
 *  @param {Boolean} [false] options.exclude_failed
 *  @param {Array of Strings} options.types Possible values are "payment", "offercreate", "offercancel", "trustset", "accountset"
 *  @param {RippleAddress} options.source_account
 *  @param {RippleAddress} options.destination_account
 *  @param {String} options.direction Possible values are "incoming", "outgoing"
 *
 *  @returns {Array of transactions in JSON format} filtered_transactions
 */
function transactionFilter(transactions, options) {
  var filtered_transactions = transactions.filter(function(transaction) {
    if (options.exclude_failed) {
      if (transaction.state === 'failed' || (transaction.meta && transaction.meta.TransactionResult !== 'tesSUCCESS')) {
        return false;
      }
    }
    if (options.types && options.types.length > 0) {
      if (options.types.indexOf(transaction.TransactionType.toLowerCase()) === -1) {
        return false;
      }
    }
    if (options.source_account) {
      if (transaction.Account !== options.source_account) {
        return false;
      }
    }
    if (options.destination_account) {
      if (transaction.Destination !== options.destination_account) {
        return false;
      }
    }
    if (options.direction) {
      if (options.direction === 'outgoing' && transaction.Account !== options.account) {
        return false;
      }
      if (options.direction === 'incoming' && transaction.Destination && transaction.Destination !== options.account) {
        return false;
      }
    }
    return true;
  });
  return filtered_transactions;
};

/**
 *  Order two transactions based on their ledger_index.
 *  If two transactions took place in the same ledger, sort
 *  them based on a lexicographical comparison of their hashes
 *  to ensure the ordering is deterministic.
 *
 *  @param {transaction in JSON format} first
 *  @param {transaction in JSON format} second
 *  @param {Boolean} [false] earliest_first
 *  @returns {Number} comparison Returns -1 or 1
 */
function compareTransactions(first, second, earliest_first) {
  var first_index = first.ledger || first.ledger_index;
  var second_index = second.ledger || second.ledger_index;
  var first_less_than_second = true;
  if (first_index === second_index) {
    if (first.hash <= second.hash) {
      first_less_than_second = true;
    } else {
      first_less_than_second = false;
    }
  } else if (first_index < second_index) {
    first_less_than_second = true;
  } else {
    first_less_than_second = false;
  }
  if (earliest_first) {
    if (first_less_than_second) {
      return -1;
    } else {
      return 1;
    }
  } else  {
    if (first_less_than_second) {
      return 1;
    } else {
      return -1;
    }
  }
};

/**
 *  Wrapper around the standard ripple-lib requestAccountTx function
 *
 *  @param {Remote} remote
 *  @param {RippleAddress} options.account
 *  @param {Number} [-1] options.ledger_index_min
 *  @param {Number} [-1] options.ledger_index_max
 *  @param {Boolean} [false] options.earliest_first
 *  @param {Boolean} [false] options.binary
 *  @param {opaque value} options.marker
 *  @param {Function} callback
 *
 *  @callback
 *  @param {Error} error
 *  @param {Array of transactions in JSON format} response.transactions
 *  @param {opaque value} response.marker
 */
function getAccountTx(remote, options, callback) {
  var params = {
    account: options.account,
    ledger_index_min: options.ledger_index_min || options.ledger_index || -1,
    ledger_index_max: options.ledger_index_max || options.ledger_index || -1,
    limit: options.limit || DEFAULT_RESULTS_PER_PAGE,
    forward: options.earliest_first,
    marker: options.marker
  };
  if (options.binary) {
    params.binary = true;
  }
  remote.requestAccountTx(params, function(error, account_tx_results) {
    if (error) {
      return callback(error);
    }
    var transactions = [];
    account_tx_results.transactions.forEach(function(tx_entry) {
      if (!tx_entry.validated) return;
      var tx = tx_entry.tx;
      tx.meta = tx_entry.meta;
      transactions.push(tx);
    });
    callback(null, {
      transactions: transactions,
      marker: account_tx_results.marker
    });
  });
};
<commit_msg>Update config loader<commit_after>var fs    = require('fs');
var path = require('path');
var nconf = require('nconf');

/** Load Configuration according to the following hierarchy
 *  (where items higher on the list take precedence)
 *
 *  1. Command line arguments
 *  2. Environment variables
 *  3. The config.json file (if it exists) in the root directory
 *  4. The defaults defined below
 */

nconf.argv().env();

var config_url = nconf.get('config') || path.join(process.cwd(), 'config.json');

// Get rippled from command line args, if supplied
if (nconf.get('rippled')) {
  var match = nconf.get('rippled').match(/^(wss|ws):\/\/(.+):([0-9]+)$/);
  if (match) {
    nconf.overrides({
      rippled_servers: [{
        host: match[2],
        port: match[3],
        secure: (match[1] === 'wss')
      }]
    });
  }
}

function checkConfig() {
  // Print configuration and exit

  try {
    fs.readFileSync(config_url);
  } catch (e) {
    console.error('failed to load configuration ' + config_url);
    process.exit(1);
  }

  nconf.file(config_url);

  console.log(JSON.stringify(nconf.get(), null, 2));

  process.exit(0);
};

if (~process.argv.indexOf('--checkconfig')) {
  return checkConfig();
}

// If config.json exists, load from that
try {
  nconf.file(config_url);
} catch (e) {
}

nconf.defaults({
  PORT: 5990,
  NODE_ENV: 'development',
  HOST: 'localhost',
  // sqlite: {
  //   schemas: __dirname + '/../schemas-for-sqlite',
  //   files: __dirname + '../'
  // },
  rippled_servers: [
    {
      host: 's-west.ripple.com',
      port: 443,
      secure: true
    }
  ],
  debug: false
});

module.exports = nconf;
<|endoftext|>


<commit_before><commit_msg>Added missing comma after ready statement<commit_after><|endoftext|>


<commit_before>import React from "react";
import ReactDOM from "react-dom";
import InstitutionEditor from "./components/InstitutionEditor";

class CreateInstitution extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            institutions: [],
            newInstitutionDetails: {
                name: "",
                logo: "",
                base64Image: "",
                url: "",
                description: "",
            },
        };
    }

    componentDidMount() {
        this.getInstitutions();
    }

    getInstitutions = () => fetch(this.props.documentRoot + "/get-all-institutions")
        .then(response => response.ok ? response.json() : Promise.reject(response))
        .then(data => this.setState({ institutions: data }))
        .catch(response => {
            console.log(response);
            alert("Error downloading institution list. See console for details.");
        });

    createInstitution = () => {
        const duplicateInst = this.state.institutions.find(inst => inst.name === this.state.newInstitutionDetails.name);
        if (duplicateInst) {
            alert("An institution with this name already exists. "
                + "Either select a different name or change the name of the duplicate institution here: "
                + window.location.origin + "/review-institution?institutionId=" + duplicateInst.id);
        } else {
            fetch(this.props.documentRoot + "/create-institution",
                  {
                      method: "POST",
                      body: JSON.stringify({
                          userId: this.props.userId,
                          name: this.state.newInstitutionDetails.name,
                          logo: this.state.newInstitutionDetails.logo,
                          base64Image: this.state.newInstitutionDetails.base64Image,
                          url: this.state.newInstitutionDetails.url,
                          description: this.state.newInstitutionDetails.description,
                      }),
                  }
            )
                .then(response => Promise.all([response.ok, response.text()]))
                .then(data => {
                    const isInteger = n => !isNaN(parseInt(n)) && isFinite(n) && !n.includes(".");
                    if (isInteger(data)) {
                        window.location = this.props.documentRoot + "/review-institution?institutionId=" + data;
                        return Promise.resolve();
                    } else {
                        return Promise.reject(data[1]);
                    }
                })
                .catch(message => alert("Error creating institution.\n\n" + message));
        }
    };

    setInstitutionDetails = (key, newValue) => {
        this.setState({
            newInstitutionDetails: {
                ...this.state.newInstitutionDetails, [key]: newValue,
            },
        });
    };

    renderButtonGroup = () =>
        <input
            id="create-institution"
            className="btn btn-outline-lightgreen btn-sm btn-block"
            type="button"
            value="Create Institution"
            onClick={this.createInstitution}
            disabled={this.state.newInstitutionDetails.name === "" || this.state.newInstitutionDetails.description === ""}
        />;

    render() {
        return (
            <InstitutionEditor
                title="Create New Institution"
                name={this.state.newInstitutionDetails.name}
                logo={this.state.newInstitutionDetails.logo}
                url={this.state.newInstitutionDetails.url}
                description={this.state.newInstitutionDetails.description}
                buttonGroup={this.renderButtonGroup}
                setInstitutionDetails={this.setInstitutionDetails}
            />
        );
    }
}

export function renderCreateInstitutionPage(args) {
    ReactDOM.render(
        <CreateInstitution
            documentRoot={args.documentRoot}
            userId={args.userId === "" ? -1 : parseInt(args.userId)}
        />,
        document.getElementById("institution")
    );
}
<commit_msg>fix merge<commit_after>import React from "react";
import ReactDOM from "react-dom";
import InstitutionEditor from "./components/InstitutionEditor";

class CreateInstitution extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            institutions: [],
            newInstitutionDetails: {
                name: "",
                logo: "",
                base64Image: "",
                url: "",
                description: "",
            },
        };
    }

    componentDidMount() {
        this.getInstitutions();
    }

    getInstitutions = () => fetch(this.props.documentRoot + "/get-all-institutions")
        .then(response => response.ok ? response.json() : Promise.reject(response))
        .then(data => this.setState({ institutions: data }))
        .catch(response => {
            console.log(response);
            alert("Error downloading institution list. See console for details.");
        });

    createInstitution = () => {
        const duplicateInst = this.state.institutions.find(inst => inst.name === this.state.newInstitutionDetails.name);
        if (duplicateInst) {
            alert("An institution with this name already exists. "
                + "Either select a different name or change the name of the duplicate institution here: "
                + window.location.origin + "/review-institution?institutionId=" + duplicateInst.id);
        } else {
            fetch(this.props.documentRoot + "/create-institution",
                  {
                      method: "POST",
                      body: JSON.stringify({
                          userId: this.props.userId,
                          name: this.state.newInstitutionDetails.name,
                          logo: this.state.newInstitutionDetails.logo,
                          base64Image: this.state.newInstitutionDetails.base64Image,
                          url: this.state.newInstitutionDetails.url,
                          description: this.state.newInstitutionDetails.description,
                      }),
                  }
            )
                .then(response => Promise.all([response.ok, response.text()]))
                .then(data => {
                    const isInteger = n => !isNaN(parseInt(n)) && isFinite(n) && !n.includes(".");
                    if (data[0] && isInteger(data[1])) {
                        window.location = this.props.documentRoot + "/review-institution?institutionId=" + data[1];
                        return Promise.resolve();
                    } else {
                        return Promise.reject(data[1]);
                    }
                })
                .catch(message => alert("Error creating institution.\n\n" + message));
        }
    };

    setInstitutionDetails = (key, newValue) => {
        this.setState({
            newInstitutionDetails: {
                ...this.state.newInstitutionDetails, [key]: newValue,
            },
        });
    };

    renderButtonGroup = () =>
        <input
            id="create-institution"
            className="btn btn-outline-lightgreen btn-sm btn-block"
            type="button"
            value="Create Institution"
            onClick={this.createInstitution}
            disabled={this.state.newInstitutionDetails.name === "" || this.state.newInstitutionDetails.description === ""}
        />;

    render() {
        return (
            <InstitutionEditor
                title="Create New Institution"
                name={this.state.newInstitutionDetails.name}
                logo={this.state.newInstitutionDetails.logo}
                url={this.state.newInstitutionDetails.url}
                description={this.state.newInstitutionDetails.description}
                buttonGroup={this.renderButtonGroup}
                setInstitutionDetails={this.setInstitutionDetails}
            />
        );
    }
}

export function renderCreateInstitutionPage(args) {
    ReactDOM.render(
        <CreateInstitution
            documentRoot={args.documentRoot}
            userId={args.userId === "" ? -1 : parseInt(args.userId)}
        />,
        document.getElementById("institution")
    );
}
<|endoftext|>


<commit_before>
function openerp_picking_widgets(instance){
    var module = instance.stock;

    module.PickingEditorWidget = instance.web.Widget.extend({
        template: 'PickingEditorWidget',
        init: function(parent,options){
            this._super(parent,options);
        },
        get_header: function(){
            return this._header || 'Picking: INTERNAL/00112';
        },
        get_rows: function(){
            var model = this.getParent();
            var rows = [];
            console.log('Parent:', this.getParent());

            _.each( model.movelines, function(moveline){
                console.log('Moveline:',moveline);
                rows.push({
                    cols: { product: moveline.product_id[1],
                            qty: moveline.product_qty,
                            rem: moveline.qty_remaining,
                            uom: moveline.product_uom[1],
                            loc: moveline.location_id[1],
                            stat: moveline.state
                    },
                    classes: (moveline.qty_remaining < 0 ? 'oe_invalid' : '')
                });
            });

            return rows;
        },
    });

    module.PackageEditorWidget = instance.web.Widget.extend({
        template: 'PackageEditorWidget',
        get_header: function(){
            return this._header || 'Package: 032 ';
        },
        get_rows: function(){
            return this._rows || [
                { cols: { product:'abc', qty:1, uom: 5, },   },
                { cols: { product:'dec', qty:2, uom: 5, },  classes: '' },
                { cols: { product:'qcr', qty:4, uom: 5, }, },
            ];
        },
    });

    module.PackageSelectorWidget = instance.web.Widget.extend({
        template: 'PackageSelectorWidget',
        get_header: function(){
            return this._header || 'Package Selector';
        },
        get_rows: function(){
            return this._rows || [
                { cols: { pack:'abc', qty:12  },   },
                { cols: { pack:'def', qty:500 }, classes: ''   },
                { cols: { pack:'ghi', qty:1   },   },
            ];
        },
    });

    module.PickingMainWidget = instance.web.Widget.extend({
        template: 'PickingMainWidget',
        init: function(parent,params){
            this._super(parent,params);
            var self = this;

            this.picking = null;
            this.movelines = null;

            window.pickwidget = this;

            console.log('Action params:', params);

            this.loaded = new instance.web.Model('stock.picking.in')
                .query()
                .all()
                .then(function(picking_in){
                    self.picking = picking_in[0];
                    console.log('Picking In:',picking_in);

                    return new instance.web.Model('stock.move').call('read',[self.picking.move_lines, []]);
                }).then(function(movelines){
                    self.movelines = movelines;
                    console.log('Move Lines:',movelines);
                });

        },
        start: function(){
            var self = this;
            instance.webclient.set_content_full_screen(true);

            this.$('.js_pick_quit').click(function(){ self.quit(); });

            $.when(this.loaded).done(function(){
                var picking_editor = new module.PickingEditorWidget(self);
                picking_editor.replace(self.$('.oe_placeholder_picking_editor'));

                var package_editor = new module.PackageEditorWidget(self);
                package_editor.replace(self.$('.oe_placeholder_package_editor'));

                var package_selector = new module.PackageSelectorWidget(self);
                package_selector.replace(self.$('.oe_placeholder_package_selector'));
            });

            return this._super();
        },
        scan: function(ean){
            new instance.web.Model('stock.picking')
                .call('get_barcode_and_return_todo_stuff', [this.picking.id, ean])
                .then(function(results){
                    console.log('STUFF TODO:', arguments);
                });
        },
        quit: function(){
            console.log('Quit');
            instance.webclient.set_content_full_screen(false);
            window.location = '/'; // FIXME THIS IS SHIT NIV WILL KILL YOU (BY MULTIPLE FACE-STABBING) IF YOU MERGE THIS IN TRUNK
        },
    });
}
<commit_msg>[IMP] stock.ui: proper handling of the scan response<commit_after>
function openerp_picking_widgets(instance){
    var module = instance.stock;

    module.PickingEditorWidget = instance.web.Widget.extend({
        template: 'PickingEditorWidget',
        init: function(parent,options){
            this._super(parent,options);
        },
        get_header: function(){
            var model = this.getParent();
            return 'Picking: '+model.picking.name;
        },
        get_rows: function(){
            var model = this.getParent();
            var rows = [];
            console.log('Parent:', this.getParent());

            _.each( model.movelines, function(moveline){
                console.log('Moveline:',moveline);
                rows.push({
                    cols: { product: moveline.product_id[1],
                            qty: moveline.product_qty,
                            rem: moveline.remaining_qty,
                            uom: moveline.product_uom[1],
                            loc: moveline.location_id[1],
                            stat: moveline.state
                    },
                    classes: (moveline.qty_remaining < 0 ? 'oe_invalid' : '')
                });
            });

            return rows;
        },
    });

    module.PackageEditorWidget = instance.web.Widget.extend({
        template: 'PackageEditorWidget',
        get_header: function(){
            return this._header || 'Package: 032 ';
        },
        get_rows: function(){
            var model = this.getParent();
            var rows = [];

            _.each( model.operations, function(op){
                rows.push({
                    cols: {
                        product: op.product_id[1],
                        uom: op.product_uom ? product_uom[1] : 'false',
                        qty: op.product_qty,
                    }
                });
            });

            return rows;
        },
    });

    module.PackageSelectorWidget = instance.web.Widget.extend({
        template: 'PackageSelectorWidget',
        get_header: function(){
            return this._header || 'Package Selector';
        },
        get_rows: function(){
            return this._rows || [
                { cols: { pack:'abc', qty:12  },   },
                { cols: { pack:'def', qty:500 }, classes: ''   },
                { cols: { pack:'ghi', qty:1   },   },
            ];
        },
    });

    module.PickingMainWidget = instance.web.Widget.extend({
        template: 'PickingMainWidget',
        init: function(parent,params){
            this._super(parent,params);
            var self = this;

            this.picking = null;
            this.movelines = null;
            this.operations = null;

            window.pickwidget = this;

            console.log('Action params:', params);

            this.loaded = new instance.web.Model('stock.picking.in')
                .query()
                .all()
                .then(function(picking_in){
                    self.picking = picking_in[0];
                    console.log('Picking In:',picking_in);

                    return new instance.web.Model('stock.move').call('read',[self.picking.move_lines, []]);
                }).then(function(movelines){
                    self.movelines = movelines;
                    console.log('Move Lines:',movelines);

                    return new instance.web.Model('stock.pack.operation').call('read',[self.picking.pack_operation_ids, []]);
                }).then(function(operations){
                    self.operations = operations;
                    console.log('Operations:',self.operations);
                });

        },
        start: function(){
            var self = this;
            instance.webclient.set_content_full_screen(true);

            this.$('.js_pick_quit').click(function(){ self.quit(); });

            $.when(this.loaded).done(function(){
                self.picking_editor = new module.PickingEditorWidget(self);
                self.picking_editor.replace(self.$('.oe_placeholder_picking_editor'));

                self.package_editor = new module.PackageEditorWidget(self);
                self.package_editor.replace(self.$('.oe_placeholder_package_editor'));

                self.package_selector = new module.PackageSelectorWidget(self);
                self.package_selector.replace(self.$('.oe_placeholder_package_selector'));
            });

            return this._super();
        },
        scan: function(ean){
            var self = this;
            new instance.web.Model('stock.picking')
                .call('get_barcode_and_return_todo_stuff', [this.picking.id, ean])
                .then(function(todo){

                    _.each(todo.moves_to_update, function(update){
                        if(update[0] === 0){ // create a new line
                            console.log('New line:',update);
                            self.movelines.push(update[2]);

                        }else if(update[0] === 1){ // update a line
                            console.log('Update line:',update);
                            for(var i = 0; i < self.movelines.length; i++){
                                if( self.movelines[i].id === update[1]){
                                    for(field in update[2]){
                                        self.movelines[i][field] = update[2][field];
                                    }
                                    break;
                                }
                            }
                        }else if(update[0] === 2){ // remove a line
                            console.log('Remove line:',update);
                            for(var i = 0; i < self.movelines.length; i++){
                                if( self.movelines[i].id === update[1] ){
                                    self.movelines.splice(i,1);
                                    break;
                                }
                            }
                        }

                    });

                    self.picking_editor.renderElement();

                    new instance.web.Model('stock.pack.operation').call('read',[self.picking.pack_operation_ids, []])
                        .then(function(operations){
                            self.operations = operations;
                            self.package_editor.renderElement();
                            console.log('Updated the operations list !');
                        });
                });
        },
        quit: function(){
            console.log('Quit');
            instance.webclient.set_content_full_screen(false);
            window.location = '/'; // FIXME THIS IS SHIT NIV WILL KILL YOU (BY MULTIPLE FACE-STABBING) IF YOU MERGE THIS IN TRUNK
        },
    });
}
<|endoftext|>


<commit_before>'use strict';

var Model = require('ampersand-model');
var clone = require('lodash.clone');

module.exports = function(config) {
  var model = clone(config);

  if (model.url == null) {
    model.url = '/';
  }
  model.urlRoot = model.url;
  delete model.url;
  model.sync = this.getSync(model);
  return Model.extend(model);
};
<commit_msg>attach original model spec to model for access to metadata<commit_after>'use strict';

var Model = require('ampersand-model');
var clone = require('lodash.clone');

module.exports = function(config) {
  var model = clone(config);

  if (model.url == null) {
    model.url = '/';
  }
  model.urlRoot = model.url;
  delete model.url;
  model.sync = this.getSync(model);
  model = Model.extend(model);
  model.prototype.spec = config;
  return model
};
<|endoftext|>


<commit_before>/**
 * Utility for reading the angularity configuration files.
 *
 * By default the config is a `angularity.json` that is located at the root
 * of an angularity project.
 *
 * This utility also makes sure that the package.json of the project is kept in sync with
 * angularity so that it can be distributed with npm.
 *
 * @type {exports} Object
 */
'use strict';

var fs     = require('fs'),
    merge  = require('lodash.merge'),
    reduce = require('lodash.reduce'),
    path   = require('path');

var installMenu    = require('./../cli/installMenu'),
    templateUtil   = require('ide-template').util,
    configDefaults = require('./defaults');

var CONFIG_PATH_GLOBAL  = path.join(templateUtil.HOME(), '.angularity'),
    CONFIG_PATH_PROJECT = path.join(process.cwd(), 'angularity.json'),
    CONFIG_PATH_NPM     = path.join(process.cwd(), 'package.json'),
    CONFIG_PATH_BOWER   = path.join(process.cwd(), 'bower.json');

/**
 * Retreive a method that tests a configuration for the requisite fields and prints an error message on failure
 * @param {object} types A lookup of the required types of fields in the config
 * @return {function({object}):{boolean}} Method that takes a configuration and tests its validity
 */
function getValidator(types) {
  return function(config) {
    var missing = reduce(types, function(result, type, field) {
        (typeof config[field] !== type) && result.push(field);
        return result;
      }, [ ]);
    if (missing.length) {
      var message = ['Error validating', path.basename(config._filename), 'missing field(s):']
        .concat(missing)
        .join(' ');
      console.error(message);
      return false;
    } else {
      return true;
    }
  }
}

/**
 * Given a semver string create a heuristic string that ranks the semver in the correct order.
 * To do this it applies leading zero padding such that all similar term is the same length across all given semvers.
 * @param {Array.<string>} candidates A list of semver strings
 * @returns {Array.<string>} A list of heuristics based on the given semvers
 */
function semverRankingHeuristic(candidates) {
  var maxLengths = [ ];
  return candidates
    .map(function split(candidate) {    // split the semver into terms and find the longest length of similar terms
      return String(candidate)
        .replace(/[^0-9.]/g, '')
        .split('.')
        .map(function measureEachTerm(value, i) {
          maxLengths[i] = Math.max(maxLengths[i], value.length) || value.length;
          return value;
        });
    })
    .map(function zeroPadding(split) {  // apply leading zero padding to equalise the length of the terms
      return split
        .forEach(function zeroPadEachTerm(value, i) {
          var length = maxLengths[i];
          return (Array(length).join('0') + value).slice(-length);
        })
        .join('.');
    });
}

/**
 * Determine the highest SemVersion between a project's bower, npm and angularity configs.
 * If the versions are out of sync, update the config files with the highest version.
 * Candidates are expected to have a _filename field with the full file path.
 * @param {...object} config Any number of candidate configurations
 */
function synchroniseConfigs(config) {

  // the list of configurations (copy)
  var configurations = Array.prototype.slice.call(config);

  // a list of configurations that have been tainted
  var tainted = [ ];

  // create a heuristic of the version which may be safely sorted
  var versions = semverRankingHeuristic(configurations.map(function (config) {
    return config.version;
  }));

  // we can now find the configuration with the highest version
  var index   = versions.indexOf(versions.sort().pop());
  var highest = configurations[index];

  // normalise version
  var isEqualVersion = versions.every(function (versionFloat, i, array) {
    return (version === array[0]);
  })
  if (!isEqualVersion) {

    // warning message
    console.warn('Your configuration versions are out of sync, the highest version',
      highest.version, 'from your', path.basename(highest._filename), 'will now be used for all.');

    // amend the relevant configurations
    configurations.forEach(function (config) {
      if (config.version !== highest.version) {
        config.version = highest.version;
        (tainted.indexOf(config) < 0) && tainted.push(config);
      }
    });
  }

  // normalise name
  var isEqualName = configurations.every(function (config, i, array) {
    return (config.name === array[0].name);
  })
  if (!isEqualName) {
    var reference = configurations[0];

    // warning message
    console.warn('Your configuration names are out of sync. The name specified in the project\'s',
      path.basename(reference._filename), 'will be used for all.');

    // amend the relevant configurations
    configurations.forEach(function (config) {
      if (config.name !== reference.name) {
        config.name = reference.name;
        (tainted.indexOf(config) < 0) && tainted.push(config);
      }
    });
  }

  // save tainted configurations
  tainted.forEach(function (config) {
    var copy = merge(config, { filename: undefined });
    var text = JSON.stringify(copy, null, 2);
    fs.writeFileSync(config._filename, text);
  });
}

/**
 * Resolve a config value by order of priority,
 * Use the project specific angularity.json first if it is defined,
 * then the global .angularity in the local HOME directory.
 * @param {string} name
 * @returns {function}
 */
function configGetterFor(name) {
  return function() {
    if (this.projectConfig && this.projectConfig[name]) {
      return this.projectConfig[name];
    } else if (this.globalConfig[name]) {
      return this.globalConfig[name];
    } else {
      throw new Error(['Cannot resolve the config value of', name, 'in the project config', CONFIG_PATH_PROJECT,
          'or the global angularity config', CONFIG_PATH_GLOBAL].join(' '));
    }
  }
}

function Config() {
  var globalValidator = getValidator({
    serverHttpPort   : 'number',
    javascriptVersion: 'string',
    consoleWidth     : 'string'
  });
  var localValidator = getValidator({
    name   : 'string',
    version: 'string'
  });

  // Load angularity's global config file from the user's Home directory.
  this.globalConfig = merge({ _filename: CONFIG_PATH_GLOBAL }, JSON.parse(fs.readFileSync(CONFIG_PATH_GLOBAL, 'utf8')));
  globalValidator(this.globalConfig);

  // Load all the project's config files and validate them
  this.projectConfigPresent = fs.existsSync(CONFIG_PATH_PROJECT);
  if (this.projectConfigPresent) {
    this.projectConfig = merge({ _filename: CONFIG_PATH_PROJECT }, require(CONFIG_PATH_PROJECT));
    localValidator(this.projectConfig);
  }
  this.npmConfigPresent = fs.existsSync(CONFIG_PATH_NPM);
  if (this.npmConfigPresent) {
    this.npmConfig = merge({ _filename: CONFIG_PATH_NPM }, require(CONFIG_PATH_NPM));
    localValidator(this.npmConfig);
  }
  this.bowerConfigPresent = fs.existsSync(CONFIG_PATH_BOWER);
  if (this.bowerConfigPresent) {
    this.bowerConfig = merge({ _filename: CONFIG_PATH_BOWER }, require(CONFIG_PATH_BOWER));
    localValidator(this.bowerConfig);
  }

  // Keep the config file's version numbers in sync
  // TODO remove dependency of bower config
  var isAllPresent = [this.projectConfigPresent, this.npmConfigPresent, this.bowerConfigPresent].every(Boolean);
  if (isAllPresent) {
    synchroniseConfigs(this.projectConfig, this.npmConfig, this.bowerConfig);
  }
}

// TODO comment block
Config.prototype.values = configDefaults;

// TODO comment block
Config.prototype.isMinify = (process.argv.indexOf('nominify') < 0);

/**
 * Configurable getter methods for resolving the config values for the Angularity configurations.
 */
// TODO specific comment block for each method

Config.prototype.getConsoleWidth = configGetterFor('consoleWidth');

Config.prototype.getServerHttpPort = configGetterFor('serverHttpPort');

Config.prototype.getJavascriptVersion = configGetterFor('javascriptVersion');

Config.prototype.getWebstormExecutablePath = configGetterFor('webstormExecutablePath');

/**
 * Initialise the global angularity install.
 * A config file is created in the local Documents/Home folder named .angularity.
 * If there is no config file present the tool will generate one with default options.
 */
var globalConfigPresent = fs.existsSync(path.join(templateUtil.HOME(), '.angularity'));
if (!globalConfigPresent) {
  installMenu.initGlobalConfig();
}

module.exports = new Config();<commit_msg>minor tweaks<commit_after>/**
 * Utility for reading the angularity configuration files.
 *
 * By default the config is a `angularity.json` that is located at the root
 * of an angularity project.
 *
 * This utility also makes sure that the package.json of the project is kept in sync with
 * angularity so that it can be distributed with npm.
 *
 * @type {exports} Object
 */
'use strict';

var fs     = require('fs'),
    merge  = require('lodash.merge'),
    reduce = require('lodash.reduce'),
    path   = require('path');

var installMenu    = require('./../cli/installMenu'),
    templateUtil   = require('ide-template').util,
    configDefaults = require('./defaults');

var CONFIG_PATH_GLOBAL  = path.join(templateUtil.HOME(), '.angularity'),
    CONFIG_PATH_PROJECT = path.join(process.cwd(), 'angularity.json'),
    CONFIG_PATH_NPM     = path.join(process.cwd(), 'package.json'),
    CONFIG_PATH_BOWER   = path.join(process.cwd(), 'bower.json');

/**
 * Retreive a method that tests a configuration for the requisite fields and prints an error message on failure
 * @param {object} types A lookup of the required types of fields in the config
 * @return {function({object}):{boolean}} Method that takes a configuration and tests its validity
 */
function getValidator(types) {
  return function(config) {
    var missing = reduce(types, function(result, type, field) {
        (typeof config[field] !== type) && result.push(field);
        return result;
      }, [ ]);
    if (missing.length) {
      var message = ['Error validating', path.basename(config._filename), 'missing field(s):']
        .concat(missing)
        .join(' ');
      console.error(message);
      return false;
    } else {
      return true;
    }
  }
}

/**
 * Given a semver string create a heuristic string that ranks the semver in the correct order.
 * To do this it applies leading zero padding such that all similar term is the same length across all given semvers.
 * @param {Array.<string>} candidates A list of semver strings
 * @returns {Array.<string>} A list of heuristics based on the given semvers
 */
function semverRankingHeuristic(candidates) {
  var maxLengths = [ ];
  return candidates
    .map(function split(candidate) {    // split the semver into terms and find the longest length of similar terms
      return String(candidate)
        .replace(/[^0-9.]/g, '')
        .split('.')
        .map(function measureEachTerm(value, i) {
          maxLengths[i] = Math.max(maxLengths[i], value.length) || value.length;
          return value;
        });
    })
    .map(function zeroPadding(split) {  // apply leading zero padding to equalise the length of the terms
      return split
        .forEach(function zeroPadEachTerm(value, i) {
          var length = maxLengths[i];
          return ((new Array(length)).join('0') + value).slice(-length);
        })
        .join('.');
    });
}

/**
 * Determine the highest SemVersion between a project's bower, npm and angularity configs.
 * If the versions are out of sync, update the config files with the highest version.
 * Candidates are expected to have a _filename field with the full file path.
 * @param {...object} config Any number of candidate configurations
 */
function synchroniseConfigs(config) {

  // the list of configurations (copy)
  var configurations = Array.prototype.slice.call(config);

  // a list of configurations that have been tainted
  var tainted = [ ];

  // create a heuristic of the version which may be safely sorted
  var versions = semverRankingHeuristic(configurations.map(function (config) {
    return config.version;
  }));

  // we can now find the configuration with the highest version
  var index   = versions.indexOf(versions.sort().pop());
  var highest = configurations[index];

  // normalise version
  var isEqualVersion = versions.every(function (versionFloat, i, array) {
    return (version === array[0]);
  });
  if (!isEqualVersion) {

    // warning message
    console.warn('Your configuration versions are out of sync, the highest version',
      highest.version, 'from your', path.basename(highest._filename), 'will now be used for all.');

    // amend the relevant configurations
    configurations.forEach(function (config) {
      if (config.version !== highest.version) {
        config.version = highest.version;
        (tainted.indexOf(config) < 0) && tainted.push(config);
      }
    });
  }

  // normalise name
  var isEqualName = configurations.every(function (config, i, array) {
    return (config.name === array[0].name);
  });
  if (!isEqualName) {
    var reference = configurations[0];

    // warning message
    console.warn('Your configuration names are out of sync. The name specified in the project\'s',
      path.basename(reference._filename), 'will be used for all.');

    // amend the relevant configurations
    configurations.forEach(function (config) {
      if (config.name !== reference.name) {
        config.name = reference.name;
        (tainted.indexOf(config) < 0) && tainted.push(config);
      }
    });
  }

  // save tainted configurations
  tainted.forEach(function (config) {
    var copy = merge(config, { filename: undefined });
    var text = JSON.stringify(copy, null, 2);
    fs.writeFileSync(config._filename, text);
  });
}

/**
 * Resolve a config value by order of priority,
 * Use the project specific angularity.json first if it is defined,
 * then the global .angularity in the local HOME directory.
 * @param {string} name
 * @returns {function}
 */
function configGetterFor(name) {
  return function() {
    if (this.projectConfig && this.projectConfig[name]) {
      return this.projectConfig[name];
    } else if (this.globalConfig[name]) {
      return this.globalConfig[name];
    } else {
      throw new Error(['Cannot resolve the config value of', name, 'in the project config', CONFIG_PATH_PROJECT,
          'or the global angularity config', CONFIG_PATH_GLOBAL].join(' '));
    }
  }
}

function Config() {
  var globalValidator = getValidator({
    serverHttpPort   : 'number',
    javascriptVersion: 'string',
    consoleWidth     : 'string'
  });
  var localValidator = getValidator({
    name   : 'string',
    version: 'string'
  });

  // Load angularity's global config file from the user's Home directory.
  this.globalConfig = merge({ _filename: CONFIG_PATH_GLOBAL }, JSON.parse(fs.readFileSync(CONFIG_PATH_GLOBAL, 'utf8')));
  globalValidator(this.globalConfig);

  // Load all the project's config files and validate them
  this.projectConfigPresent = fs.existsSync(CONFIG_PATH_PROJECT);
  if (this.projectConfigPresent) {
    this.projectConfig = merge({ _filename: CONFIG_PATH_PROJECT }, require(CONFIG_PATH_PROJECT));
    localValidator(this.projectConfig);
  }
  this.npmConfigPresent = fs.existsSync(CONFIG_PATH_NPM);
  if (this.npmConfigPresent) {
    this.npmConfig = merge({ _filename: CONFIG_PATH_NPM }, require(CONFIG_PATH_NPM));
    localValidator(this.npmConfig);
  }
  this.bowerConfigPresent = fs.existsSync(CONFIG_PATH_BOWER);
  if (this.bowerConfigPresent) {
    this.bowerConfig = merge({ _filename: CONFIG_PATH_BOWER }, require(CONFIG_PATH_BOWER));
    localValidator(this.bowerConfig);
  }

  // Keep the config file's version numbers in sync
  // TODO remove dependency of bower config
  var isAllPresent = [this.projectConfigPresent, this.npmConfigPresent, this.bowerConfigPresent].every(Boolean);
  if (isAllPresent) {
    synchroniseConfigs(this.projectConfig, this.npmConfig, this.bowerConfig);
  }
}

// TODO comment block
Config.prototype.values = configDefaults;

// TODO comment block
Config.prototype.isMinify = (process.argv.indexOf('nominify') < 0);

/**
 * Configurable getter methods for resolving the config values for the Angularity configurations.
 */
// TODO specific comment block for each method

Config.prototype.getConsoleWidth = configGetterFor('consoleWidth');

Config.prototype.getServerHttpPort = configGetterFor('serverHttpPort');

Config.prototype.getJavascriptVersion = configGetterFor('javascriptVersion');

Config.prototype.getWebstormExecutablePath = configGetterFor('webstormExecutablePath');

/**
 * Initialise the global angularity install.
 * A config file is created in the local Documents/Home folder named .angularity.
 * If there is no config file present the tool will generate one with default options.
 */
var globalConfigPresent = fs.existsSync(path.join(templateUtil.HOME(), '.angularity'));
if (!globalConfigPresent) {
  installMenu.initGlobalConfig();
}

module.exports = new Config();<|endoftext|>


<commit_before><commit_msg>Replace calls to goog.define with assignments to the result of goog.define.<commit_after><|endoftext|>


<commit_before>var description = ' Test8: channels';
var failureMessage = 'This test tests Bridge Channels feature.\nExpected behavior: The server broadcasts a messages to all clients. The clients must echo back to the server.\n';

var test = require(__dirname + '/../lib/test.js')(failureMessage, 1);
var Bridge = require(__dirname + '/../../lib/bridge.js').Bridge;
var bridgeServer = new Bridge({host: 'localhost'});

bridgeServer.ready(function(){
    var joinCount = 0;
    var pongCount = 0;

    var ChatServer = {
        join: function(handler, callback) {
            bridgeServer.joinChannel('test8', handler, callback);
            joinCount++;

            if (joinCount == 2) {
                bridgeServer.getService('test8_channels', function(service) {
                    service.join({
                        send: function(msg) {
                            pongCount++;
                            if (pongCount == 2) {
                                test.pass();
                            }
                        }
                    }, function () {
                        test.log("all clients init");
                        bridgeServer.getChannel('test8').get('send')('ping');
                    });
                });
            }
        }
    }
    bridgeServer.publishService('test8_channels', ChatServer, function() {
        test.log("server init");
        initClient();
    });
});

setTimeout(function() {
    test.log('time out');
    test.fail();
}, 5000);

function initClient() {
    var b1 = new Bridge({host: 'localhost'});
    var b2 = new Bridge({host: 'localhost'});

    b1.ready(function() {
        b1.getService('test8_channels', function(service) {
            service.join({
                send: function(msg) {
                    if (msg == 'ping') {
                        test.log('ping received');
                        b1.getChannel('test8').get('send')('pong from b1');
                    }
                }
            }, function () {
                test.log('b1 init');
            });
        });
    });

    b2.ready(function() {
        b2.getService('test8_channels', function(service) {
           service.join({
                send: function(msg) {
                    if (msg == 'ping') {
                        test.log('ping received');
                        b2.getChannel('test8').get('send')('pong from b2');
                    }
                }
            }, function () {
                test.log('b2 init');
            });
        });
    });
}
<commit_msg>test using one handler object in multiple bridge instances<commit_after>var description = ' Test8: channels';
var failureMessage = 'This test tests Bridge Channels feature.\nExpected behavior: The server broadcasts a messages to all clients. The clients must echo back to the server.\n';

var test = require(__dirname + '/../lib/test.js')(failureMessage, 1);
var Bridge = require(__dirname + '/../../lib/bridge.js').Bridge;
var bridgeServer = new Bridge({host: 'localhost'});

bridgeServer.ready(function(){
    var joinCount = 0;
    var pongCount = 0;

    var ChatServer = {
        join: function(handler, callback) {
            bridgeServer.joinChannel('test8', handler, callback);
            joinCount++;

            if (joinCount == 2) {
                bridgeServer.getService('test8_channels', function(service) {
                    service.join({
                        send: function(msg) {
                            pongCount++;
                            if (pongCount == 5) {
                                test.pass();
                            }
                        }
                    }, function () {
                        test.log("all clients init");
                        bridgeServer.getChannel('test8').get('send')('ping');
                    });
                });
            }
        }
    }
    bridgeServer.publishService('test8_channels', ChatServer, function() {
        test.log("server init");
        initClient();
    });
});

setTimeout(function() {
    test.log('time out');
    test.fail();
}, 5000);

function initClient() {
    var b1 = new Bridge({host: 'localhost'});
    var b2 = new Bridge({host: 'localhost'});

    var handle = {
                send: function(msg) {
                    if (msg == 'ping') {
                        test.log('ping received');
                        b1.getChannel('test8').get('send')('pong from b1');
                        b2.getChannel('test8').get('send')('pong from b2');
                    }
                }
            };

    b1.ready(function() {
        b1.getService('test8_channels', function(service) {
            service.join(handle, function () {
                test.log('b1 init');
            });
        });
    });

    b2.ready(function() {
        b2.getService('test8_channels', function(service) {
           service.join(handle, function () {
                test.log('b2 init');
            });
        });
    });
}
<|endoftext|>


<commit_before>var _ = require('lodash');
var Promise = require('bluebird');

var search = require('./search');
var query = require('./query');

var modelOptions = {};

function Model(connection, defaults, opt, schema) {
    this.index = opt.index || defaults.index;
    this.type = opt.type || defaults.type;
    this.connection = connection;
    this.schema = schema;
    // TODO after the props have been set it should check to see if the index exists
    // if the index does not exists then it should create the index mapping
    // based off of the schema mappings
    // There should also be strict mapping vs non strict

    var mapping = this.schema.getIndexMapping();
    var opts = this.schema.getIndexOpts();
    // todo compare mappings.
    connection.indices.exists({index: this.index}, function (err, indexTest) {
        console.log('indexTest',err,indexTest);
        if (!indexTest) {
            console.log('creating index %s',this.index);
            connection.indices.create({index: this.index},function(err,idx){
                console.log('created index %s Error: %s',this.index,err);
                connection.indices.putMapping({index: this.index, type: this.type, body: mapping})
            });
        }else {
            connection.indices.getSettings({index: this.index, name: "index.mapper.dynamic"}, function (err, settings) {
                console.log(err, settings)
            });
            if (opts && !opts.dynamic) {
                //  connection.indices.putSettings({index:this.index, body:{"index.mapper.dynamic":opts.dynamic}});
            }

            connection.indices.putMapping({index: this.index, type: this.type, body: mapping})
        }
    })
}

/**
 * # Model
 */

/**
 * Creates an elasticsearch document
 *
 * To create the documents with your own id set the *opt.id* property to the id you want for that document.
 * @param  {Object}   doc the body of the elasticsearch document
 * @param  {Object}   opt Optional options objectg
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.create = function (doc, opt, cb) {
    if (!opt) opt = {};
    var err = this.schema.validateDoc(doc);
    if (err.length > 0) {
        if (cb)
            cb({msg: err.join('\m')}, undefined);
        else
            throw new Error(err.join('\n'));
    } else {
        var body = {
            body: this.schema.applySchema(doc)
        };
        return this
            .connection
            .create(_.merge(
                {
                    index: this.index,
                    type: this.type,
                    id: opt.id
                }, body),
                cb
            );
    }
}

/**
 * Update document by id
 * @param  {String|Number|ElasticsearchId}   id  document id
 * @param  {Object}   doc body
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.update = function (id, doc, opt, cb) {
    if (!opt) opt = {};

    return this
        .connection
        .update(_.merge(
            {
                index: this.index,
                type: this.type,
                id: id,
                body: {
                    doc: doc
                }
            }, opt),
            cb
        );
}

/**
 * Deletes a document based of the supllied id
 * @param  {String|Number|ElasicsearchId}   id  document id
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.delete = function (id, opt, cb) {
    if (!opt) opt = {};

    return this
        .connection
        .delete(_.merge(
            {
                index: this.index,
                type: this.type,
                id: id
            }, opt),
            cb
        );
}

/**
 * Delete document by a query
 * @param  {Object}   body Query body
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.deleteByQuery = function (body, opt, cb) {
    if (!opt) opt = {};

    return this
        .connection
        .deleteByQuery(_.merge(
            {
                index: this.index,
                type: this.type,
                body: body
            }, opt),
            cb
        );
}

Model.prototype = _.merge(Model.prototype, query);

Model.prototype = _.merge(Model.prototype, search);

module.exports = Model;

/**
 * ## Query API
 *
 * Click [here](https://github.com/LucioFranco/Rebound-ODM/blob/master/API.md#query) for the Query API
 *
 * ## Search API
 *
 * Click [here](https://github.com/LucioFranco/Rebound-ODM/blob/master/API.md#search) for the Search API
 */
<commit_msg>adding create index if does not exists<commit_after>var _ = require('lodash');
var Promise = require('bluebird');

var search = require('./search');
var query = require('./query');

var modelOptions = {};

function Model(connection, defaults, opt, schema) {
    this.index = opt.index || defaults.index;
    this.type = opt.type || defaults.type;
    this.connection = connection;
    this.schema = schema;
    // TODO after the props have been set it should check to see if the index exists
    // if the index does not exists then it should create the index mapping
    // based off of the schema mappings
    // There should also be strict mapping vs non strict

    var mapping = this.schema.getIndexMapping();
    var opts = this.schema.getIndexOpts();
    var index = this.index;
    var type = this.type;
    // todo compare mappings.
    connection.indices.exists({index: this.index}, function (err, indexTest) {
        console.log('indexTest',err,indexTest);
        if (!indexTest) {
            console.log('creating index %s',index);
            connection.indices.create({index: index},function(err,idx){
                console.log('created index %s Error: %s',index,err);
                connection.indices.putMapping({index: index, type: type, body: mapping})
            });
        }else {
            connection.indices.getSettings({index: index, name: "index.mapper.dynamic"}, function (err, settings) {
                console.log(err, settings)
            });
            if (opts && !opts.dynamic) {
                //  connection.indices.putSettings({index:this.index, body:{"index.mapper.dynamic":opts.dynamic}});
            }

            connection.indices.putMapping({index: index, type: type, body: mapping})
        }
    })
}

/**
 * # Model
 */

/**
 * Creates an elasticsearch document
 *
 * To create the documents with your own id set the *opt.id* property to the id you want for that document.
 * @param  {Object}   doc the body of the elasticsearch document
 * @param  {Object}   opt Optional options objectg
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.create = function (doc, opt, cb) {
    if (!opt) opt = {};
    var err = this.schema.validateDoc(doc);
    if (err.length > 0) {
        if (cb)
            cb({msg: err.join('\m')}, undefined);
        else
            throw new Error(err.join('\n'));
    } else {
        var body = {
            body: this.schema.applySchema(doc)
        };
        return this
            .connection
            .create(_.merge(
                {
                    index: this.index,
                    type: this.type,
                    id: opt.id
                }, body),
                cb
            );
    }
}

/**
 * Update document by id
 * @param  {String|Number|ElasticsearchId}   id  document id
 * @param  {Object}   doc body
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.update = function (id, doc, opt, cb) {
    if (!opt) opt = {};

    return this
        .connection
        .update(_.merge(
            {
                index: this.index,
                type: this.type,
                id: id,
                body: {
                    doc: doc
                }
            }, opt),
            cb
        );
}

/**
 * Deletes a document based of the supllied id
 * @param  {String|Number|ElasicsearchId}   id  document id
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.delete = function (id, opt, cb) {
    if (!opt) opt = {};

    return this
        .connection
        .delete(_.merge(
            {
                index: this.index,
                type: this.type,
                id: id
            }, opt),
            cb
        );
}

/**
 * Delete document by a query
 * @param  {Object}   body Query body
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.deleteByQuery = function (body, opt, cb) {
    if (!opt) opt = {};

    return this
        .connection
        .deleteByQuery(_.merge(
            {
                index: this.index,
                type: this.type,
                body: body
            }, opt),
            cb
        );
}

Model.prototype = _.merge(Model.prototype, query);

Model.prototype = _.merge(Model.prototype, search);

module.exports = Model;

/**
 * ## Query API
 *
 * Click [here](https://github.com/LucioFranco/Rebound-ODM/blob/master/API.md#query) for the Query API
 *
 * ## Search API
 *
 * Click [here](https://github.com/LucioFranco/Rebound-ODM/blob/master/API.md#search) for the Search API
 */
<|endoftext|>