<commit_before>var React = require('react')
var _ = require('_')
var chartDefinitions = require('./ChartDefinitions.js')
var SpinKitCube = require('./SpinKitCube.js')
var tauCharts = require('tauCharts')
var Alert = require('react-s-alert').default

var SqlpadTauChart = React.createClass({
  componentDidUpdate: function (prevProps) {
    var prevResultId = (prevProps.queryResult ? prevProps.queryResult.id : null)
    var currentResultId = (this.props.queryResult ? this.props.queryResult.id : null)
    if (prevResultId !== currentResultId) {
      console.log('rendering because queryResults changed')
      this.renderChart()
    }
  },
  chart: undefined,
  chartStyle: {
    padding: '20px 10px 10px 20px',
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0
  },
  renderChart: function (rerender) {
    // This is invoked during following:
    //  - Vis tab enter
    //  - Visualize button press (forces rerender)
    //  - new data arrival
    var meta = (this.props.queryResult ? this.props.queryResult.meta : {})
    var dataRows = (this.props.queryResult ? this.props.queryResult.rows : [])
    var chartType = this.props.query.chartConfiguration.chartType
    var selectedFields = this.props.query.chartConfiguration.fields
    var chartDefinition = _.findWhere(chartDefinitions, {chartType: chartType})

    if (this.chart && (!dataRows.length || !chartDefinition)) {
      this.chart.destroy()
    }

    // If there's no data just exit the chart render
    if (!dataRows.length) return

    // if there's no chart definition exit the render
    if (!chartDefinition) return

    var chartConfig = {
      type: chartDefinition.tauChartsType,
      plugins: [
        tauCharts.api.plugins.get('tooltip')(),
        tauCharts.api.plugins.get('legend')(),
        tauCharts.api.plugins.get('exportTo')({
          cssPaths: [this.props.config.baseUrl + '/javascripts/vendor/tauCharts/tauCharts.min.css'],
          fileName: this.props.query.name || 'unnamed query'
        })
      ]
    }

    var unmetRequiredFields = []
    var definitionFields = chartDefinition.fields.map(function (field) {
      if (field.required && !selectedFields[field.fieldId]) {
        unmetRequiredFields.push(field)
      }
      field.val = selectedFields[field.fieldId]
      return field
    })
    if (unmetRequiredFields.length) {
      // if rerender is true, a render was explicitly requested by user clicking the vis button
      // TODO - highlight fields that are required but not provided
      if (rerender) {
        Alert.error('Unmet required fields: ' + unmetRequiredFields.map(f => f.label).join(', '))
      }
      return
    }

    // loop through data rows and convert types as needed
    dataRows = dataRows.map((row) => {
      var newRow = {}
      for (var col in row) {
        var datatype = this.props.queryResult.meta[col].datatype
        if (datatype === 'date') {
          newRow[col] = new Date(row[col])
        } else if (datatype === 'number') {
          newRow[col] = Number(row[col])
        } else {
          newRow[col] = row[col]
        }
      }
      // HACK -
      // Facets need to be a dimension, not a measure.
      // tauCharts auto detects numbers to be measures
      // Here we'll convert a number to a string,
      // to trick tauCharts into thinking its a dimension
      var forceDimensionFields = _.where(definitionFields, {forceDimension: true})
      forceDimensionFields.forEach(function (fieldDefinition) {
        var col = fieldDefinition.val
        var colDatatype = (meta[col] ? meta[col].datatype : null)
        if (col && colDatatype === 'number' && newRow[col]) {
          newRow[col] = newRow[col].toString()
        }
      })
      return newRow
    })

    var definitionFieldsById = _.indexBy(definitionFields, 'fieldId')
    switch (chartType) {
      case 'line':
        chartConfig.x = [definitionFieldsById.x.val]
        if (definitionFieldsById.xFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.xFacet.val)
        }
        chartConfig.y = [definitionFieldsById.y.val]
        if (definitionFieldsById.yFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.yFacet.val)
        }
        if (definitionFieldsById.filter.val) {
          chartConfig.plugins.push(tauCharts.api.plugins.get('quick-filter')())
        }
        if (definitionFieldsById.trendline.val) {
          chartConfig.plugins.push(tauCharts.api.plugins.get('trendline')())
        }
        if (definitionFieldsById.split.val) chartConfig.color = definitionFieldsById.split.val
        if (definitionFieldsById.size.val) chartConfig.size = definitionFieldsById.size.val
        if (definitionFieldsById.yMin.val || definitionFieldsById.yMax.val) {
          chartConfig.guide = {
            y: {autoScale: false}
          }
          if (definitionFieldsById.yMin.val) chartConfig.guide.y.min = Number(definitionFieldsById.yMin.val)
          if (definitionFieldsById.yMax.val) chartConfig.guide.y.max = Number(definitionFieldsById.yMax.val)
        }
        break

      case 'bar':
        chartConfig.x = [definitionFieldsById.barvalue.val]
        if (definitionFieldsById.valueFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.valueFacet.val)
        }
        chartConfig.y = [definitionFieldsById.barlabel.val]
        if (definitionFieldsById.labelFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.labelFacet.val)
        }
        break

      case 'verticalbar':
        chartConfig.y = [definitionFieldsById.barvalue.val]
        if (definitionFieldsById.valueFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.valueFacet.val)
        }
        chartConfig.x = [definitionFieldsById.barlabel.val]
        if (definitionFieldsById.labelFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.labelFacet.val)
        }
        break

      case 'stacked-bar-horizontal':
        chartConfig.x = [definitionFieldsById.barvalue.val]
        if (definitionFieldsById.valueFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.valueFacet.val)
        }
        chartConfig.y = [definitionFieldsById.barlabel.val]
        if (definitionFieldsById.labelFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.labelFacet.val)
        }
        if (definitionFieldsById.color.val) chartConfig.color = definitionFieldsById.color.val
        break

      case 'stacked-bar-vertical':
        chartConfig.y = [definitionFieldsById.barvalue.val]
        if (definitionFieldsById.valueFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.valueFacet.val)
        }
        chartConfig.x = [definitionFieldsById.barlabel.val]
        if (definitionFieldsById.labelFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.labelFacet.val)
        }
        if (definitionFieldsById.color.val) chartConfig.color = definitionFieldsById.color.val
        break

      case 'bubble':
        chartConfig.x = [definitionFieldsById.x.val]
        if (definitionFieldsById.xFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.xFacet.val)
        }
        chartConfig.y = [definitionFieldsById.y.val]
        if (definitionFieldsById.yFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.yFacet.val)
        }
        if (definitionFieldsById.filter.val) {
          chartConfig.plugins.push(tauCharts.api.plugins.get('quick-filter')())
        }
        if (definitionFieldsById.trendline.val) {
          chartConfig.plugins.push(tauCharts.api.plugins.get('trendline')())
        }
        if (definitionFieldsById.size.val) chartConfig.size = definitionFieldsById.size.val
        if (definitionFieldsById.color.val) chartConfig.color = definitionFieldsById.color.val
        break

      default:
        console.error('unknown chart type')
    }

    // Add data to chart config
    chartConfig.data = dataRows

    if (!this.chart) {
      this.chart = new tauCharts.Chart(chartConfig)
      this.chart.renderTo('#chart')
    } else if (this.chart && rerender) {
      this.chart.destroy()
      this.chart = new tauCharts.Chart(chartConfig)
      this.chart.renderTo('#chart')
    } else {
      this.chart.setData(dataRows)
    }
  },
  setData: function (chartData) {
    this.chart.setData(chartData)
  },
  componentWillUnmount () {
    if (this.chart) this.chart.destroy()
  },
  render: function () {
    var runResultNotification = () => {
      if (this.props.isRunning) {
        return (

            <SpinKitCube />

        )
      }
      return null
    }
    var runResultErrorNotification = () => {
      if (this.props.queryError) {
        return (

            {this.props.queryError}

        )
      }
    }
    return (

        {runResultNotification()}
        {runResultErrorNotification()}

    )
  }
})

