<commit_before>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.
*/

/**
 * @file Get initial data and define sankey view's series model
 * @author Deqing Li(annong035@gmail.com)
 */

import SeriesModel from '../../model/Series';
import createGraphFromNodeEdge from '../helper/createGraphFromNodeEdge';
import {encodeHTML} from '../../util/format';

var SankeySeries = SeriesModel.extend({

    type: 'series.sankey',

    layoutInfo: null,

    /**
     * Init a graph data structure from data in option series
     *
     * @param  {Object} option  the object used to config echarts view
     * @return {module:echarts/data/List} storage initial data
     */
    getInitialData: function (option) {
        var links = option.edges || option.links;
        var nodes = option.data || option.nodes;
        if (nodes && links) {
            var graph = createGraphFromNodeEdge(nodes, links, this, true);
            return graph.data;
        }
    },

    setNodePosition: function (dataIndex, localPosition) {
        var dataItem = this.option.data[dataIndex];
        dataItem.localX = localPosition[0];
        dataItem.localY = localPosition[1];
    },

    /**
     * Return the graphic data structure
     *
     * @return {module:echarts/data/Graph} graphic data structure
     */
    getGraph: function () {
        return this.getData().graph;
    },

    /**
     * Get edge data of graphic data structure
     *
     * @return {module:echarts/data/List} data structure of list
     */
    getEdgeData: function () {
        return this.getGraph().edgeData;
    },

    /**
     * @override
     */
    formatTooltip: function (dataIndex, multipleSeries, dataType) {
        // dataType === 'node' or empty do not show tooltip by default
        if (dataType === 'edge') {
            var params = this.getDataParams(dataIndex, dataType);
            var rawDataOpt = params.data;
            var html = rawDataOpt.source + ' -- ' + rawDataOpt.target;
            if (params.value) {
                html += ' : ' + params.value;
            }
            return encodeHTML(html);
        }

        return SankeySeries.superCall(this, 'formatTooltip', dataIndex, multipleSeries);
    },

    optionUpdated: function () {
        var option = this.option;
        if (option.focusNodeAdjacency === true) {
            option.focusNodeAdjacency = 'allEdges';
        }
    },

    defaultOption: {
        zlevel: 0,
        z: 2,

        coordinateSystem: 'view',

        layout: null,

        // The position of the whole view
        left: '5%',
        top: '5%',
        right: '20%',
        bottom: '5%',

        // Value can be 'vertical'
        orient: 'horizontal',

        // The dx of the node
        nodeWidth: 20,

        // The vertical distance between two nodes
        nodeGap: 8,

        // Control if the node can move or not
        draggable: true,

        // Value can be 'inEdges', 'outEdges', 'allEdges', true (the same as 'allEdges').
        focusNodeAdjacency: false,

        // The number of iterations to change the position of the node
        layoutIterations: 32,

        label: {
            show: true,
            position: 'right',
            color: '#000',
            fontSize: 12
        },

        itemStyle: {
            borderWidth: 1,
            borderColor: '#333'
        },

        lineStyle: {
            color: '#314656',
            opacity: 0.2,
            curveness: 0.5
        },

        emphasis: {
            label: {
                show: true
            },
            lineStyle: {
                opacity: 0.6
            }
        },

        animationEasing: 'linear',

        animationDuration: 1000
    }

});

export default SankeySeries;<commit_msg>feat(sankey): format sankey node tooltip<commit_after>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.
*/

/**
 * @file Get initial data and define sankey view's series model
 * @author Deqing Li(annong035@gmail.com)
 */

import SeriesModel from '../../model/Series';
import createGraphFromNodeEdge from '../helper/createGraphFromNodeEdge';
import {encodeHTML} from '../../util/format';

var SankeySeries = SeriesModel.extend({

    type: 'series.sankey',

    layoutInfo: null,

    /**
     * Init a graph data structure from data in option series
     *
     * @param  {Object} option  the object used to config echarts view
     * @return {module:echarts/data/List} storage initial data
     */
    getInitialData: function (option) {
        var links = option.edges || option.links;
        var nodes = option.data || option.nodes;
        if (nodes && links) {
            var graph = createGraphFromNodeEdge(nodes, links, this, true);
            return graph.data;
        }
    },

    setNodePosition: function (dataIndex, localPosition) {
        var dataItem = this.option.data[dataIndex];
        dataItem.localX = localPosition[0];
        dataItem.localY = localPosition[1];
    },

    /**
     * Return the graphic data structure
     *
     * @return {module:echarts/data/Graph} graphic data structure
     */
    getGraph: function () {
        return this.getData().graph;
    },

    /**
     * Get edge data of graphic data structure
     *
     * @return {module:echarts/data/List} data structure of list
     */
    getEdgeData: function () {
        return this.getGraph().edgeData;
    },

    /**
     * @override
     */
    formatTooltip: function (dataIndex, multipleSeries, dataType) {
        // dataType === 'node' or empty do not show tooltip by default
        if (dataType === 'edge') {
            var params = this.getDataParams(dataIndex, dataType);
            var rawDataOpt = params.data;
            var html = rawDataOpt.source + ' -- ' + rawDataOpt.target;
            if (params.value) {
                html += ' : ' + params.value;
            }
            return encodeHTML(html);
        }
        else if (dataType === 'node') {
            var node = this.getGraph().getNodeByIndex(dataIndex);
            var value = node.getLayout().value;
            var name = this.getDataParams(dataIndex, dataType).data.name;
            if (value) {
                var html = name + ' : ' + value;
            }
            return encodeHTML(html);
        }
        return SankeySeries.superCall(this, 'formatTooltip', dataIndex, multipleSeries);
    },

    optionUpdated: function () {
        var option = this.option;
        if (option.focusNodeAdjacency === true) {
            option.focusNodeAdjacency = 'allEdges';
        }
    },

    defaultOption: {
        zlevel: 0,
        z: 2,

        coordinateSystem: 'view',

        layout: null,

        // The position of the whole view
        left: '5%',
        top: '5%',
        right: '20%',
        bottom: '5%',

        // Value can be 'vertical'
        orient: 'horizontal',

        // The dx of the node
        nodeWidth: 20,

        // The vertical distance between two nodes
        nodeGap: 8,

        // Control if the node can move or not
        draggable: true,

        // Value can be 'inEdges', 'outEdges', 'allEdges', true (the same as 'allEdges').
        focusNodeAdjacency: false,

        // The number of iterations to change the position of the node
        layoutIterations: 32,

        label: {
            show: true,
            position: 'right',
            color: '#000',
            fontSize: 12
        },

        itemStyle: {
            borderWidth: 1,
            borderColor: '#333'
        },

        lineStyle: {
            color: '#314656',
            opacity: 0.2,
            curveness: 0.5
        },

        emphasis: {
            label: {
                show: true
            },
            lineStyle: {
                opacity: 0.6
            }
        },

        animationEasing: 'linear',

        animationDuration: 1000
    }

});

export default SankeySeries;<|endoftext|>


<commit_before>/** @babel */

/**
 * Copyright (c) 2016-present, PlatformIO Plus <contact@pioplus.com>
 * All rights reserved.
 *
 * This source code is licensed under the license found in the LICENSE file in
 * the root directory of this source tree.
 */

import fs from 'fs-plus';
import path from 'path';

export const ATOM_CONFIG = {
  showPIOHome: {
    title: 'Show PlatformIO Home on startup',
    type: 'boolean',
    default: true,
    order: 0
  },
  highlightActiveProject: {
    title: 'Highlight active project',
    type: 'boolean',
    default: true,
    order: 10
  },
  autoUpdateIDE: {
    title: 'Automatically Update PlatformIO IDE',
    type: 'boolean',
    default: true,
    order: 15
  },
  autoCloseSerialMonitor: {
    title: 'Automatically close Serial Port Monitor before uploading',
    description: '',
    type: 'boolean',
    default: true,
    order: 20
  },
  autoRebuildAutocompleteIndex: {
    title: 'Automatically rebuild C/C++ Project Index',
    description: 'Rebuild C/C++ Project Index (Intelligent Code Completion, ' +
      'Smart Code Linter) when new libraries are added or [platformio.ini](http://docs.platformio.org/page/projectconf.html) is modified',
    type: 'boolean',
    default: true,
    order: 30
  },
  useBuiltinPIOCore: {
    title: 'Use built-in PlatformIO Core',
    description: 'PlatformIO IDE has built-in [PlatformIO Core](http://docs.platformio.org/en/latest/core.html) ' +
      'and depends on it. Uncheck this option (NOT RECOMMENDED) to use own version of ' +
      'installed PlatformIO Core (it should be located in the system `PATH`)',
    type: 'boolean',
    default: true,
    order: 40
  },
  advanced: {
    type: 'object',
    title: 'Advanced',
    order: 50,
    properties: {
      showPlatformIOFiles: {
        title: 'Show PlatformIO service files',
        description: 'Do not hide in `Tree View` PlatformIO service files and ' +
          'directories (`.pioenvs`, `.piolibdeps`, other configuration files)',
        type: 'boolean',
        default: false,
        order: 0
      },
      useDevelopmentIDE: {
        title: 'Use development version of PlatformIO IDE',
        description: '[Git](https://git-scm.com/downloads) should be installed in a system.',
        type: 'boolean',
        default: false,
        order: 5
      },
      useDevelopmentPIOCore: {
        title: 'Use development version of PlatformIO Core',
        description: 'This option is valid when "Use built-in PlatformIO Core" is enabled. ' +
        'To upgrade to the latest development version, please use ' +
        '`Menu: PlatformIO > Upgrade PlatformIO Core`.',
        type: 'boolean',
        default: false,
        order: 10
      },
      customLibraryStorages: {
        title: 'Custom Library Storages',
        description: 'Specify folder path to custom library storage. ' +
          'You will be able to list installed libraries, check updates or install ' +
          'new libraries. Multiple paths are allowed, separate them with `, ` (comma + space)',
        type: 'string',
        default: '',
        order: 20
      },
      customPATH: {
        title: 'Custom PATH for `platformio` command',
        description: 'Paste here the result of `echo $PATH` (Unix) / `echo %PATH%` ' +
          '(Windows) command by typing into your system terminal ' +
          'if you prefer to use custom version of PlatformIO Core',
        type: 'string',
        default: '',
        order: 30
      }
    }
  }
};

