<commit_before>import InputConnectorElement from '../input-connector/index.js';

const CONNECTORS = new Set();

let activeConnector = null;

/**
 * Handle connector elements linking
 */
class InputConnectorLinkableElement extends InputConnectorElement {
  constructor() {
    super();

    this.shadowRoot.querySelector('slot style').insertAdjacentHTML('beforeend', `
      :host {
        cursor: pointer;
        margin: 0;
        padding: .2em;
        touch-action: none;
      }
      :host(:hover) {
        background: red;
      }
      :host(:focus-within) {
        background: green;
      }
      :host([connected]) {
        background: orange;
      }
    `);

    this.addEventListener('pointerdown', this._onPointerDown);

    this._onWindowPointerUpBinded = this._onWindowPointerUp.bind(this);
    this.addEventListener('pointerup', (event) => {
    }, { passive: false });
  }

  connectedCallback() {
    CONNECTORS.add(this);
  }

  disconnectedCallback() {
    CONNECTORS.delete(this);
    super.disconnectedCallback();
  }

  _onPointerDown() {
    if (activeConnector) {
      return;
    }
    activeConnector = this;

    window.addEventListener('pointerup', this._onWindowPointerUpBinded, { passive: false });

    this.dispatchEvent(new CustomEvent('linkstart', {
      composed: true,
      bubbles: true,
      detail: {
        input: this,
        output: undefined,
      },
    }));
  }

  _onWindowPointerUp(event) {
    if (!activeConnector) {
      return;
    }

    let hitConnector;

    for (const connector of CONNECTORS) {
      const boundingClientRect = connector.getBoundingClientRect();
      if (event.clientX > boundingClientRect.x &&
        event.clientX < boundingClientRect.x + boundingClientRect.width &&
        event.clientY > boundingClientRect.y &&
        event.clientY < boundingClientRect.y + boundingClientRect.height) {
        hitConnector = connector;
      }
    }

    if (hitConnector === activeConnector) {
      return;
    }

    window.removeEventListener('pointerup', this._onWindowPointerUpBinded);

    if (!hitConnector || (activeConnector.type === hitConnector.type && hitConnector.type !== InputConnectorLinkableElement.TYPE_BOTH)) {
      activeConnector = null;
      this.dispatchEvent(new CustomEvent('linkend', {
        composed: true,
        bubbles: true,
        detail: {
          input: null,
          output: null,
        },
      }));
      return;
    }

    const inputConnector = activeConnector.type & InputConnectorLinkableElement.TYPE_OUTPUT ? activeConnector : hitConnector;
    const outputConnector = hitConnector.type & InputConnectorLinkableElement.TYPE_INPUT ? hitConnector : activeConnector;

    inputConnector.outputs.add(outputConnector);

    activeConnector = null;

    this.dispatchEvent(new CustomEvent('linkend', {
      composed: true,
      bubbles: true,
      detail: {
        input: inputConnector,
        output: outputConnector,
      },
    }));
  }
}

export default InputConnectorLinkableElement;
<commit_msg>fix connectors when inputs/outputs are undefined<commit_after>import InputConnectorElement from '../input-connector/index.js';

const CONNECTORS = new Set();

let activeConnector = null;

/**
 * Handle connector elements linking
 */
class InputConnectorLinkableElement extends InputConnectorElement {
  constructor() {
    super();

    this.shadowRoot.querySelector('slot style').insertAdjacentHTML('beforeend', `
      :host {
        cursor: pointer;
        margin: 0;
        padding: .2em;
        touch-action: none;
      }
      :host(:hover) {
        background: red;
      }
      :host(:focus-within) {
        background: green;
      }
      :host([connected]) {
        background: orange;
      }
    `);

    this.addEventListener('pointerdown', this._onPointerDown);

    this._onWindowPointerUpBinded = this._onWindowPointerUp.bind(this);
    this.addEventListener('pointerup', (event) => {
    }, { passive: false });
  }

  connectedCallback() {
    CONNECTORS.add(this);
  }

  disconnectedCallback() {
    CONNECTORS.delete(this);
    super.disconnectedCallback();
  }

  _onPointerDown() {
    if (activeConnector) {
      return;
    }
    activeConnector = this;

    window.addEventListener('pointerup', this._onWindowPointerUpBinded, { passive: false });

    this.dispatchEvent(new CustomEvent('linkstart', {
      composed: true,
      bubbles: true,
      detail: {
        input: this,
        output: undefined,
      },
    }));
  }

  _onWindowPointerUp(event) {
    if (!activeConnector) {
      return;
    }

    let hitConnector;

    for (const connector of CONNECTORS) {
      const boundingClientRect = connector.getBoundingClientRect();
      if (event.clientX > boundingClientRect.x &&
        event.clientX < boundingClientRect.x + boundingClientRect.width &&
        event.clientY > boundingClientRect.y &&
        event.clientY < boundingClientRect.y + boundingClientRect.height) {
        hitConnector = connector;
      }
    }

    if (hitConnector === activeConnector) {
      return;
    }

    window.removeEventListener('pointerup', this._onWindowPointerUpBinded);

    if (!hitConnector || (activeConnector.type === hitConnector.type && hitConnector.type !== InputConnectorLinkableElement.TYPE_BOTH)) {
      activeConnector = null;
      this.dispatchEvent(new CustomEvent('linkend', {
        composed: true,
        bubbles: true,
        detail: {
          input: null,
          output: null,
        },
      }));
      return;
    }

    const inputConnector = activeConnector.type & InputConnectorLinkableElement.TYPE_INPUT || hitConnector.type & InputConnectorLinkableElement.TYPE_OUTPUT ? hitConnector : activeConnector;
    const outputConnector = inputConnector === activeConnector ? hitConnector : activeConnector;

    inputConnector.outputs.add(outputConnector);

    activeConnector = null;

    this.dispatchEvent(new CustomEvent('linkend', {
      composed: true,
      bubbles: true,
      detail: {
        input: inputConnector,
        output: outputConnector,
      },
    }));
  }
}

export default InputConnectorLinkableElement;
<|endoftext|>


<commit_before>/**
 * @module src/UploadSource
 *
 * Component that display SourceDocument
 * Accepts the following properties:
 *  - language: Ethnologue code of the language
 *  - version: version of source language
 *  - base64_arr: file in the form of base64
*/

import React, { Component } from 'react';
import './App.css';
import Header from './Header';
import Footer from './Footer';
import { FormControl } from 'react-bootstrap';
import SourceLanguages from './SourceLanguages';
import $ from 'jquery';
import GlobalURL from './GlobalURL';

class UploadSource extends Component {
  constructor(props) {
    super(props);

    this.state = {
      language:'tam',
      version: '',
      base64_arr: [],
      uploaded:'Uploading',
      message: ''
    }

      // Upload file specific callback handlers
      this.uploadFile = this.uploadFile.bind(this);
      this.onSelect = this.onSelect.bind(this);
      this.file_base64 = this.file_base64.bind(this);
  }

  onSelect(e) {
    this.setState({
      [e.target.name]: e.target.value });
  }

  file_base64(e){
    var files = document.getElementById('file-input').files
    var file = [];
    global.base64_arr = [];
    if(files.length > 0){
        for (var i = 0; i < files.length; i++) {
        var reader = new FileReader();
        reader.readAsDataURL(files[i] );
        reader.onload = (function (file) {
          return function (e) {
            var data = this.result;
            var unwantedData = "data:;base64,";
            data = data.replace(unwantedData, "");
            global.base64_arr.push(data);
          }
        })(file);
        reader.onerror = function (error) {
        };
      }
    }

  }

  uploadFile(e){
    e.preventDefault();
    var ext = $('#file-input').val().split('.').pop().toLowerCase();
    if($.inArray(ext, ['usfm']) === -1) {
      this.setState({uploaded: 'success'})
    } else {
      this.setState({uploaded: 'failure'})
    }

    var _this = this
    for(var i = 0; i < (global.base64_arr).length; i++){
      var data = {
        "language": this.state.language, "version": this.state.version, "content": [global.base64_arr[i]]
      }
      let accessToken = JSON.parse(window.localStorage.getItem('access_token'));

      $.ajax({
        url: GlobalURL["hostURL"]+"/v1/sources",
        contentType: "application/json; charset=utf-8",
        data : JSON.stringify(data),
        method : "POST",
        headers: {
                  "Authorization": "bearer " + JSON.stringify(accessToken['access_token']).slice(1,-1)},
        success: function (result) {
        result = JSON.parse(result)
        if (result.success !== false) {
          _this.setState({message: result.message, uploaded: 'success'})
          var elem = document.getElementById("myBar");
          var width = 1;
          var id = setInterval(frame, 500);
            function frame() {
              if (width >= 100) {
                clearInterval(id);
              } else {
                width++;
                elem.style.width = width + '%';
                elem.innerHTML = width * 1  + '%';
              }
          }
        }else {
          _this.setState({message: result.message, uploaded: 'failure'})
          }
        }
      });
     }
    }

  render() {
    return(

          <form className="col-md-8 uploader" encType="multipart/form-data">

Upload Sources

20%

                {this.state.message}

                {this.state.message}

                <lable className="control-label">  Language Name  </lable>
                    <FormControl value={this.state.language} onChange={this.onSelect} name="language" componentClass="select" placeholder="select">
                      {SourceLanguages.map((language, i) => <option  key={i} value={language.code}>{language.value}</option>)}
                    </FormControl>

                <lable className="control-lable">  Ethnologue Code  </lable>
                      <input value={this.state.language} onChange={this.onSelect} type="text" name="EthnologueCode" placeholder="tam" className="form-control"/>

                <lable className="control-lable">  Version  </lable>
                    <input value={this.state.version} onChange={this.onSelect} name="version" type="text"  placeholder="version" className="form-control" />

                  <input id="file-input" type="file" className="fileInput" onChange={this.file_base64} multiple />

                  <button id="button" type="button" className="btn btn-success sourcefooter" onClick={this.uploadFile}>  Upload Source</button>

          </form>

      );
    }
}

export default UploadSource;
<commit_msg>Upload source progress changed<commit_after>/**
 * @module src/UploadSource
 *
 * Component that display SourceDocument
 * Accepts the following properties:
 *  - language: Ethnologue code of the language
 *  - version: version of source language
 *  - base64_arr: file in the form of base64
*/

import React, { Component } from 'react';
import './App.css';
import Header from './Header';
import Footer from './Footer';
import { FormControl } from 'react-bootstrap';
import SourceLanguages from './SourceLanguages';
import $ from 'jquery';
import GlobalURL from './GlobalURL';

class UploadSource extends Component {
  constructor(props) {
    super(props);

    this.state = {
      language:'tam',
      version: '',
      base64_arr: [],
      uploaded:'Uploading',
      message: ''
    }

      // Upload file specific callback handlers
      this.uploadFile = this.uploadFile.bind(this);
      this.onSelect = this.onSelect.bind(this);
      this.file_base64 = this.file_base64.bind(this);
  }

  onSelect(e) {
    this.setState({
      [e.target.name]: e.target.value });
  }

