<commit_before>/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, brackets, $, window */

define(function (require, exports, module) {
    "use strict";

    var CodeHintManager     = brackets.getModule("editor/CodeHintManager"),
        CommandManager      = brackets.getModule("command/CommandManager"),
        CSSUtils            = brackets.getModule("language/CSSUtils"),
        CSSProperties       = require("text!CSSProperties.json"),
        Menus               = brackets.getModule("command/Menus"),
        properties          = JSON.parse(CSSProperties);

    var enabledSeparator  = true,
        enabledWhitespace = true;

    /**
     * @constructor
     */
    function CssPropHints() {
        this.primaryTriggerKeys = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-()";
        this.secondaryTriggerKeys           = ":";
        this.secondaryTriggerKeysSeparator  = ";{";
        this.secondaryTriggerKeysWhitespace = " \t\n\r";
    }

    /**
     * Determines whether CSS propertyname or -name hints are available in the current editor
     * context.
     *
     * @param {Editor} editor
     * A non-null editor object for the active window.
     *
     * @param {String} implicitChar
     * Either null, if the hinting request was explicit, or a single character
     * that represents the last insertion and that indicates an implicit
     * hinting request.
     *
     * @return {Boolean}
     * Determines whether the current provider is able to provide hints for
     * the given editor context and, in case implicitChar is non- null,
     * whether it is appropriate to do so.
     */
    CssPropHints.prototype.hasHints = function (editor, implicitChar) {
        this.editor = editor;
        var cursor = this.editor.getCursorPos();

        this.info = CSSUtils.getInfoAtPos(editor, cursor);

        if (implicitChar === null) {
            if (this.info.context === CSSUtils.PROP_NAME || this.info.context === CSSUtils.PROP_VALUE) {
                return true;
            }
        } else {
            return (this.primaryTriggerKeys.indexOf(implicitChar) !== -1) ||
                   (this.secondaryTriggerKeys.indexOf(implicitChar) !== -1) ||
                   (enabledSeparator  && (this.secondaryTriggerKeysSeparator.indexOf(implicitChar)  !== -1)) ||
                   (enabledWhitespace && (this.secondaryTriggerKeysWhitespace.indexOf(implicitChar) !== -1));
        }

        return false;
    };

    /**
     * Returns a list of availble CSS protertyname or -value hints if possible for the current
     * editor context.
     *
     * @param {Editor} implicitChar
     * Either null, if the hinting request was explicit, or a single character
     * that represents the last insertion and that indicates an implicit
     * hinting request.
     *
     * @return {Object<hints: Array<(String + jQuery.Obj)>, match: String,
     *      selectInitial: Boolean>}
     * Null if the provider wishes to end the hinting session. Otherwise, a
     * response object that provides
     * 1. a sorted array hints that consists of strings
     * 2. a string match that is used by the manager to emphasize matching
     *    substrings when rendering the hint list
     * 3. a boolean that indicates whether the first result, if one exists, should be
     *    selected by default in the hint list window.
     */
    CssPropHints.prototype.getHints = function (implicitChar) {
        this.info = CSSUtils.getInfoAtPos(this.editor, this.editor.getCursorPos());

        var needle = this.info.name,
            valueNeedle = "",
            context = this.info.context,
            result,
            selectInitial = false;

        if (this.primaryTriggerKeys.indexOf(implicitChar) !== -1) {
            selectInitial = true;
        }

        if (context === CSSUtils.PROP_VALUE) {
            if (!properties[needle]) {
                return null;
            } else {

                if (this.info.values.length > 0) {
                    valueNeedle = this.info.values[this.info.values.length - 1].trim();
                }

                result = $.map(properties[needle].values, function (pvalue, pindex) {
                    if (pvalue.indexOf(valueNeedle) === 0) {
                        return pvalue;
                    }
                }).sort();

                return {
                    hints: result,
                    match: valueNeedle,
                    selectInitial: selectInitial
                };
            }
        } else if (context === CSSUtils.PROP_NAME) {
            result = $.map(properties, function (pvalues, pname) {
                if (pname.indexOf(needle) === 0) {
                    return pname;
                }
            }).sort();

            return {
                hints: result,
                match: needle,
                selectInitial: selectInitial
            };
        }
        return null;
    };

    /**
     * Inserts a given CSS protertyname or -value hint into the current editor context.
     *
     * @param {String} hint
     * The hint to be inserted into the editor context.
     *
     * @return {Boolean}
     * Indicates whether the manager should follow hint insertion with an
     * additional explicit hint request.
     */
    CssPropHints.prototype.insertHint = function (hint) {
        var offset = this.info.offset,
            cursor = this.editor.getCursorPos(),
            closure = "",
            start = {line: -1, ch: -1},
            end = {line: -1, ch: -1},
            keepHints = true;

        if (this.info.context === CSSUtils.PROP_NAME) {
            closure = ":";
        } else if (this.info.context === CSSUtils.PROP_VALUE) {
            closure = ";";
        } else {
            return false;
        }

        hint = hint + closure;

        start.line = end.line = cursor.line;
        start.ch = cursor.ch - offset;
        end.ch = start.ch + hint.length;

        this.editor.document.replaceRange(hint, start, end);

        return keepHints;
    };

    var cssPropHints = new CssPropHints();
    CodeHintManager.registerHintProvider(cssPropHints, ["css"], 0);

    // For unit testing
    exports.cssPropHintProvider = cssPropHints;

    // TEMPORARY TOGGLE COMMANDS - start
    var POPUP_ON_SEPARATOR      = "CSS Hints: Popup on separator ( ; { )",
        POPUP_ON_WHITESPACE     = "CSS Hints: Popup on whitespace (space, newline, tab)",
        CMD_POPUP_SEPARATOR     = "test.popup-semicolon.debug.menu",
        CMD_POPUP_WHITESPACE    = "test.popup-whitespace.debug.menu";

    function updateSeparatorCheckmark() {
        CommandManager.get(CMD_POPUP_SEPARATOR).setChecked(enabledSeparator);
    }
    function updateWhitespaceCheckmark() {
        CommandManager.get(CMD_POPUP_WHITESPACE).setChecked(enabledWhitespace);
    }
    function toggleEnableSeparator() {
        enabledSeparator = !enabledSeparator;
        updateSeparatorCheckmark();
    }
    function toggleEnableWhitespace() {
        enabledWhitespace = !enabledWhitespace;
        updateWhitespaceCheckmark();
    }

    CommandManager.register(POPUP_ON_SEPARATOR, CMD_POPUP_SEPARATOR, toggleEnableSeparator);
    CommandManager.register(POPUP_ON_WHITESPACE, CMD_POPUP_WHITESPACE, toggleEnableWhitespace);
    var menu = Menus.getMenu(Menus.AppMenuBar.DEBUG_MENU);
    if (menu) {
        menu.addMenuDivider();

        menu.addMenuItem(CMD_POPUP_SEPARATOR);
        updateSeparatorCheckmark();

        menu.addMenuItem(CMD_POPUP_WHITESPACE);
        updateWhitespaceCheckmark();
    }
    // TEMPORARY TOGGLE COMMANDS - end
});<commit_msg>remove toggles<commit_after>/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, brackets, $, window */

define(function (require, exports, module) {
    "use strict";

    var CodeHintManager     = brackets.getModule("editor/CodeHintManager"),
        CSSUtils            = brackets.getModule("language/CSSUtils"),
        CSSProperties       = require("text!CSSProperties.json"),
        properties          = JSON.parse(CSSProperties);

    /**
     * @constructor
     */
    function CssPropHints() {
        this.primaryTriggerKeys = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-()";
        this.secondaryTriggerKeys = ":";
    }

    /**
     * Determines whether CSS propertyname or -name hints are available in the current editor
     * context.
     *
     * @param {Editor} editor
     * A non-null editor object for the active window.
     *
     * @param {String} implicitChar
     * Either null, if the hinting request was explicit, or a single character
     * that represents the last insertion and that indicates an implicit
     * hinting request.
     *
     * @return {Boolean}
     * Determines whether the current provider is able to provide hints for
     * the given editor context and, in case implicitChar is non- null,
     * whether it is appropriate to do so.
     */
    CssPropHints.prototype.hasHints = function (editor, implicitChar) {
        this.editor = editor;
        var cursor = this.editor.getCursorPos();

        this.info = CSSUtils.getInfoAtPos(editor, cursor);

        if (implicitChar === null) {
            if (this.info.context === CSSUtils.PROP_NAME || this.info.context === CSSUtils.PROP_VALUE) {
                return true;
            }
        } else {
            return (this.primaryTriggerKeys.indexOf(implicitChar) !== -1) ||
                   (this.secondaryTriggerKeys.indexOf(implicitChar) !== -1);
        }

        return false;
    };

    /**
     * Returns a list of availble CSS protertyname or -value hints if possible for the current
     * editor context.
     *
     * @param {Editor} implicitChar
     * Either null, if the hinting request was explicit, or a single character
     * that represents the last insertion and that indicates an implicit
     * hinting request.
     *
     * @return {Object<hints: Array<(String + jQuery.Obj)>, match: String,
     *      selectInitial: Boolean>}
     * Null if the provider wishes to end the hinting session. Otherwise, a
     * response object that provides
     * 1. a sorted array hints that consists of strings
     * 2. a string match that is used by the manager to emphasize matching
     *    substrings when rendering the hint list
     * 3. a boolean that indicates whether the first result, if one exists, should be
     *    selected by default in the hint list window.
     */
    CssPropHints.prototype.getHints = function (implicitChar) {
        this.info = CSSUtils.getInfoAtPos(this.editor, this.editor.getCursorPos());

        var needle = this.info.name,
            valueNeedle = "",
            context = this.info.context,
            result,
            selectInitial = false;

        if (this.primaryTriggerKeys.indexOf(implicitChar) !== -1) {
            selectInitial = true;
        }

        if (context === CSSUtils.PROP_VALUE) {
            if (!properties[needle]) {
                return null;
            } else {

                if (this.info.values.length > 0) {
                    valueNeedle = this.info.values[this.info.values.length - 1].trim();
                }

                result = $.map(properties[needle].values, function (pvalue, pindex) {
                    if (pvalue.indexOf(valueNeedle) === 0) {
                        return pvalue;
                    }
                }).sort();

                return {
                    hints: result,
                    match: valueNeedle,
                    selectInitial: selectInitial
                };
            }
        } else if (context === CSSUtils.PROP_NAME) {
            result = $.map(properties, function (pvalues, pname) {
                if (pname.indexOf(needle) === 0) {
                    return pname;
                }
            }).sort();

            return {
                hints: result,
                match: needle,
                selectInitial: selectInitial
            };
        }
        return null;
    };

    /**
     * Inserts a given CSS protertyname or -value hint into the current editor context.
     *
     * @param {String} hint
     * The hint to be inserted into the editor context.
     *
     * @return {Boolean}
     * Indicates whether the manager should follow hint insertion with an
     * additional explicit hint request.
     */
    CssPropHints.prototype.insertHint = function (hint) {
        var offset = this.info.offset,
            cursor = this.editor.getCursorPos(),
            closure = "",
            start = {line: -1, ch: -1},
            end = {line: -1, ch: -1},
            keepHints = true;

        if (this.info.context === CSSUtils.PROP_NAME) {
            closure = ":";
        } else if (this.info.context === CSSUtils.PROP_VALUE) {
            closure = ";";
        } else {
            return false;
        }

        hint = hint + closure;

        start.line = end.line = cursor.line;
        start.ch = cursor.ch - offset;
        end.ch = start.ch + hint.length;

        this.editor.document.replaceRange(hint, start, end);

        return keepHints;
    };

    var cssPropHints = new CssPropHints();
    CodeHintManager.registerHintProvider(cssPropHints, ["css"], 0);

    // For unit testing
    exports.cssPropHintProvider = cssPropHints;
});<|endoftext|>


