<commit_before>/* eslint no-bitwise: 0, jsx-no-bind: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import axios from 'axios';
import { Button, Icon, message, Modal, Spin, Tooltip } from 'antd';
import { MonacoEditor } from '../common';
import { fetchFileContent, saveFile, showDemoAlert, codeChange, stickTab } from './redux/actions';
import editorStateMap from './editorStateMap';
import modelManager from '../common/monaco/modelManager';
import { storage } from '../common/utils';
import { OutlineView, OutlineResizer } from '.';

export class CodeEditor extends Component {
  static propTypes = {
    outlineWidth: PropTypes.number.isRequired,
    fileContentById: PropTypes.object.isRequired,
    fileContentNeedReload: PropTypes.object.isRequired,
    fetchFileContentPending: PropTypes.bool.isRequired, // eslint-disable-line
    saveFilePending: PropTypes.bool.isRequired,
    actions: PropTypes.object.isRequired,
    file: PropTypes.string.isRequired,
    onError: PropTypes.func,
    onStateChange: PropTypes.func,
    onRunTest: PropTypes.func,
  };

  static defaultProps = {
    onError() {},
    onStateChange() {},
    onRunTest: null,
  };

  constructor(props) {
    super(props);
    // BIG magic here! When open/switch a new file, it will trigger cursor change first
    // which causes to save status. So if the file is new open, should not save its state
    // before recover the state. So when file is changed set this flag to true. After recover
    // the status, set it to false so that state could be saved.
    this.preventSaveEditorState = true;

    this.monacoListeners = [];
  }

  state = {
    notFound: false,
    loadingFile: false,
    loadingEditor: true,
    cursorPos: {
      lineNumber: 1,
      column: 1,
    },
    showOutline: !storage.local.getItem('noOutline'),
  };

  async componentWillMount() {
    this.setState({
      loadingFile: true,
    });
    await this.checkAndFetchFileContent(this.props);
    // Todo: check if conflict
    modelManager.setInitialValue(this.props.file, this.getFileContent(this.props.file), true);
    this.setState({
      // eslint-disable-line
      loadingFile: false,
    });
    this.props.onStateChange({ hasChange: false });
  }

  async componentWillReceiveProps(nextProps) {
    const { props } = this;
    if (props.file !== nextProps.file) {
      // When file is changed, prevent saving before its state is restored.
      this.preventSaveEditorState = true;
      this.setState(
        {
          loadingFile: true,
        },
        () => this.editor.layout()
      );
      await this.checkAndFetchFileContent(nextProps);
      // Todo: check if conflict
      modelManager.setInitialValue(nextProps.file, this.getFileContent(nextProps.file), true);
      this.preventSaveEditorState = false;
      this.recoverEditorState();
      this.setState({
        loadingFile: false,
      });
    } else if (nextProps.fileContentNeedReload[nextProps.file]) {
      const oldContent = this.getFileContent();
      const hasChange = this.hasChange(); // has changed
      await this.checkAndFetchFileContent(nextProps);
      modelManager.setInitialValue(nextProps.file, this.getFileContent(nextProps.file), true);
      this.setState({
        loadingFile: false,
      });
      const newContent = this.getFileContent();
      if (hasChange && oldContent !== newContent && newContent !== modelManager.getValue(nextProps.file)) {
        Modal.confirm({
          title: 'The file has changed on disk.',
          content: 'Do you want to reload it?',
          okText: 'Yes',
          cancelText: 'No',
          onOk: () => {
            modelManager.reset(nextProps.file);
          },
        });
      }
    }
  }

  componentWillUnmount() {
    this.monacoListeners.forEach(lis => lis.dispose());
  }

  getFileContent(filePath) {
    return this.props.fileContentById[filePath || this.props.file];
  }

  getOutlineWidth() {
    return this.hasOutline() && this.state.showOutline ? this.props.outlineWidth : 0;
  }

  hasOutline() {
    return this.props.file.split('.').pop() === 'js';
  }

  formatCode = () => {
    this.setState({ loadingFile: true });
    const lines = this.editor.getValue().split('\n');
    const { lineNumber, column } = this.editor.getPosition();
    const cursorOffset = lines.slice(0, lineNumber - 1).reduce((c, line) => c + line.length + 1, 0) + column - 1;

    axios
      .post('/rekit/api/format-code', {
        content: modelManager.getValue(this.props.file),
        file: this.props.file,
        cursorOffset,
      })
      .then(res => {
        if (res.data.error || !res.data.content.formatted) {
          this.setState({ loadingFile: false });
          return;
        }
        this.editor.executeEdits('format', [
          { range: new monaco.Range(1, 1, 1000000, 1), text: res.data.content.formatted, forceMoveMarkers: true },
        ]);
        const newCursorOffset = res.data.content.cursorOffset;
        const newLines = res.data.content.formatted.split('\n');
        let c = 0;
        let newLineNumber = 0;
        while (c + newLines[newLineNumber].length + 1 < newCursorOffset && newLineNumber < newLines.length) {
          c += newLines[newLineNumber].length + 1;
          newLineNumber += 1;
        }
        const col = newCursorOffset - c;
        this.editor.setPosition({ lineNumber: newLineNumber + 1, column: col + 1 });
        this.setState({
          loadingFile: false,
        });
      })
      .catch(() => {
        this.setState({
          loadingFile: false,
        });
      });
  };

  recoverEditorState = () => {
    if (!this.editor) return;
    const { file } = this.props;
    this.preventSaveEditorState = false;
    const editorState = editorStateMap[file] || null;
    this.editor.restoreViewState(editorState);
    this.editor.focus();
  };

  hasChange() {
    // Whether the editor content is different from which in store.
    return modelManager.isChanged(this.props.file);
    // return this.state.currentContent !== this.getFileContent();
  }

  checkAndFetchFileContent(props) {
    // Check if content exists or need reload, if yes then fetch it.
    const { fileContentById, fileContentNeedReload, fetchFileContentPending, file } = props;
    if ((!_.has(fileContentById, file) || fileContentNeedReload[file]) && !fetchFileContentPending) {
      return this.props.actions
        .fetchFileContent(props.file)
        .then(() => {
          this.setState({ notFound: false });
        })
        .catch(e => {
          message.error(`Failed to load file: ${e.toString()}`);
          if (_.get(e, 'response.status') === 404) {
            this.setState({ notFound: true, loadingFile: false });
            this.props.onError(404);
          }
        });
    } else {
      this.setState({ notFound: false });
      return Promise.resolve();
    }
  }

  handleEditorChange = () => {
    this.props.actions.codeChange();
  };

  handleOutlineSelect = nodeData => {
    if (nodeData.startLine && this.editor) {
      this.editor.setScrollTop(this.editor.getTopForLineNumber(nodeData.startLine));
    }
  };

  handleEditorDidMount = editor => {
    this.editor = editor;
    editor.focus();
    // This seems to be able to add multiple times.
    editor.addCommand([monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S], () => {
      this.handleSave();
    });
    editor.addCommand([monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_O], () => {
      this.handleToggleOutline();
    });
    editor.addCommand([monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_B], () => {
      this.formatCode();
    });
    this.monacoListeners.push(
      editor.onDidChangeCursorPosition(() => this.setState({ cursorPos: editor.getPosition() })),
      editor.onDidChangeCursorPosition(this.handleEditorCursorScrollerChange),
      editor.onDidScrollChange(this.handleEditorCursorScrollerChange)
    );
    this.setState({
      loadingEditor: false,
    });
    // // It needs some time for editor to load its content
    setTimeout(this.recoverEditorState, 30);
  };

  handleEditorCursorScrollerChange = () => {
    if (this.preventSaveEditorState) return;
    const { file } = this.props;

    editorStateMap[file] = this.editor.saveViewState();
  };

  handleRunTest = () => {
    this.props.onRunTest();
  };

  handleSave = () => {
    this.props.actions.stickTab();
    if (!this.hasChange()) return;
    this.props.actions
      .saveFile(this.props.file, this.editor.getValue())
      .then(() => {
        modelManager.setInitialValue(this.props.file, this.editor.getValue());
        this.props.actions.codeChange();
      })
      .catch(() => {
        if (process.env.REKIT_ENV === 'demo') {
          this.props.actions.showDemoAlert();
          return;
        }
        Modal.error({
          title: 'Failed to save.',
          content: 'Please retry or use other text editor.',
        });
      });
  };

  handleCancel = () => {
    Modal.confirm({
      content: 'Are you sure to discard your changes?',
      okText: 'Discard',
      cancelText: 'No',
      onOk: () => {
        modelManager.setValue(this.props.file, modelManager.getInitialValue(this.props.file));
      },
    });
  };

  handleToggleOutline = () => {
    this.setState(
      {
        showOutline: !this.state.showOutline,
      },
      () => {
        this.editor.layout();
        storage.local.setItem('noOutline', !this.state.showOutline);
      }
    );
  };

  render() {
    if (this.state.notFound) {
      return (

              {this.props.file}

File not found.

      );
    }
    const options = {
      selectOnLineNumbers: true,
      wrappingIndent: 'same',
    };
    const hasChange = this.hasChange();
    const { saveFilePending } = this.props;
    return (

        <OutlineResizer />

{this.props.file}

            {this.state.cursorPos.column && (

                Ln {this.state.cursorPos.lineNumber}, Col {this.state.cursorPos.column}

            )}
            <Tooltip
              overlayClassName="tooltip-no-arrow"
              title={

                  Beautify your code using prettier{' '}

                    ({/^Mac/.test(window.navigator.platform) ? 'Cmd' : 'Ctrl'}+B)

              }
            >
              <Button onClick={this.formatCode} size="small">
                <Icon type="menu-fold" />
              </Button>
            </Tooltip>
            {this.props.onRunTest && (
              <Button type="primary" onClick={this.handleRunTest} size="small">
                <Icon type="play-circle-o" /> Run test
              </Button>
            )}
            {hasChange &&
              !this.state.loadingFile && (
                <Tooltip
                  title={

                      Save{' '}

                        ({/^Mac/.test(window.navigator.platform) ? 'Cmd' : 'Ctrl'}+S)

                  }
                >
                  <Button
                    type="primary"
                    size="small"
                    loading={saveFilePending}
                    disabled={saveFilePending}
                    onClick={this.handleSave}
                  >
                    <Icon type="save" />
                  </Button>
                </Tooltip>
              )}
            {hasChange &&
              !this.state.loadingFile && (
                <Tooltip title="Discard changes">
                  <Button size="small" onClick={this.handleCancel} disabled={saveFilePending}>
                    <Icon type="close-circle" />
                  </Button>
                </Tooltip>
              )}
            {this.hasOutline() && (
              <Tooltip
                title={

                    Toggle Outline View{' '}

                      ({/^Mac/.test(window.navigator.platform) ? 'Cmd' : 'Ctrl'}+O)

                }
              >
                <Button size="small" onClick={this.handleToggleOutline}>
                  <Icon type="bars" />
                </Button>
              </Tooltip>
            )}

        {(this.state.loadingFile || this.state.loadingEditor) && (
          <div className="loading-container" style={{ marginRight: `${this.getOutlineWidth()}px` }}>
            <Spin size="large" />

        )}
        <div className="monaco-editor-container" style={{ marginRight: `${this.getOutlineWidth()}px` }}>
          <MonacoEditor
            file={this.props.file}
            options={options}
            onChange={this.handleEditorChange}
            editorDidMount={this.handleEditorDidMount}
          />

        {this.editor &&
          this.hasOutline() &&
          this.state.showOutline && (
            <OutlineView
              code={this.editor.getValue()}
              width={this.getOutlineWidth()}
              onSelectNode={this.handleOutlineSelect}
            />
          )}

    );
  }
}

/* istanbul ignore next */
function mapStateToProps(state) {
  return {
    // codeChange: state.home.codeChange,
    outlineWidth: state.home.outlineWidth,
    fileContentById: state.home.fileContentById,
    fileContentNeedReload: state.home.fileContentNeedReload,
    fetchFileContentPending: state.home.fetchFileContentPending,
    saveFilePending: state.home.saveFilePending,
  };
}