  file_base64(e){
    var files = document.getElementById('file-input').files
    var file = [];
    global.base64_arr = [];
    if(files.length > 0){
        for (var i = 0; i < files.length; i++) {
        var reader = new FileReader();
        reader.readAsDataURL(files[i] );
        reader.onload = (function (file) {
          return function (e) {
            var data = this.result;
            var unwantedData = "data:;base64,";
            data = data.replace(unwantedData, "");
            global.base64_arr.push(data);
          }
        })(file);
        reader.onerror = function (error) {
        };
      }
    }

  }

  uploadFile(e){
    e.preventDefault();
    var ext = $('#file-input').val().split('.').pop().toLowerCase();
    if($.inArray(ext, ['usfm']) === -1) {
      this.setState({uploaded: 'success'})
    } else {
      this.setState({uploaded: 'failure'})
    }

    var _this = this
    for(var i = 0; i < (global.base64_arr).length; i++){
      var data = {
        "language": this.state.language, "version": this.state.version, "content": [global.base64_arr[i]]
      }
      let accessToken = JSON.parse(window.localStorage.getItem('access_token'));
      var countSuccess = 0;
      var countFailure = 0;

      $.ajax({
        url: GlobalURL["hostURL"]+"/v1/sources",
        contentType: "application/json; charset=utf-8",
        data : JSON.stringify(data),
        method : "POST",
        headers: {
                  "Authorization": "bearer " + JSON.stringify(accessToken['access_token']).slice(1,-1)},
        success: function (result) {
        result = JSON.parse(result)
        if (result.success !== false) {
            countSuccess++;
          _this.setState({message: "Uploaded " + countSuccess + " files", uploaded: 'success'})
          if((countSuccess + countFailure) === (global.base64_arr).length){
            _this.setState({message: "Uploaded " + countSuccess + " files successfully", uploaded: 'success'})
          }
        }else {
          countFailure++;
          _this.setState({message: result.message, uploaded: 'failure'})
          if((countSuccess + countFailure) === (global.base64_arr).length){
             _this.setState({message: "Uploaded " + countSuccess + " files successfully", uploaded: 'success'})
          }          }
        }
      });
     }
    }

  render() {
    return(

          <form className="col-md-8 uploader" encType="multipart/form-data">

Upload Sources

                {this.state.message}

                No Changes. Existing source is already up-to-date

                <lable className="control-label">  Language Name  </lable>
                    <FormControl value={this.state.language} onChange={this.onSelect} name="language" componentClass="select" placeholder="select">
                      {SourceLanguages.map((language, i) => <option  key={i} value={language.code}>{language.value}</option>)}
                    </FormControl>

                <lable className="control-lable">  Ethnologue Code  </lable>
                      <input value={this.state.language} onChange={this.onSelect} type="text" name="EthnologueCode" placeholder="tam" className="form-control"/>

                <lable className="control-lable">  Version  </lable>
                    <input value={this.state.version} onChange={this.onSelect} name="version" type="text"  placeholder="version" className="form-control" />

                  <input id="file-input" type="file" className="fileInput" onChange={this.file_base64} multiple />

                  <button id="button" type="button" className="btn btn-success sourcefooter" onClick={this.uploadFile}>  Upload Source</button>

          </form>

      );
    }
}

export default UploadSource;
<|endoftext|>


<commit_before>/*
 * regnum2phyx.js: A tool for converting PhyloRegnum database dumps to Phyx files.
 *
 * Synopsis:
 *  regnum2phyx.js [JSON file to process] -o [directory to write files to]
 *
 * Note that existing files in the output directory will be silently overwritten,
 * so this script should usually be run on a new, empty output directory.
 *
 * PhyloRegnum can be accessed at http://app.phyloregnum.org
 */

// We currently produce Phyx files in v0.2.0 format. If this changes, please
// update this here.
const PHYX_CONTEXT_URL = 'http://www.phyloref.org/phyx.js/context/v0.2.0/phyx.json';

// Load necessary modules.
const fs = require('fs');
const path = require('path');
const yargs = require('yargs');
const {
  has, keys, pickBy, isEmpty,
} = require('lodash');

// Helper functions.
function convertAuthorsIntoStrings(authors, lastNameFirst = true) {
  // Given a list of authors with first_name, middle_name and last_name properties,
  // return a list of author names with a single name.
  //
  // We combine author names in two possible ways:
  //  If lastNameFirst is true: $last_name $first_name $middle_name
  //  If lastNameFirst is false: $first_name $middle_name $last_name
  // The middle name will be ignored if it is blank or not present.

  if (lastNameFirst) {
    // Use "last first middle".
    return authors.map(author => (
      `${author.last_name || ''}, ${author.first_name || ''}${
        ((has(author, 'middle_name') && author.middle_name.trim() !== '') ? ` ${author.middle_name}` : '')
      }`.trim()
    )).filter(name => name !== '');
  }

  // Use "first middle last".
  return authors.map(author => (
    `${author.first_name || ''} ${
      ((has(author, 'middle_name') && author.middle_name.trim() !== '') ? `${author.middle_name} ` : '')
    }${author.last_name || ''}`.trim()
  )).filter(name => name !== '');
}

function convertAuthorsIntoBibJSON(authors) {
  // Convert a list of authors in the Regnum dump format into a list of authors
  // in the BibJSON format (http://okfnlabs.org/bibjson/). Names without a
  // last name will be ignored.
  return authors
    .filter(author => author.last_name)
    .map(author => pickBy({ // lodash.pickBy will remove empty keys from the object.
      // We store the author name as first_name middle_name last_name
      name: convertAuthorsIntoStrings([author], false).join(),
      alternate: [
        // We store an alternate author name as last_name, first_name middle_name.
        convertAuthorsIntoStrings([author], true).join(),
      ],
      firstname: (author.first_name || '').trim(),
      lastname: (author.last_name || '').trim(),
      middlename: (author.middle_name || '').trim(),
    }));
}

function convertCitationsToBibJSON(citation) {
  // Convert a citation from its Regnum representation into the
  // BibJSON format (http://okfnlabs.org/bibjson/). We use this rather than
  // CSL-JSON (https://github.com/citation-style-language/schema) because it's
  // easier to set up. We might want to switch over to CSL-JSON
  // eventually (https://github.com/phyloref/clade-ontology/issues/69).

  if (!citation) return [];
  if (Array.isArray(citation)) {
    // If given an array of citation objects, convert each one separately.
    return citation.map(c => convertCitationsToBibJSON(c))
      .reduce((acc, val) => acc.concat(val), []);
  }

  // Do we have a title and a year? If not, skip this entry.
  if (
    citation.title === undefined || citation.title.trim() === ''
    || citation.year === undefined || citation.year.trim() === ''
  ) {
    return [];
  }

  // Assume a default type of 'article' if none was provided.
  let type = citation.citation_type || 'article';

  // Regnum uses 'journal' where BibJSON uses 'article'.
  if (type === 'journal') type = 'article';

  // In BibJSON, identifiers are kept separate from URLs.
  const identifiers = [];
  if (citation.doi) identifiers.push({ type: 'doi', id: citation.doi });

  const urls = [];
  if (citation.url) urls.push({ url: citation.url });

  // lodash.pickBy will remove empty keys from the object.
  const entry = pickBy({
    type,
    title: (citation.title || '').trim(),
    section_title: (citation.section_title || '').trim(),
    year: Number((citation.year || '')),
    edition: (citation.edition || '').trim(),
    authors: convertAuthorsIntoBibJSON(citation.authors),
    editors: convertAuthorsIntoBibJSON(citation.editors || []),
    series_editors: convertAuthorsIntoBibJSON(citation.series_editors || []),
    publisher: (citation.publisher || '').trim(),
    city: (citation.city || '').trim(),
    pages: (citation.pages || '').trim(),
    figure: (citation.figure || '').trim(),
    // keywords: (citation.keyword || '').trim(), -- We really don't need this.
    identifier: identifiers,
    link: urls,
  });

  if (type === 'book' || type === 'book_section') {
    // Add the ISBN to the entry itself.
    if (citation.isbn) {
      identifiers.push({ type: 'isbn', id: citation.isbn });
    }
  } else if (type === 'article') {
    // Identify journal identifiers, such as the
    const journalIdentifiers = [];
    if (citation.isbn) {
      journalIdentifiers.push({ type: 'isbn', id: citation.isbn });
    }
    if (citation.issn) {
      journalIdentifiers.push({ type: 'issn', id: citation.issn });
    }

    // In BibJSON (http://okfnlabs.org/bibjson/), the journal name, volume, number
    // and pages should go into the 'journal' object.
    entry.journal = pickBy({
      name: (citation.journal || '').trim(),
      volume: (citation.volume || '').trim(),
      number: (citation.number || '').trim(),
      identifier: journalIdentifiers,
    });

    // Since we've moved pages and ISBN into journal, we don't also need it in the main entry.
    if (has(entry, 'pages')) delete entry.pages;
  } else {
    process.stderr.write(`Unknown citation type: '${type}', using anyway.`);
  }

  return [entry];
}

// Command line application starts here.

// Read command-line arguments.
const argv = yargs
  .usage('Usage: $0 <JSON file to process> -o <directory to write files to>')
  .demandCommand(1, 1) // Make sure there's one and only one file to convert.
  .option('output-dir', {
    alias: 'o',
    describe: 'Directory to write Phyx files to',
  })
  .demandOption(['o'])
  .help('h')
  .alias('h', 'help')
  .argv;

// Read the database dump.
const dump = JSON.parse(fs.readFileSync(argv._[0], 'utf8'));

// This dump consists of multiple named phylogenetic clade definitions,
// each of which should be written out to a separate file.
const phyxProduced = {};
let countErrors = 0;

