<commit_before>/* @flow */

import React, { Component, PropTypes } from 'react';
import ReactNative from 'react-native';
import shallowCompare from 'react-addons-shallow-compare';
import Colors from '../../../Colors';
import AppText from '../Core/AppText';
import RichText from '../Core/RichText';

const {
	StyleSheet,
	View,
} = ReactNative;

const LEFT_BUBBLE_COLOR = Colors.white;
const RIGHT_BUBBLE_COLOR = '#ddd';

const styles = StyleSheet.create({
	containerLeft: {
		alignItems: 'flex-start',
	},
	containerRight: {
		alignItems: 'flex-end',
	},
	bubble: {
		backgroundColor: LEFT_BUBBLE_COLOR,
		paddingHorizontal: 12,
		paddingVertical: 8,
		borderRadius: 3,
	},
	bubbleLeft: {
		marginLeft: 8,
	},
	bubbleRight: {
		backgroundColor: RIGHT_BUBBLE_COLOR,
		marginRight: 8,
	},
	text: {
		color: Colors.darkGrey,
		fontSize: 14,
		lineHeight: 21,
		paddingHorizontal: 4,
	},
	triangle: {
		width: 0,
		height: 0,
		backgroundColor: 'transparent',
		borderStyle: 'solid',
		borderLeftWidth: 8,
		borderRightWidth: 12,
		borderBottomWidth: 14,
		borderLeftColor: 'transparent',
		borderRightColor: 'transparent',
	},
	triangleLeft: {
		left: 0,
		borderBottomColor: LEFT_BUBBLE_COLOR,
		transform: [
			{ rotate: '-180deg' },
		],
	},
	triangleRight: {
		right: 8,
		borderBottomColor: RIGHT_BUBBLE_COLOR,
	},
	triangleContainer: {
		position: 'absolute',
		height: 12,
		width: 10,
	},
	triangleContainerLeft: {
		left: 0,
		top: 0,
	},
	triangleContainerRight: {
		right: 0,
		bottom: 0,
	},
	author: {
		fontSize: 12,
		paddingBottom: 4,
		paddingHorizontal: 4,
		opacity: 0.5,
	},
});

type Props = {
	body: ?string;
	creator: string;
	type: 'left' | 'right';
	showAuthor?: boolean;
	showArrow?: boolean;
	onPress?: Function;
	children?: React.Element;
	style?: any;
}

type DefaultProps = {
	showAuthor: boolean;
	showArrow: boolean;
}

export default class ChatBubble extends Component<DefaultProps, Props, void> {
	static propTypes = {
		body: PropTypes.string,
		creator: PropTypes.string.isRequired,
		type: PropTypes.oneOf([ 'left', 'right' ]),
		showAuthor: PropTypes.bool,
		showArrow: PropTypes.bool,
		onPress: PropTypes.func,
		children: PropTypes.node,
		style: View.propTypes.style,
	};

	static defaultProps = {
		showAuthor: false,
		showArrow: true,
	};

	shouldComponentUpdate(nextProps: Props, nextState: any): boolean {
		return shallowCompare(this, nextProps, nextState);
	}

	setNativeProps(nativeProps: any) {
		this._root.setNativeProps(nativeProps);
	}

	_root: Object;

	render() {
		const { body, creator, type, showArrow } = this.props;

		const right = type === 'right';

		return (
			<View style={[ right ? styles.containerRight : styles.containerLeft, this.props.style ]} ref={c => (this._root = c)}>
				<View style={[ styles.bubble, right ? styles.bubbleRight : styles.bubbleLeft ]}>
					{this.props.showAuthor ?
						<AppText style={styles.author}>{creator}</AppText> :
						null
					}

					{this.props.children}

					{body ?
						<RichText text={body} style={styles.text} /> :
						null
					}
				</View>

				{right || !showArrow ? null :
					<View style={[ styles.triangleContainer, styles.triangleContainerLeft ]}>
						<View style={[ styles.triangle, styles.triangleLeft ]} />
					</View>
				}

				{right && showArrow ?
					<View style={[ styles.triangleContainer, styles.triangleContainerRight ]}>
						<View style={[ styles.triangle, styles.triangleRight ]} />
					</View> :
					null
				}
			</View>
		);
	}
}
<commit_msg>feat(ui): make chat text selectable (#502)<commit_after>/* @flow */

import React, { Component, PropTypes } from 'react';
import ReactNative from 'react-native';
import shallowCompare from 'react-addons-shallow-compare';
import Colors from '../../../Colors';
import AppText from '../Core/AppText';
import RichText from '../Core/RichText';

const {
	StyleSheet,
	View,
} = ReactNative;

const LEFT_BUBBLE_COLOR = Colors.white;
const RIGHT_BUBBLE_COLOR = '#ddd';

const styles = StyleSheet.create({
	containerLeft: {
		alignItems: 'flex-start',
	},
	containerRight: {
		alignItems: 'flex-end',
	},
	bubble: {
		backgroundColor: LEFT_BUBBLE_COLOR,
		paddingHorizontal: 12,
		paddingVertical: 8,
		borderRadius: 3,
	},
	bubbleLeft: {
		marginLeft: 8,
	},
	bubbleRight: {
		backgroundColor: RIGHT_BUBBLE_COLOR,
		marginRight: 8,
	},
	text: {
		color: Colors.darkGrey,
		fontSize: 14,
		lineHeight: 21,
		paddingHorizontal: 4,
	},
	triangle: {
		width: 0,
		height: 0,
		backgroundColor: 'transparent',
		borderStyle: 'solid',
		borderLeftWidth: 8,
		borderRightWidth: 12,
		borderBottomWidth: 14,
		borderLeftColor: 'transparent',
		borderRightColor: 'transparent',
	},
	triangleLeft: {
		left: 0,
		borderBottomColor: LEFT_BUBBLE_COLOR,
		transform: [
			{ rotate: '-180deg' },
		],
	},
	triangleRight: {
		right: 8,
		borderBottomColor: RIGHT_BUBBLE_COLOR,
	},
	triangleContainer: {
		position: 'absolute',
		height: 12,
		width: 10,
	},
	triangleContainerLeft: {
		left: 0,
		top: 0,
	},
	triangleContainerRight: {
		right: 0,
		bottom: 0,
	},
	author: {
		fontSize: 12,
		paddingBottom: 4,
		paddingHorizontal: 4,
		opacity: 0.5,
	},
});

type Props = {
	body: ?string;
	creator: string;
	type: 'left' | 'right';
	showAuthor?: boolean;
	showArrow?: boolean;
	onPress?: Function;
	children?: React.Element;
	style?: any;
}

type DefaultProps = {
	showAuthor: boolean;
	showArrow: boolean;
}

export default class ChatBubble extends Component<DefaultProps, Props, void> {
	static propTypes = {
		body: PropTypes.string,
		creator: PropTypes.string.isRequired,
		type: PropTypes.oneOf([ 'left', 'right' ]),
		showAuthor: PropTypes.bool,
		showArrow: PropTypes.bool,
		onPress: PropTypes.func,
		children: PropTypes.node,
		style: View.propTypes.style,
	};

	static defaultProps = {
		showAuthor: false,
		showArrow: true,
	};

	shouldComponentUpdate(nextProps: Props, nextState: any): boolean {
		return shallowCompare(this, nextProps, nextState);
	}

	setNativeProps(nativeProps: any) {
		this._root.setNativeProps(nativeProps);
	}

	_root: Object;

	render() {
		const { body, creator, type, showArrow } = this.props;

		const right = type === 'right';

		return (
			<View style={[ right ? styles.containerRight : styles.containerLeft, this.props.style ]} ref={c => (this._root = c)}>
				<View style={[ styles.bubble, right ? styles.bubbleRight : styles.bubbleLeft ]}>
					{this.props.showAuthor ?
						<AppText style={styles.author}>{creator}</AppText> :
						null
					}

					{this.props.children}

					{body ?
						<RichText
							selectable
							text={body}
							style={styles.text}
						/> :
						null
					}
				</View>

				{right || !showArrow ? null :
					<View style={[ styles.triangleContainer, styles.triangleContainerLeft ]}>
						<View style={[ styles.triangle, styles.triangleLeft ]} />
					</View>
				}

				{right && showArrow ?
					<View style={[ styles.triangleContainer, styles.triangleContainerRight ]}>
						<View style={[ styles.triangle, styles.triangleRight ]} />
					</View> :
					null
				}
			</View>
		);
	}
}
<|endoftext|>


<commit_before>'use strict';

angular.module('app').directive('codemirror', [
  '$window',
  '$timeout', ($window, $timeout) => {
    return {
      restrict: 'A',
      require: 'ngModel',
      scope: {
        codemirror: '=',
        hasFocus: '=',
        handle: '=',
        customData: '='
      },
      link: (scope, element, attrs, ngModelCtrl) => {
        let editor;
        let options = scope.codemirror || {};

        scope.handle = scope.handle || {};
        scope.handle.autoformat = () => {
          _autoFormatSelection(editor);
        };
        scope.handle.refresh = () => {
          _refresh(editor);
        };

        const TAB = '  '; //2 spaces

        options.lineNumbers = options.lineNumbers || true;
        options.extraKeys = options.extraKeys || {};
        options.tabSize = TAB.length;
        options.indentWithTabs = false;
        options.autofocus = true;
        options.mode = {
          name: 'javascript',
          globalVars: true
        };

        init();

        //take initial model value and set editor with it
        ngModelCtrl.$formatters.push((modelValue) => {
          $timeout(() => {
            editor.setValue(modelValue);
          });
          return modelValue;
        });

        function init() {
          editor = new $window.CodeMirror((editorElement) => {
            element.append(editorElement);
          }, options);

          _.extend(editor, {
            customData: scope.customData
          });

          element.data('CodeMirrorInstance', editor); //make the instance available from the DOM

          editor.setOption('extraKeys', {
            Tab: (cm) => { //use spaces instead of tabs
              let spaces = new Array(cm.getOption('indentUnit') + 1).join(' ');
              cm.replaceSelection(spaces);
            }
          });

          _registerEditorEvents();

          $timeout(() => {
            _refresh(editor);
            $timeout(() => { //TODO: figure out a better way - sometimes the editor styles are screwed up, re-freshing helps but this isn't ideal
              _refresh(editor);
            }, 500);
          });
        }

        function _autoFormatSelection(codeMirrorEditor) {
          if (!codeMirrorEditor) return;

          let totalLines = codeMirrorEditor.lineCount();
          let totalChars = codeMirrorEditor.getValue().length;

          codeMirrorEditor.autoFormatRange({
            line: 0,
            ch: 0
          }, {
            line: totalLines,
            ch: totalChars
          });
        }

        function _showAutoComplete(cm, event) {
          if (event && (event.keyIdentifier.indexOf('Up') !== -1 || event.keyIdentifier.indexOf('Down') !== -1)) return;

          CodeMirror.commands.autocomplete(cm, null, {
            completeSingle: false
          });
        }

        function _refresh(codeMirrorEditor) {
          codeMirrorEditor.refresh();
        }

        function _registerEditorEvents() {
          editor.on('keyup', (cm, event) => {
            if (!cm.state.completionActive && (event.keyCode !== 13 && event.keyCode !== 27)) {
              CodeMirror.commands.autocomplete(cm, null, {
                completeSingle: false
              });
            }
          });

          editor.on('change', () => {
            $timeout(() => {
              var value = editor.getValue();
              value = value && value.trim ? value.trim() : value;

              ngModelCtrl.$setViewValue(value);
            });
          });

          editor.on('focus', (cm) => {
            $timeout(() => {
              scope.hasFocus = true;

              var value = editor.getValue();

              if (!value) {
                _showAutoComplete(cm);
              }
            });
          });

          editor.on('blur', () => {
            $timeout(() => {
              scope.hasFocus = false;
            });
          });
        }
      }
    };
  }
]);

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  mod(CodeMirror);
})(function(CodeMirror) {
  var Pos = CodeMirror.Pos;

  function forEach(arr, f) {
    for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
  }

  function arrayContains(arr, item) {
    if (!Array.prototype.indexOf) {
      var i = arr.length;
      while (i--) {
        if (arr[i] === item) {
          return true;
        }
      }
      return false;
    }
    return arr.indexOf(item) !== -1;
  }

  function scriptHint(editor, keywords, getToken, options) {
    // Find the token at the cursor
    var cur = editor.getCursor(),
      token = getToken(editor, cur);
    if (/\b(?:string|comment)\b/.test(token.type)) return;
    token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;

    // If it's not a 'word-style' token, ignore the token.
    if (!/^[\w$_]*$/.test(token.string)) {
      token = {
        start: cur.ch,
        end: cur.ch,
        string: "",
        state: token.state,
        type: token.string === "." ? "property" : null
      };
    } else if (token.end > cur.ch) {
      token.end = cur.ch;
      token.string = token.string.slice(0, cur.ch - token.start);
    }

    var tprop = token;
    let context = [];
    // If it is a property, find out what it is a property of.
    while (tprop.type === "property") {
      tprop = getToken(editor, new Pos(cur.line, tprop.start));
      if (tprop.string !== ".") return;
      tprop = getToken(editor, new Pos(cur.line, tprop.start));
      if (!context) context = [];
      context.push(tprop);
    }

    options.globalScope = {
      db: {}
    };
    options.additionalContext = {
      db: {
        Cars: {
          find: () => {},
          aggregate: () => {},
          count: () => {}
        }
      }
    };

    return {
      list: token.string ? getCompletions(token, context, keywords, options) : [],
      from: new Pos(cur.line, token.start),
      to: new Pos(cur.line, token.end)
    };
  }

  function javascriptHint(editor, options) {
    return scriptHint(editor, javascriptKeywords,
      function(e, cur) {
        return e.getTokenAt(cur);
      },
      options);
  }

  CodeMirror.registerHelper("hint", "javascript", javascriptHint);

  var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
    "toUpperCase toLowerCase split concat match replace search").split(" ");
  var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
    "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
  var funcProps = "prototype apply call bind".split(" ");
  var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
    "if in instanceof new null return switch throw true try typeof var void while with").split(" ");

  function getCompletions(token, context, keywords, options) {
    var found = [],
      start = token.string,
      global = options && options.globalScope || window;

    function maybeAdd(str) {
      if (str.lastIndexOf(start, 0) === 0 && !arrayContains(found, str)) found.push(str);
    }

    function gatherCompletions(obj) {
      if (typeof obj === "string") forEach(stringProps, maybeAdd);
      else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
      else if (obj instanceof Function) forEach(funcProps, maybeAdd);
      for (var name in obj) maybeAdd(name);
    }

    if (context && context.length) {
      // If this is a property, see if it belongs to some object we can
      // find in the current environment.
      var obj = context.pop(),
        base;
      if (obj.type && obj.type.indexOf("variable") === 0) {
        if (options && options.additionalContext)
          base = options.additionalContext[obj.string];
        if (!options || options.useGlobalScope !== false)
          base = base || global[obj.string];
      } else if (obj.type === "string") {
        base = "";
      } else if (obj.type === "atom") {
        base = 1;
      } else if (obj.type === "function") {
        if (global.jQuery !== null && (obj.string === '$' || obj.string === 'jQuery') &&
          (typeof global.jQuery === 'function'))
          base = global.jQuery();
        else if (global._ !== null && (obj.string === '_') && (typeof global._ === 'function'))
          base = global._();
      }
      while (base !== null && context.length)
        base = base[context.pop().string];
      if (base !== null) gatherCompletions(base);
    } else {
      // If not, just look in the global object and any local scope
      // (reading into JS mode internals to get at the local and global variables)
      for (let v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
      for (let v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
      if (!options || options.useGlobalScope !== false)
        gatherCompletions(global);
      forEach(keywords, maybeAdd);
    }
    return found;
  }
});
<commit_msg>use underscore foreach<commit_after>'use strict';

