<commit_before>// noflo-component-access.js

var _ = require('underscore');
var noflo = require('noflo');

module.exports = facadeComponent;

/**
 * Create a noflo.Component facade from a given component. Access to the component
 * is limited to only select properties and functions. An rpf hash property is
 * also present for arbitrary assignments and is shared for all facades of the
 * same Component instance.
 * This facade mimic the main usage of http://noflojs.org/api/Component.html
 * Usage:
 *  var component = componentAccess(new noflo.Component());
 */
function facadeComponent(component) {
    if (component._noflo_access_facade)
        return component._noflo_access_facade;
    var facade = {};
    _.extend(facade, {
        inPorts: _.mapObject(_.pick(component.inPorts, isInPort), facadePort.bind(this, facade)),
        outPorts: _.mapObject(_.pick(component.outPorts, isOutPort), facadePort.bind(this, facade))
    });
    return component._noflo_access_facade = facade;
}

/**
 * Create a noflo Port facade from a given noflo Port that includes only a limited
 * subset of properties and functions.
 * This facade mimic the main usage of http://noflojs.org/api/OutPort.html
 */
function facadePort(nodeInstance, port, name) {
    return _.extend({
        name: name,
        nodeInstance: nodeInstance,
        isMulti: port.isAddressable.bind(port),
        isRequired: port.isRequired.bind(port),
        listAttached: port.listAttached.bind(port),
        getComponentIdOn: function(socketIndex) {
            if (port.sockets[socketIndex] && port.sockets[socketIndex].from)
                return port.sockets[socketIndex].from.process.id;
        },
        getComponentPortNameOn: function(socketIndex) {
            if (port.sockets[socketIndex] && port.sockets[socketIndex].from)
                return port.sockets[socketIndex].from.port;
        }
    }, isOutPort(port) ? {
        connect: port.connect.bind(port),
        send: port.send.bind(port),
        disconnect: port.disconnect.bind(port)
    } : {});
}

/**
 * Tests if the given object is a noflo.InPort
 * @param port a noflo.InPort if the result is true
 */
function isInPort(port) {
    return port instanceof noflo.InPort;
}

/**
 * Tests if the given object is a noflo.OutPort
 * @param port a noflo.OutPort if the result is true
 */
function isOutPort(port) {
    return port instanceof noflo.OutPort;
}
<commit_msg>Add getComponentNameOn to port facade<commit_after>// noflo-component-access.js

var _ = require('underscore');
var noflo = require('noflo');

module.exports = facadeComponent;

/**
 * Create a noflo.Component facade from a given component. Access to the component
 * is limited to only select properties and functions. An rpf hash property is
 * also present for arbitrary assignments and is shared for all facades of the
 * same Component instance.
 * This facade mimic the main usage of http://noflojs.org/api/Component.html
 * Usage:
 *  var component = componentAccess(new noflo.Component());
 */
function facadeComponent(component) {
    if (component._noflo_access_facade)
        return component._noflo_access_facade;
    var facade = {};
    _.extend(facade, {
        inPorts: _.mapObject(_.pick(component.inPorts, isInPort), facadePort.bind(this, facade)),
        outPorts: _.mapObject(_.pick(component.outPorts, isOutPort), facadePort.bind(this, facade))
    });
    return component._noflo_access_facade = facade;
}

/**
 * Create a noflo Port facade from a given noflo Port that includes only a limited
 * subset of properties and functions.
 * This facade mimic the main usage of http://noflojs.org/api/OutPort.html
 */
function facadePort(nodeInstance, port, name) {
    return _.extend({
        name: name,
        nodeInstance: nodeInstance,
        isMulti: port.isAddressable.bind(port),
        isRequired: port.isRequired.bind(port),
        listAttached: port.listAttached.bind(port),
        getComponentIdOn: function(socketIndex) {
            return this.getComponentNameOn(socketIndex);
        },
        getComponentNameOn: function(socketIndex) {
            if (port.sockets[socketIndex] && port.sockets[socketIndex].from)
                return port.sockets[socketIndex].from.process.id;
        },
        getComponentPortNameOn: function(socketIndex) {
            if (port.sockets[socketIndex] && port.sockets[socketIndex].from)
                return port.sockets[socketIndex].from.port;
        }
    }, isOutPort(port) ? {
        connect: port.connect.bind(port),
        send: port.send.bind(port),
        disconnect: port.disconnect.bind(port)
    } : {});
}

/**
 * Tests if the given object is a noflo.InPort
 * @param port a noflo.InPort if the result is true
 */
function isInPort(port) {
    return port instanceof noflo.InPort;
}

/**
 * Tests if the given object is a noflo.OutPort
 * @param port a noflo.OutPort if the result is true
 */
function isOutPort(port) {
    return port instanceof noflo.OutPort;
}
<|endoftext|>


<commit_before>/* vim: ts=4:sw=4
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

'use strict';

;(function() {
    /**********************
    *** Device Storage ***
    **********************/
    window.textsecure = window.textsecure || {};
    window.textsecure.storage = window.textsecure.storage || {};

    window.textsecure.storage.devices = {
        saveDeviceObject: function(deviceObject) {
            return internalSaveDeviceObject(deviceObject, false);
        },

        saveKeysToDeviceObject: function(deviceObject) {
            return internalSaveDeviceObject(deviceObject, true);
        },

        getDeviceObjectsForNumber: function(number) {
            var map = textsecure.storage.getEncrypted("devices" + number);
            return map === undefined ? [] : map.devices;
        },

        getDeviceObject: function(encodedNumber) {
            var number = textsecure.utils.unencodeNumber(encodedNumber);
            var devices = textsecure.storage.devices.getDeviceObjectsForNumber(number[0]);
            if (devices === undefined)
                return undefined;

            for (var i in devices)
                if (devices[i].encodedNumber == encodedNumber)
                    return devices[i];

            return undefined;
        },

        removeDeviceIdsForNumber: function(number, deviceIdsToRemove) {
            var map = textsecure.storage.getEncrypted("devices" + number);
            if (map === undefined)
                throw new Error("Tried to remove device for unknown number");

            var newDevices = [];
            var devicesRemoved = 0;
            for (var i in map.devices) {
                var keep = true;
                for (var j in deviceIdsToRemove)
                    if (map.devices[i].encodedNumber == number + "." + deviceIdsToRemove[j])
                        keep = false;

                if (keep)
                    newDevices.push(map.devices[i]);
                else
                    devicesRemoved++;
            }

            if (devicesRemoved != deviceIdsToRemove.length)
                throw new Error("Tried to remove unknown device");
        }
    };

    var internalSaveDeviceObject = function(deviceObject, onlyKeys) {
        if (deviceObject.identityKey === undefined || deviceObject.encodedNumber === undefined)
            throw new Error("Tried to store invalid deviceObject");

        var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0];
        var map = textsecure.storage.getEncrypted("devices" + number);

        if (map === undefined)
            map = { devices: [deviceObject], identityKey: deviceObject.identityKey };
        else if (map.identityKey != getString(deviceObject.identityKey))
            throw new Error("Identity key changed");
        else {
            var updated = false;
            for (var i in map.devices) {
                if (map.devices[i].encodedNumber == deviceObject.encodedNumber) {
                    if (!onlyKeys)
                        map.devices[i] = deviceObject;
                    else {
                        map.devices[i].preKey = deviceObject.preKey;
                        map.devices[i].preKeyId = deviceObject.preKeyId;
                        map.devices[i].signedKey = deviceObject.signedKey;
                        map.devices[i].signedKeyId = deviceObject.signedKeyId;
                        map.devices[i].registrationId = deviceObject.registrationId;
                    }
                    updated = true;
                }
            }

            if (!updated)
                map.devices.push(deviceObject);
        }

        textsecure.storage.putEncrypted("devices" + number, map);
    };
})();
<commit_msg>Add missing validity check to device storage<commit_after>/* vim: ts=4:sw=4
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

'use strict';

;(function() {
    /**********************
    *** Device Storage ***
    **********************/
    window.textsecure = window.textsecure || {};
    window.textsecure.storage = window.textsecure.storage || {};

    window.textsecure.storage.devices = {
        saveDeviceObject: function(deviceObject) {
            return internalSaveDeviceObject(deviceObject, false);
        },

        saveKeysToDeviceObject: function(deviceObject) {
            return internalSaveDeviceObject(deviceObject, true);
        },

        getDeviceObjectsForNumber: function(number) {
            var map = textsecure.storage.getEncrypted("devices" + number);
            return map === undefined ? [] : map.devices;
        },

        getDeviceObject: function(encodedNumber) {
            var number = textsecure.utils.unencodeNumber(encodedNumber);
            var devices = textsecure.storage.devices.getDeviceObjectsForNumber(number[0]);
            if (devices === undefined)
                return undefined;

            for (var i in devices)
                if (devices[i].encodedNumber == encodedNumber)
                    return devices[i];

            return undefined;
        },

        removeDeviceIdsForNumber: function(number, deviceIdsToRemove) {
            var map = textsecure.storage.getEncrypted("devices" + number);
            if (map === undefined)
                throw new Error("Tried to remove device for unknown number");

            var newDevices = [];
            var devicesRemoved = 0;
            for (var i in map.devices) {
                var keep = true;
                for (var j in deviceIdsToRemove)
                    if (map.devices[i].encodedNumber == number + "." + deviceIdsToRemove[j])
                        keep = false;

                if (keep)
                    newDevices.push(map.devices[i]);
                else
                    devicesRemoved++;
            }

            if (devicesRemoved != deviceIdsToRemove.length)
                throw new Error("Tried to remove unknown device");
        }
    };

    var internalSaveDeviceObject = function(deviceObject, onlyKeys) {
        if (deviceObject.identityKey === undefined || deviceObject.encodedNumber === undefined || deviceObject.registrationId === undefined)
            throw new Error("Tried to store invalid deviceObject");

        var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0];
        var map = textsecure.storage.getEncrypted("devices" + number);

        if (map === undefined)
            map = { devices: [deviceObject], identityKey: deviceObject.identityKey };
        else if (map.identityKey != getString(deviceObject.identityKey))
            throw new Error("Identity key changed");
        else {
            var updated = false;
            for (var i in map.devices) {
                if (map.devices[i].encodedNumber == deviceObject.encodedNumber) {
                    if (!onlyKeys)
                        map.devices[i] = deviceObject;
                    else {
                        map.devices[i].preKey = deviceObject.preKey;
                        map.devices[i].preKeyId = deviceObject.preKeyId;
                        map.devices[i].signedKey = deviceObject.signedKey;
                        map.devices[i].signedKeyId = deviceObject.signedKeyId;
                        map.devices[i].registrationId = deviceObject.registrationId;
                    }
                    updated = true;
                }
            }

            if (!updated)
                map.devices.push(deviceObject);
        }

        textsecure.storage.putEncrypted("devices" + number, map);
    };
})();
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import _ from 'lodash'

import Tags from 'shared/components/Tags'
import SlideToggle from 'shared/components/SlideToggle'
import ConfirmButton from 'shared/components/ConfirmButton'

import {ALL_USERS_TABLE} from 'src/admin/constants/chronografTableSizing'
const {
  colOrganizations,
  colProvider,
  colScheme,
  colSuperAdmin,
  colActions,
} = ALL_USERS_TABLE

