<commit_before>'use strict'

var React = require('react')
var ReactBootstrap = require('react-bootstrap')
var ReactRouterBootstrap = require('react-router-bootstrap')
var _ = require('lodash')
var FinaliseAssessment = require('./finaliseAssessment')
var AppAlert = require('../common/appAlert')
var PageHeader = ReactBootstrap.PageHeader
var Nav = ReactBootstrap.Nav
var NavItem = ReactBootstrap.NavItem
var Row = ReactBootstrap.Row
var Col = ReactBootstrap.Col
var Pager = ReactBootstrap.Pager
var Glyphicon = ReactBootstrap.Glyphicon
var Label = ReactBootstrap.Label
var LinkContainer = ReactRouterBootstrap.LinkContainer
var Loader = require('react-loader')
var TagList = require('../common/tagList')
var $ = require('jquery')

var Assessment = React.createClass({
  propTypes: {
    params: React.PropTypes.object,
    location: React.PropTypes.object,
    children: React.PropTypes.object
  },
  getInitialState: function () {
    return {
      activeTab: parseInt(this.props.location.query.tab, 10) || 1,
      activeAttribute: null,
      measurements: null,
      template: null,
      assessment: null,
      initialLoad: false,
      measureSyncActivity: false,
      dirtyObservation: {},
      showAlert: false,
      alertDetail: '',
      alertType: '',
      previous_hide: false,
      next_hide: false,
      assessmentTags: []
    }
  },
  contextTypes: {
    router: React.PropTypes.object
  },
  componentWillMount: function () {
    this.dataSource('/api/assessments/' + this.props.params.assessmentId + '/', this.assessmentCallback)
  },
  tagsCallback: function (data) {
    this.setState({
      assessmentTags: data
    })
  },
  measurementCallback: function (data) {
    this.setState({
      measurements: data,
      initialLoad: true
    }, this.dataSource('/api/tags/?assessment__id=' + this.props.params.assessmentId, this.tagsCallback)
    )
  },
  templateCallback: function (data) {
    this.setState({
      template: data
    }, this.dataSource('/api/measurements/?assessment__id=' + this.props.params.assessmentId, this.measurementCallback)
    )
  },
  assessmentCallback: function (assessment) {
    this.setState({
      assessment: assessment,
      assessmentTags: assessment.tags.map(function (tagId) {
        return { id: tagId, name: '•••' }
      })
    }, this.dataSource('/api/templates/' + assessment.template.id + '/', this.templateCallback)
    )
  },
  handleAlertHide () {
    this.setState({ showAlert: false })
  },
  handleSubmitFailure: function (xhr, ajaxOptions, thrownError) {
    console.log(thrownError)
    console.log(xhr.responseJSON.detail)
    console.log(ajaxOptions)
    this.setState({
      measureSyncActivity: false,
      showAlert: true,
      alertType: thrownError,
      alertDetail: xhr.responseJSON.detail
    })
  },
  dataSource: function (url, callback) {
    $.ajax({
      type: 'get',
      dataType: 'json',
      url: url,
      success: callback,
      error: this.handleSubmitFailure
    })
  },
  measurementUpdateCallback: function (data) {
    var existingMeasurementIndex = _.findIndex(this.state.measurements, function (measurement) {
      return measurement.id === data.id
    })
    if (existingMeasurementIndex !== -1) {
      var updatedMeasurements = this.state.measurements.slice()
      updatedMeasurements[existingMeasurementIndex] = data
      this.setState({
        measurements: updatedMeasurements,
        measureSyncActivity: false,
        dirtyObservation: false
      })
    } else {
      var newMeasurements = this.state.measurements.concat([data])
      this.setState({
        measurements: newMeasurements,
        measureSyncActivity: false,
        dirtyObservation: false
      })
    }
  },
  syncMeasurement: function (postData) {
    var createNewMeasure = !postData.id
    this.setState({ measureSyncActivity: true })
    $.ajax({
      type: ((createNewMeasure) ? 'POST' : 'PUT'),
      contentType: 'application/json; charset=utf-8',
      url: ((createNewMeasure) ? '/api/measurements/' : ('/api/measurements/' + postData.id + '/')),
      data: JSON.stringify(postData),
      dataType: 'json',
      success: this.measurementUpdateCallback,
      error: this.handleSubmitFailure
    })
  },
  markAssessmentDone: function () {
    var data = this.state.assessment
    data.status = 'DONE'
    $.ajax({
      context: this,
      url: '/api/assessments/' + this.state.assessment.id + '/',
      contentType: 'application/json; charset=utf-8',
      dataType: 'json',
      data: JSON.stringify(data),
      type: 'PUT',
      cache: true,
      success: function (output) {
        this.setState({assessment: data})
      }.bind(this),
      error: this.handleSubmitFailure
    })
  },
  handleNext: function () {
    this.scrollToTop('#attribute-list')
    var currentAttribute = this.props.params.attribute
    var index = _.findIndex(this.state.template.attributes, ['id', parseInt(currentAttribute, 10)])
    var nextId = (this.state.template.attributes[index + 1]) ? this.state.template.attributes[index + 1].id : 'summary'
    var path = '/assessment/' + this.props.params.assessmentId + '/' + nextId
    this.context.router.push(path)
  },
  handlePrevious: function () {
    this.scrollToTop('#attribute-list')
    var currentAttribute = this.props.params.attribute
    var index = _.findIndex(this.state.template.attributes, ['id', parseInt(currentAttribute, 10)])
    var nextId = (this.state.template.attributes[index - 1]) ? this.state.template.attributes[index - 1].id : (index === 0) ? 'summary' : _.last(this.state.template.attributes).id
    var path = '/assessment/' + this.props.params.assessmentId + '/' + nextId
    this.context.router.push(path)
  },
  scrollToTop: function (attList) {
    var $target = $(attList)

    $('html, body').stop().animate({
      'scrollTop': $target.offset().top
    }, 900, 'swing', function () {
        // window.location.hash = $target
    })
  },
  getAttributeForRating: function (queryRating) {
    var matchingAttribute = null
    for (var i = 0; i < this.state.template.attributes.length; i++) {
      for (var ii = 0; ii < this.state.template.attributes[i].ratings.length; ii++) {
        if (queryRating === this.state.template.attributes[i].ratings[ii].id) {
          matchingAttribute = this.state.template.attributes[i].id
          break
        }
      }
    }
    return matchingAttribute
  },
  getMeasurementForAttribute: function (attribute) {
    if (this.state.measurements !== null) {
      for (var i = 0; i < this.state.measurements.length; i++) {
        if (attribute.id === this.getAttributeForRating(this.state.measurements[i].rating)) {
          return this.state.measurements[i]
        }
      }
    } else {
      return null
    }
  },
  render: function () {
    if (this.state.template) {
      var attributeNodes = this.state.template.attributes.map(function (attribute, i) {
        var measurement = this.getMeasurementForAttribute(attribute)
        var completeMeasurement = measurement && measurement.rating && measurement.target_rating
        var tabIcon = (completeMeasurement) ? <Glyphicon glyph='ok' className='text-success' /> : <Glyphicon glyph='minus' />
        return (
          <LinkContainer
            key={attribute.id}
            to={{pathname: '/assessment/' + this.state.assessment.id + '/' + attribute.id}}>
            <NavItem eventKey={i + 1}>{tabIcon} {attribute.name}</NavItem>
          </LinkContainer>
        )
      }, this)
    }
    var isSummaryTab = this.props.location.pathname.indexOf('/summary') > -1
    return (

        <Loader loaded={this.state.initialLoad}>
          {this.state.assessment && <PageHeader>
            {this.state.assessment.template.name}

              {this.state.assessment.template.short_desc}

                <TagList tags={this.state.assessmentTags} />

              {this.state.assessment.status === 'DONE' && Read Only}

          </PageHeader>}

            <Row>
              <Col className='attribute-content' xs={12} md={9} lg={9}>
                {React.cloneElement(this.props.children, {
                  template: this.state.template,
                  measurements: this.state.measurements,
                  syncMeasurement: this.syncMeasurement,
                  measureSyncActivity: this.state.measureSyncActivity,
                  assessment: this.state.assessment,
                  disabled: (this.state.assessment && this.state.assessment.status === 'DONE')
                })}
                <Pager>
                  <Pager.Item disabled={this.state.previous_hide} onClick={this.handlePrevious}>
                    <Glyphicon glyph='chevron-left' /> {' '} Previous
                  </Pager.Item>
                  {' '}
                  <Pager.Item disabled={this.state.next_hide} onClick={this.handleNext}>
                    Next {' '} <Glyphicon glyph='chevron-right' />
                  </Pager.Item>
                </Pager>
              </Col>
              <Col className='attribute-tabs' xs={12} md={3} lg={3}>

                  {attributeNodes}
                  {this.state.template &&
                    <LinkContainer
                      key='summary'
                      to={{pathname: '/assessment/' + this.state.assessment.id + '/summary'}}>
                      <NavItem eventKey={this.state.template.attributes.length + 1}>
                        <Glyphicon glyph='stats' /> Summary
                      </NavItem>
                    </LinkContainer>}

                <FinaliseAssessment
                  assessment={this.state.assessment}
                  markAssessmentDone={this.markAssessmentDone}
                  isSummaryTab={isSummaryTab}
                />
              </Col>
            </Row>

        </Loader>
        <AppAlert showAlert={this.state.showAlert} alertType={this.state.alertType} alertDetail={this.state.alertDetail} handleHide={this.handleAlertHide} />

    )
  }
})

module.exports = Assessment
<commit_msg>log error response<commit_after>'use strict'