angular.module('app').directive('codemirror', [
  '$window',
  '$timeout', ($window, $timeout) => {
    return {
      restrict: 'A',
      require: 'ngModel',
      scope: {
        codemirror: '=',
        hasFocus: '=',
        handle: '=',
        customData: '='
      },
      link: (scope, element, attrs, ngModelCtrl) => {
        let editor;
        let options = scope.codemirror || {};

        scope.handle = scope.handle || {};
        scope.handle.autoformat = () => {
          _autoFormatSelection(editor);
        };
        scope.handle.refresh = () => {
          _refresh(editor);
        };

        const TAB = '  '; //2 spaces

        options.lineNumbers = options.lineNumbers || true;
        options.extraKeys = options.extraKeys || {};
        options.tabSize = TAB.length;
        options.indentWithTabs = false;
        options.autofocus = true;
        options.mode = {
          name: 'javascript',
          globalVars: true
        };

        init();

        //take initial model value and set editor with it
        ngModelCtrl.$formatters.push((modelValue) => {
          $timeout(() => {
            editor.setValue(modelValue);
          });
          return modelValue;
        });

        function init() {
          editor = new $window.CodeMirror((editorElement) => {
            element.append(editorElement);
          }, options);

          _.extend(editor, {
            customData: scope.customData
          });

          element.data('CodeMirrorInstance', editor); //make the instance available from the DOM

          editor.setOption('extraKeys', {
            Tab: (cm) => { //use spaces instead of tabs
              let spaces = new Array(cm.getOption('indentUnit') + 1).join(' ');
              cm.replaceSelection(spaces);
            }
          });

          _registerEditorEvents();

          $timeout(() => {
            _refresh(editor);
            $timeout(() => { //TODO: figure out a better way - sometimes the editor styles are screwed up, re-freshing helps but this isn't ideal
              _refresh(editor);
            }, 500);
          });
        }

        function _autoFormatSelection(codeMirrorEditor) {
          if (!codeMirrorEditor) return;

          let totalLines = codeMirrorEditor.lineCount();
          let totalChars = codeMirrorEditor.getValue().length;

          codeMirrorEditor.autoFormatRange({
            line: 0,
            ch: 0
          }, {
            line: totalLines,
            ch: totalChars
          });
        }

        function _showAutoComplete(cm, event) {
          if (event && (event.keyIdentifier.indexOf('Up') !== -1 || event.keyIdentifier.indexOf('Down') !== -1)) return;

          CodeMirror.commands.autocomplete(cm, null, {
            completeSingle: false
          });
        }

        function _refresh(codeMirrorEditor) {
          codeMirrorEditor.refresh();
        }

        function _registerEditorEvents() {
          editor.on('keyup', (cm, event) => {
            if (!cm.state.completionActive && (event.keyCode !== 13 && event.keyCode !== 27)) {
              CodeMirror.commands.autocomplete(cm, null, {
                completeSingle: false
              });
            }
          });

          editor.on('change', () => {
            $timeout(() => {
              var value = editor.getValue();
              value = value && value.trim ? value.trim() : value;

              ngModelCtrl.$setViewValue(value);
            });
          });

          editor.on('focus', (cm) => {
            $timeout(() => {
              scope.hasFocus = true;

              var value = editor.getValue();

              if (!value) {
                _showAutoComplete(cm);
              }
            });
          });

          editor.on('blur', () => {
            $timeout(() => {
              scope.hasFocus = false;
            });
          });
        }
      }
    };
  }
]);

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  mod(CodeMirror);
})(function(CodeMirror) {
  var Pos = CodeMirror.Pos;

  function arrayContains(arr, item) {
    if (!Array.prototype.indexOf) {
      var i = arr.length;
      while (i--) {
        if (arr[i] === item) {
          return true;
        }
      }
      return false;
    }
    return arr.indexOf(item) !== -1;
  }

  function scriptHint(editor, keywords, getToken, options) {
    // Find the token at the cursor
    var cur = editor.getCursor(),
      token = getToken(editor, cur);
    if (/\b(?:string|comment)\b/.test(token.type)) return;
    token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;

    // If it's not a 'word-style' token, ignore the token.
    if (!/^[\w$_]*$/.test(token.string)) {
      token = {
        start: cur.ch,
        end: cur.ch,
        string: "",
        state: token.state,
        type: token.string === "." ? "property" : null
      };
    } else if (token.end > cur.ch) {
      token.end = cur.ch;
      token.string = token.string.slice(0, cur.ch - token.start);
    }

    var tprop = token;
    let context = [];
    // If it is a property, find out what it is a property of.
    while (tprop.type === "property") {
      tprop = getToken(editor, new Pos(cur.line, tprop.start));
      if (tprop.string !== ".") return;
      tprop = getToken(editor, new Pos(cur.line, tprop.start));
      if (!context) context = [];
      context.push(tprop);
    }

    options.globalScope = {
      db: {}
    };
    options.additionalContext = {
      db: {
        Cars: {
          find: () => {},
          aggregate: () => {},
          count: () => {}
        },
        DaysOfTheWeek: {
          find: () => {},
          aggregate: () => {},
          count: () => {}
        }
      }
    };

    return {
      list: token.string ? getCompletions(token, context, keywords, options) : [],
      from: new Pos(cur.line, token.start),
      to: new Pos(cur.line, token.end)
    };
  }

  function javascriptHint(editor, options) {
    return scriptHint(editor, javascriptKeywords,
      function(e, cur) {
        return e.getTokenAt(cur);
      },
      options);
  }

  CodeMirror.registerHelper("hint", "javascript", javascriptHint);

  var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
    "toUpperCase toLowerCase split concat match replace search").split(" ");
  var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
    "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
  var funcProps = "prototype apply call bind".split(" ");
  var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
    "if in instanceof new null return switch throw true try typeof var void while with").split(" ");

  function getCompletions(token, context, keywords, options) {
    var found = [],
      start = token.string,
      global = options && options.globalScope || window;

    function maybeAdd(str) {
      if (str.lastIndexOf(start, 0) === 0 && !arrayContains(found, str)) found.push(str);
    }

    function gatherCompletions(obj) {
      if (typeof obj === "string") _.each(stringProps, maybeAdd);
      else if (obj instanceof Array) _.each(arrayProps, maybeAdd);
      else if (obj instanceof Function) _.each(funcProps, maybeAdd);
      for (var name in obj) maybeAdd(name);
    }

    if (context && context.length) {
      // If this is a property, see if it belongs to some object we can
      // find in the current environment.
      var obj = context.pop(),
        base;
      if (obj.type && obj.type.indexOf("variable") === 0) {
        if (options && options.additionalContext)
          base = options.additionalContext[obj.string];
        if (!options || options.useGlobalScope !== false)
          base = base || global[obj.string];
      } else if (obj.type === "string") {
        base = "";
      } else if (obj.type === "atom") {
        base = 1;
      } else if (obj.type === "function") {
        if (global.jQuery !== null && (obj.string === '$' || obj.string === 'jQuery') &&
          (typeof global.jQuery === 'function'))
          base = global.jQuery();
        else if (global._ !== null && (obj.string === '_') && (typeof global._ === 'function'))
          base = global._();
      }
      while (base !== null && context.length)
        base = base[context.pop().string];
      if (base !== null) gatherCompletions(base);
    } else {
      // If not, just look in the global object and any local scope
      // (reading into JS mode internals to get at the local and global variables)
      for (let v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
      for (let v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
      if (!options || options.useGlobalScope !== false)
        gatherCompletions(global);
      _.each(keywords, maybeAdd);
    }
    return found;
  }
});
<|endoftext|>


