<commit_before>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("julia", function(config, parserConf) {
  function wordRegexp(words, end) {
    if (typeof end === "undefined") { end = "\\b"; }
    return new RegExp("^((" + words.join(")|(") + "))" + end);
  }

  var octChar = "\\\\[0-7]{1,3}";
  var hexChar = "\\\\x[A-Fa-f0-9]{1,2}";
  var sChar = "\\\\[abefnrtv0%?'\"\\\\]";
  var uChar = "([^\\u0027\\u005C\\uD800-\\uDFFF]|[\\uD800-\\uDFFF][\\uDC00-\\uDFFF])";

  var operators = parserConf.operators || wordRegexp([
      "\\.?[\\\\%*+\\-<>!=\\/^]=?", "\\.?[|&\\u00F7\\u2260\\u2264\\u2265]",
      "\\u00D7", "\\u2208", "\\u2209", "\\u220B", "\\u220C", "\\u2229",
      "\\u222A", "\\u2286", "\\u2288", "\\u228A", "\\u22c5", "\\?", "~", ":",
      "\\$", "\\.[<>]", "<<=?", ">>>?=?", "\\.[<>=]=", "->?", "\\/\\/", "=>",
      "<:", "\\bin\\b(?!\\()"], "");
  var delimiters = parserConf.delimiters || /^[;,()[\]{}]/;
  var identifiers = parserConf.identifiers || /^[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/;

  var chars = wordRegexp([octChar, hexChar, sChar, uChar], "'");
  var openers = wordRegexp(["begin", "function", "type", "immutable", "let",
      "macro", "for", "while", "quote", "if", "else", "elseif", "try",
      "finally", "catch", "do"]);
  var closers = wordRegexp(["end", "else", "elseif", "catch", "finally"]);
  var keywords = wordRegexp(["if", "else", "elseif", "while", "for", "begin",
      "let", "end", "do", "try", "catch", "finally", "return", "break",
      "continue", "global", "local", "const", "export", "import", "importall",
      "using", "function", "macro", "module", "baremodule", "type",
      "immutable", "quote", "typealias", "abstract", "bitstype"]);
  var builtins = wordRegexp(["true", "false", "nothing", "NaN", "Inf"]);

  var macro = /^@[_A-Za-z][\w]*/;
  var symbol = /^:[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/;
  var stringPrefixes = /^(`|"{3}|([_A-Za-z\u00A1-\uFFFF]*"))/;

  function inArray(state) {
    return inGenerator(state, '[')
  }

  function inGenerator(state, bracket) {
    var curr = currentScope(state),
        prev = currentScope(state, 1);
    if (typeof(bracket) === "undefined") { bracket = '('; }
    if (curr === bracket || (prev === bracket && curr === "for")) {
      return true;
    }
    return false;
  }

  function currentScope(state, n) {
    if (typeof(n) === "undefined") { n = 0; }
    if (state.scopes.length <= n) {
      return null;
    }
    return state.scopes[state.scopes.length - (n + 1)];
  }

  // tokenizers
  function tokenBase(stream, state) {
    // Handle multiline comments
    if (stream.match(/^#=/, false)) {
      state.tokenize = tokenComment;
      return state.tokenize(stream, state);
    }

    // Handle scope changes
    var leavingExpr = state.leavingExpr;
    if (stream.sol()) {
      leavingExpr = false;
    }
    state.leavingExpr = false;

    if (leavingExpr) {
      if (stream.match(/^'+/)) {
        return "operator";
      }
    }

    if (stream.match(/^\.{2,3}/)) {
      return "operator";
    }

    if (stream.eatSpace()) {
      return null;
    }

    var ch = stream.peek();

    // Handle single line comments
    if (ch === '#') {
      stream.skipToEnd();
      return "comment";
    }

    if (ch === '[') {
      state.scopes.push('[');
    }

    if (ch === '(') {
      state.scopes.push('(');
    }

    var scope = currentScope(state);

    if (inArray(state) && ch === ']') {
      if (scope === "for") { state.scopes.pop(); }
      state.scopes.pop();
      state.leavingExpr = true;
    }

    if (inGenerator(state) && ch === ')') {
      if (scope === "for") { state.scopes.pop(); }
      state.scopes.pop();
      state.leavingExpr = true;
    }

    var match;
    if (match = stream.match(openers, false)) {
      state.scopes.push(match[0]);
    }

    if (stream.match(closers, false)) {
      state.scopes.pop();
    }

    if (inArray(state)) {
      if (state.lastToken == "end" && stream.match(/^:/)) {
        return "operator";
      }
      if (stream.match(/^end/)) {
        return "number";
      }
    }

    // Handle type annotations
    if (stream.match(/^::(?![:\$])/)) {
      state.tokenize = tokenAnnotation;
      return state.tokenize(stream, state);
    }

    // Handle symbols
    if (!leavingExpr && stream.match(symbol) || stream.match(/:\./)) {
      return "builtin";
    }

    // Handle parametric types
    if (stream.match(/^{[^}]*}(?=\()/)) {
      return "builtin";
    }

    // Handle operators and Delimiters
    if (stream.match(operators)) {
      return "operator";
    }

    // Handle Number Literals
    if (stream.match(/^[0-9\.]/, false)) {
      var imMatcher = RegExp(/^im\b/);
      var numberLiteral = false;
      // Floats
      if (stream.match(/^\d*\.(?!\.)\d*([Eef][\+\-]?\d+)?/i)) { numberLiteral = true; }
      if (stream.match(/^\d+\.(?!\.)\d*/)) { numberLiteral = true; }
      if (stream.match(/^\.\d+/)) { numberLiteral = true; }
      if (stream.match(/^0x\.[0-9a-f]+p[\+\-]?\d+/i)) { numberLiteral = true; }
      // Integers
      if (stream.match(/^0x[0-9a-f]+/i)) { numberLiteral = true; } // Hex
      if (stream.match(/^0b[01]+/i)) { numberLiteral = true; } // Binary
      if (stream.match(/^0o[0-7]+/i)) { numberLiteral = true; } // Octal
      if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { numberLiteral = true; } // Decimal
      // Zero by itself with no other piece of number.
      if (stream.match(/^0(?![\dx])/i)) { numberLiteral = true; }
      if (numberLiteral) {
          // Integer literals may be "long"
          stream.match(imMatcher);
          state.leavingExpr = true;
          return "number";
      }
    }

    // Handle Chars
    if (stream.match(/^'/)) {
      state.tokenize = tokenChar;
      return state.tokenize(stream, state);
    }

    // Handle Strings
    if (stream.match(stringPrefixes)) {
      state.tokenize = tokenStringFactory(stream.current());
      return state.tokenize(stream, state);
    }

    if (stream.match(macro)) {
      return "meta";
    }

    if (stream.match(delimiters)) {
      return null;
    }

    if (stream.match(keywords)) {
      return "keyword";
    }

    if (stream.match(builtins)) {
      return "builtin";
    }

    var isDefinition = state.isDefinition || state.lastToken == "function" ||
                       state.lastToken == "macro" || state.lastToken == "type" ||
                       state.lastToken == "immutable";

    if (stream.match(identifiers)) {
      if (isDefinition) {
        if (stream.peek() === '.') {
          state.isDefinition = true;
          return "variable";
        }
        state.isDefinition = false;
        return "def";
      }
      if (stream.match(/^({[^}]*})*\(/, false)) {
        return callOrDef(stream, state);
      }
      state.leavingExpr = true;
      return "variable";
    }

    // Handle non-detected items
    stream.next();
    return "error";
  }

  function callOrDef(stream, state) {
    var match = stream.match(/^(\(\s*)/);
    if (match) {
      if (state.firstParenPos < 0)
        state.firstParenPos = state.scopes.length;
      state.scopes.push('(');
      state.charsAdvanced += match[1].length;
    }
    if (currentScope(state) == '(' && stream.match(/^\)/)) {
      state.scopes.pop();
      state.charsAdvanced += 1;
      if (state.scopes.length <= state.firstParenPos) {
        var isDefinition = stream.match(/^\s*?=(?!=)/, false);
        stream.backUp(state.charsAdvanced);
        state.firstParenPos = -1;
        state.charsAdvanced = 0;
        if (isDefinition)
          return "def";
        return "builtin";
      }
    }
    // Unfortunately javascript does not support multiline strings, so we have
    // to undo anything done upto here if a function call or definition splits
    // over two or more lines.
    if (stream.match(/^$/g, false)) {
      stream.backUp(state.charsAdvanced);
      while (state.scopes.length > state.firstParenPos)
        state.scopes.pop();
      state.firstParenPos = -1;
      state.charsAdvanced = 0;
      return "builtin";
    }
    state.charsAdvanced += stream.match(/^([^()]*)/)[1].length;
    return callOrDef(stream, state);
  }

  function tokenAnnotation(stream, state) {
    stream.match(/.*?(?=,|;|{|}|\(|\)|=|$|\s)/);
    if (stream.match(/^{/)) {
      state.nestedLevels++;
    } else if (stream.match(/^}/)) {
      state.nestedLevels--;
    }
    if (state.nestedLevels > 0) {
      stream.match(/.*?(?={|})/);
    } else if (state.nestedLevels == 0) {
      state.tokenize = tokenBase;
    }
    return "builtin";
  }

  function tokenComment(stream, state) {
    if (stream.match(/^#=/)) {
      state.nestedLevels++;
    }
    if (!stream.match(/.*?(?=(#=|=#))/)) {
      stream.skipToEnd();
    }
    if (stream.match(/^=#/)) {
      state.nestedLevels--;
      if (state.nestedLevels == 0)
        state.tokenize = tokenBase;
    }
    return "comment";
  }

  function tokenChar(stream, state) {
    var isChar = false, match;
    if (stream.match(chars)) {
      isChar = true;
    } else if (match = stream.match(/\\u([a-f0-9]{1,4})(?=')/i)) {
      var value = parseInt(match[1], 16);
      if (value <= 55295 || value >= 57344) { // (U+0,U+D7FF), (U+E000,U+FFFF)
        isChar = true;
        stream.next();
      }
    } else if (match = stream.match(/\\U([A-Fa-f0-9]{5,8})(?=')/)) {
      var value = parseInt(match[1], 16);
      if (value <= 1114111) { // U+10FFFF
        isChar = true;
        stream.next();
      }
    }
    if (isChar) {
      state.leavingExpr = true;
      state.tokenize = tokenBase;
      return "string";
    }
    if (!stream.match(/^[^']+(?=')/)) { stream.skipToEnd(); }
    if (stream.match(/^'/)) { state.tokenize = tokenBase; }
    return "error";
  }

  function tokenStringFactory(delimiter) {
    delimiter = (delimiter === '`' || delimiter === '"""') ? delimiter : '"';
    function tokenString(stream, state) {
      if (stream.eat('\\')) {
        stream.next();
      } else if (stream.match(delimiter)) {
        state.tokenize = tokenBase;
        state.leavingExpr = true;
        return "string";
      } else {
        stream.eat(/[`"]/);
      }
      stream.eatWhile(/[^\\`"]/);
      return "string";
    }
    return tokenString;
  }

  var external = {
    startState: function() {
      return {
        tokenize: tokenBase,
        scopes: [],
        lastToken: null,
        leavingExpr: false,
        isDefinition: false,
        nestedLevels: 0,
        charsAdvanced: 0,
        firstParenPos: -1
      };
    },

    token: function(stream, state) {
      var style = state.tokenize(stream, state);
      var current = stream.current();

      if (current && style) {
        state.lastToken = current;
      }

      // Handle '.' connected identifiers
      if (current === '.') {
        style = stream.match(identifiers, false) || stream.match(macro, false) ||
                stream.match(/\(/, false) ? "operator" : "error";
      }
      return style;
    },

    indent: function(state, textAfter) {
      var delta = 0;
      if ( textAfter === ']' || textAfter === ')' || textAfter === "end" ||
           textAfter === "else" || textAfter === "catch" || textAfter === "elseif" ||
           textAfter === "finally" ) {
        delta = -1;
      }
      return (state.scopes.length + delta) * config.indentUnit;
    },

    electricInput: /\b(end|else|catch|finally)\b/,
    blockCommentStart: "#=",
    blockCommentEnd: "=#",
    lineComment: "#",
    fold: "indent"
  };
  return external;
});

CodeMirror.defineMIME("text/x-julia", "julia");

});
<commit_msg>Fix #4668, properly handle string literals<commit_after>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("julia", function(config, parserConf) {
  function wordRegexp(words, end) {
    if (typeof end === "undefined") { end = "\\b"; }
    return new RegExp("^((" + words.join(")|(") + "))" + end);
  }

  var octChar = "\\\\[0-7]{1,3}";
  var hexChar = "\\\\x[A-Fa-f0-9]{1,2}";
  var sChar = "\\\\[abefnrtv0%?'\"\\\\]";
  var uChar = "([^\\u0027\\u005C\\uD800-\\uDFFF]|[\\uD800-\\uDFFF][\\uDC00-\\uDFFF])";

  var operators = parserConf.operators || wordRegexp([
      "\\.?[\\\\%*+\\-<>!=\\/^]=?", "\\.?[|&\\u00F7\\u2260\\u2264\\u2265]",
      "\\u00D7", "\\u2208", "\\u2209", "\\u220B", "\\u220C", "\\u2229",
      "\\u222A", "\\u2286", "\\u2288", "\\u228A", "\\u22c5", "\\?", "~", ":",
      "\\$", "\\.[<>]", "<<=?", ">>>?=?", "\\.[<>=]=", "->?", "\\/\\/", "=>",
      "<:", "\\bin\\b(?!\\()"], "");
  var delimiters = parserConf.delimiters || /^[;,()[\]{}]/;
  var identifiers = parserConf.identifiers || /^[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/;

  var chars = wordRegexp([octChar, hexChar, sChar, uChar], "'");
  var openers = wordRegexp(["begin", "function", "type", "immutable", "let",
      "macro", "for", "while", "quote", "if", "else", "elseif", "try",
      "finally", "catch", "do"]);
  var closers = wordRegexp(["end", "else", "elseif", "catch", "finally"]);
  var keywords = wordRegexp(["if", "else", "elseif", "while", "for", "begin",
      "let", "end", "do", "try", "catch", "finally", "return", "break",
      "continue", "global", "local", "const", "export", "import", "importall",
      "using", "function", "macro", "module", "baremodule", "type",
      "immutable", "quote", "typealias", "abstract", "bitstype"]);
  var builtins = wordRegexp(["true", "false", "nothing", "NaN", "Inf"]);

  var macro = /^@[_A-Za-z][\w]*/;
  var symbol = /^:[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/;
  var stringPrefixes = /^(`|([_A-Za-z\u00A1-\uFFFF]*"("")?))/;

  function inArray(state) {
    return inGenerator(state, '[')
  }

  function inGenerator(state, bracket) {
    var curr = currentScope(state),
        prev = currentScope(state, 1);
    if (typeof(bracket) === "undefined") { bracket = '('; }
    if (curr === bracket || (prev === bracket && curr === "for")) {
      return true;
    }
    return false;
  }

  function currentScope(state, n) {
    if (typeof(n) === "undefined") { n = 0; }
    if (state.scopes.length <= n) {
      return null;
    }
    return state.scopes[state.scopes.length - (n + 1)];
  }

  // tokenizers
  function tokenBase(stream, state) {
    // Handle multiline comments
    if (stream.match(/^#=/, false)) {
      state.tokenize = tokenComment;
      return state.tokenize(stream, state);
    }

    // Handle scope changes
    var leavingExpr = state.leavingExpr;
    if (stream.sol()) {
      leavingExpr = false;
    }
    state.leavingExpr = false;

    if (leavingExpr) {
      if (stream.match(/^'+/)) {
        return "operator";
      }
    }

    if (stream.match(/^\.{2,3}/)) {
      return "operator";
    }

    if (stream.eatSpace()) {
      return null;
    }

    var ch = stream.peek();

    // Handle single line comments
    if (ch === '#') {
      stream.skipToEnd();
      return "comment";
    }

    if (ch === '[') {
      state.scopes.push('[');
    }

    if (ch === '(') {
      state.scopes.push('(');
    }

    var scope = currentScope(state);

    if (inArray(state) && ch === ']') {
      if (scope === "for") { state.scopes.pop(); }
      state.scopes.pop();
      state.leavingExpr = true;
    }

    if (inGenerator(state) && ch === ')') {
      if (scope === "for") { state.scopes.pop(); }
      state.scopes.pop();
      state.leavingExpr = true;
    }

    var match;
    if (match = stream.match(openers, false)) {
      state.scopes.push(match[0]);
    }

    if (stream.match(closers, false)) {
      state.scopes.pop();
    }

    if (inArray(state)) {
      if (state.lastToken == "end" && stream.match(/^:/)) {
        return "operator";
      }
      if (stream.match(/^end/)) {
        return "number";
      }
    }

    // Handle type annotations
    if (stream.match(/^::(?![:\$])/)) {
      state.tokenize = tokenAnnotation;
      return state.tokenize(stream, state);
    }

    // Handle symbols
    if (!leavingExpr && stream.match(symbol) || stream.match(/:\./)) {
      return "builtin";
    }

    // Handle parametric types
    if (stream.match(/^{[^}]*}(?=\()/)) {
      return "builtin";
    }

    // Handle operators and Delimiters
    if (stream.match(operators)) {
      return "operator";
    }

    // Handle Number Literals
    if (stream.match(/^[0-9\.]/, false)) {
      var imMatcher = RegExp(/^im\b/);
      var numberLiteral = false;
      // Floats
      if (stream.match(/^\d*\.(?!\.)\d*([Eef][\+\-]?\d+)?/i)) { numberLiteral = true; }
      if (stream.match(/^\d+\.(?!\.)\d*/)) { numberLiteral = true; }
      if (stream.match(/^\.\d+/)) { numberLiteral = true; }
      if (stream.match(/^0x\.[0-9a-f]+p[\+\-]?\d+/i)) { numberLiteral = true; }
      // Integers
      if (stream.match(/^0x[0-9a-f]+/i)) { numberLiteral = true; } // Hex
      if (stream.match(/^0b[01]+/i)) { numberLiteral = true; } // Binary
      if (stream.match(/^0o[0-7]+/i)) { numberLiteral = true; } // Octal
      if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { numberLiteral = true; } // Decimal
      // Zero by itself with no other piece of number.
      if (stream.match(/^0(?![\dx])/i)) { numberLiteral = true; }
      if (numberLiteral) {
          // Integer literals may be "long"
          stream.match(imMatcher);
          state.leavingExpr = true;
          return "number";
      }
    }

    // Handle Chars
    if (stream.match(/^'/)) {
      state.tokenize = tokenChar;
      return state.tokenize(stream, state);
    }

    // Handle Strings
    if (stream.match(stringPrefixes)) {
      state.tokenize = tokenStringFactory(stream.current());
      return state.tokenize(stream, state);
    }

    if (stream.match(macro)) {
      return "meta";
    }

    if (stream.match(delimiters)) {
      return null;
    }

    if (stream.match(keywords)) {
      return "keyword";
    }

    if (stream.match(builtins)) {
      return "builtin";
    }

    var isDefinition = state.isDefinition || state.lastToken == "function" ||
                       state.lastToken == "macro" || state.lastToken == "type" ||
                       state.lastToken == "immutable";

    if (stream.match(identifiers)) {
      if (isDefinition) {
        if (stream.peek() === '.') {
          state.isDefinition = true;
          return "variable";
        }
        state.isDefinition = false;
        return "def";
      }
      if (stream.match(/^({[^}]*})*\(/, false)) {
        return callOrDef(stream, state);
      }
      state.leavingExpr = true;
      return "variable";
    }

    // Handle non-detected items
    stream.next();
    return "error";
  }

  function callOrDef(stream, state) {
    var match = stream.match(/^(\(\s*)/);
    if (match) {
      if (state.firstParenPos < 0)
        state.firstParenPos = state.scopes.length;
      state.scopes.push('(');
      state.charsAdvanced += match[1].length;
    }
    if (currentScope(state) == '(' && stream.match(/^\)/)) {
      state.scopes.pop();
      state.charsAdvanced += 1;
      if (state.scopes.length <= state.firstParenPos) {
        var isDefinition = stream.match(/^\s*?=(?!=)/, false);
        stream.backUp(state.charsAdvanced);
        state.firstParenPos = -1;
        state.charsAdvanced = 0;
        if (isDefinition)
          return "def";
        return "builtin";
      }
    }
    // Unfortunately javascript does not support multiline strings, so we have
    // to undo anything done upto here if a function call or definition splits
    // over two or more lines.
    if (stream.match(/^$/g, false)) {
      stream.backUp(state.charsAdvanced);
      while (state.scopes.length > state.firstParenPos)
        state.scopes.pop();
      state.firstParenPos = -1;
      state.charsAdvanced = 0;
      return "builtin";
    }
    state.charsAdvanced += stream.match(/^([^()]*)/)[1].length;
    return callOrDef(stream, state);
  }

  function tokenAnnotation(stream, state) {
    stream.match(/.*?(?=,|;|{|}|\(|\)|=|$|\s)/);
    if (stream.match(/^{/)) {
      state.nestedLevels++;
    } else if (stream.match(/^}/)) {
      state.nestedLevels--;
    }
    if (state.nestedLevels > 0) {
      stream.match(/.*?(?={|})/);
    } else if (state.nestedLevels == 0) {
      state.tokenize = tokenBase;
    }
    return "builtin";
  }

  function tokenComment(stream, state) {
    if (stream.match(/^#=/)) {
      state.nestedLevels++;
    }
    if (!stream.match(/.*?(?=(#=|=#))/)) {
      stream.skipToEnd();
    }
    if (stream.match(/^=#/)) {
      state.nestedLevels--;
      if (state.nestedLevels == 0)
        state.tokenize = tokenBase;
    }
    return "comment";
  }

  function tokenChar(stream, state) {
    var isChar = false, match;
    if (stream.match(chars)) {
      isChar = true;
    } else if (match = stream.match(/\\u([a-f0-9]{1,4})(?=')/i)) {
      var value = parseInt(match[1], 16);
      if (value <= 55295 || value >= 57344) { // (U+0,U+D7FF), (U+E000,U+FFFF)
        isChar = true;
        stream.next();
      }
    } else if (match = stream.match(/\\U([A-Fa-f0-9]{5,8})(?=')/)) {
      var value = parseInt(match[1], 16);
      if (value <= 1114111) { // U+10FFFF
        isChar = true;
        stream.next();
      }
    }
    if (isChar) {
      state.leavingExpr = true;
      state.tokenize = tokenBase;
      return "string";
    }
    if (!stream.match(/^[^']+(?=')/)) { stream.skipToEnd(); }
    if (stream.match(/^'/)) { state.tokenize = tokenBase; }
    return "error";
  }

  function tokenStringFactory(delimiter) {
    if (delimiter.substr(-3) === '"""') {
      delimiter = '"""';
    } else if (delimiter.substr(-1) === '"') {
      delimiter = '"';
    }
    function tokenString(stream, state) {
      if (stream.eat('\\')) {
        stream.next();
      } else if (stream.match(delimiter)) {
        state.tokenize = tokenBase;
        state.leavingExpr = true;
        return "string";
      } else {
        stream.eat(/[`"]/);
      }
      stream.eatWhile(/[^\\`"]/);
      return "string";
    }
    return tokenString;
  }

  var external = {
    startState: function() {
      return {
        tokenize: tokenBase,
        scopes: [],
        lastToken: null,
        leavingExpr: false,
        isDefinition: false,
        nestedLevels: 0,
        charsAdvanced: 0,
        firstParenPos: -1
      };
    },

    token: function(stream, state) {
      var style = state.tokenize(stream, state);
      var current = stream.current();

      if (current && style) {
        state.lastToken = current;
      }

      // Handle '.' connected identifiers
      if (current === '.') {
        style = stream.match(identifiers, false) || stream.match(macro, false) ||
                stream.match(/\(/, false) ? "operator" : "error";
      }
      return style;
    },

    indent: function(state, textAfter) {
      var delta = 0;
      if ( textAfter === ']' || textAfter === ')' || textAfter === "end" ||
           textAfter === "else" || textAfter === "catch" || textAfter === "elseif" ||
           textAfter === "finally" ) {
        delta = -1;
      }
      return (state.scopes.length + delta) * config.indentUnit;
    },

    electricInput: /\b(end|else|catch|finally)\b/,
    blockCommentStart: "#=",
    blockCommentEnd: "=#",
    lineComment: "#",
    fold: "indent"
  };
  return external;
});

CodeMirror.defineMIME("text/x-julia", "julia");

});
<|endoftext|>


<commit_before>/***
|''Name''|TiddlyServer upload plugin|
|''Description''|Upload TWC file to TiddlyServer |
|''Author''|icm7216|
|''Version''|1.0.0|
|''date''|Jul 19, 2017|
|''Requires''|[[Arlen22/TiddlyServer|https://github.com/Arlen22/TiddlyServer]]|
|''Source:''|TiddlyServerUploadPlugin.js|
|''License''|[[MIT|https://opensource.org/licenses/MIT]]|
|''~CoreVersion''|2.8.1|

!Description

When saving the TiddlyWiki Classic (TWC) file, allows to upload it to TiddlyServer with this plugin.
This plugin was created as a saving method instead of Tiddlyfox when the extension of Tiddlyfox becomes invalid.

Thanks to [[Arlen22/TiddlyServer|https://github.com/Arlen22/TiddlyServer]]

!Installation Plugin

Create a new tiddler with the following contents.

title:
{{{=>}}} ''TiddlyServer upload plugin''

content:
{{{=>}}} Copy the contents of ''TiddlyServerUploadPlugin.js'' and paste it in the contents area.

tags:
{{{=>}}} ''systemConfig''

To enable the plugin, Save the TWC file and reload it.

!Options

Upload to TiddlyServer if enabled.
<<option chkEnableUpload>> ''chkEnableUpload''

!Code
***/
//{{{

// Upload to TiddlyServer if true
config.options.chkEnableUpload = true;
// Show editing features when viewed over HTTP
config.options.chkHttpReadOnly = false;

// Upload to TiddlyServer function
function UploadToTiddlyServer(filePath, content) {
  if (config.options.chkEnableUpload) {
    config.saveByDownload = true;
    var url = filePath.replace(/\\\\/, 'http://').replace(/\\/g, '/');
    var data = decodeURIComponent(escape(content));
    var xhr = new XMLHttpRequest();
    xhr.onload = () => {
      if (xhr.status == 200) {
        console.log("upload Ok!");
      }
    }
    try {
      xhr.open('PUT', url, true);
      xhr.setRequestHeader("Content-Type", "text/html;charset=UTF-8");
      xhr.send(data);
      return true;
    } catch (e) {
      alert("Cannot connect to TiddlyServer");
      return false;
    }
  }
  return null;
}

// =====================================
// override window.saveFile
// add upload to TiddlyServer function
// =====================================
window.saveFile = function(fileUrl,content) {
  var r = UploadToTiddlyServer(fileUrl,content);
  if(!r)
    r = mozillaSaveFile(fileUrl,content);
  if(!r)
    r = ieSaveFile(fileUrl,content);
  if(!r)
    r = javaSaveFile(fileUrl,content);
  if(!r)
    r = HTML5DownloadSaveFile(fileUrl,content);
  if(!r)
    r = manualSaveFile(fileUrl,content);
  return r;
}

//}}}
<commit_msg>Fix source link<commit_after>/***
|''Name''|TiddlyServer upload plugin|
|''Description''|Upload TWC file to TiddlyServer |
|''Author''|icm7216|
|''Version''|1.0.0|
|''date''|Jul 19, 2017|
|''Requires''|[[Arlen22/TiddlyServer|https://github.com/Arlen22/TiddlyServer]]|
|''Source:''|[[icm7216/TiddlyServer-upload-plugin|https://github.com/icm7216/TiddlyServer-upload-plugin/blob/master/TiddlyServerUploadPlugin.js]]|
|''License''|[[MIT|https://opensource.org/licenses/MIT]]|
|''~CoreVersion''|2.8.1|

!Description

When saving the TiddlyWiki Classic (TWC) file, allows to upload it to TiddlyServer with this plugin.
This plugin was created as a saving method instead of Tiddlyfox when the extension of Tiddlyfox becomes invalid.

Thanks to [[Arlen22/TiddlyServer|https://github.com/Arlen22/TiddlyServer]]

!Installation Plugin

Create a new tiddler with the following contents.

title:
{{{=>}}} ''TiddlyServer upload plugin''

content:
{{{=>}}} Copy the contents of ''TiddlyServerUploadPlugin.js'' and paste it in the contents area.

tags:
{{{=>}}} ''systemConfig''

To enable the plugin, Save the TWC file and reload it.

!Options

Upload to TiddlyServer if enabled.
<<option chkEnableUpload>> ''chkEnableUpload''

!Code
***/
//{{{

// Upload to TiddlyServer if true
config.options.chkEnableUpload = true;
// Show editing features when viewed over HTTP
config.options.chkHttpReadOnly = false;

// Upload to TiddlyServer function
function UploadToTiddlyServer(filePath, content) {
  if (config.options.chkEnableUpload) {
    config.saveByDownload = true;
    var url = filePath.replace(/\\\\/, 'http://').replace(/\\/g, '/');
    var data = decodeURIComponent(escape(content));
    var xhr = new XMLHttpRequest();
    xhr.onload = () => {
      if (xhr.status == 200) {
        console.log("upload Ok!");
      }
    }
    try {
      xhr.open('PUT', url, true);
      xhr.setRequestHeader("Content-Type", "text/html;charset=UTF-8");
      xhr.send(data);
      return true;
    } catch (e) {
      alert("Cannot connect to TiddlyServer");
      return false;
    }
  }
  return null;
}

// =====================================
// override window.saveFile
// add upload to TiddlyServer function
// =====================================
window.saveFile = function(fileUrl,content) {
  var r = UploadToTiddlyServer(fileUrl,content);
  if(!r)
    r = mozillaSaveFile(fileUrl,content);
  if(!r)
    r = ieSaveFile(fileUrl,content);
  if(!r)
    r = javaSaveFile(fileUrl,content);
  if(!r)
    r = HTML5DownloadSaveFile(fileUrl,content);
  if(!r)
    r = manualSaveFile(fileUrl,content);
  return r;
}

//}}}
<|endoftext|>


<commit_before><commit_msg>Add VideoItem component<commit_after>import React from 'react';

const VideoItem = ({ video }) => {
  const imgUrl = video.snippet.thumbnails.default.url;

  return(

{video.snippet.title}

  );
}

export default VideoItem;
<|endoftext|>


<commit_before>import React from 'react';
import Layout from '../../components/Layout';
import RecipeListView from '../../components/ListView/RecipeListView';
import CreateRecipe from '../../components/Modal/CreateRecipe';
import RecipeApi from '../../data/RecipeApi';
import constants from '../../core/constants';
import utils from '../../core/utils';

class RecipesPage extends React.Component {
  constructor() {
    super();
    this.setNotifications = this.setNotifications.bind(this);
  }

  state = { recipes: [] };

  componentWillMount() {
    this.getRecipes();
  }

  componentDidMount() {
    document.title = 'Recipes';
  }

  setNotifications = () => {
    this.refs.layout.setNotifications();
  }

  getRecipes() {
    // The /recipes/list response looks like:
    // {"recipes":["example","http-server","nfs-server"],"offset":0,"limit":20}
    utils.apiFetch(constants.get_recipes_list)
      .then(listdata => {
        for (const i in listdata.recipes) {
          const recipeName = listdata.recipes[i];
            // Recipe info looks like:
            // {"recipes":[{"name":"http-server","description":"An example http server",
            // "modules":[{"name":"fm-httpd","version":"23.*"},{"name":"fm-php","version":"11.6.*"}]
            // ,"packages":[{"name":"tmux","version":"2.2"}]}],"offset":0,"limit":20}
          utils.apiFetch(constants.get_recipes_info + recipeName)
              .then(recipedata => {
                let recipe = recipedata.recipes[0];
                recipe.id = recipeName;
                this.setState({ recipes: this.state.recipes.concat(recipe) });
              });
        }
      })
      .catch(e => console.log(`Error getting recipes: ${e}`));
  }

  handleDelete = (event, recipe) => {
    event.preventDefault();
    event.stopPropagation();
    // delete the recipe
    RecipeApi.deleteRecipe(recipe);
    // get recipes again
    this.getRecipes();
  }

  render() {
    return (
      <Layout
        className="container-fluid container-pf-nav-pf-vertical"
        ref="layout"
      >

            <form className="toolbar-pf-actions">

                Name

                    <button
                      type="button"
                      className="btn btn-default dropdown-toggle"
                      data-toggle="dropdown"
                      aria-haspopup="true"
                      aria-expanded="false"
                    >Name</button>

Name

Version

                  <input
                    type="text"
                    className="form-control"
                    id="filter"
                    placeholder="Filter By Name..."
                  />

                  <button
                    type="button"
                    className="btn btn-default dropdown-toggle"
                    data-toggle="dropdown"
                    aria-haspopup="true"
                    aria-expanded="false"
                  >Name</button>

Name

Version

                <button className="btn btn-link" type="button">

                </button>

                  <button
                    className="btn btn-default"
                    type="button"
                    data-toggle="modal"
                    data-target="#cmpsr-modal-crt-recipe"
                  >Create Recipe</button>

                    <button
                      className="btn btn-link dropdown-toggle"
                      type="button"
                      id="dropdownKebab"
                      data-toggle="dropdown"
                      aria-haspopup="true"
                      aria-expanded="false"
                    ></button>

Import Recipe

Create Compositions

Export Selected Recipes

Archive Selected Recipes

                  <button className="btn btn-link btn-find" type="button">

                  </button>

                    <input
                      type="text"
                      className="form-control"
                      id="find"
                      placeholder="Find By Keyword..."
                    />

                      1 of 3
                      <button className="btn btn-link" type="button">

                      </button>
                      <button className="btn btn-link" type="button">

                      </button>
                      <button className="btn btn-link btn-find-close" type="button">

                      </button>

            </form>

40 Results

Active filters:

                    Name: nameofthething

                    Version: 3

                    Lifecycle: 5

Clear All Filters

        <RecipeListView recipes={this.state.recipes} handleDelete={this.handleDelete} setNotifications={this.setNotifications} />
        <CreateRecipe />
      </Layout>
    );
  }

}

export default RecipesPage;
<commit_msg>updating Delete to remove deleted recipe obj<commit_after>import React from 'react';
import Layout from '../../components/Layout';
import RecipeListView from '../../components/ListView/RecipeListView';
import CreateRecipe from '../../components/Modal/CreateRecipe';
import RecipeApi from '../../data/RecipeApi';
import constants from '../../core/constants';
import utils from '../../core/utils';

class RecipesPage extends React.Component {
  constructor() {
    super();
    this.setNotifications = this.setNotifications.bind(this);
  }

  state = { recipes: [] };

  componentWillMount() {
    this.getRecipes();
  }

  componentDidMount() {
    document.title = 'Recipes';
  }

  setNotifications = () => {
    this.refs.layout.setNotifications();
  }

  getRecipes() {
    // The /recipes/list response looks like:
    // {"recipes":["example","http-server","nfs-server"],"offset":0,"limit":20}
    utils.apiFetch(constants.get_recipes_list)
      .then(listdata => {
        for (const i in listdata.recipes) {
          const recipeName = listdata.recipes[i];
            // Recipe info looks like:
            // {"recipes":[{"name":"http-server","description":"An example http server",
            // "modules":[{"name":"fm-httpd","version":"23.*"},{"name":"fm-php","version":"11.6.*"}]
            // ,"packages":[{"name":"tmux","version":"2.2"}]}],"offset":0,"limit":20}
          utils.apiFetch(constants.get_recipes_info + recipeName)
              .then(recipedata => {
                let recipe = recipedata.recipes[0];
                recipe.id = recipeName;
                this.setState({ recipes: this.state.recipes.concat(recipe) });
              });
        }
      })
      .catch(e => console.log(`Error getting recipes: ${e}`));
  }

  handleDelete = (event, recipe) => {
    event.preventDefault();
    event.stopPropagation();
    const p = new Promise((resolve, reject) => {
      RecipeApi.deleteRecipe(recipe)
      .then(() => {
        // find the recipe in recipes and remove it
        let recipes = this.state.recipes;
        recipes = recipes.filter(
          (obj) => (obj.id !== recipe)
        );
        this.setState({recipes: recipes});
        resolve();
      }).catch(e => {
        console.log(`Error deleting recipe: ${e}`);
        reject();
      });
    });
    return p;
  }

  render() {
    return (
      <Layout
        className="container-fluid container-pf-nav-pf-vertical"
        ref="layout"
      >

            <form className="toolbar-pf-actions">

                Name

                    <button
                      type="button"
                      className="btn btn-default dropdown-toggle"
                      data-toggle="dropdown"
                      aria-haspopup="true"
                      aria-expanded="false"
                    >Name</button>

Name

Version

                  <input
                    type="text"
                    className="form-control"
                    id="filter"
                    placeholder="Filter By Name..."
                  />

                  <button
                    type="button"
                    className="btn btn-default dropdown-toggle"
                    data-toggle="dropdown"
                    aria-haspopup="true"
                    aria-expanded="false"
                  >Name</button>

Name

Version

                <button className="btn btn-link" type="button">

                </button>

                  <button
                    className="btn btn-default"
                    type="button"
                    data-toggle="modal"
                    data-target="#cmpsr-modal-crt-recipe"
                  >Create Recipe</button>

                    <button
                      className="btn btn-link dropdown-toggle"
                      type="button"
                      id="dropdownKebab"
                      data-toggle="dropdown"
                      aria-haspopup="true"
                      aria-expanded="false"
                    ></button>

Import Recipe

Create Compositions

Export Selected Recipes

Archive Selected Recipes

                  <button className="btn btn-link btn-find" type="button">

                  </button>

                    <input
                      type="text"
                      className="form-control"
                      id="find"
                      placeholder="Find By Keyword..."
                    />

                      1 of 3
                      <button className="btn btn-link" type="button">

                      </button>
                      <button className="btn btn-link" type="button">

                      </button>
                      <button className="btn btn-link btn-find-close" type="button">

                      </button>

            </form>

40 Results

Active filters:

                    Name: nameofthething

                    Version: 3

                    Lifecycle: 5

Clear All Filters

        <RecipeListView recipes={this.state.recipes} handleDelete={this.handleDelete} setNotifications={this.setNotifications} />
        <CreateRecipe />
      </Layout>
    );
  }

}

export default RecipesPage;
<|endoftext|>


<commit_before>define([
    '/common/messages.js',
    '/customize/DecorateToolbar.js',
    '/common/cryptpad-common.js',
    '/bower_components/lil-uri/uri.min.js',
    '/customize/email.js',
    '/bower_components/jquery/dist/jquery.min.js',
], function (Messages, DecorateToolbar, Cryptpad, LilUri, Email) {
    var $ = window.$;

    var email = Email.makeScrambler(1);

    // slip past the spammers, then unscramble mailto links
    $('a[href^="mailto:"]').each(function () {
        $(this).attr('href', function (i, href) {
            return href.replace(/:(.*$)/, function (a, address) {
                return ':' + email.decrypt(address);
            });
        });
    });

    DecorateToolbar.main($('#bottom-bar'));
    Cryptpad.styleAlerts();

    var $table = $('table.scroll');
    var $tbody = $table.find('tbody');
    var $tryit = $('#tryit');
    var now = new Date();
    var hasRecent = false;

    var memorySpan = Cryptpad.timeframe; // thirty days

    var forgetPad = Cryptpad.forgetPad;

    var padTypes = {
        '/pad/': 'Pad',
        '/code/': 'Code'
    };

    var truncateTitle = function (title, len) {
        if (typeof(title) === 'string' && title.length > len) {
            return title.slice(0, len) + '…';
        }
        return title;
    };

    var recentPads = Cryptpad.getRecentPads();
    recentPads.sort(Cryptpad.mostRecent);

    var fixHTML = function (html) {
        return html.replace(/</g, '<');
    };

    var makeRecentPadsTable = function () {
        if (!recentPads.length) { return; }
        recentPads.some(function (pad, index) {
            if (!pad) { return; }

            //console.log(pad);

            // don't link to old pads
            if (now.getTime() - new Date(pad.atime).getTime() > memorySpan) { return true; }

            hasRecent = true;

            // split up the uri
            var uri = LilUri(pad.href);

            // derive the name
            var name = padTypes[uri.path()];

            var title = pad.title || uri.parts.hash.slice(0,8);
            var shortTitle = truncateTitle(pad.title, 48);

            var date = new Date(pad.atime).toLocaleDateString();
            var created = new Date(pad.ctime).toLocaleDateString();

            if (date === now.toLocaleDateString()) {
                date = new Date(pad.atime).toLocaleTimeString().replace(/ /g, '');
            }

            var id = 'pad-'+index;

            var $row = $('<tr>', {
                id: id
            });

            var $remove = $('<td>', {
                'class': 'remove',
                title: "forget '"+shortTitle + "'"
            }).text('✖').click(function () {
                Cryptpad.confirm(Messages.forgetPrompt + ' (' + fixHTML(shortTitle) + ')', function (yes) {
                    if (!yes) { return; }
                    forgetPad(pad.href);
                    $row.fadeOut(750, function () {
                        $row.remove();
                        if (!$table.find('tr').find('td').length) {
                            $table.remove();
                            $tryit.text(Messages.tryIt);
                        }
                    });
                });
            });

            $row
                .append($('<td>').text(name))
                .append($('<td>').append($('<a>', {
                    href: pad.href,
                    title: pad.title,
                }).text(shortTitle)))
                .append($('<td>').text(created))
                .append($('<td>').text(date))
                .append($remove);
            $tbody.append($row);
        });
    };

    if (recentPads.length) {
        recentPads.sort(Cryptpad.mostRecent);
        makeRecentPadsTable();
    }
    if (hasRecent) {
        $('table').attr('style', '');
        $tryit.text(Messages.recentPads);
    }
});

<commit_msg>missed one<commit_after>define([
    '/customize/messages.js',
    '/customize/DecorateToolbar.js',
    '/common/cryptpad-common.js',
    '/bower_components/lil-uri/uri.min.js',
    '/customize/email.js',
    '/bower_components/jquery/dist/jquery.min.js',
], function (Messages, DecorateToolbar, Cryptpad, LilUri, Email) {
    var $ = window.$;

    var email = Email.makeScrambler(1);

    // slip past the spammers, then unscramble mailto links
    $('a[href^="mailto:"]').each(function () {
        $(this).attr('href', function (i, href) {
            return href.replace(/:(.*$)/, function (a, address) {
                return ':' + email.decrypt(address);
            });
        });
    });

    DecorateToolbar.main($('#bottom-bar'));
    Cryptpad.styleAlerts();

    var $table = $('table.scroll');
    var $tbody = $table.find('tbody');
    var $tryit = $('#tryit');
    var now = new Date();
    var hasRecent = false;

    var memorySpan = Cryptpad.timeframe; // thirty days

    var forgetPad = Cryptpad.forgetPad;

    var padTypes = {
        '/pad/': 'Pad',
        '/code/': 'Code'
    };

    var truncateTitle = function (title, len) {
        if (typeof(title) === 'string' && title.length > len) {
            return title.slice(0, len) + '…';
        }
        return title;
    };

    var recentPads = Cryptpad.getRecentPads();
    recentPads.sort(Cryptpad.mostRecent);

    var fixHTML = function (html) {
        return html.replace(/</g, '<');
    };

    var makeRecentPadsTable = function () {
        if (!recentPads.length) { return; }
        recentPads.some(function (pad, index) {
            if (!pad) { return; }

            //console.log(pad);

            // don't link to old pads
            if (now.getTime() - new Date(pad.atime).getTime() > memorySpan) { return true; }

            hasRecent = true;

            // split up the uri
            var uri = LilUri(pad.href);

            // derive the name
            var name = padTypes[uri.path()];

            var title = pad.title || uri.parts.hash.slice(0,8);
            var shortTitle = truncateTitle(pad.title, 48);

            var date = new Date(pad.atime).toLocaleDateString();
            var created = new Date(pad.ctime).toLocaleDateString();

            if (date === now.toLocaleDateString()) {
                date = new Date(pad.atime).toLocaleTimeString().replace(/ /g, '');
            }

            var id = 'pad-'+index;

            var $row = $('<tr>', {
                id: id
            });

            var $remove = $('<td>', {
                'class': 'remove',
                title: "forget '"+shortTitle + "'"
            }).text('✖').click(function () {
                Cryptpad.confirm(Messages.forgetPrompt + ' (' + fixHTML(shortTitle) + ')', function (yes) {
                    if (!yes) { return; }
                    forgetPad(pad.href);
                    $row.fadeOut(750, function () {
                        $row.remove();
                        if (!$table.find('tr').find('td').length) {
                            $table.remove();
                            $tryit.text(Messages.tryIt);
                        }
                    });
                });
            });

            $row
                .append($('<td>').text(name))
                .append($('<td>').append($('<a>', {
                    href: pad.href,
                    title: pad.title,
                }).text(shortTitle)))
                .append($('<td>').text(created))
                .append($('<td>').text(date))
                .append($remove);
            $tbody.append($row);
        });
    };

    if (recentPads.length) {
        recentPads.sort(Cryptpad.mostRecent);
        makeRecentPadsTable();
    }
    if (hasRecent) {
        $('table').attr('style', '');
        $tryit.text(Messages.recentPads);
    }
});

<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'

import EntryContainer from 'components/list/entry/EntryContainer'

import './List.css'

class List extends Component {
  render() {
    return (

          {this.props.title}
          {this.props.clearable && (

          )}

          {this.props.reminders.map(reminder => (
            <EntryContainer
              data={reminder}
              key={reminder.id}
            />
          ))}
          {this.props.reminders.length === 0 && (

No reminders matched your query

          )}

          © 2017 Florian Dejonckheere

    )
  }
}

List.propTypes = {
  reminders: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.number.isRequired,
      title: PropTypes.string.isRequired,
      active: PropTypes.bool.isRequired,
      standalone: PropTypes.bool.isRequired,
      due: PropTypes.number.isRequired,
      interval: PropTypes.number,
      labels: PropTypes.arrayOf(PropTypes.number),
      alerts: PropTypes.arrayOf(
        PropTypes.shape({
          time: PropTypes.number.isRequired,
          type: PropTypes.arrayOf(PropTypes.string).isRequired,
        })
      ).isRequired,
    }).isRequired,
  ).isRequired,
  dateFilter: PropTypes.string,
  textFilter: PropTypes.string,
}

