<commit_before>import * as messages from "../../messages";
import Remaps from "./lib/remaps";
import extend from "lodash/object/extend";
import object from "../../helpers/object";
import * as util from  "../../util";
import * as t from "../../types";

/**
 * [Please add a description.]
 */

var metadataVisitor = {

  /**
   * [Please add a description.]
   */

  ModuleDeclaration: {
    enter(node, parent, scope, formatter) {
      if (node.source) {
        node.source.value = formatter.file.resolveModuleSource(node.source.value);
        formatter.addScope(this);
      }
    }
  },

  /**
   * [Please add a description.]
   */

  ImportDeclaration: {
    exit(node, parent, scope, formatter) {
      formatter.hasLocalImports = true;

      var specifiers = [];
      var imported = [];
      formatter.metadata.imports.push({
        source: node.source.value,
        imported,
        specifiers
      });

      for (var specifier of (this.get("specifiers"): Array)) {
        var ids = specifier.getBindingIdentifiers();
        extend(formatter.localImports, ids);

        var local = specifier.node.local.name;

        if (specifier.isImportDefaultSpecifier()) {
          imported.push("default");
          specifiers.push({
            kind: "named",
            imported: "default",
            local
          });
        }

        if (specifier.isImportSpecifier()) {
          var importedName = specifier.node.imported.name;
          imported.push(importedName);
          specifiers.push({
            kind: "named",
            imported: importedName,
            local
          });
        }

        if (specifier.isImportNamespaceSpecifier()) {
          imported.push("*");
          specifiers.push({
            kind: "namespace",
            local
          });
        }
      }
    }
  },

  /**
   * [Please add a description.]
   */

  ExportDeclaration(node, parent, scope, formatter) {
    formatter.hasLocalExports = true;

    var source = node.source ? node.source.value : null;
    var exports = formatter.metadata.exports;

    // export function foo() {}
    // export var foo = "bar";
    var declar = this.get("declaration");
    if (declar.isStatement()) {
      var bindings = declar.getBindingIdentifiers();

      for (var name in bindings) {
        var binding = bindings[name];
        formatter._addExport(name, binding);

        exports.exported.push(name);
        exports.specifiers.push({
          kind: "local",
          local: name,
          exported: this.isExportDefaultDeclaration() ? "default" : name
        });
      }
    }

    if (this.isExportNamedDeclaration() && node.specifiers) {
      for (var specifier of (node.specifiers: Array)) {
        var exported = specifier.exported.name;
        exports.exported.push(exported);

        // export foo from "bar";
        if (t.isExportDefaultSpecifier(specifier)) {
          exports.specifiers.push({
            kind: "external",
            local: exported,
            exported,
            source
          });
        }

        // export * as foo from "bar";
        if (t.isExportNamespaceSpecifier(specifier)) {
          exports.specifiers.push({
            kind: "external-namespace",
            exported,
            source
          });
        }

        var local = specifier.local;
        if (!local) continue;

        formatter._addExport(local.name, specifier.exported);

        // export { foo } from "bar";
        // export { foo as bar } from "bar";
        if (source) {
          exports.specifiers.push({
            kind: "external",
            local: local.name,
            exported,
            source
          });
        }

        // export { foo };
        // export { foo as bar };
        if (!source) {
          exports.specifiers.push({
            kind: "local",
            local: local.name,
            exported
          });
        }
      }
    }

    // export * from "bar";
    if (this.isExportAllDeclaration()) {
      exports.specifiers.push({
        kind: "external-all",
        source
      });
    }

    if (!t.isExportDefaultDeclaration(node) && !declar.isTypeAlias()) {
      var onlyDefault = node.specifiers && node.specifiers.length === 1 && t.isSpecifierDefault(node.specifiers[0]);
      if (!onlyDefault) {
        formatter.hasNonDefaultExports = true;
      }
    }
  },

  /**
   * [Please add a description.]
   */

  Scope(node, parent, scope, formatter) {
    if (!formatter.isLoose()) {
      this.skip();
    }
  }
};

/**
 * [Please add a description.]
 */

export default class DefaultFormatter {
  constructor(file) {
    // object containg all module sources with the scope that they're contained in
    this.sourceScopes = object();

    // ids for use in module ids
    this.defaultIds = object();
    this.ids        = object();

    // contains reference aliases for live bindings
    this.remaps = new Remaps(file, this);

    this.scope = file.scope;
    this.file  = file;

    this.hasNonDefaultExports = false;

    this.hasLocalExports = false;
    this.hasLocalImports = false;

    this.localExports = object();
    this.localImports = object();

    this.metadata = file.metadata.modules;
    this.getMetadata();
  }

  /**
   * [Please add a description.]
   */

  addScope(path) {
    var source = path.node.source && path.node.source.value;
    if (!source) return;

    var existingScope = this.sourceScopes[source];
    if (existingScope && existingScope !== path.scope) {
      throw path.errorWithNode(messages.get("modulesDuplicateDeclarations"));
    }

    this.sourceScopes[source] = path.scope;
  }

  /**
   * [Please add a description.]
   */

  isModuleType(node, type) {
    var modules = this.file.dynamicImportTypes[type];
    return modules && modules.indexOf(node) >= 0;
  }

  /**
   * [Please add a description.]
   */

  transform() {
    this.remapAssignments();
  }

  /**
   * [Please add a description.]
   */

  doDefaultExportInterop(node) {
    return (t.isExportDefaultDeclaration(node) || t.isSpecifierDefault(node)) && !this.noInteropRequireExport && !this.hasNonDefaultExports;
  }

  /**
   * [Please add a description.]
   */

  getMetadata() {
    var has = false;
    for (var node of (this.file.ast.program.body: Array)) {
      if (t.isModuleDeclaration(node)) {
        has = true;
        break;
      }
    }
    if (has || this.isLoose()) {
      this.file.path.traverse(metadataVisitor, this);
    }
  }

  /**
   * [Please add a description.]
   */

  remapAssignments() {
    if (this.hasLocalExports || this.hasLocalImports) {
      this.remaps.run();
    }
  }

  /**
   * [Please add a description.]
   */

  remapExportAssignment(node, exported) {
    var assign = node;

    for (var i = 0; i < exported.length; i++) {
      assign = t.assignmentExpression(
        "=",
        t.memberExpression(t.identifier("exports"), exported[i]),
        assign
      );
    }

    return assign;
  }

  /**
   * [Please add a description.]
   */

  _addExport(name, exported) {
    var info = this.localExports[name] = this.localExports[name] || {
      binding: this.scope.getBindingIdentifier(name),
      exported: []
    };
    info.exported.push(exported);
  }

  /**
   * [Please add a description.]
   */

  getExport(node, scope) {
    if (!t.isIdentifier(node)) return;

    var local = this.localExports[node.name];
    if (local && local.binding === scope.getBindingIdentifier(node.name)) {
      return local.exported;
    }
  }

  /**
   * [Please add a description.]
   */

  getModuleName() {
    var opts = this.file.opts;
    // moduleId is n/a if a `getModuleId()` is provided
    if (opts.moduleId != null && !opts.getModuleId) {
      return opts.moduleId;
    }

    var filenameRelative = opts.filenameRelative;
    var moduleName = "";

    if (opts.moduleRoot != null) {
      moduleName = opts.moduleRoot + "/";
    }

    if (!opts.filenameRelative) {
      return moduleName + opts.filename.replace(/^\//, "");
    }

    if (opts.sourceRoot != null) {
      // remove sourceRoot from filename
      var sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "\/?");
      filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
    }

    if (!opts.keepModuleIdExtensions) {
      // remove extension
      filenameRelative = filenameRelative.replace(/\.(\w*?)$/, "");
    }

    moduleName += filenameRelative;

    // normalize path separators
    moduleName = moduleName.replace(/\\/g, "/");

    if (opts.getModuleId) {
      // If return is falsy, assume they want us to use our generated default name
      return opts.getModuleId(moduleName) || moduleName;
    } else {
      return moduleName;
    }
  }

  /**
   * [Please add a description.]
   */

  _pushStatement(ref, nodes) {
    if (t.isClass(ref) || t.isFunction(ref)) {
      if (ref.id) {
        nodes.push(t.toStatement(ref));
        ref = ref.id;
      }
    }

    return ref;
  }

  /**
   * [Please add a description.]
   */

  _hoistExport(declar, assign, priority) {
    if (t.isFunctionDeclaration(declar)) {
      assign._blockHoist = priority || 2;
    }

    return assign;
  }

  /**
   * [Please add a description.]
   */

  getExternalReference(node, nodes) {
    var ids = this.ids;
    var id = node.source.value;

    if (ids[id]) {
      return ids[id];
    } else {
      return this.ids[id] = this._getExternalReference(node, nodes);
    }
  }

  /**
   * [Please add a description.]
   */

  checkExportIdentifier(node) {
    if (node.loc && t.isIdentifier(node, { name: "__esModule" })) {
      throw this.file.errorWithNode(node, messages.get("modulesIllegalExportName", node.name));
    }
  }

  /**
   * [Please add a description.]
   */

  exportAllDeclaration(node, nodes) {
    var ref = this.getExternalReference(node, nodes);
    nodes.push(this.buildExportsWildcard(ref, node));
  }

  /**
   * [Please add a description.]
   */

  isLoose() {
    return this.file.isLoose("es6.modules");
  }

  /**
   * [Please add a description.]
   */

  exportSpecifier(specifier, node, nodes) {
    if (node.source) {
      var ref = this.getExternalReference(node, nodes);

      if (specifier.local.name === "default" && !this.noInteropRequireExport) {
        // importing a default so we need to normalize it
        ref = t.callExpression(this.file.addHelper("interop-require"), [ref]);
      } else {
        ref = t.memberExpression(ref, specifier.local);

        if (!this.isLoose()) {
          nodes.push(this.buildExportsFromAssignment(specifier.exported, ref, node));
          return;
        }
      }

      // export { foo } from "test";
      nodes.push(this.buildExportsAssignment(specifier.exported, ref, node));
    } else {
      // export { foo };
      nodes.push(this.buildExportsAssignment(specifier.exported, specifier.local, node));
    }
  }

  /**
   * [Please add a description.]
   */

