<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');
var sys = require('sys');
var path = require('path');
var events = require('events');

var sprintf = require('sprintf').sprintf;
var async = require('async');

var Errorf = require('util/misc').Errorf;

/**
 * Resources for which jobs can be queued and executed. Implementations must
 * specify an 'exists' method.
 * @extends {events.EventEmitter}
 * @param {String} name The name of this resource's directory.
 */
function Resource(name) {
  this.name = name;
  this._serializer = undefined;
  this._jobs = [];
  this._waiters = [];
  this._running = null;
  this._jobCount = 0;
  this._state = null;
}

sys.inherits(Resource, events.EventEmitter);

Resource.prototype.list = function(callback) { callback(new Error('Not Implemented')); };

/**
 * Determine whether this resource exists. Should be overridden by resource
 * implementations.
 * @param {Function} callback A callback fired with (exists).
 */
Resource.prototype.exists = function(callback) { callback(false); };

/**
 * Determine the swiz type for this resource. Implementations should specify
 * a _serializerType property.
 * @returns {String} The serializer type for use by swiz.
 */
Resource.prototype.getSerializerType = function() {
  return this.constructor.name;
};

/**
 * Retrieve the serialized state of this resource. If a job is currently
 * executing on this resource this will use the state cached when that job
 * began. Otherwise it will retrieve the state on demand.
 * @param {Function} callback A callback fired with (err, state).
 */
Resource.prototype.getState = function(callback) {
  var self = this;

  if (this._running) {
    // If a job is running...
    if (!this._state) {
      // The state isn't ready yet, wait for it...
      this.once('cache', callback);
    } else if (this._state instanceof Error) {
      // The state was an error, whoops
      callback(this._state);
    } else {
      // Use the cached state directly
      callback(null, this._state);
    }
  } else {
    // Make sure no jobs start while we're doing this
    this._jobCount++;
    this._waitToCheck(function(afterCheck) {
      self.exists(function(exists) {
        if (!exists) {
          callback(self.getExistenceError(exists));
          self._removeJob(false);
          afterCheck();
          return;
        }
        self._serializer.buildObject(self, function(err, state) {
          callback(err, state);
          self._removeJob(false);
          afterCheck();
        });
      });
    });
  }
};

/**
 * Attempt to predict whether a resource will exist after the current job
 * queue has been flushed.
 * @param {Function} callback A callback fired with (willExist).
 */
Resource.prototype.willExist = function(callback) {
  var i;

  // Make a copy of the job queue and reverse it
  var priorJobs = this._jobs.slice(0, this._jobs.length).reverse();

  if (this._running) {
    priorJobs.push(this._running);
  }

  // Traverse prior jobs to see if they create/delete the resource
  for (i = 0; i < priorJobs.length; i++) {
    if (priorJobs[i].willCreate()) {
      callback(true);
      return;
    }

    if (priorJobs[i].willDelete()) {
      callback(false);
      return;
    }
  }

  // No job will create or delete this resource, does it exist now?
  this.exists(callback);
};

/**
 * Enqueue a job for this resource.
 * @param {Object} job The job to enqueue.
 */
Resource.prototype.enqueueJob = function(job, callback) {
  var self = this;
  this._jobCount++;

  this._waitToCheck(function(afterCheck) {

    // Test whether the resource will exist after the queue flushes.
    self.willExist(function(willExist) {

      // If the job can't handle a resource with willExist, callback with error
      if (!job.canHandleExistence(willExist)) {
        callback(self.getExistenceError(willExist));
        afterCheck();
        self._removeJob(false);
        return;
      }

      // When the job ends, start the next one
      job.on('error', function() {
        self._removeJob(true);
      });

      job.on('success', function() {
        self._removeJob(true);
      });

      // Enqueue this job and make sure the queue is being processed
      self._jobs.push(job);
      self._cycle();
      afterCheck();
      callback();
    });
  });
};

/**
 * Generate an error for this resource based on the passed boolean indicating
 * what the problem is.
 * @param {Boolean} exists Is that problem that it does exist, or doesn't?
 * @returns {Error} The appropriate error.
 */
Resource.prototype.getExistenceError = function(exists) {
  var fmt;

  if (exists) {
    fmt = '%s \'%s\' already exists.';
  } else {
    fmt = '%s \'%s\' does not exist.';
  }

  return new Errorf(fmt, this.constructor.name, this.name);
};

/**
 * Remove a job by decreasing the reference counter and, if the job was queued,
 * removing the reference to it as well.
 * @param {Boolean} queued Whether the job was queued.
 */
Resource.prototype._removeJob = function(queued) {
  this._jobCount--;

  // Jobs that have reached the queue will always make it to the head
  if (queued) {
    this._running = null;
    this._state = null;
    this._cycle();
  }

  if (this._jobCount === 0) {
    this.emit('drain');
  }
};

/**
 * If no job is currently being processed, start the one at the head of the
 * queue.
 * @private
 */
Resource.prototype._cycle = function() {
  var self = this;

  if (!this._running && this._jobs.length > 0) {
    this._running = this._jobs.shift();

    this._serializer.buildObject(this, function(err, state) {
      self._state = err || state;
      self.emit('cache', err, state);
      self._running.start();
    });
  }
};

/**
 * Called by jobs waiting to check their options. Only one job may be checking
 * its options at any given time.
 * @param {Function} callback A callback fired when job may check its options.
 */
Resource.prototype._waitToCheck = function(callback) {
  var self = this;

  function afterCheck() {
    self._waiters.shift();
    if (self._waiters.length > 0) {
      self._waiters[0](afterCheck);
    }
  }

  this._waiters.push(callback);
  if (this._waiters.length === 1) {
    this._waiters[0](afterCheck);
  }
};

/**
 * A resource that is backed by a directory.
 * @param {String} name The name of this resource's directory.
 * @constructor
 */
function DirectoryResource(name) {
  Resource.call(this, name);
  this.parentDir = this.getParentDir();
}

sys.inherits(DirectoryResource, Resource);

/**
 * Get parent directory of resources of this type. This must be set by
 * DirectoryResource implementations.
 * @returns {String} The path to the directory containing resource sof this
 *     type.
 */
DirectoryResource.prototype.getParentDir = function() { return undefined; };

/**
 * @inheritdoc
 */
DirectoryResource.prototype.list = function(callback) {
  fs.readdir(this.getParentDir(), callback);
};

/**
 * Get the path to the root of this resource.
 * @returns {String} Path to the root of this resource.
 */
DirectoryResource.prototype.getRoot = function() {
  return path.join(this.parentDir, this.name);
};

/**
 * Determine whether this resource exists by checking for its root directory.
 * @param {Function} callback A callback fired with (exists).
 */
DirectoryResource.prototype.exists = function(callback) {
  fs.stat(this.getRoot(), function(err, stats) {
    callback(!err && stats.isDirectory());
  });
};

/**
 * A ResourceManager manages access to resources in order to enforce locking,
 * queueing, etc. When a request to access a resource is received, the manager
 * will automatically construct resource objects as necessary, then deconstruct
 * them when they are no longer in use. The resource objects only provide
 * mechanisms for accessing the data they represent, and shouldn't try to
 * maintain resource state in memory.
 * @constructor
 */
function ResourceManager() {
  this.resourceType = undefined;
  this.resources = {};
}

/**
 * Retrieve, if necessary by instantiating, a resource with the specified name.
 * When a resource is instantiated it "job count" will be 0, but it won't be
 * removed until something causes it to emit a 'drain'. Thereore, if you are
 * going to call this you should make sure to kick off something that will
 * increment and later decrement the job counter.
 * @param {String} name The name of this job.
 */
ResourceManager.prototype._getOrCreate = function(name) {
  var self = this;

  // If necessary, instantiate the resource
  if (!this.resources[name]) {
    this.resources[name] = new this.resourceType(name);

    this.resources[name].on('drain', function() {
      delete self.resources[name];
    });
  }

  return this.resources[name];
};

/**
 * Execute the given job against the resource identified by the specified name.
 * @param {Object} job The job to execute.
 */
ResourceManager.prototype.runJob = function(job) {
  var self = this;
  var name = job.resourceName;

  job.enqueueFor(this._getOrCreate(name));
};

/**
 * Retrieve the serialized state of an instance.
 * @param {String} name The name of the resource to retreieve.
 * @param {Function} callback A callback fired with (err, state).
 */
ResourceManager.prototype.get = function(name, callback) {
  var self = this;
  var resource = this._getOrCreate(name);
  resource.getState(callback);
};

/**
 * Get a serialized copy of each resource.
 * @param {Function} callback A callback fired with (err, states).
 */
ResourceManager.prototype.list = function(callback) {
  var self = this;

  function getNames(callback) {
    self.resourceType.prototype.list(callback);
  }

  function mapToStates(names, callback) {
    var resources = names.map(function(name) {
      return self._getOrCreate(name);
    });

    async.map(resources, function(resource, callback) {
      resource.getState(callback);
    }, callback);
  }

  async.waterfall([getNames, mapToStates], callback);
};

/**
 * Resource managers may optionally override this to do asynchronous
 * initialization tasks.
 * @param {Function} callback A callback fired with (err).
 */
ResourceManager.prototype.init = function(callback) {
  callback();
};

exports.ResourceManager = ResourceManager;
exports.DirectoryResource = DirectoryResource;
<commit_msg>sort listed resources<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');
var sys = require('sys');
var path = require('path');
var events = require('events');

var sprintf = require('sprintf').sprintf;
var async = require('async');

var Errorf = require('util/misc').Errorf;

/**
 * Resources for which jobs can be queued and executed. Implementations must
 * specify an 'exists' method.
 * @extends {events.EventEmitter}
 * @param {String} name The name of this resource's directory.
 */
function Resource(name) {
  this.name = name;
  this._serializer = undefined;
  this._jobs = [];
  this._waiters = [];
  this._running = null;
  this._jobCount = 0;
  this._state = null;
}