export default List
<commit_msg>Add link to footer<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'

import EntryContainer from 'components/list/entry/EntryContainer'

import './List.css'

class List extends Component {
  render() {
    return (

          {this.props.title}
          {this.props.clearable && (

          )}

          {this.props.reminders.map(reminder => (
            <EntryContainer
              data={reminder}
              key={reminder.id}
            />
          ))}
          {this.props.reminders.length === 0 && (

No reminders matched your query

          )}

          © 2017 Florian Dejonckheere

    )
  }
}

List.propTypes = {
  reminders: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.number.isRequired,
      title: PropTypes.string.isRequired,
      active: PropTypes.bool.isRequired,
      standalone: PropTypes.bool.isRequired,
      due: PropTypes.number.isRequired,
      interval: PropTypes.number,
      labels: PropTypes.arrayOf(PropTypes.number),
      alerts: PropTypes.arrayOf(
        PropTypes.shape({
          time: PropTypes.number.isRequired,
          type: PropTypes.arrayOf(PropTypes.string).isRequired,
        })
      ).isRequired,
    }).isRequired,
  ).isRequired,
  dateFilter: PropTypes.string,
  textFilter: PropTypes.string,
}

export default List
<|endoftext|>


<commit_before><commit_msg>#Autopush 06/08/17 19:09:55<commit_after><|endoftext|>