/* istanbul ignore next */
function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({ fetchFileContent, saveFile, codeChange, showDemoAlert, stickTab }, dispatch),
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(CodeEditor);
<commit_msg>Stick tab when code changed.<commit_after>/* eslint no-bitwise: 0, jsx-no-bind: 0 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import axios from 'axios';
import { Button, Icon, message, Modal, Spin, Tooltip } from 'antd';
import { MonacoEditor } from '../common';
import { fetchFileContent, saveFile, showDemoAlert, codeChange, stickTab } from './redux/actions';
import editorStateMap from './editorStateMap';
import modelManager from '../common/monaco/modelManager';
import { storage } from '../common/utils';
import { OutlineView, OutlineResizer } from '.';

export class CodeEditor extends Component {
  static propTypes = {
    outlineWidth: PropTypes.number.isRequired,
    fileContentById: PropTypes.object.isRequired,
    fileContentNeedReload: PropTypes.object.isRequired,
    fetchFileContentPending: PropTypes.bool.isRequired, // eslint-disable-line
    saveFilePending: PropTypes.bool.isRequired,
    actions: PropTypes.object.isRequired,
    file: PropTypes.string.isRequired,
    onError: PropTypes.func,
    onStateChange: PropTypes.func,
    onRunTest: PropTypes.func,
  };

  static defaultProps = {
    onError() {},
    onStateChange() {},
    onRunTest: null,
  };

  constructor(props) {
    super(props);
    // BIG magic here! When open/switch a new file, it will trigger cursor change first
    // which causes to save status. So if the file is new open, should not save its state
    // before recover the state. So when file is changed set this flag to true. After recover
    // the status, set it to false so that state could be saved.
    this.preventSaveEditorState = true;

    this.monacoListeners = [];
  }

  state = {
    notFound: false,
    loadingFile: false,
    loadingEditor: true,
    cursorPos: {
      lineNumber: 1,
      column: 1,
    },
    showOutline: !storage.local.getItem('noOutline'),
  };

  async componentWillMount() {
    this.setState({
      loadingFile: true,
    });
    await this.checkAndFetchFileContent(this.props);
    // Todo: check if conflict
    modelManager.setInitialValue(this.props.file, this.getFileContent(this.props.file), true);
    this.setState({
      // eslint-disable-line
      loadingFile: false,
    });
    this.props.onStateChange({ hasChange: false });
  }

  async componentWillReceiveProps(nextProps) {
    const { props } = this;
    if (props.file !== nextProps.file) {
      // When file is changed, prevent saving before its state is restored.
      this.preventSaveEditorState = true;
      this.setState(
        {
          loadingFile: true,
        },
        () => this.editor.layout()
      );
      await this.checkAndFetchFileContent(nextProps);
      // Todo: check if conflict
      modelManager.setInitialValue(nextProps.file, this.getFileContent(nextProps.file), true);
      this.preventSaveEditorState = false;
      this.recoverEditorState();
      this.setState({
        loadingFile: false,
      });
    } else if (nextProps.fileContentNeedReload[nextProps.file]) {
      const oldContent = this.getFileContent();
      const hasChange = this.hasChange(); // has changed
      await this.checkAndFetchFileContent(nextProps);
      modelManager.setInitialValue(nextProps.file, this.getFileContent(nextProps.file), true);
      this.setState({
        loadingFile: false,
      });
      const newContent = this.getFileContent();
      if (hasChange && oldContent !== newContent && newContent !== modelManager.getValue(nextProps.file)) {
        Modal.confirm({
          title: 'The file has changed on disk.',
          content: 'Do you want to reload it?',
          okText: 'Yes',
          cancelText: 'No',
          onOk: () => {
            modelManager.reset(nextProps.file);
          },
        });
      }
    }
  }

  componentWillUnmount() {
    this.monacoListeners.forEach(lis => lis.dispose());
  }

  getFileContent(filePath) {
    return this.props.fileContentById[filePath || this.props.file];
  }

  getOutlineWidth() {
    return this.hasOutline() && this.state.showOutline ? this.props.outlineWidth : 0;
  }

  hasOutline() {
    return this.props.file.split('.').pop() === 'js';
  }

  formatCode = () => {
    this.setState({ loadingFile: true });
    const lines = this.editor.getValue().split('\n');
    const { lineNumber, column } = this.editor.getPosition();
    const cursorOffset = lines.slice(0, lineNumber - 1).reduce((c, line) => c + line.length + 1, 0) + column - 1;

    axios
      .post('/rekit/api/format-code', {
        content: modelManager.getValue(this.props.file),
        file: this.props.file,
        cursorOffset,
      })
      .then(res => {
        if (res.data.error || !res.data.content.formatted) {
          this.setState({ loadingFile: false });
          return;
        }
        this.editor.executeEdits('format', [
          { range: new monaco.Range(1, 1, 1000000, 1), text: res.data.content.formatted, forceMoveMarkers: true },
        ]);
        const newCursorOffset = res.data.content.cursorOffset;
        const newLines = res.data.content.formatted.split('\n');
        let c = 0;
        let newLineNumber = 0;
        while (c + newLines[newLineNumber].length + 1 < newCursorOffset && newLineNumber < newLines.length) {
          c += newLines[newLineNumber].length + 1;
          newLineNumber += 1;
        }
        const col = newCursorOffset - c;
        this.editor.setPosition({ lineNumber: newLineNumber + 1, column: col + 1 });
        this.setState({
          loadingFile: false,
        });
      })
      .catch(() => {
        this.setState({
          loadingFile: false,
        });
      });
  };

  recoverEditorState = () => {
    if (!this.editor) return;
    const { file } = this.props;
    this.preventSaveEditorState = false;
    const editorState = editorStateMap[file] || null;
    this.editor.restoreViewState(editorState);
    this.editor.focus();
  };

  hasChange() {
    // Whether the editor content is different from which in store.
    return modelManager.isChanged(this.props.file);
    // return this.state.currentContent !== this.getFileContent();
  }

  checkAndFetchFileContent(props) {
    // Check if content exists or need reload, if yes then fetch it.
    const { fileContentById, fileContentNeedReload, fetchFileContentPending, file } = props;
    if ((!_.has(fileContentById, file) || fileContentNeedReload[file]) && !fetchFileContentPending) {
      return this.props.actions
        .fetchFileContent(props.file)
        .then(() => {
          this.setState({ notFound: false });
        })
        .catch(e => {
          message.error(`Failed to load file: ${e.toString()}`);
          if (_.get(e, 'response.status') === 404) {
            this.setState({ notFound: true, loadingFile: false });
            this.props.onError(404);
          }
        });
    } else {
      this.setState({ notFound: false });
      return Promise.resolve();
    }
  }

  handleEditorChange = () => {
    this.props.actions.stickTab();
    this.props.actions.codeChange();
  };

  handleOutlineSelect = nodeData => {
    if (nodeData.startLine && this.editor) {
      this.editor.setScrollTop(this.editor.getTopForLineNumber(nodeData.startLine));
    }
  };

  handleEditorDidMount = editor => {
    this.editor = editor;
    editor.focus();
    // This seems to be able to add multiple times.
    editor.addCommand([monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S], () => {
      this.handleSave();
    });
    editor.addCommand([monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_O], () => {
      this.handleToggleOutline();
    });
    editor.addCommand([monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_B], () => {
      this.formatCode();
    });
    this.monacoListeners.push(
      editor.onDidChangeCursorPosition(() => this.setState({ cursorPos: editor.getPosition() })),
      editor.onDidChangeCursorPosition(this.handleEditorCursorScrollerChange),
      editor.onDidScrollChange(this.handleEditorCursorScrollerChange)
    );
    this.setState({
      loadingEditor: false,
    });
    // // It needs some time for editor to load its content
    setTimeout(this.recoverEditorState, 30);
  };

  handleEditorCursorScrollerChange = () => {
    if (this.preventSaveEditorState) return;
    const { file } = this.props;

    editorStateMap[file] = this.editor.saveViewState();
  };

  handleRunTest = () => {
    this.props.onRunTest();
  };

  handleSave = () => {
    this.props.actions.stickTab();
    if (!this.hasChange()) return;
    this.props.actions
      .saveFile(this.props.file, this.editor.getValue())
      .then(() => {
        modelManager.setInitialValue(this.props.file, this.editor.getValue());
        this.props.actions.codeChange();
      })
      .catch(() => {
        if (process.env.REKIT_ENV === 'demo') {
          this.props.actions.showDemoAlert();
          return;
        }
        Modal.error({
          title: 'Failed to save.',
          content: 'Please retry or use other text editor.',
        });
      });
  };

  handleCancel = () => {
    Modal.confirm({
      content: 'Are you sure to discard your changes?',
      okText: 'Discard',
      cancelText: 'No',
      onOk: () => {
        modelManager.setValue(this.props.file, modelManager.getInitialValue(this.props.file));
      },
    });
  };

  handleToggleOutline = () => {
    this.setState(
      {
        showOutline: !this.state.showOutline,
      },
      () => {
        this.editor.layout();
        storage.local.setItem('noOutline', !this.state.showOutline);
      }
    );
  };

  render() {
    if (this.state.notFound) {
      return (

              {this.props.file}

File not found.

      );
    }
    const options = {
      selectOnLineNumbers: true,
      wrappingIndent: 'same',
    };
    const hasChange = this.hasChange();
    const { saveFilePending } = this.props;
    return (

        <OutlineResizer />

{this.props.file}

            {this.state.cursorPos.column && (

                Ln {this.state.cursorPos.lineNumber}, Col {this.state.cursorPos.column}

            )}
            <Tooltip
              overlayClassName="tooltip-no-arrow"
              title={

                  Beautify your code using prettier{' '}

                    ({/^Mac/.test(window.navigator.platform) ? 'Cmd' : 'Ctrl'}+B)

              }
            >
              <Button onClick={this.formatCode} size="small">
                <Icon type="menu-fold" />
              </Button>
            </Tooltip>
            {this.props.onRunTest && (
              <Button type="primary" onClick={this.handleRunTest} size="small">
                <Icon type="play-circle-o" /> Run test
              </Button>
            )}
            {hasChange &&
              !this.state.loadingFile && (
                <Tooltip
                  title={

                      Save{' '}

                        ({/^Mac/.test(window.navigator.platform) ? 'Cmd' : 'Ctrl'}+S)

                  }
                >
                  <Button
                    type="primary"
                    size="small"
                    loading={saveFilePending}
                    disabled={saveFilePending}
                    onClick={this.handleSave}
                  >
                    <Icon type="save" />
                  </Button>
                </Tooltip>
              )}
            {hasChange &&
              !this.state.loadingFile && (
                <Tooltip title="Discard changes">
                  <Button size="small" onClick={this.handleCancel} disabled={saveFilePending}>
                    <Icon type="close-circle" />
                  </Button>
                </Tooltip>
              )}
            {this.hasOutline() && (
              <Tooltip
                title={

                    Toggle Outline View{' '}

                      ({/^Mac/.test(window.navigator.platform) ? 'Cmd' : 'Ctrl'}+O)

                }
              >
                <Button size="small" onClick={this.handleToggleOutline}>
                  <Icon type="bars" />
                </Button>
              </Tooltip>
            )}

        {(this.state.loadingFile || this.state.loadingEditor) && (
          <div className="loading-container" style={{ marginRight: `${this.getOutlineWidth()}px` }}>
            <Spin size="large" />

        )}
        <div className="monaco-editor-container" style={{ marginRight: `${this.getOutlineWidth()}px` }}>
          <MonacoEditor
            file={this.props.file}
            options={options}
            onChange={this.handleEditorChange}
            editorDidMount={this.handleEditorDidMount}
          />

        {this.editor &&
          this.hasOutline() &&
          this.state.showOutline && (
            <OutlineView
              code={this.editor.getValue()}
              width={this.getOutlineWidth()}
              onSelectNode={this.handleOutlineSelect}
            />
          )}

    );
  }
}

/* istanbul ignore next */
function mapStateToProps(state) {
  return {
    // codeChange: state.home.codeChange,
    outlineWidth: state.home.outlineWidth,
    fileContentById: state.home.fileContentById,
    fileContentNeedReload: state.home.fileContentNeedReload,
    fetchFileContentPending: state.home.fetchFileContentPending,
    saveFilePending: state.home.saveFilePending,
  };
}