module.exports = SqlpadTauChart
<commit_msg>Vis tab: hide error on rerun (#137)<commit_after>var React = require('react')
var _ = require('_')
var chartDefinitions = require('./ChartDefinitions.js')
var SpinKitCube = require('./SpinKitCube.js')
var tauCharts = require('tauCharts')
var Alert = require('react-s-alert').default

var SqlpadTauChart = React.createClass({
  componentDidUpdate: function (prevProps) {
    var prevResultId = (prevProps.queryResult ? prevProps.queryResult.id : null)
    var currentResultId = (this.props.queryResult ? this.props.queryResult.id : null)
    if (prevResultId !== currentResultId) {
      console.log('rendering because queryResults changed')
      this.renderChart()
    }
  },
  chart: undefined,
  chartStyle: {
    padding: '20px 10px 10px 20px',
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0
  },
  renderChart: function (rerender) {
    // This is invoked during following:
    //  - Vis tab enter
    //  - Visualize button press (forces rerender)
    //  - new data arrival
    var meta = (this.props.queryResult ? this.props.queryResult.meta : {})
    var dataRows = (this.props.queryResult ? this.props.queryResult.rows : [])
    var chartType = this.props.query.chartConfiguration.chartType
    var selectedFields = this.props.query.chartConfiguration.fields
    var chartDefinition = _.findWhere(chartDefinitions, {chartType: chartType})

    if (this.chart && (!dataRows.length || !chartDefinition)) {
      this.chart.destroy()
    }

    // If there's no data just exit the chart render
    if (!dataRows.length) return

    // if there's no chart definition exit the render
    if (!chartDefinition) return

    var chartConfig = {
      type: chartDefinition.tauChartsType,
      plugins: [
        tauCharts.api.plugins.get('tooltip')(),
        tauCharts.api.plugins.get('legend')(),
        tauCharts.api.plugins.get('exportTo')({
          cssPaths: [this.props.config.baseUrl + '/javascripts/vendor/tauCharts/tauCharts.min.css'],
          fileName: this.props.query.name || 'unnamed query'
        })
      ]
    }

    var unmetRequiredFields = []
    var definitionFields = chartDefinition.fields.map(function (field) {
      if (field.required && !selectedFields[field.fieldId]) {
        unmetRequiredFields.push(field)
      }
      field.val = selectedFields[field.fieldId]
      return field
    })
    if (unmetRequiredFields.length) {
      // if rerender is true, a render was explicitly requested by user clicking the vis button
      // TODO - highlight fields that are required but not provided
      if (rerender) {
        Alert.error('Unmet required fields: ' + unmetRequiredFields.map(f => f.label).join(', '))
      }
      return
    }

    // loop through data rows and convert types as needed
    dataRows = dataRows.map((row) => {
      var newRow = {}
      for (var col in row) {
        var datatype = this.props.queryResult.meta[col].datatype
        if (datatype === 'date') {
          newRow[col] = new Date(row[col])
        } else if (datatype === 'number') {
          newRow[col] = Number(row[col])
        } else {
          newRow[col] = row[col]
        }
      }
      // HACK -
      // Facets need to be a dimension, not a measure.
      // tauCharts auto detects numbers to be measures
      // Here we'll convert a number to a string,
      // to trick tauCharts into thinking its a dimension
      var forceDimensionFields = _.where(definitionFields, {forceDimension: true})
      forceDimensionFields.forEach(function (fieldDefinition) {
        var col = fieldDefinition.val
        var colDatatype = (meta[col] ? meta[col].datatype : null)
        if (col && colDatatype === 'number' && newRow[col]) {
          newRow[col] = newRow[col].toString()
        }
      })
      return newRow
    })

    var definitionFieldsById = _.indexBy(definitionFields, 'fieldId')
    switch (chartType) {
      case 'line':
        chartConfig.x = [definitionFieldsById.x.val]
        if (definitionFieldsById.xFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.xFacet.val)
        }
        chartConfig.y = [definitionFieldsById.y.val]
        if (definitionFieldsById.yFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.yFacet.val)
        }
        if (definitionFieldsById.filter.val) {
          chartConfig.plugins.push(tauCharts.api.plugins.get('quick-filter')())
        }
        if (definitionFieldsById.trendline.val) {
          chartConfig.plugins.push(tauCharts.api.plugins.get('trendline')())
        }
        if (definitionFieldsById.split.val) chartConfig.color = definitionFieldsById.split.val
        if (definitionFieldsById.size.val) chartConfig.size = definitionFieldsById.size.val
        if (definitionFieldsById.yMin.val || definitionFieldsById.yMax.val) {
          chartConfig.guide = {
            y: {autoScale: false}
          }
          if (definitionFieldsById.yMin.val) chartConfig.guide.y.min = Number(definitionFieldsById.yMin.val)
          if (definitionFieldsById.yMax.val) chartConfig.guide.y.max = Number(definitionFieldsById.yMax.val)
        }
        break

      case 'bar':
        chartConfig.x = [definitionFieldsById.barvalue.val]
        if (definitionFieldsById.valueFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.valueFacet.val)
        }
        chartConfig.y = [definitionFieldsById.barlabel.val]
        if (definitionFieldsById.labelFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.labelFacet.val)
        }
        break

      case 'verticalbar':
        chartConfig.y = [definitionFieldsById.barvalue.val]
        if (definitionFieldsById.valueFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.valueFacet.val)
        }
        chartConfig.x = [definitionFieldsById.barlabel.val]
        if (definitionFieldsById.labelFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.labelFacet.val)
        }
        break

      case 'stacked-bar-horizontal':
        chartConfig.x = [definitionFieldsById.barvalue.val]
        if (definitionFieldsById.valueFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.valueFacet.val)
        }
        chartConfig.y = [definitionFieldsById.barlabel.val]
        if (definitionFieldsById.labelFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.labelFacet.val)
        }
        if (definitionFieldsById.color.val) chartConfig.color = definitionFieldsById.color.val
        break

      case 'stacked-bar-vertical':
        chartConfig.y = [definitionFieldsById.barvalue.val]
        if (definitionFieldsById.valueFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.valueFacet.val)
        }
        chartConfig.x = [definitionFieldsById.barlabel.val]
        if (definitionFieldsById.labelFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.labelFacet.val)
        }
        if (definitionFieldsById.color.val) chartConfig.color = definitionFieldsById.color.val
        break

      case 'bubble':
        chartConfig.x = [definitionFieldsById.x.val]
        if (definitionFieldsById.xFacet.val) {
          chartConfig.x.unshift(definitionFieldsById.xFacet.val)
        }
        chartConfig.y = [definitionFieldsById.y.val]
        if (definitionFieldsById.yFacet.val) {
          chartConfig.y.unshift(definitionFieldsById.yFacet.val)
        }
        if (definitionFieldsById.filter.val) {
          chartConfig.plugins.push(tauCharts.api.plugins.get('quick-filter')())
        }
        if (definitionFieldsById.trendline.val) {
          chartConfig.plugins.push(tauCharts.api.plugins.get('trendline')())
        }
        if (definitionFieldsById.size.val) chartConfig.size = definitionFieldsById.size.val
        if (definitionFieldsById.color.val) chartConfig.color = definitionFieldsById.color.val
        break

      default:
        console.error('unknown chart type')
    }

    // Add data to chart config
    chartConfig.data = dataRows

    if (!this.chart) {
      this.chart = new tauCharts.Chart(chartConfig)
      this.chart.renderTo('#chart')
    } else if (this.chart && rerender) {
      this.chart.destroy()
      this.chart = new tauCharts.Chart(chartConfig)
      this.chart.renderTo('#chart')
    } else {
      this.chart.setData(dataRows)
    }
  },
  setData: function (chartData) {
    this.chart.setData(chartData)
  },
  componentWillUnmount () {
    if (this.chart) this.chart.destroy()
  },
  render: function () {
    var runResultNotification = () => {
      if (this.props.isRunning) {
        return (

            <SpinKitCube />

        )
      } else if (this.props.queryError) {
        return (

            {this.props.queryError}

        )
      } else {
        return null
      }
    }
    return (

        {runResultNotification()}

    )
  }
})

module.exports = SqlpadTauChart
<|endoftext|>


<commit_before>//
// Gistbook
// A model representing a new Gistbook
//

import { BaseModel, BaseCollection } from 'base/entities';

export default BaseModel.extend({
  initialize() {
    this._dirty = false;
    this.on('change', this._markDirty, this);
    this.listenTo(this.get('pages'), 'change', this._markDirty);
  },

  // Create a deeply nested model structure
  // Gistbooks have a collection of pages
  // Pages have a collection of sections
  parse(data) {

    // Create our nested pages
    data.pages = new BaseCollection(data.pages);

    // Loop through each page...
    data.pages.each(page => {

      // ...to create our nested sections
      page.set({
        sections: new BaseCollection(page.get('sections'))
      }, {silent: true});

      // And forward all events from our sections to our pages
      page.listenTo(page.get('sections'), 'all', function() {
        page.trigger.apply(page, arguments);
      });
    });
    return data;
  },

  isDirty() {
    return !!this._dirty;
  },

  _markDirty() {
    this._dirty = true;
  },
});
<commit_msg>Fix bug where homepage only displayed once.<commit_after>//
// Gistbook
// A model representing a new Gistbook
//

import * as _ from 'underscore';
import { BaseModel, BaseCollection } from 'base/entities';

export default BaseModel.extend({
  initialize() {
    this._dirty = false;
    this.on('change', this._markDirty, this);
    this.listenTo(this.get('pages'), 'change', this._markDirty);
  },

  // Create a deeply nested model structure
  // Gistbooks have a collection of pages
  // Pages have a collection of sections
  parse(data) {
    data = _.clone(data);

    // Create our nested pages
    data.pages = new BaseCollection(data.pages);

    // Loop through each page...
    data.pages.each(page => {

      // ...to create our nested sections
      page.set({
        sections: new BaseCollection(page.get('sections'))
      }, {silent: true});

      // And forward all events from our sections to our pages
      page.listenTo(page.get('sections'), 'all', function() {
        page.trigger.apply(page, arguments);
      });
    });
    return data;
  },

  isDirty() {
    return !!this._dirty;
  },

  _markDirty() {
    this._dirty = true;
  },
});
<|endoftext|>


<commit_before>import attributes from './attributes';

export {Icon, Spacer} from './misc';
export {Layout, Header, HeaderRow, Title, Tabs, Tab, Drawer, Navigation, NavLink, Content} from './layout';
export {Button, Fab} from './button';
export {Grid, Cell} from './grid';
export {ProgressBar} from './loading';
export {TextInput} from './input';
export {Card, CardTitle, CardSupportingText} from './card';
<commit_msg>Export attributes function<commit_after>export {default as attributes} from './attributes';

export {Icon, Spacer} from './misc';
export {Layout, Header, HeaderRow, Title, Tabs, Tab, Drawer, Navigation, NavLink, Content} from './layout';
export {Button, Fab} from './button';
export {Grid, Cell} from './grid';
export {ProgressBar} from './loading';
export {TextInput} from './input';
export {Card, CardTitle, CardSupportingText} from './card';
<|endoftext|>


<commit_before>import React from 'react'
import styles from './LandingF.scss'
import logoV from '../../images/logo-home-video-copy.png'
import c3nonprofit from '../../images/501-c-3-nonprofit.png'
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import styles from './LandingF.scss';
import logoV from '../../images/logo-home-video-copy.png';
import facebook from '../../images/facebook.png';
import linkedIn from '../../images/linked-in.png';
import pininterest from '../../images/pininterest.png';
import twitter from '../../images/twitter.png';
import c3nonprofit from '../../images/501-c-3-nonprofit.png';

class Footer extends React.Component {
  render () {
    return (

Projects

import React, { Component } from 'react'
import styles from './LandingF.scss'
import logo from '../../images/logo-home.png'
import facebook from '../../images/facebook.png'
import linkedin from '../../images/linked-in.png'
import pininterest from '../../images/pininterest.png'
import twitter from '../../images/twitter.png'
import c3nonprofit from '../../images/501-c-3-nonprofit.png'
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import styles from './LandingF.scss';
import logo from '../../images/logo-home.png';
import facebook from '../../images/facebook.png';
import linkedIn from '../../images/linked-in.png';
import pininterest from '../../images/pininterest.png';
import twitter from '../../images/twitter.png';
import c3nonprofit from '../../images/501-c-3-nonprofit.png';

class Footer extends React.Component {
  render(){
    return (

Product

Popular

Trending

Catalog

Popular

Trending

Catalog

Popular

Trending

Catalog

Projects

            //
Popular

            //
Trending

            //
Catalog

            //
Features

About

    )
  }
}

export default Footer

Company

Press

Releases

Mission

Strategy

Works

About

            //
Press

            //
Releases

            //
Mission

            //
Strategy

            //
Works

        //

        //
FOLLOW US

        //

        //
        //
        //
        //
        //

        //

    )
  }
};

export default LandingF
<commit_msg>remove first 2 lines<commit_after><<<<<<>>>>>> remove first 2 lines
import styles from './LandingF.scss'
import logoV from '../../images/logo-home-video-copy.png'
import c3nonprofit from '../../images/501-c-3-nonprofit.png'
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import styles from './LandingF.scss';
import logoV from '../../images/logo-home-video-copy.png';
import facebook from '../../images/facebook.png';
import linkedIn from '../../images/linked-in.png';
import pininterest from '../../images/pininterest.png';
import twitter from '../../images/twitter.png';
import c3nonprofit from '../../images/501-c-3-nonprofit.png';