sys.inherits(Resource, events.EventEmitter);

/**
 * Retrieve a list of resources of this type.
 * @param {Function} callback A callback fired with (err, list).
 */
Resource.prototype.list = function(callback) { callback(new Error('Not Implemented')); };

/**
 * Determine whether this resource exists. Should be overridden by resource
 * implementations.
 * @param {Function} callback A callback fired with (exists).
 */
Resource.prototype.exists = function(callback) { callback(false); };

/**
 * Determine the swiz type for this resource. Implementations should specify
 * a _serializerType property.
 * @returns {String} The serializer type for use by swiz.
 */
Resource.prototype.getSerializerType = function() {
  return this.constructor.name;
};

/**
 * Retrieve the serialized state of this resource. If a job is currently
 * executing on this resource this will use the state cached when that job
 * began. Otherwise it will retrieve the state on demand.
 * @param {Function} callback A callback fired with (err, state).
 */
Resource.prototype.getState = function(callback) {
  var self = this;

  if (this._running) {
    // If a job is running...
    if (!this._state) {
      // The state isn't ready yet, wait for it...
      this.once('cache', callback);
    } else if (this._state instanceof Error) {
      // The state was an error, whoops
      callback(this._state);
    } else {
      // Use the cached state directly
      callback(null, this._state);
    }
  } else {
    // Make sure no jobs start while we're doing this
    this._jobCount++;
    this._waitToCheck(function(afterCheck) {
      self.exists(function(exists) {
        if (!exists) {
          callback(self.getExistenceError(exists));
          self._removeJob(false);
          afterCheck();
          return;
        }
        self._serializer.buildObject(self, function(err, state) {
          callback(err, state);
          self._removeJob(false);
          afterCheck();
        });
      });
    });
  }
};

/**
 * Attempt to predict whether a resource will exist after the current job
 * queue has been flushed.
 * @param {Function} callback A callback fired with (willExist).
 */
Resource.prototype.willExist = function(callback) {
  var i;

  // Make a copy of the job queue and reverse it
  var priorJobs = this._jobs.slice(0, this._jobs.length).reverse();

  if (this._running) {
    priorJobs.push(this._running);
  }

  // Traverse prior jobs to see if they create/delete the resource
  for (i = 0; i < priorJobs.length; i++) {
    if (priorJobs[i].willCreate()) {
      callback(true);
      return;
    }

    if (priorJobs[i].willDelete()) {
      callback(false);
      return;
    }
  }

  // No job will create or delete this resource, does it exist now?
  this.exists(callback);
};

/**
 * Enqueue a job for this resource.
 * @param {Object} job The job to enqueue.
 */
Resource.prototype.enqueueJob = function(job, callback) {
  var self = this;
  this._jobCount++;

  this._waitToCheck(function(afterCheck) {

    // Test whether the resource will exist after the queue flushes.
    self.willExist(function(willExist) {

      // If the job can't handle a resource with willExist, callback with error
      if (!job.canHandleExistence(willExist)) {
        callback(self.getExistenceError(willExist));
        afterCheck();
        self._removeJob(false);
        return;
      }

      // When the job ends, start the next one
      job.on('error', function() {
        self._removeJob(true);
      });

      job.on('success', function() {
        self._removeJob(true);
      });

      // Enqueue this job and make sure the queue is being processed
      self._jobs.push(job);
      self._cycle();
      afterCheck();
      callback();
    });
  });
};

/**
 * Generate an error for this resource based on the passed boolean indicating
 * what the problem is.
 * @param {Boolean} exists Is that problem that it does exist, or doesn't?
 * @returns {Error} The appropriate error.
 */
Resource.prototype.getExistenceError = function(exists) {
  var fmt;

  if (exists) {
    fmt = '%s \'%s\' already exists.';
  } else {
    fmt = '%s \'%s\' does not exist.';
  }

  return new Errorf(fmt, this.constructor.name, this.name);
};

/**
 * Remove a job by decreasing the reference counter and, if the job was queued,
 * removing the reference to it as well.
 * @param {Boolean} queued Whether the job was queued.
 */
Resource.prototype._removeJob = function(queued) {
  this._jobCount--;

  // Jobs that have reached the queue will always make it to the head
  if (queued) {
    this._running = null;
    this._state = null;
    this._cycle();
  }

  if (this._jobCount === 0) {
    this.emit('drain');
  }
};

/**
 * If no job is currently being processed, start the one at the head of the
 * queue.
 * @private
 */
Resource.prototype._cycle = function() {
  var self = this;

  if (!this._running && this._jobs.length > 0) {
    this._running = this._jobs.shift();

    this._serializer.buildObject(this, function(err, state) {
      self._state = err || state;
      self.emit('cache', err, state);
      self._running.start();
    });
  }
};

/**
 * Called by jobs waiting to check their options. Only one job may be checking
 * its options at any given time.
 * @param {Function} callback A callback fired when job may check its options.
 */
Resource.prototype._waitToCheck = function(callback) {
  var self = this;

  function afterCheck() {
    self._waiters.shift();
    if (self._waiters.length > 0) {
      self._waiters[0](afterCheck);
    }
  }

  this._waiters.push(callback);
  if (this._waiters.length === 1) {
    this._waiters[0](afterCheck);
  }
};

/**
 * A resource that is backed by a directory.
 * @param {String} name The name of this resource's directory.
 * @constructor
 */
function DirectoryResource(name) {
  Resource.call(this, name);
  this.parentDir = this.getParentDir();
}

sys.inherits(DirectoryResource, Resource);

/**
 * Get parent directory of resources of this type. This must be set by
 * DirectoryResource implementations.
 * @returns {String} The path to the directory containing resource sof this
 *     type.
 */
DirectoryResource.prototype.getParentDir = function() { return undefined; };

/**
 * @inheritdoc
 */
DirectoryResource.prototype.list = function(callback) {
  fs.readdir(this.getParentDir(), callback);
};

/**
 * Get the path to the root of this resource.
 * @returns {String} Path to the root of this resource.
 */
DirectoryResource.prototype.getRoot = function() {
  return path.join(this.parentDir, this.name);
};

/**
 * Determine whether this resource exists by checking for its root directory.
 * @param {Function} callback A callback fired with (exists).
 */
DirectoryResource.prototype.exists = function(callback) {
  fs.stat(this.getRoot(), function(err, stats) {
    callback(!err && stats.isDirectory());
  });
};

/**
 * A ResourceManager manages access to resources in order to enforce locking,
 * queueing, etc. When a request to access a resource is received, the manager
 * will automatically construct resource objects as necessary, then deconstruct
 * them when they are no longer in use. The resource objects only provide
 * mechanisms for accessing the data they represent, and shouldn't try to
 * maintain resource state in memory.
 * @constructor
 */
function ResourceManager() {
  this.resourceType = undefined;
  this.resources = {};
}

/**
 * Retrieve, if necessary by instantiating, a resource with the specified name.
 * When a resource is instantiated it "job count" will be 0, but it won't be
 * removed until something causes it to emit a 'drain'. Thereore, if you are
 * going to call this you should make sure to kick off something that will
 * increment and later decrement the job counter.
 * @param {String} name The name of this job.
 */
ResourceManager.prototype._getOrCreate = function(name) {
  var self = this;

  // If necessary, instantiate the resource
  if (!this.resources[name]) {
    this.resources[name] = new this.resourceType(name);

    this.resources[name].on('drain', function() {
      delete self.resources[name];
    });
  }

  return this.resources[name];
};

/**
 * Execute the given job against the resource identified by the specified name.
 * @param {Object} job The job to execute.
 */
ResourceManager.prototype.runJob = function(job) {
  var self = this;
  var name = job.resourceName;

  job.enqueueFor(this._getOrCreate(name));
};

/**
 * Retrieve the serialized state of an instance.
 * @param {String} name The name of the resource to retreieve.
 * @param {Function} callback A callback fired with (err, state).
 */
ResourceManager.prototype.get = function(name, callback) {
  var self = this;
  var resource = this._getOrCreate(name);
  resource.getState(callback);
};

/**
 * Get a serialized copy of each resource.
 * @param {Function} callback A callback fired with (err, states).
 */
ResourceManager.prototype.list = function(callback) {
  var self = this;

  function getNames(callback) {
    self.resourceType.prototype.list(callback);
  }

  function mapToStates(names, callback) {
    var resources = names.map(function(name) {
      return self._getOrCreate(name);
    });

    async.map(resources, function(resource, callback) {
      resource.getState(callback);
    },
    function(err, requests) {
      if (!err) {
        requests.sort(function(a, b) {
          return (a.name > b.name);
        });
      }
      callback(err, requests);
    });
  }

  async.waterfall([getNames, mapToStates], callback);
};

/**
 * Resource managers may optionally override this to do asynchronous
 * initialization tasks.
 * @param {Function} callback A callback fired with (err).
 */
ResourceManager.prototype.init = function(callback) {
  callback();
};

exports.ResourceManager = ResourceManager;
exports.DirectoryResource = DirectoryResource;
<|endoftext|>


<commit_before>/**
 * @fileoverview Integration test for a JS server and a JS client communication
 *
 * Grunt's subtask_setupIntegrationTestEnvironment should spawn these servers
 * before running the tests. See Gruntfile's test target for details.
 *
 * Runs in both browser and NodeJS.
 *
 * Only the public "veyron" module is available for integration tests.
 * All globals (veyron, expect, testconfig) are injected by test runners.
 */