const AllUsersTableRow = ({
  organizations,
  user,
  onAddToOrganization,
  onRemoveFromOrganization,
  onChangeSuperAdmin,
  onDelete,
  meID,
}) => {
  const dropdownOrganizationsItems = organizations
    .filter(o => !user.roles.find(role => role.organization === o.id))
    .map(o => ({
      ...o,
      text: o.name,
    }))

  const userIsMe = user.id === meID

  const userOrganizations = user.roles.map(r => ({
    ...r,
    name: organizations.find(o => r.organization === o.id).name,
  }))

  const wrappedDelete = () => {
    onDelete(user)
  }

  const removeWarning = userIsMe
    ? 'Delete your user record\nand log yourself out?'
    : 'Delete this user?'

  return (

        {userIsMe ? (

            {user.name}

        ) : (
          {user.name}
        )}

        <Tags
          tags={userOrganizations}
          onDeleteTag={onRemoveFromOrganization(user)}
          emptyStateText="None"
          addMenuItems={dropdownOrganizationsItems}
          addMenuChoose={onAddToOrganization(user)}
        />

      {user.provider}
      {user.scheme}

        <SlideToggle
          active={user.superAdmin}
          onToggle={onChangeSuperAdmin(user)}
          size="xs"
          disabled={userIsMe}
        />

        <ConfirmButton
          confirmText={removeWarning}
          confirmAction={wrappedDelete}
          size="btn-xs"
          type="btn-danger"
          text="Delete"
          customClass="table--show-on-row-hover"
        />

  )
}

const {arrayOf, func, shape, string} = PropTypes

AllUsersTableRow.propTypes = {
  user: shape(),
  organization: shape({
    name: string.isRequired,
    id: string.isRequired,
  }),
  onAddToOrganization: func.isRequired,
  onRemoveFromOrganization: func.isRequired,
  onChangeSuperAdmin: func.isRequired,
  onDelete: func.isRequired,
  meID: string.isRequired,
  organizations: arrayOf(
    shape({
      id: string.isRequired,
      name: string.isRequired,
    })
  ),
}

export default AllUsersTableRow
<commit_msg>Remove lodash<commit_after>import React from 'react'
import PropTypes from 'prop-types'

import Tags from 'shared/components/Tags'
import SlideToggle from 'shared/components/SlideToggle'
import ConfirmButton from 'shared/components/ConfirmButton'

import {ALL_USERS_TABLE} from 'src/admin/constants/chronografTableSizing'
const {
  colOrganizations,
  colProvider,
  colScheme,
  colSuperAdmin,
  colActions,
} = ALL_USERS_TABLE

const AllUsersTableRow = ({
  organizations,
  user,
  onAddToOrganization,
  onRemoveFromOrganization,
  onChangeSuperAdmin,
  onDelete,
  meID,
}) => {
  const dropdownOrganizationsItems = organizations
    .filter(o => !user.roles.find(role => role.organization === o.id))
    .map(o => ({
      ...o,
      text: o.name,
    }))

  const userIsMe = user.id === meID

  const userOrganizations = user.roles.map(r => ({
    ...r,
    name: organizations.find(o => r.organization === o.id).name,
  }))

  const wrappedDelete = () => {
    onDelete(user)
  }

  const removeWarning = userIsMe
    ? 'Delete your user record\nand log yourself out?'
    : 'Delete this user?'

  return (

        {userIsMe ? (

            {user.name}

        ) : (
          {user.name}
        )}

        <Tags
          tags={userOrganizations}
          onDeleteTag={onRemoveFromOrganization(user)}
          emptyStateText="None"
          addMenuItems={dropdownOrganizationsItems}
          addMenuChoose={onAddToOrganization(user)}
        />

      {user.provider}
      {user.scheme}

        <SlideToggle
          active={user.superAdmin}
          onToggle={onChangeSuperAdmin(user)}
          size="xs"
          disabled={userIsMe}
        />

        <ConfirmButton
          confirmText={removeWarning}
          confirmAction={wrappedDelete}
          size="btn-xs"
          type="btn-danger"
          text="Delete"
          customClass="table--show-on-row-hover"
        />

  )
}

const {arrayOf, func, shape, string} = PropTypes

AllUsersTableRow.propTypes = {
  user: shape(),
  organization: shape({
    name: string.isRequired,
    id: string.isRequired,
  }),
  onAddToOrganization: func.isRequired,
  onRemoveFromOrganization: func.isRequired,
  onChangeSuperAdmin: func.isRequired,
  onDelete: func.isRequired,
  meID: string.isRequired,
  organizations: arrayOf(
    shape({
      id: string.isRequired,
      name: string.isRequired,
    })
  ),
}

export default AllUsersTableRow
<|endoftext|>


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

/**
 * Nexus 5X metrics adapted from emulated_devices/module.json
 */
const NEXUS5X_EMULATION_METRICS = {
  mobile: true,
  screenWidth: 412,
  screenHeight: 732,
  width: 412,
  height: 732,
  positionX: 0,
  positionY: 0,
  scale: 1,
  deviceScaleFactor: 2.625,
  fitWindow: false,
  screenOrientation: {
    angle: 0,
    type: 'portraitPrimary'
  }
};

const NEXUS5X_USERAGENT = {
  userAgent: 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36' +
    '(KHTML, like Gecko) Chrome/61.0.3116.0 Mobile Safari/537.36'
};

/**
 * Adjustments needed for DevTools network throttling to simulate
 * more realistic network conditions.
 * See: crbug.com/721112
 */
const LATENCY_FACTOR = 3.75;
const THROUGHPUT_FACTOR = 0.9;

const TARGET_LATENCY = 150; // 150ms
const TARGET_DOWNLOAD_THROUGHPUT = Math.floor(1.6 * 1024 * 1024 / 8); // 1.6Mbps
const TARGET_UPLOAD_THROUGHPUT = Math.floor(750 * 1024 / 8); // 750Kbps

const TYPICAL_MOBILE_THROTTLING_METRICS = {
  targetLatency: TARGET_LATENCY,
  latency: TARGET_LATENCY * LATENCY_FACTOR,
  targetDownloadThroughput: TARGET_DOWNLOAD_THROUGHPUT,
  downloadThroughput: TARGET_DOWNLOAD_THROUGHPUT * THROUGHPUT_FACTOR,
  targetUploadThroughput: TARGET_UPLOAD_THROUGHPUT,
  uploadThroughput: TARGET_UPLOAD_THROUGHPUT * THROUGHPUT_FACTOR,
  offline: false
};

const OFFLINE_METRICS = {
  offline: true,
  // values of 0 remove any active throttling. crbug.com/456324#c9
  latency: 0,
  downloadThroughput: 0,
  uploadThroughput: 0
};

const NO_THROTTLING_METRICS = {
  latency: 0,
  downloadThroughput: 0,
  uploadThroughput: 0,
  offline: false
};

const NO_CPU_THROTTLE_METRICS = {
  rate: 1
};
const CPU_THROTTLE_METRICS = {
  rate: 4
};

function enableNexus5X(driver) {
  /**
   * Finalizes touch emulation by enabling `"ontouchstart" in window` feature detect
   * to work. Messy hack, though copied verbatim from DevTools' emulation/TouchModel.js
   * where it's been working for years. addScriptToEvaluateOnLoad runs before any of the
   * page's JavaScript executes.
   */
  /* eslint-disable no-proto */ /* global window, document */ /* istanbul ignore next */
  const injectedTouchEventsFunction = function() {
    const touchEvents = ['ontouchstart', 'ontouchend', 'ontouchmove', 'ontouchcancel'];
    const recepients = [window.__proto__, document.__proto__];
    for (let i = 0; i < touchEvents.length; ++i) {
      for (let j = 0; j < recepients.length; ++j) {
        if (!(touchEvents[i] in recepients[j])) {
          Object.defineProperty(recepients[j], touchEvents[i], {
            value: null, writable: true, configurable: true, enumerable: true
          });
        }
      }
    }
  };
  /* eslint-enable */

  return Promise.all([
    driver.sendCommand('Emulation.setDeviceMetricsOverride', NEXUS5X_EMULATION_METRICS),
    // required for screenshotting emulated page size, rather than full size
    driver.sendCommand('Emulation.setVisibleSize', {
      width: NEXUS5X_EMULATION_METRICS.screenWidth,
      height: NEXUS5X_EMULATION_METRICS.screenHeight
    }),
    // Network.enable must be called for UA overriding to work
    driver.sendCommand('Network.enable'),
    driver.sendCommand('Network.setUserAgentOverride', NEXUS5X_USERAGENT),
    driver.sendCommand('Emulation.setTouchEmulationEnabled', {
      enabled: true,
      configuration: 'mobile'
    }),
    driver.sendCommand('Page.addScriptToEvaluateOnLoad', {
      scriptSource: '(' + injectedTouchEventsFunction.toString() + ')()'
    })
  ]);
}

function enableNetworkThrottling(driver) {
  return driver.sendCommand('Network.emulateNetworkConditions', TYPICAL_MOBILE_THROTTLING_METRICS);
}

function disableNetworkThrottling(driver) {
  return driver.sendCommand('Network.emulateNetworkConditions', NO_THROTTLING_METRICS);
}

function goOffline(driver) {
  return driver.sendCommand('Network.emulateNetworkConditions', OFFLINE_METRICS);
}

function enableCPUThrottling(driver) {
  return driver.sendCommand('Emulation.setCPUThrottlingRate', CPU_THROTTLE_METRICS);
}

function disableCPUThrottling(driver) {
  return driver.sendCommand('Emulation.setCPUThrottlingRate', NO_CPU_THROTTLE_METRICS);
}

function getEmulationDesc() {
  const {latency, downloadThroughput, uploadThroughput} = TYPICAL_MOBILE_THROTTLING_METRICS;
  const byteToMbit = bytes => (bytes / 1024 / 1024 * 8).toFixed(1);
  return {
    'deviceEmulation': 'Nexus 5X',
    'cpuThrottling': `${CPU_THROTTLE_METRICS.rate}x slowdown`,
    'networkThrottling': `${latency}ms RTT, ${byteToMbit(downloadThroughput)}Mbps down, ` +
        `${byteToMbit(uploadThroughput)}Mbps up`
  };
}

module.exports = {
  enableNexus5X,
  enableNetworkThrottling,
  disableNetworkThrottling,
  enableCPUThrottling,
  disableCPUThrottling,
  goOffline,
  getEmulationDesc,
  settings: {
    NEXUS5X_EMULATION_METRICS,
    NEXUS5X_USERAGENT,
    TYPICAL_MOBILE_THROTTLING_METRICS,
    OFFLINE_METRICS,
    NO_THROTTLING_METRICS,
    NO_CPU_THROTTLE_METRICS,
    CPU_THROTTLE_METRICS
  }
};
<commit_msg>emulation comment: can remove injectedTouchEventsFunction in October (#2889)<commit_after>/**
 * @license Copyright 2016 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 */
'use strict';

/**
 * Nexus 5X metrics adapted from emulated_devices/module.json
 */
const NEXUS5X_EMULATION_METRICS = {
  mobile: true,
  screenWidth: 412,
  screenHeight: 732,
  width: 412,
  height: 732,
  positionX: 0,
  positionY: 0,
  scale: 1,
  deviceScaleFactor: 2.625,
  fitWindow: false,
  screenOrientation: {
    angle: 0,
    type: 'portraitPrimary'
  }
};

const NEXUS5X_USERAGENT = {
  userAgent: 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/MRA58N) AppleWebKit/537.36' +
    '(KHTML, like Gecko) Chrome/61.0.3116.0 Mobile Safari/537.36'
};

/**
 * Adjustments needed for DevTools network throttling to simulate
 * more realistic network conditions.
 * See: crbug.com/721112
 */
const LATENCY_FACTOR = 3.75;
const THROUGHPUT_FACTOR = 0.9;

const TARGET_LATENCY = 150; // 150ms
const TARGET_DOWNLOAD_THROUGHPUT = Math.floor(1.6 * 1024 * 1024 / 8); // 1.6Mbps
const TARGET_UPLOAD_THROUGHPUT = Math.floor(750 * 1024 / 8); // 750Kbps

const TYPICAL_MOBILE_THROTTLING_METRICS = {
  targetLatency: TARGET_LATENCY,
  latency: TARGET_LATENCY * LATENCY_FACTOR,
  targetDownloadThroughput: TARGET_DOWNLOAD_THROUGHPUT,
  downloadThroughput: TARGET_DOWNLOAD_THROUGHPUT * THROUGHPUT_FACTOR,
  targetUploadThroughput: TARGET_UPLOAD_THROUGHPUT,
  uploadThroughput: TARGET_UPLOAD_THROUGHPUT * THROUGHPUT_FACTOR,
  offline: false
};

