<commit_before>var CodeMirror;
(function(name, definition) {
  if( typeof module !== 'undefined' && module.exports ) {
    CodeMirror = require('codemirror');
    module.exports = definition();
  } else if(typeof define !== 'undefined' && define.amd ) {
    define(definition);
  } else {
    CodeMirror = window.CodeMirror;
    this[name] = definition();
  }
})('Console',function(){
  class Console {
    constructor(element, options = {}) {
      options.theme = options.theme || 'eclipse';
      options.mode = options.mode || 'javascript';

      this.container = element;
      this.container.classList.add('jsconsole', options.theme);
      this.logBuffer = [];
      this.history = [];
      this.historyIndex = -1;
      this.events = {};

      var enter = () => {
        var text = this.input.getValue().trim();
        if (text) this.exec(text);
      };

      var shiftEnter = () => {
        CodeMirror.commands.newlineAndIndent(this.input);
      };

      var cancel = () => {
        // TODO: copy, not cancel when we hit ^C on windows with an active selection
        this.resetInput();
      };

      var up = (cm, evt) => {
        var cursor = this.input.getCursor();
        if (cursor.line === 0 && cursor.ch === 0) {
          this.historyIndex++;
          if (this.historyIndex > (this.history.length - 1)) this.historyIndex = this.history.length - 1;
          this.resetInput(this.history[this.historyIndex]);
        } else {
          CodeMirror.commands.goLineUp(this.input);
        }
      };

      var down = (cm, evt) => {
        var cursor = this.input.getCursor();
        var lastLine = this.input.lastLine();
        if (cursor.line === lastLine) {
          this.historyIndex--;
          if (this.historyIndex < -1) this.historyIndex = -1;
          this.resetInput(this.history[this.historyIndex]);
        } else {
          CodeMirror.commands.goLineDown(this.input);
        }
      };

      var inputKeymap = {
        "Up": up,
        "Down": down,
        "Ctrl-C": cancel,
        "Enter": enter,
        "Shift-Enter": shiftEnter
      };

      var outputContainer = document.createElement('div');
      var inputContainer = document.createElement('div');
      outputContainer.className = 'jsconsole-output';
      inputContainer.className = 'jsconsole-input';

      this.container.appendChild(outputContainer);
      this.container.appendChild(inputContainer);

      this.input = CodeMirror(inputContainer, {
        theme: options.theme,
        mode: options.mode,
        extraKeys: inputKeymap,
        tabSize: 2,
        indentUnit: 2,
        undoDepth: 100,
        lineWrapping: true,
        viewportMargin: Infinity,
        gutters: ['repl']
      });
      this.output = CodeMirror(outputContainer, {
        theme: options.theme,
        mode: options.mode,
        gutters: ['repl'],
        tabSize: 2,
        viewportMargin: Infinity,
        lineWrapping: true,
        indentUnit: 2,
        readOnly: true
      });
      this.resetOutput();

      this.input.on('focus', () => {
        var cursor = this.output.getCursor();
        this.output.setSelection(cursor, cursor);
      });
      this.output.on('focus', () => {
        var cursor = this.input.getCursor();
        this.input.setSelection(cursor, cursor);
      });

      this.output.on('keydown', (cm, evt) => {
        // if we start typing when the output is focused, send it to the input
        if (evt.metaKey || evt.ctrlKey) {
          if (evt.which === 67) { // ^C
            // don't need to do
            // anything here yet.
          } else if (evt.which === 86) { // ^V
            this.input.triggerOnKeyDown(evt);
          }
        } else {
          this.input.triggerOnKeyDown(evt);
          this.input.focus();
        }
      });

      // codemirror doesn't handle mouseup events, so need to bind to the container
      outputContainer.addEventListener('mouseup', (evt) => {
        if (this.output.getSelection().length === 0) {
          // need to defer the input focusing to get it to work.
          setTimeout(() => this.input.focus(), 0);
        }
      });

      this.input.setMarker = this.output.setMarker = function(line, el) {
        this.setGutterMarker(line, 'repl', el.cloneNode());
      };

      this.resetInput();
    }
    on(event, fn) {
      this.events[event] = fn;
    }
    off(event) {
      delete this.events[event];
    }
    trigger(event, data) {
      if (typeof this.events[event] === 'function') this.events[event](data);
    }
    flushLogBuffer() {
      if (this.logBuffer.length) {
        this.logBuffer.forEach((msg)=>{
          this.print(msg);
          this.origConsoleLog(msg);
        });
        this.logBuffer.length = 0;
      }
    }
    addHistory(text) {
      this.historyIndex = -1;
      this.history.unshift(text);
    }
    appendEntry(input, output) {
      this.trigger('entry', {input, output});
      var range = this.appendOutput(input.toString().trim());
      this.output.setMarker(range[0].line, previousCommand);
      for (let i = range[0].line; i <= range[1].line; i++) {
        if (i > range[0].line) this.output.setMarker(i, previousCommandContinuation);
        this.output.addLineClass(i, 'text', 'prev-command');
      }

      this.flushLogBuffer();

      var parsedOutput =  this.parseOutput(output);

      range = this.appendOutput(parsedOutput.formatted);
      var isError = parsedOutput.value instanceof Error;

      if (isError) {
        this.output.setMarker(range[0].line, errorMarker);
      } else {
        this.output.setMarker(range[0].line, completionValue);
      }
      for (let i = range[0].line; i <= range[1].line; i++) {
        this.output.addLineClass(i, 'text', 'completion-value');
        this.output.addLineClass(i, 'text', parsedOutput.class);
      }
      this.output.addLineClass(range[1].line, 'text', 'completion-value-end');
    }
    parseOutput(value) {
      var type = typeof value;
      if (value instanceof Error) type = 'error';
      if (value === null) type = 'null';
      var output = {
        value : value,
        type : type,
        class : 'type-' + type
      };

      switch (type) {
        case "string":
          output.formatted =  '"' + value + '"';
          output.class = "string";
          break;
        case "undefined":
          output.formatted = "undefined";
          break;
        case "null":
          output.formatted = "null";
          break;
        case "object":
        case "array":
          // Todo: pretty print object output
          output.formatted = JSON.stringify(value);
          break;
        case "error":
          output.formatted = value.message.trim();
          break;
        default:
          output.formatted = value.toString().trim();
      }
      return output;
    }
    evaluate(code) {
      var out = {};
      try {
        out.completionValue = eval.call(null, code);
      } catch(e) {
        out.error = true;
        out.completionValue = e;
        out.recoverable = (e instanceof SyntaxError && e.message.match('^Unexpected (token|end)'));
      }
      return out;
    }
    exec(text) {
      this.isEvaluating = true;
      var rv = this.evaluate(text);
      if (!rv) return;
      this.isEvaluating = false;
      var doc = this.input.getDoc();

      if (rv.error && !rv.recoverable) {
        this.appendEntry(text, rv.completionValue);
        this.addHistory(text);
        this.resetInput();
      } else if (rv.recoverable) {
        CodeMirror.commands.newlineAndIndent(this.input);
      } else {
        this.appendEntry(text, rv.completionValue);
        this.addHistory(text);
        this.resetInput();
      }

      doc.eachLine((line) => {
        if (line.lineNo() === 0) this.input.setMarker(line, prompt);
        else this.input.setMarker(line, promptContinuation);
      });
    }
    resetInput(text = '') {
      this.input.setValue(text.toString());
      this.input.execCommand('goDocEnd');
      this.input.setMarker(0, prompt);
    }
    resetOutput() {
      // magic number to make things align properly when there is no input;
      this.output.setSize(null, 8);
      this.output.setValue('');
    }
    appendOutput(text) {
      this.output.setSize(null, 'auto');
      var doc = this.output.getDoc();
      var range;
      if (doc.getLine(doc.lastLine()).match(/^\s*$/)) {
        range = append(this.output, text.toString());
      } else {
        range = append(this.output, '\n' + text.toString());
        range[0].line = range[0].line + 1;
      }
      //this.output.markText(range[0], range[1], {className : 'output'});

      return range;
    }
    print(text, className = 'message', gutterMarker = document.createElement('span')) {
      var range = this.appendOutput(text);
      for (let i = range[0].line; i <= range[1].line; i++) {
        this.output.addLineClass(i, 'text', className);
        this.output.setMarker(i, gutterMarker);
      }
      return range;
    }
    // basic, dumb formatter for console.log style %X formatting
    simpleFormatter(msg, ...args) {
      if( typeof msg === 'string' ) {
        var replacementIndex = 0;
        return msg.replace(/%./mg,function(pattern, loc, originalString){
          return args[replacementIndex++];
        });
      } else {
        return msg + args;
      }
    }

    complexFormatter( ...args ) {
      let res = '';
      if( typeof args[0] === 'string' && args[0].search("%s") !== -1) {
        let s = args[0],
            search,
            i = 1;

        while( i < args.length && (search = s.search(/%s|%d|%i|%f]/)) !== -1 ) {
          let replace = s[search] + s[search+1];
          s = s.replace(replace,args[i]);
          i++;
        }
        res = s;
      } else {
        args.forEach(arg => {
          if( typeof arg === 'object' ) res += `${JSON.stringify(arg)} `;
          else res += `${arg} `;
        });
      }
      return res;
    }

    appendInput(text) {
      return append(this.input, text.toString());
    }
    wrapLog(console) {
      var origConsoleLog = console.log.bind(console);
      console.log = (...args) => {
        this.logBuffer.push(this.complexFormatter(...args));
        if (!this.isEvaluating) {
          this.flushLogBuffer();
        }
      };
      return this.origConsoleLog = origConsoleLog;
    }
    setMode(mode) {
      this.input.setOption("mode", mode);
      this.output.setOption("mode", mode);
    }
    setTheme(theme) {
      this.input.setOption("theme", theme);
      this.output.setOption("theme", theme);
    }
  }

  var prompt = document.createElement('span'),
    promptContinuation = document.createElement('span'),
    errorMarker = document.createElement('span'),
    infoMarker = document.createElement('span'),
    previousCommand = document.createElement('span'),
    previousCommandContinuation = document.createElement('span'),
    completionValue = document.createElement('span');

  errorMarker.className = 'console-error gutter-icon';
  infoMarker.className = 'console-info gutter-icon';
  prompt.className = 'prompt gutter-icon';
  promptContinuation.className = 'prompt-continuation gutter-icon';
  previousCommand.className = 'prev-command gutter-icon';
  previousCommandContinuation.className = 'prev-command-continuation gutter-icon';
  completionValue.className = 'completion-value gutter-icon';

  function append(cm, text) {
    var doc = cm.getDoc();

    var lastLine = doc.lastLine();
    var line = doc.getLine(lastLine); // get the line contents
    var pos = CodeMirror.Pos(lastLine, line.length + 1);
    doc.replaceRange(text, pos); // adds a new line
    return [pos, CodeMirror.Pos(doc.lastLine())]
  }

  return Console;
});
<commit_msg>Reset console on Ctrl-L<commit_after>var CodeMirror;
(function(name, definition) {
  if( typeof module !== 'undefined' && module.exports ) {
    CodeMirror = require('codemirror');
    module.exports = definition();
  } else if(typeof define !== 'undefined' && define.amd ) {
    define(definition);
  } else {
    CodeMirror = window.CodeMirror;
    this[name] = definition();
  }
})('Console',function(){
  class Console {
    constructor(element, options = {}) {
      options.theme = options.theme || 'eclipse';
      options.mode = options.mode || 'javascript';

      this.container = element;
      this.container.classList.add('jsconsole', options.theme);
      this.logBuffer = [];
      this.history = [];
      this.historyIndex = -1;
      this.events = {};

      var enter = () => {
        var text = this.input.getValue().trim();
        if (text) this.exec(text);
      };

      var shiftEnter = () => {
        CodeMirror.commands.newlineAndIndent(this.input);
      };

      var cancel = () => {
        // TODO: copy, not cancel when we hit ^C on windows with an active selection
        this.resetInput();
      };

      var clear = () => {
        console.log('Clear input');
      };

      var up = (cm, evt) => {
        var cursor = this.input.getCursor();
        if (cursor.line === 0 && cursor.ch === 0) {
          this.historyIndex++;
          if (this.historyIndex > (this.history.length - 1)) this.historyIndex = this.history.length - 1;
          this.resetInput(this.history[this.historyIndex]);
        } else {
          CodeMirror.commands.goLineUp(this.input);
        }
      };

      var down = (cm, evt) => {
        var cursor = this.input.getCursor();
        var lastLine = this.input.lastLine();
        if (cursor.line === lastLine) {
          this.historyIndex--;
          if (this.historyIndex < -1) this.historyIndex = -1;
          this.resetInput(this.history[this.historyIndex]);
        } else {
          CodeMirror.commands.goLineDown(this.input);
        }
      };

      var inputKeymap = {
        "Up": up,
        "Down": down,
        "Ctrl-C": cancel,
        "Enter": enter,
        "Shift-Enter": shiftEnter,
        "Ctrl-L": clear,
      };

      var outputContainer = document.createElement('div');
      var inputContainer = document.createElement('div');
      outputContainer.className = 'jsconsole-output';
      inputContainer.className = 'jsconsole-input';

      this.container.appendChild(outputContainer);
      this.container.appendChild(inputContainer);

      this.input = CodeMirror(inputContainer, {
        theme: options.theme,
        mode: options.mode,
        extraKeys: inputKeymap,
        tabSize: 2,
        indentUnit: 2,
        undoDepth: 100,
        lineWrapping: true,
        viewportMargin: Infinity,
        gutters: ['repl']
      });
      this.output = CodeMirror(outputContainer, {
        theme: options.theme,
        mode: options.mode,
        gutters: ['repl'],
        tabSize: 2,
        viewportMargin: Infinity,
        lineWrapping: true,
        indentUnit: 2,
        readOnly: true
      });
      this.resetOutput();

      this.input.on('focus', () => {
        var cursor = this.output.getCursor();
        this.output.setSelection(cursor, cursor);
      });
      this.output.on('focus', () => {
        var cursor = this.input.getCursor();
        this.input.setSelection(cursor, cursor);
      });

      this.output.on('keydown', (cm, evt) => {
        // if we start typing when the output is focused, send it to the input
        if (evt.metaKey || evt.ctrlKey) {
          if (evt.which === 67) { // ^C
            // don't need to do
            // anything here yet.
          } else if (evt.which === 86) { // ^V
            this.input.triggerOnKeyDown(evt);
          }
        } else {
          this.input.triggerOnKeyDown(evt);
          this.input.focus();
        }
      });

      // codemirror doesn't handle mouseup events, so need to bind to the container
      outputContainer.addEventListener('mouseup', (evt) => {
        if (this.output.getSelection().length === 0) {
          // need to defer the input focusing to get it to work.
          setTimeout(() => this.input.focus(), 0);
        }
      });

      this.input.setMarker = this.output.setMarker = function(line, el) {
        this.setGutterMarker(line, 'repl', el.cloneNode());
      };

      this.resetInput();
    }
    on(event, fn) {
      this.events[event] = fn;
    }
    off(event) {
      delete this.events[event];
    }
    trigger(event, data) {
      if (typeof this.events[event] === 'function') this.events[event](data);
    }
    flushLogBuffer() {
      if (this.logBuffer.length) {
        this.logBuffer.forEach((msg)=>{
          this.print(msg);
          this.origConsoleLog(msg);
        });
        this.logBuffer.length = 0;
      }
    }
    addHistory(text) {
      this.historyIndex = -1;
      this.history.unshift(text);
    }
    appendEntry(input, output) {
      this.trigger('entry', {input, output});
      var range = this.appendOutput(input.toString().trim());
      this.output.setMarker(range[0].line, previousCommand);
      for (let i = range[0].line; i <= range[1].line; i++) {
        if (i > range[0].line) this.output.setMarker(i, previousCommandContinuation);
        this.output.addLineClass(i, 'text', 'prev-command');
      }

      this.flushLogBuffer();

      var parsedOutput =  this.parseOutput(output);

      range = this.appendOutput(parsedOutput.formatted);
      var isError = parsedOutput.value instanceof Error;

      if (isError) {
        this.output.setMarker(range[0].line, errorMarker);
      } else {
        this.output.setMarker(range[0].line, completionValue);
      }
      for (let i = range[0].line; i <= range[1].line; i++) {
        this.output.addLineClass(i, 'text', 'completion-value');
        this.output.addLineClass(i, 'text', parsedOutput.class);
      }
      this.output.addLineClass(range[1].line, 'text', 'completion-value-end');
    }
    parseOutput(value) {
      var type = typeof value;
      if (value instanceof Error) type = 'error';
      if (value === null) type = 'null';
      var output = {
        value : value,
        type : type,
        class : 'type-' + type
      };

      switch (type) {
        case "string":
          output.formatted =  '"' + value + '"';
          output.class = "string";
          break;
        case "undefined":
          output.formatted = "undefined";
          break;
        case "null":
          output.formatted = "null";
          break;
        case "object":
        case "array":
          // Todo: pretty print object output
          output.formatted = JSON.stringify(value);
          break;
        case "error":
          output.formatted = value.message.trim();
          break;
        default:
          output.formatted = value.toString().trim();
      }
      return output;
    }
    evaluate(code) {
      var out = {};
      try {
        out.completionValue = eval.call(null, code);
      } catch(e) {
        out.error = true;
        out.completionValue = e;
        out.recoverable = (e instanceof SyntaxError && e.message.match('^Unexpected (token|end)'));
      }
      return out;
    }
    exec(text) {
      this.isEvaluating = true;
      var rv = this.evaluate(text);
      if (!rv) return;
      this.isEvaluating = false;
      var doc = this.input.getDoc();

      if (rv.error && !rv.recoverable) {
        this.appendEntry(text, rv.completionValue);
        this.addHistory(text);
        this.resetInput();
      } else if (rv.recoverable) {
        CodeMirror.commands.newlineAndIndent(this.input);
      } else {
        this.appendEntry(text, rv.completionValue);
        this.addHistory(text);
        this.resetInput();
      }

      doc.eachLine((line) => {
        if (line.lineNo() === 0) this.input.setMarker(line, prompt);
        else this.input.setMarker(line, promptContinuation);
      });
    }
    resetInput(text = '') {
      this.input.setValue(text.toString());
      this.input.execCommand('goDocEnd');
      this.input.setMarker(0, prompt);
    }
    resetOutput() {
      // magic number to make things align properly when there is no input;
      this.output.setSize(null, 8);
      this.output.setValue('');
    }
    appendOutput(text) {
      this.output.setSize(null, 'auto');
      var doc = this.output.getDoc();
      var range;
      if (doc.getLine(doc.lastLine()).match(/^\s*$/)) {
        range = append(this.output, text.toString());
      } else {
        range = append(this.output, '\n' + text.toString());
        range[0].line = range[0].line + 1;
      }
      //this.output.markText(range[0], range[1], {className : 'output'});

      return range;
    }
    print(text, className = 'message', gutterMarker = document.createElement('span')) {
      var range = this.appendOutput(text);
      for (let i = range[0].line; i <= range[1].line; i++) {
        this.output.addLineClass(i, 'text', className);
        this.output.setMarker(i, gutterMarker);
      }
      return range;
    }
    // basic, dumb formatter for console.log style %X formatting
    simpleFormatter(msg, ...args) {
      if( typeof msg === 'string' ) {
        var replacementIndex = 0;
        return msg.replace(/%./mg,function(pattern, loc, originalString){
          return args[replacementIndex++];
        });
      } else {
        return msg + args;
      }
    }

    complexFormatter( ...args ) {
      let res = '';
      if( typeof args[0] === 'string' && args[0].search("%s") !== -1) {
        let s = args[0],
            search,
            i = 1;

        while( i < args.length && (search = s.search(/%s|%d|%i|%f]/)) !== -1 ) {
          let replace = s[search] + s[search+1];
          s = s.replace(replace,args[i]);
          i++;
        }
        res = s;
      } else {
        args.forEach(arg => {
          if( typeof arg === 'object' ) res += `${JSON.stringify(arg)} `;
          else res += `${arg} `;
        });
      }
      return res;
    }

    appendInput(text) {
      return append(this.input, text.toString());
    }
    wrapLog(console) {
      var origConsoleLog = console.log.bind(console);
      console.log = (...args) => {
        this.logBuffer.push(this.complexFormatter(...args));
        if (!this.isEvaluating) {
          this.flushLogBuffer();
        }
      };
      return this.origConsoleLog = origConsoleLog;
    }
    setMode(mode) {
      this.input.setOption("mode", mode);
      this.output.setOption("mode", mode);
    }
    setTheme(theme) {
      this.input.setOption("theme", theme);
      this.output.setOption("theme", theme);
    }
  }

  var prompt = document.createElement('span'),
    promptContinuation = document.createElement('span'),
    errorMarker = document.createElement('span'),
    infoMarker = document.createElement('span'),
    previousCommand = document.createElement('span'),
    previousCommandContinuation = document.createElement('span'),
    completionValue = document.createElement('span');

  errorMarker.className = 'console-error gutter-icon';
  infoMarker.className = 'console-info gutter-icon';
  prompt.className = 'prompt gutter-icon';
  promptContinuation.className = 'prompt-continuation gutter-icon';
  previousCommand.className = 'prev-command gutter-icon';
  previousCommandContinuation.className = 'prev-command-continuation gutter-icon';
  completionValue.className = 'completion-value gutter-icon';

  function append(cm, text) {
    var doc = cm.getDoc();

    var lastLine = doc.lastLine();
    var line = doc.getLine(lastLine); // get the line contents
    var pos = CodeMirror.Pos(lastLine, line.length + 1);
    doc.replaceRange(text, pos); // adds a new line
    return [pos, CodeMirror.Pos(doc.lastLine())]
  }

  return Console;
});
<|endoftext|>