<commit_before>/**
 * @file
 * Drush wrapper for Aquifer.
 */

/* globals require, Aquifer, AquiferDrushConfig, module */

module.exports = function(Aquifer, AquiferDrushConfig) {

  'use strict';

  var AquiferDrush  = function() {},
      drush         = require('drush-node'),
      Q             = require('q');

  /**
   * Informs Aquifer of what this extension does.
   *
   * @return object
   * Details about this deployment script.
   */
  AquiferDrush.commands = function () {
    return {
      'drush': {
        description: 'Runs drush commnds against the built Aquifer project.',
        allowUnknownOption: true
      }
    };
  };

  /**
   * Run when user runs commands within this extension.
   *
   * @param string command string representing the name of the command defined in AquiferDrush.commands that should run.
   * @param object options options passed from the command.
   * @param function callback function that is called when there is an error message to send.
   */
  AquiferDrush.run = function (command, options, callback) {
    if (command !== 'drush') {
      callback('Invalid command.');
      return;
    }

    var drushCommand  = process.argv.slice(3).join(' ');

    Q.when(drush.init({log: true, cwd: Aquifer.project.config.paths.build}))
      .then(function () {
        Aquifer.console.log('Executing drush command...', 'status');
        return drush.exec(drushCommand);
      })
      .then(function () {
        Aquifer.console.log('Drush command completed successfully.', 'success');
      })
      .catch(function (error) {
        Aquifer.console.log(error.message, 'error');
      });
  };

  return AquiferDrush;
};
<commit_msg>Fix documentation to comply with standards.<commit_after>/**
 * @file
 * Drush wrapper for Aquifer.
 */

/* globals require, Aquifer, AquiferDrushConfig, module */

module.exports = function(Aquifer, AquiferDrushConfig) {

  'use strict';

  var AquiferDrush  = function() {},
      drush         = require('drush-node'),
      Q             = require('q');

  /**
   * Informs Aquifer of what this extension does.
   *
   * @returns {object} Details about this deployment script.
   */
  AquiferDrush.commands = function () {
    return {
      'drush': {
        description: 'Runs drush commnds against the built Aquifer project.',
        allowUnknownOption: true
      }
    };
  };

  /**
   * Run when user runs commands within this extension.
   *
   * @param {string} command - Command string representing the name of the command defined in AquiferDrush.commands that should run.
   * @param {object} options - Options options passed from the command.
   * @param {function} callback - Callback function that is called when there is an error message to send.
   *
   * @returns {undefined} null.
   */
  AquiferDrush.run = function (command, options, callback) {
    if (command !== 'drush') {
      callback('Invalid command.');
      return;
    }

    var drushCommand  = process.argv.slice(3).join(' ');

    Q.when(drush.init({log: true, cwd: Aquifer.project.config.paths.build}))
      .then(function () {
        Aquifer.console.log('Executing drush command...', 'status');
        return drush.exec(drushCommand);
      })
      .then(function () {
        Aquifer.console.log('Drush command completed successfully.', 'success');
      })
      .catch(function (error) {
        Aquifer.console.log(error.message, 'error');
      });
  };

  return AquiferDrush;
};
<|endoftext|>


<commit_before>define(['Promise', '../LegacyExplorer', '../RangeSpec'], function(Promise, LegacyExplorer, RangeSpec) {

	'use strict';

	var CHP_DEFAULT = new Uint8Array([1, 0, 24, 0, 0, 0]);

	var PAP_DEFAULT = new Uint8Array(79);
	PAP_DEFAULT.set([61, 0, 30]);
	new DataView(PAP_DEFAULT.buffer, PAP_DEFAULT.byteOffset, PAP_DEFAULT.byteLength).setUint16(10, 240, true);

	function WRIExpedition(explorer, byteSource) {
		this.explorer = explorer;
		this.byteSource = byteSource;
		this.article = document.createElement('ARTICLE');
	}
	WRIExpedition.prototype = {
		open: function() {
			var self = this;
			return this.byteSource.getBytes(0, 14)
				.then(function(bytes) {
					var dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
					switch(dv.getUint16(0, true)) {
						case 0xBE31: self.containsOLE = false; break;
						case 0xBE32: self.containsOLE = true; break;
						default: return Promise.reject('Not a Microsoft Write file');
					}
					if (dv.getUint16(2, true) !== 0
							|| dv.getUint16(4, true) !== 0xab00
							|| dv.getUint16(6, true) !== 0
							|| dv.getUint16(8, true) !== 0
							|| dv.getUint16(10, true) !== 0
							|| dv.getUint16(12, true) !== 0) {
						return Promise.reject('Not a Microsoft Write file');
					}
					return Promise.all([self.byteSource.getBytes(14, 16), self.byteSource.getBytes(96, 2)]);
				})
				.then(function(values) {
					var bytes = values[0], bytes2 = values[1];

					self.endOfData = 128 * new DataView(bytes2.buffer, 0, 2).getUint16(0, true);

					if (self.endOfData === 0) {
						return Promise.reject('Word files are not supported');
					}

					var dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);

					self.textOffset = 128;
					self.textByteLength = dv.getUint32(0, true);

					self.charInfoOffset = 128 * Math.ceil(1 + self.textByteLength / 128);
					self.paragraphInfoOffset = 128 * dv.getUint16(4, true);
					self.footnoteTableOffset = 128 * dv.getUint16(6, true);
					self.sectionPropertyOffset = 128 * dv.getUint16(8, true);
					self.sectionTableOffset = 128 * dv.getUint16(10, true);
					self.pageTableOffset = 128 * dv.getUint16(12, true);
					self.fontFaceNameTableOffset = 128 * dv.getUint16(14, true);

					self.charInfoByteLength = self.paragraphInfoOffset - self.charInfoOffset;
					self.paragraphInfoByteLength = self.footnoteTableOffset - self.paragraphInfoOffset;
					self.footnoteTableByteLength = self.sectionPropertyOffset - self.footnoteTableOffset;
					self.sectionPropertyByteLength = self.sectionTableOffset - self.sectionPropertyByteLength;
					self.sectionTableByteLength = self.pageTableOffset - self.sectionTableOffset;
					self.pageTableByteLength = self.fontFaceNameTableOffset - self.pageTableOffset;
					self.fontFaceNameTableByteLength = self.endOfData - self.fontFaceNameTableOffset;

					function getInfo(bytes, defaultInfo) {
						var results = new RangeSpec.Set();
						for (var i_page = 0, max_page = bytes.length / 128; i_page < max_page; i_page++) {
							var dv = new DataView(bytes.buffer, bytes.byteOffset + i_page * 128, 128);
							var pos = dv.getUint32(0, true) - 128;
							for (var fod_i = 0, fodCount = bytes[i_page * 128 + 127]; fod_i < fodCount; fod_i++) {
								var afterPos = dv.getUint32(4 + fod_i * 6, true) - 128;
								var fpropOffset = dv.getInt16(4 + fod_i * 6 + 4, true);
								var fprop;
								if (fpropOffset === -1) {
									fprop = defaultInfo;
								}
								else {
									fprop = new Uint8Array(defaultInfo);
									fpropOffset += i_page * 128 + 4;
									fprop.set(bytes.subarray(fpropOffset + 1, fpropOffset + 1 + bytes[fpropOffset]));
								}
								var range = new RangeSpec(pos, afterPos - pos);
								range.userdata = fprop;
								results.put(range);
								pos = afterPos;
							}
						}
						return results;
					}

					return Promise.all([
						self.byteSource.getBytes(self.textOffset, self.textByteLength),
						self.byteSource.getBytes(self.charInfoOffset, self.charInfoByteLength)
							.then(function(charInfoBytes) {
								return getInfo(charInfoBytes, CHP_DEFAULT);
							}),
						self.byteSource.getBytes(self.paragraphInfoOffset, self.paragraphInfoByteLength)
							.then(function(paragraphInfoBytes) {
								return getInfo(paragraphInfoBytes, PAP_DEFAULT);
							})
					]);
				})
				.then(function(values) {
					var textData = values[0], charInfo = values[1], paragraphInfo = values[2];
					charInfo.ranges = charInfo.ranges.filter(function(a) { return a.userdata !== CHP_DEFAULT; });
					charInfo.ranges.forEach(function(a) {
						var info = a.userdata;
						a.userdata = {};
						var styleSet = [];
						if ((info[1] & 1) !== 0) {
							styleSet.push('font-weight: bold');
						}
						if ((info[1] & 2) !== 0) {
							styleSet.push('font-style: italic');
						}
						if (info[2] !== 24) {
							styleSet.push('font-size: ' + Math.floor((info[2] * 100) / 24) + '%');
						}
						var fontCode = (info[1] >> 2) | ((info[4] & 3) << 6);
						if (info[3] & 1) {
							styleSet.push('text-decoration: underline');
						}
						a.userdata.style = styleSet.join('; ');
					});
					paragraphInfo.ranges.forEach(function(para) {
						if ((para.userdata[16] & 16) !== 0) {
							// TODO: handle images
						}
						else {
							var d = document.createElement('DIV');
							var styles = charInfo.slice(para.offset, para.offset + para.length);
							if (styles.ranges.length >= 1 && (styles.ranges.length === 1
									|| styles.ranges[0].offset !== para.offset
									|| styles.ranges[0].length !== para.length)) {
								var pos = para.offset;
								for (var i = 0; i < styles.ranges.length; i++) {
									var range = styles.ranges[i];
									if (range.offset > pos) {
										var preData = textData.subarray(pos, range.offset);
										var preText = String.fromCharCode.apply(null, preData);
										d.appendChild(document.createTextNode(preText));
									}
									var span = document.createElement('SPAN');
									span.style.cssText = range.userdata.style;
									var inData = textData.subarray(range.offset, range.offset + range.length);
									var inText = String.fromCharCode.apply(null, inData);
									span.appendChild(document.createTextNode(inText));
									d.appendChild(span);
									pos = range.offset + range.length;
								}
								if (pos < (para.offset + para.length)) {
									var postData = textData.subarray(pos, para.offset + para.length);
									var postText = String.fromCharCode.apply(null, postData);
									d.appendChild(document.createTextNode(postText));
								}
							}
							else {
								if (styles.ranges.length === 1) {
									d.style.cssText = styles.ranges[0].userdata.style;
								}
								var paraData = textData.subarray(para.offset, para.offset + para.length);
								var paraText = String.fromCharCode.apply(null, paraData);
								d.appendChild(document.createTextNode(paraText));
							}
							switch(para.userdata[1] & 3) {
								case 1: d.style.textAlign = 'center'; break;
								case 2: d.style.textAlign = 'right'; break;
								case 3: d.style.textAlign = 'justify'; break;
							}
							d.innerHTML = d.innerHTML.replace(/\n/g, '
');
							self.article.appendChild(d);
						}
					});
				})
				.then(function() {
					return self.article;
				});
		},
	};

	LegacyExplorer.registerExpedition(WRIExpedition);

	return WRIExpedition;

});<commit_msg>Use superscript and subscript<commit_after>define(['Promise', '../LegacyExplorer', '../RangeSpec'], function(Promise, LegacyExplorer, RangeSpec) {

	'use strict';

	var CHP_DEFAULT = new Uint8Array([1, 0, 24, 0, 0, 0]);

	var PAP_DEFAULT = new Uint8Array(79);
	PAP_DEFAULT.set([61, 0, 30]);
	new DataView(PAP_DEFAULT.buffer, PAP_DEFAULT.byteOffset, PAP_DEFAULT.byteLength).setUint16(10, 240, true);

	function WRIExpedition(explorer, byteSource) {
		this.explorer = explorer;
		this.byteSource = byteSource;
		this.article = document.createElement('ARTICLE');
	}
	WRIExpedition.prototype = {
		open: function() {
			var self = this;
			return this.byteSource.getBytes(0, 14)
				.then(function(bytes) {
					var dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
					switch(dv.getUint16(0, true)) {
						case 0xBE31: self.containsOLE = false; break;
						case 0xBE32: self.containsOLE = true; break;
						default: return Promise.reject('Not a Microsoft Write file');
					}
					if (dv.getUint16(2, true) !== 0
							|| dv.getUint16(4, true) !== 0xab00
							|| dv.getUint16(6, true) !== 0
							|| dv.getUint16(8, true) !== 0
							|| dv.getUint16(10, true) !== 0
							|| dv.getUint16(12, true) !== 0) {
						return Promise.reject('Not a Microsoft Write file');
					}
					return Promise.all([self.byteSource.getBytes(14, 16), self.byteSource.getBytes(96, 2)]);
				})
				.then(function(values) {
					var bytes = values[0], bytes2 = values[1];

					self.endOfData = 128 * new DataView(bytes2.buffer, 0, 2).getUint16(0, true);

					if (self.endOfData === 0) {
						return Promise.reject('Word files are not supported');
					}

					var dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);

					self.textOffset = 128;
					self.textByteLength = dv.getUint32(0, true);

					self.charInfoOffset = 128 * Math.ceil(1 + self.textByteLength / 128);
					self.paragraphInfoOffset = 128 * dv.getUint16(4, true);
					self.footnoteTableOffset = 128 * dv.getUint16(6, true);
					self.sectionPropertyOffset = 128 * dv.getUint16(8, true);
					self.sectionTableOffset = 128 * dv.getUint16(10, true);
					self.pageTableOffset = 128 * dv.getUint16(12, true);
					self.fontFaceNameTableOffset = 128 * dv.getUint16(14, true);

					self.charInfoByteLength = self.paragraphInfoOffset - self.charInfoOffset;
					self.paragraphInfoByteLength = self.footnoteTableOffset - self.paragraphInfoOffset;
					self.footnoteTableByteLength = self.sectionPropertyOffset - self.footnoteTableOffset;
					self.sectionPropertyByteLength = self.sectionTableOffset - self.sectionPropertyByteLength;
					self.sectionTableByteLength = self.pageTableOffset - self.sectionTableOffset;
					self.pageTableByteLength = self.fontFaceNameTableOffset - self.pageTableOffset;
					self.fontFaceNameTableByteLength = self.endOfData - self.fontFaceNameTableOffset;

					function getInfo(bytes, defaultInfo) {
						var results = new RangeSpec.Set();
						for (var i_page = 0, max_page = bytes.length / 128; i_page < max_page; i_page++) {
							var dv = new DataView(bytes.buffer, bytes.byteOffset + i_page * 128, 128);
							var pos = dv.getUint32(0, true) - 128;
							for (var fod_i = 0, fodCount = bytes[i_page * 128 + 127]; fod_i < fodCount; fod_i++) {
								var afterPos = dv.getUint32(4 + fod_i * 6, true) - 128;
								var fpropOffset = dv.getInt16(4 + fod_i * 6 + 4, true);
								var fprop;
								if (fpropOffset === -1) {
									fprop = defaultInfo;
								}
								else {
									fprop = new Uint8Array(defaultInfo);
									fpropOffset += i_page * 128 + 4;
									fprop.set(bytes.subarray(fpropOffset + 1, fpropOffset + 1 + bytes[fpropOffset]));
								}
								var range = new RangeSpec(pos, afterPos - pos);
								range.userdata = fprop;
								results.put(range);
								pos = afterPos;
							}
						}
						return results;
					}

					return Promise.all([
						self.byteSource.getBytes(self.textOffset, self.textByteLength),
						self.byteSource.getBytes(self.charInfoOffset, self.charInfoByteLength)
							.then(function(charInfoBytes) {
								return getInfo(charInfoBytes, CHP_DEFAULT);
							}),
						self.byteSource.getBytes(self.paragraphInfoOffset, self.paragraphInfoByteLength)
							.then(function(paragraphInfoBytes) {
								return getInfo(paragraphInfoBytes, PAP_DEFAULT);
							})
					]);
				})
				.then(function(values) {
					var textData = values[0], charInfo = values[1], paragraphInfo = values[2];
					charInfo.ranges = charInfo.ranges.filter(function(a) { return a.userdata !== CHP_DEFAULT; });
					charInfo.ranges.forEach(function(a) {
						var info = a.userdata;
						a.userdata = {};
						var styleSet = [];
						if ((info[1] & 1) !== 0) {
							styleSet.push('font-weight: bold');
						}
						if ((info[1] & 2) !== 0) {
							styleSet.push('font-style: italic');
						}
						if (info[2] !== 24) {
							styleSet.push('font-size: ' + Math.floor((info[2] * 100) / 24) + '%');
						}
						var fontCode = (info[1] >> 2) | ((info[4] & 3) << 6);
						if (info[3] & 1) {
							styleSet.push('text-decoration: underline');
						}
						a.userdata.style = styleSet.join('; ');
						if (info[5] >= 128) {
							a.userdata.tags = ['SUB'];
						}
						else if (info[5] > 0) {
							a.userdata.tags = ['SUP'];
						}
					});
					paragraphInfo.ranges.forEach(function(para) {
						if ((para.userdata[16] & 16) !== 0) {
							// TODO: handle images
						}
						else {
							var d = document.createElement('DIV');
							var styles = charInfo.slice(para.offset, para.offset + para.length);
							if (styles.ranges.length >= 1 && (styles.ranges.length > 1
									|| styles.ranges[0].offset !== para.offset
									|| styles.ranges[0].length !== para.length
									|| styles.ranges[0].tags)) {
								var pos = para.offset;
								for (var i = 0; i < styles.ranges.length; i++) {
									var range = styles.ranges[i];
									if (range.offset > pos) {
										var preData = textData.subarray(pos, range.offset);
										var preText = String.fromCharCode.apply(null, preData);
										d.appendChild(document.createTextNode(preText));
									}
									var span = document.createElement('SPAN');
									span.style.cssText = range.userdata.style;
									var inData = textData.subarray(range.offset, range.offset + range.length);
									var inText = String.fromCharCode.apply(null, inData);
									span.appendChild(document.createTextNode(inText));
									if (range.userdata.tags) {
										for (var j = range.userdata.tags.length-1; j >= 0; j--) {
											var enclosed = document.createElement(range.userdata.tags[j]);
											enclosed.appendChild(span);
											span = enclosed;
										}
									}
									d.appendChild(span);
									pos = range.offset + range.length;
								}
								if (pos < (para.offset + para.length)) {
									var postData = textData.subarray(pos, para.offset + para.length);
									var postText = String.fromCharCode.apply(null, postData);
									d.appendChild(document.createTextNode(postText));
								}
							}
							else {
								if (styles.ranges.length === 1) {
									d.style.cssText = styles.ranges[0].userdata.style;
								}
								var paraData = textData.subarray(para.offset, para.offset + para.length);
								var paraText = String.fromCharCode.apply(null, paraData);
								d.appendChild(document.createTextNode(paraText));
							}
							switch(para.userdata[1] & 3) {
								case 1: d.style.textAlign = 'center'; break;
								case 2: d.style.textAlign = 'right'; break;
								case 3: d.style.textAlign = 'justify'; break;
							}
							d.innerHTML = d.innerHTML.replace(/\n/g, '
');
							self.article.appendChild(d);
						}
					});
				})
				.then(function() {
					return self.article;
				});
		},
	};

	LegacyExplorer.registerExpedition(WRIExpedition);

	return WRIExpedition;

});<|endoftext|>