var React = require('react')
var ReactBootstrap = require('react-bootstrap')
var ReactRouterBootstrap = require('react-router-bootstrap')
var _ = require('lodash')
var FinaliseAssessment = require('./finaliseAssessment')
var AppAlert = require('../common/appAlert')
var PageHeader = ReactBootstrap.PageHeader
var Nav = ReactBootstrap.Nav
var NavItem = ReactBootstrap.NavItem
var Row = ReactBootstrap.Row
var Col = ReactBootstrap.Col
var Pager = ReactBootstrap.Pager
var Glyphicon = ReactBootstrap.Glyphicon
var Label = ReactBootstrap.Label
var LinkContainer = ReactRouterBootstrap.LinkContainer
var Loader = require('react-loader')
var TagList = require('../common/tagList')
var $ = require('jquery')

var Assessment = React.createClass({
  propTypes: {
    params: React.PropTypes.object,
    location: React.PropTypes.object,
    children: React.PropTypes.object
  },
  getInitialState: function () {
    return {
      activeTab: parseInt(this.props.location.query.tab, 10) || 1,
      activeAttribute: null,
      measurements: null,
      template: null,
      assessment: null,
      initialLoad: false,
      measureSyncActivity: false,
      dirtyObservation: {},
      showAlert: false,
      alertDetail: '',
      alertType: '',
      previous_hide: false,
      next_hide: false,
      assessmentTags: []
    }
  },
  contextTypes: {
    router: React.PropTypes.object
  },
  componentWillMount: function () {
    this.dataSource('/api/assessments/' + this.props.params.assessmentId + '/', this.assessmentCallback)
  },
  tagsCallback: function (data) {
    this.setState({
      assessmentTags: data
    })
  },
  measurementCallback: function (data) {
    this.setState({
      measurements: data,
      initialLoad: true
    }, this.dataSource('/api/tags/?assessment__id=' + this.props.params.assessmentId, this.tagsCallback)
    )
  },
  templateCallback: function (data) {
    this.setState({
      template: data
    }, this.dataSource('/api/measurements/?assessment__id=' + this.props.params.assessmentId, this.measurementCallback)
    )
  },
  assessmentCallback: function (assessment) {
    this.setState({
      assessment: assessment,
      assessmentTags: assessment.tags.map(function (tagId) {
        return { id: tagId, name: '•••' }
      })
    }, this.dataSource('/api/templates/' + assessment.template.id + '/', this.templateCallback)
    )
  },
  handleAlertHide () {
    this.setState({ showAlert: false })
  },
  handleSubmitFailure: function (xhr, ajaxOptions, thrownError) {
    console.log(thrownError)
    console.log(xhr.responseJSON)
    console.log(ajaxOptions)
    this.setState({
      measureSyncActivity: false,
      showAlert: true,
      alertType: thrownError,
      alertDetail: xhr.responseJSON.detail ? xhr.responseJSON.detail : 'Unexpected error'
    })
  },
  dataSource: function (url, callback) {
    $.ajax({
      type: 'get',
      dataType: 'json',
      url: url,
      success: callback,
      error: this.handleSubmitFailure
    })
  },
  measurementUpdateCallback: function (data) {
    var existingMeasurementIndex = _.findIndex(this.state.measurements, function (measurement) {
      return measurement.id === data.id
    })
    if (existingMeasurementIndex !== -1) {
      var updatedMeasurements = this.state.measurements.slice()
      updatedMeasurements[existingMeasurementIndex] = data
      this.setState({
        measurements: updatedMeasurements,
        measureSyncActivity: false,
        dirtyObservation: false
      })
    } else {
      var newMeasurements = this.state.measurements.concat([data])
      this.setState({
        measurements: newMeasurements,
        measureSyncActivity: false,
        dirtyObservation: false
      })
    }
  },
  syncMeasurement: function (postData) {
    var createNewMeasure = !postData.id
    this.setState({ measureSyncActivity: true })
    $.ajax({
      type: ((createNewMeasure) ? 'POST' : 'PUT'),
      contentType: 'application/json; charset=utf-8',
      url: ((createNewMeasure) ? '/api/measurements/' : ('/api/measurements/' + postData.id + '/')),
      data: JSON.stringify(postData),
      dataType: 'json',
      success: this.measurementUpdateCallback,
      error: this.handleSubmitFailure
    })
  },
  markAssessmentDone: function () {
    var data = this.state.assessment
    data.status = 'DONE'
    $.ajax({
      context: this,
      url: '/api/assessments/' + this.state.assessment.id + '/',
      contentType: 'application/json; charset=utf-8',
      dataType: 'json',
      data: JSON.stringify(data),
      type: 'PUT',
      cache: true,
      success: function (output) {
        this.setState({assessment: data})
      }.bind(this),
      error: this.handleSubmitFailure
    })
  },
  handleNext: function () {
    this.scrollToTop('#attribute-list')
    var currentAttribute = this.props.params.attribute
    var index = _.findIndex(this.state.template.attributes, ['id', parseInt(currentAttribute, 10)])
    var nextId = (this.state.template.attributes[index + 1]) ? this.state.template.attributes[index + 1].id : 'summary'
    var path = '/assessment/' + this.props.params.assessmentId + '/' + nextId
    this.context.router.push(path)
  },
  handlePrevious: function () {
    this.scrollToTop('#attribute-list')
    var currentAttribute = this.props.params.attribute
    var index = _.findIndex(this.state.template.attributes, ['id', parseInt(currentAttribute, 10)])
    var nextId = (this.state.template.attributes[index - 1]) ? this.state.template.attributes[index - 1].id : (index === 0) ? 'summary' : _.last(this.state.template.attributes).id
    var path = '/assessment/' + this.props.params.assessmentId + '/' + nextId
    this.context.router.push(path)
  },
  scrollToTop: function (attList) {
    var $target = $(attList)

    $('html, body').stop().animate({
      'scrollTop': $target.offset().top
    }, 900, 'swing', function () {
        // window.location.hash = $target
    })
  },
  getAttributeForRating: function (queryRating) {
    var matchingAttribute = null
    for (var i = 0; i < this.state.template.attributes.length; i++) {
      for (var ii = 0; ii < this.state.template.attributes[i].ratings.length; ii++) {
        if (queryRating === this.state.template.attributes[i].ratings[ii].id) {
          matchingAttribute = this.state.template.attributes[i].id
          break
        }
      }
    }
    return matchingAttribute
  },
  getMeasurementForAttribute: function (attribute) {
    if (this.state.measurements !== null) {
      for (var i = 0; i < this.state.measurements.length; i++) {
        if (attribute.id === this.getAttributeForRating(this.state.measurements[i].rating)) {
          return this.state.measurements[i]
        }
      }
    } else {
      return null
    }
  },
  render: function () {
    if (this.state.template) {
      var attributeNodes = this.state.template.attributes.map(function (attribute, i) {
        var measurement = this.getMeasurementForAttribute(attribute)
        var completeMeasurement = measurement && measurement.rating && measurement.target_rating
        var tabIcon = (completeMeasurement) ? <Glyphicon glyph='ok' className='text-success' /> : <Glyphicon glyph='minus' />
        return (
          <LinkContainer
            key={attribute.id}
            to={{pathname: '/assessment/' + this.state.assessment.id + '/' + attribute.id}}>
            <NavItem eventKey={i + 1}>{tabIcon} {attribute.name}</NavItem>
          </LinkContainer>
        )
      }, this)
    }
    var isSummaryTab = this.props.location.pathname.indexOf('/summary') > -1
    return (

        <Loader loaded={this.state.initialLoad}>
          {this.state.assessment && <PageHeader>
            {this.state.assessment.template.name}

              {this.state.assessment.template.short_desc}

                <TagList tags={this.state.assessmentTags} />

              {this.state.assessment.status === 'DONE' && Read Only}

          </PageHeader>}

            <Row>
              <Col className='attribute-content' xs={12} md={9} lg={9}>
                {React.cloneElement(this.props.children, {
                  template: this.state.template,
                  measurements: this.state.measurements,
                  syncMeasurement: this.syncMeasurement,
                  measureSyncActivity: this.state.measureSyncActivity,
                  assessment: this.state.assessment,
                  disabled: (this.state.assessment && this.state.assessment.status === 'DONE')
                })}
                <Pager>
                  <Pager.Item disabled={this.state.previous_hide} onClick={this.handlePrevious}>
                    <Glyphicon glyph='chevron-left' /> {' '} Previous
                  </Pager.Item>
                  {' '}
                  <Pager.Item disabled={this.state.next_hide} onClick={this.handleNext}>
                    Next {' '} <Glyphicon glyph='chevron-right' />
                  </Pager.Item>
                </Pager>
              </Col>
              <Col className='attribute-tabs' xs={12} md={3} lg={3}>

                  {attributeNodes}
                  {this.state.template &&
                    <LinkContainer
                      key='summary'
                      to={{pathname: '/assessment/' + this.state.assessment.id + '/summary'}}>
                      <NavItem eventKey={this.state.template.attributes.length + 1}>
                        <Glyphicon glyph='stats' /> Summary
                      </NavItem>
                    </LinkContainer>}

                <FinaliseAssessment
                  assessment={this.state.assessment}
                  markAssessmentDone={this.markAssessmentDone}
                  isSummaryTab={isSummaryTab}
                />
              </Col>
            </Row>

        </Loader>
        <AppAlert showAlert={this.state.showAlert} alertType={this.state.alertType} alertDetail={this.state.alertDetail} handleHide={this.handleAlertHide} />

    )
  }
})

module.exports = Assessment
<|endoftext|>


<commit_before>import * as Base64ArrayBufferToUint8Array from "../Base64ArrayBufferToUint8Array.js";
import * as PartTime from "../PartTime.js";
import * as Random from "../Random.js";
import * as ScriptLoader from "../ScriptLoader.js";
import * as ValueMax from "../ValueMax.js";

// This string will not fit to ASCII when base64 decoded. So can not be used to test.
//const base64EncodedString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// Use all printable ASCII codes form a string of 3-divisible length.
// (So its base64-encoded codes will divisible by 4.)
let originalArray = [];
{
  const ORIGINAL_TEST_STRING_LENGTH = 3 * 4;

  const PRINTABLE_ASCII_MIN = 32;
  const PRINTABLE_ASCII_MAX = 126;

  for (let i = 0; i < ORIGINAL_TEST_STRING_LENGTH; ++i) {
    let c = Random.getIntInclusive(PRINTABLE_ASCII_MIN, PRINTABLE_ASCII_MAX);
    originalArray.push( String.fromCodePoint( c ) );
  }
}

