<commit_before>(function() {

class LinkedList {

  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
    this.allIds = [];
  }

  makeId() {
    let text = "";
    let possible = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    const makeString = () => {
      // string is 20 chars long.  Can change if desired
      for (var i = 0; i < 20; i++) {
        text += possible.charAt(Math.floor(Math.random() * possible.length));
      }
      if (this.allIds.indexOf(text) !== -1) {
        text = "";
        makeString();
      }
    }
    makeString();
    this.allIds.push(text);
    return text;
  }

//-- CREATE --------------------------------
  addToHead(val) { // Adds a node to head
    const makeNode = {
      value: val,
      __id: this.makeId(),
      next: this.head
    }
    if (!this.head) {
      this.tail = makeNode;
      this.head = makeNode;
      this.length = 1;
    } else {
      let oldHead = this.head;
      makeNode.next = oldHead;
      this.head = makeNode;
      this.length +=1;
    }
  }

  addToTail(val) { // Adds a node to tail
    const makeNode = {
      value: val,
      __id: this.makeId(),
      next: null
    }
    if (!this.tail) {
      this.tail = makeNode;
      this.head = makeNode;
      this.length = 1;
    } else {
      this.tail.next = makeNode;
      this.tail = makeNode;
      this.length +=1;
    }
  }

  insertAfterValue(lookupVal, val) {
    // Given a lookupVal and value, it acts similar to addToTail, except it creates a node after the input node
    const makeNode = {
      value: val,
      __id: this.makeId(),
      next: null
    }
    const sub = (currentNode) => {
      if (currentNode.value === lookupVal) {
        //insert node;
      let breakList = currentNode.next;
      makeNode.next = breakList;
      currentNode.next = makeNode;
      this.length +=1;
      return;
      }
      if (!currentNode.next) {
        console.log('lookupVal not found: ', lookupVal);
        return 'lookupVal not found';
      }
      sub(currentNode.next)
    }
    sub(this.head);
  }

  insertAfterId(id, val) {
    // Given an ID and value, it acts similar to addToTail, except it creates a node after the input node
    const makeNode = {
      value: val,
      __id: this.makeId(),
      next: null
    }
    const sub = (currentNode) => {
      if (currentNode.__id === id) {
        //insert node;
      let breakList = currentNode.next;
      makeNode.next = breakList;
      currentNode.next = makeNode;
      this.length +=1;
      return;
      }
      if (!currentNode.next) {
        console.log('id not found: ', id);
        return 'id not found';
      }
      sub(currentNode.next)
    }
    sub(this.head);
  }

//-- LOOKUP --------------------------------
  readValueAtId(id) { // Updated value at node with selected ID
    const sub = (node) => {
      if (node.__id === id) {
        return node.value;
      }
      if (!node.next) {
        console.log('ID not found: ', id);
        return -1;
      }
      return sub(node.next)
    }
    return sub(this.head);
  }

  containsValue(val) { // Returns a boolean indicating whether the input value is present
    const sub = (node) => {
      if (node.value === val) {
        return true;
      }
      if (!node.next) {
        return false;
      }
      return sub(node.next)
    }
    return sub(this.head);
  }

  containsId(id) { // Returns a boolean indicating whether the input ID is present
    const sub = (node) => {
      if (node.__id === id) {
        return true;
      }
      if (!node.next) {
        return false;
      }
      return sub(node.next)
    }
    return sub(this.head);
  }

  indexOfValue(val) { // Returns the numerical order or "index" of the node with value. Returns -1 if not present
    let index = 0;
    const sub = (node) => {
      if (node.value === val) {
        return index;
      }
      if (!node.next) {
        return -1;
      }
      index +=1;
      return sub(node.next)
    }
    return sub(this.head);
  }

  indexOfId(id) { // Returns the numerical order or "index" of the node with ID. Returns -1 if not present
    let index = 0;
    const sub = (node) => {
      if (node.__id === id) {
        return index;
      }
      if (!node.next) {
        return -1;
      }
      index +=1;
      return sub(node.next)
    }
    return sub(this.head);
  }

//-- UPDATE --------------------------------
  updateValueAtId(id, val) { // Updated value at node with selected ID
    const sub = (node) => {
      if (node.__id === id) {
        node.value = val;
        return node.value;
      }
      if (!node.next) {
        console.log('ID not found: ', id);
        return -1;
      }
      return sub(node.next)
    }
    return sub(this.head);
  }

//-- DELETE --------------------------------
  deleteHead() {
    if (!this.head) {
      return
    }
    if (!this.head.next) {
      this.head = null;
      this.tail = null;
      this.length = 0;
      return
    }
    let breakList = this.head.next;
    this.head = breakList
    this.length -=1;
    return
  }

  deleteTail() {
    if (!this.tail) {
      return
    }
    if (!this.head.next) {
      this.head = null;
      this.tail = null;
      this.length = 0;
      return
    }
    //recurse checking next.next
    const sub = (node) => {
      if (!node.next.next) {
        node.next = null;
        this.tail = node;
        return
      }
      sub(node.next)
    }
    sub(this.head)
    this.length -=1;
    return
  }

  deleteNodeValue(val) {
    const sub = (node) => {
      // if node is head
      if (node.value === val && node === this.head) {
        this.deleteHead();
        return
      }
      // node not found
      if (!node.next) {
        console.log('node not found: ', val);
        return 'node not found';
      }
      // if node is not head
      if (node.next.value === val) {
        // if node is tail
        if (!node.next.next) {
          this.deleteTail();
          return
        }
        let breakList = node.next.next;
        node.next = breakList
        this.length -=1;
        return
      }
      sub(node.next)
    }
    sub(this.head);
  }

  deleteNodeId(id) {
    const sub = (node) => {
      // if node is head
      if (node.__id === id && node === this.head) {
        this.deleteHead();
        return
      }
      // node not found
      if (!node.next) {
        console.log('node not found: ', id);
        return;
      }
      // if node is not head
      if (node.next.__id === id) {
        // if node is tail
        if (!node.next.next) {
          this.deleteTail();
          return
        }
        let breakList = node.next.next;
        node.next = breakList
        this.length -=1;
        return
      }
      sub(node.next)
    }
    sub(this.head);
  }

//-- HELPER --------------------------------
  onEach(cb) {
    if (!this.head) {
      return
    }
    const sub = (node) => {
      node.value = cb(node.value);
      if (!node.next) {
        return
      }
      sub(node.next);
    }
    sub(this.head);
  }

  mapToArray(cb) {
    if (!this.head) {
      return [];
    }
    let resultsArray = [];
    const sub = (node) => {
      if (cb) {
        resultsArray.push(cb(node.value));
      } else {
        resultsArray.push(node.value);
      }
      if (!node.next) {
        return [];
      }
      sub(node.next);
    }
    sub(this.head);
    return resultsArray;
  }

  filterToArray(cb) {
    if (!this.head) {
      return [];
    }
    let resultsArray = [];
    const sub = (node) => {
      if (cb(node.value)) {
        resultsArray.push(node.value);
      }
      if (!node.next) {
        return [];
      }
      sub(node.next)
    }
    sub(this.head);
    return resultsArray;
  }

  sortedListMerge (newNode, cb) {
    let mergedArray = [];
    const sub = (node) => {
      if (node) {
        mergedArray.push({value: node.value, __id: node.__id})
        sub(node.next)
      }
      return
    }
    sub(this.head);
    sub(newNode.head);
    if (cb) {
      mergedArray.sort(cb);
    } else {
      mergedArray.sort(function(a, b) {return a.value - b.value});
    }
    this.head = null;
    this.tail = null;

    const sub2 = (node) => {
      const makeNode = {
        value: node.value,
        __id: node.__id,
        next: this.head
      }
      if (!this.head) {
        this.tail = makeNode;
        this.head = makeNode;
        this.length = 1;
      } else {
        let oldHead = this.head;
        makeNode.next = oldHead;
        this.head = makeNode;
        this.length +=1;
      }
      if (mergedArray.length) {
        sub2(mergedArray.pop())
      } else {
        return
      }
    }
    sub2(mergedArray.pop())
  }

//-- DIGNOSTIC -----------------------------
  hasCycle() {
    let counter = 0;
    let lastId;
    let testHead = this.head;
    const sub = (node) => {
      if (node.counter) {
        testHead = {};
        console.log('Node with circular ref at index: ', counter, ' Between ID ', lastId, ' and ID ', node.__id);
        return true;
      }
      if (!node.counter || node.counter !== 0) {
        if (!node.next) {
          testHead = {};
          return false;
        }
        node.counter = counter;
        counter +=1;
        lastId = node.__id
        return sub(node.next);
      }
    }
    return sub(testHead);
  }

  reverseList() {
    if (!this.head || !this.head.next) {
      return
    }

    let temp = [];
    const sub = (node) => {
      if (node) {
        temp.push({value: node.value, __id: node.__id})
        sub(node.next)
      }
      return
    }
    sub(this.head)

    this.head = null;
    this.tail = null;

    const sub2 = (node) => {
      const makeNode = {
        value: node.value,
        __id: node.__id,
        next: this.head
      }
      if (!this.head) {
        this.tail = makeNode;
        this.head = makeNode;
        this.length = 1;
      } else {
        let oldHead = this.head;
        makeNode.next = oldHead;
        this.head = makeNode;
        this.length +=1;
      }
      if (temp.length) {
        sub2(temp.shift())
      } else {
        return
      }
    }
    sub2(temp.shift())
  }

  sortList(callback) {
    if (!this.head || !this.head.next) {
      return
    }
    let temp = [];
    const sub = (node) => {
      if (node) {
        temp.push({value: node.value, __id: node.__id})
        sub(node.next)
      }
      return
    }
    sub(this.head)

    if (callback) {
      temp.sort(callback);
    } else {
      temp.sort(function(a, b) {return a.value - b.value});
    }
    this.head = null;
    this.tail = null;

    const sub2 = (node) => {
      const makeNode = {
        value: node.value,
        __id: node.__id,
        next: this.head
      }
      if (!this.head) {
        this.tail = makeNode;
        this.head = makeNode;
        this.length = 1;
      } else {
        let oldHead = this.head;
        makeNode.next = oldHead;
        this.head = makeNode;
        this.length +=1;
      }
      if (temp.length) {
        sub2(temp.pop())
      } else {
        return
      }
    }
    sub2(temp.pop())

  }

  lookupTime(id) {
    if (!this.head || !this.head.next) {
      return '0ms';
    }
    if (!id) {
      const start = new Date().getTime();
      let count = 0;
      const sub = (node) => {
        if (count === this.length-1) {
          const end = new Date().getTime();
          return (end - start) + 'ms';
        }
        count++;
        return sub(node.next)
      }
      return sub(this.head);
    } else {
      const start = new Date().getTime();
      const sub = (node) => {
        if (node.__id === id) {
          const end = new Date().getTime();
          return (end - start) + 'ms';
        }
        return sub(node.next)
      }
      return sub(this.head);
    }
  }

  removeDuplicates() {
    if (!this.head || !this.head.next) {
      return;
    }
    let cache = {};
    const sub = (node) => {
      if (!cache[node.value]) {
        cache[node.value] = node.__id;
      } else {
        this.deleteNodeId(node.__id);
      }
      if (!node.next) {
        return;
      }
      sub(node.next)
    }
    sub(this.head)
  }

}

module.exports = LinkedList;
}.call(this));<commit_msg>Begin removal of recursion from Linked List<commit_after>(function() {

class LinkedList {

  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
    this.allIds = [];
  }

  makeId() {
    let text = "";
    let possible = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    const makeString = () => {
      // string is 20 chars long.  Can change if desired
      for (var i = 0; i < 20; i++) {
        text += possible.charAt(Math.floor(Math.random() * possible.length));
      }
      if (this.allIds.indexOf(text) !== -1) {
        text = "";
        makeString();
      }
    }
    makeString();
    this.allIds.push(text);
    return text;
  }

//-- CREATE --------------------------------
  addToHead(val) { // Adds a node to head
    const makeNode = {
      value: val,
      __id: this.makeId(),
      next: this.head
    }
    if (!this.head) {
      this.tail = makeNode;
      this.head = makeNode;
      this.length = 1;
    } else {
      let oldHead = this.head;
      makeNode.next = oldHead;
      this.head = makeNode;
      this.length +=1;
    }
  }

  addToTail(val) { // Adds a node to tail
    const makeNode = {
      value: val,
      __id: this.makeId(),
      next: null
    }
    if (!this.tail) {
      this.tail = makeNode;
      this.head = makeNode;
      this.length = 1;
    } else {
      this.tail.next = makeNode;
      this.tail = makeNode;
      this.length +=1;
    }
  }

  insertAfterValue(lookupVal, val) {
    // Given a lookupVal and value, it acts similar to addToTail, except it creates a node after the input node
    const makeNode = {
      value: val,
      __id: this.makeId(),
      next: null
    }
    let currentNode = this.head;
    while (currentNode) {
      if (currentNode.value === lookupVal) {
        //insert node;
        let breakList = currentNode.next;
        makeNode.next = breakList;
        currentNode.next = makeNode;
        this.length +=1;
        return;
      }
      if (!currentNode.next) {
        console.log('lookupVal not found: ', lookupVal);
        currentNode = false;
        return 'lookupVal not found';
      }
      currentNode = currentNode.next;
    }
  }

  insertAfterId(id, val) {
    // Given an ID and value, it acts similar to addToTail, except it creates a node after the input node
    const makeNode = {
      value: val,
      __id: this.makeId(),
      next: null
    }
    let currentNode = this.head;
    while (currentNode) {
      if (currentNode.__id === id) {
        //insert node;
        let breakList = currentNode.next;
        makeNode.next = breakList;
        currentNode.next = makeNode;
        this.length +=1;
        return;
      }
      if (!currentNode.next) {
        console.log('id not found: ', id);
        currentNode = false;
        return 'id not found';
      }
      currentNode = currentNode.next;
    }
  }

//-- LOOKUP --------------------------------
  readValueAtId(id) { // Updated value at node with selected ID
    const sub = (node) => {
      if (node.__id === id) {
        return node.value;
      }
      if (!node.next) {
        console.log('ID not found: ', id);
        return -1;
      }
      return sub(node.next)
    }
    return sub(this.head);
  }

  containsValue(val) { // Returns a boolean indicating whether the input value is present
    const sub = (node) => {
      if (node.value === val) {
        return true;
      }
      if (!node.next) {
        return false;
      }
      return sub(node.next)
    }
    return sub(this.head);
  }

  containsId(id) { // Returns a boolean indicating whether the input ID is present
    const sub = (node) => {
      if (node.__id === id) {
        return true;
      }
      if (!node.next) {
        return false;
      }
      return sub(node.next)
    }
    return sub(this.head);
  }

  indexOfValue(val) { // Returns the numerical order or "index" of the node with value. Returns -1 if not present
    let index = 0;
    const sub = (node) => {
      if (node.value === val) {
        return index;
      }
      if (!node.next) {
        return -1;
      }
      index +=1;
      return sub(node.next)
    }
    return sub(this.head);
  }

  indexOfId(id) { // Returns the numerical order or "index" of the node with ID. Returns -1 if not present
    let index = 0;
    const sub = (node) => {
      if (node.__id === id) {
        return index;
      }
      if (!node.next) {
        return -1;
      }
      index +=1;
      return sub(node.next)
    }
    return sub(this.head);
  }

//-- UPDATE --------------------------------
  updateValueAtId(id, val) { // Updated value at node with selected ID
    const sub = (node) => {
      if (node.__id === id) {
        node.value = val;
        return node.value;
      }
      if (!node.next) {
        console.log('ID not found: ', id);
        return -1;
      }
      return sub(node.next)
    }
    return sub(this.head);
  }

//-- DELETE --------------------------------
  deleteHead() {
    if (!this.head) {
      return
    }
    if (!this.head.next) {
      this.head = null;
      this.tail = null;
      this.length = 0;
      return
    }
    let breakList = this.head.next;
    this.head = breakList
    this.length -=1;
    return
  }

  deleteTail() {
    if (!this.tail) {
      return
    }
    if (!this.head.next) {
      this.head = null;
      this.tail = null;
      this.length = 0;
      return
    }
    //recurse checking next.next
    const sub = (node) => {
      if (!node.next.next) {
        node.next = null;
        this.tail = node;
        return
      }
      sub(node.next)
    }
    sub(this.head)
    this.length -=1;
    return
  }

  deleteNodeValue(val) {
    const sub = (node) => {
      // if node is head
      if (node.value === val && node === this.head) {
        this.deleteHead();
        return
      }
      // node not found
      if (!node.next) {
        console.log('node not found: ', val);
        return 'node not found';
      }
      // if node is not head
      if (node.next.value === val) {
        // if node is tail
        if (!node.next.next) {
          this.deleteTail();
          return
        }
        let breakList = node.next.next;
        node.next = breakList
        this.length -=1;
        return
      }
      sub(node.next)
    }
    sub(this.head);
  }

  deleteNodeId(id) {
    const sub = (node) => {
      // if node is head
      if (node.__id === id && node === this.head) {
        this.deleteHead();
        return
      }
      // node not found
      if (!node.next) {
        console.log('node not found: ', id);
        return;
      }
      // if node is not head
      if (node.next.__id === id) {
        // if node is tail
        if (!node.next.next) {
          this.deleteTail();
          return
        }
        let breakList = node.next.next;
        node.next = breakList
        this.length -=1;
        return
      }
      sub(node.next)
    }
    sub(this.head);
  }

//-- HELPER --------------------------------
  onEach(cb) {
    if (!this.head) {
      return
    }
    const sub = (node) => {
      node.value = cb(node.value);
      if (!node.next) {
        return
      }
      sub(node.next);
    }
    sub(this.head);
  }

  mapToArray(cb) {
    if (!this.head) {
      return [];
    }
    let resultsArray = [];
    const sub = (node) => {
      if (cb) {
        resultsArray.push(cb(node.value));
      } else {
        resultsArray.push(node.value);
      }
      if (!node.next) {
        return [];
      }
      sub(node.next);
    }
    sub(this.head);
    return resultsArray;
  }

  filterToArray(cb) {
    if (!this.head) {
      return [];
    }
    let resultsArray = [];
    const sub = (node) => {
      if (cb(node.value)) {
        resultsArray.push(node.value);
      }
      if (!node.next) {
        return [];
      }
      sub(node.next)
    }
    sub(this.head);
    return resultsArray;
  }

  sortedListMerge (newNode, cb) {
    let mergedArray = [];
    const sub = (node) => {
      if (node) {
        mergedArray.push({value: node.value, __id: node.__id})
        sub(node.next)
      }
      return
    }
    sub(this.head);
    sub(newNode.head);
    if (cb) {
      mergedArray.sort(cb);
    } else {
      mergedArray.sort(function(a, b) {return a.value - b.value});
    }
    this.head = null;
    this.tail = null;

    const sub2 = (node) => {
      const makeNode = {
        value: node.value,
        __id: node.__id,
        next: this.head
      }
      if (!this.head) {
        this.tail = makeNode;
        this.head = makeNode;
        this.length = 1;
      } else {
        let oldHead = this.head;
        makeNode.next = oldHead;
        this.head = makeNode;
        this.length +=1;
      }
      if (mergedArray.length) {
        sub2(mergedArray.pop())
      } else {
        return
      }
    }
    sub2(mergedArray.pop())
  }

//-- DIGNOSTIC -----------------------------
  hasCycle() {
    let counter = 0;
    let lastId;
    let testHead = this.head;
    const sub = (node) => {
      if (node.counter) {
        testHead = {};
        console.log('Node with circular ref at index: ', counter, ' Between ID ', lastId, ' and ID ', node.__id);
        return true;
      }
      if (!node.counter || node.counter !== 0) {
        if (!node.next) {
          testHead = {};
          return false;
        }
        node.counter = counter;
        counter +=1;
        lastId = node.__id
        return sub(node.next);
      }
    }
    return sub(testHead);
  }

  reverseList() {
    if (!this.head || !this.head.next) {
      return
    }

    let temp = [];
    const sub = (node) => {
      if (node) {
        temp.push({value: node.value, __id: node.__id})
        sub(node.next)
      }
      return
    }
    sub(this.head)

    this.head = null;
    this.tail = null;

    const sub2 = (node) => {
      const makeNode = {
        value: node.value,
        __id: node.__id,
        next: this.head
      }
      if (!this.head) {
        this.tail = makeNode;
        this.head = makeNode;
        this.length = 1;
      } else {
        let oldHead = this.head;
        makeNode.next = oldHead;
        this.head = makeNode;
        this.length +=1;
      }
      if (temp.length) {
        sub2(temp.shift())
      } else {
        return
      }
    }
    sub2(temp.shift())
  }

  sortList(callback) {
    if (!this.head || !this.head.next) {
      return
    }
    let temp = [];
    const sub = (node) => {
      if (node) {
        temp.push({value: node.value, __id: node.__id})
        sub(node.next)
      }
      return
    }
    sub(this.head)

    if (callback) {
      temp.sort(callback);
    } else {
      temp.sort(function(a, b) {return a.value - b.value});
    }
    this.head = null;
    this.tail = null;

    const sub2 = (node) => {
      const makeNode = {
        value: node.value,
        __id: node.__id,
        next: this.head
      }
      if (!this.head) {
        this.tail = makeNode;
        this.head = makeNode;
        this.length = 1;
      } else {
        let oldHead = this.head;
        makeNode.next = oldHead;
        this.head = makeNode;
        this.length +=1;
      }
      if (temp.length) {
        sub2(temp.pop())
      } else {
        return
      }
    }
    sub2(temp.pop())

  }

  lookupTime(id) {
    if (!this.head || !this.head.next) {
      return '0ms';
    }
    if (!id) {
      const start = new Date().getTime();
      let count = 0;
      const sub = (node) => {
        if (count === this.length-1) {
          const end = new Date().getTime();
          return (end - start) + 'ms';
        }
        count++;
        return sub(node.next)
      }
      return sub(this.head);
    } else {
      const start = new Date().getTime();
      const sub = (node) => {
        if (node.__id === id) {
          const end = new Date().getTime();
          return (end - start) + 'ms';
        }
        return sub(node.next)
      }
      return sub(this.head);
    }
  }

  removeDuplicates() {
    if (!this.head || !this.head.next) {
      return;
    }
    let cache = {};
    const sub = (node) => {
      if (!cache[node.value]) {
        cache[node.value] = node.__id;
      } else {
        this.deleteNodeId(node.__id);
      }
      if (!node.next) {
        return;
      }
      sub(node.next)
    }
    sub(this.head)
  }

}

module.exports = LinkedList;
}.call(this));<|endoftext|>


