<commit_before>import { checkParamOrThrow } from 'apify-client/build/utils';
import log from 'apify-shared/log';
import _ from 'underscore';
import Promise from 'bluebird';
import BasicCrawler from './basic_crawler';
import PuppeteerPool from './puppeteer_pool';
import { isPromise } from './utils';

const DEFAULT_OPTIONS = {
    gotoFunction: ({ request, page }) => page.goto(request.url, { timeout: 60000 }),
    pageOpsTimeoutMillis: 300000,
};

const PAGE_CLOSE_TIMEOUT_MILLIS = 30000;

/**
 * Provides a simple framework for parallel crawling of web pages
 * using headless Chrome with [Puppeteer](https://github.com/GoogleChrome/puppeteer).
 * The URLs of pages to visit are given by `Request` objects that are fed from a list (see `RequestList` class)
 * or from a dynamic queue (see `RequestQueue` class).
 *
 * `PuppeteerCrawler` opens a new Chrome page (i.e. tab) for each `Request` object to crawl
 * and then calls the function provided by user as the `handlePageFunction` option.
 * New tasks are only started if there is enough free CPU and memory available,
 * using the `AutoscaledPool` class internally.
 *
 * Basic usage:
 *
 * ```javascript
 * const crawler = new Apify.PuppeteerCrawler({
 *     requestList,
 *     handlePageFunction: async ({ page, request }) => {
 *         // This function is called to extract data from a single web page
 *         // 'page' is an instance of Puppeteer.Page with page.goto(request.url) already called
 *         // 'request' is an instance of Request class with information about the page to load
 *         await Apify.pushData({
 *             title: await page.title(),
 *             url: request.url,
 *             succeeded: true,
 *         })
 *     },
 *     handleFailedRequestFunction: async ({ request }) => {
 *         // This function is called when crawling of a request failed too many time
 *         await Apify.pushData({
 *             url: request.url,
 *             succeeded: false,
 *             errors: request.errorMessages,
 *         })
 *     },
 * });
 *
 * await crawler.run();
 * ```
 *
 * @param {RequestList} [options.requestList]
 *   List of the requests to be processed.
 *   See the `requestList` parameter of `BasicCrawler` for more details.
 * @param {RequestQueue} [options.requestQueue]
 *   Queue of the requests to be processed.
 *   See the `requestQueue` parameter of `BasicCrawler` for more details.
 * @param {Function} [options.handlePageFunction]
 *   Function that is called to process each request.
 *   It is passed an object with the following fields:
 *   `request` is an instance of the `Request` object with details about the URL to open, HTTP method etc.
 *   `page` is an instance of the `Puppeteer.Page` class with `page.goto(request.url)` already called.
 * @param {Number} [options.pageOpsTimeoutMillis=300000]
 *   Timeout in which the function passed as `options.handlePageFunction` needs to finish.
 * @param {Function} [options.gotoFunction=({ request, page }) => page.goto(request.url, { timeout: 60000 })]
 *   Overrides the function that opens the request in Puppeteer.
 *   The function should return a result of Puppeteer's
 *   page.goto() function,
 *   i.e. a promise resolving to the Response object.
 *
 *   For example, this is useful if you need to extend the page load timeout or select a different criteria
 *   to determine that the navigation succeeded.
 *
 *   Note that a single page object is only used to process a single request and it is closed afterwards.
 * @param {Function} [options.handleFailedRequestFunction=({ request }) => log.error('Request failed', _.pick(request, 'url', 'uniqueKey'))]
 *   Function to handle requests that failed more than `option.maxRequestRetries` times. See the `handleFailedRequestFunction`
 *   parameter of `Apify.BasicCrawler` for details.
 * @param {Number} [options.maxRequestRetries=3]
 *   Indicates how many times each request is retried if `handleRequestFunction` failed.
 *   See `maxRequestRetries` parameter of `BasicCrawler`.
 * @param {Number} [options.maxRequestsPerCrawl]
 *   Maximum number of pages that the crawler will open. The crawl will stop when this limit is reached.
 *   Always set this value in order to prevent infinite loops in misconfigured crawlers.
 *   Note that in cases of parallel crawling, the actual number of pages visited might be slightly higher than this value.
 *   See `maxRequestsPerCrawl` parameter of `BasicCrawler`.
 * @param {Number} [options.maxMemoryMbytes]
 *   Maximum memory available for crawling. See `maxMemoryMbytes` parameter of `AutoscaledPool`.
 * @param {Number} [options.maxConcurrency=1000]
 *   Maximum concurrency of request processing. See `maxConcurrency` parameter of `AutoscaledPool`.
 * @param {Number} [options.minConcurrency=1]
 *   Minimum concurrency of requests processing. See `minConcurrency` parameter of `AutoscaledPool`.
 * @param {Number} [options.minFreeMemoryRatio=0.2]
 *   Minimum ratio of free memory kept in the system. See `minFreeMemoryRatio` parameter of `AutoscaledPool`.
 * @param {Function} [opts.isFinishedFunction]
 *   By default PuppeteerCrawler finishes when all the requests have been processed.
 *   You can override this behaviour by providing custom `isFinishedFunction`.
 *   This function that is called every time there are no requests being processed.
 *   If it resolves to `true` then the crawler's run finishes.
 *   See `isFinishedFunction` parameter of `AutoscaledPool`.
 * @param {Number} [options.maxOpenPagesPerInstance=50]
 *   Maximum number of opened tabs per browser. If this limit is reached then a new
 *   browser instance is started. See `maxOpenPagesPerInstance` parameter of `PuppeteerPool`.
 * @param {Number} [options.retireInstanceAfterRequestCount=100]
 *   Maximum number of requests that can be processed by a single browser instance.
 *   After the limit is reached the browser will be retired and new requests will
 *   be handled by a new browser instance.
 *   See `retireInstanceAfterRequestCount` parameter of `PuppeteerPool`.
 * @param {Number} [options.instanceKillerIntervalMillis=60000]
 *   How often the launched Puppeteer instances are checked whether they can be
 *   closed. See `instanceKillerIntervalMillis` parameter of `PuppeteerPool`.
 * @param {Number} [options.killInstanceAfterMillis=300000]
 *   If Puppeteer instance reaches the `options.retireInstanceAfterRequestCount` limit then
 *   it is considered retired and no more tabs will be opened. After the last tab is closed
 *   the whole browser is closed too. This parameter defines a time limit for inactivity
 *   after which the browser is closed even if there are pending tabs. See
 *   `killInstanceAfterMillis` parameter of `PuppeteerPool`.
 * @param {Object} [options.puppeteerConfig={ dumpio: process.env.NODE_ENV !== 'production', slowMo: 0, args: []}]
 *   Default options for each new `Puppeteer` instance. See `puppeteerConfig` parameter of `PuppeteerPool`.
 * @param {Function} [options.launchPuppeteerFunction=launchPuppeteerOptions => Apify.launchPuppeteer(launchPuppeteerOptions)]
 *   Overrides the default function to launch a new Puppeteer instance.
 *   See `launchPuppeteerFunction` parameter of `PuppeteerPool`.
 * @param {LaunchPuppeteerOptions} [options.launchPuppeteerOptions]
 *   Options used by `Apify.launchPuppeteer()` to start new Puppeteer instances.
 *   See `launchPuppeteerOptions` parameter of `PuppeteerPool`.
 */
export default class PuppeteerCrawler {
    constructor(opts) {
        // For backwards compatibility, in the future we can remove this...
        if (!opts.retireInstanceAfterRequestCount && opts.abortInstanceAfterRequestCount) {
            log.warning('PuppeteerCrawler: Parameter `abortInstanceAfterRequestCount` is deprecated! Use `retireInstanceAfterRequestCount` instead!');
            opts.retireInstanceAfterRequestCount = opts.abortInstanceAfterRequestCount;
        }

        const {
            handlePageFunction,
            gotoFunction,
            pageOpsTimeoutMillis,

            // Autoscaled pool options
            maxMemoryMbytes,
            maxConcurrency,
            minConcurrency,
            minFreeMemoryRatio,
            isFinishedFunction,

            // Basic crawler options
            requestList,
            requestQueue,
            maxRequestRetries,
            maxRequestsPerCrawl,
            handleFailedRequestFunction,

            // Puppeteer Pool options
            maxOpenPagesPerInstance,
            retireInstanceAfterRequestCount,
            instanceKillerIntervalMillis,
            killInstanceAfterMillis,
            launchPuppeteerFunction,
            launchPuppeteerOptions,
        } = _.defaults(opts, DEFAULT_OPTIONS);

        checkParamOrThrow(handlePageFunction, 'opts.handlePageFunction', 'Function');
        checkParamOrThrow(handleFailedRequestFunction, 'opts.handleFailedRequestFunction', 'Maybe Function');
        checkParamOrThrow(gotoFunction, 'opts.gotoFunction', 'Function');

        this.handlePageFunction = handlePageFunction;
        this.gotoFunction = gotoFunction;
        this.pageOpsTimeoutMillis = pageOpsTimeoutMillis;

        this.puppeteerPoolOptions = {
            maxOpenPagesPerInstance,
            retireInstanceAfterRequestCount,
            instanceKillerIntervalMillis,
            killInstanceAfterMillis,
            launchPuppeteerFunction,
            launchPuppeteerOptions,
        };

        this.puppeteerPool = new PuppeteerPool(this.puppeteerPoolOptions);

        this.basicCrawler = new BasicCrawler({
            // Basic crawler options.
            requestList,
            requestQueue,
            maxRequestRetries,
            maxRequestsPerCrawl,
            handleRequestFunction: (...args) => this._handleRequestFunction(...args),
            handleFailedRequestFunction,

            // Autoscaled pool options.
            maxMemoryMbytes,
            maxConcurrency,
            minConcurrency,
            minFreeMemoryRatio,
            isFinishedFunction,
            ignoreMainProcess: true,
        });
    }