// Loop through all phylorefs in the database dump.
dump.forEach((entry) => {
  const phylorefLabel = entry.name.trim();

  // Make sure we don't have multiple phyloreferences with the same label, since
  // we name the file after the phyloreference being produced.
  if (has(phyxProduced, phylorefLabel)) {
    process.stderr.write(`Duplicate phyloreference label '${phylorefLabel}', skipping.`);
    countErrors += 1;
    return;
  }

  // We should never have an actual value for entry.citations.description; if we do,
  // we might be misinterpreting the input and should exit with an error.
  if (has(entry.citations, 'description')) {
    // The Regnum dumps contains citations marked "description" that are empty.
    // Since convertCitationsToBibJSON() removes citations that don't have a title and a
    // year, we can use it to check whether the "description" citation(s) are
    // empty or contain an actual citation. In the latter case, we throw an Error
    // so we fail with an error.
    const descriptionCitations = convertCitationsToBibJSON(entry.citations.description);

    if (descriptionCitations.length > 0) {
      throw new Error(`Citation of type 'description' found in entry: ${
        JSON.stringify(convertCitationsToBibJSON(entry.citations.definitional), null, 4)
      }`);
    }
  }

  // Create an object describing this phyloreference.
  const phylorefTemplate = pickBy({
    regnumId: entry.id,
    label: phylorefLabel,
    'dwc:scientificNameAuthorship': (convertAuthorsIntoStrings(entry.authors)).join(', '),
    'dwc:namePublishedIn': convertCitationsToBibJSON(entry.citations.preexisting),
    'obo:IAO_0000119': // IAO:definition source (http://purl.obolibrary.org/obo/IAO_0000119)
      convertCitationsToBibJSON(entry.citations.definitional),
    cladeDefinition: (entry.definition || '').trim(),
    internalSpecifiers: [],
    externalSpecifiers: [],
  });

  // Do we have any phylogenies to save?
  const primaryPhylogenyCitation = convertCitationsToBibJSON(entry.citations.primary_phylogeny).map(
    phylogeny => pickBy({ primaryPhylogenyCitation: phylogeny })
  );
  const phylogenyCitation = convertCitationsToBibJSON(entry.citations.phylogeny).map(
    phylogeny => pickBy({ phylogenyCitation: phylogeny })
  );
  const phylogenies = primaryPhylogenyCitation.concat(phylogenyCitation).filter(
    phylogeny => !isEmpty(phylogeny)
  );

  // Convert each specifier into one
  (entry.specifiers || []).forEach((specifier) => {
    const kind = specifier.specifier_kind || '';
    let addTo = [];
    if (kind.startsWith('internal')) addTo = phylorefTemplate.internalSpecifiers;
    else if (kind.startsWith('external')) addTo = phylorefTemplate.externalSpecifiers;
    else {
      process.stderr.write(`Unknown specifier type: '${kind}' for phyloreference '${phylorefLabel}'.\n`);
      countErrors += 1;
    }

    // Set up specifier name, authorship and nomenclatural code.
    const specifierName = (specifier.specifier_name || '').trim();
    const specifierAuthors = (specifier.displayAuths || '').trim();
    const specifierCode = (specifier.specifier_code || '').trim();

    // Do we have authors? If so, incorporate them into the specifier authors.
    // Otherwise, just use the year.
    let specifierAuthority = (specifier.specifier_year || '').trim();
    if (specifierAuthors.length > 0) {
      specifierAuthority = `${specifierAuthors}, ${(specifier.specifier_year || '').trim()}`;
    }

    // Write out a scientificName that includes the specifier name as well as its
    // nomenclatural authority, if present.
    const scname = `${specifierName} ${specifierAuthority}`.trim();
    const specifierTemplate = {
      verbatimSpecifier: scname,
      scientificName: scname,
      canonicalName: specifierName,
      nomenclaturalCode: specifierCode,
    };

    addTo.push(specifierTemplate);
  });

  // Prepare a simple Phyx file template.
  const phyxTemplate = pickBy({
    '@context': PHYX_CONTEXT_URL,
    phylogenies,
    phylorefs: [phylorefTemplate],
  });

  // Write out Phyx file for this phyloreference.
  const phyxFilename = path.join(argv.outputDir, `${phylorefLabel}.json`);
  fs.writeFileSync(phyxFilename, JSON.stringify(phyxTemplate, null, 4));

  // Save for later use if needed.
  phyxProduced[phylorefLabel] = entry;
});

// If there were any errors, report this and exit with a failure code.
if (countErrors > 0) {
  process.stderr.write(`${countErrors} errors occurred while processing database dump.\n`);
  process.exit(1);
} else {
  process.stdout.write(`${keys(phyxProduced).length} Phyx files produced successfully.\n`);
}
<commit_msg>Updated overall format of specifier to model 2.<commit_after>/*
 * regnum2phyx.js: A tool for converting PhyloRegnum database dumps to Phyx files.
 *
 * Synopsis:
 *  regnum2phyx.js [JSON file to process] -o [directory to write files to]
 *
 * Note that existing files in the output directory will be silently overwritten,
 * so this script should usually be run on a new, empty output directory.
 *
 * PhyloRegnum can be accessed at http://app.phyloregnum.org
 */

// We currently produce Phyx files in v0.2.0 format. If this changes, please
// update this here.
const PHYX_CONTEXT_URL = 'http://www.phyloref.org/phyx.js/context/v0.2.0/phyx.json';

// Some constants for nomenclatural codes. We should really export these in Phyx
// (see https://github.com/phyloref/phyx.js/issues/44)
const NAME_IN_UNKNOWN_CODE = 'http://purl.obolibrary.org/obo/NOMEN_0000036';
const ICZN_NAME = 'http://purl.obolibrary.org/obo/NOMEN_0000107';
const ICN_NAME = 'http://purl.obolibrary.org/obo/NOMEN_0000109';
const ICNP_NAME = 'http://purl.obolibrary.org/obo/NOMEN_0000110';
const ICTV_NAME = 'http://purl.obolibrary.org/obo/NOMEN_0000111';

// Load necessary modules.
const fs = require('fs');
const path = require('path');
const yargs = require('yargs');
const {
  has, keys, pickBy, isEmpty,
} = require('lodash');

// Helper functions.
function convertAuthorsIntoStrings(authors, lastNameFirst = true) {
  // Given a list of authors with first_name, middle_name and last_name properties,
  // return a list of author names with a single name.
  //
  // We combine author names in two possible ways:
  //  If lastNameFirst is true: $last_name $first_name $middle_name
  //  If lastNameFirst is false: $first_name $middle_name $last_name
  // The middle name will be ignored if it is blank or not present.

  if (lastNameFirst) {
    // Use "last first middle".
    return authors.map(author => (
      `${author.last_name || ''}, ${author.first_name || ''}${
        ((has(author, 'middle_name') && author.middle_name.trim() !== '') ? ` ${author.middle_name}` : '')
      }`.trim()
    )).filter(name => name !== '');
  }

  // Use "first middle last".
  return authors.map(author => (
    `${author.first_name || ''} ${
      ((has(author, 'middle_name') && author.middle_name.trim() !== '') ? `${author.middle_name} ` : '')
    }${author.last_name || ''}`.trim()
  )).filter(name => name !== '');
}

function convertAuthorsIntoBibJSON(authors) {
  // Convert a list of authors in the Regnum dump format into a list of authors
  // in the BibJSON format (http://okfnlabs.org/bibjson/). Names without a
  // last name will be ignored.
  return authors
    .filter(author => author.last_name)
    .map(author => pickBy({ // lodash.pickBy will remove empty keys from the object.
      // We store the author name as first_name middle_name last_name
      name: convertAuthorsIntoStrings([author], false).join(),
      alternate: [
        // We store an alternate author name as last_name, first_name middle_name.
        convertAuthorsIntoStrings([author], true).join(),
      ],
      firstname: (author.first_name || '').trim(),
      lastname: (author.last_name || '').trim(),
      middlename: (author.middle_name || '').trim(),
    }));
}

function convertCitationsToBibJSON(citation) {
  // Convert a citation from its Regnum representation into the
  // BibJSON format (http://okfnlabs.org/bibjson/). We use this rather than
  // CSL-JSON (https://github.com/citation-style-language/schema) because it's
  // easier to set up. We might want to switch over to CSL-JSON
  // eventually (https://github.com/phyloref/clade-ontology/issues/69).

  if (!citation) return [];
  if (Array.isArray(citation)) {
    // If given an array of citation objects, convert each one separately.
    return citation.map(c => convertCitationsToBibJSON(c))
      .reduce((acc, val) => acc.concat(val), []);
  }

  // Do we have a title and a year? If not, skip this entry.
  if (
    citation.title === undefined || citation.title.trim() === ''
    || citation.year === undefined || citation.year.trim() === ''
  ) {
    return [];
  }

  // Assume a default type of 'article' if none was provided.
  let type = citation.citation_type || 'article';

  // Regnum uses 'journal' where BibJSON uses 'article'.
  if (type === 'journal') type = 'article';

  // In BibJSON, identifiers are kept separate from URLs.
  const identifiers = [];
  if (citation.doi) identifiers.push({ type: 'doi', id: citation.doi });

  const urls = [];
  if (citation.url) urls.push({ url: citation.url });

  // lodash.pickBy will remove empty keys from the object.
  const entry = pickBy({
    type,
    title: (citation.title || '').trim(),
    section_title: (citation.section_title || '').trim(),
    year: Number((citation.year || '')),
    edition: (citation.edition || '').trim(),
    authors: convertAuthorsIntoBibJSON(citation.authors),
    editors: convertAuthorsIntoBibJSON(citation.editors || []),
    series_editors: convertAuthorsIntoBibJSON(citation.series_editors || []),
    publisher: (citation.publisher || '').trim(),
    city: (citation.city || '').trim(),
    pages: (citation.pages || '').trim(),
    figure: (citation.figure || '').trim(),
    // keywords: (citation.keyword || '').trim(), -- We really don't need this.
    identifier: identifiers,
    link: urls,
  });

  if (type === 'book' || type === 'book_section') {
    // Add the ISBN to the entry itself.
    if (citation.isbn) {
      identifiers.push({ type: 'isbn', id: citation.isbn });
    }
  } else if (type === 'article') {
    // Identify journal identifiers, such as the
    const journalIdentifiers = [];
    if (citation.isbn) {
      journalIdentifiers.push({ type: 'isbn', id: citation.isbn });
    }
    if (citation.issn) {
      journalIdentifiers.push({ type: 'issn', id: citation.issn });
    }

    // In BibJSON (http://okfnlabs.org/bibjson/), the journal name, volume, number
    // and pages should go into the 'journal' object.
    entry.journal = pickBy({
      name: (citation.journal || '').trim(),
      volume: (citation.volume || '').trim(),
      number: (citation.number || '').trim(),
      identifier: journalIdentifiers,
    });

    // Since we've moved pages and ISBN into journal, we don't also need it in the main entry.
    if (has(entry, 'pages')) delete entry.pages;
  } else {
    process.stderr.write(`Unknown citation type: '${type}', using anyway.`);
  }

  return [entry];
}

// Command line application starts here.

// Read command-line arguments.
const argv = yargs
  .usage('Usage: $0 <JSON file to process> -o <directory to write files to>')
  .demandCommand(1, 1) // Make sure there's one and only one file to convert.
  .option('output-dir', {
    alias: 'o',
    describe: 'Directory to write Phyx files to',
  })
  .demandOption(['o'])
  .help('h')
  .alias('h', 'help')
  .argv;

// Read the database dump.
const dump = JSON.parse(fs.readFileSync(argv._[0], 'utf8'));

// This dump consists of multiple named phylogenetic clade definitions,
// each of which should be written out to a separate file.
const phyxProduced = {};
let countErrors = 0;

