<commit_before>'use strict';

const OP = {
  // shifts
  SHL: -13, // iii shift left (like ASL, arithmetic shift left) = multiply by three + D
  ROL: -12, // ii0 rotate left
  ROR: -11, // ii1 rotate right
  SHR: -10, // i0i shift right = division by by power of three

  // indexing
  STX: -9, // i00 store X
  LDX: -8, // i01 load X

  // ternary dyadic functions
  BUT: -7, // i1i pref-0i1, BUT                                f i0i,000,i01
  ORA: -6, // i10 pref-10i, TOR,  maximum, ↑ U+2191, ∨ U+2228, f i01,001,111
  AND: -5, // i11 pref-i01, TAND, minimum, ↓ U+2193, ∧ U+2227, f iii,i00,i01
  EOR: -4, // 0ii exclusive max ⇑ U+2d1                        f i01,0i1,11i

  STY: -3, // 0i0 store Y
  LDY: -2, // 0i1 load Y

  // increment/no-op/decrement
  DEC: -1, // 00i decrement
  NOP: 0,  // 000 no operation
  INC: 1,  // 001 increment

  CPX: 2,  // 01i compare X

  // arithmetic
  ADC: 3, // 010 add with carry
  STA: 4, // 011 store accumulator
  LDA: 5, // 1ii load accumulator
  CMP: 6, // 1i0 compare A
  SBC: 7, // 1i1 subtract borrow carry

  // unary ternary functions (a.3.5) https://www.scribd.com/doc/78370674/Ternary-Computing-Testbed-3-Trit-Computer-Architecture
  NTI: 8, // 10i negative ternary inverter (tritwise i01 -> 1ii)
  STI: 9, // 100 simple ternary inverter   (tritwise i01 -> 10i)
  PTI:10, // 101 positive ternary inverter (tritwise i01 -> 11i)
  FD: 11, // 11i forward diode             (tritwise i01 -> 001)
  RD: 12, // 110 reverse diode             (tritwise i01 -> i00)

  CPY:13  // 111 compare Y
};

const ADDR_MODE = {
  ABSOLUTE: -1,
  ACCUMULATOR: 0,
  IMMEDIATE: 1,

  // internal modes only used by assembler, not instruction coding format
  BRANCH_RELATIVE: 2,
};

const FLAGS = {
  // flag (aa) 9 trits
  L: -4, // -4 ii L least significant trit of A (if 0, divisible by 3)
  I: -3, // -3 i0 I interrupts masked
  C: -2, // -2 i1 C carry
  D: -1, // -1 0i D dead zero
  S:  0, //  0 00 S sign, set to first nonzero trit of A (i=negative, 1=positive, or 0 if 0)
  V:  1, // +1 01 V overflow/underflow
  U:  2, // +2 1i U unused for now
  H:  3, // +3 10 H halt code
  R:  4, // +4 11 R running, 1 when executing forward, i backwards, 0 halted
};

const INSTRUCTION_ALIASES = {
  NEG: 'STI', // negate = simple ternary inverter
  NOT: 'STI', // not = simple ternary inverter

  // generic branch instruction format is BR<flag><operation><compare-trit>
  //  flag: code from FLAGS
  //  operation: L=less than, E=equal, N=not equal
  //  compare-trit: N=-1, Z=0, P=1
  BEQ: 'BRSEZ', // branch if equal = branch if sign equal to zero
  BNE: 'BRSNZ', // branch if not equal = branch if sign not equal to zero
  BMI: 'BRSEN', // branch if minus = branch if sign equal to negative
  BPL: 'BRSEP', // branch if positive = branch if sign equal to positive
  BVC: 'BRVEZ', // branch if overflow clear = branch if overflow equal to zero
  BVS: 'BRVNZ', // branch if overflow set = branch if overflow nonzero
  BRA: 'BRRNZ', // branch always = branch if running is not zero
};

const XOP = {

  TAX: 1,       // 0001 transfer accumulator to index
  TAY: 2,       // 001i transfer accumulator to yindex
  TXA: 3,       // 0010 transfer index to accumulator
  TYA: 4,       // 0011 transfer yindex to accumulator

  INX: 5,       // 01ii increment index
  INY: 6,       // 01i0 increment yindex
  DEX: 7,       // 01i1 decrement index
  DEY: 8,       // 010i decrement yindex

  CLC: 9,       // 0100 clear carry flag
  CLI: 10,      // 0101 clear interrupt-disable flag
  CLV: 11,      // 011i clear overflow flag
  SECP: 12,     // 0110 set carry flag positive
  SECN: 13,     // 0111 set carry flag negative
  SEIP: 14,     // 1iii set interrupt flag positive
  SEIN: 15,     // 1ii0 set interrupt flag negative

  INTN: 16,     // 1ii1 interrupt negative
  INTZ: 17,     // 1i0i interrupt zero
  INTP: 18,     // 1i00 interrupt positive

  BRK: 19,      // 1i01 breakpoint

  LDAXY: 20,    // 1i1i load into accumulator absolute from Y<<5 + X
  STAXY: 21,    // 1i10 store accumulator absolut to Y<<5 + X

  CLD: 22,      // 1i11 clear data flag
  SEDP: 23,     // 10ii set data flag positive
  SEDN: 24,     // 10i0 set data flag negative

  HALTP: -38,   // iii1 halt positive
  HALTZ: -39,   // iii0 halt zero
  HALTN: -40,   // iiii halt negative
};

module.exports = {
  OP,
  ADDR_MODE,
  FLAGS,
  INSTRUCTION_ALIASES,
  XOP
};
<commit_msg>Update comments for processor flags<commit_after>'use strict';

const OP = {
  // shifts
  SHL: -13, // iii shift left (like ASL, arithmetic shift left) = multiply by three + D
  ROL: -12, // ii0 rotate left
  ROR: -11, // ii1 rotate right
  SHR: -10, // i0i shift right = division by by power of three

  // indexing
  STX: -9, // i00 store X
  LDX: -8, // i01 load X

  // ternary dyadic functions
  BUT: -7, // i1i pref-0i1, BUT                                f i0i,000,i01
  ORA: -6, // i10 pref-10i, TOR,  maximum, ↑ U+2191, ∨ U+2228, f i01,001,111
  AND: -5, // i11 pref-i01, TAND, minimum, ↓ U+2193, ∧ U+2227, f iii,i00,i01
  EOR: -4, // 0ii exclusive max ⇑ U+2d1                        f i01,0i1,11i

  STY: -3, // 0i0 store Y
  LDY: -2, // 0i1 load Y

  // increment/no-op/decrement
  DEC: -1, // 00i decrement
  NOP: 0,  // 000 no operation
  INC: 1,  // 001 increment

  CPX: 2,  // 01i compare X

  // arithmetic
  ADC: 3, // 010 add with carry
  STA: 4, // 011 store accumulator
  LDA: 5, // 1ii load accumulator
  CMP: 6, // 1i0 compare A
  SBC: 7, // 1i1 subtract borrow carry

  // unary ternary functions (a.3.5) https://www.scribd.com/doc/78370674/Ternary-Computing-Testbed-3-Trit-Computer-Architecture
  NTI: 8, // 10i negative ternary inverter (tritwise i01 -> 1ii)
  STI: 9, // 100 simple ternary inverter   (tritwise i01 -> 10i)
  PTI:10, // 101 positive ternary inverter (tritwise i01 -> 11i)
  FD: 11, // 11i forward diode             (tritwise i01 -> 001)
  RD: 12, // 110 reverse diode             (tritwise i01 -> i00)

  CPY:13  // 111 compare Y
};

const ADDR_MODE = {
  ABSOLUTE: -1,
  ACCUMULATOR: 0,
  IMMEDIATE: 1,

  // internal modes only used by assembler, not instruction coding format
  BRANCH_RELATIVE: 2,
};

const FLAGS = {
  // flag (aa) 9 trits
  L: -4, // -4 ii L least significant trit of last value (if 0, divisible by 3)
  I: -3, // -3 i0 I interrupts masked
  C: -2, // -2 i1 C carry trit
  D: -1, // -1 0i D data trit, shift in
  S:  0, //  0 00 S sign, set to first nonzero trit of last value (i=negative, 1=positive, or 0 if 0)
  V:  1, // +1 01 V overflow/underflow
  U:  2, // +2 1i U unused for now
  H:  3, // +3 10 H halt code
  R:  4, // +4 11 R running, 1 when executing forward, i backwards, 0 halted
};

const INSTRUCTION_ALIASES = {
  NEG: 'STI', // negate = simple ternary inverter
  NOT: 'STI', // not = simple ternary inverter

  // generic branch instruction format is BR<flag><operation><compare-trit>
  //  flag: code from FLAGS
  //  operation: L=less than, E=equal, N=not equal
  //  compare-trit: N=-1, Z=0, P=1
  BEQ: 'BRSEZ', // branch if equal = branch if sign equal to zero
  BNE: 'BRSNZ', // branch if not equal = branch if sign not equal to zero
  BMI: 'BRSEN', // branch if minus = branch if sign equal to negative
  BPL: 'BRSEP', // branch if positive = branch if sign equal to positive
  BVC: 'BRVEZ', // branch if overflow clear = branch if overflow equal to zero
  BVS: 'BRVNZ', // branch if overflow set = branch if overflow nonzero
  BRA: 'BRRNZ', // branch always = branch if running is not zero
};