class Footer extends React.Component {
  render () {
    return (

Projects

import React, { Component } from 'react'
import styles from './LandingF.scss'
import logo from '../../images/logo-home.png'
import facebook from '../../images/facebook.png'
import linkedin from '../../images/linked-in.png'
import pininterest from '../../images/pininterest.png'
import twitter from '../../images/twitter.png'
import c3nonprofit from '../../images/501-c-3-nonprofit.png'
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import styles from './LandingF.scss';
import logo from '../../images/logo-home.png';
import facebook from '../../images/facebook.png';
import linkedIn from '../../images/linked-in.png';
import pininterest from '../../images/pininterest.png';
import twitter from '../../images/twitter.png';
import c3nonprofit from '../../images/501-c-3-nonprofit.png';

class Footer extends React.Component {
  render(){
    return (

Product

Popular

Trending

Catalog

Popular

Trending

Catalog

Popular

Trending

Catalog

Projects

            //
Popular

            //
Trending

            //
Catalog

            //
Features

About

    )
  }
}

export default Footer

Company

Press

Releases

Mission

Strategy

Works

About

            //
Press

            //
Releases

            //
Mission

            //
Strategy

            //
Works

        //

        //
FOLLOW US

        //

        //
        //
        //
        //
        //

        //

    )
  }
};

export default LandingF
<|endoftext|>


<commit_before>/*
Copyright (C) 2013 Vlad Tsepelev

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

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

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

/*
You can use this lib everywhere.
Proletariat.js microlibrary simplifies and hides routines with WebWorkers.
It set few rules and constraints to workers:

1. Messages posted TO workers should be in set ["init", "setup", "start", "cancel"] - Proletariat determine those methods.
Proletariat set "type" attribute to data object posted to webworker.
NOTE: If your dataObject already contains "type" attribute it will be overwriten by Proletariat.
Type stored into evt.data.type attribute passed to webworker's onmessage function.
So WebWorker code should listen for this types and split its workflow accordingly.

2. Messages posted FROM workers should be in set ["inited", "setuped", "started", "cancelled", "progressed", "errored", "finished"] - Proletariat listens only  for this events.
TODO: use callback with custom event type over all this methods.

3. Proletariat.createWorker method takes delegate as second argument.
delagate variable holds callbacks in one object:
delegate = {
	errored:function(evt){...},
	finished:function(evt){...},
	...
}

but you can set it from your code like this:

worker.delegate.errored =  function(evt) {console.log("Error: "+evt.data.message);};
worker.delegate.finished = finishedCallback;

 */

// Worker class extensions

Worker.prototype.inProgress = function(){
	return ((this.type != "canceled") && (this.type != "errored") && (this.type != "finished"));
}

Worker.prototype.postMessageWithType = function(type, dataObject, refBuffer){
	var object = dataObject || {};
	object.type = type;
	this.type = type;
	this.postMessage(object, refBuffer);
	return this;
}

Worker.prototype.init = function(dataObject, refBuffer){
	return this.postMessageWithType("init", dataObject, refBuffer);

}

Worker.prototype.setup = function(dataObject, refBuffer){
	return this.postMessageWithType("setup", dataObject, refBuffer);
}

Worker.prototype.start = function(){
	return this.postMessageWithType("start");
}

Worker.prototype.cancel = function(){
	return this.postMessageWithType("cancel");
}

// Proletariat methods
// TODO:

Proletariat = {};

Proletariat.createWorker = function(url, delegate){
	var worker = new Worker(url);
	worker.delegate = delegate || {};

	var onMessageHandler = function(event){
		var messageType = event.data.result;
		worker.type = messageType;
		if(messageType == 'inited' && worker.delegate.inited){
			worker.delegate.inited(event);
		}
		else if(messageType == 'setuped' && worker.delegate.setuped){
			worker.delegate.setuped(event);
		}
		else if(messageType == 'started' && worker.delegate.started){
			worker.delegate.started(event);
		}
		else if(messageType == 'cancelled' && worker.delegate.cancelled){
			worker.delegate.cancelled(event);
		}
		else if(messageType == 'progressed' && worker.delegate.progressed){
			worker.delegate.progressed(event);
		}
		else if(messageType == 'errored' && worker.delegate.errored){
			worker.delegate.errored(event);
		}
		else if(messageType == 'finished' && worker.delegate.finished){
			worker.delegate.finished(event);
		}
	}

	worker.onmessage = onMessageHandler;

	return worker;
}

Proletariat.createCrowd = function(workers){

	var crowd = [];

	if(workers){
		for (var i = workers.length - 1; i >= 0; i--) {
			crowd.push(workers[i]);
		};
	}

	return crowd;
}

Proletariat.addWorkersToCrowd = function(crowd, workers){

	if(workers){

		if(!Array.isArray(workers)){ // add one
			crowd.push(workers);
		}else{ // add all from array
			for (var i = workers.length - 1; i >= 0; i--) {
				crowd.push(workers[i]);
			};
		}
	}

	return crowd;
}

Proletariat.isCrowdInProgress = function(crowd){

	if(crowd){

		for (var i = crowd.length - 1; i >= 0; i--) {
			if(crowd[i].inProgress()) return true;
		};
	}

	return false;
}

Proletariat.startCrowd = function(crowd, allfinished){
	if(crowd){

		for (var i = crowd.length - 1; i >= 0; i--) {

			var originalhandler = crowd[i].delegate.finished;
			crowd[i].delegate.finished = function(evt){
				if(originalhandler) originalhandler(evt);
				if(!Proletariat.isCrowdInProgress(crowd) && allfinished){
					allfinished();
				}
			}
			crowd[i].start();
		};
	}

	return crowd;
}

<commit_msg>rename result to type in messages from worker scripts<commit_after>/*
Copyright (C) 2013 Vlad Tsepelev

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

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

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

/*
You can use this lib everywhere.
Proletariat.js microlibrary simplifies and hides routines with WebWorkers.
It set few rules and constraints to workers:

1. Messages posted TO workers should be in set ["init", "setup", "start", "cancel"] - Proletariat determine those methods.
Proletariat set "type" attribute to data object posted to webworker.
NOTE: If your dataObject already contains "type" attribute it will be overwriten by Proletariat.
Type stored into evt.data.type attribute passed to webworker's onmessage function.
So WebWorker code should listen for this types and split its workflow accordingly.

2. Messages posted FROM workers should be in set ["inited", "setuped", "started", "cancelled", "progressed", "errored", "finished"] - Proletariat listens only  for this events.
TODO: use callback with custom event type over all this methods.

3. Proletariat.createWorker method takes delegate as second argument.
delagate variable holds callbacks in one object:
delegate = {
	errored:function(evt){...},
	finished:function(evt){...},
	...
}

but you can set it from your code like this:

worker.delegate.errored =  function(evt) {console.log("Error: "+evt.data.message);};
worker.delegate.finished = finishedCallback;

 */

// Worker class extensions

Worker.prototype.inProgress = function(){
	return ((this.type != "canceled") && (this.type != "errored") && (this.type != "finished"));
}

Worker.prototype.postMessageWithType = function(type, dataObject, refBuffer){
	var object = dataObject || {};
	object.type = type;
	this.type = type;
	this.postMessage(object, refBuffer);
	return this;
}

Worker.prototype.init = function(dataObject, refBuffer){
	return this.postMessageWithType("init", dataObject, refBuffer);

}

Worker.prototype.setup = function(dataObject, refBuffer){
	return this.postMessageWithType("setup", dataObject, refBuffer);
}

Worker.prototype.start = function(){
	return this.postMessageWithType("start");
}

Worker.prototype.cancel = function(){
	return this.postMessageWithType("cancel");
}

// Proletariat methods
// TODO:

Proletariat = {};

Proletariat.createWorker = function(url, delegate){
	var worker = new Worker(url);
	worker.delegate = delegate || {};

	var onMessageHandler = function(event){
		var messageType = event.data.type;
		worker.type = messageType;
		if(messageType == 'inited' && worker.delegate.inited){
			worker.delegate.inited(event);
		}
		else if(messageType == 'setuped' && worker.delegate.setuped){
			worker.delegate.setuped(event);
		}
		else if(messageType == 'started' && worker.delegate.started){
			worker.delegate.started(event);
		}
		else if(messageType == 'cancelled' && worker.delegate.cancelled){
			worker.delegate.cancelled(event);
		}
		else if(messageType == 'progressed' && worker.delegate.progressed){
			worker.delegate.progressed(event);
		}
		else if(messageType == 'errored' && worker.delegate.errored){
			worker.delegate.errored(event);
		}
		else if(messageType == 'finished' && worker.delegate.finished){
			worker.delegate.finished(event);
		}
	}

	worker.onmessage = onMessageHandler;

	return worker;
}

Proletariat.createCrowd = function(workers){

	var crowd = [];

	if(workers){
		for (var i = workers.length - 1; i >= 0; i--) {
			crowd.push(workers[i]);
		};
	}

	return crowd;
}

Proletariat.addWorkersToCrowd = function(crowd, workers){

	if(workers){

		if(!Array.isArray(workers)){ // add one
			crowd.push(workers);
		}else{ // add all from array
			for (var i = workers.length - 1; i >= 0; i--) {
				crowd.push(workers[i]);
			};
		}
	}

	return crowd;
}

Proletariat.isCrowdInProgress = function(crowd){

	if(crowd){

		for (var i = crowd.length - 1; i >= 0; i--) {
			if(crowd[i].inProgress()) return true;
		};
	}

	return false;
}

Proletariat.startCrowd = function(crowd, allfinished){
	if(crowd){

		for (var i = crowd.length - 1; i >= 0; i--) {

			var originalhandler = crowd[i].delegate.finished;
			crowd[i].delegate.finished = function(evt){
				if(originalhandler) originalhandler(evt);
				if(!Proletariat.isCrowdInProgress(crowd) && allfinished){
					allfinished();
				}
			}
			crowd[i].start();
		};
	}

	return crowd;
}

<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import './contacto.scss';

export default class Contacto extends PureComponent {
  render = () => {
    return

          facebook
          instagram
          youtube

            +51 1 448-1113

              Av. Alfredo Franco 200, Urb. Chama, Surco - Lima

              britanicaballet@gmail.com

              Atención presencial:

                 Lunes a Jueves 3:30pm - 6:30pm

                 Sábados 10:00am - 1:00pm

;
  }
}
<commit_msg>NOTE: days with no attention<commit_after>import React, { PureComponent } from 'react';
import './contacto.scss';

export default class Contacto extends PureComponent {
  render = () => {
    return

          facebook
          instagram
          youtube

El 28, 30 y 31 de julio nuestra academia estará cerrada por vacaciones.

            +51 1 448-1113

              Av. Alfredo Franco 200, Urb. Chama, Surco - Lima

              britanicaballet@gmail.com

              Atención presencial:

                 Lunes a Jueves 3:30pm - 6:30pm

                 Sábados 10:00am - 1:00pm

;
  }
}
<|endoftext|>