const originalString = originalArray.join("");
const base64EncodedString = btoa(originalString);
const base64DecodedString = atob(base64EncodedString);

const base64EncodedStrings_extra = [
  // Test empty base64 content.
  "",
  "\n",
  "\r",
  "\r\n",
  "\n\r",

  // Test extra has 0 to 3 bytes. (They should be ignored.)
  base64EncodedString,
  base64EncodedString + base64EncodedString.slice(0, 1),
  base64EncodedString + base64EncodedString.slice(0, 2),
  base64EncodedString + base64EncodedString.slice(0, 3),

  // Test extra non-base64 codes inside. (They should be ignored.)
  base64EncodedString.slice(0, 3) + "\n"   + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\r"   + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\r\n" + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\n\r" + base64EncodedString.slice(3),

  // Test skip 3 lines. Test multiple non-base64 codes. (They should be ignored.)
  "qwerty5ASDFG7\n\n\r"
    + base64EncodedString.slice(0, 2) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(2, 7) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(7, 9) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(9)    + "\n\n\r\r\r\n\r\n",
];

let tEncoder = new TextEncoder();
let tDecoder = new TextDecoder();

//const base64EncodedUint8Array = tDecoder.decode(base64EncodedString);
const base64DecodedUint8Array = tEncoder.encode(base64DecodedString);
const emptyUint8Array = new Uint8Array(0);

class TestCase {
  constructor(source, skipLineCount, result, suspendByteCount, note) {
    this.source = source;
    this.skipLineCount = skipLineCount;
    this.result = result;
    this.suspendByteCount = suspendByteCount;
    this.note = note;
  }
}

let testCases = [
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 0]), 1, emptyUint8Array, undefined, "Empty. Not enough lines." ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 0]), 0, emptyUint8Array,         3, "Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 1]), 1, emptyUint8Array,         2, "LF Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 2]), 1, emptyUint8Array,         5, "CR Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 3]), 1, emptyUint8Array, undefined, "CRLF Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 4]), 2, emptyUint8Array,         5, "LFCR Empty" ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 5]), 0, base64DecodedUint8Array,        15, "Extra 0 bytes" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 6]), 0, base64DecodedUint8Array,         7, "Extra 1 bytes" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 7]), 0, base64DecodedUint8Array,        17, "Extra 2 bytes" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 8]), 0, base64DecodedUint8Array,         8, "Extra 3 bytes" ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 9]), 0, base64DecodedUint8Array,         4, "Extra LF inside" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[10]), 0, base64DecodedUint8Array,         3, "Extra CR inside" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[11]), 0, base64DecodedUint8Array,         5, "Extra CRLF inside" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[12]), 0, base64DecodedUint8Array,        11, "Extra LFCR inside" ),

  new TestCase( tEncoder.encode("\n"   + base64EncodedString), 1, base64DecodedUint8Array,         5, "Begin LF" ),
  new TestCase( tEncoder.encode("\r"   + base64EncodedString), 1, base64DecodedUint8Array,         5, "Begin CR" ),
  new TestCase( tEncoder.encode("\r\n" + base64EncodedString), 1, base64DecodedUint8Array,         5, "Begin CRLF" ),
  new TestCase( tEncoder.encode("\n\r" + base64EncodedString), 2, base64DecodedUint8Array,         5, "Begin LFCR" ),

  new TestCase( tEncoder.encode("qwerty\n"   + base64EncodedString), 1, base64DecodedUint8Array,         6, "Text LF" ),
  new TestCase( tEncoder.encode("qwerty\r"   + base64EncodedString), 1, base64DecodedUint8Array, undefined, "Text CR" ),
  new TestCase( tEncoder.encode("qwerty\r\n" + base64EncodedString), 1, base64DecodedUint8Array,      2048, "Text CRLF" ),
  new TestCase( tEncoder.encode("qwerty\n\r" + base64EncodedString), 2, base64DecodedUint8Array,         7, "Text LFCR" ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[13]), 3, base64DecodedUint8Array, 8, "Multiple LF and CR inside" ),
];

/** Aggregate all progress about downloading, JSON parsing, characters scanning, and weights scanning.  */
class Progress extends ValueMax.Percentage.Aggregate {
  constructor() {
    let children = [
//      new ValueMax.Percentage.Concrete(), // Increased when downloading from network.
//      new ValueMax.Percentage.Concrete(), // Increased when parsing the downloaded data to Uint8Array.
    ];

    for (let i = 0; i < testCases.length; ++i) {
      children.push(new ValueMax.Percentage.Concrete()); // Increased when parsing the downloaded data to Uint8Array.
    }

    super(children);

//    [this.download, this.uint8Array] = children;
//    [this.uint8Array] = children;
  }
}

let progress = new Progress();
let progressReceiver = new ValueMax.Receiver.HTMLProgress.createByTitle_or_getDummy("TestProgressBar");

window.addEventListener("load", event => {
  ScriptLoader.createPromise("https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js").then(test); });

function test() {
  console.log("Base64 decode testing...");
  let delayMilliseconds = 1000;

  let testPromiseAll = [];
  for (let i = 0; i < testCases.length; ++i) {
    let testCase = testCases[ i ];

    let decoder = Base64ArrayBufferToUint8Array.decoder(
        testCase.source, testCase.skipLineCount, progress, progress.childProgressParts[ i ], testCase.suspendByteCount);

    let testPromise = PartTime.forOf(
      decoder,
      (valueMax) => { progressReceiver.setValueMax(valueMax); /* Report progress to UI. */ },
      delayMilliseconds
    ).then(r => {
      progressReceiver.informDone(r); /* Inform UI progress done. */
      tf.util.assert(
        r.toString() == testCase.result.toString(),
        `[${i}]`
          + ` Skip ${testCase.skipLineCount} lines.`
          + ` suspendByteCount=${testCase.suspendByteCount}.`
          + ` ${testCase.note} [${r}] != [${testCase.result}]`);
    });

    testPromiseAll.push( testPromise );
  }

  Promise.all(testPromiseAll).then(values => {
    console.log("Base64 decode testing... Done.");
  });
}
<commit_msg>Move progressReceiver into test()<commit_after>import * as Base64ArrayBufferToUint8Array from "../Base64ArrayBufferToUint8Array.js";
import * as PartTime from "../PartTime.js";
import * as Random from "../Random.js";
import * as ScriptLoader from "../ScriptLoader.js";
import * as ValueMax from "../ValueMax.js";

// This string will not fit to ASCII when base64 decoded. So can not be used to test.
//const base64EncodedString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// Use all printable ASCII codes form a string of 3-divisible length.
// (So its base64-encoded codes will divisible by 4.)
let originalArray = [];
{
  const ORIGINAL_TEST_STRING_LENGTH = 3 * 4;

  const PRINTABLE_ASCII_MIN = 32;
  const PRINTABLE_ASCII_MAX = 126;

  for (let i = 0; i < ORIGINAL_TEST_STRING_LENGTH; ++i) {
    let c = Random.getIntInclusive(PRINTABLE_ASCII_MIN, PRINTABLE_ASCII_MAX);
    originalArray.push( String.fromCodePoint( c ) );
  }
}

const originalString = originalArray.join("");
const base64EncodedString = btoa(originalString);
const base64DecodedString = atob(base64EncodedString);

const base64EncodedStrings_extra = [
  // Test empty base64 content.
  "",
  "\n",
  "\r",
  "\r\n",
  "\n\r",

  // Test extra has 0 to 3 bytes. (They should be ignored.)
  base64EncodedString,
  base64EncodedString + base64EncodedString.slice(0, 1),
  base64EncodedString + base64EncodedString.slice(0, 2),
  base64EncodedString + base64EncodedString.slice(0, 3),

  // Test extra non-base64 codes inside. (They should be ignored.)
  base64EncodedString.slice(0, 3) + "\n"   + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\r"   + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\r\n" + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\n\r" + base64EncodedString.slice(3),

  // Test skip 3 lines. Test multiple non-base64 codes. (They should be ignored.)
  "qwerty5ASDFG7\n\n\r"
    + base64EncodedString.slice(0, 2) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(2, 7) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(7, 9) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(9)    + "\n\n\r\r\r\n\r\n",
];

let tEncoder = new TextEncoder();
let tDecoder = new TextDecoder();

//const base64EncodedUint8Array = tDecoder.decode(base64EncodedString);
const base64DecodedUint8Array = tEncoder.encode(base64DecodedString);
const emptyUint8Array = new Uint8Array(0);

class TestCase {
  constructor(source, skipLineCount, result, suspendByteCount, note) {
    this.source = source;
    this.skipLineCount = skipLineCount;
    this.result = result;
    this.suspendByteCount = suspendByteCount;
    this.note = note;
  }
}