const XOP = {

  TAX: 1,       // 0001 transfer accumulator to index
  TAY: 2,       // 001i transfer accumulator to yindex
  TXA: 3,       // 0010 transfer index to accumulator
  TYA: 4,       // 0011 transfer yindex to accumulator

  INX: 5,       // 01ii increment index
  INY: 6,       // 01i0 increment yindex
  DEX: 7,       // 01i1 decrement index
  DEY: 8,       // 010i decrement yindex

  CLC: 9,       // 0100 clear carry flag
  CLI: 10,      // 0101 clear interrupt-disable flag
  CLV: 11,      // 011i clear overflow flag
  SECP: 12,     // 0110 set carry flag positive
  SECN: 13,     // 0111 set carry flag negative
  SEIP: 14,     // 1iii set interrupt flag positive
  SEIN: 15,     // 1ii0 set interrupt flag negative

  INTN: 16,     // 1ii1 interrupt negative
  INTZ: 17,     // 1i0i interrupt zero
  INTP: 18,     // 1i00 interrupt positive

  BRK: 19,      // 1i01 breakpoint

  LDAXY: 20,    // 1i1i load into accumulator absolute from Y<<5 + X
  STAXY: 21,    // 1i10 store accumulator absolut to Y<<5 + X

  CLD: 22,      // 1i11 clear data flag
  SEDP: 23,     // 10ii set data flag positive
  SEDN: 24,     // 10i0 set data flag negative

  HALTP: -38,   // iii1 halt positive
  HALTZ: -39,   // iii0 halt zero
  HALTN: -40,   // iiii halt negative
};

module.exports = {
  OP,
  ADDR_MODE,
  FLAGS,
  INSTRUCTION_ALIASES,
  XOP
};
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var Task = require('../models/Task');

router.post('/create', function (req, res) {
  var TaskData = req.body;
  var newTask = Task(TaskData);
  newTask.save(function (err) {
    if (err) throw err;
    res.send(JSON.stringify(newTask));
  });

  console.log(TaskData);
});

router.post('/assign:taskID/:userID', function (req, res) {
  var userID = Number(req.param("userID"));
  var taskID = Number(req.param("taskID"));
  Task.findOne({
    _id: taskID
  }, function (err, taskTemplate) {
      if (taskTemplate) {
        var duplicatedTask = objectIdDel(JSON.parse(JSON.stringify(taskTemplate)));
        duplicatedTask.user_id = userID;
        duplicatedTask.save(function (err) {
          if (err) throw err;
          res.send(JSON.stringify(duplicatedTask));
        });

      }
      else {
        res.sendStatus(404);
      }

    });
});

var objectIdDel = function (copiedObjectWithId) {
  if (copiedObjectWithId != null && typeof (copiedObjectWithId) != 'string' &&
    typeof (copiedObjectWithId) != 'number' && typeof (copiedObjectWithId) != 'boolean') {
    //for array length is defined however for objects length is undefined
    if (typeof (copiedObjectWithId.length) == 'undefined') {
      delete copiedObjectWithId._id;
      for (var key in copiedObjectWithId) {
        objectIdDel(copiedObjectWithId[key]); //recursive del calls on object elements
      }
    }
    else {
      for (var i = 0; i < copiedObjectWithId.length; i++) {
        objectIdDel(copiedObjectWithId[i]);  //recursive del calls on array elements
      }
    }
  }
}
module.exports = router;<commit_msg>get list for user and org<commit_after>var express = require('express');
var router = express.Router();
var Task = require('../models/Task');

router.get('/organizaiton/list/:id', function (req, res) {

  var orgID = Number(req.param("id"));
  Task.find({ org_id: orgID }, function (err, tasks) {
    if (err) throw err;
    res.send(tasks);
  });

});

router.get('/user/list:id', function (req, res) {

 var userID = Number(req.param("id"));
  Task.find({ user_id: userID }, function (err, tasks) {
    if (err) throw err;
    res.send(tasks);
  });

});

router.post('/create', function (req, res) {
  var TaskData = req.body;
  var newTask = Task(TaskData);
  newTask.save(function (err) {
    if (err) throw err;
    res.send(JSON.stringify(newTask));
  });

  console.log(TaskData);
});

router.post('/assign:taskID/:userID', function (req, res) {
  var userID = Number(req.param("userID"));
  var taskID = Number(req.param("taskID"));
  Task.findOne({
    _id: taskID
  }, function (err, taskTemplate) {
      if (taskTemplate) {
        var duplicatedTask = objectIdDel(JSON.parse(JSON.stringify(taskTemplate)));
        duplicatedTask.user_id = userID;
        duplicatedTask.save(function (err) {
          if (err) throw err;
          res.send(JSON.stringify(duplicatedTask));
        });

      }
      else {
        res.sendStatus(404);
      }

    });
});

var objectIdDel = function (copiedObjectWithId) {
  if (copiedObjectWithId != null && typeof (copiedObjectWithId) != 'string' &&
    typeof (copiedObjectWithId) != 'number' && typeof (copiedObjectWithId) != 'boolean') {
    //for array length is defined however for objects length is undefined
    if (typeof (copiedObjectWithId.length) == 'undefined') {
      delete copiedObjectWithId._id;
      for (var key in copiedObjectWithId) {
        objectIdDel(copiedObjectWithId[key]); //recursive del calls on object elements
      }
    }
    else {
      for (var i = 0; i < copiedObjectWithId.length; i++) {
        objectIdDel(copiedObjectWithId[i]);  //recursive del calls on array elements
      }
    }
  }
}
module.exports = router;<|endoftext|>


<commit_before>// The ConversationPanel module is designed to handle
// all display and behaviors of the conversation column of the app.
/* eslint no-unused-vars: "off" */
/* global Api: true, Common: true*/

var ConversationPanel = (function() {
  var settings = {
    selectors: {
      chatBox: '#scrollingChat',
      fromUser: '.from-user',
      fromWatson: '.from-watson',
      latest: '.latest'
    },
    authorTypes: {
      user: 'user',
      watson: 'watson'
    }
  };

  // Publicly accessible methods defined
  return {
    init: init,
    inputKeyDown: inputKeyDown
  };

  // Initialize the module
  function init() {
    chatUpdateSetup();
    Api.sendRequest( '', null );
    setupInputBox();
  }
  // Set up callbacks on payload setters in Api module
  // This causes the displayMessage function to be called when messages are sent / received
  function chatUpdateSetup() {
    var currentRequestPayloadSetter = Api.setRequestPayload;
    Api.setRequestPayload = function(newPayloadStr) {
      currentRequestPayloadSetter.call(Api, newPayloadStr);
      displayMessage(JSON.parse(newPayloadStr), settings.authorTypes.user);
    };

    var currentResponsePayloadSetter = Api.setResponsePayload;
    Api.setResponsePayload = function(newPayloadStr) {
      currentResponsePayloadSetter.call(Api, newPayloadStr);
      displayMessage(JSON.parse(newPayloadStr), settings.authorTypes.watson);
    };
  }

// Set up the input box to underline text as it is typed
  // This is done by creating a hidden dummy version of the input box that
  // is used to determine what the width of the input text should be.
  // This value is then used to set the new width of the visible input box.
  function setupInputBox() {
    var input = document.getElementById('textInput');
    var dummy = document.getElementById('textInputDummy');
    var minFontSize = 14;
    var maxFontSize = 16;
    var minPadding = 4;
    var maxPadding = 6;

    // If no dummy input box exists, create one
    if (dummy === null) {
      var dummyJson = {
        'tagName': 'div',
        'attributes': [{
          'name': 'id',
          'value': 'textInputDummy'
        }]
      };

      dummy = Common.buildDomElement(dummyJson);
      document.body.appendChild(dummy);
    }

    function adjustInput() {
      if (input.value === '') {
        // If the input box is empty, remove the underline
        input.classList.remove('underline');
        input.setAttribute('style', 'width:' + '100%');
        input.style.width = '100%';
      } else {
        // otherwise, adjust the dummy text to match, and then set the width of
        // the visible input box to match it (thus extending the underline)
        input.classList.add('underline');
        var txtNode = document.createTextNode(input.value);
        ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height',
          'text-transform', 'letter-spacing'].forEach(function(index) {
            dummy.style[index] = window.getComputedStyle(input, null).getPropertyValue(index);
          });
        dummy.textContent = txtNode.textContent;

        var padding = 0;
        var htmlElem = document.getElementsByTagName('html')[0];
        var currentFontSize = parseInt(window.getComputedStyle(htmlElem, null).getPropertyValue('font-size'), 10);
        if (currentFontSize) {
          padding = Math.floor((currentFontSize - minFontSize) / (maxFontSize - minFontSize)
            * (maxPadding - minPadding) + minPadding);
        } else {
          padding = maxPadding;
        }

        var widthValue = ( dummy.offsetWidth + padding) + 'px';
        input.setAttribute('style', 'width:' + widthValue);
        input.style.width = widthValue;
      }
    }

    // Any time the input changes, or the window resizes, adjust the size of the input box
    input.addEventListener('input', adjustInput);
    window.addEventListener('resize', adjustInput);

    // Trigger the input event once to set up the input box and dummy element
    Common.fireEvent(input, 'input');
  }

  // Display a user or Watson message that has just been sent/received
  function displayMessage(newPayload, typeValue) {
    var isUser = isUserMessage(typeValue);
    var textExists = (newPayload.input && newPayload.input.text)
      || (newPayload.output && newPayload.output.text);
    if (isUser !== null && textExists) {
      // Create new message DOM element
      var messageDivs = buildMessageDomElements(newPayload, isUser);
      var chatBoxElement = document.querySelector(settings.selectors.chatBox);
      var previousLatest = chatBoxElement.querySelectorAll((isUser
              ? settings.selectors.fromUser : settings.selectors.fromWatson)
              + settings.selectors.latest);
      // Previous "latest" message is no longer the most recent
      if (previousLatest) {
        Common.listForEach(previousLatest, function(element) {
          element.classList.remove('latest');
        });
      }

      messageDivs.forEach(function(currentDiv) {
        chatBoxElement.appendChild(currentDiv);
        // Class to start fade in animation
        currentDiv.classList.add('load');
      });
      // Move chat to the most recent messages when new messages are added
      scrollToChatBottom();

      // check if output returns no answer for the question
      // email the bot admin that it detects an unanswered question
      if (newPayload.output && newPayload.output.text) {
        var no_answer = /I haven't got that answer, yet/;
        if (no_answer.test(newPayload.output.text[0])) {
          Api.sendEmailNotifications({
            text: newPayload.input.text
          });
        }
      }
    }
  }

  // Checks if the given typeValue matches with the user "name", the Watson "name", or neither
  // Returns true if user, false if Watson, and null if neither
  // Used to keep track of whether a message was from the user or Watson
  function isUserMessage(typeValue) {
    if (typeValue === settings.authorTypes.user) {
      return true;
    } else if (typeValue === settings.authorTypes.watson) {
      return false;
    }
    return null;
  }

  // Constructs new DOM element from a message payload
  function buildMessageDomElements(newPayload, isUser) {
    var textArray = isUser ? newPayload.input.text : newPayload.output.text;
    if (Object.prototype.toString.call( textArray ) !== '[object Array]') {
      textArray = [textArray];
    }
    var messageArray = [];

    textArray.forEach(function(currentText) {
      if (currentText) {
        var messageJson = {
          //

          'tagName': 'div',
          'classNames': ['segments'],
          'children': [{
            //

            'tagName': 'div',
            'classNames': [(isUser ? 'from-user' : 'from-watson'), 'latest', ((messageArray.length === 0) ? 'top' : 'sub')],
            'children': [{
              //

              'tagName': 'div',
              'classNames': ['message-inner'],
              'children': [{
                //
{messageText}

                'tagName': 'p',
                'text': currentText
              }]
            }]
          }]
        };
        messageArray.push(Common.buildDomElement(messageJson));
      }
    });

    return messageArray;
  }

  // Scroll to the bottom of the chat window (to the most recent messages)
  // Note: this method will bring the most recent user message into view,
  //   even if the most recent message is from Watson.
  //   This is done so that the "context" of the conversation is maintained in the view,
  //   even if the Watson message is long.
  function scrollToChatBottom() {
    var scrollingChat = document.querySelector('#scrollingChat');

    // Scroll to the latest message sent by the user
    var scrollEl = scrollingChat.querySelector(settings.selectors.fromUser
            + settings.selectors.latest);
    if (scrollEl) {
      scrollingChat.scrollTop = scrollEl.offsetTop;
    }
  }

  // Handles the submission of input
  function inputKeyDown(event, inputBox) {
    // Submit on enter key, dis-allowing blank messages
    if (event.keyCode === 13 && inputBox.value) {
      // Retrieve the context from the previous server response
      var context;
      var latestResponse = Api.getResponsePayload();
      if (latestResponse) {
        context = latestResponse.context;
      }

      // Send the user message
      Api.sendRequest(inputBox.value, context);

      // Clear input box for further messages
      inputBox.value = '';
      Common.fireEvent(inputBox, 'input');
    }
  }
}());
<commit_msg>added filter for multiple questions<commit_after>// The ConversationPanel module is designed to handle
// all display and behaviors of the conversation column of the app.
/* eslint no-unused-vars: "off" */
/* global Api: true, Common: true*/

