<commit_before>import React, { createElement, Component } from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import PropTypes from 'prop-types'
import monolithic from 'fela-monolithic'

import createComponentFactory from '../createComponentFactory'
import createRenderer from '../../createRenderer'

const createComponent = createComponentFactory(createElement, {
  renderer: PropTypes.object,
  theme: PropTypes.object
})
const createComponentWithProxy = createComponentFactory(
  createElement,
  {
    renderer: PropTypes.object,
    theme: PropTypes.object
  },
  true
)

describe('Creating Components from Fela rules', () => {
  it('should return a Component', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponent(rule)

    expect(component).toBeInstanceOf(Function)
  })

  it('should render fela rules depending on the passed props', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponent(rule)

    const renderer = createRenderer()

    const element = component({ color: 'black' }, { renderer })

    expect(element.type).toEqual('div')

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:black}.b{font-size:16}')
  })

  it('should include defaultProps if provided', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })

    const Comp = ({ color, className }) =>

        {color}

    Comp.defaultProps = {
      color: 'red'
    }

    const component = createComponent(rule, Comp)

    const renderer = createRenderer()

    const element = component({}, { renderer })

    console.log(element)

    expect(element.type).toEqual(Comp)

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:red}.b{font-size:16}')
  })

  it('should use the theme for static rendering by default', () => {
    const rule = props => ({
      color: props.theme.color,
      fontSize: 16
    })
    const component = createComponent(rule)
    const renderer = createRenderer()

    const element = component(
      {},
      {
        renderer,
        theme: { color: 'red' }
      }
    )

    expect(element.type).toEqual('div')

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:red}.b{font-size:16}')
  })

  it('should not pass props to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponent(rule, 'div', ['onClick'])

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true,
        color: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).toEqual(undefined)
    expect(element.props.color).toEqual(undefined)
  })

  it('should pass all props to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponent(rule, 'div', Object.keys)

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).not.toEqual(undefined)
  })

  it('should only use passed props to render Fela rules', () => {
    const rule = props => ({
      color: props.foo && props.color,
      fontSize: '16px'
    })
    const component = createComponent(rule, 'div', ['foo'])

    const renderer = createRenderer()

    const element = component(
      {
        foo: true,
        color: 'black'
      },
      { renderer }
    )

    expect(element.props.foo).toEqual(true)
    expect(renderer.rules).toEqual('.a{color:black}.b{font-size:16px}')
  })

  it('should compose styles', () => {
    const rule = () => ({
      color: 'blue',
      fontSize: '16px'
    })

    const anotherRule = () => ({
      color: 'red',
      lineHeight: 1.2
    })

    const Comp = createComponent(rule)
    const ComposedComp = createComponent(anotherRule, Comp)

    const renderer = createRenderer()

    const element = ComposedComp({}, { renderer })
    const renderedElement = element.type(element.props, { renderer })

    expect(renderer.rules).toEqual(
      '.a{color:red}.b{font-size:16px}.c{line-height:1.2}'
    )
    expect(renderedElement.props.className).toEqual('a b c')
  })

  it('should compose passThrough props', () => {
    const component = createComponent(() => ({}), 'div', Object.keys)
    const composedComponent = createComponent(() => ({}), component, [
      'onClick'
    ])

    const renderer = createRenderer()

    const onClick = () => true
    const element = composedComponent({ color: 'red' }, { renderer })
    const renderedElement = element.type(
      {
        ...element.props,
        onClick
      },
      { renderer }
    )

    expect(renderedElement.props.color).toEqual('red')
    expect(renderedElement.props.onClick).toEqual(onClick)
  })

  it('should only use the rule name as displayName', () => {
    const Button = () => ({
      color: 'red',
      fontSize: 16
    })
    const component = createComponent(Button)

    expect(component.displayName).toEqual('Button')
  })

  it('should use a dev-friendly className with monolithic renderer', () => {
    const Button = () => ({ fontSize: 16 })

    const component = createComponent(Button)

    const renderer = createRenderer({
      enhancers: [monolithic({ prettySelectors: true })]
    })

    const element = component({ color: 'black' }, { renderer })

    expect(element.props.className).toEqual('Button_div__abrv9k')
    expect(renderer.rules).toEqual('.Button_div__abrv9k{font-size:16}')
  })

  it('should use a dev-friendly className and the selectorPrefix', () => {
    const Button = () => ({ fontSize: 16 })

    const component = createComponent(Button)

    const renderer = createRenderer({
      enhancers: [monolithic({ prettySelectors: true })],
      selectorPrefix: 'Fela-'
    })

    const element = component({ color: 'black' }, { renderer })

    expect(element.props.className).toEqual('Fela-Button_div__abrv9k')
    expect(renderer.rules).toEqual('.Fela-Button_div__abrv9k{font-size:16}')
  })

  it('should only use the rule name as displayName', () => {
    const Button = () => ({
      color: 'red',
      fontSize: 16
    })
    const component = createComponent(Button)
    const renderer = createRenderer()
    const buttonInstance = component({ is: 'button' }, { renderer })

    expect(buttonInstance.type).toEqual('button')
  })
})

describe('Creating Components with a Proxy for props from Fela rules', () => {
  it('should return a Component', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule)

    expect(component).toBeInstanceOf(Function)
  })

  it('should render fela rules depending on the passed props', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule)

    const renderer = createRenderer()

    const element = component({ color: 'black' }, { renderer })

    expect(element.type).toEqual('div')

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:black}.b{font-size:16}')
  })

  it('should use the theme for static rendering by default', () => {
    const rule = props => ({
      color: props.theme.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule)
    const renderer = createRenderer()

    const element = component(
      {},
      {
        renderer,
        theme: { color: 'red' }
      }
    )

    expect(element.type).toEqual('div')

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:red}.b{font-size:16}')
  })

  it('should not pass props used in rules to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule, 'div')

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true,
        color: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).toEqual(true)
    expect(element.props.color).toEqual(undefined)
  })

  it('should pass props used in rules specified in passThroughProps to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule, 'div', ['color'])

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true,
        color: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).toEqual(true)
    expect(element.props.color).toEqual(true)
  })

  it('should pass all props to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule, 'div', Object.keys)

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).not.toEqual(undefined)
  })

  it('should only use passed props to render Fela rules', () => {
    const rule = props => ({
      color: props.foo && props.color,
      fontSize: '16px'
    })
    const component = createComponentWithProxy(rule, 'div', ['foo'])

    const renderer = createRenderer()

    const element = component(
      {
        foo: true,
        color: 'black'
      },
      { renderer }
    )

    expect(element.props.foo).toEqual(true)
    expect(renderer.rules).toEqual('.a{color:black}.b{font-size:16px}')
  })

  it('should compose styles', () => {
    const rule = () => ({
      color: 'blue',
      fontSize: '16px'
    })

    const anotherRule = () => ({
      color: 'red',
      lineHeight: 1.2
    })

    const Comp = createComponentWithProxy(rule)
    const ComposedComp = createComponentWithProxy(anotherRule, Comp)

    const renderer = createRenderer()

    const element = ComposedComp({}, { renderer })
    const renderedElement = element.type(element.props, { renderer })

    expect(renderer.rules).toEqual(
      '.a{color:red}.b{font-size:16px}.c{line-height:1.2}'
    )
    expect(renderedElement.props.className).toEqual('a b c')
  })

  it('should compose passThrough props', () => {
    const component = createComponentWithProxy(() => ({}), 'div', Object.keys)
    const composedComponent = createComponentWithProxy(() => ({}), component, [
      'onClick'
    ])

    const renderer = createRenderer()

    const onClick = () => true
    const element = composedComponent({ color: 'red' }, { renderer })
    const renderedElement = element.type(
      {
        ...element.props,
        onClick
      },
      { renderer }
    )

    expect(renderedElement.props.color).toEqual('red')
    expect(renderedElement.props.onClick).toEqual(onClick)
  })

  it('should only use the rule name as displayName', () => {
    const Button = () => ({
      color: 'red',
      fontSize: 16
    })
    const component = createComponentWithProxy(Button)

    expect(component.displayName).toEqual('Button')
  })

  it('should use a dev-friendly className with monolithic renderer', () => {
    const Button = () => ({ fontSize: 16 })

    const component = createComponentWithProxy(Button)

    const renderer = createRenderer({
      enhancers: [monolithic({ prettySelectors: true })]
    })

    const element = component({ color: 'black' }, { renderer })

    expect(element.props.className).toEqual('Button_div__abrv9k')
    expect(renderer.rules).toEqual('.Button_div__abrv9k{font-size:16}')
  })

  it('should use a dev-friendly className and the selectorPrefix', () => {
    const Button = () => ({ fontSize: 16 })

    const component = createComponentWithProxy(Button)

    const renderer = createRenderer({
      enhancers: [monolithic({ prettySelectors: true })],
      selectorPrefix: 'Fela-'
    })

    const element = component({ color: 'black' }, { renderer })

    expect(element.props.className).toEqual('Fela-Button_div__abrv9k')
    expect(renderer.rules).toEqual('.Fela-Button_div__abrv9k{font-size:16}')
  })

  it('should only use the rule name as displayName', () => {
    const Button = () => ({
      color: 'red',
      fontSize: 16
    })
    const component = createComponentWithProxy(Button)
    const renderer = createRenderer()
    const buttonInstance = component({ is: 'button' }, { renderer })

    expect(buttonInstance.type).toEqual('button')
  })
})
<commit_msg>Update createComponentFactory-test.js<commit_after>import { createElement } from 'react'
import PropTypes from 'prop-types'
import monolithic from 'fela-monolithic'

import createComponentFactory from '../createComponentFactory'
import createRenderer from '../../createRenderer'

const createComponent = createComponentFactory(createElement, {
  renderer: PropTypes.object,
  theme: PropTypes.object
})
const createComponentWithProxy = createComponentFactory(
  createElement,
  {
    renderer: PropTypes.object,
    theme: PropTypes.object
  },
  true
)