export const IS_WINDOWS = process.platform.startsWith('win');
export const PKG_BASE_DIR = path.resolve(path.dirname(__filename), '..');
export const CACHE_DIR = path.join(PKG_BASE_DIR, '.cache');
export const PIO_HOME_DIR = process.env.PLATFOMRIO_HOME_DIR ? process.env.PLATFORMIO_HOME_DIR : path.join(fs.getHomeDirectory(), '.platformio');
export const ENV_DIR = _get_env_dir(path.join(PIO_HOME_DIR, 'penv'));
export const ENV_BIN_DIR = path.join(ENV_DIR, IS_WINDOWS ? 'Scripts' : 'bin');

export const ATOM_DEPENDENCIES = {
  'build': {
    requirements: '>=0.56.0',
    required: true
  },
  'busy': {
    requirements: '>=0.1.0',
    required: true
  },
  'platformio-ide-terminal': {
    requirements: '>=2.5.0'
  },
  'platformio-ide-debugger': {
    requirements: '>=1.0.0'
  },
  'autocomplete-clang': {
    requirements: '>=0.8.9'
  },
  'linter-ui-default': {
    requirements: '>=1.1.0'
  },
  'intentions': {
    requirements: '>=1.1.2'
  },
  'linter': {
    // forceVersion: '1.11.23',
    requirements: '>=1.11.3'
  },
  'linter-gcc': {
    requirements: '>=0.6.5'
  },
  'language-ini': {
    requirements: '>=1.14.0'
  },
  'tool-bar': {
    requirements: '>=0.2.0'
  },
  'file-icons': {
    requirements: '>=1.7'
  },
  'minimap': {
    requirements: '>=4'
  }
};
export const ATOM_CONFLICTED_DEPENDENCIES = {
  'build-platformio': {
    requirements: '*'
  },
  'busy-signal': {
    requirements: '*'
  },
  'dbg': {
    requirements: '*'
  },
  'dbg-gdb': {
    requirements: '*'
  },
  'output-panel': {
    requirements: '*'
  },
};

export const PIO_CORE_MIN_VERSION = '3.4.0-a.4';
export const DEFAULT_PIO_ARGS = ['-f', '-c', 'atom'];
export const TERMINAL_REOPEN_DELAY = 1000; // ms, dalay before serial monitor restore
export const AUTO_REBUILD_DELAY = 3000; // ms
export const INPUT_FILTER_DELAY = 200; // ms, dalay before filtering projects, libs, platorms

export const PLATFORMIO_API_ENDPOINT = 'http://api.platformio.org';

function _get_env_dir(defaultEnvDir) {
  if (IS_WINDOWS) {
    // Put the env directory to the root of the current local disk when
    // default path contains non-ASCII characters. Virtualenv will fail to
    for (const char of defaultEnvDir) {
      if (char.charCodeAt(0) > 127) {
        const defaultEnvDirFormat = path.parse(defaultEnvDir);
        return path.format({
          root: defaultEnvDirFormat.root,
          dir: defaultEnvDirFormat.root,
          base: '.pioidepenv',
          name: '.pioidepenv',
        });
      }
    }
  }
  return defaultEnvDir;
}
<commit_msg>Fix typo for PLATFORMIO_HOME_DIR // Resolve #329 Resolve #398<commit_after>/** @babel */

/**
 * Copyright (c) 2016-present, PlatformIO Plus <contact@pioplus.com>
 * All rights reserved.
 *
 * This source code is licensed under the license found in the LICENSE file in
 * the root directory of this source tree.
 */

import fs from 'fs-plus';
import path from 'path';

export const ATOM_CONFIG = {
  showPIOHome: {
    title: 'Show PlatformIO Home on startup',
    type: 'boolean',
    default: true,
    order: 0
  },
  highlightActiveProject: {
    title: 'Highlight active project',
    type: 'boolean',
    default: true,
    order: 10
  },
  autoUpdateIDE: {
    title: 'Automatically Update PlatformIO IDE',
    type: 'boolean',
    default: true,
    order: 15
  },
  autoCloseSerialMonitor: {
    title: 'Automatically close Serial Port Monitor before uploading',
    description: '',
    type: 'boolean',
    default: true,
    order: 20
  },
  autoRebuildAutocompleteIndex: {
    title: 'Automatically rebuild C/C++ Project Index',
    description: 'Rebuild C/C++ Project Index (Intelligent Code Completion, ' +
      'Smart Code Linter) when new libraries are added or [platformio.ini](http://docs.platformio.org/page/projectconf.html) is modified',
    type: 'boolean',
    default: true,
    order: 30
  },
  useBuiltinPIOCore: {
    title: 'Use built-in PlatformIO Core',
    description: 'PlatformIO IDE has built-in [PlatformIO Core](http://docs.platformio.org/en/latest/core.html) ' +
      'and depends on it. Uncheck this option (NOT RECOMMENDED) to use own version of ' +
      'installed PlatformIO Core (it should be located in the system `PATH`)',
    type: 'boolean',
    default: true,
    order: 40
  },
  advanced: {
    type: 'object',
    title: 'Advanced',
    order: 50,
    properties: {
      showPlatformIOFiles: {
        title: 'Show PlatformIO service files',
        description: 'Do not hide in `Tree View` PlatformIO service files and ' +
          'directories (`.pioenvs`, `.piolibdeps`, other configuration files)',
        type: 'boolean',
        default: false,
        order: 0
      },
      useDevelopmentIDE: {
        title: 'Use development version of PlatformIO IDE',
        description: '[Git](https://git-scm.com/downloads) should be installed in a system.',
        type: 'boolean',
        default: false,
        order: 5
      },
      useDevelopmentPIOCore: {
        title: 'Use development version of PlatformIO Core',
        description: 'This option is valid when "Use built-in PlatformIO Core" is enabled. ' +
        'To upgrade to the latest development version, please use ' +
        '`Menu: PlatformIO > Upgrade PlatformIO Core`.',
        type: 'boolean',
        default: false,
        order: 10
      },
      customLibraryStorages: {
        title: 'Custom Library Storages',
        description: 'Specify folder path to custom library storage. ' +
          'You will be able to list installed libraries, check updates or install ' +
          'new libraries. Multiple paths are allowed, separate them with `, ` (comma + space)',
        type: 'string',
        default: '',
        order: 20
      },
      customPATH: {
        title: 'Custom PATH for `platformio` command',
        description: 'Paste here the result of `echo $PATH` (Unix) / `echo %PATH%` ' +
          '(Windows) command by typing into your system terminal ' +
          'if you prefer to use custom version of PlatformIO Core',
        type: 'string',
        default: '',
        order: 30
      }
    }
  }
};

export const IS_WINDOWS = process.platform.startsWith('win');
export const PKG_BASE_DIR = path.resolve(path.dirname(__filename), '..');
export const CACHE_DIR = path.join(PKG_BASE_DIR, '.cache');
export const PIO_HOME_DIR = process.env.PLATFORMIO_HOME_DIR ? process.env.PLATFORMIO_HOME_DIR : path.join(fs.getHomeDirectory(), '.platformio');
export const ENV_DIR = _get_env_dir(path.join(PIO_HOME_DIR, 'penv'));
export const ENV_BIN_DIR = path.join(ENV_DIR, IS_WINDOWS ? 'Scripts' : 'bin');

export const ATOM_DEPENDENCIES = {
  'build': {
    requirements: '>=0.56.0',
    required: true
  },
  'busy': {
    requirements: '>=0.1.0',
    required: true
  },
  'platformio-ide-terminal': {
    requirements: '>=2.5.0'
  },
  'platformio-ide-debugger': {
    requirements: '>=1.0.0'
  },
  'autocomplete-clang': {
    requirements: '>=0.8.9'
  },
  'linter-ui-default': {
    requirements: '>=1.1.0'
  },
  'intentions': {
    requirements: '>=1.1.2'
  },
  'linter': {
    // forceVersion: '1.11.23',
    requirements: '>=1.11.3'
  },
  'linter-gcc': {
    requirements: '>=0.6.5'
  },
  'language-ini': {
    requirements: '>=1.14.0'
  },
  'tool-bar': {
    requirements: '>=0.2.0'
  },
  'file-icons': {
    requirements: '>=1.7'
  },
  'minimap': {
    requirements: '>=4'
  }
};
export const ATOM_CONFLICTED_DEPENDENCIES = {
  'build-platformio': {
    requirements: '*'
  },
  'busy-signal': {
    requirements: '*'
  },
  'dbg': {
    requirements: '*'
  },
  'dbg-gdb': {
    requirements: '*'
  },
  'output-panel': {
    requirements: '*'
  },
};

export const PIO_CORE_MIN_VERSION = '3.4.0-a.4';
export const DEFAULT_PIO_ARGS = ['-f', '-c', 'atom'];
export const TERMINAL_REOPEN_DELAY = 1000; // ms, dalay before serial monitor restore
export const AUTO_REBUILD_DELAY = 3000; // ms
export const INPUT_FILTER_DELAY = 200; // ms, dalay before filtering projects, libs, platorms

export const PLATFORMIO_API_ENDPOINT = 'http://api.platformio.org';

