<commit_before>// ==UserScript==
// @name         Unmute me
// @namespace    http://omnimed.com
// @version      0.1
// @description  unmute the mic in the meet
// @author       ggirard
// @match        https://meet.google.com/*
// ==/UserScript==

(function() {
    'use strict';
    setInterval(function(){
        if (document.querySelector("div[jsname='LgbsSe']").parentElement.classList.contains("FTMc0c")) {
            document.querySelector("div[jsname='LgbsSe']").click();
        }
    }, 1000);
})();
<commit_msg>Update unmuteMeet.js<commit_after>// ==UserScript==
// @name         Unmute me
// @namespace    http://omnimed.com
// @version      0.2
// @description  unmute the mic in the meet
// @author       ggirard
// @match        https://meet.google.com/*
// ==/UserScript==

(function() {
    'use strict';
    setInterval(function(){
        if (document.querySelector("div[jsname='BOHaEe']").classList.contains("FTMc0c")) {
            document.querySelector("div[jsname='BOHaEe']").click();
        }
    }, 1000);
})();
<|endoftext|>


<commit_before>// Substance.Document 0.4.0
// (c) 2010-2013 Michael Aufreiter
// Substance.Document may be freely distributed under the MIT license.
// For all details and documentation:
// http://interior.substance.io/modules/document.html

(function(root) {

// Import
// ========

var _,
    util,
    errors,
    Chronicle,
    ot,
    Data;

if (typeof exports !== 'undefined') {
  _    = require('underscore');
  ot   = require('./lib/operation');
  util   = require('./lib/util/util');
  errors   = require('./lib/util/errors');
  Chronicle = require('./lib/chronicle/chronicle');
  ot = require('./lib/chronicle/lib/ot/index');
  Data = require('./lib/data/data');
} else {
  _ = root._;
  ot = root.ot;
  util = root.Substance.util;
  errors   = root.Substance.errors;
  Chronicle = root.Substance.Chronicle;
  ot = Chronicle.ot;
  Data = root.Substance.Data;
}

// Default Document Schema
// --------

var SCHEMA = {
  // Static indexes
  "indexes": {
    // all comments are now indexed by node association
    "comments": {
      "type": "comment",
      "properties": ["node"]
    },
    // All annotations are now indexed by node
    "annotations": {
      "type": "annotation",
      "properties": ["node"]
    }
  },

  "types": {
    // Specific type for substance documents, holding all content elements
    "content": {
      "properties": {
      }
    },

    "text": {
      "parent": "content",
      "properties": {
        "content": "string"
      }
    },

    "document": {
      "properties": {
        "views": ["array", "view"],
        "id": "string",
        "creator": "string",
        "title": "string",
        "abstract": "string"
      }
    },

    "view": {
      "properties": {
        "nodes": ["array", "content"]
      }
    },

    "codeblock": {
      "parent": "content",
      "properties": {
        "content": "string"
      }
    },

    "image": {
      "parent": "content",
      "properties": {
        "large": "string",
        "medium": "string",
        "caption": "string"
      }
    },

    "heading": {
      "parent": "content",
      "properties": {
        "content": "string",
        "level": "number"
      }
    },

    // Annotations
    "annotation": {
      "properties": {
        "node": "content",
        "property": "string",
        "range": "object"
      }
    },

    "strong": {
      "parent": "annotation",
      "properties": {
      }
    },

    "emphasis": {
      "properties": {
      },
      "parent": "annotation"
    },

    "code": {
      "parent": "annotation",
      "properties": {
      }
    },

    "link": {
      "parent": "annotation",
      "properties": {
        "url": "string"
      }
    },

    "idea": {
      "parent": "annotation",
      "properties": {
      }
    },

    "error": {
      "parent": "annotation",
      "properties": {
      }
    },

    "question": {
      "parent": "annotation",
      "properties": {
      }
    },

    // Comments
    "comment": {
      "properties": {
        "content": "string",
        "created_at": "string", // should be date
        "creator": "string", // should be date
        "node": "node" // references either a content node or annotation
      }
    }
  }
};

// Seed Data
// ========
//
// Some pre-defined nodes that are required for each document
// `document` stores all meta-information about the document
// `content` is the main view

// Provides an initial state by a set of nodes.
// --------
// These commands change will not be versioned.
// Every document's history must be applicable on this.
var SEED = function(options) {
  return [
    Data.Graph.Create({
      id: "document",
      type: "document",
      creator: options.creator,
      created_at: options.created_at,
      views: ["content", "figures", "publications"],
      title: "",
      abstract: ""
    }),
    Data.Graph.Set(["document", "id"], options.id),
    Data.Graph.Create({
      id: "content",
      type: "view",
      nodes: [],
    }),
    Data.Graph.Create({
      id: "figures",
      type: "view",
      nodes: [],
    }),
    Data.Graph.Create({
      id: "publications",
      type: "view",
      nodes: [],
    })
  ];
};

// forward declaration
var Converter;

// Document
// --------
//
// A generic model for representing and transforming digital documents

var Document = function(options) {
  options.seed = options.seed || SEED(options);
  Data.Graph.call(this, options.schema || SCHEMA, options);
};

Document.__prototype__ = function() {

  var __super__ = util.prototype(this);
  var converter = new Converter();

  // this.init = function() {
  //   __super__.init.call(this);
  // };

  var updateAnnotations = function(node, property, change) {
    // We need to update the range of affected annotations.

    var annotations = this.find("annotations", node.id);
    annotations = _.filter(annotations, function(a) {
      return a.property === property;
    });
    for (var idx = 0; idx < annotations.length; idx++) {
      ot.TextOperation.Range.transform(annotations[idx].range, change);
    }
  };

  // Executes a document manipulation command.
  // --------
  // The command is converted into a sequence of graph commands

  this.exec = function(command) {

    // convert the command into a Data.Graph compatible command
    command = new Data.Command(command, Document.COMMANDS);
    var graphCommand = command;

    if (converter[command.type]) {
      graphCommand = converter[command.type](this, command);
      if (_.isArray(graphCommand)) {
        graphCommand = Data.Graph.Compound(this, graphCommand);
      }
    }
    // Note: Data.Graph converts everything into ObjectOperations
    // We will pass this also back to the caller.
    var op = __super__.exec.call(this, graphCommand);

    var cmds = (graphCommand.type === Data.Graph.COMPOUND) ? graphCommand.ops : [graphCommand];
    _.each(cmds, function(c) {
      if (c.type === "update") {
        var node = this.get(c.path[0]);
        var property = c.path[1];
        var change = c.args;
        updateAnnotations.call(this, node, property, change);
      }
    }, this);

    // TODO: maybe we could add events to Data.Graph?
    this.trigger('command:executed', command);

    return op;
  };
};

// Command Converter
// ========
//
// Turns document commands into Data.Graph commands

Converter = function() {

  // Delete nodes from document
  // --------
  //
  // ["delete", {nodes: ["h1", "t1"]}]

  this.delete = function(graph, command) {
    var nodes = command.args.nodes;

    var commands = [];
    _.each(nodes, function(n) {
      commands.push(Data.Graph.Delete({id: n}));
    }, this);

    _.each(graph.get('document').views, function(view) {
      var match = _.intersection(graph.get(view).nodes, nodes);
      commands.push(this.hide(graph, {
        "path": [view],
        args: {nodes: match}
      }));
    }, this);
    return commands;
  };

  // Hide elements from provided view
  // --------
  //
  // ["hide", {"nodes": ["t1", "t2"]}]
  //

  this.hide = function(graph, command) {
    var path = command.path.concat(["nodes"]);
    var view = graph.resolve(path).get();
    var nodes = command.args.nodes;

    var indices = [];
    _.each(nodes, function(n) {
      var i = view.indexOf(n);
      if (i>=0) indices.push(i);
    }, this);

    indices = indices.sort().reverse();

    var ops = _.map(indices, function(index) {
      return ot.ArrayOperation.Delete(index, view[index]);
    });

    return Data.Graph.Update(path, ot.ArrayOperation.Compound(ops));
  };

  // Position nodes in document
  // --------
  //
  // ["position", {"nodes": ["t1", "t2"], "target": -1}]
  //

  // TODO: we could use Graph.set which computes a rather minimal set of ArrayOps
  //       to get rid of the ArrayOperation dependency here
  this.position = function(graph, command) {
    var path = command.path.concat(["nodes"]);
    var view = graph.resolve(path).get();
    var nodes = command.args.nodes;
    var ops = [];
    var idx;

    // Create a sequence of atomic array operations that
    // are bundled into a Compound operation
    // 1. Remove elements (from right to left)
    // 2. Insert at the very position

    // the sequence contains selected nodes in the order they
    // occurr in the view
    var seq = _.intersection(view, nodes);
    var l = view.length;

    while(seq.length > 0) {
      var id = seq.pop();
      idx = view.indexOf(id);
      if (idx >= 0) {
        ops.push(ot.ArrayOperation.Delete(idx, id));
        l--;
      }
    }

    // target index can be given as negative number (as known from python/ruby)
    var target = Math.min(command.args.target, l);
    if (target<0) target = Math.max(0, l+target+1);

    for (idx = 0; idx < nodes.length; idx++) {
      ops.push(ot.ArrayOperation.Insert(target + idx, nodes[idx]));
    }

    var compound = ot.ArrayOperation.Compound(ops);

    return Data.Graph.Update(path, compound);
  };

  // Update incrementally
  // --------
  //

  // TODO: if we would integrate the convenience mechanisms for update and set into
  // Data.Graph, we could get rid of the OT dependencies here.

  this.update = function(graph, command) {
    var property = graph.resolve(command.path);
    var val = property.get();
    var valueType = property.baseType();

    var update;

    if (valueType === 'string') {
      update = ot.TextOperation.fromOT(val, command.args);
    }
    else if (valueType === 'array') {
      throw new Error("Not yet implemented for arrays");
    }
    else if (valueType === 'object') {
      update = ot.ObjectOperation.Extend(val, command.args);
    }
    else {
      throw new Error("Unsupported type for update: " + valueType);
    }
    return Data.Graph.Update(command.path, update);
  };

  // Annotate document
  // --------
  //
  // `command.path` defines the referenced content node and property
  // ["annotate", "t1", "content", {"id": "a1",  type": "idea"}]

  this.annotate = function(graph, command) {
    // TODO: check if source exists, otherwise reject annotation
    if (command.path.length !== 2) throw new Error("Invalid target: " + command.path);

    var annotation = _.extend({}, command.args, {
      node: command.path[0],
      property: command.path[1]
    });

    return Data.Graph.Create(annotation);
  };

  // Comment
  // --------
  //
  // `command.path` holds the node id, where the comment should stick on

  this.comment = function(graph, command) {
    // Delegates to graph.create method
    // TODO: check if source exists, otherwise reject annotation

    // keep track of annotation
    if (command.path.length !== 1) throw new Error("Invalid target: " + command.path);

    var comment = _.extend({}, command.args);
    comment.node = command.path[0];
    comment.type = comment.type || 'comment';

    return Data.Graph.Create(comment);
  };
};
Document.__prototype__.prototype = Data.Graph.prototype;
Document.prototype = new Document.__prototype__();
// Add convenience accessors for builtin document attributes
Object.defineProperties(Document.prototype, {
  id: {
    get: function () {
      return this.get("document").id;
    }
  },
  creator: {
    get: function () {
      return this.get("document").creator;
    }
  },
  created_at: {
    get: function () {
      return this.get("document").created_at;
    }
  },
  views: {
    get: function () {
      return this.get("document").views;
    }
  }
});

// AnnotatedText
// --------
//
// Ties together a text node with its annotations
// Interface defined by Substance.Surface

var AnnotatedText = function(doc, path) {
  this.doc = doc;
  this.path = path;
  this.property = doc.resolve(path);
  this.resetCache();
};

AnnotatedText.__prototype__ = function() {

  this.setAnnotation = function(annotation) {
    this.cache.annotations[annotation.id] = annotation;
    this.commit();
  };

  this.getAnnotation = function(id) {
    return this.cache.annotations[id] || this.doc.get(id);
  };

  this.deleteAnnotation = function(id) {
    delete this.cache.annotations[id];
    this.cache.deleted_annotations.push(id);
  };

  this.setContent = function(content) {
    this.cache.content = content;
  };

  this.getContent = function() {
    if (this.cache.content !== null) return this.cache.content;
    return this.property.get();
  };

  // Transform Hook
  // --------
  //

  this.each = function(fn) {
    var annos = this.doc.find('annotations', this.property.node.id);
    _.each(this.cache.annotations, fn);

    _.each(annos, function(a) {
      if (!this.cache.annotations[a.id] && !_.include(this.cache.deleted_annotations, a.id)) fn(a, a.id);
    }, this);
  };

  // Transform Hook
  // --------
  //
  // triggered implicitly by Surface.insert|deleteTransformer)

  this.transformAnnotation = function(a, op, expand) {
    if (this.cache.annotations[a.id]) {
      a = this.cache.annotations[a.id];
    } else {
      a = util.deepclone(a);
    }
    ot.TextOperation.Range.transform(a.range, op, expand);
    this.cache.annotations[a.id] = a;
  };

  this.resetCache = function() {
    this.cache = {
      annotations: {},
      content: null,
      deleted_annotations: []
    };
  };

  // Commit changes
  // --------
  //

  this.commit = function() {

    // 1. Insert Annotations
    var newAnnotations = [];
    var updatedAnnotations = [];
    _.each(this.cache.annotations, function(a) {
      var oa = this.doc.get(a.id);
      if (!oa) newAnnotations.push(a);
      else if (a.type !== oa.type) updatedAnnotations.push(a);
    }, this);

    var cmds = [];

    _.each(newAnnotations, function(a) {
      a.node = this.property.node.id;
      cmds.push(Document.Create(a));
    }, this);

    // Text diff computation
    if (this.cache.content !== null) {
      var delta = _.extractOperation(this.property.get(), this.cache.content);
      cmds.push(Data.Graph.Update(this.path, ot.TextOperation.fromOT(delta)));
    }

    _.each(cmds, function(c) {
      this.doc.exec(c);
    }, this);
    this.resetCache();
  };
};
AnnotatedText.prototype = new AnnotatedText.__prototype__();

// Command Factories
// --------

Document.Create = function(node) {
  return Data.Graph.Create(node);
};

Document.Delete = function(nodes) {
  return ["delete", {nodes: nodes}];
};

Document.COMMANDS = _.extend({}, Data.COMMANDS, {
  "position": {
    "types": ["array"],
    "arguments": 1
  },
  "hide": {
    "types": ["array"],
    "arguments": 1
  },
  "delete": {
    "types": ["graph"],
    "arguments": 1
  },
  "annotate": {
    "types": ["content"],
    "arguments": 1
  },
  "comment": {
    "types": ["content", "annotation"],
    "arguments": 1
  }
});

// Add event support
_.extend(Document.prototype, util.Events);

Document.SCHEMA = SCHEMA;
Document.AnnotatedText = AnnotatedText;

// Export
// ========

if (typeof exports !== 'undefined') {
  module.exports = Document;
} else {
  root.Substance.Document = Document;
}

})(this);
<commit_msg>Fix regressions.<commit_after>// Substance.Document 0.4.0
// (c) 2010-2013 Michael Aufreiter
// Substance.Document may be freely distributed under the MIT license.
// For all details and documentation:
// http://interior.substance.io/modules/document.html