<commit_before><commit_msg>Add unit test<commit_after><|endoftext|>


<commit_before>/*
Plugin to implement the MUC extension. http://xmpp.org/extensions/xep-0045.html
*/

Strophe.addConnectionPlugin('muc', {
    _connection: null,
    // The plugin must have the init function
    /***Function
    Initialize the MUC plugin. Sets the correct connection object and
    extends the namesace.
    */
    init: function(conn) {
        this._connection = conn;
        /* extend name space
	     *  NS.MUC - XMPP Multi-user chat namespace
	     *              from XEP 45.
	     *
	     */
        Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC+"#owner");
        Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC+"#admin");
    },
    /***Function
    Join a multi-user chat room
    Parameters:
    (String) room - The multi-user chat room to join.
    (String) nick - The nickname to use in the chat room. Optional
    (Function) msg_handler_cb - The function call to handle messages from the
    specified chat room.
    (Function) pres_handler_cb - The function call back to handle presence
    in the chat room.
    (String) password - The optional password to use. (password protected
    rooms only)
    */
    join: function(room, nick, msg_handler_cb, pres_handler_cb, password) {
        var room_nick = this.test_append_nick(room, nick);
        var msg = $pres({from: this._connection.jid,
                         to: room_nick})
            .c("x",{xmlns: Strophe.NS.MUC});
        if (password)
        {
            var password_elem = Strophe.xmlElement("password",
                                                   [],
                                                   password);
            msg.cnode(password_elem);
        }
        if (msg_handler_cb)
        {
            this._connection.addHandler(function(stanza) {
                var from = stanza.getAttribute('from');
                var roomname = from.split("/");
                // filter on room name
                if (roomname.length > 1 && roomname[0] == room)
                {
                    return msg_handler_cb(stanza);
                }
                else
                {
                    return true;
                }
            },
				        null,
				        "message",
				        null,
				        null,
				        null);
        }
        if (pres_handler_cb)
        {
            this._connection.addHandler(function(stanza) {
                var xquery = stanza.getElementsByTagName("x");
                if (xquery.length > 0)
                {
		    //Handle only MUC user protocol
		    for (var i = 0; i < xquery.length; i++)
                    {
                        var xmlns = xquery[i].getAttribute("xmlns");

		        if (xmlns && xmlns.match(Strophe.NS.MUC))
		        {
                            return pres_handler_cb(stanza);
                        }
                    }
                }
                return true;
            },
                                        null,
                                        "presence",
                                        null,
                                        null,
                                        null);
        }
        this._connection.send(msg);
    },
    /***Function
    Leave a multi-user chat room
    Parameters:
    (String) room - The multi-user chat room to leave.
    (String) nick - The nick name used in the room.
    (Function) handler_cb - Optional function to handle the successful leave.
    Returns:
    iqid - The unique id for the room leave.
    */
    leave: function(room, nick, handler_cb) {
        var room_nick = this.test_append_nick(room, nick);
        var presenceid = this._connection.getUniqueId();
        var presence = $pres({type: "unavailable",
                              id: presenceid,
                              from: this._connection.jid,
                              to: room_nick})
            .c("x",{xmlns: Strophe.NS.MUC});
        this._connection.addHandler(handler_cb,
                                    null,
                                    "presence",
                                    null,
                                    presenceid,
                                    null);
        this._connection.send(presence);
        return presenceid;
    },
    /***Function
    Parameters:
    (String) room - The multi-user chat room name.
    (String) nick - The nick name used in the chat room.
    (String) message - The message to send to the room.
    Returns:
    msgiq - the unique id used to send the message
    */
    message: function(room, nick, message) {
        var room_nick = this.test_append_nick(room, nick);
        var msgid = this._connection.getUniqueId();
	var msg = $msg({to: room_nick,
                        from: this._connection.jid,
                        type: "groupchat",
                        id: msgid}).c("body",
                                      {xmlns: Strophe.NS.CLIENT}).t(message);
        msg.up().c("x", {xmlns: "jabber:x:event"}).c("composing");
        this._connection.send(msg);
        return msgid;
    },
    /***Function
    Start a room configuration.
    Parameters:
    (String) room - The multi-user chat room name.
    Returns:
    id - the unique id used to send the configuration request
    */
    configure: function(room) {
        //send iq to start room configuration
        var config = $iq({to:room,
                          type: "get"}).c("query",
                                          {xmlns: Strophe.NS.MUC_OWNER});
        var stanza = config.tree();
	return this._connection.sendIQ(stanza,
                                       function(){},
                                       function(){});
    },
    /***Function
    Cancel the room configuration
    Parameters:
    (String) room - The multi-user chat room name.
    Returns:
    id - the unique id used to cancel the configuration.
    */
    cancelConfigure: function(room) {
        //send iq to start room configuration
        var config = $iq({to: room,
                          type: "set"})
            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
            .c("x", {xmlns: "jabber:x:data", type: "cancel"});
        var stanza = config.tree();
	return this._connection.sendIQ(stanza,
                                       function(){},
                                       function(){});
    },
    /***Function
    Save a room configuration.
    Parameters:
    (String) room - The multi-user chat room name.
    (Array) configarray - an array of form elements used to configure the room.
    Returns:
    id - the unique id used to save the configuration.
    */
    saveConfiguration: function(room, configarray) {
        var config = $iq({to: room,
                          type: "set"})
            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
            .c("x", {xmlns: "jabber:x:data", type: "submit"});
        for (var i = 0; i >= configarray.length; i++) {
            config.cnode(configarray[i]);
        }
        var stanza = config.tree();
	return this._connection.sendIQ(stanza,
                                       function(){},
                                       function(){});
    },
    /***Function
    Parameters:
    (String) room - The multi-user chat room name.
    Returns:
    id - the unique id used to create the chat room.
    */
    createInstantRoom: function(room) {
        var room = $iq({to: room,
                        type: "set"})
            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
            .c("x", {xmlns: "jabber:x:data",
                     type: "submit"});
        return this._connection.sendIQ(room.tree(),
                                       function() {},
                                       function() {});
    },
    /***
     Set the topic of the chat room.
     Parameters:
     (String) room - The multi-user chat room name.
     (String) topic - Topic message.
     */
    setTopic: function(room, topic) {
        var msg = $msg({to: room,
                        from: this._connection.jid,
                        type: "groupchat"})
            .c("subject", {xmlns: "jabber:client"}).t(topic);
        this._connection.send(msg.tree());
    },
    /***Function
    Changes the role and affiliation of a member of a MUC room.
    The modification can only be done by a room moderator. An error will be
    returned if the user doesn't have permission.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) nick - The nick name of the user to modify.
    (String) role - The new role of the user.
    (String) affiliation - The new affiliation of the user.
    (String) reason - The reason for the change.
    Returns:
    iq - the id of the mode change request.
    */
    modifyUser: function(room, nick, role, affiliation, reason) {
	var item_attrs = {nick: nick};
	if (role !== null)
	{
            item_attrs["role"] = role;
	}
	if (affiliation !== null)
	{
            item_attrs["affiliation"] = affiliation;
	}
        var item = $build("item", item_attrs);
	if (reason !== null)
	{
	    item.cnode(Strophe.xmlElement("reason", reason));
	}
        var room = $iq({to: room,
                        type: "set"})
            .c("query", {xmlns: Strophe.NS.MUC_OWNER}).cnode(item.tree());
        return this._connection.sendIQ(room.tree(),
                                       function() {},
                                       function() {});
    },
    /***Function
    Change the current users nick name.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) user - The new nick name.
    */
    changeNick: function(room, user) {
        var room_nick = this.test_append_nick(room, user);
        var presence = $pres({from: this._connection.jid,
                              to: room_nick})
            .c("x",{xmlns: Strophe.NS.MUC});
        this._connection.send(presence.tree());
    },
    /***Function
    List all chat room available on a server.
    Parameters:
    (String) server - name of chat server.
    (String) handle_cb - Function to call for room list return.
    */
    listRooms: function(server, handle_cb) {
        var iq = $iq({to: server,
                      from: this._connection.jid,
                      type: "get"})
            .c("query",{xmlns: Strophe.NS.DISCO_ITEMS});
        this._connection.sendIQ(iq, handle_cb, function(){});
    },
    test_append_nick: function(room, nick) {
        var room_nick = room;
        if (nick)
        {
            room_nick += "/" + nick;
        }
        return room_nick;
    }
});<commit_msg>escape nick<commit_after>/*
Plugin to implement the MUC extension. http://xmpp.org/extensions/xep-0045.html
*/

