<commit_before>/**
 * Settings Controller.
 *
 * Manages gateway settings.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

'use strict';

/* jshint unused:false */

const CertificateManager = require('../certificate-manager');
const config = require('config');
const fetch = require('node-fetch');
const mDNSserver = require('../mdns-server');
const Platform = require('../platform');
const pkg = require('../../package.json');
const PromiseRouter = require('express-promise-router');
const Settings = require('../models/settings');
const TunnelService = require('../ssltunnel');

const SettingsController = PromiseRouter();

/**
 * Set an experiment setting.
 */
SettingsController.put(
  '/experiments/:experimentName',
  async (request, response) => {
    const experimentName = request.params.experimentName;

    if (!request.body || !request.body.hasOwnProperty('enabled')) {
      response.status(400).send('Enabled property not defined');
      return;
    }

    const enabled = request.body.enabled;

    try {
      const result =
        await Settings.set(`experiments.${experimentName}.enabled`,
                           enabled);
      response.status(200).json({enabled: result});
    } catch (e) {
      console.error(`Failed to set setting experiments.${experimentName}`);
      console.error(e);
      response.status(400).send(e);
    }
  });

/**
 * Get an experiment setting.
 */
SettingsController.get(
  '/experiments/:experimentName',
  async (request, response) => {
    const experimentName = request.params.experimentName;

    try {
      const result =
        await Settings.get(`experiments.${experimentName}.enabled`);
      if (typeof result === 'undefined') {
        response.status(404).send('Setting not found');
      } else {
        response.status(200).json({enabled: result});
      }
    } catch (e) {
      console.error(`Failed to get setting experiments.${experimentName}`);
      console.error(e);
      response.status(400).send(e);
    }
  });

SettingsController.post('/reclaim', async (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('subdomain')) {
    response.statusMessage = 'Subdomain missing from request';
    response.status(400).end();
    return;
  }

  const subdomain = request.body.subdomain;

  try {
    await fetch(`${config.get('ssltunnel.registration_endpoint')
    }/reclaim?name=${subdomain}`);
    response.status(200).end();
  } catch (e) {
    console.error(e);
    response.statusMessage = `Error reclaiming domain - ${e}`;
    response.status(400).end();
  }
});

SettingsController.post('/subscribe', async (request, response) => {
  if (!request.body ||
      !request.body.hasOwnProperty('email') ||
      !request.body.hasOwnProperty('subdomain') ||
      !request.body.hasOwnProperty('optout')) {
    response.statusMessage = 'Invalid request';
    response.status(400).end();
    return;
  }

  const email = request.body.email.trim().toLowerCase();
  const reclamationToken = request.body.reclamationToken.trim().toLowerCase();
  const subdomain = request.body.subdomain.trim().toLowerCase();
  const fulldomain = `${subdomain}.${config.get('ssltunnel.domain')}`;
  const optout = request.body.optout ? 1 : 0;

  function cb(err) {
    if (err) {
      response.statusMessage = `Error issuing certificate - ${err}`;
      response.status(400).end();
    } else {
      const endpoint =
        `https://${subdomain}.${config.get('ssltunnel.domain')}`;
      TunnelService.start(response, endpoint);
      TunnelService.switchToHttps();
    }
  }

  await CertificateManager.register(
    email,
    reclamationToken,
    subdomain,
    fulldomain,
    optout,
    cb
  );
});

SettingsController.post('/skiptunnel', async (request, response) => {
  try {
    await Settings.set('notunnel', true);
    response.status(200).end();
  } catch (e) {
    console.error('Failed to set notunnel setting.');
    console.error(e);
    response.status(400).send(e);
  }
});

SettingsController.get('/tunnelinfo', async (request, response) => {
  try {
    const localDomainSettings = await Settings.getTunnelInfo();
    response.send(localDomainSettings);
    response.status(200).end();
  } catch (e) {
    console.error('Failed to retrieve default settings for ' +
      'tunneltoken or local service discovery setting');
    console.error(e);
    response.status(400).send(e);
  }
});

/* This is responsible for controlling dynamically the local domain name
 * settings (via mDNS) and changing or updating mozilla tunnel endpoints.
 * The /domain endpoint is invoked from:
 *   MainMenu -> Settings -> Doamin
 *
 * JSON data: {
 *              local: {
 *                multicastDNSstate: boolean,
 *                localDNSname: string, - e.g. MyHome
 *              },
 *              mozillaTunnel: {
 *                tunnel: boolean,
 *                tunnelName: string, - e.g. MyName
 *                tunnelEmail: string
 *              }
 *            }
 */
SettingsController.put('/domain', async (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('local')) {
    response.statusMessage = 'Invalid request.';
    response.status(400).end();
    return;
  }

  try {
    if (request.body.local.hasOwnProperty('localDNSname')) {
      const requestDomainName = request.body.local.localDNSname;
      await Settings.set('localDNSname', requestDomainName);
      mDNSserver.server.setLocalDomain(requestDomainName);
    } else if (request.body.local.hasOwnProperty('multicastDNSstate')) {
      const requestState = request.body.local.multicastDNSstate;
      await Settings.set('multicastDNSstate', requestState);
      mDNSserver.server.setState(requestState);
    } else {
      response.statusMessage = 'Invalid request.';
      response.status(400).end();
      return;
    }

    let protocol, port;
    if (request.secure) {
      protocol = 'https';
      port = config.get('ports.https');
    } else {
      protocol = 'http';
      port = config.get('ports.http');
    }

    const url = `${protocol}://${mDNSserver.server.localDomain}.local:${port}`;
    const localDomainSettings = {localDomain: url,
                                 update: true,
                                 mDNSstate: mDNSserver.server.serviceState};
    response.status(200).json(localDomainSettings);
  } catch (err) {
    console.error(`Failed setting domain with: ${err} `);
    const localDomainSettings = {localDomain: mDNSserver.server.localDomain,
                                 update: false,
                                 mDNSstate: mDNSserver.server.serviceState,
                                 error: err.message};
    response.status(400).json(localDomainSettings);
  }
});

SettingsController.get('/addonsInfo', (request, response) => {
  response.json({
    urls: config.get('addonManager.listUrls'),
    api: config.get('addonManager.api'),
    architecture: Platform.getArchitecture(),
    version: pkg.version,
    nodeVersion: Platform.getNodeVersion(),
    pythonVersions: Platform.getPythonVersions(),
    testAddons: config.get('addonManager.testAddons'),
  });
});

SettingsController.get('/system/platform', (request, response) => {
  response.json({
    architecture: Platform.getArchitecture(),
    os: Platform.getOS(),
  });
});

SettingsController.get('/system/ssh', (request, response) => {
  const toggleImplemented = Platform.implemented('setSshServerStatus');
  let enabled = false;
  if (Platform.implemented('getSshServerStatus')) {
    enabled = Platform.getSshServerStatus();
  }

  response.json({
    toggleImplemented,
    enabled,
  });
});

SettingsController.put('/system/ssh', (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('enabled')) {
    response.status(400).send('Enabled property not defined');
    return;
  }

  const toggleImplemented = Platform.implemented('setSshServerStatus');
  if (toggleImplemented) {
    const enabled = request.body.enabled;
    if (Platform.setSshServerStatus(enabled)) {
      response.status(200).json({enabled});
    } else {
      response.status(400).send('Failed to toggle SSH');
    }
  } else {
    response.status(500).send('Toggle SSH not implemented');
  }
});

SettingsController.post('/system/actions', (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('action')) {
    response.status(400).send('Action property not defined');
    return;
  }

  const action = request.body.action;
  switch (action) {
    case 'restartGateway':
      if (Platform.implemented('restartGateway')) {
        if (Platform.restartGateway()) {
          response.status(200).end();
        } else {
          response.status(500).send('Failed to restart gateway');
        }
      } else {
        response.status(500).send('Restart gateway not implemented');
      }
      break;
    case 'restartSystem':
      if (Platform.implemented('restartSystem')) {
        if (Platform.restartSystem()) {
          response.status(200).end();
        } else {
          response.status(500).send('Failed to restart system');
        }
      } else {
        response.status(500).send('Restart system not implemented');
      }
      break;
    default:
      response.status(400).send('Unsupported action');
      break;
  }
});

SettingsController.get('/network/dhcp', (request, response) => {
  if (Platform.implemented('getDhcpServerStatus')) {
    response.json({enabled: Platform.getDhcpServerStatus()});
  } else {
    response.status(500).send('DHCP status not implemented');
  }
});

SettingsController.put('/network/dhcp', (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('enabled')) {
    response.status(400).send('Missing enabled property');
    return;
  }

  const enabled = request.body.enabled;

  if (Platform.implemented('setDhcpServerStatus')) {
    if (Platform.setDhcpServerStatus(enabled)) {
      response.status(200).end();
    } else {
      response.status(500).send('Failed to toggle DHCP');
    }
  } else {
    response.status(500).send('Toggle DHCP not implemented');
  }
});

SettingsController.get('/network/lan', (request, response) => {
  if (Platform.implemented('getLanMode')) {
    response.json(Platform.getLanMode());
  } else {
    response.status(500).send('LAN mode not implemented');
  }
});

SettingsController.put('/network/lan', (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('mode')) {
    response.status(400).send('Missing mode property');
    return;
  }

  const mode = request.body.mode;
  const options = request.body.options;

  if (Platform.implemented('setLanMode')) {
    if (Platform.setLanMode(mode, options)) {
      response.status(200).end();
    } else {
      response.status(500).send('Failed to update LAN configuration');
    }
  } else {
    response.status(500).send('Setting LAN mode not implemented');
  }
});

