<commit_before>/*
 * Copyright (c) 2015 Memorial Sloan-Kettering Cancer Center.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
 * FOR A PARTICULAR PURPOSE. The software and documentation provided hereunder
 * is on an "as is" basis, and Memorial Sloan-Kettering Cancer Center has no
 * obligations to provide maintenance, support, updates, enhancements or
 * modifications. In no event shall Memorial Sloan-Kettering Cancer Center be
 * liable to any party for direct, indirect, special, incidental or
 * consequential damages, including lost profits, arising out of the use of this
 * software and its documentation, even if Memorial Sloan-Kettering Cancer
 * Center has been advised of the possibility of such damage.
 */

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

var OncoKBConnector = (function () {
    var oncokbUrl = '';

    function init(data) {
        oncokbUrl = data.url || '';
    }

    function oncokbAccess(callback) {
        if (oncokbUrl && oncokbUrl !== 'null') {
            $.get('api/proxy/oncokbAccess', function () {
                callback(true);
            })
                .fail(function () {
                    callback(false);
                });
        } else {
            callback(false);
        }
    }

    function getEvidence(variants, callback) {
        var mutationEventIds = variants.mutations.getEventIds(false),
            searchPairs = [],
            geneStr = "",
            alterationStr = "",
            consequenceStr = ""
        var oncokbServiceData = {};
        var oncokbSummaryData = {};

        for (var i = 0, mutationL = mutationEventIds.length; i < mutationL; i++) {
            var datum = {},
                gene = variants.mutations.getValue(mutationEventIds[i], 'gene'),
                alteration = variants.mutations.getValue(mutationEventIds[i], 'aa'),
                consequence = consequenceConverter(variants.mutations.getValue(mutationEventIds[i], 'type'));
            datum.gene = gene;
            datum.alteration = alteration;
            datum.consequence = consequence;
            searchPairs.push(datum);

            geneStr += gene + ",";
            alterationStr += alteration + ",";
            consequenceStr += consequence + ",";
        }

        oncokbServiceData = {
            'hugoSymbol': geneStr.substring(0, geneStr.length - 1),
            'alteration': alterationStr.substring(0, alterationStr.length - 1),
            'consequence': consequenceStr.substring(0, consequenceStr.length - 1),
            'evidenceType': 'GENE_SUMMARY,GENE_BACKGROUND,MUTATION_EFFECT,STANDARD_THERAPEUTIC_IMPLICATIONS_FOR_DRUG_SENSITIVITY'
        };

        //Read Global environment parameter
        if (OncoKB.geneStatus && OncoKB.geneStatus != 'null') {
            oncokbServiceData.geneStatus = OncoKB.geneStatus;
        }

        if (variants.tumorType) {
            oncokbServiceData.tumorType = variants.tumorType;
            oncokbServiceData.source = 'cbioportal';
        }

        oncokbSummaryData = $.extend({}, oncokbServiceData);
        oncokbSummaryData.type = 'variant';

        $.when(
            $.ajax({
                type: 'POST',
                url: 'api/proxy/oncokb',
                data: oncokbServiceData,
                crossDomain: true,
                dataType: 'json'
            }),
            $.ajax({
                type: 'POST',
                url: 'api/proxy/oncokbSummary',
                data: oncokbSummaryData,
                crossDomain: true,
                dataType: 'json'
            })
        ).then(function (d1, d2) {
                var evidenceCollection = [];
                if (d1[0].length ===  d2[0].length && d2[0].length === searchPairs.length) {
                    searchPairs.forEach(function (searchPair, pairIndex) {
                        var datum = {
                            'variantSummary': '',
                            'gene': {},
                            'alteration': [],
                            'prevalence': [],
                            'progImp': [],
                            'treatments': [],
                            'trials': [],
                            'oncogenic': 0,
                            'hotspot': 0
                        };
                        var evidenceL = d1[0][pairIndex].length;

                        for (var i = 0; i < evidenceL; i++) {
                            var evidence = d1[0][pairIndex][i];
                            if (evidence.gene.hugoSymbol === searchPair.gene) {
                                if (evidence.evidenceType === 'GENE_SUMMARY') {
                                    datum.gene.summary = findRegex(evidence.description);
                                } else if (evidence.evidenceType === 'GENE_BACKGROUND') {
                                    datum.gene.background = findRegex(evidence.description);
                                } else if (evidence.evidenceType === 'MUTATION_EFFECT') {
                                    var description = '';
                                    for (var j = 0, alterationL = evidence.alterations.length; j < alterationL; j++) {
                                        var alteration = evidence.alterations[j];
                                        //if(alteration.name === searchPair.alteration) {
                                        if (alteration.hasOwnProperty('oncogenic')) {
                                            if (datum.hasOwnProperty('oncogenic') && [1, 2].indexOf(datum.oncogenic) === -1) {
                                                datum.oncogenic = Number(alteration.oncogenic);
                                            }
                                        }
                                        if (alteration.hasOwnProperty('hotspot')) {
                                            if (datum.hasOwnProperty('hotspot') && datum.hotspot === 0) {
                                                datum.hotspot = Number(alteration.hotspot);
                                            }
                                        }
                                    }

                                    if(evidence.shortDescription) {
                                        description = evidence.shortDescription;
                                    }else{
                                        description = evidence.description;
                                    }
                                    datum.alteration.push({
                                        knownEffect: evidence.knownEffect,
                                        description: findRegex(description)
                                    });
                                } else if (evidence.evidenceType === 'PREVALENCE') {
                                    datum.prevalence.push({
                                        tumorType: evidence.tumorType.name,
                                        description: findRegex(evidence.description) || 'No yet curated'
                                    });
                                } else if (evidence.evidenceType === 'PROGNOSTIC_IMPLICATION') {
                                    datum.progImp.push({
                                        tumorType: evidence.tumorType.name,
                                        description: findRegex(evidence.description) || 'No yet curated'
                                    });
                                } else if (evidence.evidenceType === 'CLINICAL_TRIAL') {
                                    datum.trials.push({
                                        tumorType: evidence.tumorType.name,
                                        list: evidence.clinicalTrials
                                    });
                                } else if (evidence.levelOfEvidence) {
                                    //if evidence has level information, that means this is treatment evidence.
                                    if (['LEVEL_0', 'LEVEL_R3'].indexOf(evidence.levelOfEvidence) === -1) {
                                        var _treatment = {};
                                        _treatment.tumorType = evidence.tumorType.name;
                                        _treatment.level = evidence.levelOfEvidence;
                                        _treatment.content = evidence.treatments;
                                        _treatment.description = findRegex(evidence.description) || 'No yet curated';
                                        datum.treatments.push(_treatment);
                                    }
                                }
                            }

                            if(d2[0][pairIndex]){
                                datum.variantSummary = d2[0][pairIndex];
                            }
                        }
                        evidenceCollection.push(datum);
                    });

                }
                callback(evidenceCollection);
            }, function () {
                console.log('POST failed.');
                callback([]);
            });
    }

    function findRegex(str) {

        if (typeof str === 'string' && str) {
            var regex = [/PMID:\s*([0-9]+,*\s*)+/ig, /NCT[0-9]+/ig],
                links = ['http://www.ncbi.nlm.nih.gov/pubmed/',
                    'http://clinicaltrials.gov/show/'];
            for (var j = 0, regexL = regex.length; j < regexL; j++) {
                var result = str.match(regex[j]);

                if (result) {
                    var uniqueResult = result.filter(function (elem, pos) {
                        return result.indexOf(elem) === pos;
                    });
                    for (var i = 0, resultL = uniqueResult.length; i < resultL; i++) {
                        var _datum = uniqueResult[i];

                        switch (j) {
                            case 0:
                                var _number = _datum.split(':')[1].trim();
                                _number = _number.replace(/\s+/g, '');
                                str = str.replace(new RegExp(_datum, 'g'), '' + _datum + '');
                                break;
                            default:
                                str = str.replace(_datum, '' + _datum + '');
                                break;
                        }

                    }
                }
            }
        } else {
            str = ''
        }
        return str;
    }

    /**
     * Convert cBioPortal consequence to OncoKB consequence
     *
     * @param consequence cBioPortal consequence
     * @returns
     */
    function consequenceConverter(consequence) {
        var matrix = {
            '3\'Flank': ['any'],
            '5\'Flank ': ['any'],
            'COMPLEX_INDEL': ['inframe_deletion', 'inframe_insertion'],
            'ESSENTIAL_SPLICE_SITE': ['feature_truncation'],
            'Exon skipping': ['inframe_deletion'],
            'Frameshift deletion': ['frameshift_variant'],
            'Frameshift insertion': ['frameshift_variant'],
            'FRAMESHIFT_CODING': ['frameshift_variant'],
            'Frame_Shift_Del': ['frameshift_variant'],
            'Frame_Shift_Ins': ['frameshift_variant'],
            'Fusion': ['fusion'],
            'Indel': ['frameshift_variant', 'inframe_deletion', 'inframe_insertion'],
            'In_Frame_Del': ['inframe_deletion', 'feature_truncation'],
            'In_Frame_Ins': ['inframe_insertion'],
            'Missense': ['missense_variant'],
            'Missense_Mutation': ['missense_variant'],
            'Nonsense_Mutation': ['stop_gained'],
            'Nonstop_Mutation': ['stop_lost'],
            'Splice_Site': ['splice_region_variant'],
            'Splice_Site_Del': ['splice_region_variant'],
            'Splice_Site_SNP': ['splice_region_variant'],
            'splicing': ['splice_region_variant'],
            'Translation_Start_Site': ['start_lost'],
            'vIII deletion': ['any']
        };
        if (matrix.hasOwnProperty(consequence)) {
            return matrix[consequence].join('+');
        } else {
            return 'any';
        }
    }

    return {
        init: init,
        oncokbAccess: oncokbAccess,
        getEvidence: getEvidence,
        findRegex: findRegex,
        consequenceConverter: consequenceConverter
    };
})();

$.fn.dataTableExt.oSort['oncokb-level-asc'] = function (x, y) {
    var levels = ['4', '3', '2B', '2A', '1', '0', 'R3', 'R2', 'R1'];
    var xIndex = levels.indexOf(x);
    var yIndex = levels.indexOf(y);
    if (xIndex < yIndex) {
        return 1;
    } else {
        return -1;
    }
};