<commit_before>//Today we're going to get in a bunch of practice with objects.
//As you start your JS journey, there's a ton of value in just building out the muscle memory for the fundamentals.
//To get these fundamentals as deeply embedded as possible, type them out new each time. Avoid copying code, as you're just ignoring a chance to get in more useful practice.

// 1. To start, let's create a variable, mysticalAnimal, and set it equal to an object.

// Dot Notation:
// Recall that dot notation takes whatever is to the right of the dot, turns it into a string, and looks up that string as a property name in the object to the left of the dot.
// Let's use dot notation to add some properties to mysticalAnimal.
// 2. Add a type property, and set it equal to 'dragon'.
// 3. Add a name property, and set it equal to 'Leslie'.
// 4. Add a likes property, and set it equal to an empty array.
// 5. Add a property called bestFriend, and set it equal to your name.
// 6. Add in a superPower property. Set it equal to 'gives amazing hugs'.

// Access using dot notation
// 7. Now try to access all the values you've stored in mysticalAnimal. One at a time (not all at once!), what do you need to do to access the values:
  // 'dragon'
  // 'Larry'
  // []
  // your own name
  // 'gives amazing hugs'
// Hopefully this starts to feel somewhat repetitive- that's awesome! That means that you're learing this super well so far. If it doesn't, try going back and doing it again on your own time.