<commit_before>/*
 * QuickBlox JavaScript SDK
 *
 * Main SDK Module
 *
 */

var config = require('./qbConfig');
var isBrowser = typeof window !== "undefined";

// Actual QuickBlox API starts here
function QuickBlox() {}

QuickBlox.prototype = {

  init: function(appId, authKey, authSecret, debug) {
    if (debug && typeof debug === 'boolean') config.debug = debug;
    else if (debug && typeof debug === 'object') config.set(debug);

    // include dependencies
    var Proxy = require('./qbProxy'),
        Auth = require('./modules/qbAuth'),
        Users = require('./modules/qbUsers'),
        Chat = require('./modules/qbChat'),
        // WebRTC = require('./modules/qbWebRTC'),
        Content = require('./modules/qbContent'),
        Location = require('./modules/qbLocation'),
        Messages = require('./modules/qbMessages'),
        Data = require('./modules/qbData');

    if (isBrowser) {
      // create Strophe Connection object
      var Connection = require('./qbStrophe');
      var conn = new Connection();
    }

    this.service = new Proxy();
    this.auth = new Auth(this.service);
    this.users = new Users(this.service);
    this.chat = new Chat(this.service, conn || null);
    // this.webrtc = new WebRTC(this.service, conn || null);
    this.content = new Content(this.service);
    this.location = new Location(this.service);
    this.messages = new Messages(this.service);
    this.data = new Data(this.service);

    // Initialization by outside token
    if (typeof appId === 'string' && !authKey && !authSecret) {
      this.service.setSession({ token: appId });
    } else {
      config.creds.appId = appId;
      config.creds.authKey = authKey;
      config.creds.authSecret = authSecret;
    }
    if(console && config.debug) console.log('QuickBlox.init', this);
  },

  createSession: function(params, callback) {
    this.auth.createSession(params, callback);
  },

  destroySession: function(callback) {
    this.auth.destroySession(callback);
  },

  login: function(params, callback) {
    this.auth.login(params, callback);
  },

  logout: function(callback) {
    this.auth.logout(callback);
  }

};