/* istanbul ignore next */
function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({ fetchFileContent, saveFile, codeChange, showDemoAlert, stickTab }, dispatch),
  };
}

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


<commit_before>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    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 Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * 2.2.15 RemoteHost
 *
 * This variable represents the source of inbound IP packets. This will be a wildcard in most cases
 * (i.e. an empty string). NAT vendors are only required to support wildcards. A non-wildcard value
 * will allow for “narrow” port mappings, which may be desirable in some usage scenarios.When
 * RemoteHost is a wildcard, all traffic sent to the ExternalPort on the WAN interface of the
 * gateway is forwarded to the InternalClient on the InternalPort. When RemoteHost is
 * specified as one external IP address as opposed to a wildcard, the NAT will only forward inbound
 * packets from this RemoteHost to the InternalClient, all other packets will be dropped.
 *
 * http://upnp.org/specs/gw/UPnP-gw-WANIPConnection-v1-Service.pdf
 */

'use strict';
const log = require('../net2/logger.js')(__filename);

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

const sem = require('../sensor/SensorEventManager.js').getInstance();

const rclient = require('../util/redis_manager.js').getRedisClient()

const UPNP = require('../extension/upnp/upnp.js');
const upnp = new UPNP();

const cfg = require('../net2/config.js');

const SysManager = require('../net2/SysManager.js');
const sysManager = new SysManager('info');

const Alarm = require('../alarm/Alarm.js');
const AM2 = require('../alarm/AlarmManager2.js');
const am2 = new AM2();

const _ = require('lodash');

const ALARM_UPNP = 'alarm_upnp';

function compareUpnp(a, b) {
  return a.public && b.public &&
         a.private && b.private &&
         a.public.port  == b.public.port &&
         a.private.host == b.private.host &&
         a.private.port == b.private.port &&
         a.protocol     == b.protocol;
}

class UPNPSensor extends Sensor {
  constructor() {
    super();
  }

  isExpired(mapping) {
    const expireInterval = this.config.expireInterval || 3600; // one hour by default
    return mapping.expire && mapping.expire < (Math.floor(new Date() / 1000) - expireInterval);
  }

  mergeResults(curMappings, preMappings) {

    curMappings.forEach((mapping) => {
      mapping.expire = Math.floor(new Date() / 1000);
    });

    const fullMappings = [...curMappings, ...preMappings];

    const uniqMappings = _.uniqWith(fullMappings, compareUpnp);

    return uniqMappings
      .filter((mapping) => !this.isExpired(mapping));
  }

  run() {
    setInterval(() => {
      upnp.getPortMappingsUPNP(async (err, results) => {
        if (err) {
          log.error("Error getting mappings", err);
        }

        if (!results) {
          results = []
          log.info("No upnp mapping found in network");
        }

        const key = "sys:scan:nat";

        try {
          let entries = await rclient.hgetAsync(key, 'upnp');
          let preMappings = JSON.parse(entries) || [];

          const mergedResults = this.mergeResults(results, preMappings);

          if (cfg.isFeatureOn(ALARM_UPNP)) {
            for (let current of mergedResults) {
              let firewallaRegistered =
                current.private.host == sysManager.myIp() &&
                upnp.getRegisteredUpnpMappings().some( m => upnp.mappingCompare(current, m) );

              if (
                !firewallaRegistered &&
                !preMappings.some(pre => compareUpnp(current, pre))
              ) {
                let alarm = new Alarm.UpnpAlarm(
                  new Date() / 1000,
                  current.private.host,
                  {
                    'p.source': 'UPNPSensor',
                    'p.device.ip': current.private.host,
                    'p.upnp.public.host'  : current.public.host,
                    'p.upnp.public.port'  : current.public.port,
                    'p.upnp.private.host' : current.private.host,
                    'p.upnp.private.port' : current.private.port,
                    'p.upnp.protocol'     : current.protocol,
                    'p.upnp.enabled'      : current.enabled,
                    'p.upnp.description'  : current.description,
                    'p.upnp.ttl'          : current.ttl,
                    'p.upnp.local'        : current.local,
                    'p.device.port': current.private.port,
                    'p.protocol': current.protocol
                  }
                );

                await am2.enqueueAlarm(alarm);
              }
            }
          }

          if (await rclient.hmsetAsync(key, {upnp: JSON.stringify(mergedResults)} ))
            log.info("UPNP mapping is updated,", mergedResults.length, "entries");

        } catch(err) {
          log.error("Failed to scan upnp mapping: " + err);
        }
      });
    }, this.config.interval * 1000 || 60 * 10 * 1000); // default to 10 minutes
  }
}

module.exports = UPNPSensor;
<commit_msg>fix upnp exception bug<commit_after>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    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 Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * 2.2.15 RemoteHost
 *
 * This variable represents the source of inbound IP packets. This will be a wildcard in most cases
 * (i.e. an empty string). NAT vendors are only required to support wildcards. A non-wildcard value
 * will allow for “narrow” port mappings, which may be desirable in some usage scenarios.When
 * RemoteHost is a wildcard, all traffic sent to the ExternalPort on the WAN interface of the
 * gateway is forwarded to the InternalClient on the InternalPort. When RemoteHost is
 * specified as one external IP address as opposed to a wildcard, the NAT will only forward inbound
 * packets from this RemoteHost to the InternalClient, all other packets will be dropped.
 *
 * http://upnp.org/specs/gw/UPnP-gw-WANIPConnection-v1-Service.pdf
 */

'use strict';
const log = require('../net2/logger.js')(__filename);

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

const sem = require('../sensor/SensorEventManager.js').getInstance();

const rclient = require('../util/redis_manager.js').getRedisClient()

const UPNP = require('../extension/upnp/upnp.js');
const upnp = new UPNP();

const cfg = require('../net2/config.js');

const SysManager = require('../net2/SysManager.js');
const sysManager = new SysManager('info');

const Alarm = require('../alarm/Alarm.js');
const AM2 = require('../alarm/AlarmManager2.js');
const am2 = new AM2();

const _ = require('lodash');

const ALARM_UPNP = 'alarm_upnp';

function compareUpnp(a, b) {
  return a.public && b.public &&
         a.private && b.private &&
         a.public.port  == b.public.port &&
         a.private.host == b.private.host &&
         a.private.port == b.private.port &&
         a.protocol     == b.protocol;
}

class UPNPSensor extends Sensor {
  constructor() {
    super();
  }

  isExpired(mapping) {
    const expireInterval = this.config.expireInterval || 3600; // one hour by default
    return mapping.expire && mapping.expire < (Math.floor(new Date() / 1000) - expireInterval);
  }

  mergeResults(curMappings, preMappings) {

    curMappings.forEach((mapping) => {
      mapping.expire = Math.floor(new Date() / 1000);
    });

    const fullMappings = [...curMappings, ...preMappings];

    const uniqMappings = _.uniqWith(fullMappings, compareUpnp);

    return uniqMappings
      .filter((mapping) => !this.isExpired(mapping));
  }

  run() {
    setInterval(() => {
      upnp.getPortMappingsUPNP(async (err, results) => {
        if (err) {
          log.error("Error getting mappings", err);
        }

        if (!results) {
          results = []
          log.info("No upnp mapping found in network");
        }

        const key = "sys:scan:nat";

        try {
          let entries = await rclient.hgetAsync(key, 'upnp');
          let preMappings = JSON.parse(entries) || [];

          const mergedResults = this.mergeResults(results, preMappings);

          if (cfg.isFeatureOn(ALARM_UPNP)) {
            for (let current of mergedResults) {
              let firewallaRegistered =
                current.private.host == sysManager.myIp() &&
                upnp.getRegisteredUpnpMappings().some( m => upnp.mappingCompare(current, m) );

              if (
                !firewallaRegistered &&
                !preMappings.some(pre => compareUpnp(current, pre))
              ) {
                let alarm = new Alarm.UpnpAlarm(
                  new Date() / 1000,
                  current.private.host,
                  {
                    'p.source': 'UPNPSensor',
                    'p.device.ip': current.private.host,
                    'p.upnp.public.host'  : current.public.host,
                    'p.upnp.public.port'  : current.public.port.toString(),
                    'p.upnp.private.host' : current.private.host,
                    'p.upnp.private.port' : current.private.port.toString(),
                    'p.upnp.protocol'     : current.protocol,
                    'p.upnp.enabled'      : current.enabled.toString(),
                    'p.upnp.description'  : current.description,
                    'p.upnp.ttl'          : current.ttl.toString(),
                    'p.upnp.local'        : current.local.toString(),
                    'p.device.port': current.private.port.toString(),
                    'p.protocol': current.protocol
                  }
                );

                await am2.enqueueAlarm(alarm);
              }
            }
          }

          if (await rclient.hmsetAsync(key, {upnp: JSON.stringify(mergedResults)} ))
            log.info("UPNP mapping is updated,", mergedResults.length, "entries");

        } catch(err) {
          log.error("Failed to scan upnp mapping: " + err);
        }
      });
    }, this.config.interval * 1000 || 60 * 10 * 1000); // default to 10 minutes
  }
}

module.exports = UPNPSensor;
<|endoftext|>


<commit_before>/*
 *   Renderer object responsible for drawing gama objects on the canvas.
 */
function Renderer(width, height) {

    this.width = width;
    this.height = height;

    var canvas = document.createElement('canvas');
    canvas.setAttribute('id', 'drawing');
    canvas.setAttribute('width', width.toString());
    canvas.setAttribute('height', height.toString());

    document.body.appendChild(canvas);

    this.ctx = canvas.getContext('2d');

    // this.myCanvas = new MyCanvas(this.ctx);
}

/*
 *   Draws all objects.
 */
Renderer.prototype.drawAll = function (blaze, eggman) {
    this.ctx.clearRect(0, 0, this.width, this.height);
    _drawBlaze(this.ctx, blaze);
    _drawClip(this.ctx, blaze);

    if (eggman) {
        _drawEggman(this.ctx, eggman);
    }
};

/*
 *   Draws Blaze.
 */