<commit_before>define(["utils"], function($u) {
    return [
        {
            "title": "Green Line Extension",
            "tags": ["capital projects", "mbta"],
            "colors": "green",
            "source": "/src/layerdata/glx.geojson",
            "template": 'Opens: <%= projectedYear %> (estimate)'
        },

        {
            "title": "Community Path",
            "tags": [],
            "colors": "orange",
            "source": "/src/layerdata/community_path.geojson",
            "template": null
        }
    ];
});
<commit_msg>add location for fire hydrants<commit_after>define(["utils"], function($u) {
    return [
        {
            "title": "Green Line Extension",
            "tags": ["capital projects", "mbta"],
            "colors": "green",
            "source": "/src/layerdata/glx.geojson",
            "template": 'Opens: <%= projectedYear %> (estimate)'
        },

        {
            "title": "Community Path",
            "tags": [],
            "colors": "orange",
            "source": "/src/layerdata/community_path.geojson",
            "template": null
        }
        {
          "title": "Fire Hydrants",
          "tags" [],
          "colors": "red",
          "source": "/src/layer/",
          "template": null
        }
    ];
});
<|endoftext|>


<commit_before>Template.post.helpers({
	post: function() {
		return Posts.findOne(Router.current().params._id);
	},
	next: function() {
		var postId = Router.current().params._id,
			posts = Posts.find().fetch();

		for(var i = 0; i < posts.length; ++i) {
			if (posts[i]._id === postId) {
				var current = posts[i],
					index = posts.indexOf(current);

				index++;

				if (index === posts.length) {
					e.preventDefault();
				} else {
					var nextPostId = posts[index]._id;
					return Posts.findOne(nextPostId);
				}
			} else {
				e.preventDefault();
			}
		}
	}
});
<commit_msg>next post wip<commit_after>Template.post.helpers({
	post: function() {
		return Posts.findOne(Router.current().params._id);
	},
	next: function() {
		//return Posts.findOne(Router.current().params._id);
		var postId = Router.current().params._id,
			posts = Posts.find().fetch();

		for(var i = 0; i < posts.length; ++i) {
			if (posts[i]._id === postId) {
				var current = posts[i],
					index = posts.indexOf(current);

				index++;

				var nextPost = Posts.findOne(posts[index]._id);

				//if (index === posts.length) {
				//	e.preventDefault();
				//} else {
				//	var nextPost = Posts.findOne(posts[index]._id);
				//}
			} else {
				e.preventDefault();
			}
		}
		return nextPost;
	}
});
<|endoftext|>


<commit_before>angular.module('phoenixeye')
.controller('ImageController', ImageController);

ImageController.$inject = [
	'$scope',
	'$http',
	'$state',
	'$modal',
	'ngToast',
	'debug',
	'ImageService',
	'PollService',
	'GPSService'
];

ImageController.$name = 'ImageController';

function ImageController() {
	injectToThis(this.constructor).apply(this, arguments);

	var vm = this;

	vm.image = vm.$state.params.image;
	vm.displayedImage = vm.$state.params.image;

	vm.analyses = {
		ela: [],
		lg: [],
		avgdist: [],
		copymove: []
	};

	vm.histograms = {
		hsv: [],
		lab_fast: []
	};

	vm.displayedHSV = null;
	vm.displayedLab = null;

	vm.collapsedPanels = {};

	vm.debug('state.params', vm.$state.params);

	//poll for jobId if its a fresh submission
	if( vm.$state.params.jobId ) {
		vm.pollJob(vm.$state.params.jobId);
	}

	//poll until image metadata gathering is complete
	vm.PollService.pollUntil({
		method: 'get',
		url: 'api/images/' + vm.$state.params.permalink
	}, function (response) {
		return response.data.image.metaComplete;
	}).promise
	.then(function (response) {
		vm.debug('image poll resolved', response);
		vm.image = response.data.image;
		vm.displayedImage = vm.image;

		vm.metaList = {};

		if( vm.image.exif ) {
			vm.metaList.exif = vm.image.exif;

			if( vm.image.exif.GPSInfo ) {
				vm.gps = vm.GPSService.getCoords(vm.image.exif.GPSInfo);
			}
		}

		if( vm.image.iptc ) {
			vm.metaList.iptc = vm.image.iptc;
		}

		if( vm.image.xmp ) {
			vm.metaList.xmp = vm.image.xmp;
		}

		vm.getAnalyses(vm.image.id);
	})
	.catch(function (err) {
		vm.debug('error while polling api/images/imageId', err);
		var errString;

		if( err.status === 404 ) {
			errString = 'This image does not exist.';
		} else {
			errString = 'Something went wrong. (' + err.statusText + ')';
		}

		vm.ngToast.danger(errString);
		vm.$state.go('404');
	});
}

ImageController.prototype.pollJob = function (jobId) {
	var vm = this;

	vm.analysisPollActive = true;

	return vm.PollService.pollUntil({
		method: 'get',
		url: 'api/jobs/' + jobId
	}, function (response) {
		return response.data.job.status == 'complete';
	}).promise
	.then(function (response) {
		vm.debug('job poll resolved', response);

		vm.analysisPollActive = false;
		vm.ngToast.success('Analyses are ready!');

		return vm.getAnalyses(vm.image.id);
	});
};

ImageController.prototype.getAnalyses = function (imageId) {
	var vm = this;

	return vm.ImageService.getAnalyses(imageId)
	.spread(function (analyses, histograms) {
		vm.debug('analyses', analyses, histograms);

		vm.analyses = analyses;
		vm.histograms = histograms;

		vm.displayedHSV = histograms.hsv[0];
		vm.displayedLab = histograms.lab_fast[0];

		//get qtables for jpg after analysis complete
		if( vm.image.type == 'jpg' && Object.keys(vm.image.qtables).length == 0 ) {
			vm.$http({
				method: 'get',
				url: 'api/images/' + vm.$state.params.permalink
			})
			.then(function (response) {
				vm.image = response.data.image;
			});
		}
	})
	.catch(function (response, status) {
		vm.debug('error analyses', response, status);
	});
};

ImageController.prototype.requestAnalysis = function () {
	var vm = this;

	var modal = vm.$modal.open({
		animation: true,
		templateUrl: 'components/requestAnalysis/requestAnalysis.html',
		controller: 'RequestAnalysisController',
		controllerAs: 'vm',
		backdrop: 'static'
	});

	modal.result
	.then(function (response) {
		vm.debug('modal response', response);

		vm.pollJob(response.data.jobId);
	})
	.catch(function (err) {
		vm.debug('modal fail', err);
	});
};<commit_msg>pollService return changes<commit_after>angular.module('phoenixeye')
.controller('ImageController', ImageController);

ImageController.$inject = [
	'$scope',
	'$http',
	'$state',
	'$modal',
	'ngToast',
	'debug',
	'ImageService',
	'PollService',
	'GPSService'
];

ImageController.$name = 'ImageController';

function ImageController() {
	injectToThis(this.constructor).apply(this, arguments);

	var vm = this;

	vm.image = vm.$state.params.image;
	vm.displayedImage = vm.$state.params.image;

	vm.analyses = {
		ela: [],
		lg: [],
		avgdist: [],
		copymove: []
	};

	vm.histograms = {
		hsv: [],
		lab_fast: []
	};

	vm.displayedHSV = null;
	vm.displayedLab = null;

	vm.collapsedPanels = {};

	vm.debug('state.params', vm.$state.params);

	//poll for jobId if its a fresh submission
	if( vm.$state.params.jobId ) {
		vm.pollJob(vm.$state.params.jobId);
	}

	//poll until image metadata gathering is complete
	vm.PollService.pollUntil({
		method: 'get',
		url: 'api/images/' + vm.$state.params.permalink
	}, function (response) {
		return response.data.image.metaComplete;
	})
	.then(function (response) {
		vm.debug('image poll resolved', response);
		vm.image = response.data.image;
		vm.displayedImage = vm.image;

		vm.metaList = {};

		if( vm.image.exif ) {
			vm.metaList.exif = vm.image.exif;

			if( vm.image.exif.GPSInfo ) {
				vm.gps = vm.GPSService.getCoords(vm.image.exif.GPSInfo);
			}
		}

		if( vm.image.iptc ) {
			vm.metaList.iptc = vm.image.iptc;
		}

		if( vm.image.xmp ) {
			vm.metaList.xmp = vm.image.xmp;
		}

		vm.getAnalyses(vm.image.id);
	})
	.catch(function (err) {
		vm.debug('error while polling api/images/imageId', err);
		var errString;

		if( err.status === 404 ) {
			errString = 'This image does not exist.';
		} else {
			errString = 'Something went wrong. (' + err.statusText + ')';
		}

		vm.ngToast.danger(errString);
		vm.$state.go('404');
	});
}

ImageController.prototype.pollJob = function (jobId) {
	var vm = this;

	vm.analysisPollActive = true;

	return vm.PollService.pollUntil({
		method: 'get',
		url: 'api/jobs/' + jobId
	}, function (response) {
		return response.data.job.status == 'complete';
	})
	.then(function (response) {
		vm.debug('job poll resolved', response);

		vm.analysisPollActive = false;
		vm.ngToast.success('Analyses are ready!');

		return vm.getAnalyses(vm.image.id);
	});
};

ImageController.prototype.getAnalyses = function (imageId) {
	var vm = this;

	return vm.ImageService.getAnalyses(imageId)
	.spread(function (analyses, histograms) {
		vm.debug('analyses', analyses, histograms);

		vm.analyses = analyses;
		vm.histograms = histograms;

		vm.displayedHSV = histograms.hsv[0];
		vm.displayedLab = histograms.lab_fast[0];

		//get qtables for jpg after analysis complete
		if( vm.image.type == 'jpg' && Object.keys(vm.image.qtables).length == 0 ) {
			vm.$http({
				method: 'get',
				url: 'api/images/' + vm.$state.params.permalink
			})
			.then(function (response) {
				vm.image = response.data.image;
			});
		}
	})
	.catch(function (response, status) {
		vm.debug('error analyses', response, status);
	});
};

ImageController.prototype.requestAnalysis = function () {
	var vm = this;

	var modal = vm.$modal.open({
		animation: true,
		templateUrl: 'components/requestAnalysis/requestAnalysis.html',
		controller: 'RequestAnalysisController',
		controllerAs: 'vm',
		backdrop: 'static'
	});

	modal.result
	.then(function (response) {
		vm.debug('modal response', response);

		vm.pollJob(response.data.jobId);
	})
	.catch(function (err) {
		vm.debug('modal fail', err);
	});
};<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// Library Control Panel
//
// Encloses controls that have to do with libraries:
// - library switcher
// - root folder adder
////////////////////////////////////////////////////////////////////////////////
/*global jQuery */
var app = app || {};

