<commit_before>/**
 * Copyright (c) 2015 Guyon Roche
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the 'Software'), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
'use strict';

var fs = require('fs');
var Bluebird = require('bluebird');
var _ = require('underscore');
var Archiver = require('archiver');

var utils = require('../../utils/utils');
var StreamBuf = require('../../utils/stream-buf');

var RelType = require('../../xlsx/rel-type');
var StylesXform = require('../../xlsx/xform/style/styles-xform');
var SharedStrings = require('../../utils/shared-strings');
var DefinedNames = require('../../doc/defined-names');

var CoreXform = require('../../xlsx/xform/core/core-xform');
var RelationshipsXform = require('../../xlsx/xform/core/relationships-xform');
var ContentTypesXform = require('../../xlsx/xform/core/content-types-xform');
var AppXform = require('../../xlsx/xform/core/app-xform');
var WorkbookXform = require('../../xlsx/xform/book/workbook-xform');
var SharedStringsXform = require('../../xlsx/xform/strings/shared-strings-xform');

var WorksheetWriter = require('./worksheet-writer');

var WorkbookWriter = module.exports = function(options) {
  options = options || {};
  //console.log(JSON.stringify(options, null, '    '))

  this.created = options.created || new Date();
  this.modified = options.modified || this.created;
  this.creator = options.creator || 'ExcelJS';
  this.lastModifiedBy = options.lastModifiedBy || 'ExcelJS';

  // using shared strings creates a smaller xlsx file but may use more memory
  this.useSharedStrings = options.useSharedStrings || false;
  this.sharedStrings = new SharedStrings();

  // style manager
  this.styles = options.useStyles ? new StylesXform(true) : new StylesXform.Mock(true);

  // defined names
  this._definedNames = new DefinedNames();

  this._worksheets = [];
  this.views = [];

  this.zip = Archiver('zip');
  if (options.stream) {
    this.stream = options.stream;
  } else if (options.filename) {
    this.stream = fs.createWriteStream(options.filename);
  } else {
    this.stream = new StreamBuf();
  }
  this.zip.pipe(this.stream);

  // these bits can be added right now
  this.promise = Bluebird.all([
    this.addThemes(),
    this.addOfficeRels()
  ]);

};
WorkbookWriter.prototype = {
  get definedNames() {
    return this._definedNames;
  },

  _openStream: function(path) {
    var self = this;
    var stream = new StreamBuf({bufSize: 65536, batch: true});
    self.zip.append(stream, { name: path });
    stream.on('end', function() {
      stream.emit('zipped');
    });
    return stream;
  },
  _commitWorksheets: function() {
    var commitWorksheet = function(worksheet) {
      if (!worksheet.committed) {
        return new Bluebird(function(resolve) {
          worksheet.stream.on('zipped', function() {
            resolve();
          });
          worksheet.commit();
        });
      } else {
        return Bluebird.resolve();
      }
    };
    // if there are any uncommitted worksheets, commit them now and wait
    var promises = this._worksheets.map(commitWorksheet);
    if (promises.length) {
      return Bluebird.all(promises);
    } else {
      return Bluebird.resolve();
    }
  },
  commit: function() {
    var self = this;

    // commit all worksheets, then add suplimentary files
    return this.promise.then(function() {
        return self._commitWorksheets();
      })
      .then(function() {
        return Bluebird.all([
          self.addContentTypes(),
          self.addApp(),
          self.addCore(),
          self.addSharedStrings(),
          self.addStyles(),
          self.addWorkbookRels()
        ]);
      })
      .then(function() {
        return self.addWorkbook();
      })
      .then(function(){
        return self._finalize();
      });
  },
  get nextId() {
    // find the next unique spot to add worksheet
    var i;
    for (i = 1; i < this._worksheets.length; i++) {
      if (!this._worksheets[i]) {
        return i;
      }
    }
    return this._worksheets.length || 1;
  },
  addWorksheet: function(name, options) {
    // it's possible to add a worksheet with different than default
    // shared string handling
    // in fact, it's even possible to switch it mid-sheet
    options = options || {};
    var useSharedStrings = options.useSharedStrings !== undefined ?
      options.useSharedStrings :
      this.useSharedStrings;

    if (options.tabColor) {
      console.trace('tabColor option has moved to { properties: tabColor: {...} }');
      options.properties  = _.extend({
        tabColor: options.tabColor
      }, options.properties);
    }

    var id = this.nextId;
    name = name || 'sheet' + id;

    var worksheet = new WorksheetWriter({
      id: id,
      name: name,
      workbook: this,
      useSharedStrings: useSharedStrings,
      properties: options.properties,
      pageSetup: options.pageSetup
    });

    this._worksheets[id] = worksheet;
    return worksheet;
  },
  getWorksheet: function(id) {
    if (id === undefined) {
      return _.find(this._worksheets, function() { return true; });
    } else if (typeof(id) === 'number') {
      return this._worksheets[id];
    } else if (typeof id === 'string') {
      return _.find(this._worksheets, function(worksheet) {
        return worksheet.name == id;
      });
    } else {
      return undefined;
    }
  },
  addStyles: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      self.zip.append(self.styles.xml, {name: 'xl/styles.xml'});
      resolve();
    });
  },
  addThemes: function() {
    var self = this;
    return utils.readModuleFile(require.resolve('../../xlsx/xml/theme1.xml'))
      .then(function(data){
        self.zip.append(data, { name: 'xl/theme/theme1.xml' });
      });
  },
  addOfficeRels: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      var xform = new RelationshipsXform();
      var xml = xform.toXml([
        {rId: 'rId1', type: RelType.OfficeDocument, target: 'xl/workbook.xml'}
      ]);
      self.zip.append(xml, {name: '/_rels/.rels'});
      resolve();
    });
  },

  addContentTypes: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      var model = {
        worksheets: self._worksheets
      };
      var xform = new ContentTypesXform();
      var xml = xform.toXml(model);
      self.zip.append(xml, {name: '[Content_Types].xml'});
      resolve();
    });
  },
  addApp: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      var model = {
        worksheets: self._worksheets
      };
      var xform = new AppXform();
      var xml = xform.toXml(model);
      self.zip.append(xml, {name: 'docProps/app.xml'});
      resolve();
    });
  },
  addCore: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      var coreXform = new CoreXform();
      var xml = coreXform.toXml(self);
      self.zip.append(xml, {name: 'docProps/core.xml'});
      resolve();
    });
  },
  addSharedStrings: function() {
    var self = this;
    if (this.sharedStrings.count) {
      return new Bluebird(function(resolve) {
        var sharedStringsXform = new SharedStringsXform();
        var xml = sharedStringsXform.toXml(self.sharedStrings);
        self.zip.append(xml, {name: '/xl/sharedStrings.xml'});
        resolve();
      });
    } else {
      return Bluebird.resolve();
    }
  },
  addWorkbookRels: function() {
    var self = this;
    var count = 1;
    var relationships = [
      {rId: 'rId' + (count++), type: RelType.Styles, target: 'styles.xml'},
      {rId: 'rId' + (count++), type: RelType.Theme, target: 'theme/theme1.xml'}
    ];
    if (this.sharedStrings.count) {
      relationships.push(
        {rId: 'rId' + (count++), type: RelType.SharedStrings, target: 'sharedStrings.xml'}
      );
    }
    _.each(this._worksheets, function (worksheet) {
      worksheet.rId = 'rId' + (count++);
      relationships.push(
        {rId: worksheet.rId, type: RelType.Worksheet, target: 'worksheets/sheet' + worksheet.id + '.xml'}
      );
    });
    return new Bluebird(function(resolve) {
      var xform = new RelationshipsXform();
      var xml = xform.toXml(relationships);
      self.zip.append(xml, {name: '/xl/_rels/workbook.xml.rels'});
      resolve();
    });
  },
  addWorkbook: function() {
    var zip = this.zip;
    var model = {
      worksheets: this._worksheets,
      definedNames: this._definedNames.model,
      views: this.views
    };

    return new Bluebird(function(resolve) {
      var xform = new WorkbookXform();
      xform.prepare(model);
      zip.append(xform.toXml(model), {name: '/xl/workbook.xml'});
      resolve();
    });
  },
  _finalize: function() {
    var self = this;
    return new Bluebird(function(resolve, reject) {
      self.stream.on('error', function(error){
        reject(error);
      });
      self.stream.on('finish', function(){
        resolve(self);
      });
      self.zip.on('error', function(error){
        reject(error);
      });

      self.zip.finalize();
    });
  }
};
<commit_msg>Pass views to worksheet-writer<commit_after>/**
 * Copyright (c) 2015 Guyon Roche
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the 'Software'), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
'use strict';

var fs = require('fs');
var Bluebird = require('bluebird');
var _ = require('underscore');
var Archiver = require('archiver');

var utils = require('../../utils/utils');
var StreamBuf = require('../../utils/stream-buf');

var RelType = require('../../xlsx/rel-type');
var StylesXform = require('../../xlsx/xform/style/styles-xform');
var SharedStrings = require('../../utils/shared-strings');
var DefinedNames = require('../../doc/defined-names');

var CoreXform = require('../../xlsx/xform/core/core-xform');
var RelationshipsXform = require('../../xlsx/xform/core/relationships-xform');
var ContentTypesXform = require('../../xlsx/xform/core/content-types-xform');
var AppXform = require('../../xlsx/xform/core/app-xform');
var WorkbookXform = require('../../xlsx/xform/book/workbook-xform');
var SharedStringsXform = require('../../xlsx/xform/strings/shared-strings-xform');

var WorksheetWriter = require('./worksheet-writer');

var WorkbookWriter = module.exports = function(options) {
  options = options || {};
  //console.log(JSON.stringify(options, null, '    '))

  this.created = options.created || new Date();
  this.modified = options.modified || this.created;
  this.creator = options.creator || 'ExcelJS';
  this.lastModifiedBy = options.lastModifiedBy || 'ExcelJS';

  // using shared strings creates a smaller xlsx file but may use more memory
  this.useSharedStrings = options.useSharedStrings || false;
  this.sharedStrings = new SharedStrings();

  // style manager
  this.styles = options.useStyles ? new StylesXform(true) : new StylesXform.Mock(true);

  // defined names
  this._definedNames = new DefinedNames();

  this._worksheets = [];
  this.views = [];

  this.zip = Archiver('zip');
  if (options.stream) {
    this.stream = options.stream;
  } else if (options.filename) {
    this.stream = fs.createWriteStream(options.filename);
  } else {
    this.stream = new StreamBuf();
  }
  this.zip.pipe(this.stream);

  // these bits can be added right now
  this.promise = Bluebird.all([
    this.addThemes(),
    this.addOfficeRels()
  ]);

};
WorkbookWriter.prototype = {
  get definedNames() {
    return this._definedNames;
  },

  _openStream: function(path) {
    var self = this;
    var stream = new StreamBuf({bufSize: 65536, batch: true});
    self.zip.append(stream, { name: path });
    stream.on('end', function() {
      stream.emit('zipped');
    });
    return stream;
  },
  _commitWorksheets: function() {
    var commitWorksheet = function(worksheet) {
      if (!worksheet.committed) {
        return new Bluebird(function(resolve) {
          worksheet.stream.on('zipped', function() {
            resolve();
          });
          worksheet.commit();
        });
      } else {
        return Bluebird.resolve();
      }
    };
    // if there are any uncommitted worksheets, commit them now and wait
    var promises = this._worksheets.map(commitWorksheet);
    if (promises.length) {
      return Bluebird.all(promises);
    } else {
      return Bluebird.resolve();
    }
  },
  commit: function() {
    var self = this;

    // commit all worksheets, then add suplimentary files
    return this.promise.then(function() {
        return self._commitWorksheets();
      })
      .then(function() {
        return Bluebird.all([
          self.addContentTypes(),
          self.addApp(),
          self.addCore(),
          self.addSharedStrings(),
          self.addStyles(),
          self.addWorkbookRels()
        ]);
      })
      .then(function() {
        return self.addWorkbook();
      })
      .then(function(){
        return self._finalize();
      });
  },
  get nextId() {
    // find the next unique spot to add worksheet
    var i;
    for (i = 1; i < this._worksheets.length; i++) {
      if (!this._worksheets[i]) {
        return i;
      }
    }
    return this._worksheets.length || 1;
  },
  addWorksheet: function(name, options) {
    // it's possible to add a worksheet with different than default
    // shared string handling
    // in fact, it's even possible to switch it mid-sheet
    options = options || {};
    var useSharedStrings = options.useSharedStrings !== undefined ?
      options.useSharedStrings :
      this.useSharedStrings;

    if (options.tabColor) {
      console.trace('tabColor option has moved to { properties: tabColor: {...} }');
      options.properties  = _.extend({
        tabColor: options.tabColor
      }, options.properties);
    }

    var id = this.nextId;
    name = name || 'sheet' + id;

    var worksheet = new WorksheetWriter({
      id: id,
      name: name,
      workbook: this,
      useSharedStrings: useSharedStrings,
      properties: options.properties,
      pageSetup: options.pageSetup,
      views: options.views
    });

    this._worksheets[id] = worksheet;
    return worksheet;
  },
  getWorksheet: function(id) {
    if (id === undefined) {
      return _.find(this._worksheets, function() { return true; });
    } else if (typeof(id) === 'number') {
      return this._worksheets[id];
    } else if (typeof id === 'string') {
      return _.find(this._worksheets, function(worksheet) {
        return worksheet.name == id;
      });
    } else {
      return undefined;
    }
  },
  addStyles: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      self.zip.append(self.styles.xml, {name: 'xl/styles.xml'});
      resolve();
    });
  },
  addThemes: function() {
    var self = this;
    return utils.readModuleFile(require.resolve('../../xlsx/xml/theme1.xml'))
      .then(function(data){
        self.zip.append(data, { name: 'xl/theme/theme1.xml' });
      });
  },
  addOfficeRels: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      var xform = new RelationshipsXform();
      var xml = xform.toXml([
        {rId: 'rId1', type: RelType.OfficeDocument, target: 'xl/workbook.xml'}
      ]);
      self.zip.append(xml, {name: '/_rels/.rels'});
      resolve();
    });
  },

  addContentTypes: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      var model = {
        worksheets: self._worksheets
      };
      var xform = new ContentTypesXform();
      var xml = xform.toXml(model);
      self.zip.append(xml, {name: '[Content_Types].xml'});
      resolve();
    });
  },
  addApp: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      var model = {
        worksheets: self._worksheets
      };
      var xform = new AppXform();
      var xml = xform.toXml(model);
      self.zip.append(xml, {name: 'docProps/app.xml'});
      resolve();
    });
  },
  addCore: function() {
    var self = this;
    return new Bluebird(function(resolve) {
      var coreXform = new CoreXform();
      var xml = coreXform.toXml(self);
      self.zip.append(xml, {name: 'docProps/core.xml'});
      resolve();
    });
  },
  addSharedStrings: function() {
    var self = this;
    if (this.sharedStrings.count) {
      return new Bluebird(function(resolve) {
        var sharedStringsXform = new SharedStringsXform();
        var xml = sharedStringsXform.toXml(self.sharedStrings);
        self.zip.append(xml, {name: '/xl/sharedStrings.xml'});
        resolve();
      });
    } else {
      return Bluebird.resolve();
    }
  },
  addWorkbookRels: function() {
    var self = this;
    var count = 1;
    var relationships = [
      {rId: 'rId' + (count++), type: RelType.Styles, target: 'styles.xml'},
      {rId: 'rId' + (count++), type: RelType.Theme, target: 'theme/theme1.xml'}
    ];
    if (this.sharedStrings.count) {
      relationships.push(
        {rId: 'rId' + (count++), type: RelType.SharedStrings, target: 'sharedStrings.xml'}
      );
    }
    _.each(this._worksheets, function (worksheet) {
      worksheet.rId = 'rId' + (count++);
      relationships.push(
        {rId: worksheet.rId, type: RelType.Worksheet, target: 'worksheets/sheet' + worksheet.id + '.xml'}
      );
    });
    return new Bluebird(function(resolve) {
      var xform = new RelationshipsXform();
      var xml = xform.toXml(relationships);
      self.zip.append(xml, {name: '/xl/_rels/workbook.xml.rels'});
      resolve();
    });
  },
  addWorkbook: function() {
    var zip = this.zip;
    var model = {
      worksheets: this._worksheets,
      definedNames: this._definedNames.model,
      views: this.views
    };

    return new Bluebird(function(resolve) {
      var xform = new WorkbookXform();
      xform.prepare(model);
      zip.append(xform.toXml(model), {name: '/xl/workbook.xml'});
      resolve();
    });
  },
  _finalize: function() {
    var self = this;
    return new Bluebird(function(resolve, reject) {
      self.stream.on('error', function(error){
        reject(error);
      });
      self.stream.on('finish', function(){
        resolve(self);
      });
      self.zip.on('error', function(error){
        reject(error);
      });

      self.zip.finalize();
    });
  }
};
<|endoftext|>


<commit_before>var handlebars = require("handlebars/compiler/parser").parser;
var Handlebars = require("../base");

// BEGIN(BROWSER)
var Handlebars = Handlebars || {};

Handlebars.Parser = handlebars;

Handlebars.parse = function(string) {
  Handlebars.Parser.yy = Handlebars.AST;
  return Handlebars.Parser.parse(string);
};

Handlebars.print = function(ast) {
  return new Handlebars.PrintVisitor().accept(ast);
};

Handlebars.logger = {
  DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,

  // override in the host environment
  log: function(level, str) {}
};

Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };

// END(BROWSER)

module.exports = Handlebars;
<commit_msg>Remove unnecessary var declaration.<commit_after>var handlebars = require("handlebars/compiler/parser").parser;
var Handlebars = require("../base");

// BEGIN(BROWSER)
Handlebars.Parser = handlebars;

Handlebars.parse = function(string) {
  Handlebars.Parser.yy = Handlebars.AST;
  return Handlebars.Parser.parse(string);
};

Handlebars.print = function(ast) {
  return new Handlebars.PrintVisitor().accept(ast);
};

Handlebars.logger = {
  DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,

  // override in the host environment
  log: function(level, str) {}
};

Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };

// END(BROWSER)

module.exports = Handlebars;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import {Emitter} from 'event-kit';

import {WorkdirContextPoolPropType} from '../prop-types';
import CommitDetailContainer from '../containers/commit-detail-container';
import RefHolder from '../models/ref-holder';

export default class CommitDetailItem extends React.Component {
  static propTypes = {
    workdirContextPool: WorkdirContextPoolPropType.isRequired,
    workingDirectory: PropTypes.string.isRequired,
    sha: PropTypes.string.isRequired,
  }

  static uriPattern = 'atom-github://commit-detail?workdir={workingDirectory}&sha={sha}'

  static buildURI(workingDirectory, sha) {
    return `atom-github://commit-detail?workdir=${encodeURIComponent(workingDirectory)}&sha=${encodeURIComponent(sha)}`;
  }

  constructor(props) {
    super(props);

    this.emitter = new Emitter();
    this.isDestroyed = false;
    this.hasTerminatedPendingState = false;
    this.refInitialFocus = new RefHolder();
  }

  terminatePendingState() {
    if (!this.hasTerminatedPendingState) {
      this.emitter.emit('did-terminate-pending-state');
      this.hasTerminatedPendingState = true;
    }
  }

  onDidTerminatePendingState(callback) {
    return this.emitter.on('did-terminate-pending-state', callback);
  }

  destroy = () => {
    /* istanbul ignore else */
    if (!this.isDestroyed) {
      this.emitter.emit('did-destroy');
      this.isDestroyed = true;
    }
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback);
  }

  render() {
    const repository = this.props.workdirContextPool.getContext(this.props.workingDirectory).getRepository();

    return (
      <CommitDetailContainer
        itemType={this.constructor}
        repository={repository}
        {...this.props}
        destroy={this.destroy}
        refInitialFocus={this.refInitialFocus}
      />
    );
  }

  getTitle() {
    return `Commit: ${this.props.sha}`;
  }

  getIconName() {
    return 'git-commit';
  }

  getWorkingDirectory() {
    return this.props.workingDirectory;
  }

  serialize() {
    return {
      deserializer: 'CommitDetailStub',
      uri: CommitDetailItem.buildURI(this.props.sha),
    };
  }

  focus() {
    this.refInitialFocus.map(focusable => focusable.focus());
  }
}
<commit_msg>fix arguments passed during serialization<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import {Emitter} from 'event-kit';

