<commit_before>/* eslint-env browser, node, worker */

// ndt7 contains the core ndt7 client functionality. Please, refer
// to the ndt7 spec available at the following URL:
//
// https://github.com/m-lab/ndt-server/blob/master/spec/ndt7-protocol.md
//
// This implementation uses v0.9.0 of the spec.

// Wrap everything in a closure to ensure that local definitions don't
// permanently shadow global definitions.
(function() {
  'use strict';

  // If this is running as a node module then WebSocket, fetch, and Worker
  // may all need to be defined.  In the browser they should already exist.
  if (typeof WebSocket === 'undefined') {
    global.WebSocket = require('isomorphic-ws');
  }
  if (typeof fetch === 'undefined') {
    global.fetch = require('node-fetch');
  }
  if (typeof Worker === 'undefined') {
    global.Worker = require('workerjs');
  }

  /**
   * @name ndt7
   * @namespace ndt7
   */
  const ndt7 = (function() {
    // cb creates a default-empty callback function, allowing library users to
    // only need to specify callback functions for the events they care about.
    //
    // This function is not exported.
    const cb = function(name, callbacks, defaultFn) {
      if (typeof(callbacks) !== 'undefined' && name in callbacks) {
        return callbacks[name];
      } else if (typeof defaultFn !== 'undefined') {
        return defaultFn;
      } else {
        // If no default function is provided, use the empty function.
        return function() {};
      }
    };

    // The default response to an error is to throw an exception.
    const defaultErrCallback = function(err) {
      throw new Error(err);
    };

    /**
     * discoverServerURLs contacts a web service (likely the Measurement Lab
     * locate service, but not necessarily) and gets URLs with access tokens in
     * them for the client. It can be short-circuted if config.server exists,
     * which is useful for clients served from the webserver of an NDT server.
     *
     * @param {Object} config - An associative array of configuration options.
     * @param {Object} userCallbacks - An associative array of user callbacks.
     *
     * It uses the callback functions `error`, `serverDiscovery`, and
     * `serverChosen`.
     *
     * @name ndt7.discoverServerURLS
     * @public
     */
    async function discoverServerURLs(config, userCallbacks) {
      const callbacks = {
        error: cb('error', userCallbacks, defaultErrCallback),
        serverDiscovery: cb('serverDiscovery', userCallbacks),
        serverChosen: cb('serverChosen', userCallbacks),
      };
      let protocol = 'wss';
      if (config && ('protocol' in config)) {
        protocol = config.protocol;
      }

      // If a server was specified, use it.
      if (config && ('server' in config)) {
        return {
          '///ndt/v7/download': protocol + '://' + config.server + '/ndt/v7/download',
          '///ndt/v7/upload': protocol + '://' + config.server + '/ndt/v7/upload',
        };
      }

      // If no server was specified then use a loadbalancer. If no loadbalancer
      // is specified, use the locate service from Measurement Lab.
      const lbURL = (config && ('loadbalancer' in config)) ? config.loadbalancer : new URL('https://locate.measurementlab.net/v2/nearest/ndt/ndt7');
      callbacks.serverDiscovery({loadbalancer: lbURL});
      const response = await fetch(lbURL).catch(err => {
        throw new Error(err);
      });
      const js = await response.json();
      if (! ('results' in js) ) {
        callbacks.error(`Could not understand response from ${lbURL}: ${js}`);
        return {};
      }

      // TODO: do not discard unused results. If the first server is unavailable
      // the client should quickly try the next server.
      //
      // Choose the first result sent by the load balancer. This ensures that
      // in cases where we have a single pod in a metro, that pod is used to
      // run the measurement. When there are multiple pods in the same metro,
      // they are randomized by the load balancer already.
      const choice = js.results[0];
      callbacks.serverChosen(choice);

      return {
        '///ndt/v7/download': choice.urls[protocol + ':///ndt/v7/download'],
        '///ndt/v7/upload': choice.urls[protocol + ':///ndt/v7/upload'],
      };
    }

    /*
     * runNDT7Worker is a helper function that runs a webworker. It uses the
     * callback functions `error`, `start`, `measurement`, and `complete`. It
     * returns a c-style return code. 0 is success, non-zero is some kind of
     * failure.
     *
     * @private
     */
    const runNDT7Worker = async function(
        config, callbacks, urlPromise, filename, testType) {
      if (config.userAcceptedDataPolicy !== true &&
          config.mlabDataPolicyInapplicable !== true) {
        callbacks.error('The M-Lab data policy is applicable and the user ' +
                        'has not explicitly accepted that data policy.');
        return 1;
      }

      let clientMeasurement;
      let serverMeasurement;

      // Sometimes things like __dirname will exist even in browser environments
      // instead check for well known node.js only environment markers
      if (typeof process !== 'undefined' &&
                 process.versions != null &&
                 process.versions.node != null) {
        filename = __dirname + '/' + filename;
      }

      // This makes the worker. The worker won't actually start until it
      // receives a message.
      const worker = new Worker(filename);

      // When the workerPromise gets resolved it will terminate the worker.
      // Workers are resolved with c-style return codes. 0 for success,
      // non-zero for failure.
      const workerPromise = new Promise((resolve) => {
        worker.resolve = function(returnCode) {
          console.log("Worker terminated with code", returnCode);
          if (returnCode == 0) {
            callbacks.complete({
              LastClientMeasurement: clientMeasurement,
              LastServerMeasurement: serverMeasurement,
            });
          }
          worker.terminate();
          resolve(returnCode);
        };
      });

      // If the worker takes 10 seconds, kill it and return an error code.
      // Most clients take longer than 10 seconds to complete the upload and
      // finish sending the buffer's content, sometimes hitting the socket's
      // timeout of 15 seconds. This makes sure uploads terminate on time.
      const workerTimeout = setTimeout(() => worker.resolve(0), 10000);

      // This is how the worker communicates back to the main thread of
      // execution.  The MsgTpe of `ev` determines which callback the message
      // gets forwarded to.
      worker.onmessage = function(ev) {
        if (!ev.data || !ev.data.MsgType || ev.data.MsgType === 'error') {
          clearTimeout(workerTimeout);
          worker.resolve(1);
          const msg = (!ev.data) ? `${testType} error` : ev.data.Error;
          callbacks.error(msg);
        } else if (ev.data.MsgType === 'start') {
          callbacks.start(ev.data.Data);
        } else if (ev.data.MsgType == 'measurement') {
          // For performance reasons, we parse the JSON outside of the thread
          // doing the downloading or uploading.
          if (ev.data.Source == 'server') {
            serverMeasurement = JSON.parse(ev.data.ServerMessage);
            callbacks.measurement({
              Source: ev.data.Source,
              Data: serverMeasurement,
            });
          } else {
            clientMeasurement = ev.data.ClientData;
            callbacks.measurement({
              Source: ev.data.Source,
              Data: ev.data.ClientData,
            });
          }
        } else if (ev.data.MsgType == 'complete') {
          clearTimeout(workerTimeout);
          worker.resolve(0);
        }
      };

      // We can't start the worker until we know the right server, so we wait
      // here to find that out.
      const urls = await urlPromise.catch(err => {
        clearTimeout(workerTimeout);
        worker.resolve(2);
        throw new Error(err);
      });

      // Start the worker.
      worker.postMessage(urls);

      // Await the resolution of the workerPromise.
      return await workerPromise;

      // Liveness guarantee - once the promise is resolved, .terminate() has
      // been called and the webworker will be terminated or in the process of
      // being terminated.
    };

    /**
     * downloadTest runs just the NDT7 download test.
     * @param {Object} config - An associative array of configuration strings
     * @param {Object} userCallbacks
     * @param {Object} urlPromise - A promise that will resolve to urls.
     *
     * @return {number} Zero on success, and non-zero error code on failure.
     *
     * @name ndt7.downloadTest
     * @public
     */
    async function downloadTest(config, userCallbacks, urlPromise) {
      const callbacks = {
        error: cb('error', userCallbacks, defaultErrCallback),
        start: cb('downloadStart', userCallbacks),
        measurement: cb('downloadMeasurement', userCallbacks),
        complete: cb('downloadComplete', userCallbacks),
      };
      const workerfile = config.downloadworkerfile || 'ndt7-download-worker.js';
      return await runNDT7Worker(
          config, callbacks, urlPromise, workerfile, 'download');
    }

    /**
     * uploadTest runs just the NDT7 download test.
     * @param {Object} config - An associative array of configuration strings
     * @param {Object} userCallbacks
     * @param {Object} urlPromise - A promise that will resolve to urls.
     *
     * @return {number} Zero on success, and non-zero error code on failure.
     *
     * @name ndt7.uploadTest
     * @public
     */
    async function uploadTest(config, userCallbacks, urlPromise) {
      const callbacks = {
        error: cb('error', userCallbacks, defaultErrCallback),
        start: cb('uploadStart', userCallbacks),
        measurement: cb('uploadMeasurement', userCallbacks),
        complete: cb('uploadComplete', userCallbacks),
      };
      const workerfile = config.uploadworkerfile || 'ndt7-upload-worker.js';
      const rv = await runNDT7Worker(
          config, callbacks, urlPromise, workerfile, 'upload');
      return rv << 4;
    }

    /**
     * test discovers a server to run against and then runs a download test
     * followed by an upload test.
     *
     * @param {Object} config - An associative array of configuration strings
     * @param {Object} userCallbacks
     *
     * @return {number} Zero on success, and non-zero error code on failure.
     *
     * @name ndt7.test
     * @public
     */
    async function test(config, userCallbacks) {
      // Starts the asynchronous process of server discovery, allowing other
      // stuff to proceed in the background.
      const urlPromise = discoverServerURLs(config, userCallbacks);
      const downloadSuccess = await downloadTest(
          config, userCallbacks, urlPromise);
      const uploadSuccess = await uploadTest(
          config, userCallbacks, urlPromise);
      return downloadSuccess + uploadSuccess;
    }

    return {
      discoverServerURLs: discoverServerURLs,
      downloadTest: downloadTest,
      uploadTest: uploadTest,
      test: test,
    };
  })();

  // Modules are used by `require`, if this file is included on a web page, then
  // module will be undefined and we use the window.ndt7 piece.
  if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
    module.exports = ndt7;
  } else {
    window.ndt7 = ndt7;
  }
})();
<commit_msg>Make linter happy. :)<commit_after>/* eslint-env browser, node, worker */