    /**
     * Runs the crawler. Returns promise that gets resolved once all the requests got processed.
     *
     * @return {Promise}
     */
    run() {
        if (this.isStopped) this.puppeteerPool = new PuppeteerPool(this.puppeteerPoolOptions);
        this.isStopped = false;
        this.isRunningPromise = new Promise((resolve, reject) => {
            this.isRunningReject = reject;
        });
        return this.basicCrawler.run()
            .finally(() => this.puppeteerPool.destroy());
    }

    /**
     * Stops the crawler by preventing crawls of additional pages. Pages already running are terminated.
     */
    stop() {
        this.isStopped = true;
        this.isRunningReject();
        this.basicCrawler.stop();
        return this.puppeteerPool.destroy();
    }

    /**
     * Wrapper around handlePageFunction that opens and closes pages etc.
     *
     * @ignore
     */
    _handleRequestFunction({ request }) {
        if (this.isStopped) return Promise.reject(new Error('PuppeteerCrawler is stopped.')); // Pool will be destroyed.
        let page;

        const promise = this.puppeteerPool
            .newPage()
            .then((newPage) => { page = newPage; })
            .then(() => this.gotoFunction({ page, request, puppeteerPool: this.puppeteerPool }))
            .then((response) => {
                const promise = this.handlePageFunction({
                    page,
                    request,
                    puppeteerPool: this.puppeteerPool,
                    response,
                });

                if (!isPromise(promise)) throw new Error('User provided handlePageFunction must return a Promise.');

                return promise;
            })
            .timeout(this.pageOpsTimeoutMillis, 'PuppeteerCrawler: handlePageFunction timed out.')
            .finally(() => {
                return Promise.resolve()
                    .then(() => {
                        if (page) return page.close();
                    })
                    .timeout(PAGE_CLOSE_TIMEOUT_MILLIS, 'Operation timed out.')
                    .catch(err => log.debug('PuppeteerCrawler: Page.close() failed.', { reason: err ? err.message : err }));
            });
        return Promise.race([promise, this.isRunningPromise]); // Reject all requests immediately after stopping the crawler (to be reclaimed).
    }
}
<commit_msg>Fix lint issue<commit_after>import { checkParamOrThrow } from 'apify-client/build/utils';
import log from 'apify-shared/log';
import _ from 'underscore';
import Promise from 'bluebird';
import BasicCrawler from './basic_crawler';
import PuppeteerPool from './puppeteer_pool';
import { isPromise } from './utils';

const DEFAULT_OPTIONS = {
    gotoFunction: ({ request, page }) => page.goto(request.url, { timeout: 60000 }),
    pageOpsTimeoutMillis: 300000,
};

const PAGE_CLOSE_TIMEOUT_MILLIS = 30000;

/**
 * Provides a simple framework for parallel crawling of web pages
 * using headless Chrome with [Puppeteer](https://github.com/GoogleChrome/puppeteer).
 * The URLs of pages to visit are given by `Request` objects that are fed from a list (see `RequestList` class)
 * or from a dynamic queue (see `RequestQueue` class).
 *
 * `PuppeteerCrawler` opens a new Chrome page (i.e. tab) for each `Request` object to crawl
 * and then calls the function provided by user as the `handlePageFunction` option.
 * New tasks are only started if there is enough free CPU and memory available,
 * using the `AutoscaledPool` class internally.
 *
 * Basic usage:
 *
 * ```javascript
 * const crawler = new Apify.PuppeteerCrawler({
 *     requestList,
 *     handlePageFunction: async ({ page, request }) => {
 *         // This function is called to extract data from a single web page
 *         // 'page' is an instance of Puppeteer.Page with page.goto(request.url) already called
 *         // 'request' is an instance of Request class with information about the page to load
 *         await Apify.pushData({
 *             title: await page.title(),
 *             url: request.url,
 *             succeeded: true,
 *         })
 *     },
 *     handleFailedRequestFunction: async ({ request }) => {
 *         // This function is called when crawling of a request failed too many time
 *         await Apify.pushData({
 *             url: request.url,
 *             succeeded: false,
 *             errors: request.errorMessages,
 *         })
 *     },
 * });
 *
 * await crawler.run();
 * ```
 *
 * @param {RequestList} [options.requestList]
 *   List of the requests to be processed.
 *   See the `requestList` parameter of `BasicCrawler` for more details.
 * @param {RequestQueue} [options.requestQueue]
 *   Queue of the requests to be processed.
 *   See the `requestQueue` parameter of `BasicCrawler` for more details.
 * @param {Function} [options.handlePageFunction]
 *   Function that is called to process each request.
 *   It is passed an object with the following fields:
 *   `request` is an instance of the `Request` object with details about the URL to open, HTTP method etc.
 *   `page` is an instance of the `Puppeteer.Page` class with `page.goto(request.url)` already called.
 * @param {Number} [options.pageOpsTimeoutMillis=300000]
 *   Timeout in which the function passed as `options.handlePageFunction` needs to finish.
 * @param {Function} [options.gotoFunction=({ request, page }) => page.goto(request.url, { timeout: 60000 })]
 *   Overrides the function that opens the request in Puppeteer.
 *   The function should return a result of Puppeteer's
 *   page.goto() function,
 *   i.e. a promise resolving to the Response object.
 *
 *   For example, this is useful if you need to extend the page load timeout or select a different criteria
 *   to determine that the navigation succeeded.
 *
 *   Note that a single page object is only used to process a single request and it is closed afterwards.
 * @param {Function} [options.handleFailedRequestFunction=({ request }) => log.error('Request failed', _.pick(request, 'url', 'uniqueKey'))]
 *   Function to handle requests that failed more than `option.maxRequestRetries` times. See the `handleFailedRequestFunction`
 *   parameter of `Apify.BasicCrawler` for details.
 * @param {Number} [options.maxRequestRetries=3]
 *   Indicates how many times each request is retried if `handleRequestFunction` failed.
 *   See `maxRequestRetries` parameter of `BasicCrawler`.
 * @param {Number} [options.maxRequestsPerCrawl]
 *   Maximum number of pages that the crawler will open. The crawl will stop when this limit is reached.
 *   Always set this value in order to prevent infinite loops in misconfigured crawlers.
 *   Note that in cases of parallel crawling, the actual number of pages visited might be slightly higher than this value.
 *   See `maxRequestsPerCrawl` parameter of `BasicCrawler`.
 * @param {Number} [options.maxMemoryMbytes]
 *   Maximum memory available for crawling. See `maxMemoryMbytes` parameter of `AutoscaledPool`.
 * @param {Number} [options.maxConcurrency=1000]
 *   Maximum concurrency of request processing. See `maxConcurrency` parameter of `AutoscaledPool`.
 * @param {Number} [options.minConcurrency=1]
 *   Minimum concurrency of requests processing. See `minConcurrency` parameter of `AutoscaledPool`.
 * @param {Number} [options.minFreeMemoryRatio=0.2]
 *   Minimum ratio of free memory kept in the system. See `minFreeMemoryRatio` parameter of `AutoscaledPool`.
 * @param {Function} [opts.isFinishedFunction]
 *   By default PuppeteerCrawler finishes when all the requests have been processed.
 *   You can override this behaviour by providing custom `isFinishedFunction`.
 *   This function that is called every time there are no requests being processed.
 *   If it resolves to `true` then the crawler's run finishes.
 *   See `isFinishedFunction` parameter of `AutoscaledPool`.
 * @param {Number} [options.maxOpenPagesPerInstance=50]
 *   Maximum number of opened tabs per browser. If this limit is reached then a new
 *   browser instance is started. See `maxOpenPagesPerInstance` parameter of `PuppeteerPool`.
 * @param {Number} [options.retireInstanceAfterRequestCount=100]
 *   Maximum number of requests that can be processed by a single browser instance.
 *   After the limit is reached the browser will be retired and new requests will
 *   be handled by a new browser instance.
 *   See `retireInstanceAfterRequestCount` parameter of `PuppeteerPool`.
 * @param {Number} [options.instanceKillerIntervalMillis=60000]
 *   How often the launched Puppeteer instances are checked whether they can be
 *   closed. See `instanceKillerIntervalMillis` parameter of `PuppeteerPool`.
 * @param {Number} [options.killInstanceAfterMillis=300000]
 *   If Puppeteer instance reaches the `options.retireInstanceAfterRequestCount` limit then
 *   it is considered retired and no more tabs will be opened. After the last tab is closed
 *   the whole browser is closed too. This parameter defines a time limit for inactivity
 *   after which the browser is closed even if there are pending tabs. See
 *   `killInstanceAfterMillis` parameter of `PuppeteerPool`.
 * @param {Object} [options.puppeteerConfig={ dumpio: process.env.NODE_ENV !== 'production', slowMo: 0, args: []}]
 *   Default options for each new `Puppeteer` instance. See `puppeteerConfig` parameter of `PuppeteerPool`.
 * @param {Function} [options.launchPuppeteerFunction=launchPuppeteerOptions => Apify.launchPuppeteer(launchPuppeteerOptions)]
 *   Overrides the default function to launch a new Puppeteer instance.
 *   See `launchPuppeteerFunction` parameter of `PuppeteerPool`.
 * @param {LaunchPuppeteerOptions} [options.launchPuppeteerOptions]
 *   Options used by `Apify.launchPuppeteer()` to start new Puppeteer instances.
 *   See `launchPuppeteerOptions` parameter of `PuppeteerPool`.
 */