let testCases = [
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 0]), 1, emptyUint8Array, undefined, "Empty. Not enough lines." ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 0]), 0, emptyUint8Array,         3, "Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 1]), 1, emptyUint8Array,         2, "LF Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 2]), 1, emptyUint8Array,         5, "CR Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 3]), 1, emptyUint8Array, undefined, "CRLF Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 4]), 2, emptyUint8Array,         5, "LFCR Empty" ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 5]), 0, base64DecodedUint8Array,        15, "Extra 0 bytes" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 6]), 0, base64DecodedUint8Array,         7, "Extra 1 bytes" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 7]), 0, base64DecodedUint8Array,        17, "Extra 2 bytes" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 8]), 0, base64DecodedUint8Array,         8, "Extra 3 bytes" ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 9]), 0, base64DecodedUint8Array,         4, "Extra LF inside" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[10]), 0, base64DecodedUint8Array,         3, "Extra CR inside" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[11]), 0, base64DecodedUint8Array,         5, "Extra CRLF inside" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[12]), 0, base64DecodedUint8Array,        11, "Extra LFCR inside" ),

  new TestCase( tEncoder.encode("\n"   + base64EncodedString), 1, base64DecodedUint8Array,         5, "Begin LF" ),
  new TestCase( tEncoder.encode("\r"   + base64EncodedString), 1, base64DecodedUint8Array,         5, "Begin CR" ),
  new TestCase( tEncoder.encode("\r\n" + base64EncodedString), 1, base64DecodedUint8Array,         5, "Begin CRLF" ),
  new TestCase( tEncoder.encode("\n\r" + base64EncodedString), 2, base64DecodedUint8Array,         5, "Begin LFCR" ),

  new TestCase( tEncoder.encode("qwerty\n"   + base64EncodedString), 1, base64DecodedUint8Array,         6, "Text LF" ),
  new TestCase( tEncoder.encode("qwerty\r"   + base64EncodedString), 1, base64DecodedUint8Array, undefined, "Text CR" ),
  new TestCase( tEncoder.encode("qwerty\r\n" + base64EncodedString), 1, base64DecodedUint8Array,      2048, "Text CRLF" ),
  new TestCase( tEncoder.encode("qwerty\n\r" + base64EncodedString), 2, base64DecodedUint8Array,         7, "Text LFCR" ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[13]), 3, base64DecodedUint8Array, 8, "Multiple LF and CR inside" ),
];

/** Aggregate all progress about downloading, JSON parsing, characters scanning, and weights scanning.  */
class Progress extends ValueMax.Percentage.Aggregate {
  constructor() {
    let children = [
//      new ValueMax.Percentage.Concrete(), // Increased when downloading from network.
//      new ValueMax.Percentage.Concrete(), // Increased when parsing the downloaded data to Uint8Array.
    ];

    for (let i = 0; i < testCases.length; ++i) {
      children.push(new ValueMax.Percentage.Concrete()); // Increased when parsing the downloaded data to Uint8Array.
    }

    super(children);

//    [this.download, this.uint8Array] = children;
//    [this.uint8Array] = children;
  }
}

window.addEventListener("load", event => {
  ScriptLoader.createPromise("https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js").then(test); });

function test() {
  console.log("Base64 decode testing...");
  let delayMilliseconds = 1000;

  let progress = new Progress();
  let progressReceiver = new ValueMax.Receiver.HTMLProgress.createByTitle_or_getDummy("TestProgressBar");

  let testPromiseAll = [];
  for (let i = 0; i < testCases.length; ++i) {
    let testCase = testCases[ i ];

    let decoder = Base64ArrayBufferToUint8Array.decoder(
        testCase.source, testCase.skipLineCount, progress, progress.childProgressParts[ i ], testCase.suspendByteCount);

    let testPromise = PartTime.forOf(
      decoder,
      (valueMax) => { progressReceiver.setValueMax(valueMax); /* Report progress to UI. */ },
      delayMilliseconds
    ).then(r => {
      progressReceiver.informDone(r); /* Inform UI progress done. */
      tf.util.assert(
        r.toString() == testCase.result.toString(),
        `[${i}]`
          + ` Skip ${testCase.skipLineCount} lines.`
          + ` suspendByteCount=${testCase.suspendByteCount}.`
          + ` ${testCase.note} [${r}] != [${testCase.result}]`);
    });

    testPromiseAll.push( testPromise );
  }

  Promise.all(testPromiseAll).then(values => {
    console.log("Base64 decode testing... Done.");
  });
}
<|endoftext|>


<commit_before>/*global module:false*/
module.exports = function(grunt) {

  require("load-grunt-tasks")(grunt);
  grunt.loadNpmTasks('grunt-connect-proxy');

  function config(name){
    return require("./tasks/options/" + name);
  }

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    dirs: grunt.file.readJSON('config/half-pipe.json'),
    bowerOpts: grunt.file.readJSON('.bowerrc'),
    jshint: config("jshint"),
    sass: config("sass"),
    cssmin: config("cssmin"),
    requirejs: config("requirejs"),
    connect: config("connect"),
    copy: config("copy"),
    watch: config("watch"),
    rails: config("rails"),
    clean: ['<%%= dirs.tmp %>']
  });

  // Default task.
  grunt.registerTask('default', 'build:debug');

  grunt.registerTask('build:debug', ['copy:prepare', 'sass:debug', 'copy:stage']);
  grunt.registerTask('build:public', ['copy:prepare', 'sass:public', 'copy:stage', 'requirejs:public', 'copy:public']);

  grunt.registerTask('server:debug', ['build:debug', 'configureProxies', 'connect:debug', 'rails:server:start', 'watch']);
  grunt.registerTask('server:public', ['build:public', 'configureProxies', 'connect:public:keepalive']);

};

<commit_msg>Include default build/server tasks<commit_after>/*global module:false*/
module.exports = function(grunt) {

  require("load-grunt-tasks")(grunt);
  grunt.loadNpmTasks('grunt-connect-proxy');

  function config(name){
    return require("./tasks/options/" + name);
  }

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    dirs: grunt.file.readJSON('config/half-pipe.json'),
    bowerOpts: grunt.file.readJSON('.bowerrc'),
    jshint: config("jshint"),
    sass: config("sass"),
    cssmin: config("cssmin"),
    requirejs: config("requirejs"),
    connect: config("connect"),
    copy: config("copy"),
    watch: config("watch"),
    rails: config("rails"),
    clean: ['<%%= dirs.tmp %>']
  });

  // Default task.
  grunt.registerTask('default', 'build:debug');

  // Configure asset building pipeline
  grunt.registerTask('build', ['build:debug']);
  grunt.registerTask('build:debug', ['copy:prepare', 'sass:debug', 'copy:stage']);
  grunt.registerTask('build:public', ['copy:prepare', 'sass:public', 'copy:stage', 'requirejs:public', 'copy:public']);

  // Configure preview server
  grunt.registerTask('server', ['server:debug']);
  grunt.registerTask('server:debug', ['build:debug', 'configureProxies', 'connect:debug', 'rails:server:start', 'watch']);
  grunt.registerTask('server:public', ['build:public', 'configureProxies', 'connect:public:keepalive']);

};

<|endoftext|>


<commit_before>'use strict'

var React = require('react')
var ReactBootstrap = require('react-bootstrap')
var Alert = ReactBootstrap.Alert
var Input = ReactBootstrap.Input
var ButtonInput = ReactBootstrap.ButtonInput
var Button = ReactBootstrap.Button
var TagSelect = require('./tagSelect')
var $ = require('jquery')

var TeamCreationForm = React.createClass({
  propTypes: {
    initialTags: React.PropTypes.array
  },
  getInitialState: function () {
    return {
      teamName: '',
      teamDesc: '',
      tags: '',
      formError: ''
    }
  },
  componentWillMount: function () {
    this.setState({
      tags: this.props.initialTags
    })
  },
  changeHandlerTags: function (val) {
    this.setState({
      tags: val
    })
  },
  handleSubmit: function (e) {
    e.preventDefault()

    if (this.state.teamName && this.state.teamDesc && this.state.tags.length > 0) {

      var teamName = this.state.teamName
      var teamDesc = this.state.teamDesc
      var tags = this.state.tags.map(function (value) {
        return (
          value.value
        )
      })
      this.showError('')
      this.createTeam(teamName, teamDesc, tags)
    } else if (this.state.formError) {
      var message = 'Name, description & tag/s required.'
      this.showError(message)
    }
  },

  showError: function (message) {
    this.setState({
      formError: message
    })
  },

  createTeam: function (teamName, teamDesc, tags) {
    var data = {
      name: teamName,
      short_desc: teamDesc,
      tags: tags
    }
    $.ajax({
      context: this,
      url: '/api/teams/',
      contentType: 'application/json; charset=utf-8',
      dataType: 'json',
      data: JSON.stringify(data),
      type: 'POST',
      cache: true,
      success: function (output) {
        window.location = '/#/team/' + output.id + '/'
      },
      error: function (xhr, status, err) {
        var message = 'Team creation failed due to unknown reason. Try again later.'
        this.showError(message)
      }
    })
  },

  handleChange: function () {
    // This could also be done using ReactLink:
    //     // http://facebook.github.io/react/docs/two-way-binding-helpers.html
    this.setState({
      teamName: this.refs.teamName.getValue(),
      teamDesc: this.refs.teamDesc.getValue()
    })
  },

  render: function () {
    return (
      <form className='form-horizontal'>
        <Alert bsStyle='danger' className={this.state.formError ? '' : 'hidden'}>
          {this.state.formError}
        </Alert>
        <Input
          type='text'
          label='Name'
          ref='teamName'
          value={this.state.teamName}
          onChange={this.handleChange}
          labelClassName='col-xs-2'
          wrapperClassName='col-xs-10'
          help='The team name must be unique'
        />
        <Input
          type='text'
          label='Description'
          ref='teamDesc'
          value={this.state.teamDesc}
          onChange={this.handleChange}
          labelClassName='col-xs-2'
          wrapperClassName='col-xs-10'
          help="The team's description"
        />

          <TagSelect
            label='Tags'
            ref='tags'
            {...this.props}
            value={this.state.tags}
            onChange={this.changeHandlerTags}
            labelClassName='col-xs-2'
            wrapperClassName='col-xs-10'
          />

          <Input className='btn btn-default' type='submit' value='Create' onClick={this.handleSubmit} wrapperClassName='col-xs-2 col-xs-offset-2' />

      </form>
    )
  }
})

module.exports = TeamCreationForm
<commit_msg>fix some lint complaints<commit_after>'use strict'

var React = require('react')
var ReactBootstrap = require('react-bootstrap')
var Alert = ReactBootstrap.Alert
var Input = ReactBootstrap.Input
var TagSelect = require('./tagSelect')
var $ = require('jquery')