import {WorkdirContextPoolPropType} from '../prop-types';
import CommitDetailContainer from '../containers/commit-detail-container';
import RefHolder from '../models/ref-holder';

export default class CommitDetailItem extends React.Component {
  static propTypes = {
    workdirContextPool: WorkdirContextPoolPropType.isRequired,
    workingDirectory: PropTypes.string.isRequired,
    sha: PropTypes.string.isRequired,
  }

  static uriPattern = 'atom-github://commit-detail?workdir={workingDirectory}&sha={sha}'

  static buildURI(workingDirectory, sha) {
    return `atom-github://commit-detail?workdir=${encodeURIComponent(workingDirectory)}&sha=${encodeURIComponent(sha)}`;
  }

  constructor(props) {
    super(props);

    this.emitter = new Emitter();
    this.isDestroyed = false;
    this.hasTerminatedPendingState = false;
    this.refInitialFocus = new RefHolder();
  }

  terminatePendingState() {
    if (!this.hasTerminatedPendingState) {
      this.emitter.emit('did-terminate-pending-state');
      this.hasTerminatedPendingState = true;
    }
  }

  onDidTerminatePendingState(callback) {
    return this.emitter.on('did-terminate-pending-state', callback);
  }

  destroy = () => {
    /* istanbul ignore else */
    if (!this.isDestroyed) {
      this.emitter.emit('did-destroy');
      this.isDestroyed = true;
    }
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback);
  }

  render() {
    const repository = this.props.workdirContextPool.getContext(this.props.workingDirectory).getRepository();

    return (
      <CommitDetailContainer
        itemType={this.constructor}
        repository={repository}
        {...this.props}
        destroy={this.destroy}
        refInitialFocus={this.refInitialFocus}
      />
    );
  }

  getTitle() {
    return `Commit: ${this.props.sha}`;
  }

  getIconName() {
    return 'git-commit';
  }

  getWorkingDirectory() {
    return this.props.workingDirectory;
  }

  serialize() {
    return {
      deserializer: 'CommitDetailStub',
      uri: CommitDetailItem.buildURI(this.props.workingDirectory, this.props.sha),
    };
  }

  focus() {
    this.refInitialFocus.map(focusable => focusable.focus());
  }
}
<|endoftext|>