(function(root) {

// Import
// ========

var _,
    util,
    errors,
    Chronicle,
    ot,
    Data;

if (typeof exports !== 'undefined') {
  _    = require('underscore');
  ot   = require('./lib/operation');
  util   = require('./lib/util/util');
  errors   = require('./lib/util/errors');
  Chronicle = require('./lib/chronicle/chronicle');
  ot = require('./lib/chronicle/lib/ot/index');
  Data = require('./lib/data/data');
} else {
  _ = root._;
  ot = root.ot;
  util = root.Substance.util;
  errors   = root.Substance.errors;
  Chronicle = root.Substance.Chronicle;
  ot = Chronicle.ot;
  Data = root.Substance.Data;
}

// Default Document Schema
// --------

var SCHEMA = {
  // Static indexes
  "indexes": {
    // all comments are now indexed by node association
    "comments": {
      "type": "comment",
      "properties": ["node"]
    },
    // All annotations are now indexed by node
    "annotations": {
      "type": "annotation",
      "properties": ["node"]
    }
  },

  "types": {
    // Specific type for substance documents, holding all content elements
    "content": {
      "properties": {
      }
    },

    "text": {
      "parent": "content",
      "properties": {
        "content": "string"
      }
    },

    "document": {
      "properties": {
        "views": ["array", "view"],
        "id": "string",
        "creator": "string",
        "title": "string",
        "abstract": "string"
      }
    },

    "view": {
      "properties": {
        "nodes": ["array", "content"]
      }
    },

    "codeblock": {
      "parent": "content",
      "properties": {
        "content": "string"
      }
    },

    "image": {
      "parent": "content",
      "properties": {
        "large": "string",
        "medium": "string",
        "caption": "string"
      }
    },

    "heading": {
      "parent": "content",
      "properties": {
        "content": "string",
        "level": "number"
      }
    },

    // Annotations
    "annotation": {
      "properties": {
        "node": "content",
        "property": "string",
        "range": "object"
      }
    },

    "strong": {
      "parent": "annotation",
      "properties": {
      }
    },

    "emphasis": {
      "properties": {
      },
      "parent": "annotation"
    },

    "code": {
      "parent": "annotation",
      "properties": {
      }
    },

    "link": {
      "parent": "annotation",
      "properties": {
        "url": "string"
      }
    },

    "idea": {
      "parent": "annotation",
      "properties": {
      }
    },

    "error": {
      "parent": "annotation",
      "properties": {
      }
    },

    "question": {
      "parent": "annotation",
      "properties": {
      }
    },

    // Comments
    "comment": {
      "properties": {
        "content": "string",
        "created_at": "string", // should be date
        "creator": "string", // should be date
        "node": "node" // references either a content node or annotation
      }
    }
  }
};

// Seed Data
// ========
//
// Some pre-defined nodes that are required for each document
// `document` stores all meta-information about the document
// `content` is the main view

// Provides an initial state by a set of nodes.
// --------
// These commands change will not be versioned.
// Every document's history must be applicable on this.
var SEED = function(options) {
  return [
    Data.Graph.Create({
      id: "document",
      type: "document",
      creator: options.creator,
      created_at: options.created_at,
      views: ["content", "figures", "publications"],
      title: "",
      abstract: ""
    }),
    Data.Graph.Set(["document", "id"], options.id),
    Data.Graph.Create({
      id: "content",
      type: "view",
      nodes: [],
    }),
    Data.Graph.Create({
      id: "figures",
      type: "view",
      nodes: [],
    }),
    Data.Graph.Create({
      id: "publications",
      type: "view",
      nodes: [],
    })
  ];
};

// forward declaration
var Converter;

// Document
// --------
//
// A generic model for representing and transforming digital documents

var Document = function(options) {
  options.seed = options.seed || SEED(options);
  Data.Graph.call(this, options.schema || SCHEMA, options);
};

Document.__prototype__ = function() {

  var __super__ = util.prototype(this);
  var converter = new Converter();

  // this.init = function() {
  //   __super__.init.call(this);
  // };

  var updateAnnotations = function(node, property, change) {
    // We need to update the range of affected annotations.

    var annotations = this.find("annotations", node.id);
    annotations = _.filter(annotations, function(a) {
      return a.property === property;
    });
    for (var idx = 0; idx < annotations.length; idx++) {
      ot.TextOperation.Range.transform(annotations[idx].range, change);
    }
  };

  // Executes a document manipulation command.
  // --------
  // The command is converted into a sequence of graph commands

  this.exec = function(command) {

    // convert the command into a Data.Graph compatible command
    command = new Data.Command(command, Document.COMMANDS);
    var graphCommand = command;

    if (converter[command.type]) {
      graphCommand = converter[command.type](this, command);
      if (_.isArray(graphCommand)) {
        graphCommand = Data.Graph.Compound(this, graphCommand);
      }
    }
    // Note: Data.Graph converts everything into ObjectOperations
    // We will pass this also back to the caller.
    var op = __super__.exec.call(this, graphCommand);

    var cmds = (graphCommand.type === Data.Graph.COMPOUND) ? graphCommand.ops : [graphCommand];
    _.each(cmds, function(c) {
      if (c.type === "update") {
        var node = this.get(c.path[0]);
        var property = c.path[1];
        var change = c.args;
        updateAnnotations.call(this, node, property, change);
      }
    }, this);

    // TODO: maybe we could add events to Data.Graph?
    this.trigger('command:executed', command);

    return op;
  };
};

// Command Converter
// ========
//
// Turns document commands into Data.Graph commands

Converter = function() {

  // Delete nodes from document
  // --------
  //
  // ["delete", {nodes: ["h1", "t1"]}]

  this.delete = function(graph, command) {
    var nodes = command.args.nodes;

    var commands = [];
    _.each(nodes, function(n) {
      commands.push(Data.Graph.Delete({id: n}));
    }, this);

    _.each(graph.get('document').views, function(view) {
      var match = _.intersection(graph.get(view).nodes, nodes);
      commands.push(this.hide(graph, {
        "path": [view],
        args: {nodes: match}
      }));
    }, this);
    return commands;
  };

  // Hide elements from provided view
  // --------
  //
  // ["hide", {"nodes": ["t1", "t2"]}]
  //

  this.hide = function(graph, command) {
    var path = command.path.concat(["nodes"]);
    var view = graph.resolve(path).get();
    var nodes = command.args.nodes;

    var indices = [];
    _.each(nodes, function(n) {
      var i = view.indexOf(n);
      if (i>=0) indices.push(i);
    }, this);

    indices = indices.sort().reverse();

    var ops = _.map(indices, function(index) {
      return ot.ArrayOperation.Delete(index, view[index]);
    });

    return Data.Graph.Update(path, ot.ArrayOperation.Compound(ops));
  };

  // Position nodes in document
  // --------
  //
  // ["position", {"nodes": ["t1", "t2"], "target": -1}]
  //

  // TODO: we could use Graph.set which computes a rather minimal set of ArrayOps
  //       to get rid of the ArrayOperation dependency here
  this.position = function(graph, command) {
    var path = command.path.concat(["nodes"]);
    var view = graph.resolve(path).get();
    var nodes = command.args.nodes;
    var ops = [];
    var idx;

    // Create a sequence of atomic array operations that
    // are bundled into a Compound operation
    // 1. Remove elements (from right to left)
    // 2. Insert at the very position

    // the sequence contains selected nodes in the order they
    // occurr in the view
    var seq = _.intersection(view, nodes);
    var l = view.length;

    while(seq.length > 0) {
      var id = seq.pop();
      idx = view.indexOf(id);
      if (idx >= 0) {
        ops.push(ot.ArrayOperation.Delete(idx, id));
        l--;
      }
    }

    // target index can be given as negative number (as known from python/ruby)
    var target = Math.min(command.args.target, l);
    if (target<0) target = Math.max(0, l+target+1);

    for (idx = 0; idx < nodes.length; idx++) {
      ops.push(ot.ArrayOperation.Insert(target + idx, nodes[idx]));
    }

    var compound = ot.ArrayOperation.Compound(ops);

    return Data.Graph.Update(path, compound);
  };

  // Update incrementally
  // --------
  //

  // TODO: if we would integrate the convenience mechanisms for update and set into
  // Data.Graph, we could get rid of the OT dependencies here.

  this.update = function(graph, command) {
    var property = graph.resolve(command.path);
    var val = property.get();
    var valueType = property.baseType;

    var update;

    if (valueType === 'string') {
      update = ot.TextOperation.fromOT(val, command.args);
    }
    else if (valueType === 'array') {
      throw new Error("Not yet implemented for arrays");
    }
    else if (valueType === 'object') {
      update = ot.ObjectOperation.Extend(val, command.args);
    }
    else {
      throw new Error("Unsupported type for update: " + valueType);
    }
    return Data.Graph.Update(command.path, update);
  };

  // Annotate document
  // --------
  //
  // `command.path` defines the referenced content node and property
  // ["annotate", "t1", "content", {"id": "a1",  type": "idea"}]

  this.annotate = function(graph, command) {
    // TODO: check if source exists, otherwise reject annotation
    if (command.path.length !== 2) throw new Error("Invalid target: " + command.path);

    var annotation = _.extend({}, command.args, {
      node: command.path[0],
      property: command.path[1]
    });

    return Data.Graph.Create(annotation);
  };

  // Comment
  // --------
  //
  // `command.path` holds the node id, where the comment should stick on

  this.comment = function(graph, command) {
    // Delegates to graph.create method
    // TODO: check if source exists, otherwise reject annotation

    // keep track of annotation
    if (command.path.length !== 1) throw new Error("Invalid target: " + command.path);

    var comment = _.extend({}, command.args);
    comment.node = command.path[0];
    comment.type = comment.type || 'comment';

    return Data.Graph.Create(comment);
  };
};
Document.__prototype__.prototype = Data.Graph.prototype;
Document.prototype = new Document.__prototype__();
// Add convenience accessors for builtin document attributes
Object.defineProperties(Document.prototype, {
  id: {
    get: function () {
      return this.get("document").id;
    }
  },
  creator: {
    get: function () {
      return this.get("document").creator;
    }
  },
  created_at: {
    get: function () {
      return this.get("document").created_at;
    }
  },
  views: {
    get: function () {
      return this.get("document").views;
    }
  }
});

// AnnotatedText
// --------
//
// Ties together a text node with its annotations
// Interface defined by Substance.Surface

var AnnotatedText = function(doc, path) {
  this.doc = doc;
  this.path = path;
  this.property = doc.resolve(path);
  this.resetCache();
};

AnnotatedText.__prototype__ = function() {

  this.setAnnotation = function(annotation) {
    this.cache.annotations[annotation.id] = annotation;
    this.commit();
  };

  this.getAnnotation = function(id) {
    return this.cache.annotations[id] || this.doc.get(id);
  };

  this.deleteAnnotation = function(id) {
    delete this.cache.annotations[id];
    this.cache.deleted_annotations.push(id);
  };

  this.setContent = function(content) {
    this.cache.content = content;
  };

  this.getContent = function() {
    if (this.cache.content !== null) return this.cache.content;
    return this.property.get();
  };

  // Transform Hook
  // --------
  //

  this.each = function(fn) {
    var annos = this.doc.find('annotations', this.property.node.id);
    _.each(this.cache.annotations, fn);

    _.each(annos, function(a) {
      if (!this.cache.annotations[a.id] && !_.include(this.cache.deleted_annotations, a.id)) fn(a, a.id);
    }, this);
  };

  // Transform Hook
  // --------
  //
  // triggered implicitly by Surface.insert|deleteTransformer)

  this.transformAnnotation = function(a, op, expand) {
    if (this.cache.annotations[a.id]) {
      a = this.cache.annotations[a.id];
    } else {
      a = util.deepclone(a);
    }
    ot.TextOperation.Range.transform(a.range, op, expand);
    this.cache.annotations[a.id] = a;
  };

  this.resetCache = function() {
    this.cache = {
      annotations: {},
      content: null,
      deleted_annotations: []
    };
  };

  // Commit changes
  // --------
  //

  this.commit = function() {

    // 1. Insert Annotations
    var newAnnotations = [];
    var updatedAnnotations = [];
    _.each(this.cache.annotations, function(a) {
      var oa = this.doc.get(a.id);
      if (!oa) newAnnotations.push(a);
      else if (a.type !== oa.type) updatedAnnotations.push(a);
    }, this);

    var cmds = [];

    _.each(newAnnotations, function(a) {
      a.node = this.property.node.id;
      cmds.push(Document.Create(a));
    }, this);

    // Text diff computation
    if (this.cache.content !== null) {
      var delta = _.extractOperation(this.property.get(), this.cache.content);
      cmds.push(Data.Graph.Update(this.path, ot.TextOperation.fromOT(delta)));
    }

    _.each(cmds, function(c) {
      this.doc.exec(c);
    }, this);
    this.resetCache();
  };
};
AnnotatedText.prototype = new AnnotatedText.__prototype__();

// Command Factories
// --------

Document.Create = function(node) {
  return Data.Graph.Create(node);
};

Document.Delete = function(nodes) {
  return ["delete", {nodes: nodes}];
};

Document.COMMANDS = _.extend({}, Data.COMMANDS, {
  "position": {
    "types": ["array"],
    "arguments": 1
  },
  "hide": {
    "types": ["array"],
    "arguments": 1
  },
  "delete": {
    "types": ["graph"],
    "arguments": 1
  },
  "annotate": {
    "types": ["content"],
    "arguments": 1
  },
  "comment": {
    "types": ["content", "annotation"],
    "arguments": 1
  }
});

// Add event support
_.extend(Document.prototype, util.Events);

Document.SCHEMA = SCHEMA;
Document.AnnotatedText = AnnotatedText;

// Export
// ========

if (typeof exports !== 'undefined') {
  module.exports = Document;
} else {
  root.Substance.Document = Document;
}

})(this);
<|endoftext|>