$.fn.dataTableExt.oSort['oncokb-level-desc'] = function (x, y) {
    var levels = ['4', '3', '2B', '2A', '1', '0', 'R3', 'R2', 'R1'];
    var xIndex = levels.indexOf(x);
    var yIndex = levels.indexOf(y);
    if (xIndex < yIndex) {
        return -1;
    } else {
        return 1;
    }
};<commit_msg>Use short description by default<commit_after>/*
 * Copyright (c) 2015 Memorial Sloan-Kettering Cancer Center.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
 * FOR A PARTICULAR PURPOSE. The software and documentation provided hereunder
 * is on an "as is" basis, and Memorial Sloan-Kettering Cancer Center has no
 * obligations to provide maintenance, support, updates, enhancements or
 * modifications. In no event shall Memorial Sloan-Kettering Cancer Center be
 * liable to any party for direct, indirect, special, incidental or
 * consequential damages, including lost profits, arising out of the use of this
 * software and its documentation, even if Memorial Sloan-Kettering Cancer
 * Center has been advised of the possibility of such damage.
 */

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

var OncoKBConnector = (function () {
    var oncokbUrl = '';

    function init(data) {
        oncokbUrl = data.url || '';
    }

    function oncokbAccess(callback) {
        if (oncokbUrl && oncokbUrl !== 'null') {
            $.get('api/proxy/oncokbAccess', function () {
                callback(true);
            })
                .fail(function () {
                    callback(false);
                });
        } else {
            callback(false);
        }
    }

    function getEvidence(variants, callback) {
        var mutationEventIds = variants.mutations.getEventIds(false),
            searchPairs = [],
            geneStr = "",
            alterationStr = "",
            consequenceStr = ""
        var oncokbServiceData = {};
        var oncokbSummaryData = {};

        for (var i = 0, mutationL = mutationEventIds.length; i < mutationL; i++) {
            var datum = {},
                gene = variants.mutations.getValue(mutationEventIds[i], 'gene'),
                alteration = variants.mutations.getValue(mutationEventIds[i], 'aa'),
                consequence = consequenceConverter(variants.mutations.getValue(mutationEventIds[i], 'type'));
            datum.gene = gene;
            datum.alteration = alteration;
            datum.consequence = consequence;
            searchPairs.push(datum);

            geneStr += gene + ",";
            alterationStr += alteration + ",";
            consequenceStr += consequence + ",";
        }

        oncokbServiceData = {
            'hugoSymbol': geneStr.substring(0, geneStr.length - 1),
            'alteration': alterationStr.substring(0, alterationStr.length - 1),
            'consequence': consequenceStr.substring(0, consequenceStr.length - 1),
            'evidenceType': 'GENE_SUMMARY,GENE_BACKGROUND,MUTATION_EFFECT,STANDARD_THERAPEUTIC_IMPLICATIONS_FOR_DRUG_SENSITIVITY'
        };

        //Read Global environment parameter
        if (OncoKB.geneStatus && OncoKB.geneStatus != 'null') {
            oncokbServiceData.geneStatus = OncoKB.geneStatus;
        }

        if (variants.tumorType) {
            oncokbServiceData.tumorType = variants.tumorType;
            oncokbServiceData.source = 'cbioportal';
        }

        oncokbSummaryData = $.extend({}, oncokbServiceData);
        oncokbSummaryData.type = 'variant';

        $.when(
            $.ajax({
                type: 'POST',
                url: 'api/proxy/oncokb',
                data: oncokbServiceData,
                crossDomain: true,
                dataType: 'json'
            }),
            $.ajax({
                type: 'POST',
                url: 'api/proxy/oncokbSummary',
                data: oncokbSummaryData,
                crossDomain: true,
                dataType: 'json'
            })
        ).then(function (d1, d2) {
                var evidenceCollection = [];
                if (d1[0].length ===  d2[0].length && d2[0].length === searchPairs.length) {
                    searchPairs.forEach(function (searchPair, pairIndex) {
                        var datum = {
                            'variantSummary': '',
                            'gene': {},
                            'alteration': [],
                            'prevalence': [],
                            'progImp': [],
                            'treatments': [],
                            'trials': [],
                            'oncogenic': 0,
                            'hotspot': 0
                        };
                        var evidenceL = d1[0][pairIndex].length;

                        for (var i = 0; i < evidenceL; i++) {
                            var evidence = d1[0][pairIndex][i];
                            var description = '';
                            if(evidence.shortDescription) {
                                description = evidence.shortDescription;
                            }else{
                                description = evidence.description;
                            }
                            if (evidence.gene.hugoSymbol === searchPair.gene) {
                                if (evidence.evidenceType === 'GENE_SUMMARY') {
                                    datum.gene.summary = findRegex(description);
                                } else if (evidence.evidenceType === 'GENE_BACKGROUND') {
                                    datum.gene.background = findRegex(description);
                                } else if (evidence.evidenceType === 'MUTATION_EFFECT') {
                                    for (var j = 0, alterationL = evidence.alterations.length; j < alterationL; j++) {
                                        var alteration = evidence.alterations[j];
                                        //if(alteration.name === searchPair.alteration) {
                                        if (alteration.hasOwnProperty('oncogenic')) {
                                            if (datum.hasOwnProperty('oncogenic') && [1, 2].indexOf(datum.oncogenic) === -1) {
                                                datum.oncogenic = Number(alteration.oncogenic);
                                            }
                                        }
                                        if (alteration.hasOwnProperty('hotspot')) {
                                            if (datum.hasOwnProperty('hotspot') && datum.hotspot === 0) {
                                                datum.hotspot = Number(alteration.hotspot);
                                            }
                                        }
                                    }
                                    datum.alteration.push({
                                        knownEffect: evidence.knownEffect,
                                        description: findRegex(description)
                                    });
                                } else if (evidence.evidenceType === 'PREVALENCE') {
                                    datum.prevalence.push({
                                        tumorType: evidence.tumorType.name,
                                        description: findRegex(description) || 'No yet curated'
                                    });
                                } else if (evidence.evidenceType === 'PROGNOSTIC_IMPLICATION') {
                                    datum.progImp.push({
                                        tumorType: evidence.tumorType.name,
                                        description: findRegex(description) || 'No yet curated'
                                    });
                                } else if (evidence.evidenceType === 'CLINICAL_TRIAL') {
                                    datum.trials.push({
                                        tumorType: evidence.tumorType.name,
                                        list: evidence.clinicalTrials
                                    });
                                } else if (evidence.levelOfEvidence) {
                                    //if evidence has level information, that means this is treatment evidence.
                                    if (['LEVEL_0', 'LEVEL_R3'].indexOf(evidence.levelOfEvidence) === -1) {
                                        var _treatment = {};
                                        _treatment.tumorType = evidence.tumorType.name;
                                        _treatment.level = evidence.levelOfEvidence;
                                        _treatment.content = evidence.treatments;
                                        _treatment.description = findRegex(description) || 'No yet curated';
                                        datum.treatments.push(_treatment);
                                    }
                                }
                            }

                            if(d2[0][pairIndex]){
                                datum.variantSummary = d2[0][pairIndex];
                            }
                        }
                        evidenceCollection.push(datum);
                    });

                }
                callback(evidenceCollection);
            }, function () {
                console.log('POST failed.');
                callback([]);
            });
    }

    function findRegex(str) {

        if (typeof str === 'string' && str) {
            var regex = [/PMID:\s*([0-9]+,*\s*)+/ig, /NCT[0-9]+/ig],
                links = ['http://www.ncbi.nlm.nih.gov/pubmed/',
                    'http://clinicaltrials.gov/show/'];
            for (var j = 0, regexL = regex.length; j < regexL; j++) {
                var result = str.match(regex[j]);

                if (result) {
                    var uniqueResult = result.filter(function (elem, pos) {
                        return result.indexOf(elem) === pos;
                    });
                    for (var i = 0, resultL = uniqueResult.length; i < resultL; i++) {
                        var _datum = uniqueResult[i];

                        switch (j) {
                            case 0:
                                var _number = _datum.split(':')[1].trim();
                                _number = _number.replace(/\s+/g, '');
                                str = str.replace(new RegExp(_datum, 'g'), '' + _datum + '');
                                break;
                            default:
                                str = str.replace(_datum, '' + _datum + '');
                                break;
                        }

                    }
                }
            }
        } else {
            str = ''
        }
        return str;
    }

    /**
     * Convert cBioPortal consequence to OncoKB consequence
     *
     * @param consequence cBioPortal consequence
     * @returns
     */
    function consequenceConverter(consequence) {
        var matrix = {
            '3\'Flank': ['any'],
            '5\'Flank ': ['any'],
            'COMPLEX_INDEL': ['inframe_deletion', 'inframe_insertion'],
            'ESSENTIAL_SPLICE_SITE': ['feature_truncation'],
            'Exon skipping': ['inframe_deletion'],
            'Frameshift deletion': ['frameshift_variant'],
            'Frameshift insertion': ['frameshift_variant'],
            'FRAMESHIFT_CODING': ['frameshift_variant'],
            'Frame_Shift_Del': ['frameshift_variant'],
            'Frame_Shift_Ins': ['frameshift_variant'],
            'Fusion': ['fusion'],
            'Indel': ['frameshift_variant', 'inframe_deletion', 'inframe_insertion'],
            'In_Frame_Del': ['inframe_deletion', 'feature_truncation'],
            'In_Frame_Ins': ['inframe_insertion'],
            'Missense': ['missense_variant'],
            'Missense_Mutation': ['missense_variant'],
            'Nonsense_Mutation': ['stop_gained'],
            'Nonstop_Mutation': ['stop_lost'],
            'Splice_Site': ['splice_region_variant'],
            'Splice_Site_Del': ['splice_region_variant'],
            'Splice_Site_SNP': ['splice_region_variant'],
            'splicing': ['splice_region_variant'],
            'Translation_Start_Site': ['start_lost'],
            'vIII deletion': ['any']
        };
        if (matrix.hasOwnProperty(consequence)) {
            return matrix[consequence].join('+');
        } else {
            return 'any';
        }
    }

    return {
        init: init,
        oncokbAccess: oncokbAccess,
        getEvidence: getEvidence,
        findRegex: findRegex,
        consequenceConverter: consequenceConverter
    };
})();

