<commit_before>/**
 * original html structure (note that extra divs have been inserted by using fela)
 *
 *

 *   Label
 *
 *

 *     <input type="hidden"/>
 *
 *

 *
Placeholder

 *
 *
 *

 *
 *
 *

 *         <input value="" tabindex="0" style="...">
 *

 *

 *
 *
 *
 *         ×
 *
 *
 *

 *
 *

 *

 *
 *
 *

 *

 *
One

 *
Two

 *
Three

 *

 *

 *
 *

 *

 */

import React from 'react';
import PropTypes from 'prop-types';
import ReactSelect from 'react-select';
import { createComponent } from 'cf-style-container';
import Value from './Value';
import Option from './Option';
import MenuHeader from './MenuHeader';
import CloseMenu from './CloseMenu';
import menuRenderer from './menuRenderer';
import arrowRenderer from './arrowRenderer';
import clearRenderer from './clearRenderer';

const Label = createComponent(
  ({ theme }) => ({
    display: 'block',
    fontSize: '0.7em',
    color: theme.color.storm,
    fontWeight: 'bold',
    textTransform: 'uppercase',
    letterSpacing: '0.1em',
    marginBottom: '0.5em'
  }),
  'label'
);

// bindRight is used to ensure that menuRenderer, called from within react-select,
// is always passed a second parameter which is used for further configuration.
const bindRight = (fn, ...rightArgs) => (...args) => fn(...args, ...rightArgs);

class Select extends React.Component {
  constructor(props) {
    super(props);
    this.menuRenderer = bindRight(props.menuRenderer, {
      menuTitle: props.menuTitle,
      menuHeaderComponent: props.menuHeaderComponent,
      closeMenuComponent: props.closeMenuComponent,
      closeMenu: () => {
        const nested = props.creatable || props.async;
        const select = nested ? this.select.select : this.select;
        select && select.closeMenu();
      }
    });
  }

  render() {
    const {
      async,
      creatable,
      searchable,
      disabled,
      label,
      className,
      ...props
    } = this.props;

    let SelectClass;
    if (async) {
      SelectClass = creatable ? ReactSelect.AsyncCreatable : ReactSelect.Async;
    } else {
      SelectClass = creatable ? ReactSelect.Creatable : ReactSelect;
    }

    return (
      <div className={`${className}`}>
        {label &&

            {label}
          }
        <SelectClass
          {...props}
          searchable={searchable}
          clearable={searchable || creatable}
          backspaceRemoves={searchable || creatable}
          menuRenderer={this.menuRenderer}
          ref={ref => this.select = ref}
        />

    );
  }
}

Select.defaultProps = {
  multi: false,
  searchable: false,
  async: false,
  creatable: false,
  disabled: false,
  menuRenderer,
  arrowRenderer,
  clearRenderer,
  optionComponent: Option,
  valueComponent: Value,
  menuHeaderComponent: MenuHeader,
  closeMenuComponent: CloseMenu
};

Select.propTypes = {
  className: PropTypes.string,
  disabled: PropTypes.bool,
  label: PropTypes.string,
  value: PropTypes.any,
  options: PropTypes.array,
  searchable: PropTypes.bool,
  multi: PropTypes.bool,
  onChange: PropTypes.func,
  async: PropTypes.bool,
  creatable: PropTypes.bool,
  menuRenderer: PropTypes.func,
  arrowRenderer: PropTypes.func,
  clearRenderer: PropTypes.func,
  isValidNewOption: PropTypes.func,
  noResultsText: PropTypes.string,
  promptTextCreator: PropTypes.func,
  newOptionCreator: PropTypes.func,
  menuTitle: PropTypes.string,
  menuHeaderComponent: PropTypes.func,
  closeMenuComponent: PropTypes.func
};

const singleOrPlaceholder = theme => ({
  bottom: 0,
  color: theme.colorGrayDark,
  left: 0,
  lineHeight: '32px',
  paddingLeft: '10px',
  paddingRight: '10px',
  position: 'absolute',
  right: 0,
  top: 0,
  maxWidth: '100%',
  overflow: 'hidden',
  textOverflow: 'ellipsis',
  whiteSpace: 'nowrap'
});

const styles = ({ theme, disabled }) => {
  const values = {
    boxSizing: 'border-box',
    fontSize: '0.86667rem'
  };

  return {
    ...values,
    '& div': values,
    '& input': values,
    '& span': values,

    flex: theme.flex,
    margin: theme.margin,
    width: theme.width,
    display: theme.display,
    verticalAlign: theme.verticalAlign,
    position: 'relative',
    opacity: disabled ? 0.5 : 1,

    '& .Select-control': {
      backgroundColor: disabled ? theme.color.smoke : theme.colorWhite,
      border: `1px solid ${theme.color.hail}`,
      borderRadius: theme.borderRadius,
      color: theme.color.charcoal,
      cursor: 'default',
      display: 'table',
      borderSpacing: 0,
      borderCollapse: 'separate',
      height: '32px',
      outline: 'none',
      overflow: 'hidden',
      position: 'relative',
      width: '100%',
      transition: 'border-color 0.2s ease'
    },
    '& .Select-control .Select-input:focus': {
      outline: 'none'
    },
    '& .Select-menu-outer': {
      position: 'relative'
    },
    '&:hover .Select-control': {
      borderColor: theme.colorBlueDark
    },
    '& .is-focused .Select-control': {
      borderColor: theme.colorBlueDark
    },
    '& .is-open .Select-control': {
      borderColor: theme.color.hail
    },
    '& .Select-placeholder': singleOrPlaceholder(theme),
    '& .Select--single > .Select-control .Select-value': singleOrPlaceholder(
      theme
    ),
    '& .Select-input': {
      height: '32px',
      paddingLeft: '10px',
      paddingRight: '10px',
      verticalAlign: 'middle'
    },
    '& .Select-input > input': {
      width: '100%',
      background: 'none transparent',
      border: ' 0 none',
      cursor: 'default',
      display: 'inline-block',
      fontFamily: 'inherit',
      fontSize: 'inherit',
      margin: 0,
      outline: 'none',
      lineHeight: '14px',
      padding: 0
    },
    '& .Select-noresults': {
      boxVizing: 'border-box',
      color: theme.color.cement,
      cursor: 'default',
      display: 'block',
      padding: '8px 10px'
    },
    '& .Select-aria-only': {
      display: 'inline-block',
      height: '1px',
      width: '1px',
      margin: '-1px',
      clip: 'rect(0, 0, 0, 0)',
      overflow: 'hidden'
    },
    '& .Select-arrow-zone': {
      cursor: 'pointer',
      display: 'table-cell',
      position: 'relative',
      textAlign: 'center',
      verticalAlign: 'middle',
      width: '25px',
      paddingRight: '5px',
      top: '1px'
    },
    '& .Select-clear-zone': {
      color: theme.color.cement,
      cursor: ' pointer',
      display: 'table-cell',
      position: 'relative',
      top: '1px',
      textAlign: 'center',
      verticalAlign: 'middle',
      width: '17px'
    }
  };
};