<commit_before>// Generated by CoffeeScript 1.7.1
(function() {
  var $, Document;

  Document = function(s) {
    if (!s || s === document) {
      return document;
    }
    if (typeof s === 'function') {
      document.ready(s);
      void 0;
    }
    this.init = function(s) {
      var s0;
      if (s === document) {
        return s;
      }
      if (s === 'html') {
        return document.documentElement;
      }
      if (s === 'head') {
        return document.head;
      }
      if (s === 'body') {
        return document.body;
      }
      if (s.indexOf(',' === -1)) {
        s0 = s[0];
        s = s.substr(1);
        if (s0 === '#') {
          return this.byId(s);
        } else if (s0 === '.') {
          return this.byClass(s);
        } else {
          return this.byTag(s0 + s);
        }
      }
      return this.bySelectors(s);
    };
    this.byId = function(s) {
      return document.getElementById(s);
    };
    this.byClass = function(s) {
      return document.getElementsByClassName(s);
    };
    this.byTag = function(s) {
      return document.getElementsByTagName(s);
    };
    this.bySelectors = function(ss) {
      var i, list, selectors;
      selectors = ss.split(",");
      list = [];
      i = selectors.length - 1;
      while (i >= 0) {
        list.push(this.bySelector(selectors[i]));
        i--;
      }
      return list;
    };
    this.bySelector = function(s) {
      var s0;
      s0 = s[0];
      s = s.substr(1);
      if (s0 === '#') {
        return this.byId(s);
      } else if (s0 === '.') {
        return this.byClass(s);
      } else {
        return false;
      }
    };
    return this.init(s);
  };

  HTMLDocument.prototype.ready = function(f) {
    return document.onreadystatechange = function() {
      if (document.readyState === "complete") {
        return f();
      }
    };
  };

  Element.prototype.html = function(v) {
    if (!v) {
      return this.innerHTML;
    }
    this.innerHTML = "" + v;
    return this;
  };

  Element.prototype.val = function(v) {
    if (!v) {
      return this.value;
    }
    this.value = v;
    return this;
  };

  Element.prototype.attr = function(k, v) {
    if (!v) {
      return this.getAttribute(k);
    }
    this.setAttribute(k, v);
    return this;
  };

  Element.prototype.clear = function() {
    while (this.firstChild) {
      this.firstChild.remove();
    }
    return this;
  };

  NodeList.prototype.clear = function() {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.clear();
    }
    return this;
  };

  Element.prototype.addClass = function(c) {
    this.className += " " + c + " ";
    return this;
  };

  NodeList.prototype.addClass = function(c) {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.addClass();
    }
    return this;
  };

  Element.prototype.removeClass = function(c) {
    var r;
    r = new RegExp("\\s" + c + '\\s?', 'gi');
    this.className = (" " + this.className).replace(r, '');
    if (this.className[0] === ' ') {
      this.className = this.className.substr(1);
    }
    return this;
  };

  NodeList.prototype.removeClass = function(c) {
    var el, i;
    i = this.length - 1;
    while (i >= 0) {
      el = this[i];
      el.removeClass(c);
      i--;
    }
    return this;
  };

  Element.prototype.hasClass = function(c) {
    return this.className.split(" ").indexOf(c) !== -1;
  };

  Element.prototype.show = function() {
    return this.style.display = '';
  };

  NodeList.prototype.show = function() {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.show();
    }
    return this;
  };

  Element.prototype.hide = function() {
    return this.style.display = 'none';
  };

  NodeList.prototype.hide = function() {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.hide();
    }
    return this;
  };

  Element.prototype.css = function(k, v) {
    if (!k) {
      return this.style;
    }
    if (!v) {
      if (this.style.hasOwnProperty(k)) {
        return this.style[k];
      }
    }
    k = k.toCamelCase();
    if (this.style.hasOwnProperty(k)) {
      this.style[k] = v;
    }
    return this;
  };

  NodeList.prototype.css = function(k, v) {
    var el, _i, _len;
    if (!v) {
      return void 0;
    }
    k = k.toCamelCase();
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.css(k, v);
    }
    return this;
  };

  String.prototype.toCamelCase = function() {
    return this.toLowerCase().replace(/-(.)/g, function(m, g) {
      return g.toUpperCase();
    });
  };

  Element.prototype.on = function(evt, callback) {
    this.addEventListener(evt, callback);
    return this;
  };

  NodeList.prototype.on = function(evt, callback) {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.addEventListener(evt, callback);
    }
    return this;
  };

  $ = Document;

  window.$ = $;

}).call(this);
<commit_msg>No more Coffee here<commit_after>(function() {
  var $, Document;

  Document = function(s) {
    if (!s || s === document) {
      return document;
    }
    if (typeof s === 'function') {
      document.ready(s);
      void 0;
    }
    this.init = function(s) {
      var s0;
      if (s === document) {
        return s;
      }
      if (s === 'html') {
        return document.documentElement;
      }
      if (s === 'head') {
        return document.head;
      }
      if (s === 'body') {
        return document.body;
      }
      if (s.indexOf(',' === -1)) {
        s0 = s[0];
        s = s.substr(1);
        if (s0 === '#') {
          return this.byId(s);
        } else if (s0 === '.') {
          return this.byClass(s);
        } else {
          return this.byTag(s0 + s);
        }
      }
      return this.bySelectors(s);
    };
    this.byId = function(s) {
      return document.getElementById(s);
    };
    this.byClass = function(s) {
      return document.getElementsByClassName(s);
    };
    this.byTag = function(s) {
      return document.getElementsByTagName(s);
    };
    this.bySelectors = function(ss) {
      var i, list, selectors;
      selectors = ss.split(",");
      list = [];
      i = selectors.length - 1;
      while (i >= 0) {
        list.push(this.bySelector(selectors[i]));
        i--;
      }
      return list;
    };
    this.bySelector = function(s) {
      var s0;
      s0 = s[0];
      s = s.substr(1);
      if (s0 === '#') {
        return this.byId(s);
      } else if (s0 === '.') {
        return this.byClass(s);
      } else {
        return false;
      }
    };
    return this.init(s);
  };

  HTMLDocument.prototype.ready = function(f) {
    return document.onreadystatechange = function() {
      if (document.readyState === "complete") {
        return f();
      }
    };
  };

  Element.prototype.html = function(v) {
    if (!v) {
      return this.innerHTML;
    }
    this.innerHTML = "" + v;
    return this;
  };

  Element.prototype.val = function(v) {
    if (!v) {
      return this.value;
    }
    this.value = v;
    return this;
  };

  Element.prototype.attr = function(k, v) {
    if (!v) {
      return this.getAttribute(k);
    }
    this.setAttribute(k, v);
    return this;
  };

  Element.prototype.clear = function() {
    while (this.firstChild) {
      this.firstChild.remove();
    }
    return this;
  };

  NodeList.prototype.clear = function() {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.clear();
    }
    return this;
  };

  Element.prototype.addClass = function(c) {
    this.className += " " + c + " ";
    return this;
  };

  NodeList.prototype.addClass = function(c) {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.addClass();
    }
    return this;
  };

  Element.prototype.removeClass = function(c) {
    var r;
    r = new RegExp("\\s" + c + '\\s?', 'gi');
    this.className = (" " + this.className).replace(r, '');
    if (this.className[0] === ' ') {
      this.className = this.className.substr(1);
    }
    return this;
  };

  NodeList.prototype.removeClass = function(c) {
    var el, i;
    i = this.length - 1;
    while (i >= 0) {
      el = this[i];
      el.removeClass(c);
      i--;
    }
    return this;
  };

  Element.prototype.hasClass = function(c) {
    return this.className.split(" ").indexOf(c) !== -1;
  };

  Element.prototype.show = function() {
    return this.style.display = '';
  };

  NodeList.prototype.show = function() {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.show();
    }
    return this;
  };

  Element.prototype.hide = function() {
    return this.style.display = 'none';
  };

  NodeList.prototype.hide = function() {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.hide();
    }
    return this;
  };

  Element.prototype.css = function(k, v) {
    if (!k) {
      return this.style;
    }
    if (!v) {
      if (this.style.hasOwnProperty(k)) {
        return this.style[k];
      }
    }
    k = k.toCamelCase();
    if (this.style.hasOwnProperty(k)) {
      this.style[k] = v;
    }
    return this;
  };

  NodeList.prototype.css = function(k, v) {
    var el, _i, _len;
    if (!v) {
      return void 0;
    }
    k = k.toCamelCase();
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.css(k, v);
    }
    return this;
  };

  String.prototype.toCamelCase = function() {
    return this.toLowerCase().replace(/-(.)/g, function(m, g) {
      return g.toUpperCase();
    });
  };

  Element.prototype.on = function(evt, callback) {
    this.addEventListener(evt, callback);
    return this;
  };

  NodeList.prototype.on = function(evt, callback) {
    var el, _i, _len;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      el = this[_i];
      el.addEventListener(evt, callback);
    }
    return this;
  };

  $ = Document;

  window.$ = $;

}).call(this);
<|endoftext|>