<commit_before>import { faFileAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { NextSeo } from 'next-seo';
import Image from 'next/image';
import Link from 'next/link';
import React, { useRef } from 'react';

import Banner from '../../components/Banner';
import Layout from '../../components/Layout';

import TestimonialsCourseChanges from '../../public/images/town-hall/testimonials-course-changes.png';
import TownHallBanner from '../../public/images/town-hall/town-hall-banner-f21.png';

const TOWN_HALL_2021_WINTER_VIDEO = 'https://www.youtube.com/embed/Eq2xsShPMVc';

const inlineButtonListStyle = {
  display: 'inline-block',
  marginBottom: '0.5em',
};

function TownHall() {
  const embed2021WRef = useRef(null);
  // note: this does not work :( prob need useEffect + useState!
  const embedWidth = embed2021WRef.current ? embed2021WRef.current.offsetWidth : 500;
	return (
		<Layout>
			<NextSeo
				title="Fall 2021 Computer Science Town Hall | ACM at UCLA"
				description="Ask questions and get your voice heard at the Fall 2021 Computer Science Town Hall! Wednesday, November 10th from 6:30 - 8:30 PM PT - we hope to see you there :)"
				openGraph={{
					images: [
						{
							url: 'https://www.uclaacm.com/images/town-hall/town-hall-banner-f21.png',
							width: 1920,
							height: 1005,
							alt: 'A banner that reads "Fall 2021 Computer Science Town Hall: ask questions and get your voice heard! Wednesday, November 10 from 6:30 - 8:30 PM PT. Held at the Mong Auditorium and Online; visit uclaacm.com/town-hall for more information. Co-hosted by ACM at UCLA, UPE at UCLA, exploretech.la, and the UCLA Computer Science Department."',
						},
					],
					site_name: 'ACM at UCLA',
				}}
			/>
			<Banner decorative />

          <Image src={TownHallBanner} alt="A banner that reads 'Fall 2021 Computer Science Town Hall: ask questions and get your voice heard! Wednesday, November 10 from 6:30 - 8:30 PM PT. Held at the Mong Auditorium and Online; visit uclaacm.com/town-hall for more information. Co-hosted by ACM at UCLA, UPE at UCLA, exploretech.la, and the UCLA Computer Science Department.'" />

Fall 2021 Computer Science Town Hall

          {/* eslint-disable-next-line max-len */}
          Ask questions and get your voice heard! The CS Town Hall is an opportunity for students to directly speak with professors and administrators in the CS department.

          {/* eslint-disable-next-line max-len */}
          The upcoming Town Hall occurs on Wednesday, November 10th (Week 7) at 6:30 - 8:30 PM PT. The event will be hybrid: an in-person offering will be in the Mong Auditorium (in Engineering VI), while a livestreamed option with an online Q&A will also be available. To attend, <Link href="https://bit.ly/CSTownHallFall2021RSVP" target="_blank" rel="noopener noreferrer">please RSVP!</Link>

          {/* eslint-disable-next-line max-len */}
          In past years, the Town Hall has been a huge driver of student feedback and improvements to curriculum; this includes:

The rework of CS35L (and CS97)

The start of engineering-wide ethics reform

More leniency around the sci-tech and tech breadth electives

          {/* eslint-disable-next-line max-len */}
          The town hall is jointly held by ACM at UCLA, exploretech.la, UPE at UCLA, and the Department of Computer Science at UCLA.

            <Link href="https://bit.ly/CSTownHallFall2021RSVP"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> RSVP now!</Link>

          {' '}

            <Link href="#surveys"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Answer Survey Questions!</Link>

Surveys

              {/* eslint-disable-next-line max-len */}
              We use pre-event surveys to gauge students' opinions on diversity & inclusion, academics and curriculum, and academic honesty. We use the answers to present problems to the CS department, and guide discussion. Survey responses are anonymous!

              We need to hear your voice! Please answer these surveys before the event.

                <Link href="https://bit.ly/CSTownHallFall2021Curriculum"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Academics and Curriculum</Link>

              {' '}

                <Link href="https://bit.ly/CSTownHallFall2021Diversity"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Diversity and Inclusion</Link>

              {' '}

                <Link href="https://bit.ly/CSTownHallFall2021Honesty"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Academic Honesty</Link>

            <Image src={TestimonialsCourseChanges} alt="A slide from the winter 2021 town hall titled 'courses studnets wish to see changes in', with several different examples (CS 111, 152A, 131, 1)" />

Past Town Halls

Winter 2021 // Wednesday, February 24th 2021

              {/* eslint-disable-next-line max-len */}
              In our first ever fully-virtual town hall, we focused on three key topics: academics & curriculum, academic honesty, and a new section devoted to diveristy & inclusion.

                <Link href="/files/town-hall/CS Town Hall Winter 2021 Slides.pdf"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Form Summaries and Slides</Link>

              {' '}

                <Link href="/files/town-hall/CS Town Hall Winter 2021 Notes.pdf"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Event Notes</Link>

		</Layout>
	);
}

export default TownHall;
<commit_msg>chore: fix typo<commit_after>import { faFileAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { NextSeo } from 'next-seo';
import Image from 'next/image';
import Link from 'next/link';
import React, { useRef } from 'react';

import Banner from '../../components/Banner';
import Layout from '../../components/Layout';

import TestimonialsCourseChanges from '../../public/images/town-hall/testimonials-course-changes.png';
import TownHallBanner from '../../public/images/town-hall/town-hall-banner-f21.png';

const TOWN_HALL_2021_WINTER_VIDEO = 'https://www.youtube.com/embed/Eq2xsShPMVc';

const inlineButtonListStyle = {
  display: 'inline-block',
  marginBottom: '0.5em',
};

function TownHall() {
  const embed2021WRef = useRef(null);
  // note: this does not work :( prob need useEffect + useState!
  const embedWidth = embed2021WRef.current ? embed2021WRef.current.offsetWidth : 500;
	return (
		<Layout>
			<NextSeo
				title="Fall 2021 Computer Science Town Hall | ACM at UCLA"
				description="Ask questions and get your voice heard at the Fall 2021 Computer Science Town Hall! Wednesday, November 10th from 6:30 - 8:30 PM PT - we hope to see you there :)"
				openGraph={{
					images: [
						{
							url: 'https://www.uclaacm.com/images/town-hall/town-hall-banner-f21.png',
							width: 1920,
							height: 1005,
							alt: 'A banner that reads "Fall 2021 Computer Science Town Hall: ask questions and get your voice heard! Wednesday, November 10 from 6:30 - 8:30 PM PT. Held at the Mong Auditorium and Online; visit uclaacm.com/town-hall for more information. Co-hosted by ACM at UCLA, UPE at UCLA, exploretech.la, and the UCLA Computer Science Department."',
						},
					],
					site_name: 'ACM at UCLA',
				}}
			/>
			<Banner decorative />

          <Image src={TownHallBanner} alt="A banner that reads 'Fall 2021 Computer Science Town Hall: ask questions and get your voice heard! Wednesday, November 10 from 6:30 - 8:30 PM PT. Held at the Mong Auditorium and Online; visit uclaacm.com/town-hall for more information. Co-hosted by ACM at UCLA, UPE at UCLA, exploretech.la, and the UCLA Computer Science Department.'" />

Fall 2021 Computer Science Town Hall

          {/* eslint-disable-next-line max-len */}
          Ask questions and get your voice heard! The CS Town Hall is an opportunity for students to directly speak with professors and administrators in the CS department.

          {/* eslint-disable-next-line max-len */}
          The upcoming Town Hall occurs on Wednesday, November 10th (Week 7) at 6:30 - 8:30 PM PT. The event will be hybrid: an in-person offering will be in the Mong Auditorium (in Engineering VI), while a livestreamed option with an online Q&A will also be available. To attend, <Link href="https://bit.ly/CSTownHallFall2021RSVP" target="_blank" rel="noopener noreferrer">please RSVP!</Link>

          {/* eslint-disable-next-line max-len */}
          In past years, the Town Hall has been a huge driver of student feedback and improvements to curriculum; this includes:

The rework of CS35L (and CS97)

The start of engineering-wide ethics reform

More leniency around the sci-tech and tech breadth electives

          {/* eslint-disable-next-line max-len */}
          The town hall is jointly held by ACM at UCLA, exploretech.la, UPE at UCLA, and the Department of Computer Science at UCLA.

            <Link href="https://bit.ly/CSTownHallFall2021RSVP"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> RSVP now!</Link>

          {' '}

            <Link href="#surveys"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Answer Survey Questions!</Link>

Surveys

              {/* eslint-disable-next-line max-len */}
              We use pre-event surveys to gauge students' opinions on diversity & inclusion, academics and curriculum, and academic honesty. We use the answers to present problems to the CS department, and guide discussion. Survey responses are anonymous!

              We need to hear your voice! Please answer these surveys before the event.

                <Link href="https://bit.ly/CSTownHallFall2021Curriculum"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Academics and Curriculum</Link>

              {' '}

                <Link href="https://bit.ly/CSTownHallFall2021Diversity"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Diversity and Inclusion</Link>

              {' '}

                <Link href="https://bit.ly/CSTownHallFall2021Honesty"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Academic Honesty</Link>

            <Image src={TestimonialsCourseChanges} alt="A slide from the winter 2021 town hall titled 'courses studnets wish to see changes in', with several different examples (CS 111, 152A, 131, 1)" />

Past Town Halls

Winter 2021 // Wednesday, February 24th 2021

              {/* eslint-disable-next-line max-len */}
              In our first ever fully-virtual town hall, we focused on three key topics: academics & curriculum, academic honesty, and a new section devoted to diversity & inclusion.

                <Link href="/files/town-hall/CS Town Hall Winter 2021 Slides.pdf"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Form Summaries and Slides</Link>

              {' '}

                <Link href="/files/town-hall/CS Town Hall Winter 2021 Notes.pdf"><FontAwesomeIcon icon={faFileAlt} fixedWidth aria-hidden={true} /> Event Notes</Link>

		</Layout>
	);
}

export default TownHall;
<|endoftext|>


<commit_before>
function MorseWord(word) {

}

MorseWord.prototype.morseForLetter = function(letter) {
    if (letter.toLowerCase() == "") {

    } else if (letter.toLowerCase() == "a") {
        return [".", "-"];
    } else if (letter.toLowerCase() == "b") {
        return ["-", ".", ".", "."];
    }
};

MorseWord.prototype.getLetters = function() {

};<commit_msg>the rest of MorseWord<commit_after>
function MorseWord(word) {
    this.letters = [];
    for (letter in word) {
        this.letters.push(this.morseForLetter(letter));
    }
}

MorseWord.prototype.morseForLetter = function(letter) {
    if (letter.toLowerCase() == "") {

    } else if (letter.toLowerCase() == "a") {
        return [".", "-"];
    } else if (letter.toLowerCase() == "b") {
        return ["-", ".", ".", "."];
    }
};

MorseWord.prototype.getLetters = function() {
    return this.letters;
};<|endoftext|>


<commit_before>import {NgElement, Component, Template, Parent} from 'angular2/angular2'
import {Toolbar} from 'ionic2/components/toolbar/toolbar'

@Component({
  selector: 'ion-view',
  bind: {
    title: 'view-title'
  }
})
@Template({
  inline: `
    <ion-toolbar [view-title]="title">
      <content select="ion-view-title"></content>
      <content select="ion-nav-items[side=primary]"></content>
      <content select="ion-nav-items[side=secondary]"></content>
    </ion-toolbar>

      <content></content>

`,
  directives: [Toolbar]
})
export class View {
  constructor(@NgElement() ele:NgElement) {
    ele.domElement.classList.add('pane')
    console.log('View constructed', ele.domElement, nav);
  }
}
<commit_msg>fix view having unreferenced<commit_after>import {NgElement, Component, Template, Parent} from 'angular2/angular2'
import {Toolbar} from 'ionic2/components/toolbar/toolbar'

@Component({
  selector: 'ion-view',
  bind: {
    title: 'view-title'
  }
})
@Template({
  inline: `
    <ion-toolbar [view-title]="title">
      <content select="ion-view-title"></content>
      <content select="ion-nav-items[side=primary]"></content>
      <content select="ion-nav-items[side=secondary]"></content>
    </ion-toolbar>

      <content></content>

`,
  directives: [Toolbar]
})
export class View {
  constructor(@NgElement() ele:NgElement) {
    ele.domElement.classList.add('pane')
    console.log('View constructed', ele.domElement);
  }
}
<|endoftext|>


<commit_before>// @flow
import * as React from 'react'
import { Route } from 'react-router-dom'

const uuid = function b(a) {
  return a
    ? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16)
    : ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, b)
}