// Loop through all phylorefs in the database dump.
dump.forEach((entry) => {
  const phylorefLabel = entry.name.trim();

  // Make sure we don't have multiple phyloreferences with the same label, since
  // we name the file after the phyloreference being produced.
  if (has(phyxProduced, phylorefLabel)) {
    process.stderr.write(`Duplicate phyloreference label '${phylorefLabel}', skipping.`);
    countErrors += 1;
    return;
  }

  // We should never have an actual value for entry.citations.description; if we do,
  // we might be misinterpreting the input and should exit with an error.
  if (has(entry.citations, 'description')) {
    // The Regnum dumps contains citations marked "description" that are empty.
    // Since convertCitationsToBibJSON() removes citations that don't have a title and a
    // year, we can use it to check whether the "description" citation(s) are
    // empty or contain an actual citation. In the latter case, we throw an Error
    // so we fail with an error.
    const descriptionCitations = convertCitationsToBibJSON(entry.citations.description);

    if (descriptionCitations.length > 0) {
      throw new Error(`Citation of type 'description' found in entry: ${
        JSON.stringify(convertCitationsToBibJSON(entry.citations.definitional), null, 4)
      }`);
    }
  }

  // Create an object describing this phyloreference.
  const phylorefTemplate = pickBy({
    regnumId: entry.id,
    label: phylorefLabel,
    'dwc:scientificNameAuthorship': (convertAuthorsIntoStrings(entry.authors)).join(', '),
    'dwc:namePublishedIn': convertCitationsToBibJSON(entry.citations.preexisting),
    'obo:IAO_0000119': // IAO:definition source (http://purl.obolibrary.org/obo/IAO_0000119)
      convertCitationsToBibJSON(entry.citations.definitional),
    cladeDefinition: (entry.definition || '').trim(),
    internalSpecifiers: [],
    externalSpecifiers: [],
  });

  // Do we have any phylogenies to save?
  const primaryPhylogenyCitation = convertCitationsToBibJSON(entry.citations.primary_phylogeny).map(
    phylogeny => pickBy({ primaryPhylogenyCitation: phylogeny })
  );
  const phylogenyCitation = convertCitationsToBibJSON(entry.citations.phylogeny).map(
    phylogeny => pickBy({ phylogenyCitation: phylogeny })
  );
  const phylogenies = primaryPhylogenyCitation.concat(phylogenyCitation).filter(
    phylogeny => !isEmpty(phylogeny)
  );

  // Convert each specifier into one
  (entry.specifiers || []).forEach((specifier) => {
    const kind = specifier.specifier_kind || '';
    let addTo = [];
    if (kind.startsWith('internal')) addTo = phylorefTemplate.internalSpecifiers;
    else if (kind.startsWith('external')) addTo = phylorefTemplate.externalSpecifiers;
    else {
      process.stderr.write(`Unknown specifier type: '${kind}' for phyloreference '${phylorefLabel}'.\n`);
      countErrors += 1;
    }

    // Set up specifier name, authorship and nomenclatural code.
    const specifierName = (specifier.specifier_name || '').trim();
    const specifierAuthors = (specifier.displayAuths || '').trim();
    const specifierCode = (specifier.specifier_code || '').trim();

    let nomenCode = NAME_IN_UNKNOWN_CODE;
    switch(specifierCode) {
      case 'ICZN':
        nomenCode = ICZN_NAME;
        break;
      case 'ICBN':
        nomenCode = ICN_NAME;
        break;
      case '':
        nomenCode = NAME_IN_UNKNOWN_CODE;
        break;
      default:
        throw new Error("Unknown specifier_code: '" + specifierCode + "'")
    }

    // Do we have authors? If so, incorporate them into the specifier authors.
    // Otherwise, just use the year.
    let specifierAuthority = (specifier.specifier_year || '').trim();
    if (specifierAuthors.length > 0) {
      specifierAuthority = `${specifierAuthors}, ${(specifier.specifier_year || '').trim()}`;
    }

    // TODO: split name into genus/specifier.

    // Write out a scientificName that includes the specifier name as well as its
    // nomenclatural authority, if present.
    const scname = `${specifierName} ${specifierAuthority}`.trim();
    const specifierTemplate = {
      "@type": "http://rs.tdwg.org/ontology/voc/TaxonConcept#TaxonConcept",
      "hasName": {
          "@type": "http://rs.tdwg.org/ontology/voc/TaxonName#TaxonName",
          "nomenclaturalCode": nomenCode,
          "label": scname,
          "nameComplete": specifierName
      }
    };

    addTo.push(specifierTemplate);
  });

  // Prepare a simple Phyx file template.
  const phyxTemplate = pickBy({
    '@context': PHYX_CONTEXT_URL,
    phylogenies,
    phylorefs: [phylorefTemplate],
  });

  // Write out Phyx file for this phyloreference.
  const phyxFilename = path.join(argv.outputDir, `${phylorefLabel}.json`);
  fs.writeFileSync(phyxFilename, JSON.stringify(phyxTemplate, null, 4));

  // Save for later use if needed.
  phyxProduced[phylorefLabel] = entry;
});

// If there were any errors, report this and exit with a failure code.
if (countErrors > 0) {
  process.stderr.write(`${countErrors} errors occurred while processing database dump.\n`);
  process.exit(1);
} else {
  process.stdout.write(`${keys(phyxProduced).length} Phyx files produced successfully.\n`);
}
<|endoftext|>


<commit_before>import initBatch from 'src/util/promise-batcher'
import { updatePageSearchIndex } from 'src/search/find-pages'
import importHistory, { getHistoryEstimates } from './import-history'
import processImportDoc from './import-doc-processor'
import {
    lastImportTimeStorageKey, importProgressStorageKey,
    setImportDocStatus, getImportDocs,
} from './'

// Local storage helpers to make the main functions a bit less messy
const getLastImportTime = async () =>
    (await browser.storage.local.get(lastImportTimeStorageKey))[lastImportTimeStorageKey]
const setLastImportTime = async () =>
    (await browser.storage.local.set({ [lastImportTimeStorageKey]: Date.now() }))
const getImportInProgressFlag = async () =>
    (await browser.storage.local.get(importProgressStorageKey))[importProgressStorageKey]
const setImportInProgressFlag = async () =>
    (await browser.storage.local.set({ [importProgressStorageKey]: true }))
const clearImportInProgressFlag = async () =>
    await browser.storage.local.remove(importProgressStorageKey)

/**
 * Creates observer functions to afford sending of messages over connection port
 * to UI on certain batcher events.
 *
 * @param {Port} port The open connection port to send messages over.
 */
const getBatchObserver = port => ({
    // Triggers on the successful finish of each batch input
    next({ input: { _id: importDocId, url } }) {
        // Send success data to listener
        port.postMessage({ cmd: 'NEXT', url })
        setImportDocStatus(importDocId, 'success')
    },
    // Triggers on any error during the processing of each batch input
    error({ input: { _id: importDocId, url }, error }) {
        // Send error data to listener
        port.postMessage({ cmd: 'NEXT', url, error })
        setImportDocStatus(importDocId, 'fail')
    },
    // Triggers after all inputs have been batch processed, regardless of success
    async complete() {
        // Final reindexing so that all the finished docs are searchable
        await updatePageSearchIndex()

        // Tell UI that it's finished
        port.postMessage({ cmd: 'COMPLETE' })
        clearImportInProgressFlag()
    },
})

/**
 * Handles calculating the estimate counts for history and bookmark imports.
 * @returns {any} The state containing import estimates completed and remaining counts.
 */
async function getEstimateCounts() {
    // Check if the importHistory stage was run previously to search history from that time
    const startTime = await getLastImportTime()

    const { completed: histCompleted, remaining: histRemaining } = await getHistoryEstimates({ startTime })
    // TODO: switch this with async getBookmarkEstimates call when implemented
    const bmCompleted = 10
    const bmRemaining = 0

    return {
        completed: {
            history: histCompleted,
            bookmark: bmCompleted,
        },
        remaining: {
            history: histRemaining,
            bookmark: bmRemaining,
        },
    }
}

/**
 * Handles fetching the input/state for the batcher (pending import docs).
 * @return Array<ImportDoc> The input derived from stored DB import docs with pending status.
 */
async function getBatchInput() {
    const fields = ['_id', 'url', 'type', 'dataDocId']
    const { docs } = await getImportDocs({ status: 'pending' }, fields)
    return docs
}

/**
 * Essentially the logic which happens when the user presses the "Start Import" button.
 * @param {any} batch The init'd batcher to init with input and then start.
 */
async function startImport(port, batch) {
    // Check if the importHistory stage was run previously to search history from that time
    const startTime = await getLastImportTime()

    // Perform history-stubs, vists, and history import docs creation, if import not in progress
    const importInProgress = await getImportInProgressFlag()
    if (!importInProgress) {
        await importHistory({ startTime })
    }

    // Tell UI to finish loading state and move into progress view
    port.postMessage({ cmd: 'START' })

    setLastImportTime()
    setImportInProgressFlag()

    // Start the batcher with needed input
    batch.init(await getBatchInput())
    batch.start()
}

/**
 * The cleanup logic that happens when user chooses to finish an import
 * (either after completion or cancellation).
 */
async function finishImport(port) {
    clearImportInProgressFlag()

    // Re-init the estimates view with updated estimates data
    const estimateCounts = await getEstimateCounts()
    port.postMessage({ cmd: 'INIT', ...estimateCounts })
}

/**
 * Main connection handler to handle background importing and fetch&analysis batching
 * logic via commands issued from the UI.
 */
export default async function importsConnectionHandler(port) {
    // Make sure to only handle connection logic for imports (allows other use of runtime.connect)
    if (port.name !== 'imports') return

    console.log('importer connected')

    const batch = initBatch({
        asyncCallback: processImportDoc,
        concurrency: 5,
        observer: getBatchObserver(port),
    })

    // If import isn't started earlier, get estimates and set view state to init
    const importInProgress = await getImportInProgressFlag()
    if (!importInProgress) {
        // Make sure estimates view init'd with count data
        const estimateCounts = await getEstimateCounts()
        port.postMessage({ cmd: 'INIT', ...estimateCounts })
    } else {
        // If import is in progress, we need to make sure it's input is ready to process again
        batch.init(await getBatchInput())
        // Make sure to start the view in paused state
        port.postMessage({ cmd: 'PAUSE' })
    }

    // Handle any incoming messages to control the batch
    port.onMessage.addListener(async ({ cmd }) => {
        switch (cmd) {
            case 'START': return await startImport(port, batch)
            case 'RESUME': return batch.start()
            case 'PAUSE': return batch.pause()
            case 'STOP': return batch.stop()
            case 'FINISH': return await finishImport(port)
            default: return console.error(`unknown command: ${cmd}`)
        }
    })
}
<commit_msg>Allow BG batch observer to send more data to UI state<commit_after>import initBatch from 'src/util/promise-batcher'
import { updatePageSearchIndex } from 'src/search/find-pages'
import importHistory, { getHistoryEstimates } from './import-history'
import processImportDoc from './import-doc-processor'
import {
    lastImportTimeStorageKey, importProgressStorageKey,
    setImportDocStatus, getImportDocs,
} from './'

// Local storage helpers to make the main functions a bit less messy
const getLastImportTime = async () =>
    (await browser.storage.local.get(lastImportTimeStorageKey))[lastImportTimeStorageKey]
const setLastImportTime = async () =>
    (await browser.storage.local.set({ [lastImportTimeStorageKey]: Date.now() }))
const getImportInProgressFlag = async () =>
    (await browser.storage.local.get(importProgressStorageKey))[importProgressStorageKey]
const setImportInProgressFlag = async () =>
    (await browser.storage.local.set({ [importProgressStorageKey]: true }))
const clearImportInProgressFlag = async () =>
    await browser.storage.local.remove(importProgressStorageKey)

/**
 * Creates observer functions to afford sending of messages over connection port
 * to UI on certain batcher events. Note that next (success) and error handlers are pretty
 * much the same; they either contain error or output/status keys, which UI handles if present.
 *
 * @param {Port} port The open connection port to send messages over.
 */
const getBatchObserver = port => {
    const handleFinishedItem = docStatus => ({ input: { _id: importDocId, url, type }, output, error }) => {
        // Send item data + outcome status down to UI (and error if present)
        port.postMessage({ cmd: 'NEXT', url, type, status: output, error })
        setImportDocStatus(importDocId, docStatus)
    }

    return {
        next: handleFinishedItem('success'), // Triggers on the successful finish of each batch input
        error: handleFinishedItem('fail'), // Triggers on any error thrown during the processing of each input
        async complete() { // Triggers when ALL batch inputs are finished
            // Final reindexing so that all the finished docs are searchable
            await updatePageSearchIndex()

            // Tell UI that it's finished
            port.postMessage({ cmd: 'COMPLETE' })
            clearImportInProgressFlag()
        },
    }
}