<commit_before>var path = require('path')
var fs = require('fs')
var get = require('simple-get')
var pump = require('pump')
var tfs = require('tar-fs')
var zlib = require('zlib')
var util = require('./util')

function downloadPrebuild (opts, cb) {
  var downloadUrl = util.getDownloadUrl(opts)
  var cachedPrebuild = util.cachedPrebuild(downloadUrl)
  var localPrebuild = util.localPrebuild(downloadUrl)
  var tempFile = util.tempFile(cachedPrebuild)

  var rc = opts.rc
  var log = opts.log

  if (opts.nolocal) return download()

  log.info('looking for local prebuild @', localPrebuild)
  fs.exists(localPrebuild, function (exists) {
    if (exists) {
      log.info('found local prebuild')
      cachedPrebuild = localPrebuild
      return unpack()
    }

    download()
  })

  function download () {
    ensureNpmCacheDir(function (err) {
      if (err) return onerror(err)

      log.info('looking for cached prebuild @', cachedPrebuild)
      fs.exists(cachedPrebuild, function (exists) {
        if (exists) {
          log.info('found cached prebuild')
          return unpack()
        }

        log.http('request', 'GET ' + downloadUrl)
        var req = get(downloadUrl, function (err, res) {
          if (err) return onerror(err)
          log.http(res.statusCode, downloadUrl)
          if (res.statusCode !== 200) return onerror()
          fs.mkdir(util.prebuildCache(), function () {
            log.info('downloading to @', tempFile)
            pump(res, fs.createWriteStream(tempFile), function (err) {
              if (err) return onerror(err)
              fs.rename(tempFile, cachedPrebuild, function (err) {
                if (err) return cb(err)
                log.info('renaming to @', cachedPrebuild)
                unpack()
              })
            })
          })
        })

        req.setTimeout(30 * 1000, function () {
          req.abort()
        })
      })

      function onerror (err) {
        fs.unlink(tempFile, function () {
          cb(err || new Error('Prebuilt binaries for node version ' + process.version + ' are not available'))
        })
      }
    })
  }

  function unpack () {
    var binaryName

    var updateName = opts.updateName || function (entry) {
      if (/\.node$/i.test(entry.name)) binaryName = entry.name
    }

    log.info('unpacking @', cachedPrebuild)
    pump(fs.createReadStream(cachedPrebuild), zlib.createGunzip(), tfs.extract(rc.path, {readable: true, writable: true}).on('entry', updateName), function (err) {
      if (err) return cb(err)
      if (!binaryName) return cb(new Error('Missing .node file in archive'))

      var resolved
      try {
        resolved = path.resolve(rc.path || '.', binaryName)
      } catch (err) {
        return cb(err)
      }
      log.info('unpack', 'resolved to ' + resolved)

      if (rc.abi === process.versions.modules) {
        try {
          require(resolved)
        } catch (err) {
          return cb(err)
        }
        log.info('unpack', 'required ' + resolved + ' successfully')
        cb(null, resolved)
      } else {
        cb(null, resolved)
      }
    })
  }

  function ensureNpmCacheDir (cb) {
    var cacheFolder = util.npmCache()
    if (fs.access) {
      fs.access(cacheFolder, fs.R_OK | fs.W_OK, function (err) {
        if (err && err.code === 'ENOENT') {
          return makeNpmCacheDir()
        }
        if (err) return cb(err)
        cb()
      })
    } else {
      fs.exists(cacheFolder, function (exists) {
        if (!exists) return makeNpmCacheDir()
        cb()
      })
    }

    function makeNpmCacheDir () {
      log.info('npm cache directory missing, creating it...')
      fs.mkdir(cacheFolder, function (err) {
        if (err) return cb(err)
        cb()
      })
    }
  }
}

module.exports = downloadPrebuild
<commit_msg>clean up callbacks in download<commit_after>var path = require('path')
var fs = require('fs')
var get = require('simple-get')
var pump = require('pump')
var tfs = require('tar-fs')
var zlib = require('zlib')
var util = require('./util')