// ndt7 contains the core ndt7 client functionality. Please, refer
// to the ndt7 spec available at the following URL:
//
// https://github.com/m-lab/ndt-server/blob/master/spec/ndt7-protocol.md
//
// This implementation uses v0.9.0 of the spec.

// Wrap everything in a closure to ensure that local definitions don't
// permanently shadow global definitions.
(function() {
  'use strict';

  // If this is running as a node module then WebSocket, fetch, and Worker
  // may all need to be defined.  In the browser they should already exist.
  if (typeof WebSocket === 'undefined') {
    global.WebSocket = require('isomorphic-ws');
  }
  if (typeof fetch === 'undefined') {
    global.fetch = require('node-fetch');
  }
  if (typeof Worker === 'undefined') {
    global.Worker = require('workerjs');
  }

  /**
   * @name ndt7
   * @namespace ndt7
   */
  const ndt7 = (function() {
    // cb creates a default-empty callback function, allowing library users to
    // only need to specify callback functions for the events they care about.
    //
    // This function is not exported.
    const cb = function(name, callbacks, defaultFn) {
      if (typeof(callbacks) !== 'undefined' && name in callbacks) {
        return callbacks[name];
      } else if (typeof defaultFn !== 'undefined') {
        return defaultFn;
      } else {
        // If no default function is provided, use the empty function.
        return function() {};
      }
    };

    // The default response to an error is to throw an exception.
    const defaultErrCallback = function(err) {
      throw new Error(err);
    };

    /**
     * discoverServerURLs contacts a web service (likely the Measurement Lab
     * locate service, but not necessarily) and gets URLs with access tokens in
     * them for the client. It can be short-circuted if config.server exists,
     * which is useful for clients served from the webserver of an NDT server.
     *
     * @param {Object} config - An associative array of configuration options.
     * @param {Object} userCallbacks - An associative array of user callbacks.
     *
     * It uses the callback functions `error`, `serverDiscovery`, and
     * `serverChosen`.
     *
     * @name ndt7.discoverServerURLS
     * @public
     */
    async function discoverServerURLs(config, userCallbacks) {
      const callbacks = {
        error: cb('error', userCallbacks, defaultErrCallback),
        serverDiscovery: cb('serverDiscovery', userCallbacks),
        serverChosen: cb('serverChosen', userCallbacks),
      };
      let protocol = 'wss';
      if (config && ('protocol' in config)) {
        protocol = config.protocol;
      }

      // If a server was specified, use it.
      if (config && ('server' in config)) {
        return {
          '///ndt/v7/download': protocol + '://' + config.server + '/ndt/v7/download',
          '///ndt/v7/upload': protocol + '://' + config.server + '/ndt/v7/upload',
        };
      }

      // If no server was specified then use a loadbalancer. If no loadbalancer
      // is specified, use the locate service from Measurement Lab.
      const lbURL = (config && ('loadbalancer' in config)) ? config.loadbalancer : new URL('https://locate.measurementlab.net/v2/nearest/ndt/ndt7');
      callbacks.serverDiscovery({loadbalancer: lbURL});
      const response = await fetch(lbURL).catch((err) => {
        throw new Error(err);
      });
      const js = await response.json();
      if (! ('results' in js) ) {
        callbacks.error(`Could not understand response from ${lbURL}: ${js}`);
        return {};
      }

      // TODO: do not discard unused results. If the first server is unavailable
      // the client should quickly try the next server.
      //
      // Choose the first result sent by the load balancer. This ensures that
      // in cases where we have a single pod in a metro, that pod is used to
      // run the measurement. When there are multiple pods in the same metro,
      // they are randomized by the load balancer already.
      const choice = js.results[0];
      callbacks.serverChosen(choice);

      return {
        '///ndt/v7/download': choice.urls[protocol + ':///ndt/v7/download'],
        '///ndt/v7/upload': choice.urls[protocol + ':///ndt/v7/upload'],
      };
    }

    /*
     * runNDT7Worker is a helper function that runs a webworker. It uses the
     * callback functions `error`, `start`, `measurement`, and `complete`. It
     * returns a c-style return code. 0 is success, non-zero is some kind of
     * failure.
     *
     * @private
     */
    const runNDT7Worker = async function(
        config, callbacks, urlPromise, filename, testType) {
      if (config.userAcceptedDataPolicy !== true &&
          config.mlabDataPolicyInapplicable !== true) {
        callbacks.error('The M-Lab data policy is applicable and the user ' +
                        'has not explicitly accepted that data policy.');
        return 1;
      }

      let clientMeasurement;
      let serverMeasurement;

      // Sometimes things like __dirname will exist even in browser environments
      // instead check for well known node.js only environment markers
      if (typeof process !== 'undefined' &&
                 process.versions != null &&
                 process.versions.node != null) {
        filename = __dirname + '/' + filename;
      }

      // This makes the worker. The worker won't actually start until it
      // receives a message.
      const worker = new Worker(filename);

      // When the workerPromise gets resolved it will terminate the worker.
      // Workers are resolved with c-style return codes. 0 for success,
      // non-zero for failure.
      const workerPromise = new Promise((resolve) => {
        worker.resolve = function(returnCode) {
          console.log('Worker terminated with code', returnCode);
          if (returnCode == 0) {
            callbacks.complete({
              LastClientMeasurement: clientMeasurement,
              LastServerMeasurement: serverMeasurement,
            });
          }
          worker.terminate();
          resolve(returnCode);
        };
      });

      // If the worker takes 10 seconds, kill it and return an error code.
      // Most clients take longer than 10 seconds to complete the upload and
      // finish sending the buffer's content, sometimes hitting the socket's
      // timeout of 15 seconds. This makes sure uploads terminate on time.
      const workerTimeout = setTimeout(() => worker.resolve(0), 10000);

      // This is how the worker communicates back to the main thread of
      // execution.  The MsgTpe of `ev` determines which callback the message
      // gets forwarded to.
      worker.onmessage = function(ev) {
        if (!ev.data || !ev.data.MsgType || ev.data.MsgType === 'error') {
          clearTimeout(workerTimeout);
          worker.resolve(1);
          const msg = (!ev.data) ? `${testType} error` : ev.data.Error;
          callbacks.error(msg);
        } else if (ev.data.MsgType === 'start') {
          callbacks.start(ev.data.Data);
        } else if (ev.data.MsgType == 'measurement') {
          // For performance reasons, we parse the JSON outside of the thread
          // doing the downloading or uploading.
          if (ev.data.Source == 'server') {
            serverMeasurement = JSON.parse(ev.data.ServerMessage);
            callbacks.measurement({
              Source: ev.data.Source,
              Data: serverMeasurement,
            });
          } else {
            clientMeasurement = ev.data.ClientData;
            callbacks.measurement({
              Source: ev.data.Source,
              Data: ev.data.ClientData,
            });
          }
        } else if (ev.data.MsgType == 'complete') {
          clearTimeout(workerTimeout);
          worker.resolve(0);
        }
      };

      // We can't start the worker until we know the right server, so we wait
      // here to find that out.
      const urls = await urlPromise.catch((err) => {
        clearTimeout(workerTimeout);
        worker.resolve(2);
        throw new Error(err);
      });

      // Start the worker.
      worker.postMessage(urls);

      // Await the resolution of the workerPromise.
      return await workerPromise;

      // Liveness guarantee - once the promise is resolved, .terminate() has
      // been called and the webworker will be terminated or in the process of
      // being terminated.
    };

    /**
     * downloadTest runs just the NDT7 download test.
     * @param {Object} config - An associative array of configuration strings
     * @param {Object} userCallbacks
     * @param {Object} urlPromise - A promise that will resolve to urls.
     *
     * @return {number} Zero on success, and non-zero error code on failure.
     *
     * @name ndt7.downloadTest
     * @public
     */
    async function downloadTest(config, userCallbacks, urlPromise) {
      const callbacks = {
        error: cb('error', userCallbacks, defaultErrCallback),
        start: cb('downloadStart', userCallbacks),
        measurement: cb('downloadMeasurement', userCallbacks),
        complete: cb('downloadComplete', userCallbacks),
      };
      const workerfile = config.downloadworkerfile || 'ndt7-download-worker.js';
      return await runNDT7Worker(
          config, callbacks, urlPromise, workerfile, 'download');
    }

    /**
     * uploadTest runs just the NDT7 download test.
     * @param {Object} config - An associative array of configuration strings
     * @param {Object} userCallbacks
     * @param {Object} urlPromise - A promise that will resolve to urls.
     *
     * @return {number} Zero on success, and non-zero error code on failure.
     *
     * @name ndt7.uploadTest
     * @public
     */
    async function uploadTest(config, userCallbacks, urlPromise) {
      const callbacks = {
        error: cb('error', userCallbacks, defaultErrCallback),
        start: cb('uploadStart', userCallbacks),
        measurement: cb('uploadMeasurement', userCallbacks),
        complete: cb('uploadComplete', userCallbacks),
      };
      const workerfile = config.uploadworkerfile || 'ndt7-upload-worker.js';
      const rv = await runNDT7Worker(
          config, callbacks, urlPromise, workerfile, 'upload');
      return rv << 4;
    }

    /**
     * test discovers a server to run against and then runs a download test
     * followed by an upload test.
     *
     * @param {Object} config - An associative array of configuration strings
     * @param {Object} userCallbacks
     *
     * @return {number} Zero on success, and non-zero error code on failure.
     *
     * @name ndt7.test
     * @public
     */
    async function test(config, userCallbacks) {
      // Starts the asynchronous process of server discovery, allowing other
      // stuff to proceed in the background.
      const urlPromise = discoverServerURLs(config, userCallbacks);
      const downloadSuccess = await downloadTest(
          config, userCallbacks, urlPromise);
      const uploadSuccess = await uploadTest(
          config, userCallbacks, urlPromise);
      return downloadSuccess + uploadSuccess;
    }

    return {
      discoverServerURLs: discoverServerURLs,
      downloadTest: downloadTest,
      uploadTest: uploadTest,
      test: test,
    };
  })();

  // Modules are used by `require`, if this file is included on a web page, then
  // module will be undefined and we use the window.ndt7 piece.
  if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
    module.exports = ndt7;
  } else {
    window.ndt7 = ndt7;
  }
})();
<|endoftext|>