describe('Creating Components from Fela rules', () => {
  it('should return a Component', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponent(rule)

    expect(component).toBeInstanceOf(Function)
  })

  it('should render fela rules depending on the passed props', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponent(rule)

    const renderer = createRenderer()

    const element = component({ color: 'black' }, { renderer })

    expect(element.type).toEqual('div')

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:black}.b{font-size:16}')
  })

  it('should include defaultProps if provided', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })

    const Comp = ({ color, className }) =>

        {color}

    Comp.defaultProps = {
      color: 'red'
    }

    const component = createComponent(rule, Comp)

    const renderer = createRenderer()

    const element = component({}, { renderer })

    console.log(element)

    expect(element.type).toEqual(Comp)

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:red}.b{font-size:16}')
  })

  it('should use the theme for static rendering by default', () => {
    const rule = props => ({
      color: props.theme.color,
      fontSize: 16
    })
    const component = createComponent(rule)
    const renderer = createRenderer()

    const element = component(
      {},
      {
        renderer,
        theme: { color: 'red' }
      }
    )

    expect(element.type).toEqual('div')

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:red}.b{font-size:16}')
  })

  it('should not pass props to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponent(rule, 'div', ['onClick'])

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true,
        color: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).toEqual(undefined)
    expect(element.props.color).toEqual(undefined)
  })

  it('should pass all props to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponent(rule, 'div', Object.keys)

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).not.toEqual(undefined)
  })

  it('should only use passed props to render Fela rules', () => {
    const rule = props => ({
      color: props.foo && props.color,
      fontSize: '16px'
    })
    const component = createComponent(rule, 'div', ['foo'])

    const renderer = createRenderer()

    const element = component(
      {
        foo: true,
        color: 'black'
      },
      { renderer }
    )

    expect(element.props.foo).toEqual(true)
    expect(renderer.rules).toEqual('.a{color:black}.b{font-size:16px}')
  })

  it('should compose styles', () => {
    const rule = () => ({
      color: 'blue',
      fontSize: '16px'
    })

    const anotherRule = () => ({
      color: 'red',
      lineHeight: 1.2
    })

    const Comp = createComponent(rule)
    const ComposedComp = createComponent(anotherRule, Comp)

    const renderer = createRenderer()

    const element = ComposedComp({}, { renderer })
    const renderedElement = element.type(element.props, { renderer })

    expect(renderer.rules).toEqual(
      '.a{color:red}.b{font-size:16px}.c{line-height:1.2}'
    )
    expect(renderedElement.props.className).toEqual('a b c')
  })

  it('should compose passThrough props', () => {
    const component = createComponent(() => ({}), 'div', Object.keys)
    const composedComponent = createComponent(() => ({}), component, [
      'onClick'
    ])

    const renderer = createRenderer()

    const onClick = () => true
    const element = composedComponent({ color: 'red' }, { renderer })
    const renderedElement = element.type(
      {
        ...element.props,
        onClick
      },
      { renderer }
    )

    expect(renderedElement.props.color).toEqual('red')
    expect(renderedElement.props.onClick).toEqual(onClick)
  })

  it('should only use the rule name as displayName', () => {
    const Button = () => ({
      color: 'red',
      fontSize: 16
    })
    const component = createComponent(Button)

    expect(component.displayName).toEqual('Button')
  })

  it('should use a dev-friendly className with monolithic renderer', () => {
    const Button = () => ({ fontSize: 16 })

    const component = createComponent(Button)

    const renderer = createRenderer({
      enhancers: [monolithic({ prettySelectors: true })]
    })

    const element = component({ color: 'black' }, { renderer })

    expect(element.props.className).toEqual('Button_div__abrv9k')
    expect(renderer.rules).toEqual('.Button_div__abrv9k{font-size:16}')
  })

  it('should use a dev-friendly className and the selectorPrefix', () => {
    const Button = () => ({ fontSize: 16 })

    const component = createComponent(Button)

    const renderer = createRenderer({
      enhancers: [monolithic({ prettySelectors: true })],
      selectorPrefix: 'Fela-'
    })

    const element = component({ color: 'black' }, { renderer })

    expect(element.props.className).toEqual('Fela-Button_div__abrv9k')
    expect(renderer.rules).toEqual('.Fela-Button_div__abrv9k{font-size:16}')
  })

  it('should only use the rule name as displayName', () => {
    const Button = () => ({
      color: 'red',
      fontSize: 16
    })
    const component = createComponent(Button)
    const renderer = createRenderer()
    const buttonInstance = component({ is: 'button' }, { renderer })

    expect(buttonInstance.type).toEqual('button')
  })
})

describe('Creating Components with a Proxy for props from Fela rules', () => {
  it('should return a Component', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule)

    expect(component).toBeInstanceOf(Function)
  })

  it('should render fela rules depending on the passed props', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule)

    const renderer = createRenderer()

    const element = component({ color: 'black' }, { renderer })

    expect(element.type).toEqual('div')

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:black}.b{font-size:16}')
  })

  it('should use the theme for static rendering by default', () => {
    const rule = props => ({
      color: props.theme.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule)
    const renderer = createRenderer()

    const element = component(
      {},
      {
        renderer,
        theme: { color: 'red' }
      }
    )

    expect(element.type).toEqual('div')

    expect(element.props.className).toEqual('a b')
    expect(renderer.rules).toEqual('.a{color:red}.b{font-size:16}')
  })

  it('should not pass props used in rules to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule, 'div')

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true,
        color: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).toEqual(true)
    expect(element.props.color).toEqual(undefined)
  })

  it('should pass props used in rules specified in passThroughProps to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule, 'div', ['color'])

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true,
        color: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).toEqual(true)
    expect(element.props.color).toEqual(true)
  })

  it('should pass all props to the element', () => {
    const rule = props => ({
      color: props.color,
      fontSize: 16
    })
    const component = createComponentWithProxy(rule, 'div', Object.keys)

    const renderer = createRenderer()

    const element = component(
      {
        onClick: false,
        onHover: true
      },
      { renderer }
    )

    expect(element.props.onClick).toEqual(false)
    expect(element.props.onHover).not.toEqual(undefined)
  })

  it('should only use passed props to render Fela rules', () => {
    const rule = props => ({
      color: props.foo && props.color,
      fontSize: '16px'
    })
    const component = createComponentWithProxy(rule, 'div', ['foo'])

    const renderer = createRenderer()

    const element = component(
      {
        foo: true,
        color: 'black'
      },
      { renderer }
    )

    expect(element.props.foo).toEqual(true)
    expect(renderer.rules).toEqual('.a{color:black}.b{font-size:16px}')
  })

  it('should compose styles', () => {
    const rule = () => ({
      color: 'blue',
      fontSize: '16px'
    })

    const anotherRule = () => ({
      color: 'red',
      lineHeight: 1.2
    })

    const Comp = createComponentWithProxy(rule)
    const ComposedComp = createComponentWithProxy(anotherRule, Comp)

    const renderer = createRenderer()

    const element = ComposedComp({}, { renderer })
    const renderedElement = element.type(element.props, { renderer })

    expect(renderer.rules).toEqual(
      '.a{color:red}.b{font-size:16px}.c{line-height:1.2}'
    )
    expect(renderedElement.props.className).toEqual('a b c')
  })

  it('should compose passThrough props', () => {
    const component = createComponentWithProxy(() => ({}), 'div', Object.keys)
    const composedComponent = createComponentWithProxy(() => ({}), component, [
      'onClick'
    ])

    const renderer = createRenderer()

    const onClick = () => true
    const element = composedComponent({ color: 'red' }, { renderer })
    const renderedElement = element.type(
      {
        ...element.props,
        onClick
      },
      { renderer }
    )

    expect(renderedElement.props.color).toEqual('red')
    expect(renderedElement.props.onClick).toEqual(onClick)
  })

  it('should only use the rule name as displayName', () => {
    const Button = () => ({
      color: 'red',
      fontSize: 16
    })
    const component = createComponentWithProxy(Button)

    expect(component.displayName).toEqual('Button')
  })

  it('should use a dev-friendly className with monolithic renderer', () => {
    const Button = () => ({ fontSize: 16 })

    const component = createComponentWithProxy(Button)

    const renderer = createRenderer({
      enhancers: [monolithic({ prettySelectors: true })]
    })

    const element = component({ color: 'black' }, { renderer })

    expect(element.props.className).toEqual('Button_div__abrv9k')
    expect(renderer.rules).toEqual('.Button_div__abrv9k{font-size:16}')
  })

  it('should use a dev-friendly className and the selectorPrefix', () => {
    const Button = () => ({ fontSize: 16 })

    const component = createComponentWithProxy(Button)

    const renderer = createRenderer({
      enhancers: [monolithic({ prettySelectors: true })],
      selectorPrefix: 'Fela-'
    })

    const element = component({ color: 'black' }, { renderer })

    expect(element.props.className).toEqual('Fela-Button_div__abrv9k')
    expect(renderer.rules).toEqual('.Fela-Button_div__abrv9k{font-size:16}')
  })

  it('should only use the rule name as displayName', () => {
    const Button = () => ({
      color: 'red',
      fontSize: 16
    })
    const component = createComponentWithProxy(Button)
    const renderer = createRenderer()
    const buttonInstance = component({ is: 'button' }, { renderer })

    expect(buttonInstance.type).toEqual('button')
  })
})
<|endoftext|>


<commit_before>/*!
 * Copyright (c) 2015-2019 Cisco Systems, Inc. See LICENSE file.
 */

import '@webex/internal-plugin-wdm';
import {partition} from 'lodash';
import {WebexPlugin} from '@webex/webex-core';