var QB = new QuickBlox();
QB.QuickBlox = QuickBlox;

module.exports = QB;
<commit_msg>enable webrtc<commit_after>/*
 * QuickBlox JavaScript SDK
 *
 * Main SDK Module
 *
 */

var config = require('./qbConfig');
var isBrowser = typeof window !== "undefined";

// Actual QuickBlox API starts here
function QuickBlox() {}

QuickBlox.prototype = {

  init: function(appId, authKey, authSecret, debug) {
    if (debug && typeof debug === 'boolean') config.debug = debug;
    else if (debug && typeof debug === 'object') config.set(debug);

    // include dependencies
    var Proxy = require('./qbProxy'),
        Auth = require('./modules/qbAuth'),
        Users = require('./modules/qbUsers'),
        Chat = require('./modules/qbChat'),
        WebRTC = require('./modules/qbWebRTC'),
        Content = require('./modules/qbContent'),
        Location = require('./modules/qbLocation'),
        Messages = require('./modules/qbMessages'),
        Data = require('./modules/qbData');

    if (isBrowser) {
      // create Strophe Connection object
      var Connection = require('./qbStrophe');
      var conn = new Connection();
    }

    this.service = new Proxy();
    this.auth = new Auth(this.service);
    this.users = new Users(this.service);
    this.chat = new Chat(this.service, conn || null);
    this.webrtc = new WebRTC(this.service, conn || null);
    this.content = new Content(this.service);
    this.location = new Location(this.service);
    this.messages = new Messages(this.service);
    this.data = new Data(this.service);

    // Initialization by outside token
    if (typeof appId === 'string' && !authKey && !authSecret) {
      this.service.setSession({ token: appId });
    } else {
      config.creds.appId = appId;
      config.creds.authKey = authKey;
      config.creds.authSecret = authSecret;
    }
    if(console && config.debug) console.log('QuickBlox.init', this);
  },

  createSession: function(params, callback) {
    this.auth.createSession(params, callback);
  },

  destroySession: function(callback) {
    this.auth.destroySession(callback);
  },

  login: function(params, callback) {
    this.auth.login(params, callback);
  },

  logout: function(callback) {
    this.auth.logout(callback);
  }

};

var QB = new QuickBlox();
QB.QuickBlox = QuickBlox;

module.exports = QB;
<|endoftext|>


<commit_before>var url       = require('url');
var qs        = require('querystring');
var http      = require('http');
var EventVat  = require('eventvat');
var request   = require('request');
var streamify = require('streamify');
var Hash      = require('hashish');
var FORMATS   = require('./formats');
var parseTime = require('./util').parseTime;

var INFO_URL = 'http://www.youtube.com/get_video_info?hl=en_US&video_id=';
var KEYS_TO_SPLIT = [
  'keywords'
, 'fmt_list'
, 'fexp'
, 'watermark'
, 'ad_channel_code_overlay'
];

// cache for recently looked up video infos
var cache = new EventVat({ autoexpire: 30 });

/**
 * Checks cache to see if info for this video has been fetched recently.
 * If not, get it, then download the video once the info is found.
 *
 * @param (string) link
 * @param (Object) options
 * @return (ReadableStream)
 */
function ytdl(link, options) {
  var id = url.parse(link, true).query.v;
  var stream = streamify({ superCtor: http.ClientResponse });

  options = options || {};
  options.quality = 'highest';

  if (cache.exists(id)) {
    var info = cache.get(id);
    process.nextTick(function() {
      download(options, stream, info);
    });

  } else {
    ytdl.getInfo(link, options, function(err, info) {
      if (err) {
        stream.emit('error', err);
        stream.readable = false;
        return;
      }

      download(options, stream, info);
    });
  }

  return stream;
}

/**
 * Downloads a video.
 *
 * @param (Object) options
 * @param (ReadableStream) stream
 * @param (Object) info
 * @return (ReadableStream)
 */
function download(options, stream, info) {
  var formats = info.formats;
  if (options.filter) {
    formats = formats.filter(options.filter);
  }

  var format;
  switch (options.quality) {
    case 'highest':
      format = formats[0];
      break;

    case 'lowest':
      format = formats[formats.length - 1];
      break;

    default:
      format = formats.filter(function(format) {
        return format.itag === options.quality;
      })[0];

  }

  if (!format) {
    stream.emit('error', new Error('No such format found'));
    return;
  }

  format = Hash.copy(format);
  var url = format.url;
  var requestOptions = Hash.copy(options);

  if (options.start) {
    url = url + '&begin=' + parseTime(options.start);
  }

  format.url = requestOptions.url = url;

  // start downloading the video
  var res = request(requestOptions);
  res.on('response', function(res) {
    if (res.statusCode !== 200) {
      return stream.emit('error', new Error('status code ' + res.statusCode));
    }

    format.size = res.headers['content-length'];
    stream.emit('info', info, format);
  });
  stream.resolve(res);
}

/**
 * Gets info from a video.
 *
 * @param (string) link
 * @param (Object) requestOptions
 * @param (Function(Error, Object)) callback
 */
ytdl.getInfo = function getInfo(link, requestOptions, callback) {
  if (typeof requestOptions === 'function') {
    callback = requestOptions;
    requestOptions = {};
  } else {
    requestOptions = Hash.copy(requestOptions);
  }

  var id = url.parse(link, true).query.v;
  if (!id) {
    process.nextTick(function() {
      callback(new Error('Video ID not found'));
    });
    return;
  }

  requestOptions.url = INFO_URL + id;

  request(requestOptions, function(err, res, body) {
    if (err) return callback(err);
    if (res.statusCode !== 200) {
      return callback(new Error('Video not found: ' + link));
    }

    var info = qs.parse(body);

    if (info.status === 'fail') {
      callback(new Error('Error ' + info.errorcode + ': ' + info.reason));
      return;
    }

    // split some keys by commas
    KEYS_TO_SPLIT.forEach(function(key) {
      if (!info[key]) return;
      info[key] = info[key].split(',').filter(function(v) { return v !== ''; });
    });

    // convert some strings to javascript numbers and booleans
    info = Hash.map(info, function(val) {
      var intVal = parseInt(val, 10);
      var floatVal = parseFloat(val, 10);

      if (intVal.toString() === val) {
        return intVal;
      } else if (floatVal.toString() === val) {
        return floatVal;
      } else if (val === 'True') {
        return true;
      } else if (val === 'False') {
        return false;
      } else {
        return val;
      }
    });

    info.fmt_list = info.fmt_list.map(function(format) {
      return format.split('/');
    });

    info.formats = info.url_encoded_fmt_stream_map
      .split(',')
      .map(function(format) {
        var data = qs.parse(format);
        if (data.sig) {
          data.url += '&signature=' + data.sig;
        }
        format = FORMATS[data.itag];

        if (!format) {
          err = new Error('No such format for itag ' + data.itag + ' found');
          return;
        }

        Hash(format).forEach(function(val, key) {
          data[key] = val;
        });

        return data;
      })
      ;

    delete info.url_encoded_fmt_stream_map;

    if (err) {
      return callback(err);
    }

    info.video_verticals = info.video_verticals
      .slice(1, -1)
      .split(', ')
      .filter(function(val) { return val !== ''; })
      .map(function(val) { return parseInt(val, 10); })
      ;

    cache.set(id, info);
    callback(null, info);
  });
};