const performAnalyticsSetup = () => {
  if (typeof window === 'undefined') {
    return
  }

  // Track custom dimensions
  const dimensions = {
    TRACKING_VERSION: 'dimension1',
    CLIENT_ID: 'dimension2',
    WINDOW_ID: 'dimension3',
    HIT_ID: 'dimension4',
    HIT_TIME: 'dimension5',
    HIT_TYPE: 'dimension6'
  }

  // Values for custom dimensions
  const TRACKING_VERSION = '1'

  // Initialize the command queue in case analytics.js hasn't loaded yet.
  window.ga = window.ga || ((...args) => (ga.q = ga.q || []).push(args))

  // Perform setup
  const ga = window.ga
  ga('create', 'UA-112190148-1', 'auto')
  ga('set', 'transport', 'beacon')

  /*
   * Begin custom dimensions tracking
   */

  // Tracking Version
  ga('set', dimensions.TRACKING_VERSION, TRACKING_VERSION)
  // Client ID
  ga(tracker => {
    const clientId = tracker.get('clientId')
    tracker.set(dimensions.CLIENT_ID, clientId)
  })
  // Window ID
  ga('set', dimensions.WINDOW_ID, uuid())
  ga(tracker => {
    const originalBuildHitTask = tracker.get('buildHitTask')
    tracker.set('buildHitTask', model => {
      model.set(dimensions.HIT_ID, uuid(), true)
      model.set(dimensions.HIT_TIME, String(+new Date()), true)
      model.set(dimensions.HIT_TYPE, model.get('hitType'), true)

      originalBuildHitTask(model)
    })
  })
}