var TeamCreationForm = React.createClass({
  propTypes: {
    initialTags: React.PropTypes.array
  },
  getInitialState: function () {
    return {
      teamName: '',
      teamDesc: '',
      tags: '',
      formError: ''
    }
  },
  componentWillMount: function () {
    this.setState({
      tags: this.props.initialTags
    })
  },
  changeHandlerTags: function (val) {
    this.setState({
      tags: val
    })
  },
  handleSubmit: function (e) {
    e.preventDefault()

    if (this.state.teamName && this.state.teamDesc && this.state.tags.length > 0) {
      var teamName = this.state.teamName
      var teamDesc = this.state.teamDesc
      var tags = this.state.tags.map(function (value) {
        return (
          value.value
        )
      })
      this.showError('')
      this.createTeam(teamName, teamDesc, tags)
    } else if (this.state.formError) {
      var message = 'Name, description & tag/s required.'
      this.showError(message)
    }
  },

  showError: function (message) {
    this.setState({
      formError: message
    })
  },

  createTeam: function (teamName, teamDesc, tags) {
    var data = {
      name: teamName,
      short_desc: teamDesc,
      tags: tags
    }
    $.ajax({
      context: this,
      url: '/api/teams/',
      contentType: 'application/json; charset=utf-8',
      dataType: 'json',
      data: JSON.stringify(data),
      type: 'POST',
      cache: true,
      success: function (output) {
        window.location = '/#/team/' + output.id + '/'
      },
      error: function (xhr, status, err) {
        var message = 'Team creation failed due to unknown reason. Try again later.'
        this.showError(message)
      }
    })
  },

  handleChange: function () {
    // This could also be done using ReactLink:
    //     // http://facebook.github.io/react/docs/two-way-binding-helpers.html
    this.setState({
      teamName: this.refs.teamName.getValue(),
      teamDesc: this.refs.teamDesc.getValue()
    })
  },

  render: function () {
    return (
      <form className='form-horizontal'>
        <Alert bsStyle='danger' className={this.state.formError ? '' : 'hidden'}>
          {this.state.formError}
        </Alert>
        <Input
          type='text'
          label='Name'
          ref='teamName'
          value={this.state.teamName}
          onChange={this.handleChange}
          labelClassName='col-xs-2'
          wrapperClassName='col-xs-10'
          help='The team name must be unique'
        />
        <Input
          type='text'
          label='Description'
          ref='teamDesc'
          value={this.state.teamDesc}
          onChange={this.handleChange}
          labelClassName='col-xs-2'
          wrapperClassName='col-xs-10'
          help="The team's description"
        />

          <TagSelect
            label='Tags'
            ref='tags'
            {...this.props}
            value={this.state.tags}
            onChange={this.changeHandlerTags}
            labelClassName='col-xs-2'
            wrapperClassName='col-xs-10'
          />

          <Input className='btn btn-default' type='submit' value='Create' onClick={this.handleSubmit} wrapperClassName='col-xs-2 col-xs-offset-2' />

      </form>
    )
  }
})

module.exports = TeamCreationForm
<|endoftext|>


<commit_before>"use strict";

var SKP = SKP || {
    Class: GT.Class
};

(function(exports) {

    var Class = exports.Class;
    var Utils = exports.Utils;
    var Composite = exports.Composite;

    var BaseElement = GT.Class.create({
        rawData: null,
        userData: null,

        setRawData: function(rawData) {
            this.rawData = JSON.parse(JSON.stringify(rawData));
        },
        initAttributes: function(options) {
            var Me = this;
            options.forEach(function(op) {
                if (typeof op == "string") {
                    Me.initAttribute(op)
                } else {
                    Me.initAttribute(op[0], op[1], op[2]);
                }
            });
        },

        initAttribute: function(name, defaultValue, newName) {
            newName = newName || name;
            if (arguments.length == 1) {
                defaultValue = this[name];
            }
            var rawData = this.rawData;
            if (name in rawData) {
                this[newName] = rawData[name]
            } else {
                this[newName] = defaultValue;
            }
            return this[newName];
        },
        getDefaultTransform: function() {
            return {
                x: 0,
                y: 0,
                scX: 1,
                scY: 1,
                skX: 0,
                skY: 0,

                scaleX: 1,
                scaleY: 1,
                angle: 0,
                rotation: 0
            };
        },
        setTransform: function(transform) {
            var defaultValue = this.getDefaultTransform();

            this.transform = transform || {};
            for (var p in defaultValue) {
                if (!(p in this.transform)) {
                    this.transform[p] = defaultValue[p];
                }
            }
            this.transform.angle = this.transform.skX;
            this.transform.rotation = this.transform.skX * Math.PI / 180;
            this.transform.scaleX = this.transform.scX;
            this.transform.scaleY = this.transform.scY;

            var matrix = new Matrix(1, 0, 0, 1, 0, 0);
            matrix.scale(this.transform.scaleX, this.transform.scaleY);
            matrix.rotate(this.transform.rotation);
            matrix.translate(this.transform.x, this.transform.y);
            this.matrix = matrix;
        },

        setColorOffset: function(color) {
            // aM, rM, gM, bM, aO, rO, gO, bO
            var defaultValue = {
                rO: 0,
                gO: 0,
                bO: 0,
                aO: 0,
                rM: 100,
                gM: 100,
                bM: 100,
                aM: 100
            };
            this.color = color || {};
            for (var p in defaultValue) {
                if (!(p in this.color)) {
                    this.color[p] = defaultValue[p];
                }
            }
        },

        setTweenCurve: function(curve) {
            // var defaultValue = [
            //     0, 0,
            //     1, 1
            // ];
            this.curve = curve; // || defaultValue;
            // for (var p in defaultValue) {
            //     if (!(p in this.curve)) {
            //         this.curve[p] = defaultValue[p];
            //     }
            // }
            if (this.curve) {
                // this.tweenFunction = this.createCubicBezier.call(null, this.curve);
            }
        },

        createCubicBezier: function(p0, p1, p2, p3) {
            return function(t) {
                return p0 * Math.pow(1 - t, 3) + 3 * p1 * t * Math.pow(1 - t, 2) + 3 * p2 * Math.pow(t, 2) * (1 - t) + p3 * Math.pow(t, 3);
            };
        },

        tweenFunction: function(t) {
            return t;
        },

        getTweenValue: function(a, b, t) {
            return a + (b - a) * this.tweenFunction(t);
        },
        getTweenAngle: function(a, b, t, tweenRotate) {
            var d = b - a;
            d = d % 360;
            d += (d < 0 ? -1 : 1) * (360 * tweenRotate)
                // if (d == 0) {
                //     return a;
                // }
                // if (spin < 0) {
                //     d = d - 360;
                // } else {
                //     d = d + 360;
                // }
                // d = d % 360;
                // console.log(a, b, d, "--", spin,b-a)
            var ta = (a + d * this.tweenFunction(t));
            // console.log(a, b, t, ta)
            return ta;
        },

        getTweenTransform: function(prevFrame, nextFrame, t) {
            var pT = prevFrame.transform;
            if (!nextFrame) {
                return {
                    x: pT.x,
                    y: pT.y,
                    scX: pT.scX,
                    scY: pT.scY,
                    skX: pT.skX,
                    skY: pT.skY,
                    scaleX: pT.scaleX,
                    scaleY: pT.scaleY,
                    angle: pT.angle,
                    rotation: pT.rotation,
                }
            }
            var nT = nextFrame.transform;
            var x = prevFrame.getTweenValue(pT.x, nT.x, t);
            var y = prevFrame.getTweenValue(pT.y, nT.y, t);
            var scaleX = prevFrame.getTweenValue(pT.scaleX, nT.scaleX, t);
            var scaleY = prevFrame.getTweenValue(pT.scaleY, nT.scaleY, t);
            var angle = prevFrame.getTweenAngle(pT.angle, nT.angle, t, prevFrame.tweenRotate);
            var transform = {
                x: x,
                y: y,
                scX: scaleX,
                scY: scaleY,
                skX: angle,
                skY: angle,
                scaleX: scaleX,
                scaleY: scaleY,
                angle: angle,
                rotation: angle * Math.PI / 180,
            };
            // console.log(transform)
            return transform;
        },

        getTweenColor: function(prevFrame, nextFrame, t) {
            var pT = prevFrame.color,
                nT = nextFrame.color;
            var keys = [
                "rO", "gO", "bO", "aO",
                "rM", "gM", "bM", "aM",
            ];
            var color = {};
            var Me = this;
            keys.forEach(function(k) {
                color[k] = prevFrame.getTweenValue(pT[k], nT[k], t);
            });
            return color;
        },

        getFrameTweenInfo: function(index) {
            var prevFrame, nextFrame;
            var passed = 0;
            for (var i = 0, len = this.frames.length; i < len; i++) {
                var keyFrame = this.frames[i];
                // console.log(i, '-', keyFrame.startIndex, index, keyFrame.endIndex)
                if (keyFrame.startIndex <= index && index < keyFrame.endIndex) {
                    prevFrame = keyFrame;
                    passed = index - keyFrame.startIndex;
                    if (passed > 0) {
                        nextFrame = this.frames[i + 1] || null;
                    }
                    // console.log(passed)
                    break;
                }
            }
            // console.log(index, prevFrame);
            if (!prevFrame) {
                return null;
            }
            return {
                passed: passed,
                duration: prevFrame.duration,
                t: passed / prevFrame.duration,
                prevFrame: prevFrame,
                nextFrame: nextFrame
            };
        },

        strokeAABB: function(context, aabb) {
            context.beginPath();
            context.moveTo(aabb[0], aabb[1]);
            context.lineTo(aabb[2], aabb[1]);
            context.lineTo(aabb[2], aabb[3]);
            context.lineTo(aabb[0], aabb[3]);
            context.closePath();
            context.stroke();
        },

        strokePoly: function(context, vertices, color, tx, ty) {
            tx = tx || 0;
            ty = ty || 0;
            if (color) {
                context.strokeStyle = color;
            }
            var vertexCount = vertices.length;
            var a = vertices[0];
            var first = a;
            context.beginPath();
            context.moveTo(a[0] + tx, a[1] + ty);
            for (var j = 1; j < vertexCount; j++) {
                var a = vertices[j];
                context.lineTo(a[0] + tx, a[1] + ty);
            }
            context.closePath();
            context.stroke();
        }
    });

    exports.BaseElement = BaseElement;

}(SKP))
<commit_msg>修正tweenRotate的用法<commit_after>"use strict";