<commit_before>const assert = require('assert')
const validate = require('validate.js')
const occupy = require('../services/occupy-pane')
const chooseLocation = require('../services/choose-location')
const mLoc = require('../services/max-location')

function maxOrSkipLocation (state, d) {
  // TODO: move this logic outside this module, grid should not bemakig this decision
  try {
    const { x, y } = mLoc(state, d)
    const skippedLocation = movedInDirection(d, x, y, state)
      ? false
      : chooseLocation(state.grid, state, d)
    if (skippedLocation) return skippedLocation
    if (d === 'up' || d === 'down') return {y, x: state.x}
    if (d === 'left' || d === 'right') return {x, y: state.y}
  } catch (e) {
    throw new Error('location blocked')
  }
}

function movedInDirection (d, x, y, state) {
  if ((d === 'up' || d === 'down') && (state.y === y)) return false
  if ((d === 'left' || d === 'right') && (state.x === x)) return false
  return true
}

function findAxis (state, x, y) {
  if (state.x === x) return 'vertical'
  if (state.y === y) return 'horizontal'
}

function findDirection (state, x, y) {
  const axis = findAxis(state, x, y)
  if (axis === 'vertical') {
    if (y > state.y) return 'down'
    if (y < state.y) return 'up'
  } else if (axis === 'horizontal') {
    if (x > state.x) return 'right'
    if (x < state.x) return 'left'
  }
}

function findBlockingPanes (state, x, y) {
  try {
    occupy(
      state.grid,
      Object.assign({}, state, {x, y}),
      true // TODO: remove this
    )
  } catch (e) {
    if (e.message === 'space is occupied') {
      return e.coords
    } else if (e.message === 'size exceeds grid') {
      return [state]
    } else {
      return []
    }
  }
  return []
}

function pushOrShrinkPane (state, pane, x, y, origLocations) {
  const direction = findDirection(state, x, y)
  const amount = direction === 'right' ? {x: x - state.x, y: 0}
    : direction === 'left' ? {x: x - state.x, y: 0}
    : direction === 'up' ? {y: y - state.y, x: 0}
    : direction === 'down' ? {y: y - state.y, x: 0}
    : {x: 0, y: 0}
  // RECORD ORIG LOCATION
  if (origLocations.filter(o => o.id === pane.id).length > 0) {
    if (pane.x > state.x + amount.x || pane.y > state.y + amount.y) return true
    const err = new Error('will not move pane twice')
    err.origLocations = origLocations
    throw err
  }
  origLocations.push({id: pane.id, x: pane.x, y: pane.y, width: pane.width, height: pane.height})
  const paneState = state.grid.getPane(pane.id)
  // MAX SELF DIRECTION TO PUSHER
  const oppositeDirection = direction === 'left' ? 'right'
    : direction === 'right' ? 'left'
    : direction === 'up' ? 'down'
    : direction === 'down' ? 'up' : ''
  paneState.maxSize({[oppositeDirection]: true})
  const newLocationForPane = {x: pane.x + amount.x, y: pane.y + amount.y}
  try {
    // ATTEMPT TO PUSH PANE
    paneState.changeLocation(newLocationForPane.x, newLocationForPane.y)
    return true
  } catch (e) {
    try {
      // MAX LOCATION TO NEXT PANE
      paneState.maxLoc({[direction]: true}, true)
      // ATTEMPT TO MOVE ADJACENT PANES OUT OF THE WAY
      const [ nextX, nextY ] = direction === 'left' ? [ x - pane.width, pane.y ]
        : direction === 'right' ? [ state.width + x, pane.y ]
        : direction === 'up' ? [ pane.x, y - pane.height ]
        : direction === 'down' ? [ pane.x, state.height + y ] : [ x, y ]
      const movedOthers = movePanesOutOfTheWay(paneState, nextX, nextY, origLocations)
      state.grid.getPane(pane.id).changeLocation(newLocationForPane.x, newLocationForPane.y)
      return movedOthers
    } catch (e) {
      try {
        // ATTEMPT TO SHRINK PANE
        state.grid.getPane(pane.id).decreaseSizeDirectional(
          direction,
          direction === 'left' || direction === 'right' ? Math.abs(amount.x) : Math.abs(amount.y)
        )
        return true
      } catch (e) {
        e.origLocations = origLocations
        throw e
      }
    }
  }
}