export default class PuppeteerCrawler {
    constructor(opts) {
        // For backwards compatibility, in the future we can remove this...
        if (!opts.retireInstanceAfterRequestCount && opts.abortInstanceAfterRequestCount) {
            log.warning('PuppeteerCrawler: Parameter `abortInstanceAfterRequestCount` is deprecated! Use `retireInstanceAfterRequestCount` instead!');
            opts.retireInstanceAfterRequestCount = opts.abortInstanceAfterRequestCount;
        }

        const {
            handlePageFunction,
            gotoFunction,
            pageOpsTimeoutMillis,

            // Autoscaled pool options
            maxMemoryMbytes,
            maxConcurrency,
            minConcurrency,
            minFreeMemoryRatio,
            isFinishedFunction,

            // Basic crawler options
            requestList,
            requestQueue,
            maxRequestRetries,
            maxRequestsPerCrawl,
            handleFailedRequestFunction,

            // Puppeteer Pool options
            maxOpenPagesPerInstance,
            retireInstanceAfterRequestCount,
            instanceKillerIntervalMillis,
            killInstanceAfterMillis,
            launchPuppeteerFunction,
            launchPuppeteerOptions,
        } = _.defaults(opts, DEFAULT_OPTIONS);

        checkParamOrThrow(handlePageFunction, 'opts.handlePageFunction', 'Function');
        checkParamOrThrow(handleFailedRequestFunction, 'opts.handleFailedRequestFunction', 'Maybe Function');
        checkParamOrThrow(gotoFunction, 'opts.gotoFunction', 'Function');

        this.handlePageFunction = handlePageFunction;
        this.gotoFunction = gotoFunction;
        this.pageOpsTimeoutMillis = pageOpsTimeoutMillis;

        this.puppeteerPoolOptions = {
            maxOpenPagesPerInstance,
            retireInstanceAfterRequestCount,
            instanceKillerIntervalMillis,
            killInstanceAfterMillis,
            launchPuppeteerFunction,
            launchPuppeteerOptions,
        };

        this.puppeteerPool = new PuppeteerPool(this.puppeteerPoolOptions);

        this.basicCrawler = new BasicCrawler({
            // Basic crawler options.
            requestList,
            requestQueue,
            maxRequestRetries,
            maxRequestsPerCrawl,
            handleRequestFunction: (...args) => this._handleRequestFunction(...args),
            handleFailedRequestFunction,

            // Autoscaled pool options.
            maxMemoryMbytes,
            maxConcurrency,
            minConcurrency,
            minFreeMemoryRatio,
            isFinishedFunction,
            ignoreMainProcess: true,
        });
    }

    /**
     * Runs the crawler. Returns promise that gets resolved once all the requests got processed.
     *
     * @return {Promise}
     */
    run() {
        if (this.isStopped) this.puppeteerPool = new PuppeteerPool(this.puppeteerPoolOptions);
        this.isStopped = false;
        this.isRunningPromise = new Promise((resolve, reject) => {
            this.isRunningReject = reject;
        });
        return this.basicCrawler.run()
            .finally(() => this.puppeteerPool.destroy());
    }

    /**
     * Stops the crawler by preventing crawls of additional pages. Pages already running are terminated.
     */
    stop() {
        this.isStopped = true;
        this.isRunningReject();
        this.basicCrawler.stop();
        return this.puppeteerPool.destroy();
    }

    /**
     * Wrapper around handlePageFunction that opens and closes pages etc.
     *
     * @ignore
     */
    _handleRequestFunction({ request }) {
        if (this.isStopped) return Promise.reject(new Error('PuppeteerCrawler is stopped.')); // Pool will be destroyed.
        let page;

        const returnPromise = this.puppeteerPool
            .newPage()
            .then((newPage) => { page = newPage; })
            .then(() => this.gotoFunction({ page, request, puppeteerPool: this.puppeteerPool }))
            .then((response) => {
                const promise = this.handlePageFunction({
                    page,
                    request,
                    puppeteerPool: this.puppeteerPool,
                    response,
                });

                if (!isPromise(promise)) throw new Error('User provided handlePageFunction must return a Promise.');

                return promise;
            })
            .timeout(this.pageOpsTimeoutMillis, 'PuppeteerCrawler: handlePageFunction timed out.')
            .finally(() => {
                return Promise.resolve()
                    .then(() => {
                        if (page) return page.close();
                    })
                    .timeout(PAGE_CLOSE_TIMEOUT_MILLIS, 'Operation timed out.')
                    .catch(err => log.debug('PuppeteerCrawler: Page.close() failed.', { reason: err ? err.message : err }));
            });
        return Promise.race([returnPromise, this.isRunningPromise]); // Reject all requests immediately after stopping the crawler (to be reclaimed).
    }
}
<|endoftext|>


<commit_before>var config = require('../config')
if(!config.tasks.js) return

var path            = require('path')
var pathToUrl       = require('./pathToUrl')
var webpack         = require('webpack')
var webpackManifest = require('./webpackManifest')
var ProvidePlugin   = require('webpack/lib/ProvidePlugin')

module.exports = function(env) {
  var jsSrc = path.resolve(config.root.src, config.tasks.js.src)
  var jsDest = path.resolve(config.root.dest, config.tasks.js.dest)
  var publicPath = pathToUrl(config.tasks.js.dest, '/')

  var extensions = config.tasks.js.extensions.map(function(extension) {
    return '.' + extension
  })

  var rev = config.tasks.production.rev && env === 'production'
  var filenamePattern = rev ? '[name]-[hash].js' : '[name].js'

  var webpackConfig = {
    context: jsSrc,
    plugins: [
      new ProvidePlugin({
        jQuery: 'jquery',
        $: 'jquery',
        jquery: 'jquery'
      })
    ],
    resolve: {
      root: jsSrc,
      extensions: [''].concat(extensions)
    },
    module: {
      loaders: [
        {
          test: /\.js$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
          query: config.tasks.js.babel
        },{
          test: /\.coffee$/,
          loader: "coffee-loader",
          exclude: /node_modules/
        }
      ]
    }
  }

  if(env === 'development') {
    webpackConfig.devtool = 'inline-source-map'

    // Create new entries object with webpack-hot-middleware added
    for (var key in config.tasks.js.entries) {
      var entry = config.tasks.js.entries[key]
      config.tasks.js.entries[key] = ['webpack-hot-middleware/client?&reload=true'].concat(entry)
    }

    webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin())
  }

  if(env !== 'test') {
    // Karma doesn't need entry points or output settings
    webpackConfig.entry = config.tasks.js.entries

    webpackConfig.output= {
      path: path.normalize(jsDest),
      filename: filenamePattern,
      publicPath: publicPath
    }

    if(config.tasks.js.extractSharedJs) {
      // Factor out common dependencies into a shared.js
      webpackConfig.plugins.push(
        new webpack.optimize.CommonsChunkPlugin({
          name: 'shared',
          filename: filenamePattern,
        })
      )
    }
  }

  if(env === 'production') {
    if(rev) {
      webpackConfig.plugins.push(new webpackManifest(publicPath, config.root.dest))
    }
    webpackConfig.plugins.push(
      new webpack.DefinePlugin({
        'process.env': {
          'NODE_ENV': JSON.stringify('production')
        }
      }),
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.UglifyJsPlugin(),
      new webpack.NoErrorsPlugin()
    )
  }

  return webpackConfig
}
<commit_msg>Changes<commit_after>var config = require('../config')
if(!config.tasks.js) return

var path            = require('path')
var pathToUrl       = require('./pathToUrl')
var webpack         = require('webpack')
var webpackManifest = require('./webpackManifest')
var ProvidePlugin   = require('webpack/lib/ProvidePlugin')

module.exports = function(env) {
  var jsSrc = path.resolve(config.root.src, config.tasks.js.src)
  var jsDest = path.resolve(config.root.dest, config.tasks.js.dest)
  var publicPath = pathToUrl(config.tasks.js.dest, '/')

  var extensions = config.tasks.js.extensions.map(function(extension) {
    return '.' + extension
  })

  var rev = config.tasks.production.rev && env === 'production'
  var filenamePattern = rev ? '[name]-[hash].js' : '[name].js'

  var webpackConfig = {
    context: jsSrc,
    plugins: [
      new ProvidePlugin({
        jQuery: 'jquery',
        $: 'jquery',
        jquery: 'jquery'
      })
    ],
    resolve: {
      root: jsSrc,
      extensions: [''].concat(extensions)
    },
    module: {
      loaders: [
        {
          test: /\.js$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
          query: config.tasks.js.babel
        },{
          test: /\.coffee$/,
          loader: "coffee-loader",
          exclude: /node_modules/
        },{ test: /bootstrap[\/\\]dist[\/\\]js[\/\\]umd[\/\\]/,
          loader: 'imports?jQuery=jquery'
        }
      ]
    }
  }

  if(env === 'development') {
    webpackConfig.devtool = 'inline-source-map'

    // Create new entries object with webpack-hot-middleware added
    for (var key in config.tasks.js.entries) {
      var entry = config.tasks.js.entries[key]
      config.tasks.js.entries[key] = ['webpack-hot-middleware/client?&reload=true'].concat(entry)
    }

    webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin())
  }

  if(env !== 'test') {
    // Karma doesn't need entry points or output settings
    webpackConfig.entry = config.tasks.js.entries

    webpackConfig.output= {
      path: path.normalize(jsDest),
      filename: filenamePattern,
      publicPath: publicPath
    }

    if(config.tasks.js.extractSharedJs) {
      // Factor out common dependencies into a shared.js
      webpackConfig.plugins.push(
        new webpack.optimize.CommonsChunkPlugin({
          name: 'shared',
          filename: filenamePattern,
        })
      )
    }
  }

  if(env === 'production') {
    if(rev) {
      webpackConfig.plugins.push(new webpackManifest(publicPath, config.root.dest))
    }
    webpackConfig.plugins.push(
      new webpack.DefinePlugin({
        'process.env': {
          'NODE_ENV': JSON.stringify('production')
        }
      }),
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.UglifyJsPlugin(),
      new webpack.NoErrorsPlugin()
    )
  }

  return webpackConfig
}
<|endoftext|>


<commit_before>// regular expression patterns
var find_tmpl = /\{([\w\.]+)\}/g;
var find_braces = /\{|\}/g;

/**
 * Create a new config event handler.
 *
 * @public
 * @param {object} The module instance.
 * @param {object} The "out" config.
 * @param {object} The adapter object (optional).
 */