var ConversationPanel = (function() {
  var settings = {
    selectors: {
      chatBox: '#scrollingChat',
      fromUser: '.from-user',
      fromWatson: '.from-watson',
      latest: '.latest'
    },
    authorTypes: {
      user: 'user',
      watson: 'watson'
    }
  };

  // custom variables
  var topic = '';
  var unanswered = '';

  // Publicly accessible methods defined
  return {
    init: init,
    inputKeyDown: inputKeyDown
  };

  // Initialize the module
  function init() {
    chatUpdateSetup();
    Api.sendRequest( '', null );
    setupInputBox();
  }
  // Set up callbacks on payload setters in Api module
  // This causes the displayMessage function to be called when messages are sent / received
  function chatUpdateSetup() {
    var currentRequestPayloadSetter = Api.setRequestPayload;
    Api.setRequestPayload = function(newPayloadStr) {
      currentRequestPayloadSetter.call(Api, newPayloadStr);
      displayMessage(JSON.parse(newPayloadStr), settings.authorTypes.user);
    };

    var currentResponsePayloadSetter = Api.setResponsePayload;
    Api.setResponsePayload = function(newPayloadStr) {
      currentResponsePayloadSetter.call(Api, newPayloadStr);
      displayMessage(JSON.parse(newPayloadStr), settings.authorTypes.watson);
    };
  }

// Set up the input box to underline text as it is typed
  // This is done by creating a hidden dummy version of the input box that
  // is used to determine what the width of the input text should be.
  // This value is then used to set the new width of the visible input box.
  function setupInputBox() {
    var input = document.getElementById('textInput');
    var dummy = document.getElementById('textInputDummy');
    var minFontSize = 14;
    var maxFontSize = 16;
    var minPadding = 4;
    var maxPadding = 6;

    // If no dummy input box exists, create one
    if (dummy === null) {
      var dummyJson = {
        'tagName': 'div',
        'attributes': [{
          'name': 'id',
          'value': 'textInputDummy'
        }]
      };

      dummy = Common.buildDomElement(dummyJson);
      document.body.appendChild(dummy);
    }

    function adjustInput() {
      if (input.value === '') {
        // If the input box is empty, remove the underline
        input.classList.remove('underline');
        input.setAttribute('style', 'width:' + '100%');
        input.style.width = '100%';
      } else {
        // otherwise, adjust the dummy text to match, and then set the width of
        // the visible input box to match it (thus extending the underline)
        input.classList.add('underline');
        var txtNode = document.createTextNode(input.value);
        ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height',
          'text-transform', 'letter-spacing'].forEach(function(index) {
            dummy.style[index] = window.getComputedStyle(input, null).getPropertyValue(index);
          });
        dummy.textContent = txtNode.textContent;

        var padding = 0;
        var htmlElem = document.getElementsByTagName('html')[0];
        var currentFontSize = parseInt(window.getComputedStyle(htmlElem, null).getPropertyValue('font-size'), 10);
        if (currentFontSize) {
          padding = Math.floor((currentFontSize - minFontSize) / (maxFontSize - minFontSize)
            * (maxPadding - minPadding) + minPadding);
        } else {
          padding = maxPadding;
        }

        var widthValue = ( dummy.offsetWidth + padding) + 'px';
        input.setAttribute('style', 'width:' + widthValue);
        input.style.width = widthValue;
      }
    }

    // Any time the input changes, or the window resizes, adjust the size of the input box
    input.addEventListener('input', adjustInput);
    window.addEventListener('resize', adjustInput);

    // Trigger the input event once to set up the input box and dummy element
    Common.fireEvent(input, 'input');
  }

  // Display a user or Watson message that has just been sent/received
  function displayMessage(newPayload, typeValue) {
    var isUser = isUserMessage(typeValue);
    var textExists = (newPayload.input && newPayload.input.text)
      || (newPayload.output && newPayload.output.text);
    if (isUser !== null && textExists) {

      // added regex filter
      if(newPayload.input && newPayload.output) {
        var str = newPayload.input.text || '';

        // regex for the multiple questions
        if((str.match(/.*?([a-z_]*\?+[a-z_]*).*?/g) || []).length > 1) {
          topic = 'multiple';
          unanswered = str;
          newPayload.output.text[0] = 'I have no immediate answer for that. Please enter you email address and a human will answer.';
        }

        // regex for the email
        if((str.match(/^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/) || []).length == 1 && topic == 'multiple') {

          // send the email and the questions
          Api.sendEmailNotifications({
            text: 'From: ' + str + '
UnAnswered Questions: ' + unanswered
          });

          // alter the output and echo back the email
          newPayload.output.text[0] = 'Got it! ' + str;

          // reset values
          topic = '';
          unanswered = '';
        }
      }

      // Create new message DOM element
      var messageDivs = buildMessageDomElements(newPayload, isUser);
      var chatBoxElement = document.querySelector(settings.selectors.chatBox);
      var previousLatest = chatBoxElement.querySelectorAll((isUser
              ? settings.selectors.fromUser : settings.selectors.fromWatson)
              + settings.selectors.latest);
      // Previous "latest" message is no longer the most recent
      if (previousLatest) {
        Common.listForEach(previousLatest, function(element) {
          element.classList.remove('latest');
        });
      }

      messageDivs.forEach(function(currentDiv) {
        chatBoxElement.appendChild(currentDiv);
        // Class to start fade in animation
        currentDiv.classList.add('load');
      });
      // Move chat to the most recent messages when new messages are added
      scrollToChatBottom();

      // check if output returns no answer for the question
      // email the bot admin that it detects an unanswered question
      if (newPayload.output && newPayload.output.text) {
        var no_answer = /I haven't got that answer, yet/;
        if (no_answer.test(newPayload.output.text[0])) {
          Api.sendEmailNotifications({
            text: newPayload.input.text
          });
        }
      }
    }
  }

  // Checks if the given typeValue matches with the user "name", the Watson "name", or neither
  // Returns true if user, false if Watson, and null if neither
  // Used to keep track of whether a message was from the user or Watson
  function isUserMessage(typeValue) {
    if (typeValue === settings.authorTypes.user) {
      return true;
    } else if (typeValue === settings.authorTypes.watson) {
      return false;
    }
    return null;
  }

  // Constructs new DOM element from a message payload
  function buildMessageDomElements(newPayload, isUser) {
    var textArray = isUser ? newPayload.input.text : newPayload.output.text;
    if (Object.prototype.toString.call( textArray ) !== '[object Array]') {
      textArray = [textArray];
    }
    var messageArray = [];

    textArray.forEach(function(currentText) {
      if (currentText) {
        var messageJson = {
          //

          'tagName': 'div',
          'classNames': ['segments'],
          'children': [{
            //

            'tagName': 'div',
            'classNames': [(isUser ? 'from-user' : 'from-watson'), 'latest', ((messageArray.length === 0) ? 'top' : 'sub')],
            'children': [{
              //

              'tagName': 'div',
              'classNames': ['message-inner'],
              'children': [{
                //
{messageText}

                'tagName': 'p',
                'text': currentText
              }]
            }]
          }]
        };
        messageArray.push(Common.buildDomElement(messageJson));
      }
    });

    return messageArray;
  }

  // Scroll to the bottom of the chat window (to the most recent messages)
  // Note: this method will bring the most recent user message into view,
  //   even if the most recent message is from Watson.
  //   This is done so that the "context" of the conversation is maintained in the view,
  //   even if the Watson message is long.
  function scrollToChatBottom() {
    var scrollingChat = document.querySelector('#scrollingChat');

    // Scroll to the latest message sent by the user
    var scrollEl = scrollingChat.querySelector(settings.selectors.fromUser
            + settings.selectors.latest);
    if (scrollEl) {
      scrollingChat.scrollTop = scrollEl.offsetTop;
    }
  }

  // Handles the submission of input
  function inputKeyDown(event, inputBox) {
    // Submit on enter key, dis-allowing blank messages
    if (event.keyCode === 13 && inputBox.value) {
      // Retrieve the context from the previous server response
      var context;
      var latestResponse = Api.getResponsePayload();
      if (latestResponse) {
        context = latestResponse.context;
      }

      // Send the user message
      Api.sendRequest(inputBox.value, context);

      // Clear input box for further messages
      inputBox.value = '';
      Common.fireEvent(inputBox, 'input');
    }
  }
}());
<|endoftext|>