/**
 * export
 */
module.exports = ytdl;
<commit_msg>support youtu.be URLs<commit_after>var url       = require('url');
var qs        = require('querystring');
var http      = require('http');
var EventVat  = require('eventvat');
var request   = require('request');
var streamify = require('streamify');
var Hash      = require('hashish');
var FORMATS   = require('./formats');
var parseTime = require('./util').parseTime;

var INFO_URL = 'http://www.youtube.com/get_video_info?hl=en_US&video_id=';
var KEYS_TO_SPLIT = [
  'keywords'
, 'fmt_list'
, 'fexp'
, 'watermark'
, 'ad_channel_code_overlay'
];

// cache for recently looked up video infos
var cache = new EventVat({ autoexpire: 30 });

/**
 * Checks cache to see if info for this video has been fetched recently.
 * If not, get it, then download the video once the info is found.
 *
 * @param (string) link
 * @param (Object) options
 * @return (ReadableStream)
 */
function ytdl(link, options) {
  var id = url.parse(link, true).query.v;
  var stream = streamify({ superCtor: http.ClientResponse });

  options = options || {};
  options.quality = 'highest';

  if (cache.exists(id)) {
    var info = cache.get(id);
    process.nextTick(function() {
      download(options, stream, info);
    });

  } else {
    ytdl.getInfo(link, options, function(err, info) {
      if (err) {
        stream.emit('error', err);
        stream.readable = false;
        return;
      }

      download(options, stream, info);
    });
  }

  return stream;
}

/**
 * Downloads a video.
 *
 * @param (Object) options
 * @param (ReadableStream) stream
 * @param (Object) info
 * @return (ReadableStream)
 */
function download(options, stream, info) {
  var formats = info.formats;
  if (options.filter) {
    formats = formats.filter(options.filter);
  }

  var format;
  switch (options.quality) {
    case 'highest':
      format = formats[0];
      break;

    case 'lowest':
      format = formats[formats.length - 1];
      break;

    default:
      format = formats.filter(function(format) {
        return format.itag === options.quality;
      })[0];

  }

  if (!format) {
    stream.emit('error', new Error('No such format found'));
    return;
  }

  format = Hash.copy(format);
  var url = format.url;
  var requestOptions = Hash.copy(options);

  if (options.start) {
    url = url + '&begin=' + parseTime(options.start);
  }

  format.url = requestOptions.url = url;

  // start downloading the video
  var res = request(requestOptions);
  res.on('response', function(res) {
    if (res.statusCode !== 200) {
      return stream.emit('error', new Error('status code ' + res.statusCode));
    }

    format.size = res.headers['content-length'];
    stream.emit('info', info, format);
  });
  stream.resolve(res);
}

/**
 * Gets info from a video.
 *
 * @param (string) link
 * @param (Object) requestOptions
 * @param (Function(Error, Object)) callback
 */
ytdl.getInfo = function getInfo(link, requestOptions, callback) {
  if (typeof requestOptions === 'function') {
    callback = requestOptions;
    requestOptions = {};
  } else {
    requestOptions = Hash.copy(requestOptions);
  }

  var linkParsed = url.parse(link, true);
  var id = linkParsed.hostname == 'youtu.be' ? linkParsed.pathname.slice(1) : linkParsed.query.v;

  if (!id) {
    process.nextTick(function() {
      callback(new Error('Video ID not found'));
    });
    return;
  }

  requestOptions.url = INFO_URL + id;

  request(requestOptions, function(err, res, body) {
    if (err) return callback(err);
    if (res.statusCode !== 200) {
      return callback(new Error('Video not found: ' + link));
    }

    var info = qs.parse(body);

    if (info.status === 'fail') {
      callback(new Error('Error ' + info.errorcode + ': ' + info.reason));
      return;
    }

    // split some keys by commas
    KEYS_TO_SPLIT.forEach(function(key) {
      if (!info[key]) return;
      info[key] = info[key].split(',').filter(function(v) { return v !== ''; });
    });

    // convert some strings to javascript numbers and booleans
    info = Hash.map(info, function(val) {
      var intVal = parseInt(val, 10);
      var floatVal = parseFloat(val, 10);

      if (intVal.toString() === val) {
        return intVal;
      } else if (floatVal.toString() === val) {
        return floatVal;
      } else if (val === 'True') {
        return true;
      } else if (val === 'False') {
        return false;
      } else {
        return val;
      }
    });

    info.fmt_list = info.fmt_list.map(function(format) {
      return format.split('/');
    });

    info.formats = info.url_encoded_fmt_stream_map
      .split(',')
      .map(function(format) {
        var data = qs.parse(format);
        if (data.sig) {
          data.url += '&signature=' + data.sig;
        }
        format = FORMATS[data.itag];

        if (!format) {
          err = new Error('No such format for itag ' + data.itag + ' found');
          return;
        }

        Hash(format).forEach(function(val, key) {
          data[key] = val;
        });

        return data;
      })
      ;

    delete info.url_encoded_fmt_stream_map;

    if (err) {
      return callback(err);
    }

    info.video_verticals = info.video_verticals
      .slice(1, -1)
      .split(', ')
      .filter(function(val) { return val !== ''; })
      .map(function(val) { return parseInt(val, 10); })
      ;

    cache.set(id, info);
    callback(null, info);
  });
};

/**
 * export
 */
module.exports = ytdl;
<|endoftext|>


<commit_before>// server.js
// where your node app starts

// init project
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var request = require('request');
var moment = require('moment')
// we've started you off with Express,
// but feel free to use whatever libs or frameworks you'd like through `package.json`.

// http://expressjs.com/en/starter/static-files.html
app.use(express.static('public'));
app.use(bodyParser.urlencoded({extended: true}));
// http://expressjs.com/en/starter/basic-routing.html
app.get("/", function (request, response) {
  response.sendFile(__dirname + '/views/index.html');
});

app.post('/meetupbot', function(req, res){
  //console.log(req.headers);
  console.log(JSON.stringify(req.body));
  var userName = req.body.user_name;
  var reply = {
    "text": "Hello, "+userName+" I am a MeetupBot. I show list of meetups going on near your location.\n Try following commands :",
    "attachments": [
        {
            title: "1) /meetupbot-find <location> (& <interest>)",
            text: "use this to find local meetup-groups based on your location \nfor ex: /meetupbot-find New-York"
            + "\noptional: add parameter for your interests: '/meetupbot-find New-York & <interest>'",
            color: "#764FA5"
        },
        {
        title: "2) /meetupbot-show <location> & <interest>",
        text: "use this to find events based on location and your interests \nfor ex: /meetupbot-show Mumbai & Javascript (Don't forget to use ampersand (&).)",
        color: "#764FA5"
        }
        ]
  };
  res.json(reply);

});

