├── .eslintignore ├── examples ├── src │ ├── constants.js │ ├── store.js │ ├── actions.js │ ├── reducers │ │ ├── index.js │ │ └── ui-reducer.js │ ├── App.js │ ├── index.js │ ├── styles │ │ └── main.scss │ └── components │ │ └── index.js ├── README.md ├── yarn.lock ├── .babelrc ├── public │ ├── index.html │ └── bundle.js ├── .eslintrc ├── webpack.config.js └── package.json ├── .npmignore ├── test ├── setup.js ├── action-creators.spec.js ├── web-audio-reducer.spec.js └── RRWA-component.spec.js ├── lib ├── constants.js ├── index.js ├── action-creators.js ├── web-audio-reducer.js └── RRWA-component.js ├── src ├── constants.js ├── index.js ├── action-creators.js ├── web-audio-reducer.js └── RRWA-component.js ├── .travis.yml ├── .gitignore ├── .babelrc ├── .eslintrc ├── rollup.config.js ├── LICENSE ├── dist ├── index.es.js └── index.js ├── package.json └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /examples/src/constants.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | -------------------------------------------------------------------------------- /examples/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | examples/ 3 | coverage/ 4 | TODO.txt 5 | .babelrc 6 | .eslintrc 7 | .travis.yml 8 | webpack.config.js 9 | -------------------------------------------------------------------------------- /test/setup.js: -------------------------------------------------------------------------------- 1 | import { RenderingAudioContext } from 'web-audio-engine'; 2 | window.AudioContext = RenderingAudioContext; 3 | -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | /** @constant */ 2 | export const QUEUE_EVENT = 'QUEUE_EVENT'; 3 | /** @constant */ 4 | 5 | export const CLEAR_EVT_QUEUE = 'CLEAR_EVT_QUEUE'; -------------------------------------------------------------------------------- /examples/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "@babel/preset-env", "@babel/preset-react" ], 3 | "plugins": [ 4 | "@babel/plugin-proposal-class-properties" 5 | ] 6 | } -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | /** @constant */ 2 | export const QUEUE_EVENT = 'QUEUE_EVENT'; 3 | 4 | /** @constant */ 5 | export const CLEAR_EVT_QUEUE = 'CLEAR_EVT_QUEUE'; 6 | -------------------------------------------------------------------------------- /examples/src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore } from 'redux'; 2 | 3 | import rootReducer from './reducers'; 4 | 5 | 6 | export default createStore( rootReducer ); 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | - "8" 5 | cache: 6 | yarn: true 7 | directories: 8 | - "node_modules" 9 | before_script: "npm run coveralls" 10 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | import * as actionCreators from './action-creators'; 2 | import webAudioReducer from './web-audio-reducer'; 3 | import RRWAEngine from './RRWA-component'; 4 | export { RRWAEngine, actionCreators, webAudioReducer }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | 4 | # misc 5 | .DS_Store 6 | .env 7 | .npmignore 8 | npm-debug.log 9 | yarn-dubug.log 10 | todo.txt 11 | TODO.txt 12 | coverage/ 13 | 14 | # IDE dependencies 15 | .idea 16 | .idea/* 17 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import * as actionCreators from './action-creators'; 2 | import webAudioReducer from './web-audio-reducer'; 3 | import RRWAEngine from './RRWA-component'; 4 | 5 | export { 6 | RRWAEngine, 7 | actionCreators, 8 | webAudioReducer 9 | }; 10 | -------------------------------------------------------------------------------- /examples/src/actions.js: -------------------------------------------------------------------------------- 1 | export const startCtxUI = () => ({ 2 | type: 'START' 3 | }); 4 | 5 | 6 | export const susResAudioCtx = () => ({ 7 | type: 'TOGGLE_CTX_RUNNING' 8 | }); 9 | 10 | 11 | export const closeCtxUI = () => ({ 12 | type: 'CLOSE' 13 | }); 14 | -------------------------------------------------------------------------------- /examples/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { webAudioReducer } from 'react-redux-webaudio'; 3 | 4 | import uiReducer from './ui-reducer'; 5 | 6 | 7 | export default combineReducers({ 8 | webAudioReducer, 9 | uiReducer 10 | }); 11 | -------------------------------------------------------------------------------- /examples/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React-Redux-Webaudio Example 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { RRWAEngine } from 'react-redux-webaudio'; 3 | 4 | import RRWAExamplesApp from './components'; 5 | import './styles/main.scss'; 6 | 7 | 8 | export default () => ( 9 |
10 | 11 | 12 |
13 | ); 14 | -------------------------------------------------------------------------------- /examples/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import { render } from 'react-dom'; 4 | 5 | import App from './App'; 6 | import store from './store'; 7 | 8 | 9 | render( 10 | 11 | 12 | , 13 | document.getElementById('app') 14 | ); 15 | -------------------------------------------------------------------------------- /lib/action-creators.js: -------------------------------------------------------------------------------- 1 | import { QUEUE_EVENT, CLEAR_EVT_QUEUE } from './constants'; 2 | export const clearEvtQueue = () => ({ 3 | type: CLEAR_EVT_QUEUE 4 | }); 5 | /** 6 | * `event` can be a single event or an array of events. An array passed as 7 | * `event` will be concatenated with the current event queue. 8 | * @param {Event | Event[]} event 9 | */ 10 | 11 | export const emit = event => ({ 12 | type: QUEUE_EVENT, 13 | event 14 | }); -------------------------------------------------------------------------------- /src/action-creators.js: -------------------------------------------------------------------------------- 1 | import { QUEUE_EVENT, CLEAR_EVT_QUEUE } from './constants'; 2 | 3 | 4 | export const clearEvtQueue = () => ({ 5 | type: CLEAR_EVT_QUEUE 6 | }); 7 | 8 | 9 | /** 10 | * `event` can be a single event or an array of events. An array passed as 11 | * `event` will be concatenated with the current event queue. 12 | * @param {Event | Event[]} event 13 | */ 14 | export const emit = (event) => ({ 15 | type: QUEUE_EVENT, 16 | event 17 | }); 18 | -------------------------------------------------------------------------------- /examples/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended", "plugin:react/recommended"], 3 | "parser": "babel-eslint", 4 | "env": { 5 | "browser": true, 6 | "node": true, 7 | "jest": true, 8 | "es6": true 9 | }, 10 | "rules": { 11 | "no-unused-vars": 1, 12 | "semi": [ 1, "always" ], 13 | "guard-for-in": "off", 14 | "require-await": "error", 15 | "react/prop-types": "off", 16 | "react/display-name": "off", 17 | "class-methods-use-this": "off", 18 | "id-length": [ "warn", { "exceptions": [ "a", "b", "c", "x", "y", "i" ] } ] 19 | } 20 | } -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["last 2 Chrome versions", "safari >=11"] 7 | } 8 | }], 9 | "@babel/preset-react" 10 | ], 11 | "plugins": [ 12 | "@babel/proposal-class-properties", 13 | "@babel/proposal-object-rest-spread" 14 | ], 15 | "env": { 16 | "test": { 17 | "presets": ["@babel/preset-env", "@babel/preset-react"], 18 | "plugins": [ 19 | "@babel/proposal-class-properties", 20 | "@babel/proposal-object-rest-spread" 21 | ] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended", "plugin:react/recommended"], 3 | "parser": "babel-eslint", 4 | "env": { 5 | "browser": true, 6 | "node": true, 7 | "jest": true, 8 | "es6": true 9 | }, 10 | "rules": { 11 | "no-console": 0, 12 | "no-unused-vars": 1, 13 | "semi": [ 1, "always" ], 14 | "quotes": ["warn", "single"], 15 | "guard-for-in": "off", 16 | "require-await": 1, 17 | "react/prop-types": "off", 18 | "react/display-name": "off", 19 | "class-methods-use-this": "off", 20 | "id-length": [ "warn", { "exceptions": [ "a", "b", "c", "x", "y", "i" ] } ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/action-creators.spec.js: -------------------------------------------------------------------------------- 1 | import * as actions from '../src/action-creators'; 2 | import * as types from '../src/constants'; 3 | 4 | 5 | describe('actions: ', () => { 6 | 7 | describe('emit', () => { 8 | it('should create an action to queue an event', () => { 9 | const event = () => {}; 10 | const expectedAction = { type: types.QUEUE_EVENT, event }; 11 | expect( actions.emit(event) ).toEqual(expectedAction); 12 | }); 13 | }); 14 | 15 | describe('clearEvtQueue', () => { 16 | it('should create an action to replace the current queue with an empty array', () => { 17 | const expectedAction = { type: types.CLEAR_EVT_QUEUE }; 18 | expect( actions.clearEvtQueue() ).toEqual(expectedAction); 19 | }); 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /examples/src/reducers/ui-reducer.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | msg: ' - ', 3 | susResToggle: 'SUSPEND' 4 | }; 5 | 6 | 7 | export default (state = initialState, action) => { 8 | const nextState = {...state}; 9 | 10 | switch (action.type) { 11 | 12 | case 'START': 13 | nextState.msg = 'BUZZING'; 14 | break; 15 | 16 | case 'TOGGLE_CTX_RUNNING': 17 | nextState.susResToggle = nextState.susResToggle === 'SUSPEND' 18 | ? 'RESUME' 19 | : 'SUSPEND'; 20 | nextState.msg = nextState.susResToggle === 'SUSPEND' 21 | ? 'BUZZING' 22 | : 'PAUSED'; 23 | break; 24 | 25 | case 'CLOSE': 26 | nextState.msg = 'AUDIO CONTEXT CLOSED!'; 27 | break; 28 | 29 | default: 30 | break; 31 | } 32 | 33 | return nextState; 34 | }; 35 | -------------------------------------------------------------------------------- /examples/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'development', 5 | entry: './src/index.js', 6 | output: { 7 | path: __dirname, 8 | filename: './public/bundle.js' 9 | }, 10 | context: __dirname, 11 | devtool: 'inline-source-map', 12 | devServer: { 13 | contentBase: path.join(__dirname, 'public'), 14 | compress: true, 15 | port: 8000 16 | }, 17 | module: { 18 | rules: [{ 19 | test: /jsx?$/, 20 | exclude: /(node_modules)/, 21 | use: { 22 | loader: 'babel-loader', 23 | options: { 24 | presets: ['@babel/preset-react', '@babel/preset-env'], 25 | plugins: [require('@babel/plugin-proposal-object-rest-spread')] 26 | } 27 | } 28 | }, { 29 | test: /\.scss$/, 30 | exclude: /(node_modules)/, 31 | use: ['style-loader', 'css-loader', 'sass-loader'] 32 | }] 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import resolve from 'rollup-plugin-node-resolve'; 3 | import commonjs from 'rollup-plugin-commonjs'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import { terser } from 'rollup-plugin-terser'; 6 | 7 | const env = process.env.NODE_ENV; 8 | const pkg = require('./package.json'); 9 | 10 | export default { 11 | input: 'src/index.js', 12 | output: { 13 | file: { 14 | es: pkg.module, 15 | cjs: pkg.main 16 | }[env], 17 | format: env 18 | }, 19 | plugins: [ 20 | resolve({ 21 | customResolveOptions: { 22 | moduleDirectory: 'node_modules' 23 | } 24 | }), 25 | babel({ 26 | exclude: 'node_modules/**', 27 | plugins: ['@babel/external-helpers'], 28 | externalHelpers: true 29 | }), 30 | commonjs(), 31 | terser(), 32 | filesize() 33 | ], 34 | external: ['react', 'redux', 'react-redux'] 35 | }; 36 | -------------------------------------------------------------------------------- /lib/web-audio-reducer.js: -------------------------------------------------------------------------------- 1 | import { QUEUE_EVENT, CLEAR_EVT_QUEUE } from './constants'; 2 | /** @constant */ 3 | 4 | const INIT_STATE = { 5 | events: [] 6 | }; 7 | 8 | const webAudioReducer = (state = INIT_STATE, action) => { 9 | const nextState = { 10 | events: [...state.events] 11 | }; 12 | 13 | switch (action.type) { 14 | case QUEUE_EVENT: 15 | queueEvent(state, action, nextState); 16 | break; 17 | 18 | case CLEAR_EVT_QUEUE: 19 | nextState.events = []; 20 | break; 21 | 22 | default: 23 | break; 24 | } 25 | 26 | return nextState; 27 | }; 28 | 29 | export default webAudioReducer; 30 | 31 | function queueEvent(state, action, nextState) { 32 | if (Array.isArray(action.event)) { 33 | action.event.forEach((event, idx) => { 34 | nextState.events.push({ 35 | key: state.events.length + idx, 36 | event: event 37 | }); 38 | }); 39 | } else { 40 | nextState.events.push({ 41 | key: state.events.length, 42 | event: action.event 43 | }); 44 | } 45 | } -------------------------------------------------------------------------------- /src/web-audio-reducer.js: -------------------------------------------------------------------------------- 1 | import { QUEUE_EVENT, CLEAR_EVT_QUEUE } from './constants'; 2 | 3 | /** @constant */ 4 | const INIT_STATE = { events: [] }; 5 | 6 | 7 | const webAudioReducer = (state = INIT_STATE, action) => { 8 | const nextState = { events: [ ...state.events ] }; 9 | 10 | switch (action.type) { 11 | 12 | case QUEUE_EVENT: 13 | queueEvent(state, action, nextState); 14 | break; 15 | 16 | case CLEAR_EVT_QUEUE: 17 | nextState.events = []; 18 | break; 19 | 20 | default: 21 | break; 22 | } 23 | 24 | return nextState; 25 | }; 26 | 27 | export default webAudioReducer; 28 | 29 | 30 | function queueEvent(state, action, nextState) { 31 | if (Array.isArray(action.event)) { 32 | action.event.forEach((event, idx) => { 33 | nextState.events.push({ 34 | key: (state.events.length + idx), 35 | event: event 36 | }); 37 | }); 38 | } else { 39 | nextState.events.push({ 40 | key: state.events.length, 41 | event: action.event 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-webaudio-examples", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "public/index.html", 6 | "scripts": { 7 | "start": "webpack-dev-server --open", 8 | "build": "webpack -p", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "bsaphier", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@babel/core": "^7.1.0", 15 | "@babel/plugin-proposal-class-properties": "^7.1.0", 16 | "@babel/plugin-proposal-object-rest-spread": "^7.0.0", 17 | "@babel/preset-env": "^7.1.0", 18 | "@babel/preset-react": "^7.0.0", 19 | "babel-loader": "^8.0.2", 20 | "css-loader": "^1.0.0", 21 | "node-sass": "^4.9.3", 22 | "sass-loader": "^7.1.0", 23 | "style-loader": "^0.23.0", 24 | "webpack": "^4.19.1", 25 | "webpack-cli": "^3.1.0", 26 | "webpack-dev-server": "^3.1.8" 27 | }, 28 | "dependencies": { 29 | "react": "^16.5.1", 30 | "react-dom": "^16.5.1", 31 | "react-redux": "^5.0.7", 32 | "redux": "^4.0.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Benjamin Saphier 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/src/styles/main.scss: -------------------------------------------------------------------------------- 1 | $on: rgb(45, 189, 45); 2 | $off: rgb(225, 189, 65); 3 | $dRed: rgb(189, 45, 45); 4 | $fontColor: rgb(189, 189, 189); 5 | $lighten: rgba(255, 255, 255, 0.1); 6 | $darken: rgba(0, 0, 0, 0.2); 7 | 8 | 9 | html { 10 | background-color: rgb(45,45,45); 11 | } 12 | 13 | #app { 14 | font-size: 20px; 15 | font-weight: 100; 16 | font-family: sans-serif; 17 | color: $fontColor; 18 | } 19 | 20 | div { 21 | p { 22 | margin: 5px auto; 23 | font-size: 2rem; 24 | text-shadow: 3px 5px 3px $darken; 25 | } 26 | } 27 | 28 | .main { 29 | text-align: center; 30 | } 31 | 32 | .title { 33 | &>h1 { 34 | display: inline; 35 | line-height: 6rem; 36 | font-weight: lighter; 37 | font-size: 4rem; 38 | } 39 | margin: 40px auto auto; 40 | } 41 | 42 | .btn-wrap { 43 | display: flex; 44 | flex-direction: column; 45 | 46 | margin: auto; 47 | min-width: 300px; 48 | max-width: 80%; 49 | 50 | } 51 | 52 | .button { 53 | &.light { 54 | background-color: $lighten; 55 | } 56 | cursor: default; 57 | 58 | min-width: 10rem; 59 | padding: 8px 0; 60 | margin: 5px auto; 61 | 62 | border: 1px solid $fontColor; 63 | border-radius: 3px; 64 | box-shadow: 0.3em 0.5em 1em 1px $darken; 65 | } 66 | 67 | .sm { 68 | color: $dRed; 69 | border-color: $dRed; 70 | } 71 | 72 | .on { 73 | color: $on; 74 | border-color: $on; 75 | } 76 | 77 | .off { 78 | color: $off; 79 | border-color: $off; 80 | } 81 | 82 | .bold { 83 | font-weight: 600; 84 | } 85 | 86 | .hide { 87 | display: none; 88 | } 89 | -------------------------------------------------------------------------------- /src/RRWA-component.js: -------------------------------------------------------------------------------- 1 | /* Export everything, for testing. */ 2 | import { Component } from 'react'; 3 | import { connect } from 'react-redux'; 4 | import { clearEvtQueue } from './action-creators'; 5 | 6 | 7 | export class RRWA extends Component { 8 | 9 | constructor(props) { 10 | super(props); 11 | const AudioContext = window.AudioContext || window.webkitAudioContext; 12 | if (AudioContext) { 13 | this.audioContext = new AudioContext(); 14 | } else { 15 | throw new Error('This environment does not support the web audio API.'); 16 | } 17 | } 18 | 19 | componentDidMount() { 20 | if (this.props.events.length) { 21 | this.props.events.forEach(this.processEvent); 22 | this.props.clearQ(); 23 | } 24 | } 25 | 26 | shouldComponentUpdate(nextProps) { 27 | return nextProps.events.length > 0; 28 | } 29 | 30 | componentDidUpdate() { 31 | if (this.props.events.length) { 32 | this.props.events.forEach(this.processEvent); 33 | this.props.clearQ(); 34 | } 35 | } 36 | 37 | componentWillUnmount() { 38 | this.audioContext.close(); 39 | } 40 | 41 | processEvent = ({ event }) => { 42 | event(this.audioContext, this.getCurrTime); 43 | } 44 | 45 | getCurrTime = () => { 46 | return this.audioContext.currentTime; 47 | } 48 | 49 | render() { 50 | return null; 51 | } 52 | } 53 | 54 | 55 | export const mapState = ({ webAudioReducer }) => ({ 56 | ...webAudioReducer 57 | }); 58 | 59 | export const mapDispatch = dispatch => ({ 60 | clearQ: () => dispatch(clearEvtQueue()) 61 | }); 62 | 63 | export default connect(mapState, mapDispatch)(RRWA); 64 | -------------------------------------------------------------------------------- /dist/index.es.js: -------------------------------------------------------------------------------- 1 | import{Component}from"react";import{connect}from"react-redux";const QUEUE_EVENT="QUEUE_EVENT",CLEAR_EVT_QUEUE="CLEAR_EVT_QUEUE",clearEvtQueue=()=>({type:CLEAR_EVT_QUEUE}),emit=e=>({type:QUEUE_EVENT,event:e});var actionCreators=Object.freeze({clearEvtQueue:clearEvtQueue,emit:emit});const INIT_STATE={events:[]},webAudioReducer=(e=INIT_STATE,t)=>{const n={events:[...e.events]};switch(t.type){case QUEUE_EVENT:queueEvent(e,t,n);break;case CLEAR_EVT_QUEUE:n.events=[]}return n};function queueEvent(e,t,n){Array.isArray(t.event)?t.event.forEach((t,r)=>{n.events.push({key:e.events.length+r,event:t})}):n.events.push({key:e.events.length,event:t.event})}function _defineProperty(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function _objectSpread(e){for(var t=1;t{e(this.audioContext,this.getCurrTime)}),_defineProperty(this,"getCurrTime",()=>this.audioContext.currentTime);const t=window.AudioContext||window.webkitAudioContext;if(!t)throw new Error("This environment does not support the web audio API.");this.audioContext=new t}componentDidMount(){this.props.events.length&&(this.props.events.forEach(this.processEvent),this.props.clearQ())}shouldComponentUpdate(e){return e.events.length>0}componentDidUpdate(){this.props.events.length&&(this.props.events.forEach(this.processEvent),this.props.clearQ())}componentWillUnmount(){this.audioContext.close()}render(){return null}}const mapState=({webAudioReducer:e})=>_objectSpread({},e),mapDispatch=e=>({clearQ:()=>e(clearEvtQueue())});var RRWAComponent=connect(mapState,mapDispatch)(RRWA);export{RRWAComponent as RRWAEngine,actionCreators,webAudioReducer}; 2 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var react=require("react"),reactRedux=require("react-redux");const QUEUE_EVENT="QUEUE_EVENT",CLEAR_EVT_QUEUE="CLEAR_EVT_QUEUE",clearEvtQueue=()=>({type:CLEAR_EVT_QUEUE}),emit=e=>({type:QUEUE_EVENT,event:e});var actionCreators=Object.freeze({clearEvtQueue:clearEvtQueue,emit:emit});const INIT_STATE={events:[]},webAudioReducer=(e=INIT_STATE,t)=>{const r={events:[...e.events]};switch(t.type){case QUEUE_EVENT:queueEvent(e,t,r);break;case CLEAR_EVT_QUEUE:r.events=[]}return r};function queueEvent(e,t,r){Array.isArray(t.event)?t.event.forEach((t,n)=>{r.events.push({key:e.events.length+n,event:t})}):r.events.push({key:e.events.length,event:t.event})}function _defineProperty(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function _objectSpread(e){for(var t=1;t{e(this.audioContext,this.getCurrTime)}),_defineProperty(this,"getCurrTime",()=>this.audioContext.currentTime);const t=window.AudioContext||window.webkitAudioContext;if(!t)throw new Error("This environment does not support the web audio API.");this.audioContext=new t}componentDidMount(){this.props.events.length&&(this.props.events.forEach(this.processEvent),this.props.clearQ())}shouldComponentUpdate(e){return e.events.length>0}componentDidUpdate(){this.props.events.length&&(this.props.events.forEach(this.processEvent),this.props.clearQ())}componentWillUnmount(){this.audioContext.close()}render(){return null}}const mapState=({webAudioReducer:e})=>_objectSpread({},e),mapDispatch=e=>({clearQ:()=>e(clearEvtQueue())});var RRWAComponent=reactRedux.connect(mapState,mapDispatch)(RRWA);exports.RRWAEngine=RRWAComponent,exports.actionCreators=actionCreators,exports.webAudioReducer=webAudioReducer; 2 | -------------------------------------------------------------------------------- /lib/RRWA-component.js: -------------------------------------------------------------------------------- 1 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } 2 | 3 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 4 | 5 | /* Export everything, for testing. */ 6 | import { Component } from 'react'; 7 | import { connect } from 'react-redux'; 8 | import { clearEvtQueue } from './action-creators'; 9 | export class RRWA extends Component { 10 | constructor(props) { 11 | super(props); 12 | 13 | _defineProperty(this, "processEvent", ({ 14 | event 15 | }) => { 16 | event(this.audioContext, this.getCurrTime); 17 | }); 18 | 19 | _defineProperty(this, "getCurrTime", () => { 20 | return this.audioContext.currentTime; 21 | }); 22 | 23 | const AudioContext = window.AudioContext || window.webkitAudioContext; 24 | 25 | if (AudioContext) { 26 | this.audioContext = new AudioContext(); 27 | } else { 28 | throw new Error('This environment does not support the web audio API.'); 29 | } 30 | } 31 | 32 | componentDidMount() { 33 | if (this.props.events.length) { 34 | this.props.events.forEach(this.processEvent); 35 | this.props.clearQ(); 36 | } 37 | } 38 | 39 | shouldComponentUpdate(nextProps) { 40 | return nextProps.events.length > 0; 41 | } 42 | 43 | componentDidUpdate() { 44 | if (this.props.events.length) { 45 | this.props.events.forEach(this.processEvent); 46 | this.props.clearQ(); 47 | } 48 | } 49 | 50 | componentWillUnmount() { 51 | this.audioContext.close(); 52 | } 53 | 54 | render() { 55 | return null; 56 | } 57 | 58 | } 59 | export const mapState = ({ 60 | webAudioReducer 61 | }) => _objectSpread({}, webAudioReducer); 62 | export const mapDispatch = dispatch => ({ 63 | clearQ: () => dispatch(clearEvtQueue()) 64 | }); 65 | export default connect(mapState, mapDispatch)(RRWA); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-webaudio", 3 | "version": "2.0.0", 4 | "description": "The Web Audio API, thinly wrapped for easy integration with React-Redux", 5 | "main": "dist/index.js", 6 | "module": "dist/index.es.js", 7 | "author": "bsaphier", 8 | "license": "ISC", 9 | "homepage": "https://bsaphier.github.io/react-redux-webaudio/", 10 | "files": [ 11 | "dist", 12 | "lib" 13 | ], 14 | "scripts": { 15 | "test": "jest .spec.js$", 16 | "coveralls": "jest --coverage --coverageReporters=text-lcov | coveralls", 17 | "clean": "rimraf dist", 18 | "build": "run-s clean && run-p build:es build:cjs build:lib:es", 19 | "build:es": "NODE_ENV=es rollup -c", 20 | "build:cjs": "NODE_ENV=cjs rollup -c", 21 | "build:lib:es": "BABEL_ENV=es babel src -d lib" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/bsaphier/react-redux-webaudio.git" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/bsaphier/react-redux-webaudio/issues" 29 | }, 30 | "jest": { 31 | "verbose": true, 32 | "collectCoverage": true, 33 | "setupTestFrameworkScriptFile": "./test/setup.js" 34 | }, 35 | "devDependencies": { 36 | "@babel/cli": "^7.1.0", 37 | "@babel/core": "^7.0.0", 38 | "@babel/plugin-external-helpers": "^7.0.0", 39 | "@babel/plugin-proposal-class-properties": "^7.0.0", 40 | "@babel/plugin-proposal-object-rest-spread": "^7.0.0", 41 | "@babel/preset-env": "^7.0.0", 42 | "@babel/preset-react": "^7.0.0", 43 | "babel-core": "^7.0.0-0", 44 | "babel-jest": "^23.4.2", 45 | "coveralls": "^3.0.2", 46 | "jest": "^23.5.0", 47 | "npm-run-all": "^4.1.3", 48 | "react-dom": "^16.5.2", 49 | "react-test-renderer": "^16.5.2", 50 | "rollup": "^0.66.2", 51 | "rollup-plugin-babel": "^4.0.3", 52 | "rollup-plugin-commonjs": "^9.1.8", 53 | "rollup-plugin-filesize": "^4.0.1", 54 | "rollup-plugin-node-resolve": "^3.4.0", 55 | "rollup-plugin-terser": "^3.0.0", 56 | "web-audio-engine": "^0.13.4" 57 | }, 58 | "dependencies": { 59 | "react": "^16.5.2", 60 | "react-redux": "^5.0.7", 61 | "redux": "^4.0.0" 62 | }, 63 | "keywords": [ 64 | "html5", 65 | "react", 66 | "redux", 67 | "audio", 68 | "webaudio", 69 | "web-audio", 70 | "webaudioapi", 71 | "react-redux", 72 | "web-audio-api" 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /test/web-audio-reducer.spec.js: -------------------------------------------------------------------------------- 1 | import webAudioReducer from '../src/web-audio-reducer'; 2 | import * as types from '../src/constants'; 3 | 4 | const event1 = function() {}; 5 | const event2 = function() {}; 6 | const event3 = function() {}; 7 | const event4 = function() {}; 8 | 9 | 10 | const INIT_STATE = { events: [] }; 11 | 12 | 13 | describe('webAudioReducer', () => { 14 | 15 | it('should return the initial state', () => { 16 | expect( webAudioReducer(undefined, {}) ).toEqual(INIT_STATE); 17 | }); 18 | 19 | describe('should handle QUEUE_EVENT', () => { 20 | 21 | it('with a single event', () => { 22 | expect( webAudioReducer( 23 | INIT_STATE, 24 | { type: types.QUEUE_EVENT, event: event1 } 25 | )).toEqual({ events: [{ key: 0, event: event1 }] }); 26 | 27 | expect( webAudioReducer( 28 | { events: [{ key: 0, event: event1 }] }, 29 | { type: types.QUEUE_EVENT, event: event2 } 30 | )).toEqual({ events: [ 31 | { key: 0, event: event1 }, 32 | { key: 1, event: event2 } 33 | ]}); 34 | }); 35 | 36 | it('with an array of events', () => { 37 | expect( webAudioReducer( 38 | INIT_STATE, 39 | { 40 | type: types.QUEUE_EVENT, 41 | event: [ event1, event2 ] 42 | } 43 | )).toEqual({ events: [ 44 | { key: 0, event: event1 }, 45 | { key: 1, event: event2 } 46 | ]}); 47 | 48 | expect( webAudioReducer( 49 | { events: [{ key: 0, event: event1 }] }, 50 | { 51 | type: types.QUEUE_EVENT, 52 | event: [ event2, event3, event4 ] 53 | } 54 | )).toEqual({ events: [ 55 | { key: 0, event: event1 }, 56 | { key: 1, event: event2 }, 57 | { key: 2, event: event3 }, 58 | { key: 3, event: event4 } 59 | ]}); 60 | }); 61 | }); 62 | 63 | 64 | describe('should handle CLEAR_EVT_QUEUE', () => { 65 | 66 | it('with an empty queue', () => { 67 | expect( webAudioReducer( 68 | INIT_STATE, 69 | { type: types.CLEAR_EVT_QUEUE } 70 | )).toEqual( INIT_STATE ); 71 | }); 72 | 73 | it('with a queue full of events', () => { 74 | expect( webAudioReducer( 75 | { events: [ 76 | { key: 0, event: event1 }, 77 | { key: 1, event: event2 } 78 | ]}, 79 | { type: types.CLEAR_EVT_QUEUE } 80 | )).toEqual( INIT_STATE ); 81 | }); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /examples/src/components/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { actionCreators } from 'react-redux-webaudio'; 4 | import { startCtxUI, closeCtxUI, susResAudioCtx } from '../actions'; 5 | const { emit } = actionCreators; 6 | 7 | 8 | /** 9 | * This is an audio event that will be handled by `react-redux-webaudio`. 10 | * @param {AudioContext} audioCtx - A Reference to an instance of the global AudioContext. 11 | * @param {() => number} [getCurrentTime] - A function that returns the current value of AudioContext.currentTime. 12 | */ 13 | const start = (audioCtx, getCurrentTime) => { 14 | // create Oscillator and gain node 15 | let oscillator = audioCtx.createOscillator(); 16 | let gainNode = audioCtx.createGain(); 17 | 18 | // connect oscillator to gain node to speakers 19 | oscillator.connect(gainNode); 20 | gainNode.connect(audioCtx.destination); 21 | 22 | // Make noise, sweet noise 23 | oscillator.type = 'square'; 24 | oscillator.frequency.value = 100; // value in hertz 25 | oscillator.start(getCurrentTime()); 26 | 27 | gainNode.gain.value = 0.1; 28 | }; 29 | 30 | /** Another audio event. */ 31 | const susRes = (audioCtx) => { 32 | if (audioCtx.state === 'running') { 33 | audioCtx.suspend(); 34 | } else if (audioCtx.state === 'suspended') { 35 | audioCtx.resume(); 36 | } 37 | }; 38 | 39 | /** Another audio event. */ 40 | const close = (audioCtx) => audioCtx.close(); 41 | 42 | 43 | /** React Component */ 44 | class RRWAExamplesApp extends PureComponent { 45 | 46 | constructor(props) { 47 | super(props); 48 | this.state = { 49 | closed: false, 50 | oscCount: 0 51 | }; 52 | } 53 | 54 | handleCreate = () => { 55 | this.props.start(); 56 | this.setState({ oscCount: this.state.oscCount + 1 }); 57 | } 58 | 59 | handleKill = () => { 60 | this.props.kill(); 61 | this.setState({ closed: true }); 62 | } 63 | 64 | render() { 65 | const { oscCount } = this.state; 66 | const { msg, susRes, susResToggle } = this.props.uiReducer; 67 | 68 | return ( 69 |
70 |

{msg}

71 |
72 |
73 |
74 |

LOUD!

75 |

TURN DOWN THE VOLUME!

76 |
77 |
78 |
0 ? 'hide' : ''}`} 80 | onClick={this.create}> 81 | {'CREATE'} 82 |
83 |
86 | {susResToggle} 87 |
88 |
91 | {'KILL'} 92 |
93 |
94 |
95 |
96 | ); 97 | } 98 | } 99 | 100 | 101 | export default connect( 102 | state => ({...state}), 103 | dispatch => ({ 104 | start: () => { 105 | dispatch( startCtxUI() ); 106 | dispatch( emit( start ) ); 107 | }, 108 | susRes: () => { 109 | dispatch( susResAudioCtx() ); 110 | dispatch( emit( susRes ) ); 111 | }, 112 | close: () => { 113 | dispatch( closeCtxUI() ); 114 | dispatch( emit( close ) ); 115 | }, 116 | }) 117 | )(RRWAExamplesApp); 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # REACT-REDUX-WEBAUDIO [![Build Status](https://travis-ci.org/bsaphier/react-redux-webaudio.svg?branch=master)](https://travis-ci.org/bsaphier/react-redux-webaudio) [![Coverage Status](https://coveralls.io/repos/github/bsaphier/react-redux-webaudio/badge.svg?branch=master)](https://coveralls.io/github/bsaphier/react-redux-webaudio) [![npm](https://img.shields.io/npm/v/react-redux-webaudio.svg)](https://www.npmjs.com/package/react-redux-webaudio) 2 | ###### An event manager for the [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API), integrated with [`react-redux`](https://redux.js.org/basics/usagewithreact). 3 | 4 | > #### ***Attn***: *Do not use this library for processing audio events that require low latency.* 5 | > Audio events are handled by React's internal reconciliation/diffing algos and therefore the latency, in terms of audio, is **huge**. 6 | 7 | ## Demo & Examples 8 | [Live Demo](https://bsaphier.github.io/react-redux-webaudio/examples/public/index.html) 9 | To build the examples locally, clone/fork the repo and run: 10 | ``` 11 | cd examples 12 | yarn /* OR */ npm install 13 | npm start // this will start a webpack-dev-server and open the demo in your browser 14 | ``` 15 | 16 | ## Installation & Setup 17 | ```bash 18 | npm i react-redux-webaudio 19 | ``` 20 | 21 | 22 | ### Basic Setup Example 23 | ```javascript 24 | /** 25 | * Imports 26 | */ 27 | // Es6+ import 28 | import { RRWAEngine, actionCreators, webAudioReducer } from 'react-redux-webaudio'; 29 | // Es5 30 | const { RRWAEngine, actionCreators, webAudioReducer } = require('react-redux-webaudio'); 31 | 32 | 33 | 34 | /** 35 | * The root reducer used in the Redux store. 36 | */ 37 | const rootReducer = combineReducers({ 38 | // your other reducers... 39 | webAudioReducer 40 | }); 41 | 42 | 43 | 44 | /** 45 | * The application entry point. 46 | * Best to keep RRWAEngine at the top-level but technically it can be 47 | * anywhere, as long as it renders before any AudioEvents are emitted. 48 | */ 49 | ReactDOM.render( 50 | 51 |
52 | 53 | 54 |
55 |
, 56 | document.getElementById('app') 57 | ); 58 | 59 | 60 | 61 | /** 62 | * A container component that will render within the component tree of 63 | */ 64 | const Container = connect( 65 | state => state, 66 | dispatch => ({ makeNoise: () => dispatch(actionCreators.emit(audioEvent)) }) 67 | )(ReactComponent); 68 | ``` 69 | 70 | 71 | ## Documentation 72 | 73 | **React-Redux-Webaudio** consists of three modules: 74 | - **webAudioReducer** – *The Redux reducer.* 75 | - **RRWAEngine** –––––– *The React component.* 76 | - **actionCreators** –––– *The Redux action-creators (it's not required that these action creators are used).* 77 | 78 | 79 | ### Defining an Audio Event 80 | Within the context of **React-Redux-Webaudio**, an `AudioEvent` is a function that receives one or two arguments: a reference to an instance of `window.AudioContext`, anda function that when called, returns that instance's `currentTime` value. 81 | 82 | ```ts 83 | type AudioEvent = (audioCtx: AudioContext, getCurrentTime?: () => number) => void | any; 84 | 85 | // a semi-practical example of what an AudioEvent could look like 86 | let audioEvent: AudioEvent = (audioCtx, getCurrentTime) => { 87 | let oscillator: OscillatorNode = audioCtx.createOscillator(); 88 | let gainNode: GainNode = audioCtx.createGain(); 89 | 90 | oscillator.connect(gainNode); 91 | gainNode.connect(audioCtx.destination); 92 | 93 | oscillator.type = 'square'; 94 | oscillator.frequency.value = 100; 95 | oscillator.start(getCurrentTime() + 500); // wait half a second, then make sound. 96 | 97 | gainNode.gain.value = 0.1; 98 | }; 99 | ``` 100 | ###### ***Note***: Directly accessing `audioCtx.currentTime` may result in the time when the event was queued, not invoked. Instead, use the optional function `getCurrentTime`, which will return the value of `audioCtx.currentTime` when the `AudioEvent` is actually invoked. 101 | 102 | ### Action Creators 103 | #### `emit` 104 | The `emit` action-creator receives a single event or an array of events. 105 | - If passed a single event, it will be pushed to a queue where it will be invoked in FIFO order. 106 | - If passed an array of events, the array will be concatenated with the current event queue. 107 | 108 | #### Queueing an audio event without the included `emit` action-creator: 109 | To use your own Redux action instead of the one created by emit, the action type must be `'QUEUE_EVENT'` and the action must have an `event` key with a value of an `AudioEvent` or `Array`. 110 | 111 | ```ts 112 | type AudioEventAction = { 113 | type: 'QUEUE_EVENT' 114 | event: AudioEvent | AudioEvent[] 115 | } 116 | 117 | let action: AudioEventAction = { 118 | type: 'QUEUE_EVENT', 119 | event: (audioCtx, currentTime) => { 120 | // do something... anything. 121 | } 122 | }; 123 | 124 | store.dispatch(action); // more practically, include the action within a mapDispatchToProps function. 125 | ``` 126 | 127 | 128 | ### The RRWAEngine Component 129 | Include the RRWAEngine component anywhere in your app (*best to keep RRWAEngine at the top-level but technically it can be anywhere*). It must be within scope of the Redux store containing the webAudioReducer. 130 | ```js 131 | class App extends React.Component { 132 | render() { 133 | return ( 134 |
135 | 136 | {/* other components would go here */} 137 |
138 | ); 139 | } 140 | } 141 | 142 | ReactDOM.render( 143 | 144 | 145 | , 146 | document.getElementById('app') 147 | ); 148 | ``` 149 | 150 | --- 151 | 152 | ###### *Pull Requests, github issues, comments, and questions are welcome* :) 153 | -------------------------------------------------------------------------------- /test/RRWA-component.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestRenderer from 'react-test-renderer'; 3 | import { RRWA, mapState, mapDispatch } from '../src/RRWA-component'; 4 | 5 | class MockAudioContext { 6 | constructor() { 7 | this.closed = false; 8 | this.currentTime = 0; 9 | } 10 | 11 | close() { 12 | this.closed = true; 13 | } 14 | } 15 | 16 | 17 | describe('RRWA component', () => { 18 | const event1Mock = jest.fn(); 19 | const event2Mock = jest.fn(); 20 | const event3Mock = jest.fn(); 21 | const eventObject1 = { key: 0, event: event1Mock }; 22 | const eventObject2 = { key: 1, event: event2Mock }; 23 | const eventObject3 = { key: 2, event: event3Mock }; 24 | const mockEvents = [eventObject1, eventObject2, eventObject3]; 25 | 26 | afterEach(() => { 27 | jest.clearAllMocks(); 28 | }); 29 | 30 | describe('* Lifecycle *', () => { 31 | describe('componentDidMount', () => { 32 | 33 | afterEach(() => { 34 | jest.clearAllMocks(); 35 | }); 36 | 37 | it('calls RRWA.processEvent on every item in RRWA.props.events if RRWA.props.events is not empty', () => { 38 | const componentDidMountSpy = jest.spyOn(RRWA.prototype, 'componentDidMount'); 39 | 40 | // test with empty events array 41 | let wrapper = TestRenderer.create( {}} events={[]} />); 42 | let instance = wrapper.getInstance(); 43 | expect(instance.props.events.length).toBeFalsy(); 44 | let processEventSpy = jest.spyOn(instance, 'processEvent'); 45 | componentDidMountSpy.mockClear(); 46 | instance.componentDidMount(); 47 | expect(componentDidMountSpy).toHaveBeenCalledTimes(1); 48 | expect(processEventSpy).not.toHaveBeenCalled(); 49 | wrapper.unmount(); 50 | 51 | // test with events in the events array 52 | wrapper = TestRenderer.create( {}} events={mockEvents} />); 53 | instance = wrapper.getInstance(); 54 | expect(instance.props.events.length).not.toBeFalsy(); 55 | processEventSpy = jest.spyOn(instance, 'processEvent'); 56 | componentDidMountSpy.mockClear(); 57 | instance.componentDidMount(); 58 | expect(componentDidMountSpy).toHaveBeenCalledTimes(1); 59 | expect(processEventSpy).toHaveBeenCalledTimes(instance.props.events.length); 60 | wrapper.unmount(); 61 | }); 62 | 63 | it('calls RRWA.props.clearQ if RRWA.props.events is not empty', () => { 64 | const componentDidMountSpy = jest.spyOn(RRWA.prototype, 'componentDidMount'); 65 | const clearQMock = jest.fn(); 66 | let wrapper = TestRenderer.create(); 67 | 68 | // test with empty events array 69 | expect(componentDidMountSpy).toHaveBeenCalledTimes(1); 70 | expect(clearQMock).not.toHaveBeenCalled(); 71 | wrapper.unmount(); 72 | 73 | // test with events in the events array 74 | wrapper = TestRenderer.create(); 75 | expect(componentDidMountSpy).toHaveBeenCalledTimes(2); 76 | expect(clearQMock).toHaveBeenCalledTimes(1); 77 | wrapper.unmount(); 78 | }); 79 | }); 80 | 81 | describe('shouldComponentUpdate', () => { 82 | it('will return `true` if RRWA.props.events is not empty', () => { 83 | const wrapper = TestRenderer.create(); 84 | const instance = wrapper.getInstance(); 85 | expect(instance.shouldComponentUpdate({ events: [] })).toBe(false); 86 | expect(instance.shouldComponentUpdate({ events: mockEvents })).toBe(true); 87 | wrapper.unmount(); 88 | jest.clearAllMocks(); 89 | }); 90 | }); 91 | 92 | describe('componentDidUpdate', () => { 93 | 94 | afterEach(() => { 95 | jest.clearAllMocks(); 96 | }); 97 | 98 | it('does not get called if the incoming RRWA.props.events is empty', () => { 99 | const componentDidUpdateSpy = jest.spyOn(RRWA.prototype, 'componentDidUpdate'); 100 | let wrapper = TestRenderer.create( {}} events={[]} />); 101 | let instance = wrapper.getInstance(); 102 | 103 | // test with events in the events array 104 | wrapper.update( {}} events={[eventObject1]} />); 105 | expect(instance.props.events.length).not.toBeFalsy(); 106 | expect(componentDidUpdateSpy).toHaveBeenCalledTimes(1); 107 | 108 | // test with empty events array 109 | wrapper.update( {}} events={[]} />); 110 | expect(instance.props.events.length).toBeFalsy(); 111 | expect(componentDidUpdateSpy).toHaveBeenCalledTimes(1); // was not called again, even though props did update 112 | }); 113 | 114 | it('calls RRWA.processEvent on every item in RRWA.props.events, if RRWA.props.events is not empty', () => { 115 | const componentDidUpdateSpy = jest.spyOn(RRWA.prototype, 'componentDidUpdate'); 116 | 117 | // test with empty events array 118 | let wrapper = TestRenderer.create( 119 | 120 | ); 121 | let instance = wrapper.getInstance(); 122 | let processEventSpy = jest.spyOn(instance, 'processEvent'); 123 | wrapper.update( {}} events={[]} />); 124 | expect(instance.props.events.length).toBeFalsy(); 125 | expect(componentDidUpdateSpy).not.toHaveBeenCalled(); 126 | expect(processEventSpy).not.toHaveBeenCalled(); 127 | 128 | // test with events in the events array 129 | wrapper.update( {}} events={mockEvents} />); 130 | expect(instance.props.events.length).toBeGreaterThan(0); 131 | expect(componentDidUpdateSpy).toHaveBeenCalledTimes(1); 132 | expect(processEventSpy).toHaveBeenCalledTimes(instance.props.events.length); 133 | 134 | wrapper.unmount(); 135 | }); 136 | 137 | it('calls RRWA.props.clearQ if RRWA.props.events is not empty', () => { 138 | const componentDidUpdateSpy = jest.spyOn(RRWA.prototype, 'componentDidUpdate'); 139 | const clearQMock = jest.fn(); 140 | 141 | // test with empty events array 142 | const wrapper = TestRenderer.create(); 143 | expect(componentDidUpdateSpy).not.toHaveBeenCalled(); 144 | expect(clearQMock).not.toHaveBeenCalled(); 145 | 146 | // test with events in the events array 147 | wrapper.update(); 148 | expect(componentDidUpdateSpy).toHaveBeenCalledTimes(1); 149 | expect(clearQMock).toHaveBeenCalledTimes(1); 150 | 151 | wrapper.unmount(); 152 | }); 153 | }); 154 | 155 | describe('componentWillUnmount', () => { 156 | 157 | afterEach(() => { 158 | jest.clearAllMocks(); 159 | }); 160 | 161 | it('gets called when the component unmounts', () => { 162 | const componentWillUnmountSpy = jest.spyOn(RRWA.prototype, 'componentWillUnmount'); 163 | const wrapper = TestRenderer.create( {}} events={[]} />); 164 | expect(componentWillUnmountSpy).not.toHaveBeenCalled(); 165 | wrapper.unmount(); 166 | expect(componentWillUnmountSpy).toHaveBeenCalledTimes(1); 167 | }); 168 | 169 | it('calls RRWA.audioContext.close', () => { 170 | const wrapper = TestRenderer.create( {}} events={[]} />); 171 | const instance = wrapper.getInstance(); 172 | const audioContextCloseSpy = jest.spyOn(instance.audioContext, 'close'); 173 | wrapper.unmount(); 174 | expect(audioContextCloseSpy).toHaveBeenCalledTimes(1); 175 | }); 176 | }); 177 | }); 178 | 179 | describe('* Instance *', () => { 180 | const _AudioContext = window.AudioContext; // store this value so that it can be reset 181 | let wrapper, instance, audioContext; 182 | 183 | beforeEach(() => { 184 | wrapper = TestRenderer.create( {}} events={[]} />); 185 | instance = wrapper.getInstance(); 186 | audioContext = instance.audioContext; 187 | }); 188 | 189 | afterEach(() => { 190 | wrapper.unmount(); 191 | jest.clearAllMocks(); 192 | window.AudioContext = _AudioContext; 193 | delete window.webkitAudioContext; 194 | }); 195 | 196 | it('should render without error', () => { 197 | expect(wrapper).toBeTruthy(); 198 | }); 199 | 200 | it('should be an instance of RRWA-component', () => { 201 | expect(instance).toBeInstanceOf(RRWA); 202 | }); 203 | 204 | it('shouldn\'t render anything', () => { 205 | expect(instance.render()).toBeNull(); 206 | }); 207 | 208 | it('constructor assigns RRWA.audioContext to a new instance of window.AudioContext || window.webkitAudioContext', () => { 209 | window.AudioContext = MockAudioContext; 210 | wrapper = TestRenderer.create( {}} events={[]} />); 211 | instance = wrapper.getInstance(); 212 | expect(instance.audioContext).toBeInstanceOf(MockAudioContext); 213 | 214 | window.AudioContext = undefined; 215 | window.webkitAudioContext = MockAudioContext; 216 | wrapper = TestRenderer.create( {}} events={[]} />); 217 | instance = wrapper.getInstance(); 218 | expect(instance.audioContext).toBeInstanceOf(MockAudioContext); 219 | }); 220 | 221 | it('should throw an error if (window.AudioContext || window.webkitAudioContext) is false', () => { 222 | window.AudioContext = undefined; 223 | window.webkitAudioContext = undefined; 224 | expect(window.AudioContext || window.webkitAudioContext).toBeFalsy(); 225 | expect(() => TestRenderer.create( {}} events={[]} />)).toThrow(); 226 | }); 227 | 228 | describe('RRWA.getCurrTime', () => { 229 | it('should return the currentTime of the audioContext instance', () => { 230 | expect(audioContext.currentTime).toEqual(0); 231 | expect(instance.getCurrTime()).toEqual(0); 232 | audioContext.processTo(500); 233 | expect(audioContext.currentTime).toBeCloseTo(500); 234 | expect(instance.getCurrTime()).toBeCloseTo(500); 235 | }); 236 | }); 237 | 238 | describe('RRWA.processEvent', () => { 239 | it('should call the function passed as args[0].event', () => { 240 | const eventMock = eventObject1.event; 241 | instance.processEvent(eventObject1); 242 | expect(eventMock.mock.calls.length).toBe(1); 243 | }); 244 | 245 | it('should pass RRWA.audioContext as the first argument to the event function that this method calls', () => { 246 | const eventMock = eventObject1.event; 247 | eventMock.mockClear(); 248 | instance.processEvent(eventObject1); 249 | expect(eventMock.mock.calls[0][0]).toBe(instance.audioContext); 250 | }); 251 | 252 | it('should pass RRWA.getCurrTime as the second argument to the event function that this method calls', () => { 253 | const eventMock = eventObject1.event; 254 | eventMock.mockClear(); 255 | instance.processEvent(eventObject1); 256 | expect(eventMock.mock.calls[0][1]).toBe(instance.getCurrTime); 257 | }); 258 | }); 259 | }); 260 | 261 | describe('* Redux Connection *', () => { 262 | 263 | describe('mapStateToProps', () => { 264 | let mockState = { webAudioReducer: { events: [] } }; 265 | 266 | it('returns an object containing the values of the webAudioReducer', () => { 267 | expect(mapState(mockState)).toEqual(mockState.webAudioReducer); 268 | expect(mapState(mockState)).toMatchObject(mockState.webAudioReducer); 269 | }); 270 | 271 | it('returns a new object', () => { 272 | expect(mapState(mockState)).toEqual(mockState.webAudioReducer); 273 | expect(mapState(mockState)).not.toBe(mockState.webAudioReducer); 274 | }); 275 | }); 276 | 277 | describe('mapDispatchToProps', () => { 278 | 279 | it('returns an object containing a key: `clearQ`', () => { 280 | expect(mapDispatch()).toHaveProperty('clearQ'); 281 | }); 282 | 283 | it('the value of clearQ is a function that calls the function passed to mapDispatch', () => { 284 | let dispatch = jest.fn(); 285 | let mappedProps = mapDispatch(dispatch); 286 | mappedProps.clearQ(); 287 | expect(dispatch).toHaveBeenCalled(); 288 | }); 289 | }); 290 | }); 291 | }); 292 | -------------------------------------------------------------------------------- /examples/public/bundle.js: -------------------------------------------------------------------------------- 1 | !function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=93)}([function(e,t,n){"use strict";function r(e,t,n,r,i,a,u,s){if(o(t),!e){var c;if(void 0===t)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[n,r,i,a,u,s],p=0;c=new Error(t.replace(/%s/g,function(){return l[p++]})),c.name="Invariant Violation"}throw c.framesToPop=1,c}}var o=function(e){};e.exports=r},function(e,t,n){"use strict";var r=n(6),o=r;e.exports=o},function(e,t,n){"use strict";function r(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r1){for(var h=Array(f),m=0;m1){for(var g=Array(v),y=0;y]/,s=n(41),c=s(function(e,t){if(e.namespaceURI!==i.svg||"innerHTML"in e)e.innerHTML=t;else{r=r||document.createElement("div"),r.innerHTML=""+t+"";for(var n=r.firstChild;n.firstChild;)e.appendChild(n.firstChild)}});if(o.canUseDOM){var l=document.createElement("div");l.innerHTML=" ",""===l.innerHTML&&(c=function(e,t){if(e.parentNode&&e.parentNode.replaceChild(e,e),a.test(t)||"<"===t[0]&&u.test(t)){e.innerHTML=String.fromCharCode(65279)+t;var n=e.firstChild;1===n.data.length?e.removeChild(n):n.deleteData(0,1)}else e.innerHTML=t}),l=null}e.exports=c},function(e,t,n){"use strict";function r(e){var t=""+e,n=i.exec(t);if(!n)return t;var r,o="",a=0,u=0;for(a=n.index;a]/;e.exports=o},function(e,t,n){"use strict";function r(e){return Object.prototype.hasOwnProperty.call(e,m)||(e[m]=f++,p[e[m]]={}),p[e[m]]}var o,i=n(3),a=n(33),u=n(165),s=n(75),c=n(166),l=n(37),p={},d=!1,f=0,h={topAbort:"abort",topAnimationEnd:c("animationend")||"animationend",topAnimationIteration:c("animationiteration")||"animationiteration",topAnimationStart:c("animationstart")||"animationstart",topBlur:"blur",topCanPlay:"canplay",topCanPlayThrough:"canplaythrough",topChange:"change",topClick:"click",topCompositionEnd:"compositionend",topCompositionStart:"compositionstart",topCompositionUpdate:"compositionupdate",topContextMenu:"contextmenu",topCopy:"copy",topCut:"cut",topDoubleClick:"dblclick",topDrag:"drag",topDragEnd:"dragend",topDragEnter:"dragenter",topDragExit:"dragexit",topDragLeave:"dragleave",topDragOver:"dragover",topDragStart:"dragstart",topDrop:"drop",topDurationChange:"durationchange",topEmptied:"emptied",topEncrypted:"encrypted",topEnded:"ended",topError:"error",topFocus:"focus",topInput:"input",topKeyDown:"keydown",topKeyPress:"keypress",topKeyUp:"keyup",topLoadedData:"loadeddata",topLoadedMetadata:"loadedmetadata",topLoadStart:"loadstart",topMouseDown:"mousedown",topMouseMove:"mousemove",topMouseOut:"mouseout",topMouseOver:"mouseover",topMouseUp:"mouseup",topPaste:"paste",topPause:"pause",topPlay:"play",topPlaying:"playing",topProgress:"progress",topRateChange:"ratechange",topScroll:"scroll",topSeeked:"seeked",topSeeking:"seeking",topSelectionChange:"selectionchange",topStalled:"stalled",topSuspend:"suspend",topTextInput:"textInput",topTimeUpdate:"timeupdate",topTouchCancel:"touchcancel",topTouchEnd:"touchend",topTouchMove:"touchmove",topTouchStart:"touchstart",topTransitionEnd:c("transitionend")||"transitionend",topVolumeChange:"volumechange",topWaiting:"waiting",topWheel:"wheel"},m="_reactListenersID"+String(Math.random()).slice(2),v=i({},u,{ReactEventListener:null,injection:{injectReactEventListener:function(e){e.setHandleTopLevel(v.handleTopLevel),v.ReactEventListener=e}},setEnabled:function(e){v.ReactEventListener&&v.ReactEventListener.setEnabled(e)},isEnabled:function(){return!(!v.ReactEventListener||!v.ReactEventListener.isEnabled())},listenTo:function(e,t){for(var n=t,o=r(n),i=a.registrationNameDependencies[e],u=0;u-1||a("96",e),!c.plugins[n]){t.extractEvents||a("97",e),c.plugins[n]=t;var r=t.eventTypes;for(var i in r)o(r[i],t,i)||a("98",i,e)}}}function o(e,t,n){c.eventNameDispatchConfigs.hasOwnProperty(n)&&a("99",n),c.eventNameDispatchConfigs[n]=e;var r=e.phasedRegistrationNames;if(r){for(var o in r)if(r.hasOwnProperty(o)){var u=r[o];i(u,t,n)}return!0}return!!e.registrationName&&(i(e.registrationName,t,n),!0)}function i(e,t,n){c.registrationNameModules[e]&&a("100",e),c.registrationNameModules[e]=t,c.registrationNameDependencies[e]=t.eventTypes[n].dependencies}var a=n(2),u=(n(0),null),s={},c={plugins:[],eventNameDispatchConfigs:{},registrationNameModules:{},registrationNameDependencies:{},possibleRegistrationNames:null,injectEventPluginOrder:function(e){u&&a("101"),u=Array.prototype.slice.call(e),r()},injectEventPluginsByName:function(e){var t=!1;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n];s.hasOwnProperty(n)&&s[n]===o||(s[n]&&a("102",n),s[n]=o,t=!0)}t&&r()},getPluginModuleForEvent:function(e){var t=e.dispatchConfig;if(t.registrationName)return c.registrationNameModules[t.registrationName]||null;if(void 0!==t.phasedRegistrationNames){var n=t.phasedRegistrationNames;for(var r in n)if(n.hasOwnProperty(r)){var o=c.registrationNameModules[n[r]];if(o)return o}}return null},_resetEventPlugins:function(){u=null;for(var e in s)s.hasOwnProperty(e)&&delete s[e];c.plugins.length=0;var t=c.eventNameDispatchConfigs;for(var n in t)t.hasOwnProperty(n)&&delete t[n];var r=c.registrationNameModules;for(var o in r)r.hasOwnProperty(o)&&delete r[o]}};e.exports=c},function(e,t,n){"use strict";function r(e){return"topMouseUp"===e||"topTouchEnd"===e||"topTouchCancel"===e}function o(e){return"topMouseMove"===e||"topTouchMove"===e}function i(e){return"topMouseDown"===e||"topTouchStart"===e}function a(e,t,n,r){var o=e.type||"unknown-event";e.currentTarget=g.getNodeFromInstance(r),t?m.invokeGuardedCallbackWithCatch(o,n,e):m.invokeGuardedCallback(o,n,e),e.currentTarget=null}function u(e,t){var n=e._dispatchListeners,r=e._dispatchInstances;if(Array.isArray(n))for(var o=0;o0&&r.length<20?n+" (keys: "+r.join(", ")+")":n}function i(e,t){var n=u.get(e);if(!n){return null}return n}var a=n(2),u=(n(9),n(22)),s=(n(7),n(8)),c=(n(0),n(1),{isMounted:function(e){var t=u.get(e);return!!t&&!!t._renderedComponent},enqueueCallback:function(e,t,n){c.validateCallback(t,n);var o=i(e);if(!o)return null;o._pendingCallbacks?o._pendingCallbacks.push(t):o._pendingCallbacks=[t],r(o)},enqueueCallbackInternal:function(e,t){e._pendingCallbacks?e._pendingCallbacks.push(t):e._pendingCallbacks=[t],r(e)},enqueueForceUpdate:function(e){var t=i(e,"forceUpdate");t&&(t._pendingForceUpdate=!0,r(t))},enqueueReplaceState:function(e,t,n){var o=i(e,"replaceState");o&&(o._pendingStateQueue=[t],o._pendingReplaceState=!0,void 0!==n&&null!==n&&(c.validateCallback(n,"replaceState"),o._pendingCallbacks?o._pendingCallbacks.push(n):o._pendingCallbacks=[n]),r(o))},enqueueSetState:function(e,t){var n=i(e,"setState");if(n){(n._pendingStateQueue||(n._pendingStateQueue=[])).push(t),r(n)}},enqueueElementInternal:function(e,t,n){e._pendingElement=t,e._context=n,r(e)},validateCallback:function(e,t){e&&"function"!=typeof e&&a("122",t,o(e))}});e.exports=c},function(e,t,n){"use strict";var r=(n(3),n(6)),o=(n(1),r);e.exports=o},function(e,t,n){"use strict";function r(e){var t,n=e.keyCode;return"charCode"in e?0===(t=e.charCode)&&13===n&&(t=13):t=n,t>=32||13===t?t:0}e.exports=r},function(e,t,n){"use strict";e.exports=n(213)},function(e,t,n){"use strict";function r(e,t,n){this.props=e,this.context=t,this.refs=c,this.updater=n||s}function o(e,t,n){this.props=e,this.context=t,this.refs=c,this.updater=n||s}function i(){}var a=n(18),u=n(3),s=n(52),c=(n(53),n(23));n(0),n(94);r.prototype.isReactComponent={},r.prototype.setState=function(e,t){"object"!=typeof e&&"function"!=typeof e&&null!=e&&a("85"),this.updater.enqueueSetState(this,e),t&&this.updater.enqueueCallback(this,t,"setState")},r.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this),e&&this.updater.enqueueCallback(this,e,"forceUpdate")};i.prototype=r.prototype,o.prototype=new i,o.prototype.constructor=o,u(o.prototype,r.prototype),o.prototype.isPureReactComponent=!0,e.exports={Component:r,PureComponent:o}},function(e,t,n){"use strict";var r=(n(1),{isMounted:function(e){return!1},enqueueCallback:function(e,t){},enqueueForceUpdate:function(e){},enqueueReplaceState:function(e,t){},enqueueSetState:function(e,t){}});e.exports=r},function(e,t,n){"use strict";var r=!1;e.exports=r},function(e,t,n){"use strict";var r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103;e.exports=r},function(e,t,n){"use strict";var r=n(102);e.exports=function(e){return r(e,!1)}},function(e,t,n){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},function(e,t,n){e.exports=n(109)()},function(e,t,n){"use strict";n.d(t,"b",function(){return i}),n.d(t,"a",function(){return a});var r=n(57),o=n.n(r),i=o.a.shape({trySubscribe:o.a.func.isRequired,tryUnsubscribe:o.a.func.isRequired,notifyNestedSubs:o.a.func.isRequired,isSubscribed:o.a.func.isRequired}),a=o.a.shape({subscribe:o.a.func.isRequired,dispatch:o.a.func.isRequired,getState:o.a.func.isRequired})},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function a(e,t){var n={};for(var r in e)t.indexOf(r)>=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function u(){}function s(e,t){var n={run:function(r){try{var o=e(t.getState(),r);(o!==n.props||n.error)&&(n.shouldComponentUpdate=!0,n.props=o,n.error=null)}catch(e){n.shouldComponentUpdate=!0,n.error=e}}};return n}function c(e){var t,n,c=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},l=c.getDisplayName,d=void 0===l?function(e){return"ConnectAdvanced("+e+")"}:l,_=c.methodName,C=void 0===_?"connectAdvanced":_,E=c.renderCountProp,w=void 0===E?void 0:E,x=c.shouldHandleStateChanges,T=void 0===x||x,P=c.storeKey,k=void 0===P?"store":P,S=c.withRef,O=void 0!==S&&S,N=a(c,["getDisplayName","methodName","renderCountProp","shouldHandleStateChanges","storeKey","withRef"]),M=k+"Subscription",I=y++,R=(t={},t[k]=v.a,t[M]=v.b,t),A=(n={},n[M]=v.b,n);return function(t){f.a("function"==typeof t,"You must pass a component to the function returned by connect. Instead received "+JSON.stringify(t));var n=t.displayName||t.name||"Component",a=d(n),c=g({},N,{getDisplayName:d,methodName:C,renderCountProp:w,shouldHandleStateChanges:T,storeKey:k,withRef:O,displayName:a,wrappedComponentName:n,WrappedComponent:t}),l=function(n){function l(e,t){r(this,l);var i=o(this,n.call(this,e,t));return i.version=I,i.state={},i.renderCount=0,i.store=e[k]||t[k],i.propsMode=Boolean(e[k]),i.setWrappedInstance=i.setWrappedInstance.bind(i),f.a(i.store,'Could not find "'+k+'" in either the context or props of "'+a+'". Either wrap the root component in a , or explicitly pass "'+k+'" as a prop to "'+a+'".'),i.initSelector(),i.initSubscription(),i}return i(l,n),l.prototype.getChildContext=function(){var e,t=this.propsMode?null:this.subscription;return e={},e[M]=t||this.context[M],e},l.prototype.componentDidMount=function(){T&&(this.subscription.trySubscribe(),this.selector.run(this.props),this.selector.shouldComponentUpdate&&this.forceUpdate())},l.prototype.componentWillReceiveProps=function(e){this.selector.run(e)},l.prototype.shouldComponentUpdate=function(){return this.selector.shouldComponentUpdate},l.prototype.componentWillUnmount=function(){this.subscription&&this.subscription.tryUnsubscribe(),this.subscription=null,this.notifyNestedSubs=u,this.store=null,this.selector.run=u,this.selector.shouldComponentUpdate=!1},l.prototype.getWrappedInstance=function(){return f.a(O,"To access the wrapped instance, you need to specify { withRef: true } in the options argument of the "+C+"() call."),this.wrappedInstance},l.prototype.setWrappedInstance=function(e){this.wrappedInstance=e},l.prototype.initSelector=function(){var t=e(this.store.dispatch,c);this.selector=s(t,this.store),this.selector.run(this.props)},l.prototype.initSubscription=function(){if(T){var e=(this.propsMode?this.props:this.context)[M];this.subscription=new m.a(this.store,e,this.onStateChange.bind(this)),this.notifyNestedSubs=this.subscription.notifyNestedSubs.bind(this.subscription)}},l.prototype.onStateChange=function(){this.selector.run(this.props),this.selector.shouldComponentUpdate?(this.componentDidUpdate=this.notifyNestedSubsOnComponentDidUpdate,this.setState(b)):this.notifyNestedSubs()},l.prototype.notifyNestedSubsOnComponentDidUpdate=function(){this.componentDidUpdate=void 0,this.notifyNestedSubs()},l.prototype.isSubscribed=function(){return Boolean(this.subscription)&&this.subscription.isSubscribed()},l.prototype.addExtraProps=function(e){if(!(O||w||this.propsMode&&this.subscription))return e;var t=g({},e);return O&&(t.ref=this.setWrappedInstance),w&&(t[w]=this.renderCount++),this.propsMode&&this.subscription&&(t[M]=this.subscription),t},l.prototype.render=function(){var e=this.selector;if(e.shouldComponentUpdate=!1,e.error)throw e.error;return h.createElement(t,this.addExtraProps(e.props))},l}(h.Component);return l.WrappedComponent=t,l.displayName=a,l.childContextTypes=A,l.contextTypes=R,l.propTypes=R,p.a(l,t)}}t.a=c;var l=n(110),p=n.n(l),d=n(111),f=n.n(d),h=n(12),m=(n.n(h),n(112)),v=n(58),g=Object.assign||function(e){for(var t=1;t1)for(var n=1;n.":"function"==typeof t?" Instead of passing a class like Foo, pass React.createElement(Foo) or .":null!=t&&void 0!==t.props?" This may be caused by unintentionally loading two independent copies of React.":"");var a,u=v.createElement(j,{child:t});if(e){var s=E.get(e);a=s._processChildContext(s._context)}else a=k;var l=d(n);if(l){var p=l._currentElement,h=p.props.child;if(N(h,t)){var m=l._renderedComponent.getPublicInstance(),g=r&&function(){r.call(m)};return F._updateRootComponent(l,u,a,n,g),m}F.unmountComponentAtNode(n)}var y=o(n),b=y&&!!i(y),_=c(n),C=b&&!l&&!_,w=F._renderNewRootComponent(u,n,C,a)._renderedComponent.getPublicInstance();return r&&r.call(w),w},render:function(e,t,n){return F._renderSubtreeIntoContainer(null,e,t,n)},unmountComponentAtNode:function(e){l(e)||f("40");var t=d(e);if(!t){c(e),1===e.nodeType&&e.hasAttribute(I);return!1}return delete U[t._instance.rootID],P.batchedUpdates(s,t,e,!1),!0},_mountImageIntoNode:function(e,t,n,i,a){if(l(t)||f("41"),i){var u=o(t);if(w.canReuseMarkup(e,u))return void y.precacheNode(n,u);var s=u.getAttribute(w.CHECKSUM_ATTR_NAME);u.removeAttribute(w.CHECKSUM_ATTR_NAME);var c=u.outerHTML;u.setAttribute(w.CHECKSUM_ATTR_NAME,s);var p=e,d=r(p,c),m=" (client) "+p.substring(d-20,d+20)+"\n (server) "+c.substring(d-20,d+20);t.nodeType===A&&f("42",m)}if(t.nodeType===A&&f("43"),a.useCreateElement){for(;t.lastChild;)t.removeChild(t.lastChild);h.insertTreeBefore(t,e,null)}else O(t,e),y.precacheNode(n,t.firstChild)}};e.exports=F},function(e,t,n){"use strict";function r(e){for(var t;(t=e._renderedNodeType)===o.COMPOSITE;)e=e._renderedComponent;return t===o.HOST?e._renderedComponent:t===o.EMPTY?null:void 0}var o=n(83);e.exports=r},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}var o=n(12),i=r(o),a=n(29),u=n(135),s=n(212),c=r(s),l=n(221),p=r(l);(0,u.render)(i.default.createElement(a.Provider,{store:p.default},i.default.createElement(c.default,null)),document.getElementById("app"))},function(e,t,n){"use strict";var r=function(){};e.exports=r},function(e,t,n){"use strict";function r(e){return(""+e).replace(_,"$&/")}function o(e,t){this.func=e,this.context=t,this.count=0}function i(e,t,n){var r=e.func,o=e.context;r.call(o,t,e.count++)}function a(e,t,n){if(null==e)return e;var r=o.getPooled(t,n);g(e,i,r),o.release(r)}function u(e,t,n,r){this.result=e,this.keyPrefix=t,this.func=n,this.context=r,this.count=0}function s(e,t,n){var o=e.result,i=e.keyPrefix,a=e.func,u=e.context,s=a.call(u,t,e.count++);Array.isArray(s)?c(s,o,n,v.thatReturnsArgument):null!=s&&(m.isValidElement(s)&&(s=m.cloneAndReplaceKey(s,i+(!s.key||t&&t.key===s.key?"":r(s.key)+"/")+n)),o.push(s))}function c(e,t,n,o,i){var a="";null!=n&&(a=r(n)+"/");var c=u.getPooled(t,a,o,i);g(e,s,c),u.release(c)}function l(e,t,n){if(null==e)return e;var r=[];return c(e,r,null,t,n),r}function p(e,t,n){return null}function d(e,t){return g(e,p,null)}function f(e){var t=[];return c(e,t,null,v.thatReturnsArgument),t}var h=n(96),m=n(14),v=n(6),g=n(97),y=h.twoArgumentPooler,b=h.fourArgumentPooler,_=/\/+/g;o.prototype.destructor=function(){this.func=null,this.context=null,this.count=0},h.addPoolingTo(o,y),u.prototype.destructor=function(){this.result=null,this.keyPrefix=null,this.func=null,this.context=null,this.count=0},h.addPoolingTo(u,b);var C={forEach:a,map:l,mapIntoWithKeyPrefixInternal:c,count:d,toArray:f};e.exports=C},function(e,t,n){"use strict";var r=n(18),o=(n(0),function(e){var t=this;if(t.instancePool.length){var n=t.instancePool.pop();return t.call(n,e),n}return new t(e)}),i=function(e,t){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,e,t),r}return new n(e,t)},a=function(e,t,n){var r=this;if(r.instancePool.length){var o=r.instancePool.pop();return r.call(o,e,t,n),o}return new r(e,t,n)},u=function(e,t,n,r){var o=this;if(o.instancePool.length){var i=o.instancePool.pop();return o.call(i,e,t,n,r),i}return new o(e,t,n,r)},s=function(e){var t=this;e instanceof t||r("25"),e.destructor(),t.instancePool.length0&&void 0!==arguments[0]?arguments[0]:"store",n=arguments[1],a=n||t+"Subscription",s=function(e){function n(i,a){r(this,n);var u=o(this,e.call(this,i,a));return u[t]=i.store,u}return i(n,e),n.prototype.getChildContext=function(){var e;return e={},e[t]=this[t],e[a]=null,e},n.prototype.render=function(){return u.Children.only(this.props.children)},n}(u.Component);return s.propTypes={store:l.a.isRequired,children:c.a.element.isRequired},s.childContextTypes=(e={},e[t]=l.a.isRequired,e[a]=l.b,e),s.displayName="Provider",s}t.a=a;var u=n(12),s=(n.n(u),n(57)),c=n.n(s),l=n(58);n(30);t.b=a()},function(e,t,n){"use strict";var r=n(6),o=n(0),i=n(56);e.exports=function(){function e(e,t,n,r,a,u){u!==i&&o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types")}function t(){return e}e.isRequired=e;var n={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t};return n.checkPropTypes=r,n.PropTypes=n,n}},function(e,t,n){"use strict";var r={childContextTypes:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,arguments:!0,arity:!0},i="function"==typeof Object.getOwnPropertySymbols;e.exports=function(e,t,n){if("string"!=typeof t){var a=Object.getOwnPropertyNames(t);i&&(a=a.concat(Object.getOwnPropertySymbols(t)));for(var u=0;u=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function o(e,t,n){for(var r=t.length-1;r>=0;r--){var o=t[r](e);if(o)return o}return function(t,r){throw new Error("Invalid value of type "+typeof e+" for "+n+" argument when connecting component "+r.wrappedComponentName+".")}}function i(e,t){return e===t}var a=n(59),u=n(114),s=n(115),c=n(131),l=n(132),p=n(133),d=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:{},t=e.connectHOC,n=void 0===t?a.a:t,f=e.mapStateToPropsFactories,h=void 0===f?c.a:f,m=e.mapDispatchToPropsFactories,v=void 0===m?s.a:m,g=e.mergePropsFactories,y=void 0===g?l.a:g,b=e.selectorFactory,_=void 0===b?p.a:b;return function(e,t,a){var s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},c=s.pure,l=void 0===c||c,p=s.areStatesEqual,f=void 0===p?i:p,m=s.areOwnPropsEqual,g=void 0===m?u.a:m,b=s.areStatePropsEqual,C=void 0===b?u.a:b,E=s.areMergedPropsEqual,w=void 0===E?u.a:E,x=r(s,["pure","areStatesEqual","areOwnPropsEqual","areStatePropsEqual","areMergedPropsEqual"]),T=o(e,h,"mapStateToProps"),P=o(t,v,"mapDispatchToProps"),k=o(a,y,"mergeProps");return n(_,d({methodName:"connect",getDisplayName:function(e){return"Connect("+e+")"},shouldHandleStateChanges:Boolean(e),initMapStateToProps:T,initMapDispatchToProps:P,initMergeProps:k,pure:l,areStatesEqual:f,areOwnPropsEqual:g,areStatePropsEqual:C,areMergedPropsEqual:w},x))}}()},function(e,t,n){"use strict";function r(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!==e&&t!==t}function o(e,t){if(r(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),o=Object.keys(t);if(n.length!==o.length)return!1;for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:{},t=arguments[1];if(s)throw s;for(var o=!1,i={},a=0;a=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function o(e,t,n,r){return function(o,i){return n(e(o,i),t(r,i),i)}}function i(e,t,n,r,o){function i(o,i){return h=o,m=i,v=e(h,m),g=t(r,m),y=n(v,g,m),f=!0,y}function a(){return v=e(h,m),t.dependsOnOwnProps&&(g=t(r,m)),y=n(v,g,m)}function u(){return e.dependsOnOwnProps&&(v=e(h,m)),t.dependsOnOwnProps&&(g=t(r,m)),y=n(v,g,m)}function s(){var t=e(h,m),r=!d(t,v);return v=t,r&&(y=n(v,g,m)),y}function c(e,t){var n=!p(t,m),r=!l(e,h);return h=e,m=t,n&&r?a():n?u():r?s():y}var l=o.areStatesEqual,p=o.areOwnPropsEqual,d=o.areStatePropsEqual,f=!1,h=void 0,m=void 0,v=void 0,g=void 0,y=void 0;return function(e,t){return f?c(e,t):i(e,t)}}function a(e,t){var n=t.initMapStateToProps,a=t.initMapDispatchToProps,u=t.initMergeProps,s=r(t,["initMapStateToProps","initMapDispatchToProps","initMergeProps"]),c=n(e,s),l=a(e,s),p=u(e,s);return(s.pure?i:o)(c,l,p,e,s)}t.a=a;n(134)},function(e,t,n){"use strict";n(30)},function(e,t,n){"use strict";e.exports=n(136)},function(e,t,n){"use strict";var r=n(4),o=n(137),i=n(91),a=n(16),u=n(8),s=n(209),c=n(210),l=n(92),p=n(211);n(1);o.inject();var d={findDOMNode:c,render:i.render,unmountComponentAtNode:i.unmountComponentAtNode,version:s,unstable_batchedUpdates:u.batchedUpdates,unstable_renderSubtreeIntoContainer:p};"undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject&&__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ComponentTree:{getClosestInstanceFromNode:r.getClosestInstanceFromNode,getNodeFromInstance:function(e){return e._renderedComponent&&(e=l(e)),e?r.getNodeFromInstance(e):null}},Mount:i,Reconciler:a});e.exports=d},function(e,t,n){"use strict";function r(){w||(w=!0,y.EventEmitter.injectReactEventListener(g),y.EventPluginHub.injectEventPluginOrder(u),y.EventPluginUtils.injectComponentTree(d),y.EventPluginUtils.injectTreeTraversal(h),y.EventPluginHub.injectEventPluginsByName({SimpleEventPlugin:E,EnterLeaveEventPlugin:s,ChangeEventPlugin:a,SelectEventPlugin:C,BeforeInputEventPlugin:i}),y.HostComponent.injectGenericComponentClass(p),y.HostComponent.injectTextComponentClass(m),y.DOMProperty.injectDOMPropertyConfig(o),y.DOMProperty.injectDOMPropertyConfig(c),y.DOMProperty.injectDOMPropertyConfig(_),y.EmptyComponent.injectEmptyComponentFactory(function(e){return new f(e)}),y.Updates.injectReconcileTransaction(b),y.Updates.injectBatchingStrategy(v),y.Component.injectEnvironment(l))}var o=n(138),i=n(139),a=n(143),u=n(146),s=n(147),c=n(148),l=n(149),p=n(155),d=n(4),f=n(180),h=n(181),m=n(182),v=n(183),g=n(184),y=n(186),b=n(187),_=n(193),C=n(194),E=n(195),w=!1;e.exports={inject:r}},function(e,t,n){"use strict";var r={Properties:{"aria-current":0,"aria-details":0,"aria-disabled":0,"aria-hidden":0,"aria-invalid":0,"aria-keyshortcuts":0,"aria-label":0,"aria-roledescription":0,"aria-autocomplete":0,"aria-checked":0,"aria-expanded":0,"aria-haspopup":0,"aria-level":0,"aria-modal":0,"aria-multiline":0,"aria-multiselectable":0,"aria-orientation":0,"aria-placeholder":0,"aria-pressed":0,"aria-readonly":0,"aria-required":0,"aria-selected":0,"aria-sort":0,"aria-valuemax":0,"aria-valuemin":0,"aria-valuenow":0,"aria-valuetext":0,"aria-atomic":0,"aria-busy":0,"aria-live":0,"aria-relevant":0,"aria-dropeffect":0,"aria-grabbed":0,"aria-activedescendant":0,"aria-colcount":0,"aria-colindex":0,"aria-colspan":0,"aria-controls":0,"aria-describedby":0,"aria-errormessage":0,"aria-flowto":0,"aria-labelledby":0,"aria-owns":0,"aria-posinset":0,"aria-rowcount":0,"aria-rowindex":0,"aria-rowspan":0,"aria-setsize":0},DOMAttributeNames:{},DOMPropertyNames:{}};e.exports=r},function(e,t,n){"use strict";function r(e){return(e.ctrlKey||e.altKey||e.metaKey)&&!(e.ctrlKey&&e.altKey)}function o(e){switch(e){case"topCompositionStart":return T.compositionStart;case"topCompositionEnd":return T.compositionEnd;case"topCompositionUpdate":return T.compositionUpdate}}function i(e,t){return"topKeyDown"===e&&t.keyCode===y}function a(e,t){switch(e){case"topKeyUp":return-1!==g.indexOf(t.keyCode);case"topKeyDown":return t.keyCode!==y;case"topKeyPress":case"topMouseDown":case"topBlur":return!0;default:return!1}}function u(e){var t=e.detail;return"object"==typeof t&&"data"in t?t.data:null}function s(e,t,n,r){var s,c;if(b?s=o(e):k?a(e,n)&&(s=T.compositionEnd):i(e,n)&&(s=T.compositionStart),!s)return null;E&&(k||s!==T.compositionStart?s===T.compositionEnd&&k&&(c=k.getData()):k=h.getPooled(r));var l=m.getPooled(s,t,n,r);if(c)l.data=c;else{var p=u(n);null!==p&&(l.data=p)}return d.accumulateTwoPhaseDispatches(l),l}function c(e,t){switch(e){case"topCompositionEnd":return u(t);case"topKeyPress":return t.which!==w?null:(P=!0,x);case"topTextInput":var n=t.data;return n===x&&P?null:n;default:return null}}function l(e,t){if(k){if("topCompositionEnd"===e||!b&&a(e,t)){var n=k.getData();return h.release(k),k=null,n}return null}switch(e){case"topPaste":return null;case"topKeyPress":return t.which&&!r(t)?String.fromCharCode(t.which):null;case"topCompositionEnd":return E?null:t.data;default:return null}}function p(e,t,n,r){var o;if(!(o=C?c(e,n):l(e,n)))return null;var i=v.getPooled(T.beforeInput,t,n,r);return i.data=o,d.accumulateTwoPhaseDispatches(i),i}var d=n(19),f=n(5),h=n(140),m=n(141),v=n(142),g=[9,13,27,32],y=229,b=f.canUseDOM&&"CompositionEvent"in window,_=null;f.canUseDOM&&"documentMode"in document&&(_=document.documentMode);var C=f.canUseDOM&&"TextEvent"in window&&!_&&!function(){var e=window.opera;return"object"==typeof e&&"function"==typeof e.version&&parseInt(e.version(),10)<=12}(),E=f.canUseDOM&&(!b||_&&_>8&&_<=11),w=32,x=String.fromCharCode(w),T={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["topCompositionEnd","topKeyPress","topTextInput","topPaste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:["topBlur","topCompositionEnd","topKeyDown","topKeyPress","topKeyUp","topMouseDown"]},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:["topBlur","topCompositionStart","topKeyDown","topKeyPress","topKeyUp","topMouseDown"]},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:["topBlur","topCompositionUpdate","topKeyDown","topKeyPress","topKeyUp","topMouseDown"]}},P=!1,k=null,S={eventTypes:T,extractEvents:function(e,t,n,r){return[s(e,t,n,r),p(e,t,n,r)]}};e.exports=S},function(e,t,n){"use strict";function r(e){this._root=e,this._startText=this.getText(),this._fallbackText=null}var o=n(3),i=n(11),a=n(70);o(r.prototype,{destructor:function(){this._root=null,this._startText=null,this._fallbackText=null},getText:function(){return"value"in this._root?this._root.value:this._root[a()]},getData:function(){if(this._fallbackText)return this._fallbackText;var e,t,n=this._startText,r=n.length,o=this.getText(),i=o.length;for(e=0;e1?1-t:void 0;return this._fallbackText=o.slice(e,u),this._fallbackText}}),i.addPoolingTo(r),e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(10),i={data:null};o.augmentClass(r,i),e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(10),i={data:null};o.augmentClass(r,i),e.exports=r},function(e,t,n){"use strict";function r(e,t,n){var r=P.getPooled(M.change,e,t,n);return r.type="change",E.accumulateTwoPhaseDispatches(r),r}function o(e){var t=e.nodeName&&e.nodeName.toLowerCase();return"select"===t||"input"===t&&"file"===e.type}function i(e){var t=r(R,e,S(e));T.batchedUpdates(a,t)}function a(e){C.enqueueEvents(e),C.processEventQueue(!1)}function u(e,t){I=e,R=t,I.attachEvent("onchange",i)}function s(){I&&(I.detachEvent("onchange",i),I=null,R=null)}function c(e,t){var n=k.updateValueIfChanged(e),r=!0===t.simulated&&U._allowSimulatedPassThrough;if(n||r)return e}function l(e,t){if("topChange"===e)return t}function p(e,t,n){"topFocus"===e?(s(),u(t,n)):"topBlur"===e&&s()}function d(e,t){I=e,R=t,I.attachEvent("onpropertychange",h)}function f(){I&&(I.detachEvent("onpropertychange",h),I=null,R=null)}function h(e){"value"===e.propertyName&&c(R,e)&&i(e)}function m(e,t,n){"topFocus"===e?(f(),d(t,n)):"topBlur"===e&&f()}function v(e,t,n){if("topSelectionChange"===e||"topKeyUp"===e||"topKeyDown"===e)return c(R,n)}function g(e){var t=e.nodeName;return t&&"input"===t.toLowerCase()&&("checkbox"===e.type||"radio"===e.type)}function y(e,t,n){if("topClick"===e)return c(t,n)}function b(e,t,n){if("topInput"===e||"topChange"===e)return c(t,n)}function _(e,t){if(null!=e){var n=e._wrapperState||t._wrapperState;if(n&&n.controlled&&"number"===t.type){var r=""+t.value;t.getAttribute("value")!==r&&t.setAttribute("value",r)}}}var C=n(20),E=n(19),w=n(5),x=n(4),T=n(8),P=n(10),k=n(73),S=n(36),O=n(37),N=n(74),M={change:{phasedRegistrationNames:{bubbled:"onChange",captured:"onChangeCapture"},dependencies:["topBlur","topChange","topClick","topFocus","topInput","topKeyDown","topKeyUp","topSelectionChange"]}},I=null,R=null,A=!1;w.canUseDOM&&(A=O("change")&&(!document.documentMode||document.documentMode>8));var D=!1;w.canUseDOM&&(D=O("input")&&(!("documentMode"in document)||document.documentMode>9));var U={eventTypes:M,_allowSimulatedPassThrough:!0,_isInputEventSupported:D,extractEvents:function(e,t,n,i){var a,u,s=t?x.getNodeFromInstance(t):window;if(o(s)?A?a=l:u=p:N(s)?D?a=b:(a=v,u=m):g(s)&&(a=y),a){var c=a(e,t,n);if(c){return r(c,n,i)}}u&&u(e,s,t),"topBlur"===e&&_(t,s)}};e.exports=U},function(e,t,n){"use strict";function r(e,t,n){"function"==typeof e?e(t.getPublicInstance()):i.addComponentAsRefTo(t,e,n)}function o(e,t,n){"function"==typeof e?e(null):i.removeComponentAsRefFrom(t,e,n)}var i=n(145),a={};a.attachRefs=function(e,t){if(null!==t&&"object"==typeof t){var n=t.ref;null!=n&&r(n,e,t._owner)}},a.shouldUpdateRefs=function(e,t){var n=null,r=null;null!==e&&"object"==typeof e&&(n=e.ref,r=e._owner);var o=null,i=null;return null!==t&&"object"==typeof t&&(o=t.ref,i=t._owner),n!==o||"string"==typeof o&&i!==r},a.detachRefs=function(e,t){if(null!==t&&"object"==typeof t){var n=t.ref;null!=n&&o(n,e,t._owner)}},e.exports=a},function(e,t,n){"use strict";function r(e){return!(!e||"function"!=typeof e.attachRef||"function"!=typeof e.detachRef)}var o=n(2),i=(n(0),{addComponentAsRefTo:function(e,t,n){r(n)||o("119"),n.attachRef(t,e)},removeComponentAsRefFrom:function(e,t,n){r(n)||o("120");var i=n.getPublicInstance();i&&i.refs[t]===e.getPublicInstance()&&n.detachRef(t)}});e.exports=i},function(e,t,n){"use strict";var r=["ResponderEventPlugin","SimpleEventPlugin","TapEventPlugin","EnterLeaveEventPlugin","ChangeEventPlugin","SelectEventPlugin","BeforeInputEventPlugin"];e.exports=r},function(e,t,n){"use strict";var r=n(19),o=n(4),i=n(25),a={mouseEnter:{registrationName:"onMouseEnter",dependencies:["topMouseOut","topMouseOver"]},mouseLeave:{registrationName:"onMouseLeave",dependencies:["topMouseOut","topMouseOver"]}},u={eventTypes:a,extractEvents:function(e,t,n,u){if("topMouseOver"===e&&(n.relatedTarget||n.fromElement))return null;if("topMouseOut"!==e&&"topMouseOver"!==e)return null;var s;if(u.window===u)s=u;else{var c=u.ownerDocument;s=c?c.defaultView||c.parentWindow:window}var l,p;if("topMouseOut"===e){l=t;var d=n.relatedTarget||n.toElement;p=d?o.getClosestInstanceFromNode(d):null}else l=null,p=t;if(l===p)return null;var f=null==l?s:o.getNodeFromInstance(l),h=null==p?s:o.getNodeFromInstance(p),m=i.getPooled(a.mouseLeave,l,n,u);m.type="mouseleave",m.target=f,m.relatedTarget=h;var v=i.getPooled(a.mouseEnter,p,n,u);return v.type="mouseenter",v.target=h,v.relatedTarget=f,r.accumulateEnterLeaveDispatches(m,v,l,p),[m,v]}};e.exports=u},function(e,t,n){"use strict";var r=n(15),o=r.injection.MUST_USE_PROPERTY,i=r.injection.HAS_BOOLEAN_VALUE,a=r.injection.HAS_NUMERIC_VALUE,u=r.injection.HAS_POSITIVE_NUMERIC_VALUE,s=r.injection.HAS_OVERLOADED_BOOLEAN_VALUE,c={isCustomAttribute:RegExp.prototype.test.bind(new RegExp("^(data|aria)-["+r.ATTRIBUTE_NAME_CHAR+"]*$")),Properties:{accept:0,acceptCharset:0,accessKey:0,action:0,allowFullScreen:i,allowTransparency:0,alt:0,as:0,async:i,autoComplete:0,autoPlay:i,capture:i,cellPadding:0,cellSpacing:0,charSet:0,challenge:0,checked:o|i,cite:0,classID:0,className:0,cols:u,colSpan:0,content:0,contentEditable:0,contextMenu:0,controls:i,coords:0,crossOrigin:0,data:0,dateTime:0,default:i,defer:i,dir:0,disabled:i,download:s,draggable:0,encType:0,form:0,formAction:0,formEncType:0,formMethod:0,formNoValidate:i,formTarget:0,frameBorder:0,headers:0,height:0,hidden:i,high:0,href:0,hrefLang:0,htmlFor:0,httpEquiv:0,icon:0,id:0,inputMode:0,integrity:0,is:0,keyParams:0,keyType:0,kind:0,label:0,lang:0,list:0,loop:i,low:0,manifest:0,marginHeight:0,marginWidth:0,max:0,maxLength:0,media:0,mediaGroup:0,method:0,min:0,minLength:0,multiple:o|i,muted:o|i,name:0,nonce:0,noValidate:i,open:i,optimum:0,pattern:0,placeholder:0,playsInline:i,poster:0,preload:0,profile:0,radioGroup:0,readOnly:i,referrerPolicy:0,rel:0,required:i,reversed:i,role:0,rows:u,rowSpan:a,sandbox:0,scope:0,scoped:i,scrolling:0,seamless:i,selected:o|i,shape:0,size:u,sizes:0,span:u,spellCheck:0,src:0,srcDoc:0,srcLang:0,srcSet:0,start:a,step:0,style:0,summary:0,tabIndex:0,target:0,title:0,type:0,useMap:0,value:0,width:0,wmode:0,wrap:0,about:0,datatype:0,inlist:0,prefix:0,property:0,resource:0,typeof:0,vocab:0,autoCapitalize:0,autoCorrect:0,autoSave:0,color:0,itemProp:0,itemScope:i,itemType:0,itemID:0,itemRef:0,results:0,security:0,unselectable:0},DOMAttributeNames:{acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv"},DOMPropertyNames:{},DOMMutationMethods:{value:function(e,t){if(null==t)return e.removeAttribute("value");"number"!==e.type||!1===e.hasAttribute("value")?e.setAttribute("value",""+t):e.validity&&!e.validity.badInput&&e.ownerDocument.activeElement!==e&&e.setAttribute("value",""+t)}}};e.exports=c},function(e,t,n){"use strict";var r=n(39),o=n(154),i={processChildrenUpdates:o.dangerouslyProcessChildrenUpdates,replaceNodeWithMarkup:r.dangerouslyReplaceNodeWithMarkup};e.exports=i},function(e,t,n){"use strict";var r=n(2),o=n(17),i=n(5),a=n(151),u=n(6),s=(n(0),{dangerouslyReplaceNodeWithMarkup:function(e,t){if(i.canUseDOM||r("56"),t||r("57"),"HTML"===e.nodeName&&r("58"),"string"==typeof t){var n=a(t,u)[0];e.parentNode.replaceChild(n,e)}else o.replaceChildWithTree(e,t)}});e.exports=s},function(e,t,n){"use strict";function r(e){var t=e.match(l);return t&&t[1].toLowerCase()}function o(e,t){var n=c;c||s(!1);var o=r(e),i=o&&u(o);if(i){n.innerHTML=i[1]+e+i[2];for(var l=i[0];l--;)n=n.lastChild}else n.innerHTML=e;var p=n.getElementsByTagName("script");p.length&&(t||s(!1),a(p).forEach(t));for(var d=Array.from(n.childNodes);n.lastChild;)n.removeChild(n.lastChild);return d}var i=n(5),a=n(152),u=n(153),s=n(0),c=i.canUseDOM?document.createElement("div"):null,l=/^\s*<(\w+)/;e.exports=o},function(e,t,n){"use strict";function r(e){var t=e.length;if((Array.isArray(e)||"object"!=typeof e&&"function"!=typeof e)&&a(!1),"number"!=typeof t&&a(!1),0===t||t-1 in e||a(!1),"function"==typeof e.callee&&a(!1),e.hasOwnProperty)try{return Array.prototype.slice.call(e)}catch(e){}for(var n=Array(t),r=0;r":"<"+e+">",u[e]=!a.firstChild),u[e]?d[e]:null}var o=n(5),i=n(0),a=o.canUseDOM?document.createElement("div"):null,u={},s=[1,'"],c=[1,"","
"],l=[3,"","
"],p=[1,'',""],d={"*":[1,"?
","
"],area:[1,"",""],col:[2,"","
"],legend:[1,"
","
"],param:[1,"",""],tr:[2,"","
"],optgroup:s,option:s,caption:c,colgroup:c,tbody:c,tfoot:c,thead:c,td:l,th:l};["circle","clipPath","defs","ellipse","g","image","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","text","tspan"].forEach(function(e){d[e]=p,u[e]=!0}),e.exports=r},function(e,t,n){"use strict";var r=n(39),o=n(4),i={dangerouslyProcessChildrenUpdates:function(e,t){var n=o.getNodeFromInstance(e);r.processUpdates(n,t)}};e.exports=i},function(e,t,n){"use strict";function r(e){if(e){var t=e._currentElement._owner||null;if(t){var n=t.getName();if(n)return" This DOM node was rendered by `"+n+"`."}}return""}function o(e,t){t&&(Q[e._tag]&&(null!=t.children||null!=t.dangerouslySetInnerHTML)&&v("137",e._tag,e._currentElement._owner?" Check the render method of "+e._currentElement._owner.getName()+".":""),null!=t.dangerouslySetInnerHTML&&(null!=t.children&&v("60"),"object"==typeof t.dangerouslySetInnerHTML&&H in t.dangerouslySetInnerHTML||v("61")),null!=t.style&&"object"!=typeof t.style&&v("62",r(e)))}function i(e,t,n,r){if(!(r instanceof A)){var o=e._hostContainerInfo,i=o._node&&o._node.nodeType===K,u=i?o._node:o._ownerDocument;V(t,u),r.getReactMountReady().enqueue(a,{inst:e,registrationName:t,listener:n})}}function a(){var e=this;x.putListener(e.inst,e.registrationName,e.listener)}function u(){var e=this;O.postMountWrapper(e)}function s(){var e=this;I.postMountWrapper(e)}function c(){var e=this;N.postMountWrapper(e)}function l(){U.track(this)}function p(){var e=this;e._rootNodeID||v("63");var t=F(e);switch(t||v("64"),e._tag){case"iframe":case"object":e._wrapperState.listeners=[P.trapBubbledEvent("topLoad","load",t)];break;case"video":case"audio":e._wrapperState.listeners=[];for(var n in Y)Y.hasOwnProperty(n)&&e._wrapperState.listeners.push(P.trapBubbledEvent(n,Y[n],t));break;case"source":e._wrapperState.listeners=[P.trapBubbledEvent("topError","error",t)];break;case"img":e._wrapperState.listeners=[P.trapBubbledEvent("topError","error",t),P.trapBubbledEvent("topLoad","load",t)];break;case"form":e._wrapperState.listeners=[P.trapBubbledEvent("topReset","reset",t),P.trapBubbledEvent("topSubmit","submit",t)];break;case"input":case"select":case"textarea":e._wrapperState.listeners=[P.trapBubbledEvent("topInvalid","invalid",t)]}}function d(){M.postUpdateWrapper(this)}function f(e){Z.call($,e)||(X.test(e)||v("65",e),$[e]=!0)}function h(e,t){return e.indexOf("-")>=0||null!=t.is}function m(e){var t=e.type;f(t),this._currentElement=e,this._tag=t.toLowerCase(),this._namespaceURI=null,this._renderedChildren=null,this._previousStyle=null,this._previousStyleCopy=null,this._hostNode=null,this._hostParent=null,this._rootNodeID=0,this._domID=0,this._hostContainerInfo=null,this._wrapperState=null,this._topLevelWrapper=null,this._flags=0}var v=n(2),g=n(3),y=n(156),b=n(157),_=n(17),C=n(40),E=n(15),w=n(79),x=n(20),T=n(33),P=n(28),k=n(67),S=n(4),O=n(167),N=n(169),M=n(80),I=n(170),R=(n(7),n(171)),A=n(178),D=(n(6),n(27)),U=(n(0),n(37),n(44),n(73)),L=(n(48),n(1),k),j=x.deleteListener,F=S.getNodeFromInstance,V=P.listenTo,B=T.registrationNameModules,W={string:!0,number:!0},H="__html",q={children:null,dangerouslySetInnerHTML:null,suppressContentEditableWarning:null},K=11,Y={topAbort:"abort",topCanPlay:"canplay",topCanPlayThrough:"canplaythrough",topDurationChange:"durationchange",topEmptied:"emptied",topEncrypted:"encrypted",topEnded:"ended",topError:"error",topLoadedData:"loadeddata",topLoadedMetadata:"loadedmetadata",topLoadStart:"loadstart",topPause:"pause",topPlay:"play",topPlaying:"playing",topProgress:"progress",topRateChange:"ratechange",topSeeked:"seeked",topSeeking:"seeking",topStalled:"stalled",topSuspend:"suspend",topTimeUpdate:"timeupdate",topVolumeChange:"volumechange",topWaiting:"waiting"},z={area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},G={listing:!0,pre:!0,textarea:!0},Q=g({menuitem:!0},z),X=/^[a-zA-Z][a-zA-Z:_\.\-\d]*$/,$={},Z={}.hasOwnProperty,J=1;m.displayName="ReactDOMComponent",m.Mixin={mountComponent:function(e,t,n,r){this._rootNodeID=J++,this._domID=n._idCounter++,this._hostParent=t,this._hostContainerInfo=n;var i=this._currentElement.props;switch(this._tag){case"audio":case"form":case"iframe":case"img":case"link":case"object":case"source":case"video":this._wrapperState={listeners:null},e.getReactMountReady().enqueue(p,this);break;case"input":O.mountWrapper(this,i,t),i=O.getHostProps(this,i),e.getReactMountReady().enqueue(l,this),e.getReactMountReady().enqueue(p,this);break;case"option":N.mountWrapper(this,i,t),i=N.getHostProps(this,i);break;case"select":M.mountWrapper(this,i,t),i=M.getHostProps(this,i),e.getReactMountReady().enqueue(p,this);break;case"textarea":I.mountWrapper(this,i,t),i=I.getHostProps(this,i),e.getReactMountReady().enqueue(l,this),e.getReactMountReady().enqueue(p,this)}o(this,i);var a,d;null!=t?(a=t._namespaceURI,d=t._tag):n._tag&&(a=n._namespaceURI,d=n._tag),(null==a||a===C.svg&&"foreignobject"===d)&&(a=C.html),a===C.html&&("svg"===this._tag?a=C.svg:"math"===this._tag&&(a=C.mathml)),this._namespaceURI=a;var f;if(e.useCreateElement){var h,m=n._ownerDocument;if(a===C.html)if("script"===this._tag){var v=m.createElement("div"),g=this._currentElement.type;v.innerHTML="<"+g+">",h=v.removeChild(v.firstChild)}else h=i.is?m.createElement(this._currentElement.type,i.is):m.createElement(this._currentElement.type);else h=m.createElementNS(a,this._currentElement.type);S.precacheNode(this,h),this._flags|=L.hasCachedChildNodes,this._hostParent||w.setAttributeForRoot(h),this._updateDOMProperties(null,i,e);var b=_(h);this._createInitialChildren(e,i,r,b),f=b}else{var E=this._createOpenTagMarkupAndPutListeners(e,i),x=this._createContentMarkup(e,i,r);f=!x&&z[this._tag]?E+"/>":E+">"+x+""}switch(this._tag){case"input":e.getReactMountReady().enqueue(u,this),i.autoFocus&&e.getReactMountReady().enqueue(y.focusDOMComponent,this);break;case"textarea":e.getReactMountReady().enqueue(s,this),i.autoFocus&&e.getReactMountReady().enqueue(y.focusDOMComponent,this);break;case"select":case"button":i.autoFocus&&e.getReactMountReady().enqueue(y.focusDOMComponent,this);break;case"option":e.getReactMountReady().enqueue(c,this)}return f},_createOpenTagMarkupAndPutListeners:function(e,t){var n="<"+this._currentElement.type;for(var r in t)if(t.hasOwnProperty(r)){var o=t[r];if(null!=o)if(B.hasOwnProperty(r))o&&i(this,r,o,e);else{"style"===r&&(o&&(o=this._previousStyleCopy=g({},t.style)),o=b.createMarkupForStyles(o,this));var a=null;null!=this._tag&&h(this._tag,t)?q.hasOwnProperty(r)||(a=w.createMarkupForCustomAttribute(r,o)):a=w.createMarkupForProperty(r,o),a&&(n+=" "+a)}}return e.renderToStaticMarkup?n:(this._hostParent||(n+=" "+w.createMarkupForRoot()),n+=" "+w.createMarkupForID(this._domID))},_createContentMarkup:function(e,t,n){var r="",o=t.dangerouslySetInnerHTML;if(null!=o)null!=o.__html&&(r=o.__html);else{var i=W[typeof t.children]?t.children:null,a=null!=i?null:t.children;if(null!=i)r=D(i);else if(null!=a){var u=this.mountChildren(a,e,n);r=u.join("")}}return G[this._tag]&&"\n"===r.charAt(0)?"\n"+r:r},_createInitialChildren:function(e,t,n,r){var o=t.dangerouslySetInnerHTML;if(null!=o)null!=o.__html&&_.queueHTML(r,o.__html);else{var i=W[typeof t.children]?t.children:null,a=null!=i?null:t.children;if(null!=i)""!==i&&_.queueText(r,i);else if(null!=a)for(var u=this.mountChildren(a,e,n),s=0;s0;)e=e._hostParent,n--;for(;o-n>0;)t=t._hostParent,o--;for(var a=n;a--;){if(e===t)return e;e=e._hostParent,t=t._hostParent}return null}function o(e,t){"_hostNode"in e||s("35"),"_hostNode"in t||s("35");for(;t;){if(t===e)return!0;t=t._hostParent}return!1}function i(e){return"_hostNode"in e||s("36"),e._hostParent}function a(e,t,n){for(var r=[];e;)r.push(e),e=e._hostParent;var o;for(o=r.length;o-- >0;)t(r[o],"captured",n);for(o=0;o0;)n(s[c],"captured",i)}var s=n(2);n(0);e.exports={isAncestor:o,getLowestCommonAncestor:r,getParentInstance:i,traverseTwoPhase:a,traverseEnterLeave:u}},function(e,t,n){"use strict";var r=n(2),o=n(3),i=n(39),a=n(17),u=n(4),s=n(27),c=(n(0),n(48),function(e){this._currentElement=e,this._stringText=""+e,this._hostNode=null,this._hostParent=null,this._domID=0,this._mountIndex=0,this._closingComment=null,this._commentNodes=null});o(c.prototype,{mountComponent:function(e,t,n,r){var o=n._idCounter++,i=" react-text: "+o+" ";if(this._domID=o,this._hostParent=t,e.useCreateElement){var c=n._ownerDocument,l=c.createComment(i),p=c.createComment(" /react-text "),d=a(c.createDocumentFragment());return a.queueChild(d,a(l)),this._stringText&&a.queueChild(d,a(c.createTextNode(this._stringText))),a.queueChild(d,a(p)),u.precacheNode(this,l),this._closingComment=p,d}var f=s(this._stringText);return e.renderToStaticMarkup?f:"\x3c!--"+i+"--\x3e"+f+"\x3c!-- /react-text --\x3e"},receiveComponent:function(e,t){if(e!==this._currentElement){this._currentElement=e;var n=""+e;if(n!==this._stringText){this._stringText=n;var r=this.getHostNode();i.replaceDelimitedText(r[0],r[1],n)}}},getHostNode:function(){var e=this._commentNodes;if(e)return e;if(!this._closingComment)for(var t=u.getNodeFromInstance(this),n=t.nextSibling;;){if(null==n&&r("67",this._domID),8===n.nodeType&&" /react-text "===n.nodeValue){this._closingComment=n;break}n=n.nextSibling}return e=[this._hostNode,this._closingComment],this._commentNodes=e,e},unmountComponent:function(){this._closingComment=null,this._commentNodes=null,u.uncacheNode(this)}}),e.exports=c},function(e,t,n){"use strict";function r(){this.reinitializeTransaction()}var o=n(3),i=n(8),a=n(24),u=n(6),s={initialize:u,close:function(){d.isBatchingUpdates=!1}},c={initialize:u,close:i.flushBatchedUpdates.bind(i)},l=[c,s];o(r.prototype,a,{getTransactionWrappers:function(){return l}});var p=new r,d={isBatchingUpdates:!1,batchedUpdates:function(e,t,n,r,o,i){var a=d.isBatchingUpdates;return d.isBatchingUpdates=!0,a?e(t,n,r,o,i):p.perform(e,null,t,n,r,o,i)}};e.exports=d},function(e,t,n){"use strict";function r(e){for(;e._hostParent;)e=e._hostParent;var t=p.getNodeFromInstance(e),n=t.parentNode;return p.getClosestInstanceFromNode(n)}function o(e,t){this.topLevelType=e,this.nativeEvent=t,this.ancestors=[]}function i(e){var t=f(e.nativeEvent),n=p.getClosestInstanceFromNode(t),o=n;do{e.ancestors.push(o),o=o&&r(o)}while(o);for(var i=0;it.end?(n=t.end,r=t.start):(n=t.start,r=t.end),o.moveToElementText(e),o.moveStart("character",n),o.setEndPoint("EndToStart",o),o.moveEnd("character",r-n),o.select()}function u(e,t){if(window.getSelection){var n=window.getSelection(),r=e[l()].length,o=Math.min(t.start,r),i=void 0===t.end?o:Math.min(t.end,r);if(!n.extend&&o>i){var a=i;i=o,o=a}var u=c(e,o),s=c(e,i);if(u&&s){var p=document.createRange();p.setStart(u.node,u.offset),n.removeAllRanges(),o>i?(n.addRange(p),n.extend(s.node,s.offset)):(p.setEnd(s.node,s.offset),n.addRange(p))}}}var s=n(5),c=n(189),l=n(70),p=s.canUseDOM&&"selection"in document&&!("getSelection"in window),d={getOffsets:p?o:i,setOffsets:p?a:u};e.exports=d},function(e,t,n){"use strict";function r(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function o(e){for(;e;){if(e.nextSibling)return e.nextSibling;e=e.parentNode}}function i(e,t){for(var n=r(e),i=0,a=0;n;){if(3===n.nodeType){if(a=i+n.textContent.length,i<=t&&a>=t)return{node:n,offset:t-i};i=a}n=r(o(n))}}e.exports=i},function(e,t,n){"use strict";function r(e,t){return!(!e||!t)&&(e===t||!o(e)&&(o(t)?r(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}var o=n(191);e.exports=r},function(e,t,n){"use strict";function r(e){return o(e)&&3==e.nodeType}var o=n(192);e.exports=r},function(e,t,n){"use strict";function r(e){var t=e?e.ownerDocument||e:document,n=t.defaultView||window;return!(!e||!("function"==typeof n.Node?e instanceof n.Node:"object"==typeof e&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName))}e.exports=r},function(e,t,n){"use strict";var r={xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace"},o={accentHeight:"accent-height",accumulate:0,additive:0,alignmentBaseline:"alignment-baseline",allowReorder:"allowReorder",alphabetic:0,amplitude:0,arabicForm:"arabic-form",ascent:0,attributeName:"attributeName",attributeType:"attributeType",autoReverse:"autoReverse",azimuth:0,baseFrequency:"baseFrequency",baseProfile:"baseProfile",baselineShift:"baseline-shift",bbox:0,begin:0,bias:0,by:0,calcMode:"calcMode",capHeight:"cap-height",clip:0,clipPath:"clip-path",clipRule:"clip-rule",clipPathUnits:"clipPathUnits",colorInterpolation:"color-interpolation",colorInterpolationFilters:"color-interpolation-filters",colorProfile:"color-profile",colorRendering:"color-rendering",contentScriptType:"contentScriptType",contentStyleType:"contentStyleType",cursor:0,cx:0,cy:0,d:0,decelerate:0,descent:0,diffuseConstant:"diffuseConstant",direction:0,display:0,divisor:0,dominantBaseline:"dominant-baseline",dur:0,dx:0,dy:0,edgeMode:"edgeMode",elevation:0,enableBackground:"enable-background",end:0,exponent:0,externalResourcesRequired:"externalResourcesRequired",fill:0,fillOpacity:"fill-opacity",fillRule:"fill-rule",filter:0,filterRes:"filterRes",filterUnits:"filterUnits",floodColor:"flood-color",floodOpacity:"flood-opacity",focusable:0,fontFamily:"font-family",fontSize:"font-size",fontSizeAdjust:"font-size-adjust",fontStretch:"font-stretch",fontStyle:"font-style",fontVariant:"font-variant",fontWeight:"font-weight",format:0,from:0,fx:0,fy:0,g1:0,g2:0,glyphName:"glyph-name",glyphOrientationHorizontal:"glyph-orientation-horizontal",glyphOrientationVertical:"glyph-orientation-vertical",glyphRef:"glyphRef",gradientTransform:"gradientTransform",gradientUnits:"gradientUnits",hanging:0,horizAdvX:"horiz-adv-x",horizOriginX:"horiz-origin-x",ideographic:0,imageRendering:"image-rendering",in:0,in2:0,intercept:0,k:0,k1:0,k2:0,k3:0,k4:0,kernelMatrix:"kernelMatrix",kernelUnitLength:"kernelUnitLength",kerning:0,keyPoints:"keyPoints",keySplines:"keySplines",keyTimes:"keyTimes",lengthAdjust:"lengthAdjust",letterSpacing:"letter-spacing",lightingColor:"lighting-color",limitingConeAngle:"limitingConeAngle",local:0,markerEnd:"marker-end",markerMid:"marker-mid",markerStart:"marker-start",markerHeight:"markerHeight",markerUnits:"markerUnits",markerWidth:"markerWidth",mask:0,maskContentUnits:"maskContentUnits",maskUnits:"maskUnits",mathematical:0,mode:0,numOctaves:"numOctaves",offset:0,opacity:0,operator:0,order:0,orient:0,orientation:0,origin:0,overflow:0,overlinePosition:"overline-position",overlineThickness:"overline-thickness",paintOrder:"paint-order",panose1:"panose-1",pathLength:"pathLength",patternContentUnits:"patternContentUnits",patternTransform:"patternTransform",patternUnits:"patternUnits",pointerEvents:"pointer-events",points:0,pointsAtX:"pointsAtX",pointsAtY:"pointsAtY",pointsAtZ:"pointsAtZ",preserveAlpha:"preserveAlpha",preserveAspectRatio:"preserveAspectRatio",primitiveUnits:"primitiveUnits",r:0,radius:0,refX:"refX",refY:"refY",renderingIntent:"rendering-intent",repeatCount:"repeatCount",repeatDur:"repeatDur",requiredExtensions:"requiredExtensions",requiredFeatures:"requiredFeatures",restart:0,result:0,rotate:0,rx:0,ry:0,scale:0,seed:0,shapeRendering:"shape-rendering",slope:0,spacing:0,specularConstant:"specularConstant",specularExponent:"specularExponent",speed:0,spreadMethod:"spreadMethod",startOffset:"startOffset",stdDeviation:"stdDeviation",stemh:0,stemv:0,stitchTiles:"stitchTiles",stopColor:"stop-color",stopOpacity:"stop-opacity",strikethroughPosition:"strikethrough-position",strikethroughThickness:"strikethrough-thickness",string:0,stroke:0,strokeDasharray:"stroke-dasharray",strokeDashoffset:"stroke-dashoffset",strokeLinecap:"stroke-linecap",strokeLinejoin:"stroke-linejoin",strokeMiterlimit:"stroke-miterlimit",strokeOpacity:"stroke-opacity",strokeWidth:"stroke-width",surfaceScale:"surfaceScale",systemLanguage:"systemLanguage",tableValues:"tableValues",targetX:"targetX",targetY:"targetY",textAnchor:"text-anchor",textDecoration:"text-decoration",textRendering:"text-rendering",textLength:"textLength",to:0,transform:0,u1:0,u2:0,underlinePosition:"underline-position",underlineThickness:"underline-thickness",unicode:0,unicodeBidi:"unicode-bidi",unicodeRange:"unicode-range",unitsPerEm:"units-per-em",vAlphabetic:"v-alphabetic",vHanging:"v-hanging",vIdeographic:"v-ideographic",vMathematical:"v-mathematical",values:0,vectorEffect:"vector-effect",version:0,vertAdvY:"vert-adv-y",vertOriginX:"vert-origin-x",vertOriginY:"vert-origin-y",viewBox:"viewBox",viewTarget:"viewTarget",visibility:0,widths:0,wordSpacing:"word-spacing",writingMode:"writing-mode",x:0,xHeight:"x-height",x1:0,x2:0,xChannelSelector:"xChannelSelector",xlinkActuate:"xlink:actuate",xlinkArcrole:"xlink:arcrole",xlinkHref:"xlink:href",xlinkRole:"xlink:role",xlinkShow:"xlink:show",xlinkTitle:"xlink:title",xlinkType:"xlink:type",xmlBase:"xml:base",xmlns:0,xmlnsXlink:"xmlns:xlink",xmlLang:"xml:lang",xmlSpace:"xml:space",y:0,y1:0,y2:0,yChannelSelector:"yChannelSelector",z:0,zoomAndPan:"zoomAndPan"},i={Properties:{},DOMAttributeNamespaces:{xlinkActuate:r.xlink,xlinkArcrole:r.xlink,xlinkHref:r.xlink,xlinkRole:r.xlink,xlinkShow:r.xlink,xlinkTitle:r.xlink,xlinkType:r.xlink,xmlBase:r.xml,xmlLang:r.xml,xmlSpace:r.xml},DOMAttributeNames:{}};Object.keys(o).forEach(function(e){i.Properties[e]=0,o[e]&&(i.DOMAttributeNames[e]=o[e])}),e.exports=i},function(e,t,n){"use strict";function r(e){if("selectionStart"in e&&s.hasSelectionCapabilities(e))return{start:e.selectionStart,end:e.selectionEnd};if(window.getSelection){var t=window.getSelection();return{anchorNode:t.anchorNode,anchorOffset:t.anchorOffset,focusNode:t.focusNode,focusOffset:t.focusOffset}}if(document.selection){var n=document.selection.createRange();return{parentElement:n.parentElement(),text:n.text,top:n.boundingTop,left:n.boundingLeft}}}function o(e,t){if(y||null==m||m!==l())return null;var n=r(m);if(!g||!d(g,n)){g=n;var o=c.getPooled(h.select,v,e,t);return o.type="select",o.target=m,i.accumulateTwoPhaseDispatches(o),o}return null}var i=n(19),a=n(5),u=n(4),s=n(89),c=n(10),l=n(90),p=n(74),d=n(44),f=a.canUseDOM&&"documentMode"in document&&document.documentMode<=11,h={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:["topBlur","topContextMenu","topFocus","topKeyDown","topKeyUp","topMouseDown","topMouseUp","topSelectionChange"]}},m=null,v=null,g=null,y=!1,b=!1,_={eventTypes:h,extractEvents:function(e,t,n,r){if(!b)return null;var i=t?u.getNodeFromInstance(t):window;switch(e){case"topFocus":(p(i)||"true"===i.contentEditable)&&(m=i,v=t,g=null);break;case"topBlur":m=null,v=null,g=null;break;case"topMouseDown":y=!0;break;case"topContextMenu":case"topMouseUp":return y=!1,o(n,r);case"topSelectionChange":if(f)break;case"topKeyDown":case"topKeyUp":return o(n,r)}return null},didPutListener:function(e,t,n){"onSelect"===t&&(b=!0)}};e.exports=_},function(e,t,n){"use strict";function r(e){return"."+e._rootNodeID}function o(e){return"button"===e||"input"===e||"select"===e||"textarea"===e}var i=n(2),a=n(88),u=n(19),s=n(4),c=n(196),l=n(197),p=n(10),d=n(198),f=n(199),h=n(25),m=n(201),v=n(202),g=n(203),y=n(21),b=n(204),_=n(6),C=n(49),E=(n(0),{}),w={};["abort","animationEnd","animationIteration","animationStart","blur","canPlay","canPlayThrough","click","contextMenu","copy","cut","doubleClick","drag","dragEnd","dragEnter","dragExit","dragLeave","dragOver","dragStart","drop","durationChange","emptied","encrypted","ended","error","focus","input","invalid","keyDown","keyPress","keyUp","load","loadedData","loadedMetadata","loadStart","mouseDown","mouseMove","mouseOut","mouseOver","mouseUp","paste","pause","play","playing","progress","rateChange","reset","scroll","seeked","seeking","stalled","submit","suspend","timeUpdate","touchCancel","touchEnd","touchMove","touchStart","transitionEnd","volumeChange","waiting","wheel"].forEach(function(e){var t=e[0].toUpperCase()+e.slice(1),n="on"+t,r="top"+t,o={phasedRegistrationNames:{bubbled:n,captured:n+"Capture"},dependencies:[r]};E[e]=o,w[r]=o});var x={},T={eventTypes:E,extractEvents:function(e,t,n,r){var o=w[e];if(!o)return null;var a;switch(e){case"topAbort":case"topCanPlay":case"topCanPlayThrough":case"topDurationChange":case"topEmptied":case"topEncrypted":case"topEnded":case"topError":case"topInput":case"topInvalid":case"topLoad":case"topLoadedData":case"topLoadedMetadata":case"topLoadStart":case"topPause":case"topPlay":case"topPlaying":case"topProgress":case"topRateChange":case"topReset":case"topSeeked":case"topSeeking":case"topStalled":case"topSubmit":case"topSuspend":case"topTimeUpdate":case"topVolumeChange":case"topWaiting":a=p;break;case"topKeyPress":if(0===C(n))return null;case"topKeyDown":case"topKeyUp":a=f;break;case"topBlur":case"topFocus":a=d;break;case"topClick":if(2===n.button)return null;case"topDoubleClick":case"topMouseDown":case"topMouseMove":case"topMouseUp":case"topMouseOut":case"topMouseOver":case"topContextMenu":a=h;break;case"topDrag":case"topDragEnd":case"topDragEnter":case"topDragExit":case"topDragLeave":case"topDragOver":case"topDragStart":case"topDrop":a=m;break;case"topTouchCancel":case"topTouchEnd":case"topTouchMove":case"topTouchStart":a=v;break;case"topAnimationEnd":case"topAnimationIteration":case"topAnimationStart":a=c;break;case"topTransitionEnd":a=g;break;case"topScroll":a=y;break;case"topWheel":a=b;break;case"topCopy":case"topCut":case"topPaste":a=l}a||i("86",e);var s=a.getPooled(o,t,n,r);return u.accumulateTwoPhaseDispatches(s),s},didPutListener:function(e,t,n){if("onClick"===t&&!o(e._tag)){var i=r(e),u=s.getNodeFromInstance(e);x[i]||(x[i]=a.listen(u,"click",_))}},willDeleteListener:function(e,t){if("onClick"===t&&!o(e._tag)){var n=r(e);x[n].remove(),delete x[n]}}};e.exports=T},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(10),i={animationName:null,elapsedTime:null,pseudoElement:null};o.augmentClass(r,i),e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(10),i={clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}};o.augmentClass(r,i),e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(21),i={relatedTarget:null};o.augmentClass(r,i),e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(21),i=n(49),a=n(200),u=n(38),s={key:a,location:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,repeat:null,locale:null,getModifierState:u,charCode:function(e){return"keypress"===e.type?i(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?i(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}};o.augmentClass(r,s),e.exports=r},function(e,t,n){"use strict";function r(e){if(e.key){var t=i[e.key]||e.key;if("Unidentified"!==t)return t}if("keypress"===e.type){var n=o(e);return 13===n?"Enter":String.fromCharCode(n)}return"keydown"===e.type||"keyup"===e.type?a[e.keyCode]||"Unidentified":""}var o=n(49),i={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},a={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"};e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(25),i={dataTransfer:null};o.augmentClass(r,i),e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(21),i=n(38),a={touches:null,targetTouches:null,changedTouches:null,altKey:null,metaKey:null,ctrlKey:null,shiftKey:null,getModifierState:i};o.augmentClass(r,a),e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(10),i={propertyName:null,elapsedTime:null,pseudoElement:null};o.augmentClass(r,i),e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){return o.call(this,e,t,n,r)}var o=n(25),i={deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:null,deltaMode:null};o.augmentClass(r,i),e.exports=r},function(e,t,n){"use strict";function r(e,t){var n={_topLevelWrapper:e,_idCounter:1,_ownerDocument:t?t.nodeType===o?t:t.ownerDocument:null,_node:t,_tag:t?t.nodeName.toLowerCase():null,_namespaceURI:t?t.namespaceURI:null};return n}var o=(n(48),9);e.exports=r},function(e,t,n){"use strict";var r={useCreateElement:!0,useFiber:!1};e.exports=r},function(e,t,n){"use strict";var r=n(208),o=/\/?>/,i=/^<\!\-\-/,a={CHECKSUM_ATTR_NAME:"data-react-checksum",addChecksumToMarkup:function(e){var t=r(e);return i.test(e)?e:e.replace(o," "+a.CHECKSUM_ATTR_NAME+'="'+t+'"$&')},canReuseMarkup:function(e,t){var n=t.getAttribute(a.CHECKSUM_ATTR_NAME);return n=n&&parseInt(n,10),r(e)===n}};e.exports=a},function(e,t,n){"use strict";function r(e){for(var t=1,n=0,r=0,i=e.length,a=-4&i;r0&&void 0!==arguments[0]?arguments[0]:i,t=arguments[1],n={nodes:e.nodes,events:[].concat(r(e.events))};switch(t.type){case o.CREATE:n.nodes[t.id]={type:t.nodeType};break;case o.QUEUE_EVENT:Array.isArray(t.event)?t.event.forEach(function(t,r){n.events.push({key:e.events.length+r,event:t})}):n.events.push({key:e.events.length,event:t.event});break;case o.CLEAR_EVT_QUEUE:n.events=[]}return n};t.default=a},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var a=Object.assign||function(e){for(var t=1;t0}},{key:"processEvent",value:function(e){(0,e.event)(this.audioContext,this.getCurrTime())}},{key:"getCurrTime",value:function(){return this.audioContext.currentTime}},{key:"render",value:function(){return null}}]),t}(c.default.Component),f=function(e){var t=e.webAudioReducer;return a({},t)},h=function(e){return{clearQ:function(){return e((0,p.clearEvtQueue)())}}};t.default=(0,l.connect)(f,h)(d)},function(t,n){t.exports=e},function(e,n){e.exports=t}])})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=Object.assign||function(e){for(var t=1;t0?"hide":""),onClick:t},"CREATE"),i.default.createElement("div",{className:"button "+("BUZZING"===o?"off":"on")+" "+(0===l?"hide":""),onClick:"CLOSE"===o?null:e.susRes},a),i.default.createElement("div",{className:"button sm "+(0===l?"hide":""),onClick:n},"KILL"))))},d=function(e,t){var n=e.createOscillator(),r=e.createGain();n.connect(r),r.connect(e.destination),n.type="square",n.frequency.value=100,n.start(t),r.gain.value=.1},f=function(e){"running"===e.state?e.suspend():"suspended"===e.state&&e.resume()},h=function(e){e.close()},m=u.actionCreators.emit;t.default=(0,a.connect)(function(e){return r({},e)},function(e){return{start:function(){e((0,s.startCtxUI)()),e(m(d))},susRes:function(){e((0,s.susResAudioCtx)()),e(m(f))},close:function(){e((0,s.closeCtxUI)()),e(m(h))}}})(p)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});t.startCtxUI=function(){return{type:"START"}},t.susResAudioCtx=function(){return{type:"TOGGLE_CTX_RUNNING"}},t.closeCtxUI=function(){return{type:"CLOSE"}}},function(e,t,n){var r=n(217);"string"==typeof r&&(r=[[e.i,r,""]]);var o={};o.transform=void 0;n(219)(r,o);r.locals&&(e.exports=r.locals)},function(e,t,n){t=e.exports=n(218)(void 0),t.push([e.i,"html{background-color:#2d2d2d}#app{font-size:20px;font-weight:100;font-family:sans-serif;color:#bdbdbd}div p{margin:5px auto;font-size:2rem;text-shadow:3px 5px 3px rgba(0,0,0,.2)}.main{text-align:center}.title{margin:40px auto auto}.title>h1{display:inline;line-height:6rem;font-weight:lighter;font-size:4rem}.btn-wrap{display:flex;flex-direction:column;margin:auto;min-width:300px;max-width:80%}.button{cursor:default;min-width:10rem;padding:8px 0;margin:5px auto;border:1px solid #bdbdbd;border-radius:3px;box-shadow:.3em .5em 1em 1px rgba(0,0,0,.2)}.button.light{background-color:hsla(0,0%,100%,.1)}.sm{color:#bd2d2d;border-color:#bd2d2d}.on{color:#2dbd2d;border-color:#2dbd2d}.off{color:#e1bd41;border-color:#e1bd41}.bold{font-weight:600}.hide{display:none}",""])},function(e,t){function n(e,t){var n=e[1]||"",o=e[3];if(!o)return n;if(t&&"function"==typeof btoa){var i=r(o);return[n].concat(o.sources.map(function(e){return"/*# sourceURL="+o.sourceRoot+e+" */"})).concat([i]).join("\n")}return[n].join("\n")}function r(e){return"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(e))))+" */"}e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var r=n(t,e);return t[2]?"@media "+t[2]+"{"+r+"}":r}).join("")},t.i=function(e,n){"string"==typeof e&&(e=[[null,e,""]]);for(var r={},o=0;o=0&&b.splice(t,1)}function u(e){var t=document.createElement("style");return e.attrs.type="text/css",c(t,e.attrs),i(e,t),t}function s(e){var t=document.createElement("link");return e.attrs.type="text/css",e.attrs.rel="stylesheet",c(t,e.attrs),i(e,t),t}function c(e,t){Object.keys(t).forEach(function(n){e.setAttribute(n,t[n])})}function l(e,t){var n,r,o,i;if(t.transform&&e.css){if(!(i=t.transform(e.css)))return function(){};e.css=i}if(t.singleton){var c=y++;n=g||(g=u(t)),r=p.bind(null,n,c,!1),o=p.bind(null,n,c,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=s(t),r=f.bind(null,n,t),o=function(){a(n),n.href&&URL.revokeObjectURL(n.href)}):(n=u(t),r=d.bind(null,n),o=function(){a(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else o()}}function p(e,t,n,r){var o=n?"":r.css;if(e.styleSheet)e.styleSheet.cssText=C(t,o);else{var i=document.createTextNode(o),a=e.childNodes;a[t]&&e.removeChild(a[t]),a.length?e.insertBefore(i,a[t]):e.appendChild(i)}}function d(e,t){var n=t.css,r=t.media;if(r&&e.setAttribute("media",r),e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}function f(e,t,n){var r=n.css,o=n.sourceMap,i=void 0===t.convertToAbsoluteUrls&&o;(t.convertToAbsoluteUrls||i)&&(r=_(r)),o&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */");var a=new Blob([r],{type:"text/css"}),u=e.href;e.href=URL.createObjectURL(a),u&&URL.revokeObjectURL(u)}var h={},m=function(e){var t;return function(){return void 0===t&&(t=e.apply(this,arguments)),t}}(function(){return window&&document&&document.all&&!window.atob}),v=function(e){var t={};return function(n){return void 0===t[n]&&(t[n]=e.call(this,n)),t[n]}}(function(e){return document.querySelector(e)}),g=null,y=0,b=[],_=n(220);e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");t=t||{},t.attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||(t.singleton=m()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=o(e,t);return r(n,t),function(e){for(var i=[],a=0;a0&&void 0!==arguments[0]?arguments[0]:o,t=arguments[1],n=r({},e);switch(t.type){case"START":n.msg="BUZZING";break;case"TOGGLE_CTX_RUNNING":n.susResToggle="SUSPEND"===n.susResToggle?"RESUME":"SUSPEND",n.msg="SUSPEND"===n.susResToggle?"BUZZING":"PAUSED";break;case"CLOSE":n.msg="AUDIO CONTEXT CLOSED!"}return n}}]); 21 | //# sourceMappingURL=bundle.js.map --------------------------------------------------------------------------------