function _drawBlaze(context, blaze) {

    var LINE_LENGTH = 30;
    var RADIUS_1 = 20;
    var RADIUS_2 = 10;
    var centerX = blaze.position.x;
    var centerY = blaze.position.y;

    var point1X = centerX + LINE_LENGTH;
    var point1Y = centerY;

    var point2X = centerX - LINE_LENGTH;
    var point2Y = centerY;

    var point3X = centerX;
    var point3Y = centerY + LINE_LENGTH;
    var point4X = centerX;
    var point4Y = centerY - LINE_LENGTH;

    context.beginPath();
    context.moveTo(point1X, point1Y);
    context.lineTo(point2X, point2Y);
    context.moveTo(point3X, point3Y);
    context.lineTo(point4X, point4Y);
    context.moveTo(centerX, centerY);
    context.arc(centerX, centerY, RADIUS_1, 0, 2 * Math.PI, false);
    context.moveTo(centerX, centerY);
    context.arc(centerX, centerY, RADIUS_2, 0, 2 * Math.PI, false);
    context.strokeStyle = 'red';
    context.stroke();
}

//Draws Bullets // TODO: add global consts and change here.
function _drawClip(context, blaze) {
    var BULLET_WIDHT = 20,
        BULLET_HEIGHT = 30,
        SPACING = 5,
        sx = 20,
        sy = context.canvas.height - BULLET_HEIGHT - 10,
        bulletsCount = blaze.getBulletsCount();

    context.beginPath();
    for (var i = 0; i < bulletsCount; i+=1) {
        context.moveTo(sx, sy);
        context.strokeRect(sx, sy, BULLET_WIDHT, BULLET_HEIGHT);
        sx = sx + BULLET_WIDHT + SPACING;
    };
    context.stroke();
}

/*
 *   Draws Eggman.
 */
function _drawEggman(context, eggman) {

    var eggmanTopLeftX = eggman.position.x;
    var eggmanTopLeftY = eggman.position.y;
    context.strokeStyle = 'green';
    context.strokeRect(eggmanTopLeftX, eggmanTopLeftY, eggman.width, eggman.height);
}
<commit_msg>Removed empty lines.<commit_after>/*
 *   Renderer object responsible for drawing gama objects on the canvas.
 */
function Renderer(width, height) {

    this.width = width;
    this.height = height;

    var canvas = document.createElement('canvas');
    canvas.setAttribute('id', 'drawing');
    canvas.setAttribute('width', width.toString());
    canvas.setAttribute('height', height.toString());

    document.body.appendChild(canvas);

    this.ctx = canvas.getContext('2d');

    // this.myCanvas = new MyCanvas(this.ctx);
}

/*
 *   Draws all objects.
 */
Renderer.prototype.drawAll = function (blaze, eggman) {
    this.ctx.clearRect(0, 0, this.width, this.height);
    _drawBlaze(this.ctx, blaze);
    _drawClip(this.ctx, blaze);

    if (eggman) {
        _drawEggman(this.ctx, eggman);
    }
};

/*
 *   Draws Blaze.
 */
function _drawBlaze(context, blaze) {

    var LINE_LENGTH = 30;
    var RADIUS_1 = 20;
    var RADIUS_2 = 10;
    var centerX = blaze.position.x;
    var centerY = blaze.position.y;

    var point1X = centerX + LINE_LENGTH;
    var point1Y = centerY;

    var point2X = centerX - LINE_LENGTH;
    var point2Y = centerY;

    var point3X = centerX;
    var point3Y = centerY + LINE_LENGTH;
    var point4X = centerX;
    var point4Y = centerY - LINE_LENGTH;

    context.beginPath();
    context.moveTo(point1X, point1Y);
    context.lineTo(point2X, point2Y);
    context.moveTo(point3X, point3Y);
    context.lineTo(point4X, point4Y);
    context.moveTo(centerX, centerY);
    context.arc(centerX, centerY, RADIUS_1, 0, 2 * Math.PI, false);
    context.moveTo(centerX, centerY);
    context.arc(centerX, centerY, RADIUS_2, 0, 2 * Math.PI, false);
    context.strokeStyle = 'red';
    context.stroke();
}

//Draws Bullets // TODO: add global consts and change here.
function _drawClip(context, blaze) {
    var BULLET_WIDHT = 20,
        BULLET_HEIGHT = 30,
        SPACING = 5,
        sx = 20,
        sy = context.canvas.height - BULLET_HEIGHT - 10,
        bulletsCount = blaze.getBulletsCount();

    context.beginPath();
    for (var i = 0; i < bulletsCount; i+=1) {
        context.moveTo(sx, sy);
        context.strokeRect(sx, sy, BULLET_WIDHT, BULLET_HEIGHT);
        sx = sx + BULLET_WIDHT + SPACING;
    };
    context.stroke();
}

/*
 *   Draws Eggman.
 */
function _drawEggman(context, eggman) {

    var eggmanTopLeftX = eggman.position.x;
    var eggmanTopLeftY = eggman.position.y;
    context.strokeStyle = 'green';
    context.strokeRect(eggmanTopLeftX, eggmanTopLeftY, eggman.width, eggman.height);
}<|endoftext|>


<commit_before>function generateDashboard(data,geom){
    var map = new lg.map('#map').geojson(geom).joinAttr('Iso_Code').zoom(3).center([53.5,20]);

    var medCol = new lg.column('Medical Interventions').domain([0,1]).axisLabels(false).valueAccessor(function(d){
        if(d=='Yes' || d== 'No'){
            return 1;
        } else {
            return null;
        }
    })
    .colorAccessor(function(d,i,max){
        if(d=='Yes'){
            return 1;
        } else {
            return 0;
        }
    })
    .colors(['#bd0026','#2E7D32']);

    var longSheltCol = new lg.column('Long-Term Shelter Support').domain([0,1]).axisLabels(false).valueAccessor(function(d){
        if(d=='Yes' || d== 'No'){
            return 1;
        } else {
            return null;
        }
    })
    .colorAccessor(function(d,i,max){
        if(d=='Yes'){
            return 1;
        } else {
            return 0;
        }
    })
    .colors(['#bd0026','#2E7D32']);

    var grid = new lg.grid('#grid')
        .data(data)
        .width($('#grid').width())
        .height(500)
        .nameAttr('Country')
        .joinAttr('ISO 3 code')
        .hWhiteSpace(10)
        .vWhiteSpace(5)
        .columns(['Total Migrants','Active Staff','Active Volunteers','Bilateral Volunteers','Surge Volunteers','Active Locations','Beneficiaries This Week','Total Beneficiary Contacts','Women and Children Benificiaries','Water Bottle Dist','Food Parcel Dist','Hygiene Kit Dist',medCol,'RFL Initatiated 2015','RFL Completed 2015',longSheltCol,'Host communities supported'])
        .margins({top: 150, right: 105, bottom: 20, left: 140});
    lg.colors(['#ffffb2','#fecc5c','#fd8d3c','#f03b20','#bd0026']);
    lg.init();

    $("#map").width($("#map").width());
}

function hxlProxyToJSON(input,headers){
    var output = [];
    var keys=[]
    input.forEach(function(e,i){
        if(headers==true && i==0){
            keys = e;
        } else if(headers==true && i>1) {
            var row = {};
            e.forEach(function(e2,i2){
                row[keys[i2]] = e2;
            });
            output.push(row);
        } else if(headers!=true){
            var row = {};
            e.forEach(function(e2,i2){
                row[keys[i2]] = e2;
            });
            output.push(row);

        }
    });
    return output;
}

function generateStats(id,data){
	var formatComma = d3.format(",.0f");
	var formatPerc = d3.format(",.1%");
	totalMigrants = 0;
	totalBeneficiaries = 0;

	for(var i = 0; i < data.length; i++) {
		numMigrants = parseInt(data[i]["Total Migrants"]);
		numBeneficiaries = parseInt(data[i]["Total Beneficiary Contacts"]);
		if (!isNaN(numMigrants)) {
			totalMigrants += numMigrants;
		};
		if (!isNaN(numBeneficiaries)) {
			totalBeneficiaries += numBeneficiaries;
		};
	};

    var html = '';
    html = html + '
Total Migrants in Europe

'+ formatComma(totalMigrants) + '
';
    html = html + '
Total Beneficiary Contacts

'+ formatComma(totalBeneficiaries) + '

   (' + formatPerc(totalBeneficiaries/totalMigrants) + ')';
    html = html + '
';
    $(id).html(html);
}

/*
function stickydiv(){
    var window_top = $(window).scrollTop();
    var div_top = $('#sticky-anchor').offset().top;
    if (window_top > div_top){
        $('#map-container').addClass('sticky');
    }
    else{
        $('#map-container').removeClass('sticky');
    }
};

$(window).scroll(function(){
    stickydiv();
});
*/

//load data

// WITH THE FORCE...
var dataCall = $.ajax({
    type: 'GET',
    url: 'http://proxy.hxlstandard.org/data.json?filter01=replace-map&replace-map-url01=https%3A//docs.google.com/spreadsheets/d/12TdWAO9BmavBkGEM-7hPV7IMjN_EOJY_2iGnW_ezjuk/pub%3Fgid%3D493036357%26single%3Dtrue%26output%3Dcsv&filter02=merge&merge-url02=https%3A//docs.google.com/spreadsheets/d/12TdWAO9BmavBkGEM-7hPV7IMjN_EOJY_2iGnW_ezjuk/pub%3Fgid%3D0%26single%3Dtrue%26output%3Dcsv&merge-tags02=%23country%2Bcode&merge-keys02=%23country-code&force=on&url=https%3A//docs.google.com/spreadsheets/d/17UV2Zqkz6YDWIEgzT16_XCMLE7_VXjo7U-Wme01fnXQ/edit%3Fusp%3Ddrive_web',
    dataType: 'json',
});

// WITHOUT THE FORCE...
var dataCall = $.ajax({
    type: 'GET',
    url: 'http://proxy.hxlstandard.org/data.json?filter01=replace-map&replace-map-url01=https%3A//docs.google.com/spreadsheets/d/12TdWAO9BmavBkGEM-7hPV7IMjN_EOJY_2iGnW_ezjuk/pub%3Fgid%3D493036357%26single%3Dtrue%26output%3Dcsv&filter02=merge&merge-url02=https%3A//docs.google.com/spreadsheets/d/12TdWAO9BmavBkGEM-7hPV7IMjN_EOJY_2iGnW_ezjuk/pub%3Fgid%3D0%26single%3Dtrue%26output%3Dcsv&merge-tags02=%23country%2Bcode&merge-keys02=%23country-code&url=https%3A//docs.google.com/spreadsheets/d/17UV2Zqkz6YDWIEgzT16_XCMLE7_VXjo7U-Wme01fnXQ/edit%3Fusp%3Ddrive_web',
    dataType: 'json',
});

//load geometry

var geomCall = $.ajax({
    type: 'GET',
    url: 'data/geom.json',
    dataType: 'json',
});

//when both ready construct dashboard

$.when(dataCall, geomCall).then(function(dataArgs, geomArgs){
    var geom = topojson.feature(geomArgs[0],geomArgs[0].objects.geom);
    console.log(geom);
    var data = hxlProxyToJSON(dataArgs[0],true);
    console.log(data);
    generateDashboard(data,geom);
	generateStats("#key_stats",data);
});
<commit_msg>Update to https<commit_after>function generateDashboard(data,geom){
    var map = new lg.map('#map').geojson(geom).joinAttr('Iso_Code').zoom(3).center([53.5,20]);

    var medCol = new lg.column('Medical Interventions').domain([0,1]).axisLabels(false).valueAccessor(function(d){
        if(d=='Yes' || d== 'No'){
            return 1;
        } else {
            return null;
        }
    })
    .colorAccessor(function(d,i,max){
        if(d=='Yes'){
            return 1;
        } else {
            return 0;
        }
    })
    .colors(['#bd0026','#2E7D32']);

    var longSheltCol = new lg.column('Long-Term Shelter Support').domain([0,1]).axisLabels(false).valueAccessor(function(d){
        if(d=='Yes' || d== 'No'){
            return 1;
        } else {
            return null;
        }
    })
    .colorAccessor(function(d,i,max){
        if(d=='Yes'){
            return 1;
        } else {
            return 0;
        }
    })
    .colors(['#bd0026','#2E7D32']);

    var grid = new lg.grid('#grid')
        .data(data)
        .width($('#grid').width())
        .height(500)
        .nameAttr('Country')
        .joinAttr('ISO 3 code')
        .hWhiteSpace(10)
        .vWhiteSpace(5)
        .columns(['Total Migrants','Active Staff','Active Volunteers','Bilateral Volunteers','Surge Volunteers','Active Locations','Beneficiaries This Week','Total Beneficiary Contacts','Women and Children Benificiaries','Water Bottle Dist','Food Parcel Dist','Hygiene Kit Dist',medCol,'RFL Initatiated 2015','RFL Completed 2015',longSheltCol,'Host communities supported'])
        .margins({top: 150, right: 105, bottom: 20, left: 140});
    lg.colors(['#ffffb2','#fecc5c','#fd8d3c','#f03b20','#bd0026']);
    lg.init();

    $("#map").width($("#map").width());
}