describe('Server and client in JS', function() {
  var client;
  var cacheServiceClient;
  var cacheServiceClientUsingEndpoint;
  before(function(done) {

    // Our cache service
    var cache = {
      cacheMap: {},
      Set: function(key, value) {
        this.cacheMap[key] = value;
      },
      Get: function(key) {
        var def = new Veyron.Deferred();
        var val = this.cacheMap[key];
        if (val === undefined) {
          def.reject('unknown key');
        } else {
          def.resolve(val);
        }
        return def.promise;
      } ,
      MultiGet: function($stream) {
        var def = new Veyron.Deferred();
        $stream.promise.then(function() {
          def.resolve();
        }).catch (function(e) {
          def.reject(e);
        });
        var self = this;
        $stream.onmessage = function(key) {
          var val = self.cacheMap[key];
          if (val === undefined) {
            def.reject('unknown key');
          }
          $stream.send(val);
        };

        return def.promise;
      }
    };

    var veyronConfig = {
      'proxy': testconfig['WSPR_SERVER_URL'],
      'identityServer': testconfig['IDENTITY_SERVER_URL'],
      'logLevel': testconfig['LOG_LEVEL']
    };

    var veyron = new Veyron(veyronConfig);
    // Create server object and publish the service
    var server = veyron.newServer();

    server.register('Cache', cache).then(function() {
      return server.publish('myCache');
    }).then(function(endpoint) {
      expect(endpoint).to.exist;
      expect(endpoint).to.be.a('string');
      expect(endpoint).to.have.string('@1@tcp@127.0.0.1');

      // Create a client to the returned endpoint
      client = veyron.newClient();

      var cacheServiceClientPromise = client.bind(
          'myCache/Cache');

      var cacheServiceClientUsingEndpointPromise = client.bind(
          '/' + endpoint + '/Cache');

      Veyron.Promise.all([cacheServiceClientPromise,
        cacheServiceClientUsingEndpointPromise]).then(function(results) {
        cacheServiceClient = results[0];
        cacheServiceClientUsingEndpoint = results[1];
        done();
      }).catch (done);

    }).catch (function(e) {
      done(e);
    });

  });

  it('Should be able to invoke methods after the service is published ' +
     'using published name', function() {
        var result = cacheServiceClient.Set('foo', 'bar').then(function() {
          return cacheServiceClient.Get('foo');
        });

        return expect(result).to.eventually.become('bar');
      });

  it('Should be able to invoke streaming methods after the service is ' +
      'published', function(done) {
        var promise = cacheServiceClient.Set('foo', 'bar');
        var thenGenerator = function(i) {
          return function() {
            cacheServiceClient.Set('' + i, '' + (i + 1));
          };
        };

        for (var i = 0; i < 10; i++) {
          promise = promise.then(thenGenerator(i));
        }

        var nextNumber = 1;
        promise.then(function() {
          return cacheServiceClient.MultiGet();
        }).then(function(stream) {
          stream.onmessage = function(value) {
            expect(value).to.equal('' + nextNumber);
            nextNumber += 2;
          };

          // Now let's send some requests.
          for (var i = 0; i < 10; i += 2) {
            stream.send('' + i);
          }

          stream.close();
          return stream.promise;
        }).then(function() {
          expect(nextNumber).to.equal(11);
          done();
        }).catch (done);
      });

  it('Should be able to return errors', function() {
    var result = cacheServiceClient.Get('bar');
    return expect(result).to.eventually.be.rejected;
  });

  it('Should get an exception calling non-existing methods', function() {
    var fn = function() {
      cacheServiceClient.SomeNonExistingMethod('bar');
    };

    expect(fn).to.throw();
  });

  it('Should be able to invoke methods after the service is published ' +
      'using the endpoint name', function() {
        var result = cacheServiceClientUsingEndpoint.Set('foo', 'bar')
            .then(function() {
              return cacheServiceClientUsingEndpoint.Get('foo');
            });

        return expect(result).to.eventually.equal('bar');

      });

  it('Should fail to bind to the wrong name', function() {
    var service = client.bind('nonexisting/name');
    return expect(service).to.eventually.be.rejected;
  });

  // TODO(aghassemi) tests and implementation for:
  // When JS service returns error
  // Ensure communication fails when service stops
  // Publishing to one proxy and calling to a different one

});
<commit_msg>javascript/api: a test for sending and returning JS objects for methods calls<commit_after>/**
 * @fileoverview Integration test for a JS server and a JS client communication
 *
 * Grunt's subtask_setupIntegrationTestEnvironment should spawn these servers
 * before running the tests. See Gruntfile's test target for details.
 *
 * Runs in both browser and NodeJS.
 *
 * Only the public "veyron" module is available for integration tests.
 * All globals (veyron, expect, testconfig) are injected by test runners.
 */

describe('Server and client in JS', function() {
  var client;
  var cacheServiceClient;
  var cacheServiceClientUsingEndpoint;
  before(function(done) {

    // Our cache service
    var cache = {
      cacheMap: {},
      Set: function(key, value) {
        this.cacheMap[key] = value;
      },
      Get: function(key) {
        var def = new Veyron.Deferred();
        var val = this.cacheMap[key];
        if (val === undefined) {
          def.reject('unknown key');
        } else {
          def.resolve(val);
        }
        return def.promise;
      } ,
      MultiGet: function($stream) {
        var def = new Veyron.Deferred();
        $stream.promise.then(function() {
          def.resolve();
        }).catch (function(e) {
          def.reject(e);
        });
        var self = this;
        $stream.onmessage = function(key) {
          var val = self.cacheMap[key];
          if (val === undefined) {
            def.reject('unknown key');
          }
          $stream.send(val);
        };

        return def.promise;
      }
    };

    var veyronConfig = {
      'proxy': testconfig['WSPR_SERVER_URL'],
      'identityServer': testconfig['IDENTITY_SERVER_URL'],
      'logLevel': testconfig['LOG_LEVEL']
    };

    var veyron = new Veyron(veyronConfig);
    // Create server object and publish the service
    var server = veyron.newServer();

    server.register('Cache', cache).then(function() {
      return server.publish('myCache');
    }).then(function(endpoint) {
      expect(endpoint).to.exist;
      expect(endpoint).to.be.a('string');
      expect(endpoint).to.have.string('@1@tcp@127.0.0.1');

      // Create a client to the returned endpoint
      client = veyron.newClient();

      var cacheServiceClientPromise = client.bind(
          'myCache/Cache');

      var cacheServiceClientUsingEndpointPromise = client.bind(
          '/' + endpoint + '/Cache');

      Veyron.Promise.all([cacheServiceClientPromise,
        cacheServiceClientUsingEndpointPromise]).then(function(results) {
        cacheServiceClient = results[0];
        cacheServiceClientUsingEndpoint = results[1];
        done();
      }).catch (done);

    }).catch (function(e) {
      done(e);
    });

  });

  it('Should be able to invoke methods after the service is published ' +
     'using published name', function() {
        var result = cacheServiceClient.Set('foo', 'bar').then(function() {
          return cacheServiceClient.Get('foo');
        });

        return expect(result).to.eventually.become('bar');
      });

  it('Should be able to use objects as arguments and returns', function() {
      var expected = { a: 'foo', b: 2 };
      var result = cacheServiceClient.Set('objkey', expected).then(function() {
        return cacheServiceClient.Get('objkey');
      });

      return expect(result).to.eventually.become(expected);
    });

  it('Should be able to invoke streaming methods after the service is ' +
      'published', function(done) {
        var promise = cacheServiceClient.Set('foo', 'bar');
        var thenGenerator = function(i) {
          return function() {
            cacheServiceClient.Set('' + i, '' + (i + 1));
          };
        };

        for (var i = 0; i < 10; i++) {
          promise = promise.then(thenGenerator(i));
        }

        var nextNumber = 1;
        promise.then(function() {
          return cacheServiceClient.MultiGet();
        }).then(function(stream) {
          stream.onmessage = function(value) {
            expect(value).to.equal('' + nextNumber);
            nextNumber += 2;
          };

          // Now let's send some requests.
          for (var i = 0; i < 10; i += 2) {
            stream.send('' + i);
          }

          stream.close();
          return stream.promise;
        }).then(function() {
          expect(nextNumber).to.equal(11);
          done();
        }).catch (done);
      });

  it('Should be able to return errors', function() {
    var result = cacheServiceClient.Get('bar');
    return expect(result).to.eventually.be.rejected;
  });

  it('Should get an exception calling non-existing methods', function() {
    var fn = function() {
      cacheServiceClient.SomeNonExistingMethod('bar');
    };

    expect(fn).to.throw();
  });

  it('Should be able to invoke methods after the service is published ' +
      'using the endpoint name', function() {
        var result = cacheServiceClientUsingEndpoint.Set('foo', 'bar')
            .then(function() {
              return cacheServiceClientUsingEndpoint.Get('foo');
            });

        return expect(result).to.eventually.equal('bar');

      });

  it('Should fail to bind to the wrong name', function() {
    var service = client.bind('nonexisting/name');
    return expect(service).to.eventually.be.rejected;
  });

  // TODO(aghassemi) tests and implementation for:
  // When JS service returns error
  // Ensure communication fails when service stops
  // Publishing to one proxy and calling to a different one

});
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * Copyright (c) 2012 ObjectLabs Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:

 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
var Module = require('module')
var argparser = require('nomnom')
var inherits = require('util').inherits
var _o = require('bond')._o

/*******************************************************************************
 * CONSTANTS
 */
var TYPE_FIELD = '_type'
var PROPERTY_FIELD = '$property'
var __DEEP_MODE__ = false

/*******************************************************************************
 * @class Atom
 * @ignore
 */
function Atom(typeResolver) {
  this._typeResolver = typeResolver || _o;
};

