<commit_before>var express = require('express'),
    multiparty = require('multiparty'),
    shortid = require('shortid'),
    fs = require('fs'),
    conf = require('./conf.js');

var router = express.Router();

router.post("*", function (req, res, next) {

    // parse a file upload
    var form = new multiparty.Form();
    var maxPhotoSize = 5000000; //in bytes

    form.parse(req, function(err, fields, files) {

      if (err) {
        console.log(err);
        next(); // go to the next function to see if the request is not a multipart
      }
      var geojson = JSON.parse(fields.geojson[0]);

      // otherwise we can use require('path')
      function getExtension(filename) {
	     var i = filename.lastIndexOf('.');
	     return (i < 0) ? '' : filename.substr(i);
	  }

	  function copyFile(source, target, cb) {
		  var cbCalled = false;

		  var rd = fs.createReadStream(source);
		  rd.on("error", function(err) {
		    done(err);
		  });
		  var wr = fs.createWriteStream(target);
		  wr.on("error", function(err) {
		    done(err);
		  });
		  wr.on("close", function(ex) {
		    done();
		  });
		  rd.pipe(wr);

		  function done(err) {
		    if (!cbCalled) {
		      cb(err);
		      cbCalled = true;
		    }
		  }
	  }

	  function sendError(error) {
	  	  //we won't send the error, just log and continue to the next module. The file is not required
	  	  console.log(error);
		  //res.status(500).send(error);
	  }

	  function fileError(error) {
	  	  sendError("Error creating file: " + error);
	  }

      // manage image
      if(files.file) {
	      var file = files.file[0];
	      if(files.file[0].size > maxPhotoSize) {
	      	sendError("Maximum photo size of " + maxPhotoSize + " exceeded");
	      }
	      var filename = shortid.generate() + getExtension(file.path);

      	  copyFile(file.path, conf.UPLOAD_DIR +  filename, fileError);
	      geojson.features[0].properties.image = conf.PUBLIC_URL + conf.UPLOAD_URL + filename;

	  }

      req.body = JSON.stringify(geojson);
      next();

    });

});

module.exports = router;
<commit_msg>Multipart error management<commit_after>var express = require('express'),
    multiparty = require('multiparty'),
    shortid = require('shortid'),
    fs = require('fs'),
    conf = require('./conf.js');

var router = express.Router();

router.post("*", function (req, res, next) {

    // parse a file upload
    var form = new multiparty.Form();
    var maxPhotoSize = 5000000; //in bytes

    form.parse(req, function(err, fields, files) {

      if (err) {
        sendError(err);
      }

      var geojson;
      if(fields.hasOwnProperty('geojson') && Array.isArray(fields.geojson) && fields.geojson.length) {
      	 try {
      	 	// we use first element of the array (if many)
		    geojson = JSON.parse(fields.geojson[0]);
		 } catch(e) {
		    sendError(e);
		 }
	  }

      // otherwise we can use require('path')
      function getExtension(filename) {
	     var i = filename.lastIndexOf('.');
	     return (i < 0) ? '' : filename.substr(i);
	  }

	  function copyFile(source, target, cb) {
		  var cbCalled = false;

		  var rd = fs.createReadStream(source);
		  rd.on("error", function(err) {
		    done(err);
		  });
		  var wr = fs.createWriteStream(target);
		  wr.on("error", function(err) {
		    done(err);
		  });
		  wr.on("close", function(ex) {
		    done();
		  });
		  rd.pipe(wr);

		  function done(err) {
		    if (!cbCalled) {
		      cb(err);
		      cbCalled = true;
		    }
		  }
	  }

	  function sendError(error) {
	  	  logWarning(error);
		  res.status(500).send(error);
	  }

	  function logWarning(error) {
	  	  //we won't send the error, just log
	  	  console.log(error);
	  }

	  function fileError(error) {
	  	  // without a file, we still want to store the geojson
	  	  logWarning("Error creating file: " + error);
	  }

      // manage image
      if(files.file) {
	      var file = files.file[0];
	      if(files.file[0].size > maxPhotoSize) {
	      	sendError("Maximum photo size of " + maxPhotoSize + " exceeded");
	      }
	      var filename = shortid.generate() + getExtension(file.path);

      	  copyFile(file.path, conf.UPLOAD_DIR +  filename, fileError);
	      geojson.features[0].properties.image = conf.PUBLIC_URL + conf.UPLOAD_URL + filename;
	  }

      req.body = JSON.stringify(geojson);
      next();

    });

});

module.exports = router;
<|endoftext|>


<commit_before>import { Component, createElement, PropTypes } from 'react';
import { propTypes } from 'redux-form';
import { isBoolean, isString, mapObject, isObject } from 'underscore';
import Renderer from '../renderer/Schema';

/**
 * A SchemaForm React Component; returns a form using the configured props.schema
 *
 * Other options are:
 * setting a config (object)prop containing the following:
 *
 *
 */
export default class SchemaForm extends Component {
  static propTypes = {
    ... propTypes,
    children: PropTypes.any,
    config: PropTypes.object,
    path: PropTypes.array,
    schema: PropTypes.object
  };

  renderer = null;

  // shouldComponentUpdate (nextProps, nextState) {
  //   console.log(nextProps, nextState);
  //   return nextProps.dirty;
  // }

  renderSchema (schema, values, config) {
    if (!this.renderer) {
      this.renderer = new Renderer(config);
      const me = this;
      this.renderer.setState = (state) => {
        me.setState(state);
      };
      this.renderer.getState = () => {
        return me.state;
      };
      this.renderer.removeField = (name) => {
        // console.log('removeField', me.props.form, name);
        return me.props.dispatch(me.props.change(name, {}));
        // return me.props.dispatch(unregisterField(me.props.form, name));
      };
      this.renderer.changeField = (name, value) => {
        // console.log('changeField', name, value);
        return me.props.dispatch(me.props.change(name, value));
      };
    }
    return this.renderer.renderObject(schema, this.props.path || [], values);
  }

  render () {
    const {
      /*eslint no-unused-vars:0*/
      // own
      schema, config, path, enableRecaptcha,
      // redux-form
      anyTouched, asyncValidate, asyncValidating, destroy, dirty, dispatch, error, focus, handleSubmit, initialize,
      invalid, pristine, reset, submitting, submitFailed, touch, untouch, valid, initialValues, shouldAsyncValidate,
      validate, initialized, registeredFields, arrayMove, arrayRemoveAll, startAsyncValidation, startSubmit,
      stopAsyncValidation, stopSubmit, setSubmitFailed, updateSyncErrors, blur, change, array,
      //
      submitSucceeded, schemaCompileError, pure, autofill,
      // rest
      ...rest
    } = this.props;

    return createElement('form', {
      ... rest,
      // onSubmitFail: () => console.log('failed', arguments),
      'data-role': 'form',
      'noValidate': true,
      children: [
        this.props.children,
        this.renderSchema(schema, {}, config),
        this.renderButtons(config)
      ]
    });
  };

  renderButtons (config) {
    let buttons = {
      'submit': true,
      'reset': true
    };

    if (config && config.buttons) {
      buttons = config.buttons;
    }

    let children = [];
    mapObject(buttons, (value, key) => {
      if (value === false) {
        return;
      }
      children.push(this.renderButton(key, value));
    });

    if (children.length === 0) {
      return null;
    }

    children.push(this.props.error
      ? createElement('div', {className: 'form-control-feedback'}, this.props.error) : null);

    const hasLabels = config.hasLabels || config.hasLabels === undefined;
    const wrapperClassName = hasLabels ? (config && config.buttonWrapperClass ? config.buttonWrapperClass : '')
      : (config && config.inputWrapperClass ? config.inputWrapperClass : '');

    return createElement('div', {
      className: (config.groupClass || '') + ' form-group-buttons',
      children: [createElement('div', {
        className: wrapperClassName + (this.props.error ? ' has-danger' : ''),
        children: children
      })]
    });
  };

  renderButton (type, config) {
    // console.log('renderButton', type, config);

    let { text, ...props } = config;
    if (isBoolean(props)) {
      props = {};
    }

    // allow props to be a string or a React.Component
    if (isString(props) || props.isReactComponent /* TODO this should work !? */ || props.$$typeof) {
      text = props;
      props = {};
    }

    if (isObject(props)) {
    }

    // add default type; else the form will submit!
    if (!props.type) {
      props.type = 'button';
    }

    let deActivatePristine;

    // add submit behaviour
    if (type === 'submit') {
      props.type = type;
      deActivatePristine = true;
      if (config === true) {
        props.children = ['Submit'];
      }
    }

    // add reset behaviour
    if (type === 'reset') {
      props.onClick = this.props.reset;
      deActivatePristine = true;
      if (config === true) {
        props.children = ['Reset'];
      }
    }

    // console.log(this.props);
    // console.log(props);
    if (!props.disabled && deActivatePristine) {
      props.disabled = this.props.submitting || this.props.pristine;
    }

    if (text) {
      props.children = [text];
    }

    return createElement('button', {
      ... props
    });
  }

}
<commit_msg>only set disabled on buttons if not already set on props<commit_after>import { Component, createElement, PropTypes } from 'react';
import { propTypes } from 'redux-form';
import { isBoolean, isString, mapObject, isObject } from 'underscore';
import Renderer from '../renderer/Schema';

/**
 * A SchemaForm React Component; returns a form using the configured props.schema
 *
 * Other options are:
 * setting a config (object)prop containing the following:
 *
 *
 */
export default class SchemaForm extends Component {
  static propTypes = {
    ... propTypes,
    children: PropTypes.any,
    config: PropTypes.object,
    path: PropTypes.array,
    schema: PropTypes.object
  };

  renderer = null;

  // shouldComponentUpdate (nextProps, nextState) {
  //   console.log(nextProps, nextState);
  //   return nextProps.dirty;
  // }

  renderSchema (schema, values, config) {
    if (!this.renderer) {
      this.renderer = new Renderer(config);
      const me = this;
      this.renderer.setState = (state) => {
        me.setState(state);
      };
      this.renderer.getState = () => {
        return me.state;
      };
      this.renderer.removeField = (name) => {
        // console.log('removeField', me.props.form, name);
        return me.props.dispatch(me.props.change(name, {}));
        // return me.props.dispatch(unregisterField(me.props.form, name));
      };
      this.renderer.changeField = (name, value) => {
        // console.log('changeField', name, value);
        return me.props.dispatch(me.props.change(name, value));
      };
    }
    return this.renderer.renderObject(schema, this.props.path || [], values);
  }

  render () {
    const {
      /*eslint no-unused-vars:0*/
      // own
      schema, config, path, enableRecaptcha,
      // redux-form
      anyTouched, asyncValidate, asyncValidating, destroy, dirty, dispatch, error, focus, handleSubmit, initialize,
      invalid, pristine, reset, submitting, submitFailed, touch, untouch, valid, initialValues, shouldAsyncValidate,
      validate, initialized, registeredFields, arrayMove, arrayRemoveAll, startAsyncValidation, startSubmit,
      stopAsyncValidation, stopSubmit, setSubmitFailed, updateSyncErrors, blur, change, array,
      //
      submitSucceeded, schemaCompileError, pure, autofill,
      // rest
      ...rest
    } = this.props;

    return createElement('form', {
      ... rest,
      // onSubmitFail: () => console.log('failed', arguments),
      'data-role': 'form',
      'noValidate': true,
      children: [
        this.props.children,
        this.renderSchema(schema, {}, config),
        this.renderButtons(config)
      ]
    });
  };