SettingsController.get('/network/wan', (request, response) => {
  if (Platform.implemented('getWanMode')) {
    response.json(Platform.getWanMode());
  } else {
    response.status(500).send('WAN mode not implemented');
  }
});

SettingsController.put('/network/wan', (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('mode')) {
    response.status(400).send('Missing mode property');
    return;
  }

  const mode = request.body.mode;
  const options = request.body.options;

  if (Platform.implemented('setWanMode')) {
    if (Platform.setWanMode(mode, options)) {
      response.status(200).end();
    } else {
      response.status(500).send('Failed to update WAN configuration');
    }
  } else {
    response.status(500).send('Setting WAN mode not implemented');
  }
});

SettingsController.get('/network/wireless', (request, response) => {
  if (Platform.implemented('getWirelessMode')) {
    response.json(Platform.getWirelessMode());
  } else {
    response.status(500).send('Wireless mode not implemented');
  }
});

SettingsController.get('/network/wireless/networks', (request, response) => {
  if (Platform.implemented('scanWirelessNetworks')) {
    response.json(Platform.scanWirelessNetworks());
  } else {
    response.status(500).send('Wireless scanning not implemented');
  }
});

SettingsController.put('/network/wireless', (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('enabled')) {
    response.status(400).send('Missing enabled property');
    return;
  }

  const enabled = request.body.enabled;
  const mode = request.body.mode;
  const options = request.body.options;

  if (Platform.implemented('setWirelessMode')) {
    if (Platform.setWirelessMode(enabled, mode, options)) {
      response.status(200).end();
    } else {
      response.status(500).send('Failed to update wireless configuration');
    }
  } else {
    response.status(500).send('Setting wireless mode not implemented');
  }
});

SettingsController.get('/network/addresses', (request, response) => {
  if (Platform.implemented('getNetworkAddresses')) {
    response.json(Platform.getNetworkAddresses());
  } else {
    response.status(500).send('Network addresses not implemented');
  }
});

module.exports = SettingsController;
<commit_msg>Make most settings routes authenticated.<commit_after>/**
 * Settings Controller.
 *
 * Manages gateway settings.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

'use strict';

/* jshint unused:false */

const CertificateManager = require('../certificate-manager');
const config = require('config');
const fetch = require('node-fetch');
const jwtMiddleware = require('../jwt-middleware');
const mDNSserver = require('../mdns-server');
const Platform = require('../platform');
const pkg = require('../../package.json');
const PromiseRouter = require('express-promise-router');
const Settings = require('../models/settings');
const TunnelService = require('../ssltunnel');

const auth = jwtMiddleware.middleware();
const SettingsController = PromiseRouter();

/**
 * Set an experiment setting.
 */
SettingsController.put(
  '/experiments/:experimentName',
  auth,
  async (request, response) => {
    const experimentName = request.params.experimentName;

    if (!request.body || !request.body.hasOwnProperty('enabled')) {
      response.status(400).send('Enabled property not defined');
      return;
    }

    const enabled = request.body.enabled;

    try {
      const result =
        await Settings.set(`experiments.${experimentName}.enabled`,
                           enabled);
      response.status(200).json({enabled: result});
    } catch (e) {
      console.error(`Failed to set setting experiments.${experimentName}`);
      console.error(e);
      response.status(400).send(e);
    }
  });

/**
 * Get an experiment setting.
 */
SettingsController.get(
  '/experiments/:experimentName',
  auth,
  async (request, response) => {
    const experimentName = request.params.experimentName;

    try {
      const result =
        await Settings.get(`experiments.${experimentName}.enabled`);
      if (typeof result === 'undefined') {
        response.status(404).send('Setting not found');
      } else {
        response.status(200).json({enabled: result});
      }
    } catch (e) {
      console.error(`Failed to get setting experiments.${experimentName}`);
      console.error(e);
      response.status(400).send(e);
    }
  });

SettingsController.post('/reclaim', async (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('subdomain')) {
    response.statusMessage = 'Subdomain missing from request';
    response.status(400).end();
    return;
  }

  const subdomain = request.body.subdomain;

  try {
    await fetch(`${config.get('ssltunnel.registration_endpoint')
    }/reclaim?name=${subdomain}`);
    response.status(200).end();
  } catch (e) {
    console.error(e);
    response.statusMessage = `Error reclaiming domain - ${e}`;
    response.status(400).end();
  }
});

SettingsController.post('/subscribe', async (request, response) => {
  if (!request.body ||
      !request.body.hasOwnProperty('email') ||
      !request.body.hasOwnProperty('subdomain') ||
      !request.body.hasOwnProperty('optout')) {
    response.statusMessage = 'Invalid request';
    response.status(400).end();
    return;
  }

  const email = request.body.email.trim().toLowerCase();
  const reclamationToken = request.body.reclamationToken.trim().toLowerCase();
  const subdomain = request.body.subdomain.trim().toLowerCase();
  const fulldomain = `${subdomain}.${config.get('ssltunnel.domain')}`;
  const optout = request.body.optout ? 1 : 0;

  function cb(err) {
    if (err) {
      response.statusMessage = `Error issuing certificate - ${err}`;
      response.status(400).end();
    } else {
      const endpoint =
        `https://${subdomain}.${config.get('ssltunnel.domain')}`;
      TunnelService.start(response, endpoint);
      TunnelService.switchToHttps();
    }
  }

  await CertificateManager.register(
    email,
    reclamationToken,
    subdomain,
    fulldomain,
    optout,
    cb
  );
});

SettingsController.post('/skiptunnel', async (request, response) => {
  try {
    await Settings.set('notunnel', true);
    response.status(200).end();
  } catch (e) {
    console.error('Failed to set notunnel setting.');
    console.error(e);
    response.status(400).send(e);
  }
});

SettingsController.get('/tunnelinfo', auth, async (request, response) => {
  try {
    const localDomainSettings = await Settings.getTunnelInfo();
    response.send(localDomainSettings);
    response.status(200).end();
  } catch (e) {
    console.error('Failed to retrieve default settings for ' +
      'tunneltoken or local service discovery setting');
    console.error(e);
    response.status(400).send(e);
  }
});

/* This is responsible for controlling dynamically the local domain name
 * settings (via mDNS) and changing or updating mozilla tunnel endpoints.
 * The /domain endpoint is invoked from:
 *   MainMenu -> Settings -> Doamin
 *
 * JSON data: {
 *              local: {
 *                multicastDNSstate: boolean,
 *                localDNSname: string, - e.g. MyHome
 *              },
 *              mozillaTunnel: {
 *                tunnel: boolean,
 *                tunnelName: string, - e.g. MyName
 *                tunnelEmail: string
 *              }
 *            }
 */
SettingsController.put('/domain', auth, async (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('local')) {
    response.statusMessage = 'Invalid request.';
    response.status(400).end();
    return;
  }

  try {
    if (request.body.local.hasOwnProperty('localDNSname')) {
      const requestDomainName = request.body.local.localDNSname;
      await Settings.set('localDNSname', requestDomainName);
      mDNSserver.server.setLocalDomain(requestDomainName);
    } else if (request.body.local.hasOwnProperty('multicastDNSstate')) {
      const requestState = request.body.local.multicastDNSstate;
      await Settings.set('multicastDNSstate', requestState);
      mDNSserver.server.setState(requestState);
    } else {
      response.statusMessage = 'Invalid request.';
      response.status(400).end();
      return;
    }

    let protocol, port;
    if (request.secure) {
      protocol = 'https';
      port = config.get('ports.https');
    } else {
      protocol = 'http';
      port = config.get('ports.http');
    }

    const url = `${protocol}://${mDNSserver.server.localDomain}.local:${port}`;
    const localDomainSettings = {localDomain: url,
                                 update: true,
                                 mDNSstate: mDNSserver.server.serviceState};
    response.status(200).json(localDomainSettings);
  } catch (err) {
    console.error(`Failed setting domain with: ${err} `);
    const localDomainSettings = {localDomain: mDNSserver.server.localDomain,
                                 update: false,
                                 mDNSstate: mDNSserver.server.serviceState,
                                 error: err.message};
    response.status(400).json(localDomainSettings);
  }
});

SettingsController.get('/addonsInfo', auth, (request, response) => {
  response.json({
    urls: config.get('addonManager.listUrls'),
    api: config.get('addonManager.api'),
    architecture: Platform.getArchitecture(),
    version: pkg.version,
    nodeVersion: Platform.getNodeVersion(),
    pythonVersions: Platform.getPythonVersions(),
    testAddons: config.get('addonManager.testAddons'),
  });
});

SettingsController.get('/system/platform', auth, (request, response) => {
  response.json({
    architecture: Platform.getArchitecture(),
    os: Platform.getOS(),
  });
});

SettingsController.get('/system/ssh', auth, (request, response) => {
  const toggleImplemented = Platform.implemented('setSshServerStatus');
  let enabled = false;
  if (Platform.implemented('getSshServerStatus')) {
    enabled = Platform.getSshServerStatus();
  }

  response.json({
    toggleImplemented,
    enabled,
  });
});

SettingsController.put('/system/ssh', auth, (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('enabled')) {
    response.status(400).send('Enabled property not defined');
    return;
  }

  const toggleImplemented = Platform.implemented('setSshServerStatus');
  if (toggleImplemented) {
    const enabled = request.body.enabled;
    if (Platform.setSshServerStatus(enabled)) {
      response.status(200).json({enabled});
    } else {
      response.status(400).send('Failed to toggle SSH');
    }
  } else {
    response.status(500).send('Toggle SSH not implemented');
  }
});