$.fn.dataTableExt.oSort['oncokb-level-asc'] = function (x, y) {
    var levels = ['4', '3', '2B', '2A', '1', '0', 'R3', 'R2', 'R1'];
    var xIndex = levels.indexOf(x);
    var yIndex = levels.indexOf(y);
    if (xIndex < yIndex) {
        return 1;
    } else {
        return -1;
    }
};

$.fn.dataTableExt.oSort['oncokb-level-desc'] = function (x, y) {
    var levels = ['4', '3', '2B', '2A', '1', '0', 'R3', 'R2', 'R1'];
    var xIndex = levels.indexOf(x);
    var yIndex = levels.indexOf(y);
    if (xIndex < yIndex) {
        return -1;
    } else {
        return 1;
    }
};<|endoftext|>


<commit_before>import React, {PureComponent as Component} from 'react'
import PropTypes from 'prop-types'
import { default as Collapsible, propTypes as collapsibleTypes } from '../Collapsible'
import Flexy from '../Flexy'
import Heading from '../Heading'
import SortableDragHandle from '../Sortable/DragHandle'
import Icon from '../Icon'
import { createUniqueIDFactory } from '../../utilities/id'
import classNames from '../../utilities/classNames'

export const propTypes = Object.assign({}, collapsibleTypes, {
  header: PropTypes.element,
  title: PropTypes.string,
  isOpen: PropTypes.bool,
  sortable: PropTypes.bool
})

export const defaultProps = {
  duration: 200,
  isOpen: false,
  sortable: false
}

const uniqueID = createUniqueIDFactory('SidebarCollapsibleCard')

class SidebarCollapsibleCard extends Component {
  constructor (props) {
    super()
    this.state = {
      id: props.id || uniqueID(),
      isOpen: props.isOpen
    }
    this.handleToggleOpen = this.handleToggleOpen.bind(this)
  }

  componentWillUpdate (nextProps, nextState) {
    if (this.props.isOpen !== nextProps.isOpen) {
      this.handleToggleOpen()
    }
  }

  handleToggleOpen (e) {
    e.preventDefault()
    this.setState({ isOpen: !this.state.isOpen })
  }

  render () {
    const {
      children,
      className,
      duration,
      header,
      onClose,
      onOpen,
      isOpen,
      sortable,
      title,
      ...rest
    } = this.props
    const {
      isOpen: open,
      id: cardId
    } = this.state

    const componentClassName = classNames(
      'c-SidebarCollapsibleCard',
      open && 'is-open',
      className
    )

    const handleToggleOpen = this.handleToggleOpen

    const displayHeader = () => {
      if (header) return header
      if (title) {
        return (
          <Heading className='c-SidebarCollapsibleCard__title' size='h4' lineHeightReset>
            {title}
          </Heading>
        )
      }
      return null
    }

    const iconName = open ? 'caret-up' : 'caret-down'
    const regionId = `${cardId}-region`
    const headerMarkup = displayHeader()
    const dragHandleMarkup = sortable ? (
      <Flexy.Item>
        <SortableDragHandle className='c-SidebarCollapsibleCard__drag-handle' />
      </Flexy.Item>
    ) : null

    return (

          <Flexy gap='sm'>
            <Flexy.Block>
              {headerMarkup}
            </Flexy.Block>
            {dragHandleMarkup}
            <Flexy.Item>
              <Icon name={iconName} size='14' muted />
            </Flexy.Item>
          </Flexy>

          <Collapsible
            duration={duration}
            onOpen={onOpen}
            onClose={onClose}
            isOpen={open}
          >

              {children}

          </Collapsible>

    )
  }
}

SidebarCollapsibleCard.propTypes = propTypes
SidebarCollapsibleCard.defaultProps = defaultProps

export default SidebarCollapsibleCard
<commit_msg>Check that event exists to fix test<commit_after>import React, {PureComponent as Component} from 'react'
import PropTypes from 'prop-types'
import { default as Collapsible, propTypes as collapsibleTypes } from '../Collapsible'
import Flexy from '../Flexy'
import Heading from '../Heading'
import SortableDragHandle from '../Sortable/DragHandle'
import Icon from '../Icon'
import { createUniqueIDFactory } from '../../utilities/id'
import classNames from '../../utilities/classNames'

export const propTypes = Object.assign({}, collapsibleTypes, {
  header: PropTypes.element,
  title: PropTypes.string,
  isOpen: PropTypes.bool,
  sortable: PropTypes.bool
})

export const defaultProps = {
  duration: 200,
  isOpen: false,
  sortable: false
}

const uniqueID = createUniqueIDFactory('SidebarCollapsibleCard')

class SidebarCollapsibleCard extends Component {
  constructor (props) {
    super()
    this.state = {
      id: props.id || uniqueID(),
      isOpen: props.isOpen
    }
    this.handleToggleOpen = this.handleToggleOpen.bind(this)
  }

  componentWillUpdate (nextProps, nextState) {
    if (this.props.isOpen !== nextProps.isOpen) {
      this.handleToggleOpen()
    }
  }

  handleToggleOpen (e) {
    e && e.preventDefault()
    this.setState({ isOpen: !this.state.isOpen })
  }

  render () {
    const {
      children,
      className,
      duration,
      header,
      onClose,
      onOpen,
      isOpen,
      sortable,
      title,
      ...rest
    } = this.props
    const {
      isOpen: open,
      id: cardId
    } = this.state

    const componentClassName = classNames(
      'c-SidebarCollapsibleCard',
      open && 'is-open',
      className
    )

    const handleToggleOpen = this.handleToggleOpen

    const displayHeader = () => {
      if (header) return header
      if (title) {
        return (
          <Heading className='c-SidebarCollapsibleCard__title' size='h4' lineHeightReset>
            {title}
          </Heading>
        )
      }
      return null
    }

    const iconName = open ? 'caret-up' : 'caret-down'
    const regionId = `${cardId}-region`
    const headerMarkup = displayHeader()
    const dragHandleMarkup = sortable ? (
      <Flexy.Item>
        <SortableDragHandle className='c-SidebarCollapsibleCard__drag-handle' />
      </Flexy.Item>
    ) : null

    return (

          <Flexy gap='sm'>
            <Flexy.Block>
              {headerMarkup}
            </Flexy.Block>
            {dragHandleMarkup}
            <Flexy.Item>
              <Icon name={iconName} size='14' muted />
            </Flexy.Item>
          </Flexy>

          <Collapsible
            duration={duration}
            onOpen={onOpen}
            onClose={onClose}
            isOpen={open}
          >

              {children}

          </Collapsible>

    )
  }
}

SidebarCollapsibleCard.propTypes = propTypes
SidebarCollapsibleCard.defaultProps = defaultProps

export default SidebarCollapsibleCard
<|endoftext|>


<commit_before>var React = require('react');
var superagent = require('superagent');
var cs = require('../../../dispatcher/constants');

var Navigation = React.createClass({

  getInitialState: function(){
    return {
      items: []
    };
  },

  componentWillMount: function(){
    var self = this;

    superagent.get(cs.JOKELAN_JSON_API + '/menus/2').end(function(err, res){
      if(err){
        console.log('ERROR: ' + err);
      }
      self.setState(res.body);
    });
  },

  render: function(){
    var menuItems = this.state.items.map(function(item){
      return(

            {item.title}

      );
    });

    return(

          {menuItems}

    );
  }
});

module.exports = Navigation;
<commit_msg>add key to navigation items<commit_after>var React = require('react');
var superagent = require('superagent');
var cs = require('../../../dispatcher/constants');

var Navigation = React.createClass({

  getInitialState: function(){
    return {
      items: []
    };
  },

  componentWillMount: function(){
    var self = this;

    superagent.get(cs.JOKELAN_JSON_API + '/menus/2').end(function(err, res){
      if(err){
        console.log('ERROR: ' + err);
      }
      self.setState(res.body);
    });
  },

  render: function(){
    var menuItems = this.state.items.map(function(item){
      return(

            {item.title}

      );
    });

    return(

          {menuItems}

    );
  }
});

module.exports = Navigation;
<|endoftext|>


<commit_before>/* @flow */
/**
 * validCytoConfig.js
 * Written by: Connor Taylor
 */
import _ from 'lodash';
import chalk from 'chalk';

import errors from '../../utils/errors';
import types from '../../utils/types';

/**
 * Checks if a cyto.config.js file that was loaded is valid. Valid cyto configs
 * meet the following conditions:
 *  1. The config is an Object
 *  2. Config has `templateId`, `args`, `dependencies`, and `options` keys
 *  3. `dependencies` must be an array
 *  4. `args` must be an array
 *  5. `options` must be an object`
 *  6. `templateId` must match the provided id
 *  7. `dependencies` has at least 1 element
 */
export default function validCytoConfig(config, providedId) {
  if (!types.isObject(config)) { // 1
    errors.invalidCytoConfig(
      provided,
      "cyto.config.js doesn't export an Object",
    );
  }

  [
    ['templateId', types.isString],
    ['dependencies', types.isArray],
    ['args', types.isArray],
    ['options', types.isObject],
  ].forEach(([key, typeTest]) => {
    const hasProperty = _.has(config, key);
    if (!hasProperty) { // 2
      errors.invalidCytoConfig(
        providedId,
        `Missing key: ${chalk.green(key)}`,
      );
    }

    if (!typeTest(config[key])) { // 3-5
      errors.invalidCytoConfig(
        providedId,
        `${chalk.green(key)} is the wrong type`,
      );
    }
  });

  if (config.templateId !== providedId) { // 6
    errors.templateIdMismatch(providedId, config.templateId);
  }

  if (config.dependencies.length === 0) { // 7
    errors.invalidCytoConfig(
      providedId,
      `${chalk.green('dependencies')} is empty, this template will not generate anything`,
    );
  }
}
<commit_msg>linting fixes<commit_after>/* @flow */
/**
 * validCytoConfig.js
 * Written by: Connor Taylor
 */
import _ from 'lodash';
import chalk from 'chalk';

import errors from '../../utils/errors';
import types from '../../utils/types';