app.post('/meetupbot-show', function(req, res) {
  /* /meetupbot-show <Location> <Category/Interest> */
  var userName = req.body.user_name;
  var commandText = req.body.text;
  var area = commandText.split('&')[0];
  var interest = commandText.split('&')[1];
  console.log("command is "+commandText);
  var reply = {};
  var location={};
  var attachment=[];
  if(!commandText || commandText == undefined){
    reply.text = 'Please provide a location along with the command @'+userName+'\nFor ex: /meetupbot-show Mumbai & Javascript.';
    return res.json({text: reply.text});
  } else if(interest =='' || interest == undefined){
    reply.text = 'Please provide a location & search term along with the command @'+userName+'\nFor ex: /meetupbot-show Mumbai & Javascript.\nIt helps in filtering the list of meetups according to your interest :blush:.'+'\nActually it will be difficult to show a long list of meetups for me right now :stuck_out_tongue_winking_eye:.';
    res.json(reply);
  } else {
     reply.text = 'Hey '+userName+',\nThis is the list of meetups near '+area+'.';
     getGeoCode(area)
       .then((data) => {
         location.lat = data.lat;
         location.lon = data.lng;
         getMeetupEvents(location, interest)
           .then((events) =>{
             if(events.length == 0){
               reply.text = 'No Meetups found in '+area+' :sleuth_or_spy: .\nMake sure the location you entered is correct and try again.:slightly_smiling_face:';
               return res.json(reply);
             }
             events.forEach((event) => {
               var status = (event.status != undefined) ? ('Status - '+event.status) : 'Status - visible only to Members';
               var desc = event.description ? event.description.split('
')[0] :  "Description - Only visible to members.";
               var date = new Date(event.time + event.utc_offset);
               date = moment(date).format('lll');
               var venue = (event.venue != undefined) ? event.venue.address_1 : 'Only visible to members';
               attachment.push({
                 title: 'Group - '+event.group.name,
                 text: '<'+event.link+'| Event - '+event.name+'>',
                 author_name: status,
                 title_link: 'https://www.meetup.com/'+event.group.urlname,
                 color: "#764FA5",
                 fields: [
                      {
                          "title": "Date",
                          "value": date,
                          "short": true
                      },
                      {
                          "title": "Venue",
                          "value": venue,
                          "short": true
                      },
                      {
                          "title": "RSVP Count",
                          "value": event.yes_rsvp_count,
                          "short": true
                      }
                ]
               });
             });
             reply.attachments = attachment;
             return res.json(reply);
           }) // catch for getMeetupEvents
           .catch((e) => {
             console.log("error occured in getMeetupEvents promise as "+e);
             return res.json({text: 'Ops something went wrong. Please try again :blush:'});
           });
       }) // catch for getGeoCode
      .catch((e) => {
         console.log("error in geocode as "+e);
         return res.json({text: 'Ops something went wrong. Please try again :blush:'});
       });
  }
});

app.post('/meetupbot-find', function(req, res){
    var location = {};
    var commandText = req.body.text.replace(" ", "");
    if(commandText.includes("&")) {
    var area = commandText.split("&")[0];
    var interest = commandText.split("&")[1];
    } else {
      var area = commandText;
      var interest = "";
    }
    var userName = req.body.user_name;
    var reply = {};

    if(!commandText || commandText == undefined){
        reply.text = '@' + userName + ' Please provide a location along with the command \nFor ex: /meetupbot-find London'
        + ' (& <category>)';
        return res.json(reply);
    } else if(interest === undefined) {
        reply.text = '@' + userName + ' Please use the correct syntax: /meetupbot-find <location> & <interest>';
        return res.json(reply);
    } else {
        reply.text = "Hey @" + userName +"\nThose are the groups near " + area;
        if(interest) reply.text += " for" + interest;

        getGeoCode(area)
        .then(function(data) {
            location.lat = data.lat;
            location.lon = data.lng;

            findMeetupGroups(location, interest)
            .then(function(groups) {
                if (groups.length === 0) {
                    reply.text = 'No groups found near '+area+' :sleuth_or_spy: .\nMake sure the location you entered is correct '
                    + 'and you didn\'t forget the "&". \nPlease  try again.:slightly_smiling_face:';
                    return res.json(reply);
                } else if (groups.length > 20) {
                    reply.attachments = [];
                    for (var i = 0; i <21; i++) {
                        var current = groups[i];
                        composeAttachments(reply.attachments, current);
                    };
                    return res.json(reply);
                } else {
                    reply.attachments = [];
                    groups.forEach(function(group) {
                        composeAttachments(reply.attachments, group);
                    });
                    return res.json(reply);
                }

            })
            .catch(function() { //catch for findMeetupGroups
                return res.json({text: 'Ops something went wrong. Please try again :blush:'});
            })
        })
        .catch(function() { // catch for getGeoCode
            return res.json({text: 'Ops something went wrong. Please try again :blush:'});
        });
    }

});

/*
*function to get the Geocode from google geocode API.
*/
function getGeoCode(location){
  return new Promise(function(resolve, reject) {
    var options = {
      method: 'GET',
      url: 'http://maps.googleapis.com/maps/api/geocode/json',
      qs: { address: location }
    };

    request(options, function (error, res, body) {
      if (error) {
        console.log("Error occured in getGeoCode as "+error);
        reject();
      }
      else{
        body = JSON.parse(body);
        var loc = body.results[0].geometry.location;
        resolve(loc);
      }
    });
  });
}
/*
*function to get meetups near your city/town/location using meetup API
*/
function getMeetupEvents(location, interest) {
  var key = process.env.SECRET;

  return new Promise((resolve, reject) => {
    var options = { method: 'GET',
      url: 'https://api.meetup.com/find/events',
      qs: {
        key: key,
        lat: location.lat,
        lon: location.lon,
        text: interest,
        radius: 10
      }
    };

    console.log(options);
    request(options, function (error, response, body) {
      if (error) {
        console.log("error occured in getMeetupEvents as "+error);
        reject();
      } else{
        body = JSON.parse(body);
        console.log(body.length);
        resolve(body);
      }
    });
  });
};

/*
*function to get meetup-groups near your city/town/location using meetup API
*/
function findMeetupGroups (location, interest) {
    var key = process.env.SECRET;

    return new Promise(function(resolve, reject) {
        var options = {
            method: "GET",
            url: "https://api.meetup.com/find/groups",
            qs: {
                key: key,
                lat: location.lat,
                lon: location.lon,
                radius: 10
            }
        }
        if(!(interest === undefined || interest === "")) options.qs.text = interest;
        console.log(options);

        //api-request
        request(options, function(error, response, body) {
           if(error) {
               console.log("error occured in findMeetupGroups: " + error);
               reject
           } else {
               body = JSON.parse(body);
              // console.log(response);
               resolve(body);
           }
        });
    });
};

//function to help compose reply
function composeAttachments(arr, obj){
    arr.push({
                            title: obj.name,
                            text: /*obj.description,*/removeHtml(obj.description),
                            color: "#764FA5",
                            mrkdwn_in: ["text", "attachments"],
                            fields: [
                                {
                                    "title": "Link",
                                    "value": obj.link,
                                    "short": true
                                },
                                {
                                    "title": "Members",
                                    "value": obj.members,
                                    "short": true
                                },
                            ]
                        })
};

function removeHtml(str) {
    var tags = /<\/?\w+>/g, bold = /<\/?b>/g, reserved = /&\w+;/g, italics = /<\/?i>/g, linebreak = /<\/?br>/g, imgAndA = /<(?:a\s)|(?:img\s).+>/g;
    var descr;
    // cut str to 300 characters
    if (str.length>300) descr=str.substr(0, 300);
    else descr = str;
    var description = descr.replace(bold, "*").replace(italics, "_").replace(reserved, "").replace(linebreak, "\n");
    var result = description.replace(tags, "").replace(imgAndA, "").replace(/<$/, "");
    return result + "...";
};

// listen for requests :)
var listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});
<commit_msg>removeHtml() now successfully removes  and  tags<commit_after>// server.js
// where your node app starts

// init project
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var request = require('request');
var moment = require('moment')
// we've started you off with Express,
// but feel free to use whatever libs or frameworks you'd like through `package.json`.

// http://expressjs.com/en/starter/static-files.html
app.use(express.static('public'));
app.use(bodyParser.urlencoded({extended: true}));
// http://expressjs.com/en/starter/basic-routing.html
app.get("/", function (request, response) {
  response.sendFile(__dirname + '/views/index.html');
});

app.post('/meetupbot', function(req, res){
  //console.log(req.headers);
  console.log(JSON.stringify(req.body));
  var userName = req.body.user_name;
  var reply = {
    "text": "Hello, "+userName+" I am a MeetupBot. I show list of meetups going on near your location.\n Try following commands :",
    "attachments": [
        {
            title: "1) /meetupbot-find <location> (& <interest>)",
            text: "use this to find local meetup-groups based on your location \nfor ex: /meetupbot-find New-York"
            + "\noptional: add parameter for your interests: '/meetupbot-find New-York & <interest>'",
            color: "#764FA5"
        },
        {
        title: "2) /meetupbot-show <location> & <interest>",
        text: "use this to find events based on location and your interests \nfor ex: /meetupbot-show Mumbai & Javascript (Don't forget to use ampersand (&).)",
        color: "#764FA5"
        }
        ]
  };
  res.json(reply);

});

