<commit_before>import React from 'react';
import {Button, InputGroup, ControlLabel, FormGroup, FormControl, Panel,
  ListGroup, ListGroupItem, Glyphicon, Tabs, Tab, Row, Col} from 'react-bootstrap';
import SVG from 'react-inlinesvg';

import ElementActions from './actions/ElementActions';
import ElementStore from './stores/ElementStore';

import UIStore from './stores/UIStore';
import UIActions from './actions/UIActions';

import ElementCollectionLabels from './ElementCollectionLabels';
import ElementAnalysesLabels from './ElementAnalysesLabels';
import SampleDetailsAnalyses from './SampleDetailsAnalyses';

import XLabels from "./extra/SampleDetailsXLabels";
import XTab from "./extra/SampleDetailsXTab";
import XTabName from "./extra/SampleDetailsXTabName";

import StickyDiv from 'react-stickydiv'

import StructureEditorModal from './structure_editor/StructureEditorModal';

import Aviator from 'aviator';

import Sample from './models/Sample';
import PolymerSection from './PolymerSection';
import ElementalCompositionGroup from './ElementalCompositionGroup';
import ToggleSection from './common/ToggleSection'
import SampleName from './common/SampleName'
import SampleForm from './SampleForm'

const MWPrecision = 6;

export default class SampleDetails extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      sample: props.sample,
      reaction: null,
      materialGroup: null,
      showStructureEditor: false,
      loadingMolecule: false,
      showElementalComposition: false
    }
  }

  componentDidMount() {
    ElementStore.listen(this.onChange.bind(this));
  }

  componentWillUnmount() {
    ElementStore.unlisten(this.onChange.bind(this));
  }

  onChange(state) {
    if(state.currentElement && state.currentElement.type == 'sample') {
      this.setState({
        sample: state.currentElement,
        reaction: state.currentReaction,
        materialGroup: state.currentMaterialGroup,
        samplePanelFixed: false,
        loadingMolecule: false
      });
    }
  }

  handleSampleChanged(sample) {
    this.setState({
      sample
    });
  }

  handleAmountChanged(amount) {
    let sample = this.state.sample;
    sample.setAmountAndNormalizeToGram(amount);
    this.setState({
      sample: sample
    });
  }

  handleImportedReadoutChanged(e) {
    let sample = this.state.sample;
    sample.imported_readout = e.target.value
    this.setState({
      sample: sample
    });
  }

  showStructureEditor() {
    this.setState({
      showStructureEditor: true
    })
  }

  hideStructureEditor() {
    this.setState({
      showStructureEditor: false
    })
  }

  updateMolecule(molfile, svg_file = null) {
    ElementActions.fetchMoleculeByMolfile(molfile, svg_file);
  }

  handleStructureEditorSave(molfile, svg_file = null) {
    let {sample} = this.state;

    if(sample) {
      sample.molfile = molfile

      sample.contains_residues = molfile.indexOf(' R# ') > -1;

      if(sample.contains_residues)
        sample.sample_svg_file = svg_file;

      sample.formulaChanged = true;
    }
    this.setState({sample: sample, loadingMolecule: true});

    if(sample.contains_residues > -1){
      this.updateMolecule(molfile, svg_file);
    } else {
      this.updateMolecule(molfile);
    }

    this.hideStructureEditor()
  }

  handleStructureEditorCancel() {
    this.hideStructureEditor()
  }

  _submitFunction() {
  let {sample} = this.state;
  let { currentReaction } = ElementStore.getState();

  if(currentReaction) {
      if(sample.isNew) {
        ElementActions.createSampleForReaction(sample);
      } else {
        ElementActions.updateSampleForReaction(sample);
      }
    } else {
      if(sample.isNew) {
        ElementActions.createSample(sample);
      } else {
        ElementActions.updateSample(new Sample(sample));
      }
    }
  }

  closeDetails() {
    let { currentReaction } = ElementStore.getState();
    let {sample} = this.state;

    if(currentReaction) {
      if(sample.isNew)
        ElementActions.openReactionDetails(currentReaction);
      else
        ElementActions.fetchReactionById(currentReaction)
    } else {
      UIActions.deselectAllElements();
      ElementActions.deselectCurrentElement();

      let uiState = UIStore.getState();
      Aviator.navigate(`/collection/${uiState.currentCollectionId}`);
    }
  }

  structureEditorButton(isDisabled) {
    return (
      <Button onClick={this.showStructureEditor.bind(this)} disabled={isDisabled}>
        <Glyphicon glyph='pencil'/>
      </Button>
    )
  }

  svgOrLoading(sample) {
    let svgPath = "";
    if (this.state.loadingMolecule) {
      svgPath = "/images/loading-bubbles.svg";
    } else {
      svgPath = sample.svgPath;
    }
    let className = svgPath ? 'svg-container' : 'svg-container-empty'
    return (

        <Glyphicon className="pull-right" glyph='pencil'/>
        <SVG key={svgPath} src={svgPath} className="molecule-mid"/>

    );
  }

  sampleAverageMW(sample) {
    let mw = sample.molecule_molecular_weight;
    if(mw)
      return `${mw.toFixed(MWPrecision)} g/mol`;
    else
      return '';
  }

  sampleExactMW(sample) {
    let mw = sample.molecule_exact_molecular_weight
    if(mw)
      return `Exact mass: ${mw.toFixed(MWPrecision)} g/mol`;
    else
      return '';
  }

  sampleHeader(sample) {
    const style = {height: '200px'};
    return (
      <Row style={style}>
        <Col md={4}>

{sample.title()}

<SampleName sample={sample}/>

{this.sampleAverageMW(sample)}

{this.sampleExactMW(sample)}

          <ElementCollectionLabels element={sample} key={sample.id}/>
          <ElementAnalysesLabels element={sample}
            key={sample.id+"_analyses"}/>
          {this.extraLabels().map((Lab,i)=><Lab key={i} element={sample}/>)}
        </Col>
        <Col md={8}>
          {this.svgOrLoading(sample)}
        </Col>
      </Row>
    )
  }

  moleculeInchi(sample) {
    return (
      <FormGroup >
        <ControlLabel></ControlLabel>
        <InputGroup>
          <InputGroup.Addon>InChI</InputGroup.Addon>
          <FormControl type="text"
             key={sample.id}
             defaultValue={sample.molecule_inchistring}
             disabled
             readOnly
          />
        </InputGroup>
      </FormGroup>
    )
  }

  moleculeCanoSmiles(sample) {
    return (
      <Input type="text" label="Canonical Smiles"
             key={'cano_smiles_' + sample.id}
             defaultValue={sample.molecule_cano_smiles}
             disabled
             readOnly
      />
    )
  }

  handleSectionToggle() {
    this.setState({
      showElementalComposition: !this.state.showElementalComposition
    });
  }

  elementalPropertiesItemHeader(sample) {
    let label
    if(sample.contains_residues) {
      label = 'Polymer section'
      if(!this.state.showElementalComposition)
        label += ' / Elemental composition';
    }
    else
      label = 'Elemental composition';

    return (
      <ListGroupItem onClick={() => this.handleSectionToggle()}>
        <Col className="padding-right elem-composition-header" md={6}>
          {label}
        </Col>

          <ToggleSection show={this.state.showElementalComposition}/>

      </ListGroupItem>
    )
  }

  elementalPropertiesItemContent(sample, materialGroup, show) {
    if(!show)
      return false;

    if(sample.contains_residues)
      return (
        <ListGroupItem className="ea-section">
          <PolymerSection sample={sample}
                          parent={this}
                          show={sample.contains_residues}
                          materialGroup={materialGroup}/>
        </ListGroupItem>
      )
    else
      return (
        <ListGroupItem className="ea-section">
          <Row>
            <Col md={6}>
              <ElementalCompositionGroup sample={sample}/>
            </Col>
          </Row>
        </ListGroupItem>
      )
  }

  elementalPropertiesItem(sample) {
    // avoid empty ListGroupItem
    if(!sample.molecule.sum_formular)
      return false;

    let show = this.state.showElementalComposition;
    let materialGroup = this.state.materialGroup;

    return(

        {this.elementalPropertiesItemHeader(sample)}

        {this.elementalPropertiesItemContent(sample, materialGroup, show)}

    )

  }

  samplePropertiesTab(ind){
    let sample = this.state.sample || {};

    return(
      <Tab eventKey={ind} title={'Properties'}
        key={'Props' + sample.id.toString()}>
        <ListGroupItem>
          <SampleForm sample={sample}
                      parent={this}/>
        </ListGroupItem>
        {this.elementalPropertiesItem(sample)}
        <ListGroupItem>
          {this.moleculeInchi(sample)}
          {this.moleculeCanoSmiles(sample)}
        </ListGroupItem>
      </Tab>
    )
  }

  sampleAnalysesTab(ind){
    let sample = this.state.sample || {}
    return(
      <Tab eventKey={ind} title={'Analyses'}
        key={'Analyses' + sample.id.toString()}>
        <ListGroupItem style={{paddingBottom: 20}}>
          <SampleDetailsAnalyses
            sample={sample}
            parent={this}
            />
        </ListGroupItem>
      </Tab>
    )
  }

  sampleImportReadoutTab(ind){
    let sample = this.state.sample || {}
    return(
      <Tab eventKey={ind} title={'Results'}
        key={'Results' + sample.id.toString()}>
        <ListGroupItem style={{paddingBottom: 20}}>
        <FormGroup controlId="importedReadoutInput">
          <ControlLabel>Imported Readout</ControlLabel>
          <InputGroup>
            <FormControl type="text"
              ref="importedReadoutInput"
              value={sample.imported_readout || ''}
             disabled
             readOnly
            />
          </InputGroup>
        </FormGroup>
        </ListGroupItem>
      </Tab>
    )
  }

  extraTab(ind){
    let sample = this.state.sample || {}
    let num = ind - 3 ;
    let NoName =  XTab["Tab"+num];
    let TabName = XTabName["TabName"+num];
    return(
       <Tab eventKey={ind} key={ind} title={TabName} >
         <ListGroupItem style={{paddingBottom: 20}}>
           <NoName  sample={sample}/>
         </ListGroupItem>
       </Tab>
      )
  }
  extraLabels(){
    let labels = [];
    for (let j=0;j < XLabels.LabelsCount;j++){
      labels.push(XLabels["Labels"+j])
    }
    return labels;
  }

  render() {
    let sample = this.state.sample || {}
    let molfile = sample.molfile;
    let hasParent = sample && sample.parent_id
    let hasChildren = sample && sample.children_count > 0
    let tabContents = [
                       (i)=>(this.samplePropertiesTab(i)),
                       (i)=>(this.sampleAnalysesTab(i)),
                       (i)=>(this.sampleImportReadoutTab(i))
                      ];
    for (let j=0;j < XTab.TabCount;j++){
      tabContents.push((i)=>this.extraTab(i))
    }

    return (

        <StructureEditorModal
          key={sample.id}
          showModal={this.state.showStructureEditor}
          onSave={this.handleStructureEditorSave.bind(this)}
          onCancel={this.handleStructureEditorCancel.bind(this)}
          molfile={molfile}
          hasParent={hasParent}
          hasChildren={hasChildren}
          />
        <StickyDiv zIndex={2}>
          <Panel className="panel-fixed"
                 header="Sample Details"
                 bsStyle={sample.isEdited ? 'info' : 'primary'}>
            <Button bsStyle="danger" bsSize="xsmall"
              className="button-right" onClick={this.closeDetails.bind(this)}>

            </Button>
            {this.sampleHeader(sample)}
            <ListGroup>
            <Tabs defaultActiveKey={0}>
              {tabContents.map((e,i)=>e(i))}
            </Tabs>
            </ListGroup>
          </Panel>
        </StickyDiv>

    )
  }
}
<commit_msg>Suppress warning<commit_after>import React from 'react';
import {Button, InputGroup, ControlLabel, FormGroup, FormControl, Panel,
  ListGroup, ListGroupItem, Glyphicon, Tabs, Tab, Row, Col} from 'react-bootstrap';