  renderButtons (config) {
    let buttons = {
      'submit': true,
      'reset': true
    };

    if (config && config.buttons) {
      buttons = config.buttons;
    }

    let children = [];
    mapObject(buttons, (value, key) => {
      if (value === false) {
        return;
      }
      children.push(this.renderButton(key, value));
    });

    if (children.length === 0) {
      return null;
    }

    children.push(this.props.error
      ? createElement('div', {className: 'form-control-feedback'}, this.props.error) : null);

    const hasLabels = config.hasLabels || config.hasLabels === undefined;
    const wrapperClassName = hasLabels ? (config && config.buttonWrapperClass ? config.buttonWrapperClass : '')
      : (config && config.inputWrapperClass ? config.inputWrapperClass : '');

    return createElement('div', {
      className: (config.groupClass || '') + ' form-group-buttons',
      children: [createElement('div', {
        className: wrapperClassName + (this.props.error ? ' has-danger' : ''),
        children: children
      })]
    });
  };

  renderButton (type, config) {
    let { text, ...props } = config;
    if (isBoolean(props)) {
      props = {};
    }

    // allow props to be a string or a React.Component
    if (isString(props) || props.isReactComponent /* TODO this should work !? */ || props.$$typeof) {
      text = props;
      props = {};
    }

    if (isObject(props)) {
    }

    // add default type; else the form will submit!
    if (!props.type) {
      props.type = 'button';
    }

    let deActivatePristine;

    // add submit behaviour
    if (type === 'submit') {
      props.type = type;
      deActivatePristine = true;
      if (config === true) {
        props.children = ['Submit'];
      }
    }

    // add reset behaviour
    if (type === 'reset') {
      props.onClick = this.props.reset;
      deActivatePristine = true;
      if (config === true) {
        props.children = ['Reset'];
      }
    }

    if (typeof props.disabled === 'undefined' && deActivatePristine) {
      props.disabled = this.props.submitting || this.props.pristine;
    }

    if (text) {
      props.children = [text];
    }

    return createElement('button', {
      ... props
    });
  }

}
<|endoftext|>


<commit_before>module.exports = {
    files: [
        {flatten: true, expand: true, src: 'vendor/dom4/build/dom4.js', dest: 'dist/polyfills'},
        {flatten: true, expand: true, src: 'vendor/es5-shim/es5-shim.min.js', dest: 'dist/polyfills'},
        {flatten: true, expand: true, src: 'vendor/placeholders/dist/placeholders.min.js', dest: 'dist/polyfills'},
        {flatten: true, expand: true, src: 'vendor/picturefill/dist/picturefill.min.js', dest: 'dist/polyfills'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF2/OTF/SourceSansPro-Light.otf.woff2', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF2/OTF/SourceSansPro-Regular.otf.woff2', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF2/OTF/SourceSansPro-Semibold.otf.woff2', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF/OTF/SourceSansPro-Light.otf.woff', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF/OTF/SourceSansPro-Regular.otf.woff', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF/OTF/SourceSansPro-Semibold.otf.woff', dest: 'dist/fonts'}
    ]
};
<commit_msg>Removed locally hosted polyfills from grunt task<commit_after>module.exports = {
    files: [
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF2/OTF/SourceSansPro-Light.otf.woff2', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF2/OTF/SourceSansPro-Regular.otf.woff2', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF2/OTF/SourceSansPro-Semibold.otf.woff2', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF/OTF/SourceSansPro-Light.otf.woff', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF/OTF/SourceSansPro-Regular.otf.woff', dest: 'dist/fonts'},
        {flatten: true, expand: true, src: 'vendor/source-sans-pro/WOFF/OTF/SourceSansPro-Semibold.otf.woff', dest: 'dist/fonts'}
    ]
};
<|endoftext|>


<commit_before>import util from 'util';
import screenLib from 'galileo-screen';
import {
  TerminalRuntimeError,
} from './TerminalErrors';
import terminalService from './TerminalService';

export const TERMINAL_STATE_NONE = 'TERMINAL_STATE_NONE';
export const TERMINAL_STATE_BUSY = 'TERMINAL_STATE_BUSY';
export const TERMINAL_STATE_READY = 'TERMINAL_STATE_READY';
export const TERMINAL_STATE_CLOSED = 'TERMINAL_STATE_CLOSED';
export const TERMINAL_STATE_ERROR = 'TERMINAL_STATE_ERROR';

const screenFunctions = screenLib({ cursor: '><' });

module.exports = function (settings) {
  const service = terminalService(settings);
  const emulatePcc = settings.auth.emulatePcc || false;
  const timeout = settings.timeout || false;
  const state = {
    terminalState: TERMINAL_STATE_NONE,
    sessionToken: null,
  };
  // Processing response with MD commands
  const processResponse = (response, previousResponse = null) => {
    const processedResponse = previousResponse
      ? screenFunctions.mergeResponse(
        previousResponse,
        response.join('\n')
      )
      : response.join('\n');
    if (!screenFunctions.hasMore(processedResponse)) {
      return processedResponse;
    }
    return service.executeCommand({
      sessionToken: state.sessionToken,
      command: 'MD',
    }).then(
      mdResponse => processResponse(mdResponse, processedResponse)
    );
  };
  // Getting session token
  const getSessionToken = () => new Promise((resolve, reject) => {
    if (state.terminalState === TERMINAL_STATE_BUSY) {
      throw new TerminalRuntimeError.TerminalIsBusy();
    }
    if (state.terminalState === TERMINAL_STATE_CLOSED) {
      throw new TerminalRuntimeError.TerminalIsClosed();
    }
    Object.assign(state, {
      terminalState: TERMINAL_STATE_BUSY,
    });
    // Return token if already obtained
    if (state.sessionToken !== null) {
      resolve(state.sessionToken);
      return;
    }
    // Getting token
    service.getSessionToken({
      timeout,
    }).then((sessionToken) => {
      // Remember sesion token
      Object.assign(state, {
        sessionToken,
      });
      // Return if no emulation needed
      if (!emulatePcc) {
        return sessionToken;
      }
      // Emulate pcc
      return service.executeCommand({
        sessionToken,
        command: `SEM/${emulatePcc}/AG`,
      }).then((response) => {
        if (!response[0].match(/^PROCEED/)) {
          throw new TerminalRuntimeError.TerminalEmulationFailed(response);
        }
        return sessionToken;
      });
    }).then(
      resolve
    ).catch(
      reject
    );
  });

  const terminal = {
    executeCommand: command => getSessionToken()
      .then(
        sessionToken => service.executeCommand({
          command,
          sessionToken,
        })
      )
      .then(processResponse)
      .then(
        (response) => {
          Object.assign(state, {
            terminalState: TERMINAL_STATE_READY,
          });
          return response;
        }
      )
      .catch(
        (err) => {
          Object.assign(state, {
            terminalState: TERMINAL_STATE_ERROR,
          });
          throw err;
        }
      ),
    closeSession: () => getSessionToken()
      .then(
        sessionToken => service.closeSession({
          sessionToken,
        })
      ).then(
        (response) => {
          Object.assign(state, {
            terminalState: TERMINAL_STATE_CLOSED,
          });
          return response;
        }
      ),
  };

  // Adding event handler on beforeExit and exit process events
  process.on('beforeExit', () => {
    switch (state.terminalState) {
      case TERMINAL_STATE_BUSY:
      case TERMINAL_STATE_READY:
      case TERMINAL_STATE_ERROR:
        if (state.terminalState === TERMINAL_STATE_BUSY) {
          util.log('UAPI-JSON WARNING: Process exited before completing TerminalService request');
        }
        if (state.sessionToken !== null) {
          util.log('UAPI-JSON WARNING: Process left TerminalService session open');
          util.log('UAPI-JSON WARNING: Session closing');
          terminal.closeSession().then(
            () => util.log('UAPI-JSON WARNING: Session closed')
          ).catch(
            () => {
              throw new TerminalRuntimeError.ErrorClosingSession();
            }
          );
        }
        break;
      default:
        break;
    }
  });
  process.on('exit', () => {
    switch (state.terminalState) {
      case TERMINAL_STATE_BUSY:
      case TERMINAL_STATE_READY:
      case TERMINAL_STATE_ERROR:
        if (state.terminalState === TERMINAL_STATE_BUSY) {
          util.log('UAPI-JSON WARNING: Process exited before completing TerminalService request');
        }
        if (state.sessionToken !== null) {
          util.log('UAPI-JSON WARNING: Process left TerminalService session open');
        }
        break;
      default:
        break;
    }
  });

  return terminal;
};
<commit_msg>Added ignore for unreachable onExit handler<commit_after>import util from 'util';
import screenLib from 'galileo-screen';
import {
  TerminalRuntimeError,
} from './TerminalErrors';
import terminalService from './TerminalService';

export const TERMINAL_STATE_NONE = 'TERMINAL_STATE_NONE';
export const TERMINAL_STATE_BUSY = 'TERMINAL_STATE_BUSY';
export const TERMINAL_STATE_READY = 'TERMINAL_STATE_READY';
export const TERMINAL_STATE_CLOSED = 'TERMINAL_STATE_CLOSED';
export const TERMINAL_STATE_ERROR = 'TERMINAL_STATE_ERROR';

const screenFunctions = screenLib({ cursor: '><' });

module.exports = function (settings) {
  const service = terminalService(settings);
  const emulatePcc = settings.auth.emulatePcc || false;
  const timeout = settings.timeout || false;
  const state = {
    terminalState: TERMINAL_STATE_NONE,
    sessionToken: null,
  };
  // Processing response with MD commands
  const processResponse = (response, previousResponse = null) => {
    const processedResponse = previousResponse
      ? screenFunctions.mergeResponse(
        previousResponse,
        response.join('\n')
      )
      : response.join('\n');
    if (!screenFunctions.hasMore(processedResponse)) {
      return processedResponse;
    }
    return service.executeCommand({
      sessionToken: state.sessionToken,
      command: 'MD',
    }).then(
      mdResponse => processResponse(mdResponse, processedResponse)
    );
  };
  // Getting session token
  const getSessionToken = () => new Promise((resolve, reject) => {
    if (state.terminalState === TERMINAL_STATE_BUSY) {
      throw new TerminalRuntimeError.TerminalIsBusy();
    }
    if (state.terminalState === TERMINAL_STATE_CLOSED) {
      throw new TerminalRuntimeError.TerminalIsClosed();
    }
    Object.assign(state, {
      terminalState: TERMINAL_STATE_BUSY,
    });
    // Return token if already obtained
    if (state.sessionToken !== null) {
      resolve(state.sessionToken);
      return;
    }
    // Getting token
    service.getSessionToken({
      timeout,
    }).then((sessionToken) => {
      // Remember sesion token
      Object.assign(state, {
        sessionToken,
      });
      // Return if no emulation needed
      if (!emulatePcc) {
        return sessionToken;
      }
      // Emulate pcc
      return service.executeCommand({
        sessionToken,
        command: `SEM/${emulatePcc}/AG`,
      }).then((response) => {
        if (!response[0].match(/^PROCEED/)) {
          throw new TerminalRuntimeError.TerminalEmulationFailed(response);
        }
        return sessionToken;
      });
    }).then(
      resolve
    ).catch(
      reject
    );
  });

  const terminal = {
    executeCommand: command => getSessionToken()
      .then(
        sessionToken => service.executeCommand({
          command,
          sessionToken,
        })
      )
      .then(processResponse)
      .then(
        (response) => {
          Object.assign(state, {
            terminalState: TERMINAL_STATE_READY,
          });
          return response;
        }
      )
      .catch(
        (err) => {
          Object.assign(state, {
            terminalState: TERMINAL_STATE_ERROR,
          });
          throw err;
        }
      ),
    closeSession: () => getSessionToken()
      .then(
        sessionToken => service.closeSession({
          sessionToken,
        })
      ).then(
        (response) => {
          Object.assign(state, {
            terminalState: TERMINAL_STATE_CLOSED,
          });
          return response;
        }
      ),
  };

  // Adding event handler on beforeExit and exit process events
  process.on('beforeExit', () => {
    switch (state.terminalState) {
      case TERMINAL_STATE_BUSY:
      case TERMINAL_STATE_READY:
      case TERMINAL_STATE_ERROR:
        if (state.terminalState === TERMINAL_STATE_BUSY) {
          util.log('UAPI-JSON WARNING: Process exited before completing TerminalService request');
        }
        if (state.sessionToken !== null) {
          util.log('UAPI-JSON WARNING: Process left TerminalService session open');
          util.log('UAPI-JSON WARNING: Session closing');
          terminal.closeSession().then(
            () => util.log('UAPI-JSON WARNING: Session closed')
          ).catch(
            () => {
              throw new TerminalRuntimeError.ErrorClosingSession();
            }
          );
        }
        break;
      default:
        break;
    }
  });
  /* istanbul ignore next */
  process.on('exit', () => {
    switch (state.terminalState) {
      case TERMINAL_STATE_BUSY:
      case TERMINAL_STATE_READY:
      case TERMINAL_STATE_ERROR:
        if (state.terminalState === TERMINAL_STATE_BUSY) {
          util.log('UAPI-JSON WARNING: Process exited before completing TerminalService request');
        }
        if (state.sessionToken !== null) {
          util.log('UAPI-JSON WARNING: Process left TerminalService session open');
        }
        break;
      default:
        break;
    }
  });

  return terminal;
};
<|endoftext|>