<commit_before>import chai from 'chai';
import chaiJsonSchema from 'chai-json-schema';
import schemas from 'jsfile-schemas';
import JsFile from 'JsFile';
import EpubEngine from './../../src/index';

chai.use(chaiJsonSchema);
const assert = chai.assert;

describe('jsFile-epub', () => {
    let files;
    const documentSchema = schemas.document;

    before(() => {
        files = window.files;
    });

    it('should exist', () => {
        assert.isFunction(EpubEngine);
    });

    it('should have files for testing', () => {
        assert.notEqual(Object.keys(files || {}).length, 0);
    });

    it('should read the file', function () {
        this.timeout(15000);
        const queue = [];
        let name;
        for (name in files) {
            if (files.hasOwnProperty(name)) {
                const jf = new JsFile(files[name], {
                    workerPath: '/base/dist/workers/'
                });
                const promise = jf.read().then(done, done);
                queue.push(promise);

                function done (result) {
                    assert.instanceOf(result, JsFile.Document, name);
                    const json = result.json();
                    const html = result.html();
                    const text = html.textContent || '';
                    assert.jsonSchema(json.content, documentSchema, name);
                    assert.notEqual(text.length, 0, 'File ' + name + ' shouldn\'t be empty');
                    assert.notEqual(result.name.length, 0, 'Engine should parse a name of file ' + name);
                }
            }
        }

        return Promise.all(queue);
    });
});
<commit_msg>Update index.spec.js<commit_after>import chai from 'chai';
import chaiJsonSchema from 'chai-json-schema';
import schemas from 'jsfile-schemas';
import JsFile from 'JsFile';
import EpubEngine from './../../src/index';

chai.use(chaiJsonSchema);
const assert = chai.assert;

describe('jsFile-epub', () => {
    let files;
    const documentSchema = schemas.document;

    before(() => {
        files = window.files;
    });

    it('should exist', () => {
        assert.isFunction(EpubEngine);
    });

    it('should have files for testing', () => {
        assert.notEqual(Object.keys(files || {}).length, 0);
    });

    it('should read the file', function () {
        this.timeout(15000);
        const queue = [];
        let name;
        for (name in files) {
            if (files.hasOwnProperty(name)) {
                const jf = new JsFile(files[name], {
                    workerPath: '/base/dist/workers/'
                });
                const promise = jf.read().then(done, done);
                queue.push(promise);

                function done (result) {
                    assert.instanceOf(result, JsFile.Document, name);
                    const json = result.json();
                    const html = result.html();
                    const text = html.textContent || '';
                    assert.jsonSchema(json, documentSchema, name);
                    assert.notEqual(text.length, 0, 'File ' + name + ' shouldn\'t be empty');
                    assert.notEqual(result.name.length, 0, 'Engine should parse a name of file ' + name);
                }
            }
        }

        return Promise.all(queue);
    });
});
<|endoftext|>


<commit_before>(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        define([], factory);
    } else if (typeof exports === "object") {
        module.exports = factory();
    } else {
        root.RiverEvent = factory();
    }
}(this, function (context) {
    'use strict';

    var RiverEvent = function(event) {
        this.event = event;
        return this;
    }

    RiverEvent.prototype.formatTitle = function() {
        return this.event.payload.actionTags.join(' ');
    };

    RiverEvent.prototype.formatTime = function() {
        var datetime = moment.utc(this.event.payload.eventDateTime);
        return datetime.hour() + "." + datetime.minute();
    };

    RiverEvent.prototype.formatProperties = function() {
        var self = this;
        return Object.keys(self.event.payload.properties).map(function(key) {
            return {
                name: key,
                value: self.event.payload.properties[key]
            };
        });
    };

    return RiverEvent;
}));
<commit_msg>Timeline: fix time format in event details<commit_after>(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        define([], factory);
    } else if (typeof exports === "object") {
        module.exports = factory();
    } else {
        root.RiverEvent = factory();
    }
}(this, function (context) {
    'use strict';

    var RiverEvent = function(event) {
        this.event = event;
        return this;
    }

    RiverEvent.prototype.formatTitle = function() {
        return this.event.payload.actionTags.join(' ');
    };

    RiverEvent.prototype.formatTime = function() {
        var zeroPad = function(num, width) {
            var an = Math.abs(num);
            var digitCount = 1;
            if (an !== 0) {
                digitCount = 1 + Math.floor(Math.log(an) / Math.LN10);
            }
            if (digitCount >= width) {
                return num;
            }
            var zeroString = Math.pow(10, width - digitCount).toString().substr(1);
            return num < 0 ? '-' + zeroString + an : zeroString + an;
        }
        var datetime = moment.utc(this.event.payload.eventDateTime);
        var localDateTime = datetime._d;
        return zeroPad(localDateTime.getHours(), 2) + "." + zeroPad(localDateTime.getMinutes(), 2);
    };

    RiverEvent.prototype.formatProperties = function() {
        var self = this;
        return Object.keys(self.event.payload.properties).map(function(key) {
            return {
                name: key,
                value: self.event.payload.properties[key]
            };
        });
    };

    return RiverEvent;
}));
<|endoftext|>


<commit_before>/** @jsx jsx */

import React, { useEffect, useRef, useState } from 'react'; // eslint-disable-line no-unused-vars
import { jsx, Global } from '@emotion/core';
import { borderRadius, colors, globalStyles, gridSize } from '@arch-ui/theme';
import throttle from 'lodash.throttle';

import { Container, Footer, Header, Sidebar, Search } from '../components';
import { media } from '../utils/media';

const SIDEBAR_WIDTH = 260;

const Layout = ({ children }) => {
  const headerRef = useRef(null);
  const [isVisible, setVisible] = useState(false);
  const toggleMenu = bool => () => setVisible(bool);

  return (
    <>
      <Global
        styles={{
          ...globalStyles,

          [media.sm]: {
            body: { fontSize: 'inherit' },
            html: { fontSize: 14 },
          },
          [media.lg]: {
            body: { fontSize: 'inherit' },
            html: { fontSize: 16 },
          },
        }}
      />

      <Container>

            <Search />
            <Sidebar />

          {children}

      </Container>
    </>
  );
};

// ==============================
// Styled Components
// ==============================

const gutter = gridSize * 4;

let oldScrollTop = 0;

