<commit_before>import React, { Component, PropTypes } from 'react';
import { combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import Router from 'react-router-dom/BrowserRouter';
import Route from 'react-router-dom/Route';
import Switch from 'react-router-dom/Switch';

import MainContainer from './components/MainContainer';
import MainNav from './components/MainNav';
import ModuleContainer from './components/ModuleContainer';
import { Front } from './components/Front';
import LoginCtrl from './components/Login';
import Settings from './components/Settings/Settings';

import getModuleRoutes from './moduleRoutes';
import initialReducers from './initialReducers';

const reducers = { ...initialReducers };

class Root extends Component {

  getChildContext() {
    return { addReducer: this.addReducer.bind(this) };
  }

  addReducer = (key, reducer) => {
    if (reducers[key] === undefined) {
      reducers[key] = reducer;
      this.props.store.replaceReducer(combineReducers({ ...reducers }));
      return true;
    }
    return false;
  }

  render() {
    const { logger, store, okapi, token, disableAuth, currentUser, currentPerms } = this.props;

    function Stripes(x) {
      Object.assign(this, x);
      this.hasPerm = (perm) => {
        logger.log('perm', `checking perm '${perm}': `, !!this.user.perms[perm]);
        return this.user.perms[perm];
      };
    }

    const stripes = new Stripes({
      logger,
      store,
      okapi,
      user: {
        user: currentUser,
        perms: currentPerms,
      },
    });

    return (
      <Provider store={store}>
        <Router>
          { token != null || disableAuth ?
            <MainContainer>
              <MainNav />
              <ModuleContainer id="content">
                <Switch>
                  <Route exact path="/" component={Front} key="root" />
                  <Route exact path="/settings" render={() => <Settings stripes={stripes} />} />
                  {getModuleRoutes(stripes)}
                  <Route
                    component={() =>

Uh-oh!

This route does not exist.

}
                  />
                </Switch>
              </ModuleContainer>
            </MainContainer> :
            <LoginCtrl />
          }
        </Router>
      </Provider>
    );
  }
}

Root.childContextTypes = {
  addReducer: PropTypes.func,
};

Root.propTypes = {
  store: PropTypes.shape({
    subscribe: PropTypes.func.isRequired,
    dispatch: PropTypes.func.isRequired,
    getState: PropTypes.func.isRequired,
    replaceReducer: PropTypes.func.isRequired,
  }),
  token: PropTypes.string,
  disableAuth: PropTypes.bool.isRequired,
  logger: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
  currentPerms: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  currentUser: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  okapi: PropTypes.shape({
    url: PropTypes.string.isRequired,
    tenant: PropTypes.string.isRequired,
  }).isRequired,
};

function mapStateToProps(state) {
  return {
    token: state.okapi.token,
    currentUser: state.okapi.currentUser,
    currentPerms: state.okapi.currentPerms,
  };
}

export default connect(mapStateToProps)(Root);
<commit_msg>hasPerm function copes when there are no user perms yet<commit_after>import React, { Component, PropTypes } from 'react';
import { combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import Router from 'react-router-dom/BrowserRouter';
import Route from 'react-router-dom/Route';
import Switch from 'react-router-dom/Switch';

import MainContainer from './components/MainContainer';
import MainNav from './components/MainNav';
import ModuleContainer from './components/ModuleContainer';
import { Front } from './components/Front';
import LoginCtrl from './components/Login';
import Settings from './components/Settings/Settings';

import getModuleRoutes from './moduleRoutes';
import initialReducers from './initialReducers';

const reducers = { ...initialReducers };

class Root extends Component {

  getChildContext() {
    return { addReducer: this.addReducer.bind(this) };
  }

  addReducer = (key, reducer) => {
    if (reducers[key] === undefined) {
      reducers[key] = reducer;
      this.props.store.replaceReducer(combineReducers({ ...reducers }));
      return true;
    }
    return false;
  }

  render() {
    const { logger, store, okapi, token, disableAuth, currentUser, currentPerms } = this.props;

    function Stripes(x) {
      Object.assign(this, x);
      this.hasPerm = (perm) => {
        if (!this.user.perms) {
          logger.log('perm', `not checking perm '${perm}': no user permissions yet`);
          return false;
        }
        logger.log('perm', `checking perm '${perm}': `, !!this.user.perms[perm]);
        return this.user.perms[perm];
      };
    }

    const stripes = new Stripes({
      logger,
      store,
      okapi,
      user: {
        user: currentUser,
        perms: currentPerms,
      },
    });

    return (
      <Provider store={store}>
        <Router>
          { token != null || disableAuth ?
            <MainContainer>
              <MainNav />
              <ModuleContainer id="content">
                <Switch>
                  <Route exact path="/" component={Front} key="root" />
                  <Route exact path="/settings" render={() => <Settings stripes={stripes} />} />
                  {getModuleRoutes(stripes)}
                  <Route
                    component={() =>

Uh-oh!

This route does not exist.

}
                  />
                </Switch>
              </ModuleContainer>
            </MainContainer> :
            <LoginCtrl />
          }
        </Router>
      </Provider>
    );
  }
}

Root.childContextTypes = {
  addReducer: PropTypes.func,
};

Root.propTypes = {
  store: PropTypes.shape({
    subscribe: PropTypes.func.isRequired,
    dispatch: PropTypes.func.isRequired,
    getState: PropTypes.func.isRequired,
    replaceReducer: PropTypes.func.isRequired,
  }),
  token: PropTypes.string,
  disableAuth: PropTypes.bool.isRequired,
  logger: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
  currentPerms: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  currentUser: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  okapi: PropTypes.shape({
    url: PropTypes.string.isRequired,
    tenant: PropTypes.string.isRequired,
  }).isRequired,
};

function mapStateToProps(state) {
  return {
    token: state.okapi.token,
    currentUser: state.okapi.currentUser,
    currentPerms: state.okapi.currentPerms,
  };
}

export default connect(mapStateToProps)(Root);
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import Router from 'react-router/BrowserRouter';
import Match from 'react-router/Match';
import Miss from 'react-router/Miss';

import MainContainer from './components/MainContainer';
import MainNav from './components/MainNav';
import ModuleContainer from './components/ModuleContainer';
import { Front } from './components/Front';
import LoginCtrl from './components/Login';

import moduleRoutes from './moduleRoutes';
import initialReducers from './initialReducers';

const reducers = { ...initialReducers };

class Root extends Component {

  getChildContext() {
    return { addReducer: this.addReducer.bind(this) };
  }

  addReducer = (key, reducer) => {
    if (reducers[key] === undefined) {
      reducers[key] = reducer;
      this.props.store.replaceReducer(combineReducers({ ...reducers }));
      return true;
    }
    return false;
  }

  render() {
    const { store, token } = this.props;
    return (
      <Provider store={store}><Router>
        <MainContainer>
          { token != null ? null : <LoginCtrl /> }
          <MainNav />
          <ModuleContainer id="content">
            <Match pattern="/" exactly component={Front} key="root" />
            {moduleRoutes}
            <Miss
              component={() =>

Uh-oh!

This route does not exist.

}
            />
          </ModuleContainer>
        </MainContainer>
      </Router></Provider>
    );
  }

}

Root.childContextTypes = {
  addReducer: PropTypes.func,
};

Root.propTypes = {
  store: PropTypes.shape({
    subscribe: PropTypes.func.isRequired,
    dispatch: PropTypes.func.isRequired,
    getState: PropTypes.func.isRequired,
    replaceReducer: PropTypes.func.isRequired,
  }),
  token: PropTypes.string,
};

function mapStateToProps(state) {
  return { token: state.okapi.token };
}

export default connect(mapStateToProps)(Root);
<commit_msg>Do not require authentication if disableAuth prop is provided. Fixes STRIPES-168.<commit_after>import React, { Component, PropTypes } from 'react';
import { combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import Router from 'react-router/BrowserRouter';
import Match from 'react-router/Match';
import Miss from 'react-router/Miss';

import MainContainer from './components/MainContainer';
import MainNav from './components/MainNav';
import ModuleContainer from './components/ModuleContainer';
import { Front } from './components/Front';
import LoginCtrl from './components/Login';

import moduleRoutes from './moduleRoutes';
import initialReducers from './initialReducers';

const reducers = { ...initialReducers };

class Root extends Component {

  getChildContext() {
    return { addReducer: this.addReducer.bind(this) };
  }

  addReducer = (key, reducer) => {
    if (reducers[key] === undefined) {
      reducers[key] = reducer;
      this.props.store.replaceReducer(combineReducers({ ...reducers }));
      return true;
    }
    return false;
  }

  render() {
    const { store, token, disableAuth } = this.props;
    return (
      <Provider store={store}><Router>
        <MainContainer>
          { token != null || disableAuth ? null : <LoginCtrl /> }
          <MainNav />
          <ModuleContainer id="content">
            <Match pattern="/" exactly component={Front} key="root" />
            {moduleRoutes}
            <Miss
              component={() =>

Uh-oh!

This route does not exist.

}
            />
          </ModuleContainer>
        </MainContainer>
      </Router></Provider>
    );
  }

}

Root.childContextTypes = {
  addReducer: PropTypes.func,
};

Root.propTypes = {
  store: PropTypes.shape({
    subscribe: PropTypes.func.isRequired,
    dispatch: PropTypes.func.isRequired,
    getState: PropTypes.func.isRequired,
    replaceReducer: PropTypes.func.isRequired,
  }),
  token: PropTypes.string,
};

function mapStateToProps(state) {
  return { token: state.okapi.token };
}

export default connect(mapStateToProps)(Root);
<|endoftext|>


<commit_before>'use strict';

/*!
 * Snakeskin
 * https://github.com/SnakeskinTpl/Snakeskin
 *
 * Released under the MIT license
 * https://github.com/SnakeskinTpl/Snakeskin/blob/master/LICENSE
 */

import Snakeskin from '../core';

Snakeskin.addDirective(
	'decl',

	{
		notEmpty: true,
		placement: 'template',
		replacers: {'{': 'decl '},
		text: true
	},

	function (command) {
		if (!this.isReady()) {
			return;
		}

		const
			code = this.replaceTplVars(command);

		const
			start = /^\{+/.exec(code) || [''],
			end = /}+$/.exec(code) || [''];

		let add;
		try {
			add = new Array(end[0].length - start[0].length + 1).join('{');

		} catch (ignore) {
			return this.error(`invalid "${this.name}" declaration`);
		}

		this.append(this.wrap(`'{${add}${code}'`));
	}
);
<commit_msg>:wrench:<commit_after>'use strict';

/*!
 * Snakeskin
 * https://github.com/SnakeskinTpl/Snakeskin
 *
 * Released under the MIT license
 * https://github.com/SnakeskinTpl/Snakeskin/blob/master/LICENSE
 */

import Snakeskin from '../core';

Snakeskin.addDirective(
	'decl',

	{
		notEmpty: true,
		placement: 'template',
		replacers: {'{': 'decl '},
		text: true
	},

	function (command) {
		const
			code = this.replaceTplVars(command);

		const
			start = /^\{+/.exec(code) || [''],
			end = /}+$/.exec(code) || [''];

		let add;
		try {
			add = new Array(end[0].length - start[0].length + 1).join('{');

		} catch (ignore) {
			return this.error(`invalid "${this.name}" declaration`);
		}

		this.append($=> this.wrap(`'{${add}${code}'`));
	}
);
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import Router from 'react-router-dom/BrowserRouter';
import Route from 'react-router-dom/Route';
import Switch from 'react-router-dom/Switch';

import MainContainer from './components/MainContainer';
import MainNav from './components/MainNav';
import ModuleContainer from './components/ModuleContainer';
import { Front } from './components/Front';
import LoginCtrl from './components/Login';
import Settings from './components/Settings/Settings';

import getModuleRoutes from './moduleRoutes';
import initialReducers from './initialReducers';

const reducers = { ...initialReducers };

class Root extends Component {

  getChildContext() {
    return { addReducer: this.addReducer.bind(this) };
  }

  addReducer = (key, reducer) => {
    if (reducers[key] === undefined) {
      reducers[key] = reducer;
      this.props.store.replaceReducer(combineReducers({ ...reducers }));
      return true;
    }
    return false;
  }

  render() {
    const { logger, store, config, okapi, token, currentUser, currentPerms } = this.props;

    function Stripes(x) {
      Object.assign(this, x);
      this.hasPerm = (perm) => {
        if (this.config && this.config.hasAllPerms) {
          logger.log('perm', `assuming perm '${perm}': hasAllPerms is true`);
          return true;
        }
        if (!this.user.perms) {
          logger.log('perm', `not checking perm '${perm}': no user permissions yet`);
          return undefined;
        }
        logger.log('perm', `checking perm '${perm}': `, !!this.user.perms[perm]);
        return this.user.perms[perm] || false;
      };
    }

    const stripes = new Stripes({
      logger,
      store,
      config,
      okapi,
      user: {
        user: currentUser,
        // ### Remove the special-case below when possible: see STRIPES-322
        perms: Object.assign({}, currentPerms, { 'module.organization.enabled': true })
      },
    });

    return (
      <Provider store={store}>
        <Router>
          { token != null ?
            <MainContainer>
              <MainNav stripes={stripes} />
              <ModuleContainer id="content">
                <Switch>
                  <Route exact path="/" component={Front} key="root" />
                  <Route exact path="/settings" render={() => <Settings stripes={stripes} />} />
                  {getModuleRoutes(stripes)}
                  <Route
                    component={() =>

Uh-oh!

This route does not exist.

}
                  />
                </Switch>
              </ModuleContainer>
            </MainContainer> :
            <LoginCtrl />
          }
        </Router>
      </Provider>
    );
  }
}

Root.childContextTypes = {
  addReducer: PropTypes.func,
};

Root.propTypes = {
  store: PropTypes.shape({
    subscribe: PropTypes.func.isRequired,
    dispatch: PropTypes.func.isRequired,
    getState: PropTypes.func.isRequired,
    replaceReducer: PropTypes.func.isRequired,
  }),
  token: PropTypes.string,
  logger: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
  currentPerms: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  currentUser: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  config: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  okapi: PropTypes.shape({
    url: PropTypes.string.isRequired,
    tenant: PropTypes.string.isRequired,
  }).isRequired,
};

function mapStateToProps(state) {
  return {
    token: state.okapi.token,
    currentUser: state.okapi.currentUser,
    currentPerms: state.okapi.currentPerms,
  };
}

export default connect(mapStateToProps)(Root);
<commit_msg>Routing to /settings is no longer exact<commit_after>import React, { Component, PropTypes } from 'react';
import { combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import Router from 'react-router-dom/BrowserRouter';
import Route from 'react-router-dom/Route';
import Switch from 'react-router-dom/Switch';

import MainContainer from './components/MainContainer';
import MainNav from './components/MainNav';
import ModuleContainer from './components/ModuleContainer';
import { Front } from './components/Front';
import LoginCtrl from './components/Login';
import Settings from './components/Settings/Settings';

import getModuleRoutes from './moduleRoutes';
import initialReducers from './initialReducers';

const reducers = { ...initialReducers };

class Root extends Component {

  getChildContext() {
    return { addReducer: this.addReducer.bind(this) };
  }

  addReducer = (key, reducer) => {
    if (reducers[key] === undefined) {
      reducers[key] = reducer;
      this.props.store.replaceReducer(combineReducers({ ...reducers }));
      return true;
    }
    return false;
  }

  render() {
    const { logger, store, config, okapi, token, currentUser, currentPerms } = this.props;

    function Stripes(x) {
      Object.assign(this, x);
      this.hasPerm = (perm) => {
        if (this.config && this.config.hasAllPerms) {
          logger.log('perm', `assuming perm '${perm}': hasAllPerms is true`);
          return true;
        }
        if (!this.user.perms) {
          logger.log('perm', `not checking perm '${perm}': no user permissions yet`);
          return undefined;
        }
        logger.log('perm', `checking perm '${perm}': `, !!this.user.perms[perm]);
        return this.user.perms[perm] || false;
      };
    }

    const stripes = new Stripes({
      logger,
      store,
      config,
      okapi,
      user: {
        user: currentUser,
        // ### Remove the special-case below when possible: see STRIPES-322
        perms: Object.assign({}, currentPerms, { 'module.organization.enabled': true })
      },
    });

    return (
      <Provider store={store}>
        <Router>
          { token != null ?
            <MainContainer>
              <MainNav stripes={stripes} />
              <ModuleContainer id="content">
                <Switch>
                  <Route exact path="/" component={Front} key="root" />
                  <Route path="/settings" render={() => <Settings stripes={stripes} />} />
                  {getModuleRoutes(stripes)}
                  <Route
                    component={() =>

Uh-oh!

This route does not exist.

}
                  />
                </Switch>
              </ModuleContainer>
            </MainContainer> :
            <LoginCtrl />
          }
        </Router>
      </Provider>
    );
  }
}

Root.childContextTypes = {
  addReducer: PropTypes.func,
};

Root.propTypes = {
  store: PropTypes.shape({
    subscribe: PropTypes.func.isRequired,
    dispatch: PropTypes.func.isRequired,
    getState: PropTypes.func.isRequired,
    replaceReducer: PropTypes.func.isRequired,
  }),
  token: PropTypes.string,
  logger: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
  currentPerms: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  currentUser: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  config: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  okapi: PropTypes.shape({
    url: PropTypes.string.isRequired,
    tenant: PropTypes.string.isRequired,
  }).isRequired,
};

function mapStateToProps(state) {
  return {
    token: state.okapi.token,
    currentUser: state.okapi.currentUser,
    currentPerms: state.okapi.currentPerms,
  };
}

export default connect(mapStateToProps)(Root);
<|endoftext|>


<commit_before>//
// Connection to SRE explorer.
//
MathJax.Hub.Register.StartupHook('Sre Ready', function() {
  var FALSE, KEY;
  var SETTINGS = MathJax.Hub.config.menuSettings;

  MathJax.Hub.Register.StartupHook('MathEvents Ready', function() {
    FALSE = MathJax.Extension.MathEvents.Event.False;
    KEY = MathJax.Extension.MathEvents.Event.KEY;
  });

  var Assistive = MathJax.Extension.Assistive = {
    version: "1.0",
    //
    // Default configurations.
    //
    default: {
      walker: 'dummy',
      highlight: 'none',
      background: 'blue',
      foreground: 'black',
      speech: true,
      subtitle: false,
      // Configuration option only.
      generateSpeech: true
    },
    prefix: 'Assistive-',

    addMenuOption: function(key, value) {
      SETTINGS[Assistive.prefix + key] = value;
    },

    addDefaults: function() {
      var keys = Object.keys(Assistive.default);
      for (var i = 0, key; key = keys[i]; i++) {
        if (typeof(SETTINGS[Assistive.prefix + key]) === 'undefined') {
          Assistive.addMenuOption(key, Assistive.default[key]);
        }
      }
      Explorer.Reset();
    },

    setOption: function(key, value) {
      if (SETTINGS[Assistive.prefix + key] === value) return;
      Assistive.addMenuOption(key, value);
      Explorer.Reset();
    },

    getOption: function(key) {
      return SETTINGS[Assistive.prefix + key];
    }

  };

  var LiveRegion = MathJax.Object.Subclass({
    div: null,
    inner: null,
    Init: function() {
      this.div = LiveRegion.Create('assertive');
      this.inner = MathJax.HTML.addElement(this.div,'div');
    },
    //
    // Adds the speech div.
    //
    Add: function() {
      if (LiveRegion.announced) return;
      document.body.appendChild(this.div);
      LiveRegion.Announce();
    },
    //
    // Shows the live region as a subtitle of a node.
    //
    Show: function(node, highlighter) {
      this.div.classList.add('MJX_LiveRegion_Show');
      var rect = node.getBoundingClientRect();
      var bot = rect.bottom + 10 + window.pageYOffset;
      var left = rect.left + window.pageXOffset;
      this.div.style.top = bot + 'px';
      this.div.style.left = left + 'px';
      var color = highlighter.colorString();
      this.inner.style.backgroundColor = color.background;
      this.inner.style.color = color.foreground;
    },
    //
    // Takes the live region out of the page flow.
    //
    Hide: function(node) {
      this.div.classList.remove('MJX_LiveRegion_Show');
    },
    //
    // Clears the speech div.
    //
    Clear: function() {
      this.Update('');
      this.inner.style.top = '';
      this.inner.style.backgroundColor = '';
    },
    //
    // Speaks a string by poking it into the speech div.
    //
    Update: function(speech) {
      if (Assistive.getOption('speech')) {
        LiveRegion.Update(this.inner, speech);
      }
    }
  }, {
    ANNOUNCE: 'Navigatable Math in page. Explore with shift space.',
    announced: false,
    styles: {'.MJX_LiveRegion':
             {
               position: 'absolute', top:'0', height: '1px', width: '1px',
               padding: '1px', overflow: 'hidden'
             },
             '.MJX_LiveRegion_Show':
             {
               top:'0', position: 'absolute', width: 'auto', height: 'auto',
               padding: '0px 0px', opacity: 1, 'z-index': '202',
               left: 0, right: 0, 'margin': '0 auto',
               'background-color': 'white', 'box-shadow': '0px 10px 20px #888',
               border: '2px solid #CCCCCC'
             },
             '.MJX_DescriptionElement':
             {
               position: 'absolute', top:'0', height: '1px', width: '1px',
               padding: '1px', overflow: 'hidden'
             }
            },
    //
    // Creates a live region with a particular type.
    //
    Create: function(type) {
      var element = MathJax.HTML.Element(
        'div', {className: 'MJX_LiveRegion'});
      element.setAttribute('aria-live', type);
      return element;
    },
    //
    // Updates a live region's text content.
    //
    Update: MathJax.Hub.Browser.isPC ?
      function(div, speech) {
        div.textContent = '';
        setTimeout(function() {div.textContent = speech;}, 100);
      } : function(div, speech) {
        div.textContent = speech;
      },
    //
    // Speaks the announce string.
    //
    Announce: function() {
      if (LiveRegion.announced) return;
      LiveRegion.announced = true;
      MathJax.Ajax.Styles(LiveRegion.styles);
      var div = LiveRegion.Create('polite');
      document.body.appendChild(div);
      LiveRegion.Update(div, LiveRegion.ANNOUNCE);
      setTimeout(function() {document.body.removeChild(div);}, 1000);
    }
  });
  MathJax.Extension.Assistive.LiveRegion = LiveRegion;

  var Explorer = MathJax.Extension.Assistive.Explorer = {
    liveRegion: LiveRegion(),
    walker: null,
    highlighter: null,
    hoverer: null,
    flamer: null,
    speechDiv: null,
    earconFile: location.protocol +
      '//progressiveaccess.com/content/invalid_keypress' +
      (['Firefox', 'Chrome', 'Opera'].indexOf(MathJax.Hub.Browser.name) !== -1 ?
       '.ogg' : '.mp3'),
    focusEvent: MathJax.Hub.Browser.isFirefox ? 'blur' : 'focusout',
    //
    // Resets the explorer, rerunning methods not triggered by events.
    //
    Reset: function() {
      Explorer.FlameEnriched();
      sre.Engine.getInstance().speech = Assistive.getOption('generateSpeech');
    },
    //
    // Registers new Maths and adds a key event if it is enriched.
    //
    Register: function(msg) {
      var script = document.getElementById(msg[1]);
      if (script && script.id) {
        var jax = MathJax.Hub.getJaxFor(script.id);
        if (jax && jax.enriched) {
          Explorer.liveRegion.Add();
          Explorer.AddEvent(script);
        }
      }
    },
    //
    // Adds Aria attributes.
    //
    AddAria: function(math) {
      math.setAttribute('role', 'application');
      math.setAttribute('aria-label', 'Math');
    },
    //
    // Adds a key event to an enriched jax.
    //
    AddEvent: function(script) {
      var id = script.id + '-Frame';
      var sibling = script.previousSibling;
      if (sibling) {
        var math = sibling.id !== id ? sibling.firstElementChild : sibling;
        Explorer.AddAria(math);
        Explorer.AddMouseEvents(math);
        if (math.className === 'MathJax_MathML') {
          math = math.firstElementChild;
        }
        if (math) {
          math.onkeydown = Explorer.Keydown;
          //
          var speechGenerator = new sre.DirectSpeechGenerator();
          var span = math.querySelector('[data-semantic-speech]');
          if (span) {
            var speech = speechGenerator.getSpeech(span);
            if (speech) {
              var descr = id + '-Descr';
              math.setAttribute('aria-labelledby', descr);
              var newSpan = MathJax.HTML.addElement(
                document.body, 'div',
                {id: descr, className: 'MJX_DescriptionElement'});
              newSpan.textContent = speech;
            }
          }
          //
          math.addEventListener(
            Explorer.focusEvent,
            function(event) {
              if (Explorer.walker) Explorer.DeactivateWalker();
            });
          return;
        }
      }
    },
    //
    // Event execution on keydown. Subsumes the same method of MathEvents.
    //
    Keydown: function(event) {
      if (event.keyCode === KEY.ESCAPE) {
        if (!Explorer.walker) return;
        Explorer.DeactivateWalker();
        FALSE(event);
        return;
      }
      // If walker is active we redirect there.
      if (Explorer.walker && Explorer.walker.isActive()) {
        var move = Explorer.walker.move(event.keyCode);
        if (move === null) return;
        if (move) {
          Explorer.liveRegion.Update(Explorer.walker.speech());
          Explorer.Highlight();
        } else {
          Explorer.PlayEarcon();
        }
        FALSE(event);
        return;
      }
      var math = event.target;
      if (event.keyCode === KEY.SPACE) {
        if (event.shiftKey) {
          Explorer.ActivateWalker(math);
        } else {
          MathJax.Extension.MathEvents.Event.ContextMenu(event, math);
        }
        FALSE(event);
        return;
      }
    },
    GetHighlighter: function(alpha) {
      Explorer.highlighter = sre.HighlighterFactory.highlighter(
        {color: Assistive.getOption('background'), alpha: alpha},
        {color: Assistive.getOption('foreground'), alpha: 1},
        {renderer: MathJax.Hub.outputJax['jax/mml'][0].id,
         browser: MathJax.Hub.Browser.name}
      );
    },
    //
    // Adds mouse events to maction items in an enriched jax.
    //
    AddMouseEvents: function(node) {
      sre.HighlighterFactory.addEvents(
        node,
        {'mouseover': Explorer.MouseOver,
         'mouseout': Explorer.MouseOut},
        {renderer: MathJax.Hub.outputJax['jax/mml'][0].id,
         browser: MathJax.Hub.Browser.name}
      );
    },
    MouseOver: function(event) {
      if (Assistive.getOption('highlight') === 'none') return;
      if (Assistive.getOption('highlight') === 'hover') {
        var frame = event.currentTarget;
        Explorer.GetHighlighter(.1);
        Explorer.highlighter.highlight([frame]);
        Explorer.hoverer = true;
      }
      MathJax.Extension.MathEvents.Event.False(event);
    },
    MouseOut: function (event) {
      if (Explorer.hoverer) {
        Explorer.highlighter.unhighlight();
        Explorer.hoverer = false;
      }
      return MathJax.Extension.MathEvents.Event.False(event);
    },
    //
    // Activates Flaming
    //
    Flame: function(node) {
      Explorer.UnFlame(node);
      if (Assistive.getOption('highlight') === 'flame') {
        Explorer.GetHighlighter(.05);
        Explorer.highlighter.highlightAll(node);
        Explorer.flamer = true;
        return;
      }
    },
    UnFlame: function(node) {
      if (Explorer.flamer) {
        Explorer.highlighter.unhighlightAll();
        Explorer.flamer = null;
      }
    },
    FlameEnriched: function() {
      for (var i = 0, all = MathJax.Hub.getAllJax(), jax; jax = all[i]; i++) {
        Explorer.Flame(document.getElementById(jax.inputID).previousSibling);
      }
    },
    //
    // Activates the walker.
    //
    Walkers: {
      'syntactic': sre.SyntaxWalker,
      'semantic': sre.SemanticWalker,
      'dummy': sre.DummyWalker
    },
    ActivateWalker: function(math) {
      var speechGenerator = new sre.DirectSpeechGenerator();
      var constructor = Explorer.Walkers[Assistive.getOption('walker')] ||
            Explorer.Walkers['dummy'];
      Explorer.walker = new constructor(math, speechGenerator);
      Explorer.GetHighlighter(.2);
      Explorer.walker.activate();
      if (Assistive.getOption('generateSpeech') &&
          Assistive.getOption('speech')) {
        if (Assistive.getOption('subtitle')) {
          Explorer.liveRegion.Show(math, Explorer.highlighter);
        }
        Explorer.liveRegion.Update(Explorer.walker.speech());
      }
      Explorer.Highlight();
    },
    //
    // Deactivates the walker.
    //
    DeactivateWalker: function() {
      Explorer.liveRegion.Clear();
      Explorer.liveRegion.Hide();
      Explorer.Unhighlight();
      Explorer.currentHighlight = null;
      Explorer.walker.deactivate();
      Explorer.walker = null;
    },
    //
    // Highlights the focused nodes.
    //
    Highlight: function() {
      Explorer.Unhighlight();
      Explorer.highlighter.highlight(Explorer.walker.getFocus().getNodes());
    },
    //
    // Unhighlights the old nodes.
    //
    Unhighlight: function() {
      Explorer.highlighter.unhighlight();
    },
    //
    // Plays the earcon.
    //
    // Every time we make new Audio element, as some browsers do not allow to
    // play audio elements more than once (e.g., Safari).
    //
    PlayEarcon: function() {
      var audio = new Audio(Explorer.earconFile);
      audio.play();
    },
    //
    // Regenerates speech.
    //
    Regenerate: function() {
      Explorer.Reset();
      var speechItems = ['SpeechOutput', 'Subtitles'];
      speechItems.forEach(
        function(x) {
          var item = MathJax.Menu.menu.FindId('Accessibility', x);
          if (item) {
            item.disabled = !item.disabled;
          }});
      for (var i = 0, all = MathJax.Hub.getAllJax(), jax; jax = all[i]; i++) {
        if (jax.enriched) {
          MathJax.Hub.Queue(['Reprocess', jax]);
        }
      }
    }
  };

  MathJax.Extension.Assistive.addDefaults();

  MathJax.Hub.Register.StartupHook('MathMenu Ready', function() {
    var ITEM = MathJax.Menu.ITEM;
    var accessibilityMenu =
          ITEM.SUBMENU(['Accessibility', 'Accessibilty'],
              ITEM.SUBMENU(['Walker', 'Walker'],
                  ITEM.RADIO(['dummy', 'No walker'], 'Assistive-walker'),
                  ITEM.RADIO(['syntactic', 'Syntax walker'], 'Assistive-walker'),
                  ITEM.RADIO(['semantic', 'Semantic walker'], 'Assistive-walker')
                          ),
              ITEM.SUBMENU(['Highlight', 'Highlight'],
                           ITEM.RADIO(['none', 'None'], 'Assistive-highlight', {action: Explorer.Reset}),
                           ITEM.RADIO(['hover', 'Hover'], 'Assistive-highlight', {action: Explorer.Reset}),
                           ITEM.RADIO(['flame','Flame'], 'Assistive-highlight', {action: Explorer.Reset})
                          ),
              ITEM.SUBMENU(['Background', 'Background'],
                           ITEM.RADIO(['blue','Blue'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['red','Red'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['green','Green'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['yellow','Yellow'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['cyan','Cyan'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['magenta','Magenta'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['white','White'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['black','Black'], 'Assistive-background', {action: Explorer.Reset})
                          ),
              ITEM.SUBMENU(['Foreground', 'Foreground'],
                           ITEM.RADIO(['black','Black'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['white','White'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['magenta','Magenta'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['cyan','Cyan'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['yellow','Yellow'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['green','Green'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['red','Red'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['blue','Blue'], 'Assistive-foreground', {action: Explorer.Reset})
                          ),
                       ITEM.RULE(),
                       ITEM.CHECKBOX(['GenerateSpeech', 'Generate Speech'], 'Assistive-generateSpeech',
                                     {action: Explorer.Regenerate}),
                       ITEM.CHECKBOX(['SpeechOutput', 'Speech Output'], 'Assistive-speech',
                                     {disabled: !SETTINGS['Assistive-generateSpeech']}),
                       ITEM.CHECKBOX(['Subtitles', 'Subtitles'], 'Assistive-subtitle',
                                     {disabled: !SETTINGS['Assistive-generateSpeech']})
                      );
    // Attaches the menu;
    var about = MathJax.Menu.menu.IndexOfId('About');
    if (about === null) {
      MathJax.Menu.menu.items.push(ITEM.RULE(), accessibilityMenu);
      return;
    }
    MathJax.Menu.menu.items.splice(about, 0, accessibilityMenu, ITEM.RULE());
  });

  MathJax.Hub.Register.MessageHook('New Math', ['Register', MathJax.Extension.Assistive.Explorer]);

  MathJax.Hub.Startup.signal.Post("Explorer Ready");
});

MathJax.Ajax.loadComplete("[RespEq]/Assistive-Explore.js");
<commit_msg>Fixes the issue that flaming would only work on one element.<commit_after>//
// Connection to SRE explorer.
//
MathJax.Hub.Register.StartupHook('Sre Ready', function() {
  var FALSE, KEY;
  var SETTINGS = MathJax.Hub.config.menuSettings;

  MathJax.Hub.Register.StartupHook('MathEvents Ready', function() {
    FALSE = MathJax.Extension.MathEvents.Event.False;
    KEY = MathJax.Extension.MathEvents.Event.KEY;
  });

  var Assistive = MathJax.Extension.Assistive = {
    version: "1.0",
    //
    // Default configurations.
    //
    default: {
      walker: 'dummy',
      highlight: 'none',
      background: 'blue',
      foreground: 'black',
      speech: true,
      subtitle: false,
      // Configuration option only.
      generateSpeech: true
    },
    prefix: 'Assistive-',

    addMenuOption: function(key, value) {
      SETTINGS[Assistive.prefix + key] = value;
    },

    addDefaults: function() {
      var keys = Object.keys(Assistive.default);
      for (var i = 0, key; key = keys[i]; i++) {
        if (typeof(SETTINGS[Assistive.prefix + key]) === 'undefined') {
          Assistive.addMenuOption(key, Assistive.default[key]);
        }
      }
      Explorer.Reset();
    },

    setOption: function(key, value) {
      if (SETTINGS[Assistive.prefix + key] === value) return;
      Assistive.addMenuOption(key, value);
      Explorer.Reset();
    },

    getOption: function(key) {
      return SETTINGS[Assistive.prefix + key];
    }

  };

  var LiveRegion = MathJax.Object.Subclass({
    div: null,
    inner: null,
    Init: function() {
      this.div = LiveRegion.Create('assertive');
      this.inner = MathJax.HTML.addElement(this.div,'div');
    },
    //
    // Adds the speech div.
    //
    Add: function() {
      if (LiveRegion.announced) return;
      document.body.appendChild(this.div);
      LiveRegion.Announce();
    },
    //
    // Shows the live region as a subtitle of a node.
    //
    Show: function(node, highlighter) {
      this.div.classList.add('MJX_LiveRegion_Show');
      var rect = node.getBoundingClientRect();
      var bot = rect.bottom + 10 + window.pageYOffset;
      var left = rect.left + window.pageXOffset;
      this.div.style.top = bot + 'px';
      this.div.style.left = left + 'px';
      var color = highlighter.colorString();
      this.inner.style.backgroundColor = color.background;
      this.inner.style.color = color.foreground;
    },
    //
    // Takes the live region out of the page flow.
    //
    Hide: function(node) {
      this.div.classList.remove('MJX_LiveRegion_Show');
    },
    //
    // Clears the speech div.
    //
    Clear: function() {
      this.Update('');
      this.inner.style.top = '';
      this.inner.style.backgroundColor = '';
    },
    //
    // Speaks a string by poking it into the speech div.
    //
    Update: function(speech) {
      if (Assistive.getOption('speech')) {
        LiveRegion.Update(this.inner, speech);
      }
    }
  }, {
    ANNOUNCE: 'Navigatable Math in page. Explore with shift space.',
    announced: false,
    styles: {'.MJX_LiveRegion':
             {
               position: 'absolute', top:'0', height: '1px', width: '1px',
               padding: '1px', overflow: 'hidden'
             },
             '.MJX_LiveRegion_Show':
             {
               top:'0', position: 'absolute', width: 'auto', height: 'auto',
               padding: '0px 0px', opacity: 1, 'z-index': '202',
               left: 0, right: 0, 'margin': '0 auto',
               'background-color': 'white', 'box-shadow': '0px 10px 20px #888',
               border: '2px solid #CCCCCC'
             },
             '.MJX_DescriptionElement':
             {
               position: 'absolute', top:'0', height: '1px', width: '1px',
               padding: '1px', overflow: 'hidden'
             }
            },
    //
    // Creates a live region with a particular type.
    //
    Create: function(type) {
      var element = MathJax.HTML.Element(
        'div', {className: 'MJX_LiveRegion'});
      element.setAttribute('aria-live', type);
      return element;
    },
    //
    // Updates a live region's text content.
    //
    Update: MathJax.Hub.Browser.isPC ?
      function(div, speech) {
        div.textContent = '';
        setTimeout(function() {div.textContent = speech;}, 100);
      } : function(div, speech) {
        div.textContent = speech;
      },
    //
    // Speaks the announce string.
    //
    Announce: function() {
      if (LiveRegion.announced) return;
      LiveRegion.announced = true;
      MathJax.Ajax.Styles(LiveRegion.styles);
      var div = LiveRegion.Create('polite');
      document.body.appendChild(div);
      LiveRegion.Update(div, LiveRegion.ANNOUNCE);
      setTimeout(function() {document.body.removeChild(div);}, 1000);
    }
  });
  MathJax.Extension.Assistive.LiveRegion = LiveRegion;

  var Explorer = MathJax.Extension.Assistive.Explorer = {
    liveRegion: LiveRegion(),
    walker: null,
    highlighter: null,
    hoverer: null,
    flamer: null,
    speechDiv: null,
    earconFile: location.protocol +
      '//progressiveaccess.com/content/invalid_keypress' +
      (['Firefox', 'Chrome', 'Opera'].indexOf(MathJax.Hub.Browser.name) !== -1 ?
       '.ogg' : '.mp3'),
    focusEvent: MathJax.Hub.Browser.isFirefox ? 'blur' : 'focusout',
    //
    // Resets the explorer, rerunning methods not triggered by events.
    //
    Reset: function() {
      Explorer.FlameEnriched();
      sre.Engine.getInstance().speech = Assistive.getOption('generateSpeech');
    },
    //
    // Registers new Maths and adds a key event if it is enriched.
    //
    Register: function(msg) {
      var script = document.getElementById(msg[1]);
      if (script && script.id) {
        var jax = MathJax.Hub.getJaxFor(script.id);
        if (jax && jax.enriched) {
          Explorer.liveRegion.Add();
          Explorer.AddEvent(script);
        }
      }
    },
    //
    // Adds Aria attributes.
    //
    AddAria: function(math) {
      math.setAttribute('role', 'application');
      math.setAttribute('aria-label', 'Math');
    },
    //
    // Adds a key event to an enriched jax.
    //
    AddEvent: function(script) {
      var id = script.id + '-Frame';
      var sibling = script.previousSibling;
      if (sibling) {
        var math = sibling.id !== id ? sibling.firstElementChild : sibling;
        Explorer.AddAria(math);
        Explorer.AddMouseEvents(math);
        if (math.className === 'MathJax_MathML') {
          math = math.firstElementChild;
        }
        if (math) {
          math.onkeydown = Explorer.Keydown;
          //
          var speechGenerator = new sre.DirectSpeechGenerator();
          var span = math.querySelector('[data-semantic-speech]');
          if (span) {
            var speech = speechGenerator.getSpeech(span);
            if (speech) {
              var descr = id + '-Descr';
              math.setAttribute('aria-labelledby', descr);
              var newSpan = MathJax.HTML.addElement(
                document.body, 'div',
                {id: descr, className: 'MJX_DescriptionElement'});
              newSpan.textContent = speech;
            }
          }
          //
          math.addEventListener(
            Explorer.focusEvent,
            function(event) {
              if (Explorer.walker) Explorer.DeactivateWalker();
            });
          return;
        }
      }
    },
    //
    // Event execution on keydown. Subsumes the same method of MathEvents.
    //
    Keydown: function(event) {
      if (event.keyCode === KEY.ESCAPE) {
        if (!Explorer.walker) return;
        Explorer.DeactivateWalker();
        FALSE(event);
        return;
      }
      // If walker is active we redirect there.
      if (Explorer.walker && Explorer.walker.isActive()) {
        var move = Explorer.walker.move(event.keyCode);
        if (move === null) return;
        if (move) {
          Explorer.liveRegion.Update(Explorer.walker.speech());
          Explorer.Highlight();
        } else {
          Explorer.PlayEarcon();
        }
        FALSE(event);
        return;
      }
      var math = event.target;
      if (event.keyCode === KEY.SPACE) {
        if (event.shiftKey) {
          Explorer.ActivateWalker(math);
        } else {
          MathJax.Extension.MathEvents.Event.ContextMenu(event, math);
        }
        FALSE(event);
        return;
      }
    },
    GetHighlighter: function(alpha) {
      Explorer.highlighter = sre.HighlighterFactory.highlighter(
        {color: Assistive.getOption('background'), alpha: alpha},
        {color: Assistive.getOption('foreground'), alpha: 1},
        {renderer: MathJax.Hub.outputJax['jax/mml'][0].id,
         browser: MathJax.Hub.Browser.name}
      );
    },
    //
    // Adds mouse events to maction items in an enriched jax.
    //
    AddMouseEvents: function(node) {
      sre.HighlighterFactory.addEvents(
        node,
        {'mouseover': Explorer.MouseOver,
         'mouseout': Explorer.MouseOut},
        {renderer: MathJax.Hub.outputJax['jax/mml'][0].id,
         browser: MathJax.Hub.Browser.name}
      );
    },
    MouseOver: function(event) {
      if (Assistive.getOption('highlight') === 'none') return;
      if (Assistive.getOption('highlight') === 'hover') {
        var frame = event.currentTarget;
        Explorer.GetHighlighter(.1);
        Explorer.highlighter.highlight([frame]);
        Explorer.hoverer = true;
      }
      MathJax.Extension.MathEvents.Event.False(event);
    },
    MouseOut: function (event) {
      if (Explorer.hoverer) {
        Explorer.highlighter.unhighlight();
        Explorer.hoverer = false;
      }
      return MathJax.Extension.MathEvents.Event.False(event);
    },
    //
    // Activates Flaming
    //
    Flame: function(node) {
      if (Assistive.getOption('highlight') === 'flame') {
        Explorer.GetHighlighter(.05);
        Explorer.highlighter.highlightAll(node);
        Explorer.flamer = true;
        return;
      }
    },
    UnFlame: function() {
      if (Explorer.flamer) {
        Explorer.highlighter.unhighlightAll();
        Explorer.flamer = null;
      }
    },
    FlameEnriched: function() {
      Explorer.UnFlame();
      for (var i = 0, all = MathJax.Hub.getAllJax(), jax; jax = all[i]; i++) {
        Explorer.Flame(document.getElementById(jax.inputID).previousSibling);
      }
    },
    //
    // Activates the walker.
    //
    Walkers: {
      'syntactic': sre.SyntaxWalker,
      'semantic': sre.SemanticWalker,
      'dummy': sre.DummyWalker
    },
    ActivateWalker: function(math) {
      var speechGenerator = new sre.DirectSpeechGenerator();
      var constructor = Explorer.Walkers[Assistive.getOption('walker')] ||
            Explorer.Walkers['dummy'];
      Explorer.walker = new constructor(math, speechGenerator);
      Explorer.GetHighlighter(.2);
      Explorer.walker.activate();
      if (Assistive.getOption('generateSpeech') &&
          Assistive.getOption('speech')) {
        if (Assistive.getOption('subtitle')) {
          Explorer.liveRegion.Show(math, Explorer.highlighter);
        }
        Explorer.liveRegion.Update(Explorer.walker.speech());
      }
      Explorer.Highlight();
    },
    //
    // Deactivates the walker.
    //
    DeactivateWalker: function() {
      Explorer.liveRegion.Clear();
      Explorer.liveRegion.Hide();
      Explorer.Unhighlight();
      Explorer.currentHighlight = null;
      Explorer.walker.deactivate();
      Explorer.walker = null;
    },
    //
    // Highlights the focused nodes.
    //
    Highlight: function() {
      Explorer.Unhighlight();
      Explorer.highlighter.highlight(Explorer.walker.getFocus().getNodes());
    },
    //
    // Unhighlights the old nodes.
    //
    Unhighlight: function() {
      Explorer.highlighter.unhighlight();
    },
    //
    // Plays the earcon.
    //
    // Every time we make new Audio element, as some browsers do not allow to
    // play audio elements more than once (e.g., Safari).
    //
    PlayEarcon: function() {
      var audio = new Audio(Explorer.earconFile);
      audio.play();
    },
    //
    // Regenerates speech.
    //
    Regenerate: function() {
      Explorer.Reset();
      var speechItems = ['SpeechOutput', 'Subtitles'];
      speechItems.forEach(
        function(x) {
          var item = MathJax.Menu.menu.FindId('Accessibility', x);
          if (item) {
            item.disabled = !item.disabled;
          }});
      for (var i = 0, all = MathJax.Hub.getAllJax(), jax; jax = all[i]; i++) {
        if (jax.enriched) {
          MathJax.Hub.Queue(['Reprocess', jax]);
        }
      }
    }
  };

  MathJax.Extension.Assistive.addDefaults();

  MathJax.Hub.Register.StartupHook('MathMenu Ready', function() {
    var ITEM = MathJax.Menu.ITEM;
    var accessibilityMenu =
          ITEM.SUBMENU(['Accessibility', 'Accessibilty'],
              ITEM.SUBMENU(['Walker', 'Walker'],
                  ITEM.RADIO(['dummy', 'No walker'], 'Assistive-walker'),
                  ITEM.RADIO(['syntactic', 'Syntax walker'], 'Assistive-walker'),
                  ITEM.RADIO(['semantic', 'Semantic walker'], 'Assistive-walker')
                          ),
              ITEM.SUBMENU(['Highlight', 'Highlight'],
                           ITEM.RADIO(['none', 'None'], 'Assistive-highlight', {action: Explorer.Reset}),
                           ITEM.RADIO(['hover', 'Hover'], 'Assistive-highlight', {action: Explorer.Reset}),
                           ITEM.RADIO(['flame','Flame'], 'Assistive-highlight', {action: Explorer.Reset})
                          ),
              ITEM.SUBMENU(['Background', 'Background'],
                           ITEM.RADIO(['blue','Blue'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['red','Red'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['green','Green'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['yellow','Yellow'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['cyan','Cyan'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['magenta','Magenta'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['white','White'], 'Assistive-background', {action: Explorer.Reset}),
                           ITEM.RADIO(['black','Black'], 'Assistive-background', {action: Explorer.Reset})
                          ),
              ITEM.SUBMENU(['Foreground', 'Foreground'],
                           ITEM.RADIO(['black','Black'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['white','White'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['magenta','Magenta'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['cyan','Cyan'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['yellow','Yellow'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['green','Green'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['red','Red'], 'Assistive-foreground', {action: Explorer.Reset}),
                           ITEM.RADIO(['blue','Blue'], 'Assistive-foreground', {action: Explorer.Reset})
                          ),
                       ITEM.RULE(),
                       ITEM.CHECKBOX(['GenerateSpeech', 'Generate Speech'], 'Assistive-generateSpeech',
                                     {action: Explorer.Regenerate}),
                       ITEM.CHECKBOX(['SpeechOutput', 'Speech Output'], 'Assistive-speech',
                                     {disabled: !SETTINGS['Assistive-generateSpeech']}),
                       ITEM.CHECKBOX(['Subtitles', 'Subtitles'], 'Assistive-subtitle',
                                     {disabled: !SETTINGS['Assistive-generateSpeech']})
                      );
    // Attaches the menu;
    var about = MathJax.Menu.menu.IndexOfId('About');
    if (about === null) {
      MathJax.Menu.menu.items.push(ITEM.RULE(), accessibilityMenu);
      return;
    }
    MathJax.Menu.menu.items.splice(about, 0, accessibilityMenu, ITEM.RULE());
  });

  MathJax.Hub.Register.MessageHook('New Math', ['Register', MathJax.Extension.Assistive.Explorer]);

  MathJax.Hub.Startup.signal.Post("Explorer Ready");
});

MathJax.Ajax.loadComplete("[RespEq]/Assistive-Explore.js");
<|endoftext|>


<commit_before>var getAllRoutes = require('wayfarer/get-all-routes')

module.exports.is = function (app) {
  return Boolean(app &&
    app.router &&
    app.router.router &&
    app.router.router._trie)
}

module.exports.listRoutes = function (app) {
  var keys = getAllRoutes(app.router.router)
  if (keys['/:']) delete keys['/:'] // Server rendering partials is tricky.
  return Object.keys(keys)
}

// Do a double render pass - the first time around we wait for promises to be
// pushed into `state._experimental_prefetch`. Once all promises resolve, we
// take the state, and do a second render pass with the new state.
//
// In Nanocomponent, people should do a conditional call to render this.
//
// ## Example
//
// ```js
// class Button extends Nanocomponent {
//   constructor (name, state, emit) {
//     super(name)
//     this.state = state
//     this.emit = emit
//     this.local = this.state.components[name] = {
//       loaded: false // This is set on the global "state" object.
//     }
//   }
//
//   render () {
//     if (!this.local.loaded) {
//       this.state._experimental_prefetch.push(this.fetch())
//     }
//
//     html`<button>
//       ${this.local.loaded ? 'loaded' : 'not loaded'
//     </button>`
//   }
//
//   update () {
//     return true
//   }
//
//   async fetch () {
//     this.local.loaded = true // async functions return promises
//   }
// }
// ```
//
// NOTE: state is never passed in it seems. Funky fn signature, this should be
// fixed.
//
// NOTE: Choo currently doesn't use the passed-in state as the base. It probably
// should, so we can treat the state as the only stateful bits, and the rest is
// just context.

module.exports.render = function (app, route, cb) {
  var state = {}
  state._experimental_prefetch = []
  app.toString(route, state)

  // TODO: replace with p-wait-all, once it knows how to handle an empty array.
  Promise.all(state._experimental_prefetch)
    .then(render, render)

  function render () {
    var body = app.toString(route, state)
    delete state._experimental_prefetch // State needs to be serializable.
    var res = { state: state }
    if (body) res.body = body
    if (app.state.title) res.title = app.state.title
    if (app.state.language) res.language = app.state.language
    if (app.selector) res.selector = app.selector
    cb(null, res)
  }
}
<commit_msg>Exclude all choo routes with partials (#445)<commit_after>var getAllRoutes = require('wayfarer/get-all-routes')

module.exports.is = function (app) {
  return Boolean(app &&
    app.router &&
    app.router.router &&
    app.router.router._trie)
}

module.exports.listRoutes = function (app) {
  var keys = getAllRoutes(app.router.router)
  return Object.keys(keys).filter(function (key) {
    return !/\/:/.test(key) // Server rendering partials is tricky.
  })
}

// Do a double render pass - the first time around we wait for promises to be
// pushed into `state._experimental_prefetch`. Once all promises resolve, we
// take the state, and do a second render pass with the new state.
//
// In Nanocomponent, people should do a conditional call to render this.
//
// ## Example
//
// ```js
// class Button extends Nanocomponent {
//   constructor (name, state, emit) {
//     super(name)
//     this.state = state
//     this.emit = emit
//     this.local = this.state.components[name] = {
//       loaded: false // This is set on the global "state" object.
//     }
//   }
//
//   render () {
//     if (!this.local.loaded) {
//       this.state._experimental_prefetch.push(this.fetch())
//     }
//
//     html`<button>
//       ${this.local.loaded ? 'loaded' : 'not loaded'
//     </button>`
//   }
//
//   update () {
//     return true
//   }
//
//   async fetch () {
//     this.local.loaded = true // async functions return promises
//   }
// }
// ```
//
// NOTE: state is never passed in it seems. Funky fn signature, this should be
// fixed.
//
// NOTE: Choo currently doesn't use the passed-in state as the base. It probably
// should, so we can treat the state as the only stateful bits, and the rest is
// just context.

module.exports.render = function (app, route, cb) {
  var state = {}
  state._experimental_prefetch = []
  app.toString(route, state)

  // TODO: replace with p-wait-all, once it knows how to handle an empty array.
  Promise.all(state._experimental_prefetch)
    .then(render, render)

  function render () {
    var body = app.toString(route, state)
    delete state._experimental_prefetch // State needs to be serializable.
    var res = { state: state }
    if (body) res.body = body
    if (app.state.title) res.title = app.state.title
    if (app.state.language) res.language = app.state.language
    if (app.selector) res.selector = app.selector
    cb(null, res)
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';

const style = {
  backgroundColor: 'white',
  margin: 5,
  borderStyle: 'solid',
  borderColor: 'black',
  height: 100,
  width: 100,
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  fontSize: 50,
};

const coveredStyle = {
  backgroundColor: 'black',
  margin: 5,
  height: 100,
  width: 100,
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  fontSize: 50,
};

const Tile = (props) => {
  let tile;

  if (props.tileState.covered) {
    const icon = ;
    tile =
{icon}
;
  }
  else {
    const icon = ;
    tile =
{icon}
;
  }

  return tile;
};

Tile.propTypes = {
  tileIndex: PropTypes.number.isRequired,
  tileState: PropTypes.shape({
    icon: PropTypes.string.isRequired,
    color: PropTypes.string.isRequired,
    covered: PropTypes.bool.isRequired,
    matched: PropTypes.bool.isRequired,
  }).isRequired,
};
export default Tile;
<commit_msg>refactor covered tile styling<commit_after>import React from 'react';
import PropTypes from 'prop-types';

const style = {
  backgroundColor: 'white',
  borderColor: 'black',
  borderStyle: 'solid',
  margin: 5,
  height: 100,
  width: 100,
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  fontSize: 50,
};

const Tile = (props) => {
  let tile;

  if (props.tileState.covered) {
    style.backgroundColor = 'black';
    const icon = ;
    tile =
{icon}
;
  }
  else {
    style.backgroundColor = props.tileState.color;
    const icon = ;
    tile =
{icon}
;
  }

  return tile;
};

Tile.propTypes = {
  tileIndex: PropTypes.number.isRequired,
  tileState: PropTypes.shape({
    icon: PropTypes.string.isRequired,
    color: PropTypes.string.isRequired,
    covered: PropTypes.bool.isRequired,
    matched: PropTypes.bool.isRequired,
  }).isRequired,
};
export default Tile;
<|endoftext|>


<commit_before>import THREE from 'three';
import Mesh from './Mesh';

/**
 * A two-dimensional rectangular tile
 */
export default class Tile extends Mesh {

  /**
   * @param x Width
   * @param z Length
   */
  constructor(x = 1, z = 1) {
    super();
    this.size = {x, y: 1, z};

    // geometry
    var rectLength = z, rectWidth = x;

    var rectShape = new THREE.Shape();
    rectShape.moveTo(0, 0);
    rectShape.lineTo(0, rectWidth);
    rectShape.lineTo(rectLength, rectWidth);
    rectShape.lineTo(rectLength, 0);
    rectShape.lineTo(0, 0);

    let geometry = new THREE.ShapeGeometry(rectShape);
    geometry.rotateX(90 * Math.PI / 180);
    geometry.rotateY(-90 * Math.PI / 180);
    geometry.rotateZ(180 * Math.PI / 180);

    // material
    let material = new THREE.MeshLambertMaterial({
      vertexColors: THREE.FaceColors,
    });

    this.threeMesh = new THREE.Mesh(geometry, material);
    this.color(new Iso.Color('red'));
    this.position(this.xyz);

    // shadow
    this.threeMesh.castShadow = true;
    this.threeMesh.receiveShadow = true;
  }

  /**
   * Set the position
   * Either pass {x, y, z} or (x, y, z) tuple
   * @returns {Tile}
   */
  position(x, y, z):Mesh {
    let xyz = (arguments.length === 3) ? {x, y, z} : x;
    this.xyz = xyz;

    this.threeMesh.position.set(
      xyz.x,
      xyz.y,
      xyz.z
    );
    return this;
  }

  /**
   * Set the color
   * @param {THREE.Color} color
   * @returns {Tile}
   */
  color(color:THREE.Color):Tile {
    for (let i = 0; i < this.threeMesh.geometry.faces.length; ++i) {
      this.threeMesh.geometry.faces[i].color.set(color);
    }
    this.threeMesh.geometry.colorsNeedUpdate = true;
    return this;
  }

  /**
   * Set the opacity
   * @param opacity
   * @returns {Tile}
   */
  opacity(opacity:number):Tile {
    //this.threeMesh.material.transparent = true;
    //this.threeMesh.material.opacity = opacity;
    return this;
  }
}<commit_msg>Add double-sidedness to tiles<commit_after>import THREE from 'three';
import Mesh from './Mesh';

/**
 * A two-dimensional rectangular tile
 */
export default class Tile extends Mesh {

  /**
   * @param x Width
   * @param z Length
   */
  constructor(x = 1, z = 1) {
    super();
    this.size = {x, y: 1, z};

    // geometry
    var rectLength = z, rectWidth = x;

    var rectShape = new THREE.Shape();
    rectShape.moveTo(0, 0);
    rectShape.lineTo(0, rectWidth);
    rectShape.lineTo(rectLength, rectWidth);
    rectShape.lineTo(rectLength, 0);
    rectShape.lineTo(0, 0);

    let geometry = new THREE.ShapeGeometry(rectShape);
    geometry.rotateX(90 * Math.PI / 180);
    geometry.rotateY(-90 * Math.PI / 180);
    geometry.rotateZ(180 * Math.PI / 180);

    // material
    let material = new THREE.MeshLambertMaterial({
      vertexColors: THREE.FaceColors,
      side: THREE.DoubleSide,
    });

    this.threeMesh = new THREE.Mesh(geometry, material);
    this.color(new Iso.Color('red')); // default color
    this.position(this.xyz);

    // shadow
    this.threeMesh.castShadow = true;
    this.threeMesh.receiveShadow = true;
  }

  /**
   * Set the position
   * Either pass {x, y, z} or (x, y, z) tuple
   * @returns {Tile}
   */
  position(x, y, z):Tile {
    let xyz = (arguments.length === 3) ? {x, y, z} : x;
    this.xyz = xyz;

    this.threeMesh.position.set(
      xyz.x,
      xyz.y,
      xyz.z
    );
    return this;
  }

  /**
   * Sets the visibility of each side of the tile. Double-sided by default.
   * @param isDoubleSided Viewable by both sides?
   */
  doubleSided(isDoubleSided:boolean):Tile {
    if (isDoubleSided) {
      this.threeMesh.material.side = THREE.DoubleSide;
    } else {
      this.threeMesh.material.side = THREE.FrontSide;
    }
  }

  /**
   * Set the color
   * @param {THREE.Color} color
   * @returns {Tile}
   */
  color(color:THREE.Color):Tile {
    for (let i = 0; i < this.threeMesh.geometry.faces.length; ++i) {
      this.threeMesh.geometry.faces[i].color.set(color);
    }
    this.threeMesh.geometry.colorsNeedUpdate = true;
    return this;
  }

  /**
   * Set the opacity
   * @param opacity
   * @returns {Tile}
   */
  opacity(opacity:number):Tile {
    this.threeMesh.material.transparent = true;
    this.threeMesh.material.opacity = opacity;
    return this;
  }
}<|endoftext|>


<commit_before>/**
 *
 */

/**
 * This is just a constant.
 * You can attach interactive playgrounds with the @playground tag.
 * You can require any npm module and write really programs.
 *
 * @constant {string}
 * @default
 *
 * @playground
 * // Testing tonicdev
 * var numbers = require('numbers')
 * var x = numbers.calculus.Riemann(Math.sin, -2, 4, 200)
 * x++
 */
var greet = 'Hello folks!'

/**
 * @constant {Object}
 * @default
 */
var config = {
  company: 'ACME TM'
}

/**
 * Super useful function.
 * @function
 */
var superFunc = function () {}

module.exports = {
  funny: require('./funny'),
  heavy: require('./heavy'),
  greet: greet
}
<commit_msg>extend example<commit_after>/**
 *
 */

/**
 * This is just a constant.
 * You can attach interactive playgrounds with the @playground tag.
 * You can require any npm module and write real programs.
 *
 * @constant {string}
 * @default
 *
 * @playground
 * // Testing tonicdev
 * var numbers = require('numbers')
 * var x = numbers.calculus.Riemann(Math.sin, -2, 4, 200)
 * x++
 */
var greet = 'Hello folks!'

/**
 * @constant {Object}
 * @default
 */
var config = {
  company: 'ACME TM'
}

/**
 * Super useful function.
 * @function
 */
var superFunc = function () {}

module.exports = {
  funny: require('./funny'),
  heavy: require('./heavy'),
  greet: greet
}
<|endoftext|>


<commit_before>import Rx from "rx";

/**
 *
 * Derived from RxJS-DOM, Copyright (c) Microsoft Open Technologies, Inc:
 *
 * https://github.com/Reactive-Extensions/RxJS-DOM
 *
 * The original source file can be viewed here:
 *
 * https://github.com/Reactive-Extensions/RxJS-DOM/blob/fdb169c8bd1612318d530e6e54074b1c9e537906/src/ajax.js
 *
 * Licensed under the Apache License, Version 2.0:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Modifications from original:
 *
 * - extracted from "Rx.DOM" namespace
 * - minor eslinter cleanup ("var" to "let" etc)
 * - addition of "auto" responseType
 *
 */

var root = window;

// Gets the proper XMLHttpRequest for support for older IE
function getXMLHttpRequest() {
  if (root.XMLHttpRequest) {
    return new root.XMLHttpRequest();
  } else {
    let progId;
    try {
      let progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
      for(let i = 0; i < 3; i++) {
        try {
          progId = progIds[i];
          if (new root.ActiveXObject(progId)) {
            break;
          }
        } catch(e) { }
      }
      return new root.ActiveXObject(progId);
    } catch (e) {
      throw new Error('XMLHttpRequest is not supported by your browser');
    }
  }
}

// Get CORS support even for older IE
function getCORSRequest() {
  var xhr = new root.XMLHttpRequest();
  if ('withCredentials' in xhr) {
    return xhr;
  } else if (!!root.XDomainRequest) {
    return new XDomainRequest();
  } else {
    throw new Error('CORS is not supported by your browser');
  }
}

function normalizeAjaxSuccessEvent(e, xhr, settings) {
  var response = ('response' in xhr) ? xhr.response : xhr.responseText;
  if (settings.responseType === 'auto') {
    try {
      response = JSON.parse(response);
    } catch (e) {}
  } else {
    response = settings.responseType === 'json' ? JSON.parse(response) : response;
  }
  return {
    response: response,
    status: xhr.status,
    responseType: xhr.responseType,
    xhr: xhr,
    originalEvent: e
  };
}

function normalizeAjaxErrorEvent(e, xhr, type) {
  return {
    type: type,
    status: xhr.status,
    xhr: xhr,
    originalEvent: e
  };
}

/**
 * Creates an observable for an Ajax request with either a settings object with url, headers, etc or a string for a URL.
 *
 * @example
 *   source = ajax('/products');
 *   source = ajax({ url: 'products', method: 'GET' });
 *
 * @param {Object} settings Can be one of the following:
 *
 *  A string of the URL to make the Ajax call.
 *  An object with the following properties
 *   - url: URL of the request
 *   - body: The body of the request
 *   - method: Method of the request, such as GET, POST, PUT, PATCH, DELETE
 *   - async: Whether the request is async
 *   - headers: Optional headers
 *   - crossDomain: true if a cross domain request, else false
 *   - responseType: "text" (default), "json" or "auto"
 *
 * @returns {Observable} An observable sequence containing the XMLHttpRequest.
*/
export default function (options) {
  var settings = {
    method: 'GET',
    crossDomain: false,
    async: true,
    headers: {},
    responseType: 'text',
    createXHR: function(){
      return this.crossDomain ? getCORSRequest() : getXMLHttpRequest();
    },
    normalizeError: normalizeAjaxErrorEvent,
    normalizeSuccess: normalizeAjaxSuccessEvent
  };

  if(typeof options === 'string') {
    settings.url = options;
  } else {
    for(let prop in options) {
      if(hasOwnProperty.call(options, prop)) {
        settings[prop] = options[prop];
      }
    }
  }

  let normalizeError = settings.normalizeError;
  let normalizeSuccess = settings.normalizeSuccess;

  if (!settings.crossDomain && !settings.headers['X-Requested-With']) {
    settings.headers['X-Requested-With'] = 'XMLHttpRequest';
  }
  settings.hasContent = settings.body !== undefined;

  return new Rx.AnonymousObservable(function (observer) {
    var isDone = false;
    var xhr;

    var processResponse = function(xhr, e){
      var status = xhr.status === 1223 ? 204 : xhr.status;
      if ((status >= 200 && status <= 300) || status === 0 || status === '') {
        observer.onNext(normalizeSuccess(e, xhr, settings));
        observer.onCompleted();
      } else {
        observer.onError(normalizeError(e, xhr, 'error'));
      }
      isDone = true;
    };

    try {
      xhr = settings.createXHR();;
    } catch (err) {
      observer.onError(err);
    }

    try {
      if (settings.user) {
        xhr.open(settings.method, settings.url, settings.async, settings.user, settings.password);
      } else {
        xhr.open(settings.method, settings.url, settings.async);
      }

      let headers = settings.headers;
      for (let header in headers) {
        if (hasOwnProperty.call(headers, header)) {
          xhr.setRequestHeader(header, headers[header]);
        }
      }

      if(!!xhr.upload || (!('withCredentials' in xhr) && !!root.XDomainRequest)) {
        xhr.onload = function(e) {
          if(settings.progressObserver) {
            settings.progressObserver.onNext(e);
            settings.progressObserver.onCompleted();
          }
          processResponse(xhr, e);
        };

        if(settings.progressObserver) {
          xhr.onprogress = function(e) {
            settings.progressObserver.onNext(e);
          };
        }

        xhr.onerror = function(e) {
          if (settings.progressObserver) {
            settings.progressObserver.onError(e);
          }
          observer.onError(normalizeError(e, xhr, 'error'));
          isDone = true;
        };

        xhr.onabort = function(e) {
          if (settings.progressObserver) {
            settings.progressObserver.onError(e);
          }
          observer.onError(normalizeError(e, xhr, 'abort'));
          isDone = true;
        };
      } else {

        xhr.onreadystatechange = function (e) {
          if (xhr.readyState === 4) {
            processResponse(xhr, e);
          }
        };
      }

      xhr.send(settings.hasContent && settings.body || null);
    } catch (e) {
      observer.onError(e);
    }

    return function () {
      if (!isDone && xhr.readyState !== 4) { xhr.abort(); }
    };
  });
};
<commit_msg>Fix problems with tests running in node.<commit_after>import Rx from "rx";

/**
 *
 * Derived from RxJS-DOM, Copyright (c) Microsoft Open Technologies, Inc:
 *
 * https://github.com/Reactive-Extensions/RxJS-DOM
 *
 * The original source file can be viewed here:
 *
 * https://github.com/Reactive-Extensions/RxJS-DOM/blob/fdb169c8bd1612318d530e6e54074b1c9e537906/src/ajax.js
 *
 * Licensed under the Apache License, Version 2.0:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Modifications from original:
 *
 * - extracted from "Rx.DOM" namespace
 * - minor eslinter cleanup ("var" to "let" etc)
 * - addition of "auto" responseType
 *
 */

var root = (typeof window !== "undefined" && window) || this;

// Gets the proper XMLHttpRequest for support for older IE
function getXMLHttpRequest() {
  if (root.XMLHttpRequest) {
    return new root.XMLHttpRequest();
  } else {
    let progId;
    try {
      let progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
      for(let i = 0; i < 3; i++) {
        try {
          progId = progIds[i];
          if (new root.ActiveXObject(progId)) {
            break;
          }
        } catch(e) { }
      }
      return new root.ActiveXObject(progId);
    } catch (e) {
      throw new Error('XMLHttpRequest is not supported by your browser');
    }
  }
}

// Get CORS support even for older IE
function getCORSRequest() {
  var xhr = new root.XMLHttpRequest();
  if ('withCredentials' in xhr) {
    return xhr;
  } else if (!!root.XDomainRequest) {
    return new XDomainRequest();
  } else {
    throw new Error('CORS is not supported by your browser');
  }
}

function normalizeAjaxSuccessEvent(e, xhr, settings) {
  var response = ('response' in xhr) ? xhr.response : xhr.responseText;
  if (settings.responseType === 'auto') {
    try {
      response = JSON.parse(response);
    } catch (e) {}
  } else {
    response = settings.responseType === 'json' ? JSON.parse(response) : response;
  }
  return {
    response: response,
    status: xhr.status,
    responseType: xhr.responseType,
    xhr: xhr,
    originalEvent: e
  };
}

function normalizeAjaxErrorEvent(e, xhr, type) {
  return {
    type: type,
    status: xhr.status,
    xhr: xhr,
    originalEvent: e
  };
}

/**
 * Creates an observable for an Ajax request with either a settings object with url, headers, etc or a string for a URL.
 *
 * @example
 *   source = ajax('/products');
 *   source = ajax({ url: 'products', method: 'GET' });
 *
 * @param {Object} settings Can be one of the following:
 *
 *  A string of the URL to make the Ajax call.
 *  An object with the following properties
 *   - url: URL of the request
 *   - body: The body of the request
 *   - method: Method of the request, such as GET, POST, PUT, PATCH, DELETE
 *   - async: Whether the request is async
 *   - headers: Optional headers
 *   - crossDomain: true if a cross domain request, else false
 *   - responseType: "text" (default), "json" or "auto"
 *
 * @returns {Observable} An observable sequence containing the XMLHttpRequest.
*/
export default function (options) {
  var settings = {
    method: 'GET',
    crossDomain: false,
    async: true,
    headers: {},
    responseType: 'text',
    createXHR: function(){
      return this.crossDomain ? getCORSRequest() : getXMLHttpRequest();
    },
    normalizeError: normalizeAjaxErrorEvent,
    normalizeSuccess: normalizeAjaxSuccessEvent
  };

  if(typeof options === 'string') {
    settings.url = options;
  } else {
    for(let prop in options) {
      if(hasOwnProperty.call(options, prop)) {
        settings[prop] = options[prop];
      }
    }
  }

  let normalizeError = settings.normalizeError;
  let normalizeSuccess = settings.normalizeSuccess;

  if (!settings.crossDomain && !settings.headers['X-Requested-With']) {
    settings.headers['X-Requested-With'] = 'XMLHttpRequest';
  }
  settings.hasContent = settings.body !== undefined;

  return new Rx.AnonymousObservable(function (observer) {
    var isDone = false;
    var xhr;

    var processResponse = function(xhr, e){
      var status = xhr.status === 1223 ? 204 : xhr.status;
      if ((status >= 200 && status <= 300) || status === 0 || status === '') {
        observer.onNext(normalizeSuccess(e, xhr, settings));
        observer.onCompleted();
      } else {
        observer.onError(normalizeError(e, xhr, 'error'));
      }
      isDone = true;
    };

    try {
      xhr = settings.createXHR();;
    } catch (err) {
      observer.onError(err);
    }

    try {
      if (settings.user) {
        xhr.open(settings.method, settings.url, settings.async, settings.user, settings.password);
      } else {
        xhr.open(settings.method, settings.url, settings.async);
      }

      let headers = settings.headers;
      for (let header in headers) {
        if (hasOwnProperty.call(headers, header)) {
          xhr.setRequestHeader(header, headers[header]);
        }
      }

      if(!!xhr.upload || (!('withCredentials' in xhr) && !!root.XDomainRequest)) {
        xhr.onload = function(e) {
          if(settings.progressObserver) {
            settings.progressObserver.onNext(e);
            settings.progressObserver.onCompleted();
          }
          processResponse(xhr, e);
        };

        if(settings.progressObserver) {
          xhr.onprogress = function(e) {
            settings.progressObserver.onNext(e);
          };
        }

        xhr.onerror = function(e) {
          if (settings.progressObserver) {
            settings.progressObserver.onError(e);
          }
          observer.onError(normalizeError(e, xhr, 'error'));
          isDone = true;
        };

        xhr.onabort = function(e) {
          if (settings.progressObserver) {
            settings.progressObserver.onError(e);
          }
          observer.onError(normalizeError(e, xhr, 'abort'));
          isDone = true;
        };
      } else {

        xhr.onreadystatechange = function (e) {
          if (xhr.readyState === 4) {
            processResponse(xhr, e);
          }
        };
      }

      xhr.send(settings.hasContent && settings.body || null);
    } catch (e) {
      observer.onError(e);
    }

    return function () {
      if (!isDone && xhr.readyState !== 4) { xhr.abort(); }
    };
  });
};
<|endoftext|>


<commit_before>var BI = require('BigInt');
var Base = require('./base.js').getInstance(15);
var S = require('./strategy.js').getInstance(10);
var C = require('./couple.js');
var ID = require('./identifier.js');

/*!
 * \class LSEQArray
 *
 * \brief Distributed array using LSEQ allocation strategy
 */
function LSEQArray(s){
    this._s = s;
    this._c = 0;
    this._hash = function(depth) { return depth%2; };
//    this._hash = function(depth) { return 0; };

    this._array = []; // array of couples {_e: element, _i: identifier}
    this._array[0] = new C(null, new ID(BI.int2bigInt(0,Base.getSumBit(0)),
					[0], [0])); // lowest id
    this._array[1] = new C(null, new ID(BI.int2bigInt(Math.pow(2,Base._b+1)-1,
						      Base.getSumBit(0)),
					[Number.MAX_VALUE],
					[Number.MAX_VALUE])); // highest id
    this.length = 0;
};

/*!
 * \brief return the identifier and element at the targeted index
 * \param index the index of the couple in the array
 * \return a couple {_e: element, _i: identifier}
 */
LSEQArray.prototype.get = function(index){
    return this._array[index];
};

/*!
 * \brief insert a value at the targeted index
 * \param element the element to insert
 * \param index the position in the array
 * \return a couple {_e: element , _i: identifier}
 */
LSEQArray.prototype.insert = function(element, index){
    // #1 getting the bounds
    var pei = this.get(index);
    var qei = this.get(index+1);
    // #2 generating the identifier between the bound
    this._c += 1;
    var id = this.alloc(pei._i, qei._i);
    // #3 add it to the structure and return value
    var couple = {_e: element, _i: id}
    this.applyInsert(element, id);
    return couple;
};

/*!
 * \brief delete the element at the index
 * \param index the index of the element to delete in the array
 * \return the identifier of the element at the index
 */
LSEQArray.prototype.remove = function(index){
    var id = this.get(index+1)._i;
    this.applyRemove(id);
    return id;
};

/*!
 * \brief generate the digit part of the identifiers  between p and q
 * \param p the digit part of the previous identifier
 * \param q the digit part of the next identifier
 * \return the digit part located between p and q
 */
LSEQArray.prototype.alloc = function (p,q){
    // #1 process the level of the new identifier
    var interval = BI.int2bigInt(0,Base.getBitBase(0));
    var level = 0;
    while ( BI.isZero(interval) || BI.negative(interval) ){
	// no room for insertions
	interval = Base.getInterval(p, q, level);
	++level;
    };
    level -=1;
    var id = null;
    if (this._hash(level) == 0){
	id = S.bPlus(p,q,level,interval, this._s, this._c);
    } else {
	id = S.bMinus(p,q,level,interval, this._s, this._c);
    };
    return id;
};

/*!
 * \brief insert an element created from a remote site into the array
 * \param e the element to insert
 * \param i the identifier of the element
 * \return the index of the newly inserted element in the array
 */
LSEQArray.prototype.applyInsert = function(e, i){
    if (!(i instanceof ID)){ // convert
	i = new ID(i._d, i._s, i._c);
    };
    var couple = new C(e, i);
    // #1 binarysearch of the identifier
    var position = this._array.binaryIndexOf(couple)
    // #2 insert in the rightfull position
    if (position<0){ // it does not exists yet
	position = Math.abs(position);
	this._array.splice(position,0, couple);
	this.length += 1;
	return position;
    };
    return -1; // It already exists
};

/*!
 * \brief delete the element with the targeted identifier
 * \param i the identifier of the element
 * \return the index of the element feshly deleted
 */
LSEQArray.prototype.applyRemove = function(i){
    if (!(i instanceof ID)){
	i = new ID(i._d, i._s, i._c);
    };
    var couple = new C(null, i);
    // #1 binarysearch of the identifier
    var position = this._array.binaryIndexOf(couple);
    // #2 if exists then delete
    if (position > 0){ // the element exists
	this._array.splice(position,1);
	this.length -= 1;
	return position;
    };
    return -1; // Nothing has been deleted
};

/**
 * \from: [https://gist.github.com/Wolfy87/5734530]
 * Performs a binary search on the host array. This method can either be
 * injected into Array.prototype or called with a specified scope like this:
 * binaryIndexOf.call(someArray, searchElement);
 *
 *
 * @param {*} searchElement The item to search for within the array.
 * @return {Number} The index of the element which defaults to -1 when not
 * found.
 */
Array.prototype.binaryIndexOf = function(searchElement) {
    var minIndex = 0;
    var maxIndex = this.length - 1;
    var currentIndex;
    var currentElement;

    while (minIndex <= maxIndex) {
	currentIndex = Math.floor((minIndex + maxIndex) / 2);
	currentElement = this[currentIndex];
	if (currentElement.compare(searchElement) < 0) {
            minIndex = currentIndex + 1;
	}
	else if (currentElement.compare(searchElement) > 0) {
            maxIndex = currentIndex - 1;
	}
	else {
            return currentIndex;
	}
    };
    return ~maxIndex;
};

module.exports = LSEQArray;
<commit_msg>minor change on upper bound<commit_after>var BI = require('BigInt');
var Base = require('./base.js').getInstance(15);
var S = require('./strategy.js').getInstance(10);
var C = require('./couple.js');
var ID = require('./identifier.js');

/*!
 * \class LSEQArray
 *
 * \brief Distributed array using LSEQ allocation strategy
 */
function LSEQArray(s){
    this._s = s;
    this._c = 0;
    this._hash = function(depth) { return depth%2; };
//    this._hash = function(depth) { return 0; };

    this._array = []; // array of couples {_e: element, _i: identifier}
    this._array[0] = new C(null, new ID(BI.int2bigInt(0,Base.getSumBit(0)),
					[0], [0])); // lowest id
    this._array[1] = new C(null, new ID(BI.int2bigInt(Math.pow(2,Base._b)-1,
						      Base.getSumBit(0)),
					[Number.MAX_VALUE],
					[Number.MAX_VALUE])); // highest id
    this.length = 0;
};

/*!
 * \brief return the identifier and element at the targeted index
 * \param index the index of the couple in the array
 * \return a couple {_e: element, _i: identifier}
 */
LSEQArray.prototype.get = function(index){
    return this._array[index];
};

/*!
 * \brief insert a value at the targeted index
 * \param element the element to insert
 * \param index the position in the array
 * \return a couple {_e: element , _i: identifier}
 */
LSEQArray.prototype.insert = function(element, index){
    // #1 getting the bounds
    var pei = this.get(index);
    var qei = this.get(index+1);
    // #2 generating the identifier between the bound
    this._c += 1;
    var id = this.alloc(pei._i, qei._i);
    // #3 add it to the structure and return value
    var couple = {_e: element, _i: id}
    this.applyInsert(element, id);
    return couple;
};

/*!
 * \brief delete the element at the index
 * \param index the index of the element to delete in the array
 * \return the identifier of the element at the index
 */
LSEQArray.prototype.remove = function(index){
    var id = this.get(index+1)._i;
    this.applyRemove(id);
    return id;
};

/*!
 * \brief generate the digit part of the identifiers  between p and q
 * \param p the digit part of the previous identifier
 * \param q the digit part of the next identifier
 * \return the digit part located between p and q
 */
LSEQArray.prototype.alloc = function (p,q){
    // #1 process the level of the new identifier
    var interval = BI.int2bigInt(0,Base.getBitBase(0));
    var level = 0;
    while ( BI.isZero(interval) || BI.negative(interval) ){
	// no room for insertions
	interval = Base.getInterval(p, q, level);
	++level;
    };
    level -=1;
    var id = null;
    if (this._hash(level) == 0){
	id = S.bPlus(p,q,level,interval, this._s, this._c);
    } else {
	id = S.bMinus(p,q,level,interval, this._s, this._c);
    };
    return id;
};

/*!
 * \brief insert an element created from a remote site into the array
 * \param e the element to insert
 * \param i the identifier of the element
 * \return the index of the newly inserted element in the array
 */
LSEQArray.prototype.applyInsert = function(e, i){
    if (!(i instanceof ID)){ // convert
	i = new ID(i._d, i._s, i._c);
    };
    var couple = new C(e, i);
    // #1 binarysearch of the identifier
    var position = this._array.binaryIndexOf(couple)
    // #2 insert in the rightfull position
    if (position<0){ // it does not exists yet
	position = Math.abs(position);
	this._array.splice(position,0, couple);
	this.length += 1;
	return position;
    };
    return -1; // It already exists
};

/*!
 * \brief delete the element with the targeted identifier
 * \param i the identifier of the element
 * \return the index of the element feshly deleted
 */
LSEQArray.prototype.applyRemove = function(i){
    if (!(i instanceof ID)){
	i = new ID(i._d, i._s, i._c);
    };
    var couple = new C(null, i);
    // #1 binarysearch of the identifier
    var position = this._array.binaryIndexOf(couple);
    // #2 if exists then delete
    if (position > 0){ // the element exists
	this._array.splice(position,1);
	this.length -= 1;
	return position;
    };
    return -1; // Nothing has been deleted
};

/**
 * \from: [https://gist.github.com/Wolfy87/5734530]
 * Performs a binary search on the host array. This method can either be
 * injected into Array.prototype or called with a specified scope like this:
 * binaryIndexOf.call(someArray, searchElement);
 *
 *
 * @param {*} searchElement The item to search for within the array.
 * @return {Number} The index of the element which defaults to -1 when not
 * found.
 */
Array.prototype.binaryIndexOf = function(searchElement) {
    var minIndex = 0;
    var maxIndex = this.length - 1;
    var currentIndex;
    var currentElement;

    while (minIndex <= maxIndex) {
	currentIndex = Math.floor((minIndex + maxIndex) / 2);
	currentElement = this[currentIndex];
	if (currentElement.compare(searchElement) < 0) {
            minIndex = currentIndex + 1;
	}
	else if (currentElement.compare(searchElement) > 0) {
            maxIndex = currentIndex - 1;
	}
	else {
            return currentIndex;
	}
    };
    return ~maxIndex;
};

module.exports = LSEQArray;
<|endoftext|>


<commit_before>
let r = require('r-dom')
let mori = require('mori')
let PropTypes = require('react').PropTypes
let ShallowComponent = require('./shallow-component')

let Thumbnail = require('./game-cell/thumbnail')
let MainAction = require('./game-cell/main-action')
let SecondaryActions = require('./game-cell/secondary-actions')

let platform_data = require('../constants/platform-data')
let platform = require('../util/os').itch_platform()

/* before you think you can download all itch.io games:
there's obviously server-side checking.
you'll get neat error logs for free though! */
let may_download_all = (process.env.TRUST_ME_IM_AN_ENGINEER === '1')

class GameCell extends ShallowComponent {
  render () {
    let owned = this.props.owned
    let game = this.props.game
    let cave = this.props.cave

    let min_price = mori.get(game, 'min_price')
    let free = (min_price === 0)

    let may_download = may_download_all || owned || free

    let platform_compatible = false
    for (let platform_spec of platform_data) {
      if (platform === platform_spec.platform) {
        platform_compatible = !!mori.get(game, platform_spec.field)
      }
    }

    let children = []

    children.push(r(Thumbnail, {cave, game}))

    let title = mori.get(game, 'title')
    children.push(r.div({className: 'game_title'}, title))

    let user = mori.get(game, 'user')
    if (user) {
      r.div({className: 'game_author'}, user.display_name)
    }

    children.push(r(MainAction, {cave, game, platform_compatible, may_download}))

    children.push(r(SecondaryActions, {cave, game, may_download}))

    return r.div({className: 'game_cell'}, children)
  }
}

GameCell.propTypes = {
  game: PropTypes.object,
  cave: PropTypes.object
}

module.exports = GameCell
<commit_msg>:art: Use mori-ext in GameCell component #412<commit_after>
import {get} from 'mori-ext'

let r = require('r-dom')
let PropTypes = require('react').PropTypes
let ShallowComponent = require('./shallow-component')

let Thumbnail = require('./game-cell/thumbnail')
let MainAction = require('./game-cell/main-action')
let SecondaryActions = require('./game-cell/secondary-actions')

let platform_data = require('../constants/platform-data')
let platform = require('../util/os').itch_platform()

/* before you think you can download all itch.io games:
there's obviously server-side checking.
you'll get neat error logs for free though! */
let may_download_all = (process.env.TRUST_ME_IM_AN_ENGINEER === '1')

class GameCell extends ShallowComponent {
  render () {
    let owned = this.props.owned
    let game = this.props.game
    let cave = this.props.cave

    let min_price = game::get('min_price')
    let free = (min_price === 0)

    let may_download = may_download_all || owned || free

    let platform_compatible = false
    for (let platform_spec of platform_data) {
      if (platform === platform_spec.platform) {
        platform_compatible = !!game::get(platform_spec.field)
      }
    }

    let children = []

    children.push(r(Thumbnail, {cave, game}))

    let title = game::get('title')
    children.push(r.div({className: 'game_title'}, title))

    let user = game::get('user')
    if (user) {
      r.div({className: 'game_author'}, user.display_name)
    }

    children.push(r(MainAction, {cave, game, platform_compatible, may_download}))

    children.push(r(SecondaryActions, {cave, game, may_download}))

    return r.div({className: 'game_cell'}, children)
  }
}

GameCell.propTypes = {
  game: PropTypes.object,
  cave: PropTypes.object
}

module.exports = GameCell
<|endoftext|>


<commit_before>define([
  'dojo/_base/declare',
  'dijit/form/ValidationTextBox',

  'hotplate/hotDojoWidgets/_AjaxValidatorMixin',
  'hotplate/hotDojoStores/stores',
  ], function(
    declare

  , ValidationTextBox
  , _AjaxValidatorMixin
  , stores
  ){
    var Validators = sharedFunctions.hotCoreCommonValidators;
    return declare('hotplate.hotDojoAuth.ValidationUsername',  [ ValidationTextBox, _AjaxValidatorMixin ], {

      ajaxOkWhen: 'present',
      ajaxInvalidMessage: 'Ajax check failed',

      validator: function(value){

        // Run the normal field validators -- if they fail,
        // return false
        var validation =  Validators.login(value);
        if( ! validation ){
          this.invalidMessage = Validators.login(false);
          return false;
        }

        return this.ajaxValidate(value, {
           ajaxInvalidMessage: this.ajaxInvalidMessage,
           ajaxStore: stores('usersAnon'),
           ajaxFilterField: 'login',
           ajaxOkWhen: this.ajaxOkWhen,
        });

      },

      invalidMessage: Validators.login(false),
      missingMessage: Validators.notEmptyString(false),

    });
  }
);
<commit_msg>Formatting fixes<commit_after>define([
  'dojo/_base/declare',
  'dijit/form/ValidationTextBox',

  'hotplate/hotDojoWidgets/_AjaxValidatorMixin',
  'hotplate/hotDojoStores/stores',
  ], function(
    declare

  , ValidationTextBox
  , _AjaxValidatorMixin
  , stores
  ){
    var Validators = sharedFunctions.hotCoreCommonValidators;
    return declare('hotplate/hotDojoAuth/ValidationUsername',  [ ValidationTextBox, _AjaxValidatorMixin ], {

      ajaxOkWhen: 'present',
      ajaxInvalidMessage: 'Ajax check failed',

      validator: function( value ){

        // Run the normal field validators -- if they fail,
        // return false
        var validation =  Validators.login( value );
        if( ! validation ){
          this.invalidMessage = Validators.login( false );
          return false;
        }

        return this.ajaxValidate(value, {
           ajaxInvalidMessage: this.ajaxInvalidMessage,
           ajaxStore: stores('userLogins'),
           ajaxFilterField: 'login',
           ajaxOkWhen: this.ajaxOkWhen,
        });

      },

      invalidMessage: Validators.login(false),
      missingMessage: Validators.notEmptyString(false),

    });
  }
);
<|endoftext|>