<commit_before>// @flow
import React from 'react'
import ReactDOM from 'react-dom'
import Root from './Root'

export default class OutputViewContainer {
  static URI = 'git-plus://output-view'

  element: HTMLElement

  constructor() {
    this.element = document.createElement('div')
    this.element.classList.add('git-plus', 'output')
    this.render()
  }

  getURI() {
    return this.constructor.URI
  }

  getTitle() {
    return 'Git+'
  }

  getDefaultLocation() {
    return 'bottom'
  }

  serialize() {
    return {
      deserializer: 'git-plus/output-view'
    }
  }

  show() {
    atom.workspace.open(this)
  }

  hide() {
    atom.workspace.hide(this)
  }

  render() {
    ReactDOM.render(<Root container={this} />, this.element)
  }

  toggle() {
    atom.workspace.toggle(this)
  }

  destroy() {
    ReactDOM.unmountComponentAtNode(this.element)
    this.element.remove()
  }
}
<commit_msg>don't focus on output view when opening it for new results<commit_after>// @flow
import React from 'react'
import ReactDOM from 'react-dom'
import Root from './Root'

export default class OutputViewContainer {
  static URI = 'git-plus://output-view'

  element: HTMLElement

  constructor() {
    this.element = document.createElement('div')
    this.element.classList.add('git-plus', 'output')
    this.render()
  }

  getURI() {
    return this.constructor.URI
  }

  getTitle() {
    return 'Git+'
  }

  getDefaultLocation() {
    return 'bottom'
  }

  serialize() {
    return {
      deserializer: 'git-plus/output-view'
    }
  }

  show() {
    atom.workspace.open(this, { activatePane: false, activateItem: false })
  }

  hide() {
    atom.workspace.hide(this)
  }

  render() {
    ReactDOM.render(<Root container={this} />, this.element)
  }

  toggle() {
    atom.workspace.toggle(this)
  }

  destroy() {
    ReactDOM.unmountComponentAtNode(this.element)
    this.element.remove()
  }
}
<|endoftext|>


<commit_before>/*
 * snapshots.js: Commands related to snapshots resources
 *
 * (C) 2010, Nodejitsu Inc.
 *
 */

var semver = require('semver'),
    jitsu = require('../../jitsu');

var snapshots = exports;

snapshots.usage = [
  '`jitsu snapshots *` commands allow you to work with snapshots',
  'for your Applications on Nodejitsu. Snapshots are images of your',
  'Application\'s code that are deployed to the Nodejitsu Platform.',
  'Valid commands are: ',
  '',
  'jitsu snapshots create',
  'jitsu snapshots list',
  'jitsu snapshots list <app-name>',
  'jitsu snapshots activate',
  'jitsu snapshots activate <app-name>',
  'jitsu snapshots destroy',
  'jitsu snapshots destroy <app-name>',
  '',
  'For commands that take a <name> parameter, if no parameter',
  'is supplied, jitsu will attempt to read the package.json',
  'from the current directory.'
];

//
// ### function list (name, callback)
// #### @name {string} **optional** Name of the application to create
// #### @callback {function} Continuation to pass control to when complete.
// Lists the snapshots for the application belonging for the authenticated user.
// If `name` is not supplied the value for name in `package.name` will be used.
//
snapshots.list = function (name, callback) {
  function executeList() {
    jitsu.log.info('Listing snapshots for ' + name.magenta);
    jitsu.snapshots.list(name, function (err, snapshots) {
      if (err) {
        return callback(err, true);
      }

      if (snapshots && snapshots.length > 0) {
        var rows = [['name', 'created', 'md5']],
            colors = ['underline', 'underline', 'underline'];

        snapshots.forEach(function (snap) {
          rows.push([
            snap.id,
            jitsu.common.formatTime(new Date(snap.ctime)),
            snap.md5
          ]);
        });

        jitsu.inspect.putRows('data', rows, colors);
      }
      else {
        jitsu.log.warn('No snapshots for application ' + name.magenta);
      }

      callback(null, snapshots, name);
    });
  }

  if (!name) {
    return jitsu.package.tryRead(process.cwd(), callback, function (pkg) {
      name = pkg.name;
      executeList();
    });
  }

  executeList();
};

//
// Usage for `jitsu snapshots list [<name>]`
//
snapshots.list.usage = [
  'Lists all snapshots associated with the application in the',
  'current directory or the application with <name>, if supplied',
  '',
  'jitsu snapshots list',
  'jitsu snapshots list <app-name>'
];

//
// ### function create (version, callback)
// #### @version {string} **optional** Version of the application to create
// #### @callback {function} Continuation to pass control to when complete.
// Creates a snapshots for the application belonging for the authenticated user
// using the data in the current directory. If `version` is not supplied the
// value in `package.version` will be used.
//
snapshots.create = function (version, callback) {
  jitsu.package.get(process.cwd(), function (err, pkg) {
    if (err) {
      return callback(err, true);
    }

    jitsu.apps.view(pkg.name, function (err, existing) {
      if (err) {
        jitsu.log.warn('No application exists for ' + pkg.name.magenta);
        return callback(err, true)
      }

      jitsu.package.updateTarball(version, pkg, existing, callback);
    });
  });
};

snapshots.create.usage = [
  'Creates a snapshot for the application in the current directory',
  '',
  'jitsu snapshots create',
  'jitsu snapshots create <app-name>'
];

snapshots.activate = function (name, callback) {

  if (!callback) {
    callback = name;

    return jitsu.package.tryRead(process.cwd(), callback, function (pkg) {
      snapshots.list.apply(null, [ pkg.name ].concat(executeActivate));
    });
  }
  else {
    snapshots.list.apply(null, [ name ].concat(executeActivate));
  }

  function executeActivate (err, snapshots, name) {
    jitsu.prompt.get(['snapshot'], function (err, result) {
      var snapshot = snapshots.filter(function (snap) {
        return snap.id === result.snapshot;
      })[0];

      if (!snapshot) {
        return callback(new Error('Cannot find snapshot with name: ' + result['snapshot'].magenta), true);
      }

      jitsu.snapshots.activate(name, snapshot.id, callback);
    });
  }

};

snapshots.activate.usage = [
  'Activates a snapshot for the application in the current directory',
  '',
  'jitsu snapshots activate',
  'jitsu snapshots activate <app-name>'
];

//
// ### function destroy (appName, callback)
// #### @count {string} **optional** Number of snapshots to destroy
// #### @callback {function} Continuation to pass control to when complete.
// Destroys the specified number of snapshots for the application in the current
// directory. If `count` is not supplied one snapshot will be destroyed.
//
snapshots.destroy = function (name, callback) {
  if (!callback) {
    callback = name;

    return jitsu.package.tryRead(process.cwd(), callback, function (pkg) {
      snapshots.list.apply(null, [ pkg.name ].concat(executeDestroy));
    });
  }
  else {
    snapshots.list.apply(null, [ name ].concat(executeDestroy));
  }

  function executeDestroy (err, snapshots, name) {
    if (err) {
      return callback(err);
    }

    jitsu.prompt.get(['snapshot'], function (err, result) {
      var snapshot = snapshots.filter(function (snap) {
        return snap.id === result.snapshot;
      })[0];

      if (!snapshot) {
        return callback(new Error('Cannot find snapshot with name: ' + result['snapshot'].magenta), true);
      }

      jitsu.snapshots.destroy(name, snapshot.id, callback);
    });
  }
};

snapshots.destroy.destructive = true;
snapshots.destroy.usage = [
  'Destroys a snapshot for the application in the current directory',
  '',
  'jitsu snapshots destroy',
  'jitsu snapshots destroy <app-name>'
];
<commit_msg>[ux] snapshots list will now prompt with application selection if no appname is specified.<commit_after>/*
 * snapshots.js: Commands related to snapshots resources
 *
 * (C) 2010, Nodejitsu Inc.
 *
 */

var semver = require('semver'),
    jitsu = require('../../jitsu');

var snapshots = exports;

snapshots.usage = [
  '`jitsu snapshots *` commands allow you to work with snapshots',
  'for your Applications on Nodejitsu. Snapshots are images of your',
  'Application\'s code that are deployed to the Nodejitsu Platform.',
  'Valid commands are: ',
  '',
  'jitsu snapshots create',
  'jitsu snapshots list',
  'jitsu snapshots list <app-name>',
  'jitsu snapshots activate',
  'jitsu snapshots activate <app-name>',
  'jitsu snapshots destroy',
  'jitsu snapshots destroy <app-name>',
  '',
  'For commands that take a <name> parameter, if no parameter',
  'is supplied, jitsu will attempt to read the package.json',
  'from the current directory.'
];