function movePanesOutOfTheWay (state, x, y, origLocations = []) {
  const adjacentPanes = findBlockingPanes(state, x, y)
  const clearedPanesSuccessfully = adjacentPanes.every(pane => pushOrShrinkPane(state, pane, x, y, origLocations))
  return clearedPanesSuccessfully
}

module.exports = function locationChanger (state, implementation) {
  return ({
    changeLocation: function changeLocation (x, y) {
      assert(validate.isInteger(x), `${x} is not numeric`)
      assert(validate.isInteger(y), `${y} is not numeric`)
      assert(state.grid.width >= state.width + x, 'location is outside of grid')
      assert(state.grid.height >= state.height + y, 'location is outside of grid')
      assert(x >= 0, 'location is outside of grid')
      assert(y >= 0, 'location is outside of grid')
      const blockingPanes = findBlockingPanes(state, x, y)
      if (blockingPanes.length === 0) {
        state.x = x
        state.y = y
        if (implementation && typeof implementation.changeSize === 'function') {
          implementation.changeLocation(state, x, y)
        }
      } else {
        const direction = findDirection(state, x, y)
        const axis = findAxis(state, x, y)
        // TODO: remove maxedLoc and let the API user decide whether this should be done or not
        const maxedLoc = mLoc(state, direction)
        const finalX = axis === 'horizontal' ? maxedLoc.x : state.x
        const finalY = axis === 'vertical' ? maxedLoc.y : state.y
        if (finalX === state.x && finalY === state.y) throw new Error('location blocked by one or more other panes')
        state.x = finalX
        state.y = finalY
        if (implementation && typeof implementation.changeSize === 'function') {
          implementation.changeLocation(state, finalX, finalY)
        }
      }
    },
    squashIntoLocation: function squashIntoLocation (x, y) {
      assert(validate.isInteger(x), `${x} is not numeric`)
      assert(validate.isInteger(y), `${y} is not numeric`)
      assert(state.grid.width >= state.width + x, 'location is outside of grid')
      assert(state.grid.height >= state.height + y, 'location is outside of grid')
      assert(x >= 0, 'location is outside of grid')
      assert(y >= 0, 'location is outside of grid')
      const origLocation = {
        id: state.id,
        x: state.x,
        y: state.y,
        width: state.width,
        height: state.height
      }
      try {
        const direction = findDirection(state, x, y)
        state.maxLoc({[direction]: true}, true)
        if (movePanesOutOfTheWay(state, x, y)) {
          state.changeLocation(x, y)
        }
      } catch (e) {
        const origLocations = e.origLocations ? e.origLocations.concat(origLocation) : []
        origLocations.forEach(o => {
          const pane = state.grid.getPane(o.id)
          pane.changeLocation(o.x, o.y)
          pane.changeSize(o.width, o.height)
        })
        throw new Error('location is blocked by one or more panes')
      }
    },
    maxLoc: function maxLoc (directions, noSkip) {
      // TODO: noSkip should be the only option
      assert(validate.isObject(directions), `${directions} shold be an object`)
      const changed = Object.keys(directions)
        .filter(d => d)
        .filter(d => {
          assert(
            d === 'up' || d === 'down' || d === 'left' || d === 'right',
            `${d} should be one of 'up/down/left/right'`
          )
          if (noSkip) {
            const chosenLocation = mLoc(state, d)
            if (d === 'up' || d === 'down') {
              state.y = chosenLocation.y
            } else {
              state.x = chosenLocation.x
            }
          } else {
            const chosenLocation = maxOrSkipLocation(state, d)
            state.x = chosenLocation.x
            state.y = chosenLocation.y
          }
        })
      if (changed && implementation && typeof implementation.changeBounds === 'function') {
        implementation.changeBounds(state)
      }
    }
  })
}
<commit_msg>refactor: move state out of recursive move panes action<commit_after>const assert = require('assert')
const validate = require('validate.js')
const occupy = require('../services/occupy-pane')
const chooseLocation = require('../services/choose-location')
const mLoc = require('../services/max-location')

function maxOrSkipLocation (state, d) {
  // TODO: move this logic outside this module, grid should not bemakig this decision
  try {
    const { x, y } = mLoc(state, d)
    const skippedLocation = movedInDirection(d, x, y, state)
      ? false
      : chooseLocation(state.grid, state, d)
    if (skippedLocation) return skippedLocation
    if (d === 'up' || d === 'down') return {y, x: state.x}
    if (d === 'left' || d === 'right') return {x, y: state.y}
  } catch (e) {
    throw new Error('location blocked')
  }
}

function movedInDirection (d, x, y, state) {
  if ((d === 'up' || d === 'down') && (state.y === y)) return false
  if ((d === 'left' || d === 'right') && (state.x === x)) return false
  return true
}

function findAxis (state, x, y) {
  if (state.x === x) return 'vertical'
  if (state.y === y) return 'horizontal'
}

function findDirection (state, x, y) {
  const axis = findAxis(state, x, y)
  if (axis === 'vertical') {
    if (y > state.y) return 'down'
    if (y < state.y) return 'up'
  } else if (axis === 'horizontal') {
    if (x > state.x) return 'right'
    if (x < state.x) return 'left'
  }
}

function findBlockingPanes (state, x, y) {
  try {
    occupy(
      state.grid,
      Object.assign({}, state, {x, y}),
      true // TODO: remove this
    )
  } catch (e) {
    if (e.message === 'space is occupied') {
      return e.coords
    } else if (e.message === 'size exceeds grid') {
      return [state]
    } else {
      return []
    }
  }
  return []
}

function pushOrShrinkPane (pane, direction, amount, origLocations) {
  // RECORD ORIG LOCATION
  if (origLocations.filter(o => o.id === pane.id).length > 0) {
    const err = new Error('will not move pane twice')
    err.origLocations = origLocations
    throw err
  }
  origLocations.push({id: pane.id, x: pane.x, y: pane.y, width: pane.width, height: pane.height})
  // MAX SELF DIRECTION TO PUSHER
  const oppositeDirection = direction === 'left' ? 'right'
    : direction === 'right' ? 'left'
    : direction === 'up' ? 'down'
    : direction === 'down' ? 'up' : ''
  pane.maxSize({[oppositeDirection]: true})
  const newLocationForPane = {x: pane.x + amount.x, y: pane.y + amount.y}
  try {
    // ATTEMPT TO PUSH PANE
    pane.changeLocation(newLocationForPane.x, newLocationForPane.y)
    return true
  } catch (e) {
    try {
      // MAX LOCATION TO NEXT PANE
      pane.maxLoc({[direction]: true}, true)
      // ATTEMPT TO MOVE ADJACENT PANES OUT OF THE WAY
      const movedOthers = movePanesOutOfTheWay(pane, direction, amount, origLocations)
      pane.changeLocation(newLocationForPane.x, newLocationForPane.y)
      return movedOthers
    } catch (e) {
      try {
        // ATTEMPT TO SHRINK PANE
        pane.decreaseSizeDirectional(
          direction,
          direction === 'left' || direction === 'right' ? Math.abs(amount.x) : Math.abs(amount.y)
        )
        return true
      } catch (e) {
        e.origLocations = origLocations
        throw e
      }
    }
  }
}

function movePanesOutOfTheWay (pane, direction, amount, origLocations = []) {
  const {x, y} = {x: pane.x + amount.x, y: pane.y + amount.y}
  const adjacentPanes = findBlockingPanes(pane, x, y).map(p => pane.grid.getPane(p.id))
  const clearedPanesSuccessfully = adjacentPanes.every(pane => pushOrShrinkPane(pane, direction, amount, origLocations))
  return clearedPanesSuccessfully
}

module.exports = function locationChanger (state, implementation) {
  return ({
    changeLocation: function changeLocation (x, y) {
      assert(validate.isInteger(x), `${x} is not numeric`)
      assert(validate.isInteger(y), `${y} is not numeric`)
      assert(state.grid.width >= state.width + x, 'location is outside of grid')
      assert(state.grid.height >= state.height + y, 'location is outside of grid')
      assert(x >= 0, 'location is outside of grid')
      assert(y >= 0, 'location is outside of grid')
      const blockingPanes = findBlockingPanes(state, x, y)
      if (blockingPanes.length === 0) {
        state.x = x
        state.y = y
        if (implementation && typeof implementation.changeSize === 'function') {
          implementation.changeLocation(state, x, y)
        }
      } else {
        const direction = findDirection(state, x, y)
        const axis = findAxis(state, x, y)
        // TODO: remove maxedLoc and let the API user decide whether this should be done or not
        const maxedLoc = mLoc(state, direction)
        const finalX = axis === 'horizontal' ? maxedLoc.x : state.x
        const finalY = axis === 'vertical' ? maxedLoc.y : state.y
        if (finalX === state.x && finalY === state.y) throw new Error('location blocked by one or more other panes')
        state.x = finalX
        state.y = finalY
        if (implementation && typeof implementation.changeSize === 'function') {
          implementation.changeLocation(state, finalX, finalY)
        }
      }
    },
    squashIntoLocation: function squashIntoLocation (x, y) {
      assert(validate.isInteger(x), `${x} is not numeric`)
      assert(validate.isInteger(y), `${y} is not numeric`)
      assert(state.grid.width >= state.width + x, 'location is outside of grid')
      assert(state.grid.height >= state.height + y, 'location is outside of grid')
      assert(x >= 0, 'location is outside of grid')
      assert(y >= 0, 'location is outside of grid')
      const origLocation = {
        id: state.id,
        x: state.x,
        y: state.y,
        width: state.width,
        height: state.height
      }
      try {
        const direction = findDirection(state, x, y)
        // TODO: get direction from outside
        const amount = direction === 'right' ? {x: x - state.x, y: 0}
          : direction === 'left' ? {x: x - state.x, y: 0}
          : direction === 'up' ? {y: y - state.y, x: 0}
          : direction === 'down' ? {y: y - state.y, x: 0}
          : {x: 0, y: 0}
        state.maxLoc({[direction]: true}, true)
        if (movePanesOutOfTheWay(state, direction, amount)) {
          state.changeLocation(x, y)
        }
      } catch (e) {
        const origLocations = e.origLocations ? e.origLocations.concat(origLocation) : []
        origLocations.forEach(o => {
          const pane = state.grid.getPane(o.id)
          pane.changeLocation(o.x, o.y)
          pane.changeSize(o.width, o.height)
        })
        throw new Error('location is blocked by one or more panes')
      }
    },
    maxLoc: function maxLoc (directions, noSkip) {
      // TODO: noSkip should be the only option
      assert(validate.isObject(directions), `${directions} shold be an object`)
      const changed = Object.keys(directions)
        .filter(d => d)
        .filter(d => {
          assert(
            d === 'up' || d === 'down' || d === 'left' || d === 'right',
            `${d} should be one of 'up/down/left/right'`
          )
          if (noSkip) {
            const chosenLocation = mLoc(state, d)
            if (d === 'up' || d === 'down') {
              state.y = chosenLocation.y
            } else {
              state.x = chosenLocation.x
            }
          } else {
            const chosenLocation = maxOrSkipLocation(state, d)
            state.x = chosenLocation.x
            state.y = chosenLocation.y
          }
        })
      if (changed && implementation && typeof implementation.changeBounds === 'function') {
        implementation.changeBounds(state)
      }
    }
  })
}
<|endoftext|>


<commit_before>ko.bindingProvider.instance = new StringInterpolatingBindingProvider();

var availableRoles = [
  {value: 'ingest', text: 'ingest'},
  {value: 'mixer', text: 'mixer'},
  {value: 'record', text: 'record'},
  {value: 'stream', text: 'stream'}
];