SettingsController.post('/system/actions', auth, (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('action')) {
    response.status(400).send('Action property not defined');
    return;
  }

  const action = request.body.action;
  switch (action) {
    case 'restartGateway':
      if (Platform.implemented('restartGateway')) {
        if (Platform.restartGateway()) {
          response.status(200).end();
        } else {
          response.status(500).send('Failed to restart gateway');
        }
      } else {
        response.status(500).send('Restart gateway not implemented');
      }
      break;
    case 'restartSystem':
      if (Platform.implemented('restartSystem')) {
        if (Platform.restartSystem()) {
          response.status(200).end();
        } else {
          response.status(500).send('Failed to restart system');
        }
      } else {
        response.status(500).send('Restart system not implemented');
      }
      break;
    default:
      response.status(400).send('Unsupported action');
      break;
  }
});

SettingsController.get('/network/dhcp', auth, (request, response) => {
  if (Platform.implemented('getDhcpServerStatus')) {
    response.json({enabled: Platform.getDhcpServerStatus()});
  } else {
    response.status(500).send('DHCP status not implemented');
  }
});

SettingsController.put('/network/dhcp', auth, (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('enabled')) {
    response.status(400).send('Missing enabled property');
    return;
  }

  const enabled = request.body.enabled;

  if (Platform.implemented('setDhcpServerStatus')) {
    if (Platform.setDhcpServerStatus(enabled)) {
      response.status(200).end();
    } else {
      response.status(500).send('Failed to toggle DHCP');
    }
  } else {
    response.status(500).send('Toggle DHCP not implemented');
  }
});

SettingsController.get('/network/lan', auth, (request, response) => {
  if (Platform.implemented('getLanMode')) {
    response.json(Platform.getLanMode());
  } else {
    response.status(500).send('LAN mode not implemented');
  }
});

SettingsController.put('/network/lan', auth, (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('mode')) {
    response.status(400).send('Missing mode property');
    return;
  }

  const mode = request.body.mode;
  const options = request.body.options;

  if (Platform.implemented('setLanMode')) {
    if (Platform.setLanMode(mode, options)) {
      response.status(200).end();
    } else {
      response.status(500).send('Failed to update LAN configuration');
    }
  } else {
    response.status(500).send('Setting LAN mode not implemented');
  }
});

SettingsController.get('/network/wan', auth, (request, response) => {
  if (Platform.implemented('getWanMode')) {
    response.json(Platform.getWanMode());
  } else {
    response.status(500).send('WAN mode not implemented');
  }
});

SettingsController.put('/network/wan', auth, (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('mode')) {
    response.status(400).send('Missing mode property');
    return;
  }

  const mode = request.body.mode;
  const options = request.body.options;

  if (Platform.implemented('setWanMode')) {
    if (Platform.setWanMode(mode, options)) {
      response.status(200).end();
    } else {
      response.status(500).send('Failed to update WAN configuration');
    }
  } else {
    response.status(500).send('Setting WAN mode not implemented');
  }
});

SettingsController.get('/network/wireless', auth, (request, response) => {
  if (Platform.implemented('getWirelessMode')) {
    response.json(Platform.getWirelessMode());
  } else {
    response.status(500).send('Wireless mode not implemented');
  }
});

SettingsController.get(
  '/network/wireless/networks',
  auth,
  (request, response) => {
    if (Platform.implemented('scanWirelessNetworks')) {
      response.json(Platform.scanWirelessNetworks());
    } else {
      response.status(500).send('Wireless scanning not implemented');
    }
  }
);

SettingsController.put('/network/wireless', auth, (request, response) => {
  if (!request.body || !request.body.hasOwnProperty('enabled')) {
    response.status(400).send('Missing enabled property');
    return;
  }

  const enabled = request.body.enabled;
  const mode = request.body.mode;
  const options = request.body.options;

  if (Platform.implemented('setWirelessMode')) {
    if (Platform.setWirelessMode(enabled, mode, options)) {
      response.status(200).end();
    } else {
      response.status(500).send('Failed to update wireless configuration');
    }
  } else {
    response.status(500).send('Setting wireless mode not implemented');
  }
});

SettingsController.get('/network/addresses', auth, (request, response) => {
  if (Platform.implemented('getNetworkAddresses')) {
    response.json(Platform.getNetworkAddresses());
  } else {
    response.status(500).send('Network addresses not implemented');
  }
});

module.exports = SettingsController;
<|endoftext|>


<commit_before>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule shouldUpdateReactComponent
 * @typechecks static-only
 */

'use strict';

var warning = require('warning');

/**
 * Given a `prevElement` and `nextElement`, determines if the existing
 * instance should be updated as opposed to being destroyed or replaced by a new
 * instance. Both arguments are elements. This ensures that this logic can
 * operate on stateless trees without any backing instance.
 *
 * @param {?object} prevElement
 * @param {?object} nextElement
 * @return {boolean} True if the existing instance should be updated.
 * @protected
 */
function shouldUpdateReactComponent(prevElement, nextElement) {
  if (prevElement != null && nextElement != null) {
    var prevType = typeof prevElement;
    var nextType = typeof nextElement;
    if (prevType === 'string' || prevType === 'number') {
      return (nextType === 'string' || nextType === 'number');
    } else {
      if (nextType === 'object' &&
          prevElement.type === nextElement.type &&
          prevElement.key === nextElement.key) {
        var ownersMatch = prevElement._owner === nextElement._owner;
        var prevName = null;
        var nextName = null;
        var nextDisplayName = null;
        if (__DEV__) {
          if (!ownersMatch) {
            if (prevElement._owner != null &&
                prevElement._owner.getPublicInstance() != null &&
                prevElement._owner.getPublicInstance().constructor != null) {
              prevName =
                prevElement._owner.getPublicInstance().constructor.displayName;
            }
            if (nextElement._owner != null &&
                nextElement._owner.getPublicInstance() != null &&
                nextElement._owner.getPublicInstance().constructor != null) {
              nextName =
                nextElement._owner.getPublicInstance().constructor.displayName;
            }
            if (nextElement.type != null &&
                nextElement.type.displayName != null) {
              nextDisplayName = nextElement.type.displayName;
            }
            if (nextElement.type != null && typeof nextElement.type === 'string') {
              nextDisplayName = nextElement.type;
            }
            if (typeof nextElement.type !== 'string' ||
                nextElement.type === 'input' ||
                nextElement.type === 'textarea') {
              if ((prevElement._owner != null &&
                  prevElement._owner._isOwnerNecessary === false) ||
                  (nextElement._owner != null &&
                  nextElement._owner._isOwnerNecessary === false)) {
                if (prevElement._owner != null) {
                  prevElement._owner._isOwnerNecessary = true;
                }
                if (nextElement._owner != null) {
                  nextElement._owner._isOwnerNecessary = true;
                }
                warning(
                  false,
                  '<%s /> is being rendered by both %s and %s using the same ' +
                  'key (%s) in the same place. Currently, this means that ' +
                  'they don\'t preserve state. This behavior should be very ' +
                  'rare so we\'re considering deprecating it. Please contact ' +
                  'the React team and explain your use case so that we can ' +
                  'take that into consideration.',
                  nextDisplayName || 'Unknown Component',
                  prevName || '[Unknown]',
                  nextName || '[Unknown]',
                  prevElement.key
                );
              }
            }
          }
        }
        return ownersMatch;
      }
    }
  }
  return false;
}

module.exports = shouldUpdateReactComponent;
<commit_msg>initialize dev variables in dev mode only<commit_after>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule shouldUpdateReactComponent
 * @typechecks static-only
 */

'use strict';

var warning = require('warning');

/**
 * Given a `prevElement` and `nextElement`, determines if the existing
 * instance should be updated as opposed to being destroyed or replaced by a new
 * instance. Both arguments are elements. This ensures that this logic can
 * operate on stateless trees without any backing instance.
 *
 * @param {?object} prevElement
 * @param {?object} nextElement
 * @return {boolean} True if the existing instance should be updated.
 * @protected
 */
function shouldUpdateReactComponent(prevElement, nextElement) {
  if (prevElement != null && nextElement != null) {
    var prevType = typeof prevElement;
    var nextType = typeof nextElement;
    if (prevType === 'string' || prevType === 'number') {
      return (nextType === 'string' || nextType === 'number');
    } else {
      if (nextType === 'object' &&
          prevElement.type === nextElement.type &&
          prevElement.key === nextElement.key) {
        var ownersMatch = prevElement._owner === nextElement._owner;
        if (__DEV__) {
          if (!ownersMatch) {
            var prevName = null;
            var nextName = null;
            var nextDisplayName = null;
            if (prevElement._owner != null &&
                prevElement._owner.getPublicInstance() != null &&
                prevElement._owner.getPublicInstance().constructor != null) {
              prevName =
                prevElement._owner.getPublicInstance().constructor.displayName;
            }
            if (nextElement._owner != null &&
                nextElement._owner.getPublicInstance() != null &&
                nextElement._owner.getPublicInstance().constructor != null) {
              nextName =
                nextElement._owner.getPublicInstance().constructor.displayName;
            }
            if (nextElement.type != null &&
                nextElement.type.displayName != null) {
              nextDisplayName = nextElement.type.displayName;
            }
            if (nextElement.type != null && typeof nextElement.type === 'string') {
              nextDisplayName = nextElement.type;
            }
            if (typeof nextElement.type !== 'string' ||
                nextElement.type === 'input' ||
                nextElement.type === 'textarea') {
              if ((prevElement._owner != null &&
                  prevElement._owner._isOwnerNecessary === false) ||
                  (nextElement._owner != null &&
                  nextElement._owner._isOwnerNecessary === false)) {
                if (prevElement._owner != null) {
                  prevElement._owner._isOwnerNecessary = true;
                }
                if (nextElement._owner != null) {
                  nextElement._owner._isOwnerNecessary = true;
                }
                warning(
                  false,
                  '<%s /> is being rendered by both %s and %s using the same ' +
                  'key (%s) in the same place. Currently, this means that ' +
                  'they don\'t preserve state. This behavior should be very ' +
                  'rare so we\'re considering deprecating it. Please contact ' +
                  'the React team and explain your use case so that we can ' +
                  'take that into consideration.',
                  nextDisplayName || 'Unknown Component',
                  prevName || '[Unknown]',
                  nextName || '[Unknown]',
                  prevElement.key
                );
              }
            }
          }
        }
        return ownersMatch;
      }
    }
  }
  return false;
}