engine.flow = function (module_instance, config, adapter) {

    /**
     * The config event handler.
     *
     * @public
     * @param {object} The event object.
     * @param {object} The event data.
     */
    return function handler (eventStream) {

        // reslove data fields and clone the config config object
        config = resolveAndClone(config, module_instance, adapter);

        // load module instances
        if (config.load) {
            // load module instances
            for (var m = 0, ml = config.load.length; m < ml; ++m) {
                engine.module(config.load[m]);
            }
        }

        // route to url
        if (config.route) {
            engine.route(config.route);
        }

        // check flow content
        if (config.flow && config.flow.length) {

            // execute the flow configs
            for (var i = 0, l = config.flow.length, flow, key; i < l; ++i) {
                flow = config.flow[i];

                // get target module instance, or continue if not found
                // and check module instance acces for server side
                if (
                    (flow.to && !(module_instance = engine.instances[parsePath(flow.to, data, module_instance)])) &&
                    (eventStream.role && !engine.roleAccess(module_instance, eventStream.role))
                ) {
                    continue;
                }

                /*
                TODO: - pipe to "serverEvent:instance"
                */
                if (flow.to && flow.to.indexOf(':') > 0) {
                    var serverEvent = flow.to.split(':')[0];

                    var link = module_instance.link(serverEvent, function () {
                        //..
                    });

                    // ..pipe link to eventStream?
                    // ..send config config as data to server?
                }

                // pipe event to another event
                if (flow.pipe) {
                    eventStream.pipe(module_instance.event(flow.pipe));
                }

                // append method call event data handlers
                if (flow.call) {
                    eventStream.data(flow.call, module_instance);
                }
            }
        }

        // send first data event with the configured config data
        eventStream.emit(null, config.data);
    };
};

/**
 * Resolve data fields in for incoming configs.
 *
 * @private
 * @param {object} The config config.
 * @param {object} The data object.
 * @param {object} The module instance.
 */
function resolveAndClone (config, module_instance, adapter) {

    var parsedFlow = {
        data: {}
    };
    var data = parsedFlow.data;
    var key;

    // extend data with location data (hash, search, path)
    if (global.location) {
        handleStateValues(data);
    }

    // add custom data to the first data emit
    if (adapter) {
        adapter.handler(data, adapter.data);
    }

    // "data": {"key": "{value}"}
    if (config.data) {
        for (key in config.data) {

            // parse the data field values
            parsedFlow.data[key] = parsePath(config.data[key], data, module_instance);
        }
    }

    // search for path in data and module instance and set it to the cloned config
    // "set": {"key": "{path}", "key": "${#css:attr}"}
    if (config.set) {
        for (key in config.set) {
            parsedFlow.data[key] = parsePath(config.set[key], data, module_instance, true);
        }
    }

    // create nest objects with flat keys
    if (config.data || config.set) {
        parsedFlow.data = engine.deep(parsedFlow.data);
    }

    // "load": ["{instance}"]
    if (config.load) {
        parsedFlow.load = [];

        for (var l = 0, ll = config.load.length; l < ll; ++l) {
            parsedFlow.load[l] = parsePath(config.load[l], data, module_instance);
        }
    }

    // "route": "{path}"
    if (config.route) {
        parsedFlow.route = parsePath(config.route, data, module_instance);
    }

    if (config.flow && config.flow.length) {
        parsedFlow.flow = [];

        for (var f = 0, lf = config.flow.length, flow, pFlow; f < lf; ++f) {
            flow = config.flow[f];
            pFlow = {};

            // "call": "{method}"
            if (flow.call) {
                pFlow.call = parsePath(flow.call, data, module_instance, true);
            }

            // "pipe": "{event}"
            if (flow.pipe) {
                pFlow.pipe = parsePath(flow.pipe, data, module_instance);
            }

            // "to": {instance}
            if (flow.to) {
                pFlow.to = parsePath(flow.to, data, module_instance);
            }

            // push flow into parsed flow object
            parsedFlow.flow[f] = pFlow;
        }
    }

    return parsedFlow;
}

/**
 * Extend event object with location data.
 *
 * @private
 * @param {object} The event object.
 */
function handleStateValues (data) {

    // add pathname to data object
    data._path = global.location.pathname.substr(1).split('/');

    // parse and append url search to data
    if (global.location.search && !data._search) {
        data._search = searchToJSON(global.location.search);
    }

    // append url hash to data
    if (global.location.hash && !data._hash) {
        data._hash = global.location.hash.substr(1);
    }
}

/**
 * Parse a state search string to JSON.
 * Credentials: http://snipplr.com/view/70905/search-string-to-json/
 *
 * @private
 */
function searchToJSON(search) {
    var rep = {'?':'{"','=':'":"','&':'","'};
    var s = search.replace(/[\?\=\&]/g, function(r) {
        return rep[r];
    });
    return JSON.parse(s.length? s+'"}' : "{}");
}

/**
 * Replace data fields in a string.
 *
 * @private
 * @param {string} The string.
 * @param {object} The data context.
 */
function parsePath (path, data, module_instance, getValue) {

    if (path.indexOf('{') < 0) {
        return getValue ? getPathValue(path, data, module_instance) : path;
    }

    var match = path.match(find_tmpl);

    // replace route with data
    if (match) {
        for (var i = 0, value; i < match.length; ++i) {

            // get value from object
            value = engine.path(match[i].replace(find_braces, ''), [data, module_instance]);

            // replace value in route
            if (typeof value !== 'undefined') {
                path = typeof value === 'object' ? value : path.replace(match[i], value);
            }
        }
    }

    // get path value or return path
    return getValue ? getPathValue(path, data, module_instance) : path;
}

/**
 * Merge dynamic data to the event data object.
 *
 * @private
 * @param {object} The module instance.
 * @param {object} The event config.
 * @param {object} The event data object.
 */
function getPathValue (path, data, module_instance) {

    // get an attribute value from a dom element or the element itself
    if (path[0] === '$') {
        path = path.substr(1).split(':');

        // get find an element in the document
        path[0] = document.querySelector(path[0]);

        // set data key to the dom attribute value or the dom element
        return path[1] && path[0][path[1]] !== undefined ? path[0][path[1]] : path[0];

    }

    // return search value with a path: 1. data, 3. instance, 4. global
    return engine.path(path, [data, module_instance, global]);
}

<commit_msg>use utils class to parse paths<commit_after>var utils = require('./utils');

// regular expression patterns
var find_tmpl = /\{([\w\.]+)\}/g;
var find_braces = /\{|\}/g;

/**
 * Create a new config event handler.
 *
 * @public
 * @param {object} The module instance.
 * @param {object} The "out" config.
 * @param {object} The adapter object (optional).
 */
module.exports = function (module_instance, config, adapter) {

    /**
     * The config event handler.
     *
     * @public
     * @param {object} The event object.
     * @param {object} The event data.
     */
    return function handler (eventStream) {

        // reslove data fields and clone the config config object
        config = resolveAndClone(config, module_instance, adapter);

        // load module instances
        if (config.load) {
            // load module instances
            for (var m = 0, ml = config.load.length; m < ml; ++m) {
                engine.module(config.load[m]);
            }
        }

        // route to url
        if (config.route) {
            engine.route(config.route);
        }

        // check flow content
        if (config.flow && config.flow.length) {

            // execute the flow configs
            for (var i = 0, l = config.flow.length, flow, key; i < l; ++i) {
                flow = config.flow[i];

                // get target module instance, or continue if not found
                // and check module instance acces for server side
                if (
                    (flow.to && !(module_instance = engine.instances[parsePath(flow.to, data, module_instance)])) &&
                    (eventStream.role && !utils.roleAccess(module_instance, eventStream.role))
                ) {
                    continue;
                }

                /*
                TODO: - pipe to "serverEvent:instance"
                */
                if (flow.to && flow.to.indexOf(':') > 0) {
                    var serverEvent = flow.to.split(':')[0];

                    var link = module_instance.link(serverEvent, function () {
                        //..
                    });

                    // ..pipe link to eventStream?
                    // ..send config config as data to server?
                }

                // pipe event to another event
                if (flow.pipe) {
                    eventStream.pipe(module_instance.event(flow.pipe));
                }

                // append method call event data handlers
                if (flow.call) {
                    eventStream.data(flow.call, module_instance);
                }
            }
        }

        // send first data event with the configured config data
        eventStream.emit(null, config.data);
    };
};

/**
 * Resolve data fields in for incoming configs.
 *
 * @private
 * @param {object} The config config.
 * @param {object} The data object.
 * @param {object} The module instance.
 */
function resolveAndClone (config, module_instance, adapter) {

    var parsedFlow = {
        data: {}
    };
    var data = parsedFlow.data;
    var key;

    // extend data with location data (hash, search, path)
    if (global.location) {
        handleStateValues(data);
    }

    // add custom data to the first data emit
    if (adapter) {
        adapter.handler(data, adapter.data);
    }

    // "data": {"key": "{value}"}
    if (config.data) {
        for (key in config.data) {

            // parse the data field values
            parsedFlow.data[key] = parsePath(config.data[key], data, module_instance);
        }
    }

    // search for path in data and module instance and set it to the cloned config
    // "set": {"key": "{path}", "key": "${#css:attr}"}
    if (config.set) {
        for (key in config.set) {
            parsedFlow.data[key] = parsePath(config.set[key], data, module_instance, true);
        }
    }

    // create nest objects with flat keys
    if (config.data || config.set) {
        parsedFlow.data = utils.deep(parsedFlow.data);
    }

    // "load": ["{instance}"]
    if (config.load) {
        parsedFlow.load = [];

        for (var l = 0, ll = config.load.length; l < ll; ++l) {
            parsedFlow.load[l] = parsePath(config.load[l], data, module_instance);
        }
    }

    // "route": "{path}"
    if (config.route) {
        parsedFlow.route = parsePath(config.route, data, module_instance);
    }

    if (config.flow && config.flow.length) {
        parsedFlow.flow = [];

        for (var f = 0, lf = config.flow.length, flow, pFlow; f < lf; ++f) {
            flow = config.flow[f];
            pFlow = {};

            // "call": "{method}"
            if (flow.call) {
                pFlow.call = parsePath(flow.call, data, module_instance, true);
            }

            // "pipe": "{event}"
            if (flow.pipe) {
                pFlow.pipe = parsePath(flow.pipe, data, module_instance);
            }

            // "to": {instance}
            if (flow.to) {
                pFlow.to = parsePath(flow.to, data, module_instance);
            }

            // push flow into parsed flow object
            parsedFlow.flow[f] = pFlow;
        }
    }

    return parsedFlow;
}