/**
 * Handles calculating the estimate counts for history and bookmark imports.
 * @returns {any} The state containing import estimates completed and remaining counts.
 */
async function getEstimateCounts() {
    // Check if the importHistory stage was run previously to search history from that time
    const startTime = await getLastImportTime()

    const { completed: histCompleted, remaining: histRemaining } = await getHistoryEstimates({ startTime })
    // TODO: switch this with async getBookmarkEstimates call when implemented
    const bmCompleted = 10
    const bmRemaining = 0

    return {
        completed: {
            history: histCompleted,
            bookmark: bmCompleted,
        },
        remaining: {
            history: histRemaining,
            bookmark: bmRemaining,
        },
    }
}

/**
 * Handles fetching the input/state for the batcher (pending import docs).
 * @return Array<ImportDoc> The input derived from stored DB import docs with pending status.
 */
async function getBatchInput() {
    const fields = ['_id', 'url', 'type', 'dataDocId']
    const { docs } = await getImportDocs({ status: 'pending' }, fields)
    return docs
}

/**
 * Essentially the logic which happens when the user presses the "Start Import" button.
 * @param {any} batch The init'd batcher to init with input and then start.
 */
async function startImport(port, batch) {
    // Check if the importHistory stage was run previously to search history from that time
    const startTime = await getLastImportTime()

    // Perform history-stubs, vists, and history import docs creation, if import not in progress
    const importInProgress = await getImportInProgressFlag()
    if (!importInProgress) {
        await importHistory({ startTime })
    }

    // Tell UI to finish loading state and move into progress view
    port.postMessage({ cmd: 'START' })

    setLastImportTime()
    setImportInProgressFlag()

    // Start the batcher with needed input
    batch.init(await getBatchInput())
    batch.start()
}

/**
 * The cleanup logic that happens when user chooses to finish an import
 * (either after completion or cancellation).
 */
async function finishImport(port) {
    clearImportInProgressFlag()

    // Re-init the estimates view with updated estimates data
    const estimateCounts = await getEstimateCounts()
    port.postMessage({ cmd: 'INIT', ...estimateCounts })
}

/**
 * Main connection handler to handle background importing and fetch&analysis batching
 * logic via commands issued from the UI.
 */