const OFFLINE_METRICS = {
  offline: true,
  // values of 0 remove any active throttling. crbug.com/456324#c9
  latency: 0,
  downloadThroughput: 0,
  uploadThroughput: 0
};

const NO_THROTTLING_METRICS = {
  latency: 0,
  downloadThroughput: 0,
  uploadThroughput: 0,
  offline: false
};

const NO_CPU_THROTTLE_METRICS = {
  rate: 1
};
const CPU_THROTTLE_METRICS = {
  rate: 4
};

function enableNexus5X(driver) {
  // COMPAT FIMXE
  // Injecting this function clientside is no longer neccessary as of m62. This is done
  // on the backend when `Emulation.setTouchEmulationEnabled` is set.
  //   https://bugs.chromium.org/p/chromium/issues/detail?id=133915#c63
  // Once m62 hits stable (~Oct 20th) we can nuke this entirely
  /**
   * Finalizes touch emulation by enabling `"ontouchstart" in window` feature detect
   * to work. Messy hack, though copied verbatim from DevTools' emulation/TouchModel.js
   * where it's been working for years. addScriptToEvaluateOnLoad runs before any of the
   * page's JavaScript executes.
   */
  /* eslint-disable no-proto */ /* global window, document */ /* istanbul ignore next */
  const injectedTouchEventsFunction = function() {
    const touchEvents = ['ontouchstart', 'ontouchend', 'ontouchmove', 'ontouchcancel'];
    const recepients = [window.__proto__, document.__proto__];
    for (let i = 0; i < touchEvents.length; ++i) {
      for (let j = 0; j < recepients.length; ++j) {
        if (!(touchEvents[i] in recepients[j])) {
          Object.defineProperty(recepients[j], touchEvents[i], {
            value: null, writable: true, configurable: true, enumerable: true
          });
        }
      }
    }
  };
  /* eslint-enable */

  return Promise.all([
    driver.sendCommand('Emulation.setDeviceMetricsOverride', NEXUS5X_EMULATION_METRICS),
    // required for screenshotting emulated page size, rather than full size
    driver.sendCommand('Emulation.setVisibleSize', {
      width: NEXUS5X_EMULATION_METRICS.screenWidth,
      height: NEXUS5X_EMULATION_METRICS.screenHeight
    }),
    // Network.enable must be called for UA overriding to work
    driver.sendCommand('Network.enable'),
    driver.sendCommand('Network.setUserAgentOverride', NEXUS5X_USERAGENT),
    driver.sendCommand('Emulation.setTouchEmulationEnabled', {
      enabled: true,
      configuration: 'mobile'
    }),
    driver.sendCommand('Page.addScriptToEvaluateOnLoad', {
      scriptSource: '(' + injectedTouchEventsFunction.toString() + ')()'
    })
  ]);
}

function enableNetworkThrottling(driver) {
  return driver.sendCommand('Network.emulateNetworkConditions', TYPICAL_MOBILE_THROTTLING_METRICS);
}

function disableNetworkThrottling(driver) {
  return driver.sendCommand('Network.emulateNetworkConditions', NO_THROTTLING_METRICS);
}

function goOffline(driver) {
  return driver.sendCommand('Network.emulateNetworkConditions', OFFLINE_METRICS);
}

function enableCPUThrottling(driver) {
  return driver.sendCommand('Emulation.setCPUThrottlingRate', CPU_THROTTLE_METRICS);
}

function disableCPUThrottling(driver) {
  return driver.sendCommand('Emulation.setCPUThrottlingRate', NO_CPU_THROTTLE_METRICS);
}

function getEmulationDesc() {
  const {latency, downloadThroughput, uploadThroughput} = TYPICAL_MOBILE_THROTTLING_METRICS;
  const byteToMbit = bytes => (bytes / 1024 / 1024 * 8).toFixed(1);
  return {
    'deviceEmulation': 'Nexus 5X',
    'cpuThrottling': `${CPU_THROTTLE_METRICS.rate}x slowdown`,
    'networkThrottling': `${latency}ms RTT, ${byteToMbit(downloadThroughput)}Mbps down, ` +
        `${byteToMbit(uploadThroughput)}Mbps up`
  };
}

module.exports = {
  enableNexus5X,
  enableNetworkThrottling,
  disableNetworkThrottling,
  enableCPUThrottling,
  disableCPUThrottling,
  goOffline,
  getEmulationDesc,
  settings: {
    NEXUS5X_EMULATION_METRICS,
    NEXUS5X_USERAGENT,
    TYPICAL_MOBILE_THROTTLING_METRICS,
    OFFLINE_METRICS,
    NO_THROTTLING_METRICS,
    NO_CPU_THROTTLE_METRICS,
    CPU_THROTTLE_METRICS
  }
};
<|endoftext|>


<commit_before>import SearchAndReplace from './SearchAndReplace'
import Style from './Style'
import Hide from './Hide'
import Group from './Group'
import ReplaceImage from './ReplaceImage'
import ReplaceLink from './ReplaceLink'
import ReplaceNeighbor from './ReplaceNeighbor'
import OverwriteHTML from './OverwriteHTML'
import ReplaceFlowmapIcon from './appdynamics/ReplaceFlowmapIcon'
import ReplaceFlowmapConnection from './appdynamics/ReplaceFlowmapConnection'
import RecolorDashboard from './appdynamics/RecolorDashboard'
import SetDashboardBackground from './appdynamics/SetDashboardBackground'
import DelayLink from './appdynamics/DelayLink'

import Command from './Command'

class CommandBuilder {
  constructor(namespaces = []) {
    this.namespaces = namespaces
  }

  _buildRegex(search, modifiers, replace) {
    modifiers = typeof modifiers === 'string' ? modifiers : 'g'
    if (modifiers.includes('p')) {
      return new SearchAndReplace(
        new RegExp(search, modifiers.replace('p', '')),
        function (match) {
          if (match.toUpperCase() === match) {
            replace = replace.toUpperCase()
          }
          if (match.toLowerCase() === match) {
            replace = replace.toLowerCase()
          }
          return match.replace(new RegExp(search, modifiers.replace('p', '')), replace)
        })
    }
    return new SearchAndReplace(new RegExp(search, modifiers), replace)
  }

  _buildCustomCommand(namespace, command, parameters, value) {
    var location = typeof window === 'undefined' ? '' : window.location

    if (namespace === 'appdynamics' || this.namespaces.includes('appdynamics')) {
      if (command === 'replaceFlowmapIcon') {
        return new ReplaceFlowmapIcon(parameters[0], value)
      }

      if (command === 'hideApplication') {
        return new Group([
          new Hide(parameters[0], 4, 'ads-application-card', '', 'APPS_ALL_DASHBOARD', location),
          new Hide(parameters[0], 3, 'x-grid-row', '', 'APPS_ALL_DASHBOARD', location),
          // For Appd<4.3
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'AD_HOME_OVERVIEW', location, function (_, parentNode) {
            return parentNode.getAttribute('ng-click').includes('ViewApplicationDashboard')
          }),
          // For Appd>4.4
          new Hide(parameters[0], 3, 'ads-home-list-action-item', '', 'AD_HOME_OVERVIEW', location, function (node, parentNode) {
            return node.parentElement.hasAttribute('ad-test-id') && node.parentElement.getAttribute('ad-test-id').includes('home-screen-application-card-application-name')
          })
        ])
      }
      if (command === 'hideBrowserApplication') {
        return new Group([
          new Hide(parameters[0], 4, 'x-grid-row', '', 'EUM_WEB_ALL_APPS', location),
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'AD_HOME_OVERVIEW', location, function (_, parentNode) {
            return parentNode.getAttribute('ng-click').includes('ViewEumWebApplication')
          })
        ])
      }
      if (command === 'hideMobileApplication') {
        return new Group([
          new Hide(parameters[0], 4, 'ads-mobile-app-card', '', 'EUM_MOBILE_ALL_APPS', location),
          new Hide(parameters[0], 4, 'x-grid-row', '', 'EUM_MOBILE_ALL_APPS', location),
          new Hide(parameters[0], 5, 'x-grid-row', '', 'EUM_MOBILE_ALL_APPS', location),
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'AD_HOME_OVERVIEW', location, function (_, parentNode) {
            return parentNode.getAttribute('ng-click').includes('ViewEumMobileApplication')
          })
        ])
      }
      if (command === 'hideDB' || command === 'hideDatabase') {
        return new Group([
          new Hide(parameters[0], 9, 'ads-database-card', '', 'DB_MONITORING_SERVER_LIST', location),
          new Hide(parameters[0], 4, 'x-grid-row', '', 'DB_MONITORING_SERVER_LIST', location),
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'AD_HOME_OVERVIEW', location, function (_, parentNode) {
            return parentNode.getAttribute('ng-click').includes('ViewDbServer')
          })
        ])
      }
      if (command === 'hideBT' || command === 'hideBusinessTransaction') {
        return new Hide(parameters[0], 3, 'x-grid-row', '', 'APP_BT_LIST', location)
      }
      if (command === 'hideDashboard') {
        return new Group([
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'DASHBOARDS_REPORTS_HOME', location),
          new Hide(parameters[0], 3, 'x-grid-row', '', 'DASHBOARD_LIST', location, function (node, parentNode) {
            // Make sure that replacements with !not work on the dashboard list, so filter for the first cell
            return node.parentElement.parentElement.className.includes('x-grid-cell-first')
          })
        ])
      }
      if (command === 'hideBusinessJourney') {
        return new Hide(parameters[0], 9, 'ads-analytics-business-outcomes-card-size', '', 'ANALYTICS_BUSINESS_OUTCOMES', location)
      }
      if (command === 'hideAnalyticsSearch') {
        return new Hide(parameters[0], 7, 'ui-grid-row', '', 'ANALYTICS_SEARCH_LIST', location)
      }
      if (command === 'hideRemoteService') {
        return new Hide(parameters[0], 3, 'x-grid-row', '', 'APP_BACKEND_LIST', location)
      }
      if (command === 'replaceFlowmapConnection') {
        return new ReplaceFlowmapConnection(parameters[0], parameters[1], value, parameters[2])
      }
      if (command === 'replaceMobileScreenshot') {
        var condition = function (document) {
          var view = document.querySelector('.ads-session-left-panel-container-grid-with-nav .x-grid-row-selected .x-grid-cell-first .x-grid-cell-inner')
          return view !== null && view.innerHTML === parameters[0]
        }
        var thumbnailHtml = ''
        var screenshotHtml = ''
        return new Group([
          new OverwriteHTML('EUM_MOBILE_SESSION_DETAILS', '.ads-screenshot-container', screenshotHtml, location, condition),
          new OverwriteHTML('EUM_MOBILE_SESSION_DETAILS', '.ads-screenshot-tooltip-thumbnail-container', thumbnailHtml, location, condition),
          new OverwriteHTML('EUM_MOBILE_SESSION_DETAILS', '.ads-screenshots-thumbnail-container', thumbnailHtml, location, condition)
        ])
      }
      if (command === 'delayLink') {
        return new DelayLink(parameters[0], value, window)
      }
      if (command === 'recolorDashboard') {
        return new RecolorDashboard(parameters[0], value, parameters[1], location)
      }
      if (command === 'setDashboardBackground') {
        return new SetDashboardBackground(parameters[0], value, location)
      }
      if (command === 'replaceNodeCount') {
        return new Group([
          new ReplaceNeighbor(parameters[0], value, 2, 'text.adsNodeCountText', '', location),
          new ReplaceNeighbor(parameters[0], parseInt(value) === 1 ? 'Node' : 'Nodes', 2, 'text.adsNodeCountTextSmall', '', location)
        ])
      }
    }

    if (command === 'replace') {
      return new SearchAndReplace(parameters[0], value, parameters[1], parameters[2], location)
    }

    if (command === 'replaceNeighbor') {
      return new ReplaceNeighbor(parameters[0], value, parameters[1], parameters[2], parameters[3], location)
    }

    if (command === 'style') {
      return new Style(parameters[0], parameters[1], parameters[2], value)
    }

    if (command === 'hide') {
      return new Hide(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], location)
    }

    if (command === 'replaceImage') {
      return new ReplaceImage(parameters[0], value)
    }

    if (command === 'replaceLink') {
      return new ReplaceLink(parameters[0], value)
    }

    if (command === 'overwriteHTML' || command === 'overwrite') {
      return new OverwriteHTML(parameters[0], parameters[1], value, location)
    }

    if (command === 'overwritePage') {
      var iframeCode = '<title>' + parameters[1] + '</title>'
      return new OverwriteHTML(parameters[0], '', iframeCode, location)
    }

    return new Command()
  }

  _extractForCustomCommand(command) {
    if (typeof command !== 'string' || command === '') {
      return {extracted: false}
    }

    var namespace = ''
    var parameters = []

    if (command.indexOf('(') !== -1) {
      if (command.substr(-1) !== ')') {
        return {extracted: false}
      }
      // parameters = command.slice(command.indexOf('(') + 1, -1).split(/\s*,\s*/).filter(elem => elem !== '')
      var index = 0
      var params = command.slice(command.indexOf('(') + 1, -1)
      parameters.push('')
      var open = ''
      params.split('').forEach(letter => {
        if (open !== '\'' && letter === '"') {
          open = open === '"' ? '' : letter
        }
        if (open !== '"' && letter === '\'') {
          open = open === '\'' ? '' : letter
        }
        if (open === '' && letter === ',') {
          index++
          parameters.push('')
          return
        }
        parameters[index] += letter
      })

      parameters = parameters.map(e => e.trim().replace(/"(.*)"|'(.*)'/, '$1$2')) // .filter(e => e !== '')

      command = command.split('(')[0]
    }

    if (command.indexOf('.') !== -1) {
      namespace = command.slice(0, command.lastIndexOf('.'))
      command = command.slice(command.lastIndexOf('.') + 1)
    }

    return {extracted: true, command: command, namespace: namespace, parameters: parameters}
  }

  _buildCommand(key, value) {
    // handle regular expressions
    var regex = key.match(/^\/(.+)\/([gimp]+)?$/)
    if (regex !== null) {
      return this._buildRegex(regex[1], regex[2], value)
    }

    var rawCommand = this._extractForCustomCommand(key)

    if (rawCommand.extracted) {
      return this._buildCustomCommand(rawCommand.namespace, rawCommand.command, rawCommand.parameters, value)
    }
    return new Command()
  }

  build(key, value) {
    // Reverse of the replacement of \= defined in Ini.js
    if (typeof value === 'string') {
      value = value.replace('\u2260', '=')
    }
    if (typeof key === 'string') {
      key = key.replace('\u2260', '=')
    }

    if (key.charAt(0) === '!') {
      return this._buildCommand(key.substr(1), value)
    }

    if (key.charAt(0) === '\\') {
      key = key.substr(1)
    }

    return new SearchAndReplace(key, value)
  }
}