/**
 * Extend event object with location data.
 *
 * @private
 * @param {object} The event object.
 */
function handleStateValues (data) {

    // add pathname to data object
    data._path = global.location.pathname.substr(1).split('/');

    // parse and append url search to data
    if (global.location.search && !data._search) {
        data._search = searchToJSON(global.location.search);
    }

    // append url hash to data
    if (global.location.hash && !data._hash) {
        data._hash = global.location.hash.substr(1);
    }
}

/**
 * Parse a state search string to JSON.
 * Credentials: http://snipplr.com/view/70905/search-string-to-json/
 *
 * @private
 */
function searchToJSON(search) {
    var rep = {'?':'{"','=':'":"','&':'","'};
    var s = search.replace(/[\?\=\&]/g, function(r) {
        return rep[r];
    });
    return JSON.parse(s.length? s+'"}' : "{}");
}

/**
 * Replace data fields in a string.
 *
 * @private
 * @param {string} The string.
 * @param {object} The data context.
 */
function parsePath (path, data, module_instance, getValue) {

    if (path.indexOf('{') < 0) {
        return getValue ? getPathValue(path, data, module_instance) : path;
    }

    var match = path.match(find_tmpl);

    // replace route with data
    if (match) {
        for (var i = 0, value; i < match.length; ++i) {

            // get value from object
            value = utils.path(match[i].replace(find_braces, ''), [data, module_instance]);

            // replace value in route
            if (typeof value !== 'undefined') {
                path = typeof value === 'object' ? value : path.replace(match[i], value);
            }
        }
    }

    // get path value or return path
    return getValue ? getPathValue(path, data, module_instance) : path;
}

/**
 * Merge dynamic data to the event data object.
 *
 * @private
 * @param {object} The module instance.
 * @param {object} The event config.
 * @param {object} The event data object.
 */
function getPathValue (path, data, module_instance) {

    // get an attribute value from a dom element or the element itself
    if (path[0] === '$') {
        path = path.substr(1).split(':');

        // get find an element in the document
        path[0] = document.querySelector(path[0]);

        // set data key to the dom attribute value or the dom element
        return path[1] && path[0][path[1]] !== undefined ? path[0][path[1]] : path[0];

    }

    // return search value with a path: 1. data, 3. instance, 4. global
    return utils.path(path, [data, module_instance, global]);
}

<|endoftext|>


<commit_before>export default {
  data () {
    return {
      isActive: this.value
    }
  },

  props: {
    value: {
      required: false
    }
  },

  watch: {
    value (val) {
      this.isActive = Boolean(val)
    },
    isActive (val) {
      val !== this.value && this.$emit('input', val)
    }
  }
}
<commit_msg>small tweak<commit_after>export default {
  data () {
    return {
      isActive: !!this.value
    }
  },

  props: {
    value: {
      required: false
    }
  },

  watch: {
    value (val) {
      this.isActive = !!val
    },
    isActive (val) {
      val !== this.value && this.$emit('input', val)
    }
  }
}
<|endoftext|>


<commit_before>/**
 * Creates an instance of the mlfq scheduler
 */

import Scheduler from "./mlfq";

import random from "random-seed";

const scheduler = new Scheduler({
    timeQuantums: [1, 2, 3, 4],
    boostTime: 50,
    random: (function(){
        const gen = random.create();
        return {
            seed(seed) {
                gen.seed(seed);
            },
            range(highLow) {
                return gen.intBetween(...highLow);
            }
        };
    }()),
    ioFrequencyRange: [100, 1000],
    jobRuntimeRange: [1, 10],
    numJobsRange: [1, 1],
    jobCreateTimeRange: [0, 3],
    ioLengthRange: [0, 10]
});
export default scheduler;<commit_msg>Jobs must start at 1<commit_after>/**
 * Creates an instance of the mlfq scheduler
 */

import Scheduler from "./mlfq";

import random from "random-seed";

const scheduler = new Scheduler({
    timeQuantums: [1, 2, 3, 4],
    boostTime: 50,
    random: (function(){
        const gen = random.create();
        return {
            seed(seed) {
                gen.seed(seed);
            },
            range(highLow) {
                return gen.intBetween(...highLow);
            }
        };
    }()),
    ioFrequencyRange: [100, 1000],
    jobRuntimeRange: [1, 10],
    numJobsRange: [1, 1],
    jobCreateTimeRange: [1, 3],
    ioLengthRange: [0, 10]
});
export default scheduler;<|endoftext|>


<commit_before>import { debounce, Component, keys, platform } from 'substance'

const UPDATE_DELAY = 300

export default class FindAndReplaceDialog extends Component {
  constructor (...args) {
    super(...args)

    // debounce updates when patterns change, but not during tests
    if (!platform.test) {
      this._updatePattern = debounce(this._updatePattern.bind(this), UPDATE_DELAY)
      this._updateReplacePattern = debounce(this._updateReplacePattern.bind(this), UPDATE_DELAY)
    }
  }

  didMount () {
    this.context.appState.addObserver(['findAndReplace'], this._onUpdate, this, { stage: 'render' })
  }

  dispose () {
    this.context.appState.removeObserver(this)
  }

  render ($$) {
    let state = this._getState()
    let el = $$('div').addClass('sc-find-and-replace-dialog')
    el.append(
      this._renderHeader($$),
      this._renderFindSection($$),
      this._renderReplaceSection($$)
    )
    if (!state.enabled) {
      el.addClass('sm-hidden')
    }
    el.on('keydown', this._onKeydown)
    return el
  }

  _renderTitle ($$) {
    const state = this._getState()
    let title = state.showReplace ? this.getLabel(`find-replace-title-${this.props.viewName}`) : this.getLabel(`find-title-${this.props.viewName}`)
    let options = []
    if (state.caseSensitive) options.push('case-sensitive-title')
    if (state.fullWord) options.push('whole-word-title')
    if (state.regexSearch) options.push('regex-title')
    if (options.length > 0) title += ' (' + options.map(o => this.getLabel(o)).join(', ') + ')'
    return $$('div').addClass('se-title').append(title)
  }

  _renderHeader ($$) {
    const state = this._getState()
    const Button = this.getComponent('button')
    return $$('div').addClass('se-header').append(
      this._renderTitle($$),
      $$('div').addClass('se-group sm-options').append(
        $$(Button, {
          tooltip: this.getLabel('find-case-sensitive'),
          active: state.caseSensitive,
          theme: this.props.theme
        }).addClass('sm-case-sensitive').append('Aa')
          .on('click', this._toggleCaseSensitivity),
        $$(Button, {
          tooltip: this.getLabel('find-whole-word'),
          active: state.fullWord,
          theme: this.props.theme
        }).addClass('sm-whole-word').append('Abc|')
          .on('click', this._toggleFullWordSearch),
        $$(Button, {
          tooltip: this.getLabel('find-regex'),
          active: state.regexSearch,
          theme: this.props.theme
        }).addClass('sm-regex-search').append('.*')
          .on('click', this._toggleRegexSearch),
        $$(Button, {
          tooltip: this.getLabel('close'),
          theme: this.props.theme
        }).addClass('sm-close')
          .append(
            this.context.iconProvider.renderIcon($$, 'close')
          )
          .on('click', this._close)
      )
    )
  }

  _renderFindSection ($$) {
    const state = this._getState()
    const Button = this.getComponent('button')
    return $$('div').addClass('se-section').addClass('sm-find').append(
      $$('div').addClass('se-group sm-input').append(
        this._renderPatternInput($$),
        this._renderStatus($$)
      ),
      $$('div').addClass('se-group sm-actions').append(
        $$(Button, {
          tooltip: this.getLabel('find-next'),
          theme: this.props.theme,
          disabled: state.count < 1
        }).addClass('sm-next')
          .append(this.getLabel('next'))
          .on('click', this._findNext),
        $$(Button, {
          tooltip: this.getLabel('find-previous'),
          theme: this.props.theme,
          disabled: state.count < 1
        }).addClass('sm-previous')
          .append(this.getLabel('previous'))
          .on('click', this._findPrevious)
      )
    )
  }

  _renderReplaceSection ($$) {
    let state = this._getState()
    if (state.showReplace) {
      const Button = this.getComponent('button')
      return $$('div').addClass('se-section').addClass('sm-replace').append(
        $$('div').addClass('se-group sm-input').append(
          this._renderReplacePatternInput($$)
        ),
        $$('div').addClass('se-group sm-actions').append(
          $$(Button, {
            tooltip: this.getLabel('replace'),
            theme: this.props.theme,
            disabled: state.count < 1
          }).addClass('sm-replace')
            .append(this.getLabel('replace'))
            .on('click', this._replaceNext),
          $$(Button, {
            tooltip: this.getLabel('replace-all'),
            theme: this.props.theme,
            disabled: state.count < 1
          }).addClass('sm-replace-all')
            .append(this.getLabel('replace-all'))
            .on('click', this._replaceAll)
        )
      )
    }
  }

  _renderPatternInput ($$) {
    let state = this._getState()
    return $$('input').ref('pattern')
      .attr({
        type: 'text',
        placeholder: this.getLabel('find'),
        'tabindex': 500
      })
      .val(state.pattern)
      .on('keydown', this._onPatternKeydown)
      .on('input', this._updatePattern)
  }