  buildExportsWildcard(objectIdentifier) {
    return t.expressionStatement(t.callExpression(this.file.addHelper("defaults"), [
      t.identifier("exports"),
      t.callExpression(this.file.addHelper("interop-require-wildcard"), [objectIdentifier])
    ]));
  }

  /**
   * [Please add a description.]
   */

  buildExportsFromAssignment(id, init) {
    this.checkExportIdentifier(id);
    return util.template("exports-from-assign", {
      INIT: init,
      ID:   t.literal(id.name)
    }, true);
  }

  /**
   * [Please add a description.]
   */

  buildExportsAssignment(id, init) {
    this.checkExportIdentifier(id);
    return util.template("exports-assign", {
      VALUE: init,
      KEY:   id
    }, true);
  }

  /**
   * [Please add a description.]
   */

  exportDeclaration(node, nodes) {
    var declar = node.declaration;

    var id = declar.id;

    if (t.isExportDefaultDeclaration(node)) {
      id = t.identifier("default");
    }

    var assign;

    if (t.isVariableDeclaration(declar)) {
      for (var i = 0; i < declar.declarations.length; i++) {
        var decl = declar.declarations[i];

        decl.init = this.buildExportsAssignment(decl.id, decl.init, node).expression;

        var newDeclar = t.variableDeclaration(declar.kind, [decl]);
        if (i === 0) t.inherits(newDeclar, declar);
        nodes.push(newDeclar);
      }
    } else {
      var ref = declar;

      if (t.isFunctionDeclaration(declar) || t.isClassDeclaration(declar)) {
        ref = declar.id;
        nodes.push(declar);
      }

      assign = this.buildExportsAssignment(id, ref, node);

      nodes.push(assign);

      this._hoistExport(declar, assign);
    }
  }
}
<commit_msg>Revert "don't throw error on locationless illegal export name"<commit_after>import * as messages from "../../messages";
import Remaps from "./lib/remaps";
import extend from "lodash/object/extend";
import object from "../../helpers/object";
import * as util from  "../../util";
import * as t from "../../types";

/**
 * [Please add a description.]
 */

var metadataVisitor = {

  /**
   * [Please add a description.]
   */

  ModuleDeclaration: {
    enter(node, parent, scope, formatter) {
      if (node.source) {
        node.source.value = formatter.file.resolveModuleSource(node.source.value);
        formatter.addScope(this);
      }
    }
  },

  /**
   * [Please add a description.]
   */

  ImportDeclaration: {
    exit(node, parent, scope, formatter) {
      formatter.hasLocalImports = true;

      var specifiers = [];
      var imported = [];
      formatter.metadata.imports.push({
        source: node.source.value,
        imported,
        specifiers
      });

      for (var specifier of (this.get("specifiers"): Array)) {
        var ids = specifier.getBindingIdentifiers();
        extend(formatter.localImports, ids);

        var local = specifier.node.local.name;

        if (specifier.isImportDefaultSpecifier()) {
          imported.push("default");
          specifiers.push({
            kind: "named",
            imported: "default",
            local
          });
        }

        if (specifier.isImportSpecifier()) {
          var importedName = specifier.node.imported.name;
          imported.push(importedName);
          specifiers.push({
            kind: "named",
            imported: importedName,
            local
          });
        }

        if (specifier.isImportNamespaceSpecifier()) {
          imported.push("*");
          specifiers.push({
            kind: "namespace",
            local
          });
        }
      }
    }
  },

  /**
   * [Please add a description.]
   */

  ExportDeclaration(node, parent, scope, formatter) {
    formatter.hasLocalExports = true;

    var source = node.source ? node.source.value : null;
    var exports = formatter.metadata.exports;

    // export function foo() {}
    // export var foo = "bar";
    var declar = this.get("declaration");
    if (declar.isStatement()) {
      var bindings = declar.getBindingIdentifiers();

      for (var name in bindings) {
        var binding = bindings[name];
        formatter._addExport(name, binding);

        exports.exported.push(name);
        exports.specifiers.push({
          kind: "local",
          local: name,
          exported: this.isExportDefaultDeclaration() ? "default" : name
        });
      }
    }

    if (this.isExportNamedDeclaration() && node.specifiers) {
      for (var specifier of (node.specifiers: Array)) {
        var exported = specifier.exported.name;
        exports.exported.push(exported);

        // export foo from "bar";
        if (t.isExportDefaultSpecifier(specifier)) {
          exports.specifiers.push({
            kind: "external",
            local: exported,
            exported,
            source
          });
        }

        // export * as foo from "bar";
        if (t.isExportNamespaceSpecifier(specifier)) {
          exports.specifiers.push({
            kind: "external-namespace",
            exported,
            source
          });
        }

        var local = specifier.local;
        if (!local) continue;

        formatter._addExport(local.name, specifier.exported);

        // export { foo } from "bar";
        // export { foo as bar } from "bar";
        if (source) {
          exports.specifiers.push({
            kind: "external",
            local: local.name,
            exported,
            source
          });
        }

        // export { foo };
        // export { foo as bar };
        if (!source) {
          exports.specifiers.push({
            kind: "local",
            local: local.name,
            exported
          });
        }
      }
    }

    // export * from "bar";
    if (this.isExportAllDeclaration()) {
      exports.specifiers.push({
        kind: "external-all",
        source
      });
    }

    if (!t.isExportDefaultDeclaration(node) && !declar.isTypeAlias()) {
      var onlyDefault = node.specifiers && node.specifiers.length === 1 && t.isSpecifierDefault(node.specifiers[0]);
      if (!onlyDefault) {
        formatter.hasNonDefaultExports = true;
      }
    }
  },

  /**
   * [Please add a description.]
   */

  Scope(node, parent, scope, formatter) {
    if (!formatter.isLoose()) {
      this.skip();
    }
  }
};

/**
 * [Please add a description.]
 */

export default class DefaultFormatter {
  constructor(file) {
    // object containg all module sources with the scope that they're contained in
    this.sourceScopes = object();

    // ids for use in module ids
    this.defaultIds = object();
    this.ids        = object();

    // contains reference aliases for live bindings
    this.remaps = new Remaps(file, this);

    this.scope = file.scope;
    this.file  = file;

    this.hasNonDefaultExports = false;

    this.hasLocalExports = false;
    this.hasLocalImports = false;

    this.localExports = object();
    this.localImports = object();

    this.metadata = file.metadata.modules;
    this.getMetadata();
  }

  /**
   * [Please add a description.]
   */

  addScope(path) {
    var source = path.node.source && path.node.source.value;
    if (!source) return;

    var existingScope = this.sourceScopes[source];
    if (existingScope && existingScope !== path.scope) {
      throw path.errorWithNode(messages.get("modulesDuplicateDeclarations"));
    }

    this.sourceScopes[source] = path.scope;
  }

  /**
   * [Please add a description.]
   */

  isModuleType(node, type) {
    var modules = this.file.dynamicImportTypes[type];
    return modules && modules.indexOf(node) >= 0;
  }

  /**
   * [Please add a description.]
   */

  transform() {
    this.remapAssignments();
  }

  /**
   * [Please add a description.]
   */

  doDefaultExportInterop(node) {
    return (t.isExportDefaultDeclaration(node) || t.isSpecifierDefault(node)) && !this.noInteropRequireExport && !this.hasNonDefaultExports;
  }

  /**
   * [Please add a description.]
   */

  getMetadata() {
    var has = false;
    for (var node of (this.file.ast.program.body: Array)) {
      if (t.isModuleDeclaration(node)) {
        has = true;
        break;
      }
    }
    if (has || this.isLoose()) {
      this.file.path.traverse(metadataVisitor, this);
    }
  }

  /**
   * [Please add a description.]
   */

  remapAssignments() {
    if (this.hasLocalExports || this.hasLocalImports) {
      this.remaps.run();
    }
  }

  /**
   * [Please add a description.]
   */

  remapExportAssignment(node, exported) {
    var assign = node;

    for (var i = 0; i < exported.length; i++) {
      assign = t.assignmentExpression(
        "=",
        t.memberExpression(t.identifier("exports"), exported[i]),
        assign
      );
    }

    return assign;
  }

  /**
   * [Please add a description.]
   */

  _addExport(name, exported) {
    var info = this.localExports[name] = this.localExports[name] || {
      binding: this.scope.getBindingIdentifier(name),
      exported: []
    };
    info.exported.push(exported);
  }

  /**
   * [Please add a description.]
   */

  getExport(node, scope) {
    if (!t.isIdentifier(node)) return;

    var local = this.localExports[node.name];
    if (local && local.binding === scope.getBindingIdentifier(node.name)) {
      return local.exported;
    }
  }

  /**
   * [Please add a description.]
   */

  getModuleName() {
    var opts = this.file.opts;
    // moduleId is n/a if a `getModuleId()` is provided
    if (opts.moduleId != null && !opts.getModuleId) {
      return opts.moduleId;
    }

    var filenameRelative = opts.filenameRelative;
    var moduleName = "";

    if (opts.moduleRoot != null) {
      moduleName = opts.moduleRoot + "/";
    }

    if (!opts.filenameRelative) {
      return moduleName + opts.filename.replace(/^\//, "");
    }

    if (opts.sourceRoot != null) {
      // remove sourceRoot from filename
      var sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "\/?");
      filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
    }

    if (!opts.keepModuleIdExtensions) {
      // remove extension
      filenameRelative = filenameRelative.replace(/\.(\w*?)$/, "");
    }

    moduleName += filenameRelative;

    // normalize path separators
    moduleName = moduleName.replace(/\\/g, "/");

    if (opts.getModuleId) {
      // If return is falsy, assume they want us to use our generated default name
      return opts.getModuleId(moduleName) || moduleName;
    } else {
      return moduleName;
    }
  }

  /**
   * [Please add a description.]
   */

  _pushStatement(ref, nodes) {
    if (t.isClass(ref) || t.isFunction(ref)) {
      if (ref.id) {
        nodes.push(t.toStatement(ref));
        ref = ref.id;
      }
    }

    return ref;
  }

  /**
   * [Please add a description.]
   */

  _hoistExport(declar, assign, priority) {
    if (t.isFunctionDeclaration(declar)) {
      assign._blockHoist = priority || 2;
    }

    return assign;
  }