app.post('/meetupbot-show', function(req, res) {
  /* /meetupbot-show <Location> <Category/Interest> */
  var userName = req.body.user_name;
  var commandText = req.body.text;
  var area = commandText.split('&')[0];
  var interest = commandText.split('&')[1];
  console.log("command is "+commandText);
  var reply = {};
  var location={};
  var attachment=[];
  if(!commandText || commandText == undefined){
    reply.text = 'Please provide a location along with the command @'+userName+'\nFor ex: /meetupbot-show Mumbai & Javascript.';
    return res.json({text: reply.text});
  } else if(interest =='' || interest == undefined){
    reply.text = 'Please provide a location & search term along with the command @'+userName+'\nFor ex: /meetupbot-show Mumbai & Javascript.\nIt helps in filtering the list of meetups according to your interest :blush:.'+'\nActually it will be difficult to show a long list of meetups for me right now :stuck_out_tongue_winking_eye:.';
    res.json(reply);
  } else {
     reply.text = 'Hey '+userName+',\nThis is the list of meetups near '+area+'.';
     getGeoCode(area)
       .then((data) => {
         location.lat = data.lat;
         location.lon = data.lng;
         getMeetupEvents(location, interest)
           .then((events) =>{
             if(events.length == 0){
               reply.text = 'No Meetups found in '+area+' :sleuth_or_spy: .\nMake sure the location you entered is correct and try again.:slightly_smiling_face:';
               return res.json(reply);
             }
             events.forEach((event) => {
               var status = (event.status != undefined) ? ('Status - '+event.status) : 'Status - visible only to Members';
               var desc = event.description ? event.description.split('
')[0] :  "Description - Only visible to members.";
               var date = new Date(event.time + event.utc_offset);
               date = moment(date).format('lll');
               var venue = (event.venue != undefined) ? event.venue.address_1 : 'Only visible to members';
               attachment.push({
                 title: 'Group - '+event.group.name,
                 text: '<'+event.link+'| Event - '+event.name+'>',
                 author_name: status,
                 title_link: 'https://www.meetup.com/'+event.group.urlname,
                 color: "#764FA5",
                 fields: [
                      {
                          "title": "Date",
                          "value": date,
                          "short": true
                      },
                      {
                          "title": "Venue",
                          "value": venue,
                          "short": true
                      },
                      {
                          "title": "RSVP Count",
                          "value": event.yes_rsvp_count,
                          "short": true
                      }
                ]
               });
             });
             reply.attachments = attachment;
             return res.json(reply);
           }) // catch for getMeetupEvents
           .catch((e) => {
             console.log("error occured in getMeetupEvents promise as "+e);
             return res.json({text: 'Ops something went wrong. Please try again :blush:'});
           });
       }) // catch for getGeoCode
      .catch((e) => {
         console.log("error in geocode as "+e);
         return res.json({text: 'Ops something went wrong. Please try again :blush:'});
       });
  }
});

app.post('/meetupbot-find', function(req, res){
    var location = {};
    var commandText = req.body.text.replace(" ", "");
    if(commandText.includes("&")) {
    var area = commandText.split("&")[0];
    var interest = commandText.split("&")[1];
    } else {
      var area = commandText;
      var interest = "";
    }
    var userName = req.body.user_name;
    var reply = {};

    if(!commandText || commandText == undefined){
        reply.text = '@' + userName + ' Please provide a location along with the command \nFor ex: /meetupbot-find London'
        + ' (& <category>)';
        return res.json(reply);
    } else if(interest === undefined) {
        reply.text = '@' + userName + ' Please use the correct syntax: /meetupbot-find <location> & <interest>';
        return res.json(reply);
    } else {
        reply.text = "Hey @" + userName +"\nThose are the groups near " + area;
        if(interest) reply.text += " for" + interest;

        getGeoCode(area)
        .then(function(data) {
            location.lat = data.lat;
            location.lon = data.lng;

            findMeetupGroups(location, interest)
            .then(function(groups) {
                if (groups.length === 0) {
                    reply.text = 'No groups found near '+area+' :sleuth_or_spy: .\nMake sure the location you entered is correct '
                    + 'and you didn\'t forget the "&". \nPlease  try again.:slightly_smiling_face:';
                    return res.json(reply);
                } else if (groups.length > 20) {
                    reply.attachments = [];
                    for (var i = 0; i <21; i++) {
                        var current = groups[i];
                        composeAttachments(reply.attachments, current);
                    };
                    return res.json(reply);
                } else {
                    reply.attachments = [];
                    groups.forEach(function(group) {
                        composeAttachments(reply.attachments, group);
                    });
                    return res.json(reply);
                }

            })
            .catch(function() { //catch for findMeetupGroups
                return res.json({text: 'Ops something went wrong. Please try again :blush:'});
            })
        })
        .catch(function() { // catch for getGeoCode
            return res.json({text: 'Ops something went wrong. Please try again :blush:'});
        });
    }

});

/*
*function to get the Geocode from google geocode API.
*/
function getGeoCode(location){
  return new Promise(function(resolve, reject) {
    var options = {
      method: 'GET',
      url: 'http://maps.googleapis.com/maps/api/geocode/json',
      qs: { address: location }
    };

    request(options, function (error, res, body) {
      if (error) {
        console.log("Error occured in getGeoCode as "+error);
        reject();
      }
      else{
        body = JSON.parse(body);
        var loc = body.results[0].geometry.location;
        resolve(loc);
      }
    });
  });
}
/*
*function to get meetups near your city/town/location using meetup API
*/
function getMeetupEvents(location, interest) {
  var key = process.env.SECRET;

  return new Promise((resolve, reject) => {
    var options = { method: 'GET',
      url: 'https://api.meetup.com/find/events',
      qs: {
        key: key,
        lat: location.lat,
        lon: location.lon,
        text: interest,
        radius: 10
      }
    };

    console.log(options);
    request(options, function (error, response, body) {
      if (error) {
        console.log("error occured in getMeetupEvents as "+error);
        reject();
      } else{
        body = JSON.parse(body);
        console.log(body.length);
        resolve(body);
      }
    });
  });
};

/*
*function to get meetup-groups near your city/town/location using meetup API
*/
function findMeetupGroups (location, interest) {
    var key = process.env.SECRET;

    return new Promise(function(resolve, reject) {
        var options = {
            method: "GET",
            url: "https://api.meetup.com/find/groups",
            qs: {
                key: key,
                lat: location.lat,
                lon: location.lon,
                radius: 10
            }
        }
        if(!(interest === undefined || interest === "")) options.qs.text = interest;
        console.log(options);

        //api-request
        request(options, function(error, response, body) {
           if(error) {
               console.log("error occured in findMeetupGroups: " + error);
               reject
           } else {
               body = JSON.parse(body);
              // console.log(response);
               resolve(body);
           }
        });
    });
};

//function to help compose reply
function composeAttachments(arr, obj){
    arr.push({
                            title: obj.name,
                            text: /*obj.description,*/removeHtml(obj.description),
                            color: "#764FA5",
                            mrkdwn_in: ["text", "attachments"],
                            fields: [
                                {
                                    "title": "Link",
                                    "value": obj.link,
                                    "short": true
                                },
                                {
                                    "title": "Members",
                                    "value": obj.members,
                                    "short": true
                                },
                            ]
                        })
};

function removeHtml(str) {
    var tags = /<\/?\w+>/g, bold = /<\/?b>/g, reserved = /&\w+;/g, italics = /<\/?i>/g, linebreak = /<\/?br>/g, imgAndA = /<(?:a\s|img\s).+>/g;
    var descr;
    // cut str to 300 characters
    if (str.length>300) descr=str.substr(0, 300);
    else descr = str;
    var description = descr.replace(bold, "*").replace(italics, "_").replace(reserved, "").replace(linebreak, "\n");
    var result = description.replace(tags, "").replace(imgAndA, "").replace(/<$/, "");
    return result + "...";
};

// listen for requests :)
var listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});
<|endoftext|>