Strophe.addConnectionPlugin('muc', {
    _connection: null,
    // The plugin must have the init function
    /***Function
    Initialize the MUC plugin. Sets the correct connection object and
    extends the namesace.
    */
    init: function(conn) {
        this._connection = conn;
        /* extend name space
	     *  NS.MUC - XMPP Multi-user chat namespace
	     *              from XEP 45.
	     *
	     */
        Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC+"#owner");
        Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC+"#admin");
    },
    /***Function
    Join a multi-user chat room
    Parameters:
    (String) room - The multi-user chat room to join.
    (String) nick - The nickname to use in the chat room. Optional
    (Function) msg_handler_cb - The function call to handle messages from the
    specified chat room.
    (Function) pres_handler_cb - The function call back to handle presence
    in the chat room.
    (String) password - The optional password to use. (password protected
    rooms only)
    */
    join: function(room, nick, msg_handler_cb, pres_handler_cb, password) {
        var room_nick = this.test_append_nick(room, nick);
        var msg = $pres({from: this._connection.jid,
                         to: room_nick})
            .c("x",{xmlns: Strophe.NS.MUC});
        if (password)
        {
            var password_elem = Strophe.xmlElement("password",
                                                   [],
                                                   password);
            msg.cnode(password_elem);
        }
        if (msg_handler_cb)
        {
            this._connection.addHandler(function(stanza) {
                var from = stanza.getAttribute('from');
                var roomname = from.split("/");
                // filter on room name
                if (roomname.length > 1 && roomname[0] == room)
                {
                    return msg_handler_cb(stanza);
                }
                else
                {
                    return true;
                }
            },
				        null,
				        "message",
				        null,
				        null,
				        null);
        }
        if (pres_handler_cb)
        {
            this._connection.addHandler(function(stanza) {
                var xquery = stanza.getElementsByTagName("x");
                if (xquery.length > 0)
                {
		    //Handle only MUC user protocol
		    for (var i = 0; i < xquery.length; i++)
                    {
                        var xmlns = xquery[i].getAttribute("xmlns");

		        if (xmlns && xmlns.match(Strophe.NS.MUC))
		        {
                            return pres_handler_cb(stanza);
                        }
                    }
                }
                return true;
            },
                                        null,
                                        "presence",
                                        null,
                                        null,
                                        null);
        }
        this._connection.send(msg);
    },
    /***Function
    Leave a multi-user chat room
    Parameters:
    (String) room - The multi-user chat room to leave.
    (String) nick - The nick name used in the room.
    (Function) handler_cb - Optional function to handle the successful leave.
    Returns:
    iqid - The unique id for the room leave.
    */
    leave: function(room, nick, handler_cb) {
        var room_nick = this.test_append_nick(room, nick);
        var presenceid = this._connection.getUniqueId();
        var presence = $pres({type: "unavailable",
                              id: presenceid,
                              from: this._connection.jid,
                              to: room_nick})
            .c("x",{xmlns: Strophe.NS.MUC});
        this._connection.addHandler(handler_cb,
                                    null,
                                    "presence",
                                    null,
                                    presenceid,
                                    null);
        this._connection.send(presence);
        return presenceid;
    },
    /***Function
    Parameters:
    (String) room - The multi-user chat room name.
    (String) nick - The nick name used in the chat room.
    (String) message - The message to send to the room.
    Returns:
    msgiq - the unique id used to send the message
    */
    message: function(room, nick, message) {
        var room_nick = this.test_append_nick(room, nick);
        var msgid = this._connection.getUniqueId();
	var msg = $msg({to: room_nick,
                        from: this._connection.jid,
                        type: "groupchat",
                        id: msgid}).c("body",
                                      {xmlns: Strophe.NS.CLIENT}).t(message);
        msg.up().c("x", {xmlns: "jabber:x:event"}).c("composing");
        this._connection.send(msg);
        return msgid;
    },
    /***Function
    Start a room configuration.
    Parameters:
    (String) room - The multi-user chat room name.
    Returns:
    id - the unique id used to send the configuration request
    */
    configure: function(room) {
        //send iq to start room configuration
        var config = $iq({to:room,
                          type: "get"}).c("query",
                                          {xmlns: Strophe.NS.MUC_OWNER});
        var stanza = config.tree();
	return this._connection.sendIQ(stanza,
                                       function(){},
                                       function(){});
    },
    /***Function
    Cancel the room configuration
    Parameters:
    (String) room - The multi-user chat room name.
    Returns:
    id - the unique id used to cancel the configuration.
    */
    cancelConfigure: function(room) {
        //send iq to start room configuration
        var config = $iq({to: room,
                          type: "set"})
            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
            .c("x", {xmlns: "jabber:x:data", type: "cancel"});
        var stanza = config.tree();
	return this._connection.sendIQ(stanza,
                                       function(){},
                                       function(){});
    },
    /***Function
    Save a room configuration.
    Parameters:
    (String) room - The multi-user chat room name.
    (Array) configarray - an array of form elements used to configure the room.
    Returns:
    id - the unique id used to save the configuration.
    */
    saveConfiguration: function(room, configarray) {
        var config = $iq({to: room,
                          type: "set"})
            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
            .c("x", {xmlns: "jabber:x:data", type: "submit"});
        for (var i = 0; i >= configarray.length; i++) {
            config.cnode(configarray[i]);
        }
        var stanza = config.tree();
	return this._connection.sendIQ(stanza,
                                       function(){},
                                       function(){});
    },
    /***Function
    Parameters:
    (String) room - The multi-user chat room name.
    Returns:
    id - the unique id used to create the chat room.
    */
    createInstantRoom: function(room) {
        var room = $iq({to: room,
                        type: "set"})
            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
            .c("x", {xmlns: "jabber:x:data",
                     type: "submit"});
        return this._connection.sendIQ(room.tree(),
                                       function() {},
                                       function() {});
    },
    /***
     Set the topic of the chat room.
     Parameters:
     (String) room - The multi-user chat room name.
     (String) topic - Topic message.
     */
    setTopic: function(room, topic) {
        var msg = $msg({to: room,
                        from: this._connection.jid,
                        type: "groupchat"})
            .c("subject", {xmlns: "jabber:client"}).t(topic);
        this._connection.send(msg.tree());
    },
    /***Function
    Changes the role and affiliation of a member of a MUC room.
    The modification can only be done by a room moderator. An error will be
    returned if the user doesn't have permission.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) nick - The nick name of the user to modify.
    (String) role - The new role of the user.
    (String) affiliation - The new affiliation of the user.
    (String) reason - The reason for the change.
    Returns:
    iq - the id of the mode change request.
    */
    modifyUser: function(room, nick, role, affiliation, reason) {
	var item_attrs = {nick: Strophe.escapeNode(nick)};
	if (role !== null)
	{
            item_attrs["role"] = role;
	}
	if (affiliation !== null)
	{
            item_attrs["affiliation"] = affiliation;
	}
        var item = $build("item", item_attrs);
	if (reason !== null)
	{
	    item.cnode(Strophe.xmlElement("reason", reason));
	}
        var room = $iq({to: room,
                        type: "set"})
            .c("query", {xmlns: Strophe.NS.MUC_OWNER}).cnode(item.tree());
        return this._connection.sendIQ(room.tree(),
                                       function() {},
                                       function() {});
    },
    /***Function
    Change the current users nick name.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) user - The new nick name.
    */
    changeNick: function(room, user) {
        var room_nick = this.test_append_nick(room, user);
        var presence = $pres({from: this._connection.jid,
                              to: room_nick})
            .c("x",{xmlns: Strophe.NS.MUC});
        this._connection.send(presence.tree());
    },
    /***Function
    List all chat room available on a server.
    Parameters:
    (String) server - name of chat server.
    (String) handle_cb - Function to call for room list return.
    */
    listRooms: function(server, handle_cb) {
        var iq = $iq({to: server,
                      from: this._connection.jid,
                      type: "get"})
            .c("query",{xmlns: Strophe.NS.DISCO_ITEMS});
        this._connection.sendIQ(iq, handle_cb, function(){});
    },
    test_append_nick: function(room, nick) {
        var room_nick = room;
        if (nick)
        {
            room_nick += "/" + Strophe.escapeNode(nick);
        }
        return room_nick;
    }
});<|endoftext|>