  /**
   * [Please add a description.]
   */

  getExternalReference(node, nodes) {
    var ids = this.ids;
    var id = node.source.value;

    if (ids[id]) {
      return ids[id];
    } else {
      return this.ids[id] = this._getExternalReference(node, nodes);
    }
  }

  /**
   * [Please add a description.]
   */

  checkExportIdentifier(node) {
    if (t.isIdentifier(node, { name: "__esModule" })) {
      throw this.file.errorWithNode(node, messages.get("modulesIllegalExportName", node.name));
    }
  }

  /**
   * [Please add a description.]
   */

  exportAllDeclaration(node, nodes) {
    var ref = this.getExternalReference(node, nodes);
    nodes.push(this.buildExportsWildcard(ref, node));
  }

  /**
   * [Please add a description.]
   */

  isLoose() {
    return this.file.isLoose("es6.modules");
  }

  /**
   * [Please add a description.]
   */

  exportSpecifier(specifier, node, nodes) {
    if (node.source) {
      var ref = this.getExternalReference(node, nodes);

      if (specifier.local.name === "default" && !this.noInteropRequireExport) {
        // importing a default so we need to normalize it
        ref = t.callExpression(this.file.addHelper("interop-require"), [ref]);
      } else {
        ref = t.memberExpression(ref, specifier.local);

        if (!this.isLoose()) {
          nodes.push(this.buildExportsFromAssignment(specifier.exported, ref, node));
          return;
        }
      }

      // export { foo } from "test";
      nodes.push(this.buildExportsAssignment(specifier.exported, ref, node));
    } else {
      // export { foo };
      nodes.push(this.buildExportsAssignment(specifier.exported, specifier.local, node));
    }
  }

  /**
   * [Please add a description.]
   */

  buildExportsWildcard(objectIdentifier) {
    return t.expressionStatement(t.callExpression(this.file.addHelper("defaults"), [
      t.identifier("exports"),
      t.callExpression(this.file.addHelper("interop-require-wildcard"), [objectIdentifier])
    ]));
  }

  /**
   * [Please add a description.]
   */

  buildExportsFromAssignment(id, init) {
    this.checkExportIdentifier(id);
    return util.template("exports-from-assign", {
      INIT: init,
      ID:   t.literal(id.name)
    }, true);
  }

  /**
   * [Please add a description.]
   */

  buildExportsAssignment(id, init) {
    this.checkExportIdentifier(id);
    return util.template("exports-assign", {
      VALUE: init,
      KEY:   id
    }, true);
  }

  /**
   * [Please add a description.]
   */

  exportDeclaration(node, nodes) {
    var declar = node.declaration;

    var id = declar.id;

    if (t.isExportDefaultDeclaration(node)) {
      id = t.identifier("default");
    }

    var assign;

    if (t.isVariableDeclaration(declar)) {
      for (var i = 0; i < declar.declarations.length; i++) {
        var decl = declar.declarations[i];

        decl.init = this.buildExportsAssignment(decl.id, decl.init, node).expression;

        var newDeclar = t.variableDeclaration(declar.kind, [decl]);
        if (i === 0) t.inherits(newDeclar, declar);
        nodes.push(newDeclar);
      }
    } else {
      var ref = declar;

      if (t.isFunctionDeclaration(declar) || t.isClassDeclaration(declar)) {
        ref = declar.id;
        nodes.push(declar);
      }

      assign = this.buildExportsAssignment(id, ref, node);

      nodes.push(assign);

      this._hoistExport(declar, assign);
    }
  }
}
<|endoftext|>


<commit_before>dbpatterns.views.Document = Backbone.View.extend({

    messages: {
        save: "The document was saved successfully",
        rename: "The document was renamed successfully."
    },

    el: "article#document",

    events: {
        "click .edit-title": "rename",
        "click .edit-document": "show_settings_form",
        "click .save-document": "save_document",
        "click .export": "export_document",
        "click .show": "show_document",
        "click #show-comments": "render_comments"
    },

    shortcuts: {
        "option+r": "rename",
        "option+s": "save_document",
        "esc": "hide_comments"
    },

    settings_form_template: $("#document-edit-template").html(),

    initialize: function () {
        _.extend(this, new Backbone.Shortcuts);
        this.delegateShortcuts();

        // bindings
        this.model.on("change:title", this.render_title, this);
        this.model.socket.on("enter", this.enter_room.bind(this));

        // sub views
        this.entities_view = new dbpatterns.views.Entities({
            model: this.model.entities,
            app_view: this
        });
        this.comments_view = null; // it's lazy.
    },

    render_title: function () {
        this.$el.find("header h1").html(this.model.escape("title"));
        window.document.title = this.model.get("title");
        return this;
    },

    rename: function () {

        var title = window.prompt("Title", this.model.get("title"));

        if (!title) {
            return false;
        }

        this.model.set("title", title);
        dbpatterns.notifications.trigger("flash", this.messages.rename);
        return this;
    },

    save_document: function (callback) {
        this.model.save().success(function () {
            dbpatterns.notifications.trigger("flash", this.messages.save);
            callback && callback();
        }.bind(this));
    },

    render_comments: function () {

        if (this.comments_view) {
            this.comments_view.show();
            return;
        }

        this.comments_view = (new dbpatterns.views.Comments({
            document: this.model
        })).render();

        return false;

    },

    hide_comments: function () {
        if (this.comments_view) {
            this.comments_view.hide();
        }
    },

    export_document: function () {
        var exporter_link = $(event.target);
        var dialog = (new dbpatterns.views.ExportDialog({
            title: exporter_link.html(),
            url: exporter_link.attr("href")
        }));
        if (this.options.edit) {
            this.save_document(function () {
                dialog.render();
            }.bind(this));
        } else {
            dialog.render();
        }
        return false;
    },

    show_document: function (event) {
        this.save_document(_.delay(function () {
            window.location = $(event.target).attr("href");
        }, 500));
        return false;
    },

    show_settings_form: function () {
        (new dbpatterns.views.DocumentEditDialog({
            "form": _.template(this.settings_form_template, this),
            "model": this.model,
            "title": "Document Settings"
        })).success(function () {
            this.save_document();
            return true;
        }.bind(this)).render();
    },

    enter_room: function (data) {
        if (this.options.edit) {
            new dbpatterns.views.Room({
                model: new dbpatterns.models.Room(data, {
                    socket: this.model.socket
                })
            }).render();
        }
    }
});

dbpatterns.views.DocumentEditDialog = dbpatterns.views.FormDialog.extend({
    tagName: "div",
    className: "settings",
    draggable: false,

    initialize: function () {
        dbpatterns.views.FormDialog.prototype.initialize.apply(this);
        this.on("render", this.show_assignees)
    },

    show_assignees: function () {

        this.assignees = new dbpatterns.collections.Assignees(this.model.get("assignees"));
        var assignees_view = new dbpatterns.views.AssigneesView({
            model: this.assignees
        });
        assignees_view.render();
    },

    load_data: function () {

        this.form.find("#title").val(this.model.get("title"));

        if (this.model.get("is_public")) {
            this.form.find("#is_public").attr("checked", "checked");
        } else {
            this.form.find("#is_private").attr("checked", "checked");
        }
    },

    save_data: function () {
        this.model.set({
            "title": this.form.find("#title").val(),
            "is_public": this.form.find("#is_public").is(":checked"),
            "assignees": this.assignees.toJSON()
        });
    }
});<commit_msg>Document settings modal show bug was fixed<commit_after>dbpatterns.views.Document = Backbone.View.extend({

    messages: {
        save: "The document was saved successfully",
        rename: "The document was renamed successfully."
    },

    el: "article#document",

    events: {
        "click .edit-title": "rename",
        "click .edit-document": "show_settings_form",
        "click .save-document": "save_document",
        "click .export": "export_document",
        "click .show": "show_document",
        "click #show-comments": "render_comments"
    },

    shortcuts: {
        "option+r": "rename",
        "option+s": "save_document",
        "esc": "hide_comments"
    },

    settings_form_template: $("#document-edit-template").html(),

    initialize: function () {
        _.extend(this, new Backbone.Shortcuts);
        this.delegateShortcuts();

        // bindings
        this.model.on("change:title", this.render_title, this);
        this.model.socket.on("enter", this.enter_room.bind(this));

        // sub views
        this.entities_view = new dbpatterns.views.Entities({
            model: this.model.entities,
            app_view: this
        });
        this.comments_view = null; // it's lazy.
    },

    render_title: function () {
        this.$el.find("header h1").html(this.model.escape("title"));
        window.document.title = this.model.get("title");
        return this;
    },

    rename: function () {

        var title = window.prompt("Title", this.model.get("title"));

        if (!title) {
            return false;
        }

        this.model.set("title", title);
        dbpatterns.notifications.trigger("flash", this.messages.rename);
        return this;
    },

    save_document: function (callback) {
        this.model.save().success(function () {
            dbpatterns.notifications.trigger("flash", this.messages.save);
            callback && callback();
        }.bind(this));
    },

    render_comments: function () {

        if (this.comments_view) {
            this.comments_view.show();
            return;
        }

        this.comments_view = (new dbpatterns.views.Comments({
            document: this.model
        })).render();

        return false;

    },

    hide_comments: function () {
        if (this.comments_view) {
            this.comments_view.hide();
        }
    },

    export_document: function () {
        var exporter_link = $(event.target);
        var dialog = (new dbpatterns.views.ExportDialog({
            title: exporter_link.html(),
            url: exporter_link.attr("href")
        }));
        if (this.options.edit) {
            this.save_document(function () {
                dialog.render();
            }.bind(this));
        } else {
            dialog.render();
        }
        return false;
    },

    show_document: function (event) {
        this.save_document(_.delay(function () {
            window.location = $(event.target).attr("href");
        }, 500));
        return false;
    },

    show_settings_form: function () {
        if ($('div.settings').length > 0) {
            return false;
        }
        (new dbpatterns.views.DocumentEditDialog({
            "form": _.template(this.settings_form_template, this),
            "model": this.model,
            "title": "Document Settings"
        })).success(function () {
            this.save_document();
            return true;
        }.bind(this)).render();
    },

    enter_room: function (data) {
        if (this.options.edit) {
            new dbpatterns.views.Room({
                model: new dbpatterns.models.Room(data, {
                    socket: this.model.socket
                })
            }).render();
        }
    }
});