<commit_before>var CoinPocketApp = (function($, self) {
  self.VERSION = 'v1.0.0-beta4';
  $('.coin-pocket-version').text(self.VERSION);

  self.Models = {};
  self.Views = {};
  self.Controllers = {};

  $(document).off('.data-api'); // disable bootstrap data api

  return self;
})(jQuery, {});
<commit_msg>Launching 1.0.0<commit_after>var CoinPocketApp = (function($, self) {
  self.VERSION = 'v1.0.0';
  $('.coin-pocket-version').text(self.VERSION);

  self.Models = {};
  self.Views = {};
  self.Controllers = {};

  $(document).off('.data-api'); // disable bootstrap data api

  return self;
})(jQuery, {});
<|endoftext|>


<commit_before>var BfsFlowErrorLink = BfsFlowErrorLink || {};

BfsFlowErrorLink.init = function() {
  var genericFlowErrorTD = $('td:contains("A flow trigger failed to execute the flow with version ID")').filter(':last');
  genericFlowErrorTD.each(function( index, element ) {
    var versionIdRegEx = /(301\w{12})/g;
    var elementJQ = $( element );
    var elementText = elementJQ.text();
    var matches = versionIdRegEx.exec(elementText);
    var versionId = matches[0];

    var offenderLink = 'View Offending Process Builder or Flow';
    elementJQ.append(offenderLink);
  });
}

BfsFlowErrorLink.init();<commit_msg>Added Lightning Experience support so that when the generic flow error appears, the "View Offending Process Builder or Flow" link is shown there too. Previously, it was only showing in Salesforce Classic. This was implemented for Boostr issue #42 at https://github.com/mattsimonis/boostr/issues/42 (#43)<commit_after>var BfsFlowErrorLink = BfsFlowErrorLink || {};
var genericFlowErrorMsgFragment = "A flow trigger failed to execute the flow with version ID";

BfsFlowErrorLink.appendOffenderLink = function (errorContainerElement) {
  var versionIdRegEx = /(301\w{12})/g;
  var elementJQ = $(errorContainerElement);
  var elementText = elementJQ.text();
  var matches = versionIdRegEx.exec(elementText);
  var versionId = matches[0];

  var offenderLink = 'View Offending Process Builder or Flow';
  elementJQ.append(offenderLink);
}

BfsFlowErrorLink.findAndAppendOffenderLinkInClassic = function () {
  var genericFlowErrorTD = $('td:contains(' + genericFlowErrorMsgFragment + ')').filter(':last');
  genericFlowErrorTD.each(function (index, element) {
    BfsFlowErrorLink.appendOffenderLink(element);
  });
}

BfsFlowErrorLink.hasFlowError = function (mutations) {
  // Since this code executes on each DOM addition or removal to the document,
  // this low-level code was added to be as performant as possible.
  for (var mutationIndex = 0; mutationIndex < mutations.length; ++mutationIndex) {
    var mutation = mutations[mutationIndex];
    if (mutation.addedNodes) {
      for (var addedNodeIndex = 0; addedNodeIndex < mutation.addedNodes.length; ++addedNodeIndex) {
        var addedNode = mutation.addedNodes[addedNodeIndex];

        if (addedNode.innerText &&
            addedNode.innerText.indexOf(genericFlowErrorMsgFragment) != -1) {
          BfsFlowErrorLink.appendOffenderLink(addedNode);
          return;
        }
      }
    }
  }
}

BfsFlowErrorLink.init = function () {
  BfsFlowErrorLink.findAndAppendOffenderLinkInClassic();

  // Only add the mutation observer if we're in Lightning Experience to avoid
  // unnecessary overhead since the generic flow error in Classic is detectable
  // on page load whereas we have to detect DOM changes in Lightning to detect the
  // error.
  var someLightningElement = document.getElementById('auraAppcacheProgress');

  if (someLightningElement) {
      var container = document;
      var observer = new MutationObserver(BfsFlowErrorLink.hasFlowError);

      observer.observe(container, {
          childList: true,
          attributes: false,
          characterData: false,
          subtree: true,
          attributeOldValue: false,
          characterDataOldValue: false
      });
  }
}

BfsFlowErrorLink.init();<|endoftext|>


<commit_before>// Convert an element into a 3D laptop, moving its contents into the screen.

class Laptop {
  static get defaultLidAngle() { return 100; }

  constructor(elem, index, dummy = false) {
    this.elem = elem;
    this.index = index;
    this.dummy = dummy;

    this._translateX = this._translateY = this._translateZ = 0;
    this._rotateX = this._rotateY = this._rotateZ = 0;
    this._lidAngle = Laptop.defaultLidAngle;

    this.elem.classList.add('laptop3d');
    if (this.dummy) this.elem.classList.add('dummy');
    if (typeof this.index !== 'undefined') this.elem.setAttribute('data-laptop3d-index', this.index);

    const children = [...this.elem.childNodes];
    this.elem.innerHTML = `

    `;
    // Record some common elements as properties
    ['wrapper', 'base', 'lid', 'screen'].forEach((name) => {
      this[name] = this.elem.getElementsByClassName(name)[0];
    });
    // Add all former children to the new screen element
    children.forEach(child => this.screen.appendChild(child));

    // Transform: rotate by 25 degrees for each full index value, with a max of 75 degress from the
    // center so that we can't see any in the background
    this._rotateZ = `${-Math.sign(this.index) * Math.min(25 * Math.abs(this.index), 75)}deg`;

    // Lift up a bit on hover
    if (!this.dummy) {
      this.wrapper.addEventListener('mouseenter', () => { this.translateZ = '1vw'; });
      this.wrapper.addEventListener('mouseleave', () => { this.translateZ = 0; });
    }

    this._applyTransform();
  }

  _applyTransform() {
    this.wrapper.style.transform = [
      `rotateX(${this._rotateX})`,
      `rotateY(${this._rotateY})`,
      `rotateZ(${this._rotateZ})`,
      `translateX(${this._translateX})`,
      `translateY(${this._translateY})`,
      `translateZ(${this._translateZ})`,
    ].join(' ');
    this.lid.style.transform = `translateY(-33.333333vw) rotateX(${-180 + this._lidAngle}deg)`;
  }

  // Translation

  get translateX() { return this._translateX; }
  get translateY() { return this._translateY; }
  get translateZ() { return this._translateZ; }

  set translateX(val) { this._translateX = val; this._applyTransform(); }
  set translateY(val) { this._translateY = val; this._applyTransform(); }
  set translateZ(val) { this._translateZ = val; this._applyTransform(); }

  // Rotation
  get rotateX() { return this._rotateX; }
  get rotateY() { return this._rotateY; }
  get rotateZ() { return this._rotateZ; }

  _setRotate(axis, val) {
    if (!['X', 'Y', 'Z'].includes(axis)) throw new Error('Axis must be one of X Y or Z'); // val must be XYZ
    const prop = `_rotate${axis}`; // Property that we're setting
    if (typeof val === 'string' && val.endsWith('deg')) this[prop] = val; // Don't change if the value is already a string ending in 'deg'
    else this[prop] = `${val}deg`; // Otherwise add the 'deg' suffix
    this._applyTransform();
  }
  set rotateX(val) { this._setRotate('X', val); }
  set rotateY(val) { this._setRotate('Y', val); }
  set rotateZ(val) { this._setRotate('Z', val); }

  // Lid
  get lidAngle() { return this._lidAngle; }
  set lidAngle(val) { this._lidAngle = val; this._applyTransform(); }

}

class LaptopCarousel {
  constructor(container, laptops) {
    this.container = container;
    this.laptops = laptops;
    // Sort by index
    this.laptops.sort((a, b) => a.index - b.index);
    // Check that there are no overlapping indices
    const indices = this.laptops.map(l => l.index);
    if (indices.length !== new Set(indices).size) throw new Error('LaptopCarousel indices must be unique');
    // Record this as the carousel for each laptop
    laptops.forEach((l) => { l.carousel = this; });
    // Build map of laptops by index
    this.laptopsByIndex = {};
    laptops.forEach((l) => { this.laptopsByIndex[l.index] = l; });
  }

  // All indices represented
  get indices() { return this.laptops.map(l => l.index); }
  // Minimum index represented
  get minIndex() { return Math.min(...this.indices); }
  // Maximum index represented
  get maxIndex() { return Math.max(...this.indices); }

  scroll(progress) {
    this.progress = progress;
  }
}

// Set up laptop scene
document.addEventListener('DOMContentLoaded', () => {
  // Convert all elements with the class 'laptop3d' into laptops
  const laptopsContainer = document.getElementsByClassName('laptops-container')[0];
  const laptopElems = [...laptopsContainer.getElementsByClassName('laptop3d')];
  const laptops = laptopElems.map((l, i) => new Laptop(l, i));
  // Add 10 dummy laptops to the beginning
  const dummyLaptops = new Array(5)
    .fill(0)
    .map(() => document.createElement('div'))
    .map(l => laptopsContainer.appendChild(l))
    .map((l, i) => new Laptop(l, -(i + 1), true));

  window.carousel = new LaptopCarousel(laptopsContainer, laptops.concat(dummyLaptops));
});
<commit_msg>Move laptop positioning to LaptopCarousel<commit_after>// Convert an element into a 3D laptop, moving its contents into the screen.

class Laptop {
  static get defaultLidAngle() { return 100; }