<commit_before>/*!
 * Tmp
 * Copyright (c) 2011 KARASZI Istvan <github@spam.raszi.hu>
 * GPLv2 Licensed
 */

/**
 * Module dependencies.
 */
var
  fs     = require('fs'),
  path   = require('path'),
  exists = fs.exists || path.exists,
  _c     = require('constants');

/**
 * The working inner variables.
 */
var
  // store the actual TMP directory
  _TMP = _getTMPDir(),

  // the random characters to choose from
  randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz",
  randomCharsLength = randomChars.length,

  // this will hold the objects need to be removed on exit
  _removeObjects = [];

/**
 * Gets the temp directory.
 *
 * @return {String}
 * @api private
 */
function _getTMPDir() {
  var tmpNames = [ 'TMPDIR', 'TMP', 'TEMP' ];

  for (var i = 0, length = tmpNames.length; i < length; i++) {
    if (_isUndefined(process.env[tmpNames[i]])) continue;

    return process.env[tmpNames[i]];
  }

  // fallback to the default
  return '/tmp';
}

/**
 * Checks whether the `obj` parameter is defined or not.
 *
 * @param {Object} obj
 * @return {Boolean}
 * @api private
 */
function _isUndefined(obj) {
  return typeof obj === 'undefined';
}

/**
 * Parses the function arguments.
 *
 * This function helps to have optional arguments.
 *
 * @param {Object} options
 * @param {Function} callback
 * @api private
 */
function _parseArguments(options, callback) {
  if (!callback || typeof callback != "function") {
    callback = options;
    options = {};
  }

  return [ options, callback ];
}

/**
 * Gets a temporary file name.
 *
 * @param {Object} opts
 * @param {Function} cb
 * @api private
 */
function _getTmpName(opts, cb) {
  var
    template = opts.template,
    templateDefined = !_isUndefined(template),
    tries = opts.tries || 3;

  if (tries < 0)
    return cb(new Error('Invalid tries'));

  if (templateDefined && !template.match(/XXXXXX/))
    return cb(new Error('Invalid template provided'));

  function _getName() {

    // prefix and postfix
    if (!templateDefined) {
      var name = [
        (_isUndefined(opts.prefix)) ? 'tmp-' : opts.prefix,
        process.pid,
        (Math.random() * 0x1000000000).toString(36),
        opts.postfix
      ].join('');

      return path.join(opts.dir || _TMP, name);
    }

    // mkstemps like template
    var chars = [];

    for (var i = 0; i < 6; i++) {
      chars.push(
        randomChars.substr(Math.floor(Math.random() * randomCharsLength), 1));
    }

    return template.replace(/XXXXXX/, chars.join(''));
  }

  (function _getUniqueName() {
    var name = _getName();

    // check whether the path exists then retry if needed
    exists(name, function _pathExists(pathExists) {
      if (pathExists) {
        if (tries-- > 0) return _getUniqueName();

        return cb(new Error('Could not get a unique tmp filename, max tries reached'));
      }

      cb(null, name);
    });
  }());
}

/**
 * Creates and opens a temporary file.
 *
 * @param {Object} options
 * @param {Function} callback
 * @api public
 */
function _createTmpFile(options, callback) {
  var
    args = _parseArguments(options, callback),
    opts = args[0],
    cb = args[1];

    opts.postfix = (_isUndefined(opts.postfix)) ? '.tmp' : opts.postfix;

  // gets a temporary filename
  _getTmpName(opts, function _tmpNameCreated(err, name) {
    if (err) return cb(err);

    // create and open the file
    fs.open(name, _c.O_CREAT | _c.O_EXCL | _c.O_RDWR, opts.mode || 0600, function _fileCreated(err, fd) {
      if (err) return cb(err);

      if (!opts.keep) _removeObjects.push([ fs.unlinkSync, name ]);

      cb(null, name, fd);
    });
  });
}

/**
 * Creates a temporary directory.
 *
 * @param {Object} options
 * @param {Function} callback
 * @api public
 */
function _createTmpDir(options, callback) {
  var
    args = _parseArguments(options, callback),
    opts = args[0],
    cb = args[1];

  // gets a temporary filename
  _getTmpName(opts, function _tmpNameCreated(err, name) {
    if (err) return cb(err);

    // create the directory
    fs.mkdir(name, opts.mode || 0700, function _dirCreated(err) {
      if (err) return cb(err);

      if (!opts.keep) _removeObjects.push([ fs.rmdirSync, name ]);

      cb(null, name);
    });
  });
}

/**
 * The garbage collector.
 *
 * @api private
 */
function _garbageCollector() {
  for (var i = 0, length = _removeObjects.length; i < length; i++) {
    try {
      _removeObjects[i][0].call(null, _removeObjects[i][1]);
    } catch (e) {
      // already removed?
    }
  };
}

// adding to the exit listener
process.addListener('exit', _garbageCollector);

// exporting all the needed methods
module.exports.tmpdir = _TMP;
module.exports.dir = _createTmpDir;
module.exports.file = _createTmpFile;
<commit_msg>JSHint fix<commit_after>/*!
 * Tmp
 * Copyright (c) 2011 KARASZI Istvan <github@spam.raszi.hu>
 * GPLv2 Licensed
 */

/**
 * Module dependencies.
 */
var
  fs     = require('fs'),
  path   = require('path'),
  exists = fs.exists || path.exists,
  _c     = require('constants');

/**
 * The working inner variables.
 */
var
  // store the actual TMP directory
  _TMP = _getTMPDir(),

  // the random characters to choose from
  randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz",
  randomCharsLength = randomChars.length,

  // this will hold the objects need to be removed on exit
  _removeObjects = [];

/**
 * Gets the temp directory.
 *
 * @return {String}
 * @api private
 */
function _getTMPDir() {
  var tmpNames = [ 'TMPDIR', 'TMP', 'TEMP' ];

  for (var i = 0, length = tmpNames.length; i < length; i++) {
    if (_isUndefined(process.env[tmpNames[i]])) continue;

    return process.env[tmpNames[i]];
  }

  // fallback to the default
  return '/tmp';
}

/**
 * Checks whether the `obj` parameter is defined or not.
 *
 * @param {Object} obj
 * @return {Boolean}
 * @api private
 */
function _isUndefined(obj) {
  return typeof obj === 'undefined';
}

/**
 * Parses the function arguments.
 *
 * This function helps to have optional arguments.
 *
 * @param {Object} options
 * @param {Function} callback
 * @api private
 */
function _parseArguments(options, callback) {
  if (!callback || typeof callback != "function") {
    callback = options;
    options = {};
  }

  return [ options, callback ];
}

/**
 * Gets a temporary file name.
 *
 * @param {Object} opts
 * @param {Function} cb
 * @api private
 */
function _getTmpName(opts, cb) {
  var
    template = opts.template,
    templateDefined = !_isUndefined(template),
    tries = opts.tries || 3;

  if (tries < 0)
    return cb(new Error('Invalid tries'));

  if (templateDefined && !template.match(/XXXXXX/))
    return cb(new Error('Invalid template provided'));

  function _getName() {

    // prefix and postfix
    if (!templateDefined) {
      var name = [
        (_isUndefined(opts.prefix)) ? 'tmp-' : opts.prefix,
        process.pid,
        (Math.random() * 0x1000000000).toString(36),
        opts.postfix
      ].join('');

      return path.join(opts.dir || _TMP, name);
    }

    // mkstemps like template
    var chars = [];

    for (var i = 0; i < 6; i++) {
      chars.push(
        randomChars.substr(Math.floor(Math.random() * randomCharsLength), 1));
    }

    return template.replace(/XXXXXX/, chars.join(''));
  }

  (function _getUniqueName() {
    var name = _getName();

    // check whether the path exists then retry if needed
    exists(name, function _pathExists(pathExists) {
      if (pathExists) {
        if (tries-- > 0) return _getUniqueName();

        return cb(new Error('Could not get a unique tmp filename, max tries reached'));
      }

      cb(null, name);
    });
  }());
}

/**
 * Creates and opens a temporary file.
 *
 * @param {Object} options
 * @param {Function} callback
 * @api public
 */
function _createTmpFile(options, callback) {
  var
    args = _parseArguments(options, callback),
    opts = args[0],
    cb = args[1];

    opts.postfix = (_isUndefined(opts.postfix)) ? '.tmp' : opts.postfix;

  // gets a temporary filename
  _getTmpName(opts, function _tmpNameCreated(err, name) {
    if (err) return cb(err);

    // create and open the file
    fs.open(name, _c.O_CREAT | _c.O_EXCL | _c.O_RDWR, opts.mode || 0600, function _fileCreated(err, fd) {
      if (err) return cb(err);

      if (!opts.keep) _removeObjects.push([ fs.unlinkSync, name ]);

      cb(null, name, fd);
    });
  });
}