const Aside = ({ offsetTarget, isVisible, ...props }) => {
  const asideRef = useRef();
  const [isStuck, setSticky] = useState(Boolean(offsetTarget));
  const offsetTop = offsetTarget.current ? offsetTarget.current.offsetHeight : 0;

  const handleWindowScroll = () => {
    if (window.pageYOffset > offsetTop && !isStuck) {
      setSticky(true);
    }
    if (window.pageYOffset <= offsetTop && isStuck) {
      setSticky(false);
    }
  };

  const maintainSidebarScroll = throttle(() => {
    oldScrollTop = asideRef.current.scrollTop;
  });

  useEffect(() => {
    handleWindowScroll();
    window.addEventListener('scroll', handleWindowScroll);
    asideRef.current.addEventListener('scroll', maintainSidebarScroll);

    // keep the user's scroll whilst navigating between pages
    asideRef.current.scrollTo(0, oldScrollTop);

    // cleanup
    return () => {
      window.removeEventListener('scroll', handleWindowScroll);
      asideRef.current.removeEventListener('scroll', maintainSidebarScroll);
    };
  });

  const stickyStyles = {
    height: isStuck ? '100%' : `calc(100% - ${offsetTop}px)`,
    position: isStuck ? 'fixed' : 'absolute',
    width: SIDEBAR_WIDTH,
    top: isStuck ? 0 : offsetTop,
  };

  return (
    <aside
      ref={asideRef}
      css={{
        // borderRight: `1px solid ${colors.N10}`,
        boxSizing: 'border-box',
        overflowY: 'auto',
        paddingBottom: gutter,
        paddingTop: gutter,
        paddingLeft: 3, // NOTE: the 3px is to stop the select's shadows being cropped

        [media.sm]: {
          display: isVisible ? 'block' : 'none',
        },
        [media.lg]: {
          paddingRight: gutter,
          ...stickyStyles,
        },
      }}
      {...props}
    />
  );
};
const Main = props => (
  <main
    css={{
      flex: 1,
      lineHeight: '1.6',
      minWidth: 0,
      paddingBottom: gutter * 2,
      paddingTop: gutter,

      [media.lg]: {
        marginLeft: SIDEBAR_WIDTH,
        paddingLeft: gutter,
      },

      // Tables
      // ------------------------------

      table: {
        borderCollapse: 'collapse',
        borderSpacing: 0,
        fontSize: '0.9rem',
        width: '100%',
      },
      'th, td': {
        paddingBottom: gridSize,
        paddingTop: gridSize,
        textAlign: 'left',

        '&[align="right"]': {
          textAlign: 'right',
        },
      },
      th: {
        borderBottom: `2px solid ${colors.N10}`,
        fontWeight: 500,
      },
      td: {
        borderTop: `1px solid ${colors.N10}`,
      },

      // TODO: doesn't play nice with "gatsby-resp-image-wrapper"
      img: {
        backgroundColor: 'white',
        borderRadius,
        boxSizing: 'border-box',
        boxShadow: '0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 11px hsla(0, 0%, 0%, 0.1) !important',
        maxWidth: '100%',
        padding: 4,
      },

      // Misc. Typography
      // ------------------------------

      a: {
        borderBottom: `1px solid ${colors.B.A40}`,
        color: colors.N100,
        textDecoration: 'none',

        ':hover, :focus': {
          backgroundColor: colors.B.A10,
          borderBottomColor: 'currentColor',
          textDecoration: 'none',
        },
      },

      // NOTE: consider removing `gatsby-remark-images`
      '.gatsby-resp-image-link, .gatsby-resp-image-link:hover, .gatsby-resp-image-link:focus': {
        background: 0,
        border: 0,
      },
      ul: {
        lineHeight: 1.8,
      },
      'ul > li > ul, ol > li > ol, ul > li > ol, ol > li > ul': {
        paddingLeft: '1.33rem',
      },
      blockquote: {
        fontSize: '1.25rem',
        fontStyle: 'italic',
        color: colors.N60,
        margin: `3rem 0`,
        padding: 0,
        paddingLeft: '3rem',
        position: 'relative',
      },

      // Code
      // ------------------------------

      code: {
        fontFamily: 'Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace',
        fontSize: '0.85em',
      },
      pre: {
        backgroundColor: 'rgba(9, 30, 66, 0.03)',
        boxShadow: '-4px 0 0 rgba(9, 30, 66, 0.09)',
        boxSizing: 'border-box',
        fontFamily: 'Consolas,Menlo,Monaco,"Andale Mono","Ubuntu Mono",monospace',
        lineHeight: '1.4',
        padding: gridSize * 2,
        overflowX: 'auto',
        tabSize: 2,
        width: '100%',
        WebkitOverflowScrolling: 'touch',

        '.token-line:last-of-type': {
          display: 'none', // our snippets seem to have an extra line...
        },
      },

      '& :not(pre) > code': {
        backgroundColor: 'rgba(255, 227, 128,0.2)',
        borderRadius: 2,
        color: colors.N100,
        margin: 0,
        padding: '0.2em 0.4em',

        [media.sm]: {
          wordBreak: 'break-word',
        },
      },
    }}
    {...props}
  />
);

export default Layout;
<commit_msg>code in headings is hard...<commit_after>/** @jsx jsx */

import React, { useEffect, useRef, useState } from 'react'; // eslint-disable-line no-unused-vars
import { jsx, Global } from '@emotion/core';
import { borderRadius, colors, globalStyles, gridSize } from '@arch-ui/theme';
import throttle from 'lodash.throttle';

import { Container, Footer, Header, Sidebar, Search } from '../components';
import { media } from '../utils/media';

const SIDEBAR_WIDTH = 260;

const Layout = ({ children }) => {
  const headerRef = useRef(null);
  const [isVisible, setVisible] = useState(false);
  const toggleMenu = bool => () => setVisible(bool);

  return (
    <>
      <Global
        styles={{
          ...globalStyles,

          [media.sm]: {
            body: { fontSize: 'inherit' },
            html: { fontSize: 14 },
          },
          [media.lg]: {
            body: { fontSize: 'inherit' },
            html: { fontSize: 16 },
          },
        }}
      />

      <Container>

            <Search />
            <Sidebar />

          {children}

      </Container>
    </>
  );
};

// ==============================
// Styled Components
// ==============================

const gutter = gridSize * 4;

let oldScrollTop = 0;

const Aside = ({ offsetTarget, isVisible, ...props }) => {
  const asideRef = useRef();
  const [isStuck, setSticky] = useState(Boolean(offsetTarget));
  const offsetTop = offsetTarget.current ? offsetTarget.current.offsetHeight : 0;

  const handleWindowScroll = () => {
    if (window.pageYOffset > offsetTop && !isStuck) {
      setSticky(true);
    }
    if (window.pageYOffset <= offsetTop && isStuck) {
      setSticky(false);
    }
  };

  const maintainSidebarScroll = throttle(() => {
    oldScrollTop = asideRef.current.scrollTop;
  });

  useEffect(() => {
    handleWindowScroll();
    window.addEventListener('scroll', handleWindowScroll);
    asideRef.current.addEventListener('scroll', maintainSidebarScroll);

    // keep the user's scroll whilst navigating between pages
    asideRef.current.scrollTo(0, oldScrollTop);

    // cleanup
    return () => {
      window.removeEventListener('scroll', handleWindowScroll);
      asideRef.current.removeEventListener('scroll', maintainSidebarScroll);
    };
  });

  const stickyStyles = {
    height: isStuck ? '100%' : `calc(100% - ${offsetTop}px)`,
    position: isStuck ? 'fixed' : 'absolute',
    width: SIDEBAR_WIDTH,
    top: isStuck ? 0 : offsetTop,
  };

  return (
    <aside
      ref={asideRef}
      css={{
        // borderRight: `1px solid ${colors.N10}`,
        boxSizing: 'border-box',
        overflowY: 'auto',
        paddingBottom: gutter,
        paddingTop: gutter,
        paddingLeft: 3, // NOTE: the 3px is to stop the select's shadows being cropped

        [media.sm]: {
          display: isVisible ? 'block' : 'none',
        },
        [media.lg]: {
          paddingRight: gutter,
          ...stickyStyles,
        },
      }}
      {...props}
    />
  );
};
const Main = props => (
  <main
    css={{
      flex: 1,
      lineHeight: '1.6',
      minWidth: 0,
      paddingBottom: gutter * 2,
      paddingTop: gutter,

      [media.lg]: {
        marginLeft: SIDEBAR_WIDTH,
        paddingLeft: gutter,
      },

      // Tables
      // ------------------------------

      table: {
        borderCollapse: 'collapse',
        borderSpacing: 0,
        fontSize: '0.9rem',
        width: '100%',
      },
      'th, td': {
        paddingBottom: gridSize,
        paddingTop: gridSize,
        textAlign: 'left',

        '&[align="right"]': {
          textAlign: 'right',
        },
      },
      th: {
        borderBottom: `2px solid ${colors.N10}`,
        fontWeight: 500,
      },
      td: {
        borderTop: `1px solid ${colors.N10}`,
      },

      // TODO: doesn't play nice with "gatsby-resp-image-wrapper"
      img: {
        backgroundColor: 'white',
        borderRadius,
        boxSizing: 'border-box',
        boxShadow: '0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 11px hsla(0, 0%, 0%, 0.1) !important',
        maxWidth: '100%',
        padding: 4,
      },

      // Misc. Typography
      // ------------------------------

      a: {
        borderBottom: `1px solid ${colors.B.A40}`,
        color: colors.N100,
        textDecoration: 'none',

        ':hover, :focus': {
          backgroundColor: colors.B.A10,
          borderBottomColor: 'currentColor',
          textDecoration: 'none',
        },
      },

      // NOTE: consider removing `gatsby-remark-images`
      '.gatsby-resp-image-link, .gatsby-resp-image-link:hover, .gatsby-resp-image-link:focus': {
        background: 0,
        border: 0,
      },
      ul: {
        lineHeight: 1.8,
      },
      'ul > li > ul, ol > li > ol, ul > li > ol, ol > li > ul': {
        paddingLeft: '1.33rem',
      },
      blockquote: {
        fontSize: '1.25rem',
        fontStyle: 'italic',
        color: colors.N60,
        margin: `3rem 0`,
        padding: 0,
        paddingLeft: '3rem',
        position: 'relative',
      },

      // Code
      // ------------------------------

      code: {
        fontFamily: 'Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace',
        fontSize: '0.85em',
        fontWeight: 'normal',
      },
      pre: {
        backgroundColor: 'rgba(9, 30, 66, 0.03)',
        boxShadow: '-4px 0 0 rgba(9, 30, 66, 0.09)',
        boxSizing: 'border-box',
        fontFamily: 'Consolas,Menlo,Monaco,"Andale Mono","Ubuntu Mono",monospace',
        lineHeight: '1.4',
        padding: gridSize * 2,
        overflowX: 'auto',
        tabSize: 2,
        width: '100%',
        WebkitOverflowScrolling: 'touch',

        '.token-line:last-of-type': {
          display: 'none', // our snippets seem to have an extra line...
        },
      },

      '& :not(pre) > code': {
        backgroundColor: 'rgba(255, 227, 128,0.2)',
        borderRadius: 2,
        color: colors.N100,
        margin: 0,
        padding: '0.2em 0.4em',

        [media.sm]: {
          wordBreak: 'break-word',
        },
      },

      '& h1 > code, & h2 > code, & h3 > code, & h4 > code, & h5 > code, & h6 > code': {
        backgroundColor: 'rgba(255, 235, 229, 0.6)',
      },
    }}
    {...props}
  />
);