module.exports = shouldUpdateReactComponent;
<|endoftext|>


<commit_before>const debug = require('debug')('telegraf:api')
const crypto = require('crypto')
const fetch = require('node-fetch')
const fs = require('fs')
const https = require('https')
const path = require('path')
const TelegramError = require('./error')
const MultipartStream = require('./multipart-stream')

const { isStream } = MultipartStream

const webhookBlacklist = [
  'getChat',
  'getChatAdministrators',
  'getChatMember',
  'getChatMembersCount',
  'getFile',
  'getFileLink',
  'getGameHighScores',
  'getMe',
  'getUserProfilePhotos',
  'getWebhookInfo'
]

const defaultExtensions = {
  photo: 'jpg',
  audio: 'mp3',
  voice: 'ogg',
  sticker: 'webp',
  video: 'mp4'
}

const defaultOptions = {
  apiRoot: 'https://api.telegram.org',
  webhookReply: true,
  agent: new https.Agent({
    keepAlive: true,
    keepAliveMsecs: 10000
  })
}

function safeJSONParse (text) {
  try {
    return JSON.parse(text)
  } catch (err) {
    debug('JSON parse failed', err)
  }
}

class ApiClient {
  constructor (token, options, webhookResponse) {
    this.token = token
    this.options = Object.assign({}, defaultOptions, options)
    this.response = webhookResponse
  }

  set webhookReply (enable) {
    this.options.webhookReply = enable
  }

  get webhookReply () {
    return this.options.webhookReply
  }

  callApi (method, extra = {}) {
    const isMultipart = Object.keys(extra).find((x) => extra[x] && (extra[x].source || extra[x].url))
    if (this.options.webhookReply && this.response && !this.response.finished && !isMultipart && !webhookBlacklist.includes(method)) {
      debug('▷ webhook', method)
      extra.method = method
      if (!this.response.headersSent) {
        this.response.setHeader('connection', 'keep-alive')
        this.response.setHeader('content-type', 'application/json')
      }
      this.response.end(JSON.stringify(extra))
      return Promise.resolve({webhook: true})
    }

    if (!this.token) {
      throw new TelegramError({
        error_code: 401,
        description: 'Bot Token is required'
      })
    }

    debug('▶ http', method)
    const buildPayload = isMultipart ? this.buildFormDataPayload(extra) : this.buildJSONPayload(extra)
    return buildPayload
      .then((payload) => {
        payload.agent = this.options.agent
        return fetch(`${this.options.apiRoot}/bot${this.token}/${method}`, payload)
      })
      .then((res) => res.text())
      .then((text) => {
        return safeJSONParse(text) || {
          error_code: 500,
          description: 'Unsupported message from Telegram',
          response: text
        }
      })
      .then((data) => {
        if (!data.ok) {
          throw new TelegramError(data)
        }
        return data.result
      })
  }

  buildJSONPayload (options) {
    return Promise.resolve({
      method: 'POST',
      headers: { 'content-type': 'application/json', 'connection': 'keep-alive' },
      body: JSON.stringify(options)
    })
  }

  buildFormDataPayload (options) {
    if (options.reply_markup && typeof options.reply_markup !== 'string') {
      options.reply_markup = JSON.stringify(options.reply_markup)
    }
    const boundary = crypto.randomBytes(30).toString('hex')
    const formData = new MultipartStream(boundary)
    const tasks = Object.keys(options).filter((key) => options[key]).map((key) => {
      const value = options[key]
      const valueType = typeof value
      if (valueType === 'string' || valueType === 'boolean' || valueType === 'number') {
        return formData.addPart({
          headers: { 'content-disposition': `form-data; name="${key}"` },
          body: `${value}`
        })
      }
      let fileName = value.filename || `${key}.${defaultExtensions[key] || 'dat'}`
      if (value.url) {
        return fetch(value.url, { agent: this.options.agent }).then((res) => {
          formData.addPart({
            headers: { 'content-disposition': `form-data; name="${key}";filename="${fileName}"` },
            body: res.body
          })
        })
      }
      if (value.source) {
        if (fs.existsSync(value.source)) {
          fileName = value.filename || path.basename(value.source)
          value.source = fs.createReadStream(value.source)
        }
        if (isStream(value.source) || Buffer.isBuffer(value.source)) {
          return formData.addPart({
            headers: { 'content-disposition': `form-data; name="${key}";filename="${fileName}"` },
            body: value.source
          })
        }
      }
      throw new Error('Invalid file descriptor')
    })
    return Promise.all(tasks).then(() => {
      return {
        method: 'POST',
        headers: { 'content-type': `multipart/form-data; boundary=${boundary}`, 'connection': 'keep-alive' },
        body: formData
      }
    })
  }
}

module.exports = ApiClient
<commit_msg>remove agent for downloder. fix #104<commit_after>const debug = require('debug')('telegraf:api')
const crypto = require('crypto')
const fetch = require('node-fetch')
const fs = require('fs')
const https = require('https')
const path = require('path')
const TelegramError = require('./error')
const MultipartStream = require('./multipart-stream')

const { isStream } = MultipartStream

const webhookBlacklist = [
  'getChat',
  'getChatAdministrators',
  'getChatMember',
  'getChatMembersCount',
  'getFile',
  'getFileLink',
  'getGameHighScores',
  'getMe',
  'getUserProfilePhotos',
  'getWebhookInfo'
]

const defaultExtensions = {
  photo: 'jpg',
  audio: 'mp3',
  voice: 'ogg',
  sticker: 'webp',
  video: 'mp4'
}

const defaultOptions = {
  apiRoot: 'https://api.telegram.org',
  webhookReply: true,
  agent: new https.Agent({
    keepAlive: true,
    keepAliveMsecs: 10000
  })
}

function safeJSONParse (text) {
  try {
    return JSON.parse(text)
  } catch (err) {
    debug('JSON parse failed', err)
  }
}

class ApiClient {
  constructor (token, options, webhookResponse) {
    this.token = token
    this.options = Object.assign({}, defaultOptions, options)
    this.response = webhookResponse
  }

  set webhookReply (enable) {
    this.options.webhookReply = enable
  }

  get webhookReply () {
    return this.options.webhookReply
  }

  callApi (method, extra = {}) {
    const isMultipart = Object.keys(extra).find((x) => extra[x] && (extra[x].source || extra[x].url))
    if (this.options.webhookReply && this.response && !this.response.finished && !isMultipart && !webhookBlacklist.includes(method)) {
      debug('▷ webhook', method)
      extra.method = method
      if (!this.response.headersSent) {
        this.response.setHeader('connection', 'keep-alive')
        this.response.setHeader('content-type', 'application/json')
      }
      this.response.end(JSON.stringify(extra))
      return Promise.resolve({webhook: true})
    }

    if (!this.token) {
      throw new TelegramError({
        error_code: 401,
        description: 'Bot Token is required'
      })
    }

    debug('▶ http', method)
    const buildPayload = isMultipart ? this.buildFormDataPayload(extra) : this.buildJSONPayload(extra)
    return buildPayload
      .then((payload) => {
        payload.agent = this.options.agent
        return fetch(`${this.options.apiRoot}/bot${this.token}/${method}`, payload)
      })
      .then((res) => res.text())
      .then((text) => {
        return safeJSONParse(text) || {
          error_code: 500,
          description: 'Unsupported message from Telegram',
          response: text
        }
      })
      .then((data) => {
        if (!data.ok) {
          throw new TelegramError(data)
        }
        return data.result
      })
  }

  buildJSONPayload (options) {
    return Promise.resolve({
      method: 'POST',
      headers: { 'content-type': 'application/json', 'connection': 'keep-alive' },
      body: JSON.stringify(options)
    })
  }

  buildFormDataPayload (options) {
    if (options.reply_markup && typeof options.reply_markup !== 'string') {
      options.reply_markup = JSON.stringify(options.reply_markup)
    }
    const boundary = crypto.randomBytes(30).toString('hex')
    const formData = new MultipartStream(boundary)
    const tasks = Object.keys(options).filter((key) => options[key]).map((key) => {
      const value = options[key]
      const valueType = typeof value
      if (valueType === 'string' || valueType === 'boolean' || valueType === 'number') {
        return formData.addPart({
          headers: { 'content-disposition': `form-data; name="${key}"` },
          body: `${value}`
        })
      }
      let fileName = value.filename || `${key}.${defaultExtensions[key] || 'dat'}`
      if (value.url) {
        return fetch(value.url).then((res) => {
          formData.addPart({
            headers: { 'content-disposition': `form-data; name="${key}";filename="${fileName}"` },
            body: res.body
          })
        })
      }
      if (value.source) {
        if (fs.existsSync(value.source)) {
          fileName = value.filename || path.basename(value.source)
          value.source = fs.createReadStream(value.source)
        }
        if (isStream(value.source) || Buffer.isBuffer(value.source)) {
          return formData.addPart({
            headers: { 'content-disposition': `form-data; name="${key}";filename="${fileName}"` },
            body: value.source
          })
        }
      }
      throw new Error('Invalid file descriptor')
    })
    return Promise.all(tasks).then(() => {
      return {
        method: 'POST',
        headers: { 'content-type': `multipart/form-data; boundary=${boundary}`, 'connection': 'keep-alive' },
        body: formData
      }
    })
  }
}