const Feature = WebexPlugin.extend({
  namespace: 'Feature',

  /**
   * Returns the value of the requested feature toggle.
   * @param {string} keyType <developer|user|entitlement>
   * @param {string} key
   * @param {Object} options
   * @param {boolean} options.full to get full feature record including metadata.
   * @returns {string|boolean|number|FeatureModel|null}
   */
  getFeature(keyType, key, options) {
    if (keyType !== 'developer' && keyType !== 'user' && keyType !== 'entitlement') {
      return Promise.reject(new Error('Invalid feature keyType provided. Only `developer`, `user`, and `entitlement` feature toggles are permitted.'));
    }

    options = options || {};

    const feature = this.webex.internal.device.features[keyType].get(key);

    if (!feature) {
      return Promise.resolve(null);
    }

    if (options.full) {
      return Promise.resolve(feature.serialize());
    }

    return Promise.resolve(feature.value);
  },

  /**
   * Handles a feature toggle update from the server.
   * @param {Object} envelope
   * @returns {undefined}
   */
  handleFeatureUpdate(envelope) {
    if (envelope && envelope.data) {
      const feature = envelope.data.featureToggle;
      const keyType = feature.type.toLowerCase();

      if (keyType === 'user' || keyType === 'developer') {
        this.webex.internal.device.features[keyType].add([feature], {merge: true});
      }
    }
  },

  /**
   * Register to listen for incoming feature events
   * @instance
   * @returns {undefined}
   */
  listen() {
    this.listenTo(this.webex.internal.mercury, 'event:featureToggle_update', this.handleFeatureUpdate);
  },

  /**
   * Issues request to server to set a value for a feature toggle.
   * @param {string} keyType <developer|user>
   * @param {string} key
   * @param {string} value
   * @returns {Promise} Refreshes the local device and resolves with the features endpoint's response.
   */
  setFeature(keyType, key, value) {
    // Limit only to developer feature toggles for now.
    if (keyType !== 'developer' && keyType !== 'user') {
      return Promise.reject(new Error('Only `developer` and `user` feature toggles can be set.'));
    }

    return this.request({
      method: 'POST',
      api: 'feature',
      resource: `features/users/${this.webex.internal.device.userId}/${keyType}`,
      body: {
        key,
        mutable: true,
        val: value
      }
    })
      .then((res) => this.webex.internal.device.features[keyType].add(res.body, {merge: true}));
  },

  /**
   * Issues request to server to set a value for a feature toggle.
   * @param {array} featureList
   * @returns {Promise} Refreshes the local device and resolves with the features endpoint`s response.
   */
  setBundledFeatures(featureList) {
    featureList.forEach((item) => {
      item.mutable = item.mutable || 'true';
      if (item.type !== 'USER' && item.type !== 'DEV') {
        item.type = 'USER';
      }
    });

    return this.request({
      method: 'POST',
      api: 'feature',
      resource: `features/users/${this.webex.internal.device.userId}/toggles`,
      body: featureList
    })
      .then((res) => {
        const partitionedToggles = partition(res.body.featureToggles, {type: 'USER'});

        this.webex.internal.device.features.user.add(partitionedToggles[0], {merge: true});
        this.webex.internal.device.features.developer.add(partitionedToggles[1], {merge: true});
      });
  },

  initialize(...args) {
    Reflect.apply(WebexPlugin.prototype.initialize, this, args);

    this.listenToAndRun(this.webex, 'change:internal.device.features.developer', this.trigger.bind(this, 'change:developer'));
    this.listenToAndRun(this.webex, 'change:internal.device.features.entitlement', this.trigger.bind(this, 'change:entitlement'));
    this.listenToAndRun(this.webex, 'change:internal.device.features.user', this.trigger.bind(this, 'change:user'));
  }
});

export default Feature;
<commit_msg>refactor(internal-plugin-feature): migrate to device<commit_after>/*!
 * Copyright (c) 2015-2019 Cisco Systems, Inc. See LICENSE file.
 */

import '@webex/internal-plugin-device';
import {partition} from 'lodash';
import {WebexPlugin} from '@webex/webex-core';

const Feature = WebexPlugin.extend({
  namespace: 'Feature',

  /**
   * Returns the value of the requested feature toggle.
   * @param {string} keyType <developer|user|entitlement>
   * @param {string} key
   * @param {Object} options
   * @param {boolean} options.full to get full feature record including metadata.
   * @returns {string|boolean|number|FeatureModel|null}
   */
  getFeature(keyType, key, options) {
    if (keyType !== 'developer' && keyType !== 'user' && keyType !== 'entitlement') {
      return Promise.reject(new Error('Invalid feature keyType provided. Only `developer`, `user`, and `entitlement` feature toggles are permitted.'));
    }

    options = options || {};

    const feature = this.webex.internal.device.features[keyType].get(key);

    if (!feature) {
      return Promise.resolve(null);
    }

    if (options.full) {
      return Promise.resolve(feature.serialize());
    }

    return Promise.resolve(feature.value);
  },

  /**
   * Handles a feature toggle update from the server.
   * @param {Object} envelope
   * @returns {undefined}
   */
  handleFeatureUpdate(envelope) {
    if (envelope && envelope.data) {
      const feature = envelope.data.featureToggle;
      const keyType = feature.type.toLowerCase();

      if (keyType === 'user' || keyType === 'developer') {
        this.webex.internal.device.features[keyType].add([feature], {merge: true});
      }
    }
  },

  /**
   * Register to listen for incoming feature events
   * @instance
   * @returns {undefined}
   */
  listen() {
    this.listenTo(this.webex.internal.mercury, 'event:featureToggle_update', this.handleFeatureUpdate);
  },

  /**
   * Issues request to server to set a value for a feature toggle.
   * @param {string} keyType <developer|user>
   * @param {string} key
   * @param {string} value
   * @returns {Promise} Refreshes the local device and resolves with the features endpoint's response.
   */
  setFeature(keyType, key, value) {
    // Limit only to developer feature toggles for now.
    if (keyType !== 'developer' && keyType !== 'user') {
      return Promise.reject(new Error('Only `developer` and `user` feature toggles can be set.'));
    }

    return this.request({
      method: 'POST',
      api: 'feature',
      resource: `features/users/${this.webex.internal.device.userId}/${keyType}`,
      body: {
        key,
        mutable: true,
        val: value
      }
    })
      .then((res) => this.webex.internal.device.features[keyType].add(res.body, {merge: true}));
  },

  /**
   * Issues request to server to set a value for a feature toggle.
   * @param {array} featureList
   * @returns {Promise} Refreshes the local device and resolves with the features endpoint`s response.
   */
  setBundledFeatures(featureList) {
    featureList.forEach((item) => {
      item.mutable = item.mutable || 'true';
      if (item.type !== 'USER' && item.type !== 'DEV') {
        item.type = 'USER';
      }
    });

    return this.request({
      method: 'POST',
      api: 'feature',
      resource: `features/users/${this.webex.internal.device.userId}/toggles`,
      body: featureList
    })
      .then((res) => {
        const partitionedToggles = partition(res.body.featureToggles, {type: 'USER'});

        this.webex.internal.device.features.user.add(partitionedToggles[0], {merge: true});
        this.webex.internal.device.features.developer.add(partitionedToggles[1], {merge: true});
      });
  },

  initialize(...args) {
    Reflect.apply(WebexPlugin.prototype.initialize, this, args);

    this.listenToAndRun(this.webex, 'change:internal.device.features.developer', this.trigger.bind(this, 'change:developer'));
    this.listenToAndRun(this.webex, 'change:internal.device.features.entitlement', this.trigger.bind(this, 'change:entitlement'));
    this.listenToAndRun(this.webex, 'change:internal.device.features.user', this.trigger.bind(this, 'change:user'));
  }
});

export default Feature;
<|endoftext|>


<commit_before>const React = require('react');
const importJsx = require('import-jsx');
const { Static, Box } = require('ink');
const {
  STATUS_NOT_STARTED,
  STATUS_RUNNING,
  STATUS_SUCCEEDED,
  STATUS_FAILED,
} = require('../../task-runner');
const {
  TASK_TYPE_PREPARE,
  TASK_TYPE_START,
  TASK_TYPE_FETCH_STORIES,
  TASK_TYPE_TESTS,
  TASK_TYPE_TEST,
  TASK_TYPE_STOP,
} = require('../../constants');

const Task = importJsx('./Task');
const FailedTest = importJsx('./FailedTest');

const collectRecursively = (predicate, tasks, collection = []) => {
  for (let i = 0; i < tasks.length; i++) {
    const task = tasks[i];
    if (predicate(task)) {
      collection.push(task);
    }
    if (task.tasks) {
      return collectRecursively(predicate, task.tasks, collection);
    }
  }
  return collection;
};

const isRunningTest = task =>
  task.status === STATUS_RUNNING && task.meta.type === TASK_TYPE_TEST;

const isFailedTest = task =>
  task.status === STATUS_FAILED && task.meta.type === TASK_TYPE_TEST;

const isPassingTest = task =>
  task.status === STATUS_SUCCEEDED && task.meta.type === TASK_TYPE_TEST;

const groupByKind = testTasks =>
  testTasks.reduce((acc, task) => {
    const key = `${task.meta.target}/${task.meta.configuration}/${task.meta.kind}`;
    if (!acc[key]) {
      acc[key] = {
        target: task.meta.target,
        configuration: task.meta.configuration,
        kind: task.meta.kind,
        tasks: [],
      };
    }
    acc[key].tasks.push(task);
    return acc;
  }, {});

const KindTask = ({ status, target, configuration, kind }) => (
  <Task status={status} prefix={`${target}/${configuration}/`} title={kind} />
);

const TARGET_TASK_TITLE_MAP = {
  [TASK_TYPE_PREPARE]: 'Preparing',
  [TASK_TYPE_START]: 'Starting',
  [TASK_TYPE_FETCH_STORIES]: 'Fetching stories',
  [TASK_TYPE_TESTS]: 'Running tests',
  [TASK_TYPE_STOP]: 'Stopping',
};
const TargetTask = ({ status, target, tasks }) => {
  const currentTask =
    tasks &&
    tasks.find(
      task =>
        task.status === STATUS_NOT_STARTED || task.status === STATUS_RUNNING
    );
  const taskTitle = currentTask && TARGET_TASK_TITLE_MAP[currentTask.meta.type];

  return (
    <Task
      status={status}
      title={`${target}${
        status !== STATUS_FAILED && taskTitle ? `: ${taskTitle}` : ''
      }`}
    />
  );
};