  constructor(elem, index, dummy = false) {
    this.elem = elem;
    this.index = index;
    this.dummy = dummy;

    this._translateX = this._translateY = this._translateZ = 0;
    this._rotateX = this._rotateY = this._rotateZ = 0;
    this._lidAngle = Laptop.defaultLidAngle;

    this.elem.classList.add('laptop3d');
    if (this.dummy) this.elem.classList.add('dummy');
    if (typeof this.index !== 'undefined') this.elem.setAttribute('data-laptop3d-index', this.index);

    const children = [...this.elem.childNodes];
    this.elem.innerHTML = `

    `;
    // Record some common elements as properties
    ['wrapper', 'base', 'lid', 'screen'].forEach((name) => {
      this[name] = this.elem.getElementsByClassName(name)[0];
    });
    // Add all former children to the new screen element
    children.forEach(child => this.screen.appendChild(child));

    // Lift up a bit on hover
    if (!this.dummy) {
      this.wrapper.addEventListener('mouseenter', () => { this.translateZ = '1vw'; });
      this.wrapper.addEventListener('mouseleave', () => { this.translateZ = 0; });
    }

    this._applyTransform();
  }

  _applyTransform() {
    this.wrapper.style.transform = [
      `rotateX(${this._rotateX})`,
      `rotateY(${this._rotateY})`,
      `rotateZ(${this._rotateZ})`,
      `translateX(${this._translateX})`,
      `translateY(${this._translateY})`,
      `translateZ(${this._translateZ})`,
    ].join(' ');
    this.lid.style.transform = `translateY(-33.333333vw) rotateX(${-180 + this._lidAngle}deg)`;
  }

  // Translation

  get translateX() { return this._translateX; }
  get translateY() { return this._translateY; }
  get translateZ() { return this._translateZ; }

  set translateX(val) { this._translateX = val; this._applyTransform(); }
  set translateY(val) { this._translateY = val; this._applyTransform(); }
  set translateZ(val) { this._translateZ = val; this._applyTransform(); }

  // Rotation
  get rotateX() { return this._rotateX; }
  get rotateY() { return this._rotateY; }
  get rotateZ() { return this._rotateZ; }

  _setRotate(axis, val) {
    if (!['X', 'Y', 'Z'].includes(axis)) throw new Error('Axis must be one of X Y or Z'); // val must be XYZ
    const prop = `_rotate${axis}`; // Property that we're setting
    if (typeof val === 'string' && val.endsWith('deg')) this[prop] = val; // Don't change if the value is already a string ending in 'deg'
    else this[prop] = `${val}deg`; // Otherwise add the 'deg' suffix
    this._applyTransform();
  }
  set rotateX(val) { this._setRotate('X', val); }
  set rotateY(val) { this._setRotate('Y', val); }
  set rotateZ(val) { this._setRotate('Z', val); }

  // Lid
  get lidAngle() { return this._lidAngle; }
  set lidAngle(val) { this._lidAngle = val; this._applyTransform(); }

}

class LaptopCarousel {
  constructor(container, laptops) {
    this.container = container;
    this.laptops = laptops;
    // Sort by index
    this.laptops.sort((a, b) => a.index - b.index);
    // Check that there are no overlapping indices
    const indices = this.laptops.map(l => l.index);
    if (indices.length !== new Set(indices).size) throw new Error('LaptopCarousel indices must be unique');
    // Record this as the carousel for each laptop
    laptops.forEach((l) => { l.carousel = this; });
    // Build map of laptops by index
    this.laptopsByIndex = {};
    laptops.forEach((l) => { this.laptopsByIndex[l.index] = l; });

    this.arrangeLaptops();
  }

  // All indices represented
  get indices() { return this.laptops.map(l => l.index); }
  // Minimum index represented
  get minIndex() { return Math.min(...this.indices); }
  // Maximum index represented
  get maxIndex() { return Math.max(...this.indices); }

  // Force a number to be inside (-rot, rot)
  static boundRotation(rot) {
    const rotLimit = 75;
    const sign = Math.sign(rot);
    return sign * Math.min(Math.abs(rot), rotLimit);
  }

  positionLaptop(laptop) {
    // Position laptops 25 degress apart from eachother
    laptop.rotateZ = LaptopCarousel.boundRotation(laptop.index * -25);
  }

  arrangeLaptops(progress) {
    this.progress = progress;
    this.laptops.forEach(l => this.positionLaptop(l));
  }
}

// Set up laptop scene
document.addEventListener('DOMContentLoaded', () => {
  // Convert all elements with the class 'laptop3d' into laptops
  const laptopsContainer = document.getElementsByClassName('laptops-container')[0];
  const laptopElems = [...laptopsContainer.getElementsByClassName('laptop3d')];
  const laptops = laptopElems.map((l, i) => new Laptop(l, i));
  // Add 10 dummy laptops to the beginning
  const dummyLaptops = new Array(5)
    .fill(0)
    .map(() => document.createElement('div'))
    .map(l => laptopsContainer.appendChild(l))
    .map((l, i) => new Laptop(l, -(i + 1), true));

  window.carousel = new LaptopCarousel(laptopsContainer, laptops.concat(dummyLaptops));
});
<|endoftext|>


<commit_before>let path = require("path");
let pkg = require("../package.json");

module.exports = {
    "source": __dirname,
    "target": path.join(__dirname, "public"),
    "theme": "@siimple/press/packages/press-theme-siimple/config.js",
    "site": {
        "name": "colors",
        "description": "An elegant and minimalistic color palette for UI design",
        "version": pkg.version,
        "license": "MIT License",
        //Navbar links
        "navbarLinks": [
            {"text": "Getting started", "url": "/installation.html"},
            {"text": "Colors", "url": "/colors.html"},
            {"text": "GitHub", "url": "https://github.com/siimple/colors", "target": "_blank"}
        ],
        //Footer links
        "footerLinks": [
            {"text": "Releases", "url": "https://github.com/siimple/colors/releases", "target": "_blank"},
            {"text": "Repository", "url": "https://github.com/siimple/colors", "target": "_blank"}
        ],
        "repository": "https://github.com/siimple/colors",
        "issues": "https://github.com/siimple/colors/issues",
        "releases": "https://github.com/siimple/colors/releases"
    },
    //Custom head tags
    "head": [
        ["link", {"rel": "stylesheet", "href": "/css/siimple-colors.min.css"}],
        ["link", {"rel": "stylesheet", "href": "/css/siimple-colors-docs.css"}]
    ],
    //Plugins
    "plugins": [
        {
            "plugin": "@siimple/press/packages/press-plugin-sass/index.js",
            "source": path.join(__dirname, "styles", "index.scss"),
            "target": "/css/siimple-colors-docs.css"
        }
    ]
};

<commit_msg>Fixed colors package documentation configuration<commit_after>let path = require("path");
let pkg = require("../package.json");

module.exports = {
    "source": __dirname,
    "target": path.join(__dirname, "public"),
    "theme": "@siimple/press-theme-siimple/config.js",
    "site": {
        "name": "colors",
        "description": "An elegant and minimalistic color palette for UI design",
        "version": pkg.version,
        "license": "MIT License",
        //Navbar links
        "navbarLinks": [
            {"text": "Getting started", "url": "/installation.html"},
            {"text": "Colors", "url": "/colors.html"},
            {"text": "GitHub", "url": "https://github.com/siimple/colors", "target": "_blank"}
        ],
        //Footer links
        "footerLinks": [
            {"text": "Releases", "url": "https://github.com/siimple/colors/releases", "target": "_blank"},
            {"text": "Repository", "url": "https://github.com/siimple/colors", "target": "_blank"}
        ],
        "repository": "https://github.com/siimple/colors",
        "issues": "https://github.com/siimple/colors/issues",
        "releases": "https://github.com/siimple/colors/releases"
    },
    //Custom head tags
    "head": [
        ["link", {"rel": "stylesheet", "href": "/css/siimple-colors.min.css"}],
        ["link", {"rel": "stylesheet", "href": "/css/siimple-colors-docs.css"}]
    ],
    //Plugins
    "plugins": [
        {
            "plugin": "@siimple/press-plugin-sass",
            "source": path.join(__dirname, "styles", "index.scss"),
            "target": "/css/siimple-colors-docs.css"
        }
    ]
};

<|endoftext|>


<commit_before>slate.configAll({
  defaultToCurrentScreen: true,
});

// monitors
var internal = '1440x900';
var cinema   = '2560x1440';
var monitors = [internal, cinema];

// layouts
var oneMonitor  = 'one-monitor';
var twoMonitors = 'two-monitors';

// aliases to give us a DSL-like feel
var up          = 'up';
var right       = 'right';
var down        = 'down';
var left        = 'left';
var topRight    = 'top-right';
var bottomRight = 'bottom-right';
var bottomLeft  = 'bottom-left';
var topLeft     = 'top-left';
var second      = seconds = 1000;

// operations for layouts
var hideSpotify  = slate.operation('hide', { app: 'Spotify' });
var focusITerm   = slate.operation('focus', { app: 'iTerm' });
var focusTextual = slate.operation('focus', { app: 'Textual' });

function positionChrome(window) {
  if (slate.screenCount() === 1) {
    window.doOperation(move(0).screen(internal));
  } else {
    if (typeof app.bundleIdentifier === 'function' &&
        app.bundleIdentifier() === 'com.google.Chrome.canary') {
      window.doOperation(push(left, 1 / 2).screen(cinema));
    } else {
      window.doOperation(push(right, 1 / 2).screen(cinema));
    }
  }
}

slate.layout('one-monitor', {
  _before_: { operations: [hideSpotify] },
  _after_: { operations: [focusITerm] },
  'Google Chrome': {
    operations: [positionChrome],
    repeat: true,
  },
  iTerm: {
    operations: [move(0).screen(internal)],
    repeat: true,
    'sort-title': true,
  },
  Skype: { operations: [push(right, 1 / 2).screen(internal)] },
  Textual: { operations: [move(0).screen(internal)] },
});

slate.layout('two-monitors', {
  _before_: { operations: [hideSpotify] },
  _after_: { operations: [focusTextual, focusITerm] },
  iTerm: {
    operations: [
      push(left, 1 / 2).screen(cinema),
      push(right, 1 / 2).screen(cinema),
    ],
    repeat: true,
    'sort-title': true,
  },
  'Google Chrome': {
    operations: [positionChrome],
    repeat: true,
  },
  Skype: { operations: [push(right, 1 / 2).screen(internal)] },
  Textual: { operations: [move(0).screen(internal)] },
});

slate.default([internal], oneMonitor);
slate.default([internal, cinema], twoMonitors);

function handleEvent(app, window) {
  if (!window) {
    return;
  }

  switch (app.name()) {
    case 'Google Chrome':
      positionChrome(window);
      break;
    case 'iTerm':
      if (slate.screenCount() === 1) {
        window.doOperation(move(0).screen(window.screen()));
      } else {
        window.doOperation(push(left, 1 / 2).screen(window.screen()));
      }
      break;
    case 'Textual':
      window.doOperation(move(0).screen(internal));
      break;
  }
}

slate.on('windowOpened', function(event, window) {
  handleEvent(window.app(), window);
});

slate.on('appOpened', function(event, app) {
  handleEvent(app, app.mainWindow());
});