export default CommandBuilder
<commit_msg>Add recolourDashboard<commit_after>import SearchAndReplace from './SearchAndReplace'
import Style from './Style'
import Hide from './Hide'
import Group from './Group'
import ReplaceImage from './ReplaceImage'
import ReplaceLink from './ReplaceLink'
import ReplaceNeighbor from './ReplaceNeighbor'
import OverwriteHTML from './OverwriteHTML'
import ReplaceFlowmapIcon from './appdynamics/ReplaceFlowmapIcon'
import ReplaceFlowmapConnection from './appdynamics/ReplaceFlowmapConnection'
import RecolorDashboard from './appdynamics/RecolorDashboard'
import SetDashboardBackground from './appdynamics/SetDashboardBackground'
import DelayLink from './appdynamics/DelayLink'

import Command from './Command'

class CommandBuilder {
  constructor(namespaces = []) {
    this.namespaces = namespaces
  }

  _buildRegex(search, modifiers, replace) {
    modifiers = typeof modifiers === 'string' ? modifiers : 'g'
    if (modifiers.includes('p')) {
      return new SearchAndReplace(
        new RegExp(search, modifiers.replace('p', '')),
        function (match) {
          if (match.toUpperCase() === match) {
            replace = replace.toUpperCase()
          }
          if (match.toLowerCase() === match) {
            replace = replace.toLowerCase()
          }
          return match.replace(new RegExp(search, modifiers.replace('p', '')), replace)
        })
    }
    return new SearchAndReplace(new RegExp(search, modifiers), replace)
  }

  _buildCustomCommand(namespace, command, parameters, value) {
    var location = typeof window === 'undefined' ? '' : window.location

    if (namespace === 'appdynamics' || this.namespaces.includes('appdynamics')) {
      if (command === 'replaceFlowmapIcon') {
        return new ReplaceFlowmapIcon(parameters[0], value)
      }

      if (command === 'hideApplication') {
        return new Group([
          new Hide(parameters[0], 4, 'ads-application-card', '', 'APPS_ALL_DASHBOARD', location),
          new Hide(parameters[0], 3, 'x-grid-row', '', 'APPS_ALL_DASHBOARD', location),
          // For Appd<4.3
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'AD_HOME_OVERVIEW', location, function (_, parentNode) {
            return parentNode.getAttribute('ng-click').includes('ViewApplicationDashboard')
          }),
          // For Appd>4.4
          new Hide(parameters[0], 3, 'ads-home-list-action-item', '', 'AD_HOME_OVERVIEW', location, function (node, parentNode) {
            return node.parentElement.hasAttribute('ad-test-id') && node.parentElement.getAttribute('ad-test-id').includes('home-screen-application-card-application-name')
          })
        ])
      }
      if (command === 'hideBrowserApplication') {
        return new Group([
          new Hide(parameters[0], 4, 'x-grid-row', '', 'EUM_WEB_ALL_APPS', location),
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'AD_HOME_OVERVIEW', location, function (_, parentNode) {
            return parentNode.getAttribute('ng-click').includes('ViewEumWebApplication')
          })
        ])
      }
      if (command === 'hideMobileApplication') {
        return new Group([
          new Hide(parameters[0], 4, 'ads-mobile-app-card', '', 'EUM_MOBILE_ALL_APPS', location),
          new Hide(parameters[0], 4, 'x-grid-row', '', 'EUM_MOBILE_ALL_APPS', location),
          new Hide(parameters[0], 5, 'x-grid-row', '', 'EUM_MOBILE_ALL_APPS', location),
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'AD_HOME_OVERVIEW', location, function (_, parentNode) {
            return parentNode.getAttribute('ng-click').includes('ViewEumMobileApplication')
          })
        ])
      }
      if (command === 'hideDB' || command === 'hideDatabase') {
        return new Group([
          new Hide(parameters[0], 9, 'ads-database-card', '', 'DB_MONITORING_SERVER_LIST', location),
          new Hide(parameters[0], 4, 'x-grid-row', '', 'DB_MONITORING_SERVER_LIST', location),
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'AD_HOME_OVERVIEW', location, function (_, parentNode) {
            return parentNode.getAttribute('ng-click').includes('ViewDbServer')
          })
        ])
      }
      if (command === 'hideBT' || command === 'hideBusinessTransaction') {
        return new Hide(parameters[0], 3, 'x-grid-row', '', 'APP_BT_LIST', location)
      }
      if (command === 'hideDashboard') {
        return new Group([
          new Hide(parameters[0], 2, 'ads-home-list-item', '', 'DASHBOARDS_REPORTS_HOME', location),
          new Hide(parameters[0], 3, 'x-grid-row', '', 'DASHBOARD_LIST', location, function (node, parentNode) {
            // Make sure that replacements with !not work on the dashboard list, so filter for the first cell
            return node.parentElement.parentElement.className.includes('x-grid-cell-first')
          })
        ])
      }
      if (command === 'hideBusinessJourney') {
        return new Hide(parameters[0], 9, 'ads-analytics-business-outcomes-card-size', '', 'ANALYTICS_BUSINESS_OUTCOMES', location)
      }
      if (command === 'hideAnalyticsSearch') {
        return new Hide(parameters[0], 7, 'ui-grid-row', '', 'ANALYTICS_SEARCH_LIST', location)
      }
      if (command === 'hideRemoteService') {
        return new Hide(parameters[0], 3, 'x-grid-row', '', 'APP_BACKEND_LIST', location)
      }
      if (command === 'replaceFlowmapConnection') {
        return new ReplaceFlowmapConnection(parameters[0], parameters[1], value, parameters[2])
      }
      if (command === 'replaceMobileScreenshot') {
        var condition = function (document) {
          var view = document.querySelector('.ads-session-left-panel-container-grid-with-nav .x-grid-row-selected .x-grid-cell-first .x-grid-cell-inner')
          return view !== null && view.innerHTML === parameters[0]
        }
        var thumbnailHtml = ''
        var screenshotHtml = ''
        return new Group([
          new OverwriteHTML('EUM_MOBILE_SESSION_DETAILS', '.ads-screenshot-container', screenshotHtml, location, condition),
          new OverwriteHTML('EUM_MOBILE_SESSION_DETAILS', '.ads-screenshot-tooltip-thumbnail-container', thumbnailHtml, location, condition),
          new OverwriteHTML('EUM_MOBILE_SESSION_DETAILS', '.ads-screenshots-thumbnail-container', thumbnailHtml, location, condition)
        ])
      }
      if (command === 'delayLink') {
        return new DelayLink(parameters[0], value, window)
      }
      if (command === 'recolorDashboard' || command === 'recolourDashboard') {
        return new RecolorDashboard(parameters[0], value, parameters[1], location)
      }
      if (command === 'setDashboardBackground') {
        return new SetDashboardBackground(parameters[0], value, location)
      }
      if (command === 'replaceNodeCount') {
        return new Group([
          new ReplaceNeighbor(parameters[0], value, 2, 'text.adsNodeCountText', '', location),
          new ReplaceNeighbor(parameters[0], parseInt(value) === 1 ? 'Node' : 'Nodes', 2, 'text.adsNodeCountTextSmall', '', location)
        ])
      }
    }

    if (command === 'replace') {
      return new SearchAndReplace(parameters[0], value, parameters[1], parameters[2], location)
    }

    if (command === 'replaceNeighbor') {
      return new ReplaceNeighbor(parameters[0], value, parameters[1], parameters[2], parameters[3], location)
    }

    if (command === 'style') {
      return new Style(parameters[0], parameters[1], parameters[2], value)
    }

    if (command === 'hide') {
      return new Hide(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], location)
    }

    if (command === 'replaceImage') {
      return new ReplaceImage(parameters[0], value)
    }

    if (command === 'replaceLink') {
      return new ReplaceLink(parameters[0], value)
    }

    if (command === 'overwriteHTML' || command === 'overwrite') {
      return new OverwriteHTML(parameters[0], parameters[1], value, location)
    }

    if (command === 'overwritePage') {
      var iframeCode = '<title>' + parameters[1] + '</title>'
      return new OverwriteHTML(parameters[0], '', iframeCode, location)
    }

    return new Command()
  }

  _extractForCustomCommand(command) {
    if (typeof command !== 'string' || command === '') {
      return {extracted: false}
    }

    var namespace = ''
    var parameters = []

    if (command.indexOf('(') !== -1) {
      if (command.substr(-1) !== ')') {
        return {extracted: false}
      }
      // parameters = command.slice(command.indexOf('(') + 1, -1).split(/\s*,\s*/).filter(elem => elem !== '')
      var index = 0
      var params = command.slice(command.indexOf('(') + 1, -1)
      parameters.push('')
      var open = ''
      params.split('').forEach(letter => {
        if (open !== '\'' && letter === '"') {
          open = open === '"' ? '' : letter
        }
        if (open !== '"' && letter === '\'') {
          open = open === '\'' ? '' : letter
        }
        if (open === '' && letter === ',') {
          index++
          parameters.push('')
          return
        }
        parameters[index] += letter
      })

      parameters = parameters.map(e => e.trim().replace(/"(.*)"|'(.*)'/, '$1$2')) // .filter(e => e !== '')

      command = command.split('(')[0]
    }

    if (command.indexOf('.') !== -1) {
      namespace = command.slice(0, command.lastIndexOf('.'))
      command = command.slice(command.lastIndexOf('.') + 1)
    }

    return {extracted: true, command: command, namespace: namespace, parameters: parameters}
  }

  _buildCommand(key, value) {
    // handle regular expressions
    var regex = key.match(/^\/(.+)\/([gimp]+)?$/)
    if (regex !== null) {
      return this._buildRegex(regex[1], regex[2], value)
    }

    var rawCommand = this._extractForCustomCommand(key)

    if (rawCommand.extracted) {
      return this._buildCustomCommand(rawCommand.namespace, rawCommand.command, rawCommand.parameters, value)
    }
    return new Command()
  }

  build(key, value) {
    // Reverse of the replacement of \= defined in Ini.js
    if (typeof value === 'string') {
      value = value.replace('\u2260', '=')
    }
    if (typeof key === 'string') {
      key = key.replace('\u2260', '=')
    }

    if (key.charAt(0) === '!') {
      return this._buildCommand(key.substr(1), value)
    }

    if (key.charAt(0) === '\\') {
      key = key.substr(1)
    }

    return new SearchAndReplace(key, value)
  }
}