  _renderReplacePatternInput ($$) {
    let state = this._getState()
    return $$('input').ref('replacePattern')
      .attr({
        type: 'text',
        placeholder: this.getLabel('replace'),
        'tabindex': 500
      })
      .val(state.replacePattern)
      .on('keydown', this._onReplacePatternKeydown)
      .on('input', this._updateReplacePattern)
  }

  _renderStatus ($$) {
    let state = this._getState()
    let el = $$('span').addClass('se-status')
    if (state.count > 0) {
      let current = state.cursor === -1 ? '?' : String(state.cursor + 1)
      el.append(`${current} of ${state.count}`)
    } else if (state.pattern) {
      el.append(this.getLabel('no-result'))
    }
    return el
  }

  _grabFocus () {
    let state = this._getState()
    let input = state.showReplace ? this.refs.replacePattern : this.refs.pattern
    input.el.focus()
  }

  _getState () {
    return this.context.appState.get('findAndReplace')
  }

  _getManager () {
    return this.context.findAndReplaceManager
  }

  _close () {
    this._getManager().closeDialog()
  }

  _findNext () {
    this._getManager().next()
  }

  _findPrevious () {
    this._getManager().previous()
  }

  _replaceNext () {
    this._getManager().replaceNext()
  }

  _replaceAll () {
    this._getManager().replaceAll()
  }

  _updatePattern () {
    // console.log('FindAndReplaceDialog._updatePattern()', this.refs.pattern.val())
    this._getManager().setSearchPattern(this.refs.pattern.val())
  }

  _updateReplacePattern () {
    this._getManager().setReplacePattern(this.refs.replacePattern.val())
  }

  _toggleCaseSensitivity () {
    this._getManager().toggleCaseSensitivity()
  }

  _toggleFullWordSearch () {
    this._getManager().toggleFullWordSearch()
  }

  _toggleRegexSearch () {
    this._getManager().toggleRegexSearch()
  }

  _onUpdate () {
    // if this dialog is made visible, auto-focus the respective pattern input field
    // TODO: maybe we should let the app control this
    let wasHidden = this.el.hasClass('sm-hidden')
    this.rerender()
    let isHidden = this.el.hasClass('sm-hidden')
    if (wasHidden && !isHidden) {
      this._grabFocus()
    }
  }

  _onKeydown (e) {
    if (e.keyCode === keys.ESCAPE) {
      e.stopPropagation()
      e.preventDefault()
      this._close()
    }
  }

  _onPatternKeydown (e) {
    e.stopPropagation()
    if (e.keyCode === keys.ENTER) {
      e.preventDefault()
      this._findNext()
    }
  }

  _onReplacePatternKeydown (e) {
    e.stopPropagation()
    if (e.keyCode === keys.ENTER) {
      e.preventDefault()
      this._replaceNext()
    }
  }
}
<commit_msg>Let the editor get blurred when search field is focused.<commit_after>import { debounce, Component, keys, platform } from 'substance'

const UPDATE_DELAY = 300

export default class FindAndReplaceDialog extends Component {
  constructor (...args) {
    super(...args)

    // debounce updates when patterns change, but not during tests
    if (!platform.test) {
      this._updatePattern = debounce(this._updatePattern.bind(this), UPDATE_DELAY)
      this._updateReplacePattern = debounce(this._updateReplacePattern.bind(this), UPDATE_DELAY)
    }
  }

  didMount () {
    this.context.appState.addObserver(['findAndReplace'], this._onUpdate, this, { stage: 'render' })
  }

  dispose () {
    this.context.appState.removeObserver(this)
  }

  render ($$) {
    let state = this._getState()
    let el = $$('div').addClass('sc-find-and-replace-dialog')
    el.append(
      this._renderHeader($$),
      this._renderFindSection($$),
      this._renderReplaceSection($$)
    )
    if (!state.enabled) {
      el.addClass('sm-hidden')
    }
    el.on('keydown', this._onKeydown)
    return el
  }

  _renderTitle ($$) {
    const state = this._getState()
    let title = state.showReplace ? this.getLabel(`find-replace-title-${this.props.viewName}`) : this.getLabel(`find-title-${this.props.viewName}`)
    let options = []
    if (state.caseSensitive) options.push('case-sensitive-title')
    if (state.fullWord) options.push('whole-word-title')
    if (state.regexSearch) options.push('regex-title')
    if (options.length > 0) title += ' (' + options.map(o => this.getLabel(o)).join(', ') + ')'
    return $$('div').addClass('se-title').append(title)
  }

  _renderHeader ($$) {
    const state = this._getState()
    const Button = this.getComponent('button')
    return $$('div').addClass('se-header').append(
      this._renderTitle($$),
      $$('div').addClass('se-group sm-options').append(
        $$(Button, {
          tooltip: this.getLabel('find-case-sensitive'),
          active: state.caseSensitive,
          theme: this.props.theme
        }).addClass('sm-case-sensitive').append('Aa')
          .on('click', this._toggleCaseSensitivity),
        $$(Button, {
          tooltip: this.getLabel('find-whole-word'),
          active: state.fullWord,
          theme: this.props.theme
        }).addClass('sm-whole-word').append('Abc|')
          .on('click', this._toggleFullWordSearch),
        $$(Button, {
          tooltip: this.getLabel('find-regex'),
          active: state.regexSearch,
          theme: this.props.theme
        }).addClass('sm-regex-search').append('.*')
          .on('click', this._toggleRegexSearch),
        $$(Button, {
          tooltip: this.getLabel('close'),
          theme: this.props.theme
        }).addClass('sm-close')
          .append(
            this.context.iconProvider.renderIcon($$, 'close')
          )
          .on('click', this._close)
      )
    )
  }

  _renderFindSection ($$) {
    const state = this._getState()
    const Button = this.getComponent('button')
    return $$('div').addClass('se-section').addClass('sm-find').append(
      $$('div').addClass('se-group sm-input').append(
        this._renderPatternInput($$),
        this._renderStatus($$)
      ),
      $$('div').addClass('se-group sm-actions').append(
        $$(Button, {
          tooltip: this.getLabel('find-next'),
          theme: this.props.theme,
          disabled: state.count < 1
        }).addClass('sm-next')
          .append(this.getLabel('next'))
          .on('click', this._findNext),
        $$(Button, {
          tooltip: this.getLabel('find-previous'),
          theme: this.props.theme,
          disabled: state.count < 1
        }).addClass('sm-previous')
          .append(this.getLabel('previous'))
          .on('click', this._findPrevious)
      )
    )
  }

  _renderReplaceSection ($$) {
    let state = this._getState()
    if (state.showReplace) {
      const Button = this.getComponent('button')
      return $$('div').addClass('se-section').addClass('sm-replace').append(
        $$('div').addClass('se-group sm-input').append(
          this._renderReplacePatternInput($$)
        ),
        $$('div').addClass('se-group sm-actions').append(
          $$(Button, {
            tooltip: this.getLabel('replace'),
            theme: this.props.theme,
            disabled: state.count < 1
          }).addClass('sm-replace')
            .append(this.getLabel('replace'))
            .on('click', this._replaceNext),
          $$(Button, {
            tooltip: this.getLabel('replace-all'),
            theme: this.props.theme,
            disabled: state.count < 1
          }).addClass('sm-replace-all')
            .append(this.getLabel('replace-all'))
            .on('click', this._replaceAll)
        )
      )
    }
  }

  _renderPatternInput ($$) {
    let state = this._getState()
    return $$('input').ref('pattern')
      .attr({
        type: 'text',
        placeholder: this.getLabel('find'),
        'tabindex': 500
      })
      .val(state.pattern)
      .on('keydown', this._onPatternKeydown)
      .on('input', this._updatePattern)
      .on('focus', this._onFocus)
  }

  _renderReplacePatternInput ($$) {
    let state = this._getState()
    return $$('input').ref('replacePattern')
      .attr({
        type: 'text',
        placeholder: this.getLabel('replace'),
        'tabindex': 500
      })
      .val(state.replacePattern)
      .on('keydown', this._onReplacePatternKeydown)
      .on('input', this._updateReplacePattern)
  }

  _renderStatus ($$) {
    let state = this._getState()
    let el = $$('span').addClass('se-status')
    if (state.count > 0) {
      let current = state.cursor === -1 ? '?' : String(state.cursor + 1)
      el.append(`${current} of ${state.count}`)
    } else if (state.pattern) {
      el.append(this.getLabel('no-result'))
    }
    return el
  }

  _grabFocus () {
    let state = this._getState()
    let input = state.showReplace ? this.refs.replacePattern : this.refs.pattern
    input.el.focus()
  }

  _getState () {
    return this.context.appState.get('findAndReplace')
  }

  _getManager () {
    return this.context.findAndReplaceManager
  }

  _close () {
    this._getManager().closeDialog()
  }

  _findNext () {
    this._getManager().next()
  }

  _findPrevious () {
    this._getManager().previous()
  }

  _replaceNext () {
    this._getManager().replaceNext()
  }

  _replaceAll () {
    this._getManager().replaceAll()
  }

  _updatePattern () {
    // console.log('FindAndReplaceDialog._updatePattern()', this.refs.pattern.val())
    this._getManager().setSearchPattern(this.refs.pattern.val())
  }

  _updateReplacePattern () {
    this._getManager().setReplacePattern(this.refs.replacePattern.val())
  }

  _toggleCaseSensitivity () {
    this._getManager().toggleCaseSensitivity()
  }

  _toggleFullWordSearch () {
    this._getManager().toggleFullWordSearch()
  }

  _toggleRegexSearch () {
    this._getManager().toggleRegexSearch()
  }

  _onUpdate () {
    // if this dialog is made visible, auto-focus the respective pattern input field
    // TODO: maybe we should let the app control this
    let wasHidden = this.el.hasClass('sm-hidden')
    this.rerender()
    let isHidden = this.el.hasClass('sm-hidden')
    if (wasHidden && !isHidden) {
      this._grabFocus()
    }
  }