Atom.prototype = { // XXX did we just overwrite Atom.prototype.constructor? Yes but we fix below (decide)

  /***************************************************************************
   * ignoreFields
   */
  ignoreFields : [],

  /***************************************************************************
   * _typeResolver
   */
  _typeResolver : null,

  /***************************************************************************
   * make
   *
   * @param {Object} datum
   * @param {Object|string} targetType
   * @param {boolean} isClass
   * @param {Object} mod - module
   * @param {Object} result
   */
  make: function(datum, targetType, args, isClass, mod, result) { // XXX seems like result not used? Maybe for when instantiate type first? hmmm
    // primitives
    if (datum === null) {
      return null;
    }

    if (datum === undefined) {
      return undefined;
    }

    dtype = typeof(datum);
    if (dtype === 'string') {
      return datum;
    }

    if (dtype === 'boolean') {
      return datum;
    }

    if (dtype === 'number') {
      return datum;
    }

    if (dtype === 'function') {
      return datum;
    }

    // arrays
    if (datum.constructor === Array) {
      if (__DEEP_MODE__) {
        return this._makeArray(datum, mod);
      } else {
        return datum
      }
    }

    // objects
    if (dtype === 'object') {
      var value = this._makeObject(datum, targetType, args, isClass, mod, result);
      return value
    }

    throw new Error("Unable to make from datum: " + datum);
  },

  /***************************************************************************
   * _makeArray
   *
   * @param prototype
   */
  _makeArray : function(datum, mod) {
    var self = this;
    return datum.map(function(elem) { return self.make(elem, null, null, false, mod); });
  },

  /***************************************************************************
   * _makeObject
   *
   * @param {Object} datum
   * @param {boolean} [isClass]
   * @param {Object} [result]
   */
  _makeObject: function(datum, targetType, args, isClass, mod, result) {
    if (datum._ref) {
      return _o(mod)(datum._ref); // XXX is this still in play?
    }

    // instantiate object
    result = result || this.instantiate(datum, targetType, args, isClass, mod);

    // define properties
    this._defineProperties(datum, isClass, mod, result)

    if (!isClass) { // only applies to objects not classes
      // initialize
      this._initializeObject(result, args)
      // run main (will only run in right conditions)
      this._runMain(result, mod)
    }

    return result;
  },

  /***************************************************************************
   * _defineProperties
   *
   * @param {Object} datum
   * @param {boolean} [isClass]
   * @param {Object} [result]
   */
  _defineProperties: function(datum, isClass, mod, result) {
    for (var property in datum) {
      if ((this.ignoreFields.indexOf(property) === -1) &&
          property !== TYPE_FIELD &&
          datum.hasOwnProperty(property))
      {
        var value = datum[property]
        if (__DEEP_MODE__) {
          value = this.make(value, null, null, false, mod);
        }

        if (isClass) {
          this._defineProperty(result.prototype, property, value);
        } else {
          this._defineProperty(result, property, value);
        }
      }
    }
  },

  /***************************************************************************
   * _defineProperty
   *
   * @param {Object} obj
   * @param {String} property
   * @param {Object} value
   *
   * @ignore
   */
  _defineProperty : function(obj, property, value) {
    // obj[property] = value
    // obj[property] = { "$property" : <property-def> }
    // XXX this should probably be o({$property: <property-def>}) ??

    if (value != null && typeof(value) === 'object' && value[PROPERTY_FIELD]) {
      // $property case
      Object.defineProperty(obj, property, value[PROPERTY_FIELD])
    } else {
      // XXX was doing this but don't think that is quite right. Just setting works much better in
      //  the case where you want to have a non-shared property redefined in the obj not in proto
      // XXX maybe skip _C? Do this upstairs

      Object.defineProperty(obj, property, {
        enumerable: true,
        configurable: true,
        writable: true,
        value: value
      })
    }
  },

  /***************************************************************************
   * instantiate
   *
   * @param {Object} datum
   * @param {boolean} isClass
   *
   * @returns {Object} The object or class (Function) instantiated from datum
   */
  instantiate: function(datum, targetType, args, isClass, mod) {
    var self = this
    var type = targetType || datum[TYPE_FIELD] || Object

    if (typeof(type) === 'string') {
      var resolver = this._typeResolver;
      if (resolver) {
        var typeName = type;
        try {
          type = resolver(mod)(typeName);
        } catch (e) {
          throw new Error("Could not resolve _type: '" + typeName + "' from module " + mod.filename + " -- " + e.message)
        }
        if (!type) {
          throw new Error("Could not resolve _type: '" + typeName + "' from module " + mod.filename)
        }
      } else {
        throw new Error("Could not resolve _type: " + type + " . Could not find resolver")
      }
    }

    var initSuppressionArg = { __supressInit__: true }

    // helper function
    var makeConstructor = function() {
      var C = function() {
        // automatically chain with init suppression (_init definition should chain if desired)
        C.super_.apply(this, [initSuppressionArg])  // XXX chain rest of args or no?

        if (C.prototype._C) { // call _C as defined
          // pass through args but also deal with __supressInit__
          var cArgs = arguments
          var suppressInit = false
          if (cArgs && cArgs.length > 0) {
            var lastArg = arguments[cArgs.length - 1]
            if (lastArg.__supressInit__) {
              suppressInit = true
              delete cArgs[cArgs.length - 1]
            }
          }
          C.prototype._C.apply(this, cArgs)
        }

        // call _init unless supressed
        if (!suppressInit) {
          self._initializeObject(this, cArgs)
        }
      }

      // mark as defined by Atom
      C.__isAtomDefined__ = true

      return C
    }

    if (typeof(type) === 'function') { // constructor
      var result = null
      if (isClass) {
        // our constructor
        var C = makeConstructor()
        // link superclass
        inherits(C, type)
        // define _super method
        Object.defineProperty(C.prototype, '_super', { // XXX this is not right in all cases should remove
          enumerable: false,
          configurable: false,
          writable: false,
          value: function(methodName) {
            if (type.prototype[methodName]) {
              return type.prototype[methodName].bind(this)
            }
                                 // XXX
            return function() {} // just so clients don't have to check if the superclass has method
          }
        })
        // define _type method XXX
        Object.defineProperty(C.prototype, '_type', {
          enumerable: false,
          configurable: false,
          writable: false,
          value: function(methodName) {
            if (C.prototype[methodName]) {
              return C.prototype[methodName].bind(this)
            }
                                 // XXX
            return function() {} // just so clients don't have to check if the superclass has method
          }
        })
        result = C
      } else {
        args = args || []
        if (type.__isAtomDefined__) {
          // Supress the atom-defined constructor from calling _init. Will be called
          // after define-properties in make()
          args.push(initSuppressionArg)
        }

        // Can we optimize by calling new directly if no args (e.g result = new type(args)) ?
        // Dynamically call new type with variable args. This is hairy. Found solution here
        // http://jsperf.com/dynamic-arguments-to-the-constructor
        result = new (Function.prototype.bind.apply(type, [null].concat(args)))
      }

      return result
    }

    // otherwise assume it is an object
    var result
    if (isClass) { // XXX is this a case we want to support ( oo where type is object )?
      // our constructor
      var C = makeConstructor()
      C.prototype = type
      C.prototype.constructor = C
      result = C
    } else {
      result = Object.create(type)
      // XXX define _type?
      Object.defineProperty(result, '_type', {
        enumerable: false,
        configurable: false,
        writable: false,
        value: function(methodName) {
          if (type[methodName]) {
            return type[methodName].bind(this)
          }
          // XXX
          return function() {} // just so clients don't have to check if the superclass has method
        }
      })
    }

    return result
  },

  /***************************************************************************
   * _initializeObject
   */
  _initializeObject: function(obj, args) {
    if (obj._init) {
      obj._init.apply(obj, args)
    }
  },

  /***************************************************************************
   * _runMain
   */
  _runMain: function(obj, mod) {
    if (obj._main && require.main && (require.main == mod)) {
      // if cmdargs are defined use them
      var cmdargs = obj.cmdargs
      if (cmdargs) {
        argparser.options(cmdargs)
      }

      var options = argparser.parse(process.argv.slice(2))
      delete options._ // kill the _ args since we don't want them

      // configure option properties
      this._configureOptionProperties(obj, cmdargs, options)

      // do it
      obj._main(options)
    }
  },

  /***************************************************************************
   * configureOptionProperties
   */
  _configureOptionProperties: function(obj, optionDefinitions, options) {
    if (optionDefinitions) {
      for (var option in options) {
        if (optionDefinitions[option] && optionDefinitions[option].property) {
          var optionValue = options[option]
          obj[option] = optionValue
        }
      }
    }
  }

};

Atom.prototype.constructor = Atom; // very important this is here

/*******************************************************************************
 * atom
 */
var atom = new Atom();

/*******************************************************************************
 * o
 *
 * @param {Object} module
 */
function o(mod) {
  if (!(mod instanceof Module)) {
    throw(Error("Must supply a module to o: " + JSON.stringify(mod)))
  }
  return function() { // takes (datum, targetType, args...)
    var datum = arguments[0]
    var targetType
    var args
    if (arguments.length > 1) {
      targetType = arguments[1]
    }
    if (arguments.length > 2) { // the rest are constructor args
      var argumentsArray = Array.prototype.slice.call(arguments);
      args = argumentsArray.slice(2)
    }
    return atom.make(datum, targetType, args, false, mod);
  }
}

/*******************************************************************************
 * oo
 *
 * @param {Object} datum
 */
function oo(mod) {
  if (!(mod instanceof Module)) {
    throw(Error("Must supply a module to oo: " + JSON.stringify(mod)))
  }
  return function(datum) {
    return atom.make(datum, null, null, true, mod);
  }
}

/*******************************************************************************
 * exports
 */
if (typeof(exports) != "undefined") {
  exports.Atom = Atom;
  exports.o = o;
  exports.oo = oo;
}
<commit_msg>refactor of initialization steps<commit_after>/*******************************************************************************
 *
 * Copyright (c) 2012 ObjectLabs Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:

 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
var Module = require('module')
var argparser = require('nomnom')
var inherits = require('util').inherits
var _o = require('bond')._o

/*******************************************************************************
 * CONSTANTS
 */
var TYPE_FIELD = '_type'
var PROPERTY_FIELD = '$property'
var __DEEP_MODE__ = false

/*******************************************************************************
 * @class Atom
 * @ignore
 */
