<commit_before>const path = require('path');
const parser = require(path.join('..', 'orchestra-parser.js'));
const lexer = parser.lexer;
const SymbolTable = require(path.join('..', 'symbol-table.js'));

describe('Csound orchestra lexer', () => {
  it('is defined', () => {
    expect(lexer).toBeDefined();
  });

  function tokens(string) {
    const tokens = [];
    lexer.setInput(string);
    Object.assign(lexer.symbolTable.identifiers, SymbolTable.builtInOpcodeSymbolTable.identifiers);
    while (!lexer.done) {
      tokens.push(parser.terminals_[lexer.lex()]);
    }
    if (tokens[tokens.length - 1] === 'EOF')
      tokens.pop();
    return tokens;
  }

  // The tests of expressions are based on tests in
  // https://github.com/python/cpython/blob/master/Lib/test/test_grammar.py
  // and
  // https://github.com/python/cpython/blob/master/Lib/test/test_tokenize.py.

  it('lexes numbers', () => {
    expect(tokens('3.14159')).toEqual(['NUMBER']);
    expect(tokens('314159.')).toEqual(['NUMBER']);
    expect(tokens('.314159')).toEqual(['NUMBER']);
    expect(tokens('3e14159')).toEqual(['NUMBER']);
    expect(tokens('3e-1415')).toEqual(['NUMBER']);
    expect(tokens('3.14e15')).toEqual(['NUMBER']);
  });

  it('lexes strings', () => {
    expect(tokens('"" {{}}')).toEqual(['STRING', 'STRING']);
    expect(tokens('"{{\\"" {{"}}')).toEqual(['STRING', 'STRING']);
    expect(tokens('{{\n}}')).toEqual(['STRING']);
  });

  // https://github.com/csound/csound/issues/661
  it('lexes quoted string ending with escaped backslash', () => {
    expect(tokens('"x\\\\"')).toEqual(['STRING']);
  });

  it('lexes unary expressions', () => {
    expect(tokens('+1')).toEqual(['+', 'DECIMAL_INTEGER']);
    expect(tokens('-1')).toEqual(['-', 'DECIMAL_INTEGER']);
    expect(tokens('!1')).toEqual(['!', 'DECIMAL_INTEGER']);
    expect(tokens('~1')).toEqual(['~', 'DECIMAL_INTEGER']);
    expect(tokens('¬1')).toEqual(['~', 'DECIMAL_INTEGER']);
    expect(tokens('iValue = +-!~1')).toEqual(['IDENTIFIER', '=', '+', '-', '!', '~', 'DECIMAL_INTEGER']);
  });

  it('lexes multiplicative expressions', () => {
    expect(tokens('1 * 1')).toEqual(['DECIMAL_INTEGER', '*', 'DECIMAL_INTEGER']);
    expect(tokens('1 / 1')).toEqual(['DECIMAL_INTEGER', '/', 'DECIMAL_INTEGER']);
    expect(tokens('1 % 1')).toEqual(['DECIMAL_INTEGER', '%', 'DECIMAL_INTEGER']);
    expect(tokens('1 ^ 1')).toEqual(['DECIMAL_INTEGER', '^', 'DECIMAL_INTEGER']);
    expect(tokens('iValue = 1*1/1^5%0x12')).toEqual(['IDENTIFIER', '=', 'DECIMAL_INTEGER', '*', 'DECIMAL_INTEGER', '/', 'DECIMAL_INTEGER', '^', 'DECIMAL_INTEGER', '%', 'NUMBER']);
  });

  it('lexes additive expressions', () => {
    expect(tokens('1 + 1')).toEqual(['DECIMAL_INTEGER', '+', 'DECIMAL_INTEGER']);
    expect(tokens('1 - 1 - 1')).toEqual(['DECIMAL_INTEGER', '-', 'DECIMAL_INTEGER', '-', 'DECIMAL_INTEGER']);
    expect(tokens('i1 = 1 - i2 + 15 - 1 + 0x124 + i3 + i4[5]')).toEqual(['IDENTIFIER', '=', 'DECIMAL_INTEGER', '-', 'IDENTIFIER', '+', 'DECIMAL_INTEGER', '-', 'DECIMAL_INTEGER', '+', 'NUMBER', '+', 'IDENTIFIER', '+', 'IDENTIFIER', '[', 'DECIMAL_INTEGER', ']']);
  });

  it('lexes shift expressions', () => {
    expect(tokens('1 << 1')).toEqual(['DECIMAL_INTEGER', '<<', 'DECIMAL_INTEGER']);
    expect(tokens('1 >> 1')).toEqual(['DECIMAL_INTEGER', '>>', 'DECIMAL_INTEGER']);
    expect(tokens('iValue = 1 << 1 >> 5')).toEqual(['IDENTIFIER', '=', 'DECIMAL_INTEGER', '<<', 'DECIMAL_INTEGER', '>>', 'DECIMAL_INTEGER']);
  });

  it('lexes bitwise expressions', () => {
    expect(tokens('1 & 1')).toEqual(['DECIMAL_INTEGER', '&', 'DECIMAL_INTEGER']);
    expect(tokens('1 # 1')).toEqual(['DECIMAL_INTEGER', '#', 'DECIMAL_INTEGER']);
    expect(tokens('1 | 1')).toEqual(['DECIMAL_INTEGER', '|', 'DECIMAL_INTEGER']);
    expect(tokens('~1 # 1 & 1 |1 # ¬0x1')).toEqual(['~', 'DECIMAL_INTEGER', '#', 'DECIMAL_INTEGER', '&', 'DECIMAL_INTEGER', '|', 'DECIMAL_INTEGER', '#', '~', 'NUMBER']);
  });

  it('lexes comparison expressions', () => {
    expect(tokens('1 == 1')).toEqual(['DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER']);
    expect(tokens('1 != 1')).toEqual(['DECIMAL_INTEGER', '!=', 'DECIMAL_INTEGER']);
    expect(tokens('1 < 1')).toEqual(['DECIMAL_INTEGER', '<', 'DECIMAL_INTEGER']);
    expect(tokens('1 > 1')).toEqual(['DECIMAL_INTEGER', '>', 'DECIMAL_INTEGER']);
    expect(tokens('1 <= 1')).toEqual(['DECIMAL_INTEGER', '<=', 'DECIMAL_INTEGER']);
    expect(tokens('1 >= 1')).toEqual(['DECIMAL_INTEGER', '>=', 'DECIMAL_INTEGER']);
    expect(tokens('1 && 1')).toEqual(['DECIMAL_INTEGER', '&&', 'DECIMAL_INTEGER']);
    expect(tokens('1 || 1')).toEqual(['DECIMAL_INTEGER', '||', 'DECIMAL_INTEGER']);
    expect(tokens('1 < 1 > 1 == 1 >= 5 <= 0x15 != 1 && 1 || 1')).toEqual(['DECIMAL_INTEGER', '<', 'DECIMAL_INTEGER', '>', 'DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER', '>=', 'DECIMAL_INTEGER', '<=', 'NUMBER', '!=', 'DECIMAL_INTEGER', '&&', 'DECIMAL_INTEGER', '||', 'DECIMAL_INTEGER']);
  });

  it('lexes assignment expressions', () => {
    expect(tokens('iValue = 1')).toEqual(['IDENTIFIER', '=', 'DECIMAL_INTEGER']);
    expect(tokens('iValue += 1')).toEqual(['IDENTIFIER', '+=', 'DECIMAL_INTEGER']);
    expect(tokens('iValue -= 1')).toEqual(['IDENTIFIER', '-=', 'DECIMAL_INTEGER']);
    expect(tokens('iValue *= 1')).toEqual(['IDENTIFIER', '*=', 'DECIMAL_INTEGER']);
    expect(tokens('iValue /= 1')).toEqual(['IDENTIFIER', '/=', 'DECIMAL_INTEGER']);
  });

  it('lexes conditional expression', () => {
    expect(tokens('label: 0 == 1 ? 0 : 1')).toEqual(['LABEL', 'DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER', '?', 'DECIMAL_INTEGER', ':', 'DECIMAL_INTEGER']);
  });

  it('lexes keywords', () => {
    expect(tokens('do')).toEqual(['DO']);
    expect(tokens('else')).toEqual(['ELSE']);
    expect(tokens('elseif')).toEqual(['ELSEIF']);
    expect(tokens('endif')).toEqual(['ENDIF']);
    expect(tokens('endin')).toEqual(['ENDIN']);
    expect(tokens('enduntil')).toEqual(['OD']);
    expect(tokens('fi')).toEqual(['ENDIF']);
    expect(tokens('goto')).toEqual(['GOTO']);
    expect(tokens('if')).toEqual(['IF']);
    expect(tokens('igoto')).toEqual(['GOTO']);
    expect(tokens('instr')).toEqual(['INSTR']);
    expect(tokens('ithen')).toEqual(['THEN']);
    expect(tokens('kgoto')).toEqual(['GOTO']);
    expect(tokens('kthen')).toEqual(['THEN']);
    expect(tokens('od')).toEqual(['OD']);
    expect(tokens('then')).toEqual(['THEN']);
    expect(tokens('until')).toEqual(['UNTIL']);
    expect(tokens('while')).toEqual(['WHILE']);
  });

  it('warns about ‘fi’ ending if statement', () => {
    expect(tokens(`if 1 == 1 then\nfi\n`)).toEqual(['IF', 'DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER', 'THEN', 'NEWLINE', 'ENDIF', 'NEWLINE']);
    expect(lexer.messages.length).toBe(1);
    expect(lexer.messages[0]).toEqual({
      type: 'Warning',
      text: '‘fi’ instead of ‘endif’ used to end if statement',
      range: [[1, 0], [1, 2]]
    });
  });

  it('warns about ‘enduntil’ ending loop', () => {
    expect(tokens(`while 1 == 1 do\nenduntil\n`)).toEqual(['WHILE', 'DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER', 'DO', 'NEWLINE', 'OD', 'NEWLINE']);
    expect(lexer.messages.length).toBe(1);
    expect(lexer.messages[0]).toEqual({
      type: 'Warning',
      text: '‘enduntil’ instead of ‘od’ used to end loop',
      range: [[1, 0], [1, 8]]
    });
  });

  it('lexes labels', () => {
    const labelName = 'label';
    expect(tokens(`${labelName}:`)).toEqual(['LABEL']);
    expect(lexer.symbolTable.labels[labelName]).toBeDefined();
    expect(tokens('label: 0dbfs = 1\n')).toEqual(['LABEL', 'GLOBAL_VALUE_IDENTIFIER', '=', 'DECIMAL_INTEGER', 'NEWLINE']);
    expect(tokens('label:\n0dbfs = 1\n')).toEqual(['LABEL', 'GLOBAL_VALUE_IDENTIFIER', '=', 'DECIMAL_INTEGER', 'NEWLINE']);
  });

  // https://github.com/csound/csound/issues/670
  it('lexes labeled statement', () => {
    expect(tokens('label: 0dbfs = 1\n')).toEqual(['LABEL', 'GLOBAL_VALUE_IDENTIFIER', '=', 'DECIMAL_INTEGER', 'NEWLINE']);
  });

  it('warns about duplicate label', () => {
    expect(tokens(`label:\nlabel:\n`)).toEqual(['LABEL', 'LABEL']);
    expect(lexer.messages.length).toBe(1);
    expect(lexer.messages[0]).toEqual({
      type: 'Warning',
      text: 'Duplicate label ‘label’ ignored',
      range: [[1, 0], [1, 5]],
      trace: [{
        type: 'Trace',
        text: 'Label ‘label’ is defined here',
        range: [[0, 0], [0, 5]]
      }]
    });
  });

  it('lexes instrument definition', () => {
    expect(tokens(`
      instr 1 , name_1 , +name_2
      endin
    `)).toEqual(['NEWLINE', 'INSTR', 'DECIMAL_INTEGER', ',', 'IDENTIFIER', ',', '+', 'IDENTIFIER', 'NEWLINE', 'ENDIN', 'NEWLINE']);
    expect(lexer.messages.length).toBe(0);
  });

  it('lexes unexpected character after instr keyword', () => {
    try {
      tokens('instr ?\nendin\n');
      fail('Expected exception.');
    } catch (error) {
      expect(error.lintMessage).toEqual({
        type: 'Error',
        text: 'Expected instrument number or identifier',
        range: [[0, 6], [0, 6]]
      });
    }
  });

  it('lexes opcode definition', () => {
    const opcodeName = 'name_0';
    expect(tokens(`
      opcode ${opcodeName} , 0 , 0
      endop
    `)).toEqual(['NEWLINE', 'OPCODE', 'IDENTIFIER', ',', 'OPCODE_OUTPUT_TYPE_SIGNATURE', ',', 'OPCODE_INPUT_TYPE_SIGNATURE', 'NEWLINE', 'ENDOP', 'NEWLINE']);
    expect(lexer.messages.length).toBe(0);
    expect(lexer.symbolTable.identifiers[opcodeName]).toBeDefined();
  });

  it('lexes global value identifiers', () => {
    expect(tokens('0dbfs')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('A4')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('kr')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('ksmps')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('nchnls')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('nchnls_i')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('sr')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
  });

  it('lexes orchestra', () => {
    expect(tokens(`
      0dbfs = 1
      giFunctionTableID ftgen 0, 0, 16384, 10, 1
      instr A440
        outc oscili(0.5 * 0dbfs, 440, giFunctionTableID)
      endin
    `)).toEqual([
      'NEWLINE',
      'GLOBAL_VALUE_IDENTIFIER', '=', 'DECIMAL_INTEGER', 'NEWLINE',
      'IDENTIFIER', 'OPCODE', 'DECIMAL_INTEGER', ',', 'DECIMAL_INTEGER', ',', 'DECIMAL_INTEGER', ',', 'DECIMAL_INTEGER', ',', 'DECIMAL_INTEGER', 'NEWLINE',
      'INSTR', 'IDENTIFIER', 'NEWLINE',
      'VOID_OPCODE', 'OPCODE', '(', 'NUMBER', '*', 'GLOBAL_VALUE_IDENTIFIER', ',', 'DECIMAL_INTEGER', ',', 'IDENTIFIER', ')', 'NEWLINE',
      'ENDIN', 'NEWLINE'
    ]);
  });

  // https://github.com/csound/csound/issues/649
  it('lexes unexpected characters', () => {
    expect(tokens(`
      instr 1
        prints "hello, world\n"
        \`@.\\$•🎹
      endin
    `)).toEqual(['NEWLINE', 'INSTR', 'DECIMAL_INTEGER', 'NEWLINE', 'VOID_OPCODE', 'STRING', 'NEWLINE', 'NEWLINE', 'ENDIN', 'NEWLINE']);
    expect(lexer.messages.length).toBe(8);
    expect(lexer.messages[0]).toEqual({
      type: 'Error',
      text: 'Unexpected character ‘`’',
      range: [[4, 8], [4, 9]]
    });
  });
});
<commit_msg>Fix test<commit_after>const path = require('path');
const parser = require(path.join('..', 'orchestra-parser.js'));
const lexer = parser.lexer;
const SymbolTable = require(path.join('..', 'symbol-table.js'));

describe('Csound orchestra lexer', () => {
  it('is defined', () => {
    expect(lexer).toBeDefined();
  });

  function tokens(string) {
    const tokens = [];
    lexer.setInput(string);
    Object.assign(lexer.symbolTable.identifiers, SymbolTable.builtInOpcodeSymbolTable.identifiers);
    while (!lexer.done) {
      tokens.push(parser.terminals_[lexer.lex()]);
    }
    if (tokens[tokens.length - 1] === 'EOF')
      tokens.pop();
    return tokens;
  }

  // The tests of expressions are based on tests in
  // https://github.com/python/cpython/blob/master/Lib/test/test_grammar.py
  // and
  // https://github.com/python/cpython/blob/master/Lib/test/test_tokenize.py.

  it('lexes numbers', () => {
    expect(tokens('3.14159')).toEqual(['NUMBER']);
    expect(tokens('314159.')).toEqual(['NUMBER']);
    expect(tokens('.314159')).toEqual(['NUMBER']);
    expect(tokens('3e14159')).toEqual(['NUMBER']);
    expect(tokens('3e-1415')).toEqual(['NUMBER']);
    expect(tokens('3.14e15')).toEqual(['NUMBER']);
  });

  it('lexes strings', () => {
    expect(tokens('"" {{}}')).toEqual(['STRING', 'STRING']);
    expect(tokens('"{{\\"" {{"}}')).toEqual(['STRING', 'STRING']);
    expect(tokens('{{\n}}')).toEqual(['STRING']);
  });

  // https://github.com/csound/csound/issues/661
  it('lexes quoted string ending with escaped backslash', () => {
    expect(tokens('"x\\\\"')).toEqual(['STRING']);
  });

  it('lexes unary expressions', () => {
    expect(tokens('+1')).toEqual(['+', 'DECIMAL_INTEGER']);
    expect(tokens('-1')).toEqual(['-', 'DECIMAL_INTEGER']);
    expect(tokens('!1')).toEqual(['!', 'DECIMAL_INTEGER']);
    expect(tokens('~1')).toEqual(['~', 'DECIMAL_INTEGER']);
    expect(tokens('¬1')).toEqual(['~', 'DECIMAL_INTEGER']);
    expect(tokens('iValue = +-!~1')).toEqual(['IDENTIFIER', '=', '+', '-', '!', '~', 'DECIMAL_INTEGER']);
  });

  it('lexes multiplicative expressions', () => {
    expect(tokens('1 * 1')).toEqual(['DECIMAL_INTEGER', '*', 'DECIMAL_INTEGER']);
    expect(tokens('1 / 1')).toEqual(['DECIMAL_INTEGER', '/', 'DECIMAL_INTEGER']);
    expect(tokens('1 % 1')).toEqual(['DECIMAL_INTEGER', '%', 'DECIMAL_INTEGER']);
    expect(tokens('1 ^ 1')).toEqual(['DECIMAL_INTEGER', '^', 'DECIMAL_INTEGER']);
    expect(tokens('iValue = 1*1/1^5%0x12')).toEqual(['IDENTIFIER', '=', 'DECIMAL_INTEGER', '*', 'DECIMAL_INTEGER', '/', 'DECIMAL_INTEGER', '^', 'DECIMAL_INTEGER', '%', 'NUMBER']);
  });

  it('lexes additive expressions', () => {
    expect(tokens('1 + 1')).toEqual(['DECIMAL_INTEGER', '+', 'DECIMAL_INTEGER']);
    expect(tokens('1 - 1 - 1')).toEqual(['DECIMAL_INTEGER', '-', 'DECIMAL_INTEGER', '-', 'DECIMAL_INTEGER']);
    expect(tokens('i1 = 1 - i2 + 15 - 1 + 0x124 + i3 + i4[5]')).toEqual(['IDENTIFIER', '=', 'DECIMAL_INTEGER', '-', 'IDENTIFIER', '+', 'DECIMAL_INTEGER', '-', 'DECIMAL_INTEGER', '+', 'NUMBER', '+', 'IDENTIFIER', '+', 'IDENTIFIER', '[', 'DECIMAL_INTEGER', ']']);
  });

  it('lexes shift expressions', () => {
    expect(tokens('1 << 1')).toEqual(['DECIMAL_INTEGER', '<<', 'DECIMAL_INTEGER']);
    expect(tokens('1 >> 1')).toEqual(['DECIMAL_INTEGER', '>>', 'DECIMAL_INTEGER']);
    expect(tokens('iValue = 1 << 1 >> 5')).toEqual(['IDENTIFIER', '=', 'DECIMAL_INTEGER', '<<', 'DECIMAL_INTEGER', '>>', 'DECIMAL_INTEGER']);
  });

  it('lexes bitwise expressions', () => {
    expect(tokens('1 & 1')).toEqual(['DECIMAL_INTEGER', '&', 'DECIMAL_INTEGER']);
    expect(tokens('1 # 1')).toEqual(['DECIMAL_INTEGER', '#', 'DECIMAL_INTEGER']);
    expect(tokens('1 | 1')).toEqual(['DECIMAL_INTEGER', '|', 'DECIMAL_INTEGER']);
    expect(tokens('~1 # 1 & 1 |1 # ¬0x1')).toEqual(['~', 'DECIMAL_INTEGER', '#', 'DECIMAL_INTEGER', '&', 'DECIMAL_INTEGER', '|', 'DECIMAL_INTEGER', '#', '~', 'NUMBER']);
  });

  it('lexes comparison expressions', () => {
    expect(tokens('1 == 1')).toEqual(['DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER']);
    expect(tokens('1 != 1')).toEqual(['DECIMAL_INTEGER', '!=', 'DECIMAL_INTEGER']);
    expect(tokens('1 < 1')).toEqual(['DECIMAL_INTEGER', '<', 'DECIMAL_INTEGER']);
    expect(tokens('1 > 1')).toEqual(['DECIMAL_INTEGER', '>', 'DECIMAL_INTEGER']);
    expect(tokens('1 <= 1')).toEqual(['DECIMAL_INTEGER', '<=', 'DECIMAL_INTEGER']);
    expect(tokens('1 >= 1')).toEqual(['DECIMAL_INTEGER', '>=', 'DECIMAL_INTEGER']);
    expect(tokens('1 && 1')).toEqual(['DECIMAL_INTEGER', '&&', 'DECIMAL_INTEGER']);
    expect(tokens('1 || 1')).toEqual(['DECIMAL_INTEGER', '||', 'DECIMAL_INTEGER']);
    expect(tokens('1 < 1 > 1 == 1 >= 5 <= 0x15 != 1 && 1 || 1')).toEqual(['DECIMAL_INTEGER', '<', 'DECIMAL_INTEGER', '>', 'DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER', '>=', 'DECIMAL_INTEGER', '<=', 'NUMBER', '!=', 'DECIMAL_INTEGER', '&&', 'DECIMAL_INTEGER', '||', 'DECIMAL_INTEGER']);
  });

  it('lexes assignment expressions', () => {
    expect(tokens('iValue = 1')).toEqual(['IDENTIFIER', '=', 'DECIMAL_INTEGER']);
    expect(tokens('iValue += 1')).toEqual(['IDENTIFIER', '+=', 'DECIMAL_INTEGER']);
    expect(tokens('iValue -= 1')).toEqual(['IDENTIFIER', '-=', 'DECIMAL_INTEGER']);
    expect(tokens('iValue *= 1')).toEqual(['IDENTIFIER', '*=', 'DECIMAL_INTEGER']);
    expect(tokens('iValue /= 1')).toEqual(['IDENTIFIER', '/=', 'DECIMAL_INTEGER']);
  });

  it('lexes conditional expression', () => {
    expect(tokens('label: 0 == 1 ? 0 : 1')).toEqual(['LABEL', 'DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER', '?', 'DECIMAL_INTEGER', ':', 'DECIMAL_INTEGER']);
  });

  it('lexes keywords', () => {
    expect(tokens('do')).toEqual(['DO']);
    expect(tokens('else')).toEqual(['ELSE']);
    expect(tokens('elseif')).toEqual(['ELSEIF']);
    expect(tokens('endif')).toEqual(['ENDIF']);
    expect(tokens('endin')).toEqual(['ENDIN']);
    expect(tokens('enduntil')).toEqual(['OD']);
    expect(tokens('fi')).toEqual(['ENDIF']);
    expect(tokens('goto')).toEqual(['GOTO']);
    expect(tokens('if')).toEqual(['IF']);
    expect(tokens('igoto')).toEqual(['GOTO']);
    expect(tokens('instr')).toEqual(['INSTR']);
    expect(tokens('ithen')).toEqual(['THEN']);
    expect(tokens('kgoto')).toEqual(['GOTO']);
    expect(tokens('kthen')).toEqual(['THEN']);
    expect(tokens('od')).toEqual(['OD']);
    expect(tokens('then')).toEqual(['THEN']);
    expect(tokens('until')).toEqual(['UNTIL']);
    expect(tokens('while')).toEqual(['WHILE']);
  });

  it('warns about ‘fi’ ending if statement', () => {
    expect(tokens(`if 1 == 1 then\nfi\n`)).toEqual(['IF', 'DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER', 'THEN', 'NEWLINE', 'ENDIF', 'NEWLINE']);
    expect(lexer.messages.length).toBe(1);
    expect(lexer.messages[0]).toEqual({
      type: 'Warning',
      text: '‘fi’ instead of ‘endif’ used to end if statement',
      range: [[1, 0], [1, 2]]
    });
  });

  it('warns about ‘enduntil’ ending loop', () => {
    expect(tokens(`while 1 == 1 do\nenduntil\n`)).toEqual(['WHILE', 'DECIMAL_INTEGER', '==', 'DECIMAL_INTEGER', 'DO', 'NEWLINE', 'OD', 'NEWLINE']);
    expect(lexer.messages.length).toBe(1);
    expect(lexer.messages[0]).toEqual({
      type: 'Warning',
      text: '‘enduntil’ instead of ‘od’ used to end loop',
      range: [[1, 0], [1, 8]]
    });
  });

  it('lexes labels', () => {
    const labelName = 'label';
    expect(tokens(`${labelName}:`)).toEqual(['LABEL']);
    expect(lexer.symbolTable.labels[labelName]).toBeDefined();
    expect(tokens('label: 0dbfs = 1\n')).toEqual(['LABEL', 'GLOBAL_VALUE_IDENTIFIER', '=', 'DECIMAL_INTEGER', 'NEWLINE']);
    expect(tokens('label:\n0dbfs = 1\n')).toEqual(['LABEL', 'GLOBAL_VALUE_IDENTIFIER', '=', 'DECIMAL_INTEGER', 'NEWLINE']);
  });

  // https://github.com/csound/csound/issues/670
  it('lexes labeled statement', () => {
    expect(tokens('label: 0dbfs = 1\n')).toEqual(['LABEL', 'GLOBAL_VALUE_IDENTIFIER', '=', 'DECIMAL_INTEGER', 'NEWLINE']);
  });

  it('warns about duplicate label', () => {
    expect(tokens(`label:\nlabel:\n`)).toEqual(['LABEL', 'LABEL']);
    expect(lexer.messages.length).toBe(1);
    expect(lexer.messages[0]).toEqual({
      type: 'Warning',
      text: 'Duplicate label ‘label’ ignored',
      range: [[1, 0], [1, 5]],
      trace: [{
        type: 'Trace',
        text: 'Label ‘label’ is here',
        range: [[0, 0], [0, 5]]
      }]
    });
  });

  it('lexes instrument definition', () => {
    expect(tokens(`
      instr 1 , name_1 , +name_2
      endin
    `)).toEqual(['NEWLINE', 'INSTR', 'DECIMAL_INTEGER', ',', 'IDENTIFIER', ',', '+', 'IDENTIFIER', 'NEWLINE', 'ENDIN', 'NEWLINE']);
    expect(lexer.messages.length).toBe(0);
  });

  it('lexes unexpected character after instr keyword', () => {
    try {
      tokens('instr ?\nendin\n');
      fail('Expected exception.');
    } catch (error) {
      expect(error.lintMessage).toEqual({
        type: 'Error',
        text: 'Expected instrument number or identifier',
        range: [[0, 6], [0, 6]]
      });
    }
  });

  it('lexes opcode definition', () => {
    const opcodeName = 'name_0';
    expect(tokens(`
      opcode ${opcodeName} , 0 , 0
      endop
    `)).toEqual(['NEWLINE', 'OPCODE', 'IDENTIFIER', ',', 'OPCODE_OUTPUT_TYPE_SIGNATURE', ',', 'OPCODE_INPUT_TYPE_SIGNATURE', 'NEWLINE', 'ENDOP', 'NEWLINE']);
    expect(lexer.messages.length).toBe(0);
    expect(lexer.symbolTable.identifiers[opcodeName]).toBeDefined();
  });

  it('lexes global value identifiers', () => {
    expect(tokens('0dbfs')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('A4')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('kr')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('ksmps')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('nchnls')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('nchnls_i')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
    expect(tokens('sr')).toEqual(['GLOBAL_VALUE_IDENTIFIER']);
  });

  it('lexes orchestra', () => {
    expect(tokens(`
      0dbfs = 1
      giFunctionTableID ftgen 0, 0, 16384, 10, 1
      instr A440
        outc oscili(0.5 * 0dbfs, 440, giFunctionTableID)
      endin
    `)).toEqual([
      'NEWLINE',
      'GLOBAL_VALUE_IDENTIFIER', '=', 'DECIMAL_INTEGER', 'NEWLINE',
      'IDENTIFIER', 'OPCODE', 'DECIMAL_INTEGER', ',', 'DECIMAL_INTEGER', ',', 'DECIMAL_INTEGER', ',', 'DECIMAL_INTEGER', ',', 'DECIMAL_INTEGER', 'NEWLINE',
      'INSTR', 'IDENTIFIER', 'NEWLINE',
      'VOID_OPCODE', 'OPCODE', '(', 'NUMBER', '*', 'GLOBAL_VALUE_IDENTIFIER', ',', 'DECIMAL_INTEGER', ',', 'IDENTIFIER', ')', 'NEWLINE',
      'ENDIN', 'NEWLINE'
    ]);
  });

  // https://github.com/csound/csound/issues/649
  it('lexes unexpected characters', () => {
    expect(tokens(`
      instr 1
        prints "hello, world\n"
        \`@.\\$•🎹
      endin
    `)).toEqual(['NEWLINE', 'INSTR', 'DECIMAL_INTEGER', 'NEWLINE', 'VOID_OPCODE', 'STRING', 'NEWLINE', 'NEWLINE', 'ENDIN', 'NEWLINE']);
    expect(lexer.messages.length).toBe(8);
    expect(lexer.messages[0]).toEqual({
      type: 'Error',
      text: 'Unexpected character ‘`’',
      range: [[4, 8], [4, 9]]
    });
  });
});
<|endoftext|>


<commit_before>/*global require:true */
require(['backbone', 'jquery'], function (Backbone, jquery) {
  $('#versions').append('
Backbone: ' + Backbone.VERSION + '
');

  var DumbView = Backbone.View.extend({
    tagName: "li",
    render: function(){
      var view = this;
      var list = $("

");
      list.append('
Length: ' + this.collection.length + '
');
      list.append('
Total Length: ' + this.collection.totalLength + '
');
      list.append('
Query options: ' + JSON.stringify(this.collection.cloudant_options) + '
');
      // Print 10 rows out to the screen
      _.each(this.collection.first(5), function(doc){
        list.append('

' + JSON.stringify(doc) + '

');
      });
      $(view.id).html(list);
    },
    initialize: function(args){
      this.collection = args.collection;
      this.collection.on("reset", this.render, this);
      this.collection.on("add", this.render, this);
    }
  });

  // Bit of a hack to load out non- require module code
  require(['backbone.cloudant'], function () {
    $('#versions').append('
Backbone.Cloudant: ' + Backbone.Cloudant.VERSION + '
');
    Backbone.Cloudant.database = "/backbone-cloudant-demo/";

    // start the change handler
    Backbone.Cloudant.changeHandler();

    var all_docs = new Backbone.Cloudant.Docs.Collection();

    var all_docs_view = new DumbView({collection: all_docs, id: '#all_docs'});

    all_docs.fetch().fail(function(){console.log('Could not load all_docs collection');});

    var view = new Backbone.Cloudant.Index();
    view.design = 'app';
    view.view = 'test';
    view.cloudant_options = {"reduce": false, "limit": 10};

    var view_view = new DumbView({collection: view, id: '#view'});

    view.fetch().fail(function(){console.log('Could not load view collection');});

    var reducedview = new Backbone.Cloudant.Index({"watch": true});
    reducedview.design = 'app';
    reducedview.view = 'test';
    reducedview.cloudant_options = {"reduce": true, "group": true};

    var reduced_view_view = new DumbView({collection: reducedview, id: '#reduced_view'});

    reducedview.fetch().fail(function(){console.log('Could not load reduced view collection');});

    var watchedview = new Backbone.Cloudant.Index({"watch": true});
    watchedview.design = 'app';
    watchedview.view = 'test';
    watchedview.cloudant_options = {"reduce": false, "limit": 10, "descending": true};

    var watchedview_view = new DumbView({collection: watchedview, id: '#watchedview'});

    watchedview.fetch().fail(function(){console.log('Could not load watched view collection');});

    var search = new Backbone.Cloudant.Search();
    search.design = 'app';
    search.index = 'mysearch';
    search.cloudant_options = {"q": "a:1", "limit": 2};

    var search_view = new DumbView({collection: search, id: '#search'});

    search.fetch().fail(function(){console.log('Could not load search collection');});

    var limited_all_docs = new Backbone.Cloudant.Docs.Collection();
    limited_all_docs.cloudant_options = {"limit": 2, "skip": 5};
    console.log(limited_all_docs);
    var limited_all_docs_view = new DumbView({collection: limited_all_docs, id: '#limited_all_docs'});

    limited_all_docs.fetch().fail(function(){console.log('Could not load all_docs collection');});

    function testFetchMore(){
      limited_all_docs.fetchMore();
      search.fetchMore();
    }
    setTimeout(testFetchMore, 3000);

    function addDocs(did){
      var doc = new Backbone.Cloudant.Model();
      doc.set("a", Math.floor(Math.random()*11));
      doc.save();

      if (did){
        var deleteMe = new Backbone.Cloudant.Model({_id:did});
        deleteMe.fetch({success: function(){
          deleteMe.destroy();
        }});
      }

      function loop(){
        addDocs(doc.id);
      }

      setTimeout(loop, 10000);
    }
    addDocs();
  });
});
<commit_msg>Making consistent<commit_after>/*global require:true */
require(['backbone', 'jquery'], function (Backbone, jquery) {
  $('#versions').append('
Backbone: ' + Backbone.VERSION + '
');

  var DumbView = Backbone.View.extend({
    tagName: "li",
    render: function(){
      var view = this;
      var list = $("

");
      list.append('
Length: ' + this.collection.length + '
');
      list.append('
Total Length: ' + this.collection.totalLength + '
');
      list.append('
Query options: ' + JSON.stringify(this.collection.cloudant_options) + '
');
      // Print 5 rows out to the screen
      _.each(this.collection.first(5), function(doc){
        list.append('

' + JSON.stringify(doc) + '

');
      });
      $(view.id).html(list);
    },
    initialize: function(args){
      this.collection = args.collection;
      this.collection.on("reset", this.render, this);
      this.collection.on("add", this.render, this);
    }
  });

  // Bit of a hack to load out non- require module code
  require(['backbone.cloudant'], function () {
    $('#versions').append('
Backbone.Cloudant: ' + Backbone.Cloudant.VERSION + '
');
    Backbone.Cloudant.database = "/backbone-cloudant-demo/";

    // start the change handler
    Backbone.Cloudant.changeHandler();

    var all_docs = new Backbone.Cloudant.Docs.Collection();

    var all_docs_view = new DumbView({collection: all_docs, id: '#all_docs'});

    all_docs.fetch().fail(function(){console.log('Could not load all_docs collection');});

    var view = new Backbone.Cloudant.Index();
    view.design = 'app';
    view.view = 'test';
    view.cloudant_options = {"reduce": false, "limit": 5};

    var view_view = new DumbView({collection: view, id: '#view'});

    view.fetch().fail(function(){console.log('Could not load view collection');});

    var reducedview = new Backbone.Cloudant.Index({"watch": true});
    reducedview.design = 'app';
    reducedview.view = 'test';
    reducedview.cloudant_options = {"reduce": true, "group": true};

    var reduced_view_view = new DumbView({collection: reducedview, id: '#reduced_view'});

    reducedview.fetch().fail(function(){console.log('Could not load reduced view collection');});

    var watchedview = new Backbone.Cloudant.Index({"watch": true});
    watchedview.design = 'app';
    watchedview.view = 'test';
    watchedview.cloudant_options = {"reduce": false, "limit": 5, "descending": true};

    var watchedview_view = new DumbView({collection: watchedview, id: '#watchedview'});

    watchedview.fetch().fail(function(){console.log('Could not load watched view collection');});

    var search = new Backbone.Cloudant.Search();
    search.design = 'app';
    search.index = 'mysearch';
    search.cloudant_options = {"q": "a:1", "limit": 2};

    var search_view = new DumbView({collection: search, id: '#search'});

    search.fetch().fail(function(){console.log('Could not load search collection');});

    var limited_all_docs = new Backbone.Cloudant.Docs.Collection();
    limited_all_docs.cloudant_options = {"limit": 2, "skip": 5};
    console.log(limited_all_docs);
    var limited_all_docs_view = new DumbView({collection: limited_all_docs, id: '#limited_all_docs'});

    limited_all_docs.fetch().fail(function(){console.log('Could not load all_docs collection');});

    function testFetchMore(){
      limited_all_docs.fetchMore();
      search.fetchMore();
    }
    setTimeout(testFetchMore, 3000);

    function addDocs(did){
      var doc = new Backbone.Cloudant.Model();
      doc.set("a", Math.floor(Math.random()*11));
      doc.save();

      if (did){
        var deleteMe = new Backbone.Cloudant.Model({_id:did});
        deleteMe.fetch({success: function(){
          deleteMe.destroy();
        }});
      }

      function loop(){
        addDocs(doc.id);
      }

      setTimeout(loop, 10000);
    }
    addDocs();
  });
});
<|endoftext|>


<commit_before>module.exports = function(conjure) {
  'use strict';

  conjure.test('r1', function() {
    this.describe('click', function() {
      this.it('should tag last step in native-click mode' , function() {
        this.conjure.click('body', true);
      });
      this.it('should tag last step in jQuery-click mode' , function() {
        this.conjure.click('body');
      });
    });

    this.describe('then', function() {
      this.it('should tag last step' , function() {
        this.conjure.then(function() {
          this.test.assertEquals(1, 1);
        });
      });
    });

    this.describe('thenOpen', function() {
      this.it('should tag last step' , function() {
        this.conjure.thenOpen('/', function() {
        });
      });
    });

    this.describe('assertSelText', function() {
      this.it('should tag last step' , function() {
        this.conjure.assertSelText('body', /.?/);
      });
    });

    this.describe('next test', function() {
      this.it('should trigger error' , function() { var a; a.b = 'foo'; });
    });
  });
};

function conjureLastStepTestNoOp() {}
<commit_msg>test(trace): Add last-step casper test<commit_after>module.exports = function(conjure) {
  'use strict';

  conjure.test('r1', function() {
    this.describe('click', function() {
      this.it('should tag last step in native-click mode' , function() {
        this.conjure.click('body', true);
      });
      this.it('should tag last step in jQuery-click mode' , function() {
        this.conjure.click('body');
      });
    });

    this.describe('then', function() {
      this.it('should tag last step' , function() {
        this.conjure.then(function() {
          this.test.assertEquals(1, 1);
        });
      });
    });

    this.describe('thenOpen', function() {
      this.it('should tag last step' , function() {
        this.conjure.thenOpen('/', function() {
        });
      });
    });

    this.describe('assertSelText', function() {
      this.it('should tag last step' , function() {
        this.conjure.assertSelText('body', /.?/);
      });
    });

    this.describe('each', function() {
      this.it('should tag last step' , function() {
        this.conjure.each([1], function() {
          this.test.assertEquals(1, 1);
        });
      });
    });

    this.describe('openHash', function() {
      this.it('should tag last step when not waiting for selector' , function() {
        this.conjure.openHash('#foo');
      });
      this.it('should tag last step when waiting for selector' , function() {
        this.conjure.openHash('#foo', 'body');
      });
    });

    this.describe('openInitUrl', function() {
      this.it('should tag last step' , function() {
        this.conjure.openInitUrl();
      });
    });

    this.describe('selectorExists', function() {
      this.it('should tag last step' , function() {
        this.conjure.selectorExists('body');
      });
    });

    this.describe('selectorMissing', function() {
      this.it('should tag last step' , function() {
        this.conjure.selectorMissing('.not-present');
      });
    });

    this.describe('sendKeys', function() {
      this.it('should tag last step' , function() {
        this.conjure.sendKeys('body', 'foo');
      });
    });

    this.describe('next test', function() {
      this.it('should trigger error' , function() { var a; a.b = 'foo'; });
    });
  });
};

function conjureLastStepTestNoOp() {}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Resin.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

const os = require('os');

module.exports = function(WarningModalService, SettingsModel) {

  /**
   * @summary Client platform
   * @type String
   * @constant
   * @public
   */
  this.platform = os.platform();

  /**
   * @summary Refresh current settings
   * @function
   * @public
   */
  this.refreshSettings = () => {
    this.currentData = SettingsModel.getAll();
  };

  /**
   * @summary Current settings value
   * @type Object
   * @public
   */
  this.currentData = {};
  this.refreshSettings();

  /**
   * @summary Settings model
   * @type Object
   * @public
   */
  this.model = SettingsModel;

  /**
   * @summary Enable a dangerous setting
   * @function
   * @public
   *
   * @param {String} name - setting name
   * @param {String} message - danger message
   * @returns {Undefined}
   *
   * @example
   * SettingsController.enableDangerousSetting('unsafeMode', 'Don\'t do this!');
   */
  this.enableDangerousSetting = (name, message) => {
    if (!this.currentData[name]) {
      this.model.set(name, false);
      return this.refreshSettings();
    }

    WarningModalService.display(message).then((userAccepted) => {
      this.model.set(name, Boolean(userAccepted));
      this.refreshSettings();
    });
  };

};
<commit_msg>minifix(GUI): keep settings checkboxes unchecked until user confirms (#821)<commit_after>/*
 * Copyright 2016 Resin.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

const os = require('os');

module.exports = function(WarningModalService, SettingsModel) {

  /**
   * @summary Client platform
   * @type String
   * @constant
   * @public
   */
  this.platform = os.platform();

  /**
   * @summary Refresh current settings
   * @function
   * @public
   */
  this.refreshSettings = () => {
    this.currentData = SettingsModel.getAll();
  };

  /**
   * @summary Current settings value
   * @type Object
   * @public
   */
  this.currentData = {};
  this.refreshSettings();

  /**
   * @summary Settings model
   * @type Object
   * @public
   */
  this.model = SettingsModel;

  /**
   * @summary Enable a dangerous setting
   * @function
   * @public
   *
   * @param {String} name - setting name
   * @param {String} message - danger message
   * @returns {Undefined}
   *
   * @example
   * SettingsController.enableDangerousSetting('unsafeMode', 'Don\'t do this!');
   */
  this.enableDangerousSetting = (name, message) => {
    if (!this.currentData[name]) {
      this.model.set(name, false);
      return this.refreshSettings();
    }

    // Keep the checkbox unchecked until the user confirms
    this.currentData[name] = false;

    WarningModalService.display(message).then((userAccepted) => {
      if (userAccepted) {
        this.model.set(name, true);
        this.refreshSettings();
      }
    });
  };

};
<|endoftext|>


<commit_before>apos.define('apostrophe-areas', {

  afterConstruct: function(self) {
    return async.series({
      getTemplates: function(callback) {
        return self.getTemplates(callback);
      }
    }, function(err) {
      self.enableCkeditor();
      self.enableOnEnhance();
      self.enableShift();
      self.enhanceAddContent();
      self.enhanceControlsHover();
      // the enhance event already happened while
      // we were waiting for our templates, so call
      // this ourselves
      self.enableAll();
    });
  },

  construct: function(self, options) {

    // When a `[data-apos-add-content]` button is clicked, toggle the `apos-active` class
    // on the closest ancestor with `[data-apos-dropdown]`, and also the closest
    // ancestor with `.apos-area-controls`.
    self.enhanceAddContent = function() {
      var $body = $('body');
      $body.on('click', '[data-apos-add-content]', function(e) {
        $(this).closest('[data-apos-dropdown]').toggleClass('apos-active');
        $(this).closest('.apos-area-controls').toggleClass('apos-active');
      });
    }

    // Handles the hovering of widgets in the specified selector or jQuery object
    // and reveals only the controls on the directly hovered widget, not the parent wrapper widget
    self.enhanceControlsHover = function(sel) {

      $(sel).find('[data-apos-widget]').addBack('[data-apos-widget]').each(function() {
        var $widget = $(this);
        mouseoverEnhance($widget);
        mouseleaveEnhance($widget);
      });

      function mouseoverEnhance($el) {
        $el.on('mouseover', function(e) {
          console.log('mouseover');
          var $self = $(this);
          e.stopPropagation();

          $('.apos-area-widget-controls').removeClass('apos-peek');
          $self.find('[data-apos-widget-controls]:first .apos-area-widget-controls').addClass('apos-peek');
        });
      };

      function mouseleaveEnhance($el) {
        $el.on('mouseleave', function(e) {
          var $self = $(this);
          $self.find('[data-apos-widget-controls]:first .apos-area-widget-controls').removeClass('apos-peek');
        });
      }

    };

    // The area editor has a number of DOM templates that
    // it clones as needed. We don't push DOM templates with
    // every page anymore, so fetch them and append them
    // to the DOM now. This is pretty much the only place
    // we still use this technique heavily.

    self.editors = {};

    self.getTemplates = function(callback) {
      $.post(self.options.action + '/editor',
        function(markup) {
          $('body').append(markup);
          return setImmediate(callback);
        }
      );
    };

    self.fromTemplate = function(sel) {
      return $('[data-apos-area-editor-templates]').find(sel).clone();
    };

    self.enableCkeditor = function() {

      // Automatic inline use of ckeditor is not suitable as it can't handle AJAX,
      // making it unsuitable for our uses, and it interferes with explicit
      // ckeditor instantiation, the only workaround for the AJAX problem.
      //
      // So we have to globally shut this off if we are active at all. If you wish
      // to make direct use of ckeditor you must do it explicitly with
      // CKEDITOR.inline(id) like we do. Hey, it's not our fault.

      CKEDITOR.disableAutoInline = true;

      // This clears the auto-populated Title attribute CKEditor puts on stuff, makes for ugly tooltips

      CKEDITOR.on('instanceReady',function(event){
        $(event.editor.element.$).attr('title', '');
      });

      CKEDITOR.plugins.addExternal('split', apos.prefix + self.options.action + '/js/ckeditorPlugins/split/', 'plugin.js');

      // This particular plugin has proven difficult for our users and therefore,
      // we're removing it for now. --Joel (joel@punkave.com)
      CKEDITOR.config.removePlugins = 'magicline';
    };

    self.enableOnEnhance = function() {
      apos.on('enhance', function($context) {
        self.enableAll($context);
      });
    };

    // Enable the areas in the specified selector or jQuery object to be edited.
    // If sel is falsy all areas currently in the body are made editable

    self.enableAll = function(sel) {
      if (!sel) {
        sel = 'body';
      }
      $(sel).find('[data-apos-area-edit]').each(function() {
        var $el = $(this);
        if ($el.attr('data-initialized')) {
          return;
        }
        var areaId = $el.attr('data-doc-id') + $el.attr('data-dot-path');
        if (_.has(self.editors, areaId)) {
          // If there is already an existing editor for this area, use that.
          self.editors[areaId].resetEl($el);
        } else {
          apos.create('apostrophe-areas-editor', { $el: $el, action: self.options.action });
        }
      });
      self.enhanceControlsHover(sel);
    };

    self.register = function(docId, dotPath, editor) {
      self.editors[docId + dotPath] = editor;
    };

    self.enableShift = function() {

      // listen for shiftActive for power up/down nudge
      apos.on('shiftDown', function() {
        $('[data-apos-move-item]').each(function() {
          $self = $(this);
          if ($self.attr('data-apos-move-item') === 'up') {
            $self.children('i').toggleClass('icon-double-angle-up');
            $self.attr('data-apos-move-item', 'top');
          } else if ($self.attr('data-apos-move-item') === 'down') {
            $self.children('i').toggleClass('icon-double-angle-down');
            $self.attr('data-apos-move-item', 'bottom');
          }
        });
      });

      apos.on('shiftUp', function() {
        $('[data-apos-move-item]').each(function() {
          $self = $(this);
          $self.children('i').removeClass('icon-double-angle-up');
          $self.children('i').removeClass('icon-double-angle-down');
          if ($self.attr('data-apos-move-item') === 'top') {
            $self.attr('data-apos-move-item', 'up');
          } else if ($self.attr('data-apos-move-item') === 'bottom') {
            $self.attr('data-apos-move-item', 'down');
          }
        });
      });
    };

    // Helper functions for getting widget data and options that don't depend
    // on the context of a specific area editor

    // Get the options that apply to the widget in its current context
    self.getWidgetOptions = function($widget) {
      var $area = $widget.closest('[data-apos-area]');
      var options = {};
      var areaOptions = self.getAreaOptions($area);
      var type = $widget.attr('data-apos-widget');
      if (areaOptions && areaOptions.widgets) {
        $.extend(true, options, areaOptions.widgets[type] || {});
      }
      return options;
    };

    self.getAreaOptions = function($area) {
      // TODO: this could be a lot of parsing done over and over
      return JSON.parse($area.attr('data-options') || '{}');
    };

    self.getWidgetData = function($widget) {
      var type = $widget.attr('data-apos-widget');
      var manager = self.getWidgetManager(type);
      if (!manager) {
        apos.log('WARNING: no manager for widget type ' + type);
        return;
      }
      return manager.getData($widget);
    };

    self.setWidgetData = function($widget, data) {
      var type = $widget.attr('data-apos-widget');
      var manager = self.getWidgetManager(type);
      if (!manager) {
        apos.log('WARNING: no manager for widget type ' + type);
        return;
      }
      return manager.setData($widget, data);
    };

  }
});
<commit_msg>run quiet<commit_after>apos.define('apostrophe-areas', {

  afterConstruct: function(self) {
    return async.series({
      getTemplates: function(callback) {
        return self.getTemplates(callback);
      }
    }, function(err) {
      self.enableCkeditor();
      self.enableOnEnhance();
      self.enableShift();
      self.enhanceAddContent();
      self.enhanceControlsHover();
      // the enhance event already happened while
      // we were waiting for our templates, so call
      // this ourselves
      self.enableAll();
    });
  },

  construct: function(self, options) {

    // When a `[data-apos-add-content]` button is clicked, toggle the `apos-active` class
    // on the closest ancestor with `[data-apos-dropdown]`, and also the closest
    // ancestor with `.apos-area-controls`.
    self.enhanceAddContent = function() {
      var $body = $('body');
      $body.on('click', '[data-apos-add-content]', function(e) {
        $(this).closest('[data-apos-dropdown]').toggleClass('apos-active');
        $(this).closest('.apos-area-controls').toggleClass('apos-active');
      });
    }

    // Handles the hovering of widgets in the specified selector or jQuery object
    // and reveals only the controls on the directly hovered widget, not the parent wrapper widget
    self.enhanceControlsHover = function(sel) {

      $(sel).find('[data-apos-widget]').addBack('[data-apos-widget]').each(function() {
        var $widget = $(this);
        mouseoverEnhance($widget);
        mouseleaveEnhance($widget);
      });

      function mouseoverEnhance($el) {
        $el.on('mouseover', function(e) {
          var $self = $(this);
          e.stopPropagation();

          $('.apos-area-widget-controls').removeClass('apos-peek');
          $self.find('[data-apos-widget-controls]:first .apos-area-widget-controls').addClass('apos-peek');
        });
      };

      function mouseleaveEnhance($el) {
        $el.on('mouseleave', function(e) {
          var $self = $(this);
          $self.find('[data-apos-widget-controls]:first .apos-area-widget-controls').removeClass('apos-peek');
        });
      }

    };

    // The area editor has a number of DOM templates that
    // it clones as needed. We don't push DOM templates with
    // every page anymore, so fetch them and append them
    // to the DOM now. This is pretty much the only place
    // we still use this technique heavily.

    self.editors = {};

    self.getTemplates = function(callback) {
      $.post(self.options.action + '/editor',
        function(markup) {
          $('body').append(markup);
          return setImmediate(callback);
        }
      );
    };

    self.fromTemplate = function(sel) {
      return $('[data-apos-area-editor-templates]').find(sel).clone();
    };

    self.enableCkeditor = function() {

      // Automatic inline use of ckeditor is not suitable as it can't handle AJAX,
      // making it unsuitable for our uses, and it interferes with explicit
      // ckeditor instantiation, the only workaround for the AJAX problem.
      //
      // So we have to globally shut this off if we are active at all. If you wish
      // to make direct use of ckeditor you must do it explicitly with
      // CKEDITOR.inline(id) like we do. Hey, it's not our fault.

      CKEDITOR.disableAutoInline = true;

      // This clears the auto-populated Title attribute CKEditor puts on stuff, makes for ugly tooltips

      CKEDITOR.on('instanceReady',function(event){
        $(event.editor.element.$).attr('title', '');
      });

      CKEDITOR.plugins.addExternal('split', apos.prefix + self.options.action + '/js/ckeditorPlugins/split/', 'plugin.js');

      // This particular plugin has proven difficult for our users and therefore,
      // we're removing it for now. --Joel (joel@punkave.com)
      CKEDITOR.config.removePlugins = 'magicline';
    };

    self.enableOnEnhance = function() {
      apos.on('enhance', function($context) {
        self.enableAll($context);
      });
    };

    // Enable the areas in the specified selector or jQuery object to be edited.
    // If sel is falsy all areas currently in the body are made editable

    self.enableAll = function(sel) {
      if (!sel) {
        sel = 'body';
      }
      $(sel).find('[data-apos-area-edit]').each(function() {
        var $el = $(this);
        if ($el.attr('data-initialized')) {
          return;
        }
        var areaId = $el.attr('data-doc-id') + $el.attr('data-dot-path');
        if (_.has(self.editors, areaId)) {
          // If there is already an existing editor for this area, use that.
          self.editors[areaId].resetEl($el);
        } else {
          apos.create('apostrophe-areas-editor', { $el: $el, action: self.options.action });
        }
      });
      self.enhanceControlsHover(sel);
    };

    self.register = function(docId, dotPath, editor) {
      self.editors[docId + dotPath] = editor;
    };

    self.enableShift = function() {

      // listen for shiftActive for power up/down nudge
      apos.on('shiftDown', function() {
        $('[data-apos-move-item]').each(function() {
          $self = $(this);
          if ($self.attr('data-apos-move-item') === 'up') {
            $self.children('i').toggleClass('icon-double-angle-up');
            $self.attr('data-apos-move-item', 'top');
          } else if ($self.attr('data-apos-move-item') === 'down') {
            $self.children('i').toggleClass('icon-double-angle-down');
            $self.attr('data-apos-move-item', 'bottom');
          }
        });
      });

      apos.on('shiftUp', function() {
        $('[data-apos-move-item]').each(function() {
          $self = $(this);
          $self.children('i').removeClass('icon-double-angle-up');
          $self.children('i').removeClass('icon-double-angle-down');
          if ($self.attr('data-apos-move-item') === 'top') {
            $self.attr('data-apos-move-item', 'up');
          } else if ($self.attr('data-apos-move-item') === 'bottom') {
            $self.attr('data-apos-move-item', 'down');
          }
        });
      });
    };

    // Helper functions for getting widget data and options that don't depend
    // on the context of a specific area editor

    // Get the options that apply to the widget in its current context
    self.getWidgetOptions = function($widget) {
      var $area = $widget.closest('[data-apos-area]');
      var options = {};
      var areaOptions = self.getAreaOptions($area);
      var type = $widget.attr('data-apos-widget');
      if (areaOptions && areaOptions.widgets) {
        $.extend(true, options, areaOptions.widgets[type] || {});
      }
      return options;
    };

    self.getAreaOptions = function($area) {
      // TODO: this could be a lot of parsing done over and over
      return JSON.parse($area.attr('data-options') || '{}');
    };

    self.getWidgetData = function($widget) {
      var type = $widget.attr('data-apos-widget');
      var manager = self.getWidgetManager(type);
      if (!manager) {
        apos.log('WARNING: no manager for widget type ' + type);
        return;
      }
      return manager.getData($widget);
    };

    self.setWidgetData = function($widget, data) {
      var type = $widget.attr('data-apos-widget');
      var manager = self.getWidgetManager(type);
      if (!manager) {
        apos.log('WARNING: no manager for widget type ' + type);
        return;
      }
      return manager.setData($widget, data);
    };

  }
});
<|endoftext|>


<commit_before>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename)

const Sensor = require('./Sensor.js').Sensor

const Promise = require('bluebird')
const extensionManager = require('./ExtensionManager.js')

const configServerKey = "ext.guardian.socketio.server";
const configRegionKey = "ext.guardian.socketio.region";
const configBizModeKey = "ext.guardian.business";
const configAdminStatusKey = "ext.guardian.socketio.adminStatus";

const rclient = require('../util/redis_manager.js').getRedisClient();

const io = require('socket.io-client');

const EncipherTool = require('../net2/EncipherTool.js');
const et = new EncipherTool();

const CloudWrapper = require('../api/lib/CloudWrapper.js');
const cw = new CloudWrapper();
const receicveMessageAsync = Promise.promisify(cw.getCloud().receiveMessage).bind(cw.getCloud());
const encryptMessageAsync = Promise.promisify(cw.getCloud().encryptMessage).bind(cw.getCloud());

const zlib = require('zlib');
const deflateAsync = Promise.promisify(zlib.deflate);

class GuardianSensor extends Sensor {
  constructor() {
    super();
  }

  async apiRun() {
    extensionManager.onGet("guardianSocketioServer", (msg) => {
      return this.getServer();
    });

    extensionManager.onSet("guardianSocketioServer", (msg, data) => {
      return this.setServer(data.server, data.region);
    });

    extensionManager.onGet("guardian.business", async (msg) => {
      const data = await rclient.getAsync(configBizModeKey);
      if(!data) {
        return null;
      }

      try {
        return JSON.parse(data);
      } catch(err) {
        log.error(`Failed to parse data, err: ${err}`);
        return null;
      }
    });

    extensionManager.onSet("guardian.business", async (msg, data) => {
      await rclient.setAsync(configBizModeKey, JSON.stringify(data));
    });

    extensionManager.onGet("guardianSocketioRegion", (msg) => {
      return this.getRegion();
    });

    extensionManager.onCmd("startGuardianSocketioServer", (msg, data) => {
      return this.start();
    });

    extensionManager.onCmd("stopGuardianSocketioServer", (msg, data) => {
      return this.stop();
    });

    extensionManager.onCmd("setAndStartGuardianService", async (msg, data) => {
      const socketioServer = data.server;
      if(!socketioServer) {
        throw new Error("invalid guardian relay server");
      }

      await this.setServer(socketioServer, data.region);

      await this.start();
    });

    const adminStatusOn = await this.isAdminStatusOn();
    if(adminStatusOn) {
      await this.start();
    }
  }

  async setServer(server, region) {
    if(server) {
      if(region) {
        await rclient.setAsync(configRegionKey, region);
      } else {
        await rclient.delAsync(configRegionKey);
      }
      return rclient.setAsync(configServerKey, server);
    } else {
      throw new Error("invalid server");
    }
  }

  async getServer() {
    const value = await rclient.getAsync(configServerKey);
    return value || "";
  }

  async getRegion() {
    return rclient.getAsync(configRegionKey);
  }

  async isAdminStatusOn() {
    const status = await rclient.getAsync(configAdminStatusKey);
    return status === '1';
  }

  async adminStatusOn() {
    return rclient.setAsync(configAdminStatusKey, '1');
  }

  async adminStatusOff() {
    return rclient.setAsync(configAdminStatusKey, '0');
  }

  async start() {
    const server = await this.getServer();
    if(!server) {
      throw new Error("socketio server not set");
    }

    await this._stop();

    await this.adminStatusOn();

    const gid = await et.getGID();
    const eid = await et.getEID();

    const region = await this.getRegion();

    if(region) {
      this.socket = io(server, {path: `/${region}/socket.io`});
    } else {
      this.socket = io.connect(server);
    }
    if(!this.socket) {
      throw new Error("failed to init socket io");
    }

    this.socket.on('connect', () => {
      log.info(`Socket IO connection to ${server}, ${region} is connected.`);
      this.socket.emit("box_registration", {
        gid: gid,
        eid: eid
      });
    });

    this.socket.on('disconnect', () => {
      log.info(`Socket IO connection to ${server}, ${region} is disconnected.`);
    });

    const key = `send_to_box_${gid}`;
    this.socket.on(key, (message) => {
      if(message.gid === gid) {
        this.onMessage(gid, message);
      }
    })
  }

  async _stop() {
    if(this.socket) {
      this.socket.disconnect();
      this.socket = null;
    }
  }

  async stop() {
    await this.adminStatusOff();
    return this._stop();
  }

  async onMessage(gid, message) {
    const controller = await cw.getNetBotController(gid);

    if(controller && this.socket) {
      const encryptedMessage = message.message;
      const decryptedMessage = await receicveMessageAsync(gid, encryptedMessage);
      decryptedMessage.mtype = decryptedMessage.message.mtype;
      const response = await controller.msgHandlerAsync(gid, decryptedMessage);

      const input = new Buffer(JSON.stringify(response), 'utf8');
      const output = await deflateAsync(input);

      const compressedResponse = JSON.stringify({
        compressed: 1,
        compressMode: 1,
        data: output.toString('base64')
      });

      const encryptedResponse = await encryptMessageAsync(gid, compressedResponse);

      this.socket.emit("send_from_box", {
        message: encryptedResponse,
        gid: gid
      });
    }
  }
}

module.exports = GuardianSensor;
<commit_msg>set socketio transports websocket as default<commit_after>/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename)

const Sensor = require('./Sensor.js').Sensor

const Promise = require('bluebird')
const extensionManager = require('./ExtensionManager.js')

const configServerKey = "ext.guardian.socketio.server";
const configRegionKey = "ext.guardian.socketio.region";
const configBizModeKey = "ext.guardian.business";
const configAdminStatusKey = "ext.guardian.socketio.adminStatus";

const rclient = require('../util/redis_manager.js').getRedisClient();

const io = require('socket.io-client');

const EncipherTool = require('../net2/EncipherTool.js');
const et = new EncipherTool();

const CloudWrapper = require('../api/lib/CloudWrapper.js');
const cw = new CloudWrapper();
const receicveMessageAsync = Promise.promisify(cw.getCloud().receiveMessage).bind(cw.getCloud());
const encryptMessageAsync = Promise.promisify(cw.getCloud().encryptMessage).bind(cw.getCloud());

const zlib = require('zlib');
const deflateAsync = Promise.promisify(zlib.deflate);

class GuardianSensor extends Sensor {
  constructor() {
    super();
  }

  async apiRun() {
    extensionManager.onGet("guardianSocketioServer", (msg) => {
      return this.getServer();
    });

    extensionManager.onSet("guardianSocketioServer", (msg, data) => {
      return this.setServer(data.server, data.region);
    });

    extensionManager.onGet("guardian.business", async (msg) => {
      const data = await rclient.getAsync(configBizModeKey);
      if(!data) {
        return null;
      }

      try {
        return JSON.parse(data);
      } catch(err) {
        log.error(`Failed to parse data, err: ${err}`);
        return null;
      }
    });

    extensionManager.onSet("guardian.business", async (msg, data) => {
      await rclient.setAsync(configBizModeKey, JSON.stringify(data));
    });

    extensionManager.onGet("guardianSocketioRegion", (msg) => {
      return this.getRegion();
    });

    extensionManager.onCmd("startGuardianSocketioServer", (msg, data) => {
      return this.start();
    });

    extensionManager.onCmd("stopGuardianSocketioServer", (msg, data) => {
      return this.stop();
    });

    extensionManager.onCmd("setAndStartGuardianService", async (msg, data) => {
      const socketioServer = data.server;
      if(!socketioServer) {
        throw new Error("invalid guardian relay server");
      }

      await this.setServer(socketioServer, data.region);

      await this.start();
    });

    const adminStatusOn = await this.isAdminStatusOn();
    if(adminStatusOn) {
      await this.start();
    }
  }

  async setServer(server, region) {
    if(server) {
      if(region) {
        await rclient.setAsync(configRegionKey, region);
      } else {
        await rclient.delAsync(configRegionKey);
      }
      return rclient.setAsync(configServerKey, server);
    } else {
      throw new Error("invalid server");
    }
  }

  async getServer() {
    const value = await rclient.getAsync(configServerKey);
    return value || "";
  }

  async getRegion() {
    return rclient.getAsync(configRegionKey);
  }

  async isAdminStatusOn() {
    const status = await rclient.getAsync(configAdminStatusKey);
    return status === '1';
  }

  async adminStatusOn() {
    return rclient.setAsync(configAdminStatusKey, '1');
  }

  async adminStatusOff() {
    return rclient.setAsync(configAdminStatusKey, '0');
  }

  async start() {
    const server = await this.getServer();
    if(!server) {
      throw new Error("socketio server not set");
    }

    await this._stop();

    await this.adminStatusOn();

    const gid = await et.getGID();
    const eid = await et.getEID();

    const region = await this.getRegion();

    if(region) {
      this.socket = io(server, {
        path: `/${region}/socket.io`,
        transports: ['websocket']
      });
    } else {
      this.socket = io(server, {
        transports: ['websocket']
      });
    }
    if(!this.socket) {
      throw new Error("failed to init socket io");
    }

    this.socket.on('connect', () => {
      log.info(`Socket IO connection to ${server}, ${region} is connected.`);
      this.socket.emit("box_registration", {
        gid: gid,
        eid: eid
      });
    });

    this.socket.on('disconnect', () => {
      log.info(`Socket IO connection to ${server}, ${region} is disconnected.`);
    });

    const key = `send_to_box_${gid}`;
    this.socket.on(key, (message) => {
      if(message.gid === gid) {
        this.onMessage(gid, message);
      }
    })
  }

  async _stop() {
    if(this.socket) {
      this.socket.disconnect();
      this.socket = null;
    }
  }

  async stop() {
    await this.adminStatusOff();
    return this._stop();
  }

  async onMessage(gid, message) {
    const controller = await cw.getNetBotController(gid);

    if(controller && this.socket) {
      const encryptedMessage = message.message;
      const decryptedMessage = await receicveMessageAsync(gid, encryptedMessage);
      decryptedMessage.mtype = decryptedMessage.message.mtype;
      const response = await controller.msgHandlerAsync(gid, decryptedMessage);

      const input = new Buffer(JSON.stringify(response), 'utf8');
      const output = await deflateAsync(input);

      const compressedResponse = JSON.stringify({
        compressed: 1,
        compressMode: 1,
        data: output.toString('base64')
      });

      const encryptedResponse = await encryptMessageAsync(gid, compressedResponse);

      this.socket.emit("send_from_box", {
        message: encryptedResponse,
        gid: gid
      });
    }
  }
}

module.exports = GuardianSensor;
<|endoftext|>


<commit_before>// Include The 'http' Module
var http = require("http");

// Include The 'url' Module
var url = require("url");

// Include The 'request' Module
var request = require("request");

// Include The 'async' Module
var async = require("async");

// Include The 'JSONStream' Module
var jsonStream = require("JSONStream");

// Include The 'event-stream' Module
var eventStream = require("event-stream");

// Include The 'parser' Module
var Parser = require("./lib/parser");

// Create the HTTP Server
var server = http.createServer(function(req, res) {
    // Handle HTTP Request
    // Parse the request querystring
    var parsedUrl = url.parse(req.url, true);
    var qs = parsedUrl.query;

    // Validating existence of query param
    if (qs.term) {
        async.auto({
            twitxy: function (callback) {
                var parser = new Parser();
                request("http://twitxy.itkoren.com/?lang=en&count=5&term=" + encodeURIComponent(qs.term))
                    .pipe(jsonStream.parse("statuses.*"))
                    .pipe(eventStream.mapSync(function (data) {
                        parser.parse({
                            src: "Twitter",
                            text: data.text,
                            score: 0
                        });
                    })).on("end", function(){
                        console.log("End Of Twitter Search Stream");
                        callback(null, { items: parser.getItems() });
                    });
            },
            google: function (callback) {
                var parser = new Parser();
                var hasUTube = false;
                request("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&language=en&resultSize=5&q=" + encodeURIComponent(qs.term))
                    .pipe(jsonStream.parse("responseData.results.*"))
                    .pipe(eventStream.mapSync(function (data) {
                        parser.parse({
                            src: "Google",
                            text: data.title,
                            score: 0
                        });

                        // Check if in utube
                        if (!hasUTube && -1 !== data.unescapedUrl.indexOf("utube.com")) {
                            hasUTube = true;
                        }
                    })).on("end", function() {
                        console.log("End Of Google Search Stream");
                        callback(null, { items: parser.getItems(), hasUTube: hasUTube });
                    });
            },
            utube: ["google", function (callback, results) {
                var parser = new Parser();

                if (results.google.hasUTube) {
                    callback(null, parser.getItems());
                }
                else {
                    request("https://gdata.youtube.com/feeds/api/videos?max-results=5&alt=json&orderby=published&v=2&q=" + encodeURIComponent(qs.term))
                        .pipe(jsonStream.parse("feed.entry.*"))
                        .pipe(eventStream.mapSync(function (data) {
                            parser.parse({
                                src: "UTube",
                                text: data.title.$t,
                                score: 0
                            });
                        })).on("end", function() {
                            console.log("End Of Utube Search Stream");
                            callback(null, { items: parser.getItems() });
                        });
                }
            }]
        },
        // optional callback
        function (err, results) {
            // the results array will equal ['one','two'] even though
            // the second function had a shorter timeout.
            if (err) {
                // Deal with errors
                console.log("Got error: " + err.message);
                res.writeHead(500);
                res.end("** Only Bear Here :) **");
            }
            else {
                var items = results.twitxy.items.concat(results.google.items, results.utube.items);
                res.writeHead(200, { "Content-Type": "application/json" });
                res.end(JSON.stringify(items));
            }
        });
    }
    else {
        // No search term supplied, just return
        console.log("Search failed!");
        console.log("Query parameters are missing");
        res.writeHead(500);
        res.end("** Only Bear Here :) **");
    }
}).listen(process.env.PORT || 8000, process.env.HOST || "0.0.0.0", function() {
    console.log("HTTP Server Started. Listening on " + server.address().address + " : Port " + server.address().port);
});<commit_msg>fix youtube url check<commit_after>// Include The 'http' Module
var http = require("http");

// Include The 'url' Module
var url = require("url");

// Include The 'request' Module
var request = require("request");

// Include The 'async' Module
var async = require("async");

// Include The 'JSONStream' Module
var jsonStream = require("JSONStream");

// Include The 'event-stream' Module
var eventStream = require("event-stream");

// Include The 'parser' Module
var Parser = require("./lib/parser");

// Create the HTTP Server
var server = http.createServer(function(req, res) {
    // Handle HTTP Request
    // Parse the request querystring
    var parsedUrl = url.parse(req.url, true);
    var qs = parsedUrl.query;

    // Validating existence of query param
    if (qs.term) {
        async.auto({
            twitxy: function (callback) {
                var parser = new Parser();
                request("http://twitxy.itkoren.com/?lang=en&count=5&term=" + encodeURIComponent(qs.term))
                    .pipe(jsonStream.parse("statuses.*"))
                    .pipe(eventStream.mapSync(function (data) {
                        parser.parse({
                            src: "Twitter",
                            text: data.text,
                            score: 0
                        });
                    })).on("end", function(){
                        console.log("End Of Twitter Search Stream");
                        callback(null, { items: parser.getItems() });
                    });
            },
            google: function (callback) {
                var parser = new Parser();
                var hasUTube = false;
                request("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&language=en&resultSize=5&q=" + encodeURIComponent(qs.term))
                    .pipe(jsonStream.parse("responseData.results.*"))
                    .pipe(eventStream.mapSync(function (data) {
                        parser.parse({
                            src: "Google",
                            text: data.title,
                            score: 0
                        });

                        // Check if in utube
                        if (!hasUTube && -1 !== data.unescapedUrl.indexOf("youtube.com")) {
                            hasUTube = true;
                        }
                    })).on("end", function() {
                        console.log("End Of Google Search Stream");
                        callback(null, { items: parser.getItems(), hasUTube: hasUTube });
                    });
            },
            utube: ["google", function (callback, results) {
                var parser = new Parser();

                if (results.google.hasUTube) {
                    callback(null, parser.getItems());
                }
                else {
                    request("https://gdata.youtube.com/feeds/api/videos?max-results=5&alt=json&orderby=published&v=2&q=" + encodeURIComponent(qs.term))
                        .pipe(jsonStream.parse("feed.entry.*"))
                        .pipe(eventStream.mapSync(function (data) {
                            parser.parse({
                                src: "UTube",
                                text: data.title.$t,
                                score: 0
                            });
                        })).on("end", function() {
                            console.log("End Of Utube Search Stream");
                            callback(null, { items: parser.getItems() });
                        });
                }
            }]
        },
        // optional callback
        function (err, results) {
            // the results array will equal ['one','two'] even though
            // the second function had a shorter timeout.
            if (err) {
                // Deal with errors
                console.log("Got error: " + err.message);
                res.writeHead(500);
                res.end("** Only Bear Here :) **");
            }
            else {
                var items = results.twitxy.items.concat(results.google.items, results.utube.items);
                res.writeHead(200, { "Content-Type": "application/json" });
                res.end(JSON.stringify(items));
            }
        });
    }
    else {
        // No search term supplied, just return
        console.log("Search failed!");
        console.log("Query parameters are missing");
        res.writeHead(500);
        res.end("** Only Bear Here :) **");
    }
}).listen(process.env.PORT || 8000, process.env.HOST || "0.0.0.0", function() {
    console.log("HTTP Server Started. Listening on " + server.address().address + " : Port " + server.address().port);
});<|endoftext|>


<commit_before>'use strict';

module.exports = {
    extends: 'xo',

    env: {
        browser: false,

        mocha: true
    },

    ecmaFeatures: {
        generators: true
    },

    // http://eslint.org/docs/rules/
    rules: {
        /**
         * +++++++++++++++++++
         * + Possible Errors +
         * +++++++++++++++++++
         */

        // http://eslint.org/docs/rules/no-console
        'no-console': 'warn',

        // http://eslint.org/docs/rules/valid-jsdoc
        'valid-jsdoc': 'error',

        /**
         * ++++++++++++++++++
         * + Best Practices +
         * ++++++++++++++++++
         */

        // http://eslint.org/docs/rules/class-methods-use-this
        // 'class-methods-use-this': 'error',

        // http://eslint.org/docs/rules/complexity
        complexity: ['error', {
            max: 5
        }],

        // http://eslint.org/docs/rules/consistent-return
        // 'consistent-return': ['error', {
            // treatUndefinedAsUnspecified: true
        // }],

        // http://eslint.org/docs/rules/no-param-reassign
        'no-param-reassign': ['off'],

        /**
         * +++++++++++++
         * + Variables +
         * +++++++++++++
         */

        // http://eslint.org/docs/rules/no-catch-shadow
        'no-catch-shadow': 'error',

        // http://eslint.org/docs/rules/no-shadow
        'no-shadow': ['error', {
            builtinGlobals: true
        }],

        // http://eslint.org/docs/rules/no-unused-vars
        'no-unused-vars': ['error', {
            args: 'none',
            vars: 'local',
            varsIgnorePattern: '^_'
        }],

        /**
         * +++++++++++++++++++++++++
         * + Node.JS and Common JS +
         * +++++++++++++++++++++++++
         */

        // http://eslint.org/docs/rules/no-restricted-modules
        'no-restricted-modules': 'off',

        /**
         * ++++++++++++++++++++
         * + Stylistic Issues +
         * ++++++++++++++++++++
         */

        // http://eslint.org/docs/rules/indent
        indent: ['error', 4, {
            SwitchCase: 1
        }],

        // http://eslint.org/docs/rules/max-params
        'max-params': ['error', 6]

        // http://eslint.org/docs/rules/new-cap
        'new-cap': 'error',

        /**
         * ++++++++++++++++
         * + ECMAScript 6 +
         * ++++++++++++++++
         */

        // http://eslint.org/docs/rules/no-bitwise
        'no-bitwise': 'error',

        // http://eslint.org/docs/rules/generator-star-spacing
        'generator-star-spacing': ['error', 'after'],

        // http://eslint.org/docs/rules/max-len
        'max-len': ['error', 200, 2, {
            ignoreUrls: false,
            ignoreComments: false
        }],

        // http://eslint.org/docs/rules/object-shorthand
        'object-shorthand': 'off',

        // http://eslint.org/docs/rules/prefer-arrow-callback
        'prefer-arrow-callback': 'off',

        // http://eslint.org/docs/rules/prefer-const
        'prefer-const': 'error',

        // http://eslint.org/docs/rules/prefer-template
        'prefer-template': 'off'
    }
};
<commit_msg>Corrected for eslint<commit_after>'use strict';

module.exports = {
    extends: 'xo',

    env: {
        browser: false,

        mocha: true
    },

    ecmaFeatures: {
        generators: true
    },

    // http://eslint.org/docs/rules/
    rules: {
        /**
         * +++++++++++++++++++
         * + Possible Errors +
         * +++++++++++++++++++
         */

        // http://eslint.org/docs/rules/no-console
        'no-console': 'warn',

        // http://eslint.org/docs/rules/valid-jsdoc
        'valid-jsdoc': 'error',

        /**
         * ++++++++++++++++++
         * + Best Practices +
         * ++++++++++++++++++
         */

        // http://eslint.org/docs/rules/class-methods-use-this
        // 'class-methods-use-this': 'error',

        // http://eslint.org/docs/rules/complexity
        complexity: ['error', {
            max: 5
        }],

        // http://eslint.org/docs/rules/consistent-return
        // 'consistent-return': ['error', {
            // treatUndefinedAsUnspecified: true
        // }],

        // http://eslint.org/docs/rules/no-param-reassign
        'no-param-reassign': ['off'],

        /**
         * +++++++++++++
         * + Variables +
         * +++++++++++++
         */

        // http://eslint.org/docs/rules/no-catch-shadow
        'no-catch-shadow': 'error',

        // http://eslint.org/docs/rules/no-shadow
        'no-shadow': ['error', {
            builtinGlobals: true
        }],

        // http://eslint.org/docs/rules/no-unused-vars
        'no-unused-vars': ['error', {
            args: 'none',
            vars: 'local',
            varsIgnorePattern: '^_'
        }],

        /**
         * +++++++++++++++++++++++++
         * + Node.JS and Common JS +
         * +++++++++++++++++++++++++
         */

        // http://eslint.org/docs/rules/no-restricted-modules
        'no-restricted-modules': 'off',

        /**
         * ++++++++++++++++++++
         * + Stylistic Issues +
         * ++++++++++++++++++++
         */

        // http://eslint.org/docs/rules/indent
        indent: ['error', 4, {
            SwitchCase: 1
        }],

        // http://eslint.org/docs/rules/max-params
        'max-params': ['error', 6],

        // http://eslint.org/docs/rules/new-cap
        'new-cap': 'error',

        /**
         * ++++++++++++++++
         * + ECMAScript 6 +
         * ++++++++++++++++
         */

        // http://eslint.org/docs/rules/no-bitwise
        'no-bitwise': 'error',

        // http://eslint.org/docs/rules/generator-star-spacing
        'generator-star-spacing': ['error', 'after'],

        // http://eslint.org/docs/rules/max-len
        'max-len': ['error', 200, 2, {
            ignoreUrls: false,
            ignoreComments: false
        }],

        // http://eslint.org/docs/rules/object-shorthand
        'object-shorthand': 'off',

        // http://eslint.org/docs/rules/prefer-arrow-callback
        'prefer-arrow-callback': 'off',

        // http://eslint.org/docs/rules/prefer-const
        'prefer-const': 'error',

        // http://eslint.org/docs/rules/prefer-template
        'prefer-template': 'off'
    }
};
<|endoftext|>


<commit_before>/*
 * Ext JS Library 2.0.2
 * Copyright(c) 2006-2008, Ext JS, LLC.
 * licensing@extjs.com
 *
 * http://extjs.com/license
 */

/**
  * Ext.ux.fbk.sonet.MeteoTrentino Extension Class
  *
  * @author  Marco Frassoni, Maurizio Napolitano & Davide Setti
  * @version 1.0
  * @class Ext.ux.fbk.sonet.MeteoTrentino
  *
MeteoTrentino weather forecast

  *

    This is a example of the json

*/

MeteoTrentino = function(conf, panel_conf){
    Ext.apply(this, panel_conf);

    var l = conf.selected;

    if(!(l in conf.lang))
        l = conf.defaultValue;

    var url = conf.lang[l].url;
    var xslt = conf.lang[l].xslt_file;

    this.html = '';

    this.loadForecast = function(){

        var p = this;

        Ext.Ajax.request({
            url : 'xslt-applier.php',
            params: {'url': url, 'xslt': xslt},
            method: 'POST',
            success: function(result, request){
                p.html = result.responseText;
                p.renderForecast();
            },
            failure: function(result, request){
                $('#'+p.getId()+'-forecast-overview').html('
Uh oh! Something apparently went wrong, please apoligize us and send us a feedback!
');
            }
        });
    };

    this.renderForecast = function(){

        var ov = $('#' +this.getId()+'-forecast-overview');
        var dv = $('#' +this.getId()+'-forecast-detailedview');

        if(this.html === null || this.html === '')
            ov.html('
Uh oh! Something apparently went wrong, please apoligize us and send us a feedback!
');

        var doc = $("
").html(this.html);

        ov.html(doc.find('#meteo_sintesi'));

        var f = doc.find('.meteo_forecast');

        f.not('#today').hide();

        dv.html(f);

        this.visualize();
    }

    this.visualize = function(day){

        var ov = $('#' +this.getId()+'-forecast-overview');
        var dv = $('#' +this.getId()+'-forecast-detailedview');
        var lk = $('#' +this.getId()+'-forecast-links');

        var w_id = this.getId();

        var link = 'javascript:Ext.getCmp(\''+w_id+'\').visualize(\'{0}\')';

        if(this.html === null || this.html === '')
            ov.html('
Uh oh! Something apparently went wrong, please apoligize us and send us a feedback!
');

        lk.html('');

        if (day == null || day == '')
            day = 'today';

        dv.children().each(function(){
            var id = $(this).attr('id');
            var label = $(this).attr('label');
            if(id == day){
                lk.append($('').text(label));
                $(this).show();
            } else {
                lk.append($('').attr('href', String.format(link,id)).text(label));
                $(this).hide();
            }
        });

        lk.children().css({'padding' : '10px', 'font-size' : '13px'});
    }

    MeteoTrentino.superclass.constructor.call(this, {
        autoHeight: true
        ,autoWidth: true
        ,defaults: {
            autoScroll: true
        }
        ,items: [{
            html:
                '
'
                    +'

'
                    +'

'
                    +'

'
                    +'
ReloadChange language
'
                +'
'
            ,border: false
            ,autoHeight: true
        }]
        ,listeners: {
            render: function(){
                this.doLayout(); // TO DO: do this only if it is collapsed
                this.loadForecast()
            }
        }
    });

};
Ext.extend(MeteoTrentino, Ext.Panel);
<commit_msg>Styling<commit_after>/*
 * Ext JS Library 2.0.2
 * Copyright(c) 2006-2008, Ext JS, LLC.
 * licensing@extjs.com
 *
 * http://extjs.com/license
 */

/**
  * Ext.ux.fbk.sonet.MeteoTrentino Extension Class
  *
  * @author  Marco Frassoni, Maurizio Napolitano & Davide Setti
  * @version 1.0
  * @class Ext.ux.fbk.sonet.MeteoTrentino
  *
MeteoTrentino weather forecast

  *

    This is a example of the json

*/

MeteoTrentino = function(conf, panel_conf){
    Ext.apply(this, panel_conf);

    var l = conf.selected;

    if(!(l in conf.lang))
        l = conf.defaultValue;

    var url = conf.lang[l].url;
    var xslt = conf.lang[l].xslt_file;

    this.html = '';

    this.loadForecast = function(){

        var p = this;

        Ext.Ajax.request({
            url : 'xslt-applier.php',
            params: {'url': url, 'xslt': xslt},
            method: 'POST',
            success: function(result, request){
                p.html = result.responseText;
                p.renderForecast();
            },
            failure: function(result, request){
                $('#'+p.getId()+'-forecast-overview').html('<div').class('error-msg').text('Uh oh! Something apparently went wrong, please apoligize us and send us a feedback!');
            }
        });
    };

    this.renderForecast = function(){

        var ov = $('#' +this.getId()+'-forecast-overview');
        var dv = $('#' +this.getId()+'-forecast-detailedview');

        if(this.html === null || this.html === '')
            ov.html('
Uh oh! Something apparently went wrong, please apoligize us and send us a feedback!
');

        var doc = $("
").html(this.html);

        ov.html(doc.find('#meteo_sintesi'));

        var f = doc.find('.meteo_forecast');

        f.not('#today').hide();

        dv.html(f);

        this.visualize();
    }

    this.visualize = function(day){

        var ov = $('#' +this.getId()+'-forecast-overview');
        var dv = $('#' +this.getId()+'-forecast-detailedview');
        var lk = $('#' +this.getId()+'-forecast-links');

        var w_id = this.getId();

        var link = 'javascript:Ext.getCmp(\''+w_id+'\').visualize(\'{0}\')';

        if(this.html === null || this.html === '')
            ov.html('<div').class('error-msg').text('Uh oh! Something apparently went wrong, please apoligize us and send us a feedback!');

        lk.html('');

        if (day == null || day == '')
            day = 'today';

        dv.children().each(function(){
            var id = $(this).attr('id');
            var label = $(this).attr('label');
            if(id == day){
                lk.append($('').text(label));
                $(this).show();
            } else {
                lk.append($('').attr('href', String.format(link,id)).text(label));
                $(this).hide();
            }
        });

        lk.children().css({'padding' : '10px', 'font-size' : '13px'});
    }

    MeteoTrentino.superclass.constructor.call(this, {
        autoHeight: true
        ,autoWidth: true
        ,defaults: {
            autoScroll: true
        }
        ,items: [{
            html:
                '
'
                    +'

'
                    +'

'
                    +'

'
                    +'
ReloadChange language
'
                +'
'
            ,border: false
            ,autoHeight: true
        }]
        ,listeners: {
            render: function(){
                this.doLayout(); // TO DO: do this only if it is collapsed
                this.loadForecast()
            }
        }
    });
};
Ext.extend(MeteoTrentino, Ext.Panel);
<|endoftext|>


<commit_before>init();

urls = [chrome.extension.getURL("images/fhrs_0_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_1_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_2_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_3_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_4_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_5_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_awaitinginspection_en-gb.jpg")];

function init() {

    takeaways = []
    $( "div" ).filter(function( index ) {
        return $( this ).attr( "class" ) == "o-tile c-restaurant";
    }).each(function( index ) {

        var postcode =  $( this ).find(
            "[data-ft='restaurantDetailsAddress']"
        ).html();

        postcode = postcode.split(", ");
        postcode = postcode[postcode.length - 1];

        var rating = 0;

        takeaways.push(
            [
                postcode,

                $( this ).find(
                    "[data-ft='restaurantDetailsName']"
                ).html()

                ,
                rating
            ]
        );

    });

    for (var res in takeaways) {
        var rating = getTakeawayRatingMP(takeaways[res], res);
        console.log(takeaways[res]);
    }
}

function getTakeawayRatingMP(takeaway, index) {
    var takeawayPostcode = takeaway[0];
    var takeawayName = takeaway[1];
    /*
     var ratingUrl = FSA_HOST + takeawayName + "/" + takeawayPostcode + "/" + FSA_HOST_SUFFIX;*/
    var ratingJson = "";

    //console.log(ratingUrl);

    /*var ratingJson = $.ajax({
     url: ratingUrl,
     success: function(data) {
     console.log(data);
     },
     error: function () {
     console.log("Error!");
     }
     });chrom*/

    chrome.runtime.sendMessage({"postcode": takeawayPostcode, "name": takeawayName}, function(response) {
        jsonResponse = JSON.parse(response.rating);
        /**
         * Call a function here to insert the RATING IMAGE.
         * Index: index
         * Data: jsonResponse.FHRSEstablishment.EstablishmentCollection.EstablishmentDetail
         * eg --> somefunction(index, jsonResponse.FHRSEstablishment.EstablishmentCollection.EstablishmentDetail.ratingValue)
         */
        if (jsonResponse.FHRSEstablishment.EstablishmentCollection) {
            insertRatingImage(index, '');
        } else {
            insertRatingImage(index, '');}
    });
}

jQuery.fn.insertAt = function(index, element) {
    var lastIndex = this.children().size();
    if (index < 0) {
        index = Math.max(0, lastIndex + 1 + index)
    }
    this.append(element);
    if (index < lastIndex) {
        this.children().eq(index).before(this.children().last())
    }
    return this;
};

function insertRatingImage(index, rating) {
    //Quite possibly the most disgusting javascript selector I've ever written.
    var $detailsDiv = $("div").filter(function( index ) {
        return $( this ).attr( "class" ) == "o-tile c-restaurant";
    }).eq(index).eq(0).children().eq(0).children().eq(2).children().eq(1);
    $( "
" + rating + "
" ).insertAfter($detailsDiv)
}

insertRatingImage(1, "");

<commit_msg>polish(extension): Update Just-Eat rating<commit_after>init();

urls = [chrome.extension.getURL("images/fhrs_0_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_1_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_2_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_3_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_4_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_5_en-gb.jpg"),
    chrome.extension.getURL("images/fhrs_awaitinginspection_en-gb.jpg")];

function init() {

    takeaways = []
    $( "div" ).filter(function( index ) {
        return $( this ).attr( "class" ) == "o-tile c-restaurant";
    }).each(function( index ) {

        var postcode =  $( this ).find(
            "[data-ft='restaurantDetailsAddress']"
        ).html();

        postcode = postcode.split(", ");
        postcode = postcode[postcode.length - 1];

        var rating = 0;

        takeaways.push(
            [
                postcode,

                $( this ).find(
                    "[data-ft='restaurantDetailsName']"
                ).html()

                ,
                rating
            ]
        );

    });

    for (var res in takeaways) {
        var rating = getTakeawayRatingMP(takeaways[res], res);
        console.log(takeaways[res]);
    }
}

function getTakeawayRatingMP(takeaway, index) {
    var takeawayPostcode = takeaway[0];
    var takeawayName = takeaway[1];
    /*
     var ratingUrl = FSA_HOST + takeawayName + "/" + takeawayPostcode + "/" + FSA_HOST_SUFFIX;*/
    var ratingJson = "";

    //console.log(ratingUrl);

    /*var ratingJson = $.ajax({
     url: ratingUrl,
     success: function(data) {
     console.log(data);
     },
     error: function () {
     console.log("Error!");
     }
     });chrom*/

    chrome.runtime.sendMessage({"postcode": takeawayPostcode, "name": takeawayName}, function(response) {
        jsonResponse = JSON.parse(response.rating);
        /**
         * Call a function here to insert the RATING IMAGE.
         * Index: index
         * Data: jsonResponse.FHRSEstablishment.EstablishmentCollection.EstablishmentDetail
         * eg --> somefunction(index, jsonResponse.FHRSEstablishment.EstablishmentCollection.EstablishmentDetail.ratingValue)
         */
        if (jsonResponse.FHRSEstablishment.EstablishmentCollection) {
            insertRatingImage(index, '');
        } else {
            insertRatingImage(index, '');}
    });
}

jQuery.fn.insertAt = function(index, element) {
    var lastIndex = this.children().size();
    if (index < 0) {
        index = Math.max(0, lastIndex + 1 + index)
    }
    this.append(element);
    if (index < lastIndex) {
        this.children().eq(index).before(this.children().last())
    }
    return this;
};

function insertRatingImage(index, rating) {
    //Quite possibly the most disgusting javascript selector I've ever written.
    var $detailsDiv = $("div").filter(function( index ) {
        return $( this ).attr( "class" ) == "o-tile c-restaurant";
    }).eq(index).eq(0).children().eq(0).children().eq(2).children().eq(1);
    $( "
" + rating + "
" ).insertAfter($detailsDiv)
}

insertRatingImage(1, "");

<|endoftext|>


<commit_before>(function () {
  var domains = [], refreshActive = false;

  chrome.extension.onMessage.addListener (function(message, sender) {
    var msgObj = JSON.parse (message);

    if (msgObj.msgType === "file-update") {

      if (!refreshActive) {
        return;
      }

      var change = JSON.parse (msgObj.data);

      switch (change.type) {

      case "css":
        console.log ("CSS updated: " + change.name);
        var links = document.getElementsByTagName ("link");
        for (var i=0; i<links.length; i++) {
          var link = links [i];
          if (link.href.indexOf (change.name) !== -1) {
            var newHref = link.href.split ("?") [0];
            newHref += "?forceReload=" + new Date ().getTime ();
            link.href = newHref;
          }
        }
        break;

      case "png":
      case "jpg":
      case "jpeg":
      case "gif":
        console.log ("Image updated: " + change.name);
        break;

      case "js":
        console.log ("JS updated: " + change.name);
        break;

      case "html":
        console.log ("HTML updated: " + change.name);
        break;
      }

    } else if (msgObj.msgType === "domains-update") {
      domains = JSON.parse (msgObj.data);
      refreshActive = domains.indexOf (window.location.host) !== -1;
    }
  });

  // Ask for domains
  chrome.extension.sendRequest ("get-domains");

}) ();
<commit_msg>Add refresh functions for images, js<commit_after>(function () {
  var domains = [], refreshActive = false;

  chrome.extension.onMessage.addListener (function(message, sender) {
    var msgObj = JSON.parse (message);

    if (msgObj.msgType === "file-update") {

      if (!refreshActive) {
        return;
      }

      var change = JSON.parse (msgObj.data);

      switch (change.type) {

      case "css":
        // console.log ("CSS updated: " + change.name);
        refresh.css (change.name);
        break;

      case "png":
      case "jpg":
      case "jpeg":
      case "gif":
        // console.log ("Image updated: " + change.name);
        refresh.image (change.name);
        refresh.css (true);
        break;

      case "js":
        // console.log ("JS updated: " + change.name);
        refresh.js (change.name);
        break;

      case "eot":
      case "svg":
      case "ttf":
      case "woff":
        // console.log ("Font updated: " + change.name);
        refresh.css (true);
        break;
      }

    } else if (msgObj.msgType === "domains-update") {
      domains = JSON.parse (msgObj.data);
      refreshActive = domains.indexOf (window.location.host) !== -1;
    }
  });

  // Ask for domains
  chrome.extension.sendRequest ("get-domains");

  var refresh = {

    css: function (name) {
      var all = typeof name === "boolean" && all;
      var links = document.getElementsByTagName ("link");
      for (var i = 0; i < links.length; i++) {
        var link = links [i];
        if (all || link.href.indexOf (name) !== -1) {
          var newHref = link.href.split ("?") [0];
          newHref += "?forceReload=" + new Date ().getTime ();
          link.href = newHref;
        }
      }
    },

    image: function (name) {
      var images = document.getElementsByTagName ("img");
      for (var i = 0; i < images.length; i++) {
        var image = image [i];
        if (image.src.indexOf (name) !== -1 || all) {
          var newSrc = image.src.split ("?") [0];
          newSrc += "?forceReload=" + new Date ().getTime ();
          image.src = newSrc;
        }
      }
    },

    js: function (name) {
      var scripts = document.getElementsByTagName ("script");
      for (var i = 0; i < scripts.length; i++) {
        var js = scripts [i];
        if (js.src.indexOf (name) !== -1) {
          window.location.reload ();
        }
      }
    }
  };

}) ();
<|endoftext|>