app.controls = function (controls, $, services) {
	controls.library = function () {
		var self = controls.control.create(),
				dropdown = controls.dropdown(),
				busy = false;

		//////////////////////////////
		// Getters, setters

		self.dropdown = function () {
			return dropdown;
		};

		self.name = function () {
			return dropdown.caption();
		};

		self.busy = function (value) {
			busy = value;
			return self;
		};

		//////////////////////////////
		// Overrides

		self.build = function () {
			controls.rootadd
				.appendTo(self);

			dropdown
				.popup(controls.libsel)
				.appendTo(self);

			return self;
		};

		self.init = function (elem) {
			// setting state
			if (busy || self.disabled()) {
				elem.find('button')
					.prop('disabled', true);
			} else {
				elem.find('button')
					.prop('disabled', false);
			}

			if (busy) {
				elem.find('.spinner')
					.show();
			} else {
				elem.find('.spinner')
					.hide();
			}
		};

		self.html = function () {
			return [
				'',
				'Library:',
				dropdown.html(),
				controls.rootadd.html(),
				'',
				''
			].join('');
		};

		return self;
	}();

	return controls;
}(app.controls || {},
	jQuery,
	app.services);

<commit_msg>hints for library dropdown<commit_after>////////////////////////////////////////////////////////////////////////////////
// Library Control Panel
//
// Encloses controls that have to do with libraries:
// - library switcher
// - root folder adder
////////////////////////////////////////////////////////////////////////////////
/*global jQuery */
var app = app || {};

app.controls = function (controls, $, services) {
	var hints = [
		"Save a backup copy of your library before extensive changes.",
		"Delete a library by deleting its database file."
	];

	controls.library = function () {
		var self = controls.control.create(),
				dropdown = controls.dropdown(),
				busy = false;

		//////////////////////////////
		// Initialization

		dropdown.hints = hints;

		//////////////////////////////
		// Getters, setters

		self.dropdown = function () {
			return dropdown;
		};

		self.name = function () {
			return dropdown.caption();
		};

		self.busy = function (value) {
			busy = value;
			return self;
		};

		//////////////////////////////
		// Overrides

		self.build = function () {
			controls.rootadd
				.appendTo(self);

			dropdown
				.popup(controls.libsel)
				.appendTo(self);

			return self;
		};

		self.init = function (elem) {
			// setting state
			if (busy || self.disabled()) {
				elem.find('button')
					.prop('disabled', true);
			} else {
				elem.find('button')
					.prop('disabled', false);
			}

			if (busy) {
				elem.find('.spinner')
					.show();
			} else {
				elem.find('.spinner')
					.hide();
			}
		};

		self.html = function () {
			return [
				'',
				'Library:',
				dropdown.html(),
				controls.rootadd.html(),
				'',
				''
			].join('');
		};

		return self;
	}();

	return controls;
}(app.controls || {},
	jQuery,
	app.services);

<|endoftext|>


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

/**
 * @fileoverview Closure user agent detection (Browser).
 * @see User agent strings
 * For more information on rendering engine, platform, or device see the other
 * sub-namespaces in goog.labs.userAgent, goog.labs.userAgent.platform,
 * goog.labs.userAgent.device respectively.)
 *
 */

goog.provide('goog.labs.userAgent.browser');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.labs.userAgent.util');
goog.require('goog.string');

/**
 * @return {boolean} Whether the user's browser is Opera.
 * @private
 */
goog.labs.userAgent.browser.matchOpera_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Opera') ||
      goog.labs.userAgent.util.matchUserAgent('OPR');
};

/**
 * @return {boolean} Whether the user's browser is IE.
 * @private
 */
goog.labs.userAgent.browser.matchIE_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Trident') ||
      goog.labs.userAgent.util.matchUserAgent('MSIE');
};

/**
 * @return {boolean} Whether the user's browser is Firefox.
 * @private
 */
goog.labs.userAgent.browser.matchFirefox_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Firefox');
};

/**
 * @return {boolean} Whether the user's browser is Safari.
 * @private
 */
goog.labs.userAgent.browser.matchSafari_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Safari') &&
      !goog.labs.userAgent.util.matchUserAgent('Chrome') &&
      !goog.labs.userAgent.util.matchUserAgent('CriOS') &&
      !goog.labs.userAgent.util.matchUserAgent('Android');
};

/**
 * @return {boolean} Whether the user's browser is Chrome.
 * @private
 */
goog.labs.userAgent.browser.matchChrome_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Chrome') ||
      goog.labs.userAgent.util.matchUserAgent('CriOS');
};

/**
 * @return {boolean} Whether the user's browser is the Android browser.
 * @private
 */
goog.labs.userAgent.browser.matchAndroidBrowser_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Android') &&
      !goog.labs.userAgent.util.matchUserAgent('Chrome') &&
      !goog.labs.userAgent.util.matchUserAgent('CriOS');
};

/**
 * @return {boolean} Whether the user's browser is Opera.
 */
goog.labs.userAgent.browser.isOpera = goog.labs.userAgent.browser.matchOpera_;

/**
 * @return {boolean} Whether the user's browser is IE.
 */
goog.labs.userAgent.browser.isIE = goog.labs.userAgent.browser.matchIE_;

/**
 * @return {boolean} Whether the user's browser is Firefox.
 */
goog.labs.userAgent.browser.isFirefox =
    goog.labs.userAgent.browser.matchFirefox_;

/**
 * @return {boolean} Whether the user's browser is Safari.
 */
goog.labs.userAgent.browser.isSafari =
    goog.labs.userAgent.browser.matchSafari_;

/**
 * @return {boolean} Whether the user's browser is Chrome.
 */
goog.labs.userAgent.browser.isChrome =
    goog.labs.userAgent.browser.matchChrome_;

/**
 * @return {boolean} Whether the user's browser is the Android browser.
 */
goog.labs.userAgent.browser.isAndroidBrowser =
    goog.labs.userAgent.browser.matchAndroidBrowser_;

/**
 * For more information, see:
 * http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
 * @return {boolean} Whether the user's browser is Silk.
 */
goog.labs.userAgent.browser.isSilk = function() {
  return goog.labs.userAgent.util.matchUserAgent('Silk');
};

/**
 * @return {string} The browser version or empty string if version cannot be
 *     determined. Note that for Internet Explorer, this returns the version of
 *     the browser, not the version of the rendering engine. (IE 8 in
 *     compatibility mode will return 8.0 rather than 7.0. To determine the
 *     rendering engine version, look at document.documentMode instead. See
 *     http://msdn.microsoft.com/en-us/library/cc196988(v=vs.85).aspx for more
 *     details.)
 */
goog.labs.userAgent.browser.getVersion = function() {
  var userAgentString = goog.labs.userAgent.util.getUserAgent();
  // Special case IE since IE's version is inside the parenthesis and
  // without the '/'.
  if (goog.labs.userAgent.browser.isIE()) {
    return goog.labs.userAgent.browser.getIEVersion_(userAgentString);
  }

  if (goog.labs.userAgent.browser.isOpera()) {
    return goog.labs.userAgent.browser.getOperaVersion_(userAgentString);
  }

  var versionTuples =
      goog.labs.userAgent.util.extractVersionTuples(userAgentString);
  return goog.labs.userAgent.browser.getVersionFromTuples_(versionTuples);
};

/**
 * @param {string|number} version The version to check.
 * @return {boolean} Whether the browser version is higher or the same as the
 *     given version.
 */
goog.labs.userAgent.browser.isVersionOrHigher = function(version) {
  return goog.string.compareVersions(goog.labs.userAgent.browser.getVersion(),
                                     version) >= 0;
};

/**
 * Determines IE version. More information:
 * http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx#uaString
 * http://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
 * http://blogs.msdn.com/b/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx
 * http://blogs.msdn.com/b/ie/archive/2009/01/09/the-internet-explorer-8-user-agent-string-updated-edition.aspx
 *
 * @param {string} userAgent the User-Agent.
 * @return {string}
 * @private
 */
goog.labs.userAgent.browser.getIEVersion_ = function(userAgent) {
  var version = '';
  var arr = /\b(?:MSIE|rv)[: ]([^\);]+)(?:\)|;)/.exec(userAgent);
  if (arr && arr[1]) {
    if (arr[1] == '7.0') {
      // IE in compatibility mode identifies itself as MSIE 7.0. Here we use the
      // Trident version to determine the version of IE. For more details, see
      // the links above.
      var tridentVersion = /Trident\/(\d.\d)/.exec(userAgent);
      if (tridentVersion && tridentVersion[1]) {
        switch (tridentVersion[1]) {
          case '4.0':
            version = '8.0';
            break;
          case '5.0':
            version = '9.0';
            break;
          case '6.0':
            version = '10.0';
            break;
        }
      } else {
        version = '7.0';
      }
    } else {
      version = arr[1];
    }
  }
  return version;
};

/**
 * Determines Opera version. More information:
 * http://my.opera.com/ODIN/blog/2013/07/15/opera-user-agent-strings-opera-15-and-beyond
 *
 * @param {string} userAgent The User-Agent.
 * @return {string}
 * @private
 */
goog.labs.userAgent.browser.getOperaVersion_ = function(userAgent) {
  var versionTuples =
      goog.labs.userAgent.util.extractVersionTuples(userAgent);
  var lastTuple = goog.array.peek(versionTuples);
  if (lastTuple[0] == 'OPR' && lastTuple[1]) {
    return lastTuple[1];
  }

  return goog.labs.userAgent.browser.getVersionFromTuples_(versionTuples);
};

/**
 * Nearly all User-Agents start with Mozilla/N.0. This looks at the second tuple
 * for the actual browser version number.
 * @param {!Array.<!Array.<string>>} versionTuples
 * @return {string} The version or empty string if it cannot be determined.
 * @private
 */
goog.labs.userAgent.browser.getVersionFromTuples_ = function(versionTuples) {
  // versionTuples[2] (The first X/Y tuple after the parenthesis) contains the
  // browser version number.
  goog.asserts.assert(versionTuples.length > 2,
      'Couldn\'t extract version tuple from user agent string');
  return versionTuples[2] && versionTuples[2][1] ? versionTuples[2][1] : '';
};
<commit_msg>Fix IE11 detection. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=55755063<commit_after>// Copyright 2013 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Closure user agent detection (Browser).
 * @see User agent strings
 * For more information on rendering engine, platform, or device see the other
 * sub-namespaces in goog.labs.userAgent, goog.labs.userAgent.platform,
 * goog.labs.userAgent.device respectively.)
 *
 */

goog.provide('goog.labs.userAgent.browser');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.labs.userAgent.util');
goog.require('goog.string');

/**
 * @return {boolean} Whether the user's browser is Opera.
 * @private
 */
goog.labs.userAgent.browser.matchOpera_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Opera') ||
      goog.labs.userAgent.util.matchUserAgent('OPR');
};

/**
 * @return {boolean} Whether the user's browser is IE.
 * @private
 */
goog.labs.userAgent.browser.matchIE_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Trident') ||
      goog.labs.userAgent.util.matchUserAgent('MSIE');
};

/**
 * @return {boolean} Whether the user's browser is Firefox.
 * @private
 */
goog.labs.userAgent.browser.matchFirefox_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Firefox');
};