function Atom(typeResolver) {
  this._typeResolver = typeResolver || _o;
};

Atom.prototype = { // XXX did we just overwrite Atom.prototype.constructor? Yes but we fix below (decide)

  /***************************************************************************
   * ignoreFields
   */
  ignoreFields : [],

  /***************************************************************************
   * _typeResolver
   */
  _typeResolver : null,

  /***************************************************************************
   * make
   *
   * @param {Object} datum
   * @param {Object|string} targetType
   * @param {boolean} isClass
   * @param {Object} mod - module
   * @param {Object} result
   */
  make: function(datum, targetType, args, isClass, mod, result) { // XXX seems like result not used? Maybe for when instantiate type first? hmmm
    // primitives
    if (datum === null) {
      return null;
    }

    if (datum === undefined) {
      return undefined;
    }

    dtype = typeof(datum);
    if (dtype === 'string') {
      return datum;
    }

    if (dtype === 'boolean') {
      return datum;
    }

    if (dtype === 'number') {
      return datum;
    }

    if (dtype === 'function') {
      return datum;
    }

    // arrays
    if (datum.constructor === Array) {
      if (__DEEP_MODE__) {
        return this._makeArray(datum, mod);
      } else {
        return datum
      }
    }

    // objects
    if (dtype === 'object') {
      var value = this._makeObject(datum, targetType, args, isClass, mod, result);
      return value
    }

    throw new Error("Unable to make from datum: " + datum);
  },

  /***************************************************************************
   * _makeArray
   *
   * @param prototype
   */
  _makeArray : function(datum, mod) {
    var self = this;
    return datum.map(function(elem) { return self.make(elem, null, null, false, mod); });
  },

  /***************************************************************************
   * _makeObject
   *
   * @param {Object} datum
   * @param {boolean} [isClass]
   * @param {Object} [result]
   */
  _makeObject: function(datum, targetType, args, isClass, mod, result) {
    if (datum._ref) {
      return _o(mod)(datum._ref); // XXX is this still in play?
    }

    // instantiate object
    result = result || this.instantiate(datum, targetType, args, isClass, mod);

    // define properties
    this._defineProperties(datum, isClass, mod, result)

    if (!isClass) { // only applies to objects not classes
      // initialize
      this._initializeObject(result, args)
      // run main (will only run in right conditions)
      this._runMain(result, mod)
    }

    return result;
  },

  /***************************************************************************
   * _defineProperties
   *
   * @param {Object} datum
   * @param {boolean} [isClass]
   * @param {Object} [result]
   */
  _defineProperties: function(datum, isClass, mod, result) {
    for (var property in datum) {
      if ((this.ignoreFields.indexOf(property) === -1) &&
          property !== TYPE_FIELD &&
          datum.hasOwnProperty(property))
      {
        var value = datum[property]
        if (__DEEP_MODE__) {
          value = this.make(value, null, null, false, mod);
        }

        if (isClass) {
          this._defineProperty(result.prototype, property, value);
        } else {
          this._defineProperty(result, property, value);
        }
      }
    }
  },

  /***************************************************************************
   * _defineProperty
   *
   * @param {Object} obj
   * @param {String} property
   * @param {Object} value
   *
   * @ignore
   */
  _defineProperty : function(obj, property, value) {
    // obj[property] = value
    // obj[property] = { "$property" : <property-def> }
    // XXX this should probably be o({$property: <property-def>}) ??

    if (value != null && typeof(value) === 'object' && value[PROPERTY_FIELD]) {
      // $property case
      Object.defineProperty(obj, property, value[PROPERTY_FIELD])
    } else {
      // XXX was doing this but don't think that is quite right. Just setting works much better in
      //  the case where you want to have a non-shared property redefined in the obj not in proto
      // XXX maybe skip _C? Do this upstairs

      Object.defineProperty(obj, property, {
        enumerable: true,
        configurable: true,
        writable: true,
        value: value
      })
    }
  },

  /***************************************************************************
   * instantiate
   *
   * @param {Object} datum
   * @param {boolean} isClass
   *
   * @returns {Object} The object or class (Function) instantiated from datum
   */
  instantiate: function(datum, targetType, args, isClass, mod) {
    var self = this
    var type = targetType || datum[TYPE_FIELD] || Object

    if (typeof(type) === 'string') {
      var resolver = this._typeResolver;
      if (resolver) {
        var typeName = type;
        try {
          type = resolver(mod)(typeName);
        } catch (e) {
          console.log(e.stack)
          throw new Error("Could not resolve _type: '" + typeName + "' from module " + mod.filename + " -- " + e.message)
        }
        if (!type) {
          throw new Error("Could not resolve _type: '" + typeName + "' from module " + mod.filename)
        }
      } else {
        throw new Error("Could not resolve _type: " + type + " . Could not find resolver")
      }
    }

    var initSuppressionArg = { __supressInit__: true }

    // helper function
    var makeConstructor = function() {
      var C = function() {
        // automatically chain with init suppression (_init definition should chain if desired)
        C.super_.apply(this, [initSuppressionArg])  // XXX chain rest of args or no?

        if (C.prototype._C) { // call _C as defined
          // pass through args but also deal with __supressInit__
          var cArgs = arguments
          var suppressInit = false
          if (cArgs && cArgs.length > 0) {
            var lastArg = arguments[cArgs.length - 1]
            if (lastArg.__supressInit__) {
              suppressInit = true
              delete cArgs[cArgs.length - 1]
            }
          }
          C.prototype._C.apply(this, cArgs)
        }

        // call _init unless supressed
        if (!suppressInit) {
          self._initializeObject(this, cArgs)
        }
      }

      // mark as defined by Atom
      C.__isAtomDefined__ = true

      return C
    }

    if (typeof(type) === 'function') { // constructor
      var result = null
      if (isClass) {
        // our constructor
        var C = makeConstructor()
        // link superclass
        inherits(C, type)

        if (!C.prototype._init) { // XXX will this stomp on _init functions we inherit? Dont think so
          C.prototype._init = function() {}
        }

        result = C
      } else {
        args = args || []
        if (type.__isAtomDefined__) {
          // Supress the atom-defined constructor from calling _init. Will be called
          // after define-properties in make()
          args.push(initSuppressionArg)
        }

        // Can we optimize by calling new directly if no args (e.g result = new type(args)) ?
        // Dynamically call new type with variable args. This is hairy. Found solution here
        // http://jsperf.com/dynamic-arguments-to-the-constructor
        result = new (Function.prototype.bind.apply(type, [null].concat(args)))
      }

      return result
    }

    // otherwise assume it is an object
    var result
    if (isClass) { // XXX is this a case we want to support ( oo where type is object )?
      // our constructor
      var C = makeConstructor()
      C.prototype = type
      C.prototype.constructor = C
      result = C
    } else {
      result = Object.create(type)
    }

    return result
  },

  /***************************************************************************
   * _initializeObject
   */
  _initializeObject: function(obj, args) {
    if (obj._init) {
      obj._init.apply(obj, args)
    }
  },

  /***************************************************************************
   * _runMain
   */
  _runMain: function(obj, mod) {
    if (obj._main && require.main && (require.main == mod)) {
      // if cmdargs are defined use them
      var cmdargs = obj.cmdargs
      if (cmdargs) {
        argparser.options(cmdargs)
      }

      var options = argparser.parse(process.argv.slice(2))
      delete options._ // kill the _ args since we don't want them

      // configure option properties
      this._configureOptionProperties(obj, cmdargs, options)

      // do it
      obj._main(options)
    }
  },

  /***************************************************************************
   * configureOptionProperties
   */
  _configureOptionProperties: function(obj, optionDefinitions, options) {
    if (optionDefinitions) {
      for (var option in options) {
        if (optionDefinitions[option] && optionDefinitions[option].property) {
          var optionValue = options[option]
          obj[option] = optionValue
        }
      }
    }
  }

};

Atom.prototype.constructor = Atom; // very important this is here

/*******************************************************************************
 * atom
 */
var atom = new Atom();

/*******************************************************************************
 * o
 *
 * @param {Object} module
 */
function o(mod) {
  if (!(mod instanceof Module)) {
    throw(Error("Must supply a module to o: " + JSON.stringify(mod)))
  }
  return function() { // takes (datum, targetType, args...)
    var datum = arguments[0]
    var targetType
    var args
    if (arguments.length > 1) {
      targetType = arguments[1]
    }
    if (arguments.length > 2) { // the rest are constructor args
      var argumentsArray = Array.prototype.slice.call(arguments);
      args = argumentsArray.slice(2)
    }

    return atom.make(datum, targetType, args, false, mod);
  }
}

/*******************************************************************************
 * oo
 *
 * @param {Object} datum
 */
function oo(mod) {
  if (!(mod instanceof Module)) {
    throw(Error("Must supply a module to oo: " + JSON.stringify(mod)))
  }
  return function(datum) {
    return atom.make(datum, null, null, true, mod);
  }
}

/*******************************************************************************
 * exports
 */
if (typeof(exports) != "undefined") {
  exports.Atom = Atom;
  exports.o = o;
  exports.oo = oo;
}

<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import flatten from 'lodash/fp/flatten';
import sortBy from 'lodash/fp/sortBy';
import snakeCase from 'lodash/fp/snakeCase';

import NavBar from '../../components/NavBar';
import SideBar from '../../components/SideBar';
import Content from '../../components/Content';
import { actions } from '../actions';
import { buildNavHref, cleanPath, getOperation, onClickHref } from '../../utils';
import docs from '../../../documents.json';

import styles from './app.css';

class App extends Component {

  getCurrentItem(params) {
    if (params.model) {
      return params.model;
    } else if (params.path) {
      return `${params.resource}${params.method}${params.path}`;
    }
    return null;
  }