/*
 * Component which logs on every page change
 */
const LogPageView = () => {
  if (typeof window !== 'undefined') {
    const ga = window.ga
    ga('send', 'pageview')
  }

  return null
}

/*
 * Component which runs once on setup and only renders children when the page
 * changes
 */
class AnalyticsImpl extends React.Component {
  constructor() {
    super()
    performAnalyticsSetup()
  }

  shouldComponentUpdate(nextProps) {
    const isSamePath =
      nextProps.location.pathname !== this.props.location.pathname
    const isSameHash = nextProps.location.hash !== this.props.location.hash

    return !isSamePath || !isSameHash
  }

  render() {
    return <LogPageView />
  }
}

const Analytics = () => {
  return <Route path="/" component={AnalyticsImpl} />
}

export default Analytics
<commit_msg>Disable tracking on localhost.<commit_after>// @flow
import * as React from 'react'
import { Route } from 'react-router-dom'

const uuid = function b(a) {
  return a
    ? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16)
    : ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, b)
}

const performAnalyticsSetup = () => {
  if (typeof window === 'undefined') {
    return
  }

  // Track custom dimensions
  const dimensions = {
    TRACKING_VERSION: 'dimension1',
    CLIENT_ID: 'dimension2',
    WINDOW_ID: 'dimension3',
    HIT_ID: 'dimension4',
    HIT_TIME: 'dimension5',
    HIT_TYPE: 'dimension6'
  }

  // Values for custom dimensions
  const TRACKING_VERSION = '1'

  // Initialize the command queue in case analytics.js hasn't loaded yet.
  window.ga = window.ga || ((...args) => (ga.q = ga.q || []).push(args))

  // Perform setup
  const ga = window.ga
  ga('create', 'UA-112190148-1', 'auto')
  ga('set', 'transport', 'beacon')

  // Disable development tracking
  if (window.location.hostname == 'localhost') {
    ga('set', 'sendHitTask', null)
  }

  /*
   * Begin custom dimensions tracking
   */

  // Tracking Version
  ga('set', dimensions.TRACKING_VERSION, TRACKING_VERSION)
  // Client ID
  ga(tracker => {
    const clientId = tracker.get('clientId')
    tracker.set(dimensions.CLIENT_ID, clientId)
  })
  // Window ID
  ga('set', dimensions.WINDOW_ID, uuid())
  ga(tracker => {
    const originalBuildHitTask = tracker.get('buildHitTask')
    tracker.set('buildHitTask', model => {
      model.set(dimensions.HIT_ID, uuid(), true)
      model.set(dimensions.HIT_TIME, String(+new Date()), true)
      model.set(dimensions.HIT_TYPE, model.get('hitType'), true)

      originalBuildHitTask(model)
    })
  })
}

