<commit_before>import React, { Component, PropTypes, } from 'react';
import { Button, Select, } from 're-bulma';

const propTypes = {
  onClick: PropTypes.string,
  buttonProps: PropTypes.object,
  spanProps: PropTypes.object,
  style: PropTypes.object,
  onclickProps:PropTypes.any,
};

const defaultProps = {
  // onClick: '/',
  style: {},
};

class ResponsiveButton extends Component {
  // constructor(props) {
  //   super(props);
  // }
  getButtonLink(baseurl, params, prop) {
    // console.debug({ baseurl, params, prop });
    let returnLink = baseurl;
    try {
      if (params && params.length > 0) {
        params.forEach((param) => {
          returnLink = returnLink.replace(param.key, prop[ param.val ]);
        });
      }
    } catch (e) {
      console.debug(e, { baseurl, params, prop, });
    }
    return returnLink;
  }
  getHref(options) {
    let { thisDotProp, clickThisProp, clickPropObject, clickBaseUrl, clickLinkParams, clickPassProps, /*clickprop, clickFetchProps, clickSuccessProps, */ } = options;
    // console.debug('getHref',{options})
    let linkSelectionProp = (clickThisProp)
      ? thisDotProp[clickThisProp]
      : clickPropObject;
    let onclickProp = (clickBaseUrl)
      ? this.getButtonLink(clickBaseUrl, clickLinkParams, linkSelectionProp)
      : clickPassProps;
    return onclickProp;
  }
  handleOnClick(options) {
    // console.debug({ options });
    let { clickprop, thisDotProp, clickThisProp, clickPropObject, clickBaseUrl, clickLinkParams, clickPassProps, clickFetchProps, clickSuccessProps, } = options;
    let onclickFunction = (data) => {
      console.debug('ResponsiveButton', { data, });
    };
    let linkSelectionProp = (clickThisProp)
      ? thisDotProp[clickThisProp]
      : clickPropObject;
    let onclickProp = (clickBaseUrl)
      ? this.getButtonLink(clickBaseUrl, clickLinkParams, linkSelectionProp)
      : clickPassProps;

    if (typeof clickprop === 'string' && clickprop.indexOf('func:this.props.reduxRouter') !== -1) {
      onclickFunction = this.props.reduxRouter[ clickprop.replace('func:this.props.reduxRouter.', '') ];
    } else if (typeof clickprop === 'string' && clickprop.indexOf('func:this.funcs') !== -1) {
      onclickFunction = this.funcs[ clickprop.replace('func:this.funcs.', '') ];
    } else if (typeof clickprop === 'string' && clickprop.indexOf('func:window') !== -1) {
      onclickFunction = window[ clickprop.replace('func:window.', '') ].bind(this);
    } else if (typeof clickprop === 'string' && clickprop.indexOf('func:this.props') !== -1) {
      // console.debug('this.props', this.props);
      onclickFunction = this.props[ clickprop.replace('func:this.props.', '') ];
    } else if (typeof clickprop === 'function') {
      onclickFunction = clickprop;
    }
    // onclickFunction = onclickFunction.bind(this);
    if (this.props.confirmModal) {
      return this.props.createModal(Object.assign({
        title: 'Please Confirm',
        text: {
          component: 'div',
          props: {
            style: {
              textAlign: 'center',
            },
          },
          children: [
            {
              component: 'div',
              children: this.props.confirmModal.textContent || '',
            },
            {
              component: 'div',
              children: [
                {
                  component: 'ResponsiveButton',
                  props: Object.assign({
                    style: {
                      margin: 10,
                    },
                    buttonProps: {
                      size: 'isMedium',

                      color: 'isPrimary',
                    },
                    onClick: () => {
                      // console.debug('debugging this modal', this);
                      this.props.hideModal('last');
                      onclickFunction.call(this, onclickProp, clickFetchProps, clickSuccessProps);
                    },
                    onclickProps: 'last',
                  },this.props.confirmModal.yesButtonProps),
                  children: this.props.confirmModal.yesButtonText||'Yes',
                },
                {
                  component: 'ResponsiveButton',
                  props: Object.assign({
                    style: {
                      margin: 10,
                    },
                    buttonProps: {
                      size: 'isMedium',
                    },
                    onClick: 'func:this.props.hideModal',
                    onclickProps: 'last',
                  },this.props.confirmModal.noButtonProps),
                  children: this.props.confirmModal.noButtonText||'No',
                },
              ],
            },
          ],
        },
      }, this.props.confirmModal));
    } else {
      // console.debug('debugging this regular onclick', this);
      return onclickFunction.call(this, onclickProp, clickFetchProps, clickSuccessProps);
    }
  }
  handleSelect(event, selectProps) {
    let value = event.target.value;
    let selectedProp = selectProps[ value ];
    let buttonProps = selectedProp.buttonProps;
    this.handleOnClick.call(this, {
      clickprop: buttonProps.onClick,
      clickThisProp: buttonProps.onclickThisProp,
      clickPropObject: buttonProps.onclickPropObject,
      clickBaseUrl: buttonProps.onclickBaseUrl,
      clickLinkParams: buttonProps.onclickLinkParams,
      clickPassProps: buttonProps.onclickProps,
      clickFetchProps: buttonProps.fetchProps,
      clickSuccessProps: buttonProps.successProps,
      thisDotProp: this.props,
    });
    // console.debug({ value, selectProps });
  }
  render() {
    let getPropsForOnClick = () => {
      return {
        clickprop: this.props.onClick,
        clickThisProp: this.props.onclickThisProp,
        clickPropObject: this.props.onclickPropObject,
        clickBaseUrl: this.props.onclickBaseUrl,
        clickLinkParams: this.props.onclickLinkParams,
        clickPassProps: this.props.onclickProps,
        clickFetchProps: this.props.fetchProps,
        clickSuccessProps: this.props.successProps,
        thisDotProp: this.props,
      };
    };
    if (this.props.selectProps) {
      let options = [];
      let selectPropsVals = this.props.selectProps.values;

      Object.keys(selectPropsVals).forEach(key => {
        let additionalOptionProps =
          (typeof selectPropsVals[ key ].disabled !== 'undefined')
            ? { disabled:true, }
            : {};
        options.push(<option {...additionalOptionProps} key={`sddb-${key}`} value={key}>{selectPropsVals[key].label}</option>);
      });

      return <Select className="__ra_rb" {...this.props.selectElmProps} value={this.props.selectProps.selected}  onChange={(event) => {
        // console.log({ event });
        this.handleSelect.call(this, event, this.props.selectProps.values);
      }}>
        {options}
      </Select>;
    } else if (this.props.buttonProps) {
      return <Button className="__ra_rb"
        {...this.props.buttonProps}
        style={Object.assign({
          cursor: 'pointer', display: 'inline-block',
        }, this.props.style)}
        onClick={this.handleOnClick.bind(this, getPropsForOnClick())}
        >
        {
          (this.props.onclickThisProp && this.props.displayThisProps)
          ? this.props[this.props.onclickThisProp][this.props.displayThisProps]
          : this.props.children
        }
      </Button>;
    } else if (this.props.aProps){
      return {this.props.children};
    } else {
      return
        {
          (this.props.onclickThisProp && this.props.displayThisProps)
          ? this.props[this.props.onclickThisProp][this.props.displayThisProps]
          : this.props.children
        }
      ;
    }
  }
}

ResponsiveButton.propTypes = propTypes;
ResponsiveButton.defaultProps = defaultProps;

export default ResponsiveButton;<commit_msg>adding token to aprops<commit_after>import React, { Component, PropTypes, } from 'react';
import { Button, Select, } from 're-bulma';

const propTypes = {
  onClick: PropTypes.string,
  buttonProps: PropTypes.object,
  spanProps: PropTypes.object,
  style: PropTypes.object,
  onclickProps:PropTypes.any,
};

const defaultProps = {
  // onClick: '/',
  style: {},
};