  createResourceItem(params, resource, currentItem) {
    return {
      name: resource.type,
      items: resource.operations.map((operation) => (
        {
          name: `${operation.method} ${operation.path}`,
          onClick: onClickHref(buildNavHref({
            organization: params.organizationKey,
            application: params.applicationKey,
            resource: resource.type,
            method: operation.method.toLowerCase(),
            path: cleanPath(operation.path),
          })),
          active: currentItem === `${resource.type}${operation.method.toLowerCase()}${cleanPath(operation.path)}`,
          type: 'resource',
          method: operation.method,
          path: operation.path,
        }
      )),
    };
  }

  createModelItem(params, model, currentItem, type = 'model') {
    return {
      name: `${model.name}`,
      onClick: onClickHref(buildNavHref({
        organization: params.organizationKey,
        application: params.applicationKey,
        model: model.name,
      })),
      active: currentItem === model.name,
      type,
    };
  }

  createSideBarItems(params, service, imports, organizations, organizationObj, applications) {
    if (!params.organizationKey) {
      const organizationsWithHref = organizations.map((organization) => (
        {
          name: organization.name,
          onClick: onClickHref(buildNavHref({
            organization: organization.key,
          })),
        }
      ));
      return [{
        name: 'Organizations',
        items: [{
          name: '',
          items: organizationsWithHref,
        }],
      }];
    } else if (params.organizationKey && !params.applicationKey) {
      const applicationsWithHref = applications.map((application) => (
        {
          name: application.name,
          onClick: onClickHref(buildNavHref({
            organization: params.organizationKey,
            application: application.key,
          })),
        }
      ));
      const orgDocsList = docs.organizations[params.organizationKey];
      const docsByOrg = (orgDocsList && orgDocsList.documents) || [];
      const docsWithHref = docsByOrg.map(doc => (
        {
          name: doc.name,
          onClick: onClickHref(buildNavHref({
            organization: params.organizationKey,
            documentation: snakeCase(doc.name),
          })),
        }
      ));
      const applicationSidebarGroup = [{
        name: 'Applications',
        items: [{
          name: '',
          items: applicationsWithHref,
        }],
      }];
      return applicationSidebarGroup.concat(docsWithHref.length
        ? [{
          name: 'Documentation',
          items: [{
            name: '',
            items: docsWithHref,
          }],
        }]
       : []);
    } else if (params.organizationKey && params.applicationKey && service.apidoc) {
      const currentItem = this.getCurrentItem(params);
      const allResources = flatten(service.resources.concat(imports.map((importValue) => importValue.resources)));
      const allModels = flatten(service.models.concat(imports.map((importValue) => importValue.models)));
      const allEnums = flatten(service.enums.concat(imports.map((importValue) => importValue.enums)));

      return [{
        name: 'Resources',
        items: allResources.map((resource) => (this.createResourceItem(params, resource, currentItem))),
      },
      {
        name: 'Models',
        items: [{
          name: '',
          items: allModels.map((model) => (this.createModelItem(params, model, currentItem)))
                          .concat(allEnums.map((enumValue) =>
                            (this.createModelItem(params, enumValue, currentItem, 'enum')))
                          ),
        }],
      }];
    }
    return [{ name: 'Unknown', items: [{ name: 'Unknown', items: [] }] }];
  }

  createNavBarItems(params, service) {
    if (!service.apidoc) {
      return [];
    }
    const operationPath = params.resource ?
            getOperation(params.resource, params.method, params.path, service).path :
            null;
    return [].concat(
      params.organizationKey ? {
        name: params.organizationKey,
        onClick: onClickHref(buildNavHref({
          organization: params.organizationKey,
        })),
      } : [],
      params.applicationKey ? {
        name: params.applicationKey,
        onClick: onClickHref(buildNavHref({
          organization: params.organizationKey,
          application: params.applicationKey,
        })),
      } : [],
      params.resource ? {
        name: `${params.method.toUpperCase()} ${operationPath}`,
        onClick: onClickHref(buildNavHref({
          organization: params.organizationKey,
          application: params.applicationKey,
          resource: params.resource,
          method: params.method,
          path: params.path,
        })),
      } : [],
      params.model ? {
        name: `${params.model}`,
        onClick: onClickHref(buildNavHref({
          organization: params.organizationKey,
          application: params.applicationKey,
          model: params.model,
        })),
      } : []);
  }

  render() {
    const {
      params,
      service,
      imports,
      organizations,
      organization,
      applications,
      children,
    } = this.props;

    const sideBarItems = this.createSideBarItems(params, service, imports, organizations, organization, applications)
      .map((sideBarItem) => {
        sideBarItem.items.map((items) => (
          Object.assign(items, { items: sortBy((item) => item.name, items.items) })
        ));
        return Object.assign(sideBarItem, { items: sortBy((item) => item.name, sideBarItem.items) });
      });

    const navBarItems = this.createNavBarItems(params, service);

    return (

        <NavBar items={navBarItems} homeOnClick={onClickHref('/')} />

          <SideBar sections={sideBarItems} />
          <Content>
            {children}
          </Content>

    );
  }
}

App.propTypes = {
  children: PropTypes.object.isRequired,
  service: PropTypes.object.isRequired,
  organizations: PropTypes.array,
  organization: PropTypes.object,
  applications: PropTypes.array,
  params: PropTypes.object.isRequired,
  imports: PropTypes.array.isRequired,
};

const mapStateToProps = (state) => (
  {
    service: state.application.get('service'),
    organizations: state.app.get('organizations'),
    organization: state.organization.get('organization'),
    applications: state.organization.get('applications'),
    imports: state.application.get('imports'),
  }
);

const mapDispatchToProps = (dispatch) => (
  { actions: bindActionCreators(actions, dispatch) }
);

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);
<commit_msg>Fix sidebar resource duplication<commit_after>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import flatten from 'lodash/fp/flatten';
import sortBy from 'lodash/fp/sortBy';
import snakeCase from 'lodash/fp/snakeCase';

import NavBar from '../../components/NavBar';
import SideBar from '../../components/SideBar';
import Content from '../../components/Content';
import { actions } from '../actions';
import { buildNavHref, cleanPath, getOperation, onClickHref } from '../../utils';
import docs from '../../../documents.json';

import styles from './app.css';

class App extends Component {

  getCurrentItem(params) {
    if (params.model) {
      return params.model;
    } else if (params.path) {
      return `${params.resource}${params.method}${params.path}`;
    }
    return null;
  }

  createResourceItem(params, resource, currentItem) {
    return {
      name: resource.type,
      items: resource.operations.map((operation) => (
        {
          name: `${operation.method} ${operation.path}`,
          onClick: onClickHref(buildNavHref({
            organization: params.organizationKey,
            application: params.applicationKey,
            resource: resource.type,
            method: operation.method.toLowerCase(),
            path: cleanPath(operation.path),
          })),
          active: currentItem === `${resource.type}${operation.method.toLowerCase()}${cleanPath(operation.path)}`,
          type: 'resource',
          method: operation.method,
          path: operation.path,
        }
      )),
    };
  }

  createModelItem(params, model, currentItem, type = 'model') {
    return {
      name: `${model.name}`,
      onClick: onClickHref(buildNavHref({
        organization: params.organizationKey,
        application: params.applicationKey,
        model: model.name,
      })),
      active: currentItem === model.name,
      type,
    };
  }

  createSideBarItems(params, service, imports, organizations, organizationObj, applications) {
    if (!params.organizationKey) {
      const organizationsWithHref = organizations.map((organization) => (
        {
          name: organization.name,
          onClick: onClickHref(buildNavHref({
            organization: organization.key,
          })),
        }
      ));
      return [{
        name: 'Organizations',
        items: [{
          name: '',
          items: organizationsWithHref,
        }],
      }];
    } else if (params.organizationKey && !params.applicationKey) {
      const applicationsWithHref = applications.map((application) => (
        {
          name: application.name,
          onClick: onClickHref(buildNavHref({
            organization: params.organizationKey,
            application: application.key,
          })),
        }
      ));
      const orgDocsList = docs.organizations[params.organizationKey];
      const docsByOrg = (orgDocsList && orgDocsList.documents) || [];
      const docsWithHref = docsByOrg.map(doc => (
        {
          name: doc.name,
          onClick: onClickHref(buildNavHref({
            organization: params.organizationKey,
            documentation: snakeCase(doc.name),
          })),
        }
      ));
      const applicationSidebarGroup = [{
        name: 'Applications',
        items: [{
          name: '',
          items: applicationsWithHref,
        }],
      }];
      return applicationSidebarGroup.concat(docsWithHref.length
        ? [{
          name: 'Documentation',
          items: [{
            name: '',
            items: docsWithHref,
          }],
        }]
       : []);
    } else if (params.organizationKey && params.applicationKey && service.apidoc) {
      const currentItem = this.getCurrentItem(params);
      const allResources = service.resources;
      const allModels = flatten(service.models.concat(imports.map((importValue) => importValue.models)));
      const allEnums = flatten(service.enums.concat(imports.map((importValue) => importValue.enums)));

      return [{
        name: 'Resources',
        items: allResources.map((resource) => (this.createResourceItem(params, resource, currentItem))),
      },
      {
        name: 'Models',
        items: [{
          name: '',
          items: allModels.map((model) => (this.createModelItem(params, model, currentItem)))
                          .concat(allEnums.map((enumValue) =>
                            (this.createModelItem(params, enumValue, currentItem, 'enum')))
                          ),
        }],
      }];
    }
    return [{ name: 'Unknown', items: [{ name: 'Unknown', items: [] }] }];
  }