function _get_env_dir(defaultEnvDir) {
  if (IS_WINDOWS) {
    // Put the env directory to the root of the current local disk when
    // default path contains non-ASCII characters. Virtualenv will fail to
    for (const char of defaultEnvDir) {
      if (char.charCodeAt(0) > 127) {
        const defaultEnvDirFormat = path.parse(defaultEnvDir);
        return path.format({
          root: defaultEnvDirFormat.root,
          dir: defaultEnvDirFormat.root,
          base: '.pioidepenv',
          name: '.pioidepenv',
        });
      }
    }
  }
  return defaultEnvDir;
}
<|endoftext|>


<commit_before>(function(insight) {

    /**
     * A Theme for drawing on a lightly coloured background. Sets a number of the properties defined in the Theme base
     * class.
     * @class insight.LightTheme
     */
    insight.LightTheme = function LightTheme() {

        var self = this;

        insight.Theme.apply(self);

        //Configure for axis
        self.axisStyle.gridlineWidth = 1;
        self.axisStyle.gridlineColor = '#888';
        self.axisStyle.showGridlines = false;

        self.axisStyle.tickSize = 1;
        self.axisStyle.tickPadding = 10;

        self.axisStyle.axisLineWidth = 1;
        self.axisStyle.axisLineColor = '#777';
        self.axisStyle.tickLabelFont = '11pt Helvetica Neue';
        self.axisStyle.tickLabelColor = '#777';
        self.axisStyle.axisLabelFont = '12pt Helvetica Neue';
        self.axisStyle.axisLabelColor = '#777';

        //Configure for chart
        self.chartStyle.seriesPalette = ['#3182bd', '#c6dbed', '#6baed6', '#08519c', '#9ecae1'];
        self.chartStyle.fillColor = '#fff';
        self.chartStyle.titleFont = '16pt Helvetica Neue';
        self.chartStyle.titleColor = '#000';

        //Configure series
        self.seriesStyle.showPoints = false;
        self.seriesStyle.lineStyle = 'linear';
    };

    insight.LightTheme.prototype = Object.create(insight.Theme.prototype);
    insight.LightTheme.prototype.constructor = insight.LightTheme;

    //Set LightTheme as the default theme
    insight.defaultTheme = new insight.LightTheme();

})(insight);
<commit_msg>Increase tickSize<commit_after>(function(insight) {

    /**
     * A Theme for drawing on a lightly coloured background. Sets a number of the properties defined in the Theme base
     * class.
     * @class insight.LightTheme
     */
    insight.LightTheme = function LightTheme() {

        var self = this;

        insight.Theme.apply(self);

        //Configure for axis
        self.axisStyle.gridlineWidth = 1;
        self.axisStyle.gridlineColor = '#888';
        self.axisStyle.showGridlines = false;

        self.axisStyle.tickSize = 3;
        self.axisStyle.tickPadding = 10;

        self.axisStyle.axisLineWidth = 1;
        self.axisStyle.axisLineColor = '#777';
        self.axisStyle.tickLabelFont = '11pt Helvetica Neue';
        self.axisStyle.tickLabelColor = '#777';
        self.axisStyle.axisLabelFont = '12pt Helvetica Neue';
        self.axisStyle.axisLabelColor = '#777';

        //Configure for chart
        self.chartStyle.seriesPalette = ['#3182bd', '#c6dbed', '#6baed6', '#08519c', '#9ecae1'];
        self.chartStyle.fillColor = '#fff';
        self.chartStyle.titleFont = '16pt Helvetica Neue';
        self.chartStyle.titleColor = '#000';

        //Configure series
        self.seriesStyle.showPoints = false;
        self.seriesStyle.lineStyle = 'linear';
    };

    insight.LightTheme.prototype = Object.create(insight.Theme.prototype);
    insight.LightTheme.prototype.constructor = insight.LightTheme;

    //Set LightTheme as the default theme
    insight.defaultTheme = new insight.LightTheme();

})(insight);
<|endoftext|>


<commit_before>/* @flow */

const Config = {
  getJson(key: string, _default: Object = {}) {
    const value = atom.config.get(`Hydrogen.${key}`);
    if (!value || typeof value !== "string") return _default;
    try {
      return JSON.parse(value);
    } catch (error) {
      const message = `Your Hydrogen config is broken: ${key}`;
      atom.notifications.addError(message, { detail: error });
    }
    return _default;
  },

  schema: {
    autocomplete: {
      title: "Enable Autocomplete",
      includeTitle: false,
      description:
        "If enabled, use autocomplete options provided by the current kernel.",
      type: "boolean",
      default: true,
      order: 0
    },
    autocompleteSuggestionPriority: {
      title: "Autocomple Suggestion Priority",
      description:
        "Specify the sort order of Hydrogen's autocomplete suggestions.\nNote the default providers like snippets have priority of 1.",
      type: "integer",
      default: 3,
      order: 1
    },
    showInspectorResultsInAutocomplete: {
      title: "Enable Autocomplete description",
      description:
        "If enabled, Hydrogen will try to show [the results from kernel inspection](https://nteract.gitbooks.io/hydrogen/docs/Usage/GettingStarted.html#hydrogen-toggle-inspector) in each autocomplete suggestion's description. May slow down the autocompletion performance.",
      type: "boolean",
      default: true,
      order: 2
    },
    importNotebookURI: {
      title: "Enable Notebook Auto-import",
      description:
        "If enabled, opening a file with extension `.ipynb` will [import the notebook](https://nteract.gitbooks.io/hydrogen/docs/Usage/NotebookFiles.html#notebook-import) file's source into a new tab. If disabled, or if the Hydrogen package is not activated, the raw file will open in Atom as normal.",
      type: "boolean",
      default: true,
      order: 3
    },
    statusBarDisable: {
      title: "Disable the Hydrogen status bar",
      description:
        "If enabled, no kernel information will be provided in Atom's status bar.",
      type: "boolean",
      default: false,
      order: 4
    },
    debug: {
      title: "Enable Debug Messages",
      includeTitle: false,
      description: "If enabled, log debug messages onto the dev console.",
      type: "boolean",
      default: false,
      order: 5
    },
    autoScroll: {
      title: "Enable Autoscroll",
      includeTitle: false,
      description:
        "If enabled, Hydrogen will automatically scroll to the bottom of the result view.",
      type: "boolean",
      default: true,
      order: 6
    },
    wrapOutput: {
      title: "Enable Soft Wrap for Output",
      includeTitle: false,
      description:
        "If enabled, your output code from Hydrogen will break long text and items.",
      type: "boolean",
      default: false,
      order: 7
    },
    outputAreaDefault: {
      title: "View output in the dock by default",
      description:
        "If enabled, output will be displayed in the dock by default rather than inline",
      type: "boolean",
      default: false,
      order: 8
    },
    outputAreaDock: {
      title: "Leave output dock open",
      description:
        "Do not close dock when switching to an editor without a running kernel",
      type: "boolean",
      default: false,
      order: 9
    },
    outputAreaFontSize: {
      title: "Output area fontsize",
      includeTitle: false,
      description: "Change the fontsize of the Output area.",
      type: "integer",
      minimum: 0,
      default: 0,
      order: 10
    },
    globalMode: {
      title: "Enable Global Kernel",
      description:
        "If enabled, all files of the same grammar will share a single global kernel (requires Atom restart)",
      type: "boolean",
      default: false,
      order: 11
    },
    kernelNotifications: {
      title: "Enable Kernel Notifications",
      includeTitle: false,
      description:
        "Notify if kernels writes to stdout. By default, kernel notifications are only displayed in the developer console.",
      type: "boolean",
      default: false,
      order: 12
    },
    startDir: {
      title: "Directory to start kernel in",
      includeTitle: false,
      description: "Restart the kernel for changes to take effect.",
      type: "string",
      enum: [
        {
          value: "firstProjectDir",
          description: "The first started project's directory (default)"
        },
        {
          value: "projectDirOfFile",
          description: "The project directory relative to the file"
        },
        {
          value: "dirOfFile",
          description: "Current directory of the file"
        }
      ],
      default: "firstProjectDir",
      order: 13
    },
    languageMappings: {
      title: "Language Mappings",
      includeTitle: false,
      description:
        'Custom Atom grammars and some kernels use non-standard language names. That leaves Hydrogen unable to figure out what kernel to start for your code. This field should be a valid JSON mapping from a kernel language name to Atom\'s grammar name ``` { "kernel name": "grammar name" } ```. For example ``` { "scala211": "scala", "javascript": "babel es6 javascript", "python": "magicpython" } ```.',
      type: "string",
      default: '{ "python": "magicpython" }',
      order: 14
    },
    startupCode: {
      title: "Startup Code",
      includeTitle: false,
      description:
        'This code will be executed on kernel startup. Format: `{"kernel": "your code \\nmore code"}`. Example: `{"Python 2": "%matplotlib inline"}`',
      type: "string",
      default: "{}",
      order: 15
    },
    gateways: {
      title: "Kernel Gateways",
      includeTitle: false,
      description:
        'Hydrogen can connect to remote notebook servers and kernel gateways. Each gateway needs at minimum a name and a value for options.baseUrl. The options are passed directly to the `jupyter-js-services` npm package, which includes documentation for additional fields. Example value: ``` [{ "name": "Remote notebook", "options": { "baseUrl": "http://mysite.com:8888" } }] ```',
      type: "string",
      default: "[]",
      order: 16
    }
  }
};

export default Config;
<commit_msg>Update config descriptions<commit_after>/* @flow */