// Bracket notation:
// Recall that we can do two different things with bracket notation:
  // A. Evaluate a variable or expression, and look up what that variable evalutates to as a property name in the object.
  // B. Pass in a string (as noted by the quotes surrounding it) and look up that string as a property name in the object.

// 8. Create a variable called newPropertyToAdd, and set it equal to 'food'.

// 9. Now, using bracket notation and newPropertyToAdd, create a food property on our mysticalAnimal object, and set it equal to 'BBQ'.
// 10. Now set newPropertyToAdd equal to 'canFly'.
// 11. What do you expect to happen when we type in the following line?
  // mysticalAnimal[newPropertyToAdd] = true;
  // Think through this with your pair. Then uncomment that line and console.log mysticalAnimal afterwards!
  // Now let's talk through what just happened:
    // The JS interpreter reads the line of code from left to right, just as we do.
    // The first thing it does is encounter the variable mysticalAnimal. It looks up what this variable points to, and finds that it evaluates to an object.
    // That object is now what the computer holds, as a result of evaluating the variable mysticalAnimal.
    // Next, it recognizes the brackets. It knows to evaluate whatever comes inside the brackets, and then look up the results of that as a property name on the object.
    // Next, it encounters the thing inside the brackets. In this case, that thing is a variable. So, it goes off and looks up what that variable is. It finds that variable is equal to the string 'canFly'.
    // Now, it looks up the string 'canFly' as a property name on our mysticalAnimal object, and returns the value that is stored at that property name, which is the boolean value true in this case.
  // That's pretty cool that we can pretend to be the machine and explain exactly what it's doing with each character of code that we've written! See, no black magic here. It just follows a set of rules that we've agreed on beforehand.
// Now, onto point B above of using bracket notation- passing in a string.

// ******** NIGHTMARE MODE! ********* //

// 12. Using bracket notation still, pass in the string 'collects' inside the brackets, and set it equal to the value 'diamonds and gold and fire extinguishers'.
// At first glance, this appears to be a different pattern than passing in a variable inside the brackets. But let's revisit the same steps we talked through above, and you'll notice that all we did was make one step simpler for the computer.
// Now let's talk through what just happened:
  // The JS interpreter reads the line of code from left to right, just as we do.
  // The first thing it does is encounter the variable mysticalAnimal. It looks up what this variable points to, and finds that it evaluates to an object.
  // That object is now what the computer holds, as a result of evaluating the variable mysticalAnimal.
  // Next, it recognizes the brackets. It knows to evaluate whatever comes inside the brackets, and then look up the results of that as a property name on the object.
  // Next, it encounters the thing inside the brackets. In this case, that thing is already a string, 'collects'. THIS STEP IS THE ONLY ONE THAT CHANGES AT ALL. When the interpreter goes to evaluate the thing inside the brackets, it recognizes that thing is already a string and that it doesn't have to do any further work on this step. In the previous version, the only differences is that it had to turn the thing inside the brackets into a string by evaluating it as a variable first.
  // Now, it looks up the string 'collects' as a property name on our mysticalAnimal object, and returns the value that is stored at that property name, which is the string 'diamonds and gold and fire extinguishes' in this case.

// At this point, you've gotten great practice setting properties of objects using both dot and bracket notation. Now let's get in some practice accessing those properties and when to use each form of access.
// HINT: When looking up a string, use dot notation. When looking up a variable, use bracket notation! This is all you need to know 98% of the time.

// 13. Create a variable called thisIsAVariable. Set it equal to the string 'superPower'.
// Let's use this to play with bracket vs. dot notation.
// 14. What do you expect to happen when we try the following line? Talk this through with your partner for a minute.
  // console.log(mysticalAnimal.thisIsAVariable);
  // The dot notation means that JS is going to try to look for a property name that is exactly the string after the dot- in this case, it's looking for a property called thisIsAVariable in our mysticalAnimal object. And clearly we don't have a property named that, so it will return undefined!
// 15. Now try using thisIsAVariable using the proper form of access for variables. What do you get this time?
// 16. And what happens when you put that variable in quotes inside the brackets?
  // It does the exact same thing as if you had used dot notation- looks it up as a string, not a variable.

// Object Literals:
// One last practice! So far we've been going through and creating different properties one by one. Let's use object literal notation to do a bunch at once!
// We can create an object and give it properties all at the same time using object literal notation. An example:
/*
  var goalsForTheYear = {
    cycling: '5000 miles',
    climbing: '100 days',
    giving: 'selflessly'
  };
*/
// 17. Create a new variable called mysticalAnimal2, and set it equal to an object literal with the following properties:
  // type
  // name
  // likes
  // bestFriend
  // superPower
  // food
  // canFly
  // collects

// Awesome, by now you should have a pretty good familiarity with objects, bracket and dot notation, object literals, and accessing properties of objects. Feel free to keep exploring more on your own; objects are important things to understand!
<commit_msg>Update1_objects.js<commit_after>//Today we're going to get in a bunch of practice with objects.
//As you start your JS journey, there's a ton of value in just building out the muscle memory for the fundamentals.
//To get these fundamentals as deeply embedded as possible, type them out new each time. Avoid copying code, as you're just ignoring a chance to get in more useful practice.

// 1. To start, let's create a variable, mysticalAnimal, and set it equal to an object.

// Dot Notation:
// Recall that dot notation takes whatever is to the right of the dot, turns it into a string, and looks up that string as a property name in the object to the left of the dot.
// Let's use dot notation to add some properties to mysticalAnimal.
// 2. Add a type property, and set it equal to 'dragon'.
// 3. Add a name property, and set it equal to 'Leslie'.
// 4. Add a likes property, and set it equal to an empty array.
// 5. Add a property called bestFriend, and set it equal to your name.
// 6. Add in a superPower property. Set it equal to 'gives amazing hugs'.

// Access using dot notation
// 7. Now try to access all the values you've stored in mysticalAnimal. One at a time (not all at once!), what do you need to do to access the values:
  // 'dragon'
  // 'Leslie'
  // []
  // your own name
  // 'gives amazing hugs'
// Hopefully this starts to feel somewhat repetitive- that's awesome! That means that you're learing this super well so far. If it doesn't, try going back and doing it again on your own time.

// Bracket notation:
// Recall that we can do two different things with bracket notation:
  // A. Evaluate a variable or expression, and look up what that variable evalutates to as a property name in the object.
  // B. Pass in a string (as noted by the quotes surrounding it) and look up that string as a property name in the object.

// 8. Create a variable called newPropertyToAdd, and set it equal to 'food'.

// 9. Now, using bracket notation and newPropertyToAdd, create a food property on our mysticalAnimal object, and set it equal to 'BBQ'.
// 10. Now set newPropertyToAdd equal to 'canFly'.
// 11. What do you expect to happen when we type in the following line?
  // mysticalAnimal[newPropertyToAdd] = true;
  // Think through this with your pair. Then uncomment that line and console.log mysticalAnimal afterwards!
  // Now let's talk through what just happened:
    // The JS interpreter reads the line of code from left to right, just as we do.
    // The first thing it does is encounter the variable mysticalAnimal. It looks up what this variable points to, and finds that it evaluates to an object.
    // That object is now what the computer holds, as a result of evaluating the variable mysticalAnimal.
    // Next, it recognizes the brackets. It knows to evaluate whatever comes inside the brackets, and then look up the results of that as a property name on the object.
    // Next, it encounters the thing inside the brackets. In this case, that thing is a variable. So, it goes off and looks up what that variable is. It finds that variable is equal to the string 'canFly'.
    // Now, it looks up the string 'canFly' as a property name on our mysticalAnimal object, and returns the value that is stored at that property name, which is the boolean value true in this case.
  // That's pretty cool that we can pretend to be the machine and explain exactly what it's doing with each character of code that we've written! See, no black magic here. It just follows a set of rules that we've agreed on beforehand.
// Now, onto point B above of using bracket notation- passing in a string.

// ******** NIGHTMARE MODE! ********* //

// 12. Using bracket notation still, pass in the string 'collects' inside the brackets, and set it equal to the value 'diamonds and gold and fire extinguishers'.
// At first glance, this appears to be a different pattern than passing in a variable inside the brackets. But let's revisit the same steps we talked through above, and you'll notice that all we did was make one step simpler for the computer.
// Now let's talk through what just happened:
  // The JS interpreter reads the line of code from left to right, just as we do.
  // The first thing it does is encounter the variable mysticalAnimal. It looks up what this variable points to, and finds that it evaluates to an object.
  // That object is now what the computer holds, as a result of evaluating the variable mysticalAnimal.
  // Next, it recognizes the brackets. It knows to evaluate whatever comes inside the brackets, and then look up the results of that as a property name on the object.
  // Next, it encounters the thing inside the brackets. In this case, that thing is already a string, 'collects'. THIS STEP IS THE ONLY ONE THAT CHANGES AT ALL. When the interpreter goes to evaluate the thing inside the brackets, it recognizes that thing is already a string and that it doesn't have to do any further work on this step. In the previous version, the only differences is that it had to turn the thing inside the brackets into a string by evaluating it as a variable first.
  // Now, it looks up the string 'collects' as a property name on our mysticalAnimal object, and returns the value that is stored at that property name, which is the string 'diamonds and gold and fire extinguishes' in this case.

// At this point, you've gotten great practice setting properties of objects using both dot and bracket notation. Now let's get in some practice accessing those properties and when to use each form of access.
// HINT: When looking up a string, use dot notation. When looking up a variable, use bracket notation! This is all you need to know 98% of the time.