dbpatterns.views.DocumentEditDialog = dbpatterns.views.FormDialog.extend({
    tagName: "div",
    className: "settings",
    draggable: false,

    initialize: function () {
        dbpatterns.views.FormDialog.prototype.initialize.apply(this);
        this.on("render", this.show_assignees)
    },

    show_assignees: function () {

        this.assignees = new dbpatterns.collections.Assignees(this.model.get("assignees"));
        var assignees_view = new dbpatterns.views.AssigneesView({
            model: this.assignees
        });
        assignees_view.render();
    },

    load_data: function () {

        this.form.find("#title").val(this.model.get("title"));

        if (this.model.get("is_public")) {
            this.form.find("#is_public").attr("checked", "checked");
        } else {
            this.form.find("#is_private").attr("checked", "checked");
        }
    },

    save_data: function () {
        this.model.set({
            "title": this.form.find("#title").val(),
            "is_public": this.form.find("#is_public").is(":checked"),
            "assignees": this.assignees.toJSON()
        });
    }
});
<|endoftext|>


<commit_before>/*
Copyright 2019 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import sdk from '../../../index';
import classnames from 'classnames';
import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
import {makeType} from "../../../utils/TypeUtils";

const MODULAR_URL = 'https://modular.im/?utm_source=riot-web&utm_medium=web&utm_campaign=riot-web-authentication';

export const FREE = 'Free';
export const PREMIUM = 'Premium';
export const ADVANCED = 'Advanced';

export const TYPES = {
    FREE: {
        id: FREE,
        label: () => _t('Free'),
        logo: () => ,
        description: () => _t('Join millions for free on the largest public server'),
        serverConfig: makeType(ValidatedServerConfig, {
            hsUrl: "https://matrix.org",
            hsName: "matrix.org",
            hsNameIsDifferent: false,
            isUrl: "https://vector.im",
        }),
    },
    PREMIUM: {
        id: PREMIUM,
        label: () => _t('Premium'),
        logo: () => ,
        description: () => _t('Premium hosting for organisations Learn more', {}, {
            a: sub =>
                {sub}
            ,
        }),
        identityServerUrl: "https://vector.im",
    },
    ADVANCED: {
        id: ADVANCED,
        label: () => _t('Advanced'),
        logo: () =>

            {_t('Other')}

,
        description: () => _t('Find other public servers or use a custom server'),
    },
};

export function getTypeFromServerConfig(config) {
    const {hsUrl} = config;
    if (!hsUrl) {
        return null;
    } else if (hsUrl === TYPES.FREE.serverConfig.hsUrl) {
        return FREE;
    } else if (new URL(hsUrl).hostname.endsWith('.modular.im')) {
        // This is an unlikely case to reach, as Modular defaults to hiding the
        // server type selector.
        return PREMIUM;
    } else {
        return ADVANCED;
    }
}

export default class ServerTypeSelector extends React.PureComponent {
    static propTypes = {
        // The default selected type.
        selected: PropTypes.string,
        // Handler called when the selected type changes.
        onChange: PropTypes.func.isRequired,
    };

    constructor(props) {
        super(props);

        const {
            selected,
        } = props;

        this.state = {
            selected,
        };
    }

    updateSelectedType(type) {
        if (this.state.selected === type) {
            return;
        }
        this.setState({
            selected: type,
        });
        if (this.props.onChange) {
            this.props.onChange(type);
        }
    }

    onClick = (e) => {
        e.stopPropagation();
        const type = e.currentTarget.dataset.id;
        this.updateSelectedType(type);
    };

    render() {
        const AccessibleButton = sdk.getComponent('elements.AccessibleButton');

        const serverTypes = [];
        for (const type of Object.values(TYPES)) {
            const { id, label, logo, description } = type;
            const classes = classnames(
                "mx_ServerTypeSelector_type",
                `mx_ServerTypeSelector_type_${id}`,
                {
                    "mx_ServerTypeSelector_type_selected": id === this.state.selected,
                },
            );

            serverTypes.push(

                    {label()}

                <AccessibleButton onClick={this.onClick} data-id={id}>

                        {logo()}

                        {description()}

                </AccessibleButton>

);
        }

        return

            {serverTypes}

;
    }
}
<commit_msg>Update ServerTypeSelector for new matrix.org CS API URL<commit_after>/*
Copyright 2019 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import sdk from '../../../index';
import classnames from 'classnames';
import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
import {makeType} from "../../../utils/TypeUtils";

const MODULAR_URL = 'https://modular.im/?utm_source=riot-web&utm_medium=web&utm_campaign=riot-web-authentication';

export const FREE = 'Free';
export const PREMIUM = 'Premium';
export const ADVANCED = 'Advanced';

export const TYPES = {
    FREE: {
        id: FREE,
        label: () => _t('Free'),
        logo: () => ,
        description: () => _t('Join millions for free on the largest public server'),
        serverConfig: makeType(ValidatedServerConfig, {
            hsUrl: "https://matrix-client.matrix.org",
            hsName: "matrix.org",
            hsNameIsDifferent: false,
            isUrl: "https://vector.im",
        }),
    },
    PREMIUM: {
        id: PREMIUM,
        label: () => _t('Premium'),
        logo: () => ,
        description: () => _t('Premium hosting for organisations Learn more', {}, {
            a: sub =>
                {sub}
            ,
        }),
        identityServerUrl: "https://vector.im",
    },
    ADVANCED: {
        id: ADVANCED,
        label: () => _t('Advanced'),
        logo: () =>

            {_t('Other')}

,
        description: () => _t('Find other public servers or use a custom server'),
    },
};

export function getTypeFromServerConfig(config) {
    const {hsUrl} = config;
    if (!hsUrl) {
        return null;
    } else if (hsUrl === TYPES.FREE.serverConfig.hsUrl) {
        return FREE;
    } else if (new URL(hsUrl).hostname.endsWith('.modular.im')) {
        // This is an unlikely case to reach, as Modular defaults to hiding the
        // server type selector.
        return PREMIUM;
    } else {
        return ADVANCED;
    }
}

export default class ServerTypeSelector extends React.PureComponent {
    static propTypes = {
        // The default selected type.
        selected: PropTypes.string,
        // Handler called when the selected type changes.
        onChange: PropTypes.func.isRequired,
    };

    constructor(props) {
        super(props);

        const {
            selected,
        } = props;

        this.state = {
            selected,
        };
    }

    updateSelectedType(type) {
        if (this.state.selected === type) {
            return;
        }
        this.setState({
            selected: type,
        });
        if (this.props.onChange) {
            this.props.onChange(type);
        }
    }

    onClick = (e) => {
        e.stopPropagation();
        const type = e.currentTarget.dataset.id;
        this.updateSelectedType(type);
    };

    render() {
        const AccessibleButton = sdk.getComponent('elements.AccessibleButton');

        const serverTypes = [];
        for (const type of Object.values(TYPES)) {
            const { id, label, logo, description } = type;
            const classes = classnames(
                "mx_ServerTypeSelector_type",
                `mx_ServerTypeSelector_type_${id}`,
                {
                    "mx_ServerTypeSelector_type_selected": id === this.state.selected,
                },
            );

            serverTypes.push(

                    {label()}

                <AccessibleButton onClick={this.onClick} data-id={id}>

                        {logo()}

                        {description()}

                </AccessibleButton>

);
        }

        return

            {serverTypes}

;
    }
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
'use strict';

var localConnection;
var remoteConnection;
var sendChannel;
var receiveChannel;
var bitrateDiv = document.querySelector('div#bitrate');
var fileInput = document.querySelector('input#fileInput');
var downloadAnchor = document.querySelector('a#download');
var sendProgress = document.querySelector('progress#sendProgress');
var receiveProgress = document.querySelector('progress#receiveProgress');
var statusMessage = document.querySelector('span#status');

var receiveBuffer = [];
var receivedSize = 0;

var bytesPrev = 0;
var timestampPrev = 0;
var timestampStart;
var statsInterval = null;
var bitrateMax = 0;

fileInput.addEventListener('change', handleFileInputChange, false);

function handleFileInputChange() {
  var file = fileInput.files[0];
  if (!file) {
    trace('No file chosen');
  } else {
    createConnection();
  }
}

function createConnection() {
  var servers = null;

  localConnection = localConnection = new RTCPeerConnection(servers);
  trace('Created local peer connection object localConnection');

  sendChannel = localConnection.createDataChannel('sendDataChannel');
  sendChannel.binaryType = 'arraybuffer';
  trace('Created send data channel');

  sendChannel.onopen = onSendChannelStateChange;
  sendChannel.onclose = onSendChannelStateChange;
  localConnection.onicecandidate = function(e) {
    onIceCandidate(localConnection, e);
  };

  localConnection.createOffer().then(
    gotDescription1,
    onCreateSessionDescriptionError
  );
  remoteConnection = remoteConnection = new RTCPeerConnection(servers);
  trace('Created remote peer connection object remoteConnection');

  remoteConnection.onicecandidate = function(e) {
    onIceCandidate(remoteConnection, e);
  };
  remoteConnection.ondatachannel = receiveChannelCallback;

  fileInput.disabled = true;
}

function onCreateSessionDescriptionError(error) {
  trace('Failed to create session description: ' + error.toString());
}

function sendData() {
  var file = fileInput.files[0];
  trace('File is ' + [file.name, file.size, file.type,
      file.lastModifiedDate
  ].join(' '));

  // Handle 0 size files.
  statusMessage.textContent = '';
  downloadAnchor.textContent = '';
  if (file.size === 0) {
    bitrateDiv.innerHTML = '';
    statusMessage.textContent = 'File is empty, please select a non-empty file';
    closeDataChannels();
    return;
  }
  sendProgress.max = file.size;
  receiveProgress.max = file.size;
  var chunkSize = 16384;
  var sliceFile = function(offset) {
    var reader = new window.FileReader();
    reader.onload = (function() {
      return function(e) {
        sendChannel.send(e.target.result);
        if (file.size > offset + e.target.result.byteLength) {
          window.setTimeout(sliceFile, 0, offset + chunkSize);
        }
        sendProgress.value = offset + e.target.result.byteLength;
      };
    })(file);
    var slice = file.slice(offset, offset + chunkSize);
    reader.readAsArrayBuffer(slice);
  };
  sliceFile(0);
}

function closeDataChannels() {
  trace('Closing data channels');
  sendChannel.close();
  trace('Closed data channel with label: ' + sendChannel.label);
  if (receiveChannel) {
    receiveChannel.close();
    trace('Closed data channel with label: ' + receiveChannel.label);
  }
  localConnection.close();
  remoteConnection.close();
  localConnection = null;
  remoteConnection = null;
  trace('Closed peer connections');

  // re-enable the file select
  fileInput.disabled = false;
}

function gotDescription1(desc) {
  localConnection.setLocalDescription(desc);
  trace('Offer from localConnection \n' + desc.sdp);
  remoteConnection.setRemoteDescription(desc);
  remoteConnection.createAnswer().then(
    gotDescription2,
    onCreateSessionDescriptionError
  );
}

function gotDescription2(desc) {
  remoteConnection.setLocalDescription(desc);
  trace('Answer from remoteConnection \n' + desc.sdp);
  localConnection.setRemoteDescription(desc);
}

function getOtherPc(pc) {
  return (pc === localConnection) ? remoteConnection : localConnection;
}

function getName(pc) {
  return (pc === localConnection) ? 'localPeerConnection' :
      'remotePeerConnection';
}

function onIceCandidate(pc, event) {
  getOtherPc(pc).addIceCandidate(event.candidate)
  .then(
    function() {
      onAddIceCandidateSuccess(pc);
    },
    function(err) {
      onAddIceCandidateError(pc, err);
    }
  );
  trace(getName(pc) + ' ICE candidate: \n' + (event.candidate ?
      event.candidate.candidate : '(null)'));
}

function onAddIceCandidateSuccess() {
  trace('AddIceCandidate success.');
}

function onAddIceCandidateError(error) {
  trace('Failed to add Ice Candidate: ' + error.toString());
}

function receiveChannelCallback(event) {
  trace('Receive Channel Callback');
  receiveChannel = event.channel;
  receiveChannel.binaryType = 'arraybuffer';
  receiveChannel.onmessage = onReceiveMessageCallback;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;

  receivedSize = 0;
  bitrateMax = 0;
  downloadAnchor.textContent = '';
  downloadAnchor.removeAttribute('download');
  if (downloadAnchor.href) {
    URL.revokeObjectURL(downloadAnchor.href);
    downloadAnchor.removeAttribute('href');
  }
}

function onReceiveMessageCallback(event) {
  // trace('Received Message ' + event.data.byteLength);
  receiveBuffer.push(event.data);
  receivedSize += event.data.byteLength;

  receiveProgress.value = receivedSize;

  // we are assuming that our signaling protocol told
  // about the expected file size (and name, hash, etc).
  var file = fileInput.files[0];
  if (receivedSize === file.size) {
    var received = new window.Blob(receiveBuffer);
    receiveBuffer = [];

    downloadAnchor.href = URL.createObjectURL(received);
    downloadAnchor.download = file.name;
    downloadAnchor.textContent =
      'Click to download \'' + file.name + '\' (' + file.size + ' bytes)';
    downloadAnchor.style.display = 'block';

    var bitrate = Math.round(receivedSize * 8 /
        ((new Date()).getTime() - timestampStart));
    bitrateDiv.innerHTML = 'Average Bitrate: ' +
        bitrate + ' kbits/sec (max: ' + bitrateMax + ' kbits/sec)';

    if (statsInterval) {
      window.clearInterval(statsInterval);
      statsInterval = null;
    }

    closeDataChannels();
  }
}

function onSendChannelStateChange() {
  var readyState = sendChannel.readyState;
  trace('Send channel state is: ' + readyState);
  if (readyState === 'open') {
    sendData();
  }
}

function onReceiveChannelStateChange() {
  var readyState = receiveChannel.readyState;
  trace('Receive channel state is: ' + readyState);
  if (readyState === 'open') {
    timestampStart = (new Date()).getTime();
    timestampPrev = timestampStart;
    statsInterval = window.setInterval(displayStats, 500);
    window.setTimeout(displayStats, 100);
    window.setTimeout(displayStats, 300);
  }
}

// display bitrate statistics.
function displayStats() {
  var display = function(bitrate) {
    bitrateDiv.innerHTML = 'Current Bitrate: ' +
        bitrate + ' kbits/sec';
  };

  if (remoteConnection && remoteConnection.iceConnectionState === 'connected') {
    if (adapter.browserDetails.browser === 'chrome') {
      // TODO: once https://code.google.com/p/webrtc/issues/detail?id=4321
      // lands those stats should be preferrred over the connection stats.
      remoteConnection.getStats(null, function(stats) {
        for (var key in stats) {
          var res = stats[key];
          if (timestampPrev === res.timestamp) {
            return;
          }
          if (res.type === 'googCandidatePair' &&
              res.googActiveConnection === 'true') {
            // calculate current bitrate
            var bytesNow = res.bytesReceived;
            var bitrate = Math.round((bytesNow - bytesPrev) * 8 /
                (res.timestamp - timestampPrev));
            display(bitrate);
            timestampPrev = res.timestamp;
            bytesPrev = bytesNow;
            if (bitrate > bitrateMax) {
              bitrateMax = bitrate;
            }
          }
        }
      });
    } else {
      // Firefox currently does not have data channel stats. See
      // https://bugzilla.mozilla.org/show_bug.cgi?id=1136832
      // Instead, the bitrate is calculated based on the number of
      // bytes received.
      var bytesNow = receivedSize;
      var now = (new Date()).getTime();
      var bitrate = Math.round((bytesNow - bytesPrev) * 8 /
          (now - timestampPrev));
      display(bitrate);
      timestampPrev = now;
      bytesPrev = bytesNow;
      if (bitrate > bitrateMax) {
        bitrateMax = bitrate;
      }
    }
  }
}
<commit_msg>filetransfer: update bitrate calculation<commit_after>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
'use strict';

var localConnection;
var remoteConnection;
var sendChannel;
var receiveChannel;
var bitrateDiv = document.querySelector('div#bitrate');
var fileInput = document.querySelector('input#fileInput');
var downloadAnchor = document.querySelector('a#download');
var sendProgress = document.querySelector('progress#sendProgress');
var receiveProgress = document.querySelector('progress#receiveProgress');
var statusMessage = document.querySelector('span#status');

var receiveBuffer = [];
var receivedSize = 0;

var bytesPrev = 0;
var timestampPrev = 0;
var timestampStart;
var statsInterval = null;
var bitrateMax = 0;

fileInput.addEventListener('change', handleFileInputChange, false);

function handleFileInputChange() {
  var file = fileInput.files[0];
  if (!file) {
    trace('No file chosen');
  } else {
    createConnection();
  }
}

function createConnection() {
  var servers = null;

  localConnection = localConnection = new RTCPeerConnection(servers);
  trace('Created local peer connection object localConnection');

  sendChannel = localConnection.createDataChannel('sendDataChannel');
  sendChannel.binaryType = 'arraybuffer';
  trace('Created send data channel');

  sendChannel.onopen = onSendChannelStateChange;
  sendChannel.onclose = onSendChannelStateChange;
  localConnection.onicecandidate = function(e) {
    onIceCandidate(localConnection, e);
  };

  localConnection.createOffer().then(
    gotDescription1,
    onCreateSessionDescriptionError
  );
  remoteConnection = remoteConnection = new RTCPeerConnection(servers);
  trace('Created remote peer connection object remoteConnection');

  remoteConnection.onicecandidate = function(e) {
    onIceCandidate(remoteConnection, e);
  };
  remoteConnection.ondatachannel = receiveChannelCallback;

  fileInput.disabled = true;
}

function onCreateSessionDescriptionError(error) {
  trace('Failed to create session description: ' + error.toString());
}

function sendData() {
  var file = fileInput.files[0];
  trace('File is ' + [file.name, file.size, file.type,
      file.lastModifiedDate
  ].join(' '));

  // Handle 0 size files.
  statusMessage.textContent = '';
  downloadAnchor.textContent = '';
  if (file.size === 0) {
    bitrateDiv.innerHTML = '';
    statusMessage.textContent = 'File is empty, please select a non-empty file';
    closeDataChannels();
    return;
  }
  sendProgress.max = file.size;
  receiveProgress.max = file.size;
  var chunkSize = 16384;
  var sliceFile = function(offset) {
    var reader = new window.FileReader();
    reader.onload = (function() {
      return function(e) {
        sendChannel.send(e.target.result);
        if (file.size > offset + e.target.result.byteLength) {
          window.setTimeout(sliceFile, 0, offset + chunkSize);
        }
        sendProgress.value = offset + e.target.result.byteLength;
      };
    })(file);
    var slice = file.slice(offset, offset + chunkSize);
    reader.readAsArrayBuffer(slice);
  };
  sliceFile(0);
}

function closeDataChannels() {
  trace('Closing data channels');
  sendChannel.close();
  trace('Closed data channel with label: ' + sendChannel.label);
  if (receiveChannel) {
    receiveChannel.close();
    trace('Closed data channel with label: ' + receiveChannel.label);
  }
  localConnection.close();
  remoteConnection.close();
  localConnection = null;
  remoteConnection = null;
  trace('Closed peer connections');

  // re-enable the file select
  fileInput.disabled = false;
}

function gotDescription1(desc) {
  localConnection.setLocalDescription(desc);
  trace('Offer from localConnection \n' + desc.sdp);
  remoteConnection.setRemoteDescription(desc);
  remoteConnection.createAnswer().then(
    gotDescription2,
    onCreateSessionDescriptionError
  );
}

function gotDescription2(desc) {
  remoteConnection.setLocalDescription(desc);
  trace('Answer from remoteConnection \n' + desc.sdp);
  localConnection.setRemoteDescription(desc);
}

function getOtherPc(pc) {
  return (pc === localConnection) ? remoteConnection : localConnection;
}

function getName(pc) {
  return (pc === localConnection) ? 'localPeerConnection' :
      'remotePeerConnection';
}

function onIceCandidate(pc, event) {
  getOtherPc(pc).addIceCandidate(event.candidate)
  .then(
    function() {
      onAddIceCandidateSuccess(pc);
    },
    function(err) {
      onAddIceCandidateError(pc, err);
    }
  );
  trace(getName(pc) + ' ICE candidate: \n' + (event.candidate ?
      event.candidate.candidate : '(null)'));
}

function onAddIceCandidateSuccess() {
  trace('AddIceCandidate success.');
}

function onAddIceCandidateError(error) {
  trace('Failed to add Ice Candidate: ' + error.toString());
}

function receiveChannelCallback(event) {
  trace('Receive Channel Callback');
  receiveChannel = event.channel;
  receiveChannel.binaryType = 'arraybuffer';
  receiveChannel.onmessage = onReceiveMessageCallback;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;

  receivedSize = 0;
  bitrateMax = 0;
  downloadAnchor.textContent = '';
  downloadAnchor.removeAttribute('download');
  if (downloadAnchor.href) {
    URL.revokeObjectURL(downloadAnchor.href);
    downloadAnchor.removeAttribute('href');
  }
}

function onReceiveMessageCallback(event) {
  // trace('Received Message ' + event.data.byteLength);
  receiveBuffer.push(event.data);
  receivedSize += event.data.byteLength;

  receiveProgress.value = receivedSize;

  // we are assuming that our signaling protocol told
  // about the expected file size (and name, hash, etc).
  var file = fileInput.files[0];
  if (receivedSize === file.size) {
    var received = new window.Blob(receiveBuffer);
    receiveBuffer = [];

    downloadAnchor.href = URL.createObjectURL(received);
    downloadAnchor.download = file.name;
    downloadAnchor.textContent =
      'Click to download \'' + file.name + '\' (' + file.size + ' bytes)';
    downloadAnchor.style.display = 'block';

    var bitrate = Math.round(receivedSize * 8 /
        ((new Date()).getTime() - timestampStart));
    bitrateDiv.innerHTML = 'Average Bitrate: ' +
        bitrate + ' kbits/sec (max: ' + bitrateMax + ' kbits/sec)';

    if (statsInterval) {
      window.clearInterval(statsInterval);
      statsInterval = null;
    }

    closeDataChannels();
  }
}

function onSendChannelStateChange() {
  var readyState = sendChannel.readyState;
  trace('Send channel state is: ' + readyState);
  if (readyState === 'open') {
    sendData();
  }
}

function onReceiveChannelStateChange() {
  var readyState = receiveChannel.readyState;
  trace('Receive channel state is: ' + readyState);
  if (readyState === 'open') {
    timestampStart = (new Date()).getTime();
    timestampPrev = timestampStart;
    statsInterval = window.setInterval(displayStats, 500);
    window.setTimeout(displayStats, 100);
    window.setTimeout(displayStats, 300);
  }
}

// display bitrate statistics.
function displayStats() {
  var display = function(bitrate) {
    bitrateDiv.innerHTML = 'Current Bitrate: ' +
        bitrate + ' kbits/sec';
  };

  if (remoteConnection && remoteConnection.iceConnectionState === 'connected') {
    if (adapter.browserDetails.browser === 'chrome') {
      // TODO: once https://code.google.com/p/webrtc/issues/detail?id=4321
      // lands those stats should be preferrred over the connection stats.
      remoteConnection.getStats().then(function(stats) {
        // Search for the active candidate pair.
        let activeCandidatePair;
        stats.forEach(function(report) {
          if (report.type === 'transport') {
            activeCandidatePair = stats.get(report.selectedCandidatePairId);
          }
        });
        if (activeCandidatePair) {
          if (timestampPrev === activeCandidatePair.timestamp) {
            return;
          }
          // calculate current bitrate
          var bytesNow = activeCandidatePair.bytesReceived;
          var bitrate = Math.round((bytesNow - bytesPrev) * 8 /
              (activeCandidatePair.timestamp - timestampPrev));
          display(bitrate);
          timestampPrev = activeCandidatePair.timestamp;
          bytesPrev = bytesNow;
          if (bitrate > bitrateMax) {
            bitrateMax = bitrate;
          }
        }
      });
    } else {
      // Firefox currently does not have data channel stats. See
      // https://bugzilla.mozilla.org/show_bug.cgi?id=1136832
      // Instead, the bitrate is calculated based on the number of
      // bytes received.
      var bytesNow = receivedSize;
      var now = (new Date()).getTime();
      var bitrate = Math.round((bytesNow - bytesPrev) * 8 /
          (now - timestampPrev));
      display(bitrate);
      timestampPrev = now;
      bytesPrev = bytesNow;
      if (bitrate > bitrateMax) {
        bitrateMax = bitrate;
      }
    }
  }
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
/* global TimelineDataSeries, TimelineGraphView */