const Config = {
  getJson(key: string, _default: Object = {}) {
    const value = atom.config.get(`Hydrogen.${key}`);
    if (!value || typeof value !== "string") return _default;
    try {
      return JSON.parse(value);
    } catch (error) {
      const message = `Your Hydrogen config is broken: ${key}`;
      atom.notifications.addError(message, { detail: error });
    }
    return _default;
  },

  schema: {
    autocomplete: {
      title: "Enable Autocomplete",
      includeTitle: false,
      description:
        "If enabled, use autocomplete options provided by the current kernel.",
      type: "boolean",
      default: true,
      order: 0
    },
    autocompleteSuggestionPriority: {
      title: "Autocomple Suggestion Priority",
      description:
        "Specify the sort order of Hydrogen's autocomplete suggestions.\nNote the default providers like snippets have priority of 1.",
      type: "integer",
      default: 3,
      order: 1
    },
    showInspectorResultsInAutocomplete: {
      title: "Enable Autocomplete description (Experimental)",
      description:
        "If enabled, Hydrogen will try to show [the results from kernel inspection](https://nteract.gitbooks.io/hydrogen/docs/Usage/GettingStarted.html#hydrogen-toggle-inspector) in each autocomplete suggestion's description. May slow down the autocompletion performance. (Note: Even if you disable this, you would still get autocomplete suggestions.)",
      type: "boolean",
      default: true,
      order: 2
    },
    importNotebookURI: {
      title: "Enable Notebook Auto-import",
      description:
        "If enabled, opening a file with extension `.ipynb` will [import the notebook](https://nteract.gitbooks.io/hydrogen/docs/Usage/NotebookFiles.html#notebook-import) file's source into a new tab. If disabled, or if the Hydrogen package is not activated, the raw file will open in Atom as normal.",
      type: "boolean",
      default: true,
      order: 3
    },
    statusBarDisable: {
      title: "Disable the Hydrogen status bar",
      description:
        "If enabled, no kernel information will be provided in Atom's status bar.",
      type: "boolean",
      default: false,
      order: 4
    },
    debug: {
      title: "Enable Debug Messages",
      includeTitle: false,
      description: "If enabled, log debug messages onto the dev console.",
      type: "boolean",
      default: false,
      order: 5
    },
    autoScroll: {
      title: "Enable Autoscroll",
      includeTitle: false,
      description:
        "If enabled, Hydrogen will automatically scroll to the bottom of the result view.",
      type: "boolean",
      default: true,
      order: 6
    },
    wrapOutput: {
      title: "Enable Soft Wrap for Output",
      includeTitle: false,
      description:
        "If enabled, your output code from Hydrogen will break long text and items.",
      type: "boolean",
      default: false,
      order: 7
    },
    outputAreaDefault: {
      title: "View output in the dock by default",
      description:
        "If enabled, output will be displayed in the dock by default rather than inline",
      type: "boolean",
      default: false,
      order: 8
    },
    outputAreaDock: {
      title: "Leave output dock open",
      description:
        "Do not close dock when switching to an editor without a running kernel",
      type: "boolean",
      default: false,
      order: 9
    },
    outputAreaFontSize: {
      title: "Output area fontsize",
      includeTitle: false,
      description: "Change the fontsize of the Output area.",
      type: "integer",
      minimum: 0,
      default: 0,
      order: 10
    },
    globalMode: {
      title: "Enable Global Kernel",
      description:
        "If enabled, all files of the same grammar will share a single global kernel (requires Atom restart)",
      type: "boolean",
      default: false,
      order: 11
    },
    kernelNotifications: {
      title: "Enable Kernel Notifications",
      includeTitle: false,
      description:
        "Notify if kernels writes to stdout. By default, kernel notifications are only displayed in the developer console.",
      type: "boolean",
      default: false,
      order: 12
    },
    startDir: {
      title: "Directory to start kernel in",
      includeTitle: false,
      description: "Restart the kernel for changes to take effect.",
      type: "string",
      enum: [
        {
          value: "firstProjectDir",
          description: "The first started project's directory (default)"
        },
        {
          value: "projectDirOfFile",
          description: "The project directory relative to the file"
        },
        {
          value: "dirOfFile",
          description: "Current directory of the file"
        }
      ],
      default: "firstProjectDir",
      order: 13
    },
    languageMappings: {
      title: "Language Mappings",
      includeTitle: false,
      description:
        'Custom Atom grammars and some kernels use non-standard language names. That leaves Hydrogen unable to figure out what kernel to start for your code. This field should be a valid JSON mapping from a kernel language name to Atom\'s grammar name ``` { "kernel name": "grammar name" } ```. For example ``` { "scala211": "scala", "javascript": "babel es6 javascript", "python": "magicpython" } ```.',
      type: "string",
      default: '{ "python": "magicpython" }',
      order: 14
    },
    startupCode: {
      title: "Startup Code",
      includeTitle: false,
      description:
        'This code will be executed on kernel startup. Format: `{"kernel": "your code \\nmore code"}`. Example: `{"Python 2": "%matplotlib inline"}`',
      type: "string",
      default: "{}",
      order: 15
    },
    gateways: {
      title: "Kernel Gateways",
      includeTitle: false,
      description:
        'Hydrogen can connect to remote notebook servers and kernel gateways. Each gateway needs at minimum a name and a value for options.baseUrl. The options are passed directly to the `jupyter-js-services` npm package, which includes documentation for additional fields. Example value: ``` [{ "name": "Remote notebook", "options": { "baseUrl": "http://mysite.com:8888" } }] ```',
      type: "string",
      default: "[]",
      order: 16
    }
  }
};

export default Config;
<|endoftext|>


<commit_before>SoapStone.Drop = function(args) {
  this.coords = {};
  this.coords.longitude = args.coords.longitude;
  this.coords.latitude = args.coords.latitude;
  this.text = args.text;
  this.photo = args.photo;
};

SoapStone.Drop.prototype.save = function() {
  var data = {};
  data.drop = {};
  for (var key in this) {
    if (this.hasOwnProperty(key)) {
      data.drop[key] = this[key];
    }
  }
  console.log(data);
  return $.ajax({
    type: "POST",
    url:  "/drops",
    data: data
  });
};

SoapStone.DropView = function() {
  this.setUpEventHandlers()
};

SoapStone.DropView.prototype.getLocation = function() {
return new Promise(function(resolve, reject) {
      if ("geolocation" in navigator) {
        navigator.geolocation.getCurrentPosition(function(position) {
          var coords = {};
          coords.latitude = position.coords.latitude;
          coords.longitude = position.coords.longitude;
          resolve(coords);
        });
      } else {
          reject("Geolocation Not Available");
      }
  });
};

SoapStone.DropView.prototype.setUpEventHandlers = function(){
    $("[data-role='drop-form']").on('submit', function(event){
      event.preventDefault();
      var text = this.find("[name='text']").val();
      var photo = this.find("[name='photo']").val();
      SoapStone.app.createDrop({text: text, photo: photo});
  })
}

SoapStone.Controller = function() {
  this.view = new SoapStone.DropView();
  this.view.controller = this;
};

SoapStone.Controller.prototype.createDrop = function(dropParams) {
  this.view.getLocation().then(function(location) {
    var dropData = {
      text: dropParams.text,
      photo: dropParams.photo,
      coords: location
    };
    var drop = new SoapStone.Drop(dropData);
    drop.save()
    .then(function(response) {console.log(response);})
    .fail(function(response) {console.log(response);});
  });
};