// 13. Create a variable called thisIsAVariable. Set it equal to the string 'superPower'.
// Let's use this to play with bracket vs. dot notation.
// 14. What do you expect to happen when we try the following line? Talk this through with your partner for a minute.
  // console.log(mysticalAnimal.thisIsAVariable);
  // The dot notation means that JS is going to try to look for a property name that is exactly the string after the dot- in this case, it's looking for a property called thisIsAVariable in our mysticalAnimal object. And clearly we don't have a property named that, so it will return undefined!
// 15. Now try using thisIsAVariable using the proper form of access for variables. What do you get this time?
// 16. And what happens when you put that variable in quotes inside the brackets?
  // It does the exact same thing as if you had used dot notation- looks it up as a string, not a variable.

// Object Literals:
// One last practice! So far we've been going through and creating different properties one by one. Let's use object literal notation to do a bunch at once!
// We can create an object and give it properties all at the same time using object literal notation. An example:
/*
  var goalsForTheYear = {
    cycling: '5000 miles',
    climbing: '100 days',
    giving: 'selflessly'
  };
*/
// 17. Create a new variable called mysticalAnimal2, and set it equal to an object literal with the following properties:
  // type
  // name
  // likes
  // bestFriend
  // superPower
  // food
  // canFly
  // collects

// Awesome, by now you should have a pretty good familiarity with objects, bracket and dot notation, object literals, and accessing properties of objects. Feel free to keep exploring more on your own; objects are important things to understand!
<|endoftext|>


<commit_before>module.exports = function(app, logger, router, argv) {
    logger.info('module tty');

    var ttyserver;
    router.get('/start', function(req, res) {
        var tty = require('tty.js');
        ttyserver = tty.createServer({
            shell: 'bash',
            users: {
                openfpgaduino: 'lab123'
            },
            port: 8000
        });
        ttyserver.listen();
        res.json({
            message: 'start the tty!'
        });
    });

    router.get('/stop', function(req, res) {
        delete ttyserver;
        res.json({
            message: 'stop the tty!'
        });
    });

    app.use('/tty', router);

}<commit_msg>fix bug<commit_after>module.exports = function(app, logger, express, argv) {
    logger.info('module tty');
    var router = express.Router();
    var ttyserver;
    router.get('/start', function(req, res) {
        var tty = require('tty.js');
        ttyserver = tty.createServer({
            shell: 'bash',
            users: {
                openfpgaduino: 'lab123'
            },
            port: 8000
        });
        ttyserver.listen();
        res.json({
            message: 'start the tty!'
        });
    });

    router.get('/stop', function(req, res) {
        delete ttyserver;
        res.json({
            message: 'stop the tty!'
        });
    });

    app.use('/tty', router);

}<|endoftext|>


<commit_before>'use strict';

var oo = require('../util/oo');
var Surface = require('./Surface');
var TextPropertyManager = require('../model/TextPropertyManager');
var Component = require('./Component');
var TextProperty = require('./TextPropertyComponent');
var $$ = Component.$$;

/**
 * TextPropertyAnnotator
 *
 * @memberof module:ui
 * @extends module:ui/Surface
 */
function TextPropertyAnnotator() {
  Surface.apply(this, arguments);
  var doc = this.getDocument();
  this.textPropertyManager = new TextPropertyManager(doc);
}

TextPropertyAnnotator.Prototype = function() {

  this.dispose = function() {
    Surface.prototype.dispose.call(this);
  };

  this.isContainerEditor = function() {
    return false;
  };

  this.render = function() {
    var el = $$(this.props.tagName || 'div')
      .addClass("sc-text-property-annotator")
      .append(
        $$(TextProperty, {
          tagName: "div",
          path: this.props.path
        })
      );
    return el;
  };
};

oo.inherit(TextPropertyAnnotator, Surface);
module.exports = TextPropertyAnnotator;<commit_msg>Document TextPropertyAnnotator.<commit_after>'use strict';

var oo = require('../util/oo');
var Surface = require('./Surface');
var TextPropertyManager = require('../model/TextPropertyManager');
var Component = require('./Component');
var TextProperty = require('./TextPropertyComponent');
var $$ = Component.$$;

/**
  Annotator for a text property. Needs to be instantiated inside a {@link ui/Controller}
  context. Works like a TextPropertyEditor but you can only annotate, not edit.

  @class
  @component
  @extends ui/Surface

  @prop {String} name unique surface name
  @prop {String[]} path path to a text property
  @prop {ui/SurfaceCommand[]} commands array of command classes to be available

  @example

  ```js
  $$(TextPropertyAnnotator, {
    name: 'abstract',
    path: ['metadata', 'abstract'],
    commands: [EmphasisCommand]
  })
  ```
*/

function TextPropertyAnnotator() {
  Surface.apply(this, arguments);
  var doc = this.getDocument();
  this.textPropertyManager = new TextPropertyManager(doc);
}

TextPropertyAnnotator.Prototype = function() {

  this.dispose = function() {
    Surface.prototype.dispose.call(this);
  };

  this.isContainerEditor = function() {
    return false;
  };

  this.render = function() {
    var el = $$(this.props.tagName || 'div')
      .addClass("sc-text-property-annotator")
      .append(
        $$(TextProperty, {
          tagName: "div",
          path: this.props.path
        })
      );
    return el;
  };
};

oo.inherit(TextPropertyAnnotator, Surface);
module.exports = TextPropertyAnnotator;<|endoftext|>


<commit_before>'use strict';

var store_hours= ['6am','7am','8am','9am','10am','11am','12pm','1pm','2pm','3pm','4pm','5pm','6pm','7pm','8pm'];

var store_names=
['First & Pike','SeaTac Airport','Seattle Center','Capitol Hill','Alki'];
//
// GroceryList.prototype.getTable = function(){
//   var table = document.createElement('table');
//
//   var titleRow = document.createElement('tr');
//   var titleHeading = document.createElement('th');
//   titleHeading.textContent = this.title;
//   titleRow.appendChild(titleHeading);
//   table.appendChild(titleRow);
//
//   var itemRow, itemName, itemPrice;
//   // create a new row for each item and add it to the table
//   for(var i = 0; i < this.items.length; i++){
//     itemRow = document.createElement('tr');
//     itemName = document.createElement('td');
//     itemName.textContent = this.items[i].name;
//     itemPrice = document.createElement('td');
//     itemPrice.textContent = this.items[i].price;
//     itemRow.appendChild(itemName);
//     itemRow.appendChild(itemPrice);
//     table.appendChild(itemRow);
//   }
//
//   return table;
// };

function StoreLocation(location, min, max, avgCookies) {
  this.location = location;
  this.min = min;
  this.max = max
  this.avgCookies = avgCookies;
  this.data = [];
}

function Data(array) {
  this.cookieshours= [];
  this.randomCustomers = function() {
    return Math.floor(Math.random() * (this.max - this.min + 1) + this.min);
  };
  this.randomCookiesPerHour = function() {
    for(var i=0; i<array.length; i++) {
      var avgCookies4Hour = Math.round(this.randomCustomers() * this.avgCookies);
      this.totalCookies = this.totalCookies + avgCookies4Hour;
      this.cookieshours.push(avgCookies4Hour);
    }
  };
  this.data = function () {
    for (var i = 0; i < array.length; i++) {
      array[i] + ': ' + this.cookieshours[i]
      + ' cookies';
    }
  };
}

StoreLocation.prototype.StoreData = function(dataArray) {
  var data = new Data(dataArray);
  this.data.push(data);
};

var first_and_pike = {
  location:'1st_and_Pike',
  header:'h2',
  min: 23,
  max: 65,
  avgCookies: 6.3,
  cookieshours: [],
  totalCookies:0,
  randomCustomers: function() {
    return Math.floor(Math.random()*(this.max-this.min+1)+this.min);
  },

  randomCookiesPerHour: function() {
    for(var i=0; i<store_hours.length; i++) {
      var avgCookies4Hour = Math.round(this.randomCustomers() * this.avgCookies);
      this.totalCookies = this.totalCookies + avgCookies4Hour;
      this.cookieshours.push(avgCookies4Hour);
    }
  },
  structureGenerator: function() {
    var div = document.getElementsByClassName(this.location)[0];
    var title = document.createElement(this.header);
    title.textContent = this.location;
    title.setAttribute('id','title');
    //console.log(title);
    div.appendChild(title);
    var ul = document.createElement('ul');
    ul.setAttribute('id',this.location);
    ul.textContent = this.location;
    div.appendChild(ul);
  },

  listGenerator: function() {
    var ul = document.getElementById(this.location);
    for (var i = 0; i < store_hours.length; i++) {
      var li = document.createElement('li');
      li.textContent = store_hours[i] + ': ' + this.cookieshours[i]
      + ' cookies';
      ul.appendChild(li);
    }
  },
  callfunction: function () {
    this.randomCookiesPerHour();
    this.structureGenerator();
    this.listGenerator();
  }
};

function StoreLocation(location, min, max, avgCookies) {
  this.location = location;
  this.min = min;
  this.max = max
  this.avgCookies = avgCookies;
  this.randomCustomers = function() {
    return Math.floor(Math.random() * (this.max - this.min + 1) + this.min);
  };
  this.randomCookiesPerHour = function() {
    for(var i=0; i<store_hours.length; i++) {
      var avgCookies4Hour = Math.round(this.randomCustomers() * this.avgCookies);
      this.totalCookies = this.totalCookies + avgCookies4Hour;
      this.cookieshours.push(avgCookies4Hour);
    }
  };
}
<commit_msg>changed the constructor to a master constructor with functions to calculate data<commit_after>'use strict';

var store_hours= ['6am','7am','8am','9am','10am','11am','12pm','1pm','2pm','3pm','4pm','5pm','6pm','7pm','8pm'];

var store_names=
['First & Pike','SeaTac Airport','Seattle Center','Capitol Hill','Alki'];
//
// GroceryList.prototype.getTable = function(){
//   var table = document.createElement('table');
//
//   var titleRow = document.createElement('tr');
//   var titleHeading = document.createElement('th');
//   titleHeading.textContent = this.title;
//   titleRow.appendChild(titleHeading);
//   table.appendChild(titleRow);
//
//   var itemRow, itemName, itemPrice;
//   // create a new row for each item and add it to the table
//   for(var i = 0; i < this.items.length; i++){
//     itemRow = document.createElement('tr');
//     itemName = document.createElement('td');
//     itemName.textContent = this.items[i].name;
//     itemPrice = document.createElement('td');
//     itemPrice.textContent = this.items[i].price;
//     itemRow.appendChild(itemName);
//     itemRow.appendChild(itemPrice);
//     table.appendChild(itemRow);
//   }
//
//   return table;
// };