class ResponsiveButton extends Component {
  // constructor(props) {
  //   super(props);
  // }
  getButtonLink(baseurl, params, prop) {
    // console.debug({ baseurl, params, prop });
    let returnLink = baseurl;
    try {
      if (params && params.length > 0) {
        params.forEach((param) => {
          returnLink = returnLink.replace(param.key, prop[ param.val ]);
        });
      }
    } catch (e) {
      console.debug(e, { baseurl, params, prop, });
    }
    return returnLink;
  }
  getHref(options) {
    let { thisDotProp, clickThisProp, clickPropObject, clickBaseUrl, clickLinkParams, clickPassProps, /*clickprop, clickFetchProps, clickSuccessProps, */ } = options;
    // console.debug('getHref',{options})
    let linkSelectionProp = (clickThisProp)
      ? thisDotProp[clickThisProp]
      : clickPropObject;
    let onclickProp = (clickBaseUrl)
      ? this.getButtonLink(clickBaseUrl, clickLinkParams, linkSelectionProp)
      : clickPassProps;
    return onclickProp;
  }
  handleOnClick(options) {
    // console.debug({ options });
    let { clickprop, thisDotProp, clickThisProp, clickPropObject, clickBaseUrl, clickLinkParams, clickPassProps, clickFetchProps, clickSuccessProps, } = options;
    let onclickFunction = (data) => {
      console.debug('ResponsiveButton', { data, });
    };
    let linkSelectionProp = (clickThisProp)
      ? thisDotProp[clickThisProp]
      : clickPropObject;
    let onclickProp = (clickBaseUrl)
      ? this.getButtonLink(clickBaseUrl, clickLinkParams, linkSelectionProp)
      : clickPassProps;

    if (typeof clickprop === 'string' && clickprop.indexOf('func:this.props.reduxRouter') !== -1) {
      onclickFunction = this.props.reduxRouter[ clickprop.replace('func:this.props.reduxRouter.', '') ];
    } else if (typeof clickprop === 'string' && clickprop.indexOf('func:this.funcs') !== -1) {
      onclickFunction = this.funcs[ clickprop.replace('func:this.funcs.', '') ];
    } else if (typeof clickprop === 'string' && clickprop.indexOf('func:window') !== -1) {
      onclickFunction = window[ clickprop.replace('func:window.', '') ].bind(this);
    } else if (typeof clickprop === 'string' && clickprop.indexOf('func:this.props') !== -1) {
      // console.debug('this.props', this.props);
      onclickFunction = this.props[ clickprop.replace('func:this.props.', '') ];
    } else if (typeof clickprop === 'function') {
      onclickFunction = clickprop;
    }
    // onclickFunction = onclickFunction.bind(this);
    if (this.props.confirmModal) {
      return this.props.createModal(Object.assign({
        title: 'Please Confirm',
        text: {
          component: 'div',
          props: {
            style: {
              textAlign: 'center',
            },
          },
          children: [
            {
              component: 'div',
              children: this.props.confirmModal.textContent || '',
            },
            {
              component: 'div',
              children: [
                {
                  component: 'ResponsiveButton',
                  props: Object.assign({
                    style: {
                      margin: 10,
                    },
                    buttonProps: {
                      size: 'isMedium',

                      color: 'isPrimary',
                    },
                    onClick: () => {
                      // console.debug('debugging this modal', this);
                      this.props.hideModal('last');
                      onclickFunction.call(this, onclickProp, clickFetchProps, clickSuccessProps);
                    },
                    onclickProps: 'last',
                  },this.props.confirmModal.yesButtonProps),
                  children: this.props.confirmModal.yesButtonText||'Yes',
                },
                {
                  component: 'ResponsiveButton',
                  props: Object.assign({
                    style: {
                      margin: 10,
                    },
                    buttonProps: {
                      size: 'isMedium',
                    },
                    onClick: 'func:this.props.hideModal',
                    onclickProps: 'last',
                  },this.props.confirmModal.noButtonProps),
                  children: this.props.confirmModal.noButtonText||'No',
                },
              ],
            },
          ],
        },
      }, this.props.confirmModal));
    } else {
      // console.debug('debugging this regular onclick', this);
      return onclickFunction.call(this, onclickProp, clickFetchProps, clickSuccessProps);
    }
  }
  handleSelect(event, selectProps) {
    let value = event.target.value;
    let selectedProp = selectProps[ value ];
    let buttonProps = selectedProp.buttonProps;
    this.handleOnClick.call(this, {
      clickprop: buttonProps.onClick,
      clickThisProp: buttonProps.onclickThisProp,
      clickPropObject: buttonProps.onclickPropObject,
      clickBaseUrl: buttonProps.onclickBaseUrl,
      clickLinkParams: buttonProps.onclickLinkParams,
      clickPassProps: buttonProps.onclickProps,
      clickFetchProps: buttonProps.fetchProps,
      clickSuccessProps: buttonProps.successProps,
      thisDotProp: this.props,
    });
    // console.debug({ value, selectProps });
  }
  render() {
    let getPropsForOnClick = () => {
      return {
        clickprop: this.props.onClick,
        clickThisProp: this.props.onclickThisProp,
        clickPropObject: this.props.onclickPropObject,
        clickBaseUrl: this.props.onclickBaseUrl,
        clickLinkParams: this.props.onclickLinkParams,
        clickPassProps: this.props.onclickProps,
        clickFetchProps: this.props.fetchProps,
        clickSuccessProps: this.props.successProps,
        thisDotProp: this.props,
      };
    };
    if (this.props.selectProps) {
      let options = [];
      let selectPropsVals = this.props.selectProps.values;

      Object.keys(selectPropsVals).forEach(key => {
        let additionalOptionProps =
          (typeof selectPropsVals[ key ].disabled !== 'undefined')
            ? { disabled:true, }
            : {};
        options.push(<option {...additionalOptionProps} key={`sddb-${key}`} value={key}>{selectPropsVals[key].label}</option>);
      });

      return <Select className="__ra_rb" {...this.props.selectElmProps} value={this.props.selectProps.selected}  onChange={(event) => {
        // console.log({ event });
        this.handleSelect.call(this, event, this.props.selectProps.values);
      }}>
        {options}
      </Select>;
    } else if (this.props.buttonProps) {
      return <Button className="__ra_rb"
        {...this.props.buttonProps}
        style={Object.assign({
          cursor: 'pointer', display: 'inline-block',
        }, this.props.style)}
        onClick={this.handleOnClick.bind(this, getPropsForOnClick())}
        >
        {
          (this.props.onclickThisProp && this.props.displayThisProps)
          ? this.props[this.props.onclickThisProp][this.props.displayThisProps]
          : this.props.children
        }
      </Button>;
    } else if (this.props.aProps){
      let token;
      if (this.props.aProps.token) token = localStorage.getItem('Admin Panel_jwt_token');
      return {this.props.children};
    } else {
      return
        {
          (this.props.onclickThisProp && this.props.displayThisProps)
          ? this.props[this.props.onclickThisProp][this.props.displayThisProps]
          : this.props.children
        }
      ;
    }
  }
}

ResponsiveButton.propTypes = propTypes;
ResponsiveButton.defaultProps = defaultProps;

export default ResponsiveButton;<|endoftext|>


<commit_before>export const COORDINATE_PLANE_XY = 'XY';
export const COORDINATE_PLANE_XZ = 'XZ';
export const COORDINATE_PLANE_YZ = 'YZ';
export const AXIS_LENGTH = 600;
export const GRID_X_LENGTH = 600;
export const GRID_Y_LENGTH = 600;
export const GRID_X_SPACING = 10;
export const GRID_Y_SPACING = 10;

export const CAMERA_FOV = 50;
export const CAMERA_ASPECT = 1;
export const CAMERA_NEAR = 0.1;
export const CAMERA_FAR = 10000;
export const CAMERA_POSITION_X = 0;
export const CAMERA_POSITION_Y = 0;
export const CAMERA_POSITION_Z = 200; // Move the camera out a bit from the origin (0, 0, 0)
export const WORKFLOW_STATE_RUNNING = 'running';
export const WORKFLOW_STATE_PAUSED = 'paused';
export const WORKFLOW_STATE_IDLE = 'idle';

// Grbl Active State
export const ACTIVE_STATE_IDLE = 'Idle';
export const ACTIVE_STATE_RUN = 'Run';
export const ACTIVE_STATE_HOLD = 'Hold';
export const ACTIVE_STATE_DOOR = 'Door';
export const ACTIVE_STATE_HOME = 'Home';
export const ACTIVE_STATE_ALARM = 'Alarm';
export const ACTIVE_STATE_CHECK = 'Check';
<commit_msg>Change AXIS_LENGTH to 200mm<commit_after>export const COORDINATE_PLANE_XY = 'XY';
export const COORDINATE_PLANE_XZ = 'XZ';
export const COORDINATE_PLANE_YZ = 'YZ';
export const AXIS_LENGTH = 200;
export const GRID_X_LENGTH = 600;
export const GRID_Y_LENGTH = 600;
export const GRID_X_SPACING = 10;
export const GRID_Y_SPACING = 10;

export const CAMERA_FOV = 50;
export const CAMERA_ASPECT = 1;
export const CAMERA_NEAR = 0.1;
export const CAMERA_FAR = 10000;
export const CAMERA_POSITION_X = 0;
export const CAMERA_POSITION_Y = 0;
export const CAMERA_POSITION_Z = 200; // Move the camera out a bit from the origin (0, 0, 0)
export const WORKFLOW_STATE_RUNNING = 'running';
export const WORKFLOW_STATE_PAUSED = 'paused';
export const WORKFLOW_STATE_IDLE = 'idle';

// Grbl Active State
export const ACTIVE_STATE_IDLE = 'Idle';
export const ACTIVE_STATE_RUN = 'Run';
export const ACTIVE_STATE_HOLD = 'Hold';
export const ACTIVE_STATE_DOOR = 'Door';
export const ACTIVE_STATE_HOME = 'Home';
export const ACTIVE_STATE_ALARM = 'Alarm';
export const ACTIVE_STATE_CHECK = 'Check';
<|endoftext|>