export default createComponent(styles, Select);
<commit_msg>fix(cf-component-select): Add proptypes for missing async options so fela will whitelist (#372)<commit_after>/**
 * original html structure (note that extra divs have been inserted by using fela)
 *
 *

 *   Label
 *
 *

 *     <input type="hidden"/>
 *
 *

 *
Placeholder

 *
 *
 *

 *
 *
 *

 *         <input value="" tabindex="0" style="...">
 *

 *

 *
 *
 *
 *         ×
 *
 *
 *

 *
 *

 *

 *
 *
 *

 *

 *
One

 *
Two

 *
Three

 *

 *

 *
 *

 *

 */

import React from 'react';
import PropTypes from 'prop-types';
import ReactSelect from 'react-select';
import { createComponent } from 'cf-style-container';
import Value from './Value';
import Option from './Option';
import MenuHeader from './MenuHeader';
import CloseMenu from './CloseMenu';
import menuRenderer from './menuRenderer';
import arrowRenderer from './arrowRenderer';
import clearRenderer from './clearRenderer';

const Label = createComponent(
  ({ theme }) => ({
    display: 'block',
    fontSize: '0.7em',
    color: theme.color.storm,
    fontWeight: 'bold',
    textTransform: 'uppercase',
    letterSpacing: '0.1em',
    marginBottom: '0.5em'
  }),
  'label'
);

// bindRight is used to ensure that menuRenderer, called from within react-select,
// is always passed a second parameter which is used for further configuration.
const bindRight = (fn, ...rightArgs) => (...args) => fn(...args, ...rightArgs);

class Select extends React.Component {
  constructor(props) {
    super(props);
    this.menuRenderer = bindRight(props.menuRenderer, {
      menuTitle: props.menuTitle,
      menuHeaderComponent: props.menuHeaderComponent,
      closeMenuComponent: props.closeMenuComponent,
      closeMenu: () => {
        const nested = props.creatable || props.async;
        const select = nested ? this.select.select : this.select;
        select && select.closeMenu();
      }
    });
  }

  render() {
    const {
      async,
      creatable,
      searchable,
      disabled,
      label,
      className,
      ...props
    } = this.props;

    let SelectClass;
    if (async) {
      SelectClass = creatable ? ReactSelect.AsyncCreatable : ReactSelect.Async;
    } else {
      SelectClass = creatable ? ReactSelect.Creatable : ReactSelect;
    }

    return (
      <div className={`${className}`}>
        {label &&

            {label}
          }
        <SelectClass
          {...props}
          searchable={searchable}
          clearable={searchable || creatable}
          backspaceRemoves={searchable || creatable}
          menuRenderer={this.menuRenderer}
          ref={ref => this.select = ref}
        />

    );
  }
}

Select.defaultProps = {
  multi: false,
  searchable: false,
  async: false,
  creatable: false,
  disabled: false,
  menuRenderer,
  arrowRenderer,
  clearRenderer,
  optionComponent: Option,
  valueComponent: Value,
  menuHeaderComponent: MenuHeader,
  closeMenuComponent: CloseMenu
};

Select.propTypes = {
  className: PropTypes.string,
  disabled: PropTypes.bool,
  label: PropTypes.string,
  value: PropTypes.any,
  options: PropTypes.array,
  searchable: PropTypes.bool,
  multi: PropTypes.bool,
  onChange: PropTypes.func,
  async: PropTypes.bool,
  creatable: PropTypes.bool,
  menuRenderer: PropTypes.func,
  arrowRenderer: PropTypes.func,
  clearRenderer: PropTypes.func,
  isValidNewOption: PropTypes.func,
  noResultsText: PropTypes.string,
  promptTextCreator: PropTypes.func,
  newOptionCreator: PropTypes.func,
  menuTitle: PropTypes.string,
  menuHeaderComponent: PropTypes.func,
  closeMenuComponent: PropTypes.func,
  loadOptions: PropTypes.func,
  autoload: PropTypes.bool,
  searchPromptText: PropTypes.string,
  cache: PropTypes.bool
};

const singleOrPlaceholder = theme => ({
  bottom: 0,
  color: theme.colorGrayDark,
  left: 0,
  lineHeight: '32px',
  paddingLeft: '10px',
  paddingRight: '10px',
  position: 'absolute',
  right: 0,
  top: 0,
  maxWidth: '100%',
  overflow: 'hidden',
  textOverflow: 'ellipsis',
  whiteSpace: 'nowrap'
});

const styles = ({ theme, disabled }) => {
  const values = {
    boxSizing: 'border-box',
    fontSize: '0.86667rem'
  };

  return {
    ...values,
    '& div': values,
    '& input': values,
    '& span': values,

    flex: theme.flex,
    margin: theme.margin,
    width: theme.width,
    display: theme.display,
    verticalAlign: theme.verticalAlign,
    position: 'relative',
    opacity: disabled ? 0.5 : 1,

    '& .Select-control': {
      backgroundColor: disabled ? theme.color.smoke : theme.colorWhite,
      border: `1px solid ${theme.color.hail}`,
      borderRadius: theme.borderRadius,
      color: theme.color.charcoal,
      cursor: 'default',
      display: 'table',
      borderSpacing: 0,
      borderCollapse: 'separate',
      height: '32px',
      outline: 'none',
      overflow: 'hidden',
      position: 'relative',
      width: '100%',
      transition: 'border-color 0.2s ease'
    },
    '& .Select-control .Select-input:focus': {
      outline: 'none'
    },
    '& .Select-menu-outer': {
      position: 'relative'
    },
    '&:hover .Select-control': {
      borderColor: theme.colorBlueDark
    },
    '& .is-focused .Select-control': {
      borderColor: theme.colorBlueDark
    },
    '& .is-open .Select-control': {
      borderColor: theme.color.hail
    },
    '& .Select-placeholder': singleOrPlaceholder(theme),
    '& .Select--single > .Select-control .Select-value': singleOrPlaceholder(
      theme
    ),
    '& .Select-input': {
      height: '32px',
      paddingLeft: '10px',
      paddingRight: '10px',
      verticalAlign: 'middle'
    },
    '& .Select-input > input': {
      width: '100%',
      background: 'none transparent',
      border: ' 0 none',
      cursor: 'default',
      display: 'inline-block',
      fontFamily: 'inherit',
      fontSize: 'inherit',
      margin: 0,
      outline: 'none',
      lineHeight: '14px',
      padding: 0
    },
    '& .Select-noresults': {
      boxVizing: 'border-box',
      color: theme.color.cement,
      cursor: 'default',
      display: 'block',
      padding: '8px 10px'
    },
    '& .Select-aria-only': {
      display: 'inline-block',
      height: '1px',
      width: '1px',
      margin: '-1px',
      clip: 'rect(0, 0, 0, 0)',
      overflow: 'hidden'
    },
    '& .Select-arrow-zone': {
      cursor: 'pointer',
      display: 'table-cell',
      position: 'relative',
      textAlign: 'center',
      verticalAlign: 'middle',
      width: '25px',
      paddingRight: '5px',
      top: '1px'
    },
    '& .Select-clear-zone': {
      color: theme.color.cement,
      cursor: ' pointer',
      display: 'table-cell',
      position: 'relative',
      top: '1px',
      textAlign: 'center',
      verticalAlign: 'middle',
      width: '17px'
    }
  };
};

export default createComponent(styles, Select);
<|endoftext|>


<commit_before>define([
        '../shared/EventSource',
        '../shared/Info',
        '../shared/Utilities',
        '../host/StateSnapshot',
    ], function (
        EventSource,
        info,
        util,
        StateSnapshot
    ) {

    var Controller = function () {
        this.output = {};

        this.currentFrame = null;
        this.callIndex = 0;
        this.stepping = false;

        this.stepCompleted = new EventSource("stepCompleted");
    };

    Controller.prototype.setOutput = function (canvas) {
        this.output.canvas = canvas;

        // TODO: pull attributes from source somehow?
        var gl = this.output.gl = util.getWebGLContext(canvas, null, null);
        info.initialize(gl);
    };

    Controller.prototype.reset = function (force) {
        if (this.currentFrame) {
            var gl = this.output.gl;
            if (force) {
                this.currentFrame.cleanup(gl);
            }
        }

        this.currentFrame = null;
        this.callIndex = 0;
        this.stepping = false;
    };

    Controller.prototype.getCurrentState = function () {
        if (!this.output.gl) return null;
        return new StateSnapshot(this.output.gl);
    };

    Controller.prototype.openFrame = function (frame, suppressEvents, force, useDepthShader) {
        var gl = this.output.gl;

        this.currentFrame = frame;

        if (useDepthShader) {
            frame.switchMirrors();
        } else {
            frame.switchMirrors("depth");
        }

        var depthShader = null;
        if (useDepthShader) {
            depthShader =
                "precision highp float;\n" +
                "vec4 packFloatToVec4i(const float value) {\n" +
                "   const vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n" +
                "   const vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n" +
                "   vec4 res = fract(value * bitSh);\n" +
                "   res -= res.xxyz * bitMsk;\n" +
                "   return res;\n" +
                "}\n" +
                "void main() {\n" +
                "   gl_FragColor = packFloatToVec4i(gl_FragCoord.z);\n" +
                //"   gl_FragColor = vec4(gl_FragCoord.z, gl_FragCoord.z, gl_FragCoord.z, 1.0);\n" +
                "}";
        }
        frame.makeActive(gl, force, {
            fragmentShaderOverride: depthShader,
            ignoreTextureUploads: useDepthShader
        });

        this.beginStepping();
        this.callIndex = 0;
        this.endStepping(suppressEvents);
    };

    function emitMark(mark) {
        console.log("mark hit");
    };

    Controller.prototype.issueCall = function (callIndex) {
        var gl = this.output.gl;

        if (this.currentFrame == null) {
            return false;
        }
        if (this.callIndex + 1 > this.currentFrame.calls.length) {
            return false;
        }

        if (callIndex >= 0) {
            this.callIndex = callIndex;
        } else {
            callIndex = this.callIndex;
        }

        var call = this.currentFrame.calls[callIndex];

        switch (call.type) {
            case 0: // MARK
                emitMark(call);
                break;
            case 1: // GL
                call.emit(gl);
                break;
        }

        return true;
    };

    Controller.prototype.beginStepping = function () {
        this.stepping = true;
    };

    Controller.prototype.endStepping = function (suppressEvents, overrideCallIndex) {
        this.stepping = false;
        if (!suppressEvents) {
            var callIndex = overrideCallIndex || this.callIndex;
            this.stepCompleted.fire(callIndex);
        }
    };

    Controller.prototype.stepUntil = function (callIndex) {
        if (this.callIndex > callIndex) {
            var frame = this.currentFrame;
            this.reset();
            this.openFrame(frame);
        }
        var wasStepping = this.stepping;
        if (!wasStepping) {
            this.beginStepping();
        }
        while (this.callIndex <= callIndex) {
            if (this.issueCall()) {
                this.callIndex++;
            } else {
                this.endStepping();
                return false;
            }
        }
        if (!wasStepping) {
            this.endStepping();
        }
        return true;
    };

    Controller.prototype.stepForward = function () {
        return this.stepUntil(this.callIndex);
    };

    Controller.prototype.stepBackward = function () {
        if (this.callIndex <= 1) {
            return false;
        }
        return this.stepUntil(this.callIndex - 2);
    };

    Controller.prototype.stepUntilError = function () {
        //
    };

    Controller.prototype.stepUntilDraw = function () {
        this.beginStepping();
        while (this.issueCall()) {
            var call = this.currentFrame.calls[this.callIndex];
            var funcInfo = info.functions[call.name];
            if (funcInfo.type == info.FunctionType.DRAW) {
                this.callIndex++;
                break;
            } else {
                this.callIndex++;
            }
        }
        this.endStepping();
    };

    Controller.prototype.stepUntilEnd = function () {
        this.beginStepping();
        while (this.stepForward());
        this.endStepping();
    };

    Controller.prototype.runFrame = function (frame) {
        this.openFrame(frame);
        this.stepUntilEnd();
    };

    Controller.prototype.runIsolatedDraw = function (frame, targetCall) {
        this.openFrame(frame, true);

        var gl = this.output.gl;

        this.beginStepping();
        while (true) {
            var call = this.currentFrame.calls[this.callIndex];
            var shouldExec = false;

            if (call.name == "clear") {
                // Allow clear calls
                shouldExec = true;
            } else if (call == targetCall) {
                // The target call
                shouldExec = true;

                // Before executing the call, clear the color buffer
                var oldColorMask = gl.getParameter(gl.COLOR_WRITEMASK);
                var oldColorClearValue = gl.getParameter(gl.COLOR_CLEAR_VALUE);
                gl.colorMask(true, true, true, true);
                gl.clearColor(0, 0, 0, 0);
                gl.clear(gl.COLOR_BUFFER_BIT);
                gl.colorMask(oldColorMask[0], oldColorMask[1], oldColorMask[2], oldColorMask[3]);
                gl.clearColor(oldColorClearValue[0], oldColorClearValue[1], oldColorClearValue[2], oldColorClearValue[3]);
            } else {
                var funcInfo = info.functions[call.name];
                if (funcInfo.type == info.FunctionType.DRAW) {
                    // Ignore all other draws
                    shouldExec = false;
                } else {
                    shouldExec = true;
                }
            }

            if (shouldExec) {
                if (!this.issueCall()) {
                    break;
                }
            }

            this.callIndex++;
            if (call == targetCall) {
                break;
            }
        }

        var finalCallIndex = this.callIndex;

        this.openFrame(frame, true);

        this.endStepping(false, finalCallIndex);
    };

    function packFloatToVec4i(value) {
       //vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
       //vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
       //vec4 res = fract(value * bitSh);
       var r = value * 256 * 256 * 256;
       var g = value * 256 * 256;
       var b = value * 256;
       var a = value;
       r = r - Math.floor(r);
       g = g - Math.floor(g);
       b = b - Math.floor(b);
       a = a - Math.floor(a);
       //res -= res.xxyz * bitMsk;
       g -= r / 256.0;
       b -= g / 256.0;
       a -= b / 256.0;
       return [r, g, b, a];
    };

    Controller.prototype.runDepthDraw = function (frame, targetCall) {
        this.openFrame(frame, true, undefined, true);

        var gl = this.output.gl;

        this.beginStepping();
        while (true) {
            var call = this.currentFrame.calls[this.callIndex];
            var shouldExec = true;

            var arg0;
            switch (call.name) {
            case "clear":
                arg0 = call.args[0];
                // Only allow depth clears if depth mask is set
                if (gl.getParameter(gl.DEPTH_WRITEMASK) == true) {
                    call.args[0] = call.args[0] & gl.DEPTH_BUFFER_BIT;
                    if (arg0 & gl.DEPTH_BUFFER_BIT) {
                        call.args[0] |= gl.COLOR_BUFFER_BIT;
                    }
                    var d = gl.getParameter(gl.DEPTH_CLEAR_VALUE);
                    var vd = packFloatToVec4i(d);
                    gl.clearColor(vd[0], vd[1], vd[2], vd[3]);
                } else {
                    shouldExec = false;
                }
                break;
            case "drawArrays":
            case "drawElements":
                // Only allow draws if depth mask is set
                if (gl.getParameter(gl.DEPTH_WRITEMASK) == true) {
                    // Reset state to what we need
                    gl.disable(gl.BLEND);
                    gl.colorMask(true, true, true, true);
                } else {
                    shouldExec = false;
                }
                break;
            default:
                break;
            }

            if (shouldExec) {
                if (!this.issueCall()) {
                    break;
                }
            }

            switch (call.name) {
            case "clear":
                call.args[0] = arg0;
                break;
            default:
                break;
            }

            this.callIndex++;
            if (call == targetCall) {
                break;
            }
        }

        var finalCallIndex = this.callIndex;

        this.openFrame(frame, true);

        this.endStepping(false, finalCallIndex);
    };

    return Controller;

});
<commit_msg>Set TracePreview canvas size to match original canvas size<commit_after>define([
        '../shared/EventSource',
        '../shared/Info',
        '../shared/Utilities',
        '../host/StateSnapshot',
    ], function (
        EventSource,
        info,
        util,
        StateSnapshot
    ) {

    var Controller = function () {
        this.output = {};

        this.currentFrame = null;
        this.callIndex = 0;
        this.stepping = false;

        this.stepCompleted = new EventSource("stepCompleted");
    };

    Controller.prototype.setOutput = function (canvas) {
        this.output.canvas = canvas;

        // TODO: pull attributes from source somehow?
        var gl = this.output.gl = util.getWebGLContext(canvas, null, null);
        info.initialize(gl);
    };

    Controller.prototype.reset = function (force) {
        if (this.currentFrame) {
            var gl = this.output.gl;
            if (force) {
                this.currentFrame.cleanup(gl);
            }
        }

        this.currentFrame = null;
        this.callIndex = 0;
        this.stepping = false;
    };

    Controller.prototype.getCurrentState = function () {
        if (!this.output.gl) return null;
        return new StateSnapshot(this.output.gl);
    };

    Controller.prototype.openFrame = function (frame, suppressEvents, force, useDepthShader) {
        var gl = this.output.gl;

        // Canvas must match size when frame was captured otherwise viewport
        // and matrices etc will not match
        if (gl.canvas.width !== frame.canvasInfo.width || gl.canvas.heigth !== frame.canvasInfo.height) {
            gl.canvas.width = frame.canvasInfo.width;
            gl.canvas.height = frame.canvasInfo.height;
        }

        this.currentFrame = frame;

        if (useDepthShader) {
            frame.switchMirrors();
        } else {
            frame.switchMirrors("depth");
        }

        var depthShader = null;
        if (useDepthShader) {
            depthShader =
                "precision highp float;\n" +
                "vec4 packFloatToVec4i(const float value) {\n" +
                "   const vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n" +
                "   const vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n" +
                "   vec4 res = fract(value * bitSh);\n" +
                "   res -= res.xxyz * bitMsk;\n" +
                "   return res;\n" +
                "}\n" +
                "void main() {\n" +
                "   gl_FragColor = packFloatToVec4i(gl_FragCoord.z);\n" +
                //"   gl_FragColor = vec4(gl_FragCoord.z, gl_FragCoord.z, gl_FragCoord.z, 1.0);\n" +
                "}";
        }
        frame.makeActive(gl, force, {
            fragmentShaderOverride: depthShader,
            ignoreTextureUploads: useDepthShader
        });

        this.beginStepping();
        this.callIndex = 0;
        this.endStepping(suppressEvents);
    };

    function emitMark(mark) {
        console.log("mark hit");
    };

    Controller.prototype.issueCall = function (callIndex) {
        var gl = this.output.gl;

        if (this.currentFrame == null) {
            return false;
        }
        if (this.callIndex + 1 > this.currentFrame.calls.length) {
            return false;
        }

        if (callIndex >= 0) {
            this.callIndex = callIndex;
        } else {
            callIndex = this.callIndex;
        }

        var call = this.currentFrame.calls[callIndex];

        switch (call.type) {
            case 0: // MARK
                emitMark(call);
                break;
            case 1: // GL
                call.emit(gl);
                break;
        }

        return true;
    };

    Controller.prototype.beginStepping = function () {
        this.stepping = true;
    };

    Controller.prototype.endStepping = function (suppressEvents, overrideCallIndex) {
        this.stepping = false;
        if (!suppressEvents) {
            var callIndex = overrideCallIndex || this.callIndex;
            this.stepCompleted.fire(callIndex);
        }
    };

    Controller.prototype.stepUntil = function (callIndex) {
        if (this.callIndex > callIndex) {
            var frame = this.currentFrame;
            this.reset();
            this.openFrame(frame);
        }
        var wasStepping = this.stepping;
        if (!wasStepping) {
            this.beginStepping();
        }
        while (this.callIndex <= callIndex) {
            if (this.issueCall()) {
                this.callIndex++;
            } else {
                this.endStepping();
                return false;
            }
        }
        if (!wasStepping) {
            this.endStepping();
        }
        return true;
    };

    Controller.prototype.stepForward = function () {
        return this.stepUntil(this.callIndex);
    };

    Controller.prototype.stepBackward = function () {
        if (this.callIndex <= 1) {
            return false;
        }
        return this.stepUntil(this.callIndex - 2);
    };

    Controller.prototype.stepUntilError = function () {
        //
    };

    Controller.prototype.stepUntilDraw = function () {
        this.beginStepping();
        while (this.issueCall()) {
            var call = this.currentFrame.calls[this.callIndex];
            var funcInfo = info.functions[call.name];
            if (funcInfo.type == info.FunctionType.DRAW) {
                this.callIndex++;
                break;
            } else {
                this.callIndex++;
            }
        }
        this.endStepping();
    };

    Controller.prototype.stepUntilEnd = function () {
        this.beginStepping();
        while (this.stepForward());
        this.endStepping();
    };

    Controller.prototype.runFrame = function (frame) {
        this.openFrame(frame);
        this.stepUntilEnd();
    };

    Controller.prototype.runIsolatedDraw = function (frame, targetCall) {
        this.openFrame(frame, true);

        var gl = this.output.gl;

        this.beginStepping();
        while (true) {
            var call = this.currentFrame.calls[this.callIndex];
            var shouldExec = false;

            if (call.name == "clear") {
                // Allow clear calls
                shouldExec = true;
            } else if (call == targetCall) {
                // The target call
                shouldExec = true;

                // Before executing the call, clear the color buffer
                var oldColorMask = gl.getParameter(gl.COLOR_WRITEMASK);
                var oldColorClearValue = gl.getParameter(gl.COLOR_CLEAR_VALUE);
                gl.colorMask(true, true, true, true);
                gl.clearColor(0, 0, 0, 0);
                gl.clear(gl.COLOR_BUFFER_BIT);
                gl.colorMask(oldColorMask[0], oldColorMask[1], oldColorMask[2], oldColorMask[3]);
                gl.clearColor(oldColorClearValue[0], oldColorClearValue[1], oldColorClearValue[2], oldColorClearValue[3]);
            } else {
                var funcInfo = info.functions[call.name];
                if (funcInfo.type == info.FunctionType.DRAW) {
                    // Ignore all other draws
                    shouldExec = false;
                } else {
                    shouldExec = true;
                }
            }

            if (shouldExec) {
                if (!this.issueCall()) {
                    break;
                }
            }

            this.callIndex++;
            if (call == targetCall) {
                break;
            }
        }

        var finalCallIndex = this.callIndex;

        this.openFrame(frame, true);

        this.endStepping(false, finalCallIndex);
    };

    function packFloatToVec4i(value) {
       //vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
       //vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
       //vec4 res = fract(value * bitSh);
       var r = value * 256 * 256 * 256;
       var g = value * 256 * 256;
       var b = value * 256;
       var a = value;
       r = r - Math.floor(r);
       g = g - Math.floor(g);
       b = b - Math.floor(b);
       a = a - Math.floor(a);
       //res -= res.xxyz * bitMsk;
       g -= r / 256.0;
       b -= g / 256.0;
       a -= b / 256.0;
       return [r, g, b, a];
    };

    Controller.prototype.runDepthDraw = function (frame, targetCall) {
        this.openFrame(frame, true, undefined, true);

        var gl = this.output.gl;

        this.beginStepping();
        while (true) {
            var call = this.currentFrame.calls[this.callIndex];
            var shouldExec = true;

            var arg0;
            switch (call.name) {
            case "clear":
                arg0 = call.args[0];
                // Only allow depth clears if depth mask is set
                if (gl.getParameter(gl.DEPTH_WRITEMASK) == true) {
                    call.args[0] = call.args[0] & gl.DEPTH_BUFFER_BIT;
                    if (arg0 & gl.DEPTH_BUFFER_BIT) {
                        call.args[0] |= gl.COLOR_BUFFER_BIT;
                    }
                    var d = gl.getParameter(gl.DEPTH_CLEAR_VALUE);
                    var vd = packFloatToVec4i(d);
                    gl.clearColor(vd[0], vd[1], vd[2], vd[3]);
                } else {
                    shouldExec = false;
                }
                break;
            case "drawArrays":
            case "drawElements":
                // Only allow draws if depth mask is set
                if (gl.getParameter(gl.DEPTH_WRITEMASK) == true) {
                    // Reset state to what we need
                    gl.disable(gl.BLEND);
                    gl.colorMask(true, true, true, true);
                } else {
                    shouldExec = false;
                }
                break;
            default:
                break;
            }

            if (shouldExec) {
                if (!this.issueCall()) {
                    break;
                }
            }

            switch (call.name) {
            case "clear":
                call.args[0] = arg0;
                break;
            default:
                break;
            }

            this.callIndex++;
            if (call == targetCall) {
                break;
            }
        }

        var finalCallIndex = this.callIndex;

        this.openFrame(frame, true);

        this.endStepping(false, finalCallIndex);
    };

    return Controller;

});
<|endoftext|>


<commit_before>const mongoCollections = require("../config/mongoCollections");
const forums = mongoCollections.forums;
const usersData = require("./users");

const uuidV4 = require("uuid/v4");

let exportedMethods = {
    getAllForums() {
        return forums().then((forumCollection) => {
            return forumCollection.find({}).toArray();
        });
    },
    getForumById(id) {
        return forums().then((forumCollection) => {
            return forumCollection.findOne({_id: id}).then((forum) => {
                if (!forum) throw "Forum not found";
                console.log(forum);
                return forum;
            });
        });
    },
    getForumByUser(userId) {
        return forums().then((forumsCollection) => {
            return forumsCollection.find({user: userId}).toArray();
        });
    },
    addForum(title, content, label, clothing, userId) {
        // TODO validate contents
        return forums().then((forumCollection) => {
            let newId = uuidV4();
            // TODO date
            let newForum = {
                _id: newId,
                user: userId,
                // datePosted: curDate,
                title: title,
                content: content,
                label: label,
                clothing: clothing,
                likes: [],
                comments: []
            };
            return forumCollection.insertOne(newForum)
                .then((forumInformation) => {
                    return exportedMethods.getForumById(newId);
                });
        });
    },
    addComment(forumId, userId, comment) {
        console.log("ADDING COMMENT")
        return forums().then((forumCollection) => {
            let newId = uuidV4();
            // TODO date
            let newComment = {
                _id: newId,
                // datePosted: curDate,
                content: comment,
                user: userId,
                likes: [],
                subthreads: []
            };
            return forumCollection.update(
                { _id: forumId },
                { $push: { comments: newComment }}
            ).then((forumInformation) => {
                console.log("Added comment");
                return exportedMethods.getForumById(forumId);
            }).catch((err) => {
                // err is unhandled promise rejection???????
                console.log("Error");
                console.log(err);
                return reject("Could not add comment");
            });
        });
    }
}

module.exports = exportedMethods;<commit_msg>Refactor error checking to create forum<commit_after>// Node Modules
const uuidV4 = require("uuid/v4");
// Custom Node Modules
const mongoCollections = require("../config/mongoCollections");
const forums = mongoCollections.forums;
const usersData = require("./users");

/**
 * Function checks that a string given is string with some number of
 * characters
 *
 * @params  {string} str string value to check for validity
 * @return  true if the string is valid; otherwise, return false
 */
function isValidString(str) {
	if ((str === undefined) || (typeof(str) !== "string") || (str.length <= 0)) {
		return false;
	}
	return true;
}

let exportedMethods = {
    getAllForums() {
        return forums().then((forumCollection) => {
            return forumCollection.find({}).toArray();
        });
    },
    getForumById(id) {
        return forums().then((forumCollection) => {
            return forumCollection.findOne({_id: id}).then((forum) => {
                if (!forum) throw "Forum not found";
                console.log(forum);
                return forum;
            });
        });
    },
    getForumByUser(userId) {
        return forums().then((forumsCollection) => {
            return forumsCollection.find({user: userId}).toArray();
        });
    },
    addForum(title, content, label, clothing, userId) {
        // TODO validate contents
        if (!isValidString(title)) {
            return Promise.reject('Invalid title for forum creation')
        }
        if (!isValidString(content)) {
            return Promise.reject('Invalid content for forum creation')
        }
        if (!isValidString(userId)) {
            return Promise.reject('Invalid id for forum creation')
        }
        // TODO: Maybe check that id is valid first?
        return forums().then((forumCollection) => {
            let newId = uuidV4();
            // TODO date
            let newForum = {
                _id: newId,
                user: userId,
                // datePosted: curDate,
                title: title,
                content: content,
                label: label,
                clothing: clothing,
                likes: [],
                comments: []
            };
            return forumCollection.insertOne(newForum)
                .then((forumInformation) => {
                    return exportedMethods.getForumById(newId);
                });
        });
    },
    addComment(forumId, userId, comment) {
        console.log("ADDING COMMENT")
        return forums().then((forumCollection) => {
            let newId = uuidV4();
            // TODO date
            let newComment = {
                _id: newId,
                // datePosted: curDate,
                content: comment,
                user: userId,
                likes: [],
                subthreads: []
            };
            return forumCollection.update(
                { _id: forumId },
                { $push: { comments: newComment }}
            ).then((forumInformation) => {
                console.log("Added comment");
                return exportedMethods.getForumById(forumId);
            }).catch((err) => {
                // err is unhandled promise rejection???????
                console.log("Error");
                console.log(err);
                return reject("Could not add comment");
            });
        });
    }
}

module.exports = exportedMethods;
<|endoftext|>


<commit_before>/**
 * Copyright JS Foundation and other contributors, http://js.foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var fs = require("fs");
var path = require("path");

var events;
var log;
var i18n;

var settings;
var disableNodePathScan = false;
var iconFileExtensions = [".png", ".gif"];

function init(runtime) {
    settings = runtime.settings;
    events = runtime.events;
    log = runtime.log;
    i18n = runtime.i18n;
}

function isIncluded(name) {
    if (settings.nodesIncludes) {
        for (var i=0;i<settings.nodesIncludes.length;i++) {
            if (settings.nodesIncludes[i] == name) {
                return true;
            }
        }
    } else {
        return true;
    }
    return false;
}

function isExcluded(name) {
     if (settings.nodesExcludes) {
        for (var i=0;i<settings.nodesExcludes.length;i++) {
            if (settings.nodesExcludes[i] == name) {
                return true;
            }
        }
    }
    return false;
}
function getLocalFile(file) {
    if (!isIncluded(path.basename(file)) || isExcluded(path.basename(file))) {
        return null;
    }
    try {
        fs.statSync(file.replace(/\.js$/,".html"));
        return {
            file:    file,
            module:  "node-red",
            name:    path.basename(file).replace(/^\d+-/,"").replace(/\.js$/,""),
            version: settings.version
        };
    } catch(err) {
        return null;
    }
}

/**
 * Synchronously walks the directory looking for node files.
 * Emits 'node-icon-dir' events for an icon dirs found
 * @param dir the directory to search
 * @return an array of fully-qualified paths to .js files
 */
function getLocalNodeFiles(dir) {
    dir = path.resolve(dir);

    var result = [];
    var files = [];
    var icons = [];
    try {
        files = fs.readdirSync(dir);
    } catch(err) {
        return result;
    }
    files.sort();
    files.forEach(function(fn) {
        var stats = fs.statSync(path.join(dir,fn));
        if (stats.isFile()) {
            if (/\.js$/.test(fn)) {
                var info = getLocalFile(path.join(dir,fn));
                if (info) {
                    result.push(info);
                }
            }
        } else if (stats.isDirectory()) {
            // Ignore /.dirs/, /lib/ /node_modules/
            if (!/^(\..*|lib|icons|node_modules|test|locales)$/.test(fn)) {
                var subDirResults = getLocalNodeFiles(path.join(dir,fn));
                result = result.concat(subDirResults.files);
                icons = icons.concat(subDirResults.icons);
            } else if (fn === "icons") {
                var iconList = scanIconDir(path.join(dir,fn));
                icons.push({path:path.join(dir,fn),icons:iconList});
            }
        }
    });
    return {files: result, icons: icons}
}

function scanDirForNodesModules(dir,moduleName) {
    var results = [];
    var scopeName;
    try {
        var files = fs.readdirSync(dir);
        if (moduleName) {
            var m = /^(?:(@[^/]+)[/])?([^@/]+)/.exec(moduleName);
            if (m) {
                scopeName = m[1];
                moduleName = m[2];
            }
        }
        for (var i=0;i<files.length;i++) {
            var fn = files[i];
            if (/^@/.test(fn)) {
                if (scopeName && scopeName === fn) {
                    // Looking for a specific scope/module
                    results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
                    break;
                } else {
                    results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
                }
            } else {
                if (isIncluded(fn) && !isExcluded(fn) && (!moduleName || fn == moduleName)) {
                    var pkgfn = path.join(dir,fn,"package.json");
                    try {
                        var pkg = require(pkgfn);
                        if (pkg['node-red']) {
                            var moduleDir = path.join(dir,fn);
                            results.push({dir:moduleDir,package:pkg});
                        }
                    } catch(err) {
                        if (err.code != "MODULE_NOT_FOUND") {
                            // TODO: handle unexpected error
                        }
                    }
                    if (fn == moduleName) {
                        break;
                    }
                }
            }
        }
    } catch(err) {
    }
    return results;
}

/**
 * Scans the node_modules path for nodes
 * @param moduleName the name of the module to be found
 * @return a list of node modules: {dir,package}
 */
function scanTreeForNodesModules(moduleName) {
    var dir = settings.coreNodesDir;
    var results = [];
    var userDir;

    if (settings.userDir) {
        userDir = path.join(settings.userDir,"node_modules");
        results = scanDirForNodesModules(userDir,moduleName);
        results.forEach(function(r) { r.local = true; });
    }

    if (dir) {
        var up = path.resolve(path.join(dir,".."));
        while (up !== dir) {
            var pm = path.join(dir,"node_modules");
            if (pm != userDir) {
                results = results.concat(scanDirForNodesModules(pm,moduleName));
            }
            dir = up;
            up = path.resolve(path.join(dir,".."));
        }
    }
    return results;
}

function getModuleNodeFiles(module) {

    var moduleDir = module.dir;
    var pkg = module.package;

    var nodes = pkg['node-red'].nodes||{};
    var results = [];
    var iconDirs = [];
    var iconList = [];
    for (var n in nodes) {
        /* istanbul ignore else */
        if (nodes.hasOwnProperty(n)) {
            var file = path.join(moduleDir,nodes[n]);
            results.push({
                file:    file,
                module:  pkg.name,
                name:    n,
                version: pkg.version
            });
            var iconDir = path.join(moduleDir,path.dirname(nodes[n]),"icons");
            if (iconDirs.indexOf(iconDir) == -1) {
                try {
                    fs.statSync(iconDir);
                    var icons = scanIconDir(iconDir);
                    iconList.push({path:iconDir,icons:icons});
                    iconDirs.push(iconDir);
                } catch(err) {
                }
            }
        }
    }
    var result = {files:results,icons:iconList};

    var examplesDir = path.join(moduleDir,"examples");
    try {
        fs.statSync(examplesDir)
        events.emit("node-examples-dir",{name:pkg.name,path:examplesDir});
    } catch(err) {
    }
    return result;
}

function getNodeFiles(disableNodePathScan) {
    var dir;
    // Find all of the nodes to load
    var nodeFiles = [];
    var results;

    var dir = path.resolve(__dirname + '/../../../../public/icons');
    var iconList = [{path:dir,icons:scanIconDir(dir)}];

    if (settings.coreNodesDir) {
        results = getLocalNodeFiles(path.resolve(settings.coreNodesDir));
        nodeFiles = nodeFiles.concat(results.files);
        iconList = iconList.concat(results.icons);

        var defaultLocalesPath = path.join(settings.coreNodesDir,"core","locales");
        i18n.registerMessageCatalog("node-red",defaultLocalesPath,"messages.json");
    }

    if (settings.userDir) {
        dir = path.join(settings.userDir,"lib","icons");
        var icons = scanIconDir(dir);
        if (icons.length > 0) {
            iconList.push({path:dir,icons:icons});
        }

        dir = path.join(settings.userDir,"nodes");
        results = getLocalNodeFiles(path.resolve(dir));
        nodeFiles = nodeFiles.concat(results.files);
        iconList = iconList.concat(results.icons);
    }
    if (settings.nodesDir) {
        dir = settings.nodesDir;
        if (typeof settings.nodesDir == "string") {
            dir = [dir];
        }
        for (var i=0;i<dir.length;i++) {
            results = getLocalNodeFiles(dir[i]);
            nodeFiles = nodeFiles.concat(results.files);
            iconList = iconList.concat(results.icons);
        }
    }

    var nodeList = {
        "node-red": {
            name: "node-red",
            version: settings.version,
            nodes: {},
            icons: iconList
        }
    }
    nodeFiles.forEach(function(node) {
        nodeList["node-red"].nodes[node.name] = node;
    });

    if (!disableNodePathScan) {
        var moduleFiles = scanTreeForNodesModules();
        moduleFiles.forEach(function(moduleFile) {
            var nodeModuleFiles = getModuleNodeFiles(moduleFile);
            nodeList[moduleFile.package.name] = {
                name: moduleFile.package.name,
                version: moduleFile.package.version,
                path: moduleFile.dir,
                local: moduleFile.local||false,
                nodes: {},
                icons: nodeModuleFiles.icons
            };
            if (moduleFile.package['node-red'].version) {
                nodeList[moduleFile.package.name].redVersion = moduleFile.package['node-red'].version;
            }
            nodeModuleFiles.files.forEach(function(node) {
                node.local = moduleFile.local||false;
                nodeList[moduleFile.package.name].nodes[node.name] = node;
            });
            nodeFiles = nodeFiles.concat(nodeModuleFiles.files);
        });
    } else {
        // console.log("node path scan disabled");
    }
    return nodeList;
}

function getModuleFiles(module) {
    var nodeList = {};

    var moduleFiles = scanTreeForNodesModules(module);
    if (moduleFiles.length === 0) {
        var err = new Error(log._("nodes.registry.localfilesystem.module-not-found", {module:module}));
        err.code = 'MODULE_NOT_FOUND';
        throw err;
    }

    moduleFiles.forEach(function(moduleFile) {
        var nodeModuleFiles = getModuleNodeFiles(moduleFile);
        nodeList[moduleFile.package.name] = {
            name: moduleFile.package.name,
            version: moduleFile.package.version,
            nodes: {},
            icons: nodeModuleFiles.icons
        };
        if (moduleFile.package['node-red'].version) {
            nodeList[moduleFile.package.name].redVersion = moduleFile.package['node-red'].version;
        }
        nodeModuleFiles.files.forEach(function(node) {
            nodeList[moduleFile.package.name].nodes[node.name] = node;
            nodeList[moduleFile.package.name].nodes[node.name].local = moduleFile.local || false;
        });
    });
    return nodeList;
}

function scanIconDir(dir) {
    var iconList = [];
    try {
        var files = fs.readdirSync(dir);
        files.forEach(function(file) {
            var stats = fs.statSync(path.join(dir, file));
            if (stats.isFile() && iconFileExtensions.indexOf(path.extname(file)) !== -1) {
                iconList.push(file);
            }
        });
    } catch(err) {
    }
    return iconList;
}

module.exports = {
    init: init,
    getNodeFiles: getNodeFiles,
    getLocalFile: getLocalFile,
    getModuleFiles: getModuleFiles
}
<commit_msg>Handle loading empty nodesDir<commit_after>/**
 * Copyright JS Foundation and other contributors, http://js.foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var fs = require("fs");
var path = require("path");

var events;
var log;
var i18n;

var settings;
var disableNodePathScan = false;
var iconFileExtensions = [".png", ".gif"];

function init(runtime) {
    settings = runtime.settings;
    events = runtime.events;
    log = runtime.log;
    i18n = runtime.i18n;
}

function isIncluded(name) {
    if (settings.nodesIncludes) {
        for (var i=0;i<settings.nodesIncludes.length;i++) {
            if (settings.nodesIncludes[i] == name) {
                return true;
            }
        }
    } else {
        return true;
    }
    return false;
}

function isExcluded(name) {
     if (settings.nodesExcludes) {
        for (var i=0;i<settings.nodesExcludes.length;i++) {
            if (settings.nodesExcludes[i] == name) {
                return true;
            }
        }
    }
    return false;
}
function getLocalFile(file) {
    if (!isIncluded(path.basename(file)) || isExcluded(path.basename(file))) {
        return null;
    }
    try {
        fs.statSync(file.replace(/\.js$/,".html"));
        return {
            file:    file,
            module:  "node-red",
            name:    path.basename(file).replace(/^\d+-/,"").replace(/\.js$/,""),
            version: settings.version
        };
    } catch(err) {
        return null;
    }
}

/**
 * Synchronously walks the directory looking for node files.
 * Emits 'node-icon-dir' events for an icon dirs found
 * @param dir the directory to search
 * @return an array of fully-qualified paths to .js files
 */
function getLocalNodeFiles(dir) {
    dir = path.resolve(dir);

    var result = [];
    var files = [];
    var icons = [];
    try {
        files = fs.readdirSync(dir);
    } catch(err) {
        return {files: [], icons: []};
    }
    files.sort();
    files.forEach(function(fn) {
        var stats = fs.statSync(path.join(dir,fn));
        if (stats.isFile()) {
            if (/\.js$/.test(fn)) {
                var info = getLocalFile(path.join(dir,fn));
                if (info) {
                    result.push(info);
                }
            }
        } else if (stats.isDirectory()) {
            // Ignore /.dirs/, /lib/ /node_modules/
            if (!/^(\..*|lib|icons|node_modules|test|locales)$/.test(fn)) {
                var subDirResults = getLocalNodeFiles(path.join(dir,fn));
                result = result.concat(subDirResults.files);
                icons = icons.concat(subDirResults.icons);
            } else if (fn === "icons") {
                var iconList = scanIconDir(path.join(dir,fn));
                icons.push({path:path.join(dir,fn),icons:iconList});
            }
        }
    });
    return {files: result, icons: icons}
}

function scanDirForNodesModules(dir,moduleName) {
    var results = [];
    var scopeName;
    try {
        var files = fs.readdirSync(dir);
        if (moduleName) {
            var m = /^(?:(@[^/]+)[/])?([^@/]+)/.exec(moduleName);
            if (m) {
                scopeName = m[1];
                moduleName = m[2];
            }
        }
        for (var i=0;i<files.length;i++) {
            var fn = files[i];
            if (/^@/.test(fn)) {
                if (scopeName && scopeName === fn) {
                    // Looking for a specific scope/module
                    results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
                    break;
                } else {
                    results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
                }
            } else {
                if (isIncluded(fn) && !isExcluded(fn) && (!moduleName || fn == moduleName)) {
                    var pkgfn = path.join(dir,fn,"package.json");
                    try {
                        var pkg = require(pkgfn);
                        if (pkg['node-red']) {
                            var moduleDir = path.join(dir,fn);
                            results.push({dir:moduleDir,package:pkg});
                        }
                    } catch(err) {
                        if (err.code != "MODULE_NOT_FOUND") {
                            // TODO: handle unexpected error
                        }
                    }
                    if (fn == moduleName) {
                        break;
                    }
                }
            }
        }
    } catch(err) {
    }
    return results;
}

/**
 * Scans the node_modules path for nodes
 * @param moduleName the name of the module to be found
 * @return a list of node modules: {dir,package}
 */
function scanTreeForNodesModules(moduleName) {
    var dir = settings.coreNodesDir;
    var results = [];
    var userDir;

    if (settings.userDir) {
        userDir = path.join(settings.userDir,"node_modules");
        results = scanDirForNodesModules(userDir,moduleName);
        results.forEach(function(r) { r.local = true; });
    }

    if (dir) {
        var up = path.resolve(path.join(dir,".."));
        while (up !== dir) {
            var pm = path.join(dir,"node_modules");
            if (pm != userDir) {
                results = results.concat(scanDirForNodesModules(pm,moduleName));
            }
            dir = up;
            up = path.resolve(path.join(dir,".."));
        }
    }
    return results;
}

function getModuleNodeFiles(module) {

    var moduleDir = module.dir;
    var pkg = module.package;

    var nodes = pkg['node-red'].nodes||{};
    var results = [];
    var iconDirs = [];
    var iconList = [];
    for (var n in nodes) {
        /* istanbul ignore else */
        if (nodes.hasOwnProperty(n)) {
            var file = path.join(moduleDir,nodes[n]);
            results.push({
                file:    file,
                module:  pkg.name,
                name:    n,
                version: pkg.version
            });
            var iconDir = path.join(moduleDir,path.dirname(nodes[n]),"icons");
            if (iconDirs.indexOf(iconDir) == -1) {
                try {
                    fs.statSync(iconDir);
                    var icons = scanIconDir(iconDir);
                    iconList.push({path:iconDir,icons:icons});
                    iconDirs.push(iconDir);
                } catch(err) {
                }
            }
        }
    }
    var result = {files:results,icons:iconList};

    var examplesDir = path.join(moduleDir,"examples");
    try {
        fs.statSync(examplesDir)
        events.emit("node-examples-dir",{name:pkg.name,path:examplesDir});
    } catch(err) {
    }
    return result;
}

function getNodeFiles(disableNodePathScan) {
    var dir;
    // Find all of the nodes to load
    var nodeFiles = [];
    var results;

    var dir = path.resolve(__dirname + '/../../../../public/icons');
    var iconList = [{path:dir,icons:scanIconDir(dir)}];

    if (settings.coreNodesDir) {
        results = getLocalNodeFiles(path.resolve(settings.coreNodesDir));
        nodeFiles = nodeFiles.concat(results.files);
        iconList = iconList.concat(results.icons);

        var defaultLocalesPath = path.join(settings.coreNodesDir,"core","locales");
        i18n.registerMessageCatalog("node-red",defaultLocalesPath,"messages.json");
    }

    if (settings.userDir) {
        dir = path.join(settings.userDir,"lib","icons");
        var icons = scanIconDir(dir);
        if (icons.length > 0) {
            iconList.push({path:dir,icons:icons});
        }

        dir = path.join(settings.userDir,"nodes");
        results = getLocalNodeFiles(path.resolve(dir));
        nodeFiles = nodeFiles.concat(results.files);
        iconList = iconList.concat(results.icons);
    }
    if (settings.nodesDir) {
        dir = settings.nodesDir;
        if (typeof settings.nodesDir == "string") {
            dir = [dir];
        }
        for (var i=0;i<dir.length;i++) {
            results = getLocalNodeFiles(dir[i]);
            nodeFiles = nodeFiles.concat(results.files);
            iconList = iconList.concat(results.icons);
        }
    }

    var nodeList = {
        "node-red": {
            name: "node-red",
            version: settings.version,
            nodes: {},
            icons: iconList
        }
    }
    nodeFiles.forEach(function(node) {
        nodeList["node-red"].nodes[node.name] = node;
    });

    if (!disableNodePathScan) {
        var moduleFiles = scanTreeForNodesModules();
        moduleFiles.forEach(function(moduleFile) {
            var nodeModuleFiles = getModuleNodeFiles(moduleFile);
            nodeList[moduleFile.package.name] = {
                name: moduleFile.package.name,
                version: moduleFile.package.version,
                path: moduleFile.dir,
                local: moduleFile.local||false,
                nodes: {},
                icons: nodeModuleFiles.icons
            };
            if (moduleFile.package['node-red'].version) {
                nodeList[moduleFile.package.name].redVersion = moduleFile.package['node-red'].version;
            }
            nodeModuleFiles.files.forEach(function(node) {
                node.local = moduleFile.local||false;
                nodeList[moduleFile.package.name].nodes[node.name] = node;
            });
            nodeFiles = nodeFiles.concat(nodeModuleFiles.files);
        });
    } else {
        // console.log("node path scan disabled");
    }
    return nodeList;
}

function getModuleFiles(module) {
    var nodeList = {};

    var moduleFiles = scanTreeForNodesModules(module);
    if (moduleFiles.length === 0) {
        var err = new Error(log._("nodes.registry.localfilesystem.module-not-found", {module:module}));
        err.code = 'MODULE_NOT_FOUND';
        throw err;
    }

    moduleFiles.forEach(function(moduleFile) {
        var nodeModuleFiles = getModuleNodeFiles(moduleFile);
        nodeList[moduleFile.package.name] = {
            name: moduleFile.package.name,
            version: moduleFile.package.version,
            nodes: {},
            icons: nodeModuleFiles.icons
        };
        if (moduleFile.package['node-red'].version) {
            nodeList[moduleFile.package.name].redVersion = moduleFile.package['node-red'].version;
        }
        nodeModuleFiles.files.forEach(function(node) {
            nodeList[moduleFile.package.name].nodes[node.name] = node;
            nodeList[moduleFile.package.name].nodes[node.name].local = moduleFile.local || false;
        });
    });
    return nodeList;
}

function scanIconDir(dir) {
    var iconList = [];
    try {
        var files = fs.readdirSync(dir);
        files.forEach(function(file) {
            var stats = fs.statSync(path.join(dir, file));
            if (stats.isFile() && iconFileExtensions.indexOf(path.extname(file)) !== -1) {
                iconList.push(file);
            }
        });
    } catch(err) {
    }
    return iconList;
}

module.exports = {
    init: init,
    getNodeFiles: getNodeFiles,
    getLocalFile: getLocalFile,
    getModuleFiles: getModuleFiles
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/leskoptevTribarva/01.jpg'),
  require('../../images/animals/leskoptevTribarva/02.jpg'),
  require('../../images/animals/leskoptevTribarva/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/leskoptevTribarva/01-thumb.jpg'),
  require('../../images/animals/leskoptevTribarva/02-thumb.jpg'),
  require('../../images/animals/leskoptevTribarva/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
          Dovolte, abychom se představili. Jsme tři ptáci leskoptváci. Žijeme tady v zoo už nějaký pátek, ale všechny leskoptve pocházejí z Afriky. Jestli jste Afriku někdy viděli na mapě, víte, že má na pravé straně takový roh, úplně jako nosorožec. A na tomhle rohu my žijeme. Nepatříme mezi vodní ptáky, máme raději sucho. Často se uhnízdíme taky u lidských sídel. Dobře se nám tam totiž hledá potrava. Krmíme se hlavně hmyzem a různými bobulemi.
        </AnimalText>
      <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Když jste slyšeli jméno leskoptev, možná vám to připomnělo koroptev. To je ale podobnost úplně náhodná! My jsme menší a barevnější. Měříme necelých 20 centimetrů a vážíme 60 gramů. To je jako napůl snězený sáček bonbonů.
        </AnimalText>
      <InPageImage indexes={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          I když tady v zoo jsme samí kluci, máme iVsamičky. Ty kladou obvykle čtyři vejce, z nichž se po dvou týdnech vylíhnou malá leskoptvata. Hnízda si stavíme v trnitých větvích – a pokud je těch trnů málo, nataháme si kolem hnízda další větve, abychom byli pořádně chránění. Někdy se nám ale hnízdo stavět nechce. Když nás takhle přemůže lenost, kladou naše samičky vajíčka do hnízd jiných ptáků, jmenují se snovači. U vás takhle kladou vajíčka do cizích hnízd kukačky. My jsme v něčem ale trochu zákeřnější. Když by se totiž naše vajíčka do hnízd nevešla, prostě cizí vajíčka vyhážeme ven.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<commit_msg>Update leskoptevTribarva.child.js<commit_after>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/leskoptevTribarva/01.jpg'),
  require('../../images/animals/leskoptevTribarva/02.jpg'),
  require('../../images/animals/leskoptevTribarva/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/leskoptevTribarva/01-thumb.jpg'),
  require('../../images/animals/leskoptevTribarva/02-thumb.jpg'),
  require('../../images/animals/leskoptevTribarva/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
          Dovolte, abychom se představili. Jsme tři ptáci leskoptváci. Žijeme tady v zoo už nějaký pátek, ale všechny leskoptve pocházejí z Afriky. Jestli jste Afriku někdy viděli na mapě, víte, že má na pravé straně takový roh, úplně jako nosorožec. A na tomhle rohu my žijeme. Nepatříme mezi vodní ptáky, máme raději sucho. Často se uhnízdíme taky u lidských sídel. Dobře se nám tam totiž hledá potrava. Krmíme se hlavně hmyzem a různými bobulemi.
        </AnimalText>
      <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Když jste slyšeli jméno leskoptev, možná vám to připomnělo koroptev. To je ale podobnost úplně náhodná! My jsme menší a barevnější. Měříme necelých 20 centimetrů a vážíme 60 gramů. To je jako napůl snězený sáček bonbonů.
        </AnimalText>
      <InPageImage indexes={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          I když tady v zoo jsme samí kluci, máme i samičky. Ty kladou obvykle čtyři vejce, z nichž se po dvou týdnech vylíhnou malá leskoptvata. Hnízda si stavíme v trnitých větvích – a pokud je těch trnů málo, nataháme si kolem hnízda další větve, abychom byli pořádně chránění. Někdy se nám ale hnízdo stavět nechce. Když nás takhle přemůže lenost, kladou naše samičky vajíčka do hnízd jiných ptáků, jmenují se snovači. U vás takhle kladou vajíčka do cizích hnízd kukačky. My jsme v něčem ale trochu zákeřnější. Když by se totiž naše vajíčka do hnízd nevešla, prostě cizí vajíčka vyhážeme ven.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { graphql } from 'react-apollo';

import mapErrors from 'react/util/mapErrors';

import createChannelMutation from 'react/components/NewChannelForm/mutations/createChannel';

import Text from 'react/components/UI/Text';
import TitledDialog from 'react/components/UI/TitledDialog';
import { Input, Textarea, Label, LabelledCheckbox, LabelledInput } from 'react/components/UI/Inputs';
import ChannelVisibilityPulldown from 'react/components/ChannelVisibilityPulldown';
import NewChannelGroups from 'react/components/NewChannelForm/components/NewChannelGroups';

class NewChannelForm extends Component {
  static propTypes = {
    createChannel: PropTypes.func.isRequired,
    onClose: PropTypes.func.isRequired,
  }

  state = {
    mode: 'resting',
    title: '',
    description: '',
    visibility: 'CLOSED',
    group_id: null,
    visit_channel: true,
    errorMessage: null,
    attributeErrors: {},
  }

  handleInput = fieldName => ({ target: { value: fieldValue } }) =>
    this.setState(prevState => ({
      [fieldName]: fieldValue,
      attributeErrors: {
        ...prevState.attributeErrors,
        [fieldName]: null, // Clear specific error once typing begins
      },
    }));

  handleCheckbox = fieldName => ({ target: { checked } }) =>
    this.setState({ [fieldName]: checked })
      type='checkbox'

  handleVisitChannel = this.handleCheckbox('visit_channel')
  handleTitle = this.handleInput('title')
  handleDescription = this.handleInput('description')

  handleVisibility = visibility =>
    this.setState({ visibility });

  handleAuthor = (group_id) => {
    if (group_id === 0) return;
    this.setState({ group_id });
  }

  handleSubmit = (e) => {
    e.preventDefault();

    const { createChannel, onClose } = this.props;
    const {
      title, description, visibility, group_id, visit_channel,
    } = this.state;

    const variables = {
      title, description, visibility, group_id,
    };

    this.setState({ mode: 'creating' });

    return createChannel({ variables })
      .then(({ data: { create_channel: { channel } } }) => {
        if (visit_channel) {
          window.location.href = channel.href;
          this.setState({ mode: 'redirecting' });
          return;
        }

        this.setState({ mode: 'success' });
        setTimeout(() => onClose(), 500);
      })
      .catch((err) => {
        this.setState({
          mode: 'error',
          ...mapErrors(err),
        });
      });
  }

  render() {
    const {
      mode,
      title,
      description,
      visibility,
      visit_channel,
      errorMessage,
      attributeErrors,
    } = this.state;

    return (
      <TitledDialog
        title="New channel"
        label={{
          resting: 'Create channel',
          creating: 'Creating...',
          redirecting: 'Redirecting...',
          success: 'Created',
          error: 'Error',
        }[mode]}
        onDone={this.handleSubmit}
      >

          <LabelledInput mt={6} mb={7}>

              Name

            <Input
              f={7}
              color={`channel.${visibility.toLowerCase()}`}
              placeholder="Type channel name"
              borderless
              autoFocus
              required
              value={title}
              onChange={this.handleTitle}
              errorMessage={attributeErrors.title}
            />
          </LabelledInput>

          <LabelledInput my={6} alignItems="start">

              Author

            <NewChannelGroups
              onChange={this.handleAuthor}
            />
          </LabelledInput>

          <LabelledInput my={6} alignItems="start">

              Description

            <Textarea
              placeholder="Describe your channel here"
              rows={4}
              value={description}
              onChange={this.handleDescription}
              errorMessage={attributeErrors.description}
            />
          </LabelledInput>

          <LabelledInput my={6} alignItems="start">

              Privacy

              <ChannelVisibilityPulldown
                value={visibility.toUpperCase()}
                onChange={this.handleVisibility}
              />

          </LabelledInput>

          <LabelledInput mt={6} mb={8}>

            <LabelledCheckbox
              onChange={this.handleVisitChannel}
              checked={visit_channel}
            >
              Visit channel
            </LabelledCheckbox>
          </LabelledInput>

          {mode === 'error' &&
            <Text mb={6} f={2} color="state.alert" textAlign="center">
              {errorMessage}
            </Text>
          }

      </TitledDialog>
    );
  }
}

export default graphql(createChannelMutation, {
  name: 'createChannel',
})(NewChannelForm);
<commit_msg>[GroupsDisable] Disable author field in NewChannelForm<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { graphql } from 'react-apollo';

import mapErrors from 'react/util/mapErrors';

import createChannelMutation from 'react/components/NewChannelForm/mutations/createChannel';

import Text from 'react/components/UI/Text';
import TitledDialog from 'react/components/UI/TitledDialog';
import { Input, Textarea, Label, LabelledCheckbox, LabelledInput } from 'react/components/UI/Inputs';
import ChannelVisibilityPulldown from 'react/components/ChannelVisibilityPulldown';

class NewChannelForm extends Component {
  static propTypes = {
    createChannel: PropTypes.func.isRequired,
    onClose: PropTypes.func.isRequired,
  }

  state = {
    mode: 'resting',
    title: '',
    description: '',
    visibility: 'CLOSED',
    visit_channel: true,
    errorMessage: null,
    attributeErrors: {},
  }

  handleInput = fieldName => ({ target: { value: fieldValue } }) =>
    this.setState(prevState => ({
      [fieldName]: fieldValue,
      attributeErrors: {
        ...prevState.attributeErrors,
        [fieldName]: null, // Clear specific error once typing begins
      },
    }));

  handleCheckbox = fieldName => ({ target: { checked } }) =>
    this.setState({ [fieldName]: checked })
      type='checkbox'

  handleVisitChannel = this.handleCheckbox('visit_channel')
  handleTitle = this.handleInput('title')
  handleDescription = this.handleInput('description')

  handleVisibility = visibility =>
    this.setState({ visibility });

  handleSubmit = (e) => {
    e.preventDefault();

    const { createChannel, onClose } = this.props;
    const {
      title, description, visibility, visit_channel,
    } = this.state;

    const variables = {
      title, description, visibility,
    };

    this.setState({ mode: 'creating' });

    return createChannel({ variables })
      .then(({ data: { create_channel: { channel } } }) => {
        if (visit_channel) {
          window.location.href = channel.href;
          this.setState({ mode: 'redirecting' });
          return;
        }

        this.setState({ mode: 'success' });
        setTimeout(() => onClose(), 500);
      })
      .catch((err) => {
        this.setState({
          mode: 'error',
          ...mapErrors(err),
        });
      });
  }

  render() {
    const {
      mode,
      title,
      description,
      visibility,
      visit_channel,
      errorMessage,
      attributeErrors,
    } = this.state;

    return (
      <TitledDialog
        title="New channel"
        label={{
          resting: 'Create channel',
          creating: 'Creating...',
          redirecting: 'Redirecting...',
          success: 'Created',
          error: 'Error',
        }[mode]}
        onDone={this.handleSubmit}
      >

          <LabelledInput mt={6} mb={7}>

              Name

            <Input
              f={7}
              color={`channel.${visibility.toLowerCase()}`}
              placeholder="Type channel name"
              borderless
              autoFocus
              required
              value={title}
              onChange={this.handleTitle}
              errorMessage={attributeErrors.title}
            />
          </LabelledInput>

          <LabelledInput my={6} alignItems="start">

              Description

            <Textarea
              placeholder="Describe your channel here"
              rows={4}
              value={description}
              onChange={this.handleDescription}
              errorMessage={attributeErrors.description}
            />
          </LabelledInput>

          <LabelledInput my={6} alignItems="start">

              Privacy

              <ChannelVisibilityPulldown
                value={visibility.toUpperCase()}
                onChange={this.handleVisibility}
              />

          </LabelledInput>

          <LabelledInput mt={6} mb={8}>

            <LabelledCheckbox
              onChange={this.handleVisitChannel}
              checked={visit_channel}
            >
              Visit channel
            </LabelledCheckbox>
          </LabelledInput>

          {mode === 'error' &&
            <Text mb={6} f={2} color="state.alert" textAlign="center">
              {errorMessage}
            </Text>
          }

      </TitledDialog>
    );
  }
}

export default graphql(createChannelMutation, {
  name: 'createChannel',
})(NewChannelForm);
<|endoftext|>


<commit_before>/**
 * @fileoverview RTCMediaHandler
 */

/* RTCMediaHandler
 * @class PeerConnection helper Class.
 * @param {JsSIP.RTCSession} session
 * @param {Object} [contraints]
 */
(function(JsSIP){

var RTCMediaHandler = function(session, constraints) {
  constraints = constraints || {};

  this.session = session;
  this.localMedia = null;
  this.peerConnection = null;

  this.init(constraints);
};

RTCMediaHandler.prototype = {

  createOffer: function(onSuccess, onFailure) {
    var
      self = this,
      sent = false;

    this.onIceCompleted = function() {
      if (!sent) {
        sent = true;
        onSuccess(self.peerConnection.localDescription.sdp);
      }
    };

    this.peerConnection.createOffer(
      function(sessionDescription){
        self.setLocalDescription(
          sessionDescription,
          onFailure
        );
      },
      function(e) {
        console.error(LOG_PREFIX +'unable to create offer');
        console.error(e);
        onFailure();
      }
    );
  },

  createAnswer: function(onSuccess, onFailure) {
    var
      self = this,
      sent = false;

    this.onIceCompleted = function() {
      if (!sent) {
        sent = true;
        onSuccess(self.peerConnection.localDescription.sdp);
      }
    };

    this.peerConnection.createAnswer(
      function(sessionDescription){
        self.setLocalDescription(
          sessionDescription,
          onFailure
        );
      },
      function(e) {
        console.error(LOG_PREFIX +'unable to create answer');
        console.error(e);
        onFailure();
      }
    );
  },

  setLocalDescription: function(sessionDescription, onFailure) {
    this.peerConnection.setLocalDescription(
      sessionDescription,
      function(){},
      function(e) {
        console.error(LOG_PREFIX +'unable to set local description');
        console.error(e);
        onFailure();
      }
    );
  },

  addStream: function(stream, onSuccess, onFailure, constraints) {
    try {
      this.peerConnection.addStream(stream, constraints);
    } catch(e) {
      console.error(LOG_PREFIX +'error adding stream');
      console.error(e);
      onFailure();
      return;
    }

    onSuccess();
  },

  /**
  * peerConnection creation.
  * @param {Function} onSuccess Fired when there are no more ICE candidates
  */
  init: function(constraints) {
    var idx, server, scheme, url,
      self = this,
      servers = [];

    for (idx in this.session.ua.configuration.stun_servers) {
      server = this.session.ua.configuration.stun_servers[idx];
      servers.push({'url': server});
    }

    for (idx in this.session.ua.configuration.turn_servers) {
      server = this.session.ua.configuration.turn_servers[idx];
      url = server.server;
      scheme = url.substr(0, url.indexOf(':'));
      servers.push({
        'url': scheme + ':' + server.username + '@' + url.substr(scheme.length+1),
        'credential': server.password
      });
    }

    this.peerConnection = new JsSIP.WebRTC.RTCPeerConnection({'iceServers': servers}, constraints);

    this.peerConnection.onaddstream = function(e) {
      console.log(LOG_PREFIX +'stream added: '+ e.stream.id);
    };

    this.peerConnection.onremovestream = function(e) {
      console.log(LOG_PREFIX +'stream removed: '+ e.stream.id);
    };

    this.peerConnection.onicecandidate = function(e) {
      if (e.candidate) {
        console.log(LOG_PREFIX +'ICE candidate received: '+ e.candidate.candidate);
      } else {
        self.onIceCompleted();
      }
    };

    // To be deprecated as per https://code.google.com/p/webrtc/issues/detail?id=1393
    this.peerConnection.ongatheringchange = function(e) {
      if (e.currentTarget.iceGatheringState === 'complete' && this.iceConnectionState !== 'closed') {
        self.onIceCompleted();
      }
    };

    this.peerConnection.onicechange = function() {
      console.log(LOG_PREFIX +'ICE connection state changed to "'+ this.iceConnectionState +'"');
    };

    this.peerConnection.onstatechange = function() {
      console.log(LOG_PREFIX +'PeerConnection state changed to "'+ this.readyState +'"');
    };
  },

  close: function() {
    console.log(LOG_PREFIX + 'closing PeerConnection');
    if(this.peerConnection) {
      this.peerConnection.close();

      if(this.localMedia) {
        this.localMedia.stop();
      }
    }
  },

  /**
  * @param {Object} mediaConstraints
  * @param {Function} onSuccess
  * @param {Function} onFailure
  */
  getUserMedia: function(onSuccess, onFailure, constraints) {
    var self = this;

    console.log(LOG_PREFIX + 'requesting access to local media');

    JsSIP.WebRTC.getUserMedia(constraints,
      function(stream) {
        console.log(LOG_PREFIX + 'got local media stream');
        self.localMedia = stream;
        onSuccess(stream);
      },
      function(e) {
        console.error(LOG_PREFIX +'unable to get user media');
        console.error(e);
        onFailure();
      }
    );
  },

  /**
  * Message reception.
  * @param {String} type
  * @param {String} sdp
  * @param {Function} onSuccess
  * @param {Function} onFailure
  */
  onMessage: function(type, body, onSuccess, onFailure) {
    this.peerConnection.setRemoteDescription(
      new JsSIP.WebRTC.RTCSessionDescription({type: type, sdp:body}),
      onSuccess,
      onFailure
    );
  }
};

// Return since it will be assigned to a variable.
return RTCMediaHandler;
}(JsSIP));
<commit_msg>check that onIceCompleted is a valid method before calling when a candidate is received.<commit_after>/**
 * @fileoverview RTCMediaHandler
 */

/* RTCMediaHandler
 * @class PeerConnection helper Class.
 * @param {JsSIP.RTCSession} session
 * @param {Object} [contraints]
 */
(function(JsSIP){

var RTCMediaHandler = function(session, constraints) {
  constraints = constraints || {};

  this.session = session;
  this.localMedia = null;
  this.peerConnection = null;

  this.init(constraints);
};

RTCMediaHandler.prototype = {

  createOffer: function(onSuccess, onFailure) {
    var
      self = this,
      sent = false;

    this.onIceCompleted = function() {
      if (!sent) {
        sent = true;
        onSuccess(self.peerConnection.localDescription.sdp);
      }
    };

    this.peerConnection.createOffer(
      function(sessionDescription){
        self.setLocalDescription(
          sessionDescription,
          onFailure
        );
      },
      function(e) {
        console.error(LOG_PREFIX +'unable to create offer');
        console.error(e);
        onFailure();
      }
    );
  },

  createAnswer: function(onSuccess, onFailure) {
    var
      self = this,
      sent = false;

    this.onIceCompleted = function() {
      if (!sent) {
        sent = true;
        onSuccess(self.peerConnection.localDescription.sdp);
      }
    };

    this.peerConnection.createAnswer(
      function(sessionDescription){
        self.setLocalDescription(
          sessionDescription,
          onFailure
        );
      },
      function(e) {
        console.error(LOG_PREFIX +'unable to create answer');
        console.error(e);
        onFailure();
      }
    );
  },

  setLocalDescription: function(sessionDescription, onFailure) {
    this.peerConnection.setLocalDescription(
      sessionDescription,
      function(){},
      function(e) {
        console.error(LOG_PREFIX +'unable to set local description');
        console.error(e);
        onFailure();
      }
    );
  },

  addStream: function(stream, onSuccess, onFailure, constraints) {
    try {
      this.peerConnection.addStream(stream, constraints);
    } catch(e) {
      console.error(LOG_PREFIX +'error adding stream');
      console.error(e);
      onFailure();
      return;
    }

    onSuccess();
  },

  /**
  * peerConnection creation.
  * @param {Function} onSuccess Fired when there are no more ICE candidates
  */
  init: function(constraints) {
    var idx, server, scheme, url,
      self = this,
      servers = [];

    for (idx in this.session.ua.configuration.stun_servers) {
      server = this.session.ua.configuration.stun_servers[idx];
      servers.push({'url': server});
    }

    for (idx in this.session.ua.configuration.turn_servers) {
      server = this.session.ua.configuration.turn_servers[idx];
      url = server.server;
      scheme = url.substr(0, url.indexOf(':'));
      servers.push({
        'url': scheme + ':' + server.username + '@' + url.substr(scheme.length+1),
        'credential': server.password
      });
    }

    this.peerConnection = new JsSIP.WebRTC.RTCPeerConnection({'iceServers': servers}, constraints);

    this.peerConnection.onaddstream = function(e) {
      console.log(LOG_PREFIX +'stream added: '+ e.stream.id);
    };

    this.peerConnection.onremovestream = function(e) {
      console.log(LOG_PREFIX +'stream removed: '+ e.stream.id);
    };

    this.peerConnection.onicecandidate = function(e) {
      if (e.candidate) {
        console.log(LOG_PREFIX +'ICE candidate received: '+ e.candidate.candidate);
      } else if (self.onIceCompleted !== undefined) {
        self.onIceCompleted();
      }
    };

    // To be deprecated as per https://code.google.com/p/webrtc/issues/detail?id=1393
    this.peerConnection.ongatheringchange = function(e) {
      if (e.currentTarget.iceGatheringState === 'complete' && this.iceConnectionState !== 'closed') {
        self.onIceCompleted();
      }
    };

    this.peerConnection.onicechange = function() {
      console.log(LOG_PREFIX +'ICE connection state changed to "'+ this.iceConnectionState +'"');
    };

    this.peerConnection.onstatechange = function() {
      console.log(LOG_PREFIX +'PeerConnection state changed to "'+ this.readyState +'"');
    };
  },

  close: function() {
    console.log(LOG_PREFIX + 'closing PeerConnection');
    if(this.peerConnection) {
      this.peerConnection.close();

      if(this.localMedia) {
        this.localMedia.stop();
      }
    }
  },

  /**
  * @param {Object} mediaConstraints
  * @param {Function} onSuccess
  * @param {Function} onFailure
  */
  getUserMedia: function(onSuccess, onFailure, constraints) {
    var self = this;

    console.log(LOG_PREFIX + 'requesting access to local media');

    JsSIP.WebRTC.getUserMedia(constraints,
      function(stream) {
        console.log(LOG_PREFIX + 'got local media stream');
        self.localMedia = stream;
        onSuccess(stream);
      },
      function(e) {
        console.error(LOG_PREFIX +'unable to get user media');
        console.error(e);
        onFailure();
      }
    );
  },

  /**
  * Message reception.
  * @param {String} type
  * @param {String} sdp
  * @param {Function} onSuccess
  * @param {Function} onFailure
  */
  onMessage: function(type, body, onSuccess, onFailure) {
    this.peerConnection.setRemoteDescription(
      new JsSIP.WebRTC.RTCSessionDescription({type: type, sdp:body}),
      onSuccess,
      onFailure
    );
  }
};

// Return since it will be assigned to a variable.
return RTCMediaHandler;
}(JsSIP));
<|endoftext|>