<commit_before>// # Quick start guide to the open platform
//
// This introduction to getting started with the open platform is online on:
// [https://openplatform.dbc.dk/v1/guide.html#client\_id:client\_secret](https://openplatform.dbc.dk/v1/guide.html#client_id:client_secret). Supply your `client_id` and `client_secret` in the url hash, to make the examples work.
//
// The api-documentation is [https://openplatform.dbc.dk/v1/](https://openplatform.dbc.dk/v1/).
//
// The guide is written as a literate JavaScript
// [source file](https://openplatform.dbc.dk/v1/guide.js),
// that can be executed directly in the browser.
// Open the browser console to see the result of the examples.
//
// # JavaScript API
//
// To use the open platform from a browser, load
// `https://openplatform.dbc.dk/v1/dbc_openplatform.min.js`,
// with a `<script>`-tag, or in a similar way.
// Then the `dbcOpenPlatform` object will be available.
// Do not cache this JavaScript library indefinitely,
// as the underlying implementation may change
// if we change the transport protocol.
//
// The JavaScript API, assumes that you are using a web browser
// with support for WebSockets and Promises
// (Firefox, Edge, Safari, Chrome, etc.).
// If you also want to support Internet Explorer 11, you need to add
// a Promise polyfill before loading `dbc_openplatform.min.js`.
//
// This guide assumes familiarity with [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which are used asynchronous JavaScript code.
//
// ## Connecting
//
// First you need to connect to the platform:

dbcOpenPlatform.connect(
    client_id(), client_secret(),
    user_id(), user_password()) // optional