function hxlProxyToJSON(input,headers){
    var output = [];
    var keys=[]
    input.forEach(function(e,i){
        if(headers==true && i==0){
            keys = e;
        } else if(headers==true && i>1) {
            var row = {};
            e.forEach(function(e2,i2){
                row[keys[i2]] = e2;
            });
            output.push(row);
        } else if(headers!=true){
            var row = {};
            e.forEach(function(e2,i2){
                row[keys[i2]] = e2;
            });
            output.push(row);

        }
    });
    return output;
}

function generateStats(id,data){
	var formatComma = d3.format(",.0f");
	var formatPerc = d3.format(",.1%");
	totalMigrants = 0;
	totalBeneficiaries = 0;

	for(var i = 0; i < data.length; i++) {
		numMigrants = parseInt(data[i]["Total Migrants"]);
		numBeneficiaries = parseInt(data[i]["Total Beneficiary Contacts"]);
		if (!isNaN(numMigrants)) {
			totalMigrants += numMigrants;
		};
		if (!isNaN(numBeneficiaries)) {
			totalBeneficiaries += numBeneficiaries;
		};
	};

    var html = '';
    html = html + '
Total Migrants in Europe

'+ formatComma(totalMigrants) + '
';
    html = html + '
Total Beneficiary Contacts

'+ formatComma(totalBeneficiaries) + '

   (' + formatPerc(totalBeneficiaries/totalMigrants) + ')';
    html = html + '
';
    $(id).html(html);
}

/*
function stickydiv(){
    var window_top = $(window).scrollTop();
    var div_top = $('#sticky-anchor').offset().top;
    if (window_top > div_top){
        $('#map-container').addClass('sticky');
    }
    else{
        $('#map-container').removeClass('sticky');
    }
};

$(window).scroll(function(){
    stickydiv();
});
*/

//load data

// WITH THE FORCE...
var dataCall = $.ajax({
    type: 'GET',
    url: 'https://proxy.hxlstandard.org/data.json?filter01=replace-map&replace-map-url01=https%3A//docs.google.com/spreadsheets/d/12TdWAO9BmavBkGEM-7hPV7IMjN_EOJY_2iGnW_ezjuk/pub%3Fgid%3D493036357%26single%3Dtrue%26output%3Dcsv&filter02=merge&merge-url02=https%3A//docs.google.com/spreadsheets/d/12TdWAO9BmavBkGEM-7hPV7IMjN_EOJY_2iGnW_ezjuk/pub%3Fgid%3D0%26single%3Dtrue%26output%3Dcsv&merge-tags02=%23country%2Bcode&merge-keys02=%23country-code&force=on&url=https%3A//docs.google.com/spreadsheets/d/17UV2Zqkz6YDWIEgzT16_XCMLE7_VXjo7U-Wme01fnXQ/edit%3Fusp%3Ddrive_web',
    dataType: 'json',
});

// WITHOUT THE FORCE...
var dataCall = $.ajax({
    type: 'GET',
    url: 'https://proxy.hxlstandard.org/data.json?filter01=replace-map&replace-map-url01=https%3A//docs.google.com/spreadsheets/d/12TdWAO9BmavBkGEM-7hPV7IMjN_EOJY_2iGnW_ezjuk/pub%3Fgid%3D493036357%26single%3Dtrue%26output%3Dcsv&filter02=merge&merge-url02=https%3A//docs.google.com/spreadsheets/d/12TdWAO9BmavBkGEM-7hPV7IMjN_EOJY_2iGnW_ezjuk/pub%3Fgid%3D0%26single%3Dtrue%26output%3Dcsv&merge-tags02=%23country%2Bcode&merge-keys02=%23country-code&url=https%3A//docs.google.com/spreadsheets/d/17UV2Zqkz6YDWIEgzT16_XCMLE7_VXjo7U-Wme01fnXQ/edit%3Fusp%3Ddrive_web',
    dataType: 'json',
});

//load geometry

var geomCall = $.ajax({
    type: 'GET',
    url: 'data/geom.json',
    dataType: 'json',
});

//when both ready construct dashboard

$.when(dataCall, geomCall).then(function(dataArgs, geomArgs){
    var geom = topojson.feature(geomArgs[0],geomArgs[0].objects.geom);
    console.log(geom);
    var data = hxlProxyToJSON(dataArgs[0],true);
    console.log(data);
    generateDashboard(data,geom);
	generateStats("#key_stats",data);
});
<|endoftext|>


<commit_before>const Profile = require('../models/profile');

const profileController = {
    getProfile: (req,res)=>{
        Profile.getInfo(req.user.id).then(data=>{
            res.json(data);
        })
    }
}

module.exports = profileController;<commit_msg>add controller for CreateProfile<commit_after>const Profile = require('../models/profile');

const profileController = {
    getProfile: (req,res)=>{
        Profile.getInfo(req.user.id).then(data=>{
            console.log(data);
            console.log('hello');
            res.json(data);
        });
    },
    createProfile: (req,res) => {
        Profile.setInfo({
            age: req.body.age,
            class: req.body.class,
            cohort: req.body.cohort,
            interest : req.body.interest,
            location : req.body.location,
            bio : req.body.bio,
            pic : req.body.picture_url
        }).then(data=>{
                console.log(data);
                res.send(data);
            }).catch(err=>{
                console.log(err);
                res.send(err);
            });
    }
}

module.exports = profileController;<|endoftext|>


<commit_before>import {AdjacencyList} from './adjacency_list';

export function connectedComponents(graph) {
    if (graph.directed) {
        throw new Error('This algorithm only supports undirected graphs');
    }

    let list = new AdjacencyList(graph);

    let currentComponent = 0;
    let components = new Array(list.a.length);

    for (let x = 0; x < list.a.length; x++) {
        if (!isNaN(components[x])) {
            // This vertex has already been processed.
            continue;
        }

        // Mark this vertex and all connected vertices with the current component number.
        components[x] = currentComponent;
        list.depthFirstSearch(x, y => {
            components[y] = currentComponent;
        });

        currentComponent++;
    }

    return components;
}
<commit_msg>[connected_components/javascript] Remove redundant line<commit_after>import {AdjacencyList} from './adjacency_list';

export function connectedComponents(graph) {
    if (graph.directed) {
        throw new Error('This algorithm only supports undirected graphs');
    }

    let list = new AdjacencyList(graph);

    let currentComponent = 0;
    let components = new Array(list.a.length);

    for (let x = 0; x < list.a.length; x++) {
        if (!isNaN(components[x])) {
            // This vertex has already been processed.
            continue;
        }

        // Mark this vertex and all connected vertices with the current component number.
        list.depthFirstSearch(x, y => {
            components[y] = currentComponent;
        });

        currentComponent++;
    }

    return components;
}
<|endoftext|>


<commit_before>"use strict";