<commit_before>const webpack = require('webpack');
const path = require('path');
const ManifestPlugin = require('webpack-manifest-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

const devBuild = process.env.RAILS_ENV === 'development';
const firebaseApiKey = process.env.FIREBASE_API_KEY;
const firebaseDatabaseUrl = process.env.FIREBASE_DATABASE_URL;
const pusherKey = process.env.PUSHER_KEY;
const defaultUrl = process.env.DEFAULT_URL;
const cdnUrl = process.env.CDN_URL;
const { join, } = require('path');
const webpackConfigLoader = require('react-on-rails/webpackConfigLoader');

console.log('Directory: ', __dirname);

const configPath = join(__dirname, '..', 'config');
console.log('Directory: ', configPath);
const { output, } = webpackConfigLoader(configPath);
const nodeEnv = devBuild ? 'development' : 'production';

console.log('nodeEnv', nodeEnv)

const basePlugins = [new webpack.DefinePlugin({
  'process.env': {
    RAILS_ENV: JSON.stringify(nodeEnv),
    FIREBASE_API_KEY: JSON.stringify(firebaseApiKey),
    FIREBASE_DATABASE_URL: JSON.stringify(firebaseDatabaseUrl),
    PUSHER_KEY: JSON.stringify(pusherKey),
    DEFAULT_URL: JSON.stringify(defaultUrl),
    CDN_URL: JSON.stringify(cdnUrl),
  },
  TRACE_TURBOLINKS: devBuild,
}),
  new webpack.LoaderOptionsPlugin({
    test: /\.scss$/,
    options: {
      sassResources: [
        './app/assets/styles/app-variables.scss'
      ],
    },
  }),
  new ManifestPlugin({
    publicPath: output.publicPath,
    writeToFileEmit: true,
  })
];

// const plugins = () => {
//   if (nodeEnv === 'development') {
//     return basePlugins;
//   }
//   basePlugins.splice(1, 0, new UglifyJSPlugin());
//   return basePlugins;
// };
//
module.exports = {
  mode: nodeEnv,
  context: __dirname,
  entry: {
    vendor: [
      'babel-polyfill',
      'es5-shim/es5-shim',
      'es5-shim/es5-sham',
      'jquery-ujs',
      'jquery'
    ],
    app: [
      './app/bundles/Teacher/startup/clientRegistration'
    ],
    home: [
      './app/bundles/Home/home'
    ],
    student: [
      './app/bundles/Student/startup/clientRegistration'
    ],
    session: [
      './app/bundles/Session/startup/clientRegistration'
    ],
    login: [
      './app/bundles/Login/startup/clientRegistration'
    ],
    firewall_test: [
      './app/bundles/Firewall_test/firewall_test.js'
    ],
    public: [
      './app/bundles/Public/public.js'
    ],
    tools: [
      './app/bundles/Tools/tools.js'
    ],
    staff: [
      './app/bundles/Staff/startup/clientRegistration.js'
    ],
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    modules: [
      './node_modules',
      './app'
    ],
    alias: {
      lib: path.join(process.cwd(), 'app', 'lib'),
      react: path.resolve('./node_modules/react'),
      'react-dom': path.resolve('./node_modules/react-dom'),
    },
  },
  plugins: basePlugins,
  module: {
    rules: [
      {
        test: /\.(woff|woff2|jpe?g|png|gif|svg|ico|ttf|eot)$/,
        use: {
          loader: 'url-loader',
          options: {
            name: '[name]-[hash].[ext]',
            limit: 10000,
          },
        },
      },
      {
        test: /\.tsx?$/,
        loader: 'awesome-typescript-loader?errorsAsWarnings=true',
        exclude: /node_modules/,
      },
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      // {
      //   test: /\.(ttf|eot)$/,
      //   use: 'file-loader',
      // },
      {
        test: require.resolve('jquery'),
        use: [
          {
            loader: 'expose-loader',
            query: 'jQuery',
          },
          {
            loader: 'expose-loader',
            query: '$',
          }
        ],
      }
    ],
  },
  node: {
    console: true,
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
  },
};
<commit_msg>clean-up<commit_after>const webpack = require('webpack');
const path = require('path');
const ManifestPlugin = require('webpack-manifest-plugin');

const devBuild = process.env.RAILS_ENV === 'development';
const firebaseApiKey = process.env.FIREBASE_API_KEY;
const firebaseDatabaseUrl = process.env.FIREBASE_DATABASE_URL;
const pusherKey = process.env.PUSHER_KEY;
const defaultUrl = process.env.DEFAULT_URL;
const cdnUrl = process.env.CDN_URL;
const { join, } = require('path');
const webpackConfigLoader = require('react-on-rails/webpackConfigLoader');

const configPath = join(__dirname, '..', 'config');
const { output, } = webpackConfigLoader(configPath);
const mode = devBuild ? 'development' : 'production';

const basePlugins = [new webpack.DefinePlugin({
  'process.env': {
    RAILS_ENV: JSON.stringify(process.env.RAILS_ENV),
    FIREBASE_API_KEY: JSON.stringify(firebaseApiKey),
    FIREBASE_DATABASE_URL: JSON.stringify(firebaseDatabaseUrl),
    PUSHER_KEY: JSON.stringify(pusherKey),
    DEFAULT_URL: JSON.stringify(defaultUrl),
    CDN_URL: JSON.stringify(cdnUrl),
  },
  TRACE_TURBOLINKS: devBuild,
}),
  new webpack.LoaderOptionsPlugin({
    test: /\.scss$/,
    options: {
      sassResources: [
        './app/assets/styles/app-variables.scss'
      ],
    },
  }),
  new ManifestPlugin({
    publicPath: output.publicPath,
    writeToFileEmit: true,
  })
];

module.exports = {
  mode,
  context: __dirname,
  entry: {
    vendor: [
      'babel-polyfill',
      'es5-shim/es5-shim',
      'es5-shim/es5-sham',
      'jquery-ujs',
      'jquery'
    ],
    app: [
      './app/bundles/Teacher/startup/clientRegistration'
    ],
    home: [
      './app/bundles/Home/home'
    ],
    student: [
      './app/bundles/Student/startup/clientRegistration'
    ],
    session: [
      './app/bundles/Session/startup/clientRegistration'
    ],
    login: [
      './app/bundles/Login/startup/clientRegistration'
    ],
    firewall_test: [
      './app/bundles/Firewall_test/firewall_test.js'
    ],
    public: [
      './app/bundles/Public/public.js'
    ],
    tools: [
      './app/bundles/Tools/tools.js'
    ],
    staff: [
      './app/bundles/Staff/startup/clientRegistration.js'
    ],
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    modules: [
      './node_modules',
      './app'
    ],
    alias: {
      lib: path.join(process.cwd(), 'app', 'lib'),
      react: path.resolve('./node_modules/react'),
      'react-dom': path.resolve('./node_modules/react-dom'),
    },
  },
  plugins: basePlugins,
  module: {
    rules: [
      {
        test: /\.(woff|woff2|jpe?g|png|gif|svg|ico|ttf|eot)$/,
        use: {
          loader: 'url-loader',
          options: {
            name: '[name]-[hash].[ext]',
            limit: 10000,
          },
        },
      },
      {
        test: /\.tsx?$/,
        loader: 'awesome-typescript-loader?errorsAsWarnings=true',
        exclude: /node_modules/,
      },
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      // {
      //   test: /\.(ttf|eot)$/,
      //   use: 'file-loader',
      // },
      {
        test: require.resolve('jquery'),
        use: [
          {
            loader: 'expose-loader',
            query: 'jQuery',
          },
          {
            loader: 'expose-loader',
            query: '$',
          }
        ],
      }
    ],
  },
  node: {
    console: true,
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
  },
};
<|endoftext|>


<commit_before>import { Store } from 'flummox';

const initialState = {
  notes: null,
  bpm: null,

  inPlayback: false,
  playbackOffset: null,

  startTime: null,
  initialOffsetTime: null,
  msPerOffset: null
};

// ripped off from In the Groove http://r21freak.com/phpbb3/viewtopic.php?p=326033#p326033
const judgements = [
  [21.5, 'Fantastic'],
  [43, 'Excellent'],
  [102, 'Great'],
  [135, 'Decent'],
  [180, 'Way Off']
];

const missedJudgement = 'Miss';

const maxJudgementThreshold = judgements[4][0];

const judgementFor = function(diff) {
  const absDiff = Math.abs(diff);
  const label = judgements.filter((j) => absDiff < j[0])[0][1];
  const sign = diff < 0 ? '-' : '+';
  return `${label} ${sign}`;
};

class PlaybackStore extends Store {
  constructor(flux) {
    super(flux);

    const actionIds = flux.getActionIds('playback');

    this.register(actionIds.enterPlayback, this.handleEnterPlayback);
    this.register(actionIds.exitPlayback, this.handleExitPlayback);

    this.register(actionIds.playNote, this.handlePlayNote);

    this.state = initialState;
  }

  reset() {
    if (this.state.inPlayback) {
      this._stopPlaybackRunLoop();
    }

    this.setState(initialState);
  }

  _getMsPerOffset(bpm) {
    const secPerBeat = 60 / bpm;
    const secPerThirtySecond = secPerBeat / 24;
    return secPerThirtySecond * 1000;
  }

  handleEnterPlayback({offset, bpm, notes}) {
    this._createPlaybackRunLoop();

    notes = notes.map((note) => {
      const totalOffset = note.offset + note.beat * 24;
      const time = totalOffset * this._getMsPerOffset(bpm);
      return note.set('time', time);
    });

    notes = notes.toSet();

    const msPerOffset = this._getMsPerOffset(bpm);

    this.setState({
      notes,
      bpm,
      inPlayback: true,
      initialOffsetTime: offset * msPerOffset,
      playbackOffset: offset,
      startTime: Date.now(),
      msPerOffset
    });
  }

  handleExitPlayback() {
    this._stopPlaybackRunLoop();

    this.setState({
      inPlayback: false
    });
  }

  _createPlaybackRunLoop() {
    let prev = Date.now();

    let runLoop = () => {
      const now = Date.now();
      const dt = now - prev;
      prev = now;

      this._updatePlaybackOffset(dt);
      this._removeMissedNotes();

      window.requestAnimationFrame(runLoop);
    };

    this._stopPlaybackRunLoop = () => {
      runLoop = () => {};
    };

    window.requestAnimationFrame(runLoop);
  }

  _updatePlaybackOffset(dt) {
    const prevOffset = this.state.playbackOffset;

    const elapsedOffset = dt / this.state.msPerOffset;

    this.setState({
      playbackOffset: prevOffset + elapsedOffset
    });
  }

  _removeMissedNotes() {
    const elapsed = Date.now() - this.state.startTime + this.state.initialOffsetTime;

    const missedNotes = this.state.notes.filter((note) => elapsed > note.time + maxJudgementThreshold);

    if (missedNotes.count() > 0) {
      this.setState({
        notes: this.state.notes.subtract(missedNotes),
        judgement: missedJudgement
      });
    }
  }

  _findNoteFor(time, column) {
    // 1. Calculate offset for time
    // 2. Calculate offset for time-50ms and time+50ms
    // 3. Return *earliest* note filtered for in that range with matching column
    return this.state.notes.filter((note) => {
      if (note.col !== column) {
        return false;
      }

      return (time + maxJudgementThreshold > note.time && time - maxJudgementThreshold < note.time);

    }).minBy((note) => note.offset);
  }

  handlePlayNote({time, column}) {
    const elapsed = time - this.state.startTime + this.state.initialOffsetTime;
    const note = this._findNoteFor(elapsed, column);

    if (!note) {
      return;
    }

    this.setState({
      notes: this.state.notes.remove(note),
      judgement: judgementFor(elapsed - note.time)
    });
  }
}

export default PlaybackStore;
<commit_msg>Ensure judgement is unset when player is exited<commit_after>import { Store } from 'flummox';

const initialState = {
  notes: null,
  bpm: null,

  inPlayback: false,
  playbackOffset: null,

  startTime: null,
  initialOffsetTime: null,
  msPerOffset: null,
  judgement: null
};

// ripped off from In the Groove http://r21freak.com/phpbb3/viewtopic.php?p=326033#p326033
const judgements = [
  [21.5, 'Fantastic'],
  [43, 'Excellent'],
  [102, 'Great'],
  [135, 'Decent'],
  [180, 'Way Off']
];

const missedJudgement = 'Miss';

const maxJudgementThreshold = judgements[4][0];

const judgementFor = function(diff) {
  const absDiff = Math.abs(diff);
  const label = judgements.filter((j) => absDiff < j[0])[0][1];
  const sign = diff < 0 ? '-' : '+';
  return `${label} ${sign}`;
};

class PlaybackStore extends Store {
  constructor(flux) {
    super(flux);

    const actionIds = flux.getActionIds('playback');

    this.register(actionIds.enterPlayback, this.handleEnterPlayback);
    this.register(actionIds.exitPlayback, this.handleExitPlayback);

    this.register(actionIds.playNote, this.handlePlayNote);

    this.state = initialState;
  }

  reset() {
    if (this.state.inPlayback) {
      this._stopPlaybackRunLoop();
    }

    this.setState(initialState);
  }

  _getMsPerOffset(bpm) {
    const secPerBeat = 60 / bpm;
    const secPerThirtySecond = secPerBeat / 24;
    return secPerThirtySecond * 1000;
  }

  handleEnterPlayback({offset, bpm, notes}) {
    this._createPlaybackRunLoop();

    notes = notes.map((note) => {
      const totalOffset = note.offset + note.beat * 24;
      const time = totalOffset * this._getMsPerOffset(bpm);
      return note.set('time', time);
    });

    notes = notes.toSet();

    const msPerOffset = this._getMsPerOffset(bpm);

    this.setState({
      notes,
      bpm,
      inPlayback: true,
      initialOffsetTime: offset * msPerOffset,
      playbackOffset: offset,
      startTime: Date.now(),
      msPerOffset
    });
  }

  handleExitPlayback() {
    this._stopPlaybackRunLoop();

    this.setState({
      inPlayback: false
    });
  }

  _createPlaybackRunLoop() {
    let prev = Date.now();

    let runLoop = () => {
      const now = Date.now();
      const dt = now - prev;
      prev = now;

      this._updatePlaybackOffset(dt);
      this._removeMissedNotes();

      window.requestAnimationFrame(runLoop);
    };

    this._stopPlaybackRunLoop = () => {
      runLoop = () => {};
    };

    window.requestAnimationFrame(runLoop);
  }

  _updatePlaybackOffset(dt) {
    const prevOffset = this.state.playbackOffset;

    const elapsedOffset = dt / this.state.msPerOffset;

    this.setState({
      playbackOffset: prevOffset + elapsedOffset
    });
  }

  _removeMissedNotes() {
    const elapsed = Date.now() - this.state.startTime + this.state.initialOffsetTime;

    const missedNotes = this.state.notes.filter((note) => elapsed > note.time + maxJudgementThreshold);

    if (missedNotes.count() > 0) {
      this.setState({
        notes: this.state.notes.subtract(missedNotes),
        judgement: missedJudgement
      });
    }
  }

  _findNoteFor(time, column) {
    // 1. Calculate offset for time
    // 2. Calculate offset for time-50ms and time+50ms
    // 3. Return *earliest* note filtered for in that range with matching column
    return this.state.notes.filter((note) => {
      if (note.col !== column) {
        return false;
      }

      return (time + maxJudgementThreshold > note.time && time - maxJudgementThreshold < note.time);

    }).minBy((note) => note.offset);
  }

  handlePlayNote({time, column}) {
    const elapsed = time - this.state.startTime + this.state.initialOffsetTime;
    const note = this._findNoteFor(elapsed, column);

    if (!note) {
      return;
    }

    this.setState({
      notes: this.state.notes.remove(note),
      judgement: judgementFor(elapsed - note.time)
    });
  }
}

export default PlaybackStore;
<|endoftext|>


<commit_before>function playback(){
	var diff = new htmlDiff();
	diff.clearHash();
	var listOfRevisions = [], pageTitle, startRev, endRev, revisionInfo, modifyList;
	var playAnimation = true;
	this.animationSpeed = 1000;
	var usingLanguageNamespace = 'en';
	var modifyList =[];
	var revisionListDict = {
		'format': 'json',
		'action': 'query',
		'prop': 'revisions',
		'rvprop': 'ids|user|timestamp|size|flags',
		'rvdir': 'newer',
	};

	var compareRevisionDict = {
		'format': 'json',
		'action': 'query',
		'prop': 'revisions',
		'rvprop': 'content',
		'rvexpandtemplates': '',
		'rvparse': '',
	};

	var baseUrl = 'https://en.wikipedia.org/w/api.php?callback=?';
	var that = this;
	this.wikiNameSpace = function (language) {
	  usingLanguageNamespace = language;
	  baseUrl = 'https://'+language+'.wikipedia.org/w/api.php?callback=?';
	};
	this.cleanUp = function(){
		listOfRevisions = [];
		$('#wikiBody').html('');
	};
	this.getRevisions = function (page,selectedEdits){

			listOfRevisions = selectedEdits;
	        pageTitle = page;
	        startRev = listOfRevisions.shift().revid;
	        revisionInfo = listOfRevisions[0];
	        endRev = revisionInfo.revid;
	        listOfRevisions.shift();
	        playAnimation = true;
	        $('body').trigger( "editAnimationBegins", [startRev] );
	        that.wikiDiff();

	};
	/** Caching the results memoization **/
	var hashTable = hashTable || {};
	function getRequest(revid){
		//var deferredReady = $.Deferred();
		if (revid in hashTable){
			//console.log('cache hit', revid);
			return true;
		}
		else{
			//console.log('cache fail',revid );
			compareRevisionDict['revids'] = revid;
			return $.getJSON(baseUrl,compareRevisionDict,function(data){
				var resultKey = Object.keys(data.query.pages);
				var dataRev = data.query.pages[resultKey].revisions[0]['*'];
				hashTable[revid] = dataRev;
			});
		}
	};
	var empty = function (list){
		var l =[];
		for (ll in list ){
			if ($(list[ll]).text().trim()){
				l.push(list[ll]);
				}
		}
		return l;
	};
	//hard coding parent element
	var removeRef = function(parentElement){
		$('del a[href^=#cite_note],del a[href^=#cite_ref],del *[id^=cite_note]').remove();
		$('del sup a[href^=#cite_note]').parent().parent().remove();
		$('a[href^=#cite_note] del').remove();
		$('a[href^=#cite_note] ins').each(function(){
			var element = $(this);
			element.replaceWith(element.text());
		});
	};
	this.wikiDiff = function(){
	    //Creating the info box about the revisions
        var revInfo = {
				'revid': revisionInfo.revid,
				'user': revisionInfo.user,
				'timestamp': revisionInfo.timestamp.slice(0,10),
				'minor': revisionInfo.hasOwnProperty('minor')? 'M' : null
		};
		that.infoBox(revInfo);
		$.when(getRequest(startRev),getRequest(endRev)).done(function(){
			var dataFirstRev  = hashTable[startRev];
			var dataSecondRev = hashTable[endRev];
			console.time('diff');
			var modifiedHtml = diff.diff(dataFirstRev,dataSecondRev);
			console.timeEnd('diff');
			$('#wikiBody').html(modifiedHtml);
			// To remove ref changes
			removeRef();
			console.time('making array');
			modifyList = empty($.makeArray($('del,ins')));
			console.timeEnd('making array');
			that.animateDiff();
		});
	};

	this.infoBox = function (revInfo){
        //$('#infoBox').html('');
        for (key in revInfo){
            if(key == 'revid'){
                var urlBase = 'https://'+usingLanguageNamespace+'.wikipedia.org/w/index.php?oldid='+revInfo[key];
                var anchor =$(''+revInfo[key]+'').attr({'target':'_blank','href':urlBase});
                 $('#infoBox .revisionLink').html(anchor);
            }
            else if(key == 'timestamp'){
            	$('#infoBox .editDate').html(revInfo[key]);
            }
            else if(key == 'user'){
            	$('#infoBox .userName').html(revInfo[key]);
            }
            else{
            	var minor = revInfo[key]?revInfo[key]:'';
                $('#infoBox .minor').html(minor);

            }
        }
	};

	this.animateDiff = function () {
		if(playAnimation){
                if(modifyList.length>0){
					var element = modifyList[0];
					var scrollPromise = that.customScrollIntoView('#wikiBody',element);

                    $.when(scrollPromise).then(function(){
                    	if ($(element).prop('tagName') == 'DEL'){
                        	console.log('scroll end:: animation begin add ',Date.now(),modifyList.length,element.id);
                        	return $(element).fadeOut(that.animationSpeed);
                    	}
                    	else{
                    		console.log('scroll end:: animation begin delete ',Date.now(),modifyList.length,element.id);
                        	return $(element).fadeIn(that.animationSpeed).css('display','inline-block');
                    	}

                    }).then(function(){
                    		console.log('animation end',Date.now(),modifyList.length,element.id);
                    		modifyList.shift();
                    		that.animateDiff();
                    	});
				}
                else{
                	$('body').trigger( "editAnimationBegins", [endRev] );
                    if(listOfRevisions.length>0){
                        startRev = endRev;
                        revisionInfo = listOfRevisions.shift();
                        endRev = revisionInfo.revid;
                        that.wikiDiff();
                    }
                    else{
						$('#playButton').removeClass().addClass('play');
                    }
				}
		}
	};
	var getOffsetTop = function(element){
		if (element.parentElement.tagName == 'TD'){
			return element.parentElement.offsetTop;
		}
		else{
			return element.offsetTop;
		}
	};
	this.customScrollIntoView = function(parent,element){
		//console.log('scroll begin',Date.now(),modifyList.length,element);
		var offset = 0;
		if ($(element).css('display') == 'none'){
			offset = getOffsetTop($(element).css('display','inline-block')[0]);
			$(element).css('display','none');
		}
		else{
			offset = getOffsetTop(element);
		}
		return $(parent).animate({scrollTop: offset }, that.animationSpeed);
	};

	this.startPlayback = function(selectedEdits,reset){
		userNotification('play');
		$('#playButton').removeClass('play').addClass('pause');
		var page = $('#pageTitle').val();
	    //Handling the case where the the player was paused
		    if(!slider.pegMoved && listOfRevisions.length && listOfRevisions.length > 0){
		        playAnimation = true;
		        that.animateDiff();
		    }
		    else{
		    	//refractor this
		    	selectedEdits = slider.selectedEdits;
		    	slider.refreshProgressBar(selectedEdits[0]);
		    	slider.pegMoved = false;
		        that.getRevisions(page,selectedEdits);
		    }
	};

	this.pausePlayback = function(button){
		userNotification('pause');
		$(button).removeClass('pause').addClass('play');
		$('del,ins').finish();
		playAnimation = false;
	};
	//Attaching control for play / pause
	this.playbackControl  = function(){
		$('#playButton').click(function(){
			var button = this;
			if($(button).hasClass('play')){
				that.startPlayback();
			}
			else{
				that.pausePlayback(button);
			}
		});
	};
};

function addLanguageOptions(languages){
	for(language in languages){
		var option = $('<option>').val(language).html(languages[language]);
		$('select.languageNamespace').append(option);
	}
};

//The fullscreen Api handling
function fullscreenApi(screen){
	var elem = $(screen).get(0);
	if (elem.requestFullscreen) {
		elem.requestFullscreen();
	}
	else if (elem.mozRequestFullScreen) {
		elem.mozRequestFullScreen();
	}
	else if (elem.webkitRequestFullscreen) {
		elem.webkitRequestFullscreen();
	}

};

function chooseRandomArticle(lang_code) {
	lang_code = lang_code ? lang_code : 'en';
	var api_url = 'https://' + lang_code + '.wikipedia.org/w/api.php?callback=?';
	var params = {
		'action': 'query',
		'list': 'random',
		'rnnamespace': 0,
		'rnlimit': 1,
		'format': 'json'
	};
	$.getJSON(api_url, params, function(data, e) {
		var page_title = data['query']['random'][0]['title'];
		console.log('Randomly selected:', page_title);
		$('#overlayTitle').val(page_title);
		$('#overlayLoad').trigger('click');
	});
}
<commit_msg>Removing TOC from the from detected as changes<commit_after>function playback(){
	var diff = new htmlDiff();
	diff.clearHash();
	var listOfRevisions = [], pageTitle, startRev, endRev, revisionInfo, modifyList;
	var playAnimation = true;
	this.animationSpeed = 1000;
	var usingLanguageNamespace = 'en';
	var modifyList =[];
	var revisionListDict = {
		'format': 'json',
		'action': 'query',
		'prop': 'revisions',
		'rvprop': 'ids|user|timestamp|size|flags',
		'rvdir': 'newer',
	};

	var compareRevisionDict = {
		'format': 'json',
		'action': 'query',
		'prop': 'revisions',
		'rvprop': 'content',
		'rvexpandtemplates': '',
		'rvparse': '',
	};

	var baseUrl = 'https://en.wikipedia.org/w/api.php?callback=?';
	var that = this;
	this.wikiNameSpace = function (language) {
	  usingLanguageNamespace = language;
	  baseUrl = 'https://'+language+'.wikipedia.org/w/api.php?callback=?';
	};
	this.cleanUp = function(){
		listOfRevisions = [];
		$('#wikiBody').html('');
	};
	this.getRevisions = function (page,selectedEdits){

			listOfRevisions = selectedEdits;
	        pageTitle = page;
	        startRev = listOfRevisions.shift().revid;
	        revisionInfo = listOfRevisions[0];
	        endRev = revisionInfo.revid;
	        listOfRevisions.shift();
	        playAnimation = true;
	        $('body').trigger( "editAnimationBegins", [startRev] );
	        that.wikiDiff();

	};
	/** Caching the results memoization **/
	var hashTable = hashTable || {};
	function getRequest(revid){
		//var deferredReady = $.Deferred();
		if (revid in hashTable){
			//console.log('cache hit', revid);
			return true;
		}
		else{
			//console.log('cache fail',revid );
			compareRevisionDict['revids'] = revid;
			return $.getJSON(baseUrl,compareRevisionDict,function(data){
				var resultKey = Object.keys(data.query.pages);
				var dataRev = data.query.pages[resultKey].revisions[0]['*'];
				hashTable[revid] = dataRev;
			});
		}
	};
	var empty = function (list){
		var l =[];
		for (ll in list ){
			if ($(list[ll]).text().trim()){
				l.push(list[ll]);
				}
		}
		return l;
	};
	//hard coding parent element
	var removeRef = function(parentElement){
		$('del a[href^=#cite_note],del a[href^=#cite_ref],del *[id^=cite_note]').remove();
		$('del sup a[href^=#cite_note]').parent().parent().remove();
		$('a[href^=#cite_note] del').remove();
		$('a[href^=#cite_note] ins').each(function(){
			var element = $(this);
			element.replaceWith(element.text());
		});
	};
	//Removing TOC
	var removeToc = function(list){
		var modifiedList = [];
		for (i=0;i<list.length;i++) {
			if (!$(list[i]).find('[class^="toclevel"]').length) {
					modifiedList.push(list[i]);
				}
			}
		return modifiedList;
	};
	this.wikiDiff = function(){
	    //Creating the info box about the revisions
        var revInfo = {
				'revid': revisionInfo.revid,
				'user': revisionInfo.user,
				'timestamp': revisionInfo.timestamp.slice(0,10),
				'minor': revisionInfo.hasOwnProperty('minor')? 'M' : null
		};
		that.infoBox(revInfo);
		$.when(getRequest(startRev),getRequest(endRev)).done(function(){
			var dataFirstRev  = hashTable[startRev];
			var dataSecondRev = hashTable[endRev];
			console.time('diff');
			var modifiedHtml = diff.diff(dataFirstRev,dataSecondRev);
			console.timeEnd('diff');
			$('#wikiBody').html(modifiedHtml);
			// To remove ref changes
			removeRef();
			console.time('making array');
			modifyList = empty($.makeArray($('del,ins')));
			modifyList = removeToc(modifyList);
			console.timeEnd('making array');
			that.animateDiff();
		});
	};

	this.infoBox = function (revInfo){
        //$('#infoBox').html('');
        for (key in revInfo){
            if(key == 'revid'){
                var urlBase = 'https://'+usingLanguageNamespace+'.wikipedia.org/w/index.php?oldid='+revInfo[key];
                var anchor =$(''+revInfo[key]+'').attr({'target':'_blank','href':urlBase});
                 $('#infoBox .revisionLink').html(anchor);
            }
            else if(key == 'timestamp'){
            	$('#infoBox .editDate').html(revInfo[key]);
            }
            else if(key == 'user'){
            	$('#infoBox .userName').html(revInfo[key]);
            }
            else{
            	var minor = revInfo[key]?revInfo[key]:'';
                $('#infoBox .minor').html(minor);

            }
        }
	};

	this.animateDiff = function () {
		if(playAnimation){
                if(modifyList.length>0){
					var element = modifyList[0];
					var scrollPromise = that.customScrollIntoView('#wikiBody',element);

                    $.when(scrollPromise).then(function(){
                    	if ($(element).prop('tagName') == 'DEL'){
                        	console.log('scroll end:: animation begin add ',Date.now(),modifyList.length,element.id);
                        	return $(element).fadeOut(that.animationSpeed);
                    	}
                    	else{
                    		console.log('scroll end:: animation begin delete ',Date.now(),modifyList.length,element.id);
                        	return $(element).fadeIn(that.animationSpeed).css('display','inline-block');
                    	}

                    }).then(function(){
                    		console.log('animation end',Date.now(),modifyList.length,element.id);
                    		modifyList.shift();
                    		that.animateDiff();
                    	});
				}
                else{
                	$('body').trigger( "editAnimationBegins", [endRev] );
                    if(listOfRevisions.length>0){
                        startRev = endRev;
                        revisionInfo = listOfRevisions.shift();
                        endRev = revisionInfo.revid;
                        that.wikiDiff();
                    }
                    else{
						$('#playButton').removeClass().addClass('play');
                    }
				}
		}
	};
	var getOffsetTop = function(element){
		if (element.parentElement.tagName == 'TD'){
			return element.parentElement.offsetTop;
		}
		else{
			return element.offsetTop;
		}
	};
	this.customScrollIntoView = function(parent,element){
		//console.log('scroll begin',Date.now(),modifyList.length,element);
		var offset = 0;
		if ($(element).css('display') == 'none'){
			offset = getOffsetTop($(element).css('display','inline-block')[0]);
			$(element).css('display','none');
		}
		else{
			offset = getOffsetTop(element);
		}
		return $(parent).animate({scrollTop: offset }, that.animationSpeed);
	};

	this.startPlayback = function(selectedEdits,reset){
		userNotification('play');
		$('#playButton').removeClass('play').addClass('pause');
		var page = $('#pageTitle').val();
	    //Handling the case where the the player was paused
		    if(!slider.pegMoved && listOfRevisions.length && listOfRevisions.length > 0){
		        playAnimation = true;
		        that.animateDiff();
		    }
		    else{
		    	//refractor this
		    	selectedEdits = slider.selectedEdits;
		    	slider.refreshProgressBar(selectedEdits[0]);
		    	slider.pegMoved = false;
		        that.getRevisions(page,selectedEdits);
		    }
	};

	this.pausePlayback = function(button){
		userNotification('pause');
		$(button).removeClass('pause').addClass('play');
		$('del,ins').finish();
		playAnimation = false;
	};
	//Attaching control for play / pause
	this.playbackControl  = function(){
		$('#playButton').click(function(){
			var button = this;
			if($(button).hasClass('play')){
				that.startPlayback();
			}
			else{
				that.pausePlayback(button);
			}
		});
	};
};

function addLanguageOptions(languages){
	for(language in languages){
		var option = $('<option>').val(language).html(languages[language]);
		$('select.languageNamespace').append(option);
	}
};

//The fullscreen Api handling
function fullscreenApi(screen){
	var elem = $(screen).get(0);
	if (elem.requestFullscreen) {
		elem.requestFullscreen();
	}
	else if (elem.mozRequestFullScreen) {
		elem.mozRequestFullScreen();
	}
	else if (elem.webkitRequestFullscreen) {
		elem.webkitRequestFullscreen();
	}

};

function chooseRandomArticle(lang_code) {
	lang_code = lang_code ? lang_code : 'en';
	var api_url = 'https://' + lang_code + '.wikipedia.org/w/api.php?callback=?';
	var params = {
		'action': 'query',
		'list': 'random',
		'rnnamespace': 0,
		'rnlimit': 1,
		'format': 'json'
	};
	$.getJSON(api_url, params, function(data, e) {
		var page_title = data['query']['random'][0]['title'];
		console.log('Randomly selected:', page_title);
		$('#overlayTitle').val(page_title);
		$('#overlayLoad').trigger('click');
	});
}
<|endoftext|>


<commit_before>/*
 * LICENCE : CloudUnit is available under the Affero Gnu Public License GPL V3 : https://www.gnu.org/licenses/agpl-3.0.html
 *     but CloudUnit is licensed too under a standard commercial license.
 *     Please contact our sales team if you would like to discuss the specifics of our Enterprise license.
 *     If you are not sure whether the GPL is right for you,
 *     you can always test our software under the GPL and inspect the source code before you contact us
 *     about purchasing a commercial license.
 *
 *     LEGAL TERMS : "CloudUnit" is a registered trademark of Treeptik and can't be used to endorse
 *     or promote products derived from this project without prior written permission from Treeptik.
 *     Products or services derived from this software may not be called "CloudUnit"
 *     nor may "Treeptik" or similar confusing terms appear in their names without prior written permission.
 *     For any questions, contact us : contact@treeptik.fr
 */

(function () {
  'use strict';
  angular
    .module('webuiApp.editApplication')
    .component('environmentComponent', EnvironmentComponent());

  function EnvironmentComponent(){
    return {
      templateUrl: 'scripts/components/editApplication/settings/environment/editApplication.settings.environment.html',
      bindings: {
        application: '<app'
      },
      controller: [
        '$stateParams',
        '$q',
        'ApplicationService',
        'ErrorService',
        EnvironmentCtrl
      ],
      controllerAs: 'environment',
    }
  }

  function EnvironmentCtrl($stateParams, $q, ApplicationService, ErrorService) {

    var vm = this;
    vm.env = [];
    vm.containers = [];
    vm.myContainer = {};
    vm.pageSize = 5;
    vm.currentPage = 1;
    vm.environmentVariableKey = '';
    vm.environmentVariableValue = '';
    vm.addNoticeMsg = '';
    vm.addErrorMsg = '';
    vm.manageNoticeMsg = '';
    vm.manageErrorMsg = '';

    vm.predicate = 'value';
    vm.reverse = false;
    vm.order = order;

    vm.editEnv = editEnv;
    vm.deleteEnv = deleteEnv;
    vm.addEnv = addEnv;

    vm.$onInit = function() {
      getContainers()
      .then(function() {
        getListEnvironmentVariable();
      })
      .catch(function(response) {
         ErrorService.handle(response);
      });
    }

    ////////////////////////////////////////////////

    function getListEnvironmentVariable() {
      ApplicationService.getListSettingsEnvironmentVariable($stateParams.name, vm.myContainer.name)
        .then(function(response) {
          vm.env = response;
          console.log(response);
        })
        .catch(function(response) {
          ErrorService.handle(response);
        });
    }

    function getContainers ( selectedContainer ) {
      var deferred = $q.defer ();
      vm.isLoading = true;
      ApplicationService.listContainers ( $stateParams.name )
        .then ( function ( containers ) {
          vm.containers = containers;
          vm.myContainer = selectedContainer || containers[0];
          vm.isLoading = false;
          deferred.resolve ( containers );
        } )
        .catch ( function ( response ) {
          deferred.reject ( response );
        } );
        return deferred.promise;
    }

    function deleteEnv (environmentVariable) {
      ApplicationService.deleteEnvironmentVariable (  $stateParams.name, vm.myContainer.name, environmentVariable.id )
        .then ( function() {
          cleanMessage();
          vm.env.splice(vm.env.indexOf(environmentVariable), 1);
          vm.manageNoticeMsg = 'The variable has been removed !';
        } )
        .catch (errorManageEnvironment);
    }

    function editEnv (environmentVariableID, environmentVariableKey, environmentVariableValue) {
      ApplicationService.editEnvironmentVariable ( $stateParams.name, vm.myContainer.name, environmentVariableID, environmentVariableKey, environmentVariableValue )
        .then(function(env) {
          cleanMessage();
          var elementPos = vm.env.map(function(x) {return x.id; }).indexOf(environmentVariableID);
          vm.env[elementPos] = env;
          vm.manageNoticeMsg = 'The variable has been edited !';
        })
        .catch (function(response) {
          getListEnvironmentVariable();
          errorManageEnvironment(response);
        });
    }

    function addEnv (environmentVariableKey, environmentVariableValue) {
      ApplicationService.addEnvironmentVariable($stateParams.name, vm.myContainer.name, environmentVariableKey, environmentVariableValue)
        .then ( function(env) {
          cleanMessage();
          vm.env.push(env);
          vm.environmentVariableKey = '';
          vm.environmentVariableValue = '';
          vm.addNoticeMsg = 'Variable successfully created !';
        } )
        .catch (errorAddEnvironment);
    }

    function errorScript (res) {
      if(res.data.message) {
        vm.manageNoticeMsg = res.data.message;
      } else {
        vm.manageNoticeMsg = 'An error has been encountered!';
      }
      vm.manageErrorMsg = '';
    }

    function errorAddEnvironment (res) {
      cleanMessage();
      if(res.data.message) {
        vm.addErrorMsg = res.data.message;
      } else {
        vm.addErrorMsg = 'An error has been encountered!';
      }
    }

    function errorManageEnvironment (res) {
      cleanMessage();
      if(res.data.message) {
        vm.manageErrorMsg = res.data.message;
      } else {
        vm.manageErrorMsg = 'An error has been encountered!';
      }
    }

    function cleanMessage() {
      vm.addErrorMsg = '';
      vm.addNoticeMsg = '';
      vm.manageErrorMsg = '';
      vm.manageNoticeMsg = '';
    }

    function order (predicate) {
      vm.reverse = (vm.predicate === predicate) ? !vm.reverse : false;
      vm.predicate = predicate;
    }
  }
})();
<commit_msg>FRONT - retablish environnement variable delete<commit_after>/*
 * LICENCE : CloudUnit is available under the Affero Gnu Public License GPL V3 : https://www.gnu.org/licenses/agpl-3.0.html
 *     but CloudUnit is licensed too under a standard commercial license.
 *     Please contact our sales team if you would like to discuss the specifics of our Enterprise license.
 *     If you are not sure whether the GPL is right for you,
 *     you can always test our software under the GPL and inspect the source code before you contact us
 *     about purchasing a commercial license.
 *
 *     LEGAL TERMS : "CloudUnit" is a registered trademark of Treeptik and can't be used to endorse
 *     or promote products derived from this project without prior written permission from Treeptik.
 *     Products or services derived from this software may not be called "CloudUnit"
 *     nor may "Treeptik" or similar confusing terms appear in their names without prior written permission.
 *     For any questions, contact us : contact@treeptik.fr
 */

(function () {
  'use strict';
  angular
    .module('webuiApp.editApplication')
    .component('environmentComponent', EnvironmentComponent());

  function EnvironmentComponent(){
    return {
      templateUrl: 'scripts/components/editApplication/settings/environment/editApplication.settings.environment.html',
      bindings: {
        application: '<app'
      },
      controller: [
        '$stateParams',
        '$q',
        'ApplicationService',
        'ErrorService',
        EnvironmentCtrl
      ],
      controllerAs: 'environment',
    }
  }

  function EnvironmentCtrl($stateParams, $q, ApplicationService, ErrorService) {

    var vm = this;
    vm.env = [];
    vm.containers = [];
    vm.myContainer = {};
    vm.pageSize = 5;
    vm.currentPage = 1;
    vm.environmentVariableKey = '';
    vm.environmentVariableValue = '';
    vm.addNoticeMsg = '';
    vm.addErrorMsg = '';
    vm.manageNoticeMsg = '';
    vm.manageErrorMsg = '';

    vm.predicate = 'value';
    vm.reverse = false;
    vm.order = order;

    vm.editEnv = editEnv;
    vm.deleteEnv = deleteEnv;
    vm.addEnv = addEnv;

    vm.$onInit = function() {
      getContainers()
      .then(function() {
        getListEnvironmentVariable();
      })
      .catch(function(response) {
         ErrorService.handle(response);
      });
    }

    ////////////////////////////////////////////////

    function getListEnvironmentVariable() {
      ApplicationService.getListSettingsEnvironmentVariable($stateParams.name, vm.myContainer.name)
        .then(function(response) {
          vm.env = response;
          console.log(response);
        })
        .catch(function(response) {
          ErrorService.handle(response);
        });
    }

    function getContainers ( selectedContainer ) {
      var deferred = $q.defer ();
      vm.isLoading = true;
      ApplicationService.listContainers ( $stateParams.name )
        .then ( function ( containers ) {
          vm.containers = containers;
          vm.myContainer = selectedContainer || containers[0];
          vm.isLoading = false;
          deferred.resolve ( containers );
        } )
        .catch ( function ( response ) {
          deferred.reject ( response );
        } );
        return deferred.promise;
    }

    function deleteEnv (environmentVariable) {
      ApplicationService.deleteEnvironmentVariable (  $stateParams.name, vm.myContainer.name, environmentVariable.id )
        .then ( function() {
          cleanMessage();
          vm.env.splice(vm.env.indexOf(environmentVariable), 1);
          vm.manageNoticeMsg = 'The variable has been removed !';
        } )
        .catch (errorManageEnvironment);
    }

    function editEnv (environmentVariableID, environmentVariableKey, environmentVariableValue) {
      ApplicationService.editEnvironmentVariable($stateParams.name, vm.myContainer.name, environmentVariableID, environmentVariableKey,
      environmentVariableValue)
        .then(function(env) {
          cleanMessage();
          getListEnvironmentVariable();
          var elementPos = vm.env.map(function(x) {return x.id; }).indexOf(environmentVariableID);
          vm.env[elementPos] = env;
          vm.manageNoticeMsg = 'The variable has been edited !';
        })
        .catch (function(response) {
          getListEnvironmentVariable();
          errorManageEnvironment(response);
        });
    }

    function addEnv (environmentVariableKey, environmentVariableValue) {
      ApplicationService.addEnvironmentVariable($stateParams.name, vm.myContainer.name, environmentVariableKey, environmentVariableValue)
        .then ( function(env) {
          cleanMessage();
          getListEnvironmentVariable();
          vm.addNoticeMsg = 'Variable successfully created !';
        } )
        .catch (errorAddEnvironment);
    }

    function errorScript (res) {
      if(res.data.message) {
        vm.manageNoticeMsg = res.data.message;
      } else {
        vm.manageNoticeMsg = 'An error has been encountered!';
      }
      vm.manageErrorMsg = '';
    }

    function errorAddEnvironment (res) {
      cleanMessage();
      if(res.data.message) {
        vm.addErrorMsg = res.data.message;
      } else {
        vm.addErrorMsg = 'An error has been encountered!';
      }
    }

    function errorManageEnvironment (res) {
      cleanMessage();
      if(res.data.message) {
        vm.manageErrorMsg = res.data.message;
      } else {
        vm.manageErrorMsg = 'An error has been encountered!';
      }
    }

    function cleanMessage() {
      vm.addErrorMsg = '';
      vm.addNoticeMsg = '';
      vm.manageErrorMsg = '';
      vm.manageNoticeMsg = '';
    }

    function order (predicate) {
      vm.reverse = (vm.predicate === predicate) ? !vm.reverse : false;
      vm.predicate = predicate;
    }
  }
})();
<|endoftext|>


<commit_before>// Copyright 2015, University of Colorado Boulder

/**
 * Tandem is used to assign unique identifiers to instances in PhET simulations and register/unregister them in a
 * registry. It is used to support PhET-iO.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var tandemNamespace = require( 'TANDEM/tandemNamespace' );
  var toCamelCase = require( 'PHET_CORE/toCamelCase' );

  // text
  var packageString = require( 'text!REPOSITORY/package.json' );

  // constants
  var packageJSON = JSON.parse( packageString ); // Tandem can't depend on joist, so requiring packageJSON doesn't work
  var PHET_IO_ENABLED = !!( window.phet && window.phet.phetio );

  // Listeners that will be notified when items are registered/deregistered. See doc in addInstanceListener
  var instanceListeners = [];

  // variables
  // Before listeners are wired up, tandems are buffered.  When listeners are wired up, Tandem.launch() is called
  // and buffered tandems are flushed, then subsequent tandems are delivered to listeners directly
  var launched = false;
  var bufferedElements = [];

  // increment names of uninstrumented common code tandems to avoid collisions for uninstrumented sims with
  // phetioValidateTandems=false
  var uninstrumentedCodeIndex = 0;

  /**
   * Typically, sims will create tandems using `tandem.createTandem`.  This constructor is used internally or when
   * a tandem must be created from scratch.
   *
   * @param {string} phetioID - unique identifier as a string ('' for a root id)
   * @param {Object} [options]
   * @constructor
   */
  function Tandem( phetioID, options ) {

    // options (even subtype options) must be stored on the instance so they can be passed through to children
    // Note: Make sure that added options here are also added to options for inheritance and/or
    // for composition (createTandem/parentTandem) as they make sense.
    options = _.extend( {

      // Enabled tandems notify listeners when they are added. Disabled tandems do not notify listeners,
      // but children of a disabled tandem may be enabled.
      enabled: true,

      // if the tandem is not supplied and required, an error will be thrown.
      supplied: true,

      // required === false means it is an optional tandem
      required: true
    }, options );

    // @public (read-only)
    this.phetioID = ( phetioID !== undefined ) ? phetioID : '';

    // @private
    this.required = options.required;

    // @private
    this.supplied = options.supplied;

    // @private
    this.enabled = options.enabled;
  }

  tandemNamespace.register( 'Tandem', Tandem );

  inherit( Object, Tandem, {

    /**
     * Adds an instance of any type.  For example, it could be an axon Property, scenery Node or Sun button.  Each
     * item should only be added to the registry once, but that is not enforced here in Tandem.  For PhET-iO, phetio.js
     * enforces one entry per ID in phetio.addInstance
     *
     * This is used to register instances with PhET-iO.
     * @param {PhetioObject} instance - the instance to add
     * @public
     */
    addInstance: function( instance ) {

      assert && assert( arguments.length === 1, 'Tandem.addInstance takes one argument' );

      // Check that the instrumented instance is an instance of PhetioObject, cannot use typical require statement for
      // PhetioObject because it creates a module loading loop
      assert && assert( instance instanceof tandemNamespace.PhetioObject, 'Instance should be of type PhetioObject' );

      if ( PHET_IO_ENABLED && this.enabled ) {

        // Throw an error if the tandem is required but not supplied
        if ( phet.phetio.queryParameters.phetioValidateTandems ) {
          assert && assert( !( this.required && !this.supplied ), 'Tandem was required but not supplied' );
        }

        // ValidateTandems is false and printMissingTandems flag is present for a tandem that is required but not supplied.
        if ( phet.phetio.queryParameters.printMissingTandems && ( this.required && !this.supplied ) ) {
          console.log( 'Required Tandem not supplied.\n' +
                       'this.phetioID = ' + this.phetioID + '\n' +
                       'Stack trace: ' + new Error().stack );
        }

        // If tandem is optional, then don't add the instance
        if ( !this.required && !this.supplied ) {
          if ( phet.phetio.queryParameters.printMissingTandems ) {
            var stackTrace = new Error().stack;

            // Generally Font is not desired because there are so many untandemized instances.
            if ( stackTrace.indexOf( 'PhetFont' ) === -1 ) {
              console.log( 'Optional Tandem not supplied.\n' +
                           'this.phetioID = ' + this.phetioID + '\n' +
                           'Stack trace: ' + stackTrace );
            }
          }

          // For optionally instrumented types that are not provided tandems, the instance isn't really "added"
          // but likewise, it in not an error
          return;
        }

        if ( !launched ) {
          bufferedElements.push( instance );
        }
        else {
          for ( var i = 0; i < instanceListeners.length; i++ ) {
            instanceListeners[ i ].addInstance( instance );
          }
        }
      }
    },

    /**
     * Removes an instance from the registry
     * @param {PhetioObject} instance - the instance to remove
     * @public
     */
    removeInstance: function( instance ) {
      if ( !this.required && !this.supplied ) {
        return;
      }

      // Only active when running as phet-io
      if ( PHET_IO_ENABLED && this.enabled ) {
        for ( var i = 0; i < instanceListeners.length; i++ ) {
          instanceListeners[ i ].removeInstance( instance );
        }
      }
    },

    /**
     * Create a new Tandem by appending the given id
     * @param {string} id
     * @param {Object} [options]
     * @returns {Tandem}
     * @public
     */
    createTandem: function( id, options ) {

      // Make sure the id was provided
      assert && assert( typeof id === 'string' && id.length > 0, 'id must be defined' );

      var string = ( this.phetioID.length > 0 ) ? phetio.PhetioIDUtils.append( this.phetioID, id ) : id;

      // Any child of something should be passed all inherited options. Make sure that this extend call includes all
      // that make sense from the constructor's extend call.
      options = _.extend( {
        enabled: this.enabled,
        supplied: this.supplied,
        required: this.required
      }, options );

      return new Tandem( string, options );
    },

    /**
     * Creates a group tandem for creating multiple indexed child tandems, such as:
     * sim.screen.model.electron_0
     * sim.screen.model.electron_1
     *
     * In this case, 'sim.screen.model.electron' is the string passed to createGroupTandem.
     *
     * Used for arrays, observable arrays, or when many elements of the same type are created and they do not otherwise
     * have unique identifiers.
     * @param id
     * @returns {GroupTandem}
     * @public
     */
    createGroupTandem: function( id ) {

      // Unfortunately we must resort to globals here since loading through the namespace would create a cycle
      return new GroupTandem( phetio.PhetioIDUtils.append( this.phetioID, id ) );
    },

    /**
     * Get the last part of the tandem (after the last .), used in Joist for creating button names dynamically based
     * on screen names
     * @returns {string} the tail of the tandem
     * @public
     */
    get tail() { // TODO: rename to getComponentName()
      return phetio.PhetioIDUtils.getComponentName( this.phetioID );
    },

    /**
     * Returns a Tandem for everything except the tail.
     * @returns {Tandem}
     * @public
     */
    get parentTandem() {
      var headID = phetio.PhetioIDUtils.getParentID( this.phetioID );

      return new Tandem( headID, {
        required: this.required,
        supplied: this.supplied,
        enabled: this.enabled
      } );
    },

    /**
     * Return true if this tandem is supplied and the sim is running in PhET-iO mode.
     * @returns {boolean}
     * @public
     */
    isSuppliedAndEnabled: function() {
      return this.supplied && PHET_IO_ENABLED;
    }
  }, {

    /**
     * Adds a listener that will be notified when items are registered/deregistered
     * Listeners have the form
     * {
     *   addInstance(id,instance),
     *   removeInstance(id,instance)
     * }
     * where id is of type {string} and instance is of type {Object}
     *
     * @param {Object} instanceListener - described above
     * @public
     * @static
     */
    addInstanceListener: function( instanceListener ) {
      instanceListeners.push( instanceListener );
    },

    /**
     * When all listeners are listening, all buffered instances are registered.
     * @public
     * @static
     */
    launch: function() {
      assert && assert( !launched, 'Tandem was launched twice' );
      launched = true;
      while ( bufferedElements.length > 0 ) {
        var element = bufferedElements.shift();
        element.tandem.addInstance( element );
      }
    },

    /**
     * Catch cases where tandem is being supplied to a class that doesn't support tandem.
     * @param {Object} [options]
     * @public
     * @static
     */
    disallowTandem: function( options ) {

      if ( Tandem.validationEnabled() ) {
        assert && assert( !options.tandem, 'tandem is not allowed' );
      }
    },

    /**
     * When running in PhET-iO brand, some code (such as user interface components) must be instrumented for PhET-iO.
     * Uninstrumented files should call this function to indicate they still need to be instrumented, so they aren't
     * missed.  See https://github.com/phetsims/phet-io/issues/668
     * @public
     * @static
     */
    indicateUninstrumentedCode: function() {

      // Guard against undefined errors
      if ( PHET_IO_ENABLED ) {

        // Assert if validating tandems
        if ( phet.phetio.queryParameters.phetioValidateTandems ) {
          assert && assert( false, 'Uninstrumented code detected' );
        }

        // Print stack trace if query parameter supplied
        if ( phet.phetio.queryParameters.printMissingTandems ) {
          var stackTrace = new Error().stack;
          console.log( 'Uninstrumented Code! Tandem not supplied: ' + ( uninstrumentedCodeIndex++ ) + '.\n' +
                       'Stack trace: ' + stackTrace );
        }
      }
    },

    /**
     * Determine whether or not tandem validation is turned on for the sim.
     * @returns {Boolean} If tandems are being validated or not.
     * @public
     * @static
     */
    validationEnabled: function() {
      return PHET_IO_ENABLED && phet.phetio.queryParameters.phetioValidateTandems;
    }
  } );

  // The next few statics are created outside the static block because they instantiate Tandem instances.

  /**
   * The root tandem for a simulation
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.rootTandem = new Tandem( toCamelCase( packageJSON.name ) );

  /**
   * Used to indicate a common code component that supports tandem, but doesn't not require it.
   * If a tandem is not passed through to this instance, then it will not be instrumented.
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.optional = Tandem.rootTandem.createTandem( 'optionalTandem', {
    required: false,
    supplied: false
  } );

  /**
   * Some common code (such as Checkbox or RadioButton) must always be instrumented and hence requires a tandem to be
   * passed in.
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.required = Tandem.rootTandem.createTandem( 'requiredTandem', {
    required: true,
    supplied: false
  } );

  /**
   * Group Tandem -- Declared in the same file to avoid circular reference errors in module loading.
   * @param {string} id - id as a string (or '' for a root id)
   * @constructor
   * @private create with Tandem.createGroupTandem
   */
  function GroupTandem( id ) {

    Tandem.call( this, id );

    // @private for generating indices from a pool
    this.groupElementIndex = 0;
  }

  tandemNamespace.register( 'Tandem.GroupTandem', GroupTandem );

  inherit( Tandem, GroupTandem, {

    /**
     * Creates the next tandem in the group.
     * @returns {Tandem}
     * @public
     */
    createNextTandem: function() {
      return new Tandem( this.phetioID + '_' + ( this.groupElementIndex++ ) );
    }
  } );

  return Tandem;
} );<commit_msg>Simplified buffering strategy for tandems, see https://github.com/phetsims/phet-io/issues/1363<commit_after>// Copyright 2015, University of Colorado Boulder