.then(function(token) {

// Notice that the `user_id` consist of "user-id@agency-id".
// You can always check whether you are connected,

console.log('connected:',
    dbcOpenPlatform.connected());

// It also possible to disconnect
// (useful to save power on mobile devices)

dbcOpenPlatform.disconnect()
.then(function() {

// and to reconnect with an existing token

dbcOpenPlatform.connect(token)
.then(function() {

// ## Calling the api
//
// The api exposes the different endpoints as methods
// on the `dbcOpenPlatform` object. For example,
// a search is executed with:

dbcOpenPlatform.search({
    q: 'ost',
    fields: ['title', 'creator', 'pid']})
.then(function(results) {
    console.log('search example', results);
});

// Errors are caught as usual with promises:

dbcOpenPlatform.work({invalid_parameter: 'foo'})
.catch(function(err) {
    console.log('work error example', err);
});

// By default, successful requests exclude the
// result envelope, - if you want the envelope,
// add `envelope: true` to the request.

dbcOpenPlatform.suggest({
    q: 'jens', type: 'creator',
    timings: true, envelope: true})
.then(function(results) {
    console.log('suggest example', results);
});

// Notice that while suggest just takes a string,
// queries for search and facets
// are expressed as [CQL](http://www.danbib.dk/broend3_soeg).
// This means that searches like `den lille prins` will fail,
// and has to be `den AND lille AND prins` or `"den lille prins"` or ...,
// depending on the desired result.

dbcOpenPlatform.facets({q: '"den lille prins"'})
.then(function(results) {
    console.log('facets example', results);
});

// # OAuth2 Authentication
//
// In order to use the HTTP-API, we need to acquire an `access_token`.
//
// For this we need various credentials:
//
// - `client_id` - identifies app and library
// - `client_secret` - password connected with the `client_id`
// - `user_id` - library user id (often consisting of 10 digits) followed by an "@"
//   followed by the library agency id, or `@` for anonymous user, optionally
//   including agency id. So `@` is the anonymous user, and `@710100`
//   is the anonymous user at Copenhagen Library. An agency ids are identifiers
//   for the libraries, and can be found via the `libraries` endpoint,
//   through an anonymous user login.
// - `user_password` - typically the pin for the library user.
//   The anonymous users password is the same as the user id
//

// The `access_token` is retrieved with a HTTP-POST request,
// with `client_id` and `client_secret` supplied through basic authentication,
// and `user_id`, `user_password` supplied in the request body.
// In browser JavaScript this can be done with XHR:

var xhr = new XMLHttpRequest();

xhr.open('POST', 'https://auth.dbc.dk/oauth/token');

xhr.setRequestHeader('Authorization', 'Basic ' +
    btoa(client_id() + ':' + client_secret()));

xhr.setRequestHeader('Content-Type',
    'application/x-www-form-urlencoded');

xhr.send('grant_type=password' +
    '&username=' + user_id() +
    '&password=' + user_password());

// This request returns a JSON object,
// which has an `access_token` property on success.
// The rest of this guide assume that we have a valid `access_token`

xhr_promise(xhr).then(function(result) {
    var access_token = result.access_token;

// # GET API
//
// You can also express the entire query in an url,
// which is useful for interactive testing.
// An example search url is:
// https://openplatform.dbc.dk/v1/search?q=hej&pretty=true&access_token=...
//
// The serviceprovider tries to parse each individual url parameter
// as JSON, and if that fails just use it as a string. This
// makes it possible to add more complex parameters, such as `.../work?pids=["870970-basis:05760755","870970-basis:27648452"]&...`
//
// # POST API
//
// Requests to the API can be sent by POSTing a JSON object
// to the API endpoint:

HTTP_POST('https://openplatform.dbc.dk/v1/suggest',
    {q: 'Steppe', type: 'title',
     access_token: access_token});

HTTP_POST('https://openplatform.dbc.dk/v1/search',
    {q: 'hello', access_token: access_token});

// All of the other APIs also have the same structure
// of sending a JSON object of parameters to the endpoint
// and then getting the result back.
//
// Due to browser limitations, webapps should use
// websockets through the JavaScript API, instead
// of POST-requests. Browsers throttle http-requests,
// and requires CORS for requests from different hosts.
//
//

// # Support code
//
// The following sections are the utility functions used above.
// It is implemented here for completeness.
// Feel free to skip the rest of this file.
//
// In browser JavaScript, HTTP-POSTing a JSON object
// can be done like this (works only on same host):

function HTTP_POST(url, parameters) {
    xhr = new XMLHttpRequest();
    xhr.open('POST', url);
    xhr.setRequestHeader('Content-Type',
        'application/json');
    xhr.send(JSON.stringify(parameters));
    return xhr_promise(xhr);
}

// Make sample get-request-url include proper `access_token`:

var link = document.getElementById('sample_url');
link.href = link.innerHTML =
  'https://openplatform.dbc.dk/v1/search?' +
  'q=hej&pretty=true&access_token=' + access_token;

// Close open code blocks. They contain scope for logins / tokens.

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

// The example code assumes that the credentials are supplied in
// the url-hash. Here is a quick hack to extract them from the url:

function client_id() {
  return location.hash.split(':')[0].slice(1); }
function client_secret() {
  return location.hash.split(':')[1]; }
function user_id() {
  return location.hash.split(':')[2] || '@'; }
function user_password() {
  return location.hash.split(':')[3] || '@'; }
if (client_id() === 'id' || !client_secret()) {
  throw 'Please use your client_id' +
    ' and client_secret in the url';
}

// A XMLHttpRequest requires setting event handlers
// to get the result of the request.
// Here is a utility function that does the boilerplate
// code, and transforms the XHR-request into a promise.
// It also logs, and parse the result as JSON
// on the way through.

function xhr_promise(xhr) {
  return new Promise(function(resolve, reject) {
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        console.log(xhr.responseURL, xhr);
        if (xhr.status === 200) {
          var result = xhr.response;
          try {
            result = JSON.parse(result);
          } catch (e) {
          }
          resolve(result);
        } else {
          reject(xhr);
        }
      }
    }
  });
}

// Final note: the code above is written as a tutorial code,
// designed to be simple to read, and get started with,
// rather than proper and correct. It does not follow
// best practices for production code.
<commit_msg>changed v1 to v3<commit_after>// # Quick start guide to the open platform
//
// This introduction to getting started with the open platform is online on:
// [https://openplatform.dbc.dk/v3/guide.html#client\_id:client\_secret](https://openplatform.dbc.dk/v3/guide.html#client_id:client_secret). Supply your `client_id` and `client_secret` in the url hash, to make the examples work.
//
// The api-documentation is [https://openplatform.dbc.dk/v3/](https://openplatform.dbc.dk/v3/).
//
// The guide is written as a literate JavaScript
// [source file](https://openplatform.dbc.dk/v3/guide.js),
// that can be executed directly in the browser.
// Open the browser console to see the result of the examples.
//
// # JavaScript API
//
// To use the open platform from a browser, load
// `https://openplatform.dbc.dk/v3/dbc_openplatform.min.js`,
// with a `<script>`-tag, or in a similar way.
// Then the `dbcOpenPlatform` object will be available.
// Do not cache this JavaScript library indefinitely,
// as the underlying implementation may change
// if we change the transport protocol.
//
// The JavaScript API, assumes that you are using a web browser
// with support for WebSockets and Promises
// (Firefox, Edge, Safari, Chrome, etc.).
// If you also want to support Internet Explorer 11, you need to add
// a Promise polyfill before loading `dbc_openplatform.min.js`.
//
// This guide assumes familiarity with [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which are used asynchronous JavaScript code.
//
// ## Connecting
//
// First you need to connect to the platform:

dbcOpenPlatform.connect(
    client_id(), client_secret(),
    user_id(), user_password()) // optional
.then(function(token) {

// Notice that the `user_id` consist of "user-id@agency-id".
// You can always check whether you are connected,

console.log('connected:',
    dbcOpenPlatform.connected());

// It also possible to disconnect
// (useful to save power on mobile devices)

dbcOpenPlatform.disconnect()
.then(function() {

// and to reconnect with an existing token

dbcOpenPlatform.connect(token)
.then(function() {

// ## Calling the api
//
// The api exposes the different endpoints as methods
// on the `dbcOpenPlatform` object. For example,
// a search is executed with:

dbcOpenPlatform.search({
    q: 'ost',
    fields: ['title', 'creator', 'pid']})
.then(function(results) {
    console.log('search example', results);
});

// Errors are caught as usual with promises:

dbcOpenPlatform.work({invalid_parameter: 'foo'})
.catch(function(err) {
    console.log('work error example', err);
});

// By default, successful requests exclude the
// result envelope, - if you want the envelope,
// add `envelope: true` to the request.

dbcOpenPlatform.suggest({
    q: 'jens', type: 'creator',
    timings: true, envelope: true})
.then(function(results) {
    console.log('suggest example', results);
});

// Notice that while suggest just takes a string,
// queries for search and facets
// are expressed as [CQL](http://www.danbib.dk/broend3_soeg).
// This means that searches like `den lille prins` will fail,
// and has to be `den AND lille AND prins` or `"den lille prins"` or ...,
// depending on the desired result.

dbcOpenPlatform.facets({q: '"den lille prins"'})
.then(function(results) {
    console.log('facets example', results);
});

// # OAuth2 Authentication
//
// In order to use the HTTP-API, we need to acquire an `access_token`.
//
// For this we need various credentials:
//
// - `client_id` - identifies app and library
// - `client_secret` - password connected with the `client_id`
// - `user_id` - library user id (often consisting of 10 digits) followed by an "@"
//   followed by the library agency id, or `@` for anonymous user, optionally
//   including agency id. So `@` is the anonymous user, and `@710100`
//   is the anonymous user at Copenhagen Library. An agency ids are identifiers
//   for the libraries, and can be found via the `libraries` endpoint,
//   through an anonymous user login.
// - `user_password` - typically the pin for the library user.
//   The anonymous users password is the same as the user id
//

// The `access_token` is retrieved with a HTTP-POST request,
// with `client_id` and `client_secret` supplied through basic authentication,
// and `user_id`, `user_password` supplied in the request body.
// In browser JavaScript this can be done with XHR:

var xhr = new XMLHttpRequest();

xhr.open('POST', 'https://auth.dbc.dk/oauth/token');

xhr.setRequestHeader('Authorization', 'Basic ' +
    btoa(client_id() + ':' + client_secret()));

xhr.setRequestHeader('Content-Type',
    'application/x-www-form-urlencoded');

xhr.send('grant_type=password' +
    '&username=' + user_id() +
    '&password=' + user_password());

// This request returns a JSON object,
// which has an `access_token` property on success.
// The rest of this guide assume that we have a valid `access_token`

xhr_promise(xhr).then(function(result) {
    var access_token = result.access_token;

// # GET API
//
// You can also express the entire query in an url,
// which is useful for interactive testing.
// An example search url is:
// https://openplatform.dbc.dk/v3/search?q=hej&pretty=true&access_token=...
//
// The serviceprovider tries to parse each individual url parameter
// as JSON, and if that fails just use it as a string. This
// makes it possible to add more complex parameters, such as `.../work?pids=["870970-basis:05760755","870970-basis:27648452"]&...`
//
// # POST API
//
// Requests to the API can be sent by POSTing a JSON object
// to the API endpoint:

HTTP_POST('https://openplatform.dbc.dk/v3/suggest',
    {q: 'Steppe', type: 'title',
     access_token: access_token});

HTTP_POST('https://openplatform.dbc.dk/v3/search',
    {q: 'hello', access_token: access_token});

// All of the other APIs also have the same structure
// of sending a JSON object of parameters to the endpoint
// and then getting the result back.
//
// Due to browser limitations, webapps should use
// websockets through the JavaScript API, instead
// of POST-requests. Browsers throttle http-requests,
// and requires CORS for requests from different hosts.
//
//

// # Support code
//
// The following sections are the utility functions used above.
// It is implemented here for completeness.
// Feel free to skip the rest of this file.
//
// In browser JavaScript, HTTP-POSTing a JSON object
// can be done like this (works only on same host):

function HTTP_POST(url, parameters) {
    xhr = new XMLHttpRequest();
    xhr.open('POST', url);
    xhr.setRequestHeader('Content-Type',
        'application/json');
    xhr.send(JSON.stringify(parameters));
    return xhr_promise(xhr);
}

// Make sample get-request-url include proper `access_token`:

var link = document.getElementById('sample_url');
link.href = link.innerHTML =
  'https://openplatform.dbc.dk/v3/search?' +
  'q=hej&pretty=true&access_token=' + access_token;

// Close open code blocks. They contain scope for logins / tokens.

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

// The example code assumes that the credentials are supplied in
// the url-hash. Here is a quick hack to extract them from the url:

function client_id() {
  return location.hash.split(':')[0].slice(1); }
function client_secret() {
  return location.hash.split(':')[1]; }
function user_id() {
  return location.hash.split(':')[2] || '@'; }
function user_password() {
  return location.hash.split(':')[3] || '@'; }
if (client_id() === 'id' || !client_secret()) {
  throw 'Please use your client_id' +
    ' and client_secret in the url';
}

// A XMLHttpRequest requires setting event handlers
// to get the result of the request.
// Here is a utility function that does the boilerplate
// code, and transforms the XHR-request into a promise.
// It also logs, and parse the result as JSON
// on the way through.

function xhr_promise(xhr) {
  return new Promise(function(resolve, reject) {
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        console.log(xhr.responseURL, xhr);
        if (xhr.status === 200) {
          var result = xhr.response;
          try {
            result = JSON.parse(result);
          } catch (e) {
          }
          resolve(result);
        } else {
          reject(xhr);
        }
      }
    }
  });
}

// Final note: the code above is written as a tutorial code,
// designed to be simple to read, and get started with,
// rather than proper and correct. It does not follow
// best practices for production code.
<|endoftext|>


<commit_before>'use strict';
var test = require('./shared').assert;
var setupDatabase = require('./shared').setupDatabase;

describe('Decimal128', function() {
  before(function() {
    return setupDatabase(this.configuration);
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForReadCommand', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] }
    },

    // The actual test we wish to run
    test: function(done) {
      var Domain = require('domain');
      var domainInstance = Domain.create();
      var configuration = this.configuration;
      var client = configuration.newClient(configuration.writeConcernMax(), {
        poolSize: 1,
        domainsEnabled: true
      });
      client.connect(function(err, client) {
        var db = client.db(configuration.db);
        test.ok(!err);
        var collection = db.collection('test');

        domainInstance.run(function() {
          collection.count({}, function(err) {
            test.ok(!err);
            test.ok(domainInstance === process.domain);
            domainInstance.exit();
            client.close(done);
          });
        });
      });
    }
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForReadCommandUsingMongoClient', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] }
    },

    // The actual test we wish to run
    test: function(done) {
      var configuration = this.configuration;
      var Domain = require('domain');
      var domainInstance = Domain.create();

      const client = configuration.newClient({}, { domainsEnabled: true });
      client.connect(function(err, client) {
        test.ok(!err);
        var db = client.db(configuration.db);
        var collection = db.collection('test');
        domainInstance.run(function() {
          collection.count({}, function(err) {
            test.ok(!err);
            test.ok(domainInstance === process.domain);
            domainInstance.exit();
            client.close(done);
          });
        });
      });
    }
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForWriteCommand', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] }
    },

    // The actual test we wish to run
    test: function(done) {
      var Domain = require('domain');
      var domainInstance = Domain.create();
      var configuration = this.configuration;
      var client = configuration.newClient(
        { w: 1 },
        { poolSize: 1, auto_reconnect: true, domainsEnabled: true }
      );

      client.connect(function(err, client) {
        test.ok(!err);
        var db = client.db(configuration.db);
        var collection = db.collection('test');
        domainInstance.run(function() {
          collection.insert({ field: 123 }, function(err) {
            test.ok(!err);
            test.ok(domainInstance === process.domain);
            domainInstance.exit();
            client.close(done);
          });
        });
      });
    }
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForQueuedReadCommand', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] }
    },

    // The actual test we wish to run
    test: function(done) {
      var Domain = require('domain');
      var domainInstance = Domain.create();
      var configuration = this.configuration;
      if (configuration.usingUnifiedTopology()) {
        // The unified topology does not use a store
        return this.skip();
      }

      var client = configuration.newClient(
        { w: 0 },
        { poolSize: 1, auto_reconnect: true, domainsEnabled: true, bufferMaxEntries: 0 }
      );

      client.connect(function(err, client) {
        var db = client.db(configuration.db);
        var connection = client.topology.connections()[0];
        var collection = db.collection('test');
        connection.destroy();

        domainInstance.run(function() {
          collection.count({}, function(err) {
            test.ok(err != null);
            test.ok(process.domain === domainInstance);
            domainInstance.exit();
            client.close(done);
          });
        });
      });
    }
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForQueuedWriteCommand', {
    metadata: {
      requires: {
        topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger']
      }
    },

    // The actual test we wish to run
    test: function(done) {
      var Domain = require('domain');
      var domainInstance = Domain.create();
      var configuration = this.configuration;
      if (configuration.usingUnifiedTopology()) {
        // The unified topology does not use a store
        return this.skip();
      }

      var client = configuration.newClient(
        { w: 1 },
        { poolSize: 1, auto_reconnect: true, domainsEnabled: true, bufferMaxEntries: 0 }
      );

      client.connect(function(err, client) {
        test.ok(!err);
        var db = client.db(configuration.db);
        var connection = client.topology.connections()[0];
        var collection = db.collection('test');
        connection.destroy();

        domainInstance.run(function() {
          collection.insert({ field: 123 }, function(err) {
            test.ok(err != null);
            test.ok(process.domain === domainInstance);
            domainInstance.exit();
            client.close(done);
          });
        });
      });
    }
  });
});
<commit_msg>test: force close connections in domain tests<commit_after>'use strict';
var test = require('./shared').assert;
var setupDatabase = require('./shared').setupDatabase;

describe('Domains', function() {
  before(function() {
    return setupDatabase(this.configuration);
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForReadCommand', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] }
    },

    // The actual test we wish to run
    test: function(done) {
      var Domain = require('domain');
      var domainInstance = Domain.create();
      var configuration = this.configuration;
      var client = configuration.newClient(configuration.writeConcernMax(), {
        poolSize: 1,
        domainsEnabled: true
      });
      client.connect(function(err, client) {
        var db = client.db(configuration.db);
        test.ok(!err);
        var collection = db.collection('test');

        domainInstance.run(function() {
          collection.count({}, function(err) {
            test.ok(!err);
            test.ok(domainInstance === process.domain);
            domainInstance.exit();
            client.close(done);
          });
        });
      });
    }
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForReadCommandUsingMongoClient', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] }
    },

    // The actual test we wish to run
    test: function(done) {
      var configuration = this.configuration;
      var Domain = require('domain');
      var domainInstance = Domain.create();

      const client = configuration.newClient({}, { domainsEnabled: true });
      client.connect(function(err, client) {
        test.ok(!err);
        var db = client.db(configuration.db);
        var collection = db.collection('test');
        domainInstance.run(function() {
          collection.count({}, function(err) {
            test.ok(!err);
            test.ok(domainInstance === process.domain);
            domainInstance.exit();
            client.close(done);
          });
        });
      });
    }
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForWriteCommand', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] }
    },

    // The actual test we wish to run
    test: function(done) {
      var Domain = require('domain');
      var domainInstance = Domain.create();
      var configuration = this.configuration;
      var client = configuration.newClient(
        { w: 1 },
        { poolSize: 1, auto_reconnect: true, domainsEnabled: true }
      );

      client.connect(function(err, client) {
        test.ok(!err);
        var db = client.db(configuration.db);
        var collection = db.collection('test');
        domainInstance.run(function() {
          collection.insert({ field: 123 }, function(err) {
            test.ok(!err);
            test.ok(domainInstance === process.domain);
            domainInstance.exit();
            client.close(done);
          });
        });
      });
    }
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForQueuedReadCommand', {
    metadata: {
      requires: { topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger'] }
    },

    // The actual test we wish to run
    test: function(done) {
      var Domain = require('domain');
      var domainInstance = Domain.create();
      var configuration = this.configuration;
      if (configuration.usingUnifiedTopology()) {
        // The unified topology does not use a store
        return this.skip();
      }

      var client = configuration.newClient(
        { w: 0 },
        { poolSize: 1, auto_reconnect: true, domainsEnabled: true, bufferMaxEntries: 0 }
      );

      client.connect(function(err, client) {
        var db = client.db(configuration.db);
        var connection = client.topology.connections()[0];
        var collection = db.collection('test');
        connection.destroy();

        domainInstance.run(function() {
          collection.count({}, function(err) {
            test.ok(err != null);
            test.ok(process.domain === domainInstance);
            domainInstance.exit();
            client.close(true, done);
          });
        });
      });
    }
  });

  /**
   * @ignore
   */
  it('shouldStayInCorrectDomainForQueuedWriteCommand', {
    metadata: {
      requires: {
        topology: ['single', 'replicaset', 'sharded', 'ssl', 'heap', 'wiredtiger']
      }
    },

    // The actual test we wish to run
    test: function(done) {
      var Domain = require('domain');
      var domainInstance = Domain.create();
      var configuration = this.configuration;
      if (configuration.usingUnifiedTopology()) {
        // The unified topology does not use a store
        return this.skip();
      }

      var client = configuration.newClient(
        { w: 1 },
        { poolSize: 1, auto_reconnect: true, domainsEnabled: true, bufferMaxEntries: 0 }
      );

      client.connect(function(err, client) {
        test.ok(!err);
        var db = client.db(configuration.db);
        var connection = client.topology.connections()[0];
        var collection = db.collection('test');
        connection.destroy();

        domainInstance.run(function() {
          collection.insert({ field: 123 }, function(err) {
            test.ok(err != null);
            test.ok(process.domain === domainInstance);
            domainInstance.exit();
            client.close(true, done);
          });
        });
      });
    }
  });
});
<|endoftext|>


<commit_before>// var sensuApiHost = "http://172.24.50.7";
// var sensuApiPort = "4567";
// var uchiwaHost = "http://172.24.50.7";
// var uchiwaPort = "3000";
// var datacenter = "hiraoka";

function getOptions(cb) {
    chrome.storage.sync.get({
        sensuApiHost: "",
        sensuApiPort: "",
        uchiwaHost: "",
        uchiwaPort: "",
        datacenter: ""
    }, function(items) {

        items.configured = (items.sensuApiHost == "" ||
                              items.sensuApiPort == "" ||
                              items.uchiwaHost == "" ||
                              items.uchiwaPort == "" ||
                              items.datacenter == "")? false: true;
        cb(items);
    });
}

function setOptions(items, cb) {
    chrome.storage.sync.set({
        sensuApiHost: items.sensuApiHost,
        sensuApiPort: items.sensuApiPort,
        uchiwaHost:   items.uchiwaHost,
        uchiwaPort:   items.uchiwaPort,
        datacenter:   items.datacenter
    }, function() {
        cb();
    });
}

function getEvents(callback) {
    getOptions(function(items) {
        if (items.configured) {
            $.ajax({
                dataType: 'json',
                url: items.sensuApiHost + ':' + items.sensuApiPort + '/events',
                success: function(data) {
                    callback(data, items);
                }
            });
        }
    });
}

function postResolve(client, check, callback) {
    getOptions(function(items) {
        if (items.configured) {
            $.ajax({
                method: 'post',
                url: items.sensuApiHost + ':' + items.sensuApiPort + '/resolve',
                data: JSON.stringify({'client': client, 'check': check}),
                contentType: 'application/json',
                success: function(data) {
                    callback(data);
                }
            });
        }
    });
}

function postRecheck(check, subscribe, callback) {
    getOptions(function(items) {
        if (items.configured) {
            reloadIcon();
            $.ajax({
                method: 'post',
                url: items.sensuApiHost + ':' + items.sensuApiPort + '/request',
                data: JSON.stringify({'check': check, "subscribers": subscribe }),
                contentType: 'application/json',
                success: function(data) {
                    callback(data);
                }
            });
        }
    });
}

function reloadIcon() {
    getEvents(setIconBadge);
}

function reloadPopup() {
    getEvents(setPopup);
    setFooter();
}

function setIconBadge(data, items) {

    var warn = 0;
    var crit = 0;
    for (i in data) {
        if (data[i].check.status == 2) { crit += 1; }
        if (data[i].check.status == 1) { warn += 1; }
    }

    color = (crit > 0 )? "#EA5443": "#F9BA46";

    if (data.length > 0) {
        chrome.browserAction.setBadgeText({text: data.length.toString()});
        chrome.browserAction.setBadgeBackgroundColor({color: color});
    } else {
        chrome.browserAction.setBadgeText({text: ""});
    }
}

function setPopup(data, items) {

    if (data.length == 0) {
        var str = "Alert does not have anything. System is a normal state.";
        $('#main').html(str);
    } else {
        $('main').html("");
        var d = {};
        for (i in data) {
            client = data[i].client;
            check  = data[i].check;
            if (client.name in d) {
            } else {
                d[client.name] = {
                    "check": [],
                    "address": client.address,
                    "subscriptions": client.subscriptions
                };
            }
            var item = {
                "name": client.name,
                "command": check.command,
                "check": check.name,
                "output": check.output,
                "status": check.status,
                "history": check.history,
                "subscribers": check.subscribers,
                "issued": check.issued,
                "history": check.history,
                "executed": check.executed,
                "id": data[i].id
            };
            d[client.name]["check"].push(item);
        }

        for (client in d) {

            // error message
            var body = $('
');
            body.attr('id', client + '_body');

            var crit = 0;
            var warn = 0;
            for (error in d[client]["check"]) {
                var e = d[client]["check"][error];

                var check = $('');
                check
                    .addClass((e.status == 2)? 'label-danger': 'label-warning')
                    .text(e.check);

                var action = getAction(e, items);

                var message = $('
');
                message.html(e.output);

                var hr = $('
');

                var dt = new Date((e.issued || e.executed) * 1000).toISOString();
                var issued = $('
');
                issued.append(
                    $('').attr('title', dt).text(dt)
                );

                var history = $('
');
                history.append($(''));
                for (i in e.history) {
                    history.append(
                        $('')
                            .addClass('history_color_' + e.history[i])
                            .text("●")
                    );
                }

                var c = $('
');
                c.append(action).append(message).append(check).append(hr).append(issued).append(history);

                body.append(c);
                if (e.status == 2) { crit += 1; }
                if (e.status == 1) { warn += 1; }
            }

            // header
            var panel = $('
');
            var title = $('');
            title
                .attr({
                    'data-toggle': 'collapse',
                    'data-parent': '#main',
                    'href': '#' + client + '_body',
                    'id': 'id_' + client,
                    'data-placement': 'right',
                    'title': 'Address: ' + d[client].address
                })
                .text(client)
                .append(getClientInfo(e))
                .append(getCheckInfo(e))
                .append(getHeaderBadge(crit, warn))
                .append(getSubscriptions(d[client]))
                .appendTo($('
')).parent()
                .appendTo($('
')).parent()
                .appendTo(panel);

            body.appendTo(panel);
            $('#main').append(panel);

            $('#id_' + client).tooltip();
        }
        $('abbr.timeago').timeago();
        $('.collapse').collapse();
    }
}

function getSubscriptions(c) {
    var subscriptions = $('
');
    for (i in c.subscriptions) {
        var labelColor = 0;
        var l = c.subscriptions[i];
        for (e in c.check) {
            var check = c.check[e];
            if (check.subscribers && check.subscribers.indexOf(l) >= 0) {
                if (labelColor == 0 && check.status == 1) {
                    labelColor = 1;
                } else {
                    labelColor = 2;
                }
            }
        }
        var label = ['label-success', 'label-warning', 'label-danger'];
        subscriptions.append(
            $('
')
                .addClass(label[labelColor])
                .text(l)
        );
    }
    return subscriptions;
}

function getCheckInfo(e) {

}

function getClientInfo(e) {

}

function getAction(e, items) {
    var resolve =[items.uchiwaHost + ':' + items.uchiwaPort,
                  '#',
                  'client',
                  items.datacenter,
                  e.name + '?check=' + e.check].join('/');
    var uchiwa = [items.uchiwaHost + ':' + items.uchiwaPort,
                  '#',
                  'client',
                  items.datacenter,
                  e.name + '?check=' + e.check].join('/');

    var action = $('
').css('float', 'right');
    action
        .append(
            $('')
                .append(
                    $('')
                        .attr('title', 'Resolve')
                )
                .css('cursor', 'pointer')
                .click(
                    function() {
                        postResolve(e.name, e.check, function(data) {
                            location.reload();
                        });

                    }
                )
        );

    action
        .append(
            $('').attr({'href': uchiwa, 'target': '_blank'})
                .append(
                    $('')
                        .attr('title', 'Open uchiwa page')
                )
        );
    if (e.check != 'keepalive') {
        action
            .append(
                $('')
                    .append(
                        $('')
                            .attr('title', 'Recheck')
                    )
                    .css('cursor', 'pointer')
                    .click(
                        function() {
                            postRecheck(e.check, e.subscribers, function(data) {
                                location.reload();
                            });

                        }
                    )
            );
    }

    return action;
}

function getHeaderBadge(crit, warn) {
    var bgcolor = (crit > 0)? "#b94a48": "#f89406";
    var badge = $('');
    badge
        .css('backgroundColor', bgcolor)
        .text(crit + warn);
    return badge;
}

function setFooter() {
    $.ajax({
        dataType: 'json',
        url: chrome.extension.getURL('/manifest.json'),
        success: function(data) {
            $('#footer').text(data.name + " Ver." + data.version);
        }
    });
}
<commit_msg>古い設定の削除<commit_after>function getOptions(cb) {
    chrome.storage.sync.get({
        sensuApiHost: "",
        sensuApiPort: "",
        uchiwaHost: "",
        uchiwaPort: "",
        datacenter: ""
    }, function(items) {

        items.configured = (items.sensuApiHost == "" ||
                              items.sensuApiPort == "" ||
                              items.uchiwaHost == "" ||
                              items.uchiwaPort == "" ||
                              items.datacenter == "")? false: true;
        cb(items);
    });
}

function setOptions(items, cb) {
    chrome.storage.sync.set({
        sensuApiHost: items.sensuApiHost,
        sensuApiPort: items.sensuApiPort,
        uchiwaHost:   items.uchiwaHost,
        uchiwaPort:   items.uchiwaPort,
        datacenter:   items.datacenter
    }, function() {
        cb();
    });
}

function getEvents(callback) {
    getOptions(function(items) {
        if (items.configured) {
            $.ajax({
                dataType: 'json',
                url: items.sensuApiHost + ':' + items.sensuApiPort + '/events',
                success: function(data) {
                    callback(data, items);
                }
            });
        }
    });
}

function postResolve(client, check, callback) {
    getOptions(function(items) {
        if (items.configured) {
            $.ajax({
                method: 'post',
                url: items.sensuApiHost + ':' + items.sensuApiPort + '/resolve',
                data: JSON.stringify({'client': client, 'check': check}),
                contentType: 'application/json',
                success: function(data) {
                    callback(data);
                }
            });
        }
    });
}

function postRecheck(check, subscribe, callback) {
    getOptions(function(items) {
        if (items.configured) {
            reloadIcon();
            $.ajax({
                method: 'post',
                url: items.sensuApiHost + ':' + items.sensuApiPort + '/request',
                data: JSON.stringify({'check': check, "subscribers": subscribe }),
                contentType: 'application/json',
                success: function(data) {
                    callback(data);
                }
            });
        }
    });
}

function reloadIcon() {
    getEvents(setIconBadge);
}

function reloadPopup() {
    getEvents(setPopup);
    setFooter();
}

function setIconBadge(data, items) {

    var warn = 0;
    var crit = 0;
    for (i in data) {
        if (data[i].check.status == 2) { crit += 1; }
        if (data[i].check.status == 1) { warn += 1; }
    }

    color = (crit > 0 )? "#EA5443": "#F9BA46";

    if (data.length > 0) {
        chrome.browserAction.setBadgeText({text: data.length.toString()});
        chrome.browserAction.setBadgeBackgroundColor({color: color});
    } else {
        chrome.browserAction.setBadgeText({text: ""});
    }
}

function setPopup(data, items) {

    if (data.length == 0) {
        var str = "Alert does not have anything. System is a normal state.";
        $('#main').html(str);
    } else {
        $('main').html("");
        var d = {};
        for (i in data) {
            client = data[i].client;
            check  = data[i].check;
            if (client.name in d) {
            } else {
                d[client.name] = {
                    "check": [],
                    "address": client.address,
                    "subscriptions": client.subscriptions
                };
            }
            var item = {
                "name": client.name,
                "command": check.command,
                "check": check.name,
                "output": check.output,
                "status": check.status,
                "history": check.history,
                "subscribers": check.subscribers,
                "issued": check.issued,
                "history": check.history,
                "executed": check.executed,
                "id": data[i].id
            };
            d[client.name]["check"].push(item);
        }

        for (client in d) {

            // error message
            var body = $('
');
            body.attr('id', client + '_body');

            var crit = 0;
            var warn = 0;
            for (error in d[client]["check"]) {
                var e = d[client]["check"][error];

                var check = $('');
                check
                    .addClass((e.status == 2)? 'label-danger': 'label-warning')
                    .text(e.check);

                var action = getAction(e, items);

                var message = $('
');
                message.html(e.output);

                var hr = $('
');

                var dt = new Date((e.issued || e.executed) * 1000).toISOString();
                var issued = $('
');
                issued.append(
                    $('').attr('title', dt).text(dt)
                );

                var history = $('
');
                history.append($(''));
                for (i in e.history) {
                    history.append(
                        $('')
                            .addClass('history_color_' + e.history[i])
                            .text("●")
                    );
                }

                var c = $('
');
                c.append(action).append(message).append(check).append(hr).append(issued).append(history);

                body.append(c);
                if (e.status == 2) { crit += 1; }
                if (e.status == 1) { warn += 1; }
            }

            // header
            var panel = $('
');
            var title = $('');
            title
                .attr({
                    'data-toggle': 'collapse',
                    'data-parent': '#main',
                    'href': '#' + client + '_body',
                    'id': 'id_' + client,
                    'data-placement': 'right',
                    'title': 'Address: ' + d[client].address
                })
                .text(client)
                .append(getClientInfo(e))
                .append(getCheckInfo(e))
                .append(getHeaderBadge(crit, warn))
                .append(getSubscriptions(d[client]))
                .appendTo($('
')).parent()
                .appendTo($('
')).parent()
                .appendTo(panel);

            body.appendTo(panel);
            $('#main').append(panel);

            $('#id_' + client).tooltip();
        }
        $('abbr.timeago').timeago();
        $('.collapse').collapse();
    }
}

function getSubscriptions(c) {
    var subscriptions = $('
');
    for (i in c.subscriptions) {
        var labelColor = 0;
        var l = c.subscriptions[i];
        for (e in c.check) {
            var check = c.check[e];
            if (check.subscribers && check.subscribers.indexOf(l) >= 0) {
                if (labelColor == 0 && check.status == 1) {
                    labelColor = 1;
                } else {
                    labelColor = 2;
                }
            }
        }
        var label = ['label-success', 'label-warning', 'label-danger'];
        subscriptions.append(
            $('
')
                .addClass(label[labelColor])
                .text(l)
        );
    }
    return subscriptions;
}

function getCheckInfo(e) {

}

function getClientInfo(e) {

}

function getAction(e, items) {
    var resolve =[items.uchiwaHost + ':' + items.uchiwaPort,
                  '#',
                  'client',
                  items.datacenter,
                  e.name + '?check=' + e.check].join('/');
    var uchiwa = [items.uchiwaHost + ':' + items.uchiwaPort,
                  '#',
                  'client',
                  items.datacenter,
                  e.name + '?check=' + e.check].join('/');

    var action = $('
').css('float', 'right');
    action
        .append(
            $('')
                .append(
                    $('')
                        .attr('title', 'Resolve')
                )
                .css('cursor', 'pointer')
                .click(
                    function() {
                        postResolve(e.name, e.check, function(data) {
                            location.reload();
                        });

                    }
                )
        );

    action
        .append(
            $('').attr({'href': uchiwa, 'target': '_blank'})
                .append(
                    $('')
                        .attr('title', 'Open uchiwa page')
                )
        );
    if (e.check != 'keepalive') {
        action
            .append(
                $('')
                    .append(
                        $('')
                            .attr('title', 'Recheck')
                    )
                    .css('cursor', 'pointer')
                    .click(
                        function() {
                            postRecheck(e.check, e.subscribers, function(data) {
                                location.reload();
                            });

                        }
                    )
            );
    }

    return action;
}

function getHeaderBadge(crit, warn) {
    var bgcolor = (crit > 0)? "#b94a48": "#f89406";
    var badge = $('');
    badge
        .css('backgroundColor', bgcolor)
        .text(crit + warn);
    return badge;
}

function setFooter() {
    $.ajax({
        dataType: 'json',
        url: chrome.extension.getURL('/manifest.json'),
        success: function(data) {
            $('#footer').text(data.name + " Ver." + data.version);
        }
    });
}
<|endoftext|>


<commit_before>import Canvas from 'canvas'
import { capitalizeName } from './../util/pokemon-names'
import { drawRects, drawTexts, drawOutlines, loadAndDrawImages } from './../util/image'

const padding = 10
const maxwidth = 400
const maxheight = 300
// those apply to both back and front sprites
const imgW = 96
const imgH = 96

export async function renderImage (pokeinfo) {
  const canvas = new Canvas(maxwidth, maxheight)
  const ctx = canvas.getContext('2d')

  ctx.fillStyle = 'lightgray'
  ctx.fillRect(0, 0, maxwidth, maxheight)

  await drawPokemonBlock(pokeinfo, ctx)
  drawStatsBlock(pokeinfo, ctx)

  return canvas.toBuffer()
}

async function drawPokemonBlock (pokeinfo, ctx) {
  console.log('\x1b[32m', `Drawing "${pokeinfo.name}" block`)

  const rects = [{
    x: padding,
    y: padding,
    width: maxwidth - (padding * 2),
    height: 35,
    style: 'white'
  },
  {
    x: padding,
    y: 60,
    width: imgW,
    height: imgH,
    style: 'white'
  }]

  const texts = [{
    text: capitalizeName(pokeinfo.name),
    style: 'black',
    font: '22px Consolas',
    x: maxwidth / 2,
    y: 30
  }]

  const noFrontSpriteText = {
    text: '?',
    style: 'lightgray',
    font: '48px Consolas',
    x: padding + (imgW / 2),
    y: 60 + (imgH / 2)
  }

  const frontSprite = pokeinfo.sprites.front_default

  const images = []

  if (frontSprite) {
    images.push({
      url: frontSprite,
      x: padding,
      y: 60,
      width: imgW,
      height: imgH
    })
  } else {
    texts.push(noFrontSpriteText)
  }

  drawRects(ctx, rects)
  await loadAndDrawImages(ctx, images, true)
  drawTexts(ctx, texts)
}

function drawStatsBlock (pokeinfo, ctx) {
  const initialY = 60
  const initialX = padding + 96 + padding

  const maxHp = 255
  const maxAttack = 190
  const maxDefense = 230
  const maxSpAttack = 194
  const maxSpDefense = 230
  const maxSpeed = 180

  const hp = pokeinfo.stats.find((element) => element.stat.name === 'hp').base_stat
  const attack = pokeinfo.stats.find((element) => element.stat.name === 'attack').base_stat
  const defense = pokeinfo.stats.find((element) => element.stat.name === 'defense').base_stat
  const spAttack = pokeinfo.stats.find((element) => element.stat.name === 'special-attack').base_stat
  const spDefense = pokeinfo.stats.find((element) => element.stat.name === 'special-defense').base_stat
  const speed = pokeinfo.stats.find((element) => element.stat.name === 'speed').base_stat

  const barHeight = 15
  const barWidth = (maxwidth - initialX - padding)
  drawStatBar(ctx, initialX, initialY, barWidth, barHeight, '#FF0000', '#FF5959', '#A60000', 'HP', hp, maxHp)
  drawStatBar(ctx, initialX, initialY + 20, barWidth, barHeight, '#F08030', '#F5AC78', '#9C531F', 'Attack', attack, maxAttack)
  drawStatBar(ctx, initialX, initialY + 40, barWidth, barHeight, '#F8D030', '#FAE078', '#A1871F', 'Defense', defense, maxDefense)
  drawStatBar(ctx, initialX, initialY + 60, barWidth, barHeight, '#6890F0', '#9DB7F5', '#445E9C', 'Sp.Attack', spAttack, maxSpAttack)
  drawStatBar(ctx, initialX, initialY + 80, barWidth, barHeight, '#78C850', '#A7DB8D', '#4E8234', 'Sp.Defense', spDefense, maxSpDefense)
  drawStatBar(ctx, initialX, initialY + 100, barWidth, barHeight, '#F85888', '#FA92B2', '#A13959', 'Speed', speed, maxSpeed)
}

function drawStatBar (ctx, x, y, width, height, color1, color2, color3, statName, statValue, maxValue) {
  const texts = [{
    text: `${statName}: ${statValue}`,
    style: 'black',
    font: '12px Consolas',
    x: x + (width / 2),
    y: y + (height / 2)
  }]

  const outLines = [{
    x: x,
    y: y,
    width: width,
    height: height,
    style: color3,
    lineWidth: 1
  }]

  const rects = [{
    x: x,
    y,
    width,
    height,
    style: color2
  },
  {
    x: x,
    y,
    width: (width / maxValue) * statValue,
    height,
    style: color1
  }]

  drawRects(ctx, rects)
  drawOutlines(ctx, outLines)
  drawTexts(ctx, texts)
}
<commit_msg>Better bars, still a ONE FUCKING PIXEL alignment left to do. ARGH<commit_after>import Canvas from 'canvas'
import { capitalizeName } from './../util/pokemon-names'
import { drawRects, drawTexts, drawOutlines, loadAndDrawImages } from './../util/image'

const padding = 10
const maxwidth = 400
const maxheight = 300
// those apply to both back and front sprites
const imgW = 96
const imgH = 96

export async function renderImage (pokeinfo) {
  const canvas = new Canvas(maxwidth, maxheight)
  const ctx = canvas.getContext('2d')

  ctx.fillStyle = 'lightgray'
  ctx.fillRect(0, 0, maxwidth, maxheight)

  await drawPokemonBlock(pokeinfo, ctx)
  drawStatsBlock(pokeinfo, ctx)

  return canvas.toBuffer()
}

async function drawPokemonBlock (pokeinfo, ctx) {
  console.log('\x1b[32m', `Drawing "${pokeinfo.name}" block`)

  const rects = [{
    x: padding,
    y: padding,
    width: maxwidth - (padding * 2),
    height: 35,
    style: 'white'
  },
  {
    x: padding,
    y: 60,
    width: imgW,
    height: imgH,
    style: 'white'
  }]

  const texts = [{
    text: capitalizeName(pokeinfo.name),
    style: 'black',
    font: '22px Consolas',
    x: maxwidth / 2,
    y: 30
  }]

  const noFrontSpriteText = {
    text: '?',
    style: 'lightgray',
    font: '48px Consolas',
    x: padding + (imgW / 2),
    y: 60 + (imgH / 2)
  }

  const frontSprite = pokeinfo.sprites.front_default

  const images = []

  if (frontSprite) {
    images.push({
      url: frontSprite,
      x: padding,
      y: 60,
      width: imgW,
      height: imgH
    })
  } else {
    texts.push(noFrontSpriteText)
  }

  drawRects(ctx, rects)
  await loadAndDrawImages(ctx, images)
  drawTexts(ctx, texts)
}

function drawStatsBlock (pokeinfo, ctx) {
  const initialY = 60
  const initialX = padding + 96 + padding

  const maxHp = 255
  const maxAttack = 190
  const maxDefense = 230
  const maxSpAttack = 194
  const maxSpDefense = 230
  const maxSpeed = 180

  const hp = pokeinfo.stats.find((element) => element.stat.name === 'hp').base_stat
  const attack = pokeinfo.stats.find((element) => element.stat.name === 'attack').base_stat
  const defense = pokeinfo.stats.find((element) => element.stat.name === 'defense').base_stat
  const spAttack = pokeinfo.stats.find((element) => element.stat.name === 'special-attack').base_stat
  const spDefense = pokeinfo.stats.find((element) => element.stat.name === 'special-defense').base_stat
  const speed = pokeinfo.stats.find((element) => element.stat.name === 'speed').base_stat

  const barHeight = 12
  const barWidth = (maxwidth - initialX - padding)
  const spaceBetweenBars = 5
  const yIncrement = (barHeight + spaceBetweenBars)
  drawStatBar(ctx, initialX, initialY, barWidth, barHeight, '#FF0000', '#FF5959', '#A60000', 'HP', hp, maxHp)
  drawStatBar(ctx, initialX, initialY + yIncrement, barWidth, barHeight, '#F08030', '#F5AC78', '#9C531F', 'Attack', attack, maxAttack)
  drawStatBar(ctx, initialX, initialY + (yIncrement * 2), barWidth, barHeight, '#F8D030', '#FAE078', '#A1871F', 'Defense', defense, maxDefense)
  drawStatBar(ctx, initialX, initialY + (yIncrement * 3), barWidth, barHeight, '#6890F0', '#9DB7F5', '#445E9C', 'Sp.Attack', spAttack, maxSpAttack)
  drawStatBar(ctx, initialX, initialY + (yIncrement * 4), barWidth, barHeight, '#78C850', '#A7DB8D', '#4E8234', 'Sp.Defense', spDefense, maxSpDefense)
  drawStatBar(ctx, initialX, initialY + (yIncrement * 5), barWidth, barHeight, '#F85888', '#FA92B2', '#A13959', 'Speed', speed, maxSpeed)
}

function drawStatBar (ctx, x, y, width, height, color1, color2, color3, statName, statValue, maxValue) {
  const texts = [{
    text: `${statName}: ${statValue}`,
    style: 'black',
    font: '12px Consolas',
    x: x + (width / 2),
    y: y + (height / 2)
  }]

  const rects = [{
    x: x,
    y,
    width,
    height,
    style: color2
  },
  {
    x: x,
    y,
    width: (width / maxValue) * statValue,
    height,
    style: color1
  }]

  drawRects(ctx, rects)
  drawTexts(ctx, texts)
}
<|endoftext|>


<commit_before>require("babel-polyfill");

import config from "config";
import promisify from "promisify-node";
import log from "./log";
import * as dbCache from "./dbCache";
import * as fastCache from "./fastCache";
import * as image from "./image";
import aws from "./aws";
import {futureDate} from "./helper";
import metrics, {GENERATION, ORIGINAL, REDIRECT} from './metrics';

const fs = promisify('fs');

const imagePath = (name) => `${config.get('originals_dir')}/${name}`;

const redirectTimeout = config.has('redirect_cache_timeout') ? config.get('redirect_cache_timeout') : 0;

const didTimeout = (error) => {
  return error.message === 'gm() resulted in a timeout.';
};

// Determine whether the image exists on disk
// Returns either true of false
const doesImageExist = async (name) => {
  try {
    await fs.access(imagePath(name), fs.R_OK);
    return true;
  } catch (e) {
    return false;
  }
};

// GM does not always return a nice buffer
// https://github.com/aheckmann/gm/issues/572#issuecomment-293768810
const gmToBuffer = (data) => {
  return new Promise((resolve, reject) => {
    data.stream((err, stdout, stderr) => {
      if (err) {
        reject(err);
        return;
      }
      const chunks = [];
      stdout.on('data', (chunk) => {
        chunks.push(chunk);
      });
      // these are 'once' because they can and do fire multiple times for multiple errors,
      // but this is a promise so you'll have to deal with them one at a time
      stdout.once('end', () => {
        resolve(Buffer.concat(chunks));
      });
      stderr.once('data', (data) => {
        reject(String(data));
      });
    });
  });
};

const isRequestedImageWithinBounds = (params) => {
  // Check if we are allowed to serve an image of this size and optionally redirect
  return (params.width && params.height) &&
    (params.width <= config.get('constraints.max_width') && params.height <= config.get('constraints.max_height'));
};

const calculateNewBounds = async (params) => {
  // Resize the parameters
  // If no params are set then we load them from the actual image before calculating new bounds
  if (!params.width || !params.height) {
    const fileSize = await image.imageSize(imagePath(params.name));
    params.width = fileSize.width;
    params.height = fileSize.height;
  }
  const providedRatio = params.width / params.height;
  if (params.width > config.get('constraints.max_width')) {
    params.width = config.get('constraints.max_width');
    if (params.fit === 'crop') {
      params.height = params.width / providedRatio;
    }
  }
  if (params.height > config.get('constraints.max_height')) {
    params.height = config.get('constraints.max_height');
    if (params.fit === 'crop') {
      params.width = params.height * providedRatio;
    }
  }
  return params;
};

const isHeadRequest = method => (method === 'HEAD');

const redirectImageToWithinBounds = (params, response) => {
  const newLocation = `/${params.name}_${params.width}_${params.height}.${params.type}` +
    `?fit=${params.fit}&blur=${Boolean(params.blur)}&quality=${params.quality}`;
  return response.status(303).set({
    'X-Redirect-Info': 'The requested image size falls outside of the allowed boundaries of this service. We are directing you to the closest available match.', //eslint-disable-line max-len
    'Location': newLocation
  }).end();
};

const redirectToCachedEntity = (cacheUrl, params, response) => {
  // We redirect the user to the new location. We issue a temporary redirect such that the
  // request url stays the representitive url, and because temporary redirects generally
  // give less issues than permanent redirects for the odd chance that the underlying resource
  // does actually change
  const headers = {
    'Location': cacheUrl
  };
  if (redirectTimeout) {
    headers['Cache-Control'] = `max-age=${redirectTimeout}`;
  }

  response.status(303).set(headers).end();
  response.end();
};

const sendFoundHeaders = (params, response) => {
  // Get the image and resize it. We allow any intermediate servers and browsers to use this cached resource as well
  response.status(200).type(params.mime).set({
    'Expires': futureDate(),
    'Cache-Control': 'public'
  });
};

const imageKey = params =>
  `${params.name}_${params.width}x${params.height}.${params.fit}` +
  `.b-${Boolean(params.blur)}.q-${params.quality}.${params.type}`;

export async function magic(params, method, response, stats = undefined, metric = undefined) {
    if (params === null) {
      // Invalid, hence reject
      response.status(400).end();
      if (metric) {
        metric.addTag('status', 400);
        metrics.write(metric);
      }
      return;
    }

    const imageExists = await doesImageExist(params.name);
    if (!imageExists) {
      response.status(404).end();
      if (metric) {
        metric.addTag('status', 404);
        metrics.write(metric);
      }
      return;
    }

    // Image exists
    if (!isRequestedImageWithinBounds(params)) {
      redirectImageToWithinBounds(await calculateNewBounds(params), response);
      if (metric) {
        metric.addTag('status', 307);
        metric.addTag('withinBounds', false);
        metrics.write(metric);
      }
      return;
    }

    const imageDescription = this.description(params);
    // Image exists and is within bounds.
    // This method is mainly used by browsers to serve retina images
    if (isHeadRequest(method)) {
      response.status(200).end();
      log('debug', `HEAD request for ${imageDescription} can be served`);
      // No metrics here
      return;
    }
    log('debug', `Request for ${imageDescription}`);

    const fastCacheValue = await fastCache.getImageFromCache(params);
    if (fastCacheValue) {
      log('debug', `Fast cache hit for ${imageDescription}`);
      redirectToCachedEntity(fastCacheValue, params, response);
      if (metric) {
        metric.addTag('cacheHit', true);
        metric.addTag('withinBounds', true);
        metric.addTag('status', 303);
        metric.stop();
        metrics.write(metric);
        metrics.write(metric.copy(REDIRECT));
      }
      return;
    }

    metric.addTag('cacheHit', false);
    const cacheValue = await dbCache.getFromCache(params);
    if (cacheValue) {
      log('debug', `Cache hit for ${imageDescription}`);
      if (stats) {
        stats.hits.incrementAndGet();
      }
      redirectToCachedEntity(cacheValue, params, response);
      if (metric) {
        metric.addFields(dbCache.stats());
        metric.addTag('status', 303);
        metric.addTag('withinBounds', true);
        metric.stop();
        metrics.write(metric);
        metrics.write(metric.copy(REDIRECT));
      }
      await fastCache.addImageToCache(params, cacheValue);
      return;
    }
    if (stats) {
      stats.misses.incrementAndGet();
    }

    // Image is present but not in the correct setting
    log('debug', `Cache miss for ${imageDescription}`);
    sendFoundHeaders(params, response);

    const clientStartTime = new Date();
    const browserImage = await image.magic(imagePath(params.name), params);
    try {
      const browserBuffer = await gmToBuffer(browserImage);
      log('info', `Creating image took ${new Date() - clientStartTime}ms: ${imageDescription}`);

      const awsBuffer = Buffer.from(browserBuffer);
      response.end(browserBuffer);
      if (metric) {
        metric.addFields(dbCache.stats());
        metric.addTag('status', 200);
        metric.addTag('withinBounds', true);
        metric.stop();
        metrics.write(metric);
        metrics.write(metric.copy(GENERATION));
      }
      await aws(imageKey(params), params, awsBuffer);
    } catch (err) {
      const status = didTimeout(err) ? 504 : 500;
      response.status(status).end();
      if (metric) {
        metric.addTag('status', status);
        metric.stop();
        metrics.write(metric);
        metrics.write(metric.copy(GENERATION));
      }
      log('error', `Error occurred while creating live image ${imageDescription}: ${err}`);
    }
  }

export async function original(params, method, response, metric = undefined) {
    const startTime = new Date();
    const imageExists = await doesImageExist(params.name);
    if (!imageExists) {
      response.status(404).end();
      if (metric) {
        metric.addTag('status', 404);
        metrics.write(metric);
      }
      return;
    }
    response.status(200).set({
      'Content-Type': params.mime,
      'Cache-Control': 'public',
      Etag: `${params.name}_${params.type}`,
      Expires: futureDate()
    });
    const data = await fs.readFile(imagePath(params.name));
    response.end(data);
    if (metric) {
      metric.addTag('status', 200);
      metric.stop();
      metrics.write(metric);
      metrics.write(metric.copy(ORIGINAL));
    }
    log('info', `Serving original image ${params.name} took ${new Date() - startTime}ms`);
  }
  export async function upload(name, path, cropParameters) {
    const destinationPath = `${config.get('originals_dir')}/${name}`;
    return await image.writeOriented(path, destinationPath, cropParameters);
  }
  export function description(params) {
    return `${params.name}.${params.type} (${params.width}x${params.height}px, fit: ${params.fit}, blur: ${Boolean(params.blur)}), quality: ${Number(params.quality) || 'auto'}`; //eslint-disable-line max-len
  }
  export async function hasAllowableImageSize(path, maxSizeInMegapixel) {
    const imageSize = await image.imageArea(path);
    return imageSize < (maxSizeInMegapixel * 1e6);
  }
<commit_msg>Ensure timeouts are properly caught<commit_after>require("babel-polyfill");

import config from "config";
import promisify from "promisify-node";
import log from "./log";
import * as dbCache from "./dbCache";
import * as fastCache from "./fastCache";
import * as image from "./image";
import aws from "./aws";
import {futureDate} from "./helper";
import metrics, {GENERATION, ORIGINAL, REDIRECT} from './metrics';

const fs = promisify('fs');

const imagePath = (name) => `${config.get('originals_dir')}/${name}`;

const redirectTimeout = config.has('redirect_cache_timeout') ? config.get('redirect_cache_timeout') : 0;

const didTimeout = (error) => {
  return error.message === 'gm() resulted in a timeout.';
};

// Determine whether the image exists on disk
// Returns either true of false
const doesImageExist = async (name) => {
  try {
    await fs.access(imagePath(name), fs.R_OK);
    return true;
  } catch (e) {
    return false;
  }
};

// GM does not always return a nice buffer
// https://github.com/aheckmann/gm/issues/572#issuecomment-293768810
const gmToBuffer = (data) => {
  return new Promise((resolve, reject) => {
    data.stream((err, stdout, stderr) => {
      if (err) {
        reject(err);
        return;
      }
      const chunks = [];
      stdout.on('data', (chunk) => {
        chunks.push(chunk);
      });
      // these are 'once' because they can and do fire multiple times for multiple errors,
      // but this is a promise so you'll have to deal with them one at a time
      stdout.once('end', () => {
        resolve(Buffer.concat(chunks));
      });
      stderr.once('data', (data) => {
        reject(String(data));
      });
    });
  });
};

const isRequestedImageWithinBounds = (params) => {
  // Check if we are allowed to serve an image of this size and optionally redirect
  return (params.width && params.height) &&
    (params.width <= config.get('constraints.max_width') && params.height <= config.get('constraints.max_height'));
};

const calculateNewBounds = async (params) => {
  // Resize the parameters
  // If no params are set then we load them from the actual image before calculating new bounds
  if (!params.width || !params.height) {
    const fileSize = await image.imageSize(imagePath(params.name));
    params.width = fileSize.width;
    params.height = fileSize.height;
  }
  const providedRatio = params.width / params.height;
  if (params.width > config.get('constraints.max_width')) {
    params.width = config.get('constraints.max_width');
    if (params.fit === 'crop') {
      params.height = params.width / providedRatio;
    }
  }
  if (params.height > config.get('constraints.max_height')) {
    params.height = config.get('constraints.max_height');
    if (params.fit === 'crop') {
      params.width = params.height * providedRatio;
    }
  }
  return params;
};

const isHeadRequest = method => (method === 'HEAD');

const redirectImageToWithinBounds = (params, response) => {
  const newLocation = `/${params.name}_${params.width}_${params.height}.${params.type}` +
    `?fit=${params.fit}&blur=${Boolean(params.blur)}&quality=${params.quality}`;
  return response.status(303).set({
    'X-Redirect-Info': 'The requested image size falls outside of the allowed boundaries of this service. We are directing you to the closest available match.', //eslint-disable-line max-len
    'Location': newLocation
  }).end();
};

const redirectToCachedEntity = (cacheUrl, params, response) => {
  // We redirect the user to the new location. We issue a temporary redirect such that the
  // request url stays the representitive url, and because temporary redirects generally
  // give less issues than permanent redirects for the odd chance that the underlying resource
  // does actually change
  const headers = {
    'Location': cacheUrl
  };
  if (redirectTimeout) {
    headers['Cache-Control'] = `max-age=${redirectTimeout}`;
  }

  response.status(303).set(headers).end();
  response.end();
};

const sendFoundHeaders = (params, response) => {
  // Get the image and resize it. We allow any intermediate servers and browsers to use this cached resource as well
  response.status(200).type(params.mime).set({
    'Expires': futureDate(),
    'Cache-Control': 'public'
  });
};

const imageKey = params =>
  `${params.name}_${params.width}x${params.height}.${params.fit}` +
  `.b-${Boolean(params.blur)}.q-${params.quality}.${params.type}`;

export async function magic(params, method, response, stats = undefined, metric = undefined) {
    if (params === null) {
      // Invalid, hence reject
      response.status(400).end();
      if (metric) {
        metric.addTag('status', 400);
        metrics.write(metric);
      }
      return;
    }

    const imageExists = await doesImageExist(params.name);
    if (!imageExists) {
      response.status(404).end();
      if (metric) {
        metric.addTag('status', 404);
        metrics.write(metric);
      }
      return;
    }

    // Image exists
    if (!isRequestedImageWithinBounds(params)) {
      redirectImageToWithinBounds(await calculateNewBounds(params), response);
      if (metric) {
        metric.addTag('status', 307);
        metric.addTag('withinBounds', false);
        metrics.write(metric);
      }
      return;
    }

    const imageDescription = this.description(params);
    // Image exists and is within bounds.
    // This method is mainly used by browsers to serve retina images
    if (isHeadRequest(method)) {
      response.status(200).end();
      log('debug', `HEAD request for ${imageDescription} can be served`);
      // No metrics here
      return;
    }
    log('debug', `Request for ${imageDescription}`);

    const fastCacheValue = await fastCache.getImageFromCache(params);
    if (fastCacheValue) {
      log('debug', `Fast cache hit for ${imageDescription}`);
      redirectToCachedEntity(fastCacheValue, params, response);
      if (metric) {
        metric.addTag('cacheHit', true);
        metric.addTag('withinBounds', true);
        metric.addTag('status', 303);
        metric.stop();
        metrics.write(metric);
        metrics.write(metric.copy(REDIRECT));
      }
      return;
    }

    metric.addTag('cacheHit', false);
    const cacheValue = await dbCache.getFromCache(params);
    if (cacheValue) {
      log('debug', `Cache hit for ${imageDescription}`);
      if (stats) {
        stats.hits.incrementAndGet();
      }
      redirectToCachedEntity(cacheValue, params, response);
      if (metric) {
        metric.addFields(dbCache.stats());
        metric.addTag('status', 303);
        metric.addTag('withinBounds', true);
        metric.stop();
        metrics.write(metric);
        metrics.write(metric.copy(REDIRECT));
      }
      await fastCache.addImageToCache(params, cacheValue);
      return;
    }
    if (stats) {
      stats.misses.incrementAndGet();
    }

    // Image is present but not in the correct setting
    log('debug', `Cache miss for ${imageDescription}`);
    sendFoundHeaders(params, response);

    const clientStartTime = new Date();
    try {
      const browserImage = await image.magic(imagePath(params.name), params);
      const browserBuffer = await gmToBuffer(browserImage);
      log('info', `Creating image took ${new Date() - clientStartTime}ms: ${imageDescription}`);

      const awsBuffer = Buffer.from(browserBuffer);
      response.end(browserBuffer);
      if (metric) {
        metric.addFields(dbCache.stats());
        metric.addTag('status', 200);
        metric.addTag('withinBounds', true);
        metric.stop();
        metrics.write(metric);
        metrics.write(metric.copy(GENERATION));
      }
      await aws(imageKey(params), params, awsBuffer);
    } catch (err) {
      const status = didTimeout(err) ? 504 : 500;
      response.status(status).end();
      if (metric) {
        metric.addTag('status', status);
        metric.stop();
        metrics.write(metric);
        metrics.write(metric.copy(GENERATION));
      }
      log('error', `Error occurred while creating live image ${imageDescription}: ${err}`);
    }
  }

export async function original(params, method, response, metric = undefined) {
    const startTime = new Date();
    const imageExists = await doesImageExist(params.name);
    if (!imageExists) {
      response.status(404).end();
      if (metric) {
        metric.addTag('status', 404);
        metrics.write(metric);
      }
      return;
    }
    response.status(200).set({
      'Content-Type': params.mime,
      'Cache-Control': 'public',
      Etag: `${params.name}_${params.type}`,
      Expires: futureDate()
    });
    const data = await fs.readFile(imagePath(params.name));
    response.end(data);
    if (metric) {
      metric.addTag('status', 200);
      metric.stop();
      metrics.write(metric);
      metrics.write(metric.copy(ORIGINAL));
    }
    log('info', `Serving original image ${params.name} took ${new Date() - startTime}ms`);
  }
  export async function upload(name, path, cropParameters) {
    const destinationPath = `${config.get('originals_dir')}/${name}`;
    return await image.writeOriented(path, destinationPath, cropParameters);
  }
  export function description(params) {
    return `${params.name}.${params.type} (${params.width}x${params.height}px, fit: ${params.fit}, blur: ${Boolean(params.blur)}), quality: ${Number(params.quality) || 'auto'}`; //eslint-disable-line max-len
  }
  export async function hasAllowableImageSize(path, maxSizeInMegapixel) {
    const imageSize = await image.imageArea(path);
    return imageSize < (maxSizeInMegapixel * 1e6);
  }
<|endoftext|>


<commit_before>'use strict';

const assert = require('assert');
const { browser } = require('../mini-testium-mocha');

const { getConfig } = require('testium-core');

const browserName = getConfig().get('browser');

describe('dialogs', () => {
  let target;

  if (browserName === 'phantomjs') {
    it.skip("skipping tests because browser phantomjs doesn't support alerts");
    return;
  }

  before(browser.beforeHook());

  before(async () => {
    await browser.loadPage('/');

    target = await browser.getElement('#alert_target');
    await browser.clickOn('.link_to_clear_alert_target');
  });

  describe('alert', () => {
    beforeEach(() => browser.clickOn('.link_to_open_an_alert'));

    it('can get an alert text', done => {
      browser
        .getAlertText()
        .then(text => {
          assert.strictEqual(text, 'An alert!', 'Alert text was not found');
        })
        .acceptAlert(done);
    });

    it('can accept an alert', done => {
      browser.acceptAlert(() => {
        target.text().then(text => {
          assert.strictEqual(text, 'alerted');
          done();
        });
      });
    });

    it('can dismiss an alert', done => {
      browser.dismissAlert(() => {
        target.text().then(text => {
          assert.strictEqual(text, 'alerted');
          done();
        });
      });
    });
  });

  describe('confirm', () => {
    beforeEach(() => browser.clickOn('.link_to_open_a_confirm'));

    it('can get confirm text', done => {
      browser
        .getAlertText()
        .then(text => {
          assert.strictEqual(
            text,
            'A confirmation!',
            'Confirm text was not found'
          );
        })
        .acceptAlert(done);
    });

    it('can accept a confirm', done => {
      browser.acceptAlert(() => {
        target.text().then(text => {
          assert.strictEqual(text, 'confirmed');
          done();
        });
      });
    });

    it('can dismiss a confirm', done => {
      browser.dismissAlert(() => {
        target.text().then(text => {
          assert.strictEqual(text, 'dismissed');
          done();
        });
      });
    });
  });

  describe('prompt', function () {
    this.retries(3); // prompts seem to be flaky in chromedriver
    beforeEach(() =>
      browser
        .waitForElementDisplayed('.link_to_open_a_prompt')
        .clickOn('.link_to_open_a_prompt')
    );

    it('can get prompt text', done => {
      browser
        .getAlertText()
        .then(text => {
          assert.strictEqual(text, 'A prompt!', 'Confirm text was not found');
        })
        .acceptAlert(done);
    });

    it('can send text to and accept a prompt', done => {
      browser.typeAlert('Some words').acceptAlert(() => {
        target.text().then(text => {
          assert.strictEqual(text, 'Some words');
          done();
        });
      });
    });

    it('can dismiss a prompt', done => {
      browser.dismissAlert(() => {
        target.text().then(text => {
          assert.strictEqual(text, 'dismissed');
          done();
        });
      });
    });
  });
});
<commit_msg>test: rewrite dialog tests<commit_after>'use strict';

const assert = require('assert');
const { browser } = require('../mini-testium-mocha');

const { getConfig } = require('testium-core');

const browserName = getConfig().get('browser');

describe('dialogs', () => {
  let target;

  if (browserName === 'phantomjs') {
    it.skip("skipping tests because browser phantomjs doesn't support alerts");
    return;
  }

  before(browser.beforeHook());

  before(async () => {
    await browser.loadPage('/');

    target = await browser.getElement('#alert_target');
    await browser.clickOn('.link_to_clear_alert_target');
  });

  describe('alert', () => {
    beforeEach(() => browser.clickOn('.link_to_open_an_alert'));

    it('can get an alert text', async () => {
      await browser
        .getAlertText()
        .then(text => {
          assert.strictEqual(text, 'An alert!', 'Alert text was not found');
        })
        .acceptAlert();
    });

    it('can accept an alert', async () => {
      await browser.acceptAlert();
      const text = await target.text();

      assert.strictEqual(text, 'alerted');
    });

    it('can dismiss an alert', async () => {
      await browser.dismissAlert();
      const text = await target.text();

      assert.strictEqual(text, 'alerted');
    });
  });

  describe('confirm', () => {
    beforeEach(() => browser.clickOn('.link_to_open_a_confirm'));

    it('can get confirm text', async () => {
      const text = await browser.getAlertText();
      await browser.acceptAlert();

      assert.strictEqual(text, 'A confirmation!', 'Confirm text was not found');
    });

    it('can accept a confirm', async () => {
      await browser.acceptAlert();
      const text = await target.text();

      assert.strictEqual(text, 'confirmed');
    });

    it('can dismiss a confirm', async () => {
      await browser.dismissAlert();
      const text = await target.text();

      assert.strictEqual(text, 'dismissed');
    });
  });

  describe('prompt', function () {
    this.retries(3); // prompts seem to be flaky in chromedriver
    beforeEach(() =>
      browser
        .waitForElementDisplayed('.link_to_open_a_prompt')
        .clickOn('.link_to_open_a_prompt')
    );

    it('can get prompt text', done => {
      browser
        .getAlertText()
        .then(text => {
          assert.strictEqual(text, 'A prompt!', 'Confirm text was not found');
        })
        .acceptAlert(done);
    });

    it('can send text to and accept a prompt', done => {
      browser.typeAlert('Some words').acceptAlert(() => {
        target.text().then(text => {
          assert.strictEqual(text, 'Some words');
          done();
        });
      });
    });

    it('can dismiss a prompt', done => {
      browser.dismissAlert(() => {
        target.text().then(text => {
          assert.strictEqual(text, 'dismissed');
          done();
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');
const fold = require('fold-to-ascii').fold;

const Couch = require('../index');
const debug = require('../util/debug')('import');
const getConfig = require('../config/config').getConfig;

exports.import = async function (database, importName, file) {
    debug(`import ${file} (${database}, ${importName})`);

    const filename = path.parse(file).base;
    let contents = fs.readFileSync(file);

    let config = getConfig(database);
    if (!config.import || !config.import[importName]) {
        throw new Error(`no import config for ${database}/${importName}`);
    }
    config = config.import[importName];

    const couch = Couch.get(database);

    // Callbacks
    const getId = verifyConfig(config, 'getID', null, true);
    const getOwner = verifyConfig(config, 'getOwner', null, true);
    let parse = null;
    let json = null;
    try {
        parse = verifyConfig(config, 'parse', null, true);
    } catch (e) {
        json = verifyConfig(config, 'json', null, true);
    }

    if (json) contents = JSON.parse(contents);

    const info = {};
    try {
        await getMetadata(info, getId, getOwner, filename, contents, couch);
        await parseFile(info, parse, json, filename, contents, couch);
        if (config.kind) {
            await getKind(info, config.kind, filename, contents, couch);
        }
        const docInfo = await checkDocumentExists(info, filename, contents, couch);
        await updateDocument(info, docInfo, parse, json, filename, contents, couch);
        debug.trace(`import ${file} success`);
    } catch (e) {
        debug.error(`import ${file} failure: ${e.message}, ${e.stack}`);
        throw e;
    }

};

function verifyConfig(config, name, defaultValue, mustBeFunction) {
    const value = config[name];
    if (value === undefined) {
        if (defaultValue) {
            return defaultValue;
        }
        throw new Error('missing configuration value: ' + name);
    }
    if (mustBeFunction && typeof value !== 'function') {
        throw new Error(`configuration value ${name} must be a function`);
    }
    return value;
}

async function getMetadata(info, getId, getOwner, filename, contents, couch) {
    debug.trace('get metadata');
    let [id, owner] = await Promise.all([
        getId(filename, contents, couch),
        getOwner(filename, contents, couch)
    ]);
    debug.trace(`id: ${id}, owner: ${owner}`);
    let owners;
    if (Array.isArray(owner)) {
        owners = owner;
        owner = owners[0];
        owners = owners.slice(1);
    }
    info.id = id;
    info.owner = owner;
    info.owners = owners;
}

async function parseFile(info, parse, json, filename, contents, couch) {
    debug.trace('parse file contents');
    if (parse) {
        const result = await parse(filename, contents, couch);
        if (result.skip) {
            const error = new Error('skipped');
            error.skip = true;
            throw error;
        }
        if (typeof result.jpath !== 'string') {
            throw new Error('parse: jpath must be a string');
        }
        if (typeof result.data !== 'object' || result.data === null) {
            throw new Error('parse: data must be an object');
        }
        if (typeof result.field !== 'string') {
            throw new Error('parse: field must be a string');
        }

        debug.trace(`jpath: ${result.jpath}`);
        info.jpath = result.jpath.split('.');
        info.data = result.data;
        info.content_type = result.content_type || 'application/octet-stream';
        info.field = result.field;
        info.reference = result.reference;
        info.content = result.content;
        if (result.noUpload) {
            info.noUpload = true;
        }
        info.attachments = result.attachments;
        return;
    } else if (json) {
        info.data = await json(filename, contents, couch);
        return;
    }
    throw new Error('unreachable');
}

async function getKind(info, kind, filename, contents, couch) {
    debug.trace('getKind');
    if (typeof kind !== 'function') {
        info.kind = kind;
    } else {
        info.kind = await kind(filename, contents, couch);
    }
}

async function checkDocumentExists(info, filename, contents, couch) {
    debug.trace('checkDocumentExists');
    return couch.createEntry(info.id, info.owner, {
        createParameters: [filename, contents],
        kind: info.kind,
        owners: info.owners
    });
}

async function updateDocument(info, docInfo, parse, json, filename, contents, couch) {
    debug.trace('updateDocument');
    if (parse) {
        const joined = info.jpath.join('/') + '/';
        if (!info.noUpload) {
            const goodFilename = fold(filename, '_');
            await couch.addFileToJpath(info.id, info.owner, info.jpath, info.data, {
                field: info.field,
                reference: info.reference,
                name: joined + goodFilename,
                data: contents,
                content_type: info.content_type
            }, info.content);
        } else {
            await updateContent();
        }
        if (info.attachments && info.attachments.length) {
            debug(`got ${info.attachments.length} more attachments`);
            if (!info.reference) throw new Error('cannot upload more attachments without a reference');
            for (const attachment of info.attachments) {
                if (!attachment.field ||
                    !attachment.filename ||
                    !attachment.contents ||
                    !attachment.content_type) {
                    throw new Error('attachment is missing a field');
                }
            }
            for (const attachment of info.attachments) {
                const attachmentName = fold(attachment.filename, '_');
                await couch.addFileToJpath(info.id, info.owner, info.jpath, attachment.data || {}, {
                    field: attachment.field,
                    reference: info.reference,
                    name: joined + attachmentName,
                    data: attachment.contents,
                    content_type: attachment.content_type
                });
            }
        }
        return null;
    } else if (json) {
        return updateContent();
    }
    throw new Error('unreachable');

    function updateContent() {
        let entry = {
            $id: info.id,
            $kind: info.kind,
            $content: info.data,
            _id: docInfo.id,
            _rev: docInfo.rev
        };
        return couch.insertEntry(entry, info.owner, {merge: true});
    }
}
<commit_msg>feat(import): allow to do everything in the same callback (fullProcess)<commit_after>'use strict';

const fs = require('fs');
const path = require('path');
const fold = require('fold-to-ascii').fold;

const Couch = require('../index');
const debug = require('../util/debug')('import');
const getConfig = require('../config/config').getConfig;

exports.import = async function (database, importName, file) {
    debug(`import ${file} (${database}, ${importName})`);

    const filename = path.parse(file).base;
    let contents = fs.readFileSync(file);

    let config = getConfig(database);
    if (!config.import || !config.import[importName]) {
        throw new Error(`no import config for ${database}/${importName}`);
    }
    config = config.import[importName];

    const couch = Couch.get(database);

    const info = {};

    let isParse = false;
    let isJson = false;

    if (typeof config.fullProcess === 'function') {
        isParse = true;
        await fullyProcessResult(config.fullProcess, filename, contents, couch);
    } else {
        // Callbacks
        const getId = verifyConfig(config, 'getID', null, true);
        const getOwner = verifyConfig(config, 'getOwner', null, true);
        let parse = null;
        let json = null;
        try {
            parse = verifyConfig(config, 'parse', null, true);
            isParse = true;
        } catch (e) {
            json = verifyConfig(config, 'json', null, true);
            isJson = true;
        }

        if (json) contents = JSON.parse(contents);

        await getMetadata(info, getId, getOwner, filename, contents, couch);
        await parseFile(info, parse, json, filename, contents, couch);
        if (config.kind) {
            await getKind(info, config.kind, filename, contents, couch);
        }
    }

    try {
        const docInfo = await checkDocumentExists(info, filename, contents, couch);
        await updateDocument(info, docInfo, isParse, isJson, filename, contents, couch);
        debug.trace(`import ${file} success`);
    } catch (e) {
        debug.error(`import ${file} failure: ${e.message}, ${e.stack}`);
        throw e;
    }

};

function verifyConfig(config, name, defaultValue, mustBeFunction) {
    const value = config[name];
    if (value === undefined) {
        if (defaultValue) {
            return defaultValue;
        }
        throw new Error('missing configuration value: ' + name);
    }
    if (mustBeFunction && typeof value !== 'function') {
        throw new Error(`configuration value ${name} must be a function`);
    }
    return value;
}

async function getMetadata(info, getId, getOwner, filename, contents, couch) {
    debug.trace('get metadata');
    let [id, owner] = await Promise.all([
        getId(filename, contents, couch),
        getOwner(filename, contents, couch)
    ]);
    debug.trace(`id: ${id}, owner: ${owner}`);
    const ownerData = getOwnerData(owner);
    info.id = id;
    info.owner = ownerData.owner;
    info.owners = ownerData.owners;
}

async function parseFile(info, parse, json, filename, contents, couch) {
    debug.trace('parse file contents');
    if (parse) {
        const result = await parse(filename, contents, couch);
        fillInfoWithResult(info, result);
        return;
    } else if (json) {
        info.data = await json(filename, contents, couch);
        return;
    }
    throw new Error('unreachable');
}

async function getKind(info, kind, filename, contents, couch) {
    debug.trace('getKind');
    if (typeof kind !== 'function') {
        info.kind = kind;
    } else {
        info.kind = await kind(filename, contents, couch);
    }
}

async function fullyProcessResult(info, fullProcess, filename, contents, couch) {
    const result = await fullProcess(filename, contents, couch);

    if (!result.id) {
        throw new Error('missing id');
    }
    info.id = result.id;

    if (!result.owner) {
        throw new Error('missing owner');
    }
    const ownerData = getOwnerData(result.owner);
    info.owner = ownerData.owner;
    info.owners = ownerData.owners;

    fillInfoWithResult(info, result);

    if (!result.kind) {
        throw new Error('missing kind');
    }
    info.kind = result.kind;
}

function fillInfoWithResult(info, result) {
    if (result.skip) {
        const error = new Error('skipped');
        error.skip = true;
        throw error;
    }
    if (typeof result.jpath !== 'string') {
        throw new Error('parse: jpath must be a string');
    }
    if (typeof result.data !== 'object' || result.data === null) {
        throw new Error('parse: data must be an object');
    }
    if (typeof result.field !== 'string') {
        throw new Error('parse: field must be a string');
    }

    debug.trace(`jpath: ${result.jpath}`);
    info.jpath = result.jpath.split('.');
    info.data = result.data;
    info.content_type = result.content_type || 'application/octet-stream';
    info.field = result.field;
    info.reference = result.reference;
    info.content = result.content;
    if (result.noUpload) {
        info.noUpload = true;
    }
    info.attachments = result.attachments;
}

async function checkDocumentExists(info, filename, contents, couch) {
    debug.trace('checkDocumentExists');
    return couch.createEntry(info.id, info.owner, {
        createParameters: [filename, contents],
        kind: info.kind,
        owners: info.owners
    });
}

async function updateDocument(info, docInfo, isParse, isJson, filename, contents, couch) {
    debug.trace('updateDocument');
    if (isParse) {
        const joined = info.jpath.join('/') + '/';
        if (!info.noUpload) {
            const goodFilename = fold(filename, '_');
            await couch.addFileToJpath(info.id, info.owner, info.jpath, info.data, {
                field: info.field,
                reference: info.reference,
                name: joined + goodFilename,
                data: contents,
                content_type: info.content_type
            }, info.content);
        } else {
            await updateContent();
        }
        if (info.attachments && info.attachments.length) {
            debug(`got ${info.attachments.length} more attachments`);
            if (!info.reference) throw new Error('cannot upload more attachments without a reference');
            for (const attachment of info.attachments) {
                if (!attachment.field ||
                    !attachment.filename ||
                    !attachment.contents ||
                    !attachment.content_type) {
                    throw new Error('attachment is missing a field');
                }
            }
            for (const attachment of info.attachments) {
                const attachmentName = fold(attachment.filename, '_');
                await couch.addFileToJpath(info.id, info.owner, info.jpath, attachment.data || {}, {
                    field: attachment.field,
                    reference: info.reference,
                    name: joined + attachmentName,
                    data: attachment.contents,
                    content_type: attachment.content_type
                });
            }
        }
        return null;
    } else if (isJson) {
        return updateContent();
    }
    throw new Error('unreachable');

    function updateContent() {
        let entry = {
            $id: info.id,
            $kind: info.kind,
            $content: info.data,
            _id: docInfo.id,
            _rev: docInfo.rev
        };
        return couch.insertEntry(entry, info.owner, {merge: true});
    }
}

function getOwnerData(owner) {
    let owners;
    if (Array.isArray(owner)) {
        owners = owner;
        owner = owners[0];
        owners = owners.slice(1);
    }
    return {owner, owners};
}
<|endoftext|>


<commit_before>import atImport from 'postcss-import';
import plugins  from './plugins';

export const importRegexp = /\:import\(['"](.*)['"]\)/;

export default function importModule(css, result) {
  css.each(importRule => {
    const match = importRegexp.exec(importRule.selector);

    if (!match) return;

    const moduleName = match[1];
    css.prepend({ name: 'import', params: `"${ moduleName }"` });
  });

  // Replace @import directives with imported modules
  atImport({ plugins })(css, result);
}
<commit_msg>Do not export importRegexp<commit_after>import atImport from 'postcss-import';
import plugins  from './plugins';

const importRegexp = /\:import\(['"](.*)['"]\)/;

export default function importModule(css, result) {
  css.each(importRule => {
    const match = importRegexp.exec(importRule.selector);

    if (!match) return;

    const moduleName = match[1];
    css.prepend({ name: 'import', params: `"${ moduleName }"` });
  });

  // Replace @import directives with imported modules
  atImport({ plugins })(css, result);
}
<|endoftext|>