'use strict';

const remoteVideo = document.querySelector('video#remoteVideo');
const localVideo = document.querySelector('video#localVideo');
const callButton = document.querySelector('button#callButton');
const hangupButton = document.querySelector('button#hangupButton');
const bandwidthSelector = document.querySelector('select#bandwidth');
hangupButton.disabled = true;
callButton.onclick = call;
hangupButton.onclick = hangup;

let pc1;
let pc2;
let localStream;

// Can be set in the console before making a call to test this keeps
// within the envelope set by the SDP. In kbps.
let maxBandwidth = 0;

let bitrateGraph;
let bitrateSeries;

let packetGraph;
let packetSeries;

let lastResult;

const offerOptions = {
  offerToReceiveAudio: 0,
  offerToReceiveVideo: 1
};

function gotStream(stream) {
  hangupButton.disabled = false;
  console.log('Received local stream');
  localStream = stream;
  localVideo.srcObject = stream;
  localStream.getTracks().forEach(track => pc1.addTrack(track, localStream));
  console.log('Adding Local Stream to peer connection');

  pc1.createOffer(
    offerOptions
  ).then(
    gotDescription1,
    onCreateSessionDescriptionError
  );

  bitrateSeries = new TimelineDataSeries();
  bitrateGraph = new TimelineGraphView('bitrateGraph', 'bitrateCanvas');
  bitrateGraph.updateEndDate();

  packetSeries = new TimelineDataSeries();
  packetGraph = new TimelineGraphView('packetGraph', 'packetCanvas');
  packetGraph.updateEndDate();
}