const TaskList = ({ tasks }) => {
  const passedTests = collectRecursively(isPassingTest, tasks);
  const runningTests = collectRecursively(isRunningTest, tasks);
  const failedTests = collectRecursively(isFailedTest, tasks);
  const passedKinds = groupByKind(passedTests);
  const runningKinds = groupByKind(runningTests);
  const failedKinds = groupByKind(failedTests);
  const fullyFailedKindKeys = Object.keys(failedKinds).filter(
    key => !runningKinds[key]
  );
  const fullyPassedKindKeys = Object.keys(passedKinds).filter(
    key => !runningKinds[key] && !failedKinds[key]
  );

  return (
    <Box flexDirection="column">
      <Static>
        {fullyPassedKindKeys
          .map(key => (
            <KindTask
              key={key}
              status={STATUS_SUCCEEDED}
              {...passedKinds[key]}
            />
          ))
          .concat(
            fullyFailedKindKeys.map(key => (
              <React.Fragment key={key}>
                <KindTask status={STATUS_FAILED} {...failedKinds[key]} />
                {failedKinds[key].tasks.map(task => (
                  <FailedTest
                    key={task.id}
                    title={task.meta.story}
                    error={task.error}
                  />
                ))}
              </React.Fragment>
            ))
          )}
      </Static>
      {Object.keys(runningKinds).map(key => (
        <React.Fragment key={key}>
          <KindTask status={STATUS_RUNNING} {...runningKinds[key]} />
          {failedKinds[key] &&
            failedKinds[key].tasks.map(task => (
              <FailedTest
                key={task.id}
                title={task.meta.story}
                error={task.error}
              />
            ))}
        </React.Fragment>
      ))}
      {tasks.map(task => (
        <TargetTask
          key={task.id}
          status={task.status}
          target={task.id}
          tasks={task.tasks}
        />
      ))}
    </Box>
  );
};

module.exports = TaskList;
<commit_msg>Fix garbled output in interactive renderer due to ink bug<commit_after>const React = require('react');
const importJsx = require('import-jsx');
const { Static, Box } = require('ink');
const {
  STATUS_NOT_STARTED,
  STATUS_RUNNING,
  STATUS_SUCCEEDED,
  STATUS_FAILED,
} = require('../../task-runner');
const {
  TASK_TYPE_PREPARE,
  TASK_TYPE_START,
  TASK_TYPE_FETCH_STORIES,
  TASK_TYPE_TESTS,
  TASK_TYPE_TEST,
  TASK_TYPE_STOP,
} = require('../../constants');

const Task = importJsx('./Task');
const FailedTest = importJsx('./FailedTest');

const collectRecursively = (predicate, tasks, collection = []) => {
  for (let i = 0; i < tasks.length; i++) {
    const task = tasks[i];
    if (predicate(task)) {
      collection.push(task);
    }
    if (task.tasks) {
      return collectRecursively(predicate, task.tasks, collection);
    }
  }
  return collection;
};

const isRunningTest = task =>
  task.status === STATUS_RUNNING && task.meta.type === TASK_TYPE_TEST;

const isCompletedTest = task =>
  (task.status === STATUS_FAILED || task.status === STATUS_SUCCEEDED) &&
  task.meta.type === TASK_TYPE_TEST;

const isFailedTest = task =>
  task.status === STATUS_FAILED && task.meta.type === TASK_TYPE_TEST;

const groupByKind = testTasks =>
  testTasks.reduce((acc, task) => {
    const key = `${task.meta.target}/${task.meta.configuration}/${task.meta.kind}`;
    if (!acc[key]) {
      acc[key] = {
        target: task.meta.target,
        configuration: task.meta.configuration,
        kind: task.meta.kind,
        tasks: [],
      };
    }
    acc[key].tasks.push(task);
    return acc;
  }, {});

const KindTask = ({ status, target, configuration, kind }) => (
  <Task status={status} prefix={`${target}/${configuration}/`} title={kind} />
);

const TARGET_TASK_TITLE_MAP = {
  [TASK_TYPE_PREPARE]: 'Preparing',
  [TASK_TYPE_START]: 'Starting',
  [TASK_TYPE_FETCH_STORIES]: 'Fetching stories',
  [TASK_TYPE_TESTS]: 'Running tests',
  [TASK_TYPE_STOP]: 'Stopping',
};
const TargetTask = ({ status, target, tasks }) => {
  const currentTask =
    tasks &&
    tasks.find(
      task =>
        task.status === STATUS_NOT_STARTED || task.status === STATUS_RUNNING
    );
  const taskTitle = currentTask && TARGET_TASK_TITLE_MAP[currentTask.meta.type];

  return (
    <Task
      status={status}
      title={`${target}${
        status !== STATUS_FAILED && taskTitle ? `: ${taskTitle}` : ''
      }`}
    />
  );
};

const renderFailedTasks = tasks =>
  tasks
    .filter(isFailedTest)
    .map(task => (
      <FailedTest key={task.id} title={task.meta.story} error={task.error} />
    ));

const renderKinds = kinds =>
  kinds.map(({ key, status, target, configuration, kind, tasks }) => (
    <React.Fragment key={key}>
      <KindTask
        status={status}
        target={target}
        configuration={configuration}
        kind={kind}
      />
      {renderFailedTasks(tasks)}
    </React.Fragment>
  ));

const TaskList = ({ tasks }) => {
  const runningGrouped = groupByKind(collectRecursively(isRunningTest, tasks));
  const running = Object.keys(runningGrouped).map(key => ({
    key,
    ...runningGrouped[key],
    status: STATUS_RUNNING,
  }));

  const completedGrouped = groupByKind(
    collectRecursively(isCompletedTest, tasks)
  );
  const completed = Object.keys(completedGrouped)
    .filter(key => !runningGrouped[key])
    .map(key => ({
      key,
      ...completedGrouped[key],
      status: completedGrouped[key].tasks.find(
        test => test.status === STATUS_FAILED
      )
        ? STATUS_FAILED
        : STATUS_SUCCEEDED,
      completedAt: completedGrouped[key].tasks.reduce(
        (acc, task) => Math.max(acc, task.completedAt),
        0
      ),
    }))
    .sort((a, b) => a.completedAt - b.completedAt);

  return (
    <Box flexDirection="column">
      <Static>{renderKinds(completed)}</Static>
      {renderKinds(running)}
      {tasks.map(task => (
        <TargetTask
          key={task.id}
          status={task.status}
          target={task.id}
          tasks={task.tasks}
        />
      ))}
    </Box>
  );
};

module.exports = TaskList;
<|endoftext|>


<commit_before>var $ = window.jQuery;

function init (id, lg, urls) {
  /*
    Custom functionality for the language picker modal:

    * Checks for forever.language value on localStorage on page load. If
      not found, opens the modal.
    * On clicking modal link, sets forever.language on localStorage before
      navigating to new page.
  */

  var app_lg;
  var no_redirect = localStorage.getItem('no_redirect');
  var $lp = $(id);

  if (no_redirect) {
    localStorage.setItem('no_redirect', null);
  }

  $lp.click(function (e) {
    /*
      Delegated event listener to watch for clicks on modal link.
    */
    var lg;

    e.preventDefault();

    if (lg = $(e.target).data('lang')) {
      localStorage.setItem('forever.language', JSON.stringify(lg));
    }

    window.location.href = e.target.href;
  });

  if (!(app_lg = JSON.parse(localStorage.getItem('forever.language')))) {
    $lp.openModal();
  } else if (app_lg !== lg && !no_redirect) {
    localStorage.setItem('no_redirect', true);
    window.location.href = urls[app_lg];
  }
}

module.exports = init;
<commit_msg>Actually remove no_redirect<commit_after>var $ = window.jQuery;

function init (id, lg, urls) {
  /*
    Custom functionality for the language picker modal:

    * Checks for forever.language value on localStorage on page load. If
      not found, opens the modal.
    * On clicking modal link, sets forever.language on localStorage before
      navigating to new page.
  */

  var app_lg;
  var no_redirect = localStorage.getItem('no_redirect');
  var $lp = $(id);

  if (no_redirect) {
    localStorage.removeItem('no_redirect');
  }

  $lp.click(function (e) {
    /*
      Delegated event listener to watch for clicks on modal link.
    */
    var lg;

    e.preventDefault();

    if (lg = $(e.target).data('lang')) {
      localStorage.setItem('forever.language', JSON.stringify(lg));
    }

    window.location.href = e.target.href;
  });

  if (!(app_lg = JSON.parse(localStorage.getItem('forever.language')))) {
    $lp.openModal();
  } else if (app_lg !== lg && !no_redirect) {
    localStorage.setItem('no_redirect', true);
    window.location.href = urls[app_lg];
  }
}

module.exports = init;
<|endoftext|>


<commit_before>//import * as TensorTools from "../util/TensorTools.js";

/**
 * Test performancce of conditional and unconditional branch.
 *
 * @see {@link https://jsperf.com/colorfulcakechen-conditional-unconditional-branch}
 */

/**
 * A test set.
 */
class TestSet {

  /**
   */
  constructor( a, b, c, d ) {

    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;

    this.arrayOp = new Array( 4 );

    if ( this.a ) {
      this.aOp = TestSet.a1;
      this.arrayOp[ 0 ] = TestSet.a1.bind( this );
    } else {
      this.aOp = TestSet.a2;
      this.arrayOp[ 0 ] = TestSet.a2.bind( this );
    }

    if ( this.b ) {
      this.bOp = TestSet.b3;
      this.arrayOp[ 1 ] = TestSet.b3.bind( this );
    } else {
      this.bOp = TestSet.b4;
      this.arrayOp[ 1 ] = TestSet.b4.bind( this );
    }

    if ( this.c ) {
      this.cOp = TestSet.c5;
      this.arrayOp[ 2 ] = TestSet.c5.bind( this );
    } else {
      this.cOp = TestSet.c6;
      this.arrayOp[ 2 ] = TestSet.c6.bind( this );
    }

    if ( this.d ) {
      this.dOp = TestSet.d7;
      this.arrayOp[ 3 ] = TestSet.d7.bind( this );
    } else {
      this.dOp = TestSet.d8;
      this.arrayOp[ 3 ] = TestSet.d8.bind( this );
    }

  }

  static a1( p ) { return Math.sin( this.a + 1 ) + p; }
  static a2( p ) { return Math.sin( this.a + 2 ) + p; }
  static b3( p ) { return Math.sin( this.b + 3 ) + p; }
  static b4( p ) { return Math.sin( this.b + 4 ) + p; }
  static c5( p ) { return Math.sin( this.c + 5 ) + p; }
  static c6( p ) { return Math.sin( this.c + 6 ) + p; }
  static d7( p ) { return Math.sin( this.d + 7 ) + p; }
  static d8( p ) { return Math.sin( this.d + 8 ) + p; }