import SVG from 'react-inlinesvg';

import ElementActions from './actions/ElementActions';
import ElementStore from './stores/ElementStore';

import UIStore from './stores/UIStore';
import UIActions from './actions/UIActions';

import ElementCollectionLabels from './ElementCollectionLabels';
import ElementAnalysesLabels from './ElementAnalysesLabels';
import SampleDetailsAnalyses from './SampleDetailsAnalyses';

import XLabels from "./extra/SampleDetailsXLabels";
import XTab from "./extra/SampleDetailsXTab";
import XTabName from "./extra/SampleDetailsXTabName";

import StickyDiv from 'react-stickydiv'

import StructureEditorModal from './structure_editor/StructureEditorModal';

import Aviator from 'aviator';

import Sample from './models/Sample';
import PolymerSection from './PolymerSection';
import ElementalCompositionGroup from './ElementalCompositionGroup';
import ToggleSection from './common/ToggleSection'
import SampleName from './common/SampleName'
import SampleForm from './SampleForm'

const MWPrecision = 6;

export default class SampleDetails extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      sample: props.sample,
      reaction: null,
      materialGroup: null,
      showStructureEditor: false,
      loadingMolecule: false,
      showElementalComposition: false
    }
  }

  componentDidMount() {
    ElementStore.listen(this.onChange.bind(this));
  }

  componentWillUnmount() {
    ElementStore.unlisten(this.onChange.bind(this));
  }

  onChange(state) {
    if(state.currentElement && state.currentElement.type == 'sample') {
      this.setState({
        sample: state.currentElement,
        reaction: state.currentReaction,
        materialGroup: state.currentMaterialGroup,
        samplePanelFixed: false,
        loadingMolecule: false
      });
    }
  }

  handleSampleChanged(sample) {
    this.setState({
      sample
    });
  }

  handleAmountChanged(amount) {
    let sample = this.state.sample;
    sample.setAmountAndNormalizeToGram(amount);
    this.setState({
      sample: sample
    });
  }

  handleImportedReadoutChanged(e) {
    let sample = this.state.sample;
    sample.imported_readout = e.target.value
    this.setState({
      sample: sample
    });
  }

  showStructureEditor() {
    this.setState({
      showStructureEditor: true
    })
  }

  hideStructureEditor() {
    this.setState({
      showStructureEditor: false
    })
  }

  updateMolecule(molfile, svg_file = null) {
    ElementActions.fetchMoleculeByMolfile(molfile, svg_file);
  }

  handleStructureEditorSave(molfile, svg_file = null) {
    let {sample} = this.state;

    if(sample) {
      sample.molfile = molfile

      sample.contains_residues = molfile.indexOf(' R# ') > -1;

      if(sample.contains_residues)
        sample.sample_svg_file = svg_file;

      sample.formulaChanged = true;
    }
    this.setState({sample: sample, loadingMolecule: true});

    if(sample.contains_residues > -1){
      this.updateMolecule(molfile, svg_file);
    } else {
      this.updateMolecule(molfile);
    }

    this.hideStructureEditor()
  }

  handleStructureEditorCancel() {
    this.hideStructureEditor()
  }

  _submitFunction() {
  let {sample} = this.state;
  let { currentReaction } = ElementStore.getState();

  if(currentReaction) {
      if(sample.isNew) {
        ElementActions.createSampleForReaction(sample);
      } else {
        ElementActions.updateSampleForReaction(sample);
      }
    } else {
      if(sample.isNew) {
        ElementActions.createSample(sample);
      } else {
        ElementActions.updateSample(new Sample(sample));
      }
    }
  }

  closeDetails() {
    let { currentReaction } = ElementStore.getState();
    let {sample} = this.state;

    if(currentReaction) {
      if(sample.isNew)
        ElementActions.openReactionDetails(currentReaction);
      else
        ElementActions.fetchReactionById(currentReaction)
    } else {
      UIActions.deselectAllElements();
      ElementActions.deselectCurrentElement();

      let uiState = UIStore.getState();
      Aviator.navigate(`/collection/${uiState.currentCollectionId}`);
    }
  }

  structureEditorButton(isDisabled) {
    return (
      <Button onClick={this.showStructureEditor.bind(this)} disabled={isDisabled}>
        <Glyphicon glyph='pencil'/>
      </Button>
    )
  }

  svgOrLoading(sample) {
    let svgPath = "";
    if (this.state.loadingMolecule) {
      svgPath = "/images/loading-bubbles.svg";
    } else {
      svgPath = sample.svgPath;
    }
    let className = svgPath ? 'svg-container' : 'svg-container-empty'
    return (

        <Glyphicon className="pull-right" glyph='pencil'/>
        <SVG key={svgPath} src={svgPath} className="molecule-mid"/>

    );
  }

  sampleAverageMW(sample) {
    let mw = sample.molecule_molecular_weight;
    if(mw)
      return `${mw.toFixed(MWPrecision)} g/mol`;
    else
      return '';
  }

  sampleExactMW(sample) {
    let mw = sample.molecule_exact_molecular_weight
    if(mw)
      return `Exact mass: ${mw.toFixed(MWPrecision)} g/mol`;
    else
      return '';
  }

  sampleHeader(sample) {
    const style = {height: '200px'};
    return (
      <Row style={style}>
        <Col md={4}>

{sample.title()}

<SampleName sample={sample}/>

{this.sampleAverageMW(sample)}

{this.sampleExactMW(sample)}

          <ElementCollectionLabels element={sample} key={sample.id}/>
          <ElementAnalysesLabels element={sample}
            key={sample.id+"_analyses"}/>
          {this.extraLabels().map((Lab,i)=><Lab key={i} element={sample}/>)}
        </Col>
        <Col md={8}>
          {this.svgOrLoading(sample)}
        </Col>
      </Row>
    )
  }

  moleculeInchi(sample) {
    return (
      <FormGroup >
        <ControlLabel></ControlLabel>
        <InputGroup>
          <InputGroup.Addon>InChI</InputGroup.Addon>
          <FormControl type="text"
             key={sample.id}
             defaultValue={sample.molecule_inchistring}
             disabled
             readOnly
          />
        </InputGroup>
      </FormGroup>
    )
  }

  moleculeCanoSmiles(sample) {
    return (
      <FormControl
        type="text" label="Canonical Smiles"
        key={'cano_smiles_' + sample.id}
        defaultValue={sample.molecule_cano_smiles}
        disabled
        readOnly
      />
    )
  }

  handleSectionToggle() {
    this.setState({
      showElementalComposition: !this.state.showElementalComposition
    });
  }

  elementalPropertiesItemHeader(sample) {
    let label
    if(sample.contains_residues) {
      label = 'Polymer section'
      if(!this.state.showElementalComposition)
        label += ' / Elemental composition';
    }
    else
      label = 'Elemental composition';

    return (
      <ListGroupItem onClick={() => this.handleSectionToggle()}>
        <Col className="padding-right elem-composition-header" md={6}>
          {label}
        </Col>

          <ToggleSection show={this.state.showElementalComposition}/>

      </ListGroupItem>
    )
  }

  elementalPropertiesItemContent(sample, materialGroup, show) {
    if(!show)
      return false;

    if(sample.contains_residues)
      return (
        <ListGroupItem className="ea-section">
          <PolymerSection sample={sample}
                          parent={this}
                          show={sample.contains_residues}
                          materialGroup={materialGroup}/>
        </ListGroupItem>
      )
    else
      return (
        <ListGroupItem className="ea-section">
          <Row>
            <Col md={6}>
              <ElementalCompositionGroup sample={sample}/>
            </Col>
          </Row>
        </ListGroupItem>
      )
  }

  elementalPropertiesItem(sample) {
    // avoid empty ListGroupItem
    if(!sample.molecule.sum_formular)
      return false;

    let show = this.state.showElementalComposition;
    let materialGroup = this.state.materialGroup;

    return(

        {this.elementalPropertiesItemHeader(sample)}

        {this.elementalPropertiesItemContent(sample, materialGroup, show)}

    )

  }

  samplePropertiesTab(ind){
    let sample = this.state.sample || {};

    return(
      <Tab eventKey={ind} title={'Properties'}
        key={'Props' + sample.id.toString()}>
        <ListGroupItem>
          <SampleForm sample={sample}
                      parent={this}/>
        </ListGroupItem>
        {this.elementalPropertiesItem(sample)}
        <ListGroupItem>
          {this.moleculeInchi(sample)}
          {this.moleculeCanoSmiles(sample)}
        </ListGroupItem>
      </Tab>
    )
  }

  sampleAnalysesTab(ind){
    let sample = this.state.sample || {}
    return(
      <Tab eventKey={ind} title={'Analyses'}
        key={'Analyses' + sample.id.toString()}>
        <ListGroupItem style={{paddingBottom: 20}}>
          <SampleDetailsAnalyses
            sample={sample}
            parent={this}
            />
        </ListGroupItem>
      </Tab>
    )
  }

  sampleImportReadoutTab(ind){
    let sample = this.state.sample || {}
    return(
      <Tab eventKey={ind} title={'Results'}
        key={'Results' + sample.id.toString()}>
        <ListGroupItem style={{paddingBottom: 20}}>
        <FormGroup controlId="importedReadoutInput">
          <ControlLabel>Imported Readout</ControlLabel>
          <InputGroup>
            <FormControl type="text"
              ref="importedReadoutInput"
              value={sample.imported_readout || ''}
             disabled
             readOnly
            />
          </InputGroup>
        </FormGroup>
        </ListGroupItem>
      </Tab>
    )
  }

  extraTab(ind){
    let sample = this.state.sample || {}
    let num = ind - 3 ;
    let NoName =  XTab["Tab"+num];
    let TabName = XTabName["TabName"+num];
    return(
       <Tab eventKey={ind} key={ind} title={TabName} >
         <ListGroupItem style={{paddingBottom: 20}}>
           <NoName  sample={sample}/>
         </ListGroupItem>
       </Tab>
      )
  }
  extraLabels(){
    let labels = [];
    for (let j=0;j < XLabels.LabelsCount;j++){
      labels.push(XLabels["Labels"+j])
    }
    return labels;
  }

  render() {
    let sample = this.state.sample || {}
    let molfile = sample.molfile;
    let hasParent = sample && sample.parent_id
    let hasChildren = sample && sample.children_count > 0
    let tabContents = [
                       (i)=>(this.samplePropertiesTab(i)),
                       (i)=>(this.sampleAnalysesTab(i)),
                       (i)=>(this.sampleImportReadoutTab(i))
                      ];
    for (let j=0;j < XTab.TabCount;j++){
      tabContents.push((i)=>this.extraTab(i))
    }

    return (

        <StructureEditorModal
          key={sample.id}
          showModal={this.state.showStructureEditor}
          onSave={this.handleStructureEditorSave.bind(this)}
          onCancel={this.handleStructureEditorCancel.bind(this)}
          molfile={molfile}
          hasParent={hasParent}
          hasChildren={hasChildren}
          />
        <StickyDiv zIndex={2}>
          <Panel className="panel-fixed"
                 header="Sample Details"
                 bsStyle={sample.isEdited ? 'info' : 'primary'}>
            <Button bsStyle="danger" bsSize="xsmall"
              className="button-right" onClick={this.closeDetails.bind(this)}>

            </Button>
            {this.sampleHeader(sample)}
            <ListGroup>
            <Tabs defaultActiveKey={0} id="SampleDetailsXTab">
              {tabContents.map((e,i)=>e(i))}
            </Tabs>
            </ListGroup>
          </Panel>
        </StickyDiv>

    )
  }
}
<|endoftext|>