<commit_before>var Views = {
	Options: Backbone.View.extend({
		tagName: "form",

		events: {
			"change input": "handleChange"
		},

		initialize: function() {
			this.$el.appendTo("body");

			var metrics = localStorage.getItem("metrics") === "on";
			this.model.set("metrics", metrics);

			this.model.on("change", this.render, this);
			this.render();
		},

		render: function() {
			var data = this.model.toJSON();
			this.$el.html(Templates.Options(data));

			return this;
		},

		handleChange: function(event) {
			var metrics = this.$("[name=metrics]").prop("checked");

			if (!metrics) {
				this.setAndStore("metrics", "off");
			} else if (confirm("Enabling this will query Altmetric and Scopus for article-level metrics, and they will be able to see your search terms.")) {
				this.setAndStore("metrics", "on");
			} else {
				event.preventDefault();
			}
		},

		setAndStore: function(name, metrics) {
			this.model.set(name, metrics);
			localStorage.setItem(name, metrics);
			window.location.reload(); // TODO: just update the page
		}
	}),

	Input: Backbone.View.extend({
		tagName: "form",

		attributes: {
			autocapitalize: "off"
		},

		events: {
			"change input[type=checkbox],select": "submitChangedForm",
			"click .clear": "clearInput",
			//"click input[name=term]": "selectInput"
		},

		initialize: function() {
			this.$el.appendTo("body");

			if (location.search) {
				this.parseQueryString().forEach(this.handleQueryPart, this);

				// only use "days" for "related" queries
				if (!this.model.get("relatedQuery")) {
					this.model.set("days", 0);
				}
			}

			this.model.on("change", this.render, this);
			this.render();
		},

		render: function() {
			var data = this.model.toJSON();
			this.$el.html(Templates.Input(data));
		},

		parseQueryString: function() {
			return location.search.substring(1).split("&").map(function(item) {
				return item.split("=").map(decodeURIComponent).map(function(text) {
					return text.replace(/\+/g, " ");
				});
			});
		},

		handleQueryPart: function(item) {
			var name = item[0];
			var value = item[1].replace(/\/$/, "");

			switch (name) {
				case "days":
					this.model.set("days", Number(value));
					return;

				case "term":
					this.model.set("relatedQuery", value.match(/^related:/));
					this.model.set("term", value);
					break;

				case "filter":
					var filters = this.model.get("filters");

					if (typeof filters[value] !== "undefined") {
						filters[value].enabled = true;
						this.model.set("filters", filters);
					}

					break;
			}
		},

		submitChangedForm: function() {
			this.$el.submit();
		},

		clearInput: function() {
			this.model.set("term", null);
			this.$("[name=term]").val("").focus();
		},

		selectInput: function(event) {
			$(event.currentTarget).select();
		}
	}),

	Articles: Backbone.View.extend({
		tagName: "ol",
		offset: 0,
		limit: 5,

		initialize: function() {
			this.$el.appendTo("body");
			this.collection.on("reset", this.reset, this);
			this.collection.on("add", this.add, this);
		},

		reset: function() {
			this.$el.empty();

			this.collection.each(this.add, this);

			var articles = $(".article");

			if (articles.length === 1) {
				articles.trigger("toggleExpanded");
			}
		},

		add: function(article) {
			var view = new Views.Article({ model: article });
			this.$el.append(view.render().el);
		}
	}),

	Article: Backbone.View.extend({
		tagName: "li",
		className: "article",

		events: {
			"click a[data-action]": "action",
			"toggleExpanded": "toggleExpanded",
			"click .link": "handleLink",
		},

		initialize: function() {
			this.links = new Views.Links({ model: this.model });
			this.metrics = new Views.Metrics({ collection: this.model.metrics });

			this.model.on("change", this.render, this);
		},

		render: function() {
			var data = this.model.toJSON();
			this.$el.html(Templates.Article(data));

			this.$el.find("[property=creators]").formatAuthors(5, "creator");
			this.$el.find("[property=abstract]").formatAbstract();

			this.$el.find("footer").append(this.links.$el);
			this.$el.find(".context").append(this.metrics.$el);

			return this;
		},

		action: function(event) {
			if (event.metaKey || event.ctrlKey) {
				return true;
			}

			var node = $(event.currentTarget);

			switch (node.data("action")) {
				case "show-abstract":
					node.closest("article").trigger("toggleExpanded");
				break;
			}

			return false;
		},

		toggleExpanded: function(event) {
			var node = $(event.target);
			var expanded = node.is(".expanded");
			$(".expanded").removeClass("expanded");
			node.toggleClass("expanded", !expanded);

			var url = this.$(".read").attr("href");

			$(".article.active").removeClass("active");

			if (!expanded) {
				node.parent().addClass("active").attr("tabIndex", -1).focus().scrollIntoView();
				window.parent.postMessage({ url: url }, window.location.origin);
			}
		},

		handleLink: function(event) {
			var node = $(event.target);

			switch (node.data("intent")) {
				case "save":
					var type = localStorage.getItem("saveType");
					if (type) {
						this.$(".links [rel=save][type='" + type + "']").click();
					} else {
						node.next(".link").click();
					}
					return;

				case "find":
					var type = localStorage.getItem("findType");

					if (type) {
						this.$(".links [rel=find][type='" + type + "']").click();
					} else {
						node.next(".link").click();
					}
					return;

				case "read":
					this.openURL(node.attr("href"));
					return false;
			}

			var targetSelector = node.data("dropdown-target");

			if (targetSelector) {
				var target = this.$(targetSelector);

				if (target.is(":visible")) {
					target.hide();
				} else {
					event.stopPropagation();
					var offset = node.offset();
					var previous = node.prev(".link");

					target.show();
					target.offset({ top: offset.top + node.height(), left: offset.left - previous.width() });

					window.setTimeout(function() {
						$(document).one("click", function() {
							$(".dropdown-list:visible").hide();
						});
					}, 100);
				}

				return false;
			}

			switch (node.attr("rel")) {
				case "related":
					return;

				case "add-related":
					event.preventDefault();

					var pmid = this.model.get("pmid");

					var currentTerm = $.trim(app.models.query.get("term"));

					var term;
					if (app.models.query.get("relatedQuery")) {
						term = currentTerm + "," + pmid;
					} else {
						term = "related:" + pmid;
					}

					app.models.query.set("term", term);
					app.views.input.$el.submit();

					return;

				case "save":
					event.preventDefault();
					event.stopPropagation();
					localStorage.setItem("saveType", node.attr("type"));
					if (node.attr("download")) {
						window.location = node.attr("href");
					} else {
						this.openURL(node.attr("href"));
					}
					return;

				case "find":
					event.preventDefault();
					event.stopPropagation();
					localStorage.setItem("findType", node.attr("type"));
					this.openURL(node.attr("href"));
					return;

				default:
					return;
			}
		},

		openURL: function(url) {
			if (typeof window.parent == "defined") {
				window.parent.getElementById("external").src = url;
			} else {
				window.open(url);
			}
		}
	}),

	Metrics: Backbone.View.extend({
		tagName: "span",
		className: "metrics",

		initialize: function() {
			this.collection.on("reset", this.reset, this);
			this.collection.on("add", this.add, this);
		},

		reset: function() {
			this.$el.empty();
			this.collection.each(this.add, this);
		},

		add: function(metric) {
			var view = new Views.Metric({ model: metric });
			view.render().$el.appendTo(this.$el);
		}
	}),

	Metric: Backbone.View.extend({
		tagName: "a",

		className: "metric",

		attributes: {
			target: "_blank"
		},

		initialize: function() {
			this.model.on("change", this.render, this);
		},

		render: function() {
			var data = this.model.toJSON();

			this.$el.attr("href", data.url).text(data.text);

			if (data.image) {
				$("<img/>", { src: "images/" + data.image }).prependTo(this.$el);
			}

			return this;
		}
	}),

	Links: Backbone.View.extend({
		className: "links",

		initialize: function() {
			this.render();
		},

		render: function() {
			var data = this.model.toJSON();
			this.$el.html(Templates.Links(data));
		}
	}),

	Pagination: Backbone.View.extend({
		tagName: "a",

		events: {
			"click": "fetchPage"
		},

        initialize: function() {
            _.bindAll(this);

            this
                .$el
                .attr("href", "#")
                .attr("rel", "next")
                .html("More ↓")
                .data("offset", 0)
                .hide()
                .appendTo("body");
        },

        start: function() {
            this.fetchPage();
            this.watchScrollPosition(this.fetchPage, 500, 500);
        },

        watchScrollPosition: function(callback, distance, interval) {
            var $window = $(window),
                $document = $(document);

            var checkScrollPosition = function() {
                var top = $document.height() - $window.height() - distance;

                if ($window.scrollTop() >= top) {
                    callback();
                }
            };

            setInterval(checkScrollPosition, interval);
        },

		setNextOffset: function() {
			var offset = app.views.articles.offset + app.views.articles.limit;
			this.$el.data("offset", offset).removeClass("loading").html("More ↓");
			this.$el.show();
		},

		fetchPage: function() {
			var node = this.$el;

			if (node.hasClass("loading")) {
				return false;
			}

			var spinner = $("<img/>", { src: "./images/spinner.gif"}).addClass("spinner");

			var count = app.models.query.get("count");
			var text;
			if (count) {
				var offset = app.views.articles.offset + app.views.articles.limit + 1;
				var nextOffset = Math.min(count, offset + app.views.articles.limit);
				var text = "Loading " + offset + " - " + nextOffset + " of " + this.numberWithCommas(count) + " articles";
			} else {
				text = "Searching";
			}
			node.addClass("loading").text(text).append(spinner);

			app.views.articles.offset = node.data("offset");

			app.collections.articles.fetch({ add: true, success: this.collectionUpdated });

            return false;
        },

        numberWithCommas: function(x) {
            return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
        },

		noMoreItems: function() {
			this.$el.text("No more items");
		},

		collectionUpdated: function() {
			if (app.views.articles.offset == 0) {
				$(document).trigger("ZoteroItemUpdated");
			}
		}
	})
};<commit_msg>Update views.js<commit_after>var Views = {
	Options: Backbone.View.extend({
		tagName: "form",

		events: {
			"change input": "handleChange"
		},

		initialize: function() {
			this.$el.appendTo("body");

			//var metrics = localStorage.getItem("metrics") === "on";
			this.model.set("metrics", true);

			this.model.on("change", this.render, this);
			this.render();
		},

		render: function() {
			var data = this.model.toJSON();
			this.$el.html(Templates.Options(data));

			return this;
		},

		setAndStore: function(name, metrics) {
			this.model.set(name, metrics);
			localStorage.setItem(name, metrics);
			window.location.reload(); // TODO: just update the page
		}
	}),

	Input: Backbone.View.extend({
		tagName: "form",

		attributes: {
			autocapitalize: "off"
		},

		events: {
			"change input[type=checkbox],select": "submitChangedForm",
			"click .clear": "clearInput",
			//"click input[name=term]": "selectInput"
		},

		initialize: function() {
			this.$el.appendTo("body");

			if (location.search) {
				this.parseQueryString().forEach(this.handleQueryPart, this);

				// only use "days" for "related" queries
				if (!this.model.get("relatedQuery")) {
					this.model.set("days", 0);
				}
			}

			this.model.on("change", this.render, this);
			this.render();
		},

		render: function() {
			var data = this.model.toJSON();
			this.$el.html(Templates.Input(data));
		},

		parseQueryString: function() {
			return location.search.substring(1).split("&").map(function(item) {
				return item.split("=").map(decodeURIComponent).map(function(text) {
					return text.replace(/\+/g, " ");
				});
			});
		},

		handleQueryPart: function(item) {
			var name = item[0];
			var value = item[1].replace(/\/$/, "");

			switch (name) {
				case "days":
					this.model.set("days", Number(value));
					return;

				case "term":
					this.model.set("relatedQuery", value.match(/^related:/));
					this.model.set("term", value);
					break;

				case "filter":
					var filters = this.model.get("filters");

					if (typeof filters[value] !== "undefined") {
						filters[value].enabled = true;
						this.model.set("filters", filters);
					}

					break;
			}
		},

		submitChangedForm: function() {
			this.$el.submit();
		},

		clearInput: function() {
			this.model.set("term", null);
			this.$("[name=term]").val("").focus();
		},

		selectInput: function(event) {
			$(event.currentTarget).select();
		}
	}),

	Articles: Backbone.View.extend({
		tagName: "ol",
		offset: 0,
		limit: 5,

		initialize: function() {
			this.$el.appendTo("body");
			this.collection.on("reset", this.reset, this);
			this.collection.on("add", this.add, this);
		},

		reset: function() {
			this.$el.empty();

			this.collection.each(this.add, this);

			var articles = $(".article");

			if (articles.length === 1) {
				articles.trigger("toggleExpanded");
			}
		},

		add: function(article) {
			var view = new Views.Article({ model: article });
			this.$el.append(view.render().el);
		}
	}),

	Article: Backbone.View.extend({
		tagName: "li",
		className: "article",

		events: {
			"click a[data-action]": "action",
			"toggleExpanded": "toggleExpanded",
			"click .link": "handleLink",
		},

		initialize: function() {
			this.links = new Views.Links({ model: this.model });
			this.metrics = new Views.Metrics({ collection: this.model.metrics });

			this.model.on("change", this.render, this);
		},

		render: function() {
			var data = this.model.toJSON();
			this.$el.html(Templates.Article(data));

			this.$el.find("[property=creators]").formatAuthors(5, "creator");
			this.$el.find("[property=abstract]").formatAbstract();

			this.$el.find("footer").append(this.links.$el);
			this.$el.find(".context").append(this.metrics.$el);

			return this;
		},

		action: function(event) {
			if (event.metaKey || event.ctrlKey) {
				return true;
			}

			var node = $(event.currentTarget);

			switch (node.data("action")) {
				case "show-abstract":
					node.closest("article").trigger("toggleExpanded");
				break;
			}

			return false;
		},

		toggleExpanded: function(event) {
			var node = $(event.target);
			var expanded = node.is(".expanded");
			$(".expanded").removeClass("expanded");
			node.toggleClass("expanded", !expanded);

			var url = this.$(".read").attr("href");

			$(".article.active").removeClass("active");

			if (!expanded) {
				node.parent().addClass("active").attr("tabIndex", -1).focus().scrollIntoView();
				window.parent.postMessage({ url: url }, window.location.origin);
			}
		},

		handleLink: function(event) {
			var node = $(event.target);

			switch (node.data("intent")) {
				case "save":
					var type = localStorage.getItem("saveType");
					if (type) {
						this.$(".links [rel=save][type='" + type + "']").click();
					} else {
						node.next(".link").click();
					}
					return;

				case "find":
					var type = localStorage.getItem("findType");

					if (type) {
						this.$(".links [rel=find][type='" + type + "']").click();
					} else {
						node.next(".link").click();
					}
					return;

				case "read":
					this.openURL(node.attr("href"));
					return false;
			}

			var targetSelector = node.data("dropdown-target");

			if (targetSelector) {
				var target = this.$(targetSelector);

				if (target.is(":visible")) {
					target.hide();
				} else {
					event.stopPropagation();
					var offset = node.offset();
					var previous = node.prev(".link");

					target.show();
					target.offset({ top: offset.top + node.height(), left: offset.left - previous.width() });

					window.setTimeout(function() {
						$(document).one("click", function() {
							$(".dropdown-list:visible").hide();
						});
					}, 100);
				}

				return false;
			}

			switch (node.attr("rel")) {
				case "related":
					return;

				case "add-related":
					event.preventDefault();

					var pmid = this.model.get("pmid");

					var currentTerm = $.trim(app.models.query.get("term"));

					var term;
					if (app.models.query.get("relatedQuery")) {
						term = currentTerm + "," + pmid;
					} else {
						term = "related:" + pmid;
					}

					app.models.query.set("term", term);
					app.views.input.$el.submit();

					return;

				case "save":
					event.preventDefault();
					event.stopPropagation();
					localStorage.setItem("saveType", node.attr("type"));
					if (node.attr("download")) {
						window.location = node.attr("href");
					} else {
						this.openURL(node.attr("href"));
					}
					return;

				case "find":
					event.preventDefault();
					event.stopPropagation();
					localStorage.setItem("findType", node.attr("type"));
					this.openURL(node.attr("href"));
					return;

				default:
					return;
			}
		},

		openURL: function(url) {
			if (typeof window.parent == "defined") {
				window.parent.getElementById("external").src = url;
			} else {
				window.open(url);
			}
		}
	}),

	Metrics: Backbone.View.extend({
		tagName: "span",
		className: "metrics",

		initialize: function() {
			this.collection.on("reset", this.reset, this);
			this.collection.on("add", this.add, this);
		},

		reset: function() {
			this.$el.empty();
			this.collection.each(this.add, this);
		},

		add: function(metric) {
			var view = new Views.Metric({ model: metric });
			view.render().$el.appendTo(this.$el);
		}
	}),

	Metric: Backbone.View.extend({
		tagName: "a",

		className: "metric",

		attributes: {
			target: "_blank"
		},

		initialize: function() {
			this.model.on("change", this.render, this);
		},

		render: function() {
			var data = this.model.toJSON();

			this.$el.attr("href", data.url).text(data.text);

			if (data.image) {
				$("<img/>", { src: "images/" + data.image }).prependTo(this.$el);
			}

			return this;
		}
	}),

	Links: Backbone.View.extend({
		className: "links",

		initialize: function() {
			this.render();
		},

		render: function() {
			var data = this.model.toJSON();
			this.$el.html(Templates.Links(data));
		}
	}),

	Pagination: Backbone.View.extend({
		tagName: "a",

		events: {
			"click": "fetchPage"
		},

        initialize: function() {
            _.bindAll(this);

            this
                .$el
                .attr("href", "#")
                .attr("rel", "next")
                .html("More ↓")
                .data("offset", 0)
                .hide()
                .appendTo("body");
        },

        start: function() {
            this.fetchPage();
            this.watchScrollPosition(this.fetchPage, 500, 500);
        },

        watchScrollPosition: function(callback, distance, interval) {
            var $window = $(window),
                $document = $(document);

            var checkScrollPosition = function() {
                var top = $document.height() - $window.height() - distance;

                if ($window.scrollTop() >= top) {
                    callback();
                }
            };

            setInterval(checkScrollPosition, interval);
        },

		setNextOffset: function() {
			var offset = app.views.articles.offset + app.views.articles.limit;
			this.$el.data("offset", offset).removeClass("loading").html("More ↓");
			this.$el.show();
		},

		fetchPage: function() {
			var node = this.$el;

			if (node.hasClass("loading")) {
				return false;
			}

			var spinner = $("<img/>", { src: "./images/spinner.gif"}).addClass("spinner");

			var count = app.models.query.get("count");
			var text;
			if (count) {
				var offset = app.views.articles.offset + app.views.articles.limit + 1;
				var nextOffset = Math.min(count, offset + app.views.articles.limit);
				var text = "Loading " + offset + " - " + nextOffset + " of " + this.numberWithCommas(count) + " articles";
			} else {
				text = "Searching";
			}
			node.addClass("loading").text(text).append(spinner);

			app.views.articles.offset = node.data("offset");

			app.collections.articles.fetch({ add: true, success: this.collectionUpdated });

            return false;
        },

        numberWithCommas: function(x) {
            return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
        },

		noMoreItems: function() {
			this.$el.text("No more items");
		},

		collectionUpdated: function() {
			if (app.views.articles.offset == 0) {
				$(document).trigger("ZoteroItemUpdated");
			}
		}
	})
};
<|endoftext|>