  test_ConditionalBranch() {
    let p = 1;
    let r;

    if ( this.a ) {
      r = Math.sin( this.a + 1 ) + p;
    } else {
      r = Math.sin( this.a + 2 ) + p;
    }

    if ( this.b ) {
      r = Math.sin( this.b + 3 ) + p;
    } else {
      r = Math.sin( this.b + 4 ) + p;
    }

    if ( this.c ) {
      r = Math.sin( this.c + 5 ) + p;
    } else {
      r = Math.sin( this.c + 6 ) + p;
    }

    if ( this.d ) {
      r = Math.sin( this.d + 7 ) + p;
    } else {
      r = Math.sin( this.d + 8 ) + p;
    }
  }

  test_UnconditionalBranch() {
    let p = 1;
    let r;

    r = this.aOp( p );
    r = this.bOp( p );
    r = this.cOp( p );
    r = this.dOp( p );
  }

  test_UnconditionalBranchTry() {
    try {
      let p = 1;
      let r;

      r = this.aOp( p );
      r = this.bOp( p );
      r = this.cOp( p );
      r = this.dOp( p );
    } finally {
    }
  }

  test_UnconditionalBranchArray() {
    let p = 1;
    let r;

    r = this.arrayOp[ 0 ]( p );
    r = this.arrayOp[ 1 ]( p );
    r = this.arrayOp[ 2 ]( p );
    r = this.arrayOp[ 3 ]( p );
  }

  test_UnconditionalBranchArraySpread() {
    let p = 1;
    let r;

    let [ aOp, bOp, cOp, dOp ] = [ ...this.arrayOp ];
    r = aOp( p );
    r = bOp( p );
    r = cOp( p );
    r = dOp( p );
  }

  test_UnconditionalBranchArrayLoopIndex() {
    let p = 1;
    let r;

    for ( let i = 0; i < this.arrayOp.length; ++i ) {
      r = this.arrayOp[ i ]( p );
    }
  }

  test_UnconditionalBranchArrayLoopIndexLocal() {
    let p = 1;
    let r;

    let count = this.arrayOp.length;
    for ( let i = 0; i < count; ++i ) {
      r = this.arrayOp[ i ]( p );
    }
  }

  test_UnconditionalBranchArrayLoopIterator() {
    let p = 1;
    let r;

    for ( let op of this.arrayOp ) {
      r = op( p );
    }
  }

  // Testing whether the results of different implementation are the same. Also, pre-compile the codes.
  async testCaseLoader() {
    this.test_ConditionalBranch();
    this.test_UnconditionalBranch();
    this.test_UnconditionalBranchTry();
    this.test_UnconditionalBranchArray();
    this.test_UnconditionalBranchArraySpread();
    this.test_UnconditionalBranchArrayLoopIndex();
    this.test_UnconditionalBranchArrayLoopIndexLocal();
    this.test_UnconditionalBranchArrayLoopIterator();
  }

}

globalThis.testSet = new TestSet( 3, 2, 0, 1 );
<commit_msg>Update jsPerf_ConditionalUnconditionalBranch.js<commit_after>//import * as TensorTools from "../util/TensorTools.js";

/**
 * Test performancce of conditional and unconditional branch.
 *
 * @see {@link https://www.measurethat.net/Benchmarks/Show/9224/0/colorfulcakechen-conditional-unconditional-branch-d3e82}
 * @see {@link https://jsperf.com/colorfulcakechen-conditional-unconditional-branch}
 */

/**
 * A test set.
 */
class TestSet {

  /**
   */
  constructor( a, b, c, d ) {

    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;

    this.arrayOp = new Array( 4 );

    if ( this.a ) {
      this.aOp = TestSet.a1;
      this.arrayOp[ 0 ] = TestSet.a1.bind( this );
    } else {
      this.aOp = TestSet.a2;
      this.arrayOp[ 0 ] = TestSet.a2.bind( this );
    }

    if ( this.b ) {
      this.bOp = TestSet.b3;
      this.arrayOp[ 1 ] = TestSet.b3.bind( this );
    } else {
      this.bOp = TestSet.b4;
      this.arrayOp[ 1 ] = TestSet.b4.bind( this );
    }

    if ( this.c ) {
      this.cOp = TestSet.c5;
      this.arrayOp[ 2 ] = TestSet.c5.bind( this );
    } else {
      this.cOp = TestSet.c6;
      this.arrayOp[ 2 ] = TestSet.c6.bind( this );
    }

    if ( this.d ) {
      this.dOp = TestSet.d7;
      this.arrayOp[ 3 ] = TestSet.d7.bind( this );
    } else {
      this.dOp = TestSet.d8;
      this.arrayOp[ 3 ] = TestSet.d8.bind( this );
    }

  }

  static a1( p ) { return Math.sin( this.a + 1 ) + p; }
  static a2( p ) { return Math.sin( this.a + 2 ) + p; }
  static b3( p ) { return Math.sin( this.b + 3 ) + p; }
  static b4( p ) { return Math.sin( this.b + 4 ) + p; }
  static c5( p ) { return Math.sin( this.c + 5 ) + p; }
  static c6( p ) { return Math.sin( this.c + 6 ) + p; }
  static d7( p ) { return Math.sin( this.d + 7 ) + p; }
  static d8( p ) { return Math.sin( this.d + 8 ) + p; }

  test_ConditionalBranch() {
    let p = 1;
    let r;

    if ( this.a ) {
      r = Math.sin( this.a + 1 ) + p;
    } else {
      r = Math.sin( this.a + 2 ) + p;
    }

    if ( this.b ) {
      r = Math.sin( this.b + 3 ) + p;
    } else {
      r = Math.sin( this.b + 4 ) + p;
    }

    if ( this.c ) {
      r = Math.sin( this.c + 5 ) + p;
    } else {
      r = Math.sin( this.c + 6 ) + p;
    }

    if ( this.d ) {
      r = Math.sin( this.d + 7 ) + p;
    } else {
      r = Math.sin( this.d + 8 ) + p;
    }
  }

  test_UnconditionalBranch() {
    let p = 1;
    let r;

    r = this.aOp( p );
    r = this.bOp( p );
    r = this.cOp( p );
    r = this.dOp( p );
  }

  test_UnconditionalBranchTry() {
    try {
      let p = 1;
      let r;

      r = this.aOp( p );
      r = this.bOp( p );
      r = this.cOp( p );
      r = this.dOp( p );
    } finally {
    }
  }

  test_UnconditionalBranchArray() {
    let p = 1;
    let r;

    r = this.arrayOp[ 0 ]( p );
    r = this.arrayOp[ 1 ]( p );
    r = this.arrayOp[ 2 ]( p );
    r = this.arrayOp[ 3 ]( p );
  }

  test_UnconditionalBranchArraySpread() {
    let p = 1;
    let r;

    let [ aOp, bOp, cOp, dOp ] = [ ...this.arrayOp ];
    r = aOp( p );
    r = bOp( p );
    r = cOp( p );
    r = dOp( p );
  }

  test_UnconditionalBranchArrayLoopIndex() {
    let p = 1;
    let r;

    for ( let i = 0; i < this.arrayOp.length; ++i ) {
      r = this.arrayOp[ i ]( p );
    }
  }

  test_UnconditionalBranchArrayLoopIndexLocal() {
    let p = 1;
    let r;

    let count = this.arrayOp.length;
    for ( let i = 0; i < count; ++i ) {
      r = this.arrayOp[ i ]( p );
    }
  }

  test_UnconditionalBranchArrayLoopIterator() {
    let p = 1;
    let r;

    for ( let op of this.arrayOp ) {
      r = op( p );
    }
  }

  // Testing whether the results of different implementation are the same. Also, pre-compile the codes.
  async testCaseLoader() {
    this.test_ConditionalBranch();
    this.test_UnconditionalBranch();
    this.test_UnconditionalBranchTry();
    this.test_UnconditionalBranchArray();
    this.test_UnconditionalBranchArraySpread();
    this.test_UnconditionalBranchArrayLoopIndex();
    this.test_UnconditionalBranchArrayLoopIndexLocal();
    this.test_UnconditionalBranchArrayLoopIterator();
  }

}

globalThis.testSet = new TestSet( 3, 2, 0, 1 );
<|endoftext|>