/**
 * Tandem is used to assign unique identifiers to instances in PhET simulations and register/unregister them in a
 * registry. It is used to support PhET-iO.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var tandemNamespace = require( 'TANDEM/tandemNamespace' );
  var toCamelCase = require( 'PHET_CORE/toCamelCase' );

  // text
  var packageString = require( 'text!REPOSITORY/package.json' );

  // constants
  var packageJSON = JSON.parse( packageString ); // Tandem can't depend on joist, so requiring packageJSON doesn't work
  var PHET_IO_ENABLED = !!( window.phet && window.phet.phetio );

  // Listeners that will be notified when items are registered/deregistered. See doc in addInstanceListener
  var instanceListeners = [];

  // variables
  // Before listeners are wired up, tandems are buffered.  When listeners are wired up, Tandem.launch() is called
  // and buffered tandems are flushed, then subsequent tandems are delivered to listeners directly
  var launched = false;
  var bufferedElements = [];

  // increment names of uninstrumented common code tandems to avoid collisions for uninstrumented sims with
  // phetioValidateTandems=false
  var uninstrumentedCodeIndex = 0;

  /**
   * Typically, sims will create tandems using `tandem.createTandem`.  This constructor is used internally or when
   * a tandem must be created from scratch.
   *
   * @param {string} phetioID - unique identifier as a string ('' for a root id)
   * @param {Object} [options]
   * @constructor
   */
  function Tandem( phetioID, options ) {

    // options (even subtype options) must be stored on the instance so they can be passed through to children
    // Note: Make sure that added options here are also added to options for inheritance and/or
    // for composition (createTandem/parentTandem) as they make sense.
    options = _.extend( {

      // Enabled tandems notify listeners when they are added. Disabled tandems do not notify listeners,
      // but children of a disabled tandem may be enabled.
      enabled: true,

      // if the tandem is not supplied and required, an error will be thrown.
      supplied: true,

      // required === false means it is an optional tandem
      required: true
    }, options );

    // @public (read-only)
    this.phetioID = ( phetioID !== undefined ) ? phetioID : '';

    // @private
    this.required = options.required;

    // @private
    this.supplied = options.supplied;

    // @private
    this.enabled = options.enabled;
  }

  tandemNamespace.register( 'Tandem', Tandem );

  inherit( Object, Tandem, {

    /**
     * Adds an instance of any type.  For example, it could be an axon Property, scenery Node or Sun button.  Each
     * item should only be added to the registry once, but that is not enforced here in Tandem.  For PhET-iO, phetio.js
     * enforces one entry per ID in phetio.addInstance
     *
     * This is used to register instances with PhET-iO.
     * @param {PhetioObject} instance - the instance to add
     * @public
     */
    addInstance: function( instance ) {

      assert && assert( arguments.length === 1, 'Tandem.addInstance takes one argument' );

      // Check that the instrumented instance is an instance of PhetioObject, cannot use typical require statement for
      // PhetioObject because it creates a module loading loop
      assert && assert( instance instanceof tandemNamespace.PhetioObject, 'Instance should be of type PhetioObject' );

      if ( PHET_IO_ENABLED && this.enabled ) {

        // Throw an error if the tandem is required but not supplied
        if ( phet.phetio.queryParameters.phetioValidateTandems ) {
          assert && assert( !( this.required && !this.supplied ), 'Tandem was required but not supplied' );
        }

        // ValidateTandems is false and printMissingTandems flag is present for a tandem that is required but not supplied.
        if ( phet.phetio.queryParameters.printMissingTandems && ( this.required && !this.supplied ) ) {
          console.log( 'Required Tandem not supplied.\n' +
                       'this.phetioID = ' + this.phetioID + '\n' +
                       'Stack trace: ' + new Error().stack );
        }

        // If tandem is optional, then don't add the instance
        if ( !this.required && !this.supplied ) {
          if ( phet.phetio.queryParameters.printMissingTandems ) {
            var stackTrace = new Error().stack;

            // Generally Font is not desired because there are so many untandemized instances.
            if ( stackTrace.indexOf( 'PhetFont' ) === -1 ) {
              console.log( 'Optional Tandem not supplied.\n' +
                           'this.phetioID = ' + this.phetioID + '\n' +
                           'Stack trace: ' + stackTrace );
            }
          }

          // For optionally instrumented types that are not provided tandems, the instance isn't really "added"
          // but likewise, it in not an error
          return;
        }

        if ( !launched ) {
          bufferedElements.push( instance );
        }
        else {
          for ( var i = 0; i < instanceListeners.length; i++ ) {
            instanceListeners[ i ].addInstance( instance );
          }
        }
      }
    },

    /**
     * Removes an instance from the registry
     * @param {PhetioObject} instance - the instance to remove
     * @public
     */
    removeInstance: function( instance ) {
      if ( !this.required && !this.supplied ) {
        return;
      }

      // Only active when running as phet-io
      if ( PHET_IO_ENABLED && this.enabled ) {
        for ( var i = 0; i < instanceListeners.length; i++ ) {
          instanceListeners[ i ].removeInstance( instance );
        }
      }
    },

    /**
     * Create a new Tandem by appending the given id
     * @param {string} id
     * @param {Object} [options]
     * @returns {Tandem}
     * @public
     */
    createTandem: function( id, options ) {

      // Make sure the id was provided
      assert && assert( typeof id === 'string' && id.length > 0, 'id must be defined' );

      var string = ( this.phetioID.length > 0 ) ? phetio.PhetioIDUtils.append( this.phetioID, id ) : id;

      // Any child of something should be passed all inherited options. Make sure that this extend call includes all
      // that make sense from the constructor's extend call.
      options = _.extend( {
        enabled: this.enabled,
        supplied: this.supplied,
        required: this.required
      }, options );

      return new Tandem( string, options );
    },

    /**
     * Creates a group tandem for creating multiple indexed child tandems, such as:
     * sim.screen.model.electron_0
     * sim.screen.model.electron_1
     *
     * In this case, 'sim.screen.model.electron' is the string passed to createGroupTandem.
     *
     * Used for arrays, observable arrays, or when many elements of the same type are created and they do not otherwise
     * have unique identifiers.
     * @param id
     * @returns {GroupTandem}
     * @public
     */
    createGroupTandem: function( id ) {

      // Unfortunately we must resort to globals here since loading through the namespace would create a cycle
      return new GroupTandem( phetio.PhetioIDUtils.append( this.phetioID, id ) );
    },

    /**
     * Get the last part of the tandem (after the last .), used in Joist for creating button names dynamically based
     * on screen names
     * @returns {string} the tail of the tandem
     * @public
     */
    get tail() { // TODO: rename to getComponentName()
      return phetio.PhetioIDUtils.getComponentName( this.phetioID );
    },

    /**
     * Returns a Tandem for everything except the tail.
     * @returns {Tandem}
     * @public
     */
    get parentTandem() {
      var headID = phetio.PhetioIDUtils.getParentID( this.phetioID );

      return new Tandem( headID, {
        required: this.required,
        supplied: this.supplied,
        enabled: this.enabled
      } );
    },

    /**
     * Return true if this tandem is supplied and the sim is running in PhET-iO mode.
     * @returns {boolean}
     * @public
     */
    isSuppliedAndEnabled: function() {
      return this.supplied && PHET_IO_ENABLED;
    }
  }, {

    /**
     * Adds a listener that will be notified when items are registered/deregistered
     * Listeners have the form
     * {
     *   addInstance(id,instance),
     *   removeInstance(id,instance)
     * }
     * where id is of type {string} and instance is of type {Object}
     *
     * @param {Object} instanceListener - described above
     * @public
     * @static
     */
    addInstanceListener: function( instanceListener ) {
      instanceListeners.push( instanceListener );
    },

    /**
     * When all listeners are listening, all buffered instances are registered.
     * @public
     * @static
     */
    launch: function() {
      assert && assert( !launched, 'Tandem was launched twice' );
      launched = true;
      while ( bufferedElements.length > 0 ) {
        var element = bufferedElements.shift();
        element.tandem.addInstance( element );
      }
    },

    /**
     * Catch cases where tandem is being supplied to a class that doesn't support tandem.
     * @param {Object} [options]
     * @public
     * @static
     */
    disallowTandem: function( options ) {

      if ( Tandem.validationEnabled() ) {
        assert && assert( !options.tandem, 'tandem is not allowed' );
      }
    },

    /**
     * When running in PhET-iO brand, some code (such as user interface components) must be instrumented for PhET-iO.
     * Uninstrumented files should call this function to indicate they still need to be instrumented, so they aren't
     * missed.  See https://github.com/phetsims/phet-io/issues/668
     * @public
     * @static
     */
    indicateUninstrumentedCode: function() {

      // Guard against undefined errors
      if ( PHET_IO_ENABLED ) {

        // Assert if validating tandems
        if ( phet.phetio.queryParameters.phetioValidateTandems ) {
          assert && assert( false, 'Uninstrumented code detected' );
        }

        // Print stack trace if query parameter supplied
        if ( phet.phetio.queryParameters.printMissingTandems ) {
          var stackTrace = new Error().stack;
          console.log( 'Uninstrumented Code! Tandem not supplied: ' + ( uninstrumentedCodeIndex++ ) + '.\n' +
                       'Stack trace: ' + stackTrace );
        }
      }
    },

    /**
     * Determine whether or not tandem validation is turned on for the sim.
     * @returns {Boolean} If tandems are being validated or not.
     * @public
     * @static
     */
    validationEnabled: function() {
      return PHET_IO_ENABLED && phet.phetio.queryParameters.phetioValidateTandems;
    },

    /**
     * Returns true if the bufferedElements contain the given phetioID.
     * @param {string} phetioID
     * @returns {boolean}
     * @public
     */
    containsBufferedID: function( phetioID ) {
      return bufferedElements.map( function( instance ) {return instance.tandem.phetioID;} ).indexOf( phetioID ) >= 0;
    }
  } );

  // The next few statics are created outside the static block because they instantiate Tandem instances.

  /**
   * The root tandem for a simulation
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.rootTandem = new Tandem( toCamelCase( packageJSON.name ) );

  /**
   * Used to indicate a common code component that supports tandem, but doesn't not require it.
   * If a tandem is not passed through to this instance, then it will not be instrumented.
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.optional = Tandem.rootTandem.createTandem( 'optionalTandem', {
    required: false,
    supplied: false
  } );

  /**
   * Some common code (such as Checkbox or RadioButton) must always be instrumented and hence requires a tandem to be
   * passed in.
   * @public
   * @static
   * @type {Tandem}
   */
  Tandem.required = Tandem.rootTandem.createTandem( 'requiredTandem', {
    required: true,
    supplied: false
  } );

  /**
   * Group Tandem -- Declared in the same file to avoid circular reference errors in module loading.
   * @param {string} id - id as a string (or '' for a root id)
   * @constructor
   * @private create with Tandem.createGroupTandem
   */
  function GroupTandem( id ) {

    Tandem.call( this, id );

    // @private for generating indices from a pool
    this.groupElementIndex = 0;
  }

  tandemNamespace.register( 'Tandem.GroupTandem', GroupTandem );

  inherit( Tandem, GroupTandem, {

    /**
     * Creates the next tandem in the group.
     * @returns {Tandem}
     * @public
     */
    createNextTandem: function() {
      return new Tandem( this.phetioID + '_' + ( this.groupElementIndex++ ) );
    }
  } );

  return Tandem;
} );<|endoftext|>