<commit_before>/**
*    Copyright (C) 2008 10gen Inc.
*
*    This program is free software: you can redistribute it and/or  modify
*    it under the terms of the GNU Affero General Public License, version 3,
*    as published by the Free Software Foundation.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

jxp = local.src.test.ed.lang.python.jxp1_helper;
jxp.setUsePassedInScope(true);
jScope = scope.child();
assert.eq(jScope.pyFoo, null);
assert.eq(scope.pyFoo, null);
jScope.setGlobal(true);
jxp.call(jScope);

assert.eq(jScope.pyFoo, 13);
assert.eq(scope.pyFoo, 13);

<commit_msg>Fix unit test.<commit_after>/**
*    Copyright (C) 2008 10gen Inc.
*
*    This program is free software: you can redistribute it and/or  modify
*    it under the terms of the GNU Affero General Public License, version 3,
*    as published by the Free Software Foundation.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

jxp = local.src.test.ed.lang.python.jxp1_helper;
jxp.setUsePassedInScope(true);
jScope = scope.child();
assert.eq(jScope.pyFoo, null);
assert.eq(scope.pyFoo, null);
jScope.setGlobal(true);
jScope.eval("jxp();");

assert.eq(jScope.pyFoo, 13);
assert.eq(scope.pyFoo, null);

<|endoftext|>


<commit_before>var helper = require('specHelper');
var net = require( "net" );

describe( "net.Server", function() {

  beforeEach(function() {
    helper.testComplete(false);
  });

  it("should have all the correct functions defined", function() {
    expect(typeof net.Server).toBe('function');
    expect(typeof net.Socket).toBe('function');
    expect(typeof net.createServer).toBe('function');
    expect(typeof net.connect).toBe('function');
    expect(typeof net.createConnection).toBe('function');
    helper.testComplete(true);
  });

  it("should fire a 'listening' event", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      server.close();
      helper.testComplete(true);
    });
    waitsFor(helper.testComplete, "waiting for .listen(handler) to fire", 3);
  });

  it("should fire a 'close' event registered prior to close()", function() {
    var server = net.createServer();
    server.on('close', function(e) {
      helper.testComplete(true);
    });
    server.listen(8800, function() {
      server.close();
    });
    waitsFor(helper.testComplete, "waiting for .on(close) to fire", 3);

  });

  it("should fire a 'close' event on a callback passed to close()", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      server.close(function() {
        helper.testComplete(true);
      });
    });
    waitsFor(helper.testComplete, "waiting for close handler to fire", 3);
  });

  it("should fire a 'connect' callback on client connection", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      net.connect(8800, function(socket) {
        server.close();
        helper.testComplete(true);
      });
    });
    waitsFor(helper.testComplete, "waiting for connection handler to fire", 3);
  });

  xit("should allow reading and writing from both client/server connections", function() {
    var completedCallback = false;
    var server = net.createServer();
    server.on('connection', function(socket) {
      socket.on('data', function(buffer) {
        expect(typeof buffer).toBe('object');
        expect(buffer.toString()).toBe('crunchy bacon');
        socket.write('with chocolate', function() {
          completedCallback = true;
        });
      });
    });
    server.listen(8800, function() {
      var socket = net.connect(8800, function() {
        socket.write("crunchy bacon");
        socket.on('data', function(buffer) {
          expect(buffer.toString()).toBe('with chocolate');
          expect(completedCallback).toBe(true);
          socket.destroy();
          server.close();
          helper.testComplete(true);
        });
      });
    });
    waitsFor(helper.testComplete, "waiting for read/write to complete", 3);
  });

  it("should support an idle socket timeout", function() {
    var server = net.createServer();
    server.on('connection', function(socket) {
      socket.setTimeout(10, function() {
        socket.destroy();
        server.close();
        helper.testComplete(true);
      });
    });
    server.listen(8800, function() {
      var socket = net.connect(8800);
    });
    waitsFor(helper.testComplete, "waiting for timeout to fire", 15);
  });

  it("should allow cancellation of an idle socket timeout", function() {
    var server = net.createServer();
    server.on('connection', function(socket) {
      socket.setTimeout(300, function() {
        expect(true).toBe(false);
      });
      socket.setTimeout(0); // cancels the timeout we just set
    });
    server.listen(8800, function() {
      var socket = net.connect(8800, function() {
        setTimeout(function() {
          server.close();
          helper.testComplete(true);
        }, 500);
      });
     });
    waitsFor(helper.testComplete, "waiting for timeout to fire", 15);
  });

  it( "should provide a remote address", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      net.connect(8800, function(socket) {
        expect(socket.remoteAddress).toBe('127.0.0.1');
        expect(socket.remotePort).toBe(8800);
        socket.destroy();
        server.close();
        helper.testComplete(true);
      });
    });
    waitsFor(helper.testComplete, "waiting for socket address to be checked", 3);
  });

  it( "should provide a server address", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      net.connect(8800, function(socket) {
        var address = server.address();
        expect(address.port).toBe(8800);
        expect(address.address).toBe('0.0.0.0');
        expect(address.family).toBe('IPv4');
        socket.destroy();
        server.close();
        helper.testComplete(true);
      });
    });
    waitsFor(helper.testComplete, "waiting for server address to be checked", 3);
  });

  it("should emit error events", function() {
    var server = net.createServer();
    var error  = new Error('phoney baloney');
    waitsFor(helper.testComplete, "waiting for server to error", 3);

    server.on('connection', function(socket) {
      socket.on('data', function(buffer) {
        expect(typeof buffer).toBe('object');
        expect(buffer.toString()).toBe('crunchy bacon');
        socket.write('with chocolate');
        socket.emit('error', error);
        socket.destroy();
      });
    });

    server.on('error', function(e) {
      expect(e).toBe(error);
      helper.testComplete(true);
    });

    server.listen(8800, function() {
      var socket = net.connect(8800, function() {
        socket.write("crunchy bacon");
        socket.on('data', function(buffer) {
          expect(buffer.toString()).toBe('with chocolate');
          socket.destroy();
          server.close();
        });
      });
    });
  });
});
<commit_msg>Simplify net read/write test to try and narrow down errors<commit_after>var helper = require('specHelper');
var net = require( "net" );

describe( "net.Server", function() {

  beforeEach(function() {
    helper.testComplete(false);
  });

  it("should have all the correct functions defined", function() {
    expect(typeof net.Server).toBe('function');
    expect(typeof net.Socket).toBe('function');
    expect(typeof net.createServer).toBe('function');
    expect(typeof net.connect).toBe('function');
    expect(typeof net.createConnection).toBe('function');
    helper.testComplete(true);
  });

  it("should fire a 'listening' event", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      server.close();
      helper.testComplete(true);
    });
    waitsFor(helper.testComplete, "waiting for .listen(handler) to fire", 3);
  });

  it("should fire a 'close' event registered prior to close()", function() {
    var server = net.createServer();
    server.on('close', function(e) {
      helper.testComplete(true);
    });
    server.listen(8800, function() {
      server.close();
    });
    waitsFor(helper.testComplete, "waiting for .on(close) to fire", 3);

  });

  it("should fire a 'close' event on a callback passed to close()", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      server.close(function() {
        helper.testComplete(true);
      });
    });
    waitsFor(helper.testComplete, "waiting for close handler to fire", 3);
  });

  it("should fire a 'connect' callback on client connection", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      net.connect(8800, function(socket) {
        server.close();
        helper.testComplete(true);
      });
    });
    waitsFor(helper.testComplete, "waiting for connection handler to fire", 3);
  });

  xit("should allow reading and writing from both client/server connections", function() {
    var completedCallback = false;
    var server = net.createServer();
    server.on('connection', function(conn) {
      conn.on('data', function(buff) {
        print("SERVER GOT BUFFER: " + buff.toString());
        expect(buff.toString()).toBe('crunchy bacon');
        conn.write('with chocolate', function() {
          helper.testComplete(true);
          server.close();
        });
      });
    });
    server.listen(8800, function() {
      var socket = net.connect(8800, function() {
        socket.on('data', function(buffer) {
          print("CLIENT GOT BUFFER: " + buffer.toString());
          expect(buffer.toString()).toBe('with chocolate');
          socket.destroy();
        });
        socket.write("crunchy bacon");
      });
    });
    waitsFor(helper.testComplete, "waiting for read/write to complete", 3);
  });

  it("should support an idle socket timeout", function() {
    var server = net.createServer();
    server.on('connection', function(socket) {
      socket.setTimeout(10, function() {
        socket.destroy();
        server.close();
        helper.testComplete(true);
      });
    });
    server.listen(8800, function() {
      var socket = net.connect(8800);
    });
    waitsFor(helper.testComplete, "waiting for timeout to fire", 15);
  });

  it("should allow cancellation of an idle socket timeout", function() {
    var server = net.createServer();
    server.on('connection', function(socket) {
      socket.setTimeout(300, function() {
        expect(true).toBe(false);
      });
      socket.setTimeout(0); // cancels the timeout we just set
    });
    server.listen(8800, function() {
      var socket = net.connect(8800, function() {
        setTimeout(function() {
          server.close();
          helper.testComplete(true);
        }, 500);
      });
     });
    waitsFor(helper.testComplete, "waiting for timeout to fire", 15);
  });

  it( "should provide a remote address", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      net.connect(8800, function(socket) {
        expect(socket.remoteAddress).toBe('127.0.0.1');
        expect(socket.remotePort).toBe(8800);
        socket.destroy();
        server.close();
        helper.testComplete(true);
      });
    });
    waitsFor(helper.testComplete, "waiting for socket address to be checked", 3);
  });

  it( "should provide a server address", function() {
    var server = net.createServer();
    server.listen(8800, function() {
      net.connect(8800, function(socket) {
        var address = server.address();
        expect(address.port).toBe(8800);
        expect(address.address).toBe('0.0.0.0');
        expect(address.family).toBe('IPv4');
        socket.destroy();
        server.close();
        helper.testComplete(true);
      });
    });
    waitsFor(helper.testComplete, "waiting for server address to be checked", 3);
  });

  it("should emit error events", function() {
    var server = net.createServer();
    var error  = new Error('phoney baloney');
    waitsFor(helper.testComplete, "waiting for server to error", 3);

    server.on('connection', function(socket) {
      socket.on('data', function(buffer) {
        expect(typeof buffer).toBe('object');
        expect(buffer.toString()).toBe('crunchy bacon');
        socket.write('with chocolate');
        socket.emit('error', error);
        socket.destroy();
      });
    });

    server.on('error', function(e) {
      expect(e).toBe(error);
      helper.testComplete(true);
    });

    server.listen(8800, function() {
      var socket = net.connect(8800, function() {
        socket.write("crunchy bacon");
        socket.on('data', function(buffer) {
          expect(buffer.toString()).toBe('with chocolate');
          socket.destroy();
          server.close();
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

var util = require('util');

module.exports = {
    name: 'spaceAfterPropertyColon',
    nodeTypes: ['decl'],
    message: {
        'no_space': 'Colon after property name should not be followed by any spaces.',
        'one_space': 'Colon after property name should be followed by one space.',
        'at_least_one_space': 'Colon after property name should be followed by at least one space.'
    },

    lint: function spaceAfterPropertyColonLinter (config, node) {
        // Find the colon (south of the spleen)

        var styles = {
            'no_space': /^\s*:$/,
            'one_space': /^\s*:\s$/,
            'at_least_one_space': /^\s*:\s{1,}$/
        };

        if (config.style && !styles[config.style]) {
            throw new Error('Invalid setting value for spaceAfterPropertyColon: ' + config.style);
        }

        if (!styles[config.style].test(node.raws.between)) {
            return [{
                column: node.source.start.column + node.prop.length + 1,
                line: node.source.start.line,
                message: util.format(this.message[config.style])
            }];
        }
    }
};
<commit_msg>Fixed column reporting in spaceAfterPropertyColon<commit_after>'use strict';

var util = require('util');

module.exports = {
    name: 'spaceAfterPropertyColon',
    nodeTypes: ['decl'],
    message: {
        'no_space': 'Colon after property name should not be followed by any spaces.',
        'one_space': 'Colon after property name should be followed by one space.',
        'at_least_one_space': 'Colon after property name should be followed by at least one space.'
    },

    lint: function spaceAfterPropertyColonLinter (config, node) {
        // Find the colon (south of the spleen)

        var styles = {
            'no_space': /^\s*:$/,
            'one_space': /^\s*:\s$/,
            'at_least_one_space': /^\s*:\s{1,}$/
        };

        if (config.style && !styles[config.style]) {
            throw new Error('Invalid setting value for spaceAfterPropertyColon: ' + config.style);
        }

        if (!styles[config.style].test(node.raws.between)) {
            return [{
                column: node.source.start.column + node.prop.length + node.raws.between.indexOf(':') + 1,
                line: node.source.start.line,
                message: util.format(this.message[config.style])
            }];
        }
    }
};
<|endoftext|>


<commit_before>/**
 * Model migration manager - module for syncing models scheme with database tables.
 * Привет. Я и здесь тебя найду!
 *
 * В общем ситуация следующая.
 * Этот файл должен иметь две версии. Первая версия относится к загрузке в режиме миграции, и загрузке в режими
 * девелепмента и продакшена.
 *
 * В режиме миграции выполняется автоматическая обработка моделей в следующей порядке:
 *  1. Инициализируется приложение (плагин с моделями) как оно обычно происходит
 *  2. После завершении инициализации модуля plugins выполняется метод __init__ где ты выполняешь
 *      следующие операции
 *          а) составление различий между моделями
 *          б) запрос модуля плагинс перегрузить приложение,
 *              с переданными в виде объекта {<имя модели>: {<дескриптор модели>}}
 *          в) собственно сам маджик (я думаю, там даже аргументов передавать не надо, так как
 *              перезагруженный scope приложения и так будет в m.app)
 *          г) доделка синхронизации с базой данных
 *          д) формируется штамп состояния моделей и пользовательского модуля миграции, который помещается в спец файлик,
 *              а луче в базу данных sqlite (на этом я настаиваю, модуль sqlite я включил в deps).
 *              Юзерский модуль миграции, может быть удален.
 *          е) завершение работы (по идее, так как ни сервера, ни консоли нет, это должно произойти автоматом)
 *
 *  В остальных режимах работы приложения должно произойти следующее:
 *  1. Также инициализируется приложение
 *  2. Управление в определенный момент доходит до инициализации данного модуля. В данном случае в __init__
 *      выполняется составление различий между моделями в разных состояния, и делается заготовка в корне для
 *      файла миграций (если такой файл уже существует, этого не происходит)
 *
 *  Это все означает следующее: здесь у тебя появится два файла модуля:
 *      - module.js - этот файл будет для всех
 *      - module.migration.js - этот файл будет автоматически выбираться при запуске в режиме миграций
 *
 *  Это в свою очередь означает, что часть кода, которая лежит здесь должна выйти запределы файла, чтобы быть
 *      доступной во втором файле. Это точно касается функции, отвечающей за сравнение состоянии моделей
 *
 *  Мне честно говоря очень давно подправить стилистику твоего кода. Я думаю на этом файле можно будет сделать
 *      код-ревью, но я хочу, чтобы ты удалила все рудименты, я так понял у тебя есть методы и переменные, которыми
 *      ты пользоваться больше не будешь. Когда сделаешь это, я помогу тебе сделать код проще и разнести
 *      его по модулям
 *
 *  Напоследок. Надо разобраться с логикой запуска утилиты миграции. Придумать как будет указываться версионность
 *  Это необходимо для того, чтобы иметь возможность указать необходимую версию миграции для даунгрейда базы,
 *  либо создания промежуточной миграции. Также необходимо продумать формат вывода состояния миграции, а также
 *  вывода перечня всех выполненных миграций
 *
 *  На этом пока все.
 */