var SKP = SKP || {
    Class: GT.Class
};

(function(exports) {

    var Class = exports.Class;
    var Utils = exports.Utils;
    var Composite = exports.Composite;

    var BaseElement = GT.Class.create({
        rawData: null,
        userData: null,

        setRawData: function(rawData) {
            this.rawData = JSON.parse(JSON.stringify(rawData));
        },
        initAttributes: function(options) {
            var Me = this;
            options.forEach(function(op) {
                if (typeof op == "string") {
                    Me.initAttribute(op)
                } else {
                    Me.initAttribute(op[0], op[1], op[2]);
                }
            });
        },

        initAttribute: function(name, defaultValue, newName) {
            newName = newName || name;
            if (arguments.length == 1) {
                defaultValue = this[name];
            }
            var rawData = this.rawData;
            if (name in rawData) {
                this[newName] = rawData[name]
            } else {
                this[newName] = defaultValue;
            }
            return this[newName];
        },
        getDefaultTransform: function() {
            return {
                x: 0,
                y: 0,
                scX: 1,
                scY: 1,
                skX: 0,
                skY: 0,

                scaleX: 1,
                scaleY: 1,
                angle: 0,
                rotation: 0
            };
        },
        setTransform: function(transform) {
            var defaultValue = this.getDefaultTransform();

            this.transform = transform || {};
            for (var p in defaultValue) {
                if (!(p in this.transform)) {
                    this.transform[p] = defaultValue[p];
                }
            }
            this.transform.angle = this.transform.skX;
            this.transform.rotation = this.transform.skX * Math.PI / 180;
            this.transform.scaleX = this.transform.scX;
            this.transform.scaleY = this.transform.scY;

            var matrix = new Matrix(1, 0, 0, 1, 0, 0);
            matrix.scale(this.transform.scaleX, this.transform.scaleY);
            matrix.rotate(this.transform.rotation);
            matrix.translate(this.transform.x, this.transform.y);
            this.matrix = matrix;
        },

        setColorOffset: function(color) {
            // aM, rM, gM, bM, aO, rO, gO, bO
            var defaultValue = {
                rO: 0,
                gO: 0,
                bO: 0,
                aO: 0,
                rM: 100,
                gM: 100,
                bM: 100,
                aM: 100
            };
            this.color = color || {};
            for (var p in defaultValue) {
                if (!(p in this.color)) {
                    this.color[p] = defaultValue[p];
                }
            }
        },

        setTweenCurve: function(curve) {
            // var defaultValue = [
            //     0, 0,
            //     1, 1
            // ];
            this.curve = curve; // || defaultValue;
            // for (var p in defaultValue) {
            //     if (!(p in this.curve)) {
            //         this.curve[p] = defaultValue[p];
            //     }
            // }
            if (this.curve) {
                // this.tweenFunction = this.createCubicBezier.call(null, this.curve);
            }
        },

        createCubicBezier: function(p0, p1, p2, p3) {
            return function(t) {
                return p0 * Math.pow(1 - t, 3) + 3 * p1 * t * Math.pow(1 - t, 2) + 3 * p2 * Math.pow(t, 2) * (1 - t) + p3 * Math.pow(t, 3);
            };
        },

        tweenFunction: function(t) {
            return t;
        },

        getTweenValue: function(a, b, t) {
            return a + (b - a) * this.tweenFunction(t);
        },
        getTweenAngle: function(a, b, t, tweenRotate) {
            var d = b + 360 * tweenRotate - a;
            // d = d % 360;
            // d += (d < 0 ? -1 : 1) * (360 * tweenRotate);

            // if (d == 0) {
            //     return a;
            // }
            // if (spin < 0) {
            //     d = d - 360;
            // } else {
            //     d = d + 360;
            // }
            // d = d % 360;
            // console.log(a, b, d, "--", spin,b-a)
            var ta = (a + d * this.tweenFunction(t));
            // console.log(a, b, t, ta)
            return ta;
        },

        getTweenTransform: function(prevFrame, nextFrame, t) {
            var pT = prevFrame.transform;
            if (!nextFrame) {
                return {
                    x: pT.x,
                    y: pT.y,
                    scX: pT.scX,
                    scY: pT.scY,
                    skX: pT.skX,
                    skY: pT.skY,
                    scaleX: pT.scaleX,
                    scaleY: pT.scaleY,
                    angle: pT.angle,
                    rotation: pT.rotation,
                }
            }
            var nT = nextFrame.transform;
            var x = prevFrame.getTweenValue(pT.x, nT.x, t);
            var y = prevFrame.getTweenValue(pT.y, nT.y, t);
            var scaleX = prevFrame.getTweenValue(pT.scaleX, nT.scaleX, t);
            var scaleY = prevFrame.getTweenValue(pT.scaleY, nT.scaleY, t);
            var angle = prevFrame.getTweenAngle(pT.angle, nT.angle, t, prevFrame.tweenRotate);
            var transform = {
                x: x,
                y: y,
                scX: scaleX,
                scY: scaleY,
                skX: angle,
                skY: angle,
                scaleX: scaleX,
                scaleY: scaleY,
                angle: angle,
                rotation: angle * Math.PI / 180,
            };
            // console.log(transform)
            return transform;
        },

        getTweenColor: function(prevFrame, nextFrame, t) {
            var pT = prevFrame.color,
                nT = nextFrame.color;
            var keys = [
                "rO", "gO", "bO", "aO",
                "rM", "gM", "bM", "aM",
            ];
            var color = {};
            var Me = this;
            keys.forEach(function(k) {
                color[k] = prevFrame.getTweenValue(pT[k], nT[k], t);
            });
            return color;
        },

        getFrameTweenInfo: function(index) {
            var prevFrame, nextFrame;
            var passed = 0;
            for (var i = 0, len = this.frames.length; i < len; i++) {
                var keyFrame = this.frames[i];
                // console.log(i, '-', keyFrame.startIndex, index, keyFrame.endIndex)
                if (keyFrame.startIndex <= index && index < keyFrame.endIndex) {
                    prevFrame = keyFrame;
                    passed = index - keyFrame.startIndex;
                    if (passed > 0) {
                        nextFrame = this.frames[i + 1] || null;
                    }
                    // console.log(passed)
                    break;
                }
            }
            // console.log(index, prevFrame);
            if (!prevFrame) {
                return null;
            }
            return {
                passed: passed,
                duration: prevFrame.duration,
                t: passed / prevFrame.duration,
                prevFrame: prevFrame,
                nextFrame: nextFrame
            };
        },

        strokeAABB: function(context, aabb) {
            context.beginPath();
            context.moveTo(aabb[0], aabb[1]);
            context.lineTo(aabb[2], aabb[1]);
            context.lineTo(aabb[2], aabb[3]);
            context.lineTo(aabb[0], aabb[3]);
            context.closePath();
            context.stroke();
        },

        strokePoly: function(context, vertices, color, tx, ty) {
            tx = tx || 0;
            ty = ty || 0;
            if (color) {
                context.strokeStyle = color;
            }
            var vertexCount = vertices.length;
            var a = vertices[0];
            var first = a;
            context.beginPath();
            context.moveTo(a[0] + tx, a[1] + ty);
            for (var j = 1; j < vertexCount; j++) {
                var a = vertices[j];
                context.lineTo(a[0] + tx, a[1] + ty);
            }
            context.closePath();
            context.stroke();
        }
    });

    exports.BaseElement = BaseElement;

}(SKP))
<|endoftext|>


<commit_before>var gateway = require(__dirname+'/../../../../');

module.exports = function(req, res){

  gateway.config.set('RIPPLE_REST_API', req.body.ripple_rest_api);
  res.send({ 'RIPPLE_REST_API': gateway.config.get('RIPPLE_REST_API') });

};
<commit_msg>[CHORE] have http api interact with core API<commit_after>var gateway = require(__dirname+'/../../../../');

module.exports = function(req, res){
  var url = req.body.url;
  gateway.api.setRippleRestUrl(url, function(err, url){
    if (err) {
      res.send(500, { error: err });
    } else {
      res.send({ 'RIPPLE_REST_API': url });
    }
  });
};
<|endoftext|>


<commit_before>
$(document).ready(function () {
	var dropdown = $("#timeSelectDropdown");
	$("#timeSelectDropdownMenu").offset({left: dropdown.offset().left});
});

// goes here so that all the on-click methods can get the canvas references
var interestContext = $("#chart").get(0).getContext("2d");
var ChartObject = new Chart(interestContext);