<commit_before>enyo.kind({
    name: "VideoRequest",
    kind: enyo.Request,
    components: [
        { name: "TouchPlayer", kind: "PalmService", service: "palm://com.wordpress.mobilecoder.touchplayer.service/", method: "play", onSuccess: "touchPlayerLaunched", onFailure: "touchPlayerFailed" },
        { name: "WebLauncher", kind: "PalmService", service: "palm://com.palm.applicationManager/", method: "open", onSuccess: "webBrowserLaunched", onFailure: "webBrowserFailed" },
    ],
    call: function()
    {
        var url = "http://" + prefs.get("serverip") + "/rest/stream.view?id=" + this.itemId + "&u=" + prefs.get("username") + "&p=" + prefs.get("password") + "&v=1.7.0" + "&c=XO-webOS";
        this.log("*** Playing Video URL ", url);
        if(window.PalmSystem)
            this.$.TouchPlayer.call( { source: url } );
        else
            this.touchPlayerFailed();
    },
    touchPlayerLaunched: function(inSender, inResponse)
    {
        this.log(inResponse);
        this.receive({ result: "ok" });
    },
    touchPlayerFailed: function(inSender, inResponse)
    {
        this.log(inResponse);
        var url = "http://" + prefs.get("serverip") + "/rest/videoPlayer.view?id=" + this.itemId + "&u=" + prefs.get("username") + "&p=" + prefs.get("password") + "&v=1.7.0" + "&c=XO-webOS";
        this.log("*** Playing Video URL ", url);
        if(window.PalmSystem) {
            this.$.WebLauncher.call( { target: url });
        }
        else if(typeof blackberry != "undefined") {
            this.blackberrybrowser(url);
        }
        this.receive(); // null response == failure
    },
    webBrowserLaunched: function(inSender, inResponse)
    {
        this.log(inResponse);
        this.receive({ result: "ok" });
    },
    webBrowserFailed: function(inSender, inResponse)
    {
        this.log(inResponse);
        this.receive();
    },
    blackberrybrowser: function(address)
    {
        this.log(address);
	var encodedAddress = "";
	// URL Encode all instances of ':' in the address
	encodedAddress = address.replace(/:/g, "%3A");
	// Leave the first instance of ':' in its normal form
	encodedAddress = encodedAddress.replace(/%3A/, ":");
	// Escape all instances of '&' in the address
	encodedAddress = encodedAddress.replace(/&/g, "\&");

	if (typeof blackberry !== 'undefined') {
			var args = new blackberry.invoke.BrowserArguments(encodedAddress);
			blackberry.invoke.invoke(blackberry.invoke.APP_BROWSER, args);
	} else {
		// If I am not a BlackBerry device, open link in current browser
		window.location = encodedAddress;
	}
    },

});<commit_msg>video<commit_after>enyo.kind({
    name: "VideoRequest",
    kind: enyo.Request,
    components: [
        { name: "TouchPlayer", kind: "PalmService", service: "palm://com.wordpress.mobilecoder.touchplayer.service/", method: "play", onSuccess: "touchPlayerLaunched", onFailure: "touchPlayerFailed" },
        { name: "WebLauncher", kind: "PalmService", service: "palm://com.palm.applicationManager/", method: "open", onSuccess: "webBrowserLaunched", onFailure: "webBrowserFailed" },
    ],
    call: function()
    {
        var url = "http://" + prefs.get("serverip") + "/rest/stream.view?id=" + this.itemId + "&u=" + prefs.get("username") + "&p=" + prefs.get("password") + "&v=1.7.0" + "&c=XO-webOS";
        this.log("*** Playing Video URL ", url);
        if(typeof blackberry != "undefined")
            this.touchPlayerFailed();
        else if(window.PalmSystem)
            this.$.TouchPlayer.call( { source: url } );
    },
    touchPlayerLaunched: function(inSender, inResponse)
    {
        this.log(inResponse);
        this.receive({ result: "ok" });
    },
    touchPlayerFailed: function(inSender, inResponse)
    {
        this.log(inResponse);
        var url = "http://" + prefs.get("serverip") + "/rest/videoPlayer.view?id=" + this.itemId + "&u=" + prefs.get("username") + "&p=" + prefs.get("password") + "&v=1.7.0" + "&c=XO-webOS";
        this.log("*** Playing Video URL ", url);
        if(window.PalmSystem) {
            this.$.WebLauncher.call( { target: url });
        }
        else if(typeof blackberry != "undefined") {
            this.blackberrybrowser(url);
        }
        this.receive(); // null response == failure
    },
    webBrowserLaunched: function(inSender, inResponse)
    {
        this.log(inResponse);
        this.receive({ result: "ok" });
    },
    webBrowserFailed: function(inSender, inResponse)
    {
        this.log(inResponse);
        this.receive();
    },
    blackberrybrowser: function(address)
    {
        this.log(address);
	var encodedAddress = "";
	// URL Encode all instances of ':' in the address
	encodedAddress = address.replace(/:/g, "%3A");
	// Leave the first instance of ':' in its normal form
	encodedAddress = encodedAddress.replace(/%3A/, ":");
	// Escape all instances of '&' in the address
	encodedAddress = encodedAddress.replace(/&/g, "\&");

	if (typeof blackberry !== 'undefined') {
			var args = new blackberry.invoke.BrowserArguments(encodedAddress);
			blackberry.invoke.invoke(blackberry.invoke.APP_BROWSER, args);
	} else {
		// If I am not a BlackBerry device, open link in current browser
		window.location = encodedAddress;
	}
    },

});<|endoftext|>


<commit_before>export default [
    {
        props: [
            {
                name: 'v-model',
                description: 'Binding value',
                type: 'Array<String>, Array<Number>, Array<Object>',
                values: '—',
                default: '—'
            },
            {
                name: 'maxlength',
                description: 'Limits the length of each tag, plus character counter',
                type: 'String, Number',
                values: '—',
                default: '—'
            },
            {
                name: 'maxtags',
                description: 'Limits the number of tags, plus tag counter',
                type: 'String, Number',
                values: '—',
                default: '—'
            },
            {
                name: 'type',
                description: 'Type (color) of the tags, optional',
                type: 'String',
                values: `is-white, is-black, is-light,
                    is-dark, is-primary, is-info, is-success,
                    is-warning, is-danger,
                    and any other colors you've set in the $colors list on Sass`,
                default: 'is-light'
            },
            {
                name: 'size',
                description: 'Tag and input size, optional',
                type: 'String',
                values: 'is-small, is-medium, is-large',
                default: 'is-medium'
            },
            {
                name: 'rounded',
                description: 'Makes the tags rounded, optional',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'attached',
                description: 'Makes the tags attached instead of having an appended delete button, optional',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'ellipsis',
                description: 'Adds ellipsis on tags to not overflow the text',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'closable',
                description: 'Add close/delete button to the tag',
                type: 'Boolean',
                values: '—',
                default: 'true'
            },
            {
                name: 'field',
                description: 'Property of the object (if data is array of objects) to use as display text',
                type: 'String',
                values: '—',
                default: 'value'
            },
            {
                name: 'autocomplete',
                description: 'Add autocomplete feature',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'allow-new',
                description: 'When autocomplete, it allow to add new tags',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'remove-on-keys',
                description: 'Allow removing last tag when pressing given keys, if input is empty',
                type: 'Array',
                values: '—',
                default: '[8]'
            },
            {
                name: 'confirm-key-codes',
                description: 'Array of key codes which will add a tag when typing (default comma, enter and tab)',
                type: 'Array',
                values: '—',
                default: '[13, 188, 9]'
            },
            {
                name: 'on-paste-separators',
                description: 'Array of chars used to split when pasting a new string',
                type: 'Array',
                values: '—',
                default: '[\',\']'
            },
            {
                name: 'before-adding',
                description: 'Function to validate the value of the tag before adding',
                type: 'Function',
                values: '—',
                default: '() => true'
            },
            {
                name: 'allow-duplicates',
                description: 'Allows adding the same tag multiple times',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'Any other native attribute or Autocomplete prop',
                description: '—',
                type: '—',
                values: '—',
                default: '—'
            }
        ],
        slots: [
            {
                name: 'default',
                description: '',
                props: 'option: String|Object, index: Number'
            },
            {
                name: 'empty',
                description: 'Show like an option if data array prop is empty',
                props: '—'
            },
            {
                name: 'header',
                description: 'Show a custom header as first option',
                props: '—'
            }
        ],
        events: [
            {
                name: 'input',
                description: 'Triggers when tags are added/removed',
                parameters: 'value: Array'
            },
            {
                name: 'typing',
                description: 'User started typing a tag',
                parameters: 'value: String'
            },
            {
                name: 'add',
                description: 'Triggers when a tag has been added',
                parameters: 'value: String|Object'
            },
            {
                name: 'remove',
                description: 'Triggers when a tag has been removed',
                parameters: 'value: String|Object'
            }
        ]
    }
]
<commit_msg>Close #1203 update taginput api docs<commit_after>export default [
    {
        props: [
            {
                name: 'v-model',
                description: 'Binding value',
                type: 'Array<String>, Array<Number>, Array<Object>',
                values: '—',
                default: '—'
            },
            {
                name: 'maxlength',
                description: 'Limits the length of each tag, plus character counter',
                type: 'String, Number',
                values: '—',
                default: '—'
            },
            {
                name: 'maxtags',
                description: 'Limits the number of tags, plus tag counter',
                type: 'String, Number',
                values: '—',
                default: '—'
            },
            {
                name: 'type',
                description: 'Type (color) of the tags, optional',
                type: 'String',
                values: `is-white, is-black, is-light,
                    is-dark, is-primary, is-info, is-success,
                    is-warning, is-danger,
                    and any other colors you've set in the $colors list on Sass`,
                default: 'is-light'
            },
            {
                name: 'size',
                description: 'Tag and input size, optional',
                type: 'String',
                values: 'is-small, is-medium, is-large',
                default: 'is-medium'
            },
            {
                name: 'rounded',
                description: 'Makes the tags rounded, optional',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'attached',
                description: 'Makes the tags attached instead of having an appended delete button, optional',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'ellipsis',
                description: 'Adds ellipsis on tags to not overflow the text',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'closable',
                description: 'Add close/delete button to the tag',
                type: 'Boolean',
                values: '—',
                default: 'true'
            },
            {
                name: 'field',
                description: 'Property of the object (if data is array of objects) to use as display text',
                type: 'String',
                values: '—',
                default: 'value'
            },
            {
                name: 'autocomplete',
                description: 'Add autocomplete feature',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'allow-new',
                description: 'When autocomplete, it allow to add new tags',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'remove-on-keys',
                description: 'Allow removing last tag when pressing given keys, if input is empty',
                type: 'Array',
                values: '—',
                default: '[8]'
            },
            {
                name: 'confirm-key-codes',
                description: 'Array of key codes which will add a tag when typing (default comma, enter and tab)',
                type: 'Array',
                values: '—',
                default: '[13, 188, 9]'
            },
            {
                name: 'on-paste-separators',
                description: 'Array of chars used to split when pasting a new string',
                type: 'Array',
                values: '—',
                default: '[\',\']'
            },
            {
                name: 'before-adding',
                description: 'Function to validate the value of the tag before adding',
                type: 'Function',
                values: '—',
                default: '() => true'
            },
            {
                name: 'allow-duplicates',
                description: 'Allows adding the same tag multiple times',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'readonly',
                description: 'Disable input/typing',
                type: 'Boolean',
                values: '—',
                default: 'false'
            },
            {
                name: 'Any other native attribute or Autocomplete prop',
                description: '—',
                type: '—',
                values: '—',
                default: '—'
            }
        ],
        slots: [
            {
                name: 'default',
                description: '',
                props: 'option: String|Object, index: Number'
            },
            {
                name: 'empty',
                description: 'Show like an option if data array prop is empty',
                props: '—'
            },
            {
                name: 'header',
                description: 'Show a custom header as first option',
                props: '—'
            }
        ],
        events: [
            {
                name: 'input',
                description: 'Triggers when tags are added/removed',
                parameters: 'value: Array'
            },
            {
                name: 'typing',
                description: 'User started typing a tag',
                parameters: 'value: String'
            },
            {
                name: 'add',
                description: 'Triggers when a tag has been added',
                parameters: 'value: String|Object'
            },
            {
                name: 'remove',
                description: 'Triggers when a tag has been removed',
                parameters: 'value: String|Object'
            }
        ]
    }
]
<|endoftext|>