  createNavBarItems(params, service) {
    if (!service.apidoc) {
      return [];
    }
    const operationPath = params.resource ?
            getOperation(params.resource, params.method, params.path, service).path :
            null;
    return [].concat(
      params.organizationKey ? {
        name: params.organizationKey,
        onClick: onClickHref(buildNavHref({
          organization: params.organizationKey,
        })),
      } : [],
      params.applicationKey ? {
        name: params.applicationKey,
        onClick: onClickHref(buildNavHref({
          organization: params.organizationKey,
          application: params.applicationKey,
        })),
      } : [],
      params.resource ? {
        name: `${params.method.toUpperCase()} ${operationPath}`,
        onClick: onClickHref(buildNavHref({
          organization: params.organizationKey,
          application: params.applicationKey,
          resource: params.resource,
          method: params.method,
          path: params.path,
        })),
      } : [],
      params.model ? {
        name: `${params.model}`,
        onClick: onClickHref(buildNavHref({
          organization: params.organizationKey,
          application: params.applicationKey,
          model: params.model,
        })),
      } : []);
  }

  render() {
    const {
      params,
      service,
      imports,
      organizations,
      organization,
      applications,
      children,
    } = this.props;

    const sideBarItems = this.createSideBarItems(params, service, imports, organizations, organization, applications)
      .map((sideBarItem) => {
        sideBarItem.items.map((items) => (
          Object.assign(items, { items: sortBy((item) => item.name, items.items) })
        ));
        return Object.assign(sideBarItem, { items: sortBy((item) => item.name, sideBarItem.items) });
      });

    const navBarItems = this.createNavBarItems(params, service);

    return (

        <NavBar items={navBarItems} homeOnClick={onClickHref('/')} />

          <SideBar sections={sideBarItems} />
          <Content>
            {children}
          </Content>

    );
  }
}

App.propTypes = {
  children: PropTypes.object.isRequired,
  service: PropTypes.object.isRequired,
  organizations: PropTypes.array,
  organization: PropTypes.object,
  applications: PropTypes.array,
  params: PropTypes.object.isRequired,
  imports: PropTypes.array.isRequired,
};

const mapStateToProps = (state) => (
  {
    service: state.application.get('service'),
    organizations: state.app.get('organizations'),
    organization: state.organization.get('organization'),
    applications: state.organization.get('applications'),
    imports: state.application.get('imports'),
  }
);

const mapDispatchToProps = (dispatch) => (
  { actions: bindActionCreators(actions, dispatch) }
);

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);
<|endoftext|>


<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Visually groups sets of buttons, checks, radios, etc.
//>>label: Controlgroups
//>>group: Forms
//>>css.structure: ../../css/structure/jquery.mobile.controlgroup.css
//>>css.theme: ../../css/themes/default/jquery.mobile.theme.css