<commit_before>function EventsController($window, event) {

  var vm = this;

  vm.event = event.data;
  vm.hyperlink = openHyperlink;
  vm.comments = event.included;

  function openHyperlink() {
    $window.open('http://' + event.data.attributes.url);
  };

};

EventsController.$inject = ['$window', 'event'];

angular
  .module('uponnyc')
  .controller('EventsController', EventsController)
<commit_msg>Decoded url for event to redirect to VolunteerMatch page properly<commit_after>function EventsController($window, event) {

  var vm = this;

  vm.event = event.data;
  vm.hyperlink = openHyperlink;
  vm.comments = event.included;
  debugger;

  function openHyperlink() {
    $window.open(decodeURIComponent(event.data.attributes.url));
  };

};

EventsController.$inject = ['$window', 'event'];

angular
  .module('uponnyc')
  .controller('EventsController', EventsController)
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var fs = require('fs');
var http = require('http');
var path = require('path');
var parseURL = require('url').parse;

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

const remoteDebuggingPort = parseInt(process.env.REMOTE_DEBUGGING_PORT, 10) || 9222;
const serverPort = parseInt(process.env.PORT, 10) || 8090;
const localProtocolPath = process.env.LOCAL_PROTOCOL_PATH;
const devtoolsFolder = path.resolve(path.join(__dirname, '../..'));

http.createServer(requestHandler).listen(serverPort);
console.log(`Started hosted mode server at http://localhost:${serverPort}\n`);
console.log('For info on using the hosted mode server, see our contributing docs:');
console.log('https://bit.ly/devtools-contribution-guide');
console.log('Tip: Look for the \'Development server options\' section\n');

function requestHandler(request, response) {
  var filePath = parseURL(request.url).pathname;
  if (filePath === '/') {
    var landingURL = `http://localhost:${remoteDebuggingPort}#custom=true`;
    sendResponse(200, `<html>Please go to <a href="${landingURL}">${landingURL}</a></html>`);
    return;
  }

  var proxiedFile = proxy(filePath, sendResponse);
  if (proxiedFile) {
    proxiedFile.then(data => sendResponse(200, data)).catch(handleProxyError);
    return;
  }

  function handleProxyError(err) {
    console.log(`Error serving the file ${filePath}:`, err);
    console.log(`Make sure you opened Chrome with the flag "--remote-debugging-port=${remoteDebuggingPort}"`);
    sendResponse(500, '500 - Internal Server Error');
  }

  var absoluteFilePath = path.join(devtoolsFolder, filePath);
  if (!path.resolve(absoluteFilePath).startsWith(devtoolsFolder)) {
    console.log(`File requested is outside of devtools folder: ${devtoolsFolder}`);
    sendResponse(403, `403 - Access denied. File requested (${absoluteFilePath}) is outside of devtools folder: ${devtoolsFolder}`);
    return;
  }

  fs.exists(absoluteFilePath, fsExistsCallback);

  function fsExistsCallback(fileExists) {
    if (!fileExists) {
      console.log(`Cannot find file ${absoluteFilePath}`);
      sendResponse(404, '404 - File not found');
      return;
    }
    fs.readFile(absoluteFilePath, 'binary', readFileCallback);
  }

  function readFileCallback(err, file) {
    if (err) {
      console.log(`Unable to read local file ${absoluteFilePath}:`, err);
      sendResponse(500, '500 - Internal Server Error');
      return;
    }
    sendResponse(200, file);
  }

  function sendResponse(statusCode, data) {
    const path = parseURL(request.url).pathname;
    if (path.endsWith('.js')) {
      response.setHeader('Content-Type', 'text/javascript');
    }

    if (path.endsWith('.wasm')) {
      response.setHeader('Content-Type', 'application/wasm');
    }

    if (path.endsWith('.svg')) {
      response.setHeader('Content-Type', 'image/svg+xml');
    }

    response.writeHead(statusCode);
    response.write(data, 'binary');
    response.end();
  }
}

var proxyFilePathToURL = {
  '/front_end/SupportedCSSProperties.js': cloudURL.bind(null, 'SupportedCSSProperties.js'),
  '/front_end/InspectorBackendCommands.js': cloudURL.bind(null, 'InspectorBackendCommands.js'),
  '/favicon.ico': () => 'https://chrome-devtools-frontend.appspot.com/favicon.ico',
  '/front_end/accessibility/ARIAProperties.js': cloudURL.bind(null, 'accessibility/ARIAProperties.js'),
};

function cloudURL(path, commitHash) {
  return `https://chrome-devtools-frontend.appspot.com/serve_file/@${commitHash}/${path}`;
}

var proxyFileCache = new Map();