//this needs to go in the event handler for form posting
$( document ).ready(function() {
  SoapStone.app = new SoapStone.Controller();
}

<commit_msg>add data<commit_after>SoapStone.Drop = function(args) {
  this.coords = {};
  this.coords.longitude = args.coords.longitude;
  this.coords.latitude = args.coords.latitude;
  this.text = args.text;
  this.photo = args.photo;
};

SoapStone.Drop.prototype.save = function() {
  var data = {};
  data.drop = {};
  for (var key in this) {
    if (this.hasOwnProperty(key)) {
      data.drop[key] = this[key];
    }
  }
  console.log(data);
  return $.ajax({
    type: "POST",
    url:  "/drops",
    data: data
  });
};

SoapStone.DropView = function() {
  this.setUpEventHandlers()
};

SoapStone.DropView.prototype.getLocation = function() {
return new Promise(function(resolve, reject) {
      if ("geolocation" in navigator) {
        navigator.geolocation.getCurrentPosition(function(position) {
          var coords = {};
          coords.latitude = position.coords.latitude;
          coords.longitude = position.coords.longitude;
          resolve(coords);
        });
      } else {
          reject("Geolocation Not Available");
      }
  });
};

SoapStone.DropView.prototype.setUpEventHandlers = function(){
    $("[data-role='drop-form']").on('submit', function(event){
      event.preventDefault();
      var text = $(this).find("[name='drop[text]']").val();
      var photo = $(this).find("[name='drop[photo]']").val();
      SoapStone.app.createDrop({text: text, photo: photo});
  })
}

SoapStone.Controller = function() {
  this.view = new SoapStone.DropView();
  this.view.controller = this;
};

SoapStone.Controller.prototype.createDrop = function(dropParams) {
  this.view.getLocation().then(function(location) {
    var dropData = {
      text: dropParams.text,
      photo: dropParams.photo,
      coords: location
    };
    var drop = new SoapStone.Drop(dropData);
    drop.save()
    .then(function(response) {console.log(response);})
    .fail(function(response) {console.log(response);});
  });
};

//this needs to go in the event handler for form posting
$( document ).ready(function() {
  SoapStone.app = new SoapStone.Controller();
});
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const _ = require('lodash');
const rootPath = path.normalize(path.join(__dirname, '..'));
const defaultAppPath = path.join(rootPath, 'app');

const CLIENT_SIDE_KEYS = [
  'es',
  'features',
  'googleAnalyticsPropertyID',
  'translations',
  'search',
  'sortOptions',
  'types'
];

// Default config parameters goes here
const defaults = {
  allowRobots: true,
  root: rootPath,
  search: {
    path: 'search'
  },
  siteTitle: 'Collections Online',
  types: {
    asset: {
      router: 'collections-online/lib/routers/asset'
    }
  }
};

function override(config) {
  const path = require('path');
  const defaultAppPath = path.normalize(path.join(__dirname, '..', 'app'));
  config.appPaths = _.concat(config.appPaths, defaultAppPath);
}

var config = {};

config.setChildPath = (childPath) => {
  config.childPath = childPath;
  config.reload();
};

config.getClientSideConfig = () => {
  // Copy over the values that are not confirdential
  let result = {};
  CLIENT_SIDE_KEYS.forEach(key => {
    result[key] = config[key];
  });
  return result;
};

config.setClientSideConfig = (clientSideConfig) => {
  config = _.merge(config, clientSideConfig);
};

config.reload = () => {
  const fs = require('fs');
  const path = require('path');
  // Check pre-conditions
  if(!config.childPath) {
    throw new Error('Call setChildPath before re-loading the configuration');
  }
  let childConfigPath = path.join(config.childPath, 'config.js');
  if(!fs.existsSync(childConfigPath)) {
    throw new Error('Expected a child configuration here: ', childConfigPath);
  }
  // Invalidate the require cache (if any)
  Object.keys(require.cache).forEach(p => {
    if(p.indexOf(path.join(config.childPath, 'config')) !== -1) {
      delete require.cache[p];
    }
  });
  // Require the child configuration
  let childConfig = require(childConfigPath);
  config = _.merge(config, defaults, childConfig);
  // Override anything
  override(config);
};

module.exports = config;
<commit_msg>Exposing the siteTitle and siteSubTitle to the clientside<commit_after>'use strict';

const path = require('path');
const _ = require('lodash');
const rootPath = path.normalize(path.join(__dirname, '..'));
const defaultAppPath = path.join(rootPath, 'app');

const CLIENT_SIDE_KEYS = [
  'es',
  'features',
  'googleAnalyticsPropertyID',
  'search',
  'siteSubTitle',
  'siteTitle',
  'sortOptions',
  'translations',
  'types'
];

// Default config parameters goes here
const defaults = {
  allowRobots: true,
  root: rootPath,
  search: {
    path: 'search'
  },
  siteTitle: 'Collections Online',
  types: {
    asset: {
      router: 'collections-online/lib/routers/asset'
    }
  }
};

function override(config) {
  const path = require('path');
  const defaultAppPath = path.normalize(path.join(__dirname, '..', 'app'));
  config.appPaths = _.concat(config.appPaths, defaultAppPath);
}

var config = {};

config.setChildPath = (childPath) => {
  config.childPath = childPath;
  config.reload();
};

config.getClientSideConfig = () => {
  // Copy over the values that are not confirdential
  let result = {};
  CLIENT_SIDE_KEYS.forEach(key => {
    result[key] = config[key];
  });
  return result;
};

config.setClientSideConfig = (clientSideConfig) => {
  config = _.merge(config, clientSideConfig);
};

config.reload = () => {
  const fs = require('fs');
  const path = require('path');
  // Check pre-conditions
  if(!config.childPath) {
    throw new Error('Call setChildPath before re-loading the configuration');
  }
  let childConfigPath = path.join(config.childPath, 'config.js');
  if(!fs.existsSync(childConfigPath)) {
    throw new Error('Expected a child configuration here: ', childConfigPath);
  }
  // Invalidate the require cache (if any)
  Object.keys(require.cache).forEach(p => {
    if(p.indexOf(path.join(config.childPath, 'config')) !== -1) {
      delete require.cache[p];
    }
  });
  // Require the child configuration
  let childConfig = require(childConfigPath);
  config = _.merge(config, defaults, childConfig);
  // Override anything
  override(config);
};

module.exports = config;
<|endoftext|>


<commit_before>"use strict";

/**
 * Configuration.
 *
 * **Note**: Currently very naive. Reads a `.builderrc` file if present and
 * nothing else.
 */
var fs = require("fs");
var path = require("path");
var _ = require("lodash");
var yaml = require("js-yaml");
var chalk = require("chalk");
var log = require("./log");

/**
 * Configuration wrapper.
 *
 * @param {Object} cfg  Configuration object or JSON/YAML file (Default: `.builderrc`)
 * @returns {void}
 */
var Config = module.exports = function (cfg) {
  log.info("config:environment", JSON.stringify({
    cwd: process.cwd(),
    dir: __dirname
  }));

  this.cfg = this._loadConfig(cfg);
  this.archetypes = this.cfg.archetypes || [];

  // Include the `-dev` packages.
  this.allArchetypes = this.archetypes.reduce(function (memo, name) {
    return memo.concat([name, name + "-dev"]);
  }, []);

  // State: Information about the installation environment.
  // (State is set on `_loadScripts`)
  this._isFromNpm = false;

  // Array of [name, scripts array] pairs.
  this.scripts = this._loadScripts(this.archetypes);
};

/**
 * Load configuration.
 *
 * @param   {Object} cfg  Configuration object or JSON/YAML file (Default: `.builderrc`)
 * @returns {Object}      Configuration object
 */
Config.prototype._loadConfig = function (cfg) {
  cfg = cfg || ".builderrc";

  if (typeof cfg === "string") {
    try {
      cfg = yaml.safeLoad(fs.readFileSync(cfg, "utf8"));
    } catch (err) {
      if (err.code === "ENOENT") {
        log.warn("config", "Unable to load config file: " + cfg);
      } else {
        log.error("config", err.toString());
        throw err;
      }
    }

    cfg = cfg || {};
  }

  return cfg;
};

/**
 * Load a single archetype's package.json.
 *
 * @param   {String} name   Archetype name
 * @returns {Object}        Package.json object
 */
Config.prototype._loadArchetypePackage = function (name) {
  /*eslint-disable global-require*/
  var pkgPath;

  // Scripts can be contained (npm v2) or siblings (npm v3).
  //
  // If a package is installed from NPM **and** we're using NPM v3, then the
  // archetype is a **sibling** not contained in `ROOT/node_modules`.
  //
  // Accordingly, we use information from loading `ROOT/package.json` to
  // heursitically (hackily) determine if these conditions are true.
  //
  // https://github.com/FormidableLabs/builder/issues/25
  try {
    // Contained in the "usual place"
    pkgPath = path.join(process.cwd(), "node_modules", name, "package.json");
    return require(pkgPath);
  } catch (err) {
    /*eslint-disable no-empty*/
  }

  if (this._isFromNpm) {
    try {
      // NPM-installed (sometimes on v2, always on v3)
      pkgPath = path.join(process.cwd(), "..", name, "package.json");
      return require(pkgPath);
    } catch (err) {
      /*eslint-disable no-empty*/
    }
  }

  // TODO: Refactor / rethink `require.resolve()` approach.
  // https://github.com/FormidableLabs/builder/issues/32

  return undefined;
};

/**
 * Archetype scripts.
 *
 * @param   {String} name   Archetype name
 * @returns {Object}        Package.json scripts object
 */
Config.prototype._loadArchetypeScripts = function (name) {
  var pkg = this._loadArchetypePackage(name);
  if (!pkg) {
    throw new Error("Unable to find package.json for: " + name);
  }

  var scripts = (pkg || {}).scripts || {};
  return _(scripts)
    .pairs()
    // Remove `builder:` internal tasks.
    .reject(function (pair) { return pair[0].indexOf("builder:") === 0; })
    .object()
    .value();
};

/**
 * Load archetype scripts.
 *
 * **Note**: We load scripts into an _array_ because order of operation matters
 * and is as follows:
 * - CWD
 * - Archetypes in _reverse_ order in `.builderrc`
 *
 * @param   {Array} archetypes  Archetype names
 * @returns {Array}             Array of script objects
 */
Config.prototype._loadScripts = function (archetypes) {
  var CWD_PKG = require(path.join(process.cwd(), "package.json")) || {};
  var CWD_SCRIPTS = CWD_PKG.scripts || {};

  // HACK: Detect if potential sibling with heuristic if "from npm";
  this._isFromNpm = !!CWD_PKG._resolved;

  return [["ROOT", CWD_SCRIPTS]].concat(_(archetypes)
    .map(function (name) {
      /*eslint-disable no-invalid-this*/
      return [name, this._loadArchetypeScripts(name)];
    }, this)
    .reverse()
    .value());
};

/**
 * Return display-friendly list of script commands.
 *
 * @param   {Array} archetypes  Archetype names to filter to (Default: all)
 * @returns {String}            Display string.
 */
Config.prototype.displayScripts = function (archetypes) {
  // Get filtered list of scripts.
  var scripts = this.scripts;
  if ((archetypes || []).length) {
    scripts = _.filter(scripts, function (pair) {
      return _.contains(archetypes, pair[0]);
    });
  }

  // First, get all keys.
  var keys = _(scripts)
    .map(function (pair) {
      return _.keys(pair[1]);
    })
    .flatten()
    .sortBy(function (name) {
      // Hack in a low-occuring string to prioritize "special" `:` names
      return (name.indexOf(":") > -1 ? "0000" : "") + name;
    })
    .value();

  // Then, map in order to scripts.
  return _.map(keys, function (key) {
    var tasks = _(scripts)
      .filter(function (pair) { return pair[1][key]; })
      .map(function (pair) {
        return "\n    " + chalk.gray("[" + pair[0] + "]") + " " + pair[1][key];
      })
      .value()
      .join("");

    return "\n  " + chalk.cyan(key) + tasks;
  }, this).join("\n");
};

/**
 * Get list of tasks in preferred execution order.
 *
 * @param   {String} cmd  Script command
 * @returns {Array}       List of ordered matches
 */
Config.prototype.getCommands = function (cmd) {
  return _(this.scripts)
    .map(function (pair) { return pair[1]; })
    .pluck(cmd)
    .filter(_.identity)
    .value();
};

Object.defineProperties(Config.prototype, {
  "archetypePaths": {
    /**
     * Return `.bin` paths for archetypes in configured order.
     *
     * @returns {Array} Archetype bin paths
     */
    get: function () {
      return _.map(this.allArchetypes, function (name) {
        return path.join(process.cwd(), "node_modules", name, "node_modules/.bin");
      });
    }
  },

  "archetypeNodePaths": {
    /**
     * Return path in `node_modules` for archetypes in configured order.
     *
     * @returns {Array} Archetype `node_modules` paths
     */
    get: function () {
      return _.map(this.allArchetypes, function (name) {
        return path.join(process.cwd(), "node_modules", name, "node_modules");
      });
    }
  }
});

<commit_msg>Switch to straight require for arch package.json.<commit_after>"use strict";

/**
 * Configuration.
 *
 * **Note**: Currently very naive. Reads a `.builderrc` file if present and
 * nothing else.
 */
var fs = require("fs");
var path = require("path");
var _ = require("lodash");
var yaml = require("js-yaml");
var chalk = require("chalk");
var log = require("./log");

/**
 * Configuration wrapper.
 *
 * @param {Object} cfg  Configuration object or JSON/YAML file (Default: `.builderrc`)
 * @returns {void}
 */
var Config = module.exports = function (cfg) {
  log.info("config:environment", JSON.stringify({
    cwd: process.cwd(),
    dir: __dirname
  }));

  this.cfg = this._loadConfig(cfg);
  this.archetypes = this.cfg.archetypes || [];

  // Include the `-dev` packages.
  this.allArchetypes = this.archetypes.reduce(function (memo, name) {
    return memo.concat([name, name + "-dev"]);
  }, []);

  // Array of [name, scripts array] pairs.
  this.scripts = this._loadScripts(this.archetypes);
};

/**
 * Load configuration.
 *
 * @param   {Object} cfg  Configuration object or JSON/YAML file (Default: `.builderrc`)
 * @returns {Object}      Configuration object
 */
Config.prototype._loadConfig = function (cfg) {
  cfg = cfg || ".builderrc";

  if (typeof cfg === "string") {
    try {
      cfg = yaml.safeLoad(fs.readFileSync(cfg, "utf8"));
    } catch (err) {
      if (err.code === "ENOENT") {
        log.warn("config", "Unable to load config file: " + cfg);
      } else {
        log.error("config", err.toString());
        throw err;
      }
    }

    cfg = cfg || {};
  }

  return cfg;
};

/**
 * Archetype scripts.
 *
 * @param   {String} name   Archetype name
 * @returns {Object}        Package.json scripts object
 */
Config.prototype._loadArchetypeScripts = function (name) {
  /*eslint-disable global-require*/
  var pkg;
  try {
    pkg = require(name + "/package.json");
  } catch (err) {
    log.error("config:load-archetype-scripts",
      "Error loading package.json for: " + chalk.gray(name) + " " +
      (err.message || err.toString()));
    throw err;
  }

  var scripts = (pkg || {}).scripts || {};
  return _(scripts)
    .pairs()
    // Remove `builder:` internal tasks.
    .reject(function (pair) { return pair[0].indexOf("builder:") === 0; })
    .object()
    .value();
};

/**
 * Load archetype scripts.
 *
 * **Note**: We load scripts into an _array_ because order of operation matters
 * and is as follows:
 * - CWD
 * - Archetypes in _reverse_ order in `.builderrc`
 *
 * @param   {Array} archetypes  Archetype names
 * @returns {Array}             Array of script objects
 */
Config.prototype._loadScripts = function (archetypes) {
  var CWD_PKG = require(path.join(process.cwd(), "package.json")) || {};
  var CWD_SCRIPTS = CWD_PKG.scripts || {};

  return [["ROOT", CWD_SCRIPTS]].concat(_(archetypes)
    .map(function (name) {
      /*eslint-disable no-invalid-this*/
      return [name, this._loadArchetypeScripts(name)];
    }, this)
    .reverse()
    .value());
};

/**
 * Return display-friendly list of script commands.
 *
 * @param   {Array} archetypes  Archetype names to filter to (Default: all)
 * @returns {String}            Display string.
 */
Config.prototype.displayScripts = function (archetypes) {
  // Get filtered list of scripts.
  var scripts = this.scripts;
  if ((archetypes || []).length) {
    scripts = _.filter(scripts, function (pair) {
      return _.contains(archetypes, pair[0]);
    });
  }

  // First, get all keys.
  var keys = _(scripts)
    .map(function (pair) {
      return _.keys(pair[1]);
    })
    .flatten()
    .sortBy(function (name) {
      // Hack in a low-occuring string to prioritize "special" `:` names
      return (name.indexOf(":") > -1 ? "0000" : "") + name;
    })
    .value();

  // Then, map in order to scripts.
  return _.map(keys, function (key) {
    var tasks = _(scripts)
      .filter(function (pair) { return pair[1][key]; })
      .map(function (pair) {
        return "\n    " + chalk.gray("[" + pair[0] + "]") + " " + pair[1][key];
      })
      .value()
      .join("");

    return "\n  " + chalk.cyan(key) + tasks;
  }, this).join("\n");
};

/**
 * Get list of tasks in preferred execution order.
 *
 * @param   {String} cmd  Script command
 * @returns {Array}       List of ordered matches
 */
Config.prototype.getCommands = function (cmd) {
  return _(this.scripts)
    .map(function (pair) { return pair[1]; })
    .pluck(cmd)
    .filter(_.identity)
    .value();
};

Object.defineProperties(Config.prototype, {
  "archetypePaths": {
    /**
     * Return `.bin` paths for archetypes in configured order.
     *
     * @returns {Array} Archetype bin paths
     */
    get: function () {
      return _.map(this.allArchetypes, function (name) {
        return path.join(process.cwd(), "node_modules", name, "node_modules/.bin");
      });
    }
  },

  "archetypeNodePaths": {
    /**
     * Return path in `node_modules` for archetypes in configured order.
     *
     * @returns {Array} Archetype `node_modules` paths
     */
    get: function () {
      return _.map(this.allArchetypes, function (name) {
        return path.join(process.cwd(), "node_modules", name, "node_modules");
      });
    }
  }
});

<|endoftext|>


<commit_before>// CLOCK FOR THE GAME
var startTime = 0;
clockUpdaterID = 0;

var drawClock = function(){
  canvas = Raphael("clock_id",200, 200);
  var clock = canvas.circle(100,100,95);
   clock.attr({"fill":"#f5f5f5","stroke":"#444444","stroke-width":"5"})
   var hour_sign;
  for(i=0;i<12;i++){
      var start_x = 100+Math.round(80*Math.cos(30*i*Math.PI/180));
      var start_y = 100+Math.round(80*Math.sin(30*i*Math.PI/180));
      var end_x = 100+Math.round(90*Math.cos(30*i*Math.PI/180));
      var end_y = 100+Math.round(90*Math.sin(30*i*Math.PI/180));
      hour_sign = canvas.path("M"+start_x+" "+start_y+"L"+end_x+" "+end_y);
  }
  second_hand = canvas.path("M100 110L100 25");
  second_hand.attr({stroke: "#444444", "stroke-width": 2});
  pointClockHandUp();
  updateClock();
};

var prepareToStopClock;
var updateClock = function(){
  var now = new Date();
  var seconds = now.getSeconds() - startTime;
  second_hand.rotate(6 * seconds, 100, 100);
  if (prepareToStopClock) {
    stopClock();
  }
  if (seconds == -1) {
    prepareToStopClock = true;
  }
};

var stopClock = function(){
  clearInterval(clockUpdaterID);
  $("#game").trigger("clockEnd");
  prepareToStopClock = false;
};

var pointClockHandUp = function(){
  startTime = new Date().getSeconds();
  prepareToStopClock = false;
};

var resetClock = function(){
  stopClock();
  pointClockHandUp();
  updateClock();
}

var restartClock = function(){
  stopClock();
  pointClockHandUp();
  updateClock();
  clockUpdaterID = setInterval("updateClock()",1000);
};

// AJAX CALLS FOR FETCHING WORDS AND TRANSLATIONS
var languageCode = "";
var numWords = "200";
var gameWords = [];

var checkReady = function(){
  languageCode = $("#s2id_language-dropdown").select2("val")
  numWords = $("#num-words").find(":selected").text();
  if (languageCode != "") {
    $("#game-start-button").removeClass("disabled");
  } else {
    $("#game-start-button").addClass("disabled");
  }
};

var Word = function(text, translations){
  this.text = text;
  this.translations = $.map(translations.split("
"), function(translation){
    return translation.toLowerCase();
  });
};

var failureToLoad = function() {
  $("#game-play").slideUp();
  alert("I can't fetch the words for your game.\n" +
        "Are you connected to the internet?");
};

var getWordData = function(callback){
  gameWords.length = 0;
  var params = "?language_code=" + languageCode + "&num_words=" + numWords;
  $.getJSON("/game/words" + params, function(response){
    $.each(response, function(index, word){
      gameWords.push(new Word(word.word, word.translation));
    });
  }).then(callback, failureToLoad);
};

// PLAYING THE GAME
var points = 0;
var currentWord = new Object;
var usedWords = [];

var showMessage = function(message){
  $("#game-alerts").text(message);
}

var clearUp = function(){
  $("#game").off("keyup.dismiss");
  $("#game").off("clockEnd");
  $("#game").off("keyup.testWord");
};

var gameEnd = function(){
  console.log("executing game end");
  clearUp();

  showMessage("You got " + points + " points! (press SPACE to dismiss this message)");
  $("#game").on("keyup.dismiss", "#translation-field", function(e){
    $("#translation-field").val('');
    if (e.which == 32) {
      e.preventDefault();
      $("#game").off("keyup.dismiss");
      initiatePregameShow();
    }
  });
  if (points > 0) {
    $("#game-alerts").removeClass("bg-danger").addClass("bg-success");
  }
};

var setupGameEnd = function(){
  console.log("setting up game end");
  $("#game").on("clockEnd", gameEnd);
};

var newRandomWord = function(){
  return gameWords[Math.floor(Math.random()*gameWords.length)];
};

var displayFinishedWord = function(currentWord, correct){
  if (correct) {
    points++;
    var rowClass = "success";
  } else {
    var rowClass = "danger";
  }
  var row = '
' +
    '' + currentWord.text + '	' +
    '' + currentWord.translations.join(", ") + '
';
  $(row).appendTo($('#game-results').find('tbody')).fadeIn();
}

var changePromptWord = function(){
  currentWord = newRandomWord();
  $("#word-prompt").text('"Translate: "' + currentWord.text + '"');
};

var handleInput = function(correct){
  $("#translation-field").val('');
  usedWords.push(currentWord);
  displayFinishedWord(currentWord, correct);
  changePromptWord();
};

var runGame = function(){
  changePromptWord();
  $("#game").on("keyup.testWord", "#translation-field", function(e){
    var inputWord = $("#translation-field").val().toLowerCase();
    if ($.inArray(inputWord, currentWord.translations) > -1) {
      handleInput(true);
    } else if (e.which == 13) {
      handleInput(false);
    }
  });
};

var forceFocusOnTextField = function(){
  $("#translation-field").focus();
  $("#translation-field").off("blur").blur(function(){
    $("#translation-field").focus();
  });
};

var clearDisplay = function() {
  $("#word-prompt").text('');
  $("#game-results").find("tbody").text('');
  $("#game-alerts").removeClass("bg-success").addClass("bg-danger");
  showMessage("Press Enter to begin!");
};

var clearVariables = function() {
  points = 0;
  currentWord = new Object;
  usedWords = [];
}

var resetGame = function(){
  pointClockHandUp();
  resetClock();
  clearDisplay();
  clearVariables();

  $("#game-play").slideDown();
  forceFocusOnTextField();
};

var waitForEnter = function(){
  $("#game").off("keyup.testWord");
  $("#game").on("keypress.startGame", "#translation-field", function(event){
    event.preventDefault();
    event.stopPropagation();
    $("#translation-field").val('');
    if(event.which == 13) {
      $("#game").off("keypress.startGame").
        on("keyup.begin", "#translation-field", function(){

        $("#game").off("keyup.begin");
        $("#translation-field").val("");
        showMessage('Enter the translation! (or press Enter to pass)');
        restartClock();
        setupGameEnd();
        runGame();
      });
    }
  });
};

var initiatePregameShow = function(){
  resetGame();
  waitForEnter();
};

var buttonClickHandler = function(){
  button = $(this);
  if (!button.hasClass("disabled")){
    button.text("RESET");
    clearUp();
    getWordData(initiatePregameShow);
  }
};

var bindGameOptionSelectors = function(){
  $("body").on("change", "#game", checkReady);
  $("body").on("click", "#game-start-button", buttonClickHandler);
};

$(document).ready(function(){
  bindGameOptionSelectors();
  drawClock();
});<commit_msg>Fix up game so characters don't display while waiting for spacebar press<commit_after>// CLOCK FOR THE GAME
var startTime = 0;
clockUpdaterID = 0;

var drawClock = function(){
  canvas = Raphael("clock_id",200, 200);
  var clock = canvas.circle(100,100,95);
   clock.attr({"fill":"#f5f5f5","stroke":"#444444","stroke-width":"5"})
   var hour_sign;
  for(i=0;i<12;i++){
      var start_x = 100+Math.round(80*Math.cos(30*i*Math.PI/180));
      var start_y = 100+Math.round(80*Math.sin(30*i*Math.PI/180));
      var end_x = 100+Math.round(90*Math.cos(30*i*Math.PI/180));
      var end_y = 100+Math.round(90*Math.sin(30*i*Math.PI/180));
      hour_sign = canvas.path("M"+start_x+" "+start_y+"L"+end_x+" "+end_y);
  }
  second_hand = canvas.path("M100 110L100 25");
  second_hand.attr({stroke: "#444444", "stroke-width": 2});
  pointClockHandUp();
  updateClock();
};

var prepareToStopClock;
var updateClock = function(){
  var now = new Date();
  var seconds = now.getSeconds() - startTime;
  second_hand.rotate(6 * seconds, 100, 100);
  if (prepareToStopClock) {
    stopClock();
  }
  if (seconds == -1) {
    prepareToStopClock = true;
  }
};

var stopClock = function(){
  clearInterval(clockUpdaterID);
  $("#game").trigger("clockEnd");
  prepareToStopClock = false;
};

var pointClockHandUp = function(){
  startTime = new Date().getSeconds();
  prepareToStopClock = false;
};

var resetClock = function(){
  stopClock();
  pointClockHandUp();
  updateClock();
}

var restartClock = function(){
  stopClock();
  pointClockHandUp();
  updateClock();
  clockUpdaterID = setInterval("updateClock()",1000);
};

// AJAX CALLS FOR FETCHING WORDS AND TRANSLATIONS
var languageCode = "";
var numWords = "200";
var gameWords = [];

var checkReady = function(){
  languageCode = $("#s2id_language-dropdown").select2("val")
  numWords = $("#num-words").find(":selected").text();
  if (languageCode != "") {
    $("#game-start-button").removeClass("disabled");
  } else {
    $("#game-start-button").addClass("disabled");
  }
};

var Word = function(text, translations){
  this.text = text;
  this.translations = $.map(translations.split("
"), function(translation){
    return translation.toLowerCase();
  });
};

var failureToLoad = function() {
  $("#game-play").slideUp();
  alert("I can't fetch the words for your game.\n" +
        "Are you connected to the internet?");
};

var getWordData = function(callback){
  gameWords.length = 0;
  var params = "?language_code=" + languageCode + "&num_words=" + numWords;
  $.getJSON("/game/words" + params, function(response){
    $.each(response, function(index, word){
      gameWords.push(new Word(word.word, word.translation));
    });
  }).then(callback, failureToLoad);
};

// PLAYING THE GAME
var points = 0;
var currentWord = new Object;
var usedWords = [];

var showMessage = function(message){
  $("#game-alerts").text(message);
}

var clearUp = function(){
  $("#game").off("keyup.dismiss");
  $("#game").off("clockEnd");
  $("#game").off("keyup.testWord");
};

var gameEnd = function(){
  console.log("executing game end");
  clearUp();

  showMessage("You got " + points + " correct words!" +
    " (press SPACE to reset the game)");

  var resetGame = function(event){
    event.preventDefault();
    event.stopPropagation();
    $("#translation-field").val('');
    if(event.which == 32) {
      $("#game").off("keypress.dismiss");
      initiatePregameShow();
    }
  };
  $("#game").on("keypress.dismiss", "#translation-field", resetGame);

  if (points > 0) {
    $("#game-alerts").removeClass("bg-danger").addClass("bg-success");
  }
};

var setupGameEnd = function(){
  console.log("setting up game end");
  $("#game").on("clockEnd", gameEnd);
};

var newRandomWord = function(){
  return gameWords[Math.floor(Math.random()*gameWords.length)];
};

var displayFinishedWord = function(currentWord, correct){
  if (correct) {
    points++;
    var rowClass = "success";
  } else {
    var rowClass = "danger";
  }
  var row = '
' +
    '' + currentWord.text + '	' +
    '' + currentWord.translations.join(", ") + '
';
  $(row).appendTo($('#game-results').find('tbody')).fadeIn();
}

var changePromptWord = function(){
  currentWord = newRandomWord();
  $("#word-prompt").text('"Translate: "' + currentWord.text + '"');
};

var handleInput = function(correct){
  $("#translation-field").val('');
  usedWords.push(currentWord);
  displayFinishedWord(currentWord, correct);
  changePromptWord();
};

var runGame = function(){
  changePromptWord();
  $("#game").on("keyup.testWord", "#translation-field", function(e){
    var inputWord = $("#translation-field").val().toLowerCase();
    if ($.inArray(inputWord, currentWord.translations) > -1) {
      handleInput(true);
    } else if (e.which == 13) {
      handleInput(false);
    }
  });
};

var forceFocusOnTextField = function(){
  $("#translation-field").focus();
  $("#translation-field").off("blur").blur(function(){
    $("#translation-field").focus();
  });
};

var clearDisplay = function() {
  $("#word-prompt").text('');
  $("#game-results").find("tbody").text('');
  $("#game-alerts").removeClass("bg-success").addClass("bg-danger");
  showMessage("Press Enter to begin!");
};

var clearVariables = function() {
  points = 0;
  currentWord = new Object;
  usedWords = [];
}

var resetGame = function(){
  pointClockHandUp();
  resetClock();
  clearDisplay();
  clearVariables();

  $("#game-play").slideDown();
  forceFocusOnTextField();
};

var waitForEnter = function(){
  $("#game").off("keyup.testWord");
  $("#game").on("keypress.startGame", "#translation-field", function(event){
    event.preventDefault();
    event.stopPropagation();
    $("#translation-field").val('');
    if(event.which == 13) {
      $("#game").off("keypress.startGame").
        on("keyup.begin", "#translation-field", function(){

        $("#game").off("keyup.begin");
        $("#translation-field").val("");
        showMessage('Enter the translation! (or press Enter to pass)');
        restartClock();
        setupGameEnd();
        runGame();
      });
    }
  });
};

var initiatePregameShow = function(){
  resetGame();
  waitForEnter();
};

var buttonClickHandler = function(){
  button = $(this);
  if (!button.hasClass("disabled")){
    button.text("RESET");
    clearUp();
    getWordData(initiatePregameShow);
  }
};

var bindGameOptionSelectors = function(){
  $("body").on("change", "#game", checkReady);
  $("body").on("click", "#game-start-button", buttonClickHandler);
};

$(document).ready(function(){
  bindGameOptionSelectors();
  drawClock();
});<|endoftext|>


<commit_before>'use strict';

const utils = require('./utils');

const fs = require('fs'),
    yaml = require('js-yaml');

/**
 * Default configuration options
 *
 * @readonly
 * @type {object}
 */
const defaultConfig = {
    /**
     * Core configuration options
     *
     * @type {object}
     */
    core: {
        /**
         * Username the bot will log in as
         *
         * @default
         * @type {string}
         */
        username: '',
        /**
         * Password the bot will log in with
         *
         * @default
         * @type {string}
         */
        password: '',
        /**
         * User the bot will consider owner
         *
         * Owner promotes the user to virtual trust level 9 (above forum admins)
         *
         * @default
         * @type {string}
         */
        owner: 'accalia',
        /**
         * Base URL for the discourse instance to log into
         *
         * Is case sensitive
         *
         * @default
         * @type {string}
         */
        forum: 'https://what.thedailywtf.com',
        /**
         * Users to ignore.
         *
         * Ignoring users demotes them internally to virtual trust level 0. Forum staff cannot be ignored.
         *
         * @default
         * @type {string[]}
         */
        ignoreUsers: [
            'blakeyrat', 'PaulaBean'
        ],
        /**
         * Discourse categories to ignore
         *
         * Posts from ignored categories will not trigger bot.
         *
         * @default
         * @type {Number[]}
         */
        ignoreCategories: [8, 23],
        /**
         * Cooldown timer for users that map to virtual trust level 1 or lower
         *
         * @default
         * @type {Number}
         */
        cooldownPeriod: 3.6E6,
        /**
         * Switch to handle `acted` type channel messages.
         *
         * This type of message is often not needed for bot operation and generates a fair bit of traffic.
         * Disabling reduces load on the host forum.
         *
         * @default
         * @type {boolean}
         */
        handleActedMessage: false,
        /**
         * Set whether to poll for messages.
         *
         * If the bot only needs to handle notifications, set this to `false` to reduce load on the host forum.
         *
         * Note: Setting this to `false` will cause notifications to be polled less frequently;
         * leave `true` if you want a more responsive bot
         *
         * @default
         * @type {boolean}
         */
        pollMessages: true,
        /**
         * Set whether to poll for notifications.
         *
         * For bots, this will normally be left `true`.
         * For cyberparts, set this to `false` to stop the bot marking notifications as read.
         *
         * @default
         * @type {boolean}
         */
        pollNotifications: true
    },
    /**
     * Plugin configuration.
     *
     * See `Plugin Configuration` for details
     *
     * @type {object}
     */
    plugins: {}
};

/**
 * Read and parse configuration file from disc
 *
 * @param {string} path Path of file to read
 * @param {configComplete} callback Completion callback
 */
function readFile(path, callback) {
    if (!path || typeof path !== 'string') {
        callback(new Error('Path must be a string'));
        return;
    }
    fs.readFile(path, (err, data) => {
        if (err) {
            return callback(err);
        }
        // Remove UTF-8 BOM if present
        if (data.length >= 3 && data[0] === 0xef &&
            data[1] === 0xbb && data[2] === 0xbf) {
            data = data.slice(3);
        }
        try {
            callback(null, yaml.safeLoad(data));
        } catch (e) {
            callback(e);
        }
    });
}

/**
 * Load configuration from disc
 *
 * @param {string} path Configuration file path
 * @param {configComplete} callback Completion callback
 */
exports.loadConfiguration = function loadConfiguration(path, callback) {
    readFile(path, (err, config) => {
        if (err) {
            callback(err);
            return;
        }
        try {
            const cfg = utils.mergeObjects(true, defaultConfig, config);
            exports.core = cfg.core;
            exports.plugins = cfg.plugins;
            callback(null, cfg);
        } catch (e) {
            callback(e);
        }
    });
};

/**
 * Configuration Loaded Callback
 *
 * @callback
 * @name configComplete
 * @param {Exception} [err=null] Error encountered processing request
 * @param {Object} config Loaded Configuration
 */

const config = JSON.parse(JSON.stringify(defaultConfig));

/**
 * Current core configuration
 *
 * Set by internals. Do not edit
 *
 * @readonly
 */
exports.core = config.core;

/**
 * Current plugin configuration
 *
 * Set by ineternals. Do not edit
 *
 * @readonly
 */
exports.plugins = config.plugins;

/**
 * Current logged in user
 *
 * Set by internals. Do not edit
 *
 * @readonly
 */
exports.user = {};

/* istanbul ignore else */
if (typeof GLOBAL.describe === 'function') {
    exports.internals = {
        readFile: readFile,
        defaultConfig: defaultConfig
    };
}
<commit_msg>Eslint warning: remove trailing space from docs... done!<commit_after>'use strict';

const utils = require('./utils');

const fs = require('fs'),
    yaml = require('js-yaml');

/**
 * Default configuration options
 *
 * @readonly
 * @type {object}
 */
const defaultConfig = {
    /**
     * Core configuration options
     *
     * @type {object}
     */
    core: {
        /**
         * Username the bot will log in as
         *
         * @default
         * @type {string}
         */
        username: '',
        /**
         * Password the bot will log in with
         *
         * @default
         * @type {string}
         */
        password: '',
        /**
         * User the bot will consider owner
         *
         * Owner promotes the user to virtual trust level 9 (above forum admins)
         *
         * @default
         * @type {string}
         */
        owner: 'accalia',
        /**
         * Base URL for the discourse instance to log into
         *
         * Is case sensitive
         *
         * @default
         * @type {string}
         */
        forum: 'https://what.thedailywtf.com',
        /**
         * Users to ignore.
         *
         * Ignoring users demotes them internally to virtual trust level 0. Forum staff cannot be ignored.
         *
         * @default
         * @type {string[]}
         */
        ignoreUsers: [
            'blakeyrat', 'PaulaBean'
        ],
        /**
         * Discourse categories to ignore
         *
         * Posts from ignored categories will not trigger bot.
         *
         * @default
         * @type {Number[]}
         */
        ignoreCategories: [8, 23],
        /**
         * Cooldown timer for users that map to virtual trust level 1 or lower
         *
         * @default
         * @type {Number}
         */
        cooldownPeriod: 3.6E6,
        /**
         * Switch to handle `acted` type channel messages.
         *
         * This type of message is often not needed for bot operation and generates a fair bit of traffic.
         * Disabling reduces load on the host forum.
         *
         * @default
         * @type {boolean}
         */
        handleActedMessage: false,
        /**
         * Set whether to poll for messages.
         *
         * If the bot only needs to handle notifications, set this to `false` to reduce load on the host forum.
         *
         * Note: Setting this to `false` will cause notifications to be polled less frequently;
         * leave `true` if you want a more responsive bot
         *
         * @default
         * @type {boolean}
         */
        pollMessages: true,
        /**
         * Set whether to poll for notifications.
         *
         * For bots, this will normally be left `true`.
         * For cyberparts, set this to `false` to stop the bot marking notifications as read.
         *
         * @default
         * @type {boolean}
         */
        pollNotifications: true
    },
    /**
     * Plugin configuration.
     *
     * See `Plugin Configuration` for details
     *
     * @type {object}
     */
    plugins: {}
};

/**
 * Read and parse configuration file from disc
 *
 * @param {string} path Path of file to read
 * @param {configComplete} callback Completion callback
 */
function readFile(path, callback) {
    if (!path || typeof path !== 'string') {
        callback(new Error('Path must be a string'));
        return;
    }
    fs.readFile(path, (err, data) => {
        if (err) {
            return callback(err);
        }
        // Remove UTF-8 BOM if present
        if (data.length >= 3 && data[0] === 0xef &&
            data[1] === 0xbb && data[2] === 0xbf) {
            data = data.slice(3);
        }
        try {
            callback(null, yaml.safeLoad(data));
        } catch (e) {
            callback(e);
        }
    });
}

/**
 * Load configuration from disc
 *
 * @param {string} path Configuration file path
 * @param {configComplete} callback Completion callback
 */
exports.loadConfiguration = function loadConfiguration(path, callback) {
    readFile(path, (err, config) => {
        if (err) {
            callback(err);
            return;
        }
        try {
            const cfg = utils.mergeObjects(true, defaultConfig, config);
            exports.core = cfg.core;
            exports.plugins = cfg.plugins;
            callback(null, cfg);
        } catch (e) {
            callback(e);
        }
    });
};

/**
 * Configuration Loaded Callback
 *
 * @callback
 * @name configComplete
 * @param {Exception} [err=null] Error encountered processing request
 * @param {Object} config Loaded Configuration
 */

const config = JSON.parse(JSON.stringify(defaultConfig));

/**
 * Current core configuration
 *
 * Set by internals. Do not edit
 *
 * @readonly
 */
exports.core = config.core;

/**
 * Current plugin configuration
 *
 * Set by ineternals. Do not edit
 *
 * @readonly
 */
exports.plugins = config.plugins;

/**
 * Current logged in user
 *
 * Set by internals. Do not edit
 *
 * @readonly
 */
exports.user = {};

/* istanbul ignore else */
if (typeof GLOBAL.describe === 'function') {
    exports.internals = {
        readFile: readFile,
        defaultConfig: defaultConfig
    };
}
<|endoftext|>