module.exports = ApiClient
<|endoftext|>


<commit_before>'use strict';

var logger = require('./logger');
if (process.env.TWITTER_CONSUMER_KEY === undefined) {
	logger.info('Twitter notifications disabled as no key provided');
	return;
}

var Twitter = require('twitter');
var debug = require('debug')('echo:notify-twitter');

var models = require('../models');
var notify = require('./notify');

debug('Initialising twitter notifications');

let client = new Twitter({
	consumer_key: process.env.TWITTER_CONSUMER_KEY,
	consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
	access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,
	access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
});

function sendDirectMessage(params) {
	client.post('direct_messages/new', {
		screen_name: params.to,
		text: params.text
	}, function(error, response) {
		if (error) {
			logger.error(
					'Error sending new event tweet to %s',
					params.to, error);
		}
	})
}

notify.on('eventSubmitted', function(evt) {
	return models.User.findAll({
		where: { notify: { $like: 'twitter' } },
		attributes: [ 'twitter' ]
	}).then(function(users) {
		for (let user of users) {
			if (user.twitter) {
				sendDirectMessage({
					to: user.twitter,
					text: 'New event added: "' + evt.title + '" submitted'
				});
			}
		}
	});
});
<commit_msg>Add extra logging for twitter client<commit_after>'use strict';

var logger = require('./logger');
if (process.env.TWITTER_CONSUMER_KEY === undefined) {
	logger.info('Twitter notifications disabled as no key provided');
	return;
}

var Twitter = require('twitter');
var debug = require('debug')('echo:notify-twitter');

var models = require('../models');
var notify = require('./notify');

debug('Initialising twitter notifications');

let client = new Twitter({
	consumer_key: process.env.TWITTER_CONSUMER_KEY,
	consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
	access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,
	access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
});

function sendDirectMessage(params) {
	client.post('direct_messages/new', {
		screen_name: params.to,
		text: params.text
	}, function(error, response) {
		if (error) {
			logger.error(
					'Error sending new event tweet to %s',
					params.to, error);
		} else {
			logger.info('Tweet successful', response)
		}
	});
}

notify.on('eventSubmitted', function(evt) {
	return models.User.findAll({
		where: { notify: { $like: 'twitter' } },
		attributes: [ 'twitter' ]
	}).then(function(users) {
		for (let user of users) {
			if (user.twitter) {
				sendDirectMessage({
					to: user.twitter,
					text: 'New event added: "' + evt.title + '" submitted'
				});
			}
		}
	});
});
<|endoftext|>


<commit_before>var exports = exports || {};

exports.addNet = function(Crafty) {
	Crafty.netTrigger = function(eventName, eventObject) {
		Crafty.net.send(0, "NET_"+eventName, eventObject);
		return this;
	};
	Crafty.netBind = function(eventName, callback) {
		Crafty.bind("NET_"+eventName, callback);
		return this;
	};
	Crafty.netUnbind = function(eventName, callback) {
		Crafty.unbind("NET_"+eventName, callback);
		return this;
	};

	Crafty.c("NetEvents", {
		init: function(entity) {
		},
		netTrigger: function(eventName, eventObject) {
			Crafty.net.send(this[0], "NET_"+eventName, eventObject);
			return this;
		},
		netBind: function(eventName, callback) {
			this.bind("NET_"+eventName, callback);
			return this;
		},
		netUnbind: function(eventName, callback) {
			this.unbind("NET_"+eventName, callback);
			return this;
		}
	});

	//TODO net, room instead of _socket
	Crafty.net = {
		send: function(id, eventName, eventObject) {
			this._socket.emitCrafty(id, eventName, eventObject);
		},
		receive: function(id, eventName, eventObject) {
			if (id !== 0)
				Crafty(id).trigger(eventName, eventObject);
			else
				Crafty.trigger(eventName, eventObject);
		}
	};
};

exports.routeSocket = function(socket, Crafty) {
	Crafty.net._socket = socket;

	socket.on('crafty', function(netEvent) {
		var id = netEvent.id;
		var eventName = netEvent.eventName;
		var eventObject = netEvent.eventObject;

		Crafty.net.receive(id, eventName, eventObject);
	});

	socket.emitCrafty = function(id, eventName, eventObject) {
		var netEvent = {
			id: id,
			eventName: eventName,
			eventObject: eventObject
		};

		socket.emit('crafty', netEvent);
	};
};
<commit_msg>quick fix<commit_after>var exports = exports || {};

exports.addNet = function(Crafty) {
	Crafty.netTrigger = function(eventName, eventObject) {
		Crafty.net.send(0, "NET_"+eventName, eventObject);
		return Crafty;
	};
	Crafty.netBind = function(eventName, callback) {
		Crafty.bind("NET_"+eventName, callback);
		return Crafty;
	};
	Crafty.netUnbind = function(eventName, callback) {
		Crafty.unbind("NET_"+eventName, callback);
		return Crafty;
	};

	Crafty.c("NetEvents", {
		init: function(entity) {
		},
		netTrigger: function(eventName, eventObject) {
			Crafty.net.send(this[0], "NET_"+eventName, eventObject);
			return this;
		},
		netBind: function(eventName, callback) {
			this.bind("NET_"+eventName, callback);
			return this;
		},
		netUnbind: function(eventName, callback) {
			this.unbind("NET_"+eventName, callback);
			return this;
		}
	});

	//TODO net, room instead of _socket
	Crafty.net = {
		send: function(id, eventName, eventObject) {
			this._socket.emitCrafty(id, eventName, eventObject);
		},
		receive: function(id, eventName, eventObject) {
			if (id !== 0)
				Crafty(id).trigger(eventName, eventObject);
			else
				Crafty.trigger(eventName, eventObject);
		}
	};
};

exports.routeSocket = function(socket, Crafty) {
	Crafty.net._socket = socket;

	socket.on('crafty', function(netEvent) {
		var id = netEvent.id;
		var eventName = netEvent.eventName;
		var eventObject = netEvent.eventObject;

		Crafty.net.receive(id, eventName, eventObject);
	});

	socket.emitCrafty = function(id, eventName, eventObject) {
		var netEvent = {
			id: id,
			eventName: eventName,
			eventObject: eventObject
		};

		socket.emit('crafty', netEvent);
	};
};
<|endoftext|>


<commit_before>import mockgoose from 'mockgoose'
import mongoose from '../<%= srcDir %>/config/mongoose'
import { mongo } from '../<%= srcDir %>/config'

require('events').EventEmitter.defaultMaxListeners = Infinity
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000

// lodash
global.Array = Array
global.Date = Date
global.Function = Function
global.Math = Math
global.Number = Number
global.Object = Object
global.RegExp = RegExp
global.String = String
global.Uint8Array = Uint8Array
global.WeakMap = WeakMap
global.Set = Set
global.Error = Error
global.TypeError = TypeError
global.parseInt = parseInt
global.parseFloat = parseFloat

beforeAll(async () => {
  await mockgoose(mongoose)
  mongoose.connect(mongo.uri)
})

afterAll(() => {
  mongoose.disconnect()
})

afterEach(async () => {
  const { collections } = mongoose.connection
  const promises = []
  Object.keys(collections).forEach((collection) => {
    promises.push(collections[collection].remove())
  })
  await Promise.all(promises)
})
<commit_msg>Update test setup<commit_after>import { EventEmitter } from 'events'
import mockgoose from 'mockgoose'
import mongoose from '../<%= srcDir %>/config/mongoose'
import { mongo } from '../<%= srcDir %>/config'

EventEmitter.defaultMaxListeners = Infinity
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000

global.Array = Array
global.Date = Date
global.Function = Function
global.Math = Math
global.Number = Number
global.Object = Object
global.RegExp = RegExp
global.String = String
global.Uint8Array = Uint8Array
global.WeakMap = WeakMap
global.Set = Set
global.Error = Error
global.TypeError = TypeError
global.parseInt = parseInt
global.parseFloat = parseFloat

beforeAll(async () => {
  await mockgoose(mongoose)
  mongoose.connect(mongo.uri)
})

afterAll(() => {
  mongoose.disconnect()
})

afterEach(async () => {
  const { collections } = mongoose.connection
  const promises = []
  Object.keys(collections).forEach((collection) => {
    promises.push(collections[collection].remove())
  })
  await Promise.all(promises)
})
<|endoftext|>


<commit_before>const fs = require('fs')
const path = require('path')
const os = require('os')
const argv = require('minimist')(process.argv.slice(2))
const _ = require('lodash/fp')
const dotenv = require('dotenv').config()

const dbMapping = psqlConf => ({
  STRESS_TEST: _.replace('lamassu', 'lamassu_stress', psqlConf),
  RELEASE: _.replace('lamassu', 'lamassu_release', psqlConf),
  DEV: _.replace('lamassu', 'lamassu', psqlConf)
})

/**
 * @return {{path: string, opts: any}}
 */