function proxy(filePath) {
  if (!(filePath in proxyFilePathToURL))
    return null;
  if (localProtocolPath && filePath === '/front_end/InspectorBackendCommands.js')
    return serveLocalProtocolFile();
  if (process.env.CHROMIUM_COMMIT)
    return onProxyFileURL(proxyFilePathToURL[filePath](process.env.CHROMIUM_COMMIT));
  return utils.fetch(`http://localhost:${remoteDebuggingPort}/json/version`)
      .then(onBrowserMetadata)
      .then(onProxyFileURL);

  function serveLocalProtocolFile() {
    return new Promise((resolve, reject) => {
      fs.exists(localProtocolPath, fsExistsCallback);
      function fsExistsCallback(fileExists) {
        if (!fileExists) {
          reject(new Error(`Cannot find local protocol file ${localProtocolPath}`));
          return;
        }
        fs.readFile(localProtocolPath, 'binary', readFileCallback);
      }
      function readFileCallback(err, file) {
        if (err) {
          reject(new Error(`Unable to read local protocol file ${localProtocolPath}`));
          return;
        }
        return resolve(file);
      }
    });
  }

  function onBrowserMetadata(metadata) {
    var metadataObject = JSON.parse(metadata);
    var match = metadataObject['WebKit-Version'].match(/\s\(@(\b[0-9a-f]{5,40}\b)/);
    var commitHash = match[1];
    var proxyFileURL = proxyFilePathToURL[filePath](commitHash);
    return proxyFileURL;
  }

  function onProxyFileURL(proxyFileURL) {
    if (proxyFileCache.has(proxyFileURL))
      return Promise.resolve(proxyFileCache.get(proxyFileURL));
    return utils.fetch(proxyFileURL).then(cacheProxyFile.bind(null, proxyFileURL)).catch(onMissingFile);
  }

  function onMissingFile() {
    var isFullCheckout = utils.shellOutput('git config --get remote.origin.url') ===
        'https://chromium.googlesource.com/chromium/src.git';
    var earlierCommitHash;
    var gitLogCommand = `git log --max-count=1 --grep="Commit-Position" --before="12 hours ago"`;
    if (isFullCheckout) {
      earlierCommitHash = utils.shellOutput(`${gitLogCommand} --pretty=format:"%H"`);
    } else {
      var commitMessage = utils.shellOutput(`${gitLogCommand}`);
      earlierCommitHash = commitMessage.match(/Cr-Mirrored-Commit: (.*)/)[1];
    }
    var fallbackURL = proxyFilePathToURL[filePath](earlierCommitHash);
    console.log('WARNING: Unable to fetch generated file based on browser\'s revision');
    console.log('Fetching earlier revision of same file as fallback');
    console.log('There may be a mismatch between the front-end and back-end');
    console.log(fallbackURL, '\n');
    return utils.fetch(fallbackURL).then(cacheProxyFile.bind(null, fallbackURL));
  }

  function cacheProxyFile(proxyFileURL, data) {
    proxyFileCache.set(proxyFileURL, data);
    return data;
  }
}
<commit_msg>Updates 403 message in Hosted Mode server<commit_after>// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var fs = require('fs');
var http = require('http');
var path = require('path');
var parseURL = require('url').parse;

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

const remoteDebuggingPort = parseInt(process.env.REMOTE_DEBUGGING_PORT, 10) || 9222;
const serverPort = parseInt(process.env.PORT, 10) || 8090;
const localProtocolPath = process.env.LOCAL_PROTOCOL_PATH;
const devtoolsFolder = path.resolve(path.join(__dirname, '../..'));

http.createServer(requestHandler).listen(serverPort);
console.log(`Started hosted mode server at http://localhost:${serverPort}\n`);
console.log('For info on using the hosted mode server, see our contributing docs:');
console.log('https://bit.ly/devtools-contribution-guide');
console.log('Tip: Look for the \'Development server options\' section\n');

function requestHandler(request, response) {
  var filePath = parseURL(request.url).pathname;
  if (filePath === '/') {
    var landingURL = `http://localhost:${remoteDebuggingPort}#custom=true`;
    sendResponse(200, `<html>Please go to <a href="${landingURL}">${landingURL}</a></html>`);
    return;
  }

  var proxiedFile = proxy(filePath, sendResponse);
  if (proxiedFile) {
    proxiedFile.then(data => sendResponse(200, data)).catch(handleProxyError);
    return;
  }

  function handleProxyError(err) {
    console.log(`Error serving the file ${filePath}:`, err);
    console.log(`Make sure you opened Chrome with the flag "--remote-debugging-port=${remoteDebuggingPort}"`);
    sendResponse(500, '500 - Internal Server Error');
  }

  var absoluteFilePath = path.join(devtoolsFolder, filePath);
  if (!path.resolve(absoluteFilePath).startsWith(devtoolsFolder)) {
    console.log(`File requested (${absoluteFilePath}) is outside of devtools folder: ${devtoolsFolder}`);
    sendResponse(403, `403 - Access denied. File requested is outside of devtools folder: ${devtoolsFolder}`);
    return;
  }

  fs.exists(absoluteFilePath, fsExistsCallback);

  function fsExistsCallback(fileExists) {
    if (!fileExists) {
      console.log(`Cannot find file ${absoluteFilePath}`);
      sendResponse(404, '404 - File not found');
      return;
    }
    fs.readFile(absoluteFilePath, 'binary', readFileCallback);
  }

  function readFileCallback(err, file) {
    if (err) {
      console.log(`Unable to read local file ${absoluteFilePath}:`, err);
      sendResponse(500, '500 - Internal Server Error');
      return;
    }
    sendResponse(200, file);
  }

  function sendResponse(statusCode, data) {
    const path = parseURL(request.url).pathname;
    if (path.endsWith('.js')) {
      response.setHeader('Content-Type', 'text/javascript');
    }

    if (path.endsWith('.wasm')) {
      response.setHeader('Content-Type', 'application/wasm');
    }

    if (path.endsWith('.svg')) {
      response.setHeader('Content-Type', 'image/svg+xml');
    }

    response.writeHead(statusCode);
    response.write(data, 'binary');
    response.end();
  }
}

var proxyFilePathToURL = {
  '/front_end/SupportedCSSProperties.js': cloudURL.bind(null, 'SupportedCSSProperties.js'),
  '/front_end/InspectorBackendCommands.js': cloudURL.bind(null, 'InspectorBackendCommands.js'),
  '/favicon.ico': () => 'https://chrome-devtools-frontend.appspot.com/favicon.ico',
  '/front_end/accessibility/ARIAProperties.js': cloudURL.bind(null, 'accessibility/ARIAProperties.js'),
};

function cloudURL(path, commitHash) {
  return `https://chrome-devtools-frontend.appspot.com/serve_file/@${commitHash}/${path}`;
}

var proxyFileCache = new Map();

function proxy(filePath) {
  if (!(filePath in proxyFilePathToURL))
    return null;
  if (localProtocolPath && filePath === '/front_end/InspectorBackendCommands.js')
    return serveLocalProtocolFile();
  if (process.env.CHROMIUM_COMMIT)
    return onProxyFileURL(proxyFilePathToURL[filePath](process.env.CHROMIUM_COMMIT));
  return utils.fetch(`http://localhost:${remoteDebuggingPort}/json/version`)
      .then(onBrowserMetadata)
      .then(onProxyFileURL);

  function serveLocalProtocolFile() {
    return new Promise((resolve, reject) => {
      fs.exists(localProtocolPath, fsExistsCallback);
      function fsExistsCallback(fileExists) {
        if (!fileExists) {
          reject(new Error(`Cannot find local protocol file ${localProtocolPath}`));
          return;
        }
        fs.readFile(localProtocolPath, 'binary', readFileCallback);
      }
      function readFileCallback(err, file) {
        if (err) {
          reject(new Error(`Unable to read local protocol file ${localProtocolPath}`));
          return;
        }
        return resolve(file);
      }
    });
  }

  function onBrowserMetadata(metadata) {
    var metadataObject = JSON.parse(metadata);
    var match = metadataObject['WebKit-Version'].match(/\s\(@(\b[0-9a-f]{5,40}\b)/);
    var commitHash = match[1];
    var proxyFileURL = proxyFilePathToURL[filePath](commitHash);
    return proxyFileURL;
  }

  function onProxyFileURL(proxyFileURL) {
    if (proxyFileCache.has(proxyFileURL))
      return Promise.resolve(proxyFileCache.get(proxyFileURL));
    return utils.fetch(proxyFileURL).then(cacheProxyFile.bind(null, proxyFileURL)).catch(onMissingFile);
  }

  function onMissingFile() {
    var isFullCheckout = utils.shellOutput('git config --get remote.origin.url') ===
        'https://chromium.googlesource.com/chromium/src.git';
    var earlierCommitHash;
    var gitLogCommand = `git log --max-count=1 --grep="Commit-Position" --before="12 hours ago"`;
    if (isFullCheckout) {
      earlierCommitHash = utils.shellOutput(`${gitLogCommand} --pretty=format:"%H"`);
    } else {
      var commitMessage = utils.shellOutput(`${gitLogCommand}`);
      earlierCommitHash = commitMessage.match(/Cr-Mirrored-Commit: (.*)/)[1];
    }
    var fallbackURL = proxyFilePathToURL[filePath](earlierCommitHash);
    console.log('WARNING: Unable to fetch generated file based on browser\'s revision');
    console.log('Fetching earlier revision of same file as fallback');
    console.log('There may be a mismatch between the front-end and back-end');
    console.log(fallbackURL, '\n');
    return utils.fetch(fallbackURL).then(cacheProxyFile.bind(null, fallbackURL));
  }

  function cacheProxyFile(proxyFileURL, data) {
    proxyFileCache.set(proxyFileURL, data);
    return data;
  }
}
<|endoftext|>


<commit_before>var REF_TYPE = "testtype-reference";
var SOURCE_TYPE = "testtype-source";
var IMAGE_TYPE = "testtype-image";
var PHOTO_TYPE = "testtype-photo";

var import_source = {
    _id: "testsource-elgar_digipics",
    _rev: "testrev",
    name: "Elgar pictures",
    path: "/Users/nathan/Pictures/elgar_digipics",
    last_import: null,
    time_zone: 'US/Pacific'
};

var SUPPORTED_EXTENSIONS = {'jpg':true, 'jpeg':true};
var GET_PHOTO = __dirname + '/getphoto-osx/build/Release/getphoto';

var fs = require('fs'), path = require('path'), proc = require('child_process'), http = require('http');

function Serializer(callback) {
    var queue = [];
    var tick = function () {
        process.nextTick(nextItem);
    };
    var nextItem = function () {
        if (!queue.length) {
            return;
        }
        callback(queue.shift(), tick);
    }
    this.add = function (item) {
        if (!queue.length) {
            tick();
        }
        queue.push(item);
    }
}

function processFiles(base, subfolder, callback) {
    var folder = path.join(base, subfolder);
    fs.readdir(folder, function (e, files) {
        if (e) {
            console.warn(e);
            return;
        }

        files.forEach(function (filename) {
            if (filename[0] === '.') {
                return;
            }

            var fullpath = path.join(folder, filename);
            fs.stat(fullpath, function (e, stats) {
                if (e) {
                    console.warn(e);
                    return;
                }

                var subfile = path.join(subfolder, filename);
                if (stats.isDirectory()) {
                    processFiles(base, subfile, callback);
                } else {
                    callback(base, subfile);
                }
            });
        });
    });
}

var couchdb = require('http').createClient(5984, "localhost");

/*
var uuids;
var req = couchdb.request('GET', "/_uuids?count=1000", {'Connection': 'keep-alive'});
req.end();
req.on('response', function (resp) {
    var uuidsDoc = "";
    resp.setEncoding('utf8');
    resp.on('data', function (d) {
        uuidsDoc += d;
    });
    resp.on('end', function () {
        uuids = JSON.parse(uuidsDoc).uuids;
    });
});
*/

function makeRef(doc, denormalize) {
    var reference = {};
    reference[REF_TYPE] = true;
    reference._id = doc._id;
    if (denormalize) denormalize.forEach(function (field) {
        reference[field] = doc[field];
    }), (reference._rev = doc._rev);
    return reference;
}

var import_queue = new Serializer(function (info, finish) {
    var fullpath = path.join(info.folder, info.file);
    var get_photo = proc.spawn(GET_PHOTO, ['--thumbnail', '64', '--thumbnail', '256', '--timezone', import_source.time_zone, fullpath]);

    var imageDoc = "";
    get_photo.stdout.on('data', function (data) {
        imageDoc += data.toString();
    });
    get_photo.on('exit', function (exitCode) {
        if (exitCode !== 0) {
            finish();
            return;
        }
        imageDoc = JSON.parse(imageDoc);
        imageDoc.identifiers || (imageDoc.identifiers = {});
        imageDoc.identifiers.relative_path = {source:makeRef(import_source, ['name']), file:info.file};
        var docName = "/dev/testphoto-" + Math.random();
        var req = couchdb.request('PUT', docName, {'Connection': 'keep-alive'});
        req.write(JSON.stringify(imageDoc));
        req.end();
        req.on('response', function (resp) {
           console.log("Imported", fullpath, "to", docName);
           finish();
        });
    });
});

processFiles(import_source.path, null, function (folder, file) {
    var extension = path.extname(file).slice(1).toLowerCase();
    if (!SUPPORTED_EXTENSIONS[extension]) {
        return;
    }
    import_queue.add({folder:folder, file:file});
});
<commit_msg>changed "medium" thumbnail from 256 to 512px<commit_after>var REF_TYPE = "testtype-reference";
var SOURCE_TYPE = "testtype-source";
var IMAGE_TYPE = "testtype-image";
var PHOTO_TYPE = "testtype-photo";

var import_source = {
    _id: "testsource-elgar_digipics",
    _rev: "testrev",
    name: "Elgar pictures",
    path: "/Users/nathan/Pictures/elgar_digipics",
    last_import: null,
    time_zone: 'US/Pacific'
};

var SUPPORTED_EXTENSIONS = {'jpg':true, 'jpeg':true};
var GET_PHOTO = __dirname + '/getphoto-osx/build/Release/getphoto';

var fs = require('fs'), path = require('path'), proc = require('child_process'), http = require('http');

function Serializer(callback) {
    var queue = [];
    var tick = function () {
        process.nextTick(nextItem);
    };
    var nextItem = function () {
        if (!queue.length) {
            return;
        }
        callback(queue.shift(), tick);
    }
    this.add = function (item) {
        if (!queue.length) {
            tick();
        }
        queue.push(item);
    }
}

function processFiles(base, subfolder, callback) {
    var folder = path.join(base, subfolder);
    fs.readdir(folder, function (e, files) {
        if (e) {
            console.warn(e);
            return;
        }

        files.forEach(function (filename) {
            if (filename[0] === '.') {
                return;
            }

            var fullpath = path.join(folder, filename);
            fs.stat(fullpath, function (e, stats) {
                if (e) {
                    console.warn(e);
                    return;
                }

                var subfile = path.join(subfolder, filename);
                if (stats.isDirectory()) {
                    processFiles(base, subfile, callback);
                } else {
                    callback(base, subfile);
                }
            });
        });
    });
}

var couchdb = require('http').createClient(5984, "localhost");

/*
var uuids;
var req = couchdb.request('GET', "/_uuids?count=1000", {'Connection': 'keep-alive'});
req.end();
req.on('response', function (resp) {
    var uuidsDoc = "";
    resp.setEncoding('utf8');
    resp.on('data', function (d) {
        uuidsDoc += d;
    });
    resp.on('end', function () {
        uuids = JSON.parse(uuidsDoc).uuids;
    });
});
*/

function makeRef(doc, denormalize) {
    var reference = {};
    reference[REF_TYPE] = true;
    reference._id = doc._id;
    if (denormalize) denormalize.forEach(function (field) {
        reference[field] = doc[field];
    }), (reference._rev = doc._rev);
    return reference;
}

var import_queue = new Serializer(function (info, finish) {
    var fullpath = path.join(info.folder, info.file);
    var get_photo = proc.spawn(GET_PHOTO, ['--thumbnail', '64', '--thumbnail', '512', '--timezone', import_source.time_zone, fullpath]);

    var imageDoc = "";
    get_photo.stdout.on('data', function (data) {
        imageDoc += data.toString();
    });
    get_photo.on('exit', function (exitCode) {
        if (exitCode !== 0) {
            finish();
            return;
        }
        imageDoc = JSON.parse(imageDoc);
        imageDoc.identifiers || (imageDoc.identifiers = {});
        imageDoc.identifiers.relative_path = {source:makeRef(import_source, ['name']), file:info.file};
        var docName = "/dev/testphoto-" + Math.random();
        var req = couchdb.request('PUT', docName, {'Connection': 'keep-alive'});
        req.write(JSON.stringify(imageDoc));
        req.end();
        req.on('response', function (resp) {
           console.log("Imported", fullpath, "to", docName);
           finish();
        });
    });
});

processFiles(import_source.path, null, function (folder, file) {
    var extension = path.extname(file).slice(1).toLowerCase();
    if (!SUPPORTED_EXTENSIONS[extension]) {
        return;
    }
    import_queue.add({folder:folder, file:file});
});
<|endoftext|>


<commit_before>/* global I18n HelperModule truncateLongString animateSpinner RepositoryListColumnType */
/* global RepositoryDatatable RepositoryStatusColumnType RepositoryChecklistColumnType dropdownSelector */
/* eslint-disable no-restricted-globals */

//= require jquery-ui/widgets/sortable

var RepositoryColumns = (function() {
  var TABLE_ID = '';
  var TABLE = null;
  var columnsList = '#repository-columns-list';
  var manageModal = '#manage-repository-column';
  var columnTypeClassNames = {
    RepositoryListValue: 'RepositoryListColumnType',
    RepositoryStatusValue: 'RepositoryStatusColumnType',
    RepositoryDateValue: 'RepositoryDateColumnType',
    RepositoryDateTimeValue: 'RepositoryDateTimeColumnType',
    RepositoryTimeValue: 'RepositoryTimeColumnType',
    RepositoryChecklistValue: 'RepositoryChecklistColumnType',
    RepositoryNumberValue: 'RepositoryNumberColumnType'
  };

  function reloadDataTablePartial() {
    // Append buttons for inventory datatable
    $('div.toolbarButtonsDatatable').appendTo('.repository-show');
    $('div.toolbarButtonsDatatable').hide();

    $('div.toolbar-filter-buttons').appendTo('.repository-show');
    $('div.toolbar-filter-buttons').hide();

    // destroy datatable and remove partial
    TABLE.destroy();
    $('.repository-table').remove();

    // reload datatable partial and intialize DataTable
    $.get($('.repository-show').data('table-url'), (response) => {
      $(response.html).appendTo($('.repository-show'));
      RepositoryDatatable.init('#' + $('.repository-table table').attr('id'));
      RepositoryDatatable.redrawTableOnSidebarToggle();
      // show manage columns index modal
      $(manageModal).find('.back-to-column-modal').trigger('click');
    });
  }

  function initColumnTypeSelector() {
    var $manageModal = $(manageModal);
    $manageModal.on('change', '#repository-column-data-type', function() {
      $('.column-type').hide();
      $('[data-column-type="' + $(this).val() + '"]').show();
    });
  }

  function initDeleteSubmitAction() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '#delete-repo-column-submit', function() {
      animateSpinner();
      $.ajax({
        url: $(this).data('delete-url'),
        type: 'DELETE',
        dataType: 'json',
        success: (result) => {
          reloadDataTablePartial();
          animateSpinner(null, false);
          HelperModule.flashAlertMsg(result.message, 'success');
        },
        error: (result) => {
          animateSpinner(null, false);
          HelperModule.flashAlertMsg(result.responseJSON.error, 'danger');
        }
      });
    });
  }

  function checkData() {
    var currentPartial = $('#repository-column-data-type').val();

    if (columnTypeClassNames[currentPartial]) {
      return eval(columnTypeClassNames[currentPartial])
        .checkValidation();
    }
    return true;
  }

  function addSpecificParams(type, params) {
    var allParams = params;
    var columnParams;
    var specificParams;
    var currentPartial = $('#repository-column-data-type').val();

    if (columnTypeClassNames[currentPartial]) {
      specificParams = eval(columnTypeClassNames[currentPartial]).loadParams();
      columnParams = Object.assign(params.repository_column, specificParams);
      allParams.repository_column = columnParams;
    }

    return allParams;
  }

  function initCreateSubmitAction() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '#new-repo-column-submit', function() {
      var url = $('#repository-column-data-type').find(':selected').data('create-url');
      var params = { repository_column: { name: $('#repository-column-name').val() } };
      var selectedType = $('#repository-column-data-type').val();
      params = addSpecificParams(selectedType, params);
      if (!checkData()) return;

      $.ajax({
        url: url,
        type: 'POST',
        data: JSON.stringify(params),
        contentType: 'application/json',
        success: function(result) {
          reloadDataTablePartial();
          HelperModule.flashAlertMsg(result.data.attributes.message, 'success');
        },
        error: function(error) {
          $('#new-repository-column').renderFormErrors('repository_column', error.responseJSON.repository_column, true);
        }
      });
    });
  }

  function initEditSubmitAction() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '#update-repo-column-submit', function() {
      var url = $('#repository-column-data-type').find(':selected').data('edit-url');
      var params = { repository_column: { name: $('#repository-column-name').val() } };
      var selectedType = $('#repository-column-data-type').val();
      params = addSpecificParams(selectedType, params);
      if (!checkData()) return;

      $.ajax({
        url: url,
        type: 'PUT',
        data: JSON.stringify(params),
        dataType: 'json',
        contentType: 'application/json',
        success: function(result) {
          reloadDataTablePartial();
          HelperModule.flashAlertMsg(result.data.attributes.message, 'success');
        },
        error: function(error) {
          $('#new-repository-column').renderFormErrors('repository_column', error.responseJSON.repository_column, true);
        }
      });
    });
  }

  function initManageColumnAction() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '.manage-repo-column', function() {
      var button = $(this);
      var modalUrl = button.data('modal-url');
      var columnType;
      var delimiterOptionsRender = function(data) {
        return `<span class='icon'>${data.params.icon}</span>${data.label}`;
      };
      var delimiterDropdownConfig = {
        singleSelect: true,
        noEmptyOption: true,
        selectAppearance: 'simple',
        closeOnSelect: true,
        optionClass: 'delimiter-icon-dropdown',
        optionLabel: delimiterOptionsRender,
        tagClass: 'delimiter-icon-dropdown',
        tagLabel: delimiterOptionsRender,
        disableSearch: true
      };
      $.get(modalUrl, (data) => {
        $manageModal.find('.modal-content').html(data.html)
          .find('#repository-column-name')
          .focus();
        columnType = $('#repository-column-data-type').val();
        dropdownSelector.init('#repository-column-data-type', {
          noEmptyOption: true,
          singleSelect: true,
          closeOnSelect: true,
          optionClass: 'custom-option',
          selectAppearance: 'simple',
          disableSearch: true
        });

        dropdownSelector.init('.list-column-type .delimiter', delimiterDropdownConfig);
        RepositoryListColumnType.initListDropdown();
        RepositoryListColumnType.initListPlaceholder();

        dropdownSelector.init('.checklist-column-type .delimiter', delimiterDropdownConfig);
        RepositoryChecklistColumnType.initChecklistDropdown();
        RepositoryChecklistColumnType.initChecklistPlaceholder();

        $manageModal
          .trigger('columnModal::partialLoadedFor' + columnType);

        RepositoryStatusColumnType.updateLoadedEmojies();

        if (button.data('action') === 'new') {
          $('[data-column-type="RepositoryTextValue"]').show();
          $('#new-repo-column-submit').show();
        } else {
          $('#update-repo-column-submit').show();
          $('[data-column-type="' + columnType + '"]').show();
        }
      }).fail(function() {
        HelperModule.flashAlertMsg(I18n.t('libraries.repository_columns.no_permissions'), 'danger');
      });
    });
  }

  function generateColumnNameTooltip(name) {
    var maxLength = $(TABLE_ID).data('max-dropdown-length');
    if ($.trim(name).length > maxLength) {
      return `

                ${truncateLongString(name, maxLength)}
                ${name}

`;
    }
    return name;
  }

  function toggleColumnVisibility() {
    var lis = $(columnsList).find('.vis');
    lis.on('click', function(event) {
      var self = $(this);
      var li = self.closest('li');
      var column = TABLE.column(li.attr('data-position'));

      event.stopPropagation();

      if (column.header.id !== 'row-name') {
        if (column.visible()) {
          self.addClass('fa-eye-slash');
          self.removeClass('fa-eye');
          li.addClass('col-invisible');
          column.visible(false);
          TABLE.setColumnSearchable(column.index(), false);
        } else {
          self.addClass('fa-eye');
          self.removeClass('fa-eye-slash');
          li.removeClass('col-invisible');
          column.visible(true);
          TABLE.setColumnSearchable(column.index(), true);
        }
      }
      // Re-filter/search if neccesary
      let searchText = $('div.dataTables_filter input').val();
      if (!_.isEmpty(searchText)) {
        TABLE.search(searchText).draw();
      }
    });
  }

  function getColumnTypeText(el, colId) {
    var colType = '';
    switch (colId) {
      case 'row-id':
        colType = 'RepositoryNumberValue';
        break;
      case 'row-name':
        colType = 'RepositoryTextValue';
        break;
      case 'added-on':
        colType = 'RepositoryDateTimeValue';
        break;
      case 'added-by':
        colType = 'RepositoryListValue';
        break;
      default:
        colType = $(el).attr('data-type');
    }
    return I18n.t('libraries.manange_modal_column.select.' + colType.split(/(?=[A-Z])/).join('_').toLowerCase());
  }

  // loads the columns names in the manage columns modal index
  function loadColumnsNames() {
    var $columnsList = $(columnsList);
    var scrollPosition = $columnsList.scrollTop();
    // Clear the list
    $columnsList.find('li[data-position]').remove();
    _.each(TABLE.columns().header(), function(el, index) {
      if (index > 1) {
        let colId = $(el).attr('id');
        let colIndex = $(el).attr('data-column-index');
        let visible = TABLE.column(colIndex).visible();
        let visClass = (visible) ? 'fa-eye' : 'fa-eye-slash';
        let visLi = (visible) ? '' : 'col-invisible';
        let visText = $(TABLE_ID).data('columns-visibility-text');
        let customColumn = ($(el).attr('data-type')) ? 'editable' : '';
        let editableRow = ($(el).attr('data-editable-row') === 'true') ? 'has-permissions' : '';
        let editUrl = $(el).attr('data-edit-column-url');
        let destroyUrl = $(el).attr('data-destroy-column-url');
        let thederName;
        if ($(el).find('.modal-tooltiptext').length > 0) {
          thederName = $(el).find('.modal-tooltiptext').text();
        } else {
          thederName = el.innerText;
        }
        if (thederName === 'Name') {
          visClass = '';
          visText = '';
        }
        let listItem = `

          ${generateColumnNameTooltip(thederName)}
          ${getColumnTypeText(el, colId)}

            <button class="btn icon-btn btn-light edit-repo-column manage-repo-column"
                    data-action="edit"
                    data-modal-url="${editUrl}">

            </button>
            <button class="btn icon-btn btn-light delete-repo-column manage-repo-column"
                    data-action="destroy"
                    data-modal-url="${destroyUrl}">

            </button>

`;

        $columnsList.append(listItem);
      }
    });
    $columnsList.scrollTop(scrollPosition);
    toggleColumnVisibility();
  }

  function initSorting() {
    var $columnsList = $(columnsList);
    $columnsList.sortable({
      items: 'li',
      scrollSpeed: 10,
      axis: 'y',
      update: function() {
        var reorderer = TABLE.colReorder;
        var listIds = [];
        // We skip first two columns
        listIds.push(0, 1);
        $columnsList.find('li[data-position]').each(function() {
          listIds.push($(this).first().data('position'));
        });
        reorderer.order(listIds, false);
        loadColumnsNames();
      }
    });
  }

  function initManageColumnModal(button) {
    var modalUrl = button.data('modal-url');
    $.get(modalUrl, (data) => {
      // show modal
      $(manageModal).modal('show').find('.modal-content').html(data.html);

      TABLE_ID = '#repository-table-' + data.id;
      TABLE = $(TABLE_ID).DataTable();

      initSorting();
      toggleColumnVisibility();
      loadColumnsNames();
      RepositoryDatatable.checkAvailableColumns();
    }).fail(function() {
      HelperModule.flashAlertMsg(I18n.t('libraries.repository_columns.no_permissions'), 'danger');
    });
  }

  function initBackToManageColumns() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '.back-to-column-modal', function() {
      var button = $(this);
      initManageColumnModal(button);
    });
  }

  function initColumnsButton() {
    $('.repo-datatables-buttons').on('click', '.manage-repo-column-index', function() {
      var button = $(this);
      initManageColumnModal(button);
    });
  }

  return {
    init: () => {
      if ($('.repo-datatables-buttons').length > 0) {
        initColumnTypeSelector();
        initCreateSubmitAction();
        initEditSubmitAction();
        initDeleteSubmitAction();
        initBackToManageColumns();
        initColumnsButton();
        initManageColumnAction();
        RepositoryListColumnType.init();
        RepositoryStatusColumnType.init();
        RepositoryChecklistColumnType.init();
      }
    }
  };
}());