/**
 * @return {boolean} Whether the user's browser is Safari.
 * @private
 */
goog.labs.userAgent.browser.matchSafari_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Safari') &&
      !goog.labs.userAgent.util.matchUserAgent('Chrome') &&
      !goog.labs.userAgent.util.matchUserAgent('CriOS') &&
      !goog.labs.userAgent.util.matchUserAgent('Android');
};

/**
 * @return {boolean} Whether the user's browser is Chrome.
 * @private
 */
goog.labs.userAgent.browser.matchChrome_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Chrome') ||
      goog.labs.userAgent.util.matchUserAgent('CriOS');
};

/**
 * @return {boolean} Whether the user's browser is the Android browser.
 * @private
 */
goog.labs.userAgent.browser.matchAndroidBrowser_ = function() {
  return goog.labs.userAgent.util.matchUserAgent('Android') &&
      !goog.labs.userAgent.util.matchUserAgent('Chrome') &&
      !goog.labs.userAgent.util.matchUserAgent('CriOS');
};

/**
 * @return {boolean} Whether the user's browser is Opera.
 */
goog.labs.userAgent.browser.isOpera = goog.labs.userAgent.browser.matchOpera_;

/**
 * @return {boolean} Whether the user's browser is IE.
 */
goog.labs.userAgent.browser.isIE = goog.labs.userAgent.browser.matchIE_;

/**
 * @return {boolean} Whether the user's browser is Firefox.
 */
goog.labs.userAgent.browser.isFirefox =
    goog.labs.userAgent.browser.matchFirefox_;

/**
 * @return {boolean} Whether the user's browser is Safari.
 */
goog.labs.userAgent.browser.isSafari =
    goog.labs.userAgent.browser.matchSafari_;

/**
 * @return {boolean} Whether the user's browser is Chrome.
 */
goog.labs.userAgent.browser.isChrome =
    goog.labs.userAgent.browser.matchChrome_;

/**
 * @return {boolean} Whether the user's browser is the Android browser.
 */
goog.labs.userAgent.browser.isAndroidBrowser =
    goog.labs.userAgent.browser.matchAndroidBrowser_;

/**
 * For more information, see:
 * http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
 * @return {boolean} Whether the user's browser is Silk.
 */
goog.labs.userAgent.browser.isSilk = function() {
  return goog.labs.userAgent.util.matchUserAgent('Silk');
};

/**
 * @return {string} The browser version or empty string if version cannot be
 *     determined. Note that for Internet Explorer, this returns the version of
 *     the browser, not the version of the rendering engine. (IE 8 in
 *     compatibility mode will return 8.0 rather than 7.0. To determine the
 *     rendering engine version, look at document.documentMode instead. See
 *     http://msdn.microsoft.com/en-us/library/cc196988(v=vs.85).aspx for more
 *     details.)
 */
goog.labs.userAgent.browser.getVersion = function() {
  var userAgentString = goog.labs.userAgent.util.getUserAgent();
  // Special case IE since IE's version is inside the parenthesis and
  // without the '/'.
  if (goog.labs.userAgent.browser.isIE()) {
    return goog.labs.userAgent.browser.getIEVersion_(userAgentString);
  }

  if (goog.labs.userAgent.browser.isOpera()) {
    return goog.labs.userAgent.browser.getOperaVersion_(userAgentString);
  }

  var versionTuples =
      goog.labs.userAgent.util.extractVersionTuples(userAgentString);
  return goog.labs.userAgent.browser.getVersionFromTuples_(versionTuples);
};

/**
 * @param {string|number} version The version to check.
 * @return {boolean} Whether the browser version is higher or the same as the
 *     given version.
 */
goog.labs.userAgent.browser.isVersionOrHigher = function(version) {
  return goog.string.compareVersions(goog.labs.userAgent.browser.getVersion(),
                                     version) >= 0;
};

/**
 * Determines IE version. More information:
 * http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx#uaString
 * http://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
 * http://blogs.msdn.com/b/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx
 * http://blogs.msdn.com/b/ie/archive/2009/01/09/the-internet-explorer-8-user-agent-string-updated-edition.aspx
 *
 * @param {string} userAgent the User-Agent.
 * @return {string}
 * @private
 */
goog.labs.userAgent.browser.getIEVersion_ = function(userAgent) {
  var version = '';
  var arr = /\b(?:MSIE|rv)[: ]([^\);]+)(?:\)|;)/.exec(userAgent);
  if (arr && arr[1]) {
    if (arr[1] == '7.0') {
      // IE in compatibility mode identifies itself as MSIE 7.0. Here we use the
      // Trident version to determine the version of IE. For more details, see
      // the links above.
      var tridentVersion = /Trident\/(\d.\d)/.exec(userAgent);
      if (tridentVersion && tridentVersion[1]) {
        switch (tridentVersion[1]) {
          case '4.0':
            version = '8.0';
            break;
          case '5.0':
            version = '9.0';
            break;
          case '6.0':
            version = '10.0';
            break;
          case '7.0':
            version = '11.0';
            break;
        }
      } else {
        version = '7.0';
      }
    } else {
      version = arr[1];
    }
  }
  return version;
};

/**
 * Determines Opera version. More information:
 * http://my.opera.com/ODIN/blog/2013/07/15/opera-user-agent-strings-opera-15-and-beyond
 *
 * @param {string} userAgent The User-Agent.
 * @return {string}
 * @private
 */
goog.labs.userAgent.browser.getOperaVersion_ = function(userAgent) {
  var versionTuples =
      goog.labs.userAgent.util.extractVersionTuples(userAgent);
  var lastTuple = goog.array.peek(versionTuples);
  if (lastTuple[0] == 'OPR' && lastTuple[1]) {
    return lastTuple[1];
  }

  return goog.labs.userAgent.browser.getVersionFromTuples_(versionTuples);
};

/**
 * Nearly all User-Agents start with Mozilla/N.0. This looks at the second tuple
 * for the actual browser version number.
 * @param {!Array.<!Array.<string>>} versionTuples
 * @return {string} The version or empty string if it cannot be determined.
 * @private
 */
goog.labs.userAgent.browser.getVersionFromTuples_ = function(versionTuples) {
  // versionTuples[2] (The first X/Y tuple after the parenthesis) contains the
  // browser version number.
  goog.asserts.assert(versionTuples.length > 2,
      'Couldn\'t extract version tuple from user agent string');
  return versionTuples[2] && versionTuples[2][1] ? versionTuples[2][1] : '';
};
<|endoftext|>


<commit_before>import { Utils } from './utils';
import { Crypto } from './crypto';
import { Secret } from './secret';
// eslint-disable-next-line import/no-cycle
import { URI } from './uri';

/**
 * Default configuration.
 * @private
 * @type {Object}
 */
const defaults = {
	issuer: '',
	label: 'OTPAuth',
	algorithm: 'SHA1',
	digits: 6,
	counter: 0,
	period: 30,
	window: 50
};

/**
 * HOTP: An HMAC-based One-time Password Algorithm (RFC 4226).
 * @see https://tools.ietf.org/html/rfc4226
 */
export class HOTP {
	/**
	 * @param {Object} [config] Configuration options.
	 * @param {string} [config.issuer=''] Account provider.
	 * @param {string} [config.label='OTPAuth'] Account label.
	 * @param {Secret} [config.secret=Secret] Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.digits=6] Token length.
	 * @param {number} [config.counter=0] Initial counter value.
	 */
	constructor({
		issuer = defaults.issuer,
		label = defaults.label,
		secret = new Secret(),
		algorithm = defaults.algorithm,
		digits = defaults.digits,
		counter = defaults.counter
	} = {}) {
		/**
		 * Account provider.
		 * @type {string}
		 */
		this.issuer = issuer;
		/**
		 * Account label.
		 * @type {string}
		 */
		this.label = label;
		/**
		 * Secret key.
		 * @type {Secret}
		 */
		this.secret = secret;
		/**
		 * HMAC hashing algorithm.
		 * @type {string}
		 */
		this.algorithm = algorithm;
		/**
		 * Token length.
		 * @type {number}
		 */
		this.digits = digits;
		/**
		 * Initial counter value.
		 * @type {number}
		 */
		this.counter = counter;
	}

	/**
	 * Generates an HOTP token.
	 * @param {Object} config Configuration options.
	 * @param {Secret} config.secret Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.digits=6] Token length.
	 * @param {number} [config.counter=0] Counter value.
	 * @returns {string} Token.
	 */
	static generate({
		secret,
		algorithm = defaults.algorithm,
		digits = defaults.digits,
		counter = defaults.counter
	}) {
		const digest = new Uint8Array(Crypto.hmacDigest(algorithm, secret.buffer, Utils.uint.encode(counter)));
		const offset = digest[digest.byteLength - 1] & 15;
		const otp = (
			((digest[offset] & 127) << 24)
			| ((digest[offset + 1] & 255) << 16)
			| ((digest[offset + 2] & 255) << 8)
			| (digest[offset + 3] & 255)
		) % (10 ** digits);

		return Utils.pad(otp, digits);
	}

	/**
	 * Generates an HOTP token.
	 * @param {Object} [config] Configuration options.
	 * @param {number} [config.counter=this.counter++] Counter value.
	 * @returns {string} Token.
	 */
	generate({
		counter = this.counter++
	} = {}) {
		return HOTP.generate({
			secret: this.secret,
			algorithm: this.algorithm,
			digits: this.digits,
			counter
		});
	}

	/**
	 * Validates an HOTP token.
	 * @param {Object} config Configuration options.
	 * @param {string} config.token Token value.
	 * @param {Secret} config.secret Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.counter=0] Counter value.
	 * @param {number} [config.window=50] Window of counter values to test.
	 * @returns {number|null} Token delta, or null if the token is not found.
	 */
	static validate({
		token,
		secret,
		algorithm,
		counter = defaults.counter,
		window = defaults.window
	}) {
		for (let i = counter - window; i <= counter + window; ++i) {
			const generatedToken = HOTP.generate({
				secret,
				algorithm,
				digits: token.length,
				counter: i
			});

			if (token === generatedToken) {
				return i - counter;
			}
		}

		return null;
	}

	/**
	 * Validates an HOTP token.
	 * @param {Object} config Configuration options.
	 * @param {string} config.token Token value.
	 * @param {number} [config.counter=this.counter] Counter value.
	 * @param {number} [config.window=50] Window of counter values to test.
	 * @returns {number|null} Token delta, or null if the token is not found.
	 */
	validate({
		token,
		counter = this.counter,
		window
	}) {
		return HOTP.validate({
			token: Utils.pad(token, this.digits),
			secret: this.secret,
			algorithm: this.algorithm,
			counter,
			window
		});
	}

	/**
	 * Returns a Google Authenticator key URI.
	 * @returns {string} URI.
	 */
	toString() {
		return URI.stringify(this);
	}
}

/**
 * TOTP: Time-Based One-Time Password Algorithm (RFC 6238).
 * @see https://tools.ietf.org/html/rfc6238
 */