function onCreateSessionDescriptionError(error) {
  console.log('Failed to create session description: ' + error.toString());
}

function call() {
  callButton.disabled = true;
  bandwidthSelector.disabled = false;
  console.log('Starting call');
  const servers = null;
  pc1 = new RTCPeerConnection(servers);
  console.log('Created local peer connection object pc1');
  pc1.onicecandidate = onIceCandidate.bind(pc1);

  pc2 = new RTCPeerConnection(servers);
  console.log('Created remote peer connection object pc2');
  pc2.onicecandidate = onIceCandidate.bind(pc2);
  pc2.ontrack = gotRemoteStream;

  console.log('Requesting local stream');
  navigator.mediaDevices.getUserMedia({video: true})
    .then(gotStream)
    .catch(e => alert('getUserMedia() error: ' + e.name));
}

function gotDescription1(desc) {
  console.log('Offer from pc1 \n' + desc.sdp);
  pc1.setLocalDescription(desc).then(
    () => {
      pc2.setRemoteDescription(desc)
        .then(() => pc2.createAnswer().then(gotDescription2, onCreateSessionDescriptionError),
          onSetSessionDescriptionError);
    }, onSetSessionDescriptionError
  );
}

function gotDescription2(desc) {
  pc2.setLocalDescription(desc).then(
    () => {
      console.log('Answer from pc2 \n' + desc.sdp);
      let p;
      if (maxBandwidth) {
        p = pc1.setRemoteDescription({
          type: desc.type,
          sdp: updateBandwidthRestriction(desc.sdp, maxBandwidth)
        });
      } else {
        p = pc1.setRemoteDescription(desc);
      }
      p.then(() => {}, onSetSessionDescriptionError);
    },
    onSetSessionDescriptionError
  );
}

function hangup() {
  console.log('Ending call');
  localStream.getTracks().forEach(track => track.stop());
  pc1.close();
  pc2.close();
  pc1 = null;
  pc2 = null;
  hangupButton.disabled = true;
  callButton.disabled = false;
  bandwidthSelector.disabled = true;
}

function gotRemoteStream(e) {
  if (remoteVideo.srcObject !== e.streams[0]) {
    remoteVideo.srcObject = e.streams[0];
    console.log('Received remote stream');
  }
}

function getOtherPc(pc) {
  return pc === pc1 ? pc2 : pc1;
}

function getName(pc) {
  return pc === pc1 ? 'pc1' : 'pc2';
}

function onIceCandidate(event) {
  getOtherPc(this)
    .addIceCandidate(event.candidate)
    .then(onAddIceCandidateSuccess)
    .catch(onAddIceCandidateError);

  console.log(`${getName(this)} ICE candidate:\n${event.candidate ? event.candidate.candidate : '(null)'}`);
}

function onAddIceCandidateSuccess() {
  console.log('AddIceCandidate success.');
}

function onAddIceCandidateError(error) {
  console.log('Failed to add ICE Candidate: ' + error.toString());
}

function onSetSessionDescriptionError(error) {
  console.log('Failed to set session description: ' + error.toString());
}

// renegotiate bandwidth on the fly.
bandwidthSelector.onchange = () => {
  bandwidthSelector.disabled = true;
  const bandwidth = bandwidthSelector.options[bandwidthSelector.selectedIndex].value;

  // In Chrome, use RTCRtpSender.setParameters to change bandwidth without
  // (local) renegotiation. Note that this will be within the envelope of
  // the initial maximum bandwidth negotiated via SDP.
  if (adapter.browserDetails.browser === 'chrome' &&
      'RTCRtpSender' in window &&
      'setParameters' in window.RTCRtpSender.prototype) {
    const sender = pc1.getSenders()[0];
    const parameters = sender.getParameters();
    if (bandwidth === 'unlimited') {
      delete parameters.encodings[0].maxBitrate;
    } else {
      parameters.encodings[0].maxBitrate = bandwidth * 1000;
    }
    sender.setParameters(parameters)
    .then(() => {
      bandwidthSelector.disabled = false;
    })
    .catch(e => console.error(e));
    return;
  }
  // Fallback to the SDP munging with local renegotiation way of limiting
  // the bandwidth.
  pc1.createOffer()
    .then(offer => pc1.setLocalDescription(offer))
    .then(() => {
      const desc = {
        type: pc1.remoteDescription.type,
        sdp: bandwidth === 'unlimited'
          ? removeBandwidthRestriction(pc1.remoteDescription.sdp)
          : updateBandwidthRestriction(pc1.remoteDescription.sdp, bandwidth)
      };
      console.log('Applying bandwidth restriction to setRemoteDescription:\n' +
        desc.sdp);
      return pc1.setRemoteDescription(desc);
    })
    .then(() => {
      bandwidthSelector.disabled = false;
    })
    .catch(onSetSessionDescriptionError);
};