export default CommandBuilder
<|endoftext|>


<commit_before>import Vue from 'vue'

import slot from '../../utils/slot.js'

export default Vue.extend({
  name: 'QSlideTransition',

  props: {
    appear: Boolean,
    duration: {
      type: Number,
      default: 300
    }
  },

  methods: {
    __begin (el, height, done) {
      el.style.overflowY = 'hidden'
      if (height !== void 0) {
        el.style.height = `${height}px`
      }
      el.style.transition = `height ${this.duration}ms cubic-bezier(.25, .8, .50, 1)`

      this.animating = true
      this.done = done
    },

    __end (el, event) {
      el.style.overflowY = null
      el.style.height = null
      el.style.transition = null
      this.__cleanup()
      event !== this.lastEvent && this.$emit(event)
    },

    __cleanup () {
      this.done && this.done()
      this.done = null
      this.animating = false

      clearTimeout(this.timer)
      clearTimeout(this.timerFallback)
      this.el.removeEventListener('transitionend', this.animListener)
      this.animListener = null
    }
  },

  beforeDestroy () {
    this.animating && this.__cleanup()
  },

  render (h) {
    return h('transition', {
      props: {
        css: false,
        appear: this.appear
      },
      on: {
        enter: (el, done) => {
          let pos = 0
          this.el = el

          if (this.animating === true) {
            this.__cleanup()
            pos = el.offsetHeight === el.scrollHeight ? 0 : void 0
          }
          else {
            this.lastEvent = 'hide'
          }

          this.__begin(el, pos, done)

          this.timer = setTimeout(() => {
            el.style.height = `${el.scrollHeight}px`
            this.animListener = ev => {
              if (ev !== null && typeof ev === 'object' && ev.target !== el) {
                return
              }
              this.__end(el, 'show')
            }
            el.addEventListener('transitionend', this.animListener)
            this.timerFallback = setTimeout(this.animListener, this.duration * 1.1)
          }, 100)
        },
        leave: (el, done) => {
          let pos
          this.el = el

          if (this.animating === true) {
            this.__cleanup()
          }
          else {
            this.lastEvent = 'show'
            pos = el.scrollHeight
          }

          this.__begin(el, pos, done)

          this.timer = setTimeout(() => {
            el.style.height = 0
            this.animListener = ev => {
              if (ev !== null && typeof ev === 'object' && ev.target !== el) {
                return
              }
              this.__end(el, 'hide')
            }
            el.addEventListener('transitionend', this.animListener)
            this.timerFallback = setTimeout(this.animListener, this.duration * 1.1)
          }, 100)
        }
      }
    }, slot(this, 'default'))
  }
})
<commit_msg>Update QSlideTransition.js<commit_after>import Vue from 'vue'

import slot from '../../utils/slot.js'

export default Vue.extend({
  name: 'QSlideTransition',

  props: {
    appear: Boolean,
    duration: {
      type: Number,
      default: 300
    }
  },

  methods: {
    __begin (el, height, done) {
      el.style.overflowY = 'hidden'
      if (height !== void 0) {
        el.style.height = `${height}px`
      }
      el.style.transition = `height ${this.duration}ms cubic-bezier(.25, .8, .50, 1)`

      this.animating = true
      this.done = done
    },

    __end (el, event) {
      el.style.overflowY = null
      el.style.height = null
      el.style.transition = null
      this.__cleanup()
      event !== this.lastEvent && this.$emit(event)
    },

    __cleanup () {
      this.done && this.done()
      this.done = null
      this.animating = false

      clearTimeout(this.timer)
      clearTimeout(this.timerFallback)
      this.el.removeEventListener('transitionend', this.animListener)
      this.animListener = null
    }
  },

  beforeDestroy () {
    this.animating && this.__cleanup()
  },

  render (h) {
    return h('transition', {
      props: {
        css: false,
        appear: this.appear
      },
      on: {
        enter: (el, done) => {
          let pos = 0
          this.el = el

          if (this.animating === true) {
            this.__cleanup()
            pos = el.offsetHeight === el.scrollHeight ? 0 : void 0
          }
          else {
            this.lastEvent = 'hide'
          }

          this.__begin(el, pos, done)

          this.timer = setTimeout(() => {
            el.style.height = `${el.scrollHeight}px`
            this.animListener = ev => {
              if (Object(ev) === ev && ev.target === el) {
                this.__end(el, 'show')
              }
            }
            el.addEventListener('transitionend', this.animListener)
            this.timerFallback = setTimeout(this.animListener, this.duration * 1.1)
          }, 100)
        },
        leave: (el, done) => {
          let pos
          this.el = el

          if (this.animating === true) {
            this.__cleanup()
          }
          else {
            this.lastEvent = 'show'
            pos = el.scrollHeight
          }

          this.__begin(el, pos, done)

          this.timer = setTimeout(() => {
            el.style.height = 0
            this.animListener = ev => {
              if (Object(ev) === ev && ev.target === el) {
                this.__end(el, 'hide')
              }
            }
            el.addEventListener('transitionend', this.animListener)
            this.timerFallback = setTimeout(this.animListener, this.duration * 1.1)
          }, 100)
        }
      }
    }, slot(this, 'default'))
  }
})
<|endoftext|>


<commit_before>'use strict';

const Command = require('../../Command.js');

/**
 * Get a role from the matching string
 * @param  {string} string      String to use to search for role
 * @param  {Message} message    originating message
 * @returns {Role|null}         Role
 */
function getRoleForString(string, message) {
  const trimmedString = string.trim();
  const roleFromId = message.guild.roles.get(trimmedString);
  let roleFromName;
  if (typeof roleFromId === 'undefined') {
    roleFromName = message.guild.roles
      .find(item => item.name.toLowerCase() === trimmedString.toLowerCase());
  }
  return roleFromId || roleFromName || null;
}

/**
 * Add a joinable role
 */
class JoinRole extends Command {
  constructor(bot) {
    super(bot, 'settings.joinRole', 'join');
    this.usages = [
      { description: 'Show instructions for joining roles', parameters: [] },
      { description: 'Joining a role', parameters: ['Role/Role id to join.'] },
    ];
    this.regex = new RegExp(`^${this.call}\\s(.*)?`, 'i');
    this.allowDM = false;
  }

  /**
   * Run the command
   * @param {Message} message Message with a command to handle, reply to,
   *                          or perform an action based on parameters.
   */
  run(message) {
    const stringRole = message.strippedContent.replace(`${this.call} `, '');
    if (!stringRole) {
      this.sendInstructionEmbed(message);
    } else {
      const role = getRoleForString(stringRole, message);
      if (!role) {
        this.sendInstructionEmbed(message);
      } else {
        this.bot.settings.getRolesForGuild(message.guild)
           .then((roles) => {
             const filteredRoles = roles.filter(storedRole => role.id === storedRole.id);
             const roleAddable = filteredRoles.length > 0
               && !message.member.roles.get(role.id)
               && message.channel.permissionsFor(this.bot.client.user.id).has('MANAGE_ROLES_OR_PERMISSIONS');
             if (roleAddable) {
               message.member.addRole(role.id)
                .then(() => this.sendJoined(message, role))
                .catch(this.logger.error);
             } else {
               this.sendCantJoin(message);
             }
           })
           .catch(this.logger.error);
      }
    }
  }

  sendJoined(message, role) {
    this.messageManager.embed(message, {
      title: 'Joined Role',
      type: 'rich',
      color: 0x779ECB,
      fields: [
        {
          name: '_ _',
          value: role.name,
          inline: true,
        },
      ],
    }, true, true);
  }

  sendCantJoin(message) {
    this.messageManager.embed(message, {
      title: 'Invalid Role',
      type: 'rich',
      color: 0x779ECB,
      fields: [
        {
          name: '_ _',
          value: 'You can\'t join that role.',
          inline: true,
        },
      ],
    }, true, true);
  }

  sendInstructionEmbed(message) {
    const embed = {
      title: 'Usage',
      type: 'rich',
      color: 0x779ECB,
      fields: [
        {
          name: '_ _',
          value: 'Role or role id to join.',
        },
        {
          name: 'Possible role values:',
          value: '_ _',
        },
      ],
    };
    this.bot.settings.getChannelPrefix(message.channel)
      .then((prefix) => {
        embed.fields[0].name = `${prefix}${this.call} <role or role id>`;
        return this.bot.settings.getRolesForGuild(message.guild);
      })
      .then((roles) => {
        embed.fields[1].value = roles.map(role => role.name).join('; ');
        this.messageManager.embed(message, embed, true, false);
      })
      .catch(this.logger.error);
  }
}

module.exports = JoinRole;
<commit_msg>make space optional - join role<commit_after>'use strict';

const Command = require('../../Command.js');

/**
 * Get a role from the matching string
 * @param  {string} string      String to use to search for role
 * @param  {Message} message    originating message
 * @returns {Role|null}         Role
 */
function getRoleForString(string, message) {
  const trimmedString = string.trim();
  const roleFromId = message.guild.roles.get(trimmedString);
  let roleFromName;
  if (typeof roleFromId === 'undefined') {
    roleFromName = message.guild.roles
      .find(item => item.name.toLowerCase() === trimmedString.toLowerCase());
  }
  return roleFromId || roleFromName || null;
}

/**
 * Add a joinable role
 */
class JoinRole extends Command {
  constructor(bot) {
    super(bot, 'settings.joinRole', 'join');
    this.usages = [
      { description: 'Show instructions for joining roles', parameters: [] },
      { description: 'Joining a role', parameters: ['Role/Role id to join.'] },
    ];
    this.regex = new RegExp(`^${this.call}\\s?(.*)?`, 'i');
    this.allowDM = false;
  }

  /**
   * Run the command
   * @param {Message} message Message with a command to handle, reply to,
   *                          or perform an action based on parameters.
   */
  run(message) {
    const stringRole = message.strippedContent.replace(`${this.call} `, '');
    if (!stringRole) {
      this.sendInstructionEmbed(message);
    } else {
      const role = getRoleForString(stringRole, message);
      if (!role) {
        this.sendInstructionEmbed(message);
      } else {
        this.bot.settings.getRolesForGuild(message.guild)
           .then((roles) => {
             const filteredRoles = roles.filter(storedRole => role.id === storedRole.id);
             const roleAddable = filteredRoles.length > 0
               && !message.member.roles.get(role.id)
               && message.channel.permissionsFor(this.bot.client.user.id).has('MANAGE_ROLES_OR_PERMISSIONS');
             if (roleAddable) {
               message.member.addRole(role.id)
                .then(() => this.sendJoined(message, role))
                .catch(this.logger.error);
             } else {
               this.sendCantJoin(message);
             }
           })
           .catch(this.logger.error);
      }
    }
  }