function downloadPrebuild (opts, cb) {
  var downloadUrl = util.getDownloadUrl(opts)
  var cachedPrebuild = util.cachedPrebuild(downloadUrl)
  var localPrebuild = util.localPrebuild(downloadUrl)
  var tempFile = util.tempFile(cachedPrebuild)

  var rc = opts.rc
  var log = opts.log

  if (opts.nolocal) return download()

  log.info('looking for local prebuild @', localPrebuild)
  fs.exists(localPrebuild, function (exists) {
    if (exists) {
      log.info('found local prebuild')
      cachedPrebuild = localPrebuild
      return unpack()
    }

    download()
  })

  function download () {
    ensureNpmCacheDir(function (err) {
      if (err) return onerror(err)

      log.info('looking for cached prebuild @', cachedPrebuild)
      fs.exists(cachedPrebuild, function (exists) {
        if (exists) {
          log.info('found cached prebuild')
          return unpack()
        }

        log.http('request', 'GET ' + downloadUrl)
        var req = get(downloadUrl, function (err, res) {
          if (err) return onerror(err)
          log.http(res.statusCode, downloadUrl)
          if (res.statusCode !== 200) return onerror()
          fs.mkdir(util.prebuildCache(), function () {
            log.info('downloading to @', tempFile)
            pump(res, fs.createWriteStream(tempFile), function (err) {
              if (err) return onerror(err)
              fs.rename(tempFile, cachedPrebuild, function (err) {
                if (err) return cb(err)
                log.info('renaming to @', cachedPrebuild)
                unpack()
              })
            })
          })
        })

        req.setTimeout(30 * 1000, function () {
          req.abort()
        })
      })

      function onerror (err) {
        fs.unlink(tempFile, function () {
          cb(err || new Error('Prebuilt binaries for node version ' + process.version + ' are not available'))
        })
      }
    })
  }

  function unpack () {
    var binaryName

    var updateName = opts.updateName || function (entry) {
      if (/\.node$/i.test(entry.name)) binaryName = entry.name
    }

    log.info('unpacking @', cachedPrebuild)
    pump(fs.createReadStream(cachedPrebuild), zlib.createGunzip(), tfs.extract(rc.path, {readable: true, writable: true}).on('entry', updateName), function (err) {
      if (err) return cb(err)
      if (!binaryName) return cb(new Error('Missing .node file in archive'))

      var resolved
      try {
        resolved = path.resolve(rc.path || '.', binaryName)
      } catch (err) {
        return cb(err)
      }
      log.info('unpack', 'resolved to ' + resolved)

      if (rc.abi === process.versions.modules) {
        try {
          require(resolved)
        } catch (err) {
          return cb(err)
        }
        log.info('unpack', 'required ' + resolved + ' successfully')
      }
      cb(null, resolved)
    })
  }

  function ensureNpmCacheDir (cb) {
    var cacheFolder = util.npmCache()
    if (fs.access) {
      fs.access(cacheFolder, fs.R_OK | fs.W_OK, function (err) {
        if (err && err.code === 'ENOENT') {
          return makeNpmCacheDir()
        }
        cb(err)
      })
    } else {
      fs.exists(cacheFolder, function (exists) {
        if (!exists) return makeNpmCacheDir()
        cb()
      })
    }

    function makeNpmCacheDir () {
      log.info('npm cache directory missing, creating it...')
      fs.mkdir(cacheFolder, cb)
    }
  }
}

module.exports = downloadPrebuild
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import flatten from 'lodash/flatten';
import sortBy from 'lodash/sortBy';
import groupBy from 'lodash/groupBy';
import omit from 'lodash/omit';
import Fuse from 'fuse.js';

// Components
import Tabs from 'components/ui/Tabs';
import Tag from 'components/ui/Tag';
import Icon from 'components/ui/Icon';

import CheckboxGroup from 'components/form/CheckboxGroup';

class SearchComponent extends React.Component {
  static propTypes = {
    open: PropTypes.bool,
    list: PropTypes.array,
    options: PropTypes.object,
    selected: PropTypes.object,
    tab: PropTypes.string,
    search: PropTypes.string,

    // CALLBACKS
    onChangeOpen: PropTypes.func,
    onChangeTab: PropTypes.func,
    onChangeSearch: PropTypes.func,
    onToggleSelected: PropTypes.func,
    onChangeSelected: PropTypes.func,
    onResetSelected: PropTypes.func
  };

  constructor(props) {
    super(props);

    const { list } = props;

    this.fuse = new Fuse(list, {
      keys: [{
        name: 'label',
        weight: 0.6
      }, {
        name: 'synonyms',
        weight: 0.3
      }, {
        name: 'id',
        weight: 0.1
      }],
      threshold: 0.2,
      minMatchCharLength: 2
    });
  }

  state = {
    index: 0,
    value: '',
    filteredList: []
  }

  // UI EVENTS:
  // - onScreenClick
  // - onScreenKeyup
  // - onToggleOpen
  // - onKeyArrow
  // - onChangeTab
  // - onChangeSearch
  onScreenClick = (e) => {
    const el = document.querySelector('.c-dataset-search');
    const clickOutside = el && el.contains && !el.contains(e.target);

    if (clickOutside) {
      this.onToggleOpen(false);
    }
  }

  onScreenKeyup = (e) => {
    switch (e.keyCode) {
      case 27:
        this.onToggleOpen(false);
        break;

      // ENTER
      case 13:
        this.onKeyEnter();
        break;

      // ARROWS
      case 38:
        this.onKeyArrow('up');
        break;

      case 40:
        this.onKeyArrow('down');
        break;

      default:
        return true;
    }
  }

  onToggleOpen = (to) => {
    requestAnimationFrame(() => {
      if (to) {
        window.addEventListener('click', this.onScreenClick);
        window.addEventListener('keyup', this.onScreenKeyup);
      } else {
        window.removeEventListener('click', this.onScreenClick);
        window.removeEventListener('keyup', this.onScreenKeyup);
        this.setState({
          index: 0,
          filteredList: [],
          value: ''
        });
        if (this.input) this.input.blur();
      }
    });

    this.props.onChangeOpen(to);
  }

  onKeyArrow = (direction) => {
    const { index, filteredList } = this.state;
    if (direction === 'up') {
      this.setState({
        index: (index !== 0) ? index - 1 : filteredList.length
      });
    }

    if (direction === 'down') {
      this.setState({
        index: (index !== filteredList.length) ? index + 1 : 0
      });
    }
  }

  onKeyEnter = () => {
    const tabs = this.getTabs();
    const { value, index, groupedFilteredList } = this.state;

    if (index === 0) {
      this.props.onChangeSearch(value);
    }

    if (index !== 0) {
      const filteredList = flatten(Object.keys(groupedFilteredList).map(g =>
        groupedFilteredList[g]));

      const l = filteredList[index - 1];
      this.props.onToggleSelected({
        tag: l,
        tab: (tabs.find(t => t.type === l.labels[1]) || {}).value || 'custom'
      });
    }

    this.onToggleOpen(false);
  }

  onListItemMouseOver = (index) => {
    this.setState({
      index
    });
  }

  onChangeTab = (t) => {
    const { tab } = this.props;
    if (t === tab) {
      this.onToggleOpen(false);
    } else {
      this.props.onChangeTab(t);
    }
  }

  onChangeSearch = (e) => {
    const { value } = e.currentTarget;

    const filteredList = (value.length > 2) ? sortBy(this.fuse.search(value), 'label') : [];

    this.setState({
      index: 0,
      value,
      filteredList,
      groupedFilteredList: omit(groupBy(filteredList, l => l.labels[1]), 'undefined')
    });
  }

  // HELPERS
  getTabs = () => {
    const {
      options, selected
    } = this.props;

    return Object
      .keys(options)
      .filter((o) => {
        if (o === 'custom') {
          return selected.custom.length;
        }
        return o !== 'custom';
      })
      .map(o => ({
        label: options[o].label,
        value: options[o].value,
        type: options[o].type,
        ...selected[o].length && { number: selected[o].length }
      }));
  }

  render() {
    const {
      open, search, options, selected, tab, list
    } = this.props;

    const {
      index, value, groupedFilteredList
    } = this.state;

    let groupedFilteredListIndex = 0;

    const tabs = this.getTabs();

    const mainArr = options[tab].list;
    const secondaryArr = selected[tab]
      .filter(s => !options[tab].list.find(l => l.id === s))
      .map(s => list.find(l => l.id === s));

    const selectedAllArr = flatten(Object.keys(selected).map(s =>
      selected[s].map(c =>
        ({ ...list.find(o => o.id === c), tab: s }))));

    return (

        {/* Search */}

          <button
            className={classnames({
              'search-icon': true,
              '-search': true
            })}
          >
            <Icon name="icon-search" className="-small" />
          </button>

          <input
            ref={(c) => { this.input = c; }}
            className={classnames({
              'search-input': true,
              '-open': open
            })}
            type="search"
            placeholder="Search and filter datasets"
            value={value}
            onClick={() => this.onToggleOpen(true)}
            onChange={this.onChangeSearch}
          />

          <button
            className={classnames({
              'search-icon': true,
              '-arrow': true,
              '-open': open
            })}
            onClick={() => this.onToggleOpen(!open)}
          >
            <Icon name="icon-arrow-down-2" className="-small" />
          </button>

        {/* Dropdown */}
        {open && !value &&

            <Tabs
              className="-dark -no-margin"
              options={tabs}
              defaultSelected={tab}
              selected={tab}
              onChange={this.onChangeTab}
            />

              {!!mainArr.length &&
                <CheckboxGroup
                  name="mainArr"
                  selected={selected[tab]}
                  className="mainArr-checkbox-group"
                  options={mainArr.map(o => ({ value: o.id, label: o.label }))}
                  onChange={s => this.props.onChangeSelected(s)}
                />
              }

              {!!secondaryArr.length &&
                <CheckboxGroup
                  name="secondaryArr"
                  selected={selected[tab]}
                  className="secondaryArr-checkbox-group"
                  options={secondaryArr.map(o => ({ value: o.id, label: o.label }))}
                  onChange={s => this.props.onChangeSelected(s)}
                />
              }

        }

        {/* Dropdown search */}
        {open && value &&

Search by text:

                    <button
                      type="button"
                      className={classnames({
                        '-active': index === 0
                      })}
                      onClick={() => this.props.onChangeSearch(value)}
                      onMouseOver={() => this.onListItemMouseOver(0)}
                    >
                      {value}
                    </button>

              {Object.keys(groupedFilteredList).map(g => (

Filter by {g.toLowerCase()}:

                    {groupedFilteredList[g].map((l) => {
                      const currentIndex = ++groupedFilteredListIndex;

                      return (

                          <button
                            type="button"
                            className={classnames({
                              '-active': index === currentIndex
                            })}
                            onClick={() => {
                              this.props.onToggleSelected({
                                tag: l,
                                tab: (tabs.find(t => t.type === l.labels[1]) || {}).value || 'custom'
                              });

                              this.onToggleOpen(false);
                            }}
                            onMouseOver={() => this.onListItemMouseOver(currentIndex)}
                          >
                            {l.label}
                          </button>

                      );
                    })}

              ))}

        }

        {/* Selected */}
        {!open && (!!selectedAllArr.length || !!search) &&

              {!!search &&
                <Tag
                  key="clear-search"
                  name={`Text: ${search}`}
                  className="-secondary"
                  isRemovable
                  onClick={() => this.props.onChangeSearch('')}
                />
              }

              {selectedAllArr.map(s => (
                <Tag
                  key={s.id}
                  name={s.label}
                  className="-secondary"
                  isRemovable
                  onClick={() => this.props.onToggleSelected({ tag: s, tab: s.tab })}
                />
              ))}

              <Tag
                key="clear-filters"
                name="Clear filters"
                className="-primary"
                onClick={() => this.props.onResetSelected()}
              />

        }

    );
  }
}

export default SearchComponent;
<commit_msg>Reset groupedFilteredList<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import flatten from 'lodash/flatten';
import sortBy from 'lodash/sortBy';
import groupBy from 'lodash/groupBy';
import omit from 'lodash/omit';
import Fuse from 'fuse.js';