define( [ "jquery",
	"../jquery.mobile.buttonMarkup",
	"../jquery.mobile.widget" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

	$.widget( "mobile.controlgroup", $.mobile.widget, {
		options: {
			shadow: false,
			corners: true,
			excludeInvisible: true,
			type: "vertical",
			mini: false,
			initSelector: ":jqmData(role='controlgroup')"
		},

		_create: function() {
			var $el = this.element,
				ui = {
					inner: $( "

" ),
					legend: $( "

" )
				},
				grouplegend = $el.children( "legend" ),
				self = this;

			// Apply the proto
			$el.wrapInner( ui.inner );
			if ( grouplegend.length ) {
				ui.legend.append( grouplegend ).insertBefore( $el.children( 0 ) );
			}
			$el.addClass( "ui-corner-all ui-controlgroup" );

			$.each( this.options, function( key, value ) {
				// Cause initial options to be applied by their handler by temporarily setting the option to undefined
				// - the handler then sets it to the initial value
				self.options[ key ] = undefined;
				self._setOption( key, value, true );
			});

			this._refresh( true );
		},

		_setOption: function( key, value ) {
			var setter = "_set" + key.charAt( 0 ).toUpperCase() + key.slice( 1 );

			if ( this[ setter ] !== undefined ) {
				this[ setter ]( value );
			}

			this._super( key, value );
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + ( key.replace( /([A-Z])/, "-$1" ).toLowerCase() ), value );
		},

		_setType: function( value ) {
			this.element
				.removeClass( "ui-controlgroup-horizontal ui-controlgroup-vertical" )
				.addClass( "ui-controlgroup-" + value );
		},

		_setCorners: function( value ) {
			this.element.toggleClass( "ui-corner-all", value );
		},

		_setShadow: function( value ) {
			this.element.toggleClass( "ui-shadow", value );
		},

		_setMini: function( value ) {
			this.element.toggleClass( "ui-mini", value );
		},

		container: function() {
			return this.element.children( ".ui-controlgroup-controls" );
		},

		_refresh: function( create ) {
			var els = this.element.find( ".ui-btn" ).not( ".ui-slider-handle" );

			els.removeClass( "ui-first-child ui-last-child" );
			if ( !create && this.options.excludeInvisible ) {
				els = els.filter( ":visible" );
			}

			els.eq( 0 ).addClass( "ui-first-child" ).end().last().addClass( "ui-last-child" );
		},

		refresh: function() {
			this._refresh( false );
		}
	});

	// TODO: Implement a mechanism to allow widgets to become enhanced in the
	// correct order when their correct enhancement depends on other widgets in
	// the page being correctly enhanced already.
	//
	// For now, we wait until dom-ready to attach the controlgroup's enhancement
	// hook, because by that time, all the other widgets' enhancement hooks should
	// already be in place, ensuring that all widgets that need to be grouped will
	// already have been enhanced by the time the controlgroup is created.
	$( function() {
		$( document ).bind( "pagecreate create", function( e )  {
			$.mobile.controlgroup.prototype.enhanceWithin( e.target, true );
		});
	});
})(jQuery);
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<commit_msg>[controlgroup] Update first/last classes using common behaviour<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Visually groups sets of buttons, checks, radios, etc.
//>>label: Controlgroups
//>>group: Forms
//>>css.structure: ../../css/structure/jquery.mobile.controlgroup.css
//>>css.theme: ../../css/themes/default/jquery.mobile.theme.css

define( [ "jquery",
	"../jquery.mobile.buttonMarkup",
	"./addFirstLastClasses",
	"../jquery.mobile.widget" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

	$.widget( "mobile.controlgroup", $.mobile.widget, {
		options: {
			shadow: false,
			corners: true,
			excludeInvisible: true,
			type: "vertical",
			mini: false,
			initSelector: ":jqmData(role='controlgroup')"
		},

		_create: function() {
			var $el = this.element,
				ui = {
					inner: $( "

" ),
					legend: $( "

" )
				},
				grouplegend = $el.children( "legend" ),
				self = this;

			// Apply the proto
			$el.wrapInner( ui.inner );
			if ( grouplegend.length ) {
				ui.legend.append( grouplegend ).insertBefore( $el.children( 0 ) );
			}
			$el.addClass( "ui-corner-all ui-controlgroup" );

			$.each( this.options, function( key, value ) {
				// Cause initial options to be applied by their handler by temporarily setting the option to undefined
				// - the handler then sets it to the initial value
				self.options[ key ] = undefined;
				self._setOption( key, value, true );
			});

			this._refresh( true );
		},

		_setOption: function( key, value ) {
			var setter = "_set" + key.charAt( 0 ).toUpperCase() + key.slice( 1 );

			if ( this[ setter ] !== undefined ) {
				this[ setter ]( value );
			}

			this._super( key, value );
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + ( key.replace( /([A-Z])/, "-$1" ).toLowerCase() ), value );
		},

		_setType: function( value ) {
			this.element
				.removeClass( "ui-controlgroup-horizontal ui-controlgroup-vertical" )
				.addClass( "ui-controlgroup-" + value );
		},

		_setCorners: function( value ) {
			this.element.toggleClass( "ui-corner-all", value );
		},

		_setShadow: function( value ) {
			this.element.toggleClass( "ui-shadow", value );
		},

		_setMini: function( value ) {
			this.element.toggleClass( "ui-mini", value );
		},

		container: function() {
			return this.element.children( ".ui-controlgroup-controls" );
		},

		_refresh: function( create ) {
			var els = this.element.find( ".ui-btn" ).not( ".ui-slider-handle" );
			this._addFirstLastClasses( els, this.options.excludeInvisible ? this._getVisibles( els, create ) : els, create );
		},

		refresh: function() {
			this._refresh( false );
		}
	});

	$.widget( "mobile.controlgroup", $.mobile.controlgroup, $.mobile.behaviors.addFirstLastClasses );

	// TODO: Implement a mechanism to allow widgets to become enhanced in the
	// correct order when their correct enhancement depends on other widgets in
	// the page being correctly enhanced already.
	//
	// For now, we wait until dom-ready to attach the controlgroup's enhancement
	// hook, because by that time, all the other widgets' enhancement hooks should
	// already be in place, ensuring that all widgets that need to be grouped will
	// already have been enhanced by the time the controlgroup is created.
	$( function() {
		$( document ).bind( "pagecreate create", function( e )  {
			$.mobile.controlgroup.prototype.enhanceWithin( e.target, true );
		});
	});
})(jQuery);
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<|endoftext|>


<commit_before>import api from 'packages/api';

export const GetRolesList = (Guid: string, options?: any): Promise<IServiceResult1<IUserData$1>> => {
  const uri = `/api/roles`;
  return api.get(uri, options).then(response => response.json());
};
<commit_msg>Fix api calls<commit_after>import api from 'packages/api';

export const GetRolesList = (options?: any): Promise<IServiceResult1<IUserData$1>> => {
  const uri = `/api/roles`;
  return api.get(uri, options).then(response => response.json());
};
<|endoftext|>


<commit_before>/*!
 * libnmap
 * Copyright(c) 2013-2018 Jason Gerfen <jason.gerfen@gmail.com>
 * License: MIT
 */

'use strict'

const fs = require('fs');
const hasbin = require('hasbin');

class validation {

  constructor() {

    /**
     * @var messages
     * Error messages
     */
    this.messages = {

      version: 'Discover method requires nodejs v0.11.2 or greater; network ' +
        'range(s) could not be determined',

      path: 'Supplied path for nmap binary is invalid',

      block: 'Supplied blocksize must not exceed 128',

      range: 'Range must be an array of host(s). Examples: ' +
        '192.168.2.10 (single), 10.0.2.0/24 (CIDR), 10.0.10.5-20 (range)',

      port: 'Port(s) must match one of the following examples: ' +
        '512 (single) | 0-65535 (range) | 10-30,80,443,3306-10000 (multiple)',
    };

    /**
     * @var patterns
     * Object with various REGEX patterns to validate network params
     */
    this.patterns = {

      /**
       * @var ports
       * Regex for matching port ranges
       * @ref http://stackoverflow.com/a/21075138/901697
       */
      ports: /\d{1,6}(?:-\d+)?/g,

      /**
       * @var hostname
       * Regex for matching hostnames (RFC-1123)
       */
      hostname: /^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])|localhost$/,

      /**
       * @var IPv4
       * Regex for matching IPv4 address types
       */
      IPv4: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/,

      /**
       * @var IPv4CIDR
       * Regex for matching IPv4 CIDR notation
       */
      IPv4CIDR: /(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([1-2]\d|3[0-2]|\d))/,

      /**
       * @var IPv4Range
       * Regex for matching IPv4 Range notation
       */
      IPv4Range: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\-([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/,

      /**
       * @var IPv6
       * Regex for matching IPv6 address types
       */
      IPv6: /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*/,

      /**
       * @var IPv6CIDR
       * Regex for matching IPv6 CIDR notation
       */
      IPv6CIDR: /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*(\/(\d|\d\d|1[0-1]\d|12[0-8]))$/,
    };
  }

  /**
   * @function init
   * Construct for network/port validation
   *
   * @param {Object} opts - User supplied options
   * @param {Function} cb - Callback
   */
  init(opts, cb) {
    const scope = this;
    let errors = [];
    let result;

    scope.exists(opts.nmap, (result) => {
      if (!result) {

        // Try full path vs. process.env.PATH
        fs.access(opts.nmap, fs.constants.F_OK | fs.constants.X_OK, e => {
          if (e)
            return cb(scope.messages.path);
        });
      }
    });

    if (opts.blocksize > 128)
      return cb(scope.messages.block);

    if ((!opts.range) || (!/array|object/.test(typeof (opts.range))) ||
      (opts.range.length === 0))
      return cb(scope.messages.range);

    if (opts.range.length >= 1) {
      opts.range.forEach(value => {
        scope.verify(value, (err, result) => {
          if (err) return cb(scope.messages.range);
        });
      });
    }

    if (!opts.ports)
      errors.push(new Error(scope.messages.port));

    if (opts.ports) {
      result = opts.ports.match(scope.patterns.ports).join(",");
      if (result == "")
        return cb(scope.messages.port);
    }

    return cb(null, true);
  }

  /**
   * @function verify
   * Verify options provided
   *
   * @param {String} host User supplied configuration object
   * @param {Function} cb - Callback
   *
   * @returns {Function}
   */
  verify(host, cb) {

    if (this.test(this.patterns.hostname, host) ||
      this.test(this.patterns.IPv4, host) ||
      this.test(this.patterns.IPv6, host) ||
      this.test(this.patterns.IPv4CIDR, host) ||
      this.test(this.patterns.IPv6CIDR, host) ||
      this.test(this.patterns.IPv4Range, host)) {
      return cb(null, true);
    }
    else {
      return cb(`Supplied host (${host}) did not pass validation.
        ${this.messages.range}`);
    }
  }

  /**
   * @function test
   * Test specified regex test on string
   *
   * @param {Object} regex - Regex test case
   * @param {String} str - String to perform test on
   *
   * @returns {Boolean}
   */
  test(regex, str) {
    return regex.test(str);
  }

  /**
   * @function match
   * Match specified regex test on string and return array of results
   *
   * @param {Object} regex - Regex test case
   * @param {String} str - String to perform test on
   *
   * @returns {String}
   */
  match(regex, str) {
    return regex.match(str);
  }

  /**
   * @function exists
   * Binary file tests
   *
   * @param {String} path - Path for file
   *
   * @returns {Boolean}
   */
  exists(path) {
    return hasbin.sync(path);
  }
}

module.exports = new validation;
<commit_msg>v0.4.14: Fix for use of .match()<commit_after>/*!
 * libnmap
 * Copyright(c) 2013-2018 Jason Gerfen <jason.gerfen@gmail.com>
 * License: MIT
 */

'use strict'

const fs = require('fs');
const hasbin = require('hasbin');

class validation {

  constructor() {

    /**
     * @var messages
     * Error messages
     */
    this.messages = {

      version: 'Discover method requires nodejs v0.11.2 or greater; network ' +
        'range(s) could not be determined',

      path: 'Supplied path for nmap binary is invalid',

      block: 'Supplied blocksize must not exceed 128',

      range: 'Range must be an array of host(s). Examples: ' +
        '192.168.2.10 (single), 10.0.2.0/24 (CIDR), 10.0.10.5-20 (range)',

      port: 'Port(s) must match one of the following examples: ' +
        '512 (single) | 0-65535 (range) | 10-30,80,443,3306-10000 (multiple)',
    };

    /**
     * @var patterns
     * Object with various REGEX patterns to validate network params
     */
    this.patterns = {

      /**
       * @var ports
       * Regex for matching port ranges
       * @ref http://stackoverflow.com/a/21075138/901697
       */
      ports: /\d{1,6}(?:-\d+)?/g,

      /**
       * @var hostname
       * Regex for matching hostnames (RFC-1123)
       */
      hostname: /^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])|localhost$/,

      /**
       * @var IPv4
       * Regex for matching IPv4 address types
       */
      IPv4: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/,

      /**
       * @var IPv4CIDR
       * Regex for matching IPv4 CIDR notation
       */
      IPv4CIDR: /(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([1-2]\d|3[0-2]|\d))/,

      /**
       * @var IPv4Range
       * Regex for matching IPv4 Range notation
       */
      IPv4Range: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\-([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/,

      /**
       * @var IPv6
       * Regex for matching IPv6 address types
       */
      IPv6: /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*/,

      /**
       * @var IPv6CIDR
       * Regex for matching IPv6 CIDR notation
       */
      IPv6CIDR: /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*(\/(\d|\d\d|1[0-1]\d|12[0-8]))$/,
    };
  }

  /**
   * @function init
   * Construct for network/port validation
   *
   * @param {Object} opts - User supplied options
   * @param {Function} cb - Callback
   */
  init(opts, cb) {
    const scope = this;
    let errors = [];
    let result;

    scope.exists(opts.nmap, (result) => {
      if (!result) {

        // Try full path vs. process.env.PATH
        fs.access(opts.nmap, fs.constants.F_OK | fs.constants.X_OK, e => {
          if (e)
            return cb(scope.messages.path);
        });
      }
    });

    if (opts.blocksize > 128)
      return cb(scope.messages.block);

    if ((!opts.range) || (!/array|object/.test(typeof (opts.range))) ||
      (opts.range.length === 0))
      return cb(scope.messages.range);

    if (opts.range.length >= 1) {
      opts.range.forEach(value => {
        scope.verify(value, (err, result) => {
          if (err) return cb(scope.messages.range);
        });
      });
    }

    if (!opts.ports)
      errors.push(new Error(scope.messages.port));

    if (opts.ports) {
      result = scope.patterns.ports.match(opts.ports).join(",");
      if (result == "")
        return cb(scope.messages.port);
    }

    return cb(null, true);
  }

  /**
   * @function verify
   * Verify options provided
   *
   * @param {String} host User supplied configuration object
   * @param {Function} cb - Callback
   *
   * @returns {Function}
   */
  verify(host, cb) {

    if (this.test(this.patterns.hostname, host) ||
      this.test(this.patterns.IPv4, host) ||
      this.test(this.patterns.IPv6, host) ||
      this.test(this.patterns.IPv4CIDR, host) ||
      this.test(this.patterns.IPv6CIDR, host) ||
      this.test(this.patterns.IPv4Range, host)) {
      return cb(null, true);
    }
    else {
      return cb(`Supplied host (${host}) did not pass validation.
        ${this.messages.range}`);
    }
  }

  /**
   * @function test
   * Test specified regex test on string
   *
   * @param {Object} regex - Regex test case
   * @param {String} str - String to perform test on
   *
   * @returns {Boolean}
   */
  test(regex, str) {
    return regex.test(str);
  }

  /**
   * @function exists
   * Binary file tests
   *
   * @param {String} path - Path for file
   *
   * @returns {Boolean}
   */
  exists(path) {
    return hasbin.sync(path);
  }
}

module.exports = new validation;
<|endoftext|>


<commit_before>import {
  report,
  ruleMessages,
  validateOptions,
} from "../../utils"

export const ruleName = "keyframe-declaration-no-important"

export const messages = ruleMessages(ruleName, {
  rejected: "Unexpected !important within declarations in a keyframe",
})

export default function (actual) {
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, { actual })
    if (!validOptions) { return }

    root.walkAtRules(/^keyframes$/i, atRuleKeyframes => {
      atRuleKeyframes.walkDecls(decl => {
        if (!decl.important) {
          return
        }

        report({
          message: messages.rejected,
          node: decl,
          word: "important",
          result,
          ruleName,
        })
      })
    })
  }
}
<commit_msg>Remove redundancy from message<commit_after>import {
  report,
  ruleMessages,
  validateOptions,
} from "../../utils"

export const ruleName = "keyframe-declaration-no-important"

export const messages = ruleMessages(ruleName, {
  rejected: "Unexpected !important",
})

export default function (actual) {
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, { actual })
    if (!validOptions) { return }

    root.walkAtRules(/^keyframes$/i, atRuleKeyframes => {
      atRuleKeyframes.walkDecls(decl => {
        if (!decl.important) { return }
        report({
          message: messages.rejected,
          node: decl,
          word: "important",
          result,
          ruleName,
        })
      })
    })
  }
}
<|endoftext|>