function load () {
  if (process.env.LAMASSU_CONFIG) {
    const configPath = process.env.LAMASSU_CONFIG
    return {
      path: configPath,
      opts: JSON.parse(fs.readFileSync(configPath))
    }
  }

  if (argv.f) {
    const configPath = argv.f
    return {
      path: configPath,
      opts: JSON.parse(fs.readFileSync(configPath))
    }
  }

  try {
    const globalConfigPath = path.resolve('/etc', 'lamassu', 'lamassu.json')
    const config = {
      path: globalConfigPath,
      opts: JSON.parse(fs.readFileSync(globalConfigPath))
    }

    config.opts.postgresql = dbMapping(config.opts.postgresql)[process.env.LAMASSU_DB]

    return config
  } catch (_) {
    try {
      const homeConfigPath = path.resolve(os.homedir(), '.lamassu', 'lamassu.json')
      const config = {
        path: homeConfigPath,
        opts: JSON.parse(fs.readFileSync(homeConfigPath))
      }

      config.opts.postgresql = dbMapping(config.opts.postgresql)[process.env.LAMASSU_DB]

      return config
    } catch (_) {
      console.error("Couldn't open lamassu.json config file.")
      process.exit(1)
    }
  }
}

module.exports = load
<commit_msg>fix: remove unnecessary const<commit_after>const fs = require('fs')
const path = require('path')
const os = require('os')
const argv = require('minimist')(process.argv.slice(2))
const _ = require('lodash/fp')

require('dotenv').config()

const dbMapping = psqlConf => ({
  STRESS_TEST: _.replace('lamassu', 'lamassu_stress', psqlConf),
  RELEASE: _.replace('lamassu', 'lamassu_release', psqlConf),
  DEV: _.replace('lamassu', 'lamassu', psqlConf)
})

/**
 * @return {{path: string, opts: any}}
 */
function load () {
  if (process.env.LAMASSU_CONFIG) {
    const configPath = process.env.LAMASSU_CONFIG
    return {
      path: configPath,
      opts: JSON.parse(fs.readFileSync(configPath))
    }
  }

  if (argv.f) {
    const configPath = argv.f
    return {
      path: configPath,
      opts: JSON.parse(fs.readFileSync(configPath))
    }
  }

  try {
    const globalConfigPath = path.resolve('/etc', 'lamassu', 'lamassu.json')
    const config = {
      path: globalConfigPath,
      opts: JSON.parse(fs.readFileSync(globalConfigPath))
    }

    config.opts.postgresql = dbMapping(config.opts.postgresql)[process.env.LAMASSU_DB]

    return config
  } catch (_) {
    try {
      const homeConfigPath = path.resolve(os.homedir(), '.lamassu', 'lamassu.json')
      const config = {
        path: homeConfigPath,
        opts: JSON.parse(fs.readFileSync(homeConfigPath))
      }

      config.opts.postgresql = dbMapping(config.opts.postgresql)[process.env.LAMASSU_DB]

      return config
    } catch (_) {
      console.error("Couldn't open lamassu.json config file.")
      process.exit(1)
    }
  }
}

module.exports = load
<|endoftext|>


<commit_before>"use babel";

import reloadPackage from './reload-package';
import chokidar from 'chokidar';

export default class PackageWacher {
	constructor() {
		this.watcher = null;
	}

	watch(packageName) {
		if (this.watcher) {
			this.unwatch();
		}

		const packagePath = atom.packages.resolvePackagePath(packageName);

    this.watcher = chokidar.watch(packagePath, {
      persistent: true,
      ignoreInitial: true,
    });
    this.watcher.on('change', (filename) => {
    	const reloadGrammars = (filename.indexOf('grammars') >= 0);
    	reloadPackage(packageName, reloadGrammars);
    });

    atom.notifications.addInfo(`Start watching \`${packageName}\`.`);
	}

	unwatch() {
		if (this.watcher) {
			this.watcher.close();
			atom.notifications.addInfo('Stop watching.');
		}
	}
}
<commit_msg>Refine grammar path detection test.<commit_after>"use babel";

import reloadPackage from './reload-package';
import chokidar from 'chokidar';
import path from 'path';

export default class PackageWacher {
	constructor() {
		this.watcher = null;
	}

	watch(packageName) {
		if (this.watcher) {
			this.unwatch();
		}

		const packagePath = atom.packages.resolvePackagePath(packageName);

    this.watcher = chokidar.watch(packagePath, {
      persistent: true,
      ignoreInitial: true,
    });
    this.watcher.on('change', (filename) => {
      const dir = path.dirname(filename);
      const reloadGrammars = dir === path.join(packagePath, 'grammars');
      reloadPackage(packageName, reloadGrammars);
    });

    atom.notifications.addInfo(`Start watching \`${packageName}\`.`);
	}

	unwatch() {
		if (this.watcher) {
			this.watcher.close();
			atom.notifications.addInfo('Stop watching.');
		}
	}
}
<|endoftext|>


<commit_before>DATA = {};

Template.AccessIndexWidget.onRendered(function() {
  var template = this;
  var currData = Template.currentData();
  Meteor.call('rankData', function(e, r){ // Meteor.method in 'server/oldAPI.js'
    DATA = r; // just for easier usage here.
    currData.set({ rData: r });
  });
});

Template.AccessIndexWidget.helpers({
  dataReady: function(){
    return Template.currentData().rData;
  },
  score: function() {
    return this.score.toFixed(2);
  },
  country: function() {
    return DATA[Template.currentData().country.code];
  },
  accessUrl: function(code){
    return 'https://thenetmonitor.org/countries/' + code + '/access';
  },
  imageUrl: function(code){
    return 'https://thenetmonitor.org/countries/' + code + '/thumb';
  },
  ranks: function() {
    var width = Math.floor(Settings.numRanks / 2);
    var rank = this.rank;
    var min = Math.max(1, rank - width);
    var max = Math.min(Object.keys(DATA).length, rank + width) + 1;
    return _.map(_.range(min, max), function(r) {
      return {
        rank: r,
        offset: r - rank,
        rankedCountry: findByRank(r, DATA)
      };
    });
  },
  rankClass: function() {
    if (this.offset < 0) {
      return 'higher-ranked';
    } else if (this.offset === 0) {
      return 'this-rank';
    }

    return 'lower-ranked';
  },
  isThisRank: function() {
    return this.offset === 0;
  },
  barWidth: function() {
    return this.score / 10.0 * 100;
  }
});

function findByRank(rank, obj){
  for(country in obj){
    if(obj[country].rank === rank)
      return obj[country];
  }
}
<commit_msg>Fix widget not showing for people with no edit priv<commit_after>DATA = {};

Template.AccessIndexWidget.onRendered(function() {
  var id = Template.instance().data.widget._id;
  var currData = Template.currentData();
  Meteor.call('rankData', function(e, r){ // Meteor.method in 'server/oldAPI.js'
    DATA = r; // just for easier usage here.
    Session.set(id+'-data', r);
  });
});

Template.AccessIndexWidget.helpers({
  dataReady: function(){
    var id = Template.instance().data.widget._id;
    return Session.get(id+'-data');
  },
  score: function() {
    return this.score.toFixed(2);
  },
  country: function() {
    return DATA[Template.currentData().country.code];
  },
  accessUrl: function(code){
    return 'https://thenetmonitor.org/countries/' + code + '/access';
  },
  imageUrl: function(code){
    return 'https://thenetmonitor.org/countries/' + code + '/thumb';
  },
  ranks: function() {
    var width = Math.floor(Settings.numRanks / 2);
    var rank = this.rank;
    var min = Math.max(1, rank - width);
    var max = Math.min(Object.keys(DATA).length, rank + width) + 1;
    return _.map(_.range(min, max), function(r) {
      return {
        rank: r,
        offset: r - rank,
        rankedCountry: findByRank(r, DATA)
      };
    });
  },
  rankClass: function() {
    if (this.offset < 0) {
      return 'higher-ranked';
    } else if (this.offset === 0) {
      return 'this-rank';
    }

    return 'lower-ranked';
  },
  isThisRank: function() {
    return this.offset === 0;
  },
  barWidth: function() {
    return this.score / 10.0 * 100;
  }
});

function findByRank(rank, obj){
  for(country in obj){
    if(obj[country].rank === rank)
      return obj[country];
  }
}
<|endoftext|>


<commit_before>import commander from "commander";
import Module from "module";
import { inspect } from "util";
import path from "path";
import repl from "repl";
import * as babel from "@babel/core";
import vm from "vm";
import "@babel/polyfill";
import register from "@babel/register";

import pkg from "../package.json";

const program = new commander.Command("babel-node");

function collect(value, previousValue): Array<string> {
  // If the user passed the option with no value, like "babel-node file.js --presets", do nothing.
  if (typeof value !== "string") return previousValue;

  const values = value.split(",");

  return previousValue ? previousValue.concat(values) : values;
}

program.option("-e, --eval [script]", "Evaluate script");
program.option(
  "--no-babelrc",
  "Specify whether or not to use .babelrc and .babelignore files",
);
program.option("-r, --require [module]", "Require module");
program.option("-p, --print [code]", "Evaluate script and print result");
program.option(
  "-o, --only [globs]",
  "A comma-separated list of glob patterns to compile",
  collect,
);
program.option(
  "-i, --ignore [globs]",
  "A comma-separated list of glob patterns to skip compiling",
  collect,
);
program.option(
  "-x, --extensions [extensions]",
  "List of extensions to hook into [.es6,.js,.es,.jsx,.mjs]",
  collect,
);
program.option(
  "--config-file [path]",
  "Path to the babel config file to use. Defaults to working directory babel.config.js",
);
program.option(
  "--env-name [name]",
  "The name of the 'env' to use when loading configs and plugins. " +
    "Defaults to the value of BABEL_ENV, or else NODE_ENV, or else 'development'.",
);
commander.option(
  "--root-mode [mode]",
  "The project-root resolution mode. " +
    "One of 'root' (the default), 'upward', or 'upward-optional'.",
);
program.option("-w, --plugins [string]", "", collect);
program.option("-b, --presets [string]", "", collect);