<commit_before>;(function($, undefined)
{
	var bridge;
	var viewModel;

	$(document).ready(function()
	{
		viewModel = new ViewModel()
		ko.applyBindings(viewModel);

		bridge = new Bridge({ apiKey: "// FILL IN" });

		bridge.ready(function()
		{
			bridge.getService("pandora", function(service)
			{
				service.getStationList(function(data)
				{
					viewModel.stations(data);

					service.switchStation(viewModel.quickMix(), function()
					{
						viewModel.updateVM();
					});
				});
			});
		});
	});

	function ViewModel()
	{
		this.stations = ko.observableArray([]);

		this.json = ko.observable({});

		this.history = ko.observableArray([]);

		this.songUrl = ko.computed(function(key)
		{
			return this.json()['audioURL'];
		}, this);

		this.albumArt = ko.computed(function(key)
		{
			return this.json()['artistArtUrl'];
		}, this);

		this.title = ko.computed(function(key)
		{
			return this.json()['songTitle'];
		}, this);

		this.artist = ko.computed(function(key)
		{
			return this.json()['artistSummary'];
		}, this);

		this.album = ko.computed(function(key)
		{
			return this.json()['albumTitle'];
		}, this);

		this.quickMix = ko.computed(function(key)
		{
			return ko.utils.arrayFilter(this.stations(), function(item)
			{
				return item['isQuickMix'];
			})[0];
		}, this);

		this.addHistory = function(json)
		{
			this.history.unshift(json);
		}

		this.forceUpdateHistory = function($data)
		{
			viewModel.json($data);
			viewModel.addHistory(viewModel.json());
		}

		this.updateVM = function()
		{
			$("#jquery_jplayer_1").jPlayer("pause");
			bridge.getService("pandora", function(service)
			{
				service.getNextSong(function(data) {
					data['artistArtUrl'] = data['artistArtUrl'] || "/static/img/noalbumart.png";
					viewModel.json(data);
					viewModel.addHistory(viewModel.json());
				});
			});
		}
	}

	ko.bindingHandlers.jPlayer =
	{
		init: function(element, valueAccessor, allBindingsAccessor, viewModel)
		{
			$(element).jPlayer({
				ready: function(event)
				{
					$(this).jPlayer("setMedia", {
						mp3: viewModel.json().audioURL,
					}).jPlayer("play");
				},
				ended: function(event)
				{
					viewModel.updateVM();
				},
				swfPath: "http://www.jplayer.org/2.1.0/js/Jplayer.swf",
				supplied: "mp3",
				preload: 'auto',
				wmode: 'window',
			});
		},

		update: function(element, valueAccessor, allBindingsAccessor, viewModel)
		{
			console.log("jPlayer updated! Now playing "
						+ viewModel.json().songTitle
						+ " by "
						+ viewModel.json().artistSummary
						+ " at URL "
						+ viewModel.json().audioURL);
			$(element).jPlayer("clearMedia").jPlayer("setMedia", {
				mp3: viewModel.json().audioURL
			}).jPlayer("play");
		}
	};
}(jQuery));
<commit_msg>Refactor init.js<commit_after>;(function($, undefined) {
	var ViewModel;
	var Song;

	var bridge;
	var pandora;
	var vm;

	Song = (function() {

		function Song(data) {
			this.data = data;
		}

		Song.prototype.toString = function() {
			return "" + this.data.songTitle + " by " + this.data.artistSummary + " on " + this.data.albumTitle;
		};

		Song.prototype.url = function() {
			return "" + this.data.audioURL;
		};

		Song.prototype.albumArt = function() {
			return "" + this.data.artistArtUrl;
		};

		return Song;
	})();

	ViewModel = (function() {

		function ViewModel() {
			this.currentStation = ko.observable({});
			this.stations = ko.observableArray([]);

			this.currentSong = ko.observable(new Song({}));
			this.history = ko.observableArray([]);

			this.songUrl = ko.computed(function() {
				return this.currentSong().url();
			}, this);

			this.albumArt = ko.computed(function() {
				return this.currentSong().albumArt();
			}, this);

			this.quickMix = ko.computed(function() {
				return ko.utils.arrayFilter(this.stations(), function(item)
				{
					return item['isQuickMix'];
				})[0];
			}, this);
		}

		ViewModel.prototype.forceUpdateHistory = function(data) {
			var song = new Song(data)
			this.currentSong(song);
			this.history.unshift(song);
		}

		ViewModel.prototype.nextSong = function() {
			var self = this;

			$("#jquery_jplayer_1").jPlayer("pause");
			pandora.getNextSong(function(data) {
				data['artistArtUrl'] = data['artistArtUrl'] || "/static/img/noalbumart.png";
				self.forceUpdateHistory(data);
			});
		}

		ViewModel.prototype.switchStation = function(data) {
			var self = this;

			console.log("Switching to ", data['stationName']);
			pandora.switchStation(data, function() {
				//this.currentStation(data);
				self.nextSong();
			});
		}

		return ViewModel;
	})();

	ko.bindingHandlers.jPlayer = {
		init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
			$(element).jPlayer({
				ready: function(event) {
					$(this).jPlayer("setMedia", {
						mp3: viewModel.currentSong().audioURL,
					}).jPlayer("play");
				},
				ended: function(event) {
					viewModel.nextSong();
				},
				swfPath: "http://www.jplayer.org/2.1.0/js/Jplayer.swf",
				supplied: "mp3",
				preload: 'auto',
				wmode: 'window',
			});
		},

		update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
			console.log("jPlayer updated! Now playing "
						+ viewModel.currentSong() + " at URL "
						+ viewModel.currentSong().url());
			$(element).jPlayer("clearMedia").jPlayer("setMedia", {
				mp3: viewModel.currentSong().url()
			}).jPlayer("play");
		}
	};

	$(document).ready(function() {
		vm = new ViewModel();
		window.vm = vm;

		ko.applyBindings(vm);

		bridge = new Bridge({ apiKey: "// FILL IN" });
		console.debug("Bridge is initialized");

		bridge.ready(function() {

			console.debug("Bridge is ready");
			bridge.getService("pandora", function(service) {

				console.debug("Got pandora service");
				pandora = service;

				pandora.getStationList(function(data) {

					vm.stations(data);
					vm.switchStation(vm.quickMix());
				});
			});
		});
	});

})(jQuery);
<|endoftext|>


<commit_before>/* Generic log function for debugging. */
var log = function(msg) { if (console && console.log) console.debug(msg); }

/**
 * Reload the display (get links, render them)
 * @property offset {Integer} Optional Where in the links collection you want to start.
 * @property limit {Integer} Optional The number of links you want returned.
 * @property useJSON {Boolean} Optional Display raw JSON instead of the link's name.
 */