$(document).on('turbolinks:load', function() {
  RepositoryColumns.init();
});
<commit_msg>Set timeout for loading manage column index modal to load after datatable redraw<commit_after>/* global I18n HelperModule truncateLongString animateSpinner RepositoryListColumnType */
/* global RepositoryDatatable RepositoryStatusColumnType RepositoryChecklistColumnType dropdownSelector */
/* eslint-disable no-restricted-globals */

//= require jquery-ui/widgets/sortable

var RepositoryColumns = (function() {
  var TABLE_ID = '';
  var TABLE = null;
  var columnsList = '#repository-columns-list';
  var manageModal = '#manage-repository-column';
  var columnTypeClassNames = {
    RepositoryListValue: 'RepositoryListColumnType',
    RepositoryStatusValue: 'RepositoryStatusColumnType',
    RepositoryDateValue: 'RepositoryDateColumnType',
    RepositoryDateTimeValue: 'RepositoryDateTimeColumnType',
    RepositoryTimeValue: 'RepositoryTimeColumnType',
    RepositoryChecklistValue: 'RepositoryChecklistColumnType',
    RepositoryNumberValue: 'RepositoryNumberColumnType'
  };

  function reloadDataTablePartial() {
    // Append buttons for inventory datatable
    $('div.toolbarButtonsDatatable').appendTo('.repository-show');
    $('div.toolbarButtonsDatatable').hide();

    $('div.toolbar-filter-buttons').appendTo('.repository-show');
    $('div.toolbar-filter-buttons').hide();

    // destroy datatable and remove partial
    TABLE.destroy();
    $('.repository-table').remove();

    // reload datatable partial and intialize DataTable
    $.get($('.repository-show').data('table-url'), (response) => {
      $(response.html).appendTo($('.repository-show'));
      RepositoryDatatable.init('#' + $('.repository-table table').attr('id'));
      RepositoryDatatable.redrawTableOnSidebarToggle();
      // show manage columns index modal
      setTimeout(function() {
        $(manageModal).find('.back-to-column-modal').trigger('click');
      }, 500);
    });
  }

  function initColumnTypeSelector() {
    var $manageModal = $(manageModal);
    $manageModal.on('change', '#repository-column-data-type', function() {
      $('.column-type').hide();
      $('[data-column-type="' + $(this).val() + '"]').show();
    });
  }

  function initDeleteSubmitAction() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '#delete-repo-column-submit', function() {
      animateSpinner();
      $.ajax({
        url: $(this).data('delete-url'),
        type: 'DELETE',
        dataType: 'json',
        success: (result) => {
          reloadDataTablePartial();
          animateSpinner(null, false);
          HelperModule.flashAlertMsg(result.message, 'success');
        },
        error: (result) => {
          animateSpinner(null, false);
          HelperModule.flashAlertMsg(result.responseJSON.error, 'danger');
        }
      });
    });
  }

  function checkData() {
    var currentPartial = $('#repository-column-data-type').val();

    if (columnTypeClassNames[currentPartial]) {
      return eval(columnTypeClassNames[currentPartial])
        .checkValidation();
    }
    return true;
  }

  function addSpecificParams(type, params) {
    var allParams = params;
    var columnParams;
    var specificParams;
    var currentPartial = $('#repository-column-data-type').val();

    if (columnTypeClassNames[currentPartial]) {
      specificParams = eval(columnTypeClassNames[currentPartial]).loadParams();
      columnParams = Object.assign(params.repository_column, specificParams);
      allParams.repository_column = columnParams;
    }

    return allParams;
  }

  function initCreateSubmitAction() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '#new-repo-column-submit', function() {
      var url = $('#repository-column-data-type').find(':selected').data('create-url');
      var params = { repository_column: { name: $('#repository-column-name').val() } };
      var selectedType = $('#repository-column-data-type').val();
      params = addSpecificParams(selectedType, params);
      if (!checkData()) return;

      $.ajax({
        url: url,
        type: 'POST',
        data: JSON.stringify(params),
        contentType: 'application/json',
        success: function(result) {
          reloadDataTablePartial();
          HelperModule.flashAlertMsg(result.data.attributes.message, 'success');
        },
        error: function(error) {
          $('#new-repository-column').renderFormErrors('repository_column', error.responseJSON.repository_column, true);
        }
      });
    });
  }

  function initEditSubmitAction() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '#update-repo-column-submit', function() {
      var url = $('#repository-column-data-type').find(':selected').data('edit-url');
      var params = { repository_column: { name: $('#repository-column-name').val() } };
      var selectedType = $('#repository-column-data-type').val();
      params = addSpecificParams(selectedType, params);
      if (!checkData()) return;

      $.ajax({
        url: url,
        type: 'PUT',
        data: JSON.stringify(params),
        dataType: 'json',
        contentType: 'application/json',
        success: function(result) {
          reloadDataTablePartial();
          HelperModule.flashAlertMsg(result.data.attributes.message, 'success');
        },
        error: function(error) {
          $('#new-repository-column').renderFormErrors('repository_column', error.responseJSON.repository_column, true);
        }
      });
    });
  }

  function initManageColumnAction() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '.manage-repo-column', function() {
      var button = $(this);
      var modalUrl = button.data('modal-url');
      var columnType;
      var delimiterOptionsRender = function(data) {
        return `<span class='icon'>${data.params.icon}</span>${data.label}`;
      };
      var delimiterDropdownConfig = {
        singleSelect: true,
        noEmptyOption: true,
        selectAppearance: 'simple',
        closeOnSelect: true,
        optionClass: 'delimiter-icon-dropdown',
        optionLabel: delimiterOptionsRender,
        tagClass: 'delimiter-icon-dropdown',
        tagLabel: delimiterOptionsRender,
        disableSearch: true
      };
      $.get(modalUrl, (data) => {
        $manageModal.find('.modal-content').html(data.html)
          .find('#repository-column-name')
          .focus();
        columnType = $('#repository-column-data-type').val();
        dropdownSelector.init('#repository-column-data-type', {
          noEmptyOption: true,
          singleSelect: true,
          closeOnSelect: true,
          optionClass: 'custom-option',
          selectAppearance: 'simple',
          disableSearch: true
        });

        dropdownSelector.init('.list-column-type .delimiter', delimiterDropdownConfig);
        RepositoryListColumnType.initListDropdown();
        RepositoryListColumnType.initListPlaceholder();

        dropdownSelector.init('.checklist-column-type .delimiter', delimiterDropdownConfig);
        RepositoryChecklistColumnType.initChecklistDropdown();
        RepositoryChecklistColumnType.initChecklistPlaceholder();

        $manageModal
          .trigger('columnModal::partialLoadedFor' + columnType);

        RepositoryStatusColumnType.updateLoadedEmojies();

        if (button.data('action') === 'new') {
          $('[data-column-type="RepositoryTextValue"]').show();
          $('#new-repo-column-submit').show();
        } else {
          $('#update-repo-column-submit').show();
          $('[data-column-type="' + columnType + '"]').show();
        }
      }).fail(function() {
        HelperModule.flashAlertMsg(I18n.t('libraries.repository_columns.no_permissions'), 'danger');
      });
    });
  }

  function generateColumnNameTooltip(name) {
    var maxLength = $(TABLE_ID).data('max-dropdown-length');
    if ($.trim(name).length > maxLength) {
      return `

                ${truncateLongString(name, maxLength)}
                ${name}

`;
    }
    return name;
  }

  function toggleColumnVisibility() {
    var lis = $(columnsList).find('.vis');
    lis.on('click', function(event) {
      var self = $(this);
      var li = self.closest('li');
      var column = TABLE.column(li.attr('data-position'));

      event.stopPropagation();

      if (column.header.id !== 'row-name') {
        if (column.visible()) {
          self.addClass('fa-eye-slash');
          self.removeClass('fa-eye');
          li.addClass('col-invisible');
          column.visible(false);
          TABLE.setColumnSearchable(column.index(), false);
        } else {
          self.addClass('fa-eye');
          self.removeClass('fa-eye-slash');
          li.removeClass('col-invisible');
          column.visible(true);
          TABLE.setColumnSearchable(column.index(), true);
        }
      }
      // Re-filter/search if neccesary
      let searchText = $('div.dataTables_filter input').val();
      if (!_.isEmpty(searchText)) {
        TABLE.search(searchText).draw();
      }
    });
  }

  function getColumnTypeText(el, colId) {
    var colType = '';
    switch (colId) {
      case 'row-id':
        colType = 'RepositoryNumberValue';
        break;
      case 'row-name':
        colType = 'RepositoryTextValue';
        break;
      case 'added-on':
        colType = 'RepositoryDateTimeValue';
        break;
      case 'added-by':
        colType = 'RepositoryListValue';
        break;
      default:
        colType = $(el).attr('data-type');
    }
    return I18n.t('libraries.manange_modal_column.select.' + colType.split(/(?=[A-Z])/).join('_').toLowerCase());
  }

  // loads the columns names in the manage columns modal index
  function loadColumnsNames() {
    var $columnsList = $(columnsList);
    var scrollPosition = $columnsList.scrollTop();
    // Clear the list
    $columnsList.find('li[data-position]').remove();
    _.each(TABLE.columns().header(), function(el, index) {
      if (index > 1) {
        let colId = $(el).attr('id');
        let colIndex = $(el).attr('data-column-index');
        let visible = TABLE.column(colIndex).visible();
        let visClass = (visible) ? 'fa-eye' : 'fa-eye-slash';
        let visLi = (visible) ? '' : 'col-invisible';
        let visText = $(TABLE_ID).data('columns-visibility-text');
        let customColumn = ($(el).attr('data-type')) ? 'editable' : '';
        let editableRow = ($(el).attr('data-editable-row') === 'true') ? 'has-permissions' : '';
        let editUrl = $(el).attr('data-edit-column-url');
        let destroyUrl = $(el).attr('data-destroy-column-url');
        let thederName;
        if ($(el).find('.modal-tooltiptext').length > 0) {
          thederName = $(el).find('.modal-tooltiptext').text();
        } else {
          thederName = el.innerText;
        }
        if (thederName === 'Name') {
          visClass = '';
          visText = '';
        }
        let listItem = `

          ${generateColumnNameTooltip(thederName)}
          ${getColumnTypeText(el, colId)}

            <button class="btn icon-btn btn-light edit-repo-column manage-repo-column"
                    data-action="edit"
                    data-modal-url="${editUrl}">

            </button>
            <button class="btn icon-btn btn-light delete-repo-column manage-repo-column"
                    data-action="destroy"
                    data-modal-url="${destroyUrl}">

            </button>

`;

        $columnsList.append(listItem);
      }
    });
    $columnsList.scrollTop(scrollPosition);
    toggleColumnVisibility();
  }

  function initSorting() {
    var $columnsList = $(columnsList);
    $columnsList.sortable({
      items: 'li',
      scrollSpeed: 10,
      axis: 'y',
      update: function() {
        var reorderer = TABLE.colReorder;
        var listIds = [];
        // We skip first two columns
        listIds.push(0, 1);
        $columnsList.find('li[data-position]').each(function() {
          listIds.push($(this).first().data('position'));
        });
        reorderer.order(listIds, false);
        loadColumnsNames();
      }
    });
  }

  function initManageColumnModal(button) {
    var modalUrl = button.data('modal-url');
    $.get(modalUrl, (data) => {
      // show modal
      $(manageModal).modal('show').find('.modal-content').html(data.html);

      TABLE_ID = '#repository-table-' + data.id;
      TABLE = $(TABLE_ID).DataTable();

      initSorting();
      toggleColumnVisibility();
      loadColumnsNames();
      RepositoryDatatable.checkAvailableColumns();
    }).fail(function() {
      HelperModule.flashAlertMsg(I18n.t('libraries.repository_columns.no_permissions'), 'danger');
    });
  }

  function initBackToManageColumns() {
    var $manageModal = $(manageModal);
    $manageModal.on('click', '.back-to-column-modal', function() {
      var button = $(this);
      initManageColumnModal(button);
    });
  }

  function initColumnsButton() {
    $('.repo-datatables-buttons').on('click', '.manage-repo-column-index', function() {
      var button = $(this);
      initManageColumnModal(button);
    });
  }

  return {
    init: () => {
      if ($('.repo-datatables-buttons').length > 0) {
        initColumnTypeSelector();
        initCreateSubmitAction();
        initEditSubmitAction();
        initDeleteSubmitAction();
        initBackToManageColumns();
        initColumnsButton();
        initManageColumnAction();
        RepositoryListColumnType.init();
        RepositoryStatusColumnType.init();
        RepositoryChecklistColumnType.init();
      }
    }
  };
}());