program.version(pkg.version);
program.usage("[options] [ -e script | script.js ] [arguments]");
program.parse(process.argv);

const babelOptions = {
  caller: {
    name: "@babel/node",
  },
  extensions: program.extensions,
  ignore: program.ignore,
  only: program.only,
  plugins: program.plugins,
  presets: program.presets,
  configFile: program.configFile,
  envName: program.envName,
  rootMode: program.rootMode,

  // Commander will default the "--no-" arguments to true, but we want to
  // leave them undefined so that @babel/core can handle the
  // default-assignment logic on its own.
  babelrc: program.babelrc === true ? undefined : program.babelrc,
};

for (const key of Object.keys(babelOptions)) {
  if (babelOptions[key] === undefined) {
    delete babelOptions[key];
  }
}

register(babelOptions);

const replPlugin = ({ types: t }) => ({
  visitor: {
    ModuleDeclaration(path) {
      throw path.buildCodeFrameError("Modules aren't supported in the REPL");
    },

    VariableDeclaration(path) {
      if (path.node.kind !== "var") {
        throw path.buildCodeFrameError(
          "Only `var` variables are supported in the REPL",
        );
      }
    },

    Program(path) {
      if (path.get("body").some(child => child.isExpressionStatement())) return;

      // If the executed code doesn't evaluate to a value,
      // prevent implicit strict mode from printing 'use strict'.
      path.pushContainer(
        "body",
        t.expressionStatement(t.identifier("undefined")),
      );
    },
  },
});

const _eval = function(code, filename) {
  code = code.trim();
  if (!code) return undefined;

  code = babel.transform(code, {
    filename: filename,
    presets: program.presets,
    plugins: (program.plugins || []).concat([replPlugin]),
  }).code;

  return vm.runInThisContext(code, {
    filename: filename,
  });
};

if (program.eval || program.print) {
  let code = program.eval;
  if (!code || code === true) code = program.print;

  global.__filename = "[eval]";
  global.__dirname = process.cwd();

  const module = new Module(global.__filename);
  module.filename = global.__filename;
  module.paths = Module._nodeModulePaths(global.__dirname);

  global.exports = module.exports;
  global.module = module;
  global.require = module.require.bind(module);

  const result = _eval(code, global.__filename);
  if (program.print) {
    const output = typeof result === "string" ? result : inspect(result);
    process.stdout.write(output + "\n");
  }
} else {
  if (program.args.length) {
    // slice all arguments up to the first filename since they're babel args that we handle
    let args = process.argv.slice(2);

    let i = 0;
    let ignoreNext = false;
    args.some(function(arg, i2) {
      if (ignoreNext) {
        ignoreNext = false;
        return;
      }

      if (arg[0] === "-") {
        const camelArg = arg
          .slice(2)
          .replace(/-(\w)/, (s, c) => c.toUpperCase());
        const parsedArg = program[camelArg];
        if (
          arg === "-r" ||
          arg === "--require" ||
          (parsedArg && parsedArg !== true)
        ) {
          ignoreNext = true;
        }
      } else {
        i = i2;
        return true;
      }
    });
    args = args.slice(i);

    // We have to handle require ourselves, as we want to require it in the context of babel-register
    if (program.require) {
      let requireFileName = program.require;
      if (!path.isAbsolute(requireFileName)) {
        requireFileName = path.join(process.cwd(), requireFileName);
      }
      require(requireFileName);
    }

    // make the filename absolute
    const filename = args[0];
    if (!path.isAbsolute(filename)) {
      args[0] = path.join(process.cwd(), filename);
    }

    // add back on node and concat the sliced args
    process.argv = ["node"].concat(args);
    process.execArgv.unshift(__filename);

    Module.runMain();
  } else {
    replStart();
  }
}

function replStart() {
  repl.start({
    prompt: "> ",
    input: process.stdin,
    output: process.stdout,
    eval: replEval,
    useGlobal: true,
  });
}