$("#navbar").load("./navbar.html");
$("#nav_add").addClass("active"); // TODO: make this line work
$(document).ready(function() {
$('#spending').click(function (e) {
	e.preventDefault()
	$(this).tab('show')
})
$('#stock').click(function (e) {
	e.preventDefault()
	$(this).tab('show')
})
$('#waste').click(function (e) {
	e.preventDefault()
	$(this).tab('show')
})
$('#weekSelect').click(function (e) {
	e.preventDefault()
    // generate graph data here
    var data = {
    	labels : ["6 days","","","","2 days","","today"],
    	datasets : [
    	{
    		fillColor : "rgba(151,187,205,0.5)",
    		strokeColor : "rgba(151,187,205,1)",
    		pointColor : "rgba(151,187,205,1)",
    		pointStrokeColor : "#fff",
    		data : [28,48,40,19,96,27,100]
    	}
    	]
    }

    $("#chart").attr('width', '300px');
    $("#chart").attr('height', '300px');

    ChartObject.Line(data);

    $("#spendingLabel").html("Spent $43");
    $("#stockLabel").html("Had 17 items");
    $("#wasteLabel").html("Lost $43");
    $("#dropdown_title").html("Past week");

})
$('#monthSelect').click(function (e) {
	e.preventDefault()
                    // generate graph data here
                    var data = {
                    	labels : ["1 month","3 weeks","2 weeks","1 week","today"],
                    	datasets : [
                    	{
                    		fillColor : "rgba(151,187,205,0.5)",
                    		strokeColor : "rgba(151,187,205,1)",
                    		pointColor : "rgba(151,187,205,1)",
                    		pointStrokeColor : "#fff",
                    		data : [80,50,23,11,43]
                    	}
                    	]
                    }
                    ChartObject.Line(data);

                    $("#spendingLabel").html("Spent $163");
                    $("#stockLabel").html("Had 33 items");
                    $("#wasteLabel").html("Lost $45");
                    $("#dropdown_title").html("Past month");

                })
$('#threeMonthSelect').click(function (e) {
	e.preventDefault()
                    // generate graph data here
                    var data = {
                    	labels : ["3 months","2 months","1 month","today"],
                    	datasets : [
                    	{
                    		fillColor : "rgba(151,187,205,0.5)",
                    		strokeColor : "rgba(151,187,205,1)",
                    		pointColor : "rgba(151,187,205,1)",
                    		pointStrokeColor : "#fff",
                    		data : [80,70,95,44,12]
                    	}
                    	]
                    }
                    ChartObject.Line(data);

                    $("#spendingLabel").html("Spent $344");
                    $("#stockLabel").html("Had 65 items");
                    $("#wasteLabel").html("Lost $99");
                    $("#dropdown_title").html("Past 3 months");
                })
$('#timeOptions li').on('click', function() {
	$('#dropdown_title').html("Last ".concat($(this).find('a').html()));
});

var data = {
	labels : ["6 days","","","","2 days","","today"],
	datasets : [
	{
		fillColor : "rgba(151,187,205,0.5)",
		strokeColor : "rgba(151,187,205,1)",
		pointColor : "rgba(151,187,205,1)",
		pointStrokeColor : "#fff",
		data : [28,48,40,19,96,27,100]
	}
	]
}

$("#chart").attr('width', '300px');
$("#chart").attr('height', '300px');

ChartObject.Line(data);

$("#spendingLabel").html("Spent $43")
$("#stockLabel").html("Had 17 items")
$("#wasteLabel").html("Lost $43")
$("#dropdown_title").html("Past week");
});<commit_msg>Updating trends.js to do actual data processing<commit_after>
// global variables galore
var current_tab = null;
var interestContext = $("#chart").get(0).getContext("2d");
var ChartObject = new Chart(interestContext);

// week select function
function week_select (e) {
    e.preventDefault()
    // generate graph data here
    var computed_data = []
    // need to calculate how far back to look
    // get current date and subtract 7 days (604800000 ms)
    var today = new Date();
    var today_ms = Date.parse(today); // get today in ms since sometime in 1970
    var past_ms = today_ms - 604800000;
    var past = new Date(past_ms);
    // based on currently selected tab, selector is going to vary
    var data_pointer = null;
    if(current_tab == "spending") {
        items.find({date_acquired: {$gte: past}})
    } else if (current_tab == "stock") {

    } else if (current_tab == "waste") {

    } else {
        alert("error! error! D: wahhh")
    }

    var data = {
        labels : ["6 days","5 days","4 days","3 days","2 days","1 day","today"],
        datasets : [
        {
            fillColor : "rgba(151,187,205,0.5)",
            strokeColor : "rgba(151,187,205,1)",
            pointColor : "rgba(151,187,205,1)",
            pointStrokeColor : "#fff",
            data : computed_data
        }
        ]
    }

    $("#chart").attr('width', '300px');
    $("#chart").attr('height', '300px');

    ChartObject.Line(data);

    $("#spendingLabel").html("Spent $43");
    $("#stockLabel").html("Had 17 items");
    $("#wasteLabel").html("Lost $43");
    $("#dropdown_title").html("Past week");

}

$(document).ready(function () {
    // all the odds and ends
	var dropdown = $("#timeSelectDropdown");
	$("#timeSelectDropdownMenu").offset({left: dropdown.offset().left});
    $('#timeOptions li').on('click', function() {
        $('#dropdown_title').html("Last ".concat($(this).find('a').html()));
    });
    $("#chart").attr('width', '300px');
    $("#chart").attr('height', '300px');

    // code for handling tab switches
    // needs to call timeframe select method upon switch
    $('#spending').click(function (e) {
    	e.preventDefault()
        current_tab = "spending"
    	$(this).tab('show')
    })
    $('#stock').click(function (e) {
    	e.preventDefault()
        current_tab = "stock"
    	$(this).tab('show')
    })
    $('#waste').click(function (e) {
    	e.preventDefault()
        current_tab = "waste"
    	$(this).tab('show')
    })
    $('#weekSelect').click()
    $('#monthSelect').click(function (e) {
    	e.preventDefault()
        // generate graph data here
        var data = {
        	labels : ["1 month","3 weeks","2 weeks","1 week","today"],
        	datasets : [
        	{
        		fillColor : "rgba(151,187,205,0.5)",
        		strokeColor : "rgba(151,187,205,1)",
        		pointColor : "rgba(151,187,205,1)",
        		pointStrokeColor : "#fff",
        		data : [80,50,23,11,43]
        	}
        	]
        }
        ChartObject.Line(data);

        $("#spendingLabel").html("Spent $163");
        $("#stockLabel").html("Had 33 items");
        $("#wasteLabel").html("Lost $45");
        $("#dropdown_title").html("Past month");
    })
    $('#threeMonthSelect').click(function (e) {
    	e.preventDefault()
        // generate graph data here
        var data = {
        	labels : ["3 months","2 months","1 month","today"],
        	datasets : [
        	{
        		fillColor : "rgba(151,187,205,0.5)",
        		strokeColor : "rgba(151,187,205,1)",
        		pointColor : "rgba(151,187,205,1)",
        		pointStrokeColor : "#fff",
        		data : [80,70,95,44,12]
        	}
        	]
        }
        ChartObject.Line(data);

        $("#spendingLabel").html("Spent $344");
        $("#stockLabel").html("Had 65 items");
        $("#wasteLabel").html("Lost $99");
        $("#dropdown_title").html("Past 3 months");
    })

    ChartObject.Line(data);

    $("#spendingLabel").html("Spent $43")
    $("#stockLabel").html("Had 17 items")
    $("#wasteLabel").html("Lost $43")
    $("#dropdown_title").html("Past week");
});<|endoftext|>


<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
*/