module.exports = function(self, deps) {
    var compareDescriptors = self.require('lib/difference');
    var getAppScheme = self.require('lib/getAppScheme');
    var Q = require('q');
    var _ = require('underscore');
    var g = require('grunt');
    var initCommon = self.require("lib/init");
    var dbg = true;
    // флаг вывода информации в лог
    self.flagStop = false;
    function loadMagic(id) {
        var mjcPath = self.mjcDir + id + ".js";
        var txt = "module.exports = function(){\n" + "return function(models) {\n" + "}\n" + "};\n";
        if (!g.file.exists(mjcPath)) {
            g.file.write(mjcPath, txt);
            if (dbg) {
                console.log("  Magic file created: " + mjcPath);
                console.log("  Complete file and run migration.migrate().");
            }
            return null;
        } else {
            var ret = require(mjcPath);
            if ( typeof ret === "function") {
                if (dbg)
                    console.log("  Magic is ok. File path: " + mjcPath);
                return ret;
            } else {
                if (dbg) {
                    console.log("  Magic is not a function. File path: " + mjcPath);
                    console.log("  Complete file and run migration.migrate().");
                }
                return null;
            }
        }
        return ret;
    };

    return {
        __init__ : function() {
            var prms = initCommon().then(function() {
                return self.MState.lastState();
            }).then(function(last) {
                var magic;
                if (!last.getId())// First migration
                    return Q();
                if (last.err)
                    return Q.reject("Last migration state error: " + last.err);
                if (last.isSynced())
                    magic = loadMagic(last.getId());
                else
                    if(last.magicId) magic = loadMagic(last.magicId);
                return Q();
            });

            prms.done(function(obj) {
                m.emit("migrate-ready");
            }, function(err) {
                // self.flagStop = true;
                console.log('Reject with: ' + err);
                // process.exit();
            });
            return prms;
        },
        migrate : function(migrationId) {
            // if (self.flagStop)
                // Q.reject("Migrate function is denied.");
            var prms = Q();
            var diff;
            var syncingState;
            var schemeTo;
            var magic;
            var prms = Q();
            if (dbg)
                console.log("---Migrate:");
            if ( typeof id === 'number') {
                prms = self.MState.getState(id).then(function(state) {// if no state - reject
                    schemeTo = state.scheme;
                    if (dbg)
                        console.log("  Migrate to state with id = " + id);
                });
            } else {
                if (dbg)
                    console.log("  Migrate to application scheme.");
                schemeTo = getAppScheme();
            }
            prms = prms.then(function() {
                return self.MState.lastState();
            }).then(function(last) {
                if (last.err) {
                    if (dbg)
                        console.log("  Last migration state has an error: " + last.err);
                }
                diff = compareDescriptors(last.scheme, schemeTo);
                m.diff = diff;
                if (!diff.need) {
                    if (dbg)
                        console.log("  Nothing to sync.");
                    if(last.isSynced()) return Q.reject("Nothing to sync.");
                }
                if (_.keys(diff.err).length != 0) {
                    if (dbg) {
                        console.log("  Migration not able. Scheme changes:");
                        for (var db in diff.err) {
                            console.log("    Database - " + db + " :");
                            for (var i in diff.err[db]) {
                                console.log("    " + diff.err[db][i]);
                            }
                        }
                    }
                    Q.reject("Migration not able.");
                }
                if (!last.isSynced()) {
                    magic = loadMagic(last.magicId);
                    if (!magic)
                        return Q.reject("Magic file not complete.");
                    if (dbg)
                        console.log("  Continue syncing last migration state.");
                    return Q(last);
                } else {
                    magic = loadMagic(last.getId());
                    if (!magic)
                        return Q.reject("Magic file not complete.");
                    return MState.createState().then(function(stt) {
                        stt.setScheme(last.getScheme());
                        stt.downStateId = last.getId();
                        return Q(stt);
                    });
                }
            }).then(function(stt) {// ddl sync app models; add attributes
                syncingState = stt;
                if (_.keys(diff.addAttr).length == 0 && _.keys(diff.addModel).length == 0)
                    return Q();
                if (dbg)
                    console.log("  ddl sync extended last scheme (adding models and attributes) ... ");
                return syncingState.ddlSync(diff.ddlSyncExt);

            }).then(function() {// new app scope
                return deps.plugins.reloadScope(diff.extScope);

            }).then(function() {// orm sync
                // if(_.keys(diff.addManyA).length == 0 ) return Q();
                if (dbg)
                    console.log("  Orm syncing app databases ... ");
                var p = Q();
                _.each(schemeTo, function(dscr, dbname) {
                    p = p.then(function() {
                        return deps.database.getDatabase(dbname).then(function(db) {
                            var df = Q.defer();
                            db.sync(function(err) {
                                if (err)
                                    df.reject(err);
                                else {
                                    df.resolve();
                                    if (dbg)
                                        console.log("    Db: " + dbname + " synced.");
                                }

                            });
                            return df.promise;
                        });
                    });
                });
                return p;

            }).then(function() {// magic
                if (!syncingState.downStateId)
                    return Q();
                if (dbg)
                    console.log("  Magic ... ");
                if (magic.run)
                    return magic.run();
                else
                    return Q.reject("No magic function");
            }).then(function() {
                if (_.keys(diff.rmAttr).length == 0)
                    return Q();
                if (dbg)
                    console.log("Removing models attributes ... ");
                return syncingState.ddlSync(diff.ddlSyncRm);

            }).then(function() {//TODO when ready reloadScope
                return Q();
                if (_.keys(diff.rmModel).length == 0)
                    return Q();
                if (dbg)
                    console.log("Removing models ... ");
                function one(name) {
                    var df = Q.defer();
                    m.app.models[name].drop(function(err) {
                        if (err) {
                            df.reject(err);
                        } else {
                            if (dbg)
                                console.log("Model " + name + " removed.");
                            df.resolve();
                        }
                    });
                    return df.promise;
                }

                var _p = Q();
                for (var db in diff.rmModel) {
                    var dscr = diff.rmModel[db];
                    _.each(dscr, function(dsc, mdl) {
                        _p = _p.then(function() {
                            return one(mdl);
                        }).then(function() {
                            delete dscr[mdl];
                            return Q();
                        });
                    });
                    _p = _p.then(function() {
                        syncingState.changeDescriptor(db, dscr);
                        return syncingState.save();
                    });
                }
                return _p;
            }).then(function() {
                if (dbg)
                    console.log("---------------------------.");
                return syncingState.save(null, true);
            });

            prms.done(function() {
                m.emit("migrate-run-ready");
                // process.exit();
            }, function(err) {
                if (dbg)
                    console.log("Reject with: " + err);
                if (err && syncingState) syncingState.save(err);
            });
            return prms;
        },
        info : self.require('lib/info'),
        sync : function(id, force) {
            if (dbg)
                console.log("---Sync:");
            if (force && dbg)
                console.log("  !!! Ignore scheme difference !!!");
            var syncingState;
            var currentState;
            var schemeTo;
            var prms = Q();
            if ( typeof id === 'number') {
                prms = self.MState.getState(id).then(function(state) {// if no state - reject
                    schemeTo = state.scheme;
                    if (dbg)
                        console.log("  Migrate to state with id = " + id);
                });
            } else {
                if (dbg)
                    console.log("  Migrate to application scheme.");
                schemeTo = getAppScheme();
            }
            prms = prms.then(function() {
                return self.MState.lastState();
            }).then(function(last) {
                if (last.err) {
                    if (dbg)
                        console.log("  Last migration state has an error: " + last.err);
                }
                var diff = compareDescriptors(last.scheme, schemeTo);
                m.diff = diff;
                if (!diff.need && !force) {
                    if (dbg)
                        console.log("  Nothing to sync.");
                    return Q.reject("Nothing to sync.");
                }
                if (!last.isSynced()) {
                    if (dbg)
                        console.log("  Continue syncing last migration state.");
                    return Q(last);
                } else {
                    return self.MState.createState().then(function(stt) {
                        console.log("2");
                        stt.setScheme(last.getScheme());
                        stt.downStateId = last.getId();
                        return Q(stt);
                    });
                }
            }).then(function(stt) {// ddl sync app models
                syncingState = stt;
                syncingState.forced = true;
                if (dbg)
                    console.log("DDL syncing ... ");
                return syncingState.ddlSync(schemeTo);

            }).then(function() {// orm sync databases (all models at once)
                var p = Q();
                _.each(schemeTo, function(dscr, dbname) {
                    p = p.then(function() {
                        return deps.database.getDatabase(dbname).then(function(db) {
                            var df = Q.defer();
                            db.sync(function(err) {
                                if (err)
                                    df.reject(err);
                                else {
                                    df.resolve();
                                    if (dbg)
                                        console.log("Db: " + dbname + " synced.");
                                }

                            });
                            return df.promise;
                        });
                    });
                });
                return p;

            }).then(function(){
                syncingState.save(null, true);
                if(dbg) console.log("-------------------.");
            });

            prms.done(function(){}, function(err) {
                if (dbg)
                    console.log(" Reject with: " + err);
                if (err && syncingState) syncingState.save(err);
            });
            return prms;
        }
    };
};