  _onKeydown (e) {
    if (e.keyCode === keys.ESCAPE) {
      e.stopPropagation()
      e.preventDefault()
      this._close()
    }
  }

  _onFocus (e) {
    e.stopPropagation()
    this.context.appState.set('isBlurred', true)
  }

  _onPatternKeydown (e) {
    e.stopPropagation()
    if (e.keyCode === keys.ENTER) {
      e.preventDefault()
      this._findNext()
    }
  }

  _onReplacePatternKeydown (e) {
    e.stopPropagation()
    if (e.keyCode === keys.ENTER) {
      e.preventDefault()
      this._replaceNext()
    }
  }
}
<|endoftext|>


<commit_before>var CmdParser = require('../lib/cmdparser');

module.exports = {

    testShowHelpWithNoParams: function(test){
        var cp = new CmdParser();
        var fakeArgs = ['node', 'foobar'];
        cp.run(fakeArgs);
        test.ok(); // TODO
        test.done();
    }
};
<commit_msg>renamed to command.test.js<commit_after><|endoftext|>


<commit_before>// Serve Views
// -----------
// Extend Node's HTTP http.ServerResponse object to serve views either from a cache (in production)
// or by generating them on-the-fly (in development)
// Note: Even though this is exactly what Express.js does, it's not best practice to extend Node's native
// objects and we don't be doing this in SocketStream 0.4

var cache, fs, http, pathlib, res, view;

require('colors');

fs = require('fs');

pathlib = require('path');

http = require('http');

view = require('./view');

// Cache each view in RAM when packing assets (i.e. production mode)
cache = {};

// Get hold of the 'response' object so we can extend it later
res = http.ServerResponse.prototype;

module.exports = function(ss, clients, options) {

  // Append the 'serveClient' method to the HTTP Response object
  res.serveClient = function(name) {
    var client, fileName, self, sendHTML;
    self = this;
    sendHTML = function(html, code) {
      if (code == null) {
        code = 200;
      }
      self.writeHead(code, {
        'Content-Length': Buffer.byteLength(html),
        'Content-Type': 'text/html, utf-8'
      });
      return self.end(html);
    };
    try {
      client = typeof name === 'string' && clients[name];
      if (client == null) {
        throw new Error('Unable to find single-page client: ' + name);
      }

      // Load packed HTML file
      if (options.packedAssets) {

        // Return from in-memory cache if possible
        if (!cache[name]) {
          fileName = pathlib.join(ss.root, options.dirs.assets, client.name, client.id + '.html');
          cache[name] = fs.readFileSync(fileName, 'utf8');
        }

        // Send to browser
        return sendHTML(cache[name]);
      } else {
        // Generate View from scratch in development
        return view(ss, client, options, sendHTML);
      }
    } catch (e) {
      // Never send stack trace to the browser, log it to the terminal instead
      sendHTML('Internal Server Error', 500);
      ss.log('Error: Unable to serve HTML!'.red);
      return ss.log(e);
    }
  };

  // Alias res.serveClient to keep compatibility with existing apps
  return res.serve = res.serveClient;
};<commit_msg>Fixed to 'Content-Type': 'text/html; charset=UTF-8'<commit_after>// Serve Views
// -----------
// Extend Node's HTTP http.ServerResponse object to serve views either from a cache (in production)
// or by generating them on-the-fly (in development)
// Note: Even though this is exactly what Express.js does, it's not best practice to extend Node's native
// objects and we don't be doing this in SocketStream 0.4

var cache, fs, http, pathlib, res, view;

require('colors');

fs = require('fs');

pathlib = require('path');

http = require('http');

view = require('./view');

// Cache each view in RAM when packing assets (i.e. production mode)
cache = {};

// Get hold of the 'response' object so we can extend it later
res = http.ServerResponse.prototype;

module.exports = function(ss, clients, options) {

  // Append the 'serveClient' method to the HTTP Response object
  res.serveClient = function(name) {
    var client, fileName, self, sendHTML;
    self = this;
    sendHTML = function(html, code) {
      if (code == null) {
        code = 200;
      }
      self.writeHead(code, {
        'Content-Length': Buffer.byteLength(html),
        'Content-Type': 'text/html; charset=UTF-8'
      });
      return self.end(html);
    };
    try {
      client = typeof name === 'string' && clients[name];
      if (client == null) {
        throw new Error('Unable to find single-page client: ' + name);
      }

      // Load packed HTML file
      if (options.packedAssets) {

        // Return from in-memory cache if possible
        if (!cache[name]) {
          fileName = pathlib.join(ss.root, options.dirs.assets, client.name, client.id + '.html');
          cache[name] = fs.readFileSync(fileName, 'utf8');
        }

        // Send to browser
        return sendHTML(cache[name]);
      } else {
        // Generate View from scratch in development
        return view(ss, client, options, sendHTML);
      }
    } catch (e) {
      // Never send stack trace to the browser, log it to the terminal instead
      sendHTML('Internal Server Error', 500);
      ss.log('Error: Unable to serve HTML!'.red);
      return ss.log(e);
    }
  };

  // Alias res.serveClient to keep compatibility with existing apps
  return res.serve = res.serveClient;
};
<|endoftext|>


<commit_before>var Scrambler = (function() {
  var list = [];

  function register(scrambler) {
    list.push(scrambler);
  }

  function get(index) {
    return list[index];
  }

  return {
    register: register,
    get: get
  };
});

if (typeof module !== 'undefined')
  module.exports = Scrambler;
<commit_msg>Add Scrambler.length()<commit_after>var Scrambler = (function() {
  var list = [];

  function register(scrambler) {
    list.push(scrambler);
  }

  function get(index) {
    return list[index];
  }

  function length() {
    return list.length;
  }

  return {
    register: register,
    get: get,
    length: length
  };
});

if (typeof module !== 'undefined')
  module.exports = Scrambler;
<|endoftext|>


<commit_before>/* global $:false,bootbox,document,BootBoxWiz,Server,processPanelMessages,processDataSourceMessages,displayPanelDialog,WidgetManager, AgileSprintManager, JenkinsBuildManager */

/*
 * Main javascript logic for index.html
 *
 * Dependancies:
 *    jquery
 *    css/styles.css
 */

var server = null;
var addPanelMode = false;
var panelDragAndDrop;
var agileSprintManager = null;
var jenkinsBuildManager = null;
var widgetManager = null;
var dataSourceManager = null;
var preferenceManager = null;
// TODO: refactor this to get rid of globals
var configMode = false;

function configureApplication() {
  widgetManager = new WidgetManager();
  agileSprintManager = new AgileSprintManager({widgetManager: widgetManager});
  jenkinsBuildManager = new JenkinsBuildManager({widgetManager: widgetManager});
  dataSourceManager = new DataSourceManager();
  preferenceManager = new PreferenceManager();

  addApplicationButtonListeners();

  // apply select picker styling
  $('.selectpicker').selectpicker();

  // apply jasny rowlink logic to tables
  // $('tbody.rowlink').rowlink();

  server = new Server({
    messageHandlers: [
      processPanelMessages,
      dataSourceManager.processMessages.bind(dataSourceManager),
      preferenceManager.processMessages.bind(preferenceManager),
      widgetManager.processMessages.bind(widgetManager),
      agileSprintManager.processMessages.bind(agileSprintManager),
      jenkinsBuildManager.processMessages.bind(jenkinsBuildManager),
    ]
  });

  widgetManager.server = server;
  widgetManager.dataSourceManager = dataSourceManager;
  dataSourceManager.server = server;
  preferenceManager.server = server;
  server.connect();

  panelDragAndDrop = new PanelDragAndDrop({
    server: server,
    columnSelector: ".column",
    panelSelector: ".panel",
    handle: ".panel-heading",
    placeholderClass: "panel-placeholder",
    doNotSelect: ".panel-controls",
    dragClass: "draggable",
  });
}

function addApplicationButtonListeners() {

  $("body").on('change', '#toggleConfigMode', function() {
    toggleConfigMode();
  });

  $("body").on('click', '#viewHome', function() {
    toggleButtonViewSelection('viewHome');
    showAddPanelButton();
    displayPane("homePane");
  });

  $("body").on('click', '#viewSettings', function() {
    toggleButtonViewSelection('viewSettings');
    hideAddPanelButton();
    displayPane("settingsPane");
  });

  $("body").on('click', '#viewThemes', function() {
    toggleButtonViewSelection('viewThemes');
    hideAddPanelButton();
    displayPane("themesPane");
  });

  $("body").on('click', '#viewContent', function() {
    toggleButtonViewSelection('viewContent');
    hideAddPanelButton();
    displayPane("bannerContentPane");
  });

  $("#viewDataSources").on('click', function() {
    toggleButtonViewSelection('viewDataSources');
    hideAddPanelButton();
    displayPane("dataSourcesPane");
  });

  $("body").on('click', '#addPanel', function() {
    displayPanelDialog('add');
  });

  // TODO: better manage adding triggers for sub areas
  dataSourceManager.setupDataSourcesPane();
  preferenceManager.setupPreferencesPane();
}

function enableConfigMode() {
  configMode = true;
  $(".config-buttons").fadeIn("slow", function() {}).addClass('displayButton').css('display', '');
  panelDragAndDrop.enable();
  widgetManager.enableConfigMode();
}

function disableConfigMode() {
  configMode = false;
  var currentPaneId = $('.activePane').attr('id');

  if(currentPaneId !== "") {
    $("#viewHome").trigger('click');
  }

  panelDragAndDrop.disable();
  widgetManager.disableConfigMode();
  $(".config-buttons").fadeOut("slow", function() {$(".config-buttons").css("display", ""); }).removeClass('displayButton');
}

function toggleConfigMode() {
  if(configMode) {
    disableConfigMode();
  } else {
    enableConfigMode();
    addPanelMode = true;
  }
}