/*
 * Component which logs on every page change
 */
const LogPageView = () => {
  if (typeof window !== 'undefined') {
    const ga = window.ga
    ga('send', 'pageview')
  }

  return null
}

/*
 * Component which runs once on setup and only renders children when the page
 * changes
 */
class AnalyticsImpl extends React.Component {
  constructor() {
    super()
    performAnalyticsSetup()
  }

  shouldComponentUpdate(nextProps) {
    const isSamePath =
      nextProps.location.pathname !== this.props.location.pathname
    const isSameHash = nextProps.location.hash !== this.props.location.hash

    return !isSamePath || !isSameHash
  }

  render() {
    return <LogPageView />
  }
}

const Analytics = () => {
  return <Route path="/" component={AnalyticsImpl} />
}

export default Analytics
<|endoftext|>


<commit_before>const React = require('react');
const h = require('react-hyperscript');
const queryString = require('query-string');
const color = require('color');
const _ = require('lodash');
const classNames = require('classnames');

const cytoscape = require('cytoscape');
const cose = require('cytoscape-cose-bilkent');
cytoscape.use(cose);

const sbgn2Json = require('sbgnml-to-cytoscape');
const sbgnStylesheet = require('cytoscape-sbgn-stylesheet');

const Icon = require('../../common/components').Icon;
const PathwayCommonsService = require('../../services').PathwayCommonsService;