<commit_msg>no magic in first in migrate<commit_after>/**
 * Model migration manager - module for syncing models scheme with database tables.
 * Привет. Я и здесь тебя найду!
 *
 * В общем ситуация следующая.
 * Этот файл должен иметь две версии. Первая версия относится к загрузке в режиме миграции, и загрузке в режими
 * девелепмента и продакшена.
 *
 * В режиме миграции выполняется автоматическая обработка моделей в следующей порядке:
 *  1. Инициализируется приложение (плагин с моделями) как оно обычно происходит
 *  2. После завершении инициализации модуля plugins выполняется метод __init__ где ты выполняешь
 *      следующие операции
 *          а) составление различий между моделями
 *          б) запрос модуля плагинс перегрузить приложение,
 *              с переданными в виде объекта {<имя модели>: {<дескриптор модели>}}
 *          в) собственно сам маджик (я думаю, там даже аргументов передавать не надо, так как
 *              перезагруженный scope приложения и так будет в m.app)
 *          г) доделка синхронизации с базой данных
 *          д) формируется штамп состояния моделей и пользовательского модуля миграции, который помещается в спец файлик,
 *              а луче в базу данных sqlite (на этом я настаиваю, модуль sqlite я включил в deps).
 *              Юзерский модуль миграции, может быть удален.
 *          е) завершение работы (по идее, так как ни сервера, ни консоли нет, это должно произойти автоматом)
 *
 *  В остальных режимах работы приложения должно произойти следующее:
 *  1. Также инициализируется приложение
 *  2. Управление в определенный момент доходит до инициализации данного модуля. В данном случае в __init__
 *      выполняется составление различий между моделями в разных состояния, и делается заготовка в корне для
 *      файла миграций (если такой файл уже существует, этого не происходит)
 *
 *  Это все означает следующее: здесь у тебя появится два файла модуля:
 *      - module.js - этот файл будет для всех
 *      - module.migration.js - этот файл будет автоматически выбираться при запуске в режиме миграций
 *
 *  Это в свою очередь означает, что часть кода, которая лежит здесь должна выйти запределы файла, чтобы быть
 *      доступной во втором файле. Это точно касается функции, отвечающей за сравнение состоянии моделей
 *
 *  Мне честно говоря очень давно подправить стилистику твоего кода. Я думаю на этом файле можно будет сделать
 *      код-ревью, но я хочу, чтобы ты удалила все рудименты, я так понял у тебя есть методы и переменные, которыми
 *      ты пользоваться больше не будешь. Когда сделаешь это, я помогу тебе сделать код проще и разнести
 *      его по модулям
 *
 *  Напоследок. Надо разобраться с логикой запуска утилиты миграции. Придумать как будет указываться версионность
 *  Это необходимо для того, чтобы иметь возможность указать необходимую версию миграции для даунгрейда базы,
 *  либо создания промежуточной миграции. Также необходимо продумать формат вывода состояния миграции, а также
 *  вывода перечня всех выполненных миграций
 *
 *  На этом пока все.
 */