/**
 * Checks if a cyto.config.js file that was loaded is valid. Valid cyto configs
 * meet the following conditions:
 *  1. The config is an Object
 *  2. Config has `templateId`, `args`, `dependencies`, and `options` keys
 *  3. `dependencies` must be an array
 *  4. `args` must be an array
 *  5. `options` must be an object`
 *  6. `templateId` must match the provided id
 *  7. `dependencies` has at least 1 element
 */
export default function validCytoConfig(config, providedId) {
  if (!types.isObject(config)) { // 1
    errors.invalidCytoConfig(
      providedId,
      "cyto.config.js doesn't export an Object",
    );
  }

  [
    ['templateId', types.isString],
    ['dependencies', types.isArray],
    ['args', types.isArray],
    ['options', types.isObject],
  ].forEach(([key, typeTest]) => {
    const hasProperty = _.has(config, key);
    if (!hasProperty) { // 2
      errors.invalidCytoConfig(
        providedId,
        `Missing key: ${chalk.green(key)}`,
      );
    }

    if (!typeTest(config[key])) { // 3-5
      errors.invalidCytoConfig(
        providedId,
        `${chalk.green(key)} is the wrong type`,
      );
    }
  });

  if (config.templateId !== providedId) { // 6
    errors.templateIdMismatch(providedId, config.templateId);
  }

  if (config.dependencies.length === 0) { // 7
    errors.invalidCytoConfig(
      providedId,
      `${chalk.green('dependencies')} is empty, this template will not generate anything`,
    );
  }
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import LunchExampleForm from 'components/LunchForm/LunchExampleForm';
import { createLunch } from 'redux/modules/common';
import { show as showToast } from 'redux/modules/toast';
import { connect } from 'react-redux';
import { asyncConnect } from 'redux-async-connect';
import cloneLunch from 'helpers/cloneLunch';
import submit, { createLunchExample } from '../submit';

@asyncConnect([
  {key: 'lunchExample', promise: ({helpers, params}) => {
    return helpers.client.get(`/lunch_examples/${params.lunchExampleId}`).then(response => response.resource);
  }}
])
@connect(null, { createLunch, showToast })
export default class Clone extends Component {
  static propTypes = {
    lunchExample: PropTypes.object.isRequired,
    createLunch: PropTypes.func.isRequired,
    showToast: PropTypes.func.isRequired
  };

  static contextTypes = {
    router: PropTypes.object.isRequired,
    client: PropTypes.object.isRequired
  };

  state = {
    lunchExampleFields: {}
  };

  componentDidMount() {
    const { lunchExample } = this.props;
    const { client } = this.context;
    cloneLunch(lunchExample, client)
      .then(lunchExampleFields => {
        this.setState({lunchExampleFields});
      });
  }

  createLunch(lunch) {
    return submit(lunch, createLunchExample(this.context.client)).then(response => {
      this.props.showToast('Обед успешно добавлен');
      this.context.router.push('/admin/lunch_examples/' + response.resource.id + '/edit');
    });
  }

  render() {
    const { lunchExampleFields } = this.state;
    return (
      <LunchExampleForm acceptRules initialValues={lunchExampleFields} onSubmit={::this.createLunch}
                        title="Создание обеда" sendLabel="Создать обед"/>
    );
  }
}
<commit_msg>Error when clone unexisted lunch example<commit_after>import React, { Component, PropTypes } from 'react';
import LunchExampleForm from 'components/LunchForm/LunchExampleForm';
import { createLunch } from 'redux/modules/common';
import { show as showToast } from 'redux/modules/toast';
import { connect } from 'react-redux';
import { asyncConnect } from 'redux-async-connect';
import cloneLunch from 'helpers/cloneLunch';
import submit, { createLunchExample } from '../submit';

@asyncConnect([
  {key: 'lunchExample', promise: ({helpers, params}) => {
    return helpers.client.get(`/lunch_examples/${params.lunchExampleId}`).then(response => response.resource);
  }}
])
@connect(null, { createLunch, showToast })
export default class Clone extends Component {
  static propTypes = {
    lunchExample: PropTypes.object.isRequired,
    createLunch: PropTypes.func.isRequired,
    showToast: PropTypes.func.isRequired
  };

  static contextTypes = {
    router: PropTypes.object.isRequired,
    client: PropTypes.object.isRequired
  };

  state = {
    lunchExampleFields: {}
  };

  componentDidMount() {
    const { lunchExample } = this.props;
    const { client } = this.context;
    if ( !lunchExample ) {
      this.props.showToast('Ошибка загрузки шаблона обеда', 'warning', 'error');
      return;
    }
    cloneLunch(lunchExample, client)
      .then(lunchExampleFields => {
        this.setState({lunchExampleFields});
      });
  }

  createLunch(lunch) {
    return submit(lunch, createLunchExample(this.context.client)).then(response => {
      this.props.showToast('Обед успешно добавлен');
      this.context.router.push('/admin/lunch_examples/' + response.resource.id + '/edit');
    });
  }

  render() {
    const { lunchExampleFields } = this.state;
    return (
      <LunchExampleForm acceptRules initialValues={lunchExampleFields} onSubmit={::this.createLunch}
                        title="Создание обеда" sendLabel="Создать обед"/>
    );
  }
}
<|endoftext|>


<commit_before>'use strict';

const core = require('./core.js');
const fd = require('./field.js');
const serv = require('./../services/services.js');
const servWeather = require('./../services/weatherService.js');
const db = require('./../AslanDBConnector.js');
/*
*   Fonction qui traite les réponses de type bonjour
*/
function processingGrettings(information, response) {
	if(information != undefined && response != undefined && information.first_name != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{prenom}") != -1) {
			var answer = fd.replaceField(response.result.fulfillment.speech, "{prenom}", information.first_name);
			core.prepareMessage(answer);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingHour(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.ville != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{heure}") != -1) {
			console.log(response.result.parameters.ville);
			serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				core.prepareMessage(answer);
			});
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingFountain(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.location != undefined) {
		serv.nearestFontaines(response.result.parameters.location, 20, function(foutains) {
			message["attachment"] = foutains;
			core.prepareMessage(message);
		});
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingCitizen(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.ville != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{heure}") != -1) {
			console.log(response.result.parameters.ville);
			serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				console.log(answer);
				core.prepareMessage(answer);
			});
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingDate(response) {

}

function processingWeather(message, location) {
	if(message != undefined && message.result != undefined && message.result.parameters != undefined) {
		var fields = fd.extractFields(message.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{meteo}") != -1) {
			var coord = "";
			if(location) {

			} else if(message.result.parameters["geo-city"] != undefined){
				coord = message.result.parameters["geo-city"];
			}
			servWeather.JSONP_LocalWeather(coord, formattedDate(), function(response) {
				console.log(response.data);
				if(response.data != null && response.data.current_condition != null) {
					var weather = "";
					if(response.data.current_condition['0'].lang_fr != null)
						weather = response.data.current_condition['0'].lang_fr['0'].value + ", ";
					weather +=  response.data.current_condition['0'].temp_C + "°";
					var answer = fd.replaceField(message.result.fulfillment.speech, "{meteo}", weather);
					core.prepareMessage(answer);
				}
			});
		} else {
			core.prepareMessage(message.result.fulfillment.speech);
		}
	} else {
		core.prepareMessage(message.result.fulfillment.speech);
	}
}

function processingRestaurant(response, location) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{\"location\":[]}") != -1) {
			db.insertData("conversation", fd.removeFields(response.result), function(err, data) {
				console.log(err);
			});
			core.askLocation();
		} else if (fields.indexOf("{restaurants}") != -1 && location != null){
			console.log("on appelle le service")
			core.prepareMessage(response);
			/*serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				console.log(answer);
				core.prepareMessage(answer);
			});*/
		} else {
			core.prepareMessage(response.result.fulfillment.speech);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function formattedDate(d = new Date) {
  let month = String(d.getMonth() + 1);
  let day = String(d.getDate());
  const year = String(d.getFullYear());

  if (month.length < 2) month = '0' + month;
  if (day.length < 2) day = '0' + day;

  return `${year}-${month}-${day}`;
}
exports.processingGrettings = processingGrettings;
exports.processingHour = processingHour;
exports.processingFountain = processingFountain;
exports.processingCitizen = processingCitizen;
exports.processingDate = processingDate;
exports.processingWeather = processingWeather;
exports.processingRestaurant = processingRestaurant;<commit_msg>Fix bug<commit_after>'use strict';

const core = require('./core.js');
const fd = require('./field.js');
const serv = require('./../services/services.js');
const servWeather = require('./../services/weatherService.js');
const db = require('./../AslanDBConnector.js');
/*
*   Fonction qui traite les réponses de type bonjour
*/
function processingGrettings(information, response) {
	if(information != undefined && response != undefined && information.first_name != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{prenom}") != -1) {
			var answer = fd.replaceField(response.result.fulfillment.speech, "{prenom}", information.first_name);
			core.prepareMessage(answer);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingHour(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.ville != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{heure}") != -1) {
			console.log(response.result.parameters.ville);
			serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				core.prepareMessage(answer);
			});
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingFountain(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.location != undefined) {
		serv.nearestFontaines(response.result.parameters.location, 20, function(foutains) {
			message["attachment"] = foutains;
			core.prepareMessage(message);
		});
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingCitizen(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.ville != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{heure}") != -1) {
			console.log(response.result.parameters.ville);
			serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				console.log(answer);
				core.prepareMessage(answer);
			});
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingDate(response) {

}

function processingWeather(message, location) {
	if(message != undefined && message.result != undefined && message.result.parameters != undefined) {
		var fields = fd.extractFields(message.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{meteo}") != -1) {
			var coord = "";
			if(location) {

			} else if(message.result.parameters["geo-city"] != undefined){
				coord = message.result.parameters["geo-city"];
			}
			servWeather.JSONP_LocalWeather(coord, formattedDate(), function(response) {
				console.log(response.data);
				if(response.data != null && response.data.current_condition != null) {
					var weather = "";
					if(response.data.current_condition['0'].lang_fr != null)
						weather = response.data.current_condition['0'].lang_fr['0'].value + ", ";
					weather +=  response.data.current_condition['0'].temp_C + "°";
					var answer = fd.replaceField(message.result.fulfillment.speech, "{meteo}", weather);
					core.prepareMessage(answer);
				}
			});
		} else {
			core.prepareMessage(message.result.fulfillment.speech);
		}
	} else {
		core.prepareMessage(message.result.fulfillment.speech);
	}
}

function processingRestaurant(response, location) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{\"location\":[]}") != -1) {
			response.result.fulfillment.speech = fd.removeFields(response.result.fulfillment.speech)
			db.insertData("conversation", response.result, function(err, data) {
				console.log(err);
			});
			core.askLocation();
		} else if (fields.indexOf("{restaurants}") != -1 && location != null){
			console.log("on appelle le service")
			core.prepareMessage(response);
			/*serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				console.log(answer);
				core.prepareMessage(answer);
			});*/
		} else {
			core.prepareMessage(response.result.fulfillment.speech);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function formattedDate(d = new Date) {
  let month = String(d.getMonth() + 1);
  let day = String(d.getDate());
  const year = String(d.getFullYear());

  if (month.length < 2) month = '0' + month;
  if (day.length < 2) day = '0' + day;

  return `${year}-${month}-${day}`;
}
exports.processingGrettings = processingGrettings;
exports.processingHour = processingHour;
exports.processingFountain = processingFountain;
exports.processingCitizen = processingCitizen;
exports.processingDate = processingDate;
exports.processingWeather = processingWeather;
exports.processingRestaurant = processingRestaurant;<|endoftext|>


<commit_before>/* -*- mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil -*- */

function update() {
  // preview always needed to put the microdata into the document
  $('#preview').html($('textarea').val());
  // update selected tab
  updateTab($('#tabs').tabs('option', 'selected'));
}

function pre(text) {
  return $('
'+text.replace(/&/g, '&').replace(/</g, '<')+'
');
}

function downloadIt($appendee, mime, data) {
  $appendee.append($('Download it!'));
}

function noItems($appendee, name, itemtype, spec) {
  $appendee.append($('No '+name+' items (items with itemtype="'+itemtype+'")'));
}

function updateTab(index) {
  switch (index) {
  case 1:
    var $json = $('#json').empty();
    var jsonText = $.microdata.json();
    $json.append(pre(jsonText));
    downloadIt($json, 'application/json;encoding=utf-8', jsonText);
    break;
  case 2:
    var $turtle = $('#turtle').empty();
    var turtleText = $.microdata.turtle();
    $turtle.append(pre(turtleText));
    downloadIt($turtle, 'text/turtle;encoding=utf-8', turtleText);
    break;
  case 3:
    var $vcard = $('#vcard').empty();
    var $vcards = $(document).items('http://microformats.org/profile/hcard');
    if ($vcards.length > 0) {
      $vcards.each(function(i, node) {
        var vcardText = $.microdata.vcard(node);
        if (i > 0)
          $vcard.append(document.createElement('hr'));
        $vcard.append(pre(vcardText));
        downloadIt($vcard, 'text/directory;profile=vCard;encoding=utf-8', vcardText);
      });
    } else {
      noItems($vcard, 'vCard', 'http://microformats.org/profile/hcard',
              'http://www.whatwg.org/specs/web-apps/current-work/multipage/microdata.html#vcard');
    }
    break;
  case 4: // iCal
    var $ical = $('#ical').empty();
    var icalText = $.microdata.ical();
    if (icalText) {
      $ical.append(pre(icalText));
      downloadIt($ical, 'text/calendar;componenet=vevent;encoding=utf-8', icalText);
    } else {
      noItems($ical, 'vEvent', 'http://microformats.org/profile/hcalendar#vevent',
              'http://www.whatwg.org/specs/web-apps/current-work/multipage/microdata.html#vevent');
    }
    break;
  }
}
$(function(){
  $('#tabs').tabs({show: function(ev, ui) { updateTab(ui.index); }});
});
$(document).ready(function() {
  var $textarea = $('textarea');
  $textarea.TextAreaResizer();
  $textarea.change(update);
  $textarea.keyup(function(ev) {
    // ignore home/end/page up/page down and left/up/down/right
    if (ev.keyCode < 33 || ev.keyCode > 40)
      update();
  });
  $('select').change(function(ev) {
    var source = ev.target.value;
    if (source) {
      $.get('example/'+source, function(data) {
        $textarea.val(data);
        update();
      });
    }
  });
});
<commit_msg>use charset=UTF-8 instead of encoding=utf-8 in download links<commit_after>/* -*- mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil -*- */

function update() {
  // preview always needed to put the microdata into the document
  $('#preview').html($('textarea').val());
  // update selected tab
  updateTab($('#tabs').tabs('option', 'selected'));
}

function pre(text) {
  return $('
'+text.replace(/&/g, '&').replace(/</g, '<')+'
');
}

function downloadIt(mime, data) {
  return $('Download it!');
}

function noItems(name, itemtype, spec) {
  return $('No '+name+' items (items with itemtype="'+itemtype+'")');
}

function updateTab(index) {
  switch (index) {
  case 1:
    var $json = $('#json').empty();
    var jsonText = $.microdata.json();
    $json.append(pre(jsonText));
    $json.append(downloadIt('application/json', jsonText));
    break;
  case 2:
    var $turtle = $('#turtle').empty();
    var turtleText = $.microdata.turtle();
    $turtle.append(pre(turtleText));
    $turtle.append(downloadIt('text/turtle', turtleText));
    break;
  case 3:
    var $vcard = $('#vcard').empty();
    var $vcards = $(document).items('http://microformats.org/profile/hcard');
    if ($vcards.length > 0) {
      $vcards.each(function(i, node) {
        var vcardText = $.microdata.vcard(node);
        if (i > 0)
          $vcard.append(document.createElement('hr'));
        $vcard.append(pre(vcardText));
        $vcard.append(downloadIt('text/directory;profile=vCard', vcardText));
      });
    } else {
      $vcard.append(noItems('vCard', 'http://microformats.org/profile/hcard',
                            'http://www.whatwg.org/specs/web-apps/current-work/multipage/microdata.html#vcard'));
    }
    break;
  case 4: // iCal
    var $ical = $('#ical').empty();
    var icalText = $.microdata.ical();
    if (icalText) {
      $ical.append(pre(icalText));
      $ical.append(downloadIt('text/calendar;componenet=vevent', icalText));
    } else {
      $ical.append(noItems('vEvent', 'http://microformats.org/profile/hcalendar#vevent',
                           'http://www.whatwg.org/specs/web-apps/current-work/multipage/microdata.html#vevent'));
    }
    break;
  }
}
$(function(){
  $('#tabs').tabs({show: function(ev, ui) { updateTab(ui.index); }});
});
$(document).ready(function() {
  var $textarea = $('textarea');
  $textarea.TextAreaResizer();
  $textarea.change(update);
  $textarea.keyup(function(ev) {
    // ignore home/end/page up/page down and left/up/down/right
    if (ev.keyCode < 33 || ev.keyCode > 40)
      update();
  });
  $('select').change(function(ev) {
    var source = ev.target.value;
    if (source) {
      $.get('example/'+source, function(data) {
        $textarea.val(data);
        update();
      });
    }
  });
});
<|endoftext|>


<commit_before>/* jslint node: true */
'use strict';

//  ENiGMA½
const setClientTheme    = require('./theme.js').setClientTheme;
const clientConnections = require('./client_connections.js').clientConnections;
const StatLog           = require('./stat_log.js');
const logger            = require('./logger.js');
const Events            = require('./events.js');
const Config            = require('./config.js').get;
const {
    Errors,
    ErrorReasons
}                       = require('./enig_error.js');
const UserProps         = require('./user_property.js');
const SysProps          = require('./system_property.js');
const SystemLogKeys     = require('./system_log.js');
const User              = require('./user.js');
const {
    getMessageConferenceByTag,
    getMessageAreaByTag,
    getDefaultMessageConferenceTag,
    getDefaultMessageAreaTagByConfTag,
    getSuitableMessageConfAndAreaTags,
}                       = require('./message_area.js');
const {
    getFileAreaByTag,
    getDefaultFileAreaTag,
}                       = require('./file_base_area.js');

//  deps
const async             = require('async');
const _                 = require('lodash');
const assert            = require('assert');

exports.userLogin             = userLogin;
exports.recordLogin           = recordLogin;
exports.transformLoginError   = transformLoginError;

function userLogin(client, username, password, options, cb) {
    if(!cb && _.isFunction(options)) {
        cb = options;
        options = {};
    }

    const config = Config();

    if(config.users.badUserNames.includes(username.toLowerCase())) {
        client.log.info( { username, ip : client.remoteAddress }, 'Attempt to login with banned username');

        //  slow down a bit to thwart brute force attacks
        return setTimeout( () => {
            return cb(Errors.BadLogin('Disallowed username', ErrorReasons.NotAllowed));
        }, 2000);
    }

    const authInfo = {
        username,
        password,
    };

    authInfo.type   = options.authType || User.AuthFactor1Types.Password;
    authInfo.pubKey = options.ctx;

    client.user.authenticateFactor1(authInfo, err => {
        if(err) {
            return cb(transformLoginError(err, client, username));
        }

        const user = client.user;

        //  Good login; reset any failed attempts
        delete client.sessionFailedLoginAttempts;

        //
        //  Ensure this user is not already logged in.
        //
        const existingClientConnection = clientConnections.find(cc => {
            return user !== cc.user &&          //  not current connection
                user.userId === cc.user.userId; //  ...but same user
        });

        if(existingClientConnection) {
            client.log.info(
                {
                    existingClientId    : existingClientConnection.session.id,
                    username            : user.username,
                    userId              : user.userId
                },
                'Already logged in'
            );

            return cb(Errors.BadLogin(
                `User ${user.username} already logged in.`,
                ErrorReasons.AlreadyLoggedIn
            ));
        }

        //  update client logger with addition of username
        client.log = logger.log.child(
            {
                clientId    : client.log.fields.clientId,
                sessionId   : client.log.fields.sessionId,
                username    : user.username,
            }
        );
        client.log.info('Successful login');

        //  User's unique session identifier is the same as the connection itself
        user.sessionId = client.session.uniqueId;   //  convenience

        Events.emit(Events.getSystemEvents().UserLogin, { user } );

        setClientTheme(client, user.properties[UserProps.ThemeId]);

        postLoginPrep(client, err => {
            if(err) {
                return cb(err);
            }

            if(user.authenticated) {
                return recordLogin(client, cb);
            }

            //  recordLogin() must happen after 2FA!
            return cb(null);
        });
    });
}

function postLoginPrep(client, cb) {
    async.series(
        [
            (callback) => {
                //
                //  User may (no longer) have read (view) rights to their current
                //  message, conferences and/or areas. Move them out if so.
                //
                const confTag   = client.user.getProperty(UserProps.MessageConfTag);
                const conf      = getMessageConferenceByTag(confTag) || {};
                const area      = getMessageAreaByTag(client.user.getProperty(UserProps.MessageAreaTag), confTag) || {};

                if(!client.acs.hasMessageConfRead(conf) || !client.acs.hasMessageAreaRead(area)) {
                    //  move them out of both area and possibly conf to something suitable, hopefully.
                    const [newConfTag, newAreaTag] = getSuitableMessageConfAndAreaTags(client);
                    client.user.persistProperties({
                        [ UserProps.MessageConfTag ] : newConfTag,
                        [ UserProps.MessageAreaTag ] : newAreaTag,
                    },
                    err => {
                        return callback(err);
                    });
                } else {
                    return callback(null);
                }
            },
            (callback) => {
                //  Likewise for file areas
                const area = getFileAreaByTag(client.user.getProperty(UserProps.FileAreaTag)) || {};
                if(!client.acs.hasFileAreaRead(area)) {
                    const areaTag = getDefaultFileAreaTag(client) || '';
                    client.user.persistProperty(UserProps.FileAreaTag, areaTag, err => {
                        return callback(err);
                    });
                } else {
                    return callback(null);
                }
            }
        ],
        err => {
            return cb(err);
        }
    );
}

function recordLogin(client, cb) {
    assert(client.user.authenticated);  //  don't get in situations where this isn't true

    const user = client.user;
    async.parallel(
        [
            (callback) => {
                StatLog.incrementNonPersistentSystemStat(SysProps.LoginsToday, 1);
                return StatLog.incrementSystemStat(SysProps.LoginCount, 1, callback);
            },
            (callback) => {
                return StatLog.setUserStat(user, UserProps.LastLoginTs, StatLog.now, callback);
            },
            (callback) => {
                return StatLog.incrementUserStat(user, UserProps.LoginCount, 1, callback);
            },
            (callback) => {
                const loginHistoryMax = Config().statLog.systemEvents.loginHistoryMax;
                const historyItem = JSON.stringify({
                    userId      : user.userId,
                    sessionId   : user.sessionId,
                });

                return StatLog.appendSystemLogEntry(
                    SystemLogKeys.UserLoginHistory,
                    historyItem,
                    loginHistoryMax,
                    StatLog.KeepType.Max,
                    callback
                );
            }
        ],
        err => {
            return cb(err);
        }
    );
}

function transformLoginError(err, client, username) {
    client.sessionFailedLoginAttempts = _.get(client, 'sessionFailedLoginAttempts', 0) + 1;
    const disconnect = Config().users.failedLogin.disconnect;
    if(disconnect > 0 && client.sessionFailedLoginAttempts >= disconnect) {
        err = Errors.BadLogin('To many failed login attempts', ErrorReasons.TooMany);
    }

    client.log.info( { username, ip : client.remoteAddress, reason : err.message }, 'Failed login attempt');
    return err;
}<commit_msg>Cleanup unused<commit_after>/* jslint node: true */
'use strict';

//  ENiGMA½
const setClientTheme    = require('./theme.js').setClientTheme;
const clientConnections = require('./client_connections.js').clientConnections;
const StatLog           = require('./stat_log.js');
const logger            = require('./logger.js');
const Events            = require('./events.js');
const Config            = require('./config.js').get;
const {
    Errors,
    ErrorReasons
}                       = require('./enig_error.js');
const UserProps         = require('./user_property.js');
const SysProps          = require('./system_property.js');
const SystemLogKeys     = require('./system_log.js');
const User              = require('./user.js');
const {
    getMessageConferenceByTag,
    getMessageAreaByTag,
    getSuitableMessageConfAndAreaTags,
}                       = require('./message_area.js');
const {
    getFileAreaByTag,
    getDefaultFileAreaTag,
}                       = require('./file_base_area.js');

//  deps
const async             = require('async');
const _                 = require('lodash');
const assert            = require('assert');

exports.userLogin             = userLogin;
exports.recordLogin           = recordLogin;
exports.transformLoginError   = transformLoginError;

function userLogin(client, username, password, options, cb) {
    if(!cb && _.isFunction(options)) {
        cb = options;
        options = {};
    }

    const config = Config();

    if(config.users.badUserNames.includes(username.toLowerCase())) {
        client.log.info( { username, ip : client.remoteAddress }, 'Attempt to login with banned username');

        //  slow down a bit to thwart brute force attacks
        return setTimeout( () => {
            return cb(Errors.BadLogin('Disallowed username', ErrorReasons.NotAllowed));
        }, 2000);
    }

    const authInfo = {
        username,
        password,
    };

    authInfo.type   = options.authType || User.AuthFactor1Types.Password;
    authInfo.pubKey = options.ctx;

    client.user.authenticateFactor1(authInfo, err => {
        if(err) {
            return cb(transformLoginError(err, client, username));
        }

        const user = client.user;

        //  Good login; reset any failed attempts
        delete client.sessionFailedLoginAttempts;

        //
        //  Ensure this user is not already logged in.
        //
        const existingClientConnection = clientConnections.find(cc => {
            return user !== cc.user &&          //  not current connection
                user.userId === cc.user.userId; //  ...but same user
        });

        if(existingClientConnection) {
            client.log.info(
                {
                    existingClientId    : existingClientConnection.session.id,
                    username            : user.username,
                    userId              : user.userId
                },
                'Already logged in'
            );

            return cb(Errors.BadLogin(
                `User ${user.username} already logged in.`,
                ErrorReasons.AlreadyLoggedIn
            ));
        }

        //  update client logger with addition of username
        client.log = logger.log.child(
            {
                clientId    : client.log.fields.clientId,
                sessionId   : client.log.fields.sessionId,
                username    : user.username,
            }
        );
        client.log.info('Successful login');

        //  User's unique session identifier is the same as the connection itself
        user.sessionId = client.session.uniqueId;   //  convenience

        Events.emit(Events.getSystemEvents().UserLogin, { user } );

        setClientTheme(client, user.properties[UserProps.ThemeId]);

        postLoginPrep(client, err => {
            if(err) {
                return cb(err);
            }

            if(user.authenticated) {
                return recordLogin(client, cb);
            }

            //  recordLogin() must happen after 2FA!
            return cb(null);
        });
    });
}

function postLoginPrep(client, cb) {
    async.series(
        [
            (callback) => {
                //
                //  User may (no longer) have read (view) rights to their current
                //  message, conferences and/or areas. Move them out if so.
                //
                const confTag   = client.user.getProperty(UserProps.MessageConfTag);
                const conf      = getMessageConferenceByTag(confTag) || {};
                const area      = getMessageAreaByTag(client.user.getProperty(UserProps.MessageAreaTag), confTag) || {};

                if(!client.acs.hasMessageConfRead(conf) || !client.acs.hasMessageAreaRead(area)) {
                    //  move them out of both area and possibly conf to something suitable, hopefully.
                    const [newConfTag, newAreaTag] = getSuitableMessageConfAndAreaTags(client);
                    client.user.persistProperties({
                        [ UserProps.MessageConfTag ] : newConfTag,
                        [ UserProps.MessageAreaTag ] : newAreaTag,
                    },
                    err => {
                        return callback(err);
                    });
                } else {
                    return callback(null);
                }
            },
            (callback) => {
                //  Likewise for file areas
                const area = getFileAreaByTag(client.user.getProperty(UserProps.FileAreaTag)) || {};
                if(!client.acs.hasFileAreaRead(area)) {
                    const areaTag = getDefaultFileAreaTag(client) || '';
                    client.user.persistProperty(UserProps.FileAreaTag, areaTag, err => {
                        return callback(err);
                    });
                } else {
                    return callback(null);
                }
            }
        ],
        err => {
            return cb(err);
        }
    );
}

function recordLogin(client, cb) {
    assert(client.user.authenticated);  //  don't get in situations where this isn't true

    const user = client.user;
    async.parallel(
        [
            (callback) => {
                StatLog.incrementNonPersistentSystemStat(SysProps.LoginsToday, 1);
                return StatLog.incrementSystemStat(SysProps.LoginCount, 1, callback);
            },
            (callback) => {
                return StatLog.setUserStat(user, UserProps.LastLoginTs, StatLog.now, callback);
            },
            (callback) => {
                return StatLog.incrementUserStat(user, UserProps.LoginCount, 1, callback);
            },
            (callback) => {
                const loginHistoryMax = Config().statLog.systemEvents.loginHistoryMax;
                const historyItem = JSON.stringify({
                    userId      : user.userId,
                    sessionId   : user.sessionId,
                });

                return StatLog.appendSystemLogEntry(
                    SystemLogKeys.UserLoginHistory,
                    historyItem,
                    loginHistoryMax,
                    StatLog.KeepType.Max,
                    callback
                );
            }
        ],
        err => {
            return cb(err);
        }
    );
}

function transformLoginError(err, client, username) {
    client.sessionFailedLoginAttempts = _.get(client, 'sessionFailedLoginAttempts', 0) + 1;
    const disconnect = Config().users.failedLogin.disconnect;
    if(disconnect > 0 && client.sessionFailedLoginAttempts >= disconnect) {
        err = Errors.BadLogin('To many failed login attempts', ErrorReasons.TooMany);
    }

    client.log.info( { username, ip : client.remoteAddress, reason : err.message }, 'Failed login attempt');
    return err;
}<|endoftext|>


<commit_before>function populatePlayer(data, sortBy) {
  var filtered = data;
  if (sortBy == "timelor" || sortBy == "lor") {
    $("#rownm").remove();
    $("#rowjv").remove();
    markPersonalBest('lor');
    filtered = filterRaid(sortBy.substring(0, 1) == "t" ? filterTime(data) : filterLeaderboardGenerated(data), "lor");
    populateStatsLoR(filterLeaderboardGenerated(data));
  } else if (sortBy == "timenm" || sortBy == "nm") {
    $("#rowlor").remove();
    $("#rowjv").remove();
    markPersonalBest('nm');
    filtered = filterRaid(sortBy.substring(0, 1) == "t" ? filterTime(data) : filterLeaderboardGenerated(data), "lornm");
    populateStatsNM(filterLeaderboardGenerated(data));
  } else if (sortBy == "timejv" || sortBy == "jv") {
    $("#rowlor").remove();
    $("#rownm").remove();
    markPersonalBest('jv');
    filtered = filterRaid(sortBy.substring(0, 1) == "t" ? filterTime(data) : filterLeaderboardGenerated(data), "jv");
    populateStatsJV(filterLeaderboardGenerated(data));
  } else if (sortBy == "date") {
    filtered = filtered.sort(function (a, b) { return (a.leaderboardGenerated > b.leaderboardGenerated) ? -1 : ((b.leaderboardGenerated > a.leaderboardGenerated) ? 1 : 0); });
  } else {
    filtered = filterLeaderboardGenerated(data);
    markPersonalBest('lor');
    markPersonalBest('lornm');
    markPersonalBest('jv');
    populateStats(filterLeaderboardGenerated(data));
  }
  populateTable(filtered);
}

function filterTime(data) {
  var victory = data.filter(function (r) { return r.objective == "VICTORY"; });
  var sorted = victory.sort(function (a, b) { return (a.time < b.time) ? -1 : ((b.time < a.time) ? 1 : 0); });
  return sorted;
}

function scrollToHash() {
  var hash = window.location.href.split('#')[1] || null;
  if (hash !== null) {
    var row = $('#' + hash);
    $("html, body").animate({ scrollTop: row.offset().top }, 100);
  }
}

function filterRaid(data, raid) {
  if (raid == "lor") {
    return data.filter(function (r) { return r.type == "lor"; });
  } else if (raid == "nm" || raid == "lornm") {
    return data.filter(function (r) { return r.type == "lornm"; });
  } else if (raid == "jv") {
    return data.filter(function (r) { return r.type == "jv"; });
  } else {
    return data;
  }
}

function filterLeaderboardGenerated(data) {
  var filtered = data.filter(function (r) {
    return !(r.objective == "FAILED" && failedUnder(r.time));
  });
  filtered.sort(function (a, b) { return (a.leaderboardGenerated > b.leaderboardGenerated) ? -1 : ((b.leaderboardGenerated > a.leaderboardGenerated) ? 1 : 0); });
  return filtered;
}

function populateTable(data) {
  $("#table").find("tr:gt(0)").remove();
  var table = document.getElementById("table");

  $.each(data, function (i, r) {
    var dataType = r.type;
    var row = table.insertRow();

    var type = row.insertCell(0);
    var date = row.insertCell(1);
    var result = row.insertCell(2);
    var time = row.insertCell(3);
    var objective = row.insertCell(4);
    var kills = row.insertCell(5);
    var deaths = row.insertCell(6);
    var host = row.insertCell(7);
    var players = row.insertCell(8);

    if (dataType == "lor") {
      type.innerHTML = "LoR";
    }
    if (dataType == "lornm") {
      type.innerHTML = "NM LoR";
    }
    if (dataType == "jv") {
      type.innerHTML = "JV";
    }

    var leaderboardGeneratedSeconds = new Date(r.leaderboardGenerated).getTime() / 1000;

    $(row).attr('data-time', timeToSeconds(r.time));
    $(row).attr('data-type', r.type);
    $(row).attr('data-objective', r.objective);
    $(row).attr('id', r.trialId);
    //$(date).append($('<a>').attr('href', '/player/?user=' + r.host + '&date=' + r.leaderboardGenerated + '#' + hostNice + '_' + leaderboardGeneratedSeconds).text(formatDate(r.leaderboardGenerated)));
    // $(date).append($('<a>').attr('href', '/player/?user=' + r.host + '&date=' + r.leaderboardGenerated + '#' + hostNice + '_' + leaderboardGeneratedSeconds).text(formatDate(r.leaderboardGenerated)));
    $(date).text(formatDate(r.leaderboardGenerated));

    objective.className = 'objective';

    //date.innerHTML = formatDate(r.leaderboardGenerated);
    result.innerHTML = r.objective;
    time.innerHTML = r.time;
    if (r.objective != "VICTORY") {
      objective.innerHTML = r.previousObjective;
    }
    kills.innerHTML = r.kills;
    deaths.innerHTML = r.deaths;
    $(host).append($("<a>").attr("href", "/player/?user=" + r.host).text(r.host));
    $.each(r.players, function (i, p) {
      var player = $("<a>")
        .attr("href", "/player/?user=" + p)
        .text(p);
      $(players).append(player);
      if (i < r.players.length - 1) {
        $(players).append(", ");
      }
    });

    if (dataType == "lor" || dataType == "lornm") {
      if (r.objective == "VICTORY") {
        var seconds = timeToSeconds(r.time);
        if (seconds < 900) {
          row.className = "speedrun";
        } else if (seconds < 1200) {
          row.className = "fastrun";
        } else if (seconds > 3600) {
          row.className = "slowrun";
        } else {
          row.className = "run";
        }
      } else if (r.objective == "FAILED") {
        row.className = "failed";
      } else {
        row.className = "run";
      }
    } else if (dataType == "jv") {
      if (r.objective == "VICTORY") {
        var seconds = timeToSeconds(r.time);
        if (seconds < 1200) {
          row.className = "speedrun";
        } else if (seconds < 1500) {
          row.className = "fastrun";
        } else if (seconds > 3600) {
          row.className = "slowrun";
        } else {
          row.className = "run";
        }
      } else if (r.objective == "FAILED") {
        row.className = "failed";
      } else {
        row.className = "run";
      }
    }

    //Only for eastereggs (can be removed)
    $(row).attr('data-host', r.host);
    $(row).attr('data-players', r.players + "");

  });
}

function populateStats(data) {
  populateStatsJV(data);
  populateStatsLoR(data);
  populateStatsNM(data);
}

function formatClearRate(victory, count){
  if(count == 0){
    return "N/A";
  }
  return numeral(victory / count).format('0%');
}

function formatCompletions(victory, count){
  if(count == 0){
    return "N/A";
  }
  return victory + ' / ' + count;
}

function populateStatsJV(data) {
  var jv = data.filter(function (r) { return r.type == "jv"; });
  var summary = getSummary(jv);
  $("#averageJV").text(formatTime(summary.average));
  $("#clearRateJV").text(formatClearRate(summary.victory, summary.count));
  $("#completionsJV").text(formatCompletions(summary.victory, summary.count));
  $("#bestJV").text(formatTime(summary.best));
}

function populateStatsNM(data) {
  var lornm = data.filter(function (r) { return r.type == "lornm"; });
  var summary = getSummary(lornm);
  $("#averageLorNightmare").text(formatTime(summary.average));
  $("#clearRateLorNightmare").text(formatClearRate(summary.victory, summary.count));
  $("#completionsLorNightmare").text(formatCompletions(summary.victory, summary.count));
  $("#bestLorNightmare").text(formatTime(summary.best));
}

function populateStatsLoR(data) {
  var lor = data.filter(function (r) { return r.type == "lor"; });
  var summary = getSummary(lor);
  $("#averageLor").text(formatTime(summary.average));
  $("#clearRateLor").text(formatClearRate(summary.victory, summary.count));
  $("#completionsLor").text(formatCompletions(summary.victory, summary.count));
  $("#bestLor").text(formatTime(summary.best));
}

function markPersonalBest(type) {
  var tableRows = $('#table tr');
  var filtered = tableRows.filter(function (i, x) { return $(x).attr('data-type') == type && $(x).attr('data-objective') == 'VICTORY'; });
  var sorted = filtered.sort(function (a, b) { return +$(a).attr('data-time') > +$(b).attr('data-time') ? 1 : ((+$(b).attr('data-time') > +$(a).attr('data-time')) ? -1 : 0); });
  var top = $(sorted[0]);
  var objective = top.children('.objective');
  var img = $('<img>')
    .attr('src', '/img/star.png')
    .attr('height', '19px')
    .attr('title', 'Personal Best');
  objective.append(img);
}

function getSummary(arr) {
  var victory = arr.filter(function (r) { return r.objective == "VICTORY"; });
  var failed = arr.filter(function (r) { r.objective == "FAILED"; });
  var avg = victory.reduce(function (total, r) { return total + timeToSeconds(r.time); }, 0) / victory.length;
  var best = Math.min.apply(null, victory.map(function (r) { return timeToSeconds(r.time); }));
  return {
    average: avg,
    count: arr.length,
    victory: victory.length,
    failed: failed.length,
    best: best
  };
}

function getParameterByName(name, url) {
  name = name.replace(/[\[\]]/g, "\\$&");
  var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
    results = regex.exec(url);
  if (!results) return null;
  if (!results[2]) return "";
  return decodeURIComponent(results[2].replace(/\+/g, " "));
}

function failedUnder(time) {
  if (timeToSeconds(time) > 420) {
    return false;
  } else {
    return true;
  }
}

function formatTime(n) {
  if(isNaN(n) || !isFinite(n)){
    return "N/A";
  }
  var hours = Math.floor(n / 60 / 60),
    minutes = Math.floor((n - (hours * 60 * 60)) / 60),
    seconds = Math.round(n - (hours * 60 * 60) - (minutes * 60));
  var h = "";
  if (hours > 0) {
    h = ((hours < 10) ? '0' + hours : hours) + ':';
  }

  return h + ((minutes < 10) ? '0' + minutes : minutes) + ':' + ((seconds < 10) ? '0' + seconds : seconds);
}

function timeToSeconds(time) {
  if (time === undefined) {
    return 0;
  }
  var a = time.split(":");
  var seconds = (+a[0]) * 60 * 60 + (+a[1]) * 60 + (+a[2]);
  return seconds;
}

function formatDate(date) {
  return moment.utc(date).format("YYYY-MM-DD HH:mm");
}

<commit_msg>fix error with average times showing incorrect times (12:60 instead of 13:00)<commit_after>function populatePlayer(data, sortBy) {
  var filtered = data;
  if (sortBy == "timelor" || sortBy == "lor") {
    $("#rownm").remove();
    $("#rowjv").remove();
    markPersonalBest('lor');
    filtered = filterRaid(sortBy.substring(0, 1) == "t" ? filterTime(data) : filterLeaderboardGenerated(data), "lor");
    populateStatsLoR(filterLeaderboardGenerated(data));
  } else if (sortBy == "timenm" || sortBy == "nm") {
    $("#rowlor").remove();
    $("#rowjv").remove();
    markPersonalBest('nm');
    filtered = filterRaid(sortBy.substring(0, 1) == "t" ? filterTime(data) : filterLeaderboardGenerated(data), "lornm");
    populateStatsNM(filterLeaderboardGenerated(data));
  } else if (sortBy == "timejv" || sortBy == "jv") {
    $("#rowlor").remove();
    $("#rownm").remove();
    markPersonalBest('jv');
    filtered = filterRaid(sortBy.substring(0, 1) == "t" ? filterTime(data) : filterLeaderboardGenerated(data), "jv");
    populateStatsJV(filterLeaderboardGenerated(data));
  } else if (sortBy == "date") {
    filtered = filtered.sort(function (a, b) { return (a.leaderboardGenerated > b.leaderboardGenerated) ? -1 : ((b.leaderboardGenerated > a.leaderboardGenerated) ? 1 : 0); });
  } else {
    filtered = filterLeaderboardGenerated(data);
    markPersonalBest('lor');
    markPersonalBest('lornm');
    markPersonalBest('jv');
    populateStats(filterLeaderboardGenerated(data));
  }
  populateTable(filtered);
}

function filterTime(data) {
  var victory = data.filter(function (r) { return r.objective == "VICTORY"; });
  var sorted = victory.sort(function (a, b) { return (a.time < b.time) ? -1 : ((b.time < a.time) ? 1 : 0); });
  return sorted;
}

function scrollToHash() {
  var hash = window.location.href.split('#')[1] || null;
  if (hash !== null) {
    var row = $('#' + hash);
    $("html, body").animate({ scrollTop: row.offset().top }, 100);
  }
}

function filterRaid(data, raid) {
  if (raid == "lor") {
    return data.filter(function (r) { return r.type == "lor"; });
  } else if (raid == "nm" || raid == "lornm") {
    return data.filter(function (r) { return r.type == "lornm"; });
  } else if (raid == "jv") {
    return data.filter(function (r) { return r.type == "jv"; });
  } else {
    return data;
  }
}

function filterLeaderboardGenerated(data) {
  var filtered = data.filter(function (r) {
    return !(r.objective == "FAILED" && failedUnder(r.time));
  });
  filtered.sort(function (a, b) { return (a.leaderboardGenerated > b.leaderboardGenerated) ? -1 : ((b.leaderboardGenerated > a.leaderboardGenerated) ? 1 : 0); });
  return filtered;
}

function populateTable(data) {
  $("#table").find("tr:gt(0)").remove();
  var table = document.getElementById("table");

  $.each(data, function (i, r) {
    var dataType = r.type;
    var row = table.insertRow();

    var type = row.insertCell(0);
    var date = row.insertCell(1);
    var result = row.insertCell(2);
    var time = row.insertCell(3);
    var objective = row.insertCell(4);
    var kills = row.insertCell(5);
    var deaths = row.insertCell(6);
    var host = row.insertCell(7);
    var players = row.insertCell(8);

    if (dataType == "lor") {
      type.innerHTML = "LoR";
    }
    if (dataType == "lornm") {
      type.innerHTML = "NM LoR";
    }
    if (dataType == "jv") {
      type.innerHTML = "JV";
    }

    var leaderboardGeneratedSeconds = new Date(r.leaderboardGenerated).getTime() / 1000;

    $(row).attr('data-time', timeToSeconds(r.time));
    $(row).attr('data-type', r.type);
    $(row).attr('data-objective', r.objective);
    $(row).attr('id', r.trialId);
    //$(date).append($('<a>').attr('href', '/player/?user=' + r.host + '&date=' + r.leaderboardGenerated + '#' + hostNice + '_' + leaderboardGeneratedSeconds).text(formatDate(r.leaderboardGenerated)));
    // $(date).append($('<a>').attr('href', '/player/?user=' + r.host + '&date=' + r.leaderboardGenerated + '#' + hostNice + '_' + leaderboardGeneratedSeconds).text(formatDate(r.leaderboardGenerated)));
    $(date).text(formatDate(r.leaderboardGenerated));

    objective.className = 'objective';

    //date.innerHTML = formatDate(r.leaderboardGenerated);
    result.innerHTML = r.objective;
    time.innerHTML = r.time;
    if (r.objective != "VICTORY") {
      objective.innerHTML = r.previousObjective;
    }
    kills.innerHTML = r.kills;
    deaths.innerHTML = r.deaths;
    $(host).append($("<a>").attr("href", "/player/?user=" + r.host).text(r.host));
    $.each(r.players, function (i, p) {
      var player = $("<a>")
        .attr("href", "/player/?user=" + p)
        .text(p);
      $(players).append(player);
      if (i < r.players.length - 1) {
        $(players).append(", ");
      }
    });

    if (dataType == "lor" || dataType == "lornm") {
      if (r.objective == "VICTORY") {
        var seconds = timeToSeconds(r.time);
        if (seconds < 900) {
          row.className = "speedrun";
        } else if (seconds < 1200) {
          row.className = "fastrun";
        } else if (seconds > 3600) {
          row.className = "slowrun";
        } else {
          row.className = "run";
        }
      } else if (r.objective == "FAILED") {
        row.className = "failed";
      } else {
        row.className = "run";
      }
    } else if (dataType == "jv") {
      if (r.objective == "VICTORY") {
        var seconds = timeToSeconds(r.time);
        if (seconds < 1200) {
          row.className = "speedrun";
        } else if (seconds < 1500) {
          row.className = "fastrun";
        } else if (seconds > 3600) {
          row.className = "slowrun";
        } else {
          row.className = "run";
        }
      } else if (r.objective == "FAILED") {
        row.className = "failed";
      } else {
        row.className = "run";
      }
    }

    //Only for eastereggs (can be removed)
    $(row).attr('data-host', r.host);
    $(row).attr('data-players', r.players + "");

  });
}

function populateStats(data) {
  populateStatsJV(data);
  populateStatsLoR(data);
  populateStatsNM(data);
}

function formatClearRate(victory, count){
  if(count == 0){
    return "N/A";
  }
  return numeral(victory / count).format('0%');
}

function formatCompletions(victory, count){
  if(count == 0){
    return "N/A";
  }
  return victory + ' / ' + count;
}

function populateStatsJV(data) {
  var jv = data.filter(function (r) { return r.type == "jv"; });
  var summary = getSummary(jv);
  $("#averageJV").text(formatTime(summary.average));
  $("#clearRateJV").text(formatClearRate(summary.victory, summary.count));
  $("#completionsJV").text(formatCompletions(summary.victory, summary.count));
  $("#bestJV").text(formatTime(summary.best));
}

function populateStatsNM(data) {
  var lornm = data.filter(function (r) { return r.type == "lornm"; });
  var summary = getSummary(lornm);
  $("#averageLorNightmare").text(formatTime(summary.average));
  $("#clearRateLorNightmare").text(formatClearRate(summary.victory, summary.count));
  $("#completionsLorNightmare").text(formatCompletions(summary.victory, summary.count));
  $("#bestLorNightmare").text(formatTime(summary.best));
}

function populateStatsLoR(data) {
  var lor = data.filter(function (r) { return r.type == "lor"; });
  var summary = getSummary(lor);
  $("#averageLor").text(formatTime(summary.average));
  $("#clearRateLor").text(formatClearRate(summary.victory, summary.count));
  $("#completionsLor").text(formatCompletions(summary.victory, summary.count));
  $("#bestLor").text(formatTime(summary.best));
}

function markPersonalBest(type) {
  var tableRows = $('#table tr');
  var filtered = tableRows.filter(function (i, x) { return $(x).attr('data-type') == type && $(x).attr('data-objective') == 'VICTORY'; });
  var sorted = filtered.sort(function (a, b) { return +$(a).attr('data-time') > +$(b).attr('data-time') ? 1 : ((+$(b).attr('data-time') > +$(a).attr('data-time')) ? -1 : 0); });
  var top = $(sorted[0]);
  var objective = top.children('.objective');
  var img = $('<img>')
    .attr('src', '/img/star.png')
    .attr('height', '19px')
    .attr('title', 'Personal Best');
  objective.append(img);
}

function getSummary(arr) {
  var victory = arr.filter(function (r) { return r.objective == "VICTORY"; });
  var failed = arr.filter(function (r) { r.objective == "FAILED"; });
  var avg = victory.reduce(function (total, r) { return total + timeToSeconds(r.time); }, 0) / victory.length;
  var best = Math.min.apply(null, victory.map(function (r) { return timeToSeconds(r.time); }));
  return {
    average: avg,
    count: arr.length,
    victory: victory.length,
    failed: failed.length,
    best: best
  };
}

function getParameterByName(name, url) {
  name = name.replace(/[\[\]]/g, "\\$&");
  var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
    results = regex.exec(url);
  if (!results) return null;
  if (!results[2]) return "";
  return decodeURIComponent(results[2].replace(/\+/g, " "));
}

function failedUnder(time) {
  if (timeToSeconds(time) > 420) {
    return false;
  } else {
    return true;
  }
}

function formatTime(n) {
  if(isNaN(n) || !isFinite(n)){
    return "N/A";
  }
  n = Math.ceil(n);
  var hours = Math.floor(n / 60 / 60),
    minutes = Math.floor((n - (hours * 60 * 60)) / 60),
    seconds = Math.round(n - (hours * 60 * 60) - (minutes * 60));
  var h = "";
  if (hours > 0) {
    h = ((hours < 10) ? '0' + hours : hours) + ':';
  }

  return h + ((minutes < 10) ? '0' + minutes : minutes) + ':' + ((seconds < 10) ? '0' + seconds : seconds);
}

function timeToSeconds(time) {
  if (time === undefined) {
    return 0;
  }
  var a = time.split(":");
  var seconds = (+a[0]) * 60 * 60 + (+a[1]) * 60 + (+a[2]);
  return seconds;
}

function formatDate(date) {
  return moment.utc(date).format("YYYY-MM-DD HH:mm");
}

<|endoftext|>