export default Layout;
<|endoftext|>


<commit_before>enyo.kind({
	name: "enyo.XmlpRequest",
	kind: enyo.JsonpRequest,
	published: {
		detailedErrors:true 	//if true, on a query failure, it will re-query the xml url/params
					//to get plain the plain-text content and return that in the format
					// of {"error":"unescaped-plain-text-content"}
	},
	callbackName: "callback",
	go: function(inParams) {
		var parts = this.url.split("?");
		var uri = parts.shift() || "";
		var args = parts.join("?").split("&");
		args.push(enyo.Ajax.objectToQuery(inParams || {}));
		this.xmlUrl = [uri, args.join("&")].join("?");
		this.url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%3D'"
				+ encodeURIComponent(this.xmlUrl) + "'&format=json";
		inParams = {};
		this.inherited(arguments);
	},
	respond: function(inValue) {
		if(inValue && inValue.query) {
			inValue = inValue.query.results || undefined;
			if(!inValue && this.detailedErrors) {
				var fallbackUrl = "http://query.yahooapis.com/v1/public/yql?q=use%20%22http"
						+ "%3A%2F%2Fwww.datatables.org%2Fdata%2Fhtmlstring.xml%22%20"
						+ "as%20htmlstring%3B%20select%20*%20from%20htmlstring%20where"
						+ "%20url%3D'"+ encodeURIComponent(this.xmlUrl) + "'&format=json";
				this.fallbackTextRequest = new enyo.JsonpRequest({url:fallbackUrl,
						callbackName:"callback"});
				this.fallbackTextRequest.response(this, "fallbackTextCallback");
				this.fallbackTextRequest.go();
				return;
			}
		}
		this.inherited(arguments);
	},
	fallbackTextCallback: function(inSender, inResponse) {
		if(inResponse && inResponse.query) {
			inResponse = inResponse.query.results || undefined;
			if(inResponse && inResponse.result) {
				inResponse = inResponse.result;
				if(inResponse.indexOf("HTML Tidy for Java")>-1) {
					// plain text is within auto-generated html, so extract it
					var text = inResponse.substring(inResponse.indexOf("
")+3,
							inResponse.lastIndexOf("
"));
					inResponse = {"error":text};

				} else {
					inResponse = {"error":inResponse};
				}
			} else if(inResponse && !inResponse.result) {
				inResponse = {"error":"Unknown XML query failure"};
			}
		}
		this.respond(inResponse);
	}
});<commit_msg>Improved error handling<commit_after>enyo.kind({
	name: "enyo.XmlpRequest",
	kind: enyo.JsonpRequest,
	published: {
		detailedErrors:true 	//if true, on a query failure, it will re-query the xml url/params
					//to get the plain-text content and return that in the format
					// of {"error":"unescaped-plain-text-content"}
	},
	callbackName: "callback",
	go: function(inParams) {
		var parts = this.url.split("?");
		var uri = parts.shift() || "";
		var args = parts.join("?").split("&");
		args.push(enyo.Ajax.objectToQuery(inParams || {}));
		this.xmlUrl = [uri, args.join("&")].join("?");
		this.url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%3D'"
				+ encodeURIComponent(this.xmlUrl) + "'&format=json";
		inParams = {};
		this.inherited(arguments);
	},
	respond: function(inValue) {
		if(inValue && inValue.query) {
			inValue = inValue.query.results || undefined;
			if(!inValue && this.detailedErrors) {
				var fallbackUrl = "http://query.yahooapis.com/v1/public/yql?q=use%20%22http"
						+ "%3A%2F%2Fwww.datatables.org%2Fdata%2Fhtmlstring.xml%22%20"
						+ "as%20htmlstring%3B%20select%20*%20from%20htmlstring%20where"
						+ "%20url%3D'"+ encodeURIComponent(this.xmlUrl) + "'&format=json";
				this.fallbackTextRequest = new enyo.JsonpRequest({url:fallbackUrl,
						callbackName:"callback"});
				this.fallbackTextRequest.response(this, "fallbackTextCallback");
				this.fallbackTextRequest.go();
				return;
			}
		}
		this.inherited(arguments);
	},
	fallbackTextCallback: function(inSender, inResponse) {
		if(inResponse && inResponse.query) {
			inResponse = inResponse.query.results || undefined;
			if(inResponse && inResponse.result) {
				inResponse = inResponse.result;
				if(inResponse.indexOf("HTML Tidy for Java")>-1) {
					// plain text is within auto-generated html, so extract it
					var text = inResponse.substring(inResponse.indexOf("
")+3,
							inResponse.lastIndexOf("
"));
					inResponse = {"error":text};

				} else {
					inResponse = {"error":"Query is not in XML format"};
				}
			} else if(inResponse && !inResponse.result) {
				inResponse = {"error":"Unknown XML query failure"};
			} else if(!inResponse) {
				inResponse = {"error":"Unable to connect to server"};
			}
		}
		this.respond(inResponse);
	}
});<|endoftext|>


<commit_before>'use strict';
const expect = require('chai').expect;
const assert = require('assert');
const httpMocks = require('node-mocks-http');
const utils = require('../../lib/utils');

describe('Testing Utils', function() {
  // mock res
  let res, next, method;

  let response = {
    success: {
      status: 200,
      success: true,
      message: 'ACCESS GRANTED'
    },
    restricted: {
      status: 'Access denied',
      success: false,
      message: 'Unauthorized access'
    }
  };

  let methods = ['GET', 'PUT', 'DELETE'];

  beforeEach(function(done) {
    res = httpMocks.createResponse();

    next = function() {
      res.send(response.success);
    };

    done();
  });

  describe('Validating Utils', function() {

    it('All the function should be defined', function() {
      assert(utils, true);
      assert(utils.deny, true);
      assert(utils.whenGlobAndActionDeny, true);
      assert(utils.whenGlobAndActionAllow, true);
      assert(utils.whenResourceAndMethodGlob, true);
      assert(utils.whenIsArrayMethod, true);
    });

    it('They should be functions', function() {
      expect(utils.deny).to.be.a('function');
      expect(utils.whenGlobAndActionDeny).to.be.a('function');
      expect(utils.whenGlobAndActionAllow).to.be.a('function');
      expect(utils.whenResourceAndMethodGlob).to.be.a('function');
      expect(utils.whenIsArrayMethod).to.be.a('function');
    });

  });

  describe('Utils.deny', function() {

    it('should return default message when called with status', function() {
      utils.deny(res, 403);
      let data = res._getData();
      assert(data, true);
      expect(data).to.be.an('object');
      assert.deepEqual(data, response.restricted);
    });

    it('Should return custom message when called with message', function() {
      utils.deny(res, 450, 'Role not found');
      let data = res._getData();
      assert(data, true);
      expect(data).to.be.an('object');
      assert.deepEqual(data, {
        status: 'Access denied',
        success: false,
        message: 'Role not found'
      });
    });

    it('should return custom error when called with custom error messages', function() {
      let customErrorResponse = {
        status: 'Access Denied',
        message: 'You are not authorized to access this resource'
      };

      utils.deny(res, 403, null, customErrorResponse);
      let data = res._getData();
      assert(data);
      expect(data).to.be.an('object');
      expect(res.statusCode).to.equal(403);
      assert.deepEqual(data, customErrorResponse);
    });

  });

  describe('Utils.whenGlobAndActionAllow', function() {
    context('When the Methods are a string', function() {

      it('should call next when method is string and *', function() {
        utils.whenGlobAndActionAllow(res, next, null, '*');
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);
      });

    });

    context('When the methods are an Array', function() {

      it('Should call next if methods is Array and method exist', function() {
        let method = 'GET';
        utils.whenGlobAndActionAllow(res, next, method, methods, null);
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);

      });

      it('Should return deny response if method does not exist', function() {
        let method = 'PATCH';
        utils.whenGlobAndActionAllow(res, next, method, methods, null);
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);
      });

    });
  });

  describe('Utils.whenGlobAndActionDeny', function() {

    context('When the Methods are a string', function() {

      it('Should return deny response when called with *', function() {
        utils.whenGlobAndActionDeny(res, null, null, '*', null);
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);
      });

    });

    context('When the methods are an Array', function() {
      it('Should call next if methods is Array and method exist', function() {
        method = 'GET';
        utils.whenGlobAndActionDeny(res, next, method, methods, null);
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);

      });

      it('Should return deny response if method does not exist', function() {
        method = 'PATCH';
        utils.whenGlobAndActionDeny(res, next, method, methods, null);
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);
      });
    });

  });

  describe('Utils.whenResourceAndMethodGlob', function() {

    it('Should return next if action allow', function() {
      utils.whenResourceAndMethodGlob(res, next, 'allow', '*');
      let data = res._getData();
      assert(data, true);
      expect(data).to.be.an('object');
      assert.deepEqual(data, response.success);
    });

    it('Should return deny response when action deny', function() {
      utils.whenResourceAndMethodGlob(res, next, 'deny', '*', null);
      let data = res._getData();
      assert(data, true);
      expect(data).to.be.an('object');
      assert.deepEqual(data, response.restricted);
    });

  });

  describe('Utils.whenIsArrayMethod', function() {
    context('When action allow', function() {

      it('Should call next if method exist', function() {
        utils.whenIsArrayMethod(res, next, 'allow', 'GET', methods, null);
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);
      });

      it('Should return deny response if method doesn\'t exist', function() {
        utils.whenIsArrayMethod(res, next, 'allow', 'PATCH', methods, null);
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);
      });

    });

    context('When action deny', function() {

      it('Should return deny response if method exist', function() {
        utils.whenIsArrayMethod(res, next, 'deny', 'GET', methods, null);
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);
      });

      it('Should call next if method doesn\'t exist', function() {
        utils.whenIsArrayMethod(res, next, 'deny', 'PATCH', methods, null);
        let data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);
      });
    });
  });

  describe('Check properties', function() {
    context('When valid rules are passed', function() {
      it('Should assert core properties and return the rules', function() {
        let mockRule = [{
          group: 'user',
          permissions: [{
            resource: 'users',
            methods: [
              'POST',
              'GET',
              'PUT'
            ],
            action: 'deny'
          }]
        }];
        let rules = utils.checkProperties(mockRule);
        let permissions = rules.get('user');
        expect(typeof rules).to.equal('object');
        expect(permissions).to.be.instanceof(Array);
        expect(permissions).to.equal(mockRule[0].permissions);
      });
    });

    context('When invalid methods are passed', function() {
      it('Should assert core properties and return the rules', function() {
        let mockRule = [{
          group: 'user',
          permissions: [{
            resource: 'users',
            methods: {},
            action: 'deny'
          }]
        }];
        try {
          utils.checkProperties(mockRule);
        } catch (error) {
          expect(error.message).to.equal(
            'TypeError: Methods should be a array or string'
          );
        }
      });
    });

    context('When invalid Glob are passed', function() {
      it('Should assert core properties and return the rules', function() {
        let mockRule = [{
          group: 'user',
          permissions: [{
            resource: 'users',
            methods: '&',
            action: 'deny'
          }]
        }];
        try {
          utils.checkProperties(mockRule);
        } catch (error) {
          expect(error.message).to.equal(
            'DefinitionError: Unrecognised glob "&" , use "*" instead'
          );
        }
      });
    });

    context('When invalid action is passed ', function() {
      it('Should assert core properties and return the rules', function() {
        let mockRule = [{
          group: 'user',
          permissions: [{
            resource: 'users',
            methods: '*',
            action: 'what'
          }]
        }];
        try {
          utils.checkProperties(mockRule);
        } catch (error) {
          expect(error.message).to.equal(
            'TypeError: action should be either "deny" or "allow"'
          );
        }
      });
    });
  });

  describe('Validate', function() {
    let rules;

    it('Should return rules once validated', function() {
      let mockRule = [{
        group: 'user',
        permissions: [{
          resource: 'users',
          methods: [
            'POST',
            'GET',
            'PUT'
          ],
          action: 'deny'
        }]
      }];

      rules = utils.validate(mockRule);
      let permissions = rules.get('user');
      expect(typeof rules).to.equal('object');
      expect(permissions).to.be.instanceof(Array);
      expect(permissions).to.equal(mockRule[0].permissions);
    });

    it('Should throw an error when rules is not an array', function() {
      let mockRule = {
        group: 'user'
      };
      try {
        utils.validate(mockRule);
      } catch (error) {
        expect(utils.validate).to.throw(Error);
      }
    });

    it('Should return a message when rules is empty', function() {
      let mockRule = [];
      let message = '\u001b[33mPolicy not set, ' +
        'All traffic will be denied\u001b[39m';
      rules = utils.validate(mockRule);
      expect(rules).to.not.be.empty;
      expect(rules).to.equal(message);
    });
  });
});
<commit_msg>chore(clean): clean tests - clean tests codebase<commit_after>'use strict';
const expect = require('chai').expect;
const assert = require('assert');
const httpMocks = require('node-mocks-http');
const utils = require('../../lib/utils');