//
// ### function list (name, callback)
// #### @name {string} **optional** Name of the application to create
// #### @callback {function} Continuation to pass control to when complete.
// Lists the snapshots for the application belonging for the authenticated user.
// If `name` is not supplied the value for name in `package.name` will be used.
//
snapshots.list = function (name, callback) {

  function getAppName(callback) {
    jitsu.package.read(process.cwd(), function (err, pkg) {
      if (!err) {
        jitsu.log.info('Attempting to load snapshots for: ' + (process.cwd()+ '/package.json').grey);
        return callback(null, pkg.name);
      }
      callback(err);
    });
  }

  function listSnapshots(appName, callback) {
    jitsu.log.info('Listing snapshots for ' + appName.magenta);
    jitsu.snapshots.list(appName, function (err, snapshots) {
      if (err) {
        return callback(err, true);
      }

      if (snapshots && snapshots.length > 0) {
        var rows = [['name', 'created', 'md5']],
            colors = ['underline', 'underline', 'underline'];

        snapshots.forEach(function (snap) {
          rows.push([
            snap.id,
            jitsu.common.formatTime(new Date(snap.ctime)),
            snap.md5
          ]);
        });

        jitsu.inspect.putRows('data', rows, colors);
      }
      else {
        jitsu.log.warn('No snapshots for application ' + name.magenta);
      }

      callback(null, snapshots, name);
    });
  }

  if (!name) {
    getAppName(function (err, appName) {
      if (err) {
        jitsu.log.warn('Application name is required to list snapshots')
        jitsu.commands.list(function(){
          jitsu.log.info('Which application do you want to view ' + 'snapshots'.magenta + ' for?');
          jitsu.prompt.get(["app name"], function (err, result) {
            if (err) {
              jitsu.log.error('Prompt error:');
              return callback(err);
            }
            appName = result["app name"];
            listSnapshots(appName, callback);
          });
        })
      } else {
        listSnapshots(appName, callback);
      }
    });
  } else {
    listSnapshots(name, callback);
  }

};

//
// Usage for `jitsu snapshots list [<name>]`
//
snapshots.list.usage = [
  'Lists all snapshots associated with the application in the',
  'current directory or the application with <name>, if supplied',
  '',
  'jitsu snapshots list',
  'jitsu snapshots list <app-name>'
];

//
// ### function create (version, callback)
// #### @version {string} **optional** Version of the application to create
// #### @callback {function} Continuation to pass control to when complete.
// Creates a snapshots for the application belonging for the authenticated user
// using the data in the current directory. If `version` is not supplied the
// value in `package.version` will be used.
//
snapshots.create = function (version, callback) {
  jitsu.package.get(process.cwd(), function (err, pkg) {
    if (err) {
      return callback(err, true);
    }

    jitsu.apps.view(pkg.name, function (err, existing) {
      if (err) {
        jitsu.log.warn('No application exists for ' + pkg.name.magenta);
        return callback(err, true)
      }

      jitsu.package.updateTarball(version, pkg, existing, callback);
    });
  });
};

snapshots.create.usage = [
  'Creates a snapshot for the application in the current directory',
  '',
  'jitsu snapshots create',
  'jitsu snapshots create <app-name>'
];

snapshots.activate = function (name, callback) {

  if (!callback) {
    callback = name;

    return jitsu.package.tryRead(process.cwd(), callback, function (pkg) {
      snapshots.list.apply(null, [ pkg.name ].concat(executeActivate));
    });
  }
  else {
    snapshots.list.apply(null, [ name ].concat(executeActivate));
  }

  function executeActivate (err, snapshots, name) {
    jitsu.prompt.get(['snapshot'], function (err, result) {
      var snapshot = snapshots.filter(function (snap) {
        return snap.id === result.snapshot;
      })[0];

      if (!snapshot) {
        return callback(new Error('Cannot find snapshot with name: ' + result['snapshot'].magenta), true);
      }

      jitsu.snapshots.activate(name, snapshot.id, callback);
    });
  }

};

snapshots.activate.usage = [
  'Activates a snapshot for the application in the current directory',
  '',
  'jitsu snapshots activate',
  'jitsu snapshots activate <app-name>'
];

//
// ### function destroy (appName, callback)
// #### @count {string} **optional** Number of snapshots to destroy
// #### @callback {function} Continuation to pass control to when complete.
// Destroys the specified number of snapshots for the application in the current
// directory. If `count` is not supplied one snapshot will be destroyed.
//
snapshots.destroy = function (name, callback) {
  if (!callback) {
    callback = name;

    return jitsu.package.tryRead(process.cwd(), callback, function (pkg) {
      snapshots.list.apply(null, [ pkg.name ].concat(executeDestroy));
    });
  }
  else {
    snapshots.list.apply(null, [ name ].concat(executeDestroy));
  }

  function executeDestroy (err, snapshots, name) {
    if (err) {
      return callback(err);
    }

    jitsu.prompt.get(['snapshot'], function (err, result) {
      var snapshot = snapshots.filter(function (snap) {
        return snap.id === result.snapshot;
      })[0];

      if (!snapshot) {
        return callback(new Error('Cannot find snapshot with name: ' + result['snapshot'].magenta), true);
      }

      jitsu.snapshots.destroy(name, snapshot.id, callback);
    });
  }
};

snapshots.destroy.destructive = true;
snapshots.destroy.usage = [
  'Destroys a snapshot for the application in the current directory',
  '',
  'jitsu snapshots destroy',
  'jitsu snapshots destroy <app-name>'
];
<|endoftext|>


<commit_before>/**
 * Terminal/WindowManager core script
 * jQuery plugin for opening windows from the terminal
 * Espen Andersen, Norwegian Broadcast Corporation
 * espen.andersen@nrk.no
 * (c) 2013 - NRK Investigative unit
 * Released under the MIT license
 * http://opensource.org/licenses/MIT
 */