$(document).on('turbolinks:load', function() {
  RepositoryColumns.init();
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
const fs = require('fs')
const colors = require('colors')
const program = require('commander')
const { execSync } = require('child_process')
const _ = require('lodash')

program
  .version('0.2.4')
  .usage('[<options>...] [<search>]')
  .option('--raw', 'Show raw import/export statements from all source files')
  .option('--zero', 'Show the full list of sources from all import statements')
  .option('--json', 'JSON output (include sourceFiles, sources and importedBy sections)')
  .option('--externals', 'Show only external npm package references')
  .option('--ignore-tests', 'Ignore sources from **/__specs__/ and test/')
  .option('-N, --not-referenced', 'Show all sources which are not referenced by imports')
  .option('-R, --references', 'Show for source files from where they are referenced; you can filter the source files by <search>')
  .parse(process.argv)

const NOT_REFERENCED = program.notReferenced
const REFERENCES = program.references
const EXTERNALS_ONLY = program.externals
const NO_SPECS = program.ignoreTests
const SEARCH = program.args[0]
const SHOW_JSON = program.json
const SHOW_RAW = program.raw
const SHOW_ZERO = program.zero

let flagsUsedNo = 0
if (NOT_REFERENCED) ++flagsUsedNo
if (REFERENCES) ++flagsUsedNo
if (SEARCH) ++flagsUsedNo
if (SHOW_JSON) ++flagsUsedNo
if (SHOW_RAW) ++flagsUsedNo
if (SHOW_ZERO) ++flagsUsedNo

if (flagsUsedNo > 1 && !(flagsUsedNo === 2 && SEARCH && REFERENCES)) {
  console.log('Error: the options -R, -O, -J, -N and --raw can\'t be used together.')
  console.log('use -h (or --help) for details.')
  process.exit(1)
}

const SHOW_DEFAULT_OUTPUT = flagsUsedNo === 0

const filesList = execSync('./source-files.sh', { cwd: __dirname, encoding: 'utf-8' }).split('\n')

const filterExternals = imports => imports.filter(im => !EXTERNALS_ONLY || im.isExternal)

const jsonOut = {
  sourceFiles: [],
  sources: {},
  importedBy: {}
}

filesList.forEach((filename) => {
  if (!filename) return

  if (NO_SPECS && (filename.startsWith('test') || filename.indexOf('__specs__') >= 0)) {
    return
  }

  // step-0) load source file

  const lines = fs.readFileSync(filename, 'utf-8').split('\n')
  const imports = []
  let isImport = false

  jsonOut.sourceFiles.push(filename)

  const addImport = (sourceFile, importFile, lineNo) => {
    const im = parseImport(sourceFile, importFile, lineNo)
    imports.push(im)
    if (!jsonOut.sources[sourceFile]) {
      jsonOut.sources[sourceFile] = []
    }
    jsonOut.sources[sourceFile].push(`${im.isExternal ? 'external!' : ''}${im.fullImportFile || im.importFile}`)
    if (!jsonOut.importedBy[im.fullImportFile]) {
      jsonOut.importedBy[im.fullImportFile] = []
    }
    jsonOut.importedBy[im.fullImportFile].push(sourceFile)
  }

  // step-1) parse source file - extract all import statements

  lines.forEach((line, idx) => {
    if (!isImport) {
      const tLine = line.trim()
      if (tLine.startsWith('import') || tLine.startsWith('export')) {
        const m = line.match(/(import|export)(\s+.+from)?\s+'([^']+)'[\s;]*$/)
        if (m) {
          if (SHOW_RAW) console.log(line)
          addImport(filename, m[m.length - 1], idx)
        } else if (tLine.match(/(import|export)\s+[^{]*{\s*$/)) {
          if (SHOW_RAW) console.log(line)
          isImport = true
        }
      }
    } else {
      if (SHOW_RAW) console.log(line)
      const m = line.match(/^[^}]*\}\s+from\s+'([^']+)'[\s;]*$/)
      if (m) {
        isImport = false
        addImport(filename, m[m.length - 1], idx)
      }
    }
  })

  // step-2-a) show full imports info as human readable text (for current source file)

  if ((SEARCH && !REFERENCES) || SHOW_ZERO || SHOW_DEFAULT_OUTPUT) {
    if (imports.length) {
      if (!SEARCH) {
        if (SHOW_ZERO) {
          imports.forEach(im => console.log(im.importFile))
        } else {
          const showImports = filterExternals(imports)
          if (showImports.length) {
            console.log()
            console.log(colors.bold(`${filename}:`))
            console.log(showImports.map(im => {
              const isExternal = im.isExternal ? '(external) ' : ''
              return im.isExternal ? `- ${im.lineNo}: ${isExternal}${im.fullImportFile}` : `- ${im.lineNo}: ${isExternal}${im.importFile} -> ${im.fullImportFile}`
            }).join('\n'))
          }
        }
      } else {
        const found = []
        filterExternals(imports).forEach(im => {
          const idx = im.fullImportFile.indexOf(SEARCH)
          if (idx >= 0) {
            const isExternal = im.isExternal ? '(external) ' : ''
            found.push(`- ${im.lineNo}: ${isExternal}${im.isAbsolute ? '' : `${im.importFile} -> `}${im.fullImportFile.slice(0, idx)}${colors.bgYellow(SEARCH)}${im.fullImportFile.slice(idx + SEARCH.length, im.fullImportFile.length)}`)
          }
        })
        if (found.length) {
          console.log()
          console.log(colors.bold(`${filename}:`))
          found.forEach(line => console.log(line))
        }
      }
    }
  }
})