describe('Testing Utils', function() {
  // mock res
  let res, data, next, method;

  let response = {
    success: {
      status: 200,
      success: true,
      message: 'ACCESS GRANTED'
    },
    restricted: {
      status: 'Access denied',
      success: false,
      message: 'Unauthorized access'
    }
  };

  let methods = ['GET', 'PUT', 'DELETE'];

  beforeEach(function(done) {
    res = httpMocks.createResponse();

    next = function() {
      res.send(response.success);
    };

    done();
  });

  describe('Validating Utils', function() {

    it('All the function should be defined', function() {
      assert(utils, true);
      assert(utils.deny, true);
      assert(utils.whenGlobAndActionDeny, true);
      assert(utils.whenGlobAndActionAllow, true);
      assert(utils.whenResourceAndMethodGlob, true);
      assert(utils.whenIsArrayMethod, true);
    });

    it('They should be functions', function() {
      expect(utils.deny).to.be.a('function');
      expect(utils.whenGlobAndActionDeny).to.be.a('function');
      expect(utils.whenGlobAndActionAllow).to.be.a('function');
      expect(utils.whenResourceAndMethodGlob).to.be.a('function');
      expect(utils.whenIsArrayMethod).to.be.a('function');
    });

  });

  describe('Utils.deny', function() {

    it('should return default message when called with status', function() {
      utils.deny(res, 403);
      data = res._getData();
      assert(data, true);
      expect(data).to.be.an('object');
      assert.deepEqual(data, response.restricted);
    });

    it('Should return custom message when called with message', function() {
      utils.deny(res, 450, 'Role not found');
      data = res._getData();
      assert(data, true);
      expect(data).to.be.an('object');
      assert.deepEqual(data, {
        status: 'Access denied',
        success: false,
        message: 'Role not found'
      });
    });

    it('should return custom error when called with custom error messages', function() {
      let customErrorResponse = {
        status: 'Access Denied',
        message: 'You are not authorized to access this resource'
      };

      utils.deny(res, 403, null, customErrorResponse);
      data = res._getData();
      assert(data);
      expect(data).to.be.an('object');
      expect(res.statusCode).to.equal(403);
      assert.deepEqual(data, customErrorResponse);
    });

  });

  describe('Utils.whenGlobAndActionAllow', function() {
    context('When the Methods are a string', function() {

      it('should call next when method is string and *', function() {
        utils.whenGlobAndActionAllow(res, next, null, '*');
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);
      });

    });

    context('When the methods are an Array', function() {

      it('Should call next if methods is Array and method exist', function() {
        method = 'GET';
        utils.whenGlobAndActionAllow(res, next, method, methods, null);
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);

      });

      it('Should return deny response if method does not exist', function() {
        method = 'PATCH';
        utils.whenGlobAndActionAllow(res, next, method, methods, null);
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);
      });

    });
  });

  describe('Utils.whenGlobAndActionDeny', function() {

    context('When the Methods are a string', function() {

      it('Should return deny response when called with *', function() {
        utils.whenGlobAndActionDeny(res, null, null, '*', null);
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);
      });

    });

    context('When the methods are an Array', function() {
      it('Should call next if methods is Array and method exist', function() {
        method = 'GET';
        utils.whenGlobAndActionDeny(res, next, method, methods, null);
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);

      });

      it('Should return deny response if method does not exist', function() {
        method = 'PATCH';
        utils.whenGlobAndActionDeny(res, next, method, methods, null);
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);
      });
    });

  });

  describe('Utils.whenResourceAndMethodGlob', function() {

    it('Should return next if action allow', function() {
      utils.whenResourceAndMethodGlob(res, next, 'allow', '*');
      data = res._getData();
      assert(data, true);
      expect(data).to.be.an('object');
      assert.deepEqual(data, response.success);
    });

    it('Should return deny response when action deny', function() {
      utils.whenResourceAndMethodGlob(res, next, 'deny', '*', null);
      data = res._getData();
      assert(data, true);
      expect(data).to.be.an('object');
      assert.deepEqual(data, response.restricted);
    });

  });

  describe('Utils.whenIsArrayMethod', function() {
    context('When action allow', function() {

      it('Should call next if method exist', function() {
        utils.whenIsArrayMethod(res, next, 'allow', 'GET', methods, null);
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);
      });

      it('Should return deny response if method doesn\'t exist', function() {
        utils.whenIsArrayMethod(res, next, 'allow', 'PATCH', methods, null);
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);
      });

    });

    context('When action deny', function() {

      it('Should return deny response if method exist', function() {
        utils.whenIsArrayMethod(res, next, 'deny', 'GET', methods, null);
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.restricted);
      });

      it('Should call next if method doesn\'t exist', function() {
        utils.whenIsArrayMethod(res, next, 'deny', 'PATCH', methods, null);
        data = res._getData();
        assert(data, true);
        expect(data).to.be.an('object');
        assert.deepEqual(data, response.success);
      });
    });
  });

  describe('Check properties', function() {
    context('When valid rules are passed', function() {
      it('Should assert core properties and return the rules', function() {
        let mockRule = [{
          group: 'user',
          permissions: [{
            resource: 'users',
            methods: [
              'POST',
              'GET',
              'PUT'
            ],
            action: 'deny'
          }]
        }];
        let rules = utils.checkProperties(mockRule);
        let permissions = rules.get('user');
        expect(typeof rules).to.equal('object');
        expect(permissions).to.be.instanceof(Array);
        expect(permissions).to.equal(mockRule[0].permissions);
      });
    });

    context('When invalid methods are passed', function() {
      it('Should assert core properties and return the rules', function() {
        let mockRule = [{
          group: 'user',
          permissions: [{
            resource: 'users',
            methods: {},
            action: 'deny'
          }]
        }];
        try {
          utils.checkProperties(mockRule);
        } catch (error) {
          expect(error.message).to.equal(
            'TypeError: Methods should be a array or string'
          );
        }
      });
    });

    context('When invalid Glob are passed', function() {
      it('Should assert core properties and return the rules', function() {
        let mockRule = [{
          group: 'user',
          permissions: [{
            resource: 'users',
            methods: '&',
            action: 'deny'
          }]
        }];
        try {
          utils.checkProperties(mockRule);
        } catch (error) {
          expect(error.message).to.equal(
            'DefinitionError: Unrecognised glob "&" , use "*" instead'
          );
        }
      });
    });

    context('When invalid action is passed ', function() {
      it('Should assert core properties and return the rules', function() {
        let mockRule = [{
          group: 'user',
          permissions: [{
            resource: 'users',
            methods: '*',
            action: 'what'
          }]
        }];
        try {
          utils.checkProperties(mockRule);
        } catch (error) {
          expect(error.message).to.equal(
            'TypeError: action should be either "deny" or "allow"'
          );
        }
      });
    });
  });

  describe('Validate', function() {
    let rules;

    it('Should return rules once validated', function() {
      let mockRule = [{
        group: 'user',
        permissions: [{
          resource: 'users',
          methods: [
            'POST',
            'GET',
            'PUT'
          ],
          action: 'deny'
        }]
      }];

      rules = utils.validate(mockRule);
      let permissions = rules.get('user');
      expect(typeof rules).to.equal('object');
      expect(permissions).to.be.instanceof(Array);
      expect(permissions).to.equal(mockRule[0].permissions);
    });

    it('Should throw an error when rules is not an array', function() {
      let mockRule = {
        group: 'user'
      };
      try {
        utils.validate(mockRule);
      } catch (error) {
        expect(utils.validate).to.throw(Error);
      }
    });

    it('Should return a message when rules is empty', function() {
      let mockRule = [];
      let message = '\u001b[33mPolicy not set, ' +
        'All traffic will be denied\u001b[39m';
      rules = utils.validate(mockRule);
      expect(rules).to.not.be.empty;
      expect(rules).to.equal(message);
    });
  });
});
<|endoftext|>