//-- yuck
var roleDisplay = function(value, sourceData) {
  var checked = $.fn.editableutils.itemsByValue(value, sourceData);

  if(checked.length) {
    var selectedRoles = "";

    checked.forEach(function(value) {
      selectedRoles +=
        "
" +
          $.fn.editableutils.escape(value.text) +
        "
";
    });
    $(this).html('
' + selectedRoles + '
');
  } else {
    $(this).empty();
  }
};

var vm = {
  stations: ko.mapping.fromJS([]),
};

var availableDevices = function(station) {
  if (station.devices) {

    var allDevices = station.devices();

    if (station.settings.devices && station.settings.devices().length) {
      var configuredDevices = station.settings.devices() || [];
      configuredDevices = configuredDevices.map(function(item) {
        return item.id();
      });

      var availableDevices = allDevices.filter(function(item) {
        var deviceId = Object.keys(item)[0];
        if (configuredDevices.indexOf(deviceId) == -1) {
          return item[deviceId];
        }
      });
      return availableDevices;
    }
    return allDevices.map(function(item) {
      return item[Object.keys(item)[0]];
    });
  }
  return [];
};

var activeStatus = function(station) {

  var list = [];
  if (station.status) {
    for (var i in station.status) {
      list.push(station.status[i]);
    }
  }
  return list;
  /*
  if (station.status) {
    for( var i in station.status ) {
      station.status[i].name = i;

        // this is a hack, fix the manager so that running is populated properly
        // done enough yak shaving for one conference...
        if (typeof station.status[i].running == 'undefined') {
          station.status[i].running = '0';
        }
        if (typeof station.status[i].type == 'undefined') {
          station.status[i].type = 'internal';
        }
        // end nasty hack

      statusArray.push(station.status[i]);
    }
  }
  return statusArray;
  */
};

vm.roomDuplicates = ko.computed(function() {
  return vm.stations().map(function(item) {
    return (item.settings.room ? item.settings.room() : '');
  });
});

vm.rooms = ko.computed(function() {
  var onlyUnique = function (value, index, self) {
    return self.indexOf(value) === index;
  };
  return vm.roomDuplicates().filter(onlyUnique);
});

ko.applyBindings(vm);

var socket = io.connect('//');
var mapping = {};

$.get( "/api/station", function( data ) {
})
  .done(function(data) {
    ko.mapping.fromJS(data, mapping, vm.stations);
    socket.on('change', function (data) {
      console.log(data);
      if (data.type == 'remove') {
        vm.stations.mappedRemove({id: data.content._id});
      }
      if (data.type == 'insert') {
        vm.stations.push(ko.mapping.fromJS(data.content, mapping));
      }
      if (data.type == 'update') {
        var match = ko.utils.arrayFirst(vm.stations(), function (item) {
            return item._id() == data.content._id;
        });
        if (match) {
          ko.mapping.fromJS(data.content, mapping, match);
        }
        if (!data.content.settings.devices && match.settings.devices) {
          match.settings.devices([]);
        }

      }
      if (data.type == 'notify') {
      }

    });
  });

var removeDevice = function (configuredDevices, macaddress, id) {
  var update = ko.toJS(configuredDevices).filter(function(device) {
    return device.id !== id;
  });

  $.ajax({
    url: "/api/station/"+ macaddress + '/partial',
    type: 'POST',
    data: {
      key: 'settings.devices',
      value: update
    }
  })
    .done(function(id) {
      console.log( "removed device ", id );
    });
};

var availableDeviceClick = function (item, configured, macaddress) {
  var value = ko.toJS(item);
  var devices = ko.toJS(configured) || [];
  if (devices == 'all') {
    devices = [];
  }
  devices.push(value);

  var post = {};
  post.key = "settings.devices";
  post.value = devices;

  $.ajax({
    url: '/api/station/' + macaddress() + '/partial',
    type: 'POST',
    data: post
  });
};

var actionStationManagers = function(roomId, action) {
  ko.utils.arrayForEach(vm.stations(), function(station) {
    if (station.settings.room() === roomId) {
      var post = new Object({});
      post.station_macaddress = station.settings.macaddress();
      post.id = "Station";
      post.command_url = "manager";
      post.action = action;
      actionStationPost(post);
    }
  });
};

var actionStations = function(roomId, action) {
  ko.utils.arrayForEach(vm.stations(), function(station) {
    if (station.settings.room() === roomId) {
      var post = new Object({});
      post.station_macaddress = station.settings.macaddress();
      post.id = "all";
      post.command_url = "command";
      post.action = action;
      actionStationPost(post);
    }
  });
};

var actionStationManager = function(macaddress, action) {
  var post = new Object({});
  post.station_macaddress = macaddress;
  post.id = "Station";
  post.command_url = "manager";
  post.action = action;
  actionStationPost(post);
};

$("body").on("click", ".actionOnclick", function (e) {
  var post = new Object({});
  post.station_macaddress = $(e.currentTarget).closest("[data-macaddress]").data('macaddress');
  post.id = $(e.currentTarget).data('id');
  post.command_url = "command";
  post.action = $(e.currentTarget).data('action');
  actionStationPost(post);
});

var actionDevice = function(macaddress, device, action) {
  var post = new Object({});
  post.station_macaddress = macaddress;
  post.id = device;
  post.command_url = "command";
  post.action = action;
  actionStationPost(post);
};

var actionStationPost = function(post) {
  console.log(post);
  $.ajax({
    url: '/api/station/' + post.station_macaddress + '/action',
    type: 'POST',
    data: post
  });
};

var removeStation = function(data, event) {
  $.ajax({
    url: "/api/station/"+ data.settings.macaddress(),
    type: 'DELETE'
  })
    .done(function(data) {
      console.log( "removed station", JSON.stringify(data) );
    });
};

var removeStationRoom = function(data, event) {
  $.ajax({
    url: "/api/station/"+ data.settings.macaddress()  + '/partial',
    type: 'POST',
    data: {
      key: 'settings.room',
      value: ''
    }
  })
    .done(function(data) {
      console.log( "removed station", JSON.stringify(data) );
    });
};

function submitStation(data, event) {
  var $form = $(event.currentTarget).parents('#add-station');

  $.ajax({
    type: "POST",
    url: "/api/station",
    data: data,
  })
    .done(function() {
      $form.collapse('hide');
    });
}

var macRewrite = function(macaddress) {
  if (!macaddress) { return false; }
  return macaddress.replace(/-\s*/g, ":");
};
<commit_msg>Updated to not rely on outrageous assumption.<commit_after>ko.bindingProvider.instance = new StringInterpolatingBindingProvider();

var availableRoles = [
  {value: 'ingest', text: 'ingest'},
  {value: 'mixer', text: 'mixer'},
  {value: 'record', text: 'record'},
  {value: 'stream', text: 'stream'}
];

//-- yuck
var roleDisplay = function(value, sourceData) {
  var checked = $.fn.editableutils.itemsByValue(value, sourceData);

  if(checked.length) {
    var selectedRoles = "";

    checked.forEach(function(value) {
      selectedRoles +=
        "
" +
          $.fn.editableutils.escape(value.text) +
        "
";
    });
    $(this).html('
' + selectedRoles + '
');
  } else {
    $(this).empty();
  }
};

var vm = {
  stations: ko.mapping.fromJS([]),
};

var availableDevices = function(station) {
  if (station.devices) {

    var allDevices = station.devices();

    if (station.settings.devices && station.settings.devices().length) {
      var configuredDevices = station.settings.devices() || [];
      configuredDevices = configuredDevices.map(function(item) {
        return item.id();
      });

      var availableDevices = allDevices.filter(function(item) {
        if (configuredDevices.indexOf(Object.keys(item)[0]) == -1) {
          return item;
        }
      });
      return availableDevices;
    }
    return allDevices;
  }
  return [];
};

var activeStatus = function(station) {

  var list = [];
  if (station.status) {
    for (var i in station.status) {
      list.push(station.status[i]);
    }
  }
  return list;
  /*
  if (station.status) {
    for( var i in station.status ) {
      station.status[i].name = i;

        // this is a hack, fix the manager so that running is populated properly
        // done enough yak shaving for one conference...
        if (typeof station.status[i].running == 'undefined') {
          station.status[i].running = '0';
        }
        if (typeof station.status[i].type == 'undefined') {
          station.status[i].type = 'internal';
        }
        // end nasty hack

      statusArray.push(station.status[i]);
    }
  }
  return statusArray;
  */
};

vm.roomDuplicates = ko.computed(function() {
  return vm.stations().map(function(item) {
    return (item.settings.room ? item.settings.room() : '');
  });
});

vm.rooms = ko.computed(function() {
  var onlyUnique = function (value, index, self) {
    return self.indexOf(value) === index;
  };
  return vm.roomDuplicates().filter(onlyUnique);
});

ko.applyBindings(vm);

var socket = io.connect('//');
var mapping = {};

$.get( "/api/station", function( data ) {
})
  .done(function(data) {
    ko.mapping.fromJS(data, mapping, vm.stations);
    socket.on('change', function (data) {
      console.log(data);
      if (data.type == 'remove') {
        vm.stations.mappedRemove({id: data.content._id});
      }
      if (data.type == 'insert') {
        vm.stations.push(ko.mapping.fromJS(data.content, mapping));
      }
      if (data.type == 'update') {
        var match = ko.utils.arrayFirst(vm.stations(), function (item) {
            return item._id() == data.content._id;
        });
        if (match) {
          ko.mapping.fromJS(data.content, mapping, match);
        }
        if (!data.content.settings.devices && match.settings.devices) {
          match.settings.devices([]);
        }

      }
      if (data.type == 'notify') {
      }

    });
  });

var removeDevice = function (configuredDevices, macaddress, id) {
  var update = ko.toJS(configuredDevices).filter(function(device) {
    return device.id !== id;
  });

  $.ajax({
    url: "/api/station/"+ macaddress + '/partial',
    type: 'POST',
    data: {
      key: 'settings.devices',
      value: update
    }
  })
    .done(function(id) {
      console.log( "removed device ", id );
    });
};

var availableDeviceClick = function (item, configured, macaddress) {
  var value = ko.toJS(item);
  var devices = ko.toJS(configured) || [];
  if (devices == 'all') {
    devices = [];
  }
  devices.push(value);

  var post = {};
  post.key = "settings.devices";
  post.value = devices;

  $.ajax({
    url: '/api/station/' + macaddress() + '/partial',
    type: 'POST',
    data: post
  });
};

var actionStationManagers = function(roomId, action) {
  ko.utils.arrayForEach(vm.stations(), function(station) {
    if (station.settings.room() === roomId) {
      var post = new Object({});
      post.station_macaddress = station.settings.macaddress();
      post.id = "Station";
      post.command_url = "manager";
      post.action = action;
      actionStationPost(post);
    }
  });
};

var actionStations = function(roomId, action) {
  ko.utils.arrayForEach(vm.stations(), function(station) {
    if (station.settings.room() === roomId) {
      var post = new Object({});
      post.station_macaddress = station.settings.macaddress();
      post.id = "all";
      post.command_url = "command";
      post.action = action;
      actionStationPost(post);
    }
  });
};

var actionStationManager = function(macaddress, action) {
  var post = new Object({});
  post.station_macaddress = macaddress;
  post.id = "Station";
  post.command_url = "manager";
  post.action = action;
  actionStationPost(post);
};

$("body").on("click", ".actionOnclick", function (e) {
  var post = new Object({});
  post.station_macaddress = $(e.currentTarget).closest("[data-macaddress]").data('macaddress');
  post.id = $(e.currentTarget).data('id');
  post.command_url = "command";
  post.action = $(e.currentTarget).data('action');
  actionStationPost(post);
});

var actionDevice = function(macaddress, device, action) {
  var post = new Object({});
  post.station_macaddress = macaddress;
  post.id = device;
  post.command_url = "command";
  post.action = action;
  actionStationPost(post);
};

var actionStationPost = function(post) {
  console.log(post);
  $.ajax({
    url: '/api/station/' + post.station_macaddress + '/action',
    type: 'POST',
    data: post
  });
};

var removeStation = function(data, event) {
  $.ajax({
    url: "/api/station/"+ data.settings.macaddress(),
    type: 'DELETE'
  })
    .done(function(data) {
      console.log( "removed station", JSON.stringify(data) );
    });
};

var removeStationRoom = function(data, event) {
  $.ajax({
    url: "/api/station/"+ data.settings.macaddress()  + '/partial',
    type: 'POST',
    data: {
      key: 'settings.room',
      value: ''
    }
  })
    .done(function(data) {
      console.log( "removed station", JSON.stringify(data) );
    });
};

function submitStation(data, event) {
  var $form = $(event.currentTarget).parents('#add-station');

  $.ajax({
    type: "POST",
    url: "/api/station",
    data: data,
  })
    .done(function() {
      $form.collapse('hide');
    });
}

var macRewrite = function(macaddress) {
  if (!macaddress) { return false; }
  return macaddress.replace(/-\s*/g, ":");
};
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import * as Routes from '../helpers/Routes';

const whitePixel = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

// Pure UI component for displaying a student photo
export default class StudentPhoto extends React.Component {

  onError(e) {
    e.target.src = whitePixel;
  }

  altText() {
    const {student} = this.props;
    return `Student photo for ${student.first_name} ${student.last_name}`;
  }

  render() {
    const {student, height, style} = this.props;

    return (

    );
  }
}

StudentPhoto.propTypes = {
  student: PropTypes.object.isRequired,
  height: PropTypes.number.isRequired,
  style: PropTypes.object,
};

<commit_msg>Func sort<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import * as Routes from '../helpers/Routes';

const whitePixel = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

// Pure UI component for displaying a student photo
export default class StudentPhoto extends React.Component {

  altText() {
    const {student} = this.props;
    return `Student photo for ${student.first_name} ${student.last_name}`;
  }

  onError(e) {
    e.target.src = whitePixel;
  }

  render() {
    const {student, height, style} = this.props;

    return (

    );
  }
}

StudentPhoto.propTypes = {
  student: PropTypes.object.isRequired,
  height: PropTypes.number.isRequired,
  style: PropTypes.object,
};

<|endoftext|>


<commit_before>// An editor modal for creating and updating pieces. An instance of this modal is created
// each time you click "Add" or click to edit an existing piece. Relies on
// [apostrophe-schemas](../apostrophe-schemas/index.html) to edit the fields.

apos.define('apostrophe-pieces-editor-modal', {
  extend: 'apostrophe-modal',

  beforeConstruct: function(self, options) {
    if (!options.source) {
      if (options.create) {
        options.source = 'create-modal';
      } else {
        options.source = 'editor-modal';
      }
    }
  },

  construct: function(self, options) {
    self.schema = options.schema;
    self._id = options._id;
    self.name = options.name;
    self.copying = options.copying;
    self.manager = options.manager;
    self.beforeShow = function(callback) {
      self.$form = self.$el.find('[data-apos-form]');
      self.$form.on('change', self.onChange);

      self.link('apos-trash', function($el) {
        self.trash($el);
      });

      self.link('apos-copy', function($el) {
        self.copy($el);
      });

      self.link('apos-versions', function($el) {
        self.versions($el);
      });

      if (self._id) {
        return self.edit(self._id, callback);
      } else {
        return self.create(callback);
      }
    };

    self.edit = function(_id, callback) {
      return apos.docs.lockAndWatch(_id, function(err) {
        if (err) {
          return callback(err);
        }
        return self.open('retrieve', { _id: _id }, callback);
      });
    };

    self.create = function(callback) {
      var piece = apos.schemas.newInstance(self.schema);
      if (self.options.copying) {
        _.assign(piece, self.options.copying);
        delete piece._id;
      }
      return self.populate(piece, callback);
    };

    self.open = function(verb, data, callback) {
      self.api(verb, data, function(result) {
        if (result.status === 'notfound') {
          apos.notify('That item does not exist.', { type: 'error' });
          return callback('error');
        } else if (result.status !== 'ok') {
          apos.notify('An error occurred. Please try again.', { type: 'error', dismiss: true });
          return callback('error');
        }
        self._id = result.data._id;
        var object = result.data;
        return self.populate(object, callback);
      }, function() {
        apos.notify('An error occurred. Please try again.', { type: 'error', dismiss: true });
        return callback('network');
      });
    };

    self.populate = function(piece, callback) {
      return async.series({
        beforePopulate: function(callback) {
          return self.beforePopulate(piece, callback);
        },
        populate: function(callback) {
          return apos.schemas.populate(self.$form, self.schema, piece, callback);
        },
        afterPopulate: function(callback) {
          return self.afterPopulate(piece, callback);
        }
      }, callback);
    };

    self.beforePopulate = function(piece, callback) {
      return setImmediate(callback);
    };

    self.afterPopulate = function(piece, callback) {
      return setImmediate(callback);
    };

    self.saveContent = function(callback) {
      var piece = {
        _id: self._id
      };

      return async.series({
        before: function(callback) {
          return self.beforeConvert(piece, callback);
        },
        convert: function(callback) {
          return apos.schemas.convert(self.$form, self.schema, piece, callback);
        },
        after: function(callback) {
          return self.afterConvert(piece, callback);
        }
      }, function(err) {
        if (err) {
          return callback(err);
        }
        var verb = piece._id ? 'update' : 'insert';
        if (self.copying) {
          // Give the server side a chance to copy in any
          // anonymous areas, which would not be a part
          // of the schema
          piece._copyingId = self.copying._id;
        }
        self.api(verb, piece, function(result) {
          if (result.status !== 'ok') {
            apos.notify(self.getErrorMessage(result.status), { type: 'error' });
            return callback('error');
          }
          self.unsavedChanges = false;
          // Make the saved piece available to methods like copy()
          self.savedPiece = result.data;
          return self.displayResponse(result, callback);
        }, function() {
          apos.notify('An error occurred. Please try again', { type: 'error', dismiss: true });
          return callback(err);
        });
      });
    };

    self.getErrorMessage = function(err) {
      apos.utils.error(err);
      return 'An error occurred. Please try again.';
    };

    self.beforeConvert = function(piece, callback) {
      return setImmediate(callback);
    };

    self.afterConvert = function(piece, callback) {
      return setImmediate(callback);
    };

    // Update the display in response to this item being saved.
    //
    // If the piece is brand new and the server provided
    // a `_url` property and set `contextual: true` for this
    // type of piece, or the piece has been updated and
    // apos.pages.piece._id (the in-context piece) matches the
    // id of the piece just edited, go to `_url`.
    //
    // In any case, the main content area is refreshed and the manage
    // view, if open, refreshes its list (`apos.change` is invoked).
    // This will all make sense if the URL hasn't changed, and do no
    // harm if it has.

    self.displayResponse = function(result, callback) {
      if (self.manager.options.contextual) {
        if ((self.options.create && result.data._url) ||
          (apos.contextPiece && result.data._url && (result.data._id === apos.contextPiece._id))) {
          // If the response contains a `_url`, we should redirect to the
          // _url to edit the piece contextually
          window.location.href = result.data._url;
        }
      }
      if (self.options.create) {
        // apos event so the chooser can figure out it should auto-select this
        apos.emit('pieceInserted', result.data);
      }
      apos.change(result.data);
      return setImmediate(callback);
    };

    self.onChange = function(e) {
      if (!self.unsavedChanges) {
        self.unsavedChanges = true;
      }
    };

    self.trash = function($el, next) {
      if (self.trashing || !confirm("Are you sure you want to trash this " + self.options.label + "?")) {
        return;
      }

      var piece = {
        _id: self._id
      };

      self.trashing = true;
      $el.addClass('apos-busy');

      self.api('trash', piece, function(result) {
        self.trashing = false;
        $el.removeClass('apos-busy');
        if (result.status !== 'ok') {
          apos.notify('An error occurred. Please try again.', { type: 'error', dismiss: true });
          if (next) {
            return next('error');
          }
          return;
        }
        apos.change(self.name);
        apos.modalSupport.closeTopModal();
        if (next) {
          return next(null);
        }

      }, function(err) {
        self.trashing = false;
        $el.removeClass('apos-busy');
        apos.notify('An error occurred. Please try again', { type: 'error', dismiss: true });
        if (next) {
          return next(err);
        }

      });
    };

    self.versions = function($el) {
      apos.versions.edit(self._id, function() {
        // After reverting, the easiest way to roll back the
        // editor modal is to just cancel it and open another one
        // with the same moog type and options. We also use
        // apos.change to signal to the list view and anything
        // else that cares. -Tom
        self.hide();
        apos.change(self.name);
        apos.create(self.__meta.name, self.options);
      });
    };

    // Save this modal, then open a new modal to create a new piece of
    // this type that starts out as a copy of the current piece

    self.copy = function($el) {
      // We must save successfully before we can start a new editor for the copy
      // Stub out displayResponse so contextual pieces don't refresh the page,
      // preventing our callback from ever being invoked
      var superDisplayResponse = self.displayResponse;
      self.displayResponse = function(result, callback) {
        return callback(null);
      };
      return self.save(function(err) {
        // Restore displayResponse in case this modal lives on
        self.displayResponse = superDisplayResponse;
        if (err) {
          return;
        }
        // This modal should close now, launch a new modal
        // for a new piece
        var _options = _.clone(self.options);
        _options.copying = self.savedPiece;
        _options.create = true;
        delete _options._id;
        delete _options.source;
        apos.create(self.__meta.name, _options);
      });
    };

    var superAfterHide = self.afterHide;
    self.afterHide = function() {
      superAfterHide();
      if (self._id) {
        apos.docs.unlock(self._id, function() {});
      }
    };

  }
});
<commit_msg>Redirect after deleting piece from editor modal<commit_after>// An editor modal for creating and updating pieces. An instance of this modal is created
// each time you click "Add" or click to edit an existing piece. Relies on
// [apostrophe-schemas](../apostrophe-schemas/index.html) to edit the fields.

apos.define('apostrophe-pieces-editor-modal', {
  extend: 'apostrophe-modal',

  beforeConstruct: function(self, options) {
    if (!options.source) {
      if (options.create) {
        options.source = 'create-modal';
      } else {
        options.source = 'editor-modal';
      }
    }
  },

  construct: function(self, options) {
    self.schema = options.schema;
    self._id = options._id;
    self.name = options.name;
    self.copying = options.copying;
    self.manager = options.manager;
    self.beforeShow = function(callback) {
      self.$form = self.$el.find('[data-apos-form]');
      self.$form.on('change', self.onChange);

      self.link('apos-trash', function($el) {
        self.trash($el);
      });

      self.link('apos-copy', function($el) {
        self.copy($el);
      });

      self.link('apos-versions', function($el) {
        self.versions($el);
      });

      if (self._id) {
        return self.edit(self._id, callback);
      } else {
        return self.create(callback);
      }
    };

    self.edit = function(_id, callback) {
      return apos.docs.lockAndWatch(_id, function(err) {
        if (err) {
          return callback(err);
        }
        return self.open('retrieve', { _id: _id }, callback);
      });
    };

    self.create = function(callback) {
      var piece = apos.schemas.newInstance(self.schema);
      if (self.options.copying) {
        _.assign(piece, self.options.copying);
        delete piece._id;
      }
      return self.populate(piece, callback);
    };

    self.open = function(verb, data, callback) {
      self.api(verb, data, function(result) {
        if (result.status === 'notfound') {
          apos.notify('That item does not exist.', { type: 'error' });
          return callback('error');
        } else if (result.status !== 'ok') {
          apos.notify('An error occurred. Please try again.', { type: 'error', dismiss: true });
          return callback('error');
        }
        self._id = result.data._id;
        var object = result.data;
        return self.populate(object, callback);
      }, function() {
        apos.notify('An error occurred. Please try again.', { type: 'error', dismiss: true });
        return callback('network');
      });
    };

    self.populate = function(piece, callback) {
      return async.series({
        beforePopulate: function(callback) {
          return self.beforePopulate(piece, callback);
        },
        populate: function(callback) {
          return apos.schemas.populate(self.$form, self.schema, piece, callback);
        },
        afterPopulate: function(callback) {
          return self.afterPopulate(piece, callback);
        }
      }, callback);
    };

    self.beforePopulate = function(piece, callback) {
      return setImmediate(callback);
    };

    self.afterPopulate = function(piece, callback) {
      return setImmediate(callback);
    };

    self.saveContent = function(callback) {
      var piece = {
        _id: self._id
      };

      return async.series({
        before: function(callback) {
          return self.beforeConvert(piece, callback);
        },
        convert: function(callback) {
          return apos.schemas.convert(self.$form, self.schema, piece, callback);
        },
        after: function(callback) {
          return self.afterConvert(piece, callback);
        }
      }, function(err) {
        if (err) {
          return callback(err);
        }
        var verb = piece._id ? 'update' : 'insert';
        if (self.copying) {
          // Give the server side a chance to copy in any
          // anonymous areas, which would not be a part
          // of the schema
          piece._copyingId = self.copying._id;
        }
        self.api(verb, piece, function(result) {
          if (result.status !== 'ok') {
            apos.notify(self.getErrorMessage(result.status), { type: 'error' });
            return callback('error');
          }
          self.unsavedChanges = false;
          // Make the saved piece available to methods like copy()
          self.savedPiece = result.data;
          return self.displayResponse(result, callback);
        }, function() {
          apos.notify('An error occurred. Please try again', { type: 'error', dismiss: true });
          return callback(err);
        });
      });
    };

    self.getErrorMessage = function(err) {
      apos.utils.error(err);
      return 'An error occurred. Please try again.';
    };

    self.beforeConvert = function(piece, callback) {
      return setImmediate(callback);
    };

    self.afterConvert = function(piece, callback) {
      return setImmediate(callback);
    };

    // Update the display in response to this item being saved.
    //
    // If the piece is brand new and the server provided
    // a `_url` property and set `contextual: true` for this
    // type of piece, or the piece has been updated and
    // apos.pages.piece._id (the in-context piece) matches the
    // id of the piece just edited, go to `_url`.
    //
    // In any case, the main content area is refreshed and the manage
    // view, if open, refreshes its list (`apos.change` is invoked).
    // This will all make sense if the URL hasn't changed, and do no
    // harm if it has.

    self.displayResponse = function(result, callback) {
      if (self.manager.options.contextual) {
        if ((self.options.create && result.data._url) ||
          (apos.contextPiece && result.data._url && (result.data._id === apos.contextPiece._id))) {
          // If the response contains a `_url`, we should redirect to the
          // _url to edit the piece contextually
          window.location.href = result.data._url;
        }
      }
      if (self.options.create) {
        // apos event so the chooser can figure out it should auto-select this
        apos.emit('pieceInserted', result.data);
      }
      apos.change(result.data);
      return setImmediate(callback);
    };

    self.onChange = function(e) {
      if (!self.unsavedChanges) {
        self.unsavedChanges = true;
      }
    };

    self.trash = function($el, next) {
      if (self.trashing || !confirm("Are you sure you want to trash this " + self.options.label + "?")) {
        return;
      }

      var piece = {
        _id: self._id
      };

      self.trashing = true;
      $el.addClass('apos-busy');

      self.api('trash', piece, function(result) {
        self.trashing = false;
        $el.removeClass('apos-busy');
        if (result.status !== 'ok') {
          apos.notify('An error occurred. Please try again.', { type: 'error', dismiss: true });
          if (next) {
            return next('error');
          }
          return;
        }
        apos.change(self.name);
        apos.modalSupport.closeTopModal();
        if (next) {
          return next(null);
        }

        // Redirect to list view
        window.location.href = apos.pages.page._url;

      }, function(err) {
        self.trashing = false;
        $el.removeClass('apos-busy');
        apos.notify('An error occurred. Please try again', { type: 'error', dismiss: true });
        if (next) {
          return next(err);
        }

      });
    };

    self.versions = function($el) {
      apos.versions.edit(self._id, function() {
        // After reverting, the easiest way to roll back the
        // editor modal is to just cancel it and open another one
        // with the same moog type and options. We also use
        // apos.change to signal to the list view and anything
        // else that cares. -Tom
        self.hide();
        apos.change(self.name);
        apos.create(self.__meta.name, self.options);
      });
    };

    // Save this modal, then open a new modal to create a new piece of
    // this type that starts out as a copy of the current piece

    self.copy = function($el) {
      // We must save successfully before we can start a new editor for the copy
      // Stub out displayResponse so contextual pieces don't refresh the page,
      // preventing our callback from ever being invoked
      var superDisplayResponse = self.displayResponse;
      self.displayResponse = function(result, callback) {
        return callback(null);
      };
      return self.save(function(err) {
        // Restore displayResponse in case this modal lives on
        self.displayResponse = superDisplayResponse;
        if (err) {
          return;
        }
        // This modal should close now, launch a new modal
        // for a new piece
        var _options = _.clone(self.options);
        _options.copying = self.savedPiece;
        _options.create = true;
        delete _options._id;
        delete _options.source;
        apos.create(self.__meta.name, _options);
      });
    };

    var superAfterHide = self.afterHide;
    self.afterHide = function() {
      superAfterHide();
      if (self._id) {
        apos.docs.unlock(self._id, function() {});
      }
    };

  }
});
<|endoftext|>


<commit_before>import {
  USER_SONG_STAR,
  USER_SONG_UNSTAR,
  SOCKET_AUTH_ERROR,
  LOGIN,
  LOGOUT,
  CREATE,
  UPDATE,
  _SUCCESS,
  _ERROR,
} from 'constants/actions'
import { fetchPrefs } from './prefs'
import { browserHistory } from 'react-router'

import HttpApi from 'lib/HttpApi'
const api = new HttpApi('')

// ------------------------------------
// Login
// ------------------------------------
function requestLogin (creds) {
  return {
    type: LOGIN,
    payload: creds
  }
}

function receiveLogin (response) {
  return {
    type: LOGIN + _SUCCESS,
    payload: response
  }
}

function loginError (message) {
  return {
    type: LOGIN + _ERROR,
    meta: {
      error: message + ' (incorrect login)',
    }
  }
}

// calls api endpoint that should set an httpOnly cookie with
// our JWT, then establish the sockiet.io connection
export function loginUser (data) {
  return (dispatch, getState) => {
    dispatch(requestLogin(data))

    return api('POST', 'login', {
      body: data
    })
      .then(user => {
        // user object in response body
        dispatch(receiveLogin(user))

        // update preferences
        if (user.isAdmin) {
          dispatch(fetchPrefs())
        }

        // socket.io handshake happens over http so
        // our JWT will be sent in the cookie
        window._socket.open()

        // redirect in query string
        const loc = getState().location

        if (loc && loc.search) {
          const query = parseQuery(loc.search)

          if (query.redirect) {
            return browserHistory.push(query.redirect)
          }
        }

        // default redirect
        browserHistory.push('/library')
      })
      .catch(err => {
        dispatch(loginError(err.message))
      })
  }
}

function parseQuery (qstr) {
  var query = {}
  var a = qstr.substr(1).split('&')
  for (var i = 0; i < a.length; i++) {
    var b = a[i].split('=')
    query[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '')
  }
  return query
}

// ------------------------------------
// Logout
// ------------------------------------
function requestLogout () {
  return {
    type: LOGOUT,
    payload: null
  }
}

function receiveLogout () {
  return {
    type: LOGOUT + _SUCCESS,
    payload: null
  }
}

function logoutError (message) {
  return {
    type: LOGOUT + _ERROR,
    meta: {
      error: message,
    }
  }
}

// Logs the user out
export function logoutUser () {
  return (dispatch, getState) => {
    dispatch(requestLogout())

    return api('GET', 'logout')
      .then(response => {
        // server response should have cleared our cookie
        dispatch(receiveLogout())
      })
      .catch(err => {
        dispatch(logoutError(err.message))
      })
      .then(() => {
        // regardless of server response; we tried!
        window._persistor.purge()

        // disconnect socket
        window._socket.close()
      })
  }
}

// ------------------------------------
// Create account
// ------------------------------------
function requestCreate (user) {
  return {
    type: CREATE,
    payload: user
  }
}

function receiveCreate (user) {
  return {
    type: CREATE + _SUCCESS,
    payload: user
  }
}

function createError (message) {
  return {
    type: CREATE + _ERROR,
    meta: {
      error: message,
    }
  }
}

export function createUser (user) {
  return dispatch => {
    dispatch(requestCreate(user))

    return api('POST', 'account', {
      body: user
    })
      .then(user => {
        dispatch(receiveCreate(user))

        // socket.io handshake happens over http so
        // our JWT will be sent in the cookie
        window._socket.open()

        if (user.isAdmin) {
          dispatch(fetchPrefs())
        }
      })
      .catch(err => {
        dispatch(createError(err.message))
      })
  }
}

// ------------------------------------
// Update account
// ------------------------------------
function requestUpdate (user) {
  return {
    type: UPDATE,
    payload: user
  }
}

function receiveUpdate (response) {
  return {
    type: UPDATE + _SUCCESS,
    payload: response
  }
}

function updateError (message) {
  return {
    type: UPDATE + _ERROR,
    meta: {
      error: message,
    }
  }
}

export function updateUser (data) {
  return (dispatch, getState) => {
    dispatch(requestUpdate(data))

    return api('PUT', 'account', {
      body: data
    })
      .then(user => {
        dispatch(receiveUpdate(user))
        alert('Account updated successfully.')
      })
      .catch(err => {
        dispatch(updateError(err.message))
      })
  }
}

// ------------------------------------
// Star/unstar songs
// ------------------------------------
export function starSong (songId) {
  return {
    type: USER_SONG_STAR,
    payload: { songId },
  }
}

export function unstarSong (songId) {
  return {
    type: USER_SONG_UNSTAR,
    payload: { songId },
  }
}

// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = {
  [LOGIN + _SUCCESS]: (state, { payload }) => ({
    ...state,
    ...payload,
  }),
  [UPDATE + _SUCCESS]: (state, { payload }) => ({
    ...state,
    ...payload,
  }),
  [CREATE + _SUCCESS]: (state, { payload }) => ({
    ...state,
    ...payload,
  }),
  [LOGOUT + _SUCCESS]: (state, { payload }) => ({
    ...initialState,
  }),
  [SOCKET_AUTH_ERROR]: (state, { payload }) => ({
    ...initialState,
  }),
  [USER_SONG_STAR + _SUCCESS]: (state, { payload }) => {
    const starredSongs = state.starredSongs.slice()
    starredSongs.push(payload.songId)

    return {
      ...state,
      starredSongs,
    }
  },
  [USER_SONG_UNSTAR + _SUCCESS]: (state, { payload }) => {
    const starredSongs = state.starredSongs.slice()
    starredSongs.splice(starredSongs.indexOf(payload.songId), 1)

    return {
      ...state,
      starredSongs,
    }
  },
}

// ------------------------------------
// Reducer
// ------------------------------------
let initialState = {
  userId: null,
  username: null,
  name: null,
  isAdmin: false,
  roomId: null,
  starredArtists: [],
  starredSongs: [],
}

export default function userReducer (state = initialState, action) {
  const handler = ACTION_HANDLERS[action.type]

  return handler ? handler(state, action) : state
}
<commit_msg>Redirect to /library on account creation<commit_after>import {
  USER_SONG_STAR,
  USER_SONG_UNSTAR,
  SOCKET_AUTH_ERROR,
  LOGIN,
  LOGOUT,
  CREATE,
  UPDATE,
  _SUCCESS,
  _ERROR,
} from 'constants/actions'
import { fetchPrefs } from './prefs'
import { browserHistory } from 'react-router'

import HttpApi from 'lib/HttpApi'
const api = new HttpApi('')

// ------------------------------------
// Login
// ------------------------------------
function requestLogin (creds) {
  return {
    type: LOGIN,
    payload: creds
  }
}

function receiveLogin (response) {
  return {
    type: LOGIN + _SUCCESS,
    payload: response
  }
}

function loginError (message) {
  return {
    type: LOGIN + _ERROR,
    meta: {
      error: message + ' (incorrect login)',
    }
  }
}

// calls api endpoint that should set an httpOnly cookie with
// our JWT, then establish the sockiet.io connection
export function loginUser (data) {
  return (dispatch, getState) => {
    dispatch(requestLogin(data))

    return api('POST', 'login', {
      body: data
    })
      .then(user => {
        // user object in response body
        dispatch(receiveLogin(user))

        // update preferences
        if (user.isAdmin) {
          dispatch(fetchPrefs())
        }

        // socket.io handshake happens over http so
        // our JWT will be sent in the cookie
        window._socket.open()

        // redirect in query string
        const loc = getState().location

        if (loc && loc.search) {
          const query = parseQuery(loc.search)

          if (query.redirect) {
            return browserHistory.push(query.redirect)
          }
        }

        // default redirect
        browserHistory.push('/library')
      })
      .catch(err => {
        dispatch(loginError(err.message))
      })
  }
}

function parseQuery (qstr) {
  var query = {}
  var a = qstr.substr(1).split('&')
  for (var i = 0; i < a.length; i++) {
    var b = a[i].split('=')
    query[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '')
  }
  return query
}

// ------------------------------------
// Logout
// ------------------------------------
function requestLogout () {
  return {
    type: LOGOUT,
    payload: null
  }
}

function receiveLogout () {
  return {
    type: LOGOUT + _SUCCESS,
    payload: null
  }
}

function logoutError (message) {
  return {
    type: LOGOUT + _ERROR,
    meta: {
      error: message,
    }
  }
}

// Logs the user out
export function logoutUser () {
  return (dispatch, getState) => {
    dispatch(requestLogout())

    return api('GET', 'logout')
      .then(response => {
        // server response should have cleared our cookie
        dispatch(receiveLogout())
      })
      .catch(err => {
        dispatch(logoutError(err.message))
      })
      .then(() => {
        // regardless of server response; we tried!
        window._persistor.purge()

        // disconnect socket
        window._socket.close()
      })
  }
}

// ------------------------------------
// Create account
// ------------------------------------
function requestCreate (user) {
  return {
    type: CREATE,
    payload: user
  }
}

function receiveCreate (user) {
  return {
    type: CREATE + _SUCCESS,
    payload: user
  }
}

function createError (message) {
  return {
    type: CREATE + _ERROR,
    meta: {
      error: message,
    }
  }
}

export function createUser (user) {
  return dispatch => {
    dispatch(requestCreate(user))

    return api('POST', 'account', {
      body: user
    })
      .then(user => {
        dispatch(receiveCreate(user))

        // socket.io handshake happens over http so
        // our JWT will be sent in the cookie
        window._socket.open()

        if (user.isAdmin) {
          dispatch(fetchPrefs())
        }

        // default redirect
        browserHistory.push('/library')
      })
      .catch(err => {
        dispatch(createError(err.message))
      })
  }
}

// ------------------------------------
// Update account
// ------------------------------------
function requestUpdate (user) {
  return {
    type: UPDATE,
    payload: user
  }
}

function receiveUpdate (response) {
  return {
    type: UPDATE + _SUCCESS,
    payload: response
  }
}

function updateError (message) {
  return {
    type: UPDATE + _ERROR,
    meta: {
      error: message,
    }
  }
}

export function updateUser (data) {
  return (dispatch, getState) => {
    dispatch(requestUpdate(data))

    return api('PUT', 'account', {
      body: data
    })
      .then(user => {
        dispatch(receiveUpdate(user))
        alert('Account updated successfully.')
      })
      .catch(err => {
        dispatch(updateError(err.message))
      })
  }
}

// ------------------------------------
// Star/unstar songs
// ------------------------------------
export function starSong (songId) {
  return {
    type: USER_SONG_STAR,
    payload: { songId },
  }
}

export function unstarSong (songId) {
  return {
    type: USER_SONG_UNSTAR,
    payload: { songId },
  }
}

// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = {
  [LOGIN + _SUCCESS]: (state, { payload }) => ({
    ...state,
    ...payload,
  }),
  [UPDATE + _SUCCESS]: (state, { payload }) => ({
    ...state,
    ...payload,
  }),
  [CREATE + _SUCCESS]: (state, { payload }) => ({
    ...state,
    ...payload,
  }),
  [LOGOUT + _SUCCESS]: (state, { payload }) => ({
    ...initialState,
  }),
  [SOCKET_AUTH_ERROR]: (state, { payload }) => ({
    ...initialState,
  }),
  [USER_SONG_STAR + _SUCCESS]: (state, { payload }) => {
    const starredSongs = state.starredSongs.slice()
    starredSongs.push(payload.songId)

    return {
      ...state,
      starredSongs,
    }
  },
  [USER_SONG_UNSTAR + _SUCCESS]: (state, { payload }) => {
    const starredSongs = state.starredSongs.slice()
    starredSongs.splice(starredSongs.indexOf(payload.songId), 1)

    return {
      ...state,
      starredSongs,
    }
  },
}