/**
 * Creates a temporary directory.
 *
 * @param {Object} options
 * @param {Function} callback
 * @api public
 */
function _createTmpDir(options, callback) {
  var
    args = _parseArguments(options, callback),
    opts = args[0],
    cb = args[1];

  // gets a temporary filename
  _getTmpName(opts, function _tmpNameCreated(err, name) {
    if (err) return cb(err);

    // create the directory
    fs.mkdir(name, opts.mode || 0700, function _dirCreated(err) {
      if (err) return cb(err);

      if (!opts.keep) _removeObjects.push([ fs.rmdirSync, name ]);

      cb(null, name);
    });
  });
}

/**
 * The garbage collector.
 *
 * @api private
 */
function _garbageCollector() {
  for (var i = 0, length = _removeObjects.length; i < length; i++) {
    try {
      _removeObjects[i][0].call(null, _removeObjects[i][1]);
    } catch (e) {
      // already removed?
    }
  }
}

// adding to the exit listener
process.addListener('exit', _garbageCollector);

// exporting all the needed methods
module.exports.tmpdir = _TMP;
module.exports.dir = _createTmpDir;
module.exports.file = _createTmpFile;
<|endoftext|>


<commit_before>
function Rule(data) {
    //console.log("data: " + JSON.stringify(data));

  var rules = document.getElementById('rules');
  document.getElementById("rulesTitle").style.display = "block";
  this.node = document.getElementById('rule-template').cloneNode(true);
  this.node.id = 'rule' + (Rule.next_id++);
  this.node.rule = this;
  rules.appendChild(this.node);
  this.node.hidden = false;

  if (data) {
    this.getElement('fn-select').value = data.fnSelect;
    this.getElement('andOr').value = data.andOr;
    this.getElement('ext-select').value = data.extSelect;
    this.getElement('fn-regex-input').value = data.fnInput;
    this.getElement('ext-regex-input').value = data.extInput;
    this.getElement('folder-input').value = data.folder;
    this.getElement('enabled').checked = data.enabled;
  }

  this.getElement('enabled-label').htmlFor = this.getElement('enabled').id = this.node.id + '-enabled';
  this.render();

  //this.getElement('regex').onchange = definePlaceholdersForRule; // storeRules
  //this.getElement('regex').setAttribute('onchange', 'definePlaceholdersForRule');
  fnRegInpt = this.getElement('fn-regex-input');
  extRegInpt = this.getElement('ext-regex-input');
  var node_id = this.node.id;

  //console.log("fnRegInpt el: " + fnRegInpt.value);
  //console.log("extRegInpt el: " + extRegInpt.value);

  //this.getElement('fn-select').onchange = function () {setPlaceholders(this, rules, node_id, "fn-regex-input") };
  this.getElement('fn-select').onchange = function () {setDisabledAndPlaceholders(this.className, "fn-regex-input") };

  //this.getElement('ext-select').onchange = function () {setPlaceholders(this, rules, node_id, "ext-regex-input") };
  this.getElement('ext-select').onchange = function () {setDisabledAndPlaceholders(this.className, "ext-regex-input") };

  // this.getElement('regex-input').onkeyup = storeRules;
  this.getElement('folder-input').onchange = storeRules;
  this.getElement('enabled').onchange = storeRules;

  var rule = this;
  this.getElement('move-up').onclick = function() {
    var sib = rule.node.previousSibling;
    rule.node.parentNode.removeChild(rule.node);
    sib.parentNode.insertBefore(rule.node, sib);
    storeRules();
  };
  this.getElement('move-down').onclick = function() {
    var parentNode = rule.node.parentNode;
    var sib = rule.node.nextSibling.nextSibling;
    parentNode.removeChild(rule.node);
    if (sib) {
      parentNode.insertBefore(rule.node, sib);
    } else {
      parentNode.appendChild(rule.node);
    }
    storeRules();
  };

  this.getElement('remove').onclick = function() {
    if (rule.node.parentNode.children.length == 1) // means now we're removing the last child
        document.getElementById("rulesTitle").style.display = "none";

    rule.node.parentNode.removeChild(rule.node);
    storeRules();
  };

  setDisabledAndPlaceholders("fn-select", "fn-regex-input");
  setDisabledAndPlaceholders("ext-select", "ext-regex-input");
  storeRules();
}

Rule.prototype.getElement = function(name) {
  return document.querySelector('#' + this.node.id + ' .' + name);
}

Rule.prototype.render = function() {
  this.getElement('move-up').disabled = !this.node.previousSibling;
  this.getElement('move-down').disabled = !this.node.nextSibling;
}

Rule.next_id = 0;

function loadRules() {
  var rules = localStorage.rules;
  try {
    JSON.parse(rules).forEach(function(rule) {new Rule(rule);});
  } catch (e) {
    localStorage.rules = JSON.stringify([]);
  }
}

function checkAndStoreRules()
{
    storeRules();
    document.getElementById('saveDisk').style.display="none";
    document.getElementById('savedcheck').style.display="inline";
    setTimeout(function(){
        document.getElementById('savedcheck').style.display="none";
        document.getElementById('saveDisk').style.display="inline";
        }, 1000);

}

function storeRules() {
  localStorage.rules = JSON.stringify(Array.prototype.slice.apply(
      document.getElementById('rules').childNodes).map(function(node) {
      node.rule.render();
      var store_value = {fnSelect: node.rule.getElement("fn-select").value,
                andOr: node.rule.getElement("andOr").value,
                extSelect: node.rule.getElement("ext-select").value,
                fnInput: node.rule.getElement("fn-regex-input").value,
                extInput: node.rule.getElement("ext-regex-input").value,
                folder: node.rule.getElement('folder-input').value,
                enabled: node.rule.getElement('enabled').checked};

      return store_value
  }));

}

function clearAll()
{
  //console.log("clearing");
  var r = confirm("Clear all rules?");
  if (r == true) {
    document.getElementById("rulesTitle").style.display = "none";
    localStorage.rules = JSON.stringify([]);
    //loadRules();
    location.reload();
  }

}

function readme()
{
  //console.log("readme");
  window.open('readme.html');

}

function nextVersion()
{
    alert("This feature will be supported in the next version");
}

function setDisabledAndPlaceholders(regSelection, inputClass)
{
    //console.log("regSelection: "+regSelection + " - inputClass: " + inputClass);

    var rules = document.getElementById('rules');
    for (i = 0; i < rules.childElementCount; i++) {
        var rule = rules.children[i];
        var selectionElement = rule.getElementsByClassName(regSelection)[0];
        var inputElement = rule.getElementsByClassName(inputClass)[0];

        // on "any" selection, always empty the input to show the placeholder.
        if (selectionElement.value.substring(0,3) == "any")
            inputElement.value = "";

        var selectedIndex = selectionElement.selectedIndex;
        var placeholder = selectionElement[selectedIndex].getAttribute("placeholder");
        inputElement.placeholder = placeholder;
        var inputDisabled = selectionElement[selectedIndex].getAttribute("inputDisabled");
        inputElement.disabled = inputDisabled;

        /*
        if (selectionValue == "none" || selectionValue == "anyVideo" || selectionValue == "anyAudio") {

            var input = rules.children[i].getElementsByClassName(inputClass)[0]
            //console.log("setting "+rules.children[i].id + " to disable");
            rules.children[i].getElementsByClassName(inputClass)[0].placeholder = rules.children[i].getElementsByClassName(regSelection)[0].placeholder
            input.disabled = true;
        }
        */
    }
}

function updateVersion() {
    var version = chrome.app.getDetails().version;
    document.getElementById("version").innerHTML = "version " + version;
}

window.onload = function() {
  updateVersion();
  loadRules();
  document.getElementById('savedcheck').style.display="none";
  setDisabledAndPlaceholders("fn-select", "fn-regex-input");
  setDisabledAndPlaceholders("ext-select", "ext-regex-input");
  document.getElementById('new').onclick = function() {new Rule();};
  document.getElementById('save').onclick = checkAndStoreRules;
  document.getElementById('clearAll').onclick = clearAll;
  document.getElementById('readme').onclick = readme;
  document.getElementById('exportRules').onclick = nextVersion;
  document.getElementById('importRules').onclick = nextVersion;
}

// google analytics:
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-66616134-1']);
_gaq.push(['_trackPageview']);