<commit_before>var $ = require('jquery');
var m = require('mithril');
var osfHelpers = require('js/osfHelpers');
var Treebeard = require('treebeard');

function Meeting(data) {
    //  Treebeard version
    var tbOptions = {
        divID: 'grid',
        filesData: data,
        rowHeight : 30,         // user can override or get from .tb-row height
        paginate : false,       // Whether the applet starts with pagination or not.
        paginateToggle : false, // Show the buttons that allow users to switch between scroll and paginate.
        uploads : false,         // Turns dropzone on/off.
        columnTitles : function _conferenceColumnTitles(item, col) {
             return [
                {
                    title: 'Title',
                    width: '50%',
                    sortType : 'text',
                    sort : true
                },
                {
                    title: 'Author',
                    width : '10%',
                    sortType : 'text',
                    sort : true
                },
                {
                    title: 'Category',
                    width : '10%',
                    sortType : 'text',
                    sort : true
                },
                {
                    title: 'Downloads',
                    width : '15%',
                    sortType : 'number',
                    sort : true
                },
                 {
                    title: 'Date Created',
                    width: '15%',
                    sortType: 'date',
                    sort: true
                }
            ];
        },
        resolveRows : function _conferenceResolveRows(item){
            var default_columns = [
                {
                    data : 'title',  // Data field name
                    folderIcons : false,
                    filter : true,
                    sortInclude : true,
                    custom : function() { return m('a', { href : item.data.nodeUrl, target : '_blank' }, item.data.title ); }

                },
                {
                    data : 'author',  // Data field name
                    folderIcons : false,
                    filter : true,
                    sortInclude : true,
                    custom : function() { return m('a', { href : item.data.authorUrl }, item.data.author ); }
                },
                {
                    data : 'category',  // Data field name
                    folderIcons : false,
                    filter : false
                },
                {
                    data : 'download',  // Data field name
                    folderIcons : false,
                    filter : false,
                    custom : function() {
                        if(item.data.downloadUrl){
                            return [ m('a', { href : item.data.downloadUrl }, [
                                m('button.btn.btn-success.btn-xs', { style : 'margin-right : 10px;'},  m('i.fa.fa-download.fa-inverse')),

                            ] ), item.data.download  ];
                        } else {
                            return '';
                        }
                    }

                },
                {
                    data: 'dateCreated', // Data field name
                    sortInclude: true,
                    custom: function() {
                        var dateCreated = new osfHelpers.FormattableDate(item.data.dateCreated);
                        return m('', dateCreated.local);
                    }
                }
            ];
            return default_columns;
        },
        sortButtonSelector : {
            up : 'i.fa.fa-chevron-up',
            down : 'i.fa.fa-chevron-down'
        },
        showFilter : true,     // Gives the option to filter by showing the filter box.
        filterStyle : { 'float' : 'right', 'width' : '50%'},
        allowMove : false,       // Turn moving on or off.
        hoverClass : 'fangorn-hover',
        hiddenFilterRows : ['tags']
    };
    var grid = new Treebeard(tbOptions);
}

module.exports = Meeting;
<commit_msg>Move download to the right most<commit_after>var $ = require('jquery');
var m = require('mithril');
var osfHelpers = require('js/osfHelpers');
var Treebeard = require('treebeard');

function Meeting(data) {
    //  Treebeard version
    var tbOptions = {
        divID: 'grid',
        filesData: data,
        rowHeight : 30,         // user can override or get from .tb-row height
        paginate : false,       // Whether the applet starts with pagination or not.
        paginateToggle : false, // Show the buttons that allow users to switch between scroll and paginate.
        uploads : false,         // Turns dropzone on/off.
        columnTitles : function _conferenceColumnTitles(item, col) {
             return [
                {
                    title: 'Title',
                    width: '50%',
                    sortType : 'text',
                    sort : true
                },
                {
                    title: 'Author',
                    width : '10%',
                    sortType : 'text',
                    sort : true
                },
                {
                    title: 'Category',
                    width : '10%',
                    sortType : 'text',
                    sort : true
                },
                {
                    title: 'Date Created',
                    width: '15%',
                    sortType: 'date',
                    sort: true
                },
                {
                    title: 'Downloads',
                    width : '15%',
                    sortType : 'number',
                    sort : true
                },
            ];
        },
        resolveRows : function _conferenceResolveRows(item){
            var default_columns = [
                {
                    data : 'title',  // Data field name
                    folderIcons : false,
                    filter : true,
                    sortInclude : true,
                    custom : function() { return m('a', { href : item.data.nodeUrl, target : '_blank' }, item.data.title ); }

                },
                {
                    data : 'author',  // Data field name
                    folderIcons : false,
                    filter : true,
                    sortInclude : true,
                    custom : function() { return m('a', { href : item.data.authorUrl }, item.data.author ); }
                },
                {
                    data : 'category',  // Data field name
                    folderIcons : false,
                    filter : false
                },
                {
                    data: 'dateCreated', // Data field name
                    sortInclude: true,
                    custom: function() {
                        var dateCreated = new osfHelpers.FormattableDate(item.data.dateCreated);
                        return m('', dateCreated.local);
                    }
                },
                {
                    data : 'download',  // Data field name
                    folderIcons : false,
                    filter : false,
                    custom : function() {
                        if(item.data.downloadUrl){
                            return [ m('a', { href : item.data.downloadUrl }, [
                                m('button.btn.btn-success.btn-xs', { style : 'margin-right : 10px;'},  m('i.fa.fa-download.fa-inverse')),

                            ] ), item.data.download  ];
                        } else {
                            return '';
                        }
                    }

                },
            ];
            return default_columns;
        },
        sortButtonSelector : {
            up : 'i.fa.fa-chevron-up',
            down : 'i.fa.fa-chevron-down'
        },
        showFilter : true,     // Gives the option to filter by showing the filter box.
        filterStyle : { 'float' : 'right', 'width' : '50%'},
        allowMove : false,       // Turn moving on or off.
        hoverClass : 'fangorn-hover',
        hiddenFilterRows : ['tags']
    };
    var grid = new Treebeard(tbOptions);
}

module.exports = Meeting;
<|endoftext|>


<commit_before>import chai from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import {Route, createRouter, destroyRouter, middleware} from '../src/index';

let expect = chai.expect
chai.use(sinonChai)

let router, routes;
let RootRoute, ParentRoute, ChildRoute, GrandChildRoute, LeafRoute,
  Child2Route, DynParentRoute, DynChildRoute, DynGrandChildRoute;