( function( $ ) {

	var
		ROOT_SELECTOR = '.__window__manager__root__',

		that,
		root,
		persistent = { windows: { } },

		public_members = {
			'close_window': closeWindow,
			'flash_window': flashWindow,
			'move_window': moveWindow,
			'open_window': openWindow,
			'send_message': sendMessage,
			'set_focus': setFocus
		};

	// Produce a random, unique hexadecimal ID string
	function getUniqueId( prefix ) {
		return 	prefix +
					 String( '00000000' +
							 Math.floor( 0xFFFFFFFF * Math.random() )
							.toString( 16 ) )
					.slice( -8 );
	}

	// brings specified window to the front, normalizing but preserving
	// the z-order index for the other windows
	function bringToFront( hWnd ) {

		var
			i,

			hierarchy =
				root
					.find( '.window' )
					.toArray();

		persistent.windows[ hWnd ].css( 'z-index', 9999 );
		hierarchy.sort( function( a, b ) {
			return ( Number( a.style.zIndex ) - Number( b.style.zIndex ) );
		} );

		for( i = 0; i < hierarchy.length; i++ ) {
			$( hierarchy[ i ] ).css( 'z-index', 10 + i );
		}
	};

	// Close window, param must be either the window handle,
	// or an object with the handle stored in a hWnd property.
	function closeWindow( param ) {

		var
			hWnd = typeof param === 'object' ? param.hWnd : param;

		if( persistent.windows[ hWnd ] ) {

			var

				win =
					root
						.find( '#' + hWnd ),

				winInfo =
					win.data( 'wininfo' );

			sendMessage( { msg: 'wm_before_close' }, winInfo.hWnd );

			win
				.removeData( 'wininfo' );

			delete winInfo.hWnd;

			$( '.overlay textarea' )
				.attr( 'disabled', 'disabled' );

			$( 'a' ).focus();

			win
				.remove();

			delete persistent.windows[ hWnd ];

			var e = new $.Event( 'notify' );
			e.msg = 'close_window';
			e.winInfo = winInfo;
			that.trigger( e );

			$( '.overlay textarea' )
				.removeAttr( 'disabled' );
		}
	};

	// Flash window title bar, param must be either the window handle,
	// or an object with the handle stored in a hWnd property.
	function flashWindow( param ) {

		var
			hWnd = typeof param === 'object' ? param.hWnd : param,
			win = $( '#' + hWnd ),
			counter = 0,
			timer;

		if( persistent.windows[ hWnd ] ) {
			if( timer ) {
				clearInterval( timer );
				timer = 0;
				counter = 0;
			}
			timer =
				setInterval( function( e ) {
					if( ++counter >= 8 ) {
						clearInterval( timer );
						timer = 0;
						win.removeClass( 'flash' );
						counter = 0;
					}
					else {
						win.toggleClass( 'flash' );
					}
				}, 50 );
		}
	};

	// Create new window
	function createWindow( param ) {

		var

			styles = { display: 'none' },

			winCount = root.find( '.window' ).length,

			winInfo = {
				eventDispatcher: that,
				windowManager: root,
				hWnd: getUniqueId( 'win_' ),
				wndTitle: ( param && param.wndTitle ) || '',
				wndClass: ( param && param.wndClass ) || 'default',
				wndClose: ( param && param.wndClose ) || '',
				statusBar: param.statusBar === true,
				resizeHandle: param.resizeHandle === true
			};

			if( param ) {
				if( param.width ) styles.width = param.width;
				if( param.height ) styles.height = param.height;
			}
			else {
				param = { };
			}

			// Default positioning:
			if( styles.left === undefined ) {
				//styles.left = ( 1 + winCount ) * 30;
			}
			if( styles.top === undefined ) {
				//styles.top = ( 1 + winCount ) * 30;
			}

		var newWin = { };
		newWin[ winInfo.hWnd ] =

			root
				.prepend( 	'
' +
						   		'
' +
									'' + winInfo.wndTitle + '' +
									'X' +
								'
' +
								'
' +
								'
' +
							'
' )

				.find( '#' + winInfo.hWnd )
				.addClass( winInfo.wndClass )
				.data( 'wininfo', winInfo )
				.css( styles )
				.draggable( {
					handle: 'h2',
					start:
						function( e ) {
							bringToFront( $( e.target ).closest( '.window' ).attr( 'id' ) );
						}
				} )
				.find( '.titleBar .close' )
				.click( function( e ) {
					var
						hWnd =
							$( e.target )
								.closest( '.window' )
								.attr( 'id' );

					closeWindow( hWnd );
					e.preventDefault();
					e.stopPropagation();
				} )
				.end()
				.find( '.clientRect' )
				.on( 'mousewheel', function( scr, d ) {
					var w = $( this );
					if( d > 0 && w.scrollTop() === 0 ) {
						scr.preventDefault();
					}
					else if( d < 0 && ( w.scrollTop() >= ( w.get( 0 ).scrollHeight - w.innerHeight() - 1 ) ) ) {
						scr.preventDefault();
					}
				} )
				.end();

		if( winInfo.statusBar || winInfo.resizeHandle ) {
			root
				.find( '#' + winInfo.hWnd )
				.addClass( 'withStatusBar' )
				.append( '

Ready

' );
		}

		if( winInfo.resizeHandle ) {
			root
				.find( '#' + winInfo.hWnd )
				.find( '.statusBar' )
				.append( '

' );

			root.find( '#' + winInfo.hWnd ).resizable( { handles: "se" } );
		}

		persistent.windows = $.extend( { }, persistent.windows, newWin );

		param && param.wndProc && param.wndProc( winInfo );

		return winInfo;
	}

	// Default window proc displays en empty window
	function defaultWndProc( winInfo ) {
		showWindow( winInfo.hWnd );
	}

	// Initialize WindowManager
	function init( _options ) {

		root =
			$( that )
				.html( '

' )
				.find( ROOT_SELECTOR );
		root
			.on( 'click', '.window', function( e ) {
				$( e.target )
					.closest( '.window' )
					.each( function( index, win ) {
						var
							hWnd = $( win ).attr( 'id' );
						bringToFront( hWnd );
					} )
					.siblings( '.focus' )
					.removeClass( 'focus' )
					.end()
					.addClass( 'focus' );
			} )
			.on( 'drag', '.window', function( e ) {

				var
					hWnd = $( e.target ).attr( 'id' );

				if( persistent.windows[ hWnd ] ) {
					persistent.windows[ hWnd ].userPositioned = true;
				}

			} );
	};

	function isTopmost( hWnd ) {
		return $( '#' + hWnd ).css( 'z-index' ) == getTopmostIndex();
	};

	function getTopmostIndex() {
		var
			zOrder = [ ],
			windows = $( '.windowManager .window' );

		windows
			.each( function( i, e ) {
				zOrder[ i ] = $( e ).css( 'z-index' );
			} );

		var
			iTopMost =
				( zOrder
					.sort(
						function( a, b ) {
							return a - b;
						} )
					.reverse() ) [ 0 ]
		return iTopMost;
	};

	// Move a window
	function moveWindow( hWnd, pos ) {
		root
			.find( '#' + hWnd )
			.css( {
				top: pos.top,
				left: pos.left } );
	}

	// Open a window, create new if no handle to existing window is provided
	function openWindow( param ) {

		var winInfo;

		if( param === undefined ||
			param.hWnd === undefined ||
			persistent.windows[ param.hWnd ] === undefined ) {

			winInfo = createWindow( param );
		}
		else {
			winInfo = param;
		}

		showWindow( winInfo.hWnd );

		var e = new $.Event( 'notify' );
		e.msg = 'open_window';
		e.winInfo = winInfo;
		that.trigger( e );
	};

	// WindowManager data store
	function savePersistent() {
		root
			.data( 'persistent', persistent );
	};

	// Send message to one or all windows. If no handle is provided
	// (i.e. undefined), the message is broadcasted to all windows
	function sendMessage( param, hWnd ) {
		if( param && param.msg ) {
			var
				e = new $.Event( param.msg ),
				selector = hWnd !== undefined ? '#' + hWnd : '.window';
			e.msg = param.msg;
			e.param = param;
			root
				.find( selector )
				.trigger( e );
		}
	};

	// Bring window to front and activate it
	function setFocus( param ) {
		if( param && param.hWnd ) {
			bringToFront( param.hWnd );
		}
	};

	// Make window visible
	function showWindow( hWnd ) {

		var
			wnd = $( persistent.windows[ hWnd ] );

		bringToFront( hWnd );

		if( wnd.length === 1 ) {

			var
				x = parseInt( wnd.css( 'left' ) ),
				y = parseInt( wnd.css( 'top' ) );

			wnd
				.css( { display: 'block', left: 0, top: 0, opacity: 0.0 } )
				.animate( { left: x, top: y, opacity: 1.0 }, 500 );
		}
	};

	// Expose interface
	$.fn.windowManager = function( param ) {

		var retVal,
			index = 0,
			argv = arguments,
			argc = argv.length;

		this.each( function() {
			that = $( this );
			if( param === undefined || typeof param === 'object' ) {
				// Initialization
				init.apply( this, [ param ] );
				savePersistent();
			}
			else if( public_members[ param ] !== undefined ) {
				// Call to public member
				root = that.find( ROOT_SELECTOR );
				persistent = $( root ).data( 'persistent' );
				retVal = public_members[ param ].apply( this, Array.prototype.slice.call( argv, 1 ) );
				// Callback func should be the last argument
				if( argc > 0 && typeof argv[ argc - 1 ] === 'function' ) {
					// Pass return value for each element to callback function
					( argv[ argc - 1 ] )( index, retVal );
					savePersistent();
					retVal = null;
				}
				else {
					savePersistent();
					// No callback; break loop if return value was present
					if( retVal ) return false;
				}
			}
			else {
				$.error( 'Method not found in windowManager' );
			}
			index++;
		} );
		// Maintain chainability unless returning something
		return retVal || this;
	}

} )( jQuery );<commit_msg>added events for before/after window close<commit_after>/**
 * Terminal/WindowManager core script
 * jQuery plugin for opening windows from the terminal
 * Espen Andersen, Norwegian Broadcast Corporation
 * espen.andersen@nrk.no
 * (c) 2013 - NRK Investigative unit
 * Released under the MIT license
 * http://opensource.org/licenses/MIT
 */
( function( $ ) {

	var
		ROOT_SELECTOR = '.__window__manager__root__',

		that,
		root,
		persistent = { windows: { } },

		public_members = {
			'close_window': closeWindow,
			'flash_window': flashWindow,
			'move_window': moveWindow,
			'open_window': openWindow,
			'send_message': sendMessage,
			'set_focus': setFocus
		};

	// Produce a random, unique hexadecimal ID string
	function getUniqueId( prefix ) {
		return 	prefix +
					 String( '00000000' +
							 Math.floor( 0xFFFFFFFF * Math.random() )
							.toString( 16 ) )
					.slice( -8 );
	}

	// brings specified window to the front, normalizing but preserving
	// the z-order index for the other windows
	function bringToFront( hWnd ) {

		var
			i,

			hierarchy =
				root
					.find( '.window' )
					.toArray();

		persistent.windows[ hWnd ].css( 'z-index', 9999 );
		hierarchy.sort( function( a, b ) {
			return ( Number( a.style.zIndex ) - Number( b.style.zIndex ) );
		} );

		for( i = 0; i < hierarchy.length; i++ ) {
			$( hierarchy[ i ] ).css( 'z-index', 10 + i );
		}
	};

	// Close window, param must be either the window handle,
	// or an object with the handle stored in a hWnd property.
	function closeWindow( param ) {

		var
			hWnd = typeof param === 'object' ? param.hWnd : param;

		if( persistent.windows[ hWnd ] ) {

			var

				win =
					root
						.find( '#' + hWnd ),

				winInfo =
					win.data( 'wininfo' );

			sendMessage( { msg: 'wm_before_close' }, winInfo.hWnd );

			win
				.removeData( 'wininfo' );

			delete winInfo.hWnd;

			var e = new $.Event( 'notify' );
			e.msg = 'before_close_window';
			e.winInfo = winInfo;
			that.trigger( e );

			win
				.remove();

			delete persistent.windows[ hWnd ];

			e = new $.Event( 'notify' );
			e.msg = 'close_window';
			e.winInfo = winInfo;
			that.trigger( e );

			e = new $.Event( 'notify' );
			e.msg = 'after_close_window';
			e.winInfo = winInfo;
			that.trigger( e );
		}
	};

	// Flash window title bar, param must be either the window handle,
	// or an object with the handle stored in a hWnd property.
	function flashWindow( param ) {

		var
			hWnd = typeof param === 'object' ? param.hWnd : param,
			win = $( '#' + hWnd ),
			counter = 0,
			timer;

		if( persistent.windows[ hWnd ] ) {
			if( timer ) {
				clearInterval( timer );
				timer = 0;
				counter = 0;
			}
			timer =
				setInterval( function( e ) {
					if( ++counter >= 8 ) {
						clearInterval( timer );
						timer = 0;
						win.removeClass( 'flash' );
						counter = 0;
					}
					else {
						win.toggleClass( 'flash' );
					}
				}, 50 );
		}
	};

	// Create new window
	function createWindow( param ) {

		var

			styles = { display: 'none' },

			winCount = root.find( '.window' ).length,

			winInfo = {
				eventDispatcher: that,
				windowManager: root,
				hWnd: getUniqueId( 'win_' ),
				wndTitle: ( param && param.wndTitle ) || '',
				wndClass: ( param && param.wndClass ) || 'default',
				wndClose: ( param && param.wndClose ) || '',
				statusBar: param.statusBar === true,
				resizeHandle: param.resizeHandle === true
			};

			if( param ) {
				if( param.width ) styles.width = param.width;
				if( param.height ) styles.height = param.height;
			}
			else {
				param = { };
			}

			// Default positioning:
			if( styles.left === undefined ) {
				//styles.left = ( 1 + winCount ) * 30;
			}
			if( styles.top === undefined ) {
				//styles.top = ( 1 + winCount ) * 30;
			}

		var newWin = { };
		newWin[ winInfo.hWnd ] =

			root
				.prepend( 	'
' +
						   		'
' +
									'' + winInfo.wndTitle + '' +
									'X' +
								'
' +
								'
' +
								'
' +
							'
' )

				.find( '#' + winInfo.hWnd )
				.addClass( winInfo.wndClass )
				.data( 'wininfo', winInfo )
				.css( styles )
				.draggable( {
					handle: 'h2',
					start:
						function( e ) {
							bringToFront( $( e.target ).closest( '.window' ).attr( 'id' ) );
						}
				} )
				.find( '.titleBar .close' )
				.click( function( e ) {
					var
						hWnd =
							$( e.target )
								.closest( '.window' )
								.attr( 'id' );

					closeWindow( hWnd );
					e.preventDefault();
					e.stopPropagation();
				} )
				.end()
				.find( '.clientRect' )
				.on( 'mousewheel', function( scr, d ) {
					var w = $( this );
					if( d > 0 && w.scrollTop() === 0 ) {
						scr.preventDefault();
					}
					else if( d < 0 && ( w.scrollTop() >= ( w.get( 0 ).scrollHeight - w.innerHeight() - 1 ) ) ) {
						scr.preventDefault();
					}
				} )
				.end();

		if( winInfo.statusBar || winInfo.resizeHandle ) {
			root
				.find( '#' + winInfo.hWnd )
				.addClass( 'withStatusBar' )
				.append( '

Ready

' );
		}

		if( winInfo.resizeHandle ) {
			root
				.find( '#' + winInfo.hWnd )
				.find( '.statusBar' )
				.append( '

' );

			root.find( '#' + winInfo.hWnd ).resizable( { handles: "se" } );
		}

		persistent.windows = $.extend( { }, persistent.windows, newWin );

		param && param.wndProc && param.wndProc( winInfo );

		return winInfo;
	}

	// Default window proc displays en empty window
	function defaultWndProc( winInfo ) {
		showWindow( winInfo.hWnd );
	}

	// Initialize WindowManager
	function init( _options ) {

		root =
			$( that )
				.html( '

' )
				.find( ROOT_SELECTOR );
		root
			.on( 'click', '.window', function( e ) {
				$( e.target )
					.closest( '.window' )
					.each( function( index, win ) {
						var
							hWnd = $( win ).attr( 'id' );
						bringToFront( hWnd );
					} )
					.siblings( '.focus' )
					.removeClass( 'focus' )
					.end()
					.addClass( 'focus' );
			} )
			.on( 'drag', '.window', function( e ) {

				var
					hWnd = $( e.target ).attr( 'id' );

				if( persistent.windows[ hWnd ] ) {
					persistent.windows[ hWnd ].userPositioned = true;
				}

			} );
	};

	function isTopmost( hWnd ) {
		return $( '#' + hWnd ).css( 'z-index' ) == getTopmostIndex();
	};

	function getTopmostIndex() {
		var
			zOrder = [ ],
			windows = $( '.windowManager .window' );

		windows
			.each( function( i, e ) {
				zOrder[ i ] = $( e ).css( 'z-index' );
			} );

		var
			iTopMost =
				( zOrder
					.sort(
						function( a, b ) {
							return a - b;
						} )
					.reverse() ) [ 0 ]
		return iTopMost;
	};

	// Move a window
	function moveWindow( hWnd, pos ) {
		root
			.find( '#' + hWnd )
			.css( {
				top: pos.top,
				left: pos.left } );
	}

	// Open a window, create new if no handle to existing window is provided
	function openWindow( param ) {

		var winInfo;

		if( param === undefined ||
			param.hWnd === undefined ||
			persistent.windows[ param.hWnd ] === undefined ) {

			winInfo = createWindow( param );
		}
		else {
			winInfo = param;
		}

		showWindow( winInfo.hWnd );

		var e = new $.Event( 'notify' );
		e.msg = 'open_window';
		e.winInfo = winInfo;
		that.trigger( e );
	};

	// WindowManager data store
	function savePersistent() {
		root
			.data( 'persistent', persistent );
	};

	// Send message to one or all windows. If no handle is provided
	// (i.e. undefined), the message is broadcasted to all windows
	function sendMessage( param, hWnd ) {
		if( param && param.msg ) {
			var
				e = new $.Event( param.msg ),
				selector = hWnd !== undefined ? '#' + hWnd : '.window';
			e.msg = param.msg;
			e.param = param;
			root
				.find( selector )
				.trigger( e );
		}
	};

	// Bring window to front and activate it
	function setFocus( param ) {
		if( param && param.hWnd ) {
			bringToFront( param.hWnd );
		}
	};

	// Make window visible
	function showWindow( hWnd ) {

		var
			wnd = $( persistent.windows[ hWnd ] );

		bringToFront( hWnd );

		if( wnd.length === 1 ) {

			var
				x = parseInt( wnd.css( 'left' ) ),
				y = parseInt( wnd.css( 'top' ) );

			wnd
				.css( { display: 'block', left: 0, top: 0, opacity: 0.0 } )
				.animate( { left: x, top: y, opacity: 1.0 }, 500 );
		}
	};

	// Expose interface
	$.fn.windowManager = function( param ) {

		var retVal,
			index = 0,
			argv = arguments,
			argc = argv.length;

		this.each( function() {
			that = $( this );
			if( param === undefined || typeof param === 'object' ) {
				// Initialization
				init.apply( this, [ param ] );
				savePersistent();
			}
			else if( public_members[ param ] !== undefined ) {
				// Call to public member
				root = that.find( ROOT_SELECTOR );
				persistent = $( root ).data( 'persistent' );
				retVal = public_members[ param ].apply( this, Array.prototype.slice.call( argv, 1 ) );
				// Callback func should be the last argument
				if( argc > 0 && typeof argv[ argc - 1 ] === 'function' ) {
					// Pass return value for each element to callback function
					( argv[ argc - 1 ] )( index, retVal );
					savePersistent();
					retVal = null;
				}
				else {
					savePersistent();
					// No callback; break loop if return value was present
					if( retVal ) return false;
				}
			}
			else {
				$.error( 'Method not found in windowManager' );
			}
			index++;
		} );
		// Maintain chainability unless returning something
		return retVal || this;
	}

} )( jQuery );<|endoftext|>


<commit_before>// Copyright 2017 The Chromium Authors. ALl rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';

foam.CLASS({
  package: 'org.chromium.webidl',
  name: 'Diff',

  requires: [
    'org.chromium.webidl.DiffChunk',
    'org.chromium.webidl.DiffStatus',
  ],

  documentation: `The diff algorithm that is performed on canonicalized
      definitions.`,

  classes: [
    {
      name: 'Identifier',
      properties: [
        {
          class: 'String',
          documentation: 'Name of Definition the diff is performed on.',
          name: 'name',
        },
        {
          class: 'String',
          documentation: 'Tracks the left path to the property of the AST node.',
          name: 'leftKey',
        },
        {
          class: 'String',
          documentation: 'Tracks the right path to the property of the AST node.',
          name: 'rightKey',
        },
        {
          class: 'Array',
          of: 'String',
          documentation: 'Sources from which left definition is composed.',
          name: 'leftSources',
        },
        {
          class: 'Array',
          of: 'String',
          documentation: 'Sources from which right definition is composed.',
          name: 'rightSources',
        },
      ],
    },
  ],

  properties: [
    {
      class: 'Array',
      of: 'String',
      documentation: `Properties that are ignored during diff. These properties
          are either internal properties used by the program or properties that
          will always be different (e.g. id, sources) by nature.`,
      name: 'excludedProps',
      factory: function() {
        return ['id', 'isCanonical', 'sources', 'source'];
      },
    },
    {
      class: 'FObjectArray',
      of: 'org.chromium.webidl.DiffChunk',
      documentation: 'Collection of DiffChunks produced during diff.',
      name: 'chunks_',
    },
  ],

  methods: [
    {
      documentation: `Expects to receive two maps of canonicalized definitions.
          A diff will be performed for each definition, and an array of
          DiffChunks will be returned for each difference found.`,
      name: 'diff',
      args: [
        {
          documentation: `Map of AST Definition nodes corresponding to a
              source. The key of the map is the name of the definition.
              The definitions are used on the left side of the diff.`,
          name: 'left',
          typeName: 'Object',
        },
        {
          documentation: `Map of AST Definition nodes corresponding to a
              source. The key of the map is the name of the definition.
              The definitions are used on the right side of the diff.`,
          name: 'right',
          typeName: 'Object',
        },
      ],
      returns: 'Array',
      code: function(left, right) {
        // Calculate union of leftKeys and rightKeys.
        var leftKeys = Object.keys(left);
        var rightKeys = Object.keys(right);
        var keys = leftKeys.concat(rightKeys);
        keys = keys.filter(function(key, index) {
          return keys.indexOf(key) === index;
        });

        // Iterate through definitions and perform diff.
        keys.forEach(function(key) {
          // If an Enum or Typedef is defined multiple times in
          // the same source (e.g. WebKit), we will get an array of items.
          // These definitions are retained by Canonicalizer and placed
          // into an array. These definitions should be the same.
          // FUTURE: Handle multi definitions that are NOT the same.
          if (Array.isArray(left[key])) this.dedupDefinition_(left, key);
          if (Array.isArray(right[key])) this.dedupDefinition_(right, key);

          // Perform diff with id object to track path and source.
          var id = this.Identifier.create({
            name: key,
            leftSources: left[key] ? left[key].sources : [],
            rightSources: right[key] ? right[key].sources : [],
          });

          this.diff_(left[key], right[key], id);
        }.bind(this));

        var results = this.chunks_;
        this.chunks_ = [];
        return results;
      },
    },
    {
      documentation: `defnMap[key] should be an array of Definition AST nodes
          with key as the name of the definition. If all definitions are the
          same (i.e. they have the same members), the entry is replaced
          with a reference definition.`,
      name: 'dedupDefinition_',
      args: [
        {
          documentation: 'A map of Definition AST nodes for a given source.',
          name: 'defnMap',
          typeName: 'Object',
        },
        {
          documentation: `Name of the Definition that was defined multiple times
              in the given source.`,
          name: 'key',
          typeName: 'String',
        },
      ],
      returns: '',
      code: function(defnMap, key) {
        var id = this.Identifier.create({name: key});
        var defns = defnMap[key];

        var refDefn = defns[0];
        for (var i = 1; i < defns.length; i++) {
          var changes = [];
          this.diff_(refDefn, defns[i], id, changes);

          if (changes.length !== 0) {
            // Cannot handle different definitions right now.
            delete defnMap[key];
            console.error(`Diff: ${key} was defined multiple times.
                The definitions were not identical!`);
            return;
          }
        }

        // Concatenate the list of sources.
        var sources = defnMap[key].reduce(function(srcArr, def) {
          return srcArr.concat(def.sources);
        }, []);

        // Use first object as reference object.
        defnMap[key] = defnMap[key][0];
        defnMap[key].sources = sources;
      },
    },
    {
      documentation: `Given id, status, and left and right, a DiffChunk is
          created. If opt_changes is provided, the DiffChunk is placed in
          opt_changes. Otherwise, it is placed in the global array of chunks.`,
      name: 'addChunk_',
      args: [
        {
          documentation: 'Identification information for the diff chunk.',
          name: 'id',
          typeName: 'Identifier',
        },
        {
          documentation: 'Status information about the diff chunk.',
          name: 'status',
          typeName: 'org.chromium.webidl.DiffStatus',
        },
        {
          documentation: 'The value of the left side of the diff chunk.',
          name: 'left',
        },
        {
          documentation: 'The value of the right side of the diff chunk.',
          name: 'right',
        },
        {
          documentation: 'The array tracking diff chunks that are produced.',
          name: 'opt_changes',
          typeName: 'Array',
        },
      ],
      returns: '',
      code: function(id, status, left, right, opt_changes) {
        var chunk = this.DiffChunk.create({
          definitionName: id.name,
          status: status,
          leftKey: id.leftKey,
          leftValue: left,
          leftSources: id.leftSources,
          rightKey: id.rightKey,
          rightValue: right,
          rightSources: id.rightSources,
        });

        if (opt_changes) opt_changes.push(chunk);
        else this.chunks_.push(chunk);
      },
    },
    {
      documentation: `If left and right are of primative types, then a direct
          comparison will be performed and a DiffChunk is created. If left and
          right are both arrays, a comparison will be performed between the
          items. If left and right are objects, it will attempt to recursively
          traverse properties common to both objects. Traversal ends when a
          difference is found or there is no more properties to compare.`,
      name: 'diff_',
      args: [
        {
          documentation: 'Value of the left side that is diffed.',
          name: 'left',
        },
        {
          documentation: 'Value of the right side that is diffed.',
          name: 'right',
        },
        {
          documentation: 'Identification information for the diff chunk.',
          name: 'id',
          typeName: 'Identifier',
        },
        {
          documentation: 'The array tracking diff chunks that are produced.',
          name: 'opt_changes',
          typeName: 'Array',
        },
      ],
      returns: '',
      code: function (left, right, id, opt_changes) {
        if (left === undefined || left === null ||
            right === undefined || right === null) {
          if (left !== right)
            this.addChunk_(id, this.DiffStatus.MISSING_DEFINITION, left,
                right, opt_changes);
          return;
        }

        // Determine types and whether a direct comparison can be done.
        var leftType = foam.typeOf(left);
        var rightType = foam.typeOf(right);
        foam.assert(leftType === rightType,
            'Diff: Encountered a type mismatch!');

        // Type is a basic type, perform simple comparison.
        if (leftType === foam.Boolean || leftType === foam.Number ||
            leftType === foam.String ) {
          if (left !== right)
            this.addChunk_(id, this.DiffStatus.VALUES_DIFFER, left,
                right, opt_changes);
          return;
        }

        // Left and right are either Array or Objects at this point.
        if (leftType === foam.Array) {
          this.arrayCmp_(left, right, id, opt_changes);
        } else {
          foam.assert(leftType !== foam.Object && rightType !== foam.Object,
              'Diff: Cannot find class property of object.');

          var leftProps = left.cls_.getAxiomsByClass(foam.core.Property);
          var rightProps = right.cls_.getAxiomsByClass(foam.core.Property);

          // Determine if left and right have the same properties.
          // FUTURE: Relax condition and iterate over sorted collections of
          // left and right properties.
          if (foam.util.compare(leftProps, rightProps) !== 0) {
            // Cannot perform a deep comparison of the objects.
            this.addChunk_(id, this.DiffStatus.VALUES_DIFFER, left,
                right, opt_changes);
            return;
          }

          // leftProp and rightProp are same at this point.
          // Perform diff on each of the objects properties.
          leftProps.forEach(function(prop) {
            var propName = prop.name;
            if (this.excludedProps.includes(propName)) return;

            var nextId = id.clone();
            nextId.leftKey = nextId.rightKey += `.${propName}`;
            this.diff_(left[prop], right[prop], nextId, opt_changes);
          }.bind(this));
        }
      },
    },
    {
      documentation: `Performs a comparison between members of left and
          members of right. If no differences are found between two objects,
          they are considered to be matched and removed from the remaining
          comparisons. Once all members have been compared, a DiffChunk is
          generated for all unmatched members.`,
      name: 'arrayCmp_',
      args: [
        {
          documentation: 'Value of the left side that is diffed.',
          name: 'left',
        },
        {
          documentation: 'Value of the right side that is diffed.',
          name: 'right',
        },
        {
          documentation: 'Identification information for the diff chunk.',
          name: 'id',
          typeName: 'Identifier',
        },
        {
          documentation: 'The array tracking diff chunks that are produced.',
          name: 'opt_changes',
          typeName: 'Array',
        },
      ],
      returns: '',
      code: function arrayCmp_(left, right, id, opt_changes) {
        // Items will be removed from the array once matched.
        // Work on clones to prevent altering original data.
        left = foam.Array.clone(left);
        right = foam.Array.clone(right);

        for (var i = 0; i < left.length; i++) {
          var matched = false; // Used to determine if inner loop broke early.
          for (var j = 0; j < right.length; j++) {
            var leftName = left[i].id;
            var rightName = right[j].id;

            // If names differ, they are definitely not the same.
            if (leftName !== rightName) continue;

            // Both items have no names, or they have same names at this point.
            // Perform a diff with 'changes' so the chunks are not immediately
            // persisted.
            var changes = [];

            var nextId = id.clone();
            nextId.leftKey += `.${i}`;
            nextId.rightKey += `.${j}`;
            this.diff_(left[i], right[j], nextId, changes);

            // No differences found or they have the same name.
            if (changes.length === 0 || leftName && rightName) {
              // If they have same name and changes were found,
              // persist the changes.
              this.chunks_ = this.chunks_.concat(changes);
              matched = true;
              break;
            }

            // Unnamed objects were different at this point.
            if (opt_changes) opt_changes.concat(changes);
          }

          if (matched === true) {
            // A match on the right was found for the item on the left.
            right.splice(j, 1);
          } else {
            this.addChunk_(id, this.DiffStatus.NO_MATCH_ON_RIGHT, left[i],
                undefined, opt_changes);
          }
        }

        // All remaining items in right array need to go into diff chunk now.
        right.forEach(function(rightObj) {
          this.addChunk_(id, this.DiffStatus.NO_MATCH_ON_LEFT, undefined,
              rightObj, opt_changes);
        }.bind(this));
      },
    }
  ],
});
<commit_msg>Making opt_changes non-optional and removing chunks property.<commit_after>// Copyright 2017 The Chromium Authors. ALl rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';

foam.CLASS({
  package: 'org.chromium.webidl',
  name: 'Diff',

  requires: [
    'org.chromium.webidl.DiffChunk',
    'org.chromium.webidl.DiffStatus',
  ],

  documentation: `The diff algorithm that is performed on canonicalized
      definitions.`,

  classes: [
    {
      name: 'Identifier',
      properties: [
        {
          class: 'String',
          documentation: 'Name of Definition the diff is performed on.',
          name: 'name',
        },
        {
          class: 'String',
          documentation: 'Tracks the left path to the property of the AST node.',
          name: 'leftKey',
        },
        {
          class: 'String',
          documentation: 'Tracks the right path to the property of the AST node.',
          name: 'rightKey',
        },
        {
          class: 'Array',
          of: 'String',
          documentation: 'Sources from which left definition is composed.',
          name: 'leftSources',
        },
        {
          class: 'Array',
          of: 'String',
          documentation: 'Sources from which right definition is composed.',
          name: 'rightSources',
        },
      ],
    },
  ],

  properties: [
    {
      class: 'Array',
      of: 'String',
      documentation: `Properties that are ignored during diff. These properties
          are either internal properties used by the program or properties that
          will always be different (e.g. id, sources) by nature.`,
      name: 'excludedProps',
      factory: function() {
        return ['id', 'isCanonical', 'sources', 'source'];
      },
    },
  ],

  methods: [
    {
      documentation: `Expects to receive two maps of canonicalized definitions.
          A diff will be performed for each definition, and an array of
          DiffChunks will be returned for each difference found.`,
      name: 'diff',
      args: [
        {
          documentation: `Map of AST Definition nodes corresponding to a
              source. The key of the map is the name of the definition.
              The definitions are used on the left side of the diff.`,
          name: 'left',
          typeName: 'Object',
        },
        {
          documentation: `Map of AST Definition nodes corresponding to a
              source. The key of the map is the name of the definition.
              The definitions are used on the right side of the diff.`,
          name: 'right',
          typeName: 'Object',
        },
      ],
      returns: 'Array',
      code: function(left, right) {
        var chunks = []; // Array of DiffChunks that are produced from diff.

        // Calculate union of leftKeys and rightKeys.
        var leftKeys = Object.keys(left);
        var rightKeys = Object.keys(right);
        var keys = leftKeys.concat(rightKeys);
        keys = keys.filter(function(key, index) {
          return keys.indexOf(key) === index;
        });

        // Iterate through definitions and perform diff.
        keys.forEach(function(key) {
          // If an Enum or Typedef is defined multiple times in
          // the same source (e.g. WebKit), we will get an array of items.
          // These definitions are retained by Canonicalizer and placed
          // into an array. These definitions should be the same.
          // FUTURE: Handle multi definitions that are NOT the same.
          if (Array.isArray(left[key])) this.dedupDefinition_(left, key);
          if (Array.isArray(right[key])) this.dedupDefinition_(right, key);

          // Perform diff with id object to track path and source.
          var id = this.Identifier.create({
            name: key,
            leftSources: left[key] ? left[key].sources : [],
            rightSources: right[key] ? right[key].sources : [],
          });

          this.diff_(left[key], right[key], id, chunks);
        }.bind(this));

        return chunks;
      },
    },
    {
      documentation: `defnMap[key] should be an array of Definition AST nodes
          with key as the name of the definition. If all definitions are the
          same (i.e. they have the same members), the entry is replaced
          with a reference definition.`,
      name: 'dedupDefinition_',
      args: [
        {
          documentation: 'A map of Definition AST nodes for a given source.',
          name: 'defnMap',
          typeName: 'Object',
        },
        {
          documentation: `Name of the Definition that was defined multiple times
              in the given source.`,
          name: 'key',
          typeName: 'String',
        },
      ],
      returns: '',
      code: function(defnMap, key) {
        var id = this.Identifier.create({name: key});
        var defns = defnMap[key];

        var refDefn = defns[0];
        for (var i = 1; i < defns.length; i++) {
          var changes = [];
          this.diff_(refDefn, defns[i], id, changes);

          if (changes.length !== 0) {
            // Cannot handle different definitions right now.
            delete defnMap[key];
            console.error(`Diff: ${key} was defined multiple times.
                The definitions were not identical!`);
            return;
          }
        }

        // Concatenate the list of sources.
        var sources = defnMap[key].reduce(function(srcArr, def) {
          return srcArr.concat(def.sources);
        }, []);

        // Use first object as reference object.
        defnMap[key] = defnMap[key][0];
        defnMap[key].sources = sources;
      },
    },
    {
      documentation: `Given id, status, and left and right, a DiffChunk is
          created. The change is then placed into the array changes.`,
      name: 'addChunk_',
      args: [
        {
          documentation: 'Identification information for the diff chunk.',
          name: 'id',
          typeName: 'Identifier',
        },
        {
          documentation: 'Status information about the diff chunk.',
          name: 'status',
          typeName: 'org.chromium.webidl.DiffStatus',
        },
        {
          documentation: 'The value of the left side of the diff chunk.',
          name: 'left',
        },
        {
          documentation: 'The value of the right side of the diff chunk.',
          name: 'right',
        },
        {
          documentation: 'The array tracking diff chunks that are produced.',
          name: 'changes',
          typeName: 'Array',
        },
      ],
      returns: '',
      code: function(id, status, left, right, changes) {
        var chunk = this.DiffChunk.create({
          definitionName: id.name,
          status: status,
          leftKey: id.leftKey,
          leftValue: left,
          leftSources: id.leftSources,
          rightKey: id.rightKey,
          rightValue: right,
          rightSources: id.rightSources,
        });
        changes.push(chunk);
      },
    },
    {
      documentation: `If left and right are of primative types, then a direct
          comparison will be performed and a DiffChunk is created. If left and
          right are both arrays, a comparison will be performed between the
          items. If left and right are objects, it will attempt to recursively
          traverse properties common to both objects. Traversal ends when a
          difference is found or there is no more properties to compare.`,
      name: 'diff_',
      args: [
        {
          documentation: 'Value of the left side that is diffed.',
          name: 'left',
        },
        {
          documentation: 'Value of the right side that is diffed.',
          name: 'right',
        },
        {
          documentation: 'Identification information for the diff chunk.',
          name: 'id',
          typeName: 'Identifier',
        },
        {
          documentation: 'The array tracking diff chunks that are produced.',
          name: 'changes',
          typeName: 'Array',
        },
      ],
      returns: '',
      code: function (left, right, id, changes) {
        if (left === undefined || left === null ||
            right === undefined || right === null) {
          if (left !== right)
            this.addChunk_(id, this.DiffStatus.MISSING_DEFINITION, left,
                right, changes);
          return;
        }

        // Determine types and whether a direct comparison can be done.
        var leftType = foam.typeOf(left);
        var rightType = foam.typeOf(right);
        foam.assert(leftType === rightType,
            'Diff: Encountered a type mismatch!');

        // Type is a basic type, perform simple comparison.
        if (leftType === foam.Boolean || leftType === foam.Number ||
            leftType === foam.String ) {
          if (left !== right)
            this.addChunk_(id, this.DiffStatus.VALUES_DIFFER, left,
                right, changes);
          return;
        }

        // Left and right are either Array or Objects at this point.
        if (leftType === foam.Array) {
          this.arrayCmp_(left, right, id, changes);
        } else {
          foam.assert(leftType !== foam.Object && rightType !== foam.Object,
              'Diff: Cannot find class property of object.');

          var leftProps = left.cls_.getAxiomsByClass(foam.core.Property);
          var rightProps = right.cls_.getAxiomsByClass(foam.core.Property);

          // Determine if left and right have the same properties.
          // FUTURE: Relax condition and iterate over sorted collections of
          // left and right properties.
          if (foam.util.compare(leftProps, rightProps) !== 0) {
            // Cannot perform a deep comparison of the objects.
            this.addChunk_(id, this.DiffStatus.VALUES_DIFFER, left,
                right, changes);
            return;
          }

          // leftProp and rightProp are same at this point.
          // Perform diff on each of the objects properties.
          leftProps.forEach(function(prop) {
            var propName = prop.name;
            if (this.excludedProps.includes(propName)) return;

            var nextId = id.clone();
            nextId.leftKey = nextId.rightKey += `.${propName}`;
            this.diff_(left[prop], right[prop], nextId, changes);
          }.bind(this));
        }
      },
    },
    {
      documentation: `Performs a comparison between members of left and
          members of right. If no differences are found between two objects,
          they are considered to be matched and removed from the remaining
          comparisons. Once all members have been compared, a DiffChunk is
          generated for all unmatched members.`,
      name: 'arrayCmp_',
      args: [
        {
          documentation: 'Value of the left side that is diffed.',
          name: 'left',
        },
        {
          documentation: 'Value of the right side that is diffed.',
          name: 'right',
        },
        {
          documentation: 'Identification information for the diff chunk.',
          name: 'id',
          typeName: 'Identifier',
        },
        {
          documentation: 'The array tracking diff chunks that are produced.',
          name: 'changes',
          typeName: 'Array',
        },
      ],
      returns: '',
      code: function arrayCmp_(left, right, id, changes) {
        // Items will be removed from the array once matched.
        // Work on clones to prevent altering original data.
        left = foam.Array.clone(left);
        right = foam.Array.clone(right);

        for (var i = 0; i < left.length; i++) {
          var matched = false; // Used to determine if inner loop broke early.
          for (var j = 0; j < right.length; j++) {
            var leftName = left[i].id;
            var rightName = right[j].id;

            // If names differ, they are definitely not the same.
            if (leftName !== rightName) continue;

            // Both items have no names, or they have same names at this point.
            // Perform a diff with 'changes' so the chunks are not immediately
            // persisted.
            var tempChanges = [];

            var nextId = id.clone();
            nextId.leftKey += `.${i}`;
            nextId.rightKey += `.${j}`;
            this.diff_(left[i], right[j], nextId, tempChanges);

            // No differences found or they have the same name.
            if (tempChanges.length === 0 || leftName && rightName) {
              // If they have same name and changes were found,
              // push changes from tempChanges into this.chunks.
              // This is done instead of Array.concat to prevent
              // creating a new array (invalidating all other references).
              Array.prototype.push.apply(changes, tempChanges);
              matched = true;
              break;
            }
          }

          if (matched === true) {
            // A match on the right was found for the item on the left.
            right.splice(j, 1);
          } else {
            this.addChunk_(id, this.DiffStatus.NO_MATCH_ON_RIGHT, left[i],
                undefined, changes);
          }
        }

        // All remaining items in right array need to go into diff chunk now.
        right.forEach(function(rightObj) {
          this.addChunk_(id, this.DiffStatus.NO_MATCH_ON_LEFT, undefined,
              rightObj, changes);
        }.bind(this));
      },
    }
  ],
});
<|endoftext|>


<commit_before>const extractObject = require('../extract-object.js')
const similarityPlugin = require('./similar-text-plugin.js')
const meanAggregator = require('../aggregators/mean.js')
const utils = require('../utils.js')

/**
 * Deletes all objects from chat array inside chat object not in timerange
 * For example:
 * const intervallChat = {
 * chat: [
 *   {
 *     'type': 'message',
 *     'text': 'Hello world',
 *     'channel': 'C2147483705',
 *     'user': 'U2147483697',
 *     'ts': 300
 *   },
 *   {
 *     'type': 'message',
 *     'text': 'Hello underworld',
 *     'channel': 'C2147483705',
 *     'user': 'U2147483697',
 *     'ts': 500
 *   }
 *  ]
 * }
 *
 * using: deleteChatMessagesNotInTimeIntervall(intervallChat, 400, 1000)
 * Deletes all chatobjects not in the ts range of 400 and 100
 */
function deleteChatMessagesNotInTimeIntervall (chat, startTime, endTime) {
  let transformedChat = chat
  for (let chatObj of transformedChat.chat) {
    if ((chatObj.ts < startTime) || (chatObj.ts > endTime)) {
      var index = transformedChat.chat.indexOf(chatObj)
      transformedChat.chat[index] = null
    }
  }
  transformedChat = transformedChat.chat.filter(Boolean)
  return transformedChat
}

/**
 * Takes as an input an object of the form:
 *
 * @param chat - an object that is a chat
 * @param text - an object that is a text
 * @return score - between 1.0 and 0.0. This is the mean value of all the
 * similarities between every single chat message and text.
 */
function chatComparisonPlugin (chat, text, params) {
  let startTime = (params && params['startTime']) || 1
  let endTime = (params && params['endTime']) || 9999999999
  let intervallChat = deleteChatMessagesNotInTimeIntervall(chat, startTime, endTime)
  let [messageText, e1] = extractObject(intervallChat, 'chat[].text')

  utils.isTimestamp(startTime)
  utils.isTimestamp(endTime)

  if ((e1 !== null) && (e1.constructor === Error)) {
    throw new Error('Error extracting text from chat.')
  }

  utils.arrayNotEmpty(messageText)
  utils.isValidString(text)
  var singleMessageScores = []
  for (let message of messageText) {
    if ((message !== undefined) && (typeof (message) === 'string')) {
      singleMessageScores.push(similarityPlugin(message, text))
    }
  }

  return meanAggregator.create('*').eval(singleMessageScores)
}

module.exports = chatComparisonPlugin
<commit_msg>user filter from chat<commit_after>const extractObject = require('../extract-object.js')
const similarityPlugin = require('./similar-text-plugin.js')
const meanAggregator = require('../aggregators/mean.js')
const utils = require('../utils.js')

/**
 * Deletes all objects from chat array inside chat object not in timerange
 * For example:
 * const intervallChat = {
 * chat: [
 *   {
 *     'type': 'message',
 *     'text': 'Hello world',
 *     'channel': 'C2147483705',
 *     'user': 'U2147483697',
 *     'ts': 300
 *   },
 *   {
 *     'type': 'message',
 *     'text': 'Hello underworld',
 *     'channel': 'C2147483705',
 *     'user': 'U2147483697',
 *     'ts': 500
 *   }
 *  ]
 * }
 *
 * using: deleteChatMessagesNotInTimeIntervall(intervallChat, 400, 1000)
 * Deletes all chatobjects not in the ts range of 400 and 100
 */
function deleteChatMessagesNotInTimeIntervall (chat, startTime, endTime) {
  let transformedChat = chat
  for (let chatObj of transformedChat.chat) {
    if ((chatObj.ts < startTime) || (chatObj.ts > endTime)) {
      var index = transformedChat.chat.indexOf(chatObj)
      transformedChat.chat[index] = null
    }
  }
  transformedChat = transformedChat.chat.filter(Boolean)
  return transformedChat
}

/**
 *
 */
function deleteChatMessagesNotFromUser (chat, user) {
  let transformedChat = chat
  for (let chatObj of transformedChat.chat) {
    if (chatObj.user !== user) {
      var index = transformedChat.chat.indexOf(chatObj)
      transformedChat.chat[index] = null
    }
  }
  transformedChat = transformedChat.chat.filter(Boolean)
  return transformedChat
}

/**
 * Takes as an input an object of the form:
 *
 * @param chat - an object that is a chat
 * @param text - an object that is a text
 * @return score - between 1.0 and 0.0. This is the mean value of all the
 * similarities between every single chat message and text.
 */
function chatComparisonPlugin (chat, text, params) {
  let startTime = (params && params['startTime']) || 1
  let endTime = (params && params['endTime']) || 9999999999
  let user = (params && params['user']) || '*'

  utils.isValidString(user)
  utils.isTimestamp(startTime)
  utils.isTimestamp(endTime)

  let intervallChat = deleteChatMessagesNotInTimeIntervall(chat, startTime, endTime)
  let userAndIntervallChat = deleteChatMessagesNotFromUser(intervallChat, user)
  let finalTransChat = (user === '*' ? userAndIntervallChat : intervallChat)

  let [messageText, e1] = extractObject(finalTransChat, 'chat[].text')

  if ((e1 !== null) && (e1.constructor === Error)) {
    throw new Error('Error extracting text from chat.')
  }

  utils.arrayNotEmpty(messageText)
  utils.isValidString(text)
  var singleMessageScores = []
  for (let message of messageText) {
    if ((message !== undefined) && (typeof (message) === 'string')) {
      singleMessageScores.push(similarityPlugin(message, text))
    }
  }

  return meanAggregator.create('*').eval(singleMessageScores)
}

module.exports = chatComparisonPlugin
<|endoftext|>