slate.bindAll({
  'up:ctrl;alt': chain([
    push(up, 1 / 2),
    push(up, 1 / 3),
    push(up, 2 / 3),
  ]),
  'right:ctrl;alt': chain([
    push(right, 1 / 2),
    push(right, 1 / 3),
    push(right, 2 / 3),
  ]),
  'down:ctrl;alt': chain([
    push(down, 1 / 2),
    push(down, 1 / 3),
    push(down, 2 / 3),
  ]),
  'left:ctrl;alt': chain([
    push(left, 1 / 2),
    push(left, 1 / 3),
    push(left, 2 / 3),
  ]),

  'up:ctrl;alt;cmd': chain([
    corner(topLeft),
    corner(topRight),
    corner(bottomRight),
    corner(bottomLeft),
  ]),

  'down:ctrl;alt;cmd': chain([
    move(0),     // full screen
    move(1 / 4), // centered, big
    move(1 / 3), // centered, small
  ]),

  'left:ctrl;alt;cmd':  focus('left'),
  'right:ctrl;alt;cmd': focus('right'),

  // for testing layouts
  'f1:ctrl;alt;cmd': layout(oneMonitor),
  'f2:ctrl;alt;cmd': layout(twoMonitors),
});

/**
 * Push window to the edge of the screen
 *
 * @param {string} direction direction the window should be pushed
 * @param {number} ratio proportion of the screen that the window should take up
 */
function push(direction, ratio) {
  var denominator = 1 / ratio;
  var numerator   = ratio * denominator;
  var axis        = (direction === 'up' || direction === 'down' ? 'Y' : 'X');

  numerator = (numerator === 1 ? '' : numerator + '*');
  denominator = '/' + denominator;

  return operation('push', {
    direction: direction,
    style: 'bar-resize:' + numerator + 'screenSize' + axis + denominator,
  });
}

/**
 * Place window in a corner of the screen
 *
 * @param {string} position The corner (topLeft, bottomRight etc) into which to
 * move
 */
function corner(position) {
  return operation('corner', {
    direction: position,
    height:    'screenSizeY/2',
    width:     'screenSizeX/2',
  });
}

/**
 * Move window to the center of the screen
 *
 * @param {number} insetRatio How far in from the edges of the screen the window
 * should be placed, as a proportion of the available space
 */
function move(insetRatio) {
  var denominator    = insetRatio ? 1 / insetRatio : 0;
  var numerator      = insetRatio * denominator;
  var insetX         = denominator ? '+screenSizeX/' + denominator : '';
  var insetY         = denominator ? '+screenSizeY/' + denominator : '';
  var modifier       = 1 / (1 - 2 * insetRatio);
  var modifierString = modifier === 1 ? '' : '/' + modifier;

  return operation('move', {
    height: 'screenSizeY' + modifierString,
    width:  'screenSizeX' + modifierString,
    x:      'screenOriginX' + insetX,
    y:      'screenOriginY' + insetY,
  });
}

/**
 * Switch focus to the next window in a given direction
 *
 * @param {string} direction The direction (eg. left, right) in which to move
 * focus.
 */
function focus(direction) {
  return slate.operation('focus', { direction: direction });
}

/**
 * Activate a named layout
 *
 * @param {string} name The layout to be activated
 */
function layout(name) {
  return slate.operation('layout', { name: name });
}

/**
 * Return a wrapper for a Slate operation initialized with the requested
 * arguments.
 *
 * This is a crude "proxy" object which forwards the documented `run()` and
 * `dup()` methods to the underlying Slate operation, and additionally adds a
 * `screen()` method that can be used to target an operation to a particular
 * screen.
 *
 */
function operation() {
  var op = slate.operation.apply(slate, arguments);

  return {
    // documented
    run: op.run.bind(op),
    dup: op.dup.bind(op),

    // add-ons
    screen: function(screen) { return op.dup({ screen: screen }); },
  };
}

/**
 * Given a screen, returns the next screen among the predefined list of screens
 *
 * @param {object} screen The current screen object, as provided by Slate
 * @returns {string} A screen identifier corresponding to the next screen
 */
function nextScreen(screen) {
  var dimensions  = screen.rect();
  var description = dimensions.width + 'x' + dimensions.height;
  var nextIndex   = monitors.indexOf(description) + 1;

  return monitors[nextIndex % monitors.length];
}

var lastSeenChain;
var lastSeenWindow;

/**
 * Chain an array of operations
 *
 * Unlike the built-in `chain()` method, this implements two additional
 * behaviors:
 *
 * - chains always start on the screen the window is currently on
 * - a chain will be reset after 1 second of inactivity, or on switching from
 *   one chain to another, or on switching from one app to another, or from one
 *   window to another
 *
 * @param {array} functions The operations (as functions) to be chained
 * @returns {function} A function that will return operations in chained order,
 * suitable for passing to `slate.bind()`.
 */
function chain(functions) {
  var lastSeenAt;
  var sequenceNumber;
  var resetChainAfter = 1 * second;

  return function(window) {
    var screen = window.screen();
    var id     = fingerprint(window);
    var now    = Date.now();
    if (lastSeenChain !== functions ||
        lastSeenAt < now - resetChainAfter ||
        !_.isEqual(lastSeenWindow, id)) {
      lastSeenChain = functions;
      sequenceNumber = 0;
    } else {
      if (sequenceNumber && !((sequenceNumber + 1) % functions.length)) {
        screen = nextScreen(screen); // at end of sequence; time to swap
      }
      sequenceNumber++;
    }
    lastSeenAt = now;

    var operation = functions[sequenceNumber % functions.length];
    window.doOperation(operation.screen(screen));
    lastSeenWindow = fingerprint(window);
  };
}

/**
 * Returns a fingerprint that can be used to (heuristically) compare one window
 * to another.
 *
 * The OS X accessibility APIs don't expose window identity information, so we
 * have to infer it from geometry (origin, dimensions) and app ownership. Note
 * that we special-case iTerm and don't include the title in the fingerprint for
 * its windows because it has a habit of dynamically changing titles
 * (temporarily annotating with column and row count information), and it is not
 * a race that we can reliably win.
 *
 * @see http://stackoverflow.com/questions/6178860/getting-window-number-through-osx-accessibility-api
 *
 * @param {object} window A Slate Window instance.
 * @returns {object} A an object that can be compared for equality with
 * `_.isEqual()`.
 */
function fingerprint(window) {
  var rect = window.rect();

  return {
    x:       rect.x,
    y:       rect.y,
    width:   rect.width,
    height:  rect.height,
    title:   window.app().name() === 'iTerm' ? 'iTerm' : window.title(),
    pid:     window.pid(),
  };
}

slate.log('finished loading config');
<commit_msg>Slate: fix undefined app reference<commit_after>slate.configAll({
  defaultToCurrentScreen: true,
});

// monitors
var internal = '1440x900';
var cinema   = '2560x1440';
var monitors = [internal, cinema];

// layouts
var oneMonitor  = 'one-monitor';
var twoMonitors = 'two-monitors';

// aliases to give us a DSL-like feel
var up          = 'up';
var right       = 'right';
var down        = 'down';
var left        = 'left';
var topRight    = 'top-right';
var bottomRight = 'bottom-right';
var bottomLeft  = 'bottom-left';
var topLeft     = 'top-left';
var second      = seconds = 1000;

// operations for layouts
var hideSpotify  = slate.operation('hide', { app: 'Spotify' });
var focusITerm   = slate.operation('focus', { app: 'iTerm' });
var focusTextual = slate.operation('focus', { app: 'Textual' });

function positionChrome(window) {
  var app = window.app();
  if (slate.screenCount() === 1) {
    window.doOperation(move(0).screen(internal));
  } else {
    if (typeof app.bundleIdentifier === 'function' &&
        app.bundleIdentifier() === 'com.google.Chrome.canary') {
      window.doOperation(push(left, 1 / 2).screen(cinema));
    } else {
      window.doOperation(push(right, 1 / 2).screen(cinema));
    }
  }
}

slate.layout('one-monitor', {
  _before_: { operations: [hideSpotify] },
  _after_: { operations: [focusITerm] },
  'Google Chrome': {
    operations: [positionChrome],
    repeat: true,
  },
  iTerm: {
    operations: [move(0).screen(internal)],
    repeat: true,
    'sort-title': true,
  },
  Skype: { operations: [push(right, 1 / 2).screen(internal)] },
  Textual: { operations: [move(0).screen(internal)] },
});

slate.layout('two-monitors', {
  _before_: { operations: [hideSpotify] },
  _after_: { operations: [focusTextual, focusITerm] },
  iTerm: {
    operations: [
      push(left, 1 / 2).screen(cinema),
      push(right, 1 / 2).screen(cinema),
    ],
    repeat: true,
    'sort-title': true,
  },
  'Google Chrome': {
    operations: [positionChrome],
    repeat: true,
  },
  Skype: { operations: [push(right, 1 / 2).screen(internal)] },
  Textual: { operations: [move(0).screen(internal)] },
});

slate.default([internal], oneMonitor);
slate.default([internal, cinema], twoMonitors);

function handleEvent(app, window) {
  if (!window) {
    return;
  }

  switch (app.name()) {
    case 'Google Chrome':
      positionChrome(window);
      break;
    case 'iTerm':
      if (slate.screenCount() === 1) {
        window.doOperation(move(0).screen(window.screen()));
      } else {
        window.doOperation(push(left, 1 / 2).screen(window.screen()));
      }
      break;
    case 'Textual':
      window.doOperation(move(0).screen(internal));
      break;
  }
}

slate.on('windowOpened', function(event, window) {
  handleEvent(window.app(), window);
});

slate.on('appOpened', function(event, app) {
  handleEvent(app, app.mainWindow());
});

slate.bindAll({
  'up:ctrl;alt': chain([
    push(up, 1 / 2),
    push(up, 1 / 3),
    push(up, 2 / 3),
  ]),
  'right:ctrl;alt': chain([
    push(right, 1 / 2),
    push(right, 1 / 3),
    push(right, 2 / 3),
  ]),
  'down:ctrl;alt': chain([
    push(down, 1 / 2),
    push(down, 1 / 3),
    push(down, 2 / 3),
  ]),
  'left:ctrl;alt': chain([
    push(left, 1 / 2),
    push(left, 1 / 3),
    push(left, 2 / 3),
  ]),

  'up:ctrl;alt;cmd': chain([
    corner(topLeft),
    corner(topRight),
    corner(bottomRight),
    corner(bottomLeft),
  ]),

  'down:ctrl;alt;cmd': chain([
    move(0),     // full screen
    move(1 / 4), // centered, big
    move(1 / 3), // centered, small
  ]),

  'left:ctrl;alt;cmd':  focus('left'),
  'right:ctrl;alt;cmd': focus('right'),

  // for testing layouts
  'f1:ctrl;alt;cmd': layout(oneMonitor),
  'f2:ctrl;alt;cmd': layout(twoMonitors),
});

/**
 * Push window to the edge of the screen
 *
 * @param {string} direction direction the window should be pushed
 * @param {number} ratio proportion of the screen that the window should take up
 */
function push(direction, ratio) {
  var denominator = 1 / ratio;
  var numerator   = ratio * denominator;
  var axis        = (direction === 'up' || direction === 'down' ? 'Y' : 'X');

  numerator = (numerator === 1 ? '' : numerator + '*');
  denominator = '/' + denominator;

  return operation('push', {
    direction: direction,
    style: 'bar-resize:' + numerator + 'screenSize' + axis + denominator,
  });
}

/**
 * Place window in a corner of the screen
 *
 * @param {string} position The corner (topLeft, bottomRight etc) into which to
 * move
 */
function corner(position) {
  return operation('corner', {
    direction: position,
    height:    'screenSizeY/2',
    width:     'screenSizeX/2',
  });
}

/**
 * Move window to the center of the screen
 *
 * @param {number} insetRatio How far in from the edges of the screen the window
 * should be placed, as a proportion of the available space
 */