function StoreLocation(location, min, max, avgCookies) {
  this.location = location;
  this.min = min;
  this.max = max
  this.avgCookies = avgCookies;
  this.cookieshours= [];
  this.totalCookies= 0;
  this.data = [];
  this.headers= [];
  this.randomCustomers = function() {
    return Math.floor(Math.random() * (this.max - this.min + 1) + this.min);
  };
  this.randomCookiesPerHour = function() {
    for(var i=0; i<store_hours.length; i++) {
      var avgCookies4Hour = Math.round(this.randomCustomers() * this.avgCookies);
      this.totalCookies = this.totalCookies + avgCookies4Hour;
      this.cookieshours.push(avgCookies4Hour);
    }
    return this.cookieshours;
  };
  this.dataStore = function () {
    this.data.push(this.location);
    for (var i = 0; i < store_hours.length; i++) {
      this.data.push(store_hours[i] + ': ' + this.cookieshours[i]);
      + ' cookies';
    }
  };
}

function Data(store_hours) {
  this.cookieshours= [];
  this.randomCustomers = function() {
    return Math.floor(Math.random() * (this.max - this.min + 1) + this.min);
  };
  this.randomCookiesPerHour = function() {
    for(var i=0; i<store_hours.length; i++) {
      var avgCookies4Hour = Math.round(this.randomCustomers() * this.avgCookies);
      this.totalCookies = this.totalCookies + avgCookies4Hour;
      this.cookieshours.push(avgCookies4Hour);
    }
  };
  this.data = function () {
    for (var i = 0; i < store_hours.length; i++) {
      store_hours[i] + ': ' + this.cookieshours[i]
      + ' cookies';
    }
  };
}

GroceryList.prototype.getTable = function(){
  var table = document.createElement('table');

  var titleRow = document.createElement('tr');
  var titleHeading = document.createElement('th');
  titleHeading.textContent = this.title;
  titleRow.appendChild(titleHeading);
  table.appendChild(titleRow);

  var itemRow, itemName, itemPrice;
  // create a new row for each item and add it to the table
  for(var i = 0; i < this.items.length; i++){
    itemRow = document.createElement('tr');
    itemName = document.createElement('td');
    itemName.textContent = this.items[i].name;
    itemPrice = document.createElement('td');
    itemPrice.textContent = this.items[i].price;
    itemRow.appendChild(itemName);
    itemRow.appendChild(itemPrice);
    table.appendChild(itemRow);
  }

  return table;
};

//
// StoreLocation.prototype.StoreData = function(datastore_hours) {
//   var data = new Data(datastore_hours);
//   this.data.push(data);
// };
<|endoftext|>


<commit_before>import _ from 'lodash';

import treeherder from '../../treeherder';
import { getProjectUrl, getApiUrl } from "../../../helpers/url";
import OptionCollectionModel from '../../../models/optionCollection';