define([], function () {

    var DiagramDesignerWidgetZoom;

    DiagramDesignerWidgetZoom = function () {
    };

    DiagramDesignerWidgetZoom.prototype._initZoom = function (params) {
        this._zoomValues = params.zoomValues || DEFAULT_ZOOM_VALUES;
        if (this._zoomValues.indexOf(1) === -1) {
            this._zoomValues.push(1);
        }
        this._zoomValues.sort();
        this._zoomLevelMin = 0;
        this._zoomLevelMax = this._zoomValues.length - 1;
        this._zoomLevel = this._zoomValues.indexOf(1);

        if (params.zoomUIControls === true) {
            this._initZoomUIControl();
        }

        //add zoom level UI and handlers
        this._addZoomMouseHandler(this.$el);
    };

    DiagramDesignerWidgetZoom.prototype._initZoomUIControl = function () {
        var self = this;

        //zoom
        this._zoomSlider = $('
', {'class': 'diagram-designer-zoom'});
        this.$el.parent().append(this._zoomSlider);

        this._zoomSlider.slider({
            orientation: "vertical",
            min: this._zoomLevelMin,
            max: this._zoomLevelMax,
            value: this._zoomLevel,
            slide: function( event, ui ) {
                self._setZoomLevel(ui.value);
            }
        });

        this._zoomSlider.find('.ui-slider-handle').html('');

        this._zoomLabel = $('
', {'class': 'diagram-designer-zoom-label'});

        this._zoomSlider.find('.ui-slider-handle').append(this._zoomLabel);

        this.setZoom(this._zoomRatio);
    };

    DiagramDesignerWidgetZoom.prototype._setZoomLevel = function (val) {
        if (val >= this._zoomLevelMin && val <= this._zoomLevelMax) {
            if (this._zoomLevel !== val) {
                this._zoomLevel = val;
                this.setZoom(this._zoomValues[this._zoomLevel]);
            }
        }
    };

    DiagramDesignerWidgetZoom.prototype.setZoom = function (val) {
        this._zoomRatio = val;

        this.skinParts.$itemsContainer.css({'transform-origin': '0 0',
            'transform': 'scale('+ this._zoomRatio + ', ' + this._zoomRatio + ')'});

        if (this._zoomLabel) {
            this._zoomLabel.text( this._zoomRatio + "x" );
        }

        if (this._zoomSlider) {
            this._zoomLevel = this._zoomValues.indexOf(this._zoomRatio);
            if (this._zoomLevel === -1) {
                //get the value which is closest to the selected zoomRatio
                this._zoomLevel = 0;
                while (this._zoomLevel <= this._zoomLevelMax && this._zoomValues[this._zoomLevel] <= this._zoomRatio) {
                    this._zoomLevel += 1;
                }
            }

            this._zoomSlider.slider( "option", "value", this._zoomLevel );
        }

        this._resizeItemContainer();
    };

    DiagramDesignerWidgetZoom.prototype.getZoom = function () {
        return this._zoomRatio;
    };

    DiagramDesignerWidgetZoom.prototype.zoomIn = function () {
        this._setZoomLevel(this._zoomLevel + 1);
    };

    DiagramDesignerWidgetZoom.prototype.zoomOut = function () {
        this._setZoomLevel(this._zoomLevel - 1);
    };

    DiagramDesignerWidgetZoom.prototype._addZoomMouseHandler = function (el) {
        var self = this;

        //IE, Chrome, etc
        el.on('mousewheel', function (event){
            var org = event.originalEvent;

            if (org &&  (org.ctrlKey || org.metaKey || org.altKey)) {
                //CTRL + mouse scroll
                if (org.wheelDelta < 0) {
                    self.zoomOut();
                } else {
                    self.zoomIn();
                }

                event.stopPropagation();
                event.preventDefault();
            }
        });

        //FIREFOX
        el.on('DOMMouseScroll', function (event){
            var org = event.originalEvent;

            if (org && (org.ctrlKey || org.metaKey || org.altKey)) {
                //CTRL + mouse scroll
                if (org.detail > 0) {
                    self.zoomOut();
                } else {
                    self.zoomIn();
                }

                event.stopPropagation();
                event.preventDefault();
            }
        });
    };

    return DiagramDesignerWidgetZoom;
});
<commit_msg>doubleclick on zoom-slider to reset zoom to 100%<commit_after>"use strict";

define([], function () {

    var DiagramDesignerWidgetZoom;

    DiagramDesignerWidgetZoom = function () {
    };

    DiagramDesignerWidgetZoom.prototype._initZoom = function (params) {
        this._zoomValues = params.zoomValues || DEFAULT_ZOOM_VALUES;
        if (this._zoomValues.indexOf(1) === -1) {
            this._zoomValues.push(1);
        }
        this._zoomValues.sort();
        this._zoomLevelMin = 0;
        this._zoomLevelMax = this._zoomValues.length - 1;
        this._zoomLevel = this._zoomValues.indexOf(1);

        if (params.zoomUIControls === true) {
            this._initZoomUIControl();
        }

        //add zoom level UI and handlers
        this._addZoomMouseHandler(this.$el);
    };

    DiagramDesignerWidgetZoom.prototype._initZoomUIControl = function () {
        var self = this;

        //zoom
        this._zoomSlider = $('
', {'class': 'diagram-designer-zoom'});
        this.$el.parent().append(this._zoomSlider);

        this._zoomSlider.slider({
            orientation: "vertical",
            min: this._zoomLevelMin,
            max: this._zoomLevelMax,
            value: this._zoomLevel,
            slide: function( event, ui ) {
                self._setZoomLevel(ui.value);
            }
        });

        this._zoomSlider.find('.ui-slider-handle').html('');

        this._zoomLabel = $('
', {'class': 'diagram-designer-zoom-label'});

        this._zoomSlider.find('.ui-slider-handle').append(this._zoomLabel);

        this.setZoom(this._zoomRatio);

        this._zoomSlider.find('.ui-slider-handle').on('dblclick', function (event) {
            self.setZoom(1);
            event.stopPropagation();
            event.preventDefault();
        });
    };

    DiagramDesignerWidgetZoom.prototype._setZoomLevel = function (val) {
        if (val >= this._zoomLevelMin && val <= this._zoomLevelMax) {
            if (this._zoomLevel !== val) {
                this._zoomLevel = val;
                this.setZoom(this._zoomValues[this._zoomLevel]);
            }
        }
    };

    DiagramDesignerWidgetZoom.prototype.setZoom = function (val) {
        this._zoomRatio = val;

        this.skinParts.$itemsContainer.css({'transform-origin': '0 0',
            'transform': 'scale('+ this._zoomRatio + ', ' + this._zoomRatio + ')'});

        if (this._zoomLabel) {
            this._zoomLabel.text( this._zoomRatio + "x" );
        }

        if (this._zoomSlider) {
            this._zoomLevel = this._zoomValues.indexOf(this._zoomRatio);
            if (this._zoomLevel === -1) {
                //get the value which is closest to the selected zoomRatio
                this._zoomLevel = 0;
                while (this._zoomLevel <= this._zoomLevelMax && this._zoomValues[this._zoomLevel] <= this._zoomRatio) {
                    this._zoomLevel += 1;
                }
            }

            this._zoomSlider.slider( "option", "value", this._zoomLevel );
        }

        this._resizeItemContainer();
    };

    DiagramDesignerWidgetZoom.prototype.getZoom = function () {
        return this._zoomRatio;
    };

    DiagramDesignerWidgetZoom.prototype.zoomIn = function () {
        this._setZoomLevel(this._zoomLevel + 1);
    };

    DiagramDesignerWidgetZoom.prototype.zoomOut = function () {
        this._setZoomLevel(this._zoomLevel - 1);
    };

    DiagramDesignerWidgetZoom.prototype._addZoomMouseHandler = function (el) {
        var self = this;

        //IE, Chrome, etc
        el.on('mousewheel', function (event){
            var org = event.originalEvent;

            if (org &&  (org.ctrlKey || org.metaKey || org.altKey)) {
                //CTRL + mouse scroll
                if (org.wheelDelta < 0) {
                    self.zoomOut();
                } else {
                    self.zoomIn();
                }

                event.stopPropagation();
                event.preventDefault();
            }
        });

        //FIREFOX
        el.on('DOMMouseScroll', function (event){
            var org = event.originalEvent;

            if (org && (org.ctrlKey || org.metaKey || org.altKey)) {
                //CTRL + mouse scroll
                if (org.detail > 0) {
                    self.zoomOut();
                } else {
                    self.zoomIn();
                }

                event.stopPropagation();
                event.preventDefault();
            }
        });
    };

    return DiagramDesignerWidgetZoom;
});
<|endoftext|>


<commit_before>/*
	Copyright (c) 2010 Filip Moberg, (filip@mcsquare.se)

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
*/

function fQuery() {

	// Define global variables
	var args = arguments;
	var m;

	// Argument handler
	if (args[0] && args[0].substr(0,1) == "@") {

		// If first argument is an fQuery modifier
		fQuery._reset();
		m = args[0].split(" ");
		for (i=0; i < m.length; i++) {
			fQuery._modifier.push(m[i].replace("@", ""));
		}

	} else if(args[0] != undefined && jQuery && jQuery(args[0])[0] != "") {
		// If first argument is a valid jQuery selector
		fQuery.$ = jQuery(args[0]);
	}

	if (!fQuery._init) {
		fQuery._init = {
			alias : function() {

				var arr, obj, key;

				if (fQuery._modifier && fQuery._modifier[0]) {

					arr = fQuery._modifier[0] ? fQuery._modifier[0].split(".") : '';
					obj = fQuery();

					for (var i in arr) {
						key = arr[i];
						obj = obj[key];
					}

					window[arguments[0]] = obj;

				} else {

					for (i=0; i < arguments.length; i++) {
						window[arguments[i]] = fQuery;
					}
				}

				fQuery._reset();
			},
			extend : function() {

				var arr, arg, copy, key, n;

				for (i=0; i < fQuery._modifier.length; i++) {

					arr = fQuery._modifier[i] ? fQuery._modifier[i].split(".") : '';
					copy = new Array();
					copy['function'] = fQuery._init;
					copy['object'] = fQuery;
					arg = arguments[0];
					n = 0;

					for (var k in arr) {
						if (n == arr.length-1 && typeof(arg) == "function") {
							arg = new Object();
							arg[arr[n]] = arguments[0];
						} else {
							key = arr[k];

							if (!copy['function'][key]) {

								copy['function'][key] = {};
								copy['object'][key] = {};
							}

							copy['function'] = copy['function'][key];
							copy['object'] = copy['object'][key];
						}

						n++;
					}

					this._extend(true, copy['function'], arg);
					this._extend(true, copy['object'], arg);
				}

				fQuery._reset();
			},
			_extend : function() {
				// jQuery extend function (compressed)
				class2type={};hasOwn=Object.prototype.hasOwnProperty;var f={type:function(i){return i==null?String(i):class2type[toString.call(i)]||"object"},isWindow:function(i){return i&&typeof i==="object"&&"setInterval" in i},isFunction:function(i){return this.type(i)==="function"},isArray:Array.isArray||function(i){return this.type(i)==="array"},isPlainObject:function(m){if(!m||this.type(m)!=="object"||m.nodeType||this.isWindow(m)){return false}if(m.constructor&&!hasOwn.call(m,"constructor")&&!hasOwn.call(m.constructor.prototype,"isPrototypeOf")){return false}var i;for(i in m){}return i===undefined||hasOwn.call(m,i)}};var l,c,a,b,h,j,g=arguments[0]||{},e=1,d=arguments.length,k=false;if(typeof g==="boolean"){k=g;g=arguments[1]||{};e=2}if(typeof g!=="object"&&!f.isFunction(g)){g={}}for(;e<d;e++){if((l=arguments[e])!=null){for(c in l){a=g[c];b=l[c];if(g===b){continue}if(k&&b&&(f.isPlainObject(b)||(h=f.isArray(b)))){if(h){h=false;j=a&&f.isArray(a)?a:[]}else{j=a&&f.isPlainObject(a)?a:{}}g[c]=this._extend(k,j,b)}else{if(b!==undefined){g[c]=b}}}}}return g
			},
			_reset : function() {
				fQuery._modifier = new Array();
			},
			$ : function() {
				return fQuery.$;
			},

			// Faster than jQueries append, but lets you pass through css and attribute objects to jQuery.
			append : function(o) {

				fQuery.$.each(function() {

					var obj = document.createElement(o.element);
					this.appendChild(obj);

					if (o.css) {
						$(obj).css(o.css);
					}

					if (o.attributes) {
						$(obj).attr(o.attributes);
					}

					if (o.bind) {

						for (var k in o.bind) {
							$(obj).bind(k, o.bind[k]);
						}
					}
				});
			},
			count : function(o) {

				var c = 0;

				for (var k in o) {
					if (o.hasOwnProperty(k)) {
						++c;
					}
				}

				return c;
			},
			log : function() {

				if (typeof(console) != "undefined") {
					console.log(arguments[0]);
				}
			},
			dump : function() {
				var getTab = function() {
					var t = "";
					for (i=0; i < arguments[0]; i++) {
						t += "    ";
					}
					return t;
				}

				var level = 0;
				var inter = function() {
					var l = level;
					level++;
					var tab = getTab(level);

					if (l > 0) {
						console.log(tab.replace("    ","") + "{");
					} else {
						console.log("{");
					}

					var obj = arguments[0].object;

					for (var a in obj) {
						console.log(tab + a + " => " + typeof(obj[a]));
						if (typeof(obj[a]) == "object") {
							inter({object: obj[a]});
						}
					}

					if (l > 0) {
						console.log(tab.replace("    ","") + "}");
					} else {
						console.log("}");
					}
				}

				inter({object: obj});
			}
		};
		jQuery.extend(fQuery, fQuery._init);
	}
	return fQuery._init;
}
<commit_msg>Cleanup.<commit_after>/*
	Copyright (c) 2010 Filip Moberg, (filip@mcsquare.se)

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
*/

function fQuery() {

	// Define global variables
	var args = arguments;
	var m;

	// Argument handler
	if (args[0] && args[0].substr(0,1) == "@") {

		// If first argument is an fQuery modifier
		fQuery._reset();
		m = args[0].split(" ");
		for (i=0; i < m.length; i++) {
			fQuery._modifier.push(m[i].replace("@", ""));
		}

	} else if(args[0] != undefined && jQuery && jQuery(args[0])[0] != "") {
		// If first argument is a valid jQuery selector
		fQuery.$ = jQuery(args[0]);
	}

	if (!fQuery._init) {
		fQuery._init = {
			alias : function() {

				var arr, obj, key;

				if (fQuery._modifier && fQuery._modifier[0]) {

					arr = fQuery._modifier[0] ? fQuery._modifier[0].split(".") : '';
					obj = fQuery();

					for (var i in arr) {
						key = arr[i];
						obj = obj[key];
					}

					window[arguments[0]] = obj;

				} else {

					for (i=0; i < arguments.length; i++) {
						window[arguments[i]] = fQuery;
					}
				}

				fQuery._reset();
			},
			extend : function() {

				var arr, arg, copy, key, n;

				for (i=0; i < fQuery._modifier.length; i++) {

					arr = fQuery._modifier[i] ? fQuery._modifier[i].split(".") : '';
					copy = new Array();
					copy['function'] = fQuery._init;
					copy['object'] = fQuery;
					arg = arguments[0];
					n = 0;

					for (var k in arr) {
						if (n == arr.length-1 && typeof(arg) == "function") {
							arg = new Object();
							arg[arr[n]] = arguments[0];
						} else {
							key = arr[k];

							if (!copy['function'][key]) {

								copy['function'][key] = {};
								copy['object'][key] = {};
							}

							copy['function'] = copy['function'][key];
							copy['object'] = copy['object'][key];
						}

						n++;
					}

					this._extend(true, copy['function'], arg);
					this._extend(true, copy['object'], arg);
				}

				fQuery._reset();
			},
			_extend : function() {
				// jQuery extend function (compressed)
				class2type={};hasOwn=Object.prototype.hasOwnProperty;var f={type:function(i){return i==null?String(i):class2type[toString.call(i)]||"object"},isWindow:function(i){return i&&typeof i==="object"&&"setInterval" in i},isFunction:function(i){return this.type(i)==="function"},isArray:Array.isArray||function(i){return this.type(i)==="array"},isPlainObject:function(m){if(!m||this.type(m)!=="object"||m.nodeType||this.isWindow(m)){return false}if(m.constructor&&!hasOwn.call(m,"constructor")&&!hasOwn.call(m.constructor.prototype,"isPrototypeOf")){return false}var i;for(i in m){}return i===undefined||hasOwn.call(m,i)}};var l,c,a,b,h,j,g=arguments[0]||{},e=1,d=arguments.length,k=false;if(typeof g==="boolean"){k=g;g=arguments[1]||{};e=2}if(typeof g!=="object"&&!f.isFunction(g)){g={}}for(;e<d;e++){if((l=arguments[e])!=null){for(c in l){a=g[c];b=l[c];if(g===b){continue}if(k&&b&&(f.isPlainObject(b)||(h=f.isArray(b)))){if(h){h=false;j=a&&f.isArray(a)?a:[]}else{j=a&&f.isPlainObject(a)?a:{}}g[c]=this._extend(k,j,b)}else{if(b!==undefined){g[c]=b}}}}}return g
			},
			_reset : function() {
				fQuery._modifier = new Array();
			},
			$ : function() {
				return fQuery.$;
			},

			// Faster than jQueries append, but lets you pass through css and attribute objects to jQuery.
			append : function(o) {

				fQuery.$.each(function() {

					var obj = document.createElement(o.element);
					this.appendChild(obj);

					if (o.css) {
						$(obj).css(o.css);
					}

					if (o.attributes) {
						$(obj).attr(o.attributes);
					}

					if (o.bind) {

						for (var k in o.bind) {
							$(obj).bind(k, o.bind[k]);
						}
					}
				});
			},
			count : function(o) {

				var c = 0;

				for (var k in o) {
					if (o.hasOwnProperty(k)) {
						++c;
					}
				}

				return c;
			},
			log : function() {

				if (typeof(console) != "undefined") {
					console.log(arguments[0]);
				}
			},
			dump : function() {
				var getTab = function() {
					var t = "";
					for (i=0; i < arguments[0]; i++) {
						t += "    ";
					}
					return t;
				}

				var l = 0;
				var dump = function() {
					var level = l;
					l++;
					var tab = getTab(l);

					if (l > 0) {
						this.log(tab.replace("    ","") + "{");
					} else {
						this.log("{");
					}

					var obj = arguments[0].object;

					for (var a in obj) {
						this.log(tab + a + " => " + typeof(obj[a]));
						if (typeof(obj[a]) == "object") {
							dump({object: obj[a]});
						}
					}

					if (l > 0) {
						this.log(tab.replace("    ","") + "}");
					} else {
						this.log("}");
					}
				}

				dump({object: obj});
			}
		};
		jQuery.extend(fQuery, fQuery._init);
	}
	return fQuery._init;
}
<|endoftext|>


<commit_before>"use strict";

angular.module('arethusa.sg').service('sg', [
  'state',
  'configurator',
  '$cacheFactory',
  function(state, configurator, $cacheFactory) {
    var self = this;
    var retriever;
    this.labelAs = "long";
    this.defineAncestors = true;

    var sgCache = $cacheFactory('sg', { number:  100 });

    function configure() {
      configurator.getConfAndDelegate('sg', self, ['labels']);
      retriever = configurator.getRetriever(self.conf.retriever);
    }

    configure();

    function SgTemplate() {
      var self = this;

      this.morph = {};
      this.ancestors = [];
      this.definingAttrs = [];
      this.menu = {};
      this.hasChanged = true;
      this.isSgTemplate = true;
      this.markChange = function() {
        self.hasChanged = true;
      };
    }

    function grammarReset(grammar) {
      grammar.ancestors = [];
      // We have to redefine this property - it's untouchable now
      // that it's cached!
      grammar.definingAttrs = [];
    }

    function sgFromStateComplete(sg) {
      return sg && sg.isSgTemplate;
    }

    function sgFromRetriever(sg) {
      return sg && sg.ancestors && !sg.isTemplate;
    }

    function createInternalState() {
      // 3 possibilites here:
      //
      // 1 When we have seen this token set before, we don't need to do anything
      //   and can take the info we already created earlier in time.
      // 2 We have not seen the tokens, but they have info from the retrieved
      //   document. In such a case we build a new SgTemplate and add the sg
      //   ancestors from the token to it.
      // 3 We have to start from scratch.
      return arethusaUtil.inject({}, state.tokens, function(memo, id, token) {
        var grammar;
        var fromState = token.sg;
        if (sgFromStateComplete(fromState)) {
          grammar = fromState;
        } else {
          grammar = new SgTemplate();
          var morph = token.morphology || {};
          grammar.string = token.string;
          checkAndUpdateGrammar(morph, grammar);
          if (sgFromRetriever(fromState)) {
            addAncestorsFromState(fromState, grammar);
          }
        }
        memo[id] = grammar;
      });
    }

    function addAncestorsFromState(sg, grammar) {
      var ancestors = sg.ancestors;
      var menu = grammar.menu;
      angular.forEach(ancestors, function(ancestor, i) {
        if (menu) {
          var expandedAncestor = menu[ancestor];
          grammar.ancestors.push(expandedAncestor);
          menu = expandedAncestor.nested;
        }
      });
    }

    var hint = "Please select a morphological form first!";

    this.currentGrammar = function() {
      return arethusaUtil.inject({}, state.selectedTokens, function(memo, id, event) {
        var morph = state.tokens[id].morphology;
        var grammar = self.grammar[id];
        if (morph && morph.attributes) {
          delete grammar.hint;
          checkAndUpdateGrammar(morph, grammar);
        } else {
          grammarReset(grammar);
          grammar.morph = {};
          grammar.hint = hint;
        }
        memo[id] = grammar;
      });
    };

    function morphHasChanged(a, b) {
      return !angular.equals(a, b);
    }

    function checkAndUpdateGrammar(morph, grammar) {
      if (morphHasChanged(grammar.morph, morph.attributes)) {
        angular.extend(grammar.morph, morph.attributes);
        updateGrammar(self.labels, grammar);
      }
      return grammar;
    }

    function updateGrammar(labels, grammar) {
      grammarReset(grammar);
      findDefiningAttributes(self.labels, grammar, grammar.definingAttrs);
      extractMenu(grammar);
      cacheUpdateProcess(grammar);
    }

    function cacheUpdateProcess(grammar) {
      var key = cacheKey(grammar);
      if (!sgCache.get(key)) {
        sgCache.put(key, grammar.definingAttrs);
      }
    }

    function cacheKey(grammar) {
      return arethusaUtil.inject([], grammar.morph, function(memo, k, v) {
        memo.push(k + '-' + v);
      }).sort().join('|');
    }

    function findDefiningAttributes(labels, grammar, target) {
      var cached = sgCache.get(cacheKey(grammar));
      if (cached) {
        arethusaUtil.pushAll(target, cached);
      } else {
        arethusaUtil.inject(target, labels, function(memo, label, val) {
          var dep = val.dependency;
          if (dep) {
            var morph = grammar.morph;
            var nextLevel;
            angular.forEach(dep, function(depVal, depCat) {
              if (dependencyMet(morph[depCat], depVal)) {
                val = angular.copy(val);
                memo.push(val);
                nextLevel = val.nested;
                if (nextLevel) {
                  angular.forEach(nextLevel, function(nestedMenu, nestedLabel) {
                    if (nestedMenu.nestedDependency) {
                      var nextNestedLevel = [];
                      findDefiningAttributes(nestedMenu.nested, grammar, nextNestedLevel);
                      nestedMenu.nested = { nested: nextNestedLevel.pop() };
                    }
                  });
                  findDefiningAttributes(nextLevel, grammar, target);
                }
              }
            });
          }
        });
      }
    }

    function dependencyMet(morphValue, depValue) {
      if (angular.isDefined(morphValue)) {
        return morphValue === depValue || depValue === "*";
      }
    }

    // We already captured the defining attributes at this point - they
    // are all stored as full objects with their full nested structure.
    // The menu we want to present to the user is therefore the last one
    // in this array structure.
    function extractMenu(grammar) {
      var attrs = grammar.definingAttrs;
      // Could be that this array is empty!
      var lastAttr = attrs[attrs.length - 1] || {};
      grammar.menu = lastAttr.nested;
    }

    function propagateToState() {
      angular.forEach(self.grammar, function(val, id) {
        state.tokens[id].sg = val;
      });
    }

    this.requestGrammar = function(sections, callback) {
      retriever.getData(sections, callback);
    };

    this.init = function() {
      configure();
      self.grammar = createInternalState();
      console.log('reining');
      self.readerRequested = false;
      propagateToState();
    };
  }
]);
<commit_msg>Fix sg when the morphology of a token changes<commit_after>"use strict";

angular.module('arethusa.sg').service('sg', [
  'state',
  'configurator',
  '$cacheFactory',
  function(state, configurator, $cacheFactory) {
    var self = this;
    var retriever;
    this.labelAs = "long";
    this.defineAncestors = true;

    var sgCache = $cacheFactory('sg', { number:  100 });

    function configure() {
      configurator.getConfAndDelegate('sg', self, ['labels']);
      retriever = configurator.getRetriever(self.conf.retriever);
    }

    configure();

    function SgTemplate() {
      var self = this;

      this.morph = {};
      this.ancestors = [];
      this.definingAttrs = [];
      this.menu = {};
      this.hasChanged = true;
      this.isSgTemplate = true;
      this.markChange = function() {
        self.hasChanged = true;
      };
    }

    function grammarReset(grammar) {
      arethusaUtil.empty(grammar.ancestors);
      // We have to redefine this property - it's untouchable now
      // that it's cached!
      grammar.definingAttrs = [];
    }

    function sgFromStateComplete(sg) {
      return sg && sg.isSgTemplate;
    }

    function sgFromRetriever(sg) {
      return sg && sg.ancestors && !sg.isTemplate;
    }

    function createInternalState() {
      // 3 possibilites here:
      //
      // 1 When we have seen this token set before, we don't need to do anything
      //   and can take the info we already created earlier in time.
      // 2 We have not seen the tokens, but they have info from the retrieved
      //   document. In such a case we build a new SgTemplate and add the sg
      //   ancestors from the token to it.
      // 3 We have to start from scratch.
      return arethusaUtil.inject({}, state.tokens, function(memo, id, token) {
        var grammar;
        var fromState = token.sg;
        if (sgFromStateComplete(fromState)) {
          grammar = fromState;
        } else {
          grammar = new SgTemplate();
          var morph = token.morphology || {};
          grammar.string = token.string;
          checkAndUpdateGrammar(morph, grammar);
          if (sgFromRetriever(fromState)) {
            addAncestorsFromState(fromState, grammar);
          }
        }
        memo[id] = grammar;
      });
    }

    function addAncestorsFromState(sg, grammar) {
      var ancestors = sg.ancestors;
      var menu = grammar.menu;
      angular.forEach(ancestors, function(ancestor, i) {
        if (menu) {
          var expandedAncestor = menu[ancestor];
          grammar.ancestors.push(expandedAncestor);
          menu = expandedAncestor.nested;
        }
      });
    }

    var hint = "Please select a morphological form first!";

    this.currentGrammar = function() {
      return arethusaUtil.inject({}, state.selectedTokens, function(memo, id, event) {
        var morph = state.tokens[id].morphology;
        var grammar = self.grammar[id];
        if (morph && morph.attributes) {
          delete grammar.hint;
          checkAndUpdateGrammar(morph, grammar);
        } else {
          grammarReset(grammar);
          grammar.morph = {};
          grammar.hint = hint;
        }
        memo[id] = grammar;
      });
    };

    function morphHasChanged(a, b) {
      return !angular.equals(a, b);
    }

    function checkAndUpdateGrammar(morph, grammar) {
      if (morphHasChanged(grammar.morph, morph.attributes)) {
        // Need to empty first, otherwise we might mix attributes
        // of various part of speech types together!
        arethusaUtil.empty(grammar.morph);
        angular.extend(grammar.morph, morph.attributes);
        updateGrammar(self.labels, grammar);
      }
      return grammar;
    }

    function updateGrammar(labels, grammar) {
      grammarReset(grammar);
      findDefiningAttributes(self.labels, grammar, grammar.definingAttrs);
      extractMenu(grammar);
      cacheUpdateProcess(grammar);
    }

    function cacheUpdateProcess(grammar) {
      var key = cacheKey(grammar);
      if (!sgCache.get(key)) {
        sgCache.put(key, grammar.definingAttrs);
      }
    }

    function cacheKey(grammar) {
      return arethusaUtil.inject([], grammar.morph, function(memo, k, v) {
        memo.push(k + '-' + v);
      }).sort().join('|');
    }

    function findDefiningAttributes(labels, grammar, target) {
      var cached = sgCache.get(cacheKey(grammar));
      if (cached) {
        arethusaUtil.pushAll(target, cached);
      } else {
        arethusaUtil.inject(target, labels, function(memo, label, val) {
          var dep = val.dependency;
          if (dep) {
            var morph = grammar.morph;
            var nextLevel;
            angular.forEach(dep, function(depVal, depCat) {
              if (dependencyMet(morph[depCat], depVal)) {
                val = angular.copy(val);
                memo.push(val);
                nextLevel = val.nested;
                if (nextLevel) {
                  angular.forEach(nextLevel, function(nestedMenu, nestedLabel) {
                    if (nestedMenu.nestedDependency) {
                      var nextNestedLevel = [];
                      findDefiningAttributes(nestedMenu.nested, grammar, nextNestedLevel);
                      nestedMenu.nested = { nested: nextNestedLevel.pop() };
                    }
                  });
                  findDefiningAttributes(nextLevel, grammar, target);
                }
              }
            });
          }
        });
      }
    }

    function dependencyMet(morphValue, depValue) {
      if (angular.isDefined(morphValue)) {
        return morphValue === depValue || depValue === "*";
      }
    }

    // We already captured the defining attributes at this point - they
    // are all stored as full objects with their full nested structure.
    // The menu we want to present to the user is therefore the last one
    // in this array structure.
    function extractMenu(grammar) {
      var attrs = grammar.definingAttrs;
      // Could be that this array is empty!
      var lastAttr = attrs[attrs.length - 1] || {};
      grammar.menu = lastAttr.nested;
    }

    function propagateToState() {
      angular.forEach(self.grammar, function(val, id) {
        state.tokens[id].sg = val;
      });
    }

    this.requestGrammar = function(sections, callback) {
      retriever.getData(sections, callback);
    };

    this.init = function() {
      configure();
      self.grammar = createInternalState();
      console.log('reining');
      self.readerRequested = false;
      propagateToState();
    };
  }
]);
<|endoftext|>


<commit_before>import RTabListItemContent from 'ui-library/components/r-tab-list-item/content/component';

export default RTabListItemContent;
<commit_msg>Import template in tab-list/content, not component<commit_after>import RTabListItemContent from 'ui-library/components/r-tab-list-item/content/template';

export default RTabListItemContent;
<|endoftext|>


<commit_before>/*
 *   Initializes a new instance of the Renderer class.
 */
function Renderer(width, height) {

    this.width = width;
    this.height = height;

    var canvas = document.createElement('canvas');
    canvas.setAttribute('id', 'drawing');
    canvas.setAttribute('width', width.toString());
    canvas.setAttribute('height', height.toString());

    document.body.appendChild(canvas);

    this.ctx = canvas.getContext('2d');
}

/*
 *   Draws all objects.
 */
Renderer.prototype.drawAll = function (blaze, eggman) {
    this.ctx.clearRect(0, 0, this.width, this.height);
    _drawBlaze(this.ctx, blaze);
    _drawClip(this.ctx, blaze);

    if (eggman) {
        _drawEggman(this.ctx, eggman);
    }
};

/*
 *   Constants for the game object.
 */
Renderer.CONFIG = function () {
    var private = {
        'BLAZE_LINE_LENGTH': 60,
        'BLAZE_INNER_RADIUS': 10,
        'BLAZE_OUTER_RADIUS': 20,
        'BLAZE_COLOR':'red'
    };

    return {
        get: function (name) {
            return private[name];
        }
    };
}();

/*
 *   Draws Blaze.
 */
function _drawBlaze(context, blaze) {

    var LINE_LENGTH = Renderer.CONFIG.get('BLAZE_LINE_LENGTH');
    var INNER_RADIUS = Renderer.CONFIG.get('BLAZE_INNER_RADIUS');
    var OUTER_RADIUS = Renderer.CONFIG.get('BLAZE_OUTER_RADIUS');

    var centerX = blaze.position.x;
    var centerY = blaze.position.y;

    var point1X = centerX + LINE_LENGTH / 2;
    var point1Y = centerY;

    var point2X = centerX - LINE_LENGTH / 2;
    var point2Y = centerY;

    var point3X = centerX;
    var point3Y = centerY + LINE_LENGTH / 2;

    var point4X = centerX;
    var point4Y = centerY - LINE_LENGTH / 2;

    context.beginPath();
    context.moveTo(point1X, point1Y);
    context.lineTo(point2X, point2Y);
    context.moveTo(point3X, point3Y);
    context.lineTo(point4X, point4Y);
    context.moveTo(centerX, centerY);
    context.arc(centerX, centerY, INNER_RADIUS, 0, 2 * Math.PI, false);
    context.moveTo(centerX, centerY);
    context.arc(centerX, centerY, OUTER_RADIUS, 0, 2 * Math.PI, false);
    context.strokeStyle = Renderer.CONFIG.get('BLAZE_COLOR');
    context.stroke();
}

//Draws Bullets // TODO: add global consts and change here.
function _drawClip(context, blaze) {
    var BULLET_WIDHT = 20,
        BULLET_HEIGHT = 30,
        SPACING = 5,
        sx = 20,
        sy = context.canvas.height - BULLET_HEIGHT - 10,
        bulletsCount = blaze.getBulletsCount();

    context.beginPath();
    for (var i = 0; i < bulletsCount; i += 1) {
        context.moveTo(sx, sy);
        context.strokeRect(sx, sy, BULLET_WIDHT, BULLET_HEIGHT);
        sx = sx + BULLET_WIDHT + SPACING;
    }
    ;
    context.stroke();
}

/*
 *   Draws Eggman.
 */
function _drawEggman(context, eggman) {

    var eggmanTopLeftX = eggman.position.x;
    var eggmanTopLeftY = eggman.position.y;
    context.strokeStyle = 'green';
    context.strokeRect(eggmanTopLeftX, eggmanTopLeftY, eggman.width, eggman.height);
}<commit_msg>fix blaze property in renderer.js<commit_after>/*
 *   Initializes a new instance of the Renderer class.
 */
function Renderer(width, height) {

    this.width = width;
    this.height = height;

    var canvas = document.createElement('canvas');
    canvas.setAttribute('id', 'drawing');
    canvas.setAttribute('width', width.toString());
    canvas.setAttribute('height', height.toString());

    document.body.appendChild(canvas);

    this.ctx = canvas.getContext('2d');
}

/*
 *   Draws all objects.
 */
Renderer.prototype.drawAll = function (blaze, eggman) {
    this.ctx.clearRect(0, 0, this.width, this.height);
    _drawBlaze(this.ctx, blaze);
    _drawClip(this.ctx, blaze);

    if (eggman) {
        _drawEggman(this.ctx, eggman);
    }
};

/*
 *   Constants for the game object.
 */
Renderer.CONFIG = function () {
    var private = {
        'BLAZE_LINE_LENGTH': 60,
        'BLAZE_INNER_RADIUS': 10,
        'BLAZE_OUTER_RADIUS': 20,
        'BLAZE_COLOR':'red'
    };

    return {
        get: function (name) {
            return private[name];
        }
    };
}();

/*
 *   Draws Blaze.
 */
function _drawBlaze(context, blaze) {

    var LINE_LENGTH = Renderer.CONFIG.get('BLAZE_LINE_LENGTH');
    var INNER_RADIUS = Renderer.CONFIG.get('BLAZE_INNER_RADIUS');
    var OUTER_RADIUS = Renderer.CONFIG.get('BLAZE_OUTER_RADIUS');

    var centerX = blaze.position.x;
    var centerY = blaze.position.y;

    var point1X = centerX + LINE_LENGTH / 2;
    var point1Y = centerY;

    var point2X = centerX - LINE_LENGTH / 2;
    var point2Y = centerY;

    var point3X = centerX;
    var point3Y = centerY + LINE_LENGTH / 2;

    var point4X = centerX;
    var point4Y = centerY - LINE_LENGTH / 2;

    context.beginPath();
    context.moveTo(point1X, point1Y);
    context.lineTo(point2X, point2Y);
    context.moveTo(point3X, point3Y);
    context.lineTo(point4X, point4Y);
    context.moveTo(centerX, centerY);
    context.arc(centerX, centerY, INNER_RADIUS, 0, 2 * Math.PI, false);
    context.moveTo(centerX, centerY);
    context.arc(centerX, centerY, OUTER_RADIUS, 0, 2 * Math.PI, false);
    context.strokeStyle = Renderer.CONFIG.get('BLAZE_COLOR');
    context.stroke();
}

//Draws Bullets // TODO: add global consts and change here.
function _drawClip(context, blaze) {
    var BULLET_WIDHT = 20,
        BULLET_HEIGHT = 30,
        SPACING = 5,
        sx = 20,
        sy = context.canvas.height - BULLET_HEIGHT - 10,
        bulletsCount = blaze.bullets;

    context.beginPath();
    for (var i = 0; i < bulletsCount; i += 1) {
        context.moveTo(sx, sy);
        context.strokeRect(sx, sy, BULLET_WIDHT, BULLET_HEIGHT);
        sx = sx + BULLET_WIDHT + SPACING;
    }
    ;
    context.stroke();
}

/*
 *   Draws Eggman.
 */
function _drawEggman(context, eggman) {

    var eggmanTopLeftX = eggman.position.x;
    var eggmanTopLeftY = eggman.position.y;
    context.strokeStyle = 'green';
    context.strokeRect(eggmanTopLeftX, eggmanTopLeftY, eggman.width, eggman.height);
}<|endoftext|>