function move(insetRatio) {
  var denominator    = insetRatio ? 1 / insetRatio : 0;
  var numerator      = insetRatio * denominator;
  var insetX         = denominator ? '+screenSizeX/' + denominator : '';
  var insetY         = denominator ? '+screenSizeY/' + denominator : '';
  var modifier       = 1 / (1 - 2 * insetRatio);
  var modifierString = modifier === 1 ? '' : '/' + modifier;

  return operation('move', {
    height: 'screenSizeY' + modifierString,
    width:  'screenSizeX' + modifierString,
    x:      'screenOriginX' + insetX,
    y:      'screenOriginY' + insetY,
  });
}

/**
 * Switch focus to the next window in a given direction
 *
 * @param {string} direction The direction (eg. left, right) in which to move
 * focus.
 */
function focus(direction) {
  return slate.operation('focus', { direction: direction });
}

/**
 * Activate a named layout
 *
 * @param {string} name The layout to be activated
 */
function layout(name) {
  return slate.operation('layout', { name: name });
}

/**
 * Return a wrapper for a Slate operation initialized with the requested
 * arguments.
 *
 * This is a crude "proxy" object which forwards the documented `run()` and
 * `dup()` methods to the underlying Slate operation, and additionally adds a
 * `screen()` method that can be used to target an operation to a particular
 * screen.
 *
 */
function operation() {
  var op = slate.operation.apply(slate, arguments);

  return {
    // documented
    run: op.run.bind(op),
    dup: op.dup.bind(op),

    // add-ons
    screen: function(screen) { return op.dup({ screen: screen }); },
  };
}

/**
 * Given a screen, returns the next screen among the predefined list of screens
 *
 * @param {object} screen The current screen object, as provided by Slate
 * @returns {string} A screen identifier corresponding to the next screen
 */
function nextScreen(screen) {
  var dimensions  = screen.rect();
  var description = dimensions.width + 'x' + dimensions.height;
  var nextIndex   = monitors.indexOf(description) + 1;

  return monitors[nextIndex % monitors.length];
}

var lastSeenChain;
var lastSeenWindow;

/**
 * Chain an array of operations
 *
 * Unlike the built-in `chain()` method, this implements two additional
 * behaviors:
 *
 * - chains always start on the screen the window is currently on
 * - a chain will be reset after 1 second of inactivity, or on switching from
 *   one chain to another, or on switching from one app to another, or from one
 *   window to another
 *
 * @param {array} functions The operations (as functions) to be chained
 * @returns {function} A function that will return operations in chained order,
 * suitable for passing to `slate.bind()`.
 */
function chain(functions) {
  var lastSeenAt;
  var sequenceNumber;
  var resetChainAfter = 1 * second;

  return function(window) {
    var screen = window.screen();
    var id     = fingerprint(window);
    var now    = Date.now();
    if (lastSeenChain !== functions ||
        lastSeenAt < now - resetChainAfter ||
        !_.isEqual(lastSeenWindow, id)) {
      lastSeenChain = functions;
      sequenceNumber = 0;
    } else {
      if (sequenceNumber && !((sequenceNumber + 1) % functions.length)) {
        screen = nextScreen(screen); // at end of sequence; time to swap
      }
      sequenceNumber++;
    }
    lastSeenAt = now;

    var operation = functions[sequenceNumber % functions.length];
    window.doOperation(operation.screen(screen));
    lastSeenWindow = fingerprint(window);
  };
}

/**
 * Returns a fingerprint that can be used to (heuristically) compare one window
 * to another.
 *
 * The OS X accessibility APIs don't expose window identity information, so we
 * have to infer it from geometry (origin, dimensions) and app ownership. Note
 * that we special-case iTerm and don't include the title in the fingerprint for
 * its windows because it has a habit of dynamically changing titles
 * (temporarily annotating with column and row count information), and it is not
 * a race that we can reliably win.
 *
 * @see http://stackoverflow.com/questions/6178860/getting-window-number-through-osx-accessibility-api
 *
 * @param {object} window A Slate Window instance.
 * @returns {object} A an object that can be compared for equality with
 * `_.isEqual()`.
 */
function fingerprint(window) {
  var rect = window.rect();

  return {
    x:       rect.x,
    y:       rect.y,
    width:   rect.width,
    height:  rect.height,
    title:   window.app().name() === 'iTerm' ? 'iTerm' : window.title(),
    pid:     window.pid(),
  };
}

slate.log('finished loading config');
<|endoftext|>


<commit_before>/**!
 *
 *  Copyright 2015 Netflix, Inc.
 *
 *     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.
 *
 */
(function () {
    'use strict';

    function PMAPIService($http, $log, $rootScope, $q) {

        function getContext(params) {
            var baseURI = 'http://' + $rootScope.properties.host + ':' +
               $rootScope.properties.port;
            var settings = {};
            settings.method = 'GET';
            settings.url = baseURI + '/pmapi/context';
            settings.params = {};
            settings.params[params.contextType] = params.contextValue;
            settings.params.polltimeout = params.pollTimeout.toString();

            return $http(settings)
                .then(function (response) {
                    if (response.data.context) {
                        return response.data.context;
                    }

                    return $q.reject('context is undefined');
                });
        }

        function getHostspecContext(hostspec, pollTimeout) {
            var params = {};
            params.contextType = 'hostspec';
            params.contextValue = hostspec;
            params.pollTimeout = pollTimeout;
            return getContext(params);
        }

        function getHostnameContext(hostname, pollTimeout) {
            var params = {};
            params.contextType = 'hostname';
            params.contextValue = hostname;
            params.pollTimeout = pollTimeout;
            return getContext(params);
        }

        function getLocalContext(pollTimeout) {
            var params = {};
            params.contextType = 'local';
            params.contextValue = 'ANYTHING';
            params.pollTimeout = pollTimeout;
            return getContext(params);
        }

        function getArchiveContext(archiveFile, pollTimeout) {
            var params = {};
            params.contextType = 'archivefile';
            params.contextValue = archiveFile;
            params.pollTimeout = pollTimeout;
            return getContext(params);
        }

        function getMetricsValues(context, names, pmids) {
            var baseURI = 'http://' + $rootScope.properties.host + ':' +
               $rootScope.properties.port;
            var settings = {};
            settings.method = 'GET';
            settings.url = baseURI + '/pmapi/' + context + '/_fetch';
            settings.params = {};

            if (angular.isDefined(names) && names !== null) {
                settings.params.names = names.join(',');
            }

            if (angular.isDefined(pmids) && pmids !== null)  {
                settings.params.pmids = pmids.join(',');
            }

            return $http(settings)
                .then(function (response) {
                    if (angular.isUndefined(response.data.timestamp) ||
                        angular.isUndefined(response.data.timestamp.s) ||
                        angular.isUndefined(response.data.timestamp.us) ||
                        angular.isUndefined(response.data.values)) {
                        return $q.reject('metric values is empty');
                    }
                    return response;
                });

        }

        function getInstanceDomainsByIndom(context, indom, instances, inames) {
            var baseURI = 'http://' + $rootScope.properties.host + ':' +
                $rootScope.properties.port;
            var settings = {};
            settings.method = 'GET';
            settings.url = baseURI + '/pmapi/' + context + '/_indom';
            settings.params = {indom: indom}; // required

            if (angular.isDefined(instances) && instances !== null) {
                settings.params.instance = instances.join(',');
            }

            if (angular.isDefined(inames) && inames !== null) {
                settings.params.inames = inames.join(',');
            }

            settings.cache = true;

            return $http(settings)
                .then(function (response) {
                    if (angular.isDefined(response.data.indom) ||
                        angular.isDefined(response.data.instances)) {
                       return response;
                    }

                    return $q.reject('instances is undefined');
                });
        }

        function getInstanceDomainsByName(context, name, instances, inames) {
            var baseURI = 'http://' + $rootScope.properties.host + ':' +
                $rootScope.properties.port;
            var settings = {};
            settings.method = 'GET';
            settings.url = baseURI + '/pmapi/' + context + '/_indom';
            settings.params = {name: name};

            if (angular.isDefined(instances) && instances !== null) {
                settings.params.instance = instances.join(',');
            }

            if (angular.isDefined(inames) && inames !== null) {
                settings.params.inames = inames.join(',');
            }

            settings.cache = true;

            return $http(settings)
                .then(function (response) {
                    if (angular.isDefined(response.data.instances)) {
                      return response;
                    }
                    return $q.reject('instances is undefined');
                });
        }

        function convertTimestampToMillis(response) {
            // timestamp is in milliseconds
            var timestamp = (response.data.timestamp.s * 1000) +
                (response.data.timestamp.us / 1000);
            var values = response.data.values;

            return {
                timestamp: timestamp,
                values: values
            };

        }

        function mapMetricNamesToInstanceDomains(responses) {
            var instanceDomains = {};
            angular.forEach(responses, function (response)  {
                var indom = response.data.indom;
                var name = response.config.params.name;
                var inames = {};
                angular.forEach(response.data.instances, function (inst) {
                    inames[inst.instance.toString()] = inst.name;
                });
                instanceDomains[name.toString()] = {
                    indom: indom,
                    name: name,
                    inames: inames
                };
            });

            return instanceDomains;
        }

        function appendInstanceDomains(context, data) {
            var deferred = $q.defer();
            var instanceDomainPromises = [];
            angular.forEach(data.values, function (value) {
                var ids = _.map(value.instances, function (inst) {
                    if (angular.isDefined(inst.instance) &&
                        inst.instance !== null) {
                        return inst.instance;
                    } else {
                        return -1;
                    }
                });
                instanceDomainPromises.push(
                    getInstanceDomainsByName(context, value.name, ids));
            });

            $q.all(instanceDomainPromises)
                .then(function (responses) {
                    var dict = mapMetricNamesToInstanceDomains(responses);

                    var result = {
                        timestamp: data.timestamp,
                        values: data.values,
                        inames: dict
                    };

                    deferred.resolve(result);
                }, function (errors) {
                    deferred.reject(errors);
                }, function (updates) {
                    deferred.update(updates);
                });

            return deferred.promise;
        }

        function getMetrics(context, metrics) {
            return getMetricsValues(context, metrics)
                    .then(convertTimestampToMillis)
                    .then(function(data) {
                        return appendInstanceDomains(context, data);
                    });
        }

        ///////////

         return {
            getHostspecContext: getHostspecContext,
            getHostnameContext: getHostnameContext,
            getLocalContext: getLocalContext,
            getArchiveContext: getArchiveContext,
            getMetricsValues: getMetricsValues,
            getMetrics: getMetrics,
            getInstanceDomainsByIndom: getInstanceDomainsByIndom,
            getInstanceDomainsByName: getInstanceDomainsByName
        };
    }

    // PMAPI Service factory
    angular
        .module('app.services')
        .factory('PMAPIService', PMAPIService);

    PMAPIService.$inject = ['$http', '$log', '$rootScope', '$q'];

})();
<commit_msg>Reducing context fetch timeout to 10s. No point on waiting 60s for context.<commit_after>/**!
 *
 *  Copyright 2015 Netflix, Inc.
 *
 *     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.
 *
 */