  sendJoined(message, role) {
    this.messageManager.embed(message, {
      title: 'Joined Role',
      type: 'rich',
      color: 0x779ECB,
      fields: [
        {
          name: '_ _',
          value: role.name,
          inline: true,
        },
      ],
    }, true, true);
  }

  sendCantJoin(message) {
    this.messageManager.embed(message, {
      title: 'Invalid Role',
      type: 'rich',
      color: 0x779ECB,
      fields: [
        {
          name: '_ _',
          value: 'You can\'t join that role.',
          inline: true,
        },
      ],
    }, true, true);
  }

  sendInstructionEmbed(message) {
    const embed = {
      title: 'Usage',
      type: 'rich',
      color: 0x779ECB,
      fields: [
        {
          name: '_ _',
          value: 'Role or role id to join.',
        },
        {
          name: 'Possible role values:',
          value: '_ _',
        },
      ],
    };
    this.bot.settings.getChannelPrefix(message.channel)
      .then((prefix) => {
        embed.fields[0].name = `${prefix}${this.call} <role or role id>`;
        return this.bot.settings.getRolesForGuild(message.guild);
      })
      .then((roles) => {
        embed.fields[1].value = roles.map(role => role.name).join('; ');
        this.messageManager.embed(message, embed, true, false);
      })
      .catch(this.logger.error);
  }
}

module.exports = JoinRole;
<|endoftext|>


<commit_before>import React, {Component} from 'react'
import PropTypes from 'prop-types'
import moment from 'moment'

import InputClickToEdit from 'shared/components/InputClickToEdit'

class GraphOptionsTimeFormat extends Component {
  state = {format: this.props.timeFormat || 'MM/DD/YYYY HH:mm:ss.ss'}

  handleInputChange = value => {
    const {onTimeFormatChange} = this.props
    const date = new Date()
    const formattedDate = moment(date.toISOString()).format(value)
    const validDateFormat = moment(formattedDate, value)._isValid
    if (validDateFormat) {
      onTimeFormatChange(value)
    }
  }

  render() {
    const {format} = this.state
    return (

        Time Format
        <InputClickToEdit
          wrapperClass="fancytable--td orgs-table--name"
          value={format}
          onUpdate={this.handleInputChange}
          placeholder="MM/DD/YYYY HH:mm:ss.ss"
        />

    )
  }
}

const {func, string} = PropTypes

GraphOptionsTimeFormat.propTypes = {
  timeFormat: string,
  onTimeFormatChange: func,
}

export default GraphOptionsTimeFormat
<commit_msg>change time format from input to dropdown with an input available if custom format selected<commit_after>import React, {Component} from 'react'
import PropTypes from 'prop-types'
import moment from 'moment'

import InputClickToEdit from 'shared/components/InputClickToEdit'
import {Dropdown} from 'src/shared/components/Dropdown'
import QuestionMarkTooltip from 'src/shared/components/QuestionMarkTooltip'

const formatOptions = [
  {text: 'MM/DD/YYYY HH:mm:ss.ss'},
  {text: 'MM/DD/YYYY HH:mm'},
  {text: 'MM/DD/YYYY'},
  {text: 'h:mm:ss A'},
  {text: 'h:mm A'},
  {text: 'MMMM D, YYYY'},
  {text: 'MMMM D, YYYY h:mm A'},
  {text: 'dddd, MMMM D, YYYY h:mm A'},
  {text: 'Custom'},
]

class GraphOptionsTimeFormat extends Component {
  state = {
    format: this.props.timeFormat || 'MM/DD/YYYY HH:mm:ss.ss',
    customFormat: false,
  }

  handleInputChange = value => {
    const {onTimeFormatChange} = this.props
    onTimeFormatChange(value)
  }

  handleChooseFormat = formatOption => {
    if (formatOption.text === 'Custom') {
      this.setState({customFormat: true})
    } else {
      this.setState({format: formatOption.text, customFormat: false})
    }
  }

  render() {
    const {format, customFormat} = this.state
    const tipContent =
      'For information on formatting, see http://momentjs.com/docs/#/parsing/string-format/'

    return (

          Time Format{' '}
          {customFormat &&
            <QuestionMarkTooltip
              tipID="Time Axis Format"
              tipContent={tipContent}
            />}

        <Dropdown
          items={formatOptions}
          selected={customFormat ? 'Custom' : format}
          buttonColor="btn-primary"
          buttonSize="btn-xs"
          className="dropdown-stretch"
          onChoose={this.handleChooseFormat}
        />
        {customFormat &&
          <InputClickToEdit
            wrapperClass="fancytable--td"
            value={format}
            onUpdate={this.handleInputChange}
            placeholder="Enter custom format..."
          />}

    )
  }
}

const {func, string} = PropTypes

GraphOptionsTimeFormat.propTypes = {
  timeFormat: string,
  onTimeFormatChange: func,
}

export default GraphOptionsTimeFormat
<|endoftext|>


<commit_before>goog.provide('ol.interaction.DragPan');

goog.require('ol');
goog.require('ol.View');
goog.require('ol.coordinate');
goog.require('ol.events.condition');
goog.require('ol.functions');
goog.require('ol.interaction.Pointer');

/**
 * @classdesc
 * Allows the user to pan the map by dragging the map.
 *
 * @constructor
 * @extends {ol.interaction.Pointer}
 * @param {olx.interaction.DragPanOptions=} opt_options Options.
 * @api stable
 */
ol.interaction.DragPan = function(opt_options) {

  ol.interaction.Pointer.call(this, {
    handleDownEvent: ol.interaction.DragPan.handleDownEvent_,
    handleDragEvent: ol.interaction.DragPan.handleDragEvent_,
    handleUpEvent: ol.interaction.DragPan.handleUpEvent_
  });

  var options = opt_options ? opt_options : {};

  /**
   * @private
   * @type {ol.Kinetic|undefined}
   */
  this.kinetic_ = options.kinetic;

  /**
   * @private
   * @type {?ol.PreRenderFunction}
   */
  this.kineticPreRenderFn_ = null;

  /**
   * @type {ol.Pixel}
   */
  this.lastCentroid = null;

  /**
   * @private
   * @type {ol.EventsConditionType}
   */
  this.condition_ = options.condition ?
      options.condition : ol.events.condition.noModifierKeys;

  /**
   * @private
   * @type {boolean}
   */
  this.noKinetic_ = false;

};
ol.inherits(ol.interaction.DragPan, ol.interaction.Pointer);

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @this {ol.interaction.DragPan}
 * @private
 */
ol.interaction.DragPan.handleDragEvent_ = function(mapBrowserEvent) {
  goog.DEBUG && console.assert(this.targetPointers.length >= 1,
      'the length of this.targetPointers should be more than 1');
  var centroid =
      ol.interaction.Pointer.centroid(this.targetPointers);
  if (this.kinetic_) {
    this.kinetic_.update(centroid[0], centroid[1]);
  }
  if (this.lastCentroid) {
    var deltaX = this.lastCentroid[0] - centroid[0];
    var deltaY = centroid[1] - this.lastCentroid[1];
    var map = mapBrowserEvent.map;
    var view = map.getView();
    var viewState = view.getState();
    var center = [deltaX, deltaY];
    ol.coordinate.scale(center, viewState.resolution);
    ol.coordinate.rotate(center, viewState.rotation);
    ol.coordinate.add(center, viewState.center);
    center = view.constrainCenter(center);
    map.render();
    view.setCenter(center);
  }
  this.lastCentroid = centroid;
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Stop drag sequence?
 * @this {ol.interaction.DragPan}
 * @private
 */
ol.interaction.DragPan.handleUpEvent_ = function(mapBrowserEvent) {
  var map = mapBrowserEvent.map;
  var view = map.getView();
  if (this.targetPointers.length === 0) {
    if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) {
      var distance = this.kinetic_.getDistance();
      var angle = this.kinetic_.getAngle();
      var center = /** @type {!ol.Coordinate} */ (view.getCenter());
      this.kineticPreRenderFn_ = this.kinetic_.pan(center);
      map.beforeRender(this.kineticPreRenderFn_);
      var centerpx = map.getPixelFromCoordinate(center);
      var dest = map.getCoordinateFromPixel([
        centerpx[0] - distance * Math.cos(angle),
        centerpx[1] - distance * Math.sin(angle)
      ]);
      dest = view.constrainCenter(dest);
      view.setCenter(dest);
    }
    view.setHint(ol.View.Hint.INTERACTING, -1);
    map.render();
    return false;
  } else {
    this.lastCentroid = null;
    return true;
  }
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Start drag sequence?
 * @this {ol.interaction.DragPan}
 * @private
 */
ol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) {
  if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) {
    var map = mapBrowserEvent.map;
    var view = map.getView();
    this.lastCentroid = null;
    if (!this.handlingDownUpSequence) {
      view.setHint(ol.View.Hint.INTERACTING, 1);
    }
    map.render();
    if (this.kineticPreRenderFn_ &&
        map.removePreRenderFunction(this.kineticPreRenderFn_)) {
      view.setCenter(mapBrowserEvent.frameState.viewState.center);
      this.kineticPreRenderFn_ = null;
    }
    if (this.kinetic_) {
      this.kinetic_.begin();
    }
    // No kinetic as soon as more than one pointer on the screen is
    // detected. This is to prevent nasty pans after pinch.
    this.noKinetic_ = this.targetPointers.length > 1;
    return true;
  } else {
    return false;
  }
};

/**
 * @inheritDoc
 */
ol.interaction.DragPan.prototype.shouldStopEvent = ol.functions.FALSE;
<commit_msg>Remove extra map.render() calls from drag pan interaction<commit_after>goog.provide('ol.interaction.DragPan');

goog.require('ol');
goog.require('ol.View');
goog.require('ol.coordinate');
goog.require('ol.events.condition');
goog.require('ol.functions');
goog.require('ol.interaction.Pointer');

/**
 * @classdesc
 * Allows the user to pan the map by dragging the map.
 *
 * @constructor
 * @extends {ol.interaction.Pointer}
 * @param {olx.interaction.DragPanOptions=} opt_options Options.
 * @api stable
 */
ol.interaction.DragPan = function(opt_options) {

  ol.interaction.Pointer.call(this, {
    handleDownEvent: ol.interaction.DragPan.handleDownEvent_,
    handleDragEvent: ol.interaction.DragPan.handleDragEvent_,
    handleUpEvent: ol.interaction.DragPan.handleUpEvent_
  });

  var options = opt_options ? opt_options : {};

  /**
   * @private
   * @type {ol.Kinetic|undefined}
   */
  this.kinetic_ = options.kinetic;

  /**
   * @private
   * @type {?ol.PreRenderFunction}
   */
  this.kineticPreRenderFn_ = null;

  /**
   * @type {ol.Pixel}
   */
  this.lastCentroid = null;

  /**
   * @private
   * @type {ol.EventsConditionType}
   */
  this.condition_ = options.condition ?
      options.condition : ol.events.condition.noModifierKeys;

  /**
   * @private
   * @type {boolean}
   */
  this.noKinetic_ = false;

};
ol.inherits(ol.interaction.DragPan, ol.interaction.Pointer);

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @this {ol.interaction.DragPan}
 * @private
 */