function reload(offset, limit, useJSON) {
    // set the params if not specified
    var offset = offset || 0;
    var limit = limit || 100;
    var useJSON = useJSON || false;

    var getLinksCB = function(links) {
	// find the unordered list in our document to append to
        var linksList = $("#main ul");

	// clear the list
	linksList.html('');

	// populate the list with our links
	if (links.length == 0) linksList.append("
Sorry, no links found!
");
        for (var i in links) {
	    link = links[i];

	    log(link);
	    if (useJSON) {

		linkHTML = "
"+ JSON.stringify(link, null, 2) +"
";
	    } else {
		// get the link name, but use the first email address if no name exists
		linkHTML = link.name || link.emails[0].value;
	    }
	    liHTML = '
'+linkHTML+'
';
	    linksList.append(liHTML);
	}
    };

    $.getJSON(
	'/query/getLink',
	{'offset':offset, 'limit':limit},
	getLinksCB
    );
}

/* jQuery syntactic sugar for onDomReady */
$(function() {
    reload(0, 9000, true);
});
<commit_msg>Limit to 100 links to avoid crashing browsers and other nastiness<commit_after>/* Generic log function for debugging. */
var log = function(msg) { if (console && console.log) console.debug(msg); }

/**
 * Reload the display (get links, render them)
 * @property offset {Integer} Optional Where in the links collection you want to start.
 * @property limit {Integer} Optional The number of links you want returned.
 * @property useJSON {Boolean} Optional Display raw JSON instead of the link's name.
 */
function reload(offset, limit, useJSON) {
    // set the params if not specified
    var offset = offset || 0;
    var limit = limit || 100;
    var useJSON = useJSON || false;

    var getLinksCB = function(links) {
	// find the unordered list in our document to append to
        var linksList = $("#main ul");

	// clear the list
	linksList.html('');

	// populate the list with our links
	if (links.length == 0) linksList.append("
Sorry, no links found!
");
        for (var i in links) {
	    link = links[i];

	    log(link);
	    if (useJSON) {

		linkHTML = "
"+ JSON.stringify(link, null, 2) +"
";
	    } else {
		// get the link name, but use the first email address if no name exists
		linkHTML = link.name || link.emails[0].value;
	    }
	    liHTML = '
'+linkHTML+'
';
	    linksList.append(liHTML);
	}
    };

    $.getJSON(
	'/query/getLink',
	{'offset':offset, 'limit':limit},
	getLinksCB
    );
}

/* jQuery syntactic sugar for onDomReady */
$(function() {
    reload(0, null, true);
});
<|endoftext|>


<commit_before>
load('./BeatStepPro.utils.js');

// Global constants

var SCRIPT_API_VERSION = 2;
var SCRIPT_VERSION = "0.1";
var SCRIPT_UUID = "af9d9ec7-258a-4415-941f-c506d203b6f0";

var NUM_FX_TRACKS = 2;

// Initialization and Controller Definition

loadAPI(SCRIPT_API_VERSION);
host.defineController("Arturia", "BeatStep Pro (Hybrid Decliners Live)", SCRIPT_VERSION, SCRIPT_UUID, "Nick Donaldson");
host.defineMidiPorts(NUM_PORTS_IN, NUM_PORTS_OUT);
host.addDeviceNameBasedDiscoveryPair([DEVICE_NAME], [DEVICE_NAME]);

// Script Variables
var inPort;
var outPort;
var mainTrackBank;
var effectTrackBank;

// Script Overrides

function init() {
  inPort = host.getMidiInPort(0);
  outPort = host.getMidiOutPort(0);

  mainTrackBank = host.createMainTrackBank(16 - NUM_FX_TRACKS, NUM_FX_TRACKS, 0);
  effectTrackBank = host.createEffectTrackBank(NUM_FX_TRACKS, 0);

  inPort.createNoteInput("BeatStep Seq 1", SEQ_1_INPUT_FILTER);
  inPort.createNoteInput("BeatStep Seq 2", SEQ_2_INPUT_FILTER);
  inPort.createNoteInput("BeatStep Drum", DRUM_SEQ_INPUT_FILTER);

  inPort.setMidiCallback(onMidi);

  createDrumDevice();
}

function exit() {}

function onMidi(status, data1, data2) {
  if (isControlModeChannel(status)) {
    handleControlModeMessage(status, data1, data2);
  }
}

/// Control Mode

var DRUM_RESET_CC_NUM = 102;
var DRUM_CHANNEL_INDEX = 0;

var drumChannel;
var drumDevice;
var drumPadBank;
var pressedPads = [];

function handleControlModeMessage(status, data1, data2) {
  //println("Got control mode message: " + status + ", " + data1 + ", " + data2);

  if (isNoteOnMessage(status)) {

    var padIndex = getPadIndex(data1);

    if (padIndex !== null) {
      selectDrum(padIndex);
      pressedPads.remove(padIndex);
      pressedPads.push(padIndex);
    }

  } else if (isNoteOffMessage(status)) {

    var padIndex = getPadIndex(data1);
    if (padIndex !== null) {
      pressedPads.remove(padIndex);
    }

  } else if (isControlMessage(status)) {

    var ccNum = data1;
    var ccVal = data2;

    if (isEncoderControlNumber(ccNum)) {
      // Apply encoder modification to every drum pad pressed down
      if (!pressedPads.isEmpty()) {
        pressedPads.forEach(function(padIndex) {
          handleDrumEncoderInput(padIndex, ccNum, ccVal);
        });
      } else {
        handleMixEncoderInput(ccNum, ccVal);
      }
    }

    if (isStepControlNumber(ccNum)) {
      var stepIndex = getStepIndex(ccNum);
      handleChannelSelection(stepIndex);
    }

    if (ccNum == DRUM_RESET_CC_NUM && ccVal > 0) {

      // Reset all mix params for every drum held down
      if (!pressedPads.isEmpty()) {

        pressedPads.forEach(function(padIndex) {
          resetDrumSends(padIndex);
        });

      }

    }
  }
}

function createDrumDevice() {
  drumChannel = host.createCursorTrack(2, 0);
  drumDevice = drumChannel.createCursorDevice("Primary", 2);
  drumPadBank = drumDevice.createDrumPadBank(16);
}

function selectDrum(padIndex) {
    drumChannel.selectChannel(mainTrackBank.getChannel(0))
    var padChannel = drumPadBank.getChannel(padIndex);
    padChannel.selectInMixer();
}

function handleDrumEncoderInput(padIndex, ccNum, ccVal) {

  if (!drumDevice.hasDrumPads()) {
    println("Could not process drum params input: project layout is not valid");
    return
  }

  if (!isEncoderInBank1(ccNum)) {
    return;
  }

  var increment = getRelativeIncrement(ccVal, 2.0);
  var encoderBankIndex = getEncoderIndexInBank(ccNum);
  var padChannel = drumPadBank.getChannel(padIndex);

  switch (encoderBankIndex) {
    case 0:
      padChannel.getVolume().inc(increment, 128);
      break;
    case 1:
      padChannel.getSend(0).inc(increment, 128);
      break;
    case 4:
      padChannel.getPan().inc(increment, 128);
      break;
    case 5:
      padChannel.getSend(1).inc(increment, 128);
      break;
  }
}

function resetDrumSends(padIndex) {
  var padChannel = drumPadBank.getChannel(padIndex);
  padChannel.getSend(0).setRaw(0.0);
  padChannel.getSend(1).setRaw(0.0);
}

function getEncoderChannelIndex(ccNum) {
  var bankIndex = getEncoderIndexInBank(ccNum);
  var channelIndex = bankIndex % 4;
  if (isEncoderInBank2(ccNum)) {
    channelIndex += 4;
  }
  return channelIndex;
}

function handleChannelSelection(index) {
  var channel = null;
  var mainTrackCount = 16 - NUM_FX_TRACKS;

  if (index < mainTrackCount) {
    channel = mainTrackBank.getChannel(index);
  } else if (index < 16) {
    channel = effectTrackBank.getChannel(index - mainTrackCount);
  }

  if (channel != null) {
    channel.selectInMixer();
  }
}

function handleMixEncoderInput(ccNum, ccVal) {
  var channelIndex = getEncoderChannelIndex(ccNum);
  var increment = getRelativeIncrement(ccVal, 2.0);
  var channel = mainTrackBank.getChannel(channelIndex);

  channel.selectInMixer();

  if (getEncoderIndexInBank(ccNum) < 4) {
    channel.getSend(0).inc(increment, 128);
  } else {
    channel.getSend(1).inc(increment, 128);
  }
}

<commit_msg>Encoder bank 1 applies to selected track mix<commit_after>
load('./BeatStepPro.utils.js');

// Global constants

var SCRIPT_API_VERSION = 2;
var SCRIPT_VERSION = "0.1";
var SCRIPT_UUID = "af9d9ec7-258a-4415-941f-c506d203b6f0";

var NUM_FX_TRACKS = 2;
var DRUM_RESET_CC_NUM = 102;

// Initialization and Controller Definition

loadAPI(SCRIPT_API_VERSION);
host.defineController("Arturia", "BeatStep Pro (Hybrid Decliners Live)", SCRIPT_VERSION, SCRIPT_UUID, "Nick Donaldson");
host.defineMidiPorts(NUM_PORTS_IN, NUM_PORTS_OUT);
host.addDeviceNameBasedDiscoveryPair([DEVICE_NAME], [DEVICE_NAME]);

// Script Variables
var inPort;
var outPort;

var mainTrackBank;
var effectTrackBank;
var drumTrackBank;

var primaryTrackCursor;
var primaryDeviceCursor;

var selectedDrumIndex = null;

// Script Overrides

function init() {
  inPort = host.getMidiInPort(0);
  outPort = host.getMidiOutPort(0);

  mainTrackBank = host.createMainTrackBank(16 - NUM_FX_TRACKS, NUM_FX_TRACKS, 0);
  effectTrackBank = host.createEffectTrackBank(NUM_FX_TRACKS, 0);

  primaryTrackCursor = host.createCursorTrack(NUM_FX_TRACKS, 0);
  primaryDeviceCursor = primaryTrackCursor.createCursorDevice("Primary", 2);

  drumTrackBank = primaryDeviceCursor.createDrumPadBank(16);

  inPort.createNoteInput("BeatStep Seq 1", SEQ_1_INPUT_FILTER);
  inPort.createNoteInput("BeatStep Seq 2", SEQ_2_INPUT_FILTER);
  inPort.createNoteInput("BeatStep Drum", DRUM_SEQ_INPUT_FILTER);

  inPort.setMidiCallback(onMidi);
}

function exit() {}

function onMidi(status, data1, data2) {
  if (isControlModeChannel(status)) {
    handleControlModeMessage(status, data1, data2);
  }
}

/// Control Mode

function handleControlModeMessage(status, data1, data2) {
  //println("Got control mode message: " + status + ", " + data1 + ", " + data2);

  if (isNoteOnMessage(status)) {

    var padIndex = getPadIndex(data1);
    if (padIndex !== null) {
      selectDrum(padIndex);
    }

  } else if (isControlMessage(status)) {

    var ccNum = data1;
    var ccVal = data2;

    if (isStepControlNumber(ccNum)) {
      var stepIndex = getStepIndex(ccNum);
      selectChannel(stepIndex);
    }

    if (isEncoderControlNumber(ccNum)) {
      if (isEncoderInBank1(ccNum)) {
        handleMixEncoderInput(ccNum, ccVal);
      }
    }

    //if (ccNum == DRUM_RESET_CC_NUM && ccVal > 0) {
    //  // Reset all mix params for every drum held down
    //  if (!pressedPads.isEmpty()) {
    //    pressedPads.forEach(function(padIndex) {
    //      resetDrumSends(padIndex);
    //    });
    //  }
    //}
  }
}

function selectChannel(index) {
  var channel = null;
  var mainTrackCount = 16 - NUM_FX_TRACKS;

  if (index < mainTrackCount) {
    channel = mainTrackBank.getChannel(index);
  } else if (index < 16) {
    channel = effectTrackBank.getChannel(index - mainTrackCount);
  }

  if (channel != null) {
    channel.selectInMixer();
    selectedDrumIndex = null;
  }
}

function selectDrum(padIndex) {
    primaryTrackCursor.selectChannel(mainTrackBank.getChannel(0));
    drumTrackBank.getChannel(padIndex).selectInMixer();
    selectedDrumIndex = padIndex;
}

function handleMixEncoderInput(ccNum, ccVal) {

  var increment = getRelativeIncrement(ccVal, 2.0);
  var encoderBankIndex = getEncoderIndexInBank(ccNum);

  var selectedTrack;
  if (selectedDrumIndex != null) {
    selectedTrack = drumTrackBank.getChannel(selectedDrumIndex);
  } else {
    selectedTrack = primaryTrackCursor;
  }

  switch (encoderBankIndex) {
    case 0:
      selectedTrack.getPan().inc(increment, 128);
      break;
    case 1:
      selectedTrack.getSend(0).inc(increment, 128);
      break;
    case 4:
      selectedTrack.getVolume().inc(increment, 128);
      break;
    case 5:
      selectedTrack.getSend(1).inc(increment, 128);
      break;
  }
}

function resetDrumSends(padIndex) {
  var padChannel = drumPadBank.getChannel(padIndex);
  padChannel.getSend(0).setRaw(0.0);
  padChannel.getSend(1).setRaw(0.0);
}

function getEncoderChannelIndex(ccNum) {
  var bankIndex = getEncoderIndexInBank(ccNum);
  var channelIndex = bankIndex % 4;
  if (isEncoderInBank2(ccNum)) {
    channelIndex += 4;
  }
  return channelIndex;
}

<|endoftext|>