(function() {
    // special patch to correctly work on Ripple emulator (CB-9760)
    if (window.parent && !!window.parent.ripple) { // https://gist.github.com/triceam/4658021
        module.exports = window.open.bind(window); // fallback to default window.open behaviour
        return;
    }

    var exec = require('cordova/exec');
    var channel = require('cordova/channel');
    var modulemapper = require('cordova/modulemapper');
    var urlutil = require('cordova/urlutil');

    var inAppBrowserInstance = null;
    var lastUrl = '';
    var lastWindowName = '';
    var lasrWindowFeatures = '';

    var InAppBrowser = function() {

        var eventListenersToRestore = {},
            lastPollIntervalToRestore = null,
            lastPollFunctionToRestore = null;

        function clearPolling () {
            lastPollIntervalToRestore = null;
            lastPollFunctionToRestore = null;
        }

        function clearRestoring(){
            clearPolling();
            eventListenersToRestore = {};
        }

        function addEventListenerToRestore(eventname, f){
            if(!f) {
                throw 'the event handler is not defined';
            }
            if(!f.observer_guid) {
                throw 'the event handler does not have an observer GUID. Has the function been subscribed?';
            }

            if(!eventListenersToRestore[eventname]){
                eventListenersToRestore[eventname] = {};
            }
            eventListenersToRestore[eventname][f.observer_guid] = f;
            console.log('Added: ' + eventname + ', ' + f.observer_guid);
        }

        function removeEventListenerToRestore(eventname, f){
            if(!f && !f.observer_guid && !eventListenersToRestore[eventname]) {
                return;
            }
            delete eventListenersToRestore[eventname][f.observer_guid];
        }

        this.channels = {
            'loadstart': channel.create('loadstart'),
            'loadstop' : channel.create('loadstop'),
            'loaderror' : channel.create('loaderror'),
            'hidden' : channel.create('hidden'),
            'unhidden' : channel.create('unhidden'),
            'pollresult' : channel.create('pollresult'),
            'exit' : channel.create('exit')
        }

        this._eventHandler = function(event) {
            if (event && (event.type in this.channels)) {
               this.channels[event.type].fire(event);
            }
        }

        this.close = function(eventname) {
           exec(null, null, "InAppBrowser", "close", []);
           clearRestoring(); //TODO - ensure exit is called.
        }

        this.show = function(eventname) {
            exec(null, null, "InAppBrowser", "show", []);
        }

        this.startPoll = function(pollFunction, pollInterval){
           lastPollInterval = pollInterval;
           lastPollFunction = pollFunction;
           exec(null, null, "InAppBrowser", "startPoll", [pollFunction, pollInterval])
        }

        this.stopPoll = function() {
           clearPolling();
           exec(null, null, "InAppBrowser", "stopPoll", []);
        }

        this.hide = function(releaseResources, eventname){
            var cleanUpCallback = function(){
                for(f in eventListenersToRestore['hidden']){
                    this.channels['hidden'].unsubscribe(f);
                    if(releaseResources){
                        removeEventListenerToRestore('hidden', f);
                        console.log('Removing: hidden , ' + f.observer_guid);
                    }
                }
            }

            for(eventName in eventListenersToRestore){
                if(eventName === 'hidden'){
                    continue; //preserve hide
                }
                for(f in eventListenersToRestore[eventname]){
                    console.log('Removing: ' + eventname + ', ' + f.observer_guid);
                    this.channels[eventname].unsubscribe(f);
                    if(releaseResources){
                        removeEventListenerToRestore(eventname, f);
                    }
                }
            }

            this.channels['exit'].subscribe(cleanUpCallback);

            // Release resources has no effect in native iOS - the IAB
            // Is fully closed & the JS pretends it isn't
            exec(null,null,"InAppBrowser", "hide", [releaseResources]);
        }

        this.unHide = function(strUrl, eventname){
            lastUrl = strUrl || lastUrl;

            // TODO: not sure this is needed
            //            var cb = function(eventname) {
            //               inAppBrowserInstance._eventHandler(eventname);
            //            };

            lastUrl = strUrl;

            for (var callbackName in eventListenersToRestore) {
                console.log('Callback: ' + callbackName)
                var i =0;
                for (var f in eventListenersToRestore[callbackName]) {
                    console.log('Adding: ' + ++i);
                    inAppBrowserInstance.addEventListener(callbackName, f);
                }
            }

            //TODO: show if hidden.
            //TODO: call unhide - don't need to re-esrablish channels etc?
            exec(null, null, "InAppBrowser", "unHide", [lastUrl, lastWindowName, lasrWindowFeatures]);

            //TODO: clean up anything needed for above step
            //TODO: Re-establish polling if URL not changed and have polling information.
            //TODO: look at creating unhide....

        }

        this.addEventListener = function (eventname,f) {
            if (eventname in this.channels) {
                this.channels[eventname].subscribe(f);
                addEventListenerToRestore(eventname, f);
            }
        }

        this.removeEventListener = function (eventname, f) {
            if (eventname in this.channels) {
                removeEventListenerToRestore(eventname, f);
                this.channels[eventname].unsubscribe(f);
            }
        }

        this.executeScript = function (injectDetails, cb) {
            if (injectDetails.code) {
                exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]);
            } else if (injectDetails.file) {
                exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]);
            } else {
                throw new Error('executeScript requires exactly one of code or file to be specified');
            }
        }

        this.insertCSS = function (injectDetails, cb) {
            if (injectDetails.code) {
                exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]);
            } else if (injectDetails.file) {
                exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]);
            } else {
                throw new Error('insertCSS requires exactly one of code or file to be specified');
            }
        }
    }

    module.exports = function(strUrl, strWindowName, strWindowFeatures, callbacks) {
        // Don't catch calls that write to existing frames (e.g. named iframes).
        if (window.frames && window.frames[strWindowName]) {
            var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
            return origOpenFunc.apply(window, arguments);
        }

        strUrl = urlutil.makeAbsolute(strUrl);
        inAppBrowserInstance = new InAppBrowser();

        callbacks = callbacks || {};
        for (var callbackName in callbacks) {
            inAppBrowserInstance.addEventListener(callbackName, callbacks[callbackName]);
        }

        var cb = function(eventname) {
           inAppBrowserInstance._eventHandler(eventname);
        };

        strWindowFeatures = strWindowFeatures || "";

        lastUrl = strUrl;
        lastWindowName = strWindowName;
        lasrWindowFeatures = strWindowFeatures;
        exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
        return inAppBrowserInstance;
    };
})();
<commit_msg>tracing<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
*/

(function() {
    // special patch to correctly work on Ripple emulator (CB-9760)
    if (window.parent && !!window.parent.ripple) { // https://gist.github.com/triceam/4658021
        module.exports = window.open.bind(window); // fallback to default window.open behaviour
        return;
    }

    var exec = require('cordova/exec');
    var channel = require('cordova/channel');
    var modulemapper = require('cordova/modulemapper');
    var urlutil = require('cordova/urlutil');

    var inAppBrowserInstance = null;
    var lastUrl = '';
    var lastWindowName = '';
    var lasrWindowFeatures = '';

    var InAppBrowser = function() {

        var eventListenersToRestore = {},
            lastPollIntervalToRestore = null,
            lastPollFunctionToRestore = null;

        function clearPolling () {
            lastPollIntervalToRestore = null;
            lastPollFunctionToRestore = null;
        }

        function clearRestoring(){
            clearPolling();
            eventListenersToRestore = {};
        }

        function addEventListenerToRestore(eventname, f){
            if(!f) {
                throw 'the event handler is not defined';
            }
            if(!f.observer_guid) {
                throw 'the event handler does not have an observer GUID. Has the function been subscribed?';
            }

            if(!eventListenersToRestore[eventname]){
                eventListenersToRestore[eventname] = {};
            }
            eventListenersToRestore[eventname][f.observer_guid] = f;
            console.log('Added: ' + eventname + ', ' + f.observer_guid);
        }

        function removeEventListenerToRestore(eventname, f){
            if(!f && !f.observer_guid && !eventListenersToRestore[eventname]) {
                return;
            }
            delete eventListenersToRestore[eventname][f.observer_guid];
        }

        this.channels = {
            'loadstart': channel.create('loadstart'),
            'loadstop' : channel.create('loadstop'),
            'loaderror' : channel.create('loaderror'),
            'hidden' : channel.create('hidden'),
            'unhidden' : channel.create('unhidden'),
            'pollresult' : channel.create('pollresult'),
            'exit' : channel.create('exit')
        }

        this._eventHandler = function(event) {
            if (event && (event.type in this.channels)) {
               this.channels[event.type].fire(event);
            }
        }

        this.close = function(eventname) {
           exec(null, null, "InAppBrowser", "close", []);
           clearRestoring(); //TODO - ensure exit is called.
        }

        this.show = function(eventname) {
            exec(null, null, "InAppBrowser", "show", []);
        }

        this.startPoll = function(pollFunction, pollInterval){
           lastPollInterval = pollInterval;
           lastPollFunction = pollFunction;
           exec(null, null, "InAppBrowser", "startPoll", [pollFunction, pollInterval])
        }

        this.stopPoll = function() {
           clearPolling();
           exec(null, null, "InAppBrowser", "stopPoll", []);
        }

        this.hide = function(releaseResources, eventname){
            var cleanUpCallback = function(){
                for(f in eventListenersToRestore['hidden']){
                    this.channels['hidden'].unsubscribe(f);
                    if(releaseResources){
                        removeEventListenerToRestore('hidden', f);
                        console.log('Removing: hidden , ' + f.observer_guid);
                    }
                }
            }

            for(eventName in eventListenersToRestore){
                console.log('Removing for event: ' + eventname);
                if(eventName === 'hidden'){
                    continue; //preserve hide
                }
                for(f in eventListenersToRestore[eventname]){
                    console.log('Removing: ' + eventname + ', ' + f.observer_guid);
                    this.channels[eventname].unsubscribe(f);
                    if(releaseResources){
                        removeEventListenerToRestore(eventname, f);
                    }
                }
            }

            this.channels['exit'].subscribe(cleanUpCallback);

            // Release resources has no effect in native iOS - the IAB
            // Is fully closed & the JS pretends it isn't
            exec(null,null,"InAppBrowser", "hide", [releaseResources]);
        }

        this.unHide = function(strUrl, eventname){
            lastUrl = strUrl || lastUrl;

            // TODO: not sure this is needed
            //            var cb = function(eventname) {
            //               inAppBrowserInstance._eventHandler(eventname);
            //            };

            lastUrl = strUrl;

            for (var callbackName in eventListenersToRestore) {
                console.log('Callback: ' + callbackName)
                var i =0;
                for (var f in eventListenersToRestore[callbackName]) {
                    console.log('Adding: ' + ++i);
                    inAppBrowserInstance.addEventListener(callbackName, f);
                }
            }

            //TODO: show if hidden.
            //TODO: call unhide - don't need to re-esrablish channels etc?
            exec(null, null, "InAppBrowser", "unHide", [lastUrl, lastWindowName, lasrWindowFeatures]);

            //TODO: clean up anything needed for above step
            //TODO: Re-establish polling if URL not changed and have polling information.
            //TODO: look at creating unhide....

        }

        this.addEventListener = function (eventname,f) {
            if (eventname in this.channels) {
                this.channels[eventname].subscribe(f);
                addEventListenerToRestore(eventname, f);
            }
        }

        this.removeEventListener = function (eventname, f) {
            if (eventname in this.channels) {
                removeEventListenerToRestore(eventname, f);
                this.channels[eventname].unsubscribe(f);
            }
        }

        this.executeScript = function (injectDetails, cb) {
            if (injectDetails.code) {
                exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]);
            } else if (injectDetails.file) {
                exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]);
            } else {
                throw new Error('executeScript requires exactly one of code or file to be specified');
            }
        }

        this.insertCSS = function (injectDetails, cb) {
            if (injectDetails.code) {
                exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]);
            } else if (injectDetails.file) {
                exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]);
            } else {
                throw new Error('insertCSS requires exactly one of code or file to be specified');
            }
        }
    }

    module.exports = function(strUrl, strWindowName, strWindowFeatures, callbacks) {
        // Don't catch calls that write to existing frames (e.g. named iframes).
        if (window.frames && window.frames[strWindowName]) {
            var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
            return origOpenFunc.apply(window, arguments);
        }

        strUrl = urlutil.makeAbsolute(strUrl);
        inAppBrowserInstance = new InAppBrowser();

        callbacks = callbacks || {};
        for (var callbackName in callbacks) {
            inAppBrowserInstance.addEventListener(callbackName, callbacks[callbackName]);
        }

        var cb = function(eventname) {
           inAppBrowserInstance._eventHandler(eventname);
        };

        strWindowFeatures = strWindowFeatures || "";

        lastUrl = strUrl;
        lastWindowName = strWindowName;
        lasrWindowFeatures = strWindowFeatures;
        exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
        return inAppBrowserInstance;
    };
})();
<|endoftext|>