function toggleButtonViewSelection(buttonId) {
  var previousId = $('.config-button-active').attr('id');

  $('#' + previousId).toggleClass('config-button-inactive');
  $('#' + previousId).toggleClass('config-button-active');

  $('#' + buttonId).toggleClass('config-button-inactive');
  $('#' + buttonId).toggleClass('config-button-active');
}

function showAddPanelButton() {
  showPanelButton('addPanel');
  addPanelMode = true;
}

function hideAddPanelButton() {
  hidePanelButton('addPanel');
  addPanelMode = false;
}

function showPanelButton(buttonId) {
  $('#' + buttonId).removeClass('hiddenButton');
  panelDragAndDrop.enable();
  widgetManager.enableConfigMode();
}

function hidePanelButton(buttonId) {
  $('#' + buttonId).addClass('hiddenButton');
  panelDragAndDrop.disable();
  widgetManager.disableConfigMode();
}

function displayPane(paneId) {
  var previousId = $('.activePane').attr('id');

  if(previousId === paneId) {
    return;
  }

  $('#' + previousId).fadeToggle("fast", function() {
    $(this).toggleClass('activePane');
    $('#' + paneId).fadeToggle("fast", function() {
      $(this).toggleClass('activePane');
    });
  });
}

function viewDataSourceDetailPane(key) {
  displayPane("dataSourceDetail");
}<commit_msg>Added local preference support<commit_after>/* global $:false,bootbox,document,BootBoxWiz,Server,processPanelMessages,processDataSourceMessages,displayPanelDialog,WidgetManager, AgileSprintManager, JenkinsBuildManager */

/*
 * Main javascript logic for index.html
 *
 * Dependancies:
 *    jquery
 *    css/styles.css
 */

var server = null;
var addPanelMode = false;
var panelDragAndDrop;
var agileSprintManager = null;
var jenkinsBuildManager = null;
var widgetManager = null;
var dataSourceManager = null;
var preferenceManager = null;
var localPreferenceManager = null;
// TODO: refactor this to get rid of globals
var configMode = false;

function configureApplication() {
  widgetManager = new WidgetManager();
  agileSprintManager = new AgileSprintManager({widgetManager: widgetManager});
  jenkinsBuildManager = new JenkinsBuildManager({widgetManager: widgetManager});
  dataSourceManager = new DataSourceManager();
  preferenceManager = new PreferenceManager();
  localPreferenceManager = new LocalPreferenceManager();

  addApplicationButtonListeners();

  // apply select picker styling
  $('.selectpicker').selectpicker();

  // apply jasny rowlink logic to tables
  // $('tbody.rowlink').rowlink();

  server = new Server({
    messageHandlers: [
      processPanelMessages,
      dataSourceManager.processMessages.bind(dataSourceManager),
      preferenceManager.processMessages.bind(preferenceManager),
      localPreferenceManager.processMessages.bind(localPreferenceManager),
      widgetManager.processMessages.bind(widgetManager),
      agileSprintManager.processMessages.bind(agileSprintManager),
      jenkinsBuildManager.processMessages.bind(jenkinsBuildManager),
    ]
  });

  widgetManager.server = server;
  widgetManager.dataSourceManager = dataSourceManager;
  dataSourceManager.server = server;
  preferenceManager.server = server;
  localPreferenceManager.server = server;
  server.connect();

  panelDragAndDrop = new PanelDragAndDrop({
    server: server,
    columnSelector: ".column",
    panelSelector: ".panel",
    handle: ".panel-heading",
    placeholderClass: "panel-placeholder",
    doNotSelect: ".panel-controls",
    dragClass: "draggable",
  });
}

function addApplicationButtonListeners() {

  $("body").on('change', '#toggleConfigMode', function() {
    toggleConfigMode();
  });

  $("body").on('click', '#viewHome', function() {
    toggleButtonViewSelection('viewHome');
    showAddPanelButton();
    displayPane("homePane");
  });

  $("body").on('click', '#viewSettings', function() {
    toggleButtonViewSelection('viewSettings');
    hideAddPanelButton();
    displayPane("settingsPane");
  });

  $("body").on('click', '#viewThemes', function() {
    toggleButtonViewSelection('viewThemes');
    hideAddPanelButton();
    displayPane("themesPane");
  });

  $("body").on('click', '#viewContent', function() {
    toggleButtonViewSelection('viewContent');
    hideAddPanelButton();
    displayPane("bannerContentPane");
  });

  $("#viewDataSources").on('click', function() {
    toggleButtonViewSelection('viewDataSources');
    hideAddPanelButton();
    displayPane("dataSourcesPane");
  });

  $("body").on('click', '#addPanel', function() {
    displayPanelDialog('add');
  });

  // TODO: better manage adding triggers for sub areas
  dataSourceManager.setupDataSourcesPane();
  preferenceManager.setupPreferencesPane();
  localPreferenceManager.setupLocalPreferencesPane();
}

function enableConfigMode() {
  configMode = true;
  $(".config-buttons").fadeIn("slow", function() {}).addClass('displayButton').css('display', '');
  panelDragAndDrop.enable();
  widgetManager.enableConfigMode();
}

function disableConfigMode() {
  configMode = false;
  var currentPaneId = $('.activePane').attr('id');

  if(currentPaneId !== "") {
    $("#viewHome").trigger('click');
  }

  panelDragAndDrop.disable();
  widgetManager.disableConfigMode();
  $(".config-buttons").fadeOut("slow", function() {$(".config-buttons").css("display", ""); }).removeClass('displayButton');
}

function toggleConfigMode() {
  if(configMode) {
    disableConfigMode();
  } else {
    enableConfigMode();
    addPanelMode = true;
  }
}

function toggleButtonViewSelection(buttonId) {
  var previousId = $('.config-button-active').attr('id');

  $('#' + previousId).toggleClass('config-button-inactive');
  $('#' + previousId).toggleClass('config-button-active');

  $('#' + buttonId).toggleClass('config-button-inactive');
  $('#' + buttonId).toggleClass('config-button-active');
}

function showAddPanelButton() {
  showPanelButton('addPanel');
  addPanelMode = true;
}

function hideAddPanelButton() {
  hidePanelButton('addPanel');
  addPanelMode = false;
}

function showPanelButton(buttonId) {
  $('#' + buttonId).removeClass('hiddenButton');
  panelDragAndDrop.enable();
  widgetManager.enableConfigMode();
}

function hidePanelButton(buttonId) {
  $('#' + buttonId).addClass('hiddenButton');
  panelDragAndDrop.disable();
  widgetManager.disableConfigMode();
}

function displayPane(paneId) {
  var previousId = $('.activePane').attr('id');

  if(previousId === paneId) {
    return;
  }

  $('#' + previousId).fadeToggle("fast", function() {
    $(this).toggleClass('activePane');
    $('#' + paneId).fadeToggle("fast", function() {
      $(this).toggleClass('activePane');
    });
  });
}

function viewDataSourceDetailPane(key) {
  displayPane("dataSourceDetail");
}<|endoftext|>


<commit_before>'use strict'

var signalingFactory = require('../../../lib/signaling/in-band/factory')
var util = require('util')
var UdpTransport = require('../../../lib/transports/udp')

function FilteringUdpTransport (args) {
  if (!(this instanceof FilteringUdpTransport)) {
    return new FilteringUdpTransport(args)
  }
  // init
  this.filter = function () {
    // drop no messages
    return false
  }
  UdpTransport.call(this, args)
}

// Inherit from UdpSession
util.inherits(FilteringUdpTransport, UdpTransport)

FilteringUdpTransport.prototype._onIncomingBytes = function (bytes, rinfo) {
  var message = signalingFactory.parse(bytes)
  // if message passes the filter test
  if (this.filter(message)) {
    console.log('FilteringUdpTransport -- IGNORING message ' + message.type.toString(16) + ' ' + JSON.stringify(message) + ' from ' + JSON.stringify(rinfo))
    // then return -- dropping request on the floor
    return
  }
  // console.log('FilteringUdpTransport -- PROCESSING message ' + message.type.toString(16) + ' ' + JSON.stringify(message) + ' from ' + JSON.stringify(rinfo))
  FilteringUdpTransport.super_.prototype._onIncomingBytes.call(this, bytes, rinfo)
}

FilteringUdpTransport.prototype.dropMessage = function (messageType) {
  this.filter = function (message) {
    if (message.type === messageType) {
      return true
    }
  }
}

module.exports = FilteringUdpTransport
<commit_msg>update length signaling type bytes<commit_after>'use strict'

var signalingFactory = require('../../../lib/signaling/in-band/factory')
var util = require('util')
var UdpTransport = require('../../../lib/transports/udp')

function FilteringUdpTransport (args) {
  if (!(this instanceof FilteringUdpTransport)) {
    return new FilteringUdpTransport(args)
  }
  // init
  this.filter = function () {
    // drop no messages
    return false
  }
  UdpTransport.call(this, args)
}

// Inherit from UdpSession
util.inherits(FilteringUdpTransport, UdpTransport)

FilteringUdpTransport.prototype._onIncomingBytes = function (bytes, rinfo) {
  var message = signalingFactory.parseTransportPacket(bytes)
  // if message passes the filter test
  if (this.filter(message)) {
    console.log('FilteringUdpTransport -- IGNORING message ' + message.type + ' ' + JSON.stringify(message) + ' from ' + JSON.stringify(rinfo))
    // then return -- dropping request on the floor
    return
  }
  // console.log('FilteringUdpTransport -- PROCESSING message ' + message.type + ' ' + JSON.stringify(message) + ' from ' + JSON.stringify(rinfo))
  FilteringUdpTransport.super_.prototype._onIncomingBytes.call(this, bytes, rinfo)
}

FilteringUdpTransport.prototype.dropMessage = function (messageType) {
  this.filter = function (message) {
    if (message.type === messageType) {
      return true
    }
  }
}

module.exports = FilteringUdpTransport
<|endoftext|>