// Components
import Tabs from 'components/ui/Tabs';
import Tag from 'components/ui/Tag';
import Icon from 'components/ui/Icon';

import CheckboxGroup from 'components/form/CheckboxGroup';

class SearchComponent extends React.Component {
  static propTypes = {
    open: PropTypes.bool,
    list: PropTypes.array,
    options: PropTypes.object,
    selected: PropTypes.object,
    tab: PropTypes.string,
    search: PropTypes.string,

    // CALLBACKS
    onChangeOpen: PropTypes.func,
    onChangeTab: PropTypes.func,
    onChangeSearch: PropTypes.func,
    onToggleSelected: PropTypes.func,
    onChangeSelected: PropTypes.func,
    onResetSelected: PropTypes.func
  };

  constructor(props) {
    super(props);

    const { list } = props;

    this.fuse = new Fuse(list, {
      keys: [{
        name: 'label',
        weight: 0.6
      }, {
        name: 'synonyms',
        weight: 0.3
      }, {
        name: 'id',
        weight: 0.1
      }],
      threshold: 0.2,
      minMatchCharLength: 2
    });
  }

  state = {
    index: 0,
    value: '',
    filteredList: [],
    groupedFilteredList: {}
  }

  // UI EVENTS:
  // - onScreenClick
  // - onScreenKeyup
  // - onToggleOpen
  // - onKeyArrow
  // - onChangeTab
  // - onChangeSearch
  onScreenClick = (e) => {
    const el = document.querySelector('.c-dataset-search');
    const clickOutside = el && el.contains && !el.contains(e.target);

    if (clickOutside) {
      this.onToggleOpen(false);
    }
  }

  onScreenKeyup = (e) => {
    switch (e.keyCode) {
      case 27:
        this.onToggleOpen(false);
        break;

      // ENTER
      case 13:
        this.onKeyEnter();
        break;

      // ARROWS
      case 38:
        this.onKeyArrow('up');
        break;

      case 40:
        this.onKeyArrow('down');
        break;

      default:
        return true;
    }
  }

  onToggleOpen = (to) => {
    requestAnimationFrame(() => {
      if (to) {
        window.addEventListener('click', this.onScreenClick);
        window.addEventListener('keyup', this.onScreenKeyup);
      } else {
        window.removeEventListener('click', this.onScreenClick);
        window.removeEventListener('keyup', this.onScreenKeyup);
        this.setState({
          index: 0,
          value: '',
          filteredList: [],
          groupedFilteredList: {}
        });
        if (this.input) this.input.blur();
      }
    });

    this.props.onChangeOpen(to);
  }

  onKeyArrow = (direction) => {
    const { index, filteredList } = this.state;
    if (direction === 'up') {
      this.setState({
        index: (index !== 0) ? index - 1 : filteredList.length
      });
    }

    if (direction === 'down') {
      this.setState({
        index: (index !== filteredList.length) ? index + 1 : 0
      });
    }
  }

  onKeyEnter = () => {
    const tabs = this.getTabs();
    const { value, index, groupedFilteredList } = this.state;

    if (index === 0) {
      this.props.onChangeSearch(value);
    }

    if (index !== 0) {
      const filteredList = flatten(Object.keys(groupedFilteredList).map(g =>
        groupedFilteredList[g]));

      const l = filteredList[index - 1];
      this.props.onToggleSelected({
        tag: l,
        tab: (tabs.find(t => t.type === l.labels[1]) || {}).value || 'custom'
      });
    }

    this.onToggleOpen(false);
  }

  onListItemMouseOver = (index) => {
    this.setState({ index });
  }

  onChangeTab = (t) => {
    const { tab } = this.props;
    if (t === tab) {
      this.onToggleOpen(false);
    } else {
      this.props.onChangeTab(t);
    }
  }

  onChangeSearch = (e) => {
    const { value } = e.currentTarget;

    const filteredList = (value.length > 2) ? sortBy(this.fuse.search(value), 'label') : [];

    this.setState({
      index: 0,
      value,
      filteredList,
      groupedFilteredList: omit(groupBy(filteredList, l => l.labels[1]), 'undefined')
    });
  }

  // HELPERS
  getTabs = () => {
    const {
      options, selected
    } = this.props;

    return Object
      .keys(options)
      .filter((o) => {
        if (o === 'custom') {
          return selected.custom.length;
        }
        return o !== 'custom';
      })
      .map(o => ({
        label: options[o].label,
        value: options[o].value,
        type: options[o].type,
        ...selected[o].length && { number: selected[o].length }
      }));
  }

  render() {
    const {
      open, search, options, selected, tab, list
    } = this.props;

    const {
      index, value, groupedFilteredList
    } = this.state;

    let groupedFilteredListIndex = 0;

    const tabs = this.getTabs();

    const mainArr = options[tab].list;
    const secondaryArr = selected[tab]
      .filter(s => !options[tab].list.find(l => l.id === s))
      .map(s => list.find(l => l.id === s));

    const selectedAllArr = flatten(Object.keys(selected).map(s =>
      selected[s].map(c =>
        ({ ...list.find(o => o.id === c), tab: s }))));

    return (

        {/* Search */}

          <button
            className={classnames({
              'search-icon': true,
              '-search': true
            })}
          >
            <Icon name="icon-search" className="-small" />
          </button>

          <input
            ref={(c) => { this.input = c; }}
            className={classnames({
              'search-input': true,
              '-open': open
            })}
            type="search"
            placeholder="Search and filter datasets"
            value={value}
            onClick={() => this.onToggleOpen(true)}
            onChange={this.onChangeSearch}
          />

          <button
            className={classnames({
              'search-icon': true,
              '-arrow': true,
              '-open': open
            })}
            onClick={() => this.onToggleOpen(!open)}
          >
            <Icon name="icon-arrow-down-2" className="-small" />
          </button>

        {/* Dropdown */}
        {open && !value &&

            <Tabs
              className="-dark -no-margin"
              options={tabs}
              defaultSelected={tab}
              selected={tab}
              onChange={this.onChangeTab}
            />

              {!!mainArr.length &&
                <CheckboxGroup
                  name="mainArr"
                  selected={selected[tab]}
                  className="mainArr-checkbox-group"
                  options={mainArr.map(o => ({ value: o.id, label: o.label }))}
                  onChange={s => this.props.onChangeSelected(s)}
                />
              }

              {!!secondaryArr.length &&
                <CheckboxGroup
                  name="secondaryArr"
                  selected={selected[tab]}
                  className="secondaryArr-checkbox-group"
                  options={secondaryArr.map(o => ({ value: o.id, label: o.label }))}
                  onChange={s => this.props.onChangeSelected(s)}
                />
              }

        }

        {/* Dropdown search */}
        {open && value &&

Search by text:

                    <button
                      type="button"
                      className={classnames({
                        '-active': index === 0
                      })}
                      onClick={() => this.props.onChangeSearch(value)}
                      onMouseOver={() => this.onListItemMouseOver(0)}
                    >
                      {value}
                    </button>

              {Object.keys(groupedFilteredList).map(g => (

Filter by {g.toLowerCase()}:

                    {groupedFilteredList[g].map((l) => {
                      const currentIndex = ++groupedFilteredListIndex;

                      return (

                          <button
                            type="button"
                            className={classnames({
                              '-active': index === currentIndex
                            })}
                            onClick={() => {
                              this.props.onToggleSelected({
                                tag: l,
                                tab: (tabs.find(t => t.type === l.labels[1]) || {}).value || 'custom'
                              });

                              this.onToggleOpen(false);
                            }}
                            onMouseOver={() => this.onListItemMouseOver(currentIndex)}
                          >
                            {l.label}
                          </button>

                      );
                    })}

              ))}

        }

        {/* Selected */}
        {!open && (!!selectedAllArr.length || !!search) &&

              {!!search &&
                <Tag
                  key="clear-search"
                  name={`Text: ${search}`}
                  className="-secondary"
                  isRemovable
                  onClick={() => this.props.onChangeSearch('')}
                />
              }

              {selectedAllArr.map(s => (
                <Tag
                  key={s.id}
                  name={s.label}
                  className="-secondary"
                  isRemovable
                  onClick={() => this.props.onToggleSelected({ tag: s, tab: s.tab })}
                />
              ))}

              <Tag
                key="clear-filters"
                name="Clear filters"
                className="-primary"
                onClick={() => this.props.onResetSelected()}
              />

        }

    );
  }
}

export default SearchComponent;
<|endoftext|>