// ------------------------------------
// Reducer
// ------------------------------------
let initialState = {
  userId: null,
  username: null,
  name: null,
  isAdmin: false,
  roomId: null,
  starredArtists: [],
  starredSongs: [],
}

export default function userReducer (state = initialState, action) {
  const handler = ACTION_HANDLERS[action.type]

  return handler ? handler(state, action) : state
}
<|endoftext|>


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

/**
 * Factory for creating icons that appear in this sim.
 *
 * @author Andrea Lin
 */
define( function( require ) {
  'use strict';

  // modules
  const Dimension2 = require( 'DOT/Dimension2' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const HSlider = require( 'SUN/HSlider' );
  const Node = require( 'SCENERY/nodes/Node' );
  const NumberPicker = require( 'SCENERY_PHET/NumberPicker' );
  const NumberProperty = require( 'AXON/NumberProperty' );
  const PhetFont = require( 'SCENERY_PHET/PhetFont' );
  const Property = require( 'AXON/Property' );

  // constants
  const NUMBER_PROPERTY = new NumberProperty( 0, { range: { min: -6, max: 6 } } );

  const GQIconFactory = {

    /**
     * Creates the icon for the 'Integers' scene in the 'Standard Form' screen.
     * @returns {Node}
     */
    createIntegersIcon() {
      const numberPicker = new NumberPicker( NUMBER_PROPERTY, new Property( NUMBER_PROPERTY.range ), {
        font: new PhetFont( { size: 21, weight: 'bold' } ),
        color: 'black',
        xMargin: 5,
        scale: 0.8
      } );
      return new Node( { children: [ numberPicker ], pickable: false } );
    },

    /**
     * Creates the icon for the 'Decimals' scene in the 'Standard Form' screen.
     * @returns {Node}
     */
    createDecimalsIcon() {
      const verticalSlider = new HSlider( NUMBER_PROPERTY, NUMBER_PROPERTY.range, {
        trackSize: new Dimension2( 35, 0.4 ),
        thumbSize: new Dimension2( 12, 20 )
      } );
      verticalSlider.rotate( -Math.PI / 2 );
      return new Node( { children: [ verticalSlider ], pickable: false } );
    }
  };

  return graphingQuadratics.register( 'GQIconFactory', GQIconFactory );
} );<commit_msg>tweaks to icons<commit_after>// Copyright 2018, University of Colorado Boulder

/**
 * Factory for creating icons that appear in this sim.
 *
 * @author Andrea Lin
 */
define( function( require ) {
  'use strict';

  // modules
  const Dimension2 = require( 'DOT/Dimension2' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const HSlider = require( 'SUN/HSlider' );
  const Node = require( 'SCENERY/nodes/Node' );
  const NumberPicker = require( 'SCENERY_PHET/NumberPicker' );
  const NumberProperty = require( 'AXON/NumberProperty' );
  const PhetFont = require( 'SCENERY_PHET/PhetFont' );
  const Property = require( 'AXON/Property' );

  // constants
  const NUMBER_PROPERTY = new NumberProperty( 0, { range: { min: -6, max: 6 } } );

  const GQIconFactory = {

    /**
     * Creates the icon for the 'Integers' scene in the 'Standard Form' screen.
     * @returns {Node}
     */
    createIntegersIcon() {
      const numberPicker = new NumberPicker( NUMBER_PROPERTY, new Property( NUMBER_PROPERTY.range ), {
        font: new PhetFont( { size: 16, weight: 'bold' } ),
        color: 'black',
        xMargin: 5
      } );
      return new Node( { children: [ numberPicker ], pickable: false } );
    },

    /**
     * Creates the icon for the 'Decimals' scene in the 'Standard Form' screen.
     * @returns {Node}
     */
    createDecimalsIcon() {
      const verticalSlider = new HSlider( NUMBER_PROPERTY, NUMBER_PROPERTY.range, {
        trackSize: new Dimension2( 40, 0.4 ),
        thumbSize: new Dimension2( 12, 20 )
      } );
      verticalSlider.rotate( -Math.PI / 2 );
      return new Node( { children: [ verticalSlider ], pickable: false } );
    }
  };

  return graphingQuadratics.register( 'GQIconFactory', GQIconFactory );
} );<|endoftext|>


<commit_before>(function removeZeroCategoriesFromCoverOverbudgeting() {

  if (typeof Em !== 'undefined' && typeof Ember !== 'undefined' && typeof $ !== 'undefined') {
    var coverOverbudgetingCategories = $( ".modal-budget-overspending .options-shown .ynab-select-options" ).children('li');
    coverOverbudgetingCategories.each(function(i) {
      var t = $(this).text(); // Category balance text.
      var categoryBalance = parseInt(t.substr(t.indexOf(":"), t.length).replace(/[^\d-]/g, ''));
      if (categoryBalance <= 0) {
        $(this).remove();
      }
    });
  }

  setTimeout(removeZeroCategoriesFromCoverOverbudgeting, 50);
})();
<commit_msg>Revert "Added a more reliable css selector and fixed parsing bug"<commit_after>(function removeZeroCategoriesFromCoverOverbudgeting() {

  if (typeof Em !== 'undefined' && typeof Ember !== 'undefined' && typeof $ !== 'undefined') {
    var coverOverbudgetingCategories = $( "fieldset>.options-shown>.ynab-select-options" ).children('li');
    coverOverbudgetingCategories.each(function(i) {
      var t = $(this).text(); // Category balance text.
      var categoryBalance = parseInt(t.substr(t.length - t.indexOf(":") + 2).replace( /\D/g, ''))
      if (categoryBalance <= 0) {
        $(this).remove();
      }
    });
  }

  setTimeout(removeZeroCategoriesFromCoverOverbudgeting, 50);
})();
<|endoftext|>