// const testData = require('./sample-enrichments');

const augmentEnrichmentData = require('./enrichment-model');

class Paint extends React.Component {
  constructor(props) {
    super(props);

    const cy = cytoscape({
      style: sbgnStylesheet(cytoscape),
      minZoom: 0.16,
      maxZoom: 4,
      headless: true
    });

    this.state = {
      enrichmentDataSets: [],
      enrichmentClasses: [],
      // enrichmentDataSets: testData.dataSetExpressionList,
      // enrichmentClasses: _.get(testData.dataSetClassList, '0.classes', []),
      enrichmentTable: {},
      cy: cy,
      name: '',
      datasource: '',
      drawerOpen: false
    };

    const query = queryString.parse(props.location.search);
    const enrichmentsURI = query.uri ? query.uri : null;

    if (enrichmentsURI != null) {
      fetch(enrichmentsURI)
        .then(response => response.json())
        .then(json => {
          // console.log(augmentEnrichmentData(json.dataSetClassList, json.dataSetExpressionList));
          this.setState({
            enrichmentClasses: _.get(json.dataSetClassList, '0.classes', []),
            enrichmentDataSets: json.dataSetExpressionList
          }, () => {
          });
        });
    }

    const expressions = _.get(this.state.dataSetExpressionList, '0.expressions', []);
    const searchParam = query.q ? query.q : 'S Phase';
    this.initPainter(expressions, searchParam);

  }

  componentWillUnmount() {
    this.state.cy.destroy();
  }

  percentToColour(percent) {
    const hslValue = ( 1 - percent ) * 240;

    return color.hsl(hslValue, 100, 50).string();
  }

  // only call this after you know component is mounted
  initPainter(expressions, queryParam) {
    const state = this.state;
    const query = {
      q: queryParam,
      gt: 2,
      lt: 100,
      type: 'Pathway',
      datasource: 'reactome'
    };

    PathwayCommonsService.querySearch(query)
      .then(searchResults => {
        const uri = _.get(searchResults, '0.uri', null);
        if (uri != null) {
          PathwayCommonsService.query(uri, 'json', 'Named/displayName')
          .then(response => {
            this.setState({
              name: response ? response.traverseEntry[0].value.pop() : ''
            });
          });

        PathwayCommonsService.query(uri, 'json', 'Entity/dataSource/displayName')
          .then(responseObj => {
            this.setState({
              datasource: responseObj ? responseObj.traverseEntry[0].value.pop() : ''
            });
          });

        PathwayCommonsService.query(uri, 'SBGN')
          .then(text => {
            const sbgnJson = sbgn2Json(text);
            state.cy.remove('*');
            state.cy.add(sbgnJson);
            state.cy.layout({
              name: 'cose-bilkent',
              nodeDimensionsIncludeLabels: true
            }).run();

            const enrichmentTable = this.createEnrichmentTable();

            const networkNodes = state.cy.nodes().map(node => node.data('label'));
            const enrichmentsInNetwork = enrichmentTable.rows.filter(row => networkNodes.includes(row.geneName));
            const maxVal = _.max(enrichmentsInNetwork.map(row => _.max(row.classValues)).map((k, v) => parseFloat(k)));
            enrichmentsInNetwork.forEach(row => {
              // probably more efficient to add the enrichment data to the node field instead of interating twice
              state.cy.nodes().filter(node => node.data('label') === row.geneName).forEach(node => {

                const numSlices = row.classValues.length > 16 ? 16 : row.classValues.length;

                const pieStyle = {
                  'pie-size': '100%'
                };
                for (let i = 1; i <= numSlices; i++) {

                  pieStyle['pie-' + i + '-background-size'] = 100 / numSlices;
                  pieStyle['pie-' + i + '-background-opacity'] = 1;
                  pieStyle['pie-' + i + '-background-color'] = this.percentToColour(row.classValues[i-1] / maxVal);
                }

                node.style(pieStyle);
              });

              this.setState({enrichmentTable: enrichmentTable});

            });
          });
        }
      });
  }

  componentDidMount() {
    const props = this.props;
    const state = this.state;
    const container = document.getElementById('cy-container');
    state.cy.mount(container);
  }

  toggleDrawer() {
    this.setState({drawerOpen: !this.state.drawerOpen});
  }

  createEnrichmentTable() {
    const state = this.state;
    const enrichmentTable = {};

    const enrichmentClasses = state.enrichmentClasses;
    const header = _.uniq(state.enrichmentClasses);

    enrichmentTable.header = header;
    enrichmentTable.rows = _.get(state.enrichmentDataSets, '0.expressions', []).map(enrichment => {
      const geneName = enrichment.geneName;
      const values = enrichment.values;

      const class2ValuesMap = new Map();

      for (let enrichmentClass of header) {
        class2ValuesMap.set(enrichmentClass, []);
      }

      for (let i = 0; i < values.length; i++) {
        class2ValuesMap.get(enrichmentClasses[i]).push(values[i]);
      }

      return { geneName: geneName, classValues: Array.from(class2ValuesMap.entries()).map((entry =>  _.mean(entry[1]).toFixed(2))) };
    });

    return enrichmentTable;
  }