module.exports = function(self, deps) {
    var compareDescriptors = self.require('lib/difference');
    var getAppScheme = self.require('lib/getAppScheme');
    var Q = require('q');
    var _ = require('underscore');
    var g = require('grunt');
    var initCommon = self.require("lib/init");
    var dbg = true;
    // флаг вывода информации в лог
    self.flagStop = false;
    function loadMagic(id) {
        var mjcPath = self.mjcDir + id + ".js";
        var txt = "module.exports = function(){\n" + "return function(models) {\n" + "}\n" + "};\n";
        if (!g.file.exists(mjcPath)) {
            g.file.write(mjcPath, txt);
            if (dbg) {
                console.log("  Magic file created: " + mjcPath);
                console.log("  Complete file and run migration.migrate().");
            }
            return null;
        } else {
            var ret = require(mjcPath);
            if ( typeof ret === "function") {
                if (dbg)
                    console.log("  Magic is ok. File path: " + mjcPath);
                return ret;
            } else {
                if (dbg) {
                    console.log("  Magic is not a function. File path: " + mjcPath);
                    console.log("  Complete file and run migration.migrate().");
                }
                return null;
            }
        }
        return ret;
    };

    return {
        __init__ : function() {
            var prms = initCommon().then(function() {
                return self.MState.lastState();
            }).then(function(last) {
                var magic;
                if (!last.getId())// First migration
                    return Q();
                if (last.err)
                    return Q.reject("Last migration state error: " + last.err);
                if (last.isSynced())
                    magic = loadMagic(last.getId());
                else
                    if(last.magicId) magic = loadMagic(last.magicId);
                return Q();
            });

            prms.done(function(obj) {
                m.emit("migrate-ready");
            }, function(err) {
                // self.flagStop = true;
                console.log('Reject with: ' + err);
                // process.exit();
            });
            return prms;
        },
        migrate : function(migrationId) {
            // if (self.flagStop)
                // Q.reject("Migrate function is denied.");
            var prms = Q();
            var diff;
            var syncingState;
            var schemeTo;
            var magic;
            var prms = Q();
            if (dbg)
                console.log("---Migrate:");
            if ( typeof id === 'number') {
                prms = self.MState.getState(id).then(function(state) {// if no state - reject
                    schemeTo = state.scheme;
                    if (dbg)
                        console.log("  Migrate to state with id = " + id);
                });
            } else {
                if (dbg)
                    console.log("  Migrate to application scheme.");
                schemeTo = getAppScheme();
            }
            prms = prms.then(function() {
                return self.MState.lastState();
            }).then(function(last) {
                if (last.err) {
                    if (dbg)
                        console.log("  Last migration state has an error: " + last.err);
                }
                diff = compareDescriptors(last.scheme, schemeTo);
                m.diff = diff;
                if (!diff.need) {
                    if (dbg)
                        console.log("  Nothing to sync.");
                    if(last.isSynced()) return Q.reject("Nothing to sync.");
                }
                if (_.keys(diff.err).length != 0) {
                    if (dbg) {
                        console.log("  Migration not able. Scheme changes:");
                        for (var db in diff.err) {
                            console.log("    Database - " + db + " :");
                            for (var i in diff.err[db]) {
                                console.log("    " + diff.err[db][i]);
                            }
                        }
                    }
                    Q.reject("Migration not able.");
                }
                if (!last.isSynced() && last.getId()) {
                    if(last.magicId)
                        magic = loadMagic(last.magicId);
                    if (!magic)
                        return Q.reject("Magic file not complete.");
                    if (dbg)
                        console.log("  Continue syncing last migration state.");
                    return Q(last);
                } else {
                    magic = loadMagic(last.getId());
                    if (!magic)
                        return Q.reject("Magic file not complete.");
                    return MState.createState().then(function(stt) {
                        stt.setScheme(last.getScheme());
                        stt.downStateId = last.getId();
                        return Q(stt);
                    });
                }
            }).then(function(stt) {// ddl sync app models; add attributes
                syncingState = stt;
                if (_.keys(diff.addAttr).length == 0 && _.keys(diff.addModel).length == 0)
                    return Q();
                if (dbg)
                    console.log("  ddl sync extended last scheme (adding models and attributes) ... ");
                return syncingState.ddlSync(diff.ddlSyncExt);

            }).then(function() {// new app scope
                return deps.plugins.reloadScope(diff.extScope);

            }).then(function() {// orm sync
                // if(_.keys(diff.addManyA).length == 0 ) return Q();
                if (dbg)
                    console.log("  Orm syncing app databases ... ");
                var p = Q();
                _.each(schemeTo, function(dscr, dbname) {
                    p = p.then(function() {
                        return deps.database.getDatabase(dbname).then(function(db) {
                            var df = Q.defer();
                            db.sync(function(err) {
                                if (err)
                                    df.reject(err);
                                else {
                                    df.resolve();
                                    if (dbg)
                                        console.log("    Db: " + dbname + " synced.");
                                }

                            });
                            return df.promise;
                        });
                    });
                });
                return p;

            }).then(function() {// magic
                if (!syncingState.downStateId)
                    return Q();
                if (dbg)
                    console.log("  Magic ... ");
                if (magic.run)
                    return magic.run();
                else
                    return Q.reject("No magic function");
            }).then(function() {
                if (_.keys(diff.rmAttr).length == 0)
                    return Q();
                if (dbg)
                    console.log("Removing models attributes ... ");
                return syncingState.ddlSync(diff.ddlSyncRm);

            }).then(function() {//TODO when ready reloadScope
                return Q();
                if (_.keys(diff.rmModel).length == 0)
                    return Q();
                if (dbg)
                    console.log("Removing models ... ");
                function one(name) {
                    var df = Q.defer();
                    m.app.models[name].drop(function(err) {
                        if (err) {
                            df.reject(err);
                        } else {
                            if (dbg)
                                console.log("Model " + name + " removed.");
                            df.resolve();
                        }
                    });
                    return df.promise;
                }

                var _p = Q();
                for (var db in diff.rmModel) {
                    var dscr = diff.rmModel[db];
                    _.each(dscr, function(dsc, mdl) {
                        _p = _p.then(function() {
                            return one(mdl);
                        }).then(function() {
                            delete dscr[mdl];
                            return Q();
                        });
                    });
                    _p = _p.then(function() {
                        syncingState.changeDescriptor(db, dscr);
                        return syncingState.save();
                    });
                }
                return _p;
            }).then(function() {
                if (dbg)
                    console.log("---------------------------.");
                return syncingState.save(null, true);
            });

            prms.done(function() {
                m.emit("migrate-run-ready");
                // process.exit();
            }, function(err) {
                if (dbg)
                    console.log("Reject with: " + err);
                if (err && syncingState) syncingState.save(err);
            });
            return prms;
        },
        info : self.require('lib/info'),
        sync : function(id, force) {
            if (dbg)
                console.log("---Sync:");
            if (force && dbg)
                console.log("  !!! Ignore scheme difference !!!");
            var syncingState;
            var currentState;
            var schemeTo;
            var prms = Q();
            if ( typeof id === 'number') {
                prms = self.MState.getState(id).then(function(state) {// if no state - reject
                    schemeTo = state.scheme;
                    if (dbg)
                        console.log("  Migrate to state with id = " + id);
                });
            } else {
                if (dbg)
                    console.log("  Migrate to application scheme.");
                schemeTo = getAppScheme();
            }
            prms = prms.then(function() {
                return self.MState.lastState();
            }).then(function(last) {
                if (last.err) {
                    if (dbg)
                        console.log("  Last migration state has an error: " + last.err);
                }
                var diff = compareDescriptors(last.scheme, schemeTo);
                m.diff = diff;
                if (!diff.need && !force) {
                    if (dbg)
                        console.log("  Nothing to sync.");
                    return Q.reject("Nothing to sync.");
                }
                if (!last.isSynced()) {
                    if (dbg)
                        console.log("  Continue syncing last migration state.");
                    return Q(last);
                } else {
                    return self.MState.createState().then(function(stt) {
                        console.log("2");
                        stt.setScheme(last.getScheme());
                        stt.downStateId = last.getId();
                        return Q(stt);
                    });
                }
            }).then(function(stt) {// ddl sync app models
                syncingState = stt;
                syncingState.forced = true;
                if (dbg)
                    console.log("DDL syncing ... ");
                return syncingState.ddlSync(schemeTo);

            }).then(function() {// orm sync databases (all models at once)
                var p = Q();
                _.each(schemeTo, function(dscr, dbname) {
                    p = p.then(function() {
                        return deps.database.getDatabase(dbname).then(function(db) {
                            var df = Q.defer();
                            db.sync(function(err) {
                                if (err)
                                    df.reject(err);
                                else {
                                    df.resolve();
                                    if (dbg)
                                        console.log("Db: " + dbname + " synced.");
                                }

                            });
                            return df.promise;
                        });
                    });
                });
                return p;

            }).then(function(){
                syncingState.save(null, true);
                if(dbg) console.log("-------------------.");
            });

            prms.done(function(){}, function(err) {
                if (dbg)
                    console.log(" Reject with: " + err);
                if (err && syncingState) syncingState.save(err);
            });
            return prms;
        }
    };
};

<|endoftext|>


<commit_before>// Copyright (c) 2015, Evan Summers (twitter.com/evanxsummers)
// ISC license, see http://github.com/evanx/redexutil/LICENSE

const logger = Loggers.create(__filename, 'info');

export function length(array, defaultValue) {
   if (!array) {
      return defaultValue;
   }
   return array.length;
}

export function reverse(array) {
   return lodash(array).slice(0).reverse().value();
}

export async function mapAsync(array, fn) {
   return await* array.map(async (item) => {
      try {
         let result = await fn();
         logger.debug('mapAsync', result);
         return result;
      } catch (err) {
         logger.debug('mapAsync', err);
         throw err;
      }
   });
}
<commit_msg>arrays push if<commit_after>// Copyright (c) 2015, Evan Summers (twitter.com/evanxsummers)
// ISC license, see http://github.com/evanx/redexutil/LICENSE

const logger = Loggers.create(__filename, 'info');

export function length(array, defaultValue) {
   if (!array) {
      return defaultValue;
   }
   return array.length;
}

export function reverse(array) {
   return lodash(array).slice(0).reverse().value();
}

export function pushIf(array, value, condition) {
   if (condition || value) {
      array.push(value);
   }
}

export async function mapAsync(array, fn) {
   return await* array.map(async (item) => {
      try {
         let result = await fn();
         logger.debug('mapAsync', result);
         return result;
      } catch (err) {
         logger.debug('mapAsync', err);
         throw err;
      }
   });
}
<|endoftext|>