describe('Route configuration', () => {

  beforeEach(() => {
    router = createRouter({location: 'memory'});

    router.use(middleware);
    RootRoute = Route.extend({}), ParentRoute = Route.extend({}), ChildRoute = Route.extend({}),
      GrandChildRoute = Route.extend({}), LeafRoute = Route.extend({}),
      Child2Route = Route.extend({}), DynParentRoute = Route.extend({}), DynChildRoute = Route.extend({}),
      DynGrandChildRoute = Route.extend({});

    routes = function (route) {
      route('parent', {routeClass: ParentRoute, routeOptions: {x: 1}}, function () {
        route('child', {routeClass: ChildRoute}, function () {
          route('grandchild', {}, function () {
            route('leaf', {})
          })
        })
      })
    }
    router.map(routes);
    router.listen();
  })

  afterEach(() => {
    destroyRouter(router);
  })

  it('can be defined in a parent route class', function () {
    ChildRoute.prototype.childRoutes = function () {
      return {
        grandchild: GrandChildRoute,
        leaf: function () {
          return LeafRoute
        }
      }
    };
    let spy = sinon.spy(GrandChildRoute.prototype, 'initialize');
    let spy2 = sinon.spy(LeafRoute.prototype, 'initialize');
    return router.transitionTo('leaf').then(function () {
      expect(spy).to.be.calledOnce;
      expect(spy2).to.be.calledOnce;
    })
  });

  it('can be loaded asynchronously', function () {
    ChildRoute.prototype.childRoutes = function () {
      return {
        grandchild: GrandChildRoute,
        leaf: function () {
          let promise = new Promise(function (resolve) {
            setTimeout(function () {
              resolve()
            }, 200)
          })
          return promise.then(function () {
            return LeafRoute
          })
        }
      }
    };
    let spy = sinon.spy(LeafRoute.prototype, 'initialize');
    return router.transitionTo('leaf').then(function () {
      expect(spy).to.be.calledOnce;
    })
  });

});
<commit_msg>Simplify async rout loading test<commit_after>import chai from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import {Route, createRouter, destroyRouter, middleware} from '../src/index';

let expect = chai.expect
chai.use(sinonChai)

let router, routes;
let RootRoute, ParentRoute, ChildRoute, GrandChildRoute, LeafRoute,
  Child2Route, DynParentRoute, DynChildRoute, DynGrandChildRoute;

describe('Route configuration', () => {

  beforeEach(() => {
    router = createRouter({location: 'memory'});

    router.use(middleware);
    RootRoute = Route.extend({}), ParentRoute = Route.extend({}), ChildRoute = Route.extend({}),
      GrandChildRoute = Route.extend({}), LeafRoute = Route.extend({}),
      Child2Route = Route.extend({}), DynParentRoute = Route.extend({}), DynChildRoute = Route.extend({}),
      DynGrandChildRoute = Route.extend({});

    routes = function (route) {
      route('parent', {routeClass: ParentRoute, routeOptions: {x: 1}}, function () {
        route('child', {routeClass: ChildRoute}, function () {
          route('grandchild', {}, function () {
            route('leaf', {})
          })
        })
      })
    }
    router.map(routes);
    router.listen();
  })

  afterEach(() => {
    destroyRouter(router);
  })

  it('can be defined in a parent route class', function () {
    ChildRoute.prototype.childRoutes = function () {
      return {
        grandchild: GrandChildRoute,
        leaf: function () {
          return LeafRoute
        }
      }
    };
    let spy = sinon.spy(GrandChildRoute.prototype, 'initialize');
    let spy2 = sinon.spy(LeafRoute.prototype, 'initialize');
    return router.transitionTo('leaf').then(function () {
      expect(spy).to.be.calledOnce;
      expect(spy2).to.be.calledOnce;
    })
  });

  it('can be loaded asynchronously', function () {
    ChildRoute.prototype.childRoutes = function () {
      return {
        grandchild: GrandChildRoute,
        leaf: function () {
          return new Promise(function (resolve) {
            setTimeout(function () {
              resolve(LeafRoute)
            }, 200)
          })
        }
      }
    };
    let spy = sinon.spy(LeafRoute.prototype, 'initialize');
    return router.transitionTo('leaf').then(function () {
      expect(spy).to.be.calledOnce;
    })
  });

});
<|endoftext|>


<commit_before>'use strict';

var _Promise = require('babel-runtime/core-js/promise')['default'];

var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];

Object.defineProperty(exports, '__esModule', {
  value: true
});

var _url = require('url');

var _url2 = _interopRequireDefault(_url);

var _fs = require('fs');

var _fs2 = _interopRequireDefault(_fs);

var _swaggerParser = require('swagger-parser');

var _swaggerParser2 = _interopRequireDefault(_swaggerParser);

var _ConfigureRouter = require('./ConfigureRouter');

var _ConfigureRouter2 = _interopRequireDefault(_ConfigureRouter);

var _PrunePaths = require('./PrunePaths');

var _PrunePaths2 = _interopRequireDefault(_PrunePaths);

exports['default'] = function (config) {
  if (!config.swaggerFile) {
    throw new Error('Config is missing `swaggerFile` parameter');
  }

  if (config.ignorePaths && config.mockRoutes) {
    throw new Error('Cannot specify both ignorePaths and mockPaths in config');
  }

  var basePath = undefined;
  var router = undefined;

  var parserPromise = new _Promise(function (resolve) {
    _swaggerParser2['default'].dereference(config.swaggerFile, function (err, api) {
      if (err) throw err;

      init(api);
      resolve();
    });
  });

  if (config.watch) {
    _fs2['default'].watchFile(config.swaggerFile, function () {
      _swaggerParser2['default'].dereference(config.swaggerFile, function (err, api) {
        if (err) throw err;

        init(api);
      });
    });
  }

  function init(api) {
    if (config.ignorePaths) {
      api.paths = (0, _PrunePaths2['default'])(api.paths, config.ignorePaths);
    } else if (config.mockPaths) {
      api.paths = (0, _PrunePaths2['default'])(api.paths, config.mockPaths, true);
    }

    basePath = api.basePath || '';
    router = (0, _ConfigureRouter2['default'])(api.paths, config.mock || {});
  }

  return function (req, res, next) {
    parserPromise.then(function () {
      var method = req.method.toLowerCase();

      if (method === 'options') {
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, FETCH, OPTIONS');
        res.end();
        return;
      }

      var path = _url2['default'].parse(req.url).pathname;
      path = path.replace(basePath + '/', '');
      if (path.charAt(0) !== '/') {
        path = '/' + path;
      }

      var matchingRoute = router.match('/' + method + path);

      if (!matchingRoute) return next();

      if (process.env.debug) {
        console.log('Request: %s %s', req.method, path);
      }

      try {
        var response = matchingRoute.fn();
        res.setHeader('Content-Type', 'application/json');
        res.write(response !== null ? JSON.stringify(response) : '');
      } catch (e) {
        res.statusCode = 500;
        res.write(JSON.stringify({ message: e.message }, null, 4));
      }

      res.end();
    });
  };
};

;
module.exports = exports['default'];<commit_msg>build<commit_after>'use strict';

var _Promise = require('babel-runtime/core-js/promise')['default'];

var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];

Object.defineProperty(exports, '__esModule', {
  value: true
});

var _url = require('url');

var _url2 = _interopRequireDefault(_url);

var _fs = require('fs');

var _fs2 = _interopRequireDefault(_fs);

var _swaggerParser = require('swagger-parser');

var _swaggerParser2 = _interopRequireDefault(_swaggerParser);

var _ConfigureRouter = require('./ConfigureRouter');

var _ConfigureRouter2 = _interopRequireDefault(_ConfigureRouter);

var _PrunePaths = require('./PrunePaths');

var _PrunePaths2 = _interopRequireDefault(_PrunePaths);

exports['default'] = function (config) {
  if (!config.swaggerFile) {
    throw new Error('Config is missing `swaggerFile` parameter');
  }

  if (config.ignorePaths && config.mockRoutes) {
    throw new Error('Cannot specify both ignorePaths and mockPaths in config');
  }

  var basePath = undefined;
  var router = undefined;

  var parserPromise = new _Promise(function (resolve) {
    _swaggerParser2['default'].dereference(config.swaggerFile, function (err, api) {
      if (err) throw err;

      init(api);
      resolve();
    });
  });

  if (config.watch) {
    _fs2['default'].watchFile(config.swaggerFile, function () {
      _swaggerParser2['default'].dereference(config.swaggerFile, function (err, api) {
        if (err) throw err;

        init(api);
      });
    });
  }

  function init(api) {
    if (config.ignorePaths) {
      api.paths = (0, _PrunePaths2['default'])(api.paths, config.ignorePaths);
    } else if (config.mockPaths) {
      api.paths = (0, _PrunePaths2['default'])(api.paths, config.mockPaths, true);
    }

    basePath = api.basePath || '';
    router = (0, _ConfigureRouter2['default'])(api.paths, config.mock || {});
  }

  return function (req, res, next) {
    parserPromise.then(function () {
      var method = req.method.toLowerCase();

      if (method === 'options') {
        res.end();
        return;
      }

      var path = _url2['default'].parse(req.url).pathname;
      path = path.replace(basePath + '/', '');
      if (path.charAt(0) !== '/') {
        path = '/' + path;
      }

      var matchingRoute = router.match('/' + method + path);

      if (!matchingRoute) return next();

      if (process.env.debug) {
        console.log('Request: %s %s', req.method, path);
      }

      try {
        var response = matchingRoute.fn();
        res.setHeader('Content-Type', 'application/json');
        res.write(response !== null ? JSON.stringify(response) : '');
      } catch (e) {
        res.statusCode = 500;
        res.write(JSON.stringify({ message: e.message }, null, 4));
      }

      res.end();
    });
  };
};

;
module.exports = exports['default'];<|endoftext|>