  render() {
    const state = this.state;

    const enrichmentTable = state.enrichmentTable;

    const networkNodes = state.cy.nodes().map(node => node.data('label'));
    const enrichmentsInNetwork = _.get(enrichmentTable, 'rows', []).filter(row => networkNodes.includes(row.geneName));

    const maxVal = _.max(enrichmentsInNetwork.map(row => _.max(row.classValues)).map((k, v) => parseFloat(k)));
    const minVal = _.min(enrichmentsInNetwork.map(row => _.min(row.classValues)).map((k, v) => parseFloat(k)));

    const enrichmentTableHeader = [h('th', '')].concat(_.get(enrichmentTable, 'header', []).map(column => h('th', column)));
    const enrichmentTableRows = _.sortBy(
      _.get(enrichmentTable, 'rows', []), (o) => o.geneName
    ).map(row => h('tr',[h('td', row.geneName)].concat(row.classValues.map(cv => h('td', cv)))));

    return h('div.paint', [
      h('div.paint-content', [
        h('div', { className: classNames('paint-drawer', !state.drawerOpen ? 'closed' : '') }, [
          h('a', { onClick: e => this.toggleDrawer()}, [
            h(Icon, { icon: 'close'}),
          ]),
          h('div.paint-legend', [
            h('p', `low ${minVal}`),
            h('p', `high ${maxVal}`)
          ]),
          h('p', `columns correspond to the clockwise direction on the pie (first column starts at 12 O'Clock going clockwise)`),
          h('table', [
            h('thead', [
              h('tr', enrichmentTableHeader)
            ]),
            h('tbody', enrichmentTableRows)
          ])

        ]),
        h('div.paint-omnibar', [
          h('a', { onClick: e => this.toggleDrawer() }, [
            h(Icon, { icon: 'menu' }, 'click')
          ]),
          h('h5', `${state.name} | ${state.datasource}`)
        ]),
        h('div.paint-graph', [
          h(`div.#cy-container`, {style: {width: '100vw', height: '100vh'}})
        ])
      ])
    ]);
  }
}

module.exports = Paint;<commit_msg>Add different colour mapping functions (WIP)<commit_after>const React = require('react');
const h = require('react-hyperscript');
const queryString = require('query-string');
const color = require('color');
const _ = require('lodash');
const classNames = require('classnames');

const cytoscape = require('cytoscape');
const cose = require('cytoscape-cose-bilkent');
cytoscape.use(cose);

const sbgn2Json = require('sbgnml-to-cytoscape');
const sbgnStylesheet = require('cytoscape-sbgn-stylesheet');

const Icon = require('../../common/components').Icon;
const PathwayCommonsService = require('../../services').PathwayCommonsService;

// const testData = require('./sample-enrichments');

const augmentEnrichmentData = require('./enrichment-model');

class Paint extends React.Component {
  constructor(props) {
    super(props);

    const cy = cytoscape({
      style: sbgnStylesheet(cytoscape),
      minZoom: 0.16,
      maxZoom: 4,
      headless: true
    });

    this.state = {
      enrichmentDataSets: [],
      enrichmentClasses: [],
      // enrichmentDataSets: testData.dataSetExpressionList,
      // enrichmentClasses: _.get(testData.dataSetClassList, '0.classes', []),
      enrichmentTable: {},
      cy: cy,
      name: '',
      datasource: '',
      drawerOpen: false
    };

    const query = queryString.parse(props.location.search);
    const enrichmentsURI = query.uri ? query.uri : null;

    if (enrichmentsURI != null) {
      fetch(enrichmentsURI)
        .then(response => response.json())
        .then(json => {
          // console.log(augmentEnrichmentData(json.dataSetClassList, json.dataSetExpressionList));
          this.setState({
            enrichmentClasses: _.get(json.dataSetClassList, '0.classes', []),
            enrichmentDataSets: json.dataSetExpressionList
          }, () => {
          });
        });
    }

    const expressions = _.get(this.state.dataSetExpressionList, '0.expressions', []);
    const searchParam = query.q ? query.q : 'S Phase';
    this.initPainter(expressions, searchParam);

  }

  componentWillUnmount() {
    this.state.cy.destroy();
  }

  percentToColour(val, min, max) {
    const distToMax = Math.abs(val - max);
    const distToMin = Math.abs(val - min);

    let hVal, lVal;
    if (distToMax > distToMin) {
      hVal = 240;
      lVal = ( val / Math.abs(max) ) * 100 + 20;
    } else {
      hVal = 0;
      lVal = ( val / Math.abs(max) ) * 100 - 20;
    }
    return color.hsl(hVal, 100, lVal).string();
  }

  colourMap(percent) {
    const hslValue = ( 1 - percent ) * 240;

    return color.hsl(hslValue, 100, 50).string();
  }

  // only call this after you know component is mounted
  initPainter(expressions, queryParam) {
    const state = this.state;
    const query = {
      q: queryParam,
      gt: 2,
      lt: 100,
      type: 'Pathway',
      datasource: 'reactome'
    };

    PathwayCommonsService.querySearch(query)
      .then(searchResults => {
        const uri = _.get(searchResults, '0.uri', null);
        if (uri != null) {
          PathwayCommonsService.query(uri, 'json', 'Named/displayName')
          .then(response => {
            this.setState({
              name: response ? response.traverseEntry[0].value.pop() : ''
            });
          });

        PathwayCommonsService.query(uri, 'json', 'Entity/dataSource/displayName')
          .then(responseObj => {
            this.setState({
              datasource: responseObj ? responseObj.traverseEntry[0].value.pop() : ''
            });
          });

        PathwayCommonsService.query(uri, 'SBGN')
          .then(text => {
            const sbgnJson = sbgn2Json(text);
            state.cy.remove('*');
            state.cy.add(sbgnJson);
            state.cy.layout({
              name: 'cose-bilkent',
              nodeDimensionsIncludeLabels: true
            }).run();

            const enrichmentTable = this.createEnrichmentTable();

            const networkNodes = state.cy.nodes().map(node => node.data('label'));
            const enrichmentsInNetwork = enrichmentTable.rows.filter(row => networkNodes.includes(row.geneName));
            const maxVal = _.max(enrichmentsInNetwork.map(row => _.max(row.classValues)).map((k, v) => parseFloat(k)));
            const minVal = _.min(enrichmentsInNetwork.map(row => _.min(row.classValues)).map((k, v) => parseFloat(k)));

            enrichmentsInNetwork.forEach(row => {
              // probably more efficient to add the enrichment data to the node field instead of interating twice
              state.cy.nodes().filter(node => node.data('label') === row.geneName).forEach(node => {

                const numSlices = row.classValues.length > 16 ? 16 : row.classValues.length;

                const pieStyle = {
                  'pie-size': '100%'
                };
                for (let i = 1; i <= numSlices; i++) {

                  pieStyle['pie-' + i + '-background-size'] = 100 / numSlices;
                  pieStyle['pie-' + i + '-background-opacity'] = 1;
                  pieStyle['pie-' + i + '-background-color'] = this.percentToColour(row.classValues[i-1] / maxVal);
                }

                node.style(pieStyle);
              });

              this.setState({enrichmentTable: enrichmentTable});

            });
          });
        }
      });
  }

  componentDidMount() {
    const props = this.props;
    const state = this.state;
    const container = document.getElementById('cy-container');
    state.cy.mount(container);
  }

  toggleDrawer() {
    this.setState({drawerOpen: !this.state.drawerOpen});
  }

  createEnrichmentTable() {
    const state = this.state;
    const enrichmentTable = {};

    const enrichmentClasses = state.enrichmentClasses;
    const header = _.uniq(state.enrichmentClasses);

    enrichmentTable.header = header;
    enrichmentTable.rows = _.get(state.enrichmentDataSets, '0.expressions', []).map(enrichment => {
      const geneName = enrichment.geneName;
      const values = enrichment.values;

      const class2ValuesMap = new Map();

      for (let enrichmentClass of header) {
        class2ValuesMap.set(enrichmentClass, []);
      }

      for (let i = 0; i < values.length; i++) {
        class2ValuesMap.get(enrichmentClasses[i]).push(values[i]);
      }

      return { geneName: geneName, classValues: Array.from(class2ValuesMap.entries()).map((entry =>  _.mean(entry[1]).toFixed(2))) };
    });

    return enrichmentTable;
  }

  render() {
    const state = this.state;

    const enrichmentTable = state.enrichmentTable;

    const networkNodes = state.cy.nodes().map(node => node.data('label'));
    const enrichmentsInNetwork = _.get(enrichmentTable, 'rows', []).filter(row => networkNodes.includes(row.geneName));

    const maxVal = _.max(enrichmentsInNetwork.map(row => _.max(row.classValues)).map((k, v) => parseFloat(k)));
    const minVal = _.min(enrichmentsInNetwork.map(row => _.min(row.classValues)).map((k, v) => parseFloat(k)));

    const enrichmentTableHeader = [h('th', '')].concat(_.get(enrichmentTable, 'header', []).map(column => h('th', column)));
    const enrichmentTableRows = _.sortBy(
      _.get(enrichmentTable, 'rows', []), (o) => o.geneName
    ).map(row => h('tr',[h('td', row.geneName)].concat(row.classValues.map(cv => h('td', cv)))));

    return h('div.paint', [
      h('div.paint-content', [
        h('div', { className: classNames('paint-drawer', !state.drawerOpen ? 'closed' : '') }, [
          h('a', { onClick: e => this.toggleDrawer()}, [
            h(Icon, { icon: 'close'}),
          ]),
          h('div.paint-legend', [
            h('p', `low ${minVal}`),
            h('p', `high ${maxVal}`)
          ]),
          h('p', `columns correspond to the clockwise direction on the pie (first column starts at 12 O'Clock going clockwise)`),
          h('table', [
            h('thead', [
              h('tr', enrichmentTableHeader)
            ]),
            h('tbody', enrichmentTableRows)
          ])

        ]),
        h('div.paint-omnibar', [
          h('a', { onClick: e => this.toggleDrawer() }, [
            h(Icon, { icon: 'menu' }, 'click')
          ]),
          h('h5', `${state.name} | ${state.datasource}`)
        ]),
        h('div.paint-graph', [
          h(`div.#cy-container`, {style: {width: '100vw', height: '100vh'}})
        ])
      ])
    ]);
  }
}

module.exports = Paint;<|endoftext|>