<commit_before>var creep_farMining = {

	/** @param {Creep} creep **/
	run: function(creep) {
		if (creep.memory.priority == 'farClaimer' || creep.memory.priority == 'farClaimerNearDeath') {
			if (creep.ticksToLive <= 20) {
				creep.memory.priority == 'farClaimerNearDeath';
				creep.room.visual.text("\u2620\u27A1\uD83D\uDEA9", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			} else {
				creep.room.visual.text("\u27A1\uD83D\uDEA9", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			}

			if (creep.room.name != creep.memory.destination) {
				creep.moveTo(new RoomPosition(25, 25, creep.memory.destination));
			} else {
				if (creep.room.controller.reservation && (creep.room.name == creep.memory.destination)) {
					if (creep.room.controller.reservation.ticksToEnd <= 1000) {
						Memory.FarClaimerNeeded[creep.room.name] = true;
					} else {
						Memory.FarClaimerNeeded[creep.room.name] = false;
					}
				} else if (creep.room.name == creep.memory.destination) {
					Memory.FarClaimerNeeded[creep.room.name] = true;
				}

				if (creep.reserveController(creep.room.controller) == ERR_NOT_IN_RANGE) {
					creep.moveTo(creep.room.controller, {
						reusePath: 25
					});
				}
			}
		} else if (creep.memory.priority == 'farMiner' || creep.memory.priority == 'farMinerNearDeath') {
			if (creep.ticksToLive <= 60) {
				creep.memory.priority == 'farMinerNearDeath';
				creep.room.visual.text("\u2620\u27A1\u26CF", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			} else {
				creep.room.visual.text("\u27A1\u26CF", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			}

			if (creep.room.name != creep.memory.destination) {
				creep.moveTo(new RoomPosition(25, 25, creep.memory.destination), {
					reusePath: 25
				});
			} else {
				if (creep.room.controller.reservation && (creep.room.name == creep.memory.destination)) {
					if (creep.room.controller.reservation.ticksToEnd <= 1000) {
						Memory.FarClaimerNeeded[creep.room.name] = true;
					} else {
						Memory.FarClaimerNeeded[creep.room.name] = false;
					}
				} else if (creep.room.name == creep.memory.destination) {
					Memory.FarClaimerNeeded[creep.room.name] = true;
				}

				var mineTarget = "";

				if (creep.memory.mineSource) {
					mineTarget = Game.getObjectById(creep.memory.mineSource);
					if (mineTarget && _.sum(creep.carry) <= 35) {
						if (creep.harvest(mineTarget) == ERR_NOT_IN_RANGE) {
							creep.moveTo(mineTarget, {
								reusePath: 25
							});
						}
					}
				} else {
					//Get the source ID while in the room
					var markedSources = [];
					if (Game.flags[creep.memory.targetFlag]) {
						markedSources = Game.flags[creep.memory.targetFlag].pos.lookFor(LOOK_SOURCES);
					}
					if (markedSources.length) {
						creep.memory.mineSource = markedSources[0].id;
					}
					mineTarget = Game.getObjectById(creep.memory.mineSource);
					if (mineTarget) {
						if (creep.harvest(mineTarget) == ERR_NOT_IN_RANGE) {
							creep.moveTo(mineTarget, {
								reusePath: 25
							});
						}
					}
				}

				if (creep.memory.storageUnit) {
					var thisUnit = Game.getObjectById(creep.memory.storageUnit);
					if (thisUnit) {
						if (thisUnit.hits < thisUnit.hitsMax) {
							creep.repair(thisUnit);
						} else {
							if (creep.transfer(thisUnit, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
								creep.moveTo(thisUnit, {
									reusePath: 25
								});
							}
						}
					}
				} else {
					if (mineTarget) {
						if (creep.pos.inRangeTo(mineTarget, 5)) {
							var containers = creep.pos.findInRange(FIND_STRUCTURES, 5, {
								filter: (structure) => structure.structureType == STRUCTURE_CONTAINER
							});
							if (containers.length) {
								if (creep.transfer(containers[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
									creep.moveTo(containers[0], {
										reusePath: 25
									});
								}
								creep.memory.storageUnit = containers[0].id;
							} else {
								var sites = creep.pos.findInRange(FIND_CONSTRUCTION_SITES, 5)
								if (sites.length) {
									if (creep.build(sites[0]) == ERR_NOT_IN_RANGE) {
										creep.moveTo(sites[0], {
											reusePath: 25
										});
									}
								} else {
									//Create new container
									if (creep.pos.isNearTo(mineTarget)) {
										creep.room.createConstructionSite(creep.pos, STRUCTURE_CONTAINER)
									}
								}
							}
						}
					}
				}
			}
		} else if (creep.memory.priority == 'farMule' || creep.memory.priority == 'farMuleNearDeath') {
			if (creep.ticksToLive <= 170) {
				creep.memory.priority = 'farMuleNearDeath';
				creep.room.visual.text("\u2620\u27A1\uD83D\uDC02", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			} else {
				creep.room.visual.text("\u27A1\uD83D\uDC02", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			}

			if (creep.room.name != creep.memory.destination && _.sum(creep.carry) <= 800) {
				var droppedSources = creep.pos.findInRange(FIND_DROPPED_ENERGY, 3);
				if (droppedSources.length) {
					//Pick up dropped energy from dead mules, etc.
					if (creep.pickup(droppedSources[0]) == ERR_NOT_IN_RANGE) {
						creep.moveTo(droppedSources[0], {
							reusePath: 25
						});
					}
				} else {
					creep.moveTo(new RoomPosition(25, 25, creep.memory.destination), {
						reusePath: 25
					});
				}
			} else if (creep.room.name != creep.memory.homeRoom && _.sum(creep.carry) > 800) {
				creep.moveTo(new RoomPosition(25, 25, creep.memory.homeRoom), {
					reusePath: 25
				});
			} else {
				if (creep.room.controller.reservation && (creep.room.name == creep.memory.destination)) {
					if (creep.room.controller.reservation.ticksToEnd <= 1000) {
						Memory.FarClaimerNeeded[creep.room.name] = true;
					} else {
						Memory.FarClaimerNeeded[creep.room.name] = false;
					}
				} else if (creep.room.name == creep.memory.destination) {
					Memory.FarClaimerNeeded[creep.room.name] = true;
				}

				if (_.sum(creep.carry) <= 800) {
					var droppedSources = creep.pos.findInRange(FIND_DROPPED_ENERGY, 10);
					if (droppedSources.length) {
						//Pick up dropped energy from dead mules, etc.
						if (creep.pickup(droppedSources[0]) == ERR_NOT_IN_RANGE) {
							creep.moveTo(droppedSources[0], {
								reusePath: 25
							});
						}
					} else {
						//in farRoom, pick up container contents
						if (creep.memory.containerTarget) {
							var thisContainer = Game.getObjectById(creep.memory.containerTarget);
							if (thisContainer) {
								if (thisContainer.store[RESOURCE_ENERGY] > 0) {
									if (creep.withdraw(thisContainer, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
										creep.moveTo(thisContainer, {
											reusePath: 25,
											ignoreRoads: true
										});
									}
								} else {
									//Wait by controller
									creep.moveTo(creep.room.controller);
								}

							}
						} else {
							//No container yet, move to be near source
							if (!creep.memory.mineSource) {
								var markedSources = [];
								if (Game.flags[creep.memory.targetFlag]) {
									markedSources = Game.flags[creep.memory.targetFlag].pos.lookFor(LOOK_SOURCES);
								}
								if (markedSources.length) {
									creep.memory.mineSource = markedSources[0].id;
								}
							}

							var thisSource = Game.getObjectById(creep.memory.mineSource);
							if (thisSource) {
								creep.moveTo(thisSource, {
									reusePath: 25,
									ignoreRoads: true
								});
								if (creep.pos.inRangeTo(thisSource, 5)) {
									//Search for container
									var containers = creep.pos.findInRange(FIND_STRUCTURES, 5, {
										filter: (structure) => structure.structureType == STRUCTURE_CONTAINER
									});
									if (containers.length) {
										creep.memory.containerTarget = containers[0].id;
										if (creep.withdraw(containers[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
											creep.moveTo(containers[0], {
												reusePath: 25,
												ignoreRoads: true
											});
										}
									}
								}
							}
						}
					}
				} else {
					//in home room, drop off energy
					var storageUnit = Game.getObjectById(creep.memory.storageSource)
					if (storageUnit) {
						if (creep.transfer(storageUnit, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
							creep.moveTo(storageUnit, {
								reusePath: 25,
								ignoreRoads: true
							});
						}
					}
				}
			}
		} else if (creep.memory.priority == 'farGuard' || creep.memory.priority == 'farGuardNearDeath') {
			if (creep.ticksToLive <= 70) {
				creep.memory.priority == 'farGuardNearDeath';
				creep.room.visual.text("\u2620\u27A1\u2694", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			} else {
				creep.room.visual.text("\u27A1\u2694", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			}

			if (creep.hits < creep.hitsMax) {
				creep.heal(creep);
			}

			if (creep.room.controller.reservation && (creep.room.name == creep.memory.destination)) {
				if (creep.room.controller.reservation.ticksToEnd <= 1000) {
					Memory.FarClaimerNeeded[creep.room.name] = true;
				} else {
					Memory.FarClaimerNeeded[creep.room.name] = false;
				}
			} else if (creep.room.name == creep.memory.destination) {
				Memory.FarClaimerNeeded[creep.room.name] = true;
			}

			var Foe = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
			if (Foe) {
				if (creep.room.controller.owner && creep.room.controller.owner.username != "Montblanc") {
					//Guard specific spot, fire at things nearby
					try {
						creep.moveTo(Game.flags[creep.memory.targetFlag].pos);
					} catch (e) {
						//Eat it
					}
					if (creep.pos.getRangeTo(Foe) <= 3) {
						creep.attack(Foe);
						creep.rangedAttack(Foe);
					}
				} else {
					if (creep.pos.getRangeTo(Foe) > 3 || (Foe.getActiveBodyparts(ATTACK) == 0)) {
						creep.moveTo(Foe);
						creep.attack(Foe);
						creep.rangedAttack(Foe);
					} else {
						var foeDirection = creep.pos.getDirectionTo(Foe);
						var evadeDirection = TOP;
						switch (foeDirection) {
							case TOP:
								evadeDirection = BOTTOM;
								break;
							case TOP_RIGHT:
								evadeDirection = BOTTOM_LEFT;
								break;
							case RIGHT:
								evadeDirection = LEFT;
								break;
							case BOTTOM_RIGHT:
								evadeDirection = TOP_LEFT;
								break;
							case BOTTOM:
								evadeDirection = TOP;
								break;
							case BOTTOM_LEFT:
								evadeDirection = TOP_RIGHT;
								break;
							case LEFT:
								evadeDirection = RIGHT;
								break;
							case TOP_LEFT:
								evadeDirection = BOTTOM_RIGHT;
								break;
						}
						creep.move(evadeDirection);
						creep.attack(Foe);
						creep.rangedAttack(Foe);
					}
				}
			} else if (creep.room.controller.owner && creep.room.controller.owner.username != "Montblanc") {
				var hSpawn = creep.pos.findClosestByRange(FIND_HOSTILE_SPAWNS);
				if (hSpawn) {
					creep.moveTo(hSpawn);
					creep.attack(hSpawn);
					creep.rangedAttack(hSpawn);
				} else {
					try {
						creep.moveTo(Game.flags[creep.memory.targetFlag].pos);
					} catch (e) {
						//Eat it
					}
				}
			} else if (creep.room.name != creep.memory.destination) {
				creep.moveTo(new RoomPosition(25, 25, creep.memory.destination), {
					reusePath: 25
				});
			} else if (Game.flags[creep.memory.targetFlag]) {
				if (creep.pos != Game.flags[creep.memory.targetFlag].pos) {
					creep.moveTo(Game.flags[creep.memory.targetFlag]);
				}
			}
		}
	}
};
module.exports = creep_farMining;<commit_msg>PLEASE STOP EMAILING ME<commit_after>var creep_farMining = {

	/** @param {Creep} creep **/
	run: function(creep) {
		if (creep.memory.priority == 'farClaimer' || creep.memory.priority == 'farClaimerNearDeath') {
			if (creep.ticksToLive <= 20) {
				creep.memory.priority == 'farClaimerNearDeath';
				creep.room.visual.text("\u2620\u27A1\uD83D\uDEA9", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			} else {
				creep.room.visual.text("\u27A1\uD83D\uDEA9", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			}

			if (creep.room.name != creep.memory.destination) {
				creep.moveTo(new RoomPosition(25, 25, creep.memory.destination));
			} else {
				if (creep.room.controller.reservation && (creep.room.name == creep.memory.destination)) {
					if (creep.room.controller.reservation.ticksToEnd <= 1000) {
						Memory.FarClaimerNeeded[creep.room.name] = true;
					} else {
						Memory.FarClaimerNeeded[creep.room.name] = false;
					}
				} else if (creep.room.name == creep.memory.destination) {
					Memory.FarClaimerNeeded[creep.room.name] = true;
				}

				if (creep.reserveController(creep.room.controller) == ERR_NOT_IN_RANGE) {
					creep.moveTo(creep.room.controller, {
						reusePath: 25
					});
				}
			}
		} else if (creep.memory.priority == 'farMiner' || creep.memory.priority == 'farMinerNearDeath') {
			if (creep.ticksToLive <= 60) {
				creep.memory.priority == 'farMinerNearDeath';
				creep.room.visual.text("\u2620\u27A1\u26CF", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			} else {
				creep.room.visual.text("\u27A1\u26CF", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			}

			if (creep.room.name != creep.memory.destination) {
				creep.moveTo(new RoomPosition(25, 25, creep.memory.destination), {
					reusePath: 25
				});
			} else {
				if (creep.room.controller.reservation && (creep.room.name == creep.memory.destination)) {
					if (creep.room.controller.reservation.ticksToEnd <= 1000) {
						Memory.FarClaimerNeeded[creep.room.name] = true;
					} else {
						Memory.FarClaimerNeeded[creep.room.name] = false;
					}
				} else if (creep.room.name == creep.memory.destination) {
					Memory.FarClaimerNeeded[creep.room.name] = true;
				}

				var mineTarget = "";

				if (creep.memory.mineSource) {
					mineTarget = Game.getObjectById(creep.memory.mineSource);
					if (mineTarget && _.sum(creep.carry) <= 35) {
						if (creep.harvest(mineTarget) == ERR_NOT_IN_RANGE) {
							creep.moveTo(mineTarget, {
								reusePath: 25
							});
						}
					}
				} else {
					//Get the source ID while in the room
					var markedSources = [];
					if (Game.flags[creep.memory.targetFlag]) {
						markedSources = Game.flags[creep.memory.targetFlag].pos.lookFor(LOOK_SOURCES);
					}
					if (markedSources.length) {
						creep.memory.mineSource = markedSources[0].id;
					}
					mineTarget = Game.getObjectById(creep.memory.mineSource);
					if (mineTarget) {
						if (creep.harvest(mineTarget) == ERR_NOT_IN_RANGE) {
							creep.moveTo(mineTarget, {
								reusePath: 25
							});
						}
					}
				}

				if (creep.memory.storageUnit) {
					var thisUnit = Game.getObjectById(creep.memory.storageUnit);
					if (thisUnit) {
						if (thisUnit.hits < thisUnit.hitsMax) {
							creep.repair(thisUnit);
						} else {
							if (creep.transfer(thisUnit, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
								creep.moveTo(thisUnit, {
									reusePath: 25
								});
							}
						}
					}
				} else {
					if (mineTarget) {
						if (creep.pos.inRangeTo(mineTarget, 5)) {
							var containers = creep.pos.findInRange(FIND_STRUCTURES, 5, {
								filter: (structure) => structure.structureType == STRUCTURE_CONTAINER
							});
							if (containers.length) {
								if (creep.transfer(containers[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
									creep.moveTo(containers[0], {
										reusePath: 25
									});
								}
								creep.memory.storageUnit = containers[0].id;
							} else {
								var sites = creep.pos.findInRange(FIND_CONSTRUCTION_SITES, 5)
								if (sites.length) {
									if (creep.build(sites[0]) == ERR_NOT_IN_RANGE) {
										creep.moveTo(sites[0], {
											reusePath: 25
										});
									}
								} else {
									//Create new container
									if (creep.pos.isNearTo(mineTarget)) {
										creep.room.createConstructionSite(creep.pos, STRUCTURE_CONTAINER)
									}
								}
							}
						}
					}
				}
			}
		} else if (creep.memory.priority == 'farMule' || creep.memory.priority == 'farMuleNearDeath') {
			if (creep.ticksToLive <= 170) {
				creep.memory.priority = 'farMuleNearDeath';
				creep.room.visual.text("\u2620\u27A1\uD83D\uDC02", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			} else {
				creep.room.visual.text("\u27A1\uD83D\uDC02", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			}

			if (creep.room.name != creep.memory.destination && _.sum(creep.carry) <= 800) {
				var droppedSources = creep.pos.findInRange(FIND_DROPPED_ENERGY, 3);
				if (droppedSources.length) {
					//Pick up dropped energy from dead mules, etc.
					if (creep.pickup(droppedSources[0]) == ERR_NOT_IN_RANGE) {
						creep.moveTo(droppedSources[0], {
							reusePath: 25
						});
					}
				} else {
					creep.moveTo(new RoomPosition(25, 25, creep.memory.destination), {
						reusePath: 25
					});
				}
			} else if (creep.room.name != creep.memory.homeRoom && _.sum(creep.carry) > 800) {
				creep.moveTo(new RoomPosition(25, 25, creep.memory.homeRoom), {
					reusePath: 25
				});
			} else {
				if (creep.room.controller.reservation && (creep.room.name == creep.memory.destination)) {
					if (creep.room.controller.reservation.ticksToEnd <= 1000) {
						Memory.FarClaimerNeeded[creep.room.name] = true;
					} else {
						Memory.FarClaimerNeeded[creep.room.name] = false;
					}
				} else if (creep.room.name == creep.memory.destination) {
					Memory.FarClaimerNeeded[creep.room.name] = true;
				}

				if (_.sum(creep.carry) <= 800) {
					var droppedSources = creep.pos.findInRange(FIND_DROPPED_ENERGY, 10);
					if (droppedSources.length) {
						//Pick up dropped energy from dead mules, etc.
						if (creep.pickup(droppedSources[0]) == ERR_NOT_IN_RANGE) {
							creep.moveTo(droppedSources[0], {
								reusePath: 25
							});
						}
					} else {
						//in farRoom, pick up container contents
						if (creep.memory.containerTarget) {
							var thisContainer = Game.getObjectById(creep.memory.containerTarget);
							if (thisContainer) {
								if (thisContainer.store[RESOURCE_ENERGY] > 0) {
									if (creep.withdraw(thisContainer, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
										creep.moveTo(thisContainer, {
											reusePath: 25,
											ignoreRoads: true
										});
									}
								} else {
									//Wait by controller
									creep.moveTo(creep.room.controller);
								}

							}
						} else {
							//No container yet, move to be near source
							if (!creep.memory.mineSource) {
								var markedSources = [];
								if (Game.flags[creep.memory.targetFlag]) {
									markedSources = Game.flags[creep.memory.targetFlag].pos.lookFor(LOOK_SOURCES);
								}
								if (markedSources.length) {
									creep.memory.mineSource = markedSources[0].id;
								}
							}

							var thisSource = Game.getObjectById(creep.memory.mineSource);
							if (thisSource) {
								creep.moveTo(thisSource, {
									reusePath: 25,
									ignoreRoads: true
								});
								if (creep.pos.inRangeTo(thisSource, 5)) {
									//Search for container
									var containers = creep.pos.findInRange(FIND_STRUCTURES, 5, {
										filter: (structure) => structure.structureType == STRUCTURE_CONTAINER
									});
									if (containers.length) {
										creep.memory.containerTarget = containers[0].id;
										if (creep.withdraw(containers[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
											creep.moveTo(containers[0], {
												reusePath: 25,
												ignoreRoads: true
											});
										}
									}
								}
							}
						}
					}
				} else {
					//in home room, drop off energy
					var storageUnit = Game.getObjectById(creep.memory.storageSource)
					if (storageUnit) {
						if (creep.transfer(storageUnit, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
							creep.moveTo(storageUnit, {
								reusePath: 25,
								ignoreRoads: true
							});
						}
					}
				}
			}
		} else if (creep.memory.priority == 'farGuard' || creep.memory.priority == 'farGuardNearDeath') {
			creep.notifyWhenAttacked(false);
			if (creep.ticksToLive <= 70) {
				creep.memory.priority == 'farGuardNearDeath';
				creep.room.visual.text("\u2620\u27A1\u2694", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			} else {
				creep.room.visual.text("\u27A1\u2694", creep.pos.x, creep.pos.y, {
					align: 'left',
					color: '#7DE3B5'
				});
			}

			if (creep.hits < creep.hitsMax) {
				creep.heal(creep);
			}

			if (creep.room.controller.reservation && (creep.room.name == creep.memory.destination)) {
				if (creep.room.controller.reservation.ticksToEnd <= 1000) {
					Memory.FarClaimerNeeded[creep.room.name] = true;
				} else {
					Memory.FarClaimerNeeded[creep.room.name] = false;
				}
			} else if (creep.room.name == creep.memory.destination) {
				Memory.FarClaimerNeeded[creep.room.name] = true;
			}

			var Foe = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
			if (Foe) {
				if (creep.room.controller.owner && creep.room.controller.owner.username != "Montblanc") {
					//Guard specific spot, fire at things nearby
					try {
						creep.moveTo(Game.flags[creep.memory.targetFlag].pos);
					} catch (e) {
						//Eat it
					}
					if (creep.pos.getRangeTo(Foe) <= 3) {
						creep.attack(Foe);
						creep.rangedAttack(Foe);
					}
				} else {
					if (creep.pos.getRangeTo(Foe) > 3 || (Foe.getActiveBodyparts(ATTACK) == 0)) {
						creep.moveTo(Foe);
						creep.attack(Foe);
						creep.rangedAttack(Foe);
					} else {
						var foeDirection = creep.pos.getDirectionTo(Foe);
						var evadeDirection = TOP;
						switch (foeDirection) {
							case TOP:
								evadeDirection = BOTTOM;
								break;
							case TOP_RIGHT:
								evadeDirection = BOTTOM_LEFT;
								break;
							case RIGHT:
								evadeDirection = LEFT;
								break;
							case BOTTOM_RIGHT:
								evadeDirection = TOP_LEFT;
								break;
							case BOTTOM:
								evadeDirection = TOP;
								break;
							case BOTTOM_LEFT:
								evadeDirection = TOP_RIGHT;
								break;
							case LEFT:
								evadeDirection = RIGHT;
								break;
							case TOP_LEFT:
								evadeDirection = BOTTOM_RIGHT;
								break;
						}
						creep.move(evadeDirection);
						creep.attack(Foe);
						creep.rangedAttack(Foe);
					}
				}
			} else if (creep.room.controller.owner && creep.room.controller.owner.username != "Montblanc") {
				var hSpawn = creep.pos.findClosestByRange(FIND_HOSTILE_SPAWNS);
				if (hSpawn) {
					creep.moveTo(hSpawn);
					creep.attack(hSpawn);
					creep.rangedAttack(hSpawn);
				} else {
					try {
						creep.moveTo(Game.flags[creep.memory.targetFlag].pos);
					} catch (e) {
						//Eat it
					}
				}
			} else if (creep.room.name != creep.memory.destination) {
				creep.moveTo(new RoomPosition(25, 25, creep.memory.destination), {
					reusePath: 25
				});
			} else if (Game.flags[creep.memory.targetFlag]) {
				if (creep.pos != Game.flags[creep.memory.targetFlag].pos) {
					creep.moveTo(Game.flags[creep.memory.targetFlag]);
				}
			}
		}
	}
};
module.exports = creep_farMining;<|endoftext|>