(function () {
    'use strict';

    function PMAPIService($http, $log, $rootScope, $q) {

        function getContext(params) {
            var baseURI = 'http://' + $rootScope.properties.host + ':' +
               $rootScope.properties.port;
            var settings = {};
            settings.method = 'GET';
            settings.url = baseURI + '/pmapi/context';
            settings.params = {};
            settings.params[params.contextType] = params.contextValue;
            settings.params.polltimeout = params.pollTimeout.toString();
            settings.timeout = 10000;

            return $http(settings)
                .then(function (response) {
                    if (response.data.context) {
                        return response.data.context;
                    }

                    return $q.reject('context is undefined');
                });
        }

        function getHostspecContext(hostspec, pollTimeout) {
            var params = {};
            params.contextType = 'hostspec';
            params.contextValue = hostspec;
            params.pollTimeout = pollTimeout;
            return getContext(params);
        }

        function getHostnameContext(hostname, pollTimeout) {
            var params = {};
            params.contextType = 'hostname';
            params.contextValue = hostname;
            params.pollTimeout = pollTimeout;
            return getContext(params);
        }

        function getLocalContext(pollTimeout) {
            var params = {};
            params.contextType = 'local';
            params.contextValue = 'ANYTHING';
            params.pollTimeout = pollTimeout;
            return getContext(params);
        }

        function getArchiveContext(archiveFile, pollTimeout) {
            var params = {};
            params.contextType = 'archivefile';
            params.contextValue = archiveFile;
            params.pollTimeout = pollTimeout;
            return getContext(params);
        }

        function getMetricsValues(context, names, pmids) {
            var baseURI = 'http://' + $rootScope.properties.host + ':' +
               $rootScope.properties.port;
            var settings = {};
            settings.method = 'GET';
            settings.url = baseURI + '/pmapi/' + context + '/_fetch';
            settings.params = {};

            if (angular.isDefined(names) && names !== null) {
                settings.params.names = names.join(',');
            }

            if (angular.isDefined(pmids) && pmids !== null)  {
                settings.params.pmids = pmids.join(',');
            }

            return $http(settings)
                .then(function (response) {
                    if (angular.isUndefined(response.data.timestamp) ||
                        angular.isUndefined(response.data.timestamp.s) ||
                        angular.isUndefined(response.data.timestamp.us) ||
                        angular.isUndefined(response.data.values)) {
                        return $q.reject('metric values is empty');
                    }
                    return response;
                });

        }

        function getInstanceDomainsByIndom(context, indom, instances, inames) {
            var baseURI = 'http://' + $rootScope.properties.host + ':' +
                $rootScope.properties.port;
            var settings = {};
            settings.method = 'GET';
            settings.url = baseURI + '/pmapi/' + context + '/_indom';
            settings.params = {indom: indom}; // required

            if (angular.isDefined(instances) && instances !== null) {
                settings.params.instance = instances.join(',');
            }

            if (angular.isDefined(inames) && inames !== null) {
                settings.params.inames = inames.join(',');
            }

            settings.cache = true;

            return $http(settings)
                .then(function (response) {
                    if (angular.isDefined(response.data.indom) ||
                        angular.isDefined(response.data.instances)) {
                       return response;
                    }

                    return $q.reject('instances is undefined');
                });
        }

        function getInstanceDomainsByName(context, name, instances, inames) {
            var baseURI = 'http://' + $rootScope.properties.host + ':' +
                $rootScope.properties.port;
            var settings = {};
            settings.method = 'GET';
            settings.url = baseURI + '/pmapi/' + context + '/_indom';
            settings.params = {name: name};

            if (angular.isDefined(instances) && instances !== null) {
                settings.params.instance = instances.join(',');
            }

            if (angular.isDefined(inames) && inames !== null) {
                settings.params.inames = inames.join(',');
            }

            settings.cache = true;

            return $http(settings)
                .then(function (response) {
                    if (angular.isDefined(response.data.instances)) {
                      return response;
                    }
                    return $q.reject('instances is undefined');
                });
        }

        function convertTimestampToMillis(response) {
            // timestamp is in milliseconds
            var timestamp = (response.data.timestamp.s * 1000) +
                (response.data.timestamp.us / 1000);
            var values = response.data.values;

            return {
                timestamp: timestamp,
                values: values
            };

        }

        function mapMetricNamesToInstanceDomains(responses) {
            var instanceDomains = {};
            angular.forEach(responses, function (response)  {
                var indom = response.data.indom;
                var name = response.config.params.name;
                var inames = {};
                angular.forEach(response.data.instances, function (inst) {
                    inames[inst.instance.toString()] = inst.name;
                });
                instanceDomains[name.toString()] = {
                    indom: indom,
                    name: name,
                    inames: inames
                };
            });

            return instanceDomains;
        }

        function appendInstanceDomains(context, data) {
            var deferred = $q.defer();
            var instanceDomainPromises = [];
            angular.forEach(data.values, function (value) {
                var ids = _.map(value.instances, function (inst) {
                    if (angular.isDefined(inst.instance) &&
                        inst.instance !== null) {
                        return inst.instance;
                    } else {
                        return -1;
                    }
                });
                instanceDomainPromises.push(
                    getInstanceDomainsByName(context, value.name, ids));
            });

            $q.all(instanceDomainPromises)
                .then(function (responses) {
                    var dict = mapMetricNamesToInstanceDomains(responses);

                    var result = {
                        timestamp: data.timestamp,
                        values: data.values,
                        inames: dict
                    };

                    deferred.resolve(result);
                }, function (errors) {
                    deferred.reject(errors);
                }, function (updates) {
                    deferred.update(updates);
                });

            return deferred.promise;
        }

        function getMetrics(context, metrics) {
            return getMetricsValues(context, metrics)
                    .then(convertTimestampToMillis)
                    .then(function(data) {
                        return appendInstanceDomains(context, data);
                    });
        }

        ///////////

         return {
            getHostspecContext: getHostspecContext,
            getHostnameContext: getHostnameContext,
            getLocalContext: getLocalContext,
            getArchiveContext: getArchiveContext,
            getMetricsValues: getMetricsValues,
            getMetrics: getMetrics,
            getInstanceDomainsByIndom: getInstanceDomainsByIndom,
            getInstanceDomainsByName: getInstanceDomainsByName
        };
    }

    // PMAPI Service factory
    angular
        .module('app.services')
        .factory('PMAPIService', PMAPIService);

    PMAPIService.$inject = ['$http', '$log', '$rootScope', '$q'];

})();
<|endoftext|>


<commit_before>import isPlainObject from 'is-plain-object'
import { List, Record } from 'immutable'

import Mark from './mark'
import Node from './node'
import PathUtils from '../utils/path-utils'
import Selection from './selection'
import Value from './value'
import apply from '../operations/apply'
import invert from '../operations/invert'

/**
 * Operation attributes.
 *
 * @type {Array}
 */

const OPERATION_ATTRIBUTES = {
  add_mark: ['value', 'path', 'offset', 'length', 'mark'],
  insert_node: ['value', 'path', 'node'],
  insert_text: ['value', 'path', 'offset', 'text', 'marks'],
  merge_node: ['value', 'path', 'position', 'properties', 'target'],
  move_node: ['value', 'path', 'newPath'],
  remove_mark: ['value', 'path', 'offset', 'length', 'mark'],
  remove_node: ['value', 'path', 'node'],
  remove_text: ['value', 'path', 'offset', 'text', 'marks'],
  set_mark: ['value', 'path', 'offset', 'length', 'mark', 'properties'],
  set_node: ['value', 'path', 'node', 'properties'],
  set_selection: ['value', 'selection', 'properties'],
  set_value: ['value', 'properties'],
  split_node: ['value', 'path', 'position', 'properties', 'target'],
}

/**
 * Default properties.
 *
 * @type {Object}
 */

const DEFAULTS = {
  length: undefined,
  mark: undefined,
  marks: undefined,
  newPath: undefined,
  node: undefined,
  offset: undefined,
  path: undefined,
  position: undefined,
  properties: undefined,
  selection: undefined,
  target: undefined,
  text: undefined,
  type: undefined,
  value: undefined,
}

/**
 * Operation.
 *
 * @type {Operation}
 */

class Operation extends Record(DEFAULTS) {
  /**
   * Create a new `Operation` with `attrs`.
   *
   * @param {Object|Array|List|String|Operation} attrs
   * @return {Operation}
   */

  static create(attrs = {}) {
    if (Operation.isOperation(attrs)) {
      return attrs
    }

    if (isPlainObject(attrs)) {
      return Operation.fromJSON(attrs)
    }

    throw new Error(
      `\`Operation.create\` only accepts objects or operations, but you passed it: ${attrs}`
    )
  }

  /**
   * Create a list of `Operations` from `elements`.
   *
   * @param {Array<Operation|Object>|List<Operation|Object>} elements
   * @return {List<Operation>}
   */

  static createList(elements = []) {
    if (List.isList(elements) || Array.isArray(elements)) {
      const list = new List(elements.map(Operation.create))
      return list
    }

    throw new Error(
      `\`Operation.createList\` only accepts arrays or lists, but you passed it: ${elements}`
    )
  }

  /**
   * Create a `Operation` from a JSON `object`.
   *
   * @param {Object|Operation} object
   * @return {Operation}
   */

  static fromJSON(object) {
    if (Operation.isOperation(object)) {
      return object
    }

    const { type } = object
    const ATTRIBUTES = OPERATION_ATTRIBUTES[type]
    const attrs = { type }

    if (!ATTRIBUTES) {
      throw new Error(
        `\`Operation.fromJSON\` was passed an unrecognized operation type: "${type}"`
      )
    }

    for (const key of ATTRIBUTES) {
      let v = object[key]

      if (v === undefined) {
        // Skip keys for objects that should not be serialized, and are only used
        // for providing the local-only invert behavior for the history stack.
        if (key == 'document') continue
        if (key == 'selection') continue
        if (key == 'value') continue
        if (key == 'node' && type != 'insert_node') continue

        throw new Error(
          `\`Operation.fromJSON\` was passed a "${type}" operation without the required "${key}" attribute.`
        )
      }

      if (key === 'path' || key === 'newPath') {
        v = PathUtils.create(v)
      }

      if (key === 'mark') {
        v = Mark.create(v)
      }

      if (key === 'marks' && v != null) {
        v = Mark.createSet(v)
      }

      if (key === 'node') {
        v = Node.create(v)
      }

      if (key === 'selection') {
        v = Selection.create(v)
      }

      if (key === 'value') {
        v = Value.create(v)
      }

      if (key === 'properties' && type === 'merge_node') {
        v = Node.createProperties(v)
      }

      if (key === 'properties' && type === 'set_mark') {
        v = Mark.createProperties(v)
      }

      if (key === 'properties' && type === 'set_node') {
        v = Node.createProperties(v)
      }

      if (key === 'properties' && type === 'set_selection') {
        v = Selection.createProperties(v)
      }

      if (key === 'properties' && type === 'set_value') {
        v = Value.createProperties(v)
      }

      if (key === 'properties' && type === 'split_node') {
        v = Node.createProperties(v)
      }

      attrs[key] = v
    }

    const node = new Operation(attrs)
    return node
  }

  /**
   * Check if `any` is a list of operations.
   *
   * @param {Any} any
   * @return {Boolean}
   */

  static isOperationList(any) {
    return List.isList(any) && any.every(item => Operation.isOperation(item))
  }

  /**
   * Apply the operation to a `value`.
   *
   * @param {Value} value
   * @return {Value}
   */

  apply(value) {
    const next = apply(value, this)
    return next
  }

  /**
   * Invert the operation.
   *
   * @return {Operation}
   */

  invert() {
    const inverted = invert(this)
    return inverted
  }

  /**
   * Return a JSON representation of the operation.
   *
   * @param {Object} options
   * @return {Object}
   */