treeherder.factory('PhSeries', ['$http', '$q', function ($http, $q) {

    const _getTestName = function (signatureProps) {
        // only return suite name if testname is identical, and handle
        // undefined test name
        return _.uniq(_.filter([signatureProps.suite, signatureProps.test])).join(" ");
    };

    const _getSeriesOptions = function (signatureProps, optionCollectionMap) {
        let options = [optionCollectionMap[signatureProps.option_collection_hash]];
        if (signatureProps.extra_options) {
            options = options.concat(signatureProps.extra_options);
        }
        return _.uniq(options);
    };

    const _getSeriesName = function (signatureProps, optionCollectionMap,
                                  displayOptions) {
        const platform = signatureProps.machine_platform;
        let name = _getTestName(signatureProps);

        if (displayOptions && displayOptions.includePlatformInName) {
            name = name + " " + platform;
        }
        const options = _getSeriesOptions(signatureProps, optionCollectionMap);
        return name + " " + options.join(" ");
    };

    const _getSeriesSummary = function (projectName, signature, signatureProps,
                                     optionCollectionMap) {
        const platform = signatureProps.machine_platform;
        const options = _getSeriesOptions(signatureProps, optionCollectionMap);

        return {
            id: signatureProps.id,
            name: _getSeriesName(signatureProps, optionCollectionMap),
            testName: _getTestName(signatureProps), // unadorned with platform/option info
            suite: signatureProps.suite,
            test: signatureProps.test || null,
            signature: signature,
            hasSubtests: signatureProps.has_subtests || false,
            parentSignature: signatureProps.parent_signature || null,
            projectName: projectName,
            platform: platform,
            options: options,
            frameworkId: signatureProps.framework_id,
            lowerIsBetter: (signatureProps.lower_is_better === undefined ||
                            signatureProps.lower_is_better)
        };
    };

    return {
        getTestName: _getTestName,
        getSeriesName: _getSeriesName,
        getSeriesList: function (projectName, params) {
            return OptionCollectionModel.getMap().then(function (optionCollectionMap) {
                return $http.get(
                    getProjectUrl('/performance/signatures/', projectName),
                    { params: params }).then(function (response) {
                         return _.map(response.data, function (signatureProps, signature) {
                             return _getSeriesSummary(projectName, signature,
                                                      signatureProps,
                                                      optionCollectionMap);
                         });
                     });
            });
        },
        getPlatformList: function (projectName, params) {
            return $http.get(
                getProjectUrl('/performance/platforms/', projectName),
                { params: params }).then(function (response) {
                    return response.data;
                });
        },
        getSeriesData: function (projectName, params) {
            return $http.get(
                getProjectUrl('/performance/data/', projectName),
                { params: params }).then(function (response) {
                    if (response.data) {
                        return response.data;
                    }
                    return $q.reject("No series data found");
                });
        },
        getReplicateData: function (params) {
            params.value = 'perfherder-data.json';
            return $http.get(
                getApiUrl('/jobdetail/'),
                { params: params }).then(
                    function (response) {
                        if (response.data.results[0]) {
                            const url = response.data.results[0].url;
                            return $http.get(url).then(function (response) {
                                return response.data;
                            });
                        }
                        return $q.reject("No replicate data found");
                    });
        }
    };
}]);
<commit_msg>Bug 1467293 - convert _.filter() usages to ES6 (#3626)<commit_after>import _ from 'lodash';

import treeherder from '../../treeherder';
import { getProjectUrl, getApiUrl } from "../../../helpers/url";
import OptionCollectionModel from '../../../models/optionCollection';

treeherder.factory('PhSeries', ['$http', '$q', function ($http, $q) {

    const _getTestName = function (signatureProps) {
        // only return suite name if testname is identical, and handle
        // undefined test name
        return _.uniq([signatureProps.suite, signatureProps.test].filter(item => item)).join(" ");
    };

    const _getSeriesOptions = function (signatureProps, optionCollectionMap) {
        let options = [optionCollectionMap[signatureProps.option_collection_hash]];
        if (signatureProps.extra_options) {
            options = options.concat(signatureProps.extra_options);
        }
        return _.uniq(options);
    };

    const _getSeriesName = function (signatureProps, optionCollectionMap,
                                  displayOptions) {
        const platform = signatureProps.machine_platform;
        let name = _getTestName(signatureProps);

        if (displayOptions && displayOptions.includePlatformInName) {
            name = name + " " + platform;
        }
        const options = _getSeriesOptions(signatureProps, optionCollectionMap);
        return name + " " + options.join(" ");
    };

    const _getSeriesSummary = function (projectName, signature, signatureProps,
                                     optionCollectionMap) {
        const platform = signatureProps.machine_platform;
        const options = _getSeriesOptions(signatureProps, optionCollectionMap);

        return {
            id: signatureProps.id,
            name: _getSeriesName(signatureProps, optionCollectionMap),
            testName: _getTestName(signatureProps), // unadorned with platform/option info
            suite: signatureProps.suite,
            test: signatureProps.test || null,
            signature: signature,
            hasSubtests: signatureProps.has_subtests || false,
            parentSignature: signatureProps.parent_signature || null,
            projectName: projectName,
            platform: platform,
            options: options,
            frameworkId: signatureProps.framework_id,
            lowerIsBetter: (signatureProps.lower_is_better === undefined ||
                            signatureProps.lower_is_better)
        };
    };

    return {
        getTestName: _getTestName,
        getSeriesName: _getSeriesName,
        getSeriesList: function (projectName, params) {
            return OptionCollectionModel.getMap().then(function (optionCollectionMap) {
                return $http.get(
                    getProjectUrl('/performance/signatures/', projectName),
                    { params: params }).then(function (response) {
                         return _.map(response.data, function (signatureProps, signature) {
                             return _getSeriesSummary(projectName, signature,
                                                      signatureProps,
                                                      optionCollectionMap);
                         });
                     });
            });
        },
        getPlatformList: function (projectName, params) {
            return $http.get(
                getProjectUrl('/performance/platforms/', projectName),
                { params: params }).then(function (response) {
                    return response.data;
                });
        },
        getSeriesData: function (projectName, params) {
            return $http.get(
                getProjectUrl('/performance/data/', projectName),
                { params: params }).then(function (response) {
                    if (response.data) {
                        return response.data;
                    }
                    return $q.reject("No series data found");
                });
        },
        getReplicateData: function (params) {
            params.value = 'perfherder-data.json';
            return $http.get(
                getApiUrl('/jobdetail/'),
                { params: params }).then(
                    function (response) {
                        if (response.data.results[0]) {
                            const url = response.data.results[0].url;
                            return $http.get(url).then(function (response) {
                                return response.data;
                            });
                        }
                        return $q.reject("No replicate data found");
                    });
        }
    };
}]);
<|endoftext|>


<commit_before>// Third party dependencies
var pam = require('authenticate-pam');

// Local dependencies
var auth   = require('../lib/auth');
var config = require('../lib/config');
var fs     = require('../lib/fs');
var unix   = require('../lib/unix');

// Register our authentication mechanism
auth.register('pam', function (username, password, done) {
  pam.authenticate(username, password, function (err) {
    if (err) {
      done(err, null);
    } else {
      var user    = unix.getUser({ username: username })[0];
      user.chroot = config.auth.default_chroot === '~' ? user.home : config.auth.default_chroot;

      done(err, user);
    }
  });
});
<commit_msg>JSHint auth/pam.js<commit_after>'use strict';

// Third party dependencies
var pam = require('authenticate-pam');

// Local dependencies
var auth   = require('../lib/auth');
var config = require('../lib/config');
var unix   = require('../lib/unix');

// Register our authentication mechanism
auth.register('pam', function (username, password, done) {
  pam.authenticate(username, password, function (err) {
    if (err) {
      done(err, null);
    } else {
      var user    = unix.getUser({ username: username })[0];
      user.chroot = config.auth.default_chroot === '~' ? user.home : config.auth.default_chroot;

      done(err, user);
    }
  });
});
<|endoftext|>


<commit_before>// ==UserScript==
// @name Monster Minigame Auto-script
// @namespace https://github.com/wchill/steamSummerMinigame
// @description A script that runs the Steam Monster Minigame for you. Modified from mouseas's original version to include autoclick.
// @version 1.0
// @match http://steamcommunity.com/minigame/towerattack*
// @updateURL https://raw.githubusercontent.com/wchill/steamSummerMinigame/master/autoPlay.js
// @downloadURL https://raw.githubusercontent.com/wchill/steamSummerMinigame/master/autoPlay.js
// ==/UserScript==

// IMPORTANT: Update the @version property above to a higher number such as 1.1 and 1.2 when you update the script! Otherwise, Tamper / Greasemonkey users will not update automatically.

var clickRate = 20; // change to number of desired clicks per second

var isAlreadyRunning = false;

var disableParticleEffects = true; // Set to false to keep particle effects

// disable particle effects - this drastically reduces the game's memory leak
if (window.g_Minigame !== undefined && disableParticleEffects) {
	window.g_Minigame.CurrentScene().DoClickEffect = function() {};
	window.g_Minigame.CurrentScene().SpawnEmitter = function() {};
}

if (thingTimer !== undefined) {
	window.clearTimeout(thingTimer);
}

function doTheThing() {
	if (isAlreadyRunning || g_Minigame === undefined || !g_Minigame.CurrentScene().m_bRunning || !g_Minigame.CurrentScene().m_rgPlayerTechTree) {
		return;
	}
	isAlreadyRunning = true;

	goToLaneWithBestTarget();

	useGoodLuckCharmIfRelevant();
	useMedicsIfRelevant();

	// TODO use abilities if available and a suitable target exists
	// - Tactical Nuke on a Spawner if below 50% and above 25% of its health
	// - Cluster Bomb and Napalm if the current lane has a spawner and 2+ creeps
	// - Metal Detector if a boss, miniboss, or spawner death is imminent (predicted in > 2 and < 7 seconds)
	// - Morale Booster if available and lane has > 2 live enemies
	// - Decrease Cooldowns if another player used a long-cooldown ability < 10 seconds ago (any ability but Medics or a consumable)

	// TODO purchase abilities and upgrades intelligently

	attemptRespawn();

	isAlreadyRunning = false;
}

function goToLaneWithBestTarget() {
	// We can overlook spawners if all spawners are 40% hp or higher and a creep is under 10% hp
	var spawnerOKThreshold = 0.4;
	var creepSnagThreshold = 0.1;

	var targetFound = false;
	var lowHP = 0;
	var lowLane = 0;
	var lowTarget = 0;
	var lowPercentageHP = 0;

	var ENEMY_TYPE = {
		"SPAWNER":0,
		"CREEP":1,
		"BOSS":2,
		"MINIBOSS":3,
		"TREASURE":4
	}

	// determine which lane and enemy is the optimal target
	var enemyTypePriority = [
		ENEMY_TYPE.TREASURE,
		ENEMY_TYPE.BOSS,
		ENEMY_TYPE.MINIBOSS,
		ENEMY_TYPE.SPAWNER,
		ENEMY_TYPE.CREEP
		];

	var skippingSpawner = false;
	var skippedSpawnerLane = 0;
	var skippedSpawnerTarget = 0;

	for (var k = 0; !targetFound && k < enemyTypePriority.length; k++) {
		var enemies = [];

		// gather all the enemies of the specified type.
		for (var i = 0; i < 3; i++) {
			for (var j = 0; j < 4; j++) {
				var enemy = g_Minigame.CurrentScene().GetEnemy(i, j);
				if (enemy && enemy.m_data.type == enemyTypePriority[k]) {
					enemies[enemies.length] = enemy;
				}
			}
		}

		// target the enemy of the specified type with the lowest hp
		for (var i = 0; i < enemies.length; i++) {
			if (enemies[i] && !enemies[i].m_bIsDestroyed) {
				if(lowHP < 1 || enemies[i].m_flDisplayedHP < lowHP) {
					targetFound = true;
					lowHP = enemies[i].m_flDisplayedHP;
					lowLane = enemies[i].m_nLane;
					lowTarget = enemies[i].m_nID;
				}
				var percentageHP = enemies[i].m_flDisplayedHP / enemies[i].m_data.max_hp;
				if(lowPercentageHP == 0 || percentageHP < lowPercentageHP) {
					lowPercentageHP = percentageHP;
				}
			}
		}

		// If we just finished looking at spawners,
		// AND none of them were below our threshold,
		// remember them and look for low creeps (so don't quit now)
		if (enemyTypePriority[k] == ENEMY_TYPE.SPAWNER && lowPercentageHP > spawnerOKThreshold) {
			skippedSpawnerLane = lowLane;
			skippedSpawnerTarget = lowTarget;
			skippingSpawner = true;
			targetFound = false;
		}

		// If we skipped a spawner and just finished looking at creeps,
		// AND the lowest was above our snag threshold,
		// just go back to the spawner!
		if (skippingSpawner && enemyTypePriority[k] == ENEMY_TYPE.CREEP && lowPercentageHP > creepSnagThreshold ) {
			lowLane = skippedSpawnerLane;
			lowTarget = skippedSpawnerTarget;
		}
	}

	// go to the chosen lane
	if (targetFound) {
		if (g_Minigame.CurrentScene().m_nExpectedLane != lowLane) {
			//console.log('switching langes');
			g_Minigame.CurrentScene().TryChangeLane(lowLane);
		}

		// target the chosen enemy
		if (g_Minigame.CurrentScene().m_nTarget != lowTarget) {
			//console.log('switching targets');
			g_Minigame.CurrentScene().TryChangeTarget(lowTarget);
		}
	}
}

function useMedicsIfRelevant() {
	var myMaxHealth = g_Minigame.CurrentScene().m_rgPlayerTechTree.max_hp;

	// check if health is below 50%
	var hpPercent = g_Minigame.CurrentScene().m_rgPlayerData.hp / myMaxHealth;
	if (hpPercent > 0.5 || g_Minigame.CurrentScene().m_rgPlayerData.hp < 1) {
		return; // no need to heal - HP is above 50% or already dead
	}

	// check if Medics is purchased and cooled down
	if (hasPurchasedAbility(7)) {

		if (isAbilityCoolingDown(7)) {
			return;
		}

		// Medics is purchased, cooled down, and needed. Trigger it.
		console.log('Medics is purchased, cooled down, and needed. Trigger it.');
		triggerAbility(7);
	}
}

// Use Good Luck Charm if doable
function useGoodLuckCharmIfRelevant() {
	// check if Good Luck Charms is purchased and cooled down
	if (hasPurchasedAbility(6)) {
		if (isAbilityCoolingDown(6)) {
			return;
		}

		// Good Luck Charms is purchased, cooled down, and needed. Trigger it.
		console.log('Good Luck Charms is purchased, cooled down, and needed. Trigger it.');
		triggerAbility(6);
	}
}

//If player is dead, call respawn method
function attemptRespawn() {
	if ((g_Minigame.CurrentScene().m_bIsDead) &&
			((g_Minigame.CurrentScene().m_rgPlayerData.time_died * 1000) + 5000) < (new Date().getTime())) {
		RespawnPlayer();
	}
}

function isAbilityCoolingDown(abilityId) {
	return g_Minigame.CurrentScene().GetCooldownForAbility(abilityId) > 0;
}

function hasPurchasedAbility(abilityId) {
	// each bit in unlocked_abilities_bitfield corresponds to an ability.
	// the above condition checks if the ability's bit is set or cleared. I.e. it checks if
	// the player has purchased the specified ability.
	return (1 << abilityId) & g_Minigame.CurrentScene().m_rgPlayerTechTree.unlocked_abilities_bitfield;
}

function triggerAbility(abilityId) {
	var elem = document.getElementById('ability_' + abilityId);
	if (elem && elem.childElements() && elem.childElements().length >= 1) {
		g_Minigame.CurrentScene().TryAbility(document.getElementById('ability_' + abilityId).childElements()[0]);
	}
}

var thingTimer = window.setInterval(doTheThing, 1000);
function clickTheThing() {
    g_Minigame.m_CurrentScene.DoClick(
        {
            data: {
                getLocalPosition: function() {
                    var enemy = g_Minigame.m_CurrentScene.GetEnemy(
                                      g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane,
                                      g_Minigame.m_CurrentScene.m_rgPlayerData.target),
                        laneOffset = enemy.m_nLane * 440;

                    return {
                        x: enemy.m_Sprite.position.x - laneOffset,
                        y: enemy.m_Sprite.position.y - 52
                    }
                }
            }
        }
    );
}

var clickTimer = window.setInterval(clickTheThing, 1000/clickRate);
<commit_msg>Increment version number<commit_after>// ==UserScript==
// @name Monster Minigame Auto-script
// @namespace https://github.com/wchill/steamSummerMinigame
// @description A script that runs the Steam Monster Minigame for you. Modified from mouseas's original version to include autoclick.
// @version 1.01
// @match http://steamcommunity.com/minigame/towerattack*
// @updateURL https://raw.githubusercontent.com/wchill/steamSummerMinigame/master/autoPlay.js
// @downloadURL https://raw.githubusercontent.com/wchill/steamSummerMinigame/master/autoPlay.js
// ==/UserScript==

// IMPORTANT: Update the @version property above to a higher number such as 1.1 and 1.2 when you update the script! Otherwise, Tamper / Greasemonkey users will not update automatically.

var clickRate = 20; // change to number of desired clicks per second

var isAlreadyRunning = false;

var disableParticleEffects = true; // Set to false to keep particle effects

// disable particle effects - this drastically reduces the game's memory leak
if (window.g_Minigame !== undefined && disableParticleEffects) {
	window.g_Minigame.CurrentScene().DoClickEffect = function() {};
	window.g_Minigame.CurrentScene().SpawnEmitter = function() {};
}

if (thingTimer !== undefined) {
	window.clearTimeout(thingTimer);
}

function doTheThing() {
	if (isAlreadyRunning || g_Minigame === undefined || !g_Minigame.CurrentScene().m_bRunning || !g_Minigame.CurrentScene().m_rgPlayerTechTree) {
		return;
	}
	isAlreadyRunning = true;

	goToLaneWithBestTarget();

	useGoodLuckCharmIfRelevant();
	useMedicsIfRelevant();

	// TODO use abilities if available and a suitable target exists
	// - Tactical Nuke on a Spawner if below 50% and above 25% of its health
	// - Cluster Bomb and Napalm if the current lane has a spawner and 2+ creeps
	// - Metal Detector if a boss, miniboss, or spawner death is imminent (predicted in > 2 and < 7 seconds)
	// - Morale Booster if available and lane has > 2 live enemies
	// - Decrease Cooldowns if another player used a long-cooldown ability < 10 seconds ago (any ability but Medics or a consumable)

	// TODO purchase abilities and upgrades intelligently

	attemptRespawn();

	isAlreadyRunning = false;
}

function goToLaneWithBestTarget() {
	// We can overlook spawners if all spawners are 40% hp or higher and a creep is under 10% hp
	var spawnerOKThreshold = 0.4;
	var creepSnagThreshold = 0.1;

	var targetFound = false;
	var lowHP = 0;
	var lowLane = 0;
	var lowTarget = 0;
	var lowPercentageHP = 0;

	var ENEMY_TYPE = {
		"SPAWNER":0,
		"CREEP":1,
		"BOSS":2,
		"MINIBOSS":3,
		"TREASURE":4
	}

	// determine which lane and enemy is the optimal target
	var enemyTypePriority = [
		ENEMY_TYPE.TREASURE,
		ENEMY_TYPE.BOSS,
		ENEMY_TYPE.MINIBOSS,
		ENEMY_TYPE.SPAWNER,
		ENEMY_TYPE.CREEP
		];

	var skippingSpawner = false;
	var skippedSpawnerLane = 0;
	var skippedSpawnerTarget = 0;

	for (var k = 0; !targetFound && k < enemyTypePriority.length; k++) {
		var enemies = [];

		// gather all the enemies of the specified type.
		for (var i = 0; i < 3; i++) {
			for (var j = 0; j < 4; j++) {
				var enemy = g_Minigame.CurrentScene().GetEnemy(i, j);
				if (enemy && enemy.m_data.type == enemyTypePriority[k]) {
					enemies[enemies.length] = enemy;
				}
			}
		}

		// target the enemy of the specified type with the lowest hp
		for (var i = 0; i < enemies.length; i++) {
			if (enemies[i] && !enemies[i].m_bIsDestroyed) {
				if(lowHP < 1 || enemies[i].m_flDisplayedHP < lowHP) {
					targetFound = true;
					lowHP = enemies[i].m_flDisplayedHP;
					lowLane = enemies[i].m_nLane;
					lowTarget = enemies[i].m_nID;
				}
				var percentageHP = enemies[i].m_flDisplayedHP / enemies[i].m_data.max_hp;
				if(lowPercentageHP == 0 || percentageHP < lowPercentageHP) {
					lowPercentageHP = percentageHP;
				}
			}
		}

		// If we just finished looking at spawners,
		// AND none of them were below our threshold,
		// remember them and look for low creeps (so don't quit now)
		if (enemyTypePriority[k] == ENEMY_TYPE.SPAWNER && lowPercentageHP > spawnerOKThreshold) {
			skippedSpawnerLane = lowLane;
			skippedSpawnerTarget = lowTarget;
			skippingSpawner = true;
			targetFound = false;
		}

		// If we skipped a spawner and just finished looking at creeps,
		// AND the lowest was above our snag threshold,
		// just go back to the spawner!
		if (skippingSpawner && enemyTypePriority[k] == ENEMY_TYPE.CREEP && lowPercentageHP > creepSnagThreshold ) {
			lowLane = skippedSpawnerLane;
			lowTarget = skippedSpawnerTarget;
		}
	}

	// go to the chosen lane
	if (targetFound) {
		if (g_Minigame.CurrentScene().m_nExpectedLane != lowLane) {
			//console.log('switching langes');
			g_Minigame.CurrentScene().TryChangeLane(lowLane);
		}

		// target the chosen enemy
		if (g_Minigame.CurrentScene().m_nTarget != lowTarget) {
			//console.log('switching targets');
			g_Minigame.CurrentScene().TryChangeTarget(lowTarget);
		}
	}
}

function useMedicsIfRelevant() {
	var myMaxHealth = g_Minigame.CurrentScene().m_rgPlayerTechTree.max_hp;

	// check if health is below 50%
	var hpPercent = g_Minigame.CurrentScene().m_rgPlayerData.hp / myMaxHealth;
	if (hpPercent > 0.5 || g_Minigame.CurrentScene().m_rgPlayerData.hp < 1) {
		return; // no need to heal - HP is above 50% or already dead
	}

	// check if Medics is purchased and cooled down
	if (hasPurchasedAbility(7)) {

		if (isAbilityCoolingDown(7)) {
			return;
		}

		// Medics is purchased, cooled down, and needed. Trigger it.
		console.log('Medics is purchased, cooled down, and needed. Trigger it.');
		triggerAbility(7);
	}
}

// Use Good Luck Charm if doable
function useGoodLuckCharmIfRelevant() {
	// check if Good Luck Charms is purchased and cooled down
	if (hasPurchasedAbility(6)) {
		if (isAbilityCoolingDown(6)) {
			return;
		}

		// Good Luck Charms is purchased, cooled down, and needed. Trigger it.
		console.log('Good Luck Charms is purchased, cooled down, and needed. Trigger it.');
		triggerAbility(6);
	}
}

//If player is dead, call respawn method
function attemptRespawn() {
	if ((g_Minigame.CurrentScene().m_bIsDead) &&
			((g_Minigame.CurrentScene().m_rgPlayerData.time_died * 1000) + 5000) < (new Date().getTime())) {
		RespawnPlayer();
	}
}

function isAbilityCoolingDown(abilityId) {
	return g_Minigame.CurrentScene().GetCooldownForAbility(abilityId) > 0;
}

function hasPurchasedAbility(abilityId) {
	// each bit in unlocked_abilities_bitfield corresponds to an ability.
	// the above condition checks if the ability's bit is set or cleared. I.e. it checks if
	// the player has purchased the specified ability.
	return (1 << abilityId) & g_Minigame.CurrentScene().m_rgPlayerTechTree.unlocked_abilities_bitfield;
}

function triggerAbility(abilityId) {
	var elem = document.getElementById('ability_' + abilityId);
	if (elem && elem.childElements() && elem.childElements().length >= 1) {
		g_Minigame.CurrentScene().TryAbility(document.getElementById('ability_' + abilityId).childElements()[0]);
	}
}

var thingTimer = window.setInterval(doTheThing, 1000);
function clickTheThing() {
    g_Minigame.m_CurrentScene.DoClick(
        {
            data: {
                getLocalPosition: function() {
                    var enemy = g_Minigame.m_CurrentScene.GetEnemy(
                                      g_Minigame.m_CurrentScene.m_rgPlayerData.current_lane,
                                      g_Minigame.m_CurrentScene.m_rgPlayerData.target),
                        laneOffset = enemy.m_nLane * 440;

                    return {
                        x: enemy.m_Sprite.position.x - laneOffset,
                        y: enemy.m_Sprite.position.y - 52
                    }
                }
            }
        }
    );
}

var clickTimer = window.setInterval(clickTheThing, 1000/clickRate);
<|endoftext|>


<commit_before>/*!
	Copyright (C) 2016 Matthew D. Mower

	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.
*/

storage();

function storage() {
	if (typeof storage.area === 'undefined') {
		storage.area = chrome.storage.local;
	}
	if (typeof storage.urlPrefix === 'undefined') {
		storage.urlPrefix = "http://dx.doi.org/";
	}
	if (typeof storage.findDoi === 'undefined') {
		// http://stackoverflow.com/questions/27910/finding-a-doi-in-a-document-or-page
		storage.findDoi = /\b(10[.][0-9]{3,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)\b/ig;
	}
	if (typeof storage.findUrl === 'undefined') {
		// http://stackoverflow.com/questions/27910/finding-a-doi-in-a-document-or-page
		storage.findUrl = /^(?:https?\:\/\/)(?:dx\.)?doi\.org\/(10[.][0-9]{3,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)$/ig;
	}
	if (typeof storage.autolinkRewrite === 'undefined') {
		storage.autolinkRewrite = false;
	}

	chrome.storage.local.get(["sync_data"], function(stg) {
		if (stg.sync_data === true) {
			storage.area = chrome.storage.sync;
		} else {
			storage.area = chrome.storage.local;
		}

		var stgFetch = [
			"cr_autolink",
			"auto_link_rewrite",
			"custom_resolver",
			"doi_resolver"
		];

		storage.area.get(stgFetch, function(stg) {
			if (stg.custom_resolver === true && stg.cr_autolink == "custom") {
				storage.urlPrefix = stg.doi_resolver;
				storage.autolinkRewrite = stg.auto_link_rewrite === true;
			}
			replaceDOIsWithLinks();
		});
	});
}

// http://stackoverflow.com/questions/1444409/in-javascript-how-can-i-replace-text-in-an-html-page-without-affecting-the-tags
function replaceDOIsWithLinks() {
	replaceInElement(document.body, storage.findDoi, function(match) {
		var link = document.createElement('a');
		link.href = storage.urlPrefix + match[0];
		link.appendChild(document.createTextNode(match[0]));
		return link;
	});
}

// iterate over child nodes in reverse, as replacement may increase length of child node list.
function replaceInElement(element, find, replace) {
	// don't touch these elements
	var forbiddenTags = ["a", "input", "script", "style", "textarea"];
	for (var i = element.childNodes.length; i-- > 0;) {
		var child = element.childNodes[i];
		if (child.nodeType == 1) { // ELEMENT_NODE
			if (forbiddenTags.indexOf(child.nodeName.toLowerCase()) < 0) {
				replaceInElement(child, find, replace);
			} else if (storage.autolinkRewrite && child.nodeName.toLowerCase() == "a") {
				if (storage.findUrl.test(child.href)) {
					child.href = child.href.replace(storage.findUrl, storage.urlPrefix + "$1");
				}
			}
		} else if (child.nodeType == 3) { // TEXT_NODE
			replaceInText(child, find, replace);
		}
	}
}

function replaceInText(text, find, replace) {
	var match;
	var matches = [];
	while ((match = find.exec(text.data)) !== null) {
		matches.push(match);
	}
	for (var i = matches.length; i-- > 0;) {
		match = matches[i];
		text.splitText(match.index);
		text.nextSibling.splitText(match[0].length);
		text.parentNode.replaceChild(replace(match), text.nextSibling);
	}
}
<commit_msg>Autolink: Minor code style cleanup<commit_after>/*!
	Copyright (C) 2016 Matthew D. Mower

	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.
*/

storage();

function storage() {
	if (typeof storage.area === 'undefined') {
		storage.area = chrome.storage.local;
	}
	if (typeof storage.urlPrefix === 'undefined') {
		storage.urlPrefix = "http://dx.doi.org/";
	}
	if (typeof storage.findDoi === 'undefined') {
		// http://stackoverflow.com/questions/27910/finding-a-doi-in-a-document-or-page
		storage.findDoi = /\b(10[.][0-9]{3,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)\b/ig;
	}
	if (typeof storage.findUrl === 'undefined') {
		// http://stackoverflow.com/questions/27910/finding-a-doi-in-a-document-or-page
		storage.findUrl = /^(?:https?\:\/\/)(?:dx\.)?doi\.org\/(10[.][0-9]{3,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)$/ig;
	}
	if (typeof storage.autolinkRewrite === 'undefined') {
		storage.autolinkRewrite = false;
	}

	chrome.storage.local.get(["sync_data"], function(stg) {
		if (stg.sync_data === true) {
			storage.area = chrome.storage.sync;
		} else {
			storage.area = chrome.storage.local;
		}

		var stgFetch = [
			"cr_autolink",
			"auto_link_rewrite",
			"custom_resolver",
			"doi_resolver"
		];

		storage.area.get(stgFetch, function(stg) {
			if (stg.custom_resolver === true && stg.cr_autolink == "custom") {
				storage.urlPrefix = stg.doi_resolver;
				storage.autolinkRewrite = stg.auto_link_rewrite === true;
			}
			replaceDOIsWithLinks();
		});
	});
}

// http://stackoverflow.com/questions/1444409/in-javascript-how-can-i-replace-text-in-an-html-page-without-affecting-the-tags
function replaceDOIsWithLinks() {
	replaceInElement(document.body, storage.findDoi, function(match) {
		var link = document.createElement('a');
		link.href = storage.urlPrefix + match[0];
		link.appendChild(document.createTextNode(match[0]));
		return link;
	});
}

// iterate over child nodes in reverse, as replacement may increase length of child node list.
function replaceInElement(element, find, replace) {
	// don't touch these elements
	var forbiddenTags = ["a", "input", "script", "style", "textarea"];
	for (var i = element.childNodes.length - 1; i >= 0; i--) {
		var child = element.childNodes[i];
		if (child.nodeType === Node.ELEMENT_NODE) {
			if (forbiddenTags.indexOf(child.nodeName.toLowerCase()) < 0) {
				replaceInElement(child, find, replace);
			} else if (storage.autolinkRewrite && child.nodeName.toLowerCase() == "a") {
				if (storage.findUrl.test(child.href)) {
					child.href = child.href.replace(storage.findUrl, storage.urlPrefix + "$1");
				}
			}
		} else if (child.nodeType === Node.TEXT_NODE) {
			replaceInText(child, find, replace);
		}
	}
}

function replaceInText(text, find, replace) {
	var matches = [];
	var match = find.exec(text.data);
	while (match !== null) {
		matches.push(match);
		match = find.exec(text.data);
	}
	for (var i = matches.length - 1; i >= 0; i--) {
		match = matches[i];
		text.splitText(match.index);
		text.nextSibling.splitText(match[0].length);
		text.parentNode.replaceChild(replace(match), text.nextSibling);
	}
}
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is infoRSS.
 *
 * The Initial Developer of the Original Code is
 *   Didier Ernotte <didier@ernotte.com>.
 * Portions created by the Initial Developer are Copyright (C) 2004
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Didier Ernotte <didier@ernotte.com>.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
//-------------------------------------------------------------------------------------------------------------
// inforssParser
// Author : Didier Ernotte 2005
// Inforss extension
//-------------------------------------------------------------------------------------------------------------

var inforss = inforss || {};
Components.utils.import("chrome://inforss/content/modules/Prompt.jsm", inforss);

//-----------------------------------------------------------------------------------------------------
/* exported FeedManager */
function FeedManager()
{
  this.title = null;
  this.description = null;
  this.link = null;
  this.rssFeeds = [];
  this.addFeed = addFeed;
  this.parse = parse;
  this.getListOfCategories = getListOfCategories;
  this.type = null;
}

//-----------------------------------------------------------------------------------------------------
function Feed(title, description, link, category)
{
  this.title = title;
  this.description = description;
  this.link = link;
  this.category = category;
}

//-----------------------------------------------------------------------------------------------------
function addFeed(title, description, link, category)
{
  //FIXME This is really the best way to append something to an array?
  this.rssFeeds[this.rssFeeds.length] = new Feed(title, description, link, category);
}

//-----------------------------------------------------------------------------------------------------
//FIXME This function does the same as the factory in inforssFeed but not as
//well (and should use the factory) and in inforss.js. This should hand off
//to the individual feeds
function parse(xmlHttpRequest)
{
  try
  {
    //Note: Channel is a mozilla extension
    const url = xmlHttpRequest.channel.originalURI.asciiSpec;

    //Note: I've only seen this called when you have 'display as submenu'
    //selected. Also it is iffy as it replicates code from inforssFeedxxx
    if (xmlHttpRequest.status >= 400)
    {
      inforss.alert(xmlHttpRequest.statusText + ": " + url);
      return;
    }

    let string = xmlHttpRequest.responseText;

    {
      const pos = string.indexOf("<?xml");
      //Some places return a 404 page with a 200 status for reasons best known
      //to themselves.
      //Other sites get taken over and return a 'for sale' page.
      if (pos == -1)
      {
        throw "Received something that wasn't xml";
      }
      //Some sites have rubbish before the <?xml
      if (pos > 0)
      {
        string = string.substring(pos);
        console.log("Stripping rubbish at start of " + url);
      }
    }

    var objDOMParser = new DOMParser();
    var objDoc = objDOMParser.parseFromString(string, "text/xml");

    var str_description = null;
    var str_title = null;
    var str_link = null;
    var str_item = null;
    var feed_flag = false;
    if (objDoc.documentElement.nodeName == "feed")
    {
      str_description = "tagline";
      str_title = "title";
      str_link = "link";
      str_item = "entry";
      feed_flag = true;
      this.type = "atom";
    }
    else
    {
      str_description = "description";
      str_title = "title";
      str_link = "link";
      str_item = "item";
      this.type = "rss";
    }

    this.link = feed_flag ?
      getHref(objDoc.getElementsByTagName(str_link)) :
      getNodeValue(objDoc.getElementsByTagName(str_link));
    this.description = getNodeValue(objDoc.getElementsByTagName(str_description));
    this.title = getNodeValue(objDoc.getElementsByTagName(str_title));

    for (let item of objDoc.getElementsByTagName(str_item))
    {
      let title = item.getElementsByTagName(str_title);
      title = title.length == 0 ? "" : getNodeValue(title);

      let link = item.getElementsByTagName(str_link);
      link = link.length == 0 ? "" :
              feed_flag ? getHref(link) : getNodeValue(link);
      link = (new URL(link, xmlHttpRequest.channel.name)).href;

      let description = item.getElementsByTagName(str_description);
      description = description.length == 0 ? "" : getNodeValue(description);

      let category = item.getElementsByTagName("category");
      category = category.length == 0 ? "" : getNodeValue(category);

      this.addFeed(title, description, link, category);
    }
  }
  catch (e)
  {
    console.log("Error processing", objDoc, e);
    inforss.alert("error processing: " + e);
  }
}

//------------------------------------------------------------------------------
//FIXME Should we make this return a set?
function getListOfCategories()
{
  var categories = new Set();
  for (let feed of this.rssFeeds)
  {
    if (feed.category != "")
    {
      categories.add(feed.category);
    }
  }
  return Array.from(categories);
}

//-----------------------------------------------------------------------------------------------------
/* exported getNodeValue */
function getNodeValue(obj)
{
  //FIXME .textValue?
  return obj.length == 0 || obj[0] == null || obj[0].firstChild == null ?
          null :
          obj[0].firstChild.nodeValue;
}

/* exported getHref */
//-----------------------------------------------------------------------------------------------------
function getHref(obj)
{
  //FIXME Wouldn't this be better coded as doc.querySelector(rel == alternate && type == link) on the whole objdoc?
  for (let elem of obj)
  {
    if (elem.getAttribute("rel") == "alternate")
    {
      return elem.getAttribute("href");
    }
  }
  return null;
}
<commit_msg>Fix a not-really-new jshint issue<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is infoRSS.
 *
 * The Initial Developer of the Original Code is
 *   Didier Ernotte <didier@ernotte.com>.
 * Portions created by the Initial Developer are Copyright (C) 2004
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Didier Ernotte <didier@ernotte.com>.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
//-------------------------------------------------------------------------------------------------------------
// inforssParser
// Author : Didier Ernotte 2005
// Inforss extension
//-------------------------------------------------------------------------------------------------------------

var inforss = inforss || {};
Components.utils.import("chrome://inforss/content/modules/Prompt.jsm", inforss);

//-----------------------------------------------------------------------------------------------------
/* exported FeedManager */
function FeedManager()
{
  this.title = null;
  this.description = null;
  this.link = null;
  this.rssFeeds = [];
  this.addFeed = addFeed;
  this.parse = parse;
  this.getListOfCategories = getListOfCategories;
  this.type = null;
}

//-----------------------------------------------------------------------------------------------------
function Feed(title, description, link, category)
{
  this.title = title;
  this.description = description;
  this.link = link;
  this.category = category;
}

//-----------------------------------------------------------------------------------------------------
function addFeed(title, description, link, category)
{
  //FIXME This is really the best way to append something to an array?
  this.rssFeeds[this.rssFeeds.length] = new Feed(title, description, link, category);
}

//-----------------------------------------------------------------------------------------------------
//FIXME This function does the same as the factory in inforssFeed but not as
//well (and should use the factory) and in inforss.js. This should hand off
//to the individual feeds
function parse(xmlHttpRequest)
{
  try
  {
    //Note: Channel is a mozilla extension
    const url = xmlHttpRequest.channel.originalURI.asciiSpec;

    //Note: I've only seen this called when you have 'display as submenu'
    //selected. Also it is iffy as it replicates code from inforssFeedxxx
    if (xmlHttpRequest.status >= 400)
    {
      inforss.alert(xmlHttpRequest.statusText + ": " + url);
      return;
    }

    let string = xmlHttpRequest.responseText;

    {
      const pos = string.indexOf("<?xml");
      //Some places return a 404 page with a 200 status for reasons best known
      //to themselves.
      //Other sites get taken over and return a 'for sale' page.
      if (pos == -1)
      {
        throw "Received something that wasn't xml";
      }
      //Some sites have rubbish before the <?xml
      if (pos > 0)
      {
        string = string.substring(pos);
        console.log("Stripping rubbish at start of " + url);
      }
    }

    var objDOMParser = new DOMParser();
    var objDoc = objDOMParser.parseFromString(string, "text/xml");

    var str_description = null;
    var str_title = null;
    var str_link = null;
    var str_item = null;
    var feed_flag = false;
    if (objDoc.documentElement.nodeName == "feed")
    {
      str_description = "tagline";
      str_title = "title";
      str_link = "link";
      str_item = "entry";
      feed_flag = true;
      this.type = "atom";
    }
    else
    {
      str_description = "description";
      str_title = "title";
      str_link = "link";
      str_item = "item";
      this.type = "rss";
    }

    this.link = feed_flag ?
      getHref(objDoc.getElementsByTagName(str_link)) :
      getNodeValue(objDoc.getElementsByTagName(str_link));
    this.description =
      getNodeValue(objDoc.getElementsByTagName(str_description));
    this.title = getNodeValue(objDoc.getElementsByTagName(str_title));

    for (let item of objDoc.getElementsByTagName(str_item))
    {
      let title = item.getElementsByTagName(str_title);
      title = title.length == 0 ? "" : getNodeValue(title);

      let link = item.getElementsByTagName(str_link);
      link = link.length == 0 ? "" :
              feed_flag ? getHref(link) : getNodeValue(link);
      link = (new URL(link, xmlHttpRequest.channel.name)).href;

      let description = item.getElementsByTagName(str_description);
      description = description.length == 0 ? "" : getNodeValue(description);

      let category = item.getElementsByTagName("category");
      category = category.length == 0 ? "" : getNodeValue(category);

      this.addFeed(title, description, link, category);
    }
  }
  catch (e)
  {
    console.log("Error processing", objDoc, e);
    inforss.alert("error processing: " + e);
  }
}

//------------------------------------------------------------------------------
//FIXME Should we make this return a set?
function getListOfCategories()
{
  var categories = new Set();
  for (let feed of this.rssFeeds)
  {
    if (feed.category != "")
    {
      categories.add(feed.category);
    }
  }
  return Array.from(categories);
}

//-----------------------------------------------------------------------------------------------------
/* exported getNodeValue */
function getNodeValue(obj)
{
  //FIXME .textValue?
  return obj.length == 0 || obj[0] == null || obj[0].firstChild == null ?
          null :
          obj[0].firstChild.nodeValue;
}

/* exported getHref */
//-----------------------------------------------------------------------------------------------------
function getHref(obj)
{
  //FIXME Wouldn't this be better coded as doc.querySelector(rel == alternate && type == link) on the whole objdoc?
  for (let elem of obj)
  {
    if (elem.getAttribute("rel") == "alternate")
    {
      return elem.getAttribute("href");
    }
  }
  return null;
}
<|endoftext|>