// step-2-b) show json output

if (SHOW_JSON) {
  console.log(JSON.stringify(jsonOut, null, 2))
}

// step-2-c) show sources which are not referenced by imports

if (NOT_REFERENCED) {
  _.uniq(jsonOut.sourceFiles.filter(source => !jsonOut.importedBy[source])).sort().forEach(src => console.log(src))
}

// step-2-d) show references

if (REFERENCES) {
  jsonOut.sourceFiles.forEach(source => {
    const hasReferences = !!jsonOut.importedBy[source]
    if (hasReferences) {
      if (SEARCH) {
        const idx = source.indexOf(SEARCH)
        if (idx === -1) return
        console.log()
        console.log(colors.bold(`${source.slice(0, idx)}${colors.bgYellow(SEARCH)}${source.slice(idx + SEARCH.length, source.length)}:`))
      } else {
        console.log()
        console.log(colors.bold(`${source}:`))
      }
      jsonOut.importedBy[source].forEach(src => console.log('-', src))
    }
  })
}

// the end.  o==)----- --

// appendix) helpers --------------------------------------------------------------

function parseImport (sourceFile, importFile, lineNo) {
  let fullImportFile = importFile
  let isAbsolute = importFile[0] !== '.'
  if (!isAbsolute) {
    const path = sourceFile.split('/')
    path.pop()
    if (importFile.startsWith('./')) {
      fullImportFile = `${path.join('/')}${importFile.substr(1)}`
    } else {
      if (fullImportFile.startsWith('../')) {
        do {
          fullImportFile = fullImportFile.substr(3)
          path.pop()
        } while (fullImportFile.startsWith('../'))
        if (path.length) {
          fullImportFile = `${path.join('/')}/${fullImportFile}`
        }
      }
    }
  }
  if (importFile.startsWith('picimo')) {
    fullImportFile = importFile.replace('picimo', 'src/picimo')
  } else if (importFile.startsWith('common')) {
    fullImportFile = importFile.replace('common', 'src/common')
  } else if (importFile.startsWith('bootstrap')) {
    fullImportFile = importFile.replace('bootstrap', 'src/bootstrap')
  }
  if (!fullImportFile.endsWith('.js')) {
    if (fs.existsSync(`${fullImportFile}.js`)) {
      fullImportFile = `${fullImportFile}.js`
    } else if (fs.existsSync(`${fullImportFile}/index.js`)) {
      fullImportFile = `${fullImportFile}/index.js`
    }
  }
  const isExternal = isAbsolute && (!fs.existsSync(importFile) && !fs.existsSync(fullImportFile))
  return {
    isExternal,
    isAbsolute,
    lineNo,
    sourceFile,
    importFile,
    fullImportFile
  }
}
<commit_msg>improve javascript-imports: add ignore examples and bootstrap options<commit_after>#!/usr/bin/env node
const fs = require('fs')
const colors = require('colors')
const program = require('commander')
const { execSync } = require('child_process')
const _ = require('lodash')

program
  .version('0.2.5')
  .usage('[<options>...] [<search>]')
  .option('--raw', 'Show raw import/export statements from all source files')
  .option('--zero', 'Show the full list of sources from all import statements')
  .option('--json', 'JSON output (include sourceFiles, sources and importedBy sections)')
  .option('--externals', 'Show only external npm package references')
  .option('--ignore-tests', 'Ignore sources from **/__specs__/ and test/')
  .option('--ignore-examples', 'Ignore sources from examples/ and webgl-boilerplate/')
  .option('--ignore-bootstrap', 'Ignore sources from src/bootstrap/')
  .option('-N, --not-referenced', 'Show all sources which are not referenced by imports')
  .option('-R, --references', 'Show for source files from where they are referenced; you can filter the source files by <search>')
  .parse(process.argv)

const NOT_REFERENCED = program.notReferenced
const REFERENCES = program.references
const EXTERNALS_ONLY = program.externals
const NO_SPECS = program.ignoreTests
const NO_EXAMPLES = program.ignoreExamples
const NO_BOOTSTRAP = program.ignoreBootstrap
const SEARCH = program.args[0]
const SHOW_JSON = program.json
const SHOW_RAW = program.raw
const SHOW_ZERO = program.zero

let flagsUsedNo = 0
if (NOT_REFERENCED) ++flagsUsedNo
if (REFERENCES) ++flagsUsedNo
if (SEARCH) ++flagsUsedNo
if (SHOW_JSON) ++flagsUsedNo
if (SHOW_RAW) ++flagsUsedNo
if (SHOW_ZERO) ++flagsUsedNo