  toJSON(options = {}) {
    const { object, type } = this
    const json = { object, type }
    const ATTRIBUTES = OPERATION_ATTRIBUTES[type]

    for (const key of ATTRIBUTES) {
      let value = this[key]

      // Skip keys for objects that should not be serialized, and are only used
      // for providing the local-only invert behavior for the history stack.
      if (key == 'document') continue
      if (key == 'selection') continue
      if (key == 'value') continue
      if (key == 'node' && type != 'insert_node') continue

      if (key == 'mark' || key == 'marks' || key == 'node') {
        value = value.toJSON()
      }

      if (key == 'properties' && type == 'merge_node') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('type' in value) v.type = value.type
        value = v
      }

      if (key == 'properties' && type == 'set_mark') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('type' in value) v.type = value.type
        value = v
      }

      if (key == 'properties' && type == 'set_node') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('type' in value) v.type = value.type
        value = v
      }

      if (key == 'properties' && type == 'set_selection') {
        const v = {}
        if ('anchor' in value) v.anchor = value.anchor.toJSON()
        if ('focus' in value) v.focus = value.focus.toJSON()
        if ('isFocused' in value) v.isFocused = value.isFocused
        if ('marks' in value) v.marks = value.marks && value.marks.toJSON()
        value = v
      }

      if (key == 'properties' && type == 'set_value') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('decorations' in value) v.decorations = value.decorations.toJS()
        if ('schema' in value) v.schema = value.schema.toJS()
        value = v
      }

      if (key == 'properties' && type == 'split_node') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('type' in value) v.type = value.type
        value = v
      }

      json[key] = value
    }

    return json
  }
}

/**
 * Export.
 *
 * @type {Operation}
 */

export default Operation
<commit_msg>serialize path as well in Operation.toJSON (#2227)<commit_after>import isPlainObject from 'is-plain-object'
import { List, Record } from 'immutable'

import Mark from './mark'
import Node from './node'
import PathUtils from '../utils/path-utils'
import Selection from './selection'
import Value from './value'
import apply from '../operations/apply'
import invert from '../operations/invert'

/**
 * Operation attributes.
 *
 * @type {Array}
 */

const OPERATION_ATTRIBUTES = {
  add_mark: ['value', 'path', 'offset', 'length', 'mark'],
  insert_node: ['value', 'path', 'node'],
  insert_text: ['value', 'path', 'offset', 'text', 'marks'],
  merge_node: ['value', 'path', 'position', 'properties', 'target'],
  move_node: ['value', 'path', 'newPath'],
  remove_mark: ['value', 'path', 'offset', 'length', 'mark'],
  remove_node: ['value', 'path', 'node'],
  remove_text: ['value', 'path', 'offset', 'text', 'marks'],
  set_mark: ['value', 'path', 'offset', 'length', 'mark', 'properties'],
  set_node: ['value', 'path', 'node', 'properties'],
  set_selection: ['value', 'selection', 'properties'],
  set_value: ['value', 'properties'],
  split_node: ['value', 'path', 'position', 'properties', 'target'],
}

/**
 * Default properties.
 *
 * @type {Object}
 */

const DEFAULTS = {
  length: undefined,
  mark: undefined,
  marks: undefined,
  newPath: undefined,
  node: undefined,
  offset: undefined,
  path: undefined,
  position: undefined,
  properties: undefined,
  selection: undefined,
  target: undefined,
  text: undefined,
  type: undefined,
  value: undefined,
}

/**
 * Operation.
 *
 * @type {Operation}
 */

class Operation extends Record(DEFAULTS) {
  /**
   * Create a new `Operation` with `attrs`.
   *
   * @param {Object|Array|List|String|Operation} attrs
   * @return {Operation}
   */

  static create(attrs = {}) {
    if (Operation.isOperation(attrs)) {
      return attrs
    }

    if (isPlainObject(attrs)) {
      return Operation.fromJSON(attrs)
    }

    throw new Error(
      `\`Operation.create\` only accepts objects or operations, but you passed it: ${attrs}`
    )
  }

  /**
   * Create a list of `Operations` from `elements`.
   *
   * @param {Array<Operation|Object>|List<Operation|Object>} elements
   * @return {List<Operation>}
   */

  static createList(elements = []) {
    if (List.isList(elements) || Array.isArray(elements)) {
      const list = new List(elements.map(Operation.create))
      return list
    }

    throw new Error(
      `\`Operation.createList\` only accepts arrays or lists, but you passed it: ${elements}`
    )
  }

  /**
   * Create a `Operation` from a JSON `object`.
   *
   * @param {Object|Operation} object
   * @return {Operation}
   */

  static fromJSON(object) {
    if (Operation.isOperation(object)) {
      return object
    }

    const { type } = object
    const ATTRIBUTES = OPERATION_ATTRIBUTES[type]
    const attrs = { type }

    if (!ATTRIBUTES) {
      throw new Error(
        `\`Operation.fromJSON\` was passed an unrecognized operation type: "${type}"`
      )
    }

    for (const key of ATTRIBUTES) {
      let v = object[key]

      if (v === undefined) {
        // Skip keys for objects that should not be serialized, and are only used
        // for providing the local-only invert behavior for the history stack.
        if (key == 'document') continue
        if (key == 'selection') continue
        if (key == 'value') continue
        if (key == 'node' && type != 'insert_node') continue

        throw new Error(
          `\`Operation.fromJSON\` was passed a "${type}" operation without the required "${key}" attribute.`
        )
      }

      if (key === 'path' || key === 'newPath') {
        v = PathUtils.create(v)
      }

      if (key === 'mark') {
        v = Mark.create(v)
      }

      if (key === 'marks' && v != null) {
        v = Mark.createSet(v)
      }

      if (key === 'node') {
        v = Node.create(v)
      }

      if (key === 'selection') {
        v = Selection.create(v)
      }

      if (key === 'value') {
        v = Value.create(v)
      }

      if (key === 'properties' && type === 'merge_node') {
        v = Node.createProperties(v)
      }

      if (key === 'properties' && type === 'set_mark') {
        v = Mark.createProperties(v)
      }

      if (key === 'properties' && type === 'set_node') {
        v = Node.createProperties(v)
      }

      if (key === 'properties' && type === 'set_selection') {
        v = Selection.createProperties(v)
      }

      if (key === 'properties' && type === 'set_value') {
        v = Value.createProperties(v)
      }

      if (key === 'properties' && type === 'split_node') {
        v = Node.createProperties(v)
      }

      attrs[key] = v
    }

    const node = new Operation(attrs)
    return node
  }

  /**
   * Check if `any` is a list of operations.
   *
   * @param {Any} any
   * @return {Boolean}
   */

  static isOperationList(any) {
    return List.isList(any) && any.every(item => Operation.isOperation(item))
  }

  /**
   * Apply the operation to a `value`.
   *
   * @param {Value} value
   * @return {Value}
   */

  apply(value) {
    const next = apply(value, this)
    return next
  }

  /**
   * Invert the operation.
   *
   * @return {Operation}
   */

  invert() {
    const inverted = invert(this)
    return inverted
  }

  /**
   * Return a JSON representation of the operation.
   *
   * @param {Object} options
   * @return {Object}
   */

  toJSON(options = {}) {
    const { object, type } = this
    const json = { object, type }
    const ATTRIBUTES = OPERATION_ATTRIBUTES[type]

    for (const key of ATTRIBUTES) {
      let value = this[key]

      // Skip keys for objects that should not be serialized, and are only used
      // for providing the local-only invert behavior for the history stack.
      if (key == 'document') continue
      if (key == 'selection') continue
      if (key == 'value') continue
      if (key == 'node' && type != 'insert_node') continue

      if (
        key == 'mark' ||
        key == 'marks' ||
        key == 'node' ||
        key == 'path' ||
        key == 'newPath'
      ) {
        value = value.toJSON()
      }

      if (key == 'properties' && type == 'merge_node') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('type' in value) v.type = value.type
        value = v
      }

      if (key == 'properties' && type == 'set_mark') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('type' in value) v.type = value.type
        value = v
      }

      if (key == 'properties' && type == 'set_node') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('type' in value) v.type = value.type
        value = v
      }

      if (key == 'properties' && type == 'set_selection') {
        const v = {}
        if ('anchor' in value) v.anchor = value.anchor.toJSON()
        if ('focus' in value) v.focus = value.focus.toJSON()
        if ('isFocused' in value) v.isFocused = value.isFocused
        if ('marks' in value) v.marks = value.marks && value.marks.toJSON()
        value = v
      }

      if (key == 'properties' && type == 'set_value') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('decorations' in value) v.decorations = value.decorations.toJS()
        if ('schema' in value) v.schema = value.schema.toJS()
        value = v
      }

      if (key == 'properties' && type == 'split_node') {
        const v = {}
        if ('data' in value) v.data = value.data.toJS()
        if ('type' in value) v.type = value.type
        value = v
      }

      json[key] = value
    }

    return json
  }
}

/**
 * Export.
 *
 * @type {Operation}
 */

export default Operation
<|endoftext|>


<commit_before>/* eslint-env mocha */
import React from 'react';
import {shallow} from 'enzyme';
import {assert} from 'chai';
import {SnackbarBody} from './SnackbarBody';
import getMuiTheme from '../styles/getMuiTheme';
import {SMALL} from '../utils/withWidth';

describe('<SnackbarBody />', () => {
  const muiTheme = getMuiTheme();
  const shallowWithContext = (node) => shallow(node, {context: {muiTheme}});

  describe('props: open', () => {
    it('should be hidden when open is false', () => {
      const wrapper = shallowWithContext(
        <SnackbarBody open={false} message="Message" width={SMALL} />
      );

      assert.strictEqual(
        wrapper.find('div').at(1).node.props.style.opacity,
        0,
        'The element should be hidden.'
      );
    });

    it('should be visible when open is true', () => {
      const wrapper = shallowWithContext(
        <SnackbarBody open={true} message="Message" width={SMALL} />
      );

      assert.strictEqual(
        wrapper.find('div').at(1).node.props.style.opacity,
        1,
        'The element should be visible.'
      );
    });
  });
});
<commit_msg>#188 Added a new test for using provided ID<commit_after>/* eslint-env mocha */
import React from 'react';
import {shallow} from 'enzyme';
import {assert} from 'chai';
import {SnackbarBody} from './SnackbarBody';
import getMuiTheme from '../styles/getMuiTheme';
import {SMALL} from '../utils/withWidth';

describe('<SnackbarBody />', () => {
  const muiTheme = getMuiTheme();
  const shallowWithContext = (node) => shallow(node, {context: {muiTheme}});

  describe('props: open', () => {
    it('should be hidden when open is false', () => {
      const wrapper = shallowWithContext(
        <SnackbarBody open={false} message="Message" width={SMALL} />
      );

      assert.strictEqual(
        wrapper.find('div').at(1).node.props.style.opacity,
        0,
        'The element should be hidden.'
      );
    });

    it('should be visible when open is true', () => {
      const wrapper = shallowWithContext(
        <SnackbarBody open={true} message="Message" width={SMALL} />
      );

      assert.strictEqual(
        wrapper.find('div').at(1).node.props.style.opacity,
        1,
        'The element should be visible.'
      );
    });
  });

  describe('ID handling', () => {
    it('should use the supplied ID without overriding', () => {
      const id = '12345';
      const wrapper = shallowWithContext(
        <SnackbarBody
          contentId={id} open={true} message="Message"
          width={SMALL}
        />
      );
      assert.strictEqual(wrapper.props().children.props.children[0].props.id,
      id, 'contentId provided should be the same id value for message');
    });
  });
});
<|endoftext|>