function updateBandwidthRestriction(sdp, bandwidth) {
  let modifier = 'AS';
  if (adapter.browserDetails.browser === 'firefox') {
    bandwidth = (bandwidth >>> 0) * 1000;
    modifier = 'TIAS';
  }
  if (sdp.indexOf('b=' + modifier + ':') === -1) {
    // insert b= after c= line.
    sdp = sdp.replace(/c=IN (.*)\r\n/, 'c=IN $1\r\nb=' + modifier + ':' + bandwidth + '\r\n');
  } else {
    sdp = sdp.replace(new RegExp('b=' + modifier + ':.*\r\n'), 'b=' + modifier + ':' + bandwidth + '\r\n');
  }
  return sdp;
}

function removeBandwidthRestriction(sdp) {
  return sdp.replace(/b=AS:.*\r\n/, '').replace(/b=TIAS:.*\r\n/, '');
}

// query getStats every second
window.setInterval(() => {
  if (!pc1) {
    return;
  }
  const sender = pc1.getSenders()[0];
  if (!sender) {
    return;
  }
  sender.getStats().then(res => {
    res.forEach(report => {
      let bytes;
      let packets;
      if (report.type === 'outbound-rtp') {
        if (report.isRemote) {
          return;
        }
        const now = report.timestamp;
        bytes = report.bytesSent;
        packets = report.packetsSent;
        if (lastResult && lastResult.has(report.id)) {
          // calculate bitrate
          const bitrate = 8 * (bytes - lastResult.get(report.id).bytesSent) /
            (now - lastResult.get(report.id).timestamp);

          // append to chart
          bitrateSeries.addPoint(now, bitrate);
          bitrateGraph.setDataSeries([bitrateSeries]);
          bitrateGraph.updateEndDate();

          // calculate number of packets and append to chart
          packetSeries.addPoint(now, packets -
            lastResult.get(report.id).packetsSent);
          packetGraph.setDataSeries([packetSeries]);
          packetGraph.updateEndDate();
        }
      }
    });
    lastResult = res;
  });
}, 1000);
<commit_msg>bandwidth: Use RTCRtpSender.setParameters in Firefox 64 and up (#1128)<commit_after>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
/* global TimelineDataSeries, TimelineGraphView */

'use strict';

const remoteVideo = document.querySelector('video#remoteVideo');
const localVideo = document.querySelector('video#localVideo');
const callButton = document.querySelector('button#callButton');
const hangupButton = document.querySelector('button#hangupButton');
const bandwidthSelector = document.querySelector('select#bandwidth');
hangupButton.disabled = true;
callButton.onclick = call;
hangupButton.onclick = hangup;

let pc1;
let pc2;
let localStream;

// Can be set in the console before making a call to test this keeps
// within the envelope set by the SDP. In kbps.
let maxBandwidth = 0;

let bitrateGraph;
let bitrateSeries;

let packetGraph;
let packetSeries;

let lastResult;

const offerOptions = {
  offerToReceiveAudio: 0,
  offerToReceiveVideo: 1
};

function gotStream(stream) {
  hangupButton.disabled = false;
  console.log('Received local stream');
  localStream = stream;
  localVideo.srcObject = stream;
  localStream.getTracks().forEach(track => pc1.addTrack(track, localStream));
  console.log('Adding Local Stream to peer connection');

  pc1.createOffer(
    offerOptions
  ).then(
    gotDescription1,
    onCreateSessionDescriptionError
  );

  bitrateSeries = new TimelineDataSeries();
  bitrateGraph = new TimelineGraphView('bitrateGraph', 'bitrateCanvas');
  bitrateGraph.updateEndDate();

  packetSeries = new TimelineDataSeries();
  packetGraph = new TimelineGraphView('packetGraph', 'packetCanvas');
  packetGraph.updateEndDate();
}

function onCreateSessionDescriptionError(error) {
  console.log('Failed to create session description: ' + error.toString());
}

function call() {
  callButton.disabled = true;
  bandwidthSelector.disabled = false;
  console.log('Starting call');
  const servers = null;
  pc1 = new RTCPeerConnection(servers);
  console.log('Created local peer connection object pc1');
  pc1.onicecandidate = onIceCandidate.bind(pc1);

  pc2 = new RTCPeerConnection(servers);
  console.log('Created remote peer connection object pc2');
  pc2.onicecandidate = onIceCandidate.bind(pc2);
  pc2.ontrack = gotRemoteStream;

  console.log('Requesting local stream');
  navigator.mediaDevices.getUserMedia({video: true})
    .then(gotStream)
    .catch(e => alert('getUserMedia() error: ' + e.name));
}

function gotDescription1(desc) {
  console.log('Offer from pc1 \n' + desc.sdp);
  pc1.setLocalDescription(desc).then(
    () => {
      pc2.setRemoteDescription(desc)
        .then(() => pc2.createAnswer().then(gotDescription2, onCreateSessionDescriptionError),
          onSetSessionDescriptionError);
    }, onSetSessionDescriptionError
  );
}

function gotDescription2(desc) {
  pc2.setLocalDescription(desc).then(
    () => {
      console.log('Answer from pc2 \n' + desc.sdp);
      let p;
      if (maxBandwidth) {
        p = pc1.setRemoteDescription({
          type: desc.type,
          sdp: updateBandwidthRestriction(desc.sdp, maxBandwidth)
        });
      } else {
        p = pc1.setRemoteDescription(desc);
      }
      p.then(() => {}, onSetSessionDescriptionError);
    },
    onSetSessionDescriptionError
  );
}

function hangup() {
  console.log('Ending call');
  localStream.getTracks().forEach(track => track.stop());
  pc1.close();
  pc2.close();
  pc1 = null;
  pc2 = null;
  hangupButton.disabled = true;
  callButton.disabled = false;
  bandwidthSelector.disabled = true;
}

function gotRemoteStream(e) {
  if (remoteVideo.srcObject !== e.streams[0]) {
    remoteVideo.srcObject = e.streams[0];
    console.log('Received remote stream');
  }
}

function getOtherPc(pc) {
  return pc === pc1 ? pc2 : pc1;
}

function getName(pc) {
  return pc === pc1 ? 'pc1' : 'pc2';
}

function onIceCandidate(event) {
  getOtherPc(this)
    .addIceCandidate(event.candidate)
    .then(onAddIceCandidateSuccess)
    .catch(onAddIceCandidateError);

  console.log(`${getName(this)} ICE candidate:\n${event.candidate ? event.candidate.candidate : '(null)'}`);
}

function onAddIceCandidateSuccess() {
  console.log('AddIceCandidate success.');
}

function onAddIceCandidateError(error) {
  console.log('Failed to add ICE Candidate: ' + error.toString());
}

function onSetSessionDescriptionError(error) {
  console.log('Failed to set session description: ' + error.toString());
}

// renegotiate bandwidth on the fly.
bandwidthSelector.onchange = () => {
  bandwidthSelector.disabled = true;
  const bandwidth = bandwidthSelector.options[bandwidthSelector.selectedIndex].value;

  // In Chrome, use RTCRtpSender.setParameters to change bandwidth without
  // (local) renegotiation. Note that this will be within the envelope of
  // the initial maximum bandwidth negotiated via SDP.
  if ((adapter.browserDetails.browser === 'chrome' ||
       (adapter.browserDetails.browser === 'firefox' &&
        adapter.browserDetails.version >= 64)) &&
      'RTCRtpSender' in window &&
      'setParameters' in window.RTCRtpSender.prototype) {
    const sender = pc1.getSenders()[0];
    const parameters = sender.getParameters();
    if (!parameters.encodings) {
      parameters.encodings = [{}];
    }
    if (bandwidth === 'unlimited') {
      delete parameters.encodings[0].maxBitrate;
    } else {
      parameters.encodings[0].maxBitrate = bandwidth * 1000;
    }
    sender.setParameters(parameters)
    .then(() => {
      bandwidthSelector.disabled = false;
    })
    .catch(e => console.error(e));
    return;
  }
  // Fallback to the SDP munging with local renegotiation way of limiting
  // the bandwidth.
  pc1.createOffer()
    .then(offer => pc1.setLocalDescription(offer))
    .then(() => {
      const desc = {
        type: pc1.remoteDescription.type,
        sdp: bandwidth === 'unlimited'
          ? removeBandwidthRestriction(pc1.remoteDescription.sdp)
          : updateBandwidthRestriction(pc1.remoteDescription.sdp, bandwidth)
      };
      console.log('Applying bandwidth restriction to setRemoteDescription:\n' +
        desc.sdp);
      return pc1.setRemoteDescription(desc);
    })
    .then(() => {
      bandwidthSelector.disabled = false;
    })
    .catch(onSetSessionDescriptionError);
};

function updateBandwidthRestriction(sdp, bandwidth) {
  let modifier = 'AS';
  if (adapter.browserDetails.browser === 'firefox') {
    bandwidth = (bandwidth >>> 0) * 1000;
    modifier = 'TIAS';
  }
  if (sdp.indexOf('b=' + modifier + ':') === -1) {
    // insert b= after c= line.
    sdp = sdp.replace(/c=IN (.*)\r\n/, 'c=IN $1\r\nb=' + modifier + ':' + bandwidth + '\r\n');
  } else {
    sdp = sdp.replace(new RegExp('b=' + modifier + ':.*\r\n'), 'b=' + modifier + ':' + bandwidth + '\r\n');
  }
  return sdp;
}

function removeBandwidthRestriction(sdp) {
  return sdp.replace(/b=AS:.*\r\n/, '').replace(/b=TIAS:.*\r\n/, '');
}

// query getStats every second
window.setInterval(() => {
  if (!pc1) {
    return;
  }
  const sender = pc1.getSenders()[0];
  if (!sender) {
    return;
  }
  sender.getStats().then(res => {
    res.forEach(report => {
      let bytes;
      let packets;
      if (report.type === 'outbound-rtp') {
        if (report.isRemote) {
          return;
        }
        const now = report.timestamp;
        bytes = report.bytesSent;
        packets = report.packetsSent;
        if (lastResult && lastResult.has(report.id)) {
          // calculate bitrate
          const bitrate = 8 * (bytes - lastResult.get(report.id).bytesSent) /
            (now - lastResult.get(report.id).timestamp);

          // append to chart
          bitrateSeries.addPoint(now, bitrate);
          bitrateGraph.setDataSeries([bitrateSeries]);
          bitrateGraph.updateEndDate();

          // calculate number of packets and append to chart
          packetSeries.addPoint(now, packets -
            lastResult.get(report.id).packetsSent);
          packetGraph.setDataSeries([packetSeries]);
          packetGraph.updateEndDate();
        }
      }
    });
    lastResult = res;
  });
}, 1000);
<|endoftext|>


<commit_before>var mongoose = require('mongoose');
var Game = require('../game/game.model');
var logger = require('../../logger/logger');
var winston = require('winston');

var reviewSchema = new mongoose.Schema({
	owner: {type: mongoose.Schema.Types.ObjectId, ref: 'user', requred: true},
	game: {type: mongoose.Schema.Types.ObjectId, ref: 'game', required: true},
	reviewText: {type: String, required: true},
	rating: {type: Number, required: true},
	createdAt: {type: Date},
	updatedAt: {type: Date}
});

reviewSchema.pre('save', function (next) {
	if (!this.createdAt) this.createdAt = Date.now();
	this.updatedAt = Date.now();
	next();
});

reviewSchema.pre('update', function (next) {
	if (!this.createdAt) this.createdAt = Date.now();
	this.updatedAt = Date.now();
	next();
});

reviewSchema.statics.pushToGameAndAddRating = function (gameId, review) {
	Game.findByIdAndUpdate(gameId,
	{$addToSet: {'reviews': review._id}},
	function (err, game) {
		if (err) {
			logger.log('error', 'pushToGameAndAddRating() in review.model', err);
			return;
		}
		game.sumOfVotes += review.rating;
		game.numberOfVotes ++;
		game.rating = (game.sumOfVotes / game.numberOfVotes);
		game.save(function (err) {
			if (err) {
				logger.log('error', 'pushToGameAndAddRating() in review.model', err);
				return;
			}
		});
	});
};

reviewSchema.statics.updateRatingInGame = function (gameId, oldRating, newRating) {
	Game.findById({_id: gameId},
	function (err, game) {
		if (err) {
			logger.log('error', 'updateRatingInGame() in review.model', err);
			return;
		}
		game.sumOfVotes -= oldRating;
		game.sumOfVotes += newRating;
		game.rating = (game.sumOfVotes / game.numberOfVotes);
		game.save(function (err) {
			if (err) {
				logger.log('error', 'updateRatingInGame() in review.model', err);
				return;
			}
		});
	}
	);
};

reviewSchema.statics.pullFromGameAndRemoveRating = function (gameId, review) {
	Game.findByIdAndUpdate(gameId,
	{$pull: {'reviews': review._id}},
	function (err, game) {
		if (err) {
			logger.log('error', 'pullFromGameAndRemoveRating() in review.model', err);
			return;
		}
		game.numberOfVotes --;
		game.sumOfVotes -= review.rating;
		if (game.sumOfVotes === 0) {
			game.rating = 0;
		}
		else {
			game.rating = (game.sumOfVotes / game.numberOfVotes);
		}
		game.save(function (err) {
			if (err) {
				logger.log('error', 'pullFromGameAndRemoveRating() in review.model', err);
				return;
			}
		});
	}
	);
};

reviewSchema.statics.removePossibleReviews = function (gameId) {
	// If a game is deleted, possible reviews of that game is removed.
	this.remove({game: gameId}, function (err, reports) {
		if (err) {
			logger.log('error', 'removePossibleReviews() in review.model', err);
		}
	});
};

module.exports = mongoose.model('review', reviewSchema);
<commit_msg>updating a review no longer updates the createdAt variable in a game.<commit_after>var mongoose = require('mongoose');
var Game = require('../game/game.model');
var logger = require('../../logger/logger');
var winston = require('winston');

var reviewSchema = new mongoose.Schema({
	owner: {type: mongoose.Schema.Types.ObjectId, ref: 'user', requred: true},
	game: {type: mongoose.Schema.Types.ObjectId, ref: 'game', required: true},
	reviewText: {type: String, required: true},
	rating: {type: Number, required: true},
	createdAt: {type: Date},
	updatedAt: {type: Date}
});

reviewSchema.pre('save', function (next) {
	if (!this.createdAt) this.createdAt = Date.now();
	this.updatedAt = Date.now();
	next();
});

reviewSchema.pre('update', function (next) {
	if (!this.createdAt) this.createdAt = Date.now();
	this.updatedAt = Date.now();
	next();
});

reviewSchema.statics.pushToGameAndAddRating = function (gameId, review) {
	Game.findByIdAndUpdate(gameId,
	{$addToSet: {'reviews': review._id}},
	function (err, game) {
		if (err) {
			logger.log('error', 'pushToGameAndAddRating() in review.model', err);
			return;
		}
		game.sumOfVotes += review.rating;
		game.numberOfVotes ++;
		game.rating = (game.sumOfVotes / game.numberOfVotes);
		game.save(function (err) {
			if (err) {
				logger.log('error', 'pushToGameAndAddRating() in review.model', err);
				return;
			}
		});
	});
};

reviewSchema.statics.updateRatingInGame = function (gameId, oldRating, newRating) {
	Game.findById({_id: gameId},
	function (err, game) {
		if (err) {
			logger.log('error', 'updateRatingInGame() in review.model', err);
			return;
		}
		var newSumOfVotes = (game.sumOfVotes - oldRating + newRating);
		var newAvgRating = (newSumOfVotes / game.numberOfVotes);

		Game.findByIdAndUpdate(gameId,
		{sumOfVotes: newSumOfVotes, rating: newAvgRating},
		function (err, game) {
			if (err) {
				logger.log('error', 'updateRatingInGame() in review.model', err);
				return;
			}
		});
	});
};

reviewSchema.statics.pullFromGameAndRemoveRating = function (gameId, review) {
	Game.findByIdAndUpdate(gameId,
	{$pull: {'reviews': review._id}},
	function (err, game) {
		if (err) {
			logger.log('error', 'pullFromGameAndRemoveRating() in review.model', err);
			return;
		}
		game.numberOfVotes --;
		game.sumOfVotes -= review.rating;
		if (game.sumOfVotes === 0) {
			game.rating = 0;
		}
		else {
			game.rating = (game.sumOfVotes / game.numberOfVotes);
		}
		game.save(function (err) {
			if (err) {
				logger.log('error', 'pullFromGameAndRemoveRating() in review.model', err);
				return;
			}
		});
	}
	);
};

reviewSchema.statics.removePossibleReviews = function (gameId) {
	// If a game is deleted, possible reviews of that game is removed.
	this.remove({game: gameId}, function (err, reports) {
		if (err) {
			logger.log('error', 'removePossibleReviews() in review.model', err);
		}
	});
};

module.exports = mongoose.model('review', reviewSchema);
<|endoftext|>


<commit_before>import {Controller,Route} from "./Controller";
import models from "../db/models";

export default class Session extends Controller {
    @Route("Session:register")
    async register(msg, conn) {
        let user = await models.User.create({
            username: msg.username,
            slug: msg.username,
            language: msg.username,
            joined: Date.now(),
            gRole: 0
        });
        return user;
    }

    @Route("Session:login");
    async login(msg, conn) {
        let s = await models.User.findOne({where: {username: msg.username}});
        //TODO: password

        let s = await models.Auth.create({
            user_id: user.id,
            token: this.makeId(),
            created: Date.now(),
            last: Date.now()
        });

        return {user: user, session: s};
    }

    @Route("Session:loginToken")
    async loginToken(msg, conn) {
        let s = await models.Auth.findOne({where: {token: msg.token}});
        let user = await models.Auth.findById(s.user_id);
        return {user: user, session: s};
    }

    @Route("Session:logout")
    async logout(msg, conn) {
        let s = await models.Auth.findOne({where: {token: msg.token}});
        await s.destroy();
        return true;
    }

    //http://stackoverflow.com/a/1349426
    makeid() {
        var text = "";
        var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

        for (var i = 0; i < 5; i++)
            text += possible.charAt(Math.floor(Math.random() * possible.length));

        return text;
    }

}<commit_msg>and yet another typofix (that I forgot to git add before running --amend)<commit_after>import {Controller,Route} from "./Controller";
import models from "../db/models";

export default class Session extends Controller {
    @Route("Session:register")
    async register(msg, conn) {
        let user = await models.User.create({
            username: msg.username,
            slug: msg.username,
            language: msg.username,
            joined: Date.now(),
            gRole: 0
        });
        return user;
    }

    @Route("Session:login");
    async login(msg, conn) {
        let user = await models.User.findOne({where: {username: msg.username}});
        //TODO: password

        let s = await models.Auth.create({
            user_id: user.id,
            token: this.makeId(),
            created: Date.now(),
            last: Date.now()
        });

        return {user: user, session: s};
    }

    @Route("Session:loginToken")
    async loginToken(msg, conn) {
        let s = await models.Auth.findOne({where: {token: msg.token}});
        let user = await models.Auth.findById(s.user_id);
        return {user: user, session: s};
    }

    @Route("Session:logout")
    async logout(msg, conn) {
        let s = await models.Auth.findOne({where: {token: msg.token}});
        await s.destroy();
        return true;
    }

    //http://stackoverflow.com/a/1349426
    makeid() {
        var text = "";
        var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

        for (var i = 0; i < 5; i++)
            text += possible.charAt(Math.floor(Math.random() * possible.length));

        return text;
    }

}<|endoftext|>