(function() {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = 'https://ssl.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

// tracking buttons
function trackButtonClick(e) {
  _gaq.push(['_trackEvent', e.target.id, 'clicked']);
}

/**
 * Now set up your event handlers for the popup's `button` elements once the
 * popup's DOM has loaded.
 */
document.addEventListener('DOMContentLoaded', function () {
  var buttons = document.querySelectorAll('button');
  for (var i = 0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', trackButtonClick);
  }
});<commit_msg>moved version load to end of winload<commit_after>
function Rule(data) {
    //console.log("data: " + JSON.stringify(data));

  var rules = document.getElementById('rules');
  document.getElementById("rulesTitle").style.display = "block";
  this.node = document.getElementById('rule-template').cloneNode(true);
  this.node.id = 'rule' + (Rule.next_id++);
  this.node.rule = this;
  rules.appendChild(this.node);
  this.node.hidden = false;

  if (data) {
    this.getElement('fn-select').value = data.fnSelect;
    this.getElement('andOr').value = data.andOr;
    this.getElement('ext-select').value = data.extSelect;
    this.getElement('fn-regex-input').value = data.fnInput;
    this.getElement('ext-regex-input').value = data.extInput;
    this.getElement('folder-input').value = data.folder;
    this.getElement('enabled').checked = data.enabled;
  }

  this.getElement('enabled-label').htmlFor = this.getElement('enabled').id = this.node.id + '-enabled';
  this.render();

  //this.getElement('regex').onchange = definePlaceholdersForRule; // storeRules
  //this.getElement('regex').setAttribute('onchange', 'definePlaceholdersForRule');
  fnRegInpt = this.getElement('fn-regex-input');
  extRegInpt = this.getElement('ext-regex-input');
  var node_id = this.node.id;

  //console.log("fnRegInpt el: " + fnRegInpt.value);
  //console.log("extRegInpt el: " + extRegInpt.value);

  //this.getElement('fn-select').onchange = function () {setPlaceholders(this, rules, node_id, "fn-regex-input") };
  this.getElement('fn-select').onchange = function () {setDisabledAndPlaceholders(this.className, "fn-regex-input") };

  //this.getElement('ext-select').onchange = function () {setPlaceholders(this, rules, node_id, "ext-regex-input") };
  this.getElement('ext-select').onchange = function () {setDisabledAndPlaceholders(this.className, "ext-regex-input") };

  // this.getElement('regex-input').onkeyup = storeRules;
  this.getElement('folder-input').onchange = storeRules;
  this.getElement('enabled').onchange = storeRules;

  var rule = this;
  this.getElement('move-up').onclick = function() {
    var sib = rule.node.previousSibling;
    rule.node.parentNode.removeChild(rule.node);
    sib.parentNode.insertBefore(rule.node, sib);
    storeRules();
  };
  this.getElement('move-down').onclick = function() {
    var parentNode = rule.node.parentNode;
    var sib = rule.node.nextSibling.nextSibling;
    parentNode.removeChild(rule.node);
    if (sib) {
      parentNode.insertBefore(rule.node, sib);
    } else {
      parentNode.appendChild(rule.node);
    }
    storeRules();
  };

  this.getElement('remove').onclick = function() {
    if (rule.node.parentNode.children.length == 1) // means now we're removing the last child
        document.getElementById("rulesTitle").style.display = "none";

    rule.node.parentNode.removeChild(rule.node);
    storeRules();
  };

  setDisabledAndPlaceholders("fn-select", "fn-regex-input");
  setDisabledAndPlaceholders("ext-select", "ext-regex-input");
  storeRules();
}

Rule.prototype.getElement = function(name) {
  return document.querySelector('#' + this.node.id + ' .' + name);
}

Rule.prototype.render = function() {
  this.getElement('move-up').disabled = !this.node.previousSibling;
  this.getElement('move-down').disabled = !this.node.nextSibling;
}

Rule.next_id = 0;

function loadRules() {
  var rules = localStorage.rules;
  try {
    JSON.parse(rules).forEach(function(rule) {new Rule(rule);});

  } catch (e) {
    localStorage.rules = JSON.stringify([]);
  }
}

function checkAndStoreRules()
{
    storeRules();
    document.getElementById('saveDisk').style.display="none";
    document.getElementById('savedcheck').style.display="inline";
    setTimeout(function(){
        document.getElementById('savedcheck').style.display="none";
        document.getElementById('saveDisk').style.display="inline";
        }, 1000);

}

function storeRules() {
  localStorage.rules = JSON.stringify(Array.prototype.slice.apply(
      document.getElementById('rules').childNodes).map(function(node) {
      node.rule.render();
      var store_value = {fnSelect: node.rule.getElement("fn-select").value,
                andOr: node.rule.getElement("andOr").value,
                extSelect: node.rule.getElement("ext-select").value,
                fnInput: node.rule.getElement("fn-regex-input").value,
                extInput: node.rule.getElement("ext-regex-input").value,
                folder: node.rule.getElement('folder-input').value,
                enabled: node.rule.getElement('enabled').checked};

      return store_value
  }));

}

function clearAll()
{
  //console.log("clearing");
  var r = confirm("Clear all rules?");
  if (r == true) {
    //document.getElementById("rulesTitle").style.display = "none";
    localStorage.rules = JSON.stringify([]);
    //loadRules();
    location.reload();
  }

}

function readme()
{
  //console.log("readme");
  window.open('readme.html');

}

function nextVersion()
{
    alert("This feature will be supported in the next version");
}

function setDisabledAndPlaceholders(regSelection, inputClass)
{
    //console.log("regSelection: "+regSelection + " - inputClass: " + inputClass);

    var rules = document.getElementById('rules');
    for (i = 0; i < rules.childElementCount; i++) {
        var rule = rules.children[i];
        var selectionElement = rule.getElementsByClassName(regSelection)[0];
        var inputElement = rule.getElementsByClassName(inputClass)[0];

        // on "any" selection, always empty the input to show the placeholder.
        if (selectionElement.value.substring(0,3) == "any")
            inputElement.value = "";

        var selectedIndex = selectionElement.selectedIndex;
        var placeholder = selectionElement[selectedIndex].getAttribute("placeholder");
        inputElement.placeholder = placeholder;
        var inputDisabled = selectionElement[selectedIndex].getAttribute("inputDisabled");
        inputElement.disabled = inputDisabled;

        /*
        if (selectionValue == "none" || selectionValue == "anyVideo" || selectionValue == "anyAudio") {

            var input = rules.children[i].getElementsByClassName(inputClass)[0]
            //console.log("setting "+rules.children[i].id + " to disable");
            rules.children[i].getElementsByClassName(inputClass)[0].placeholder = rules.children[i].getElementsByClassName(regSelection)[0].placeholder
            input.disabled = true;
        }
        */
    }
}

function updateVersion() {
    var version = chrome.app.getDetails().version;
    document.getElementById("version").innerHTML = "version " + version;
}

window.onload = function() {
  loadRules();
  document.getElementById('savedcheck').style.display="none";
  setDisabledAndPlaceholders("fn-select", "fn-regex-input");
  setDisabledAndPlaceholders("ext-select", "ext-regex-input");
  document.getElementById('new').onclick = function() {new Rule();};
  document.getElementById('save').onclick = checkAndStoreRules;
  document.getElementById('clearAll').onclick = clearAll;
  document.getElementById('readme').onclick = readme;
  document.getElementById('exportRules').onclick = nextVersion;
  document.getElementById('importRules').onclick = nextVersion;
  updateVersion();
}

// google analytics:
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-66616134-1']);
_gaq.push(['_trackPageview']);

(function() {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = 'https://ssl.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

// tracking buttons
function trackButtonClick(e) {
  _gaq.push(['_trackEvent', e.target.id, 'clicked']);
}

/**
 * Now set up your event handlers for the popup's `button` elements once the
 * popup's DOM has loaded.
 */
document.addEventListener('DOMContentLoaded', function () {
  var buttons = document.querySelectorAll('button');
  for (var i = 0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', trackButtonClick);
  }
});<|endoftext|>


<commit_before>(function () {
    'use strict';

    var serviceId = 'common';
    var commonModule = angular.module('common')
        .factory(serviceId, ['$http', common]);

    commonModule.factory('common',
        ['$q', '$rootScope', '$timeout', 'logger', common]);

    function common($q, $rootScope, $timeout, logger) {
        var throttles = {};

        var service = {
            // common angular dependencies
            $broadcast: $broadcast,
            $q: $q,
            $timeout: $timeout,
            // generic
            activateController: activateController,
            controllerActivateSuccessEvent: 'controller.activateSuccess',
            createSearchThrottle: createSearchThrottle,
            debouncedThrottle: debouncedThrottle,
            isNumber: isNumber,
            logger: logger, // for accessibility
            textContains: textContains
        };

        return service;

        function activateController(promises, controllerId) {
            return $q.all(promises).then(function (eventArgs) {
                var data = { controllerId: controllerId };
                $broadcast(service.controllerActivateSuccessEvent, data);
            });
        }

        function $broadcast() {
            return $rootScope.$broadcast.apply($rootScope, arguments);
        }

        function createSearchThrottle(viewmodel, list, filteredList, filter, delay) {
            // After a delay, search a viewmodel's list using
            // a filter function, and return a filteredList.

            // custom delay or use default
            delay = +delay || 300;
            // if only vm and list parameters were passed, set others by naming convention
            if (!filteredList) {
                // assuming list is named sessions, filteredList is filteredSessions
                filteredList = 'filtered' + list[0].toUpperCase() + list.substr(1).toLowerCase(); // string
                // filter function is named sessionFilter
                filter = list + 'Filter'; // function in string form
            }

            // create the filtering function we will call from here
            var filterFn = function () {
                // translates to ...
                // vm.filteredSessions
                //      = vm.sessions.filter(function(item( { returns vm.sessionFilter (item) } );
                viewmodel[filteredList] = viewmodel[list].filter(function (item) {
                    return viewmodel[filter](item);
                });
            };

            return (function () {
                // Wrapped in outer IFFE so we can use closure
                // over filterInputTimeout which references the timeout
                var filterInputTimeout;

                // return what becomes the 'applyFilter' function in the controller
                return function (searchNow) {
                    if (filterInputTimeout) {
                        $timeout.cancel(filterInputTimeout);
                        filterInputTimeout = null;
                    }
                    if (searchNow || !delay) {
                        filterFn();
                    } else {
                        filterInputTimeout = $timeout(filterFn, delay);
                    }
                };
            })();
        }

        function debouncedThrottle(key, callback, delay, immediate) {
            // Perform some action (callback) after a delay.
            // Track the callback by key, so if the same callback
            // is issued again, restart the delay.

            var defaultDelay = 1000;
            delay = delay || defaultDelay;
            if (throttles[key]) {
                $timeout.cancel(throttles[key]);
                throttles[key] = undefined;
            }
            if (immediate) {
                callback();
            } else {
                throttles[key] = $timeout(callback, delay);
            }
        }

        function isNumber(val) {
            // negative or positive
            return (/^[-]?\d+$/).test(val);
        }

        function textContains(text, searchText) {
            return text && -1 !== text.toLowerCase().indexOf(searchText.toLowerCase());
        }
    }
})();<commit_msg>modular: fixed common service typos.<commit_after>(function () {
    'use strict';

    angular.module('common').factory('common',
            ['$q', '$rootScope', '$timeout', 'logger', common]);

    function common($q, $rootScope, $timeout, logger) {
        var throttles = {};

        var service = {
            // common angular dependencies
            $broadcast: $broadcast,
            $q: $q,
            $timeout: $timeout,
            // generic
            activateController: activateController,
            controllerActivateSuccessEvent: 'controller.activateSuccess',
            createSearchThrottle: createSearchThrottle,
            debouncedThrottle: debouncedThrottle,
            isNumber: isNumber,
            logger: logger, // for accessibility
            textContains: textContains
        };

        return service;

        function activateController(promises, controllerId) {
            return $q.all(promises).then(function (eventArgs) {
                var data = { controllerId: controllerId };
                $broadcast(service.controllerActivateSuccessEvent, data);
            });
        }

        function $broadcast() {
            return $rootScope.$broadcast.apply($rootScope, arguments);
        }

        function createSearchThrottle(viewmodel, list, filteredList, filter, delay) {
            // After a delay, search a viewmodel's list using
            // a filter function, and return a filteredList.

            // custom delay or use default
            delay = +delay || 300;
            // if only vm and list parameters were passed, set others by naming convention
            if (!filteredList) {
                // assuming list is named sessions, filteredList is filteredSessions
                filteredList = 'filtered' + list[0].toUpperCase() + list.substr(1).toLowerCase(); // string
                // filter function is named sessionFilter
                filter = list + 'Filter'; // function in string form
            }

            // create the filtering function we will call from here
            var filterFn = function () {
                // translates to ...
                // vm.filteredSessions
                //      = vm.sessions.filter(function(item( { returns vm.sessionFilter (item) } );
                viewmodel[filteredList] = viewmodel[list].filter(function (item) {
                    return viewmodel[filter](item);
                });
            };

            return (function () {
                // Wrapped in outer IFFE so we can use closure
                // over filterInputTimeout which references the timeout
                var filterInputTimeout;

                // return what becomes the 'applyFilter' function in the controller
                return function (searchNow) {
                    if (filterInputTimeout) {
                        $timeout.cancel(filterInputTimeout);
                        filterInputTimeout = null;
                    }
                    if (searchNow || !delay) {
                        filterFn();
                    } else {
                        filterInputTimeout = $timeout(filterFn, delay);
                    }
                };
            })();
        }

        function debouncedThrottle(key, callback, delay, immediate) {
            // Perform some action (callback) after a delay.
            // Track the callback by key, so if the same callback
            // is issued again, restart the delay.

            var defaultDelay = 1000;
            delay = delay || defaultDelay;
            if (throttles[key]) {
                $timeout.cancel(throttles[key]);
                throttles[key] = undefined;
            }
            if (immediate) {
                callback();
            } else {
                throttles[key] = $timeout(callback, delay);
            }
        }

        function isNumber(val) {
            // negative or positive
            return (/^[-]?\d+$/).test(val);
        }

        function textContains(text, searchText) {
            return text && -1 !== text.toLowerCase().indexOf(searchText.toLowerCase());
        }
    }
})();<|endoftext|>


<commit_before>var ElementProxy = {
    get: function (tgt, key, rcv) {
        switch(key) {
        case '..':
            return __(tgt.parentNode);
        case 'parent':
            return function (sel) {
                for(node = tgt.parentNode; node && !node.matches(sel); node = node.parentNode) {}
                return node;
            }.bind(tgt);
        case 'delegate':
            return function (event, child, handler) {
                tgt.addEventListener(event, function (ev) {
                    if(ev.target.matches(child)) handler.call(tgt, ev, this);
                });
            }
        case 'on':
            return tgt.addEventListener.bind(tgt);
        default:
            var attr = tgt[key];
            return (typeof attr === 'function') ? attr.bind(tgt) : attr;
        }
    },
    set: function (tgt, key, value, rcv) {
        tgt[key] = value;
    }
};
// ElementProxy.prototype = Reflect.prototype;

var ElementListProxy = {
    'get': function (tgt, key, value, rcv) {
        switch(key) {
        case 'forEach':
            return Array.apply(null, tgt).forEach;
        case 'addClass':
            return function (cls) {
                Array.apply(null, tgt).forEach(function (el) {
                    el.classList.add(cls);
                });
            }
        case 'removeClass':
            return function (cls) {
                Array.apply(null, tgt).forEach(function (el) {
                    el.classList.remove(cls);
                });
            }
        case 'toggleClass':
            return function (cls) {
                Array.apply(null, tgt).forEach(function (el) {
                    el.classList.toggle(cls);
                });
            }
        default:
            tgt[key] = value;
        }
    }
};
// ElementListProxy.prototype = Reflect.prototype;

function __(el) {
    return new Proxy(el, ElementProxy);
}

__.get = function (sel, root) {
    root = root || document;
    var el = root.querySelector(sel);
    return new Proxy(el, ElementProxy);
};

__.select = function (sel, root) {
    root = root || document;
    var els = root.querySelectorAll(sel);
    return new Proxy(els, ElementListProxy);
};
<commit_msg>Add onstart helper<commit_after>var ElementProxy = {
    get: function (tgt, key, rcv) {
        switch(key) {
        case '..':
            return __(tgt.parentNode);
        case 'parent':
            return function (sel) {
                for(node = tgt.parentNode; node && !node.matches(sel); node = node.parentNode) {}
                return node;
            }.bind(tgt);
        case 'delegate':
            return function (event, child, handler) {
                tgt.addEventListener(event, function (ev) {
                    if(ev.target.matches(child)) handler.call(tgt, ev, this);
                });
            }
        case 'on':
            return tgt.addEventListener.bind(tgt);
        default:
            var attr = tgt[key];
            return (typeof attr === 'function') ? attr.bind(tgt) : attr;
        }
    },
    set: function (tgt, key, value, rcv) {
        tgt[key] = value;
    }
};
// ElementProxy.prototype = Reflect.prototype;

var ElementListProxy = {
    'get': function (tgt, key, value, rcv) {
        switch(key) {
        case 'forEach':
            return Array.apply(null, tgt).forEach;
        case 'addClass':
            return function (cls) {
                Array.apply(null, tgt).forEach(function (el) {
                    el.classList.add(cls);
                });
            }
        case 'removeClass':
            return function (cls) {
                Array.apply(null, tgt).forEach(function (el) {
                    el.classList.remove(cls);
                });
            }
        case 'toggleClass':
            return function (cls) {
                Array.apply(null, tgt).forEach(function (el) {
                    el.classList.toggle(cls);
                });
            }
        default:
            tgt[key] = value;
        }
    }
};
// ElementListProxy.prototype = Reflect.prototype;

function __(el) {
    return new Proxy(el, ElementProxy);
}

__.get = function (sel, root) {
    root = root || document;
    var el = root.querySelector(sel);
    return new Proxy(el, ElementProxy);
};

__.select = function (sel, root) {
    root = root || document;
    var els = root.querySelectorAll(sel);
    return new Proxy(els, ElementListProxy);
};

__.onstart = function(handler) {
    document.addEventListener('DOMContentLoaded', handler);
};
<|endoftext|>


<commit_before>import * as _ from "../deps/underscore-1.10.2-esm.js"
import { nil, undef } from "../header.js"
import { BiwaSymbol } from "./symbol.js"

//
// write.js: Functions to convert objects to strings
//

//
// write
//

const truncate = function(str, length) {
  const truncateStr = '...';
  return str.length > length ? str.slice(0, length) + truncateStr : str;
};

const to_write = function(obj){
  if(obj === undefined)
    return "undefined";
  else if(obj === null)
    return "null";
  else if(_.isFunction(obj))
    return "#<Function "+(obj.fname ? obj.fname :
                          obj.toSource ? truncate(obj.toSource(), 40) :
                          "")+">";
  else if(_.isString(obj))
    return '"' +
           obj.replace(/\\|\"/g,function($0){return'\\'+$0;})
              .replace(/\x07/g, "\\a")
              .replace(/\x08/g, "\\b")
              .replace(/\t/g, "\\t")
              .replace(/\n/g, "\\n")
              .replace(/\v/g, "\\v")
              .replace(/\f/g, "\\f")
              .replace(/\r/g, "\\r") +
           '"';
  else if(_.isArray(obj))
    return "#(" + _.map(obj, function(e) { return to_write(e); }).join(" ") + ")";
  else if(typeof(obj.to_write) == 'function')
    return obj.to_write();
  else if(isNaN(obj) && typeof(obj) == 'number')
    return "+nan.0";
  else{
    switch(obj){
      case true: return "#t";
      case false: return "#f";
      case Infinity: return "+inf.0";
      case -Infinity: return "-inf.0";
    }
  }
  return inspect(obj);
}

//
// display
//

const to_display = function(obj){
  if(obj.to_display)
    return obj.to_display(to_display);
  if(_.isUndefined(obj))
    return 'undefined';
  else if(_.isNull(obj))
    return 'null';
  else if(typeof(obj.valueOf()) == "string")
    return obj;
  else if(obj instanceof BiwaSymbol)
    return obj.name;
  else if(obj instanceof Array)
    return '#(' + _.map(obj, to_display).join(' ') + ')';
  else
    return to_write(obj);
}

//
// inspect
//
const inspect = function(object, opts) {
  try {
    if (_.isUndefined(object)) return 'undefined';
    if (object === null) return 'null';
    if (object === true) return '#t';
    if (object === false) return '#f';
    if (object.inspect) return object.inspect();
    if (_.isString(object)) {
      return '"' + object.replace(/"/g, '\\"') + '"';
    }
    if (_.isArray(object)) {
      return '[' + _.map(object, inspect).join(', ') + ']';
    }

    if (opts && opts["fallback"]){
      return opts["fallback"];
    }
    else {
      return object.toString();
    }
  } catch (e) {
    if (e instanceof RangeError) return '...';
    throw e;
  }
};

export { to_write, to_display, inspect, truncate };
<commit_msg>fix: (display (js-eval "undefined")) raises error<commit_after>import * as _ from "../deps/underscore-1.10.2-esm.js"
import { nil, undef } from "../header.js"
import { BiwaSymbol } from "./symbol.js"

//
// write.js: Functions to convert objects to strings
//

//
// write
//

const truncate = function(str, length) {
  const truncateStr = '...';
  return str.length > length ? str.slice(0, length) + truncateStr : str;
};

const to_write = function(obj){
  if(obj === undefined)
    return "undefined";
  else if(obj === null)
    return "null";
  else if(_.isFunction(obj))
    return "#<Function "+(obj.fname ? obj.fname :
                          obj.toSource ? truncate(obj.toSource(), 40) :
                          "")+">";
  else if(_.isString(obj))
    return '"' +
           obj.replace(/\\|\"/g,function($0){return'\\'+$0;})
              .replace(/\x07/g, "\\a")
              .replace(/\x08/g, "\\b")
              .replace(/\t/g, "\\t")
              .replace(/\n/g, "\\n")
              .replace(/\v/g, "\\v")
              .replace(/\f/g, "\\f")
              .replace(/\r/g, "\\r") +
           '"';
  else if(_.isArray(obj))
    return "#(" + _.map(obj, function(e) { return to_write(e); }).join(" ") + ")";
  else if(typeof(obj.to_write) == 'function')
    return obj.to_write();
  else if(isNaN(obj) && typeof(obj) == 'number')
    return "+nan.0";
  else{
    switch(obj){
      case true: return "#t";
      case false: return "#f";
      case Infinity: return "+inf.0";
      case -Infinity: return "-inf.0";
    }
  }
  return inspect(obj);
}

//
// display
//

const to_display = function(obj){
  if(_.isUndefined(obj))
    return 'undefined';
  else if(_.isNull(obj))
    return 'null';
  else if(obj.to_display)
    return obj.to_display(to_display);
  else if(typeof(obj.valueOf()) == "string")
    return obj;
  else if(obj instanceof BiwaSymbol)
    return obj.name;
  else if(obj instanceof Array)
    return '#(' + _.map(obj, to_display).join(' ') + ')';
  else
    return to_write(obj);
}

//
// inspect
//
const inspect = function(object, opts) {
  try {
    if (_.isUndefined(object)) return 'undefined';
    if (object === null) return 'null';
    if (object === true) return '#t';
    if (object === false) return '#f';
    if (object.inspect) return object.inspect();
    if (_.isString(object)) {
      return '"' + object.replace(/"/g, '\\"') + '"';
    }
    if (_.isArray(object)) {
      return '[' + _.map(object, inspect).join(', ') + ']';
    }

    if (opts && opts["fallback"]){
      return opts["fallback"];
    }
    else {
      return object.toString();
    }
  } catch (e) {
    if (e instanceof RangeError) return '...';
    throw e;
  }
};

export { to_write, to_display, inspect, truncate };
<|endoftext|>


<commit_before>var preferences, courses;

/*
 * Saves options to chrome.storage.sync.
 */
function save_options() {

    var highlighting_group = document.getElementsByName("highlighting");
    var highlight_value = 0;
    for (var i = 0; i < highlighting_group.length; i++) {
        if (highlighting_group[i].checked) {
            highlight_value = i;
            break;
        }
    }

    preferences.inputs = document.getElementById("inputs").checked;
    preferences.mathjax = document.getElementById("mathjax").checked;
    preferences.highlighting = highlight_value;
    preferences.coloring = document.getElementById("coloring").checked;
    preferences.notes = document.getElementById("notes").checked;

    // display "Options saved" message (can't go into the sendMessage block for some reason, probably because background.js doesn't send a response)
    var status = document.getElementById("status");
    status.textContent = "Options saved.";
    setTimeout(function () {
        status.textContent = "\u00A0";
    }, 750);

    // update background.js preferences info
    chrome.runtime.sendMessage({greeting: "updatePreferences", information: preferences});
}

/*
 * After a confirmation message, deletes all information for a specific course
 */
function delete_course(element) {

    // delete the element from the courses object
    delete courses[element.getAttribute("value")];

    // remove the element from the DOM
    element.remove();

    // save courses and update background.js
    chrome.runtime.sendMessage({greeting: "updateCourses", information: courses});

    // TODO: delete all notes associated with that course

    // update memory usage in the options menu
    document.getElementById("total-memory-used").innerText = "Total memory used: " + memory_used() + " bytes";

}

/*
 * Restores select box and checkbox state using the preferences
 * stored in chrome.storage.
 */
function restore_options() {
    // load preferences from background.js
    chrome.runtime.sendMessage({greeting: "requestAll"}, function (items) {

        preferences = items.preferences;
        courses = items.courses;

        document.getElementById("inputs").checked = preferences.inputs;
        document.getElementById("mathjax").checked = preferences.mathjax;
        document.getElementById("highlighting" + preferences.highlighting).checked = true; // highlight specific radio button
        document.getElementById("coloring").checked = preferences.coloring;
        document.getElementById("notes").checked = preferences.notes;

        // course list
        var courseInfo = document.getElementById("courses");
        for (var key in courses) {
            if (courses.hasOwnProperty(key)) {
                // get name info with regexp (same code as in popup.js)
                var match = /((?:fall)|(?:spring)|(?:summer))(\d+)(mth)(\d+)/.exec(key);
                var formattedname = match[1].substr(0, 1).toUpperCase() + match[1].substr(1) + " Math " + match[4];
                courseInfo.innerHTML += '
' + formattedname + ''+JSON.stringify(courses[key]).length+' bytes' + '
';
            }
        }
        courseInfo = document.getElementsByClassName("delete-course");
        for (var i = 0; i < courseInfo.length; i++) {
            courseInfo[i].addEventListener("click", function() {delete_course(this);});
        }

        // print out total sync storage space used by extension
        chrome.storage.sync.getBytesInUse(null, function(bytesInUse) {
            document.getElementById("total-memory-used").innerText = "Total memory used: " + bytesInUse + " bytes";
        });
    });
}

document.addEventListener("DOMContentLoaded", restore_options);
// when clicked, saves the user's preferences
document.getElementById("save").addEventListener("click", save_options);
<commit_msg>fixed possible naming problems on the options page<commit_after>var preferences, courses;

/*
 * Saves options to chrome.storage.sync.
 */
function save_options() {

    var highlighting_group = document.getElementsByName("highlighting");
    var highlight_value = 0;
    for (var i = 0; i < highlighting_group.length; i++) {
        if (highlighting_group[i].checked) {
            highlight_value = i;
            break;
        }
    }

    preferences.inputs = document.getElementById("inputs").checked;
    preferences.mathjax = document.getElementById("mathjax").checked;
    preferences.highlighting = highlight_value;
    preferences.coloring = document.getElementById("coloring").checked;
    preferences.notes = document.getElementById("notes").checked;

    // display "Options saved" message (can't go into the sendMessage block for some reason, probably because background.js doesn't send a response)
    var status = document.getElementById("status");
    status.textContent = "Options saved.";
    setTimeout(function () {
        status.textContent = "\u00A0";
    }, 750);

    // update background.js preferences info
    chrome.runtime.sendMessage({greeting: "updatePreferences", information: preferences});
}

/*
 * After a confirmation message, deletes all information for a specific course
 */
function delete_course(element) {

    // delete the element from the courses object
    delete courses[element.getAttribute("value")];

    // remove the element from the DOM
    element.remove();

    // save courses and update background.js
    chrome.runtime.sendMessage({greeting: "updateCourses", information: courses});

    // TODO: delete all notes associated with that course

    // update memory usage in the options menu
    document.getElementById("total-memory-used").innerText = "Total memory used: " + memory_used() + " bytes";

}

/*
 * Restores select box and checkbox state using the preferences
 * stored in chrome.storage.
 */
function restore_options() {
    // load preferences from background.js
    chrome.runtime.sendMessage({greeting: "requestAll"}, function (items) {

        preferences = items.preferences;
        courses = items.courses;

        document.getElementById("inputs").checked = preferences.inputs;
        document.getElementById("mathjax").checked = preferences.mathjax;
        document.getElementById("highlighting" + preferences.highlighting).checked = true; // highlight specific radio button
        document.getElementById("coloring").checked = preferences.coloring;
        document.getElementById("notes").checked = preferences.notes;

        // course list
        var courseInfo = document.getElementById("courses");
        for (var key in courses) {
            if (courses.hasOwnProperty(key)) { // TODO: combine code in popup.js with this
                // get name info with regexp (same code as in popup.js)
                var match = /((?:fall)|(?:spring)|(?:summer))(\d+)(mth)(\d+)/.exec(key);
                var formattedname;
                if (match === null) {
                    formattedname = key;
                } else {
                    formattedname = match[1].substr(0, 1).toUpperCase() + match[1].substr(1) + " Math " + match[4];
                }
                courseInfo.innerHTML += '
' + formattedname + ''+JSON.stringify(courses[key]).length + ' bytes' + '
';
            }
        }
        courseInfo = document.getElementsByClassName("delete-course");
        for (var i = 0; i < courseInfo.length; i++) {
            courseInfo[i].addEventListener("click", function() {delete_course(this);});
        }

        // print out total sync storage space used by extension
        chrome.storage.sync.getBytesInUse(null, function(bytesInUse) {
            document.getElementById("total-memory-used").innerText = "Total memory used: " + bytesInUse + " bytes";
        });
    });
}

document.addEventListener("DOMContentLoaded", restore_options);
// when clicked, saves the user's preferences
document.getElementById("save").addEventListener("click", save_options);
<|endoftext|>