ol.interaction.DragPan.handleDragEvent_ = function(mapBrowserEvent) {
  goog.DEBUG && console.assert(this.targetPointers.length >= 1,
      'the length of this.targetPointers should be more than 1');
  var centroid =
      ol.interaction.Pointer.centroid(this.targetPointers);
  if (this.kinetic_) {
    this.kinetic_.update(centroid[0], centroid[1]);
  }
  if (this.lastCentroid) {
    var deltaX = this.lastCentroid[0] - centroid[0];
    var deltaY = centroid[1] - this.lastCentroid[1];
    var map = mapBrowserEvent.map;
    var view = map.getView();
    var viewState = view.getState();
    var center = [deltaX, deltaY];
    ol.coordinate.scale(center, viewState.resolution);
    ol.coordinate.rotate(center, viewState.rotation);
    ol.coordinate.add(center, viewState.center);
    center = view.constrainCenter(center);
    view.setCenter(center);
  }
  this.lastCentroid = centroid;
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Stop drag sequence?
 * @this {ol.interaction.DragPan}
 * @private
 */
ol.interaction.DragPan.handleUpEvent_ = function(mapBrowserEvent) {
  var map = mapBrowserEvent.map;
  var view = map.getView();
  if (this.targetPointers.length === 0) {
    if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) {
      var distance = this.kinetic_.getDistance();
      var angle = this.kinetic_.getAngle();
      var center = /** @type {!ol.Coordinate} */ (view.getCenter());
      this.kineticPreRenderFn_ = this.kinetic_.pan(center);
      map.beforeRender(this.kineticPreRenderFn_);
      var centerpx = map.getPixelFromCoordinate(center);
      var dest = map.getCoordinateFromPixel([
        centerpx[0] - distance * Math.cos(angle),
        centerpx[1] - distance * Math.sin(angle)
      ]);
      dest = view.constrainCenter(dest);
      view.setCenter(dest);
    }
    view.setHint(ol.View.Hint.INTERACTING, -1);
    return false;
  } else {
    this.lastCentroid = null;
    return true;
  }
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Start drag sequence?
 * @this {ol.interaction.DragPan}
 * @private
 */
ol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) {
  if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) {
    var map = mapBrowserEvent.map;
    var view = map.getView();
    this.lastCentroid = null;
    if (!this.handlingDownUpSequence) {
      view.setHint(ol.View.Hint.INTERACTING, 1);
    }
    if (this.kineticPreRenderFn_ &&
        map.removePreRenderFunction(this.kineticPreRenderFn_)) {
      view.setCenter(mapBrowserEvent.frameState.viewState.center);
      this.kineticPreRenderFn_ = null;
    }
    if (this.kinetic_) {
      this.kinetic_.begin();
    }
    // No kinetic as soon as more than one pointer on the screen is
    // detected. This is to prevent nasty pans after pinch.
    this.noKinetic_ = this.targetPointers.length > 1;
    return true;
  } else {
    return false;
  }
};

/**
 * @inheritDoc
 */
ol.interaction.DragPan.prototype.shouldStopEvent = ol.functions.FALSE;
<|endoftext|>


<commit_before>exports.commands = [
    "play",
    "add",
    "remove",
    "clear",
    "queue",
    "summon",
    "disconnect"
];
const request = require('request');
const fs = require('fs');
const youtubedl = require('youtube-dl');
const m3u8 = require('mu38');
const stream = require('stream');

var voice_channel = {};
var ffmpegs = {};
var songQ = {};
var summoners = {};
var votes = {};

exports.summon = {
    desc: 'summon the bot to a voice channel',
    longDesc: 'summon the bot to specific voice channel. you need to be in the target channel to summon the bot there.',
    main: function(bot, ctx) {
        voice_channel(voice_channel_id, function() {
            summoners[serverID] = userID;
            voice_channel[serverID] = voice_channel_id;
            ctx.msg.channel.sendMessage("Ready to Play, Imouto!");
        });
    }

}<commit_msg>added ffmpeg reqs<commit_after>exports.commands = [
    "play",
    "add",
    "remove",
    "clear",
    "queue",
    "summon",
    "disconnect"
];
var spawn = require('child_process').spawn;
const request = require('request');
const fs = require('fs');
const path = require('path');
const youtubedl = require('youtube-dl');
const m3u8 = require('mu38');
const stream = require('stream');

var voice_channel = {};
var ffmpegs = {};
var songQ = {};
var summoners = {};
var votes = {};

exports.summon = {
    desc: 'summon the bot to a voice channel',
    longDesc: 'summon the bot to specific voice channel. you need to be in the target channel to summon the bot there.',
    main: function (bot, ctx) {
        voice_channel_id = bot.servers[serverID].members[userID].voice_channel_id;
        bot.joinVoiceChannel(voice_channel_id, function () {
            summoners[serverID] = userID;
            voice_channel[serverID] = voice_channel_id;
            ctx.msg.channel.sendMessage("Ready to Play, Imouto!");
        });
    }

}<|endoftext|>


<commit_before>goog.provide('ol.interaction.Pointer');

goog.require('ol');
goog.require('ol.functions');
goog.require('ol.MapBrowserEventType');
goog.require('ol.MapBrowserPointerEvent');
goog.require('ol.interaction.Interaction');
goog.require('ol.obj');

/**
 * @classdesc
 * Base class that calls user-defined functions on `down`, `move` and `up`
 * events. This class also manages "drag sequences".
 *
 * When the `handleDownEvent` user function returns `true` a drag sequence is
 * started. During a drag sequence the `handleDragEvent` user function is
 * called on `move` events. The drag sequence ends when the `handleUpEvent`
 * user function is called and returns `false`.
 *
 * @constructor
 * @param {olx.interaction.PointerOptions=} opt_options Options.
 * @extends {ol.interaction.Interaction}
 * @api
 */
ol.interaction.Pointer = function(opt_options) {

  var options = opt_options ? opt_options : {};

  var handleEvent = options.handleEvent ?
      options.handleEvent : ol.interaction.Pointer.handleEvent;

  ol.interaction.Interaction.call(this, {
    handleEvent: handleEvent
  });

  /**
   * @type {function(ol.MapBrowserPointerEvent):boolean}
   * @private
   */
  this.handleDownEvent_ = options.handleDownEvent ?
      options.handleDownEvent : ol.interaction.Pointer.handleDownEvent;

  /**
   * @type {function(ol.MapBrowserPointerEvent)}
   * @private
   */
  this.handleDragEvent_ = options.handleDragEvent ?
      options.handleDragEvent : ol.interaction.Pointer.handleDragEvent;

  /**
   * @type {function(ol.MapBrowserPointerEvent)}
   * @private
   */
  this.handleMoveEvent_ = options.handleMoveEvent ?
      options.handleMoveEvent : ol.interaction.Pointer.handleMoveEvent;

  /**
   * @type {function(ol.MapBrowserPointerEvent):boolean}
   * @private
   */
  this.handleUpEvent_ = options.handleUpEvent ?
      options.handleUpEvent : ol.interaction.Pointer.handleUpEvent;

  /**
   * @type {boolean}
   * @protected
   */
  this.handlingDownUpSequence = false;

  /**
   * @type {Object.<number, ol.pointer.PointerEvent>}
   * @private
   */
  this.trackedPointers_ = {};

  /**
   * @type {Array.<ol.pointer.PointerEvent>}
   * @protected
   */
  this.targetPointers = [];

};
ol.inherits(ol.interaction.Pointer, ol.interaction.Interaction);

/**
 * @param {Array.<ol.pointer.PointerEvent>} pointerEvents List of events.
 * @return {ol.Pixel} Centroid pixel.
 */
ol.interaction.Pointer.centroid = function(pointerEvents) {
  var length = pointerEvents.length;
  var clientX = 0;
  var clientY = 0;
  for (var i = 0; i < length; i++) {
    clientX += pointerEvents[i].clientX;
    clientY += pointerEvents[i].clientY;
  }
  return [clientX / length, clientY / length];
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Whether the event is a pointerdown, pointerdrag
 *     or pointerup event.
 * @private
 */
ol.interaction.Pointer.prototype.isPointerDraggingEvent_ = function(mapBrowserEvent) {
  var type = mapBrowserEvent.type;
  return (
      type === ol.MapBrowserEventType.POINTERDOWN ||
      type === ol.MapBrowserEventType.POINTERDRAG ||
      type === ol.MapBrowserEventType.POINTERUP);
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @private
 */
ol.interaction.Pointer.prototype.updateTrackedPointers_ = function(mapBrowserEvent) {
  if (this.isPointerDraggingEvent_(mapBrowserEvent)) {
    var event = mapBrowserEvent.pointerEvent;

    if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERUP) {
      delete this.trackedPointers_[event.pointerId];
    } else if (mapBrowserEvent.type ==
        ol.MapBrowserEventType.POINTERDOWN) {
      this.trackedPointers_[event.pointerId] = event;
    } else if (event.pointerId in this.trackedPointers_) {
      // update only when there was a pointerdown event for this pointer
      this.trackedPointers_[event.pointerId] = event;
    }
    this.targetPointers = ol.obj.getValues(this.trackedPointers_);
  }
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @this {ol.interaction.Pointer}
 */
ol.interaction.Pointer.handleDragEvent = ol.nullFunction;

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Capture dragging.
 * @this {ol.interaction.Pointer}
 */
ol.interaction.Pointer.handleUpEvent = ol.functions.FALSE;

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Capture dragging.
 * @this {ol.interaction.Pointer}
 */
ol.interaction.Pointer.handleDownEvent = ol.functions.FALSE;

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @this {ol.interaction.Pointer}
 */
ol.interaction.Pointer.handleMoveEvent = ol.nullFunction;

/**
 * Handles the {@link ol.MapBrowserEvent map browser event} and may call into
 * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are
 * detected.
 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
 * @return {boolean} `false` to stop event propagation.
 * @this {ol.interaction.Pointer}
 * @api
 */
ol.interaction.Pointer.handleEvent = function(mapBrowserEvent) {
  if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {
    return true;
  }

  var stopEvent = false;
  this.updateTrackedPointers_(mapBrowserEvent);
  if (this.handlingDownUpSequence) {
    if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERDRAG) {
      this.handleDragEvent_(mapBrowserEvent);
    } else if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERUP) {
      this.handlingDownUpSequence = this.handleUpEvent_(mapBrowserEvent);
    }
  }
  if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERDOWN) {
    var handled = this.handleDownEvent_(mapBrowserEvent);
    this.handlingDownUpSequence = handled;
    stopEvent = this.shouldStopEvent(handled);
  } else if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERMOVE) {
    this.handleMoveEvent_(mapBrowserEvent);
  }
  return !stopEvent;
};

/**
 * This method is used to determine if "down" events should be propagated to
 * other interactions or should be stopped.
 *
 * The method receives the return code of the "handleDownEvent" function.
 *
 * By default this function is the "identity" function. It's overidden in
 * child classes.
 *
 * @param {boolean} handled Was the event handled by the interaction?
 * @return {boolean} Should the event be stopped?
 * @protected
 */
ol.interaction.Pointer.prototype.shouldStopEvent = function(handled) {
  return handled;
};
<commit_msg>Consider pointerdown only if the last pointerup has been emitted<commit_after>goog.provide('ol.interaction.Pointer');

goog.require('ol');
goog.require('ol.functions');
goog.require('ol.MapBrowserEventType');
goog.require('ol.MapBrowserPointerEvent');
goog.require('ol.interaction.Interaction');
goog.require('ol.obj');

/**
 * @classdesc
 * Base class that calls user-defined functions on `down`, `move` and `up`
 * events. This class also manages "drag sequences".
 *
 * When the `handleDownEvent` user function returns `true` a drag sequence is
 * started. During a drag sequence the `handleDragEvent` user function is
 * called on `move` events. The drag sequence ends when the `handleUpEvent`
 * user function is called and returns `false`.
 *
 * @constructor
 * @param {olx.interaction.PointerOptions=} opt_options Options.
 * @extends {ol.interaction.Interaction}
 * @api
 */