export class TOTP {
	/**
	 * @param {Object} [config] Configuration options.
	 * @param {string} [config.issuer=''] Account provider.
	 * @param {string} [config.label='OTPAuth'] Account label.
	 * @param {Secret} [config.secret=Secret] Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.digits=6] Token length.
	 * @param {number} [config.period=30] Token time-step duration.
	 */
	constructor({
		issuer = defaults.issuer,
		label = defaults.label,
		secret = new Secret(),
		algorithm = defaults.algorithm,
		digits = defaults.digits,
		period = defaults.period
	} = {}) {
		/**
		 * Account provider.
		 * @type {string}
		 */
		this.issuer = issuer;
		/**
		 * Account label.
		 * @type {string}
		 */
		this.label = label;
		/**
		 * Secret key.
		 * @type {string}
		 */
		this.secret = secret;
		/**
		 * HMAC hashing algorithm.
		 * @type {Secret}
		 */
		this.algorithm = algorithm;
		/**
		 * Token length.
		 * @type {number}
		 */
		this.digits = digits;
		/**
		 * Token time-step duration.
		 * @type {number}
		 */
		this.period = period;
	}

	/**
	 * Generates a TOTP token.
	 * @param {Object} config Configuration options.
	 * @param {Secret} config.secret Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.digits=6] Token length.
	 * @param {number} [config.period=30] Token time-step duration.
	 * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
	 * @returns {string} Token.
	 */
	static generate({
		secret,
		algorithm,
		digits,
		period = defaults.period,
		timestamp = Date.now()
	}) {
		return HOTP.generate({
			secret,
			algorithm,
			digits,
			counter: Math.floor(timestamp / 1000 / period)
		});
	}

	/**
	 * Generates a TOTP token.
	 * @param {Object} [config] Configuration options.
	 * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
	 * @returns {string} Token.
	 */
	generate({
		timestamp = Date.now()
	} = {}) {
		return TOTP.generate({
			secret: this.secret,
			algorithm: this.algorithm,
			digits: this.digits,
			period: this.period,
			timestamp
		});
	}

	/**
	 * Validates a TOTP token.
	 * @param {Object} config Configuration options.
	 * @param {string} config.token Token value.
	 * @param {Secret} config.secret Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.period=30] Token time-step duration.
	 * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
	 * @param {number} [config.window=50] Window of counter values to test.
	 * @returns {number|null} Token delta, or null if the token is not found.
	 */
	static validate({
		token,
		secret,
		algorithm,
		period = defaults.period,
		timestamp = Date.now(),
		window
	}) {
		return HOTP.validate({
			token,
			secret,
			algorithm,
			counter: Math.floor(timestamp / 1000 / period),
			window
		});
	}

	/**
	 * Validates a TOTP token.
	 * @param {Object} config Configuration options.
	 * @param {string} config.token Token value.
	 * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
	 * @param {number} [config.window=50] Window of counter values to test.
	 * @returns {number|null} Token delta, or null if the token is not found.
	 */
	validate({
		token,
		timestamp,
		window
	}) {
		return TOTP.validate({
			token: Utils.pad(token, this.digits),
			secret: this.secret,
			algorithm: this.algorithm,
			period: this.period,
			timestamp,
			window
		});
	}

	/**
	 * Returns a Google Authenticator key URI.
	 * @returns {string} URI.
	 */
	toString() {
		return URI.stringify(this);
	}
}
<commit_msg>Wrong type in JSDoc<commit_after>import { Utils } from './utils';
import { Crypto } from './crypto';
import { Secret } from './secret';
// eslint-disable-next-line import/no-cycle
import { URI } from './uri';

/**
 * Default configuration.
 * @private
 * @type {Object}
 */
const defaults = {
	issuer: '',
	label: 'OTPAuth',
	algorithm: 'SHA1',
	digits: 6,
	counter: 0,
	period: 30,
	window: 50
};

/**
 * HOTP: An HMAC-based One-time Password Algorithm (RFC 4226).
 * @see https://tools.ietf.org/html/rfc4226
 */
export class HOTP {
	/**
	 * @param {Object} [config] Configuration options.
	 * @param {string} [config.issuer=''] Account provider.
	 * @param {string} [config.label='OTPAuth'] Account label.
	 * @param {Secret} [config.secret=Secret] Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.digits=6] Token length.
	 * @param {number} [config.counter=0] Initial counter value.
	 */
	constructor({
		issuer = defaults.issuer,
		label = defaults.label,
		secret = new Secret(),
		algorithm = defaults.algorithm,
		digits = defaults.digits,
		counter = defaults.counter
	} = {}) {
		/**
		 * Account provider.
		 * @type {string}
		 */
		this.issuer = issuer;
		/**
		 * Account label.
		 * @type {string}
		 */
		this.label = label;
		/**
		 * Secret key.
		 * @type {Secret}
		 */
		this.secret = secret;
		/**
		 * HMAC hashing algorithm.
		 * @type {string}
		 */
		this.algorithm = algorithm;
		/**
		 * Token length.
		 * @type {number}
		 */
		this.digits = digits;
		/**
		 * Initial counter value.
		 * @type {number}
		 */
		this.counter = counter;
	}

	/**
	 * Generates an HOTP token.
	 * @param {Object} config Configuration options.
	 * @param {Secret} config.secret Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.digits=6] Token length.
	 * @param {number} [config.counter=0] Counter value.
	 * @returns {string} Token.
	 */
	static generate({
		secret,
		algorithm = defaults.algorithm,
		digits = defaults.digits,
		counter = defaults.counter
	}) {
		const digest = new Uint8Array(Crypto.hmacDigest(algorithm, secret.buffer, Utils.uint.encode(counter)));
		const offset = digest[digest.byteLength - 1] & 15;
		const otp = (
			((digest[offset] & 127) << 24)
			| ((digest[offset + 1] & 255) << 16)
			| ((digest[offset + 2] & 255) << 8)
			| (digest[offset + 3] & 255)
		) % (10 ** digits);

		return Utils.pad(otp, digits);
	}

	/**
	 * Generates an HOTP token.
	 * @param {Object} [config] Configuration options.
	 * @param {number} [config.counter=this.counter++] Counter value.
	 * @returns {string} Token.
	 */
	generate({
		counter = this.counter++
	} = {}) {
		return HOTP.generate({
			secret: this.secret,
			algorithm: this.algorithm,
			digits: this.digits,
			counter
		});
	}

	/**
	 * Validates an HOTP token.
	 * @param {Object} config Configuration options.
	 * @param {string} config.token Token value.
	 * @param {Secret} config.secret Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.counter=0] Counter value.
	 * @param {number} [config.window=50] Window of counter values to test.
	 * @returns {number|null} Token delta, or null if the token is not found.
	 */
	static validate({
		token,
		secret,
		algorithm,
		counter = defaults.counter,
		window = defaults.window
	}) {
		for (let i = counter - window; i <= counter + window; ++i) {
			const generatedToken = HOTP.generate({
				secret,
				algorithm,
				digits: token.length,
				counter: i
			});

			if (token === generatedToken) {
				return i - counter;
			}
		}

		return null;
	}

	/**
	 * Validates an HOTP token.
	 * @param {Object} config Configuration options.
	 * @param {string} config.token Token value.
	 * @param {number} [config.counter=this.counter] Counter value.
	 * @param {number} [config.window=50] Window of counter values to test.
	 * @returns {number|null} Token delta, or null if the token is not found.
	 */
	validate({
		token,
		counter = this.counter,
		window
	}) {
		return HOTP.validate({
			token: Utils.pad(token, this.digits),
			secret: this.secret,
			algorithm: this.algorithm,
			counter,
			window
		});
	}

	/**
	 * Returns a Google Authenticator key URI.
	 * @returns {string} URI.
	 */
	toString() {
		return URI.stringify(this);
	}
}

/**
 * TOTP: Time-Based One-Time Password Algorithm (RFC 6238).
 * @see https://tools.ietf.org/html/rfc6238
 */
export class TOTP {
	/**
	 * @param {Object} [config] Configuration options.
	 * @param {string} [config.issuer=''] Account provider.
	 * @param {string} [config.label='OTPAuth'] Account label.
	 * @param {Secret} [config.secret=Secret] Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.digits=6] Token length.
	 * @param {number} [config.period=30] Token time-step duration.
	 */
	constructor({
		issuer = defaults.issuer,
		label = defaults.label,
		secret = new Secret(),
		algorithm = defaults.algorithm,
		digits = defaults.digits,
		period = defaults.period
	} = {}) {
		/**
		 * Account provider.
		 * @type {string}
		 */
		this.issuer = issuer;
		/**
		 * Account label.
		 * @type {string}
		 */
		this.label = label;
		/**
		 * Secret key.
		 * @type {Secret}
		 */
		this.secret = secret;
		/**
		 * HMAC hashing algorithm.
		 * @type {string}
		 */
		this.algorithm = algorithm;
		/**
		 * Token length.
		 * @type {number}
		 */
		this.digits = digits;
		/**
		 * Token time-step duration.
		 * @type {number}
		 */
		this.period = period;
	}

	/**
	 * Generates a TOTP token.
	 * @param {Object} config Configuration options.
	 * @param {Secret} config.secret Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.digits=6] Token length.
	 * @param {number} [config.period=30] Token time-step duration.
	 * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
	 * @returns {string} Token.
	 */
	static generate({
		secret,
		algorithm,
		digits,
		period = defaults.period,
		timestamp = Date.now()
	}) {
		return HOTP.generate({
			secret,
			algorithm,
			digits,
			counter: Math.floor(timestamp / 1000 / period)
		});
	}

	/**
	 * Generates a TOTP token.
	 * @param {Object} [config] Configuration options.
	 * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
	 * @returns {string} Token.
	 */
	generate({
		timestamp = Date.now()
	} = {}) {
		return TOTP.generate({
			secret: this.secret,
			algorithm: this.algorithm,
			digits: this.digits,
			period: this.period,
			timestamp
		});
	}

	/**
	 * Validates a TOTP token.
	 * @param {Object} config Configuration options.
	 * @param {string} config.token Token value.
	 * @param {Secret} config.secret Secret key.
	 * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
	 * @param {number} [config.period=30] Token time-step duration.
	 * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
	 * @param {number} [config.window=50] Window of counter values to test.
	 * @returns {number|null} Token delta, or null if the token is not found.
	 */
	static validate({
		token,
		secret,
		algorithm,
		period = defaults.period,
		timestamp = Date.now(),
		window
	}) {
		return HOTP.validate({
			token,
			secret,
			algorithm,
			counter: Math.floor(timestamp / 1000 / period),
			window
		});
	}