<commit_before>var LoadingBar = require('./LoadingBar.js');
var Percentage = require('./Percentage.js');

function Overlay(parentElement) {
    'use strict';
    this.parentElement = parentElement;
    this.idName = "qLoverlay";
    this.className = "queryloader__overlay";
    this.element = null;
    this.loadingBar = null;
    this.percentage = null;
    this.backgroundColor = "#000";
    this.barHeight = 1;
    this.fadeOutTime = 300;
    this.showPercentage = false;
}

Overlay.prototype.init = function () {
    "use strict";
    this.create();

    this.loadingBar = new LoadingBar();
    this.loadingBar.barHeight = this.barHeight;
    this.loadingBar.create();
    this.element.appendChild(this.loadingBar.element);

    if (this.showPercentage) {
        this.percentage = new Percentage();
        this.percentage.create();
        this.element.appendChild(this.percentage.element);
    }

    this.parentElement.appendChild(this.element);
};

Overlay.prototype.create = function () {
    'use strict';
    this.element = (document.querySelector("#" + this.idName) || document.createElement("div"));
    this.element.setAttribute("class", this.className);
    this.element.setAttribute("id", this.qLoverlay);
    this.applyStyling();
};

Overlay.prototype.applyStyling = function () {
    'use strict';
    //determine postion of overlay and set parent position
    this.element.style.position = this.calculatePosition();
    this.element.style.width = "100%";
    this.element.style.height = "100%";
    this.element.style.backgroundColor = this.backgroundColor;
    this.element.style.backgroundPosition = "fixed";
    this.element.style.zIndex = 666999; //very HIGH
    this.element.style.top = "0";
    this.element.style.left = "0";

    this.element.style.WebkitTransition = "opacity " + this.fadeOutTime + "ms";
    this.element.style.MozTransition = "opacity " + this.fadeOutTime + "ms";
    this.element.style.OTransition = "opacity " + this.fadeOutTime + "ms";
    this.element.style.MsTransition = "opacity " + this.fadeOutTime + "ms";
    this.element.style.Transition = "opacity " + this.fadeOutTime + "ms";
};

Overlay.prototype.calculatePosition = function () {
    'use strict';
    var overlayPosition = "absolute";

    if (this.parentElement.tagName.toLowerCase() === "body") {
        overlayPosition = "fixed";
    } else {
        if (this.parentElement.style.position !== "fixed" || this.parentElement.style.position !== "absolute" ) {
            this.parentElement.style.position = "relative";
        }
    }

    return overlayPosition;
};

Overlay.prototype.updateProgress = function (percentage, time) {
    "use strict";
    if (this.loadingBar !== null) {
        this.loadingBar.updateProgress(percentage, time);
    }

    if (this.percentage !== null) {
        this.percentage.updateProgress(percentage, time);
    }
};

Overlay.prototype.remove = function () {
    "use strict";
    this.element.parentNode.removeChild(this.element);
};

module.exports = Overlay;<commit_msg>pass barcolor to bar<commit_after>var LoadingBar = require('./LoadingBar.js');
var Percentage = require('./Percentage.js');

function Overlay(parentElement) {
    'use strict';
    this.parentElement = parentElement;
    this.idName = "qLoverlay";
    this.className = "queryloader__overlay";
    this.element = null;
    this.loadingBar = null;
    this.percentage = null;
    this.barColor = "#ff0000";
    this.backgroundColor = "#000";
    this.barHeight = 1;
    this.fadeOutTime = 300;
    this.showPercentage = false;
}

Overlay.prototype.init = function () {
    "use strict";
    this.create();

    this.loadingBar = new LoadingBar();
    this.loadingBar.barHeight = this.barHeight;
    this.loadingBar.barColor = this.barColor;
    this.loadingBar.create();
    this.element.appendChild(this.loadingBar.element);

    if (this.showPercentage) {
        this.percentage = new Percentage();
        this.percentage.color = this.barColor;
        this.percentage.create();
        this.element.appendChild(this.percentage.element);
    }

    this.parentElement.appendChild(this.element);
};

Overlay.prototype.create = function () {
    'use strict';
    this.element = (document.querySelector("#" + this.idName) || document.createElement("div"));
    this.element.setAttribute("class", this.className);
    this.element.setAttribute("id", this.qLoverlay);
    this.applyStyling();
};

Overlay.prototype.applyStyling = function () {
    'use strict';
    //determine postion of overlay and set parent position
    this.element.style.position = this.calculatePosition();
    this.element.style.width = "100%";
    this.element.style.height = "100%";
    this.element.style.backgroundColor = this.backgroundColor;
    this.element.style.backgroundPosition = "fixed";
    this.element.style.zIndex = 666999; //very HIGH
    this.element.style.top = "0";
    this.element.style.left = "0";

    this.element.style.WebkitTransition = "opacity " + this.fadeOutTime + "ms";
    this.element.style.MozTransition = "opacity " + this.fadeOutTime + "ms";
    this.element.style.OTransition = "opacity " + this.fadeOutTime + "ms";
    this.element.style.MsTransition = "opacity " + this.fadeOutTime + "ms";
    this.element.style.Transition = "opacity " + this.fadeOutTime + "ms";
};

Overlay.prototype.calculatePosition = function () {
    'use strict';
    var overlayPosition = "absolute";

    if (this.parentElement.tagName.toLowerCase() === "body") {
        overlayPosition = "fixed";
    } else {
        if (this.parentElement.style.position !== "fixed" || this.parentElement.style.position !== "absolute" ) {
            this.parentElement.style.position = "relative";
        }
    }

    return overlayPosition;
};

Overlay.prototype.updateProgress = function (percentage, time) {
    "use strict";
    if (this.loadingBar !== null) {
        this.loadingBar.updateProgress(percentage, time);
    }

    if (this.percentage !== null) {
        this.percentage.updateProgress(percentage, time);
    }
};

Overlay.prototype.remove = function () {
    "use strict";
    this.element.parentNode.removeChild(this.element);
};

module.exports = Overlay;<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the w<commit_msg>Who you calling a fool?<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300
//Added a comment that achieves no real goal.

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the wa<|endoftext|>