function replEval(code, context, filename, callback) {
  let err;
  let result;

  try {
    if (code[0] === "(" && code[code.length - 1] === ")") {
      code = code.slice(1, -1); // remove "(" and ")"
    }

    result = _eval(code, filename);
  } catch (e) {
    err = e;
  }

  callback(err, result);
}
<commit_msg>Fix --root-mode option in babel-node (#9148)<commit_after>import commander from "commander";
import Module from "module";
import { inspect } from "util";
import path from "path";
import repl from "repl";
import * as babel from "@babel/core";
import vm from "vm";
import "@babel/polyfill";
import register from "@babel/register";

import pkg from "../package.json";

const program = new commander.Command("babel-node");

function collect(value, previousValue): Array<string> {
  // If the user passed the option with no value, like "babel-node file.js --presets", do nothing.
  if (typeof value !== "string") return previousValue;

  const values = value.split(",");

  return previousValue ? previousValue.concat(values) : values;
}

program.option("-e, --eval [script]", "Evaluate script");
program.option(
  "--no-babelrc",
  "Specify whether or not to use .babelrc and .babelignore files",
);
program.option("-r, --require [module]", "Require module");
program.option("-p, --print [code]", "Evaluate script and print result");
program.option(
  "-o, --only [globs]",
  "A comma-separated list of glob patterns to compile",
  collect,
);
program.option(
  "-i, --ignore [globs]",
  "A comma-separated list of glob patterns to skip compiling",
  collect,
);
program.option(
  "-x, --extensions [extensions]",
  "List of extensions to hook into [.es6,.js,.es,.jsx,.mjs]",
  collect,
);
program.option(
  "--config-file [path]",
  "Path to the babel config file to use. Defaults to working directory babel.config.js",
);
program.option(
  "--env-name [name]",
  "The name of the 'env' to use when loading configs and plugins. " +
    "Defaults to the value of BABEL_ENV, or else NODE_ENV, or else 'development'.",
);
program.option(
  "--root-mode [mode]",
  "The project-root resolution mode. " +
    "One of 'root' (the default), 'upward', or 'upward-optional'.",
);
program.option("-w, --plugins [string]", "", collect);
program.option("-b, --presets [string]", "", collect);

program.version(pkg.version);
program.usage("[options] [ -e script | script.js ] [arguments]");
program.parse(process.argv);

const babelOptions = {
  caller: {
    name: "@babel/node",
  },
  extensions: program.extensions,
  ignore: program.ignore,
  only: program.only,
  plugins: program.plugins,
  presets: program.presets,
  configFile: program.configFile,
  envName: program.envName,
  rootMode: program.rootMode,

  // Commander will default the "--no-" arguments to true, but we want to
  // leave them undefined so that @babel/core can handle the
  // default-assignment logic on its own.
  babelrc: program.babelrc === true ? undefined : program.babelrc,
};

for (const key of Object.keys(babelOptions)) {
  if (babelOptions[key] === undefined) {
    delete babelOptions[key];
  }
}

register(babelOptions);

const replPlugin = ({ types: t }) => ({
  visitor: {
    ModuleDeclaration(path) {
      throw path.buildCodeFrameError("Modules aren't supported in the REPL");
    },

    VariableDeclaration(path) {
      if (path.node.kind !== "var") {
        throw path.buildCodeFrameError(
          "Only `var` variables are supported in the REPL",
        );
      }
    },

    Program(path) {
      if (path.get("body").some(child => child.isExpressionStatement())) return;

      // If the executed code doesn't evaluate to a value,
      // prevent implicit strict mode from printing 'use strict'.
      path.pushContainer(
        "body",
        t.expressionStatement(t.identifier("undefined")),
      );
    },
  },
});

const _eval = function(code, filename) {
  code = code.trim();
  if (!code) return undefined;

  code = babel.transform(code, {
    filename: filename,
    presets: program.presets,
    plugins: (program.plugins || []).concat([replPlugin]),
  }).code;

  return vm.runInThisContext(code, {
    filename: filename,
  });
};

if (program.eval || program.print) {
  let code = program.eval;
  if (!code || code === true) code = program.print;

  global.__filename = "[eval]";
  global.__dirname = process.cwd();

  const module = new Module(global.__filename);
  module.filename = global.__filename;
  module.paths = Module._nodeModulePaths(global.__dirname);

  global.exports = module.exports;
  global.module = module;
  global.require = module.require.bind(module);

  const result = _eval(code, global.__filename);
  if (program.print) {
    const output = typeof result === "string" ? result : inspect(result);
    process.stdout.write(output + "\n");
  }
} else {
  if (program.args.length) {
    // slice all arguments up to the first filename since they're babel args that we handle
    let args = process.argv.slice(2);

    let i = 0;
    let ignoreNext = false;
    args.some(function(arg, i2) {
      if (ignoreNext) {
        ignoreNext = false;
        return;
      }

      if (arg[0] === "-") {
        const camelArg = arg
          .slice(2)
          .replace(/-(\w)/, (s, c) => c.toUpperCase());
        const parsedArg = program[camelArg];
        if (
          arg === "-r" ||
          arg === "--require" ||
          (parsedArg && parsedArg !== true)
        ) {
          ignoreNext = true;
        }
      } else {
        i = i2;
        return true;
      }
    });
    args = args.slice(i);

    // We have to handle require ourselves, as we want to require it in the context of babel-register
    if (program.require) {
      let requireFileName = program.require;
      if (!path.isAbsolute(requireFileName)) {
        requireFileName = path.join(process.cwd(), requireFileName);
      }
      require(requireFileName);
    }

    // make the filename absolute
    const filename = args[0];
    if (!path.isAbsolute(filename)) {
      args[0] = path.join(process.cwd(), filename);
    }

    // add back on node and concat the sliced args
    process.argv = ["node"].concat(args);
    process.execArgv.unshift(__filename);

    Module.runMain();
  } else {
    replStart();
  }
}

function replStart() {
  repl.start({
    prompt: "> ",
    input: process.stdin,
    output: process.stdout,
    eval: replEval,
    useGlobal: true,
  });
}

function replEval(code, context, filename, callback) {
  let err;
  let result;

  try {
    if (code[0] === "(" && code[code.length - 1] === ")") {
      code = code.slice(1, -1); // remove "(" and ")"
    }

    result = _eval(code, filename);
  } catch (e) {
    err = e;
  }

  callback(err, result);
}
<|endoftext|>


<commit_before>(function(){

	var points = raw.models.points();

	var chart = raw.chart()
		.title('Scatter Plot')
		.description(
            "A scatter plot, scatterplot, or scattergraph is a type of mathematical diagram using Cartesian coordinates to display values for two variables for a set of data. The data is displayed as a collection of points, each having the value of one variable determining the position on the horizontal axis and the value of the other variable determining the position on the vertical axis. This kind of plot is also called a scatter chart, scattergram, scatter diagram, or scatter graph.")
		.thumbnail("/imgs/scatterPlot.png")
		.model(points)

	var width = chart.number()
		.title("Width")
		.defaultValue(1000)
		.fitToWidth(true)

	var height = chart.number()
		.title("Height")
		.defaultValue(500)

	var maxRadius = chart.number()
		.title("max radius")
		.defaultValue(20)

	var useZero = chart.checkbox()
		.title("set origin at (0,0)")
		.defaultValue(false)

	var colors = chart.color()
		 .title("Color scale")

	var showPoints = chart.checkbox()
		.title("show points")
		.defaultValue(true)

	chart.draw(function (selection, data){

		var g = selection
			.attr("width", +width() )
			.attr("height", +height() )
			.append("g")

		var marginLeft = d3.max(data, function (d) { return (Math.log(d.y) / 2.302585092994046) + 1; }) * 9,
			marginBottom = 20,
			w = width() - marginLeft,
			h = height() - marginBottom;

		var xExtent = !useZero()? d3.extent(data, function (d){ return d.x; }) : [0, d3.max(data, function (d){ return d.x; })],
				yExtent = !useZero()? d3.extent(data, function (d){ return d.y; }) : [0, d3.max(data, function (d){ return d.y; })];

		var xScale = d3.scale.linear().range([marginLeft,width()-maxRadius()]).domain(xExtent),
				yScale = d3.scale.linear().range([h-maxRadius(), maxRadius()]).domain(yExtent),
				sizeScale = d3.scale.linear().range([1, Math.pow(+maxRadius(),2)*Math.PI]).domain([0, d3.max(data, function (d){ return d.size; })]),
				xAxis = d3.svg.axis().scale(xScale).tickSize(-h+maxRadius()*2).orient("bottom")//.tickSubdivide(true),
    		yAxis = d3.svg.axis().scale(yScale).ticks(10).tickSize(-w+maxRadius()).orient("left");

        g.append("g")
            .attr("class", "x axis")
            .style("stroke-width", "1px")
        	.style("font-size","10px")
        	.style("font-family","Arial, Helvetica")
            .attr("transform", "translate(" + 0 + "," + (h-maxRadius()) + ")")
            .call(xAxis);

      	g.append("g")
            .attr("class", "y axis")
            .style("stroke-width", "1px")
            .style("font-size","10px")
			.style("font-family","Arial, Helvetica")
            .attr("transform", "translate(" + marginLeft + "," + 0 + ")")
            .call(yAxis);

        d3.selectAll(".y.axis line, .x.axis line, .y.axis path, .x.axis path")
         	.style("shape-rendering","crispEdges")
         	.style("fill","none")
         	.style("stroke","#ccc")

		var circle = g.selectAll("g.circle")
			.data(data)
			.enter().append("g")
			.attr("class","circle")

		var point = g.selectAll("g.point")
			.data(data)
			.enter().append("g")
			.attr("class","point")

		colors.domain(data, function(d){ return d.color; });

    	circle.append("circle")
            .style("fill", function(d) { return colors() ? colors()(d.color) : "#eeeeee"; })
            .style("fill-opacity", .9)
    	    .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; })
    	    .attr("r", function (d){ return Math.sqrt(sizeScale(d.size)/Math.PI); });

    	point.append("circle")
            .filter(function(){ return showPoints(); })
            .style("fill", "#000")
            .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; })
            .attr("r", 1);

    	circle.append("text")
    	    .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; })
    		.attr("text-anchor", "middle")
    		.style("font-size","10px")
    		.attr("dy", 15)
    		.style("font-family","Arial, Helvetica")
    	  	.text(function (d){ return d.label? d.label.join(", ") : ""; });

	})

})();<commit_msg>Fixing marginLeft bug on Scatter plot<commit_after>(function(){

	var points = raw.models.points();

	var chart = raw.chart()
		.title('Scatter Plot')
		.description(
            "A scatter plot, scatterplot, or scattergraph is a type of mathematical diagram using Cartesian coordinates to display values for two variables for a set of data. The data is displayed as a collection of points, each having the value of one variable determining the position on the horizontal axis and the value of the other variable determining the position on the vertical axis. This kind of plot is also called a scatter chart, scattergram, scatter diagram, or scatter graph.")
		.thumbnail("/imgs/scatterPlot.png")
		.model(points)

	var width = chart.number()
		.title("Width")
		.defaultValue(1000)
		.fitToWidth(true)

	var height = chart.number()
		.title("Height")
		.defaultValue(500)

	var maxRadius = chart.number()
		.title("max radius")
		.defaultValue(20)

	var useZero = chart.checkbox()
		.title("set origin at (0,0)")
		.defaultValue(false)

	var colors = chart.color()
		 .title("Color scale")

	var showPoints = chart.checkbox()
		.title("show points")
		.defaultValue(true)

	chart.draw(function (selection, data){

		var g = selection
			.attr("width", +width() )
			.attr("height", +height() )
			.append("g")

		var marginLeft = d3.max([maxRadius(),(d3.max(data, function (d) { return (Math.log(d.y) / 2.302585092994046) + 1; }) * 9)]),
			marginBottom = 20,
			w = width() - marginLeft,
			h = height() - marginBottom;

		var xExtent = !useZero()? d3.extent(data, function (d){ return d.x; }) : [0, d3.max(data, function (d){ return d.x; })],
			yExtent = !useZero()? d3.extent(data, function (d){ return d.y; }) : [0, d3.max(data, function (d){ return d.y; })];

		var xScale = d3.scale.linear().range([marginLeft,width()-maxRadius()]).domain(xExtent),
				yScale = d3.scale.linear().range([h-maxRadius(), maxRadius()]).domain(yExtent),
				sizeScale = d3.scale.linear().range([1, Math.pow(+maxRadius(),2)*Math.PI]).domain([0, d3.max(data, function (d){ return d.size; })]),
				xAxis = d3.svg.axis().scale(xScale).tickSize(-h+maxRadius()*2).orient("bottom")//.tickSubdivide(true),
    		yAxis = d3.svg.axis().scale(yScale).ticks(10).tickSize(-w+maxRadius()).orient("left");

        g.append("g")
            .attr("class", "x axis")
            .style("stroke-width", "1px")
        	.style("font-size","10px")
        	.style("font-family","Arial, Helvetica")
            .attr("transform", "translate(" + 0 + "," + (h-maxRadius()) + ")")
            .call(xAxis);

      	g.append("g")
            .attr("class", "y axis")
            .style("stroke-width", "1px")
            .style("font-size","10px")
			.style("font-family","Arial, Helvetica")
            .attr("transform", "translate(" + marginLeft + "," + 0 + ")")
            .call(yAxis);

        d3.selectAll(".y.axis line, .x.axis line, .y.axis path, .x.axis path")
         	.style("shape-rendering","crispEdges")
         	.style("fill","none")
         	.style("stroke","#ccc")

		var circle = g.selectAll("g.circle")
			.data(data)
			.enter().append("g")
			.attr("class","circle")

		var point = g.selectAll("g.point")
			.data(data)
			.enter().append("g")
			.attr("class","point")

		colors.domain(data, function(d){ return d.color; });

    	circle.append("circle")
            .style("fill", function(d) { return colors() ? colors()(d.color) : "#eeeeee"; })
            .style("fill-opacity", .9)
    	    .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; })
    	    .attr("r", function (d){ return Math.sqrt(sizeScale(d.size)/Math.PI); });

    	point.append("circle")
            .filter(function(){ return showPoints(); })
            .style("fill", "#000")
            .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; })
            .attr("r", 1);

    	circle.append("text")
    	    .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; })
    		.attr("text-anchor", "middle")
    		.style("font-size","10px")
    		.attr("dy", 15)
    		.style("font-family","Arial, Helvetica")
    	  	.text(function (d){ return d.label? d.label.join(", ") : ""; });

	})

})();<|endoftext|>