	/**
	 * Validates a TOTP token.
	 * @param {Object} config Configuration options.
	 * @param {string} config.token Token value.
	 * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
	 * @param {number} [config.window=50] Window of counter values to test.
	 * @returns {number|null} Token delta, or null if the token is not found.
	 */
	validate({
		token,
		timestamp,
		window
	}) {
		return TOTP.validate({
			token: Utils.pad(token, this.digits),
			secret: this.secret,
			algorithm: this.algorithm,
			period: this.period,
			timestamp,
			window
		});
	}

	/**
	 * Returns a Google Authenticator key URI.
	 * @returns {string} URI.
	 */
	toString() {
		return URI.stringify(this);
	}
}
<|endoftext|>


<commit_before>"use strict";

const normalizeNewline = require("normalize-newline");
const normalizePath = require("normalize-path");
const path = require("path");

module.exports = normalizeTestRoot;

// tempy creates subdirectories with hexadecimal names that are 32 characters long
const TEMP_DIR_REGEXP = /([^\s"]*[\\/][0-9a-f]{32})([^\s"]*)/g;
// the excluded quotes are due to other snapshot serializers mutating the raw input

function normalizeTestRoot(str) {
  return normalizeNewline(str).replace(TEMP_DIR_REGEXP, serializeTestRoot);
}

function serializeTestRoot(match, cwd, subPath) {
  return normalizePath(path.join("__TEST_ROOTDIR__", subPath));
}
<commit_msg>chore: flailing around trying avoid 'no visual difference' snapshot garbage on Windows<commit_after>"use strict";

const normalizeNewline = require("normalize-newline");
const normalizePath = require("normalize-path");
const path = require("path");

module.exports = normalizeTestRoot;

// tempy creates subdirectories with hexadecimal names that are 32 characters long
const TEMP_DIR_REGEXP = /([^\s"]*[\\/][0-9a-f]{32})([^\s"]*)/g;
// the excluded quotes are due to other snapshot serializers mutating the raw input

function normalizeTestRoot(str) {
  const ret = normalizeNewline(str).replace(TEMP_DIR_REGEXP, serializeTestRoot);

  // desperately trying to avoid "Compared values have no visual difference" garbage in Windows CI
  return JSON.parse(JSON.stringify(ret));
}

function serializeTestRoot(match, cwd, subPath) {
  return normalizePath(path.join("__TEST_ROOTDIR__", subPath));
}
<|endoftext|>


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

// eslint-disable-next-line max-len
/** @typedef {import("./display/api").PDFDocumentLoadingTask} PDFDocumentLoadingTask */
/** @typedef {import("./display/api").PDFDocumentProxy} PDFDocumentProxy */
/** @typedef {import("./display/api").PDFPageProxy} PDFPageProxy */
/** @typedef {import("./display/api").RenderTask} RenderTask */
/** @typedef {import("./display/display_utils").PageViewport} PageViewport */
// eslint-disable-next-line max-len
/** @typedef {import("./display/text_layer").TextLayerRenderTask} TextLayerRenderTask */

import {
  AnnotationEditorParamsType,
  AnnotationEditorType,
  AnnotationMode,
  CMapCompressionType,
  createPromiseCapability,
  createValidAbsoluteUrl,
  InvalidPDFException,
  MissingPDFException,
  OPS,
  PasswordResponses,
  PermissionFlag,
  shadow,
  UnexpectedResponseException,
  UNSUPPORTED_FEATURES,
  Util,
  VerbosityLevel,
} from "./shared/util.js";
import {
  build,
  getDocument,
  LoopbackPort,
  PDFDataRangeTransport,
  PDFWorker,
  setPDFNetworkStreamFactory,
  version,
} from "./display/api.js";
import {
  getFilenameFromUrl,
  getPdfFilenameFromUrl,
  getXfaPageViewport,
  isPdfFile,
  isValidFetchUrl,
  loadScript,
  PDFDateString,
  PixelsPerInch,
  RenderingCancelledException,
} from "./display/display_utils.js";
import { AnnotationEditorLayer } from "./display/editor/annotation_editor_layer.js";
import { AnnotationEditorUIManager } from "./display/editor/tools.js";
import { AnnotationLayer } from "./display/annotation_layer.js";
import { GlobalWorkerOptions } from "./display/worker_options.js";
import { isNodeJS } from "./shared/is_node.js";
import { renderTextLayer } from "./display/text_layer.js";
import { SVGGraphics } from "./display/svg.js";
import { XfaLayer } from "./display/xfa_layer.js";

/* eslint-disable-next-line no-unused-vars */
const pdfjsVersion =
  typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_VERSION") : void 0;
/* eslint-disable-next-line no-unused-vars */
const pdfjsBuild =
  typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0;

if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")) {
  const streamsPromise = Promise.all([
    import("pdfjs/display/network.js"),
    import("pdfjs/display/fetch_stream.js"),
  ]);

  setPDFNetworkStreamFactory(async params => {
    const [{ PDFNetworkStream }, { PDFFetchStream }] = await streamsPromise;
    if (isValidFetchUrl(params.url)) {
      return new PDFFetchStream(params);
    }
    return new PDFNetworkStream(params);
  });
} else if (PDFJSDev.test("GENERIC || CHROME")) {
  if (PDFJSDev.test("GENERIC") && isNodeJS) {
    const { PDFNodeStream } = require("./display/node_stream.js");

    setPDFNetworkStreamFactory(params => {
      return new PDFNodeStream(params);
    });
  } else {
    const { PDFNetworkStream } = require("./display/network.js");
    const { PDFFetchStream } = require("./display/fetch_stream.js");

    setPDFNetworkStreamFactory(params => {
      if (isValidFetchUrl(params.url)) {
        return new PDFFetchStream(params);
      }
      return new PDFNetworkStream(params);
    });
  }
}

export {
  AnnotationEditorLayer,
  AnnotationEditorParamsType,
  AnnotationEditorType,
  AnnotationEditorUIManager,
  AnnotationLayer,
  AnnotationMode,
  build,
  CMapCompressionType,
  createPromiseCapability,
  createValidAbsoluteUrl,
  getDocument,
  getFilenameFromUrl,
  getPdfFilenameFromUrl,
  getXfaPageViewport,
  GlobalWorkerOptions,
  InvalidPDFException,
  isPdfFile,
  loadScript,
  LoopbackPort,
  MissingPDFException,
  OPS,
  PasswordResponses,
  PDFDataRangeTransport,
  PDFDateString,
  PDFWorker,
  PermissionFlag,
  PixelsPerInch,
  RenderingCancelledException,
  renderTextLayer,
  shadow,
  SVGGraphics,
  UnexpectedResponseException,
  UNSUPPORTED_FEATURES,
  Util,
  VerbosityLevel,
  version,
  XfaLayer,
};
<commit_msg>[api-minor] Stop exposing the `LoopbackPort` class in the API<commit_after>/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// eslint-disable-next-line max-len
/** @typedef {import("./display/api").PDFDocumentLoadingTask} PDFDocumentLoadingTask */
/** @typedef {import("./display/api").PDFDocumentProxy} PDFDocumentProxy */
/** @typedef {import("./display/api").PDFPageProxy} PDFPageProxy */
/** @typedef {import("./display/api").RenderTask} RenderTask */
/** @typedef {import("./display/display_utils").PageViewport} PageViewport */
// eslint-disable-next-line max-len
/** @typedef {import("./display/text_layer").TextLayerRenderTask} TextLayerRenderTask */

import {
  AnnotationEditorParamsType,
  AnnotationEditorType,
  AnnotationMode,
  CMapCompressionType,
  createPromiseCapability,
  createValidAbsoluteUrl,
  InvalidPDFException,
  MissingPDFException,
  OPS,
  PasswordResponses,
  PermissionFlag,
  shadow,
  UnexpectedResponseException,
  UNSUPPORTED_FEATURES,
  Util,
  VerbosityLevel,
} from "./shared/util.js";
import {
  build,
  getDocument,
  PDFDataRangeTransport,
  PDFWorker,
  setPDFNetworkStreamFactory,
  version,
} from "./display/api.js";
import {
  getFilenameFromUrl,
  getPdfFilenameFromUrl,
  getXfaPageViewport,
  isPdfFile,
  isValidFetchUrl,
  loadScript,
  PDFDateString,
  PixelsPerInch,
  RenderingCancelledException,
} from "./display/display_utils.js";
import { AnnotationEditorLayer } from "./display/editor/annotation_editor_layer.js";
import { AnnotationEditorUIManager } from "./display/editor/tools.js";
import { AnnotationLayer } from "./display/annotation_layer.js";
import { GlobalWorkerOptions } from "./display/worker_options.js";
import { isNodeJS } from "./shared/is_node.js";
import { renderTextLayer } from "./display/text_layer.js";
import { SVGGraphics } from "./display/svg.js";
import { XfaLayer } from "./display/xfa_layer.js";

/* eslint-disable-next-line no-unused-vars */
const pdfjsVersion =
  typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_VERSION") : void 0;
/* eslint-disable-next-line no-unused-vars */
const pdfjsBuild =
  typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0;

if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")) {
  const streamsPromise = Promise.all([
    import("pdfjs/display/network.js"),
    import("pdfjs/display/fetch_stream.js"),
  ]);

  setPDFNetworkStreamFactory(async params => {
    const [{ PDFNetworkStream }, { PDFFetchStream }] = await streamsPromise;
    if (isValidFetchUrl(params.url)) {
      return new PDFFetchStream(params);
    }
    return new PDFNetworkStream(params);
  });
} else if (PDFJSDev.test("GENERIC || CHROME")) {
  if (PDFJSDev.test("GENERIC") && isNodeJS) {
    const { PDFNodeStream } = require("./display/node_stream.js");

    setPDFNetworkStreamFactory(params => {
      return new PDFNodeStream(params);
    });
  } else {
    const { PDFNetworkStream } = require("./display/network.js");
    const { PDFFetchStream } = require("./display/fetch_stream.js");

    setPDFNetworkStreamFactory(params => {
      if (isValidFetchUrl(params.url)) {
        return new PDFFetchStream(params);
      }
      return new PDFNetworkStream(params);
    });
  }
}

export {
  AnnotationEditorLayer,
  AnnotationEditorParamsType,
  AnnotationEditorType,
  AnnotationEditorUIManager,
  AnnotationLayer,
  AnnotationMode,
  build,
  CMapCompressionType,
  createPromiseCapability,
  createValidAbsoluteUrl,
  getDocument,
  getFilenameFromUrl,
  getPdfFilenameFromUrl,
  getXfaPageViewport,
  GlobalWorkerOptions,
  InvalidPDFException,
  isPdfFile,
  loadScript,
  MissingPDFException,
  OPS,
  PasswordResponses,
  PDFDataRangeTransport,
  PDFDateString,
  PDFWorker,
  PermissionFlag,
  PixelsPerInch,
  RenderingCancelledException,
  renderTextLayer,
  shadow,
  SVGGraphics,
  UnexpectedResponseException,
  UNSUPPORTED_FEATURES,
  Util,
  VerbosityLevel,
  version,
  XfaLayer,
};
<|endoftext|>