export default async function importsConnectionHandler(port) {
    // Make sure to only handle connection logic for imports (allows other use of runtime.connect)
    if (port.name !== 'imports') return

    console.log('importer connected')

    const batch = initBatch({
        asyncCallback: processImportDoc,
        concurrency: 5,
        observer: getBatchObserver(port),
    })

    // If import isn't started earlier, get estimates and set view state to init
    const importInProgress = await getImportInProgressFlag()
    if (!importInProgress) {
        // Make sure estimates view init'd with count data
        const estimateCounts = await getEstimateCounts()
        port.postMessage({ cmd: 'INIT', ...estimateCounts })
    } else {
        // If import is in progress, we need to make sure it's input is ready to process again
        batch.init(await getBatchInput())
        // Make sure to start the view in paused state
        port.postMessage({ cmd: 'PAUSE' })
    }

    // Handle any incoming messages to control the batch
    port.onMessage.addListener(async ({ cmd }) => {
        switch (cmd) {
            case 'START': return await startImport(port, batch)
            case 'RESUME': return batch.start()
            case 'PAUSE': return batch.pause()
            case 'STOP': return batch.stop()
            case 'FINISH': return await finishImport(port)
            default: return console.error(`unknown command: ${cmd}`)
        }
    })
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { autoPlayGif } from '../initial_state';
import classNames from 'classnames';

export default class Avatar extends React.PureComponent {

  static propTypes = {
    account: ImmutablePropTypes.map,
    size: PropTypes.number.isRequired,
    style: PropTypes.object,
    inline: PropTypes.bool,
    animate: PropTypes.bool,
  };

  static defaultProps = {
    animate: autoPlayGif,
    size: 20,
    inline: false,
  };

  state = {
    hovering: false,
  };

  handleMouseEnter = () => {
    if (this.props.animate) return;
    this.setState({ hovering: true });
  }

  handleMouseLeave = () => {
    if (this.props.animate) return;
    this.setState({ hovering: false });
  }

  render () {
    const { account, size, animate, inline } = this.props;
    const { hovering } = this.state;

    const style = {
      ...this.props.style,
      width: `${size}px`,
      height: `${size}px`,
      backgroundSize: `${size}px ${size}px`,
    };

    if (account) {
      const src = account.get('avatar');
      const staticSrc = account.get('avatar_static');

      if (hovering || animate) {
        style.backgroundImage = `url(${src})`;
      } else {
        style.backgroundImage = `url(${staticSrc})`;
      }
    }

    return (
      <div
        className={classNames('account__avatar', { 'account__avatar-inline': inline })}
        onMouseEnter={this.handleMouseEnter}
        onMouseLeave={this.handleMouseLeave}
        style={style}
        role='img'
        aria-label={account.get('acct')}
      />
    );
  }

}
<commit_msg>Fix error when rendering limited account in web UI (#19413)<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { autoPlayGif } from '../initial_state';
import classNames from 'classnames';

export default class Avatar extends React.PureComponent {

  static propTypes = {
    account: ImmutablePropTypes.map,
    size: PropTypes.number.isRequired,
    style: PropTypes.object,
    inline: PropTypes.bool,
    animate: PropTypes.bool,
  };

  static defaultProps = {
    animate: autoPlayGif,
    size: 20,
    inline: false,
  };

  state = {
    hovering: false,
  };

  handleMouseEnter = () => {
    if (this.props.animate) return;
    this.setState({ hovering: true });
  }

  handleMouseLeave = () => {
    if (this.props.animate) return;
    this.setState({ hovering: false });
  }

  render () {
    const { account, size, animate, inline } = this.props;
    const { hovering } = this.state;

    const style = {
      ...this.props.style,
      width: `${size}px`,
      height: `${size}px`,
      backgroundSize: `${size}px ${size}px`,
    };

    if (account) {
      const src = account.get('avatar');
      const staticSrc = account.get('avatar_static');

      if (hovering || animate) {
        style.backgroundImage = `url(${src})`;
      } else {
        style.backgroundImage = `url(${staticSrc})`;
      }
    }

    return (
      <div
        className={classNames('account__avatar', { 'account__avatar-inline': inline })}
        onMouseEnter={this.handleMouseEnter}
        onMouseLeave={this.handleMouseLeave}
        style={style}
        role='img'
        aria-label={account?.get('acct')}
      />
    );
  }

}
<|endoftext|>


<commit_before>var path = require("path");
var param = require("../core/params_analyze.js");
var child_process = require("child_process");
var globals = require("../core/globals");
var create_file_list = require("./create_file_list.js")
var file = require("../core/file.js");

/**
 * Constructs a new ClosureCompiler instance.
 * @exports ClosureCompiler
 * @class Closure Compiler binding.
 * @param {Object.<string,*>=} options Compilation options
 * @constructor
 */
var ClosureCompiler = function (options) {

    /**
     * Compilation options.
     * @type {Object.<string, *>}
     */
    this.options = typeof options == 'object' ? options : {};
    try {
        Object.keys(this.options);
    } catch (e) {
        this.options = {};
    }
};

/**
 * Validates an option.
 * @param {string} name Option name
 * @param {string} actual Actual value
 * @param {Array} expected Expected values
 * @throw {Error} If the option is invalid
 * @return {string} Validated option
 * @private
 */
ClosureCompiler._assertOption = function (name, actual, expected) {
    if (expected.indexOf(actual) < 0) {
        throw("Illegal " + name + " value: " + actual + " (" + expected + " expected)");
    }
};

/**
 * Java extension, e.g. '.exe' on windows.
 * @type {string}
 * @expose
 */
ClosureCompiler.JAVA_EXT = process.platform == 'win32' ? '.exe' : '';

/**
 * Gets the path of the global java executable.
 * @return {string} Absolute path to or "java(.exe)" if not determinable
 * @expose
 */
ClosureCompiler.getGlobalJava = function () {
    var java = null;

    if (process.env["JAVA_HOME"]) {
        java = path.join(process.env["JAVA_HOME"], "bin", "java" + ClosureCompiler.JAVA_EXT);
        if (!file.exists(java)) {
            java = null;
        }
    }
    if (!java) {
        java = "java";
    }
    return java;
};

/**
 * Gets the path of the bundled java executable.
 * @return {string} Absolute path to "java(.exe)"
 * @expose
 */
ClosureCompiler.getBundledJava = function () {
    return path.normalize(path.join(__dirname, "jre", "bin", "java" + ClosureCompiler.JAVA_EXT));
};

/**
 * Tests if java is callable.
 * @param {string} java Path to java
 * @param {function(boolean, Error)} callback Callback function
 * @expose
 */
ClosureCompiler.testJava = function (java, callback) {
    child_process.exec('"' + java + '" -version', {}, function (error, stdout, stderr) {
        stderr += "";
        if (stderr.indexOf("version \"1.7.") >= 0 || stderr.indexOf("version \"1.8.") >= 0) {
            callback(true, null);
        } else if (stderr.indexOf("version \"") >= 0) {
            callback(false, new Error("Not Java 7"));
        } else {
            callback(false, error);
        }
    });
};

/**
 * Compiles one or more scripts through a new instance of ClosureCompiler.
 * @param {string|Array.<string>} files File or an array of files to compile
 * @param {Object.<string,*|Array>} options Any options Closure Compiler supports. If an option can occur
 *  multiple times, simply supply an array. Externs can additionally point to a directory to include all *.js files
 *  in it.
 * @param {function(Error,string)} callback Callback called with the error, if any, and the compiled code
 * @throws {Error} If the file cannot be compiled
 * @expose
 */
ClosureCompiler.compile = function (files, options, callback) {
    new ClosureCompiler(options).compile(files, callback);
};

/**
 * Compiles one or more scripts through this instance of ClosureCompiler.
 * @param {string|Array.<string>} files File or an array of files to compile
 * @param {function((Error|string),string)} callback Callback called with the error, if any, and the compiled code.
 *  If no error occurred, error contains the string output from stderr besides the result.
 * @throws {Error} If the file cannot be compiled
 * @expose
 */
ClosureCompiler.prototype.compile = function (files, callback) {

    // Convert all option keys to lower case
    var options = {};
    var keys = Object.keys(this.options);
    for (var i = 0; i < keys.length; i++) {
        options[keys[i].toLowerCase()] = this.options[keys[i]];
    }
    delete options["js"];

    var compilerPath = path.join(param.getEgretPath(), "tools/lib/google-closure/compiler.jar");
    var args = '-client -jar "' + compilerPath + '"';

    // Source files
    if (!(files instanceof Array)) {
        files = [files];
    }
    for (i = 0; i < files.length; i++) {
        if (typeof files[i] != 'string' || files[i].indexOf('"') >= 0) {
            throw(new Error("Illegal source file: " + files[i]));
        }
        if (!file.isFile(files[i])) {
            throw(new Error("Source file not found: " + files[i]));
        }
        args += ' --js "' + files[i] + '"';
    }

    // Externs files
    if (!options.externs) options.externs = [];
    if (!(options.externs instanceof Array)) {
        options.externs = [options.externs];
    }
    var externs = [];
    var j, stat;
    for (i = 0; i < options.externs.length; i++) {
        if (typeof options.externs[i] != 'string' || options.externs[i] == "") {
            throw(new Error("Externs directive does not point to a file or directory: " + options.externs[i]));
        }
        if (options.externs[i].toLowerCase() == "node") {
            options.externs[i] = __dirname + "/node_modules/closurecompiler-externs";
        }
        if (file.isDirectory(options.externs[i])) {
            // Use all files in that directory
            var dfiles = file.getDirectoryListing(options.externs[i]);
            for (j = 0; j < dfiles.length; j++) {
                var fname = dfiles[j];
                if (file.isFile(fname) && file.getExtension(fname).toLowerCase() == 'js') {
                    externs.push(fname);
                }
            }
        } else if (file.isFile(options.externs[i])) {
            externs.push(options.externs[i]);
        } else {
            throw(new Error("Externs file not found: " + options.externs[i]));
        }
    }

    delete options["externs"];
    for (i = 0; i < externs.length; i++) {
        args += ' --externs "' + externs[i] + '"';
    }

    // Convert any other options to command line arguments
    keys = Object.keys(options);
    for (i = 0; i < keys.length; i++) {
        var key = keys[i];
        var value = options[keys[i]];
        if (!/[a-zA-Z0-9_]+/.test(key)) {
            throw(new Error("Illegal option: " + key));
        }
        if (value === true) { // Only once
            args += ' --' + key;
        } else if (value === false) {
            // Skip
        } else { // Multiple times
            if (!(value instanceof Array)) {
                value = [value];
            }
            for (j = 0; j < value.length; j++) {
                if (!/[^\s]*/.test(value[j])) {
                    throw(new Error("Illegal value for option " + key + ": " + value[j]));
                }
                args += ' --' + key + ' ' + value[j];
            }
        }

    }

    function exec(cmd, callback) {
        require("child_process").exec(cmd, {maxBuffer: 20 * 1024 * 1024}, callback);
    }

    function run(java, args) {
        exec('"' + java + '" ' + args, function (error, stdout, stderr) {
            if (stdout.length > 0 || stderr.length > 0) { // If we get output, error basically just contains a copy of stderr
                callback(stderr + "", stdout + "");
            } else {
                callback(error, null);
            }
        });
    }

    // Try any other global java
    ClosureCompiler.testJava(ClosureCompiler.getGlobalJava(), function (ok) {
        if (ok) {
            run(ClosureCompiler.getGlobalJava(), args);
        } else {
            // If there is no global java, try the bundled one
            ClosureCompiler.testJava(ClosureCompiler.getBundledJava(), function (ok) {
                if (ok) {
                    run(ClosureCompiler.getBundledJava(), args);
                } else {
                    globals.exit(1401);
                }
            });
        }
    });

};

function getFileList(file_list) {
    if (file.exists(file_list)) {
        var js_content = file.read(file_list);
        eval(js_content);
        var path = require("path");
        var varname = path.basename(file_list).split(".js")[0];
        return eval(varname);
    }
    else {
        globals.exit(1301, file_list);
    }
}

function run(dir, args, opts) {
    var currDir = globals.joinEgretDir(dir, args[0]);

    var egret_file = path.join(currDir, "bin-debug/lib/egret_file_list.js");
    var egretFileList = getFileList(egret_file);
    egretFileList = egretFileList.map(function (item) {
        return path.join(currDir + "/bin-debug/lib/", item);
    });

    var game_file = path.join(currDir, "src/game_file_list.js");
    if(!file.exists(game_file)){
        game_file = currDir+"/bin-debug/src/game_file_list.js";
        var list = file.search(currDir+"/src/","ts");
        var gameListText = create_file_list.create(list,currDir+"/src/");
        file.save(game_file,gameListText);
    }
    var gameFileList = getFileList(game_file);
    gameFileList = gameFileList.map(function (item) {
        return path.join(currDir + "/bin-debug/src/", item);
    });

    var totalFileList = egretFileList.concat(gameFileList, currDir + "/launcher/egret_loader.js");
    ClosureCompiler.compile(totalFileList,
        {js_output_file: currDir + "/launcher/game-min.js"},
        function afterCompile(err, stdout, stderr) {
            console.log(err);
        });
}

function help_title() {
    return "发布项目，使用GoogleClosureCompiler压缩代码";
}

function help_example() {
    var result =  "\n";
    result += "    egret publish [project_name]\n";
    result += "描述:\n";
    result += "    " + help_title();
    return result;
}

exports.run = run;
exports.help_title = help_title;
exports.help_example = help_example;
<commit_msg>优化java版本判断<commit_after>var path = require("path");
var param = require("../core/params_analyze.js");
var child_process = require("child_process");
var globals = require("../core/globals");
var create_file_list = require("./create_file_list.js")
var file = require("../core/file.js");

/**
 * Constructs a new ClosureCompiler instance.
 * @exports ClosureCompiler
 * @class Closure Compiler binding.
 * @param {Object.<string,*>=} options Compilation options
 * @constructor
 */
var ClosureCompiler = function (options) {

    /**
     * Compilation options.
     * @type {Object.<string, *>}
     */
    this.options = typeof options == 'object' ? options : {};
    try {
        Object.keys(this.options);
    } catch (e) {
        this.options = {};
    }
};

/**
 * Validates an option.
 * @param {string} name Option name
 * @param {string} actual Actual value
 * @param {Array} expected Expected values
 * @throw {Error} If the option is invalid
 * @return {string} Validated option
 * @private
 */
ClosureCompiler._assertOption = function (name, actual, expected) {
    if (expected.indexOf(actual) < 0) {
        throw("Illegal " + name + " value: " + actual + " (" + expected + " expected)");
    }
};

/**
 * Java extension, e.g. '.exe' on windows.
 * @type {string}
 * @expose
 */
ClosureCompiler.JAVA_EXT = process.platform == 'win32' ? '.exe' : '';

/**
 * Gets the path of the global java executable.
 * @return {string} Absolute path to or "java(.exe)" if not determinable
 * @expose
 */
ClosureCompiler.getGlobalJava = function () {
    var java = null;

    if (process.env["JAVA_HOME"]) {
        java = path.join(process.env["JAVA_HOME"], "bin", "java" + ClosureCompiler.JAVA_EXT);
        if (!file.exists(java)) {
            java = null;
        }
    }
    if (!java) {
        java = "java";
    }
    return java;
};

/**
 * Gets the path of the bundled java executable.
 * @return {string} Absolute path to "java(.exe)"
 * @expose
 */
ClosureCompiler.getBundledJava = function () {
    return path.normalize(path.join(__dirname, "jre", "bin", "java" + ClosureCompiler.JAVA_EXT));
};

/**
 * Tests if java is callable.
 * @param {string} java Path to java
 * @param {function(boolean, Error)} callback Callback function
 * @expose
 */
ClosureCompiler.testJava = function (java, callback) {
    child_process.exec('"' + java + '" -version', {}, function (error, stdout, stderr) {
        stderr += "";
        var minVersionChar = "1.7";
        var m1 = 1,m2 = 7;
        var minVersion = 0;
        var re = /(\d+\.\d+)\.?/gi;
        var currentVersion = re.exec(stderr)[0];
        var v1 = currentVersion.split(".")[0];
        var v2 = currentVersion.split(".")[1];
        if(v2>9 || m2>9) {
            v2 = v2>9?v2:"0"+v2;
            m2 = m2>9?m2:"0"+m2;
        }
        minVersion = m1+"."+m2;
        currentVersion = v1+"."+v2;
        if (currentVersion>=minVersion) {
            callback(true, null);
        } else if (stderr.indexOf("version \"") >= 0) {
            callback(false, new Error("Need Java "+minVersionChar+" but current version is "+currentVersion));
        } else {
            callback(false, error);
        }
    });
};

/**
 * Compiles one or more scripts through a new instance of ClosureCompiler.
 * @param {string|Array.<string>} files File or an array of files to compile
 * @param {Object.<string,*|Array>} options Any options Closure Compiler supports. If an option can occur
 *  multiple times, simply supply an array. Externs can additionally point to a directory to include all *.js files
 *  in it.
 * @param {function(Error,string)} callback Callback called with the error, if any, and the compiled code
 * @throws {Error} If the file cannot be compiled
 * @expose
 */
ClosureCompiler.compile = function (files, options, callback) {
    new ClosureCompiler(options).compile(files, callback);
};

/**
 * Compiles one or more scripts through this instance of ClosureCompiler.
 * @param {string|Array.<string>} files File or an array of files to compile
 * @param {function((Error|string),string)} callback Callback called with the error, if any, and the compiled code.
 *  If no error occurred, error contains the string output from stderr besides the result.
 * @throws {Error} If the file cannot be compiled
 * @expose
 */
ClosureCompiler.prototype.compile = function (files, callback) {

    // Convert all option keys to lower case
    var options = {};
    var keys = Object.keys(this.options);
    for (var i = 0; i < keys.length; i++) {
        options[keys[i].toLowerCase()] = this.options[keys[i]];
    }
    delete options["js"];

    var compilerPath = path.join(param.getEgretPath(), "tools/lib/google-closure/compiler.jar");
    var args = '-client -jar "' + compilerPath + '"';

    // Source files
    if (!(files instanceof Array)) {
        files = [files];
    }
    for (i = 0; i < files.length; i++) {
        if (typeof files[i] != 'string' || files[i].indexOf('"') >= 0) {
            throw(new Error("Illegal source file: " + files[i]));
        }
        if (!file.isFile(files[i])) {
            throw(new Error("Source file not found: " + files[i]));
        }
        args += ' --js "' + files[i] + '"';
    }

    // Externs files
    if (!options.externs) options.externs = [];
    if (!(options.externs instanceof Array)) {
        options.externs = [options.externs];
    }
    var externs = [];
    var j, stat;
    for (i = 0; i < options.externs.length; i++) {
        if (typeof options.externs[i] != 'string' || options.externs[i] == "") {
            throw(new Error("Externs directive does not point to a file or directory: " + options.externs[i]));
        }
        if (options.externs[i].toLowerCase() == "node") {
            options.externs[i] = __dirname + "/node_modules/closurecompiler-externs";
        }
        if (file.isDirectory(options.externs[i])) {
            // Use all files in that directory
            var dfiles = file.getDirectoryListing(options.externs[i]);
            for (j = 0; j < dfiles.length; j++) {
                var fname = dfiles[j];
                if (file.isFile(fname) && file.getExtension(fname).toLowerCase() == 'js') {
                    externs.push(fname);
                }
            }
        } else if (file.isFile(options.externs[i])) {
            externs.push(options.externs[i]);
        } else {
            throw(new Error("Externs file not found: " + options.externs[i]));
        }
    }

    delete options["externs"];
    for (i = 0; i < externs.length; i++) {
        args += ' --externs "' + externs[i] + '"';
    }

    // Convert any other options to command line arguments
    keys = Object.keys(options);
    for (i = 0; i < keys.length; i++) {
        var key = keys[i];
        var value = options[keys[i]];
        if (!/[a-zA-Z0-9_]+/.test(key)) {
            throw(new Error("Illegal option: " + key));
        }
        if (value === true) { // Only once
            args += ' --' + key;
        } else if (value === false) {
            // Skip
        } else { // Multiple times
            if (!(value instanceof Array)) {
                value = [value];
            }
            for (j = 0; j < value.length; j++) {
                if (!/[^\s]*/.test(value[j])) {
                    throw(new Error("Illegal value for option " + key + ": " + value[j]));
                }
                args += ' --' + key + ' ' + value[j];
            }
        }

    }

    function exec(cmd, callback) {
        require("child_process").exec(cmd, {maxBuffer: 20 * 1024 * 1024}, callback);
    }

    function run(java, args) {
        exec('"' + java + '" ' + args, function (error, stdout, stderr) {
            if (stdout.length > 0 || stderr.length > 0) { // If we get output, error basically just contains a copy of stderr
                callback(stderr + "", stdout + "");
            } else {
                callback(error, null);
            }
        });
    }

    // Try any other global java
    ClosureCompiler.testJava(ClosureCompiler.getGlobalJava(), function (ok) {
        if (ok) {
            run(ClosureCompiler.getGlobalJava(), args);
        } else {
            // If there is no global java, try the bundled one
            ClosureCompiler.testJava(ClosureCompiler.getBundledJava(), function (ok) {
                if (ok) {
                    run(ClosureCompiler.getBundledJava(), args);
                } else {
                    globals.exit(1401);
                }
            });
        }
    });

};

function getFileList(file_list) {
    if (file.exists(file_list)) {
        var js_content = file.read(file_list);
        eval(js_content);
        var path = require("path");
        var varname = path.basename(file_list).split(".js")[0];
        return eval(varname);
    }
    else {
        globals.exit(1301, file_list);
    }
}

function run(dir, args, opts) {
    var currDir = globals.joinEgretDir(dir, args[0]);

    var egret_file = path.join(currDir, "bin-debug/lib/egret_file_list.js");
    var egretFileList = getFileList(egret_file);
    egretFileList = egretFileList.map(function (item) {
        return path.join(currDir + "/bin-debug/lib/", item);
    });

    var game_file = path.join(currDir, "src/game_file_list.js");
    if(!file.exists(game_file)){
        game_file = currDir+"/bin-debug/src/game_file_list.js";
        var list = file.search(currDir+"/src/","ts");
        var gameListText = create_file_list.create(list,currDir+"/src/");
        file.save(game_file,gameListText);
    }
    var gameFileList = getFileList(game_file);
    gameFileList = gameFileList.map(function (item) {
        return path.join(currDir + "/bin-debug/src/", item);
    });

    var totalFileList = egretFileList.concat(gameFileList, currDir + "/launcher/egret_loader.js");
    ClosureCompiler.compile(totalFileList,
        {js_output_file: currDir + "/launcher/game-min.js"},
        function afterCompile(err, stdout, stderr) {
            console.log(err);
        });
}

function help_title() {
    return "发布项目，使用GoogleClosureCompiler压缩代码";
}

function help_example() {
    var result =  "\n";
    result += "    egret publish [project_name]\n";
    result += "描述:\n";
    result += "    " + help_title();
    return result;
}

exports.run = run;
exports.help_title = help_title;
exports.help_example = help_example;
<|endoftext|>


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

'use strict';

module.exports = {
  opts: {
    readme: './README.md',
    package: './package.json',
    template: './node_modules/jsdoc-fresh',
    recurse: true,
    verbose: true,
    destination: './docs/'
  },
  plugins: [
    'plugins/markdown',
    'jsdoc-region-tag'
  ],
  source: {
    excludePattern: '(^|\\/|\\\\)[._]',
    include: [
      'build/src'
    ],
    includePattern: '\\.js$'
  },
  templates: {
    copyright: 'Copyright 2019 Google, LLC.',
    includeDate: false,
    sourceFiles: false,
    systemName: '@google-cloud/cloudbuild',
    theme: 'lumen',
    default: {
      "outputSourceFiles": false
    }
  },
  markdown: {
    idInHeadings: true
  }
};
<commit_msg>chore: update .jsdoc.js by add protos and remove double quotes (#71)<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

'use strict';

module.exports = {
  opts: {
    readme: './README.md',
    package: './package.json',
    template: './node_modules/jsdoc-fresh',
    recurse: true,
    verbose: true,
    destination: './docs/'
  },
  plugins: [
    'plugins/markdown',
    'jsdoc-region-tag'
  ],
  source: {
    excludePattern: '(^|\\/|\\\\)[._]',
    include: [
      'build/src',
      'protos'
    ],
    includePattern: '\\.js$'
  },
  templates: {
    copyright: 'Copyright 2019 Google, LLC.',
    includeDate: false,
    sourceFiles: false,
    systemName: '@google-cloud/cloudbuild',
    theme: 'lumen',
    default: {
      outputSourceFiles: false
    }
  },
  markdown: {
    idInHeadings: true
  }
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
let arupex = require('../arupex');
let fs = require('fs');
let dir = process.cwd();
let cmd = process.argv[2];
let port = process.env.PORT || 1337;
let functionName = process.argv[3];
let watch = process.argv.indexOf('watch') !== -1;
let server = null;

function run() {
    let context = process.argv[5] ? JSON.parse(fs.readFileSync(process.argv[5], 'utf8')) : {};
    let event =  process.argv[4] ? JSON.parse(fs.readFileSync(process.argv[4], 'utf8')) : {};

    if (cmd) {

        switch (cmd) {
            case 'schema':
                let value = arupex.interceptors.lambdas({
                    meterFnc: () => {},
                    traceFnc: () => {},
                    dir: dir,
                    edge: true
                }).mockGenerator;
                delete value.fncVarReplacements;
                console.log('Mock Schema is as Follows: \n\n', JSON.stringify(value, null, 3));
                break;

            case 'invoke':
                server = arupex.interceptors.lambda[functionName](event, context, (err, data) => {
                    if (err) {
                        console.log('err', err);
                    }
                    else {
                        console.log('Responded with', data);
                    }
                });
                break;

            case 'server':
                server = arupex.interceptors.http.start(port, {
                    dir: dir
                });
                break;
            case 'mock':
                server = arupex.interceptors.mockServer(port, {
                    dir: dir
                });
                break;

            default: //you entered an invalid arg 2
                console.log(`USAGE:\n
                arupex schema                           # outputs the mock schema for your app
                arupex invoke event.json context.json   # invokes your lambda via a parameterized event.json and an optional context json
                arupex server                           # runs your lambdas as a server on port 1337 based on your routes.js file
                arupex mock                             # runs a mock server for your lambda with a harness page at localhost:1337
            `);
        }
    }
    else {
        server = arupex.interceptors.http.start(port, {
            dir: dir
        });
    }
}

run();

if(watch){
    fs.watch(dir, {
        recursive: true
    }, (evt, file) => {
        console.log('saw file change', file);
        if(server && typeof server.close === 'function'){
            server.close(run);
        }
        else {
            console.log('server is not running');
        }
    });
}<commit_msg>try nuking requires cache<commit_after>#!/usr/bin/env node
let arupex = require('../arupex');
let fs = require('fs');
let dir = process.cwd();
let cmd = process.argv[2];
let port = process.env.PORT || 1337;
let functionName = process.argv[3];
let watch = process.argv.indexOf('watch') !== -1;
let server = null;

function run() {
    let context = process.argv[5] ? JSON.parse(fs.readFileSync(process.argv[5], 'utf8')) : {};
    let event =  process.argv[4] ? JSON.parse(fs.readFileSync(process.argv[4], 'utf8')) : {};

    if (cmd) {

        switch (cmd) {
            case 'schema':
                let value = arupex.interceptors.lambdas({
                    meterFnc: () => {},
                    traceFnc: () => {},
                    dir: dir,
                    edge: true
                }).mockGenerator;
                delete value.fncVarReplacements;
                console.log('Mock Schema is as Follows: \n\n', JSON.stringify(value, null, 3));
                break;

            case 'invoke':
                server = arupex.interceptors.lambda[functionName](event, context, (err, data) => {
                    if (err) {
                        console.log('err', err);
                    }
                    else {
                        console.log('Responded with', data);
                    }
                });
                break;

            case 'server':
                server = arupex.interceptors.http.start(port, {
                    dir: dir
                });
                break;
            case 'mock':
                server = arupex.interceptors.mockServer(port, {
                    dir: dir
                });
                break;

            default: //you entered an invalid arg 2
                console.log(`USAGE:\n
                arupex schema                           # outputs the mock schema for your app
                arupex invoke event.json context.json   # invokes your lambda via a parameterized event.json and an optional context json
                arupex server                           # runs your lambdas as a server on port 1337 based on your routes.js file
                arupex mock                             # runs a mock server for your lambda with a harness page at localhost:1337
            `);
        }
    }
    else {
        server = arupex.interceptors.http.start(port, {
            dir: dir
        });
    }
}

run();

if(watch){
    fs.watch(dir, {
        recursive: true
    }, (evt, file) => {
        console.log('saw file change', file);
        if(server && typeof server.close === 'function'){
            server.close(() => {
                require.cache = {};//remove data from requires cache as it will just reload old files if we dont
                run();
            });
        }
        else {
            console.log('server is not running');
        }
    });
}<|endoftext|>


<commit_before>function Button( pixiStage, mole, position ){
  // load texture
  var t = {
    on  : PIXI.Texture.fromImage(Config.textures.buttonOn),
    off : PIXI.Texture.fromImage(Config.textures.buttonOff)
  };

  // create pixi object for button
  var button = new PIXI.Sprite(t.off);
  button.anchor.x = 0;
  button.anchor.y = 0;
  button.position.x = position.x;
  button.position.y = position.y;
  button.interactive = true;

  button.mousedown = button.touchstart = function(){
    mole.hide();
    this.setTexture(t.on);
  };

  button.mouseup = button.touchend  = function(){
    mole.rise();
    this.setTexture(t.off);
  };

  button.mouseupoutside = button.touchend  = function(){
    mole.rise();
    this.setTexture(t.off);
  }

  // Add to pixi

  pixiStage.addChild( button );
}

Button.prototype = {
  update : function(time, dt){}
};
<commit_msg>mouseout fix<commit_after>function Button( pixiStage, mole, position ){
  // load texture
  var t = {
    on  : PIXI.Texture.fromImage(Config.textures.buttonOn),
    off : PIXI.Texture.fromImage(Config.textures.buttonOff)
  };

  // create pixi object for button
  var button = new PIXI.Sprite(t.off);
  button.anchor.x = 0;
  button.anchor.y = 0;
  button.position.x = position.x;
  button.position.y = position.y;
  button.interactive = true;

  button.mousedown = button.touchstart = function(){
    mole.hide();
    this.setTexture(t.on);
  };

  button.mouseup = button.touchend  = function(){
    mole.rise();
    this.setTexture(t.off);
  };

  button.mouseupoutside = button.touchend  = function(){
    mole.rise();
    this.setTexture(t.off);
  }

  button.mouseout = button.touchend  = function(){
     mole.rise();
     this.setTexture(t.off);
  }

    // Add to pixi

  pixiStage.addChild( button );
}

Button.prototype = {
  update : function(time, dt){}
};
<|endoftext|>


<commit_before>var _ = require('lodash')
var inherits = require('inherits')
var aabb = require('aabb-2d')
var math = require('mathjs')
var transform = require('./transform.js')
var circle = require('./geo/circle.js')
var Collision = require('./collision.js')
var Fixmove = require('./fixmove.js')
var Automove = require('./automove.js')
var Freemove = require('./freemove.js')
var Entity = require('crtrdg-entity')

module.exports = Player;
inherits(Player, Entity);

function Player(opts){
  this.geometry = circle({
    position: opts.position,
    angle: opts.angle,
    fill: opts.fill,
    stroke: opts.stroke,
    scale: opts.scale,
    thickness: opts.thickness,
    children: [
      circle({fill: opts.fill, stroke: opts.stroke, thickness: opts.thickness,
        position: [-0.7, -.9], scale: 0.6, angle: -45, aspect: 0.6}),
      circle({fill: opts.fill, stroke: opts.stroke, thickness: opts.thickness,
        position: [0.7, -.9], scale: 0.6, angle: 45, aspect: 0.6})
    ]
  })
  this.movement = {}
  this.movement.center = new Fixmove()
  this.movement.tile = new Automove({
    keymap: ['Q', 'W', 'E', 'A', 'S', 'D'],
    heading: [-60, 0, 60, -120, -180, 120],
    shift: 8
  })
  this.movement.path = new Automove({
    keymap: ['S'],
    heading: [-180]
  })
  this.collision = new Collision()
  this.waiting = true
}

Player.prototype.move = function(keyboard, world) {
  var self = this

  var current = self.geometry.transform
  var tile = world.tiles[world.locate(self.position())]
  var inside =  tile.children[0].contains(current.position())

  var delta
  if (inside) {
    var keysDown = keyboard.keysDown
    if (self.movement.tile.keypress(keysDown)) self.waiting = false
    if (self.waiting) {
      delta = self.movement.center.compute(current, {position: [tile.transform.position()[0], tile.transform.position()[1]]})
    } else {
      delta = self.movement.tile.compute(keysDown, current, tile.transform)
    }
  } else {
    self.waiting = true
    delta = self.movement.path.compute(keyboard.keysDown, current)
  }

  self.geometry.update(delta)
  self.collision.handle(world, self.geometry, delta)
}

Player.prototype.draw = function(context, camera) {
  this.geometry.draw(context, camera, {order: 'bottom'})
}

Player.prototype.position = function() {
  return this.geometry.transform.position()
}

Player.prototype.angle = function() {
  return this.geometry.transform.angle()
}

Player.prototype.scale = function() {
  return this.geometry.transform.scale()
}
<commit_msg>Reset tile keys<commit_after>var _ = require('lodash')
var inherits = require('inherits')
var aabb = require('aabb-2d')
var math = require('mathjs')
var transform = require('./transform.js')
var circle = require('./geo/circle.js')
var Collision = require('./collision.js')
var Fixmove = require('./fixmove.js')
var Automove = require('./automove.js')
var Freemove = require('./freemove.js')
var Entity = require('crtrdg-entity')

module.exports = Player;
inherits(Player, Entity);

function Player(opts){
  this.geometry = circle({
    position: opts.position,
    angle: opts.angle,
    fill: opts.fill,
    stroke: opts.stroke,
    scale: opts.scale,
    thickness: opts.thickness,
    children: [
      circle({fill: opts.fill, stroke: opts.stroke, thickness: opts.thickness,
        position: [-0.7, -.9], scale: 0.6, angle: -45, aspect: 0.6}),
      circle({fill: opts.fill, stroke: opts.stroke, thickness: opts.thickness,
        position: [0.7, -.9], scale: 0.6, angle: 45, aspect: 0.6})
    ]
  })
  this.movement = {}
  this.movement.center = new Fixmove()
  this.movement.tile = new Automove({
    keymap: ['Q', 'W', 'E', 'A', 'S', 'D'],
    heading: [-60, 0, 60, -120, -180, 120],
    shift: 8
  })
  this.movement.path = new Automove({
    keymap: ['S'],
    heading: [-180]
  })
  this.collision = new Collision()
  this.waiting = true
}

Player.prototype.move = function(keyboard, world) {
  var self = this

  var current = self.geometry.transform
  var tile = world.tiles[world.locate(self.position())]
  var inside =  tile.children[0].contains(current.position())

  var delta
  if (inside) {
    if (self.movement.tile.keypress(keyboard.keysDown)) self.waiting = false
    if (self.waiting) {
      delta = self.movement.center.compute(current, {position: [tile.transform.position()[0], tile.transform.position()[1]]})
    } else {
      delta = self.movement.tile.compute(keyboard.keysDown, current, tile.transform)
    }
  } else {
    self.waiting = true
    self.movement.tile.reset()
    delta = self.movement.path.compute(keyboard.keysDown, current)
  }

  self.geometry.update(delta)
  self.collision.handle(world, self.geometry, delta)
}

Player.prototype.draw = function(context, camera) {
  this.geometry.draw(context, camera, {order: 'bottom'})
}

Player.prototype.position = function() {
  return this.geometry.transform.position()
}

Player.prototype.angle = function() {
  return this.geometry.transform.angle()
}

Player.prototype.scale = function() {
  return this.geometry.transform.scale()
}
<|endoftext|>


<commit_before>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Lightweight event & listener abstraction.
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var axon = require( 'AXON/axon' );

  /**
   * @class Events
   * @constructor
   * @param values an object hash with the initial values for the properties
   */
  axon.Events = function Events() {
    this.eventListeners = {};
  };

  axon.Events.prototype = {

    /////////////////////////////////////////////
    // Below this point are the functions for event handling, basically orthogonal to property value change notifications

    /**
     * Register a listener when the specified eventName is triggered.
     * @param eventName {String} the name for the event channel
     * @param callback
     */
    on: function( eventName, callback ) {
      this.eventListeners[eventName] = this.eventListeners[eventName] || [];
      this.eventListeners[eventName].push( callback );
    },

    /**
     * Adds a function which will only be called back once, after which it is removed as a listener.
     * If you need to remove a function added with 'once' you will have to remove its handle, which is returned by the function.
     * @param eventName {String} the name for the event channel
     * @param callback function to be called back once (if at all)
     */
    once: function( eventName, callback ) {
      var events = this;
      var wrappedCallback = function() {
        events.off( eventName, wrappedCallback );

        //If no arguments being passed through, call back without processing arguments, for possible speed
        if ( arguments.length === 0 ) {
          callback();
        }
        else {

          //General case of passing events through to the wrapped callback function
          callback.apply( this, Array.prototype.slice.call( arguments, 0 ) );
        }
      };
      this.on( eventName, wrappedCallback );

      //Return the handle in case it needs to be removed.
      return wrappedCallback;
    },

    /**
     * Remove a listener from the specified event type.  Does nothing if the listener did not exist
     * @param eventName {String} the name for the event channel
     * @param callback
     */
    off: function( eventName, callback ) {
      if ( this.eventListeners[eventName] ) {
        var index = this.eventListeners[eventName].indexOf( callback );
        if ( index !== -1 ) {
          this.eventListeners[eventName].splice( index, 1 );
        }
      }
    },

    /**
     * Trigger an event with the specified name and arguments.
     * @param eventName {String} the name for the event channel
     * @param args... optional arguments to pass to the listeners
     */
    trigger: function( eventName ) {
      if ( this.eventListeners[eventName] ) {
        var listenersCopy = this.eventListeners[eventName].slice(); // make a copy, in case callback removes listener
        for ( var i = 0; i < listenersCopy.length; i++ ) {
          var listener = listenersCopy[i];

          //Simple case of no arguments, call it separately for improved performance in case it is faster (untested)
          if ( arguments.length === 1 ) {
            listener( arguments );
          }
          else {
            var suffix = Array.prototype.slice.call( arguments, 1 );
            listener.apply( this, suffix );
          }
        }
      }
    }

  };

  return axon.Events;
} );<commit_msg>added a stub for Events.reduced, see #18<commit_after>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Lightweight event & listener abstraction.
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var axon = require( 'AXON/axon' );

  /**
   * @class Events
   * @constructor
   * @param values an object hash with the initial values for the properties
   */
  axon.Events = function Events() {
    this.eventListeners = {};
  };

  axon.Events.prototype = {

    /////////////////////////////////////////////
    // Below this point are the functions for event handling, basically orthogonal to property value change notifications

    /**
     * Register a listener when the specified eventName is triggered.
     * @param eventName {String} the name for the event channel
     * @param callback
     */
    on: function( eventName, callback ) {
      this.eventListeners[eventName] = this.eventListeners[eventName] || [];
      this.eventListeners[eventName].push( callback );
    },

    /**
     * Adds a function which will only be called back once, after which it is removed as a listener.
     * If you need to remove a function added with 'once' you will have to remove its handle, which is returned by the function.
     * @param eventName {String} the name for the event channel
     * @param callback function to be called back once (if at all)
     */
    once: function( eventName, callback ) {
      var events = this;
      var wrappedCallback = function() {
        events.off( eventName, wrappedCallback );

        //If no arguments being passed through, call back without processing arguments, for possible speed
        if ( arguments.length === 0 ) {
          callback();
        }
        else {

          //General case of passing events through to the wrapped callback function
          callback.apply( this, Array.prototype.slice.call( arguments, 0 ) );
        }
      };
      this.on( eventName, wrappedCallback );

      //Return the handle in case it needs to be removed.
      return wrappedCallback;
    },

    /**
     * Remove a listener from the specified event type.  Does nothing if the listener did not exist
     * @param eventName {String} the name for the event channel
     * @param callback
     */
    off: function( eventName, callback ) {
      if ( this.eventListeners[eventName] ) {
        var index = this.eventListeners[eventName].indexOf( callback );
        if ( index !== -1 ) {
          this.eventListeners[eventName].splice( index, 1 );
        }
      }
    },

    /**
     * Trigger an event with the specified name and arguments.
     * @param eventName {String} the name for the event channel
     * @param args... optional arguments to pass to the listeners
     */
    trigger: function( eventName ) {
      if ( this.eventListeners[eventName] ) {
        var listenersCopy = this.eventListeners[eventName].slice(); // make a copy, in case callback removes listener
        for ( var i = 0; i < listenersCopy.length; i++ ) {
          var listener = listenersCopy[i];

          //Simple case of no arguments, call it separately for improved performance in case it is faster (untested)
          if ( arguments.length === 1 ) {
            listener( arguments );
          }
          else {
            var suffix = Array.prototype.slice.call( arguments, 1 );
            listener.apply( this, suffix );
          }
        }
      }
    },

    /**
     * Returns a new Events API that only includes the specified events. This makes it possible
     * to pass an event listener interface A* to a dependent class B without passing the entire class A, to limit
     * the ability of B to 'mess with' inappropriate parts of A.  This also keeps the same event listener interface so that you can pass A or A* without changing B.
     * @param {string | Array} eventNames a list of events (or a single event) that should be visible in the reduced Events.
     */
    reduced: function( eventNames ) {

      //TODO: implement me
      return this;
    }

  };

  return axon.Events;
} );<|endoftext|>