if (flagsUsedNo > 1 && !(flagsUsedNo === 2 && SEARCH && REFERENCES)) {
  console.log('Error: the options -R, -O, -J, -N and --raw can\'t be used together.')
  console.log('use -h (or --help) for details.')
  process.exit(1)
}

const SHOW_DEFAULT_OUTPUT = flagsUsedNo === 0

const filesList = execSync('./source-files.sh', { cwd: __dirname, encoding: 'utf-8' }).split('\n')

const filterExternals = imports => imports.filter(im => !EXTERNALS_ONLY || im.isExternal)

const jsonOut = {
  sourceFiles: [],
  sources: {},
  importedBy: {}
}

filesList.forEach((filename) => {
  if (!filename) return

  if (NO_SPECS && (filename.startsWith('test') || filename.indexOf('__specs__') >= 0)) return
  if (NO_EXAMPLES && (filename.startsWith('examples') || filename.startsWith('webgl-boilerplate'))) return
  if (NO_BOOTSTRAP && filename.startsWith('src/bootstrap')) return

  // step-0) load source file

  const lines = fs.readFileSync(filename, 'utf-8').split('\n')
  const imports = []
  let isImport = false

  jsonOut.sourceFiles.push(filename)

  const addImport = (sourceFile, importFile, lineNo) => {
    const im = parseImport(sourceFile, importFile, lineNo)
    imports.push(im)
    if (!jsonOut.sources[sourceFile]) {
      jsonOut.sources[sourceFile] = []
    }
    jsonOut.sources[sourceFile].push(`${im.isExternal ? 'external!' : ''}${im.fullImportFile || im.importFile}`)
    if (!jsonOut.importedBy[im.fullImportFile]) {
      jsonOut.importedBy[im.fullImportFile] = []
    }
    jsonOut.importedBy[im.fullImportFile].push(sourceFile)
  }

  // step-1) parse source file - extract all import statements

  lines.forEach((line, idx) => {
    if (!isImport) {
      const tLine = line.trim()
      if (tLine.startsWith('import') || tLine.startsWith('export')) {
        const m = line.match(/(import|export)(\s+.+from)?\s+'([^']+)'[\s;]*$/)
        if (m) {
          if (SHOW_RAW) console.log(line)
          addImport(filename, m[m.length - 1], idx)
        } else if (tLine.match(/(import|export)\s+[^{]*{\s*$/)) {
          if (SHOW_RAW) console.log(line)
          isImport = true
        }
      }
    } else {
      if (SHOW_RAW) console.log(line)
      const m = line.match(/^[^}]*\}\s+from\s+'([^']+)'[\s;]*$/)
      if (m) {
        isImport = false
        addImport(filename, m[m.length - 1], idx)
      }
    }
  })

  // step-2-a) show full imports info as human readable text (for current source file)

  if ((SEARCH && !REFERENCES) || SHOW_ZERO || SHOW_DEFAULT_OUTPUT) {
    if (imports.length) {
      if (!SEARCH) {
        if (SHOW_ZERO) {
          imports.forEach(im => console.log(im.importFile))
        } else {
          const showImports = filterExternals(imports)
          if (showImports.length) {
            console.log()
            console.log(colors.bold(`${filename}:`))
            console.log(showImports.map(im => {
              const isExternal = im.isExternal ? '(external) ' : ''
              return im.isExternal ? `- ${im.lineNo}: ${isExternal}${im.fullImportFile}` : `- ${im.lineNo}: ${isExternal}${im.importFile} -> ${im.fullImportFile}`
            }).join('\n'))
          }
        }
      } else {
        const found = []
        filterExternals(imports).forEach(im => {
          const idx = im.fullImportFile.indexOf(SEARCH)
          if (idx >= 0) {
            const isExternal = im.isExternal ? '(external) ' : ''
            found.push(`- ${im.lineNo}: ${isExternal}${im.isAbsolute ? '' : `${im.importFile} -> `}${im.fullImportFile.slice(0, idx)}${colors.bgYellow(SEARCH)}${im.fullImportFile.slice(idx + SEARCH.length, im.fullImportFile.length)}`)
          }
        })
        if (found.length) {
          console.log()
          console.log(colors.bold(`${filename}:`))
          found.forEach(line => console.log(line))
        }
      }
    }
  }
})

// step-2-b) show json output

if (SHOW_JSON) {
  console.log(JSON.stringify(jsonOut, null, 2))
}

// step-2-c) show sources which are not referenced by imports

if (NOT_REFERENCED) {
  _.uniq(jsonOut.sourceFiles.filter(source => !jsonOut.importedBy[source])).sort().forEach(src => console.log(src))
}

// step-2-d) show references

if (REFERENCES) {
  jsonOut.sourceFiles.forEach(source => {
    const hasReferences = !!jsonOut.importedBy[source]
    if (hasReferences) {
      if (SEARCH) {
        const idx = source.indexOf(SEARCH)
        if (idx === -1) return
        console.log()
        console.log(colors.bold(`${source.slice(0, idx)}${colors.bgYellow(SEARCH)}${source.slice(idx + SEARCH.length, source.length)}:`))
      } else {
        console.log()
        console.log(colors.bold(`${source}:`))
      }
      jsonOut.importedBy[source].forEach(src => console.log('-', src))
    }
  })
}

// the end.  o==)----- --

// appendix) helpers --------------------------------------------------------------

function parseImport (sourceFile, importFile, lineNo) {
  let fullImportFile = importFile
  let isAbsolute = importFile[0] !== '.'
  if (!isAbsolute) {
    const path = sourceFile.split('/')
    path.pop()
    if (importFile.startsWith('./')) {
      fullImportFile = `${path.join('/')}${importFile.substr(1)}`
    } else {
      if (fullImportFile.startsWith('../')) {
        do {
          fullImportFile = fullImportFile.substr(3)
          path.pop()
        } while (fullImportFile.startsWith('../'))
        if (path.length) {
          fullImportFile = `${path.join('/')}/${fullImportFile}`
        }
      }
    }
  }
  if (importFile.startsWith('picimo')) {
    fullImportFile = importFile.replace('picimo', 'src/picimo')
  } else if (importFile.startsWith('common')) {
    fullImportFile = importFile.replace('common', 'src/common')
  } else if (importFile.startsWith('bootstrap')) {
    fullImportFile = importFile.replace('bootstrap', 'src/bootstrap')
  }
  if (!fullImportFile.endsWith('.js')) {
    if (fs.existsSync(`${fullImportFile}.js`)) {
      fullImportFile = `${fullImportFile}.js`
    } else if (fs.existsSync(`${fullImportFile}/index.js`)) {
      fullImportFile = `${fullImportFile}/index.js`
    }
  }
  const isExternal = isAbsolute && (!fs.existsSync(importFile) && !fs.existsSync(fullImportFile))
  return {
    isExternal,
    isAbsolute,
    lineNo,
    sourceFile,
    importFile,
    fullImportFile
  }
}
<|endoftext|>


<commit_before>const baseConfig = require('./karma.config.base');

const {
  CIRCLE_BRANCH,
  CIRCLE_BUILD_NUM,
  FORCE_MOBILE_TEST,
} = process.env;

const customLaunchers = {
  sl_chrome: {
    base: 'SauceLabs',
    browserName: 'chrome',
    platform: 'Windows 7',
    version: 'latest',
  },
  sl_firefox: {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: 'latest',
  },

  // yet another IE family
  sl_mac_safari_8: {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.10',
    version: '8',
  },
  sl_mac_safari_9: {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.11',
    version: '9',
  },
  sl_mac_safari_10: {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'macOS 10.12',
  },

  // IE family
  sl_ie_10: {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 7',
    version: '10',
  },
  sl_ie_11: {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 8.1',
    version: '11',
  },
  sl_edge: {
    base: 'SauceLabs',
    browserName: 'MicrosoftEdge',
    platform: 'Windows 10',
  },
};

// mobile emulators are really really slow
// only run them on develop/master branch
if (CIRCLE_BRANCH === 'develop' || CIRCLE_BRANCH === 'master' || FORCE_MOBILE_TEST) {
  Object.assign(customLaunchers, {
    sl_ios_9: {
      base: 'SauceLabs',
      browserName: 'iphone',
      version: '9.3',
    },
    sl_ios_10: {
      base: 'SauceLabs',
      browserName: 'iphone',
      version: '10.0',
    },
    sl_android_5: {
      base: 'SauceLabs',
      browserName: 'android',
      version: '5.1',
    },
  });
}

const buildNum = CIRCLE_BUILD_NUM ? `#${CIRCLE_BUILD_NUM}` : `@${Date.now()}`;

module.exports = function (config) {
  config.set(Object.assign(baseConfig, {
    reporters: ['mocha', 'saucelabs'],
    browsers: Object.keys(customLaunchers),
    customLaunchers: customLaunchers,
    // wait for mobile emulators
    captureTimeout: 300000,
    browserNoActivityTimeout: 300000,
    sauceLabs: {
      testName: 'Service Mocker tests',
      recordScreenshots: false,
      build: `service-mocker ${buildNum}`,
    },
  }));
};
<commit_msg>ci(sauce): use minimal output<commit_after>const baseConfig = require('./karma.config.base');

const {
  CIRCLE_BRANCH,
  CIRCLE_BUILD_NUM,
  FORCE_MOBILE_TEST,
} = process.env;

const customLaunchers = {
  sl_chrome: {
    base: 'SauceLabs',
    browserName: 'chrome',
    platform: 'Windows 7',
    version: 'latest',
  },
  sl_firefox: {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: 'latest',
  },

  // yet another IE family
  sl_mac_safari_8: {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.10',
    version: '8',
  },
  sl_mac_safari_9: {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.11',
    version: '9',
  },
  sl_mac_safari_10: {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'macOS 10.12',
  },

  // IE family
  sl_ie_10: {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 7',
    version: '10',
  },
  sl_ie_11: {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 8.1',
    version: '11',
  },
  sl_edge: {
    base: 'SauceLabs',
    browserName: 'MicrosoftEdge',
    platform: 'Windows 10',
  },
};

// mobile emulators are really really slow
// only run them on develop/master branch
if (CIRCLE_BRANCH === 'develop' || CIRCLE_BRANCH === 'master' || FORCE_MOBILE_TEST) {
  Object.assign(customLaunchers, {
    sl_ios_9: {
      base: 'SauceLabs',
      browserName: 'iphone',
      version: '9.3',
    },
    sl_ios_10: {
      base: 'SauceLabs',
      browserName: 'iphone',
      version: '10.0',
    },
    sl_android_5: {
      base: 'SauceLabs',
      browserName: 'android',
      version: '5.1',
    },
  });
}

const buildNum = CIRCLE_BUILD_NUM ? `#${CIRCLE_BUILD_NUM}` : `@${Date.now()}`;

module.exports = function (config) {
  config.set(Object.assign(baseConfig, {
    reporters: ['mocha', 'saucelabs'],
    browsers: Object.keys(customLaunchers),
    customLaunchers: customLaunchers,
    // wait for mobile emulators
    captureTimeout: 300000,
    browserNoActivityTimeout: 300000,
    sauceLabs: {
      testName: 'Service Mocker tests',
      recordScreenshots: false,
      build: `service-mocker ${buildNum}`,
    },
    mochaReporter: {
      output: 'minimal',
    },
  }));
};
<|endoftext|>