ol.interaction.Pointer = function(opt_options) {

  var options = opt_options ? opt_options : {};

  var handleEvent = options.handleEvent ?
      options.handleEvent : ol.interaction.Pointer.handleEvent;

  ol.interaction.Interaction.call(this, {
    handleEvent: handleEvent
  });

  /**
   * @type {function(ol.MapBrowserPointerEvent):boolean}
   * @private
   */
  this.handleDownEvent_ = options.handleDownEvent ?
      options.handleDownEvent : ol.interaction.Pointer.handleDownEvent;

  /**
   * @type {function(ol.MapBrowserPointerEvent)}
   * @private
   */
  this.handleDragEvent_ = options.handleDragEvent ?
      options.handleDragEvent : ol.interaction.Pointer.handleDragEvent;

  /**
   * @type {function(ol.MapBrowserPointerEvent)}
   * @private
   */
  this.handleMoveEvent_ = options.handleMoveEvent ?
      options.handleMoveEvent : ol.interaction.Pointer.handleMoveEvent;

  /**
   * @type {function(ol.MapBrowserPointerEvent):boolean}
   * @private
   */
  this.handleUpEvent_ = options.handleUpEvent ?
      options.handleUpEvent : ol.interaction.Pointer.handleUpEvent;

  /**
   * @type {boolean}
   * @protected
   */
  this.handlingDownUpSequence = false;

  /**
   * @type {Object.<number, ol.pointer.PointerEvent>}
   * @private
   */
  this.trackedPointers_ = {};

  /**
   * @type {Array.<ol.pointer.PointerEvent>}
   * @protected
   */
  this.targetPointers = [];

};
ol.inherits(ol.interaction.Pointer, ol.interaction.Interaction);

/**
 * @param {Array.<ol.pointer.PointerEvent>} pointerEvents List of events.
 * @return {ol.Pixel} Centroid pixel.
 */
ol.interaction.Pointer.centroid = function(pointerEvents) {
  var length = pointerEvents.length;
  var clientX = 0;
  var clientY = 0;
  for (var i = 0; i < length; i++) {
    clientX += pointerEvents[i].clientX;
    clientY += pointerEvents[i].clientY;
  }
  return [clientX / length, clientY / length];
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Whether the event is a pointerdown, pointerdrag
 *     or pointerup event.
 * @private
 */
ol.interaction.Pointer.prototype.isPointerDraggingEvent_ = function(mapBrowserEvent) {
  var type = mapBrowserEvent.type;
  return (
      type === ol.MapBrowserEventType.POINTERDOWN ||
      type === ol.MapBrowserEventType.POINTERDRAG ||
      type === ol.MapBrowserEventType.POINTERUP);
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @private
 */
ol.interaction.Pointer.prototype.updateTrackedPointers_ = function(mapBrowserEvent) {
  if (this.isPointerDraggingEvent_(mapBrowserEvent)) {
    var event = mapBrowserEvent.pointerEvent;

    if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERUP) {
      delete this.trackedPointers_[event.pointerId];
    } else if (mapBrowserEvent.type ==
        ol.MapBrowserEventType.POINTERDOWN) {
      this.trackedPointers_[event.pointerId] = event;
    } else if (event.pointerId in this.trackedPointers_) {
      // update only when there was a pointerdown event for this pointer
      this.trackedPointers_[event.pointerId] = event;
    }
    this.targetPointers = ol.obj.getValues(this.trackedPointers_);
  }
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @this {ol.interaction.Pointer}
 */
ol.interaction.Pointer.handleDragEvent = ol.nullFunction;

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Capture dragging.
 * @this {ol.interaction.Pointer}
 */
ol.interaction.Pointer.handleUpEvent = ol.functions.FALSE;

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Capture dragging.
 * @this {ol.interaction.Pointer}
 */
ol.interaction.Pointer.handleDownEvent = ol.functions.FALSE;

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @this {ol.interaction.Pointer}
 */
ol.interaction.Pointer.handleMoveEvent = ol.nullFunction;

/**
 * Handles the {@link ol.MapBrowserEvent map browser event} and may call into
 * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are
 * detected.
 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
 * @return {boolean} `false` to stop event propagation.
 * @this {ol.interaction.Pointer}
 * @api
 */
ol.interaction.Pointer.handleEvent = function(mapBrowserEvent) {
  if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {
    return true;
  }

  var stopEvent = false;
  this.updateTrackedPointers_(mapBrowserEvent);
  if (this.handlingDownUpSequence) {
    if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERDRAG) {
      this.handleDragEvent_(mapBrowserEvent);
    } else if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERUP) {
      this.handleUpEvent_(mapBrowserEvent);
      this.handlingDownUpSequence = false;
    }
  } else {
    if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERDOWN) {
      var handled = this.handleDownEvent_(mapBrowserEvent);
      this.handlingDownUpSequence = handled;
      stopEvent = this.shouldStopEvent(handled);
    } else if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERMOVE) {
      this.handleMoveEvent_(mapBrowserEvent);
    }
  }
  return !stopEvent;
};

/**
 * This method is used to determine if "down" events should be propagated to
 * other interactions or should be stopped.
 *
 * The method receives the return code of the "handleDownEvent" function.
 *
 * By default this function is the "identity" function. It's overidden in
 * child classes.
 *
 * @param {boolean} handled Was the event handled by the interaction?
 * @return {boolean} Should the event be stopped?
 * @protected
 */
ol.interaction.Pointer.prototype.shouldStopEvent = function(handled) {
  return handled;
};
<|endoftext|>


<commit_before>"use strict";

exports.map = function* map(iterable, func) {
  for (let element of iterable)
    yield func(element);
}
<commit_msg>More iterable functions! (Enumerable inspired)<commit_after>"use strict";

exports.map = function* map(iterable, func) {
  for (let element of iterable)
    yield func(element);
};

exports.filter = function* filter(iterable, func) {
  for (let element of iterable)
    if (func(element))
      yield filter;
};

export.all = function* all(iterable, func) {
  for (let element of iterable)
    if (!func(element)) return false;
  return true;
};

export.any = function* any(iterable, func = null) {
  for (let element of iterable)
    if ((func == null) || func(element)) return true;
  return false;
};

export.take = function* take(iterable, count) {
  if (count > 0)
    for (let element of iterable) {
      yield element;
      if (--count <= 0) break;
    }
};

export.skip = function* skip(iterable, count) {
  for (let element of iterable)
    if (--count < 0)
      yield element;
};

exports.repeat = function* repeat(value, times) {
  for (let i = 0; i < times; times++)
    yield value;
};

exports.range = function* range(start, count, by = 1) {
  for (let i = 0; i < count; count++)
    yield (start + i * by);
};
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import { Helmet } from 'react-helmet';
import { FormattedMessage, FormattedHTMLMessage, injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import Snackbar from 'material-ui/Snackbar';
// polyfill for Safari :-(
import intl from 'intl'; // eslint-disable-line
import intlEn from 'intl/locale-data/jsonp/en.js'; // eslint-disable-line
import { Row } from 'react-flexbox-grid/lib';
import NavToolbar from './common/header/NavToolbar';
import messages from '../resources/messages';
import { getVersion } from '../config';
import { updateFeedback } from '../actions/appActions';
import { ErrorNotice } from './common/Notice';
import { assetUrl } from '../lib/assetUtil';
import AppNoticesContainer from './common/header/AppNoticesContainer';

const localMessages = {
  supportOptions: { id: 'app.supportOptions', defaultMessage: 'Need help? Join our discussion group
or email support@mediacloud.org.' },
  maintenance: { id: 'app.maintenance', defaultMessage: 'Sorry, we have taken our system down right now for maintenance' },
};

const AppContainer = (props) => {
  const { children, feedback, handleSnackBarRequestClose, name } = props;
  const { formatMessage } = props.intl;

  let content = children;
  if (document.appConfig.online === false) {
    content = (

        <Row center="lg">
          <ErrorNotice>

            <FormattedMessage {...localMessages.maintenance} />

          </ErrorNotice>
        </Row>

    );
  }

  return (
    <div className={`app-contiainer app-${name}`}>
      <Helmet><title>{formatMessage(messages.suiteName)}</title></Helmet>
      <AppNoticesContainer />

        <NavToolbar />

        {content}

            {'Created by the '}

              <FormattedMessage {...messages.c4cmName} />

            {' and the '}

              <FormattedMessage {...messages.berkmanName} />
            .

            <FormattedHTMLMessage {...localMessages.supportOptions} />

            v{getVersion()}

      <Snackbar
        open={feedback.open}
        message={feedback.message}
        action={feedback.action}
        onActionClick={feedback.onActionClick}
        autoHideDuration={8000}
        onRequestClose={handleSnackBarRequestClose}
      />

  );
};

AppContainer.propTypes = {
  children: PropTypes.node,
  handleTouchTapLeftIconButton: PropTypes.func,
  intl: PropTypes.object.isRequired,
  // from state
  feedback: PropTypes.object.isRequired,
  // from dispatch
  handleSnackBarRequestClose: PropTypes.func.isRequired,
  // from parent
  name: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  description: PropTypes.string.isRequired,
  showLoginButton: PropTypes.bool,
};

AppContainer.contextTypes = {
  router: PropTypes.object.isRequired,
  store: PropTypes.object.isRequired,
};

const mapStateToProps = state => ({
  feedback: state.app.feedback,
});

const mapDispatchToProps = dispatch => ({
  handleSnackBarRequestClose: () => {
    dispatch(updateFeedback({ open: false, message: '' }));
  },
});

export default
injectIntl(
  connect(mapStateToProps, mapDispatchToProps)(
    AppContainer
  )
);
<commit_msg>Fix typo in css class anme<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import { Helmet } from 'react-helmet';
import { FormattedMessage, FormattedHTMLMessage, injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import Snackbar from 'material-ui/Snackbar';
// polyfill for Safari :-(
import intl from 'intl'; // eslint-disable-line
import intlEn from 'intl/locale-data/jsonp/en.js'; // eslint-disable-line
import { Row } from 'react-flexbox-grid/lib';
import NavToolbar from './common/header/NavToolbar';
import messages from '../resources/messages';
import { getVersion } from '../config';
import { updateFeedback } from '../actions/appActions';
import { ErrorNotice } from './common/Notice';
import { assetUrl } from '../lib/assetUtil';
import AppNoticesContainer from './common/header/AppNoticesContainer';

const localMessages = {
  supportOptions: { id: 'app.supportOptions', defaultMessage: 'Need help? Join our discussion group
or email support@mediacloud.org.' },
  maintenance: { id: 'app.maintenance', defaultMessage: 'Sorry, we have taken our system down right now for maintenance' },
};

const AppContainer = (props) => {
  const { children, feedback, handleSnackBarRequestClose, name } = props;
  const { formatMessage } = props.intl;

  let content = children;
  if (document.appConfig.online === false) {
    content = (

        <Row center="lg">
          <ErrorNotice>

            <FormattedMessage {...localMessages.maintenance} />

          </ErrorNotice>
        </Row>

    );
  }

  return (
    <div className={`app-container app-${name}`}>
      <Helmet><title>{formatMessage(messages.suiteName)}</title></Helmet>
      <AppNoticesContainer />

        <NavToolbar />

        {content}

            {'Created by the '}

              <FormattedMessage {...messages.c4cmName} />

            {' and the '}

              <FormattedMessage {...messages.berkmanName} />
            .

            <FormattedHTMLMessage {...localMessages.supportOptions} />

            v{getVersion()}

      <Snackbar
        open={feedback.open}
        message={feedback.message}
        action={feedback.action}
        onActionClick={feedback.onActionClick}
        autoHideDuration={8000}
        onRequestClose={handleSnackBarRequestClose}
      />

  );
};

AppContainer.propTypes = {
  children: PropTypes.node,
  handleTouchTapLeftIconButton: PropTypes.func,
  intl: PropTypes.object.isRequired,
  // from state
  feedback: PropTypes.object.isRequired,
  // from dispatch
  handleSnackBarRequestClose: PropTypes.func.isRequired,
  // from parent
  name: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  description: PropTypes.string.isRequired,
  showLoginButton: PropTypes.bool,
};

AppContainer.contextTypes = {
  router: PropTypes.object.isRequired,
  store: PropTypes.object.isRequired,
};

const mapStateToProps = state => ({
  feedback: state.app.feedback,
});

const mapDispatchToProps = dispatch => ({
  handleSnackBarRequestClose: () => {
    dispatch(updateFeedback({ open: false, message: '' }));
  },
});

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