<commit_before>(function ($) {
    $.fn.collapseActions = function () {
        return this.each(function () {
            $(this).find('td.actions').each(function () {
                if ($(this).find('a').length < 2) {
                    $(this).find('a').show();
                    return;
                }
                var link = $('', {'href': '#', 'class': 'action'}).html('Actions');
                $(this).append(link);
                link.show()
                    .actionsTooltip({placement: 'left'});
            });
        });
    };
    $(document).ready(function () {
        $('table.manage').collapseActions()
            .bind('change', function () {$(this).collapseActions()});
    });
}) (jQuery);

!function ($) {

  "use strict"; // jshint ;_;

 /* ActionsTooltip PUBLIC CLASS DEFINITION
  * =============================== */

  var ActionsTooltip = function (element, options) {
    this.init('actionsTooltip', element, options)
  }

  ActionsTooltip.prototype = {

    constructor: ActionsTooltip

  , init: function (type, element, options) {
      var eventIn
        , eventOut

      this.type = type
      this.$element = $(element)
      this.options = this.getOptions(options)
      this.enabled = true

      if (this.options.trigger != 'manual') {
        eventIn  = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
        this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
      }

      this.options.selector ?
        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : null;
    }

  , getOptions: function (options) {
      options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())

      if (options.delay && typeof options.delay == 'number') {
        options.delay = {
          show: options.delay
        , hide: options.delay
        }
      }

      return options
    }

  , enter: function (e) {
      var self = $(e.currentTarget)[this.type](this._options).data(this.type)

      if (!self.options.delay || !self.options.delay.show) return self.show()

      clearTimeout(this.timeout)
      self.hoverState = 'in'
      this.timeout = setTimeout(function() {
        if (self.hoverState == 'in') self.show()
      }, self.options.delay.show)
    }

  , leave: function (e) {
      var placement = typeof this.options.placement == 'function' ?
        this.options.placement.call(this, this.tip(), this.$element) :
        this.options.placement;
      if (placement == 'top'
              && e.clientX > this.tip().offset().left && e.clientX < this.tip().offset().left + this.tip().width()
              && e.clientY > this.tip().offset().top && e.clientY < this.tip().offset().top + this.tip().height() + this.$element.height() + 20)
          return;
      else if (placement == 'bottom'
              && e.clientX > this.tip().offset().left && e.clientX < this.tip().offset().left + this.tip().width()
              && e.clientY > this.tip().offset().top - this.$element.height() - 20 && e.clientY < this.tip().offset().top + this.tip().height())
          return;
      else if (placement == 'left'
              && e.clientX > this.tip().offset().left && e.clientX < this.tip().offset().left + this.tip().width() + this.$element.width() + 30
              && e.clientY > this.tip().offset().top && e.clientY < this.tip().offset().top + this.tip().height() + 10)
          return;
      else if (placement == 'right'
              && e.clientX > this.tip().offset().left - this.$element.width() - 20 && e.clientX < this.tip().offset().left + this.tip().width()
              && e.clientY > this.tip().offset().top && e.clientY < this.tip().offset().top + this.tip().height() + 10)
          return;

      $(document).off('mousemove.actionsTooltip', $.proxy(this.leave, this))

      if (this.timeout) clearTimeout(this.timeout)
      if (!this.options.delay || !this.options.delay.hide) return this.hide()

      this.hoverState = 'out'
      this.timeout = setTimeout(function() {
        if (this.hoverState == 'out') this.hide()
      }, this.options.delay.hide)
    }

  , show: function () {
      var $tip
        , inside
        , pos
        , actualWidth
        , actualHeight
        , placement
        , tp
        , that

      $('.tooltip').remove();

      if (this.enabled) {
        that = this;
        $tip = this.tip()
        this.setContent()

        if (this.options.animation) {
          $tip.addClass('fade')
        }

        placement = typeof this.options.placement == 'function' ?
          this.options.placement.call(this, $tip[0], this.$element[0]) :
          this.options.placement

        inside = /in/.test(placement)

        $tip
          .detach()
          .css({ top: 0, left: 0, display: 'block' })
          .appendTo(inside ? this.$element : document.body)

        pos = this.getPosition(inside)

        actualWidth = $tip[0].offsetWidth
        actualHeight = $tip[0].offsetHeight

        switch (inside ? placement.split(' ')[1] : placement) {
          case 'bottom':
            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'top':
            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'left':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
            break
          case 'right':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
            break
        }

        $tip.find('a').click(function () {
            that.hide();
        });

        $tip
          .css(tp)
          .addClass(placement)
          .addClass('in')
        $(document).on('mousemove.actionsTooltip', $.proxy(this.leave, this))
      }
    }

  , setContent: function () {
      var $tip = this.tip()
        , title = this.getTitle()

      $tip.find('.tooltip-inner').html(title)
      $tip.removeClass('fade in top bottom left right')
    }

  , hide: function () {
      var that = this
        , $tip = this.tip()

      $tip.removeClass('in')

      function removeWithAnimation() {
        var timeout = setTimeout(function () {
          $tip.off($.support.transition.end).remove()
        }, 500)

        $tip.one($.support.transition.end, function () {
          clearTimeout(timeout)
          $tip.remove()
        })
      }

      $.support.transition && this.$tip.hasClass('fade') ?
        removeWithAnimation() :
        $tip.remove()
    }

  , getPosition: function (inside) {
      return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
        width: this.$element[0].offsetWidth
      , height: this.$element[0].offsetHeight
      })
    }

  , getTitle: function () {
      var title
        , $e = this.$element
        , o = this.options
      var title = $('
');
      $e.parent().find('a:not(.action)').each(function () {
          title.append($(this).clone(true));
      });
      return title;
    }

  , tip: function () {
      return this.$tip = this.$tip || $(this.options.template)
    }

  , enable: function () {
      this.enabled = true
    }

  , disable: function () {
      this.enabled = false
    }

  , toggleEnabled: function () {
      this.enabled = !this.enabled
    }

  , toggle: function () {
      this[this.tip().hasClass('in') ? 'hide' : 'show']()
    }

  }

 /* ActionsTooltip PLUGIN DEFINITION
  * ========================= */

  $.fn.actionsTooltip = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('actionsTooltip')
        , options = typeof option == 'object' && option
      if (!data) $this.data('actionsTooltip', (data = new ActionsTooltip(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.actionsTooltip.Constructor = ActionsTooltip

  $.fn.actionsTooltip.defaults = {
    animation: true
  , placement: 'top'
  , selector: false
  , template: '

'
  , trigger: 'hover'
  , title: ''
  , delay: 0
  }

}(window.jQuery);<commit_msg>Fixed problem actions js with scrolling<commit_after>(function ($) {
    $.fn.collapseActions = function () {
        return this.each(function () {
            $(this).find('td.actions').each(function () {
                if ($(this).find('a').length < 2) {
                    $(this).find('a').show();
                    return;
                }
                var link = $('', {'href': '#', 'class': 'action'}).html('Actions');
                $(this).append(link);
                link.show()
                    .actionsTooltip({placement: 'left'});
            });
        });
    };
    $(document).ready(function () {
        $('table.manage').collapseActions()
            .bind('change', function () {$(this).collapseActions()});
    });
}) (jQuery);

!function ($) {

  "use strict"; // jshint ;_;

 /* ActionsTooltip PUBLIC CLASS DEFINITION
  * =============================== */

  var ActionsTooltip = function (element, options) {
    this.init('actionsTooltip', element, options)
  }

  ActionsTooltip.prototype = {

    constructor: ActionsTooltip

  , init: function (type, element, options) {
      var eventIn
        , eventOut

      this.type = type
      this.$element = $(element)
      this.options = this.getOptions(options)
      this.enabled = true

      if (this.options.trigger != 'manual') {
        eventIn  = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
        this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
      }

      this.options.selector ?
        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : null;
    }

  , getOptions: function (options) {
      options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())

      if (options.delay && typeof options.delay == 'number') {
        options.delay = {
          show: options.delay
        , hide: options.delay
        }
      }

      return options
    }

  , enter: function (e) {
      var self = $(e.currentTarget)[this.type](this._options).data(this.type)

      if (!self.options.delay || !self.options.delay.show) return self.show()

      clearTimeout(this.timeout)
      self.hoverState = 'in'
      this.timeout = setTimeout(function() {
        if (self.hoverState == 'in') self.show()
      }, self.options.delay.show)
    }

  , leave: function (e) {
      var placement = typeof this.options.placement == 'function' ?
        this.options.placement.call(this, this.tip(), this.$element) :
        this.options.placement;
      var clientY = e.clientY + $(document).scrollTop();
      var clientX = e.clientX + $(document).scrollLeft();

      if (placement == 'top'
              && clientX > this.tip().offset().left && clientX < this.tip().offset().left + this.tip().width()
              && clientY > this.tip().offset().top && clientY < this.tip().offset().top + this.tip().height() + this.$element.height() + 20)
          return;
      else if (placement == 'bottom'
              && clientX > this.tip().offset().left && clientX < this.tip().offset().left + this.tip().width()
              && clientY > this.tip().offset().top - this.$element.height() - 20 && clientY < this.tip().offset().top + this.tip().height())
          return;
      else if (placement == 'left'
              && clientX > this.tip().offset().left && clientX < this.tip().offset().left + this.tip().width() + this.$element.width() + 30
              && clientY > this.tip().offset().top && clientY < this.tip().offset().top + this.tip().height() + 10)
          return;
      else if (placement == 'right'
              && clientX > this.tip().offset().left - this.$element.width() - 20 && clientX < this.tip().offset().left + this.tip().width()
              && clientY > this.tip().offset().top && clientY < this.tip().offset().top + this.tip().height() + 10)
          return;

      $(document).off('mousemove.actionsTooltip', $.proxy(this.leave, this))

      if (this.timeout) clearTimeout(this.timeout)
      if (!this.options.delay || !this.options.delay.hide) return this.hide()

      this.hoverState = 'out'
      this.timeout = setTimeout(function() {
        if (this.hoverState == 'out') this.hide()
      }, this.options.delay.hide)
    }

  , show: function () {
      var $tip
        , inside
        , pos
        , actualWidth
        , actualHeight
        , placement
        , tp
        , that

      $('.tooltip').remove();

      if (this.enabled) {
        that = this;
        $tip = this.tip()
        this.setContent()

        if (this.options.animation) {
          $tip.addClass('fade')
        }

        placement = typeof this.options.placement == 'function' ?
          this.options.placement.call(this, $tip[0], this.$element[0]) :
          this.options.placement

        inside = /in/.test(placement)

        $tip
          .detach()
          .css({ top: 0, left: 0, display: 'block' })
          .appendTo(inside ? this.$element : document.body)

        pos = this.getPosition(inside)

        actualWidth = $tip[0].offsetWidth
        actualHeight = $tip[0].offsetHeight

        switch (inside ? placement.split(' ')[1] : placement) {
          case 'bottom':
            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'top':
            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'left':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
            break
          case 'right':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
            break
        }

        $tip.find('a').click(function () {
            that.hide();
        });

        $tip
          .css(tp)
          .addClass(placement)
          .addClass('in')
        $(document).on('mousemove.actionsTooltip', $.proxy(this.leave, this))
      }
    }

  , setContent: function () {
      var $tip = this.tip()
        , title = this.getTitle()

      $tip.find('.tooltip-inner').html(title)
      $tip.removeClass('fade in top bottom left right')
    }

  , hide: function () {
      var that = this
        , $tip = this.tip()

      $tip.removeClass('in')

      function removeWithAnimation() {
        var timeout = setTimeout(function () {
          $tip.off($.support.transition.end).remove()
        }, 500)

        $tip.one($.support.transition.end, function () {
          clearTimeout(timeout)
          $tip.remove()
        })
      }

      $.support.transition && this.$tip.hasClass('fade') ?
        removeWithAnimation() :
        $tip.remove()
    }

  , getPosition: function (inside) {
      return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
        width: this.$element[0].offsetWidth
      , height: this.$element[0].offsetHeight
      })
    }

  , getTitle: function () {
      var title
        , $e = this.$element
        , o = this.options
      var title = $('
');
      $e.parent().find('a:not(.action)').each(function () {
          title.append($(this).clone(true));
      });
      return title;
    }

  , tip: function () {
      return this.$tip = this.$tip || $(this.options.template)
    }

  , enable: function () {
      this.enabled = true
    }

  , disable: function () {
      this.enabled = false
    }

  , toggleEnabled: function () {
      this.enabled = !this.enabled
    }

  , toggle: function () {
      this[this.tip().hasClass('in') ? 'hide' : 'show']()
    }

  }

 /* ActionsTooltip PLUGIN DEFINITION
  * ========================= */

  $.fn.actionsTooltip = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('actionsTooltip')
        , options = typeof option == 'object' && option
      if (!data) $this.data('actionsTooltip', (data = new ActionsTooltip(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.actionsTooltip.Constructor = ActionsTooltip

  $.fn.actionsTooltip.defaults = {
    animation: true
  , placement: 'top'
  , selector: false
  , template: '

'
  , trigger: 'hover'
  , title: ''
  , delay: 0
  }

}(window.jQuery);<|endoftext|>


<commit_before>'use strict';

const
  request = require('request'),
  mime = require('mime-db');

/* Globals */

const MESSAGE_TYPES = [
  'text', 'audio', 'voice', 'document', 'photo',
  'sticker', 'video', 'contact', 'location', 'query'
];

const ANSWER_METHODS = {
  addArticle: 'article', addPhoto: 'photo', addVideo: 'video',
  addGif: 'gif', addVideoGif: 'mpeg4_gif'
};

const REGEX = {
  cmd: /^\/([а-я\w\d]+)/,
  url: /^https?\:\/\/|www\./,
  name: /[^/\\&\?]+\.\w{3,4}(?=([\?&].*$|$))/
};

/* Telegram Bot */

const TeleBot = function(cfg) {
  const self = this;
  self.cfg = cfg;
  self.token = cfg.token;
  self.id = self.token.split(':')[0];
  self.api = 'https://api.telegram.org/bot' + self.token;
  self.fileLink = 'https://api.telegram.org/file/bot' + self.token + '/';
  self.limit = Number(cfg.limit) || 100;
  self.timeout = cfg.timeout >= 0 ? cfg.timeout : 0;
  self.retryTimeout = cfg.retryTimeout >= 0 ? cfg.retryTimeout : 5000;
  self.retry = false;
  self.pool = true;
  self.loopFn = null;
  self.looping = false;
  self.sleep = Number(cfg.sleep) || 1000;
  self.updateId = 0;
  self.eventList = {};
  self.modList = {};
};

/* Answer List */

const answerList = function(queryId) {
  this.id = queryId;
  this.list = [];
};

answerList.prototype = {
  results() {
    return JSON.stringify(this.list);
  },
  add(type, set) {
    set = set || {};
    set.type = type;
    this.list.push(set);
    return set;
  }
};

// Add answer methods
{
  for (let prop in ANSWER_METHODS) {
    answerList.prototype[prop] = (name => {
      return function(set) {
        return this.add(name, set);
      };
    })(ANSWER_METHODS[prop]);
  }
}

TeleBot.prototype = {
/* Modules */
  use(fn) {
    return fn.call(this, this);
  },
/* Keyboard */
  keyboard(keyboard, opt) {
    opt = opt || {};
    const markup = { keyboard };
    if (opt.resize === true) markup['resize_keyboard'] = true;
    if (opt.once === true) markup['one_time_keyboard'] = true;
    if (opt.selective) markup['selective'] = opt.selective;
    return JSON.stringify(markup);
  },
  /* Answer */
  answerList: answerList,
/* Actions */
  getMe() {
    this.event('getMe', arguments);
    return this.request('/getMe');
  },
  answerQuery(answers, opt) {
    this.event('answerQuery', arguments);
    return this.request('/answerInlineQuery', {
      inline_query_id: answers.id, results: answers.results(),
    });
  },
  getFile(fileId) {
    this.event('getFile', arguments);
    const self = this;
    return this.request('/getFile', { file_id: fileId }).then(function(file) {
      const result = file.result;
      result.fileLink = self.fileLink + result.file_path;
      return result;
    });
  },
  forwardMessage(id, fromId, messageId) {
    this.event('forwardMessage', arguments);
    return this.request('/forwardMessage', {
      chat_id: id, from_chat_id: fromId, message_id: messageId
    });
  },
  getUserPhoto(id, opt) {
    this.event('getUserPhoto', arguments);
    opt = opt || {};
    const form = { user_id: id };
    if (opt.offset) form['offset'] = opt.offset;
    if (opt.limit) form['limit'] = opt.limit;
    return this.request('/getUserProfilePhotos', form);
  },
  sendAction(id, action) {
    this.event('sendAction', arguments);
    return this.request('/sendChatAction', { chat_id: id, action });
  },
  sendMessage(id, text, opt) {
    this.event('sendMessage', arguments);
    opt = opt || {};
    const form = props({ chat_id: id, text }, opt);
    if (opt.preview === false) form['disable_web_page_preview'] = true;
    return this.request('/sendMessage', form);
  },
  sendLocation(id, position, opt) {
    this.event('sendLocation', arguments);
    opt = opt || {};
    const form = props({
      chat_id: id, latitude: position[0], longitude: position[1]
    }, opt);
    return this.request('/sendLocation', form);
  },
  sendPhoto(id, photo, opt) {
    return sendFile.call(this, 'photo', id,  photo, opt);
  },
  sendAudio(id, audio, opt) {
    return sendFile.call(this, 'audio', id, audio, opt);
  },
  sendVoice(id, voice, opt) {
    return sendFile.call(this, 'voice', id, voice, opt);
  },
  sendDocument(id, doc, opt) {
    return sendFile.call(this, 'document', id, doc, opt);
  },
  sendSticker(id, sticker, opt) {
    return sendFile.call(this, 'sticker', id, sticker, opt);
  },
  sendVideo(id, video, opt) {
    return sendFile.call(this, 'video', id, video, opt);
  },
  setWebhook(url, certificate) {
    this.event('setWebhook', arguments);
    return this.request('/setWebhook', { url, certificate });
  },
/* Send request to server */
  request(url, form, data) {
    const self = this, options = { url: self.api + url, json: true };
    if (form) { options.form = form; } else { options.formData = data; };
    return new Promise((resolve, reject) => {
      request.post(options, (error, response, body) => {
        if (error || !body.ok || response.statusCode == 404) {
          return reject(error || body.description || body.error_code || 404);
        }
        return resolve(body);
      });
    });
  },
/* Connection */
  connect() {
    const self = this;
    self.looping = true;
    console.log('[info] bot started');
    self.event('connect');
    self.loopFn = setInterval(x => {
      if (!self.looping) clearInterval(self.loopFn);
      if (!self.pool) return;
      self.pool = false;
      self.getUpdate().then(x => {
        if (self.retry) {
          const now = Date.now();
          const diff = (now - self.retry) / 1000;
          console.log('[info.update] reconnected after ' + diff + ' seconds');
          self.event('reconnected', {
            startTime: self.retry, endTime: now, diffTime: diff
          });
          self.retry = false;
        }
        return self.event('tick');
      }).then(x => {
        self.pool = true;
      }).catch(error => {
        if (self.retry === false) self.retry = Date.now();
        console.error('[error.update]', error.stack || error);
        self.event('error', { error });
        return Promise.reject();
      }).catch(x => {
        const seconds = self.retryTimeout / 1000;
        console.log('[info.update] reconnecting in ' + seconds + ' seconds...');
        self.event('reconnecting');
        setTimeout(x => (self.pool = true), self.retryTimeout);
      });
    }, self.sleep);
  },
  disconnect(message) {
    this.looping = false;
    console.log('[info] bot disconnected' + (message ? ': ' + message : ''));
    this.event('disconnect', message);
  },
/* Fetch updates */
  getUpdate() {
    const self = this;
    // Request an update
    return self.request('/getUpdates', {
      offset: self.updateId, limit: self.limit, timeout: self.timeout
    }).then(function(body) {
      // Check for update
      var data = body.result;
      if (!data.length) return Promise.resolve();
      return new Promise((resolve, reject) => {
        self.event('update', data).then(output => {
          var me = extend({}, output);
          // Run update processors
          var temp = self.modRun('update', { data, me });
          data = temp.data, me = temp.me;
          // Check every message in update
          for (let update of data) {
            // Set update ID
            let nextId = ++update['update_id'];
            if (self.updateId < nextId) self.updateId = nextId;
            // Run message processors
            let temp = self.modRun('message', {
              me, msg:
                update['message'] || update['inline_query'] ||
                update['chosen_inline_result'] || {}
            });
            var msg = temp.msg, me = temp.me;
            for (let type of MESSAGE_TYPES) {
              // Check for Telegram API documented types
              if (!(type in msg)) continue;
              me.type = type;
              // Send type event
              self.event(['*', type], msg, me);
              // Check for command
              if (type == 'text') {
                const match = REGEX.cmd.exec(msg.text);
                if (!match) continue;
                // Command found
                me.cmd = msg.text.split(' ');
                self.event(['/*', '/' + match[1]], msg, me);
              }
            }
          }
        }).then(resolve).catch(reject);
      });
    });
  },
  get(url, json) {
    return new Promise((resolve, reject) => {
      request.get({ url, json: !!json }, (error, response, data) => {
        if (error || !data) return reject(response);
        return resolve(data);
      });
    });
  },
  mod(name, fn) {
    if (!this.modList[name]) this.modList[name] = [];
    if (this.modList[name].indexOf(fn) !== -1) return;
    this.modList[name].push(fn);
  },
  modRun(name, data) {
    const self = this, list = self.modList[name];
    if (!list || !list.length) return data;
    for (let fn of list) data = fn.call(self, data);
    return data;
  },
/* Events */
  on(types, fn) {
    const self = this;
    if (typeof types == 'string') types = [types];
    for (let type of types) {
      let event = self.eventList[type];
      if (!event) {
        self.eventList[type] = { fired: null, list: [] };
      } else if (event.fired) {
        const fired = event.fired;
        const out = fn.call(fired.self, fired.data, fired.details);
        if (out instanceof Promise) out.catch(error => {
          console.error('[error.event.fired]', error.stack || error);
          if (type != 'error')
            self.event('error', { error, data: fired.data });
        });
      }
      event = self.eventList[type].list;
      if (event.indexOf(fn) !== -1) return;
      event.push(fn);
    }
  },
  event(types, data, me) {
    const self = this, promises = [];
    if (typeof types == 'string') types = [types];
    for (let type of types) {
      let event = this.eventList[type];
      const details = { type, time: Date.now() };
      const props = { self: me, data, details };
      if (!event) {
        this.eventList[type] = { fired: props, list: [] };
        continue;
      }
      event.fired = props;
      event = event.list;
      for (let fn of event) {
        promises.push(new Promise((resolve, reject) => {
          try {
            fn = fn.call(me, data, details);
            if (fn instanceof Promise)
              return fn.then(resolve).catch(errorHandler);
            return resolve(fn);
          } catch(error) {
            return errorHandler(error);
          }
          function errorHandler(error) {
            console.error('[error.event]', error.stack || error);
            if (type != 'error')
              self.event('error', { error, data });
            return reject(error);
          }
        }));
      }
    }
    return Promise.all(promises);
  },
  clean(type) {
    if (!this.eventList.hasOwnProperty(type)) return;
    this.eventList[type].fired = null;
  },
  remove(type, fn) {
    if (!this.eventList.hasOwnProperty(type)) return;
    const event = this.eventList[type].list;
    const index = event.indexOf(fn);
    if (index === -1) return;
    event.splice(index, 1);
  },
  destroy(type) {
    if (!this.eventList.hasOwnProperty(type)) return;
    delete this.eventList[type];
  }
};

/* Functions */

function props(form, opt) {
  opt = opt || {};
  form = form || {};
  // Reply to message
  if (opt.reply) form['reply_to_message_id'] = opt.reply;
  // Markdown/HTML support for message (bold, italic, urls and preformatted text)
  if (opt.parse) form['parse_mode'] = opt.parse;
  // Markup object
  if (opt.markup !== undefined) {
    if (opt.markup == 'hide' || opt.markup === false) {
      // Hide keyboard
      form['reply_markup'] = JSON.stringify({ hide_keyboard: true });
    } else if (opt.markup == 'reply') {
      // Fore reply
      form['reply_markup'] = JSON.stringify({ force_reply: true });
    } else {
      // JSON keyboard
      form['reply_markup'] = opt.markup;
    }
  }
  return form;
}

function sendFile(type, id, file, opt) {
  opt = opt || {};
  const self = this;
  const form = props({ chat_id: id }, opt);
  let url = 'send' + type.charAt(0).toUpperCase() + type.slice(1);
  // Send bot action event
  self.event(url, [].slice.call(arguments).splice(0, 1));
  // Add caption to photo
  if (type == 'photo' && opt.caption) form.caption = opt.caption;
  url = '/' + url;
  if (typeof file == 'string' && REGEX.url.test(file)) {
    // If url, get blob and send to user
    return getBlob(file).then(data => {
      if (!opt.name) {
        const match = REGEX.name.exec(file);
        opt.name = match ? match[0] : type + '.' + mime[data.type].extensions[0];
      }
      form[type] = {
        value: data.buffer,
        options: { filename: opt.name, contentType: data.type }
      };
      return self.request(url, null, form);
    });
  } else {
    // String as 'file_id'
    form[type] = file;
    return self.request(url, null, form);
  }
}

function getBlob(url) {
  return new Promise((resolve, reject) => {
    request.get({ url, encoding: null }, (error, response, buffer) => {
      if (error || !buffer) return reject(error);
      return resolve({ buffer, type: response.headers['content-type'] });
    });
  });
}

function extend(me, input) {
  for (let obj of input) {
    for (let name in obj) {
      const key = me[name], value = obj[name];
      if (key !== undefined) {
        if (!Array.isArray(key)) me[name] = [key];
        me[name].push(value);
        continue;
      }
      me[name] = value;
    }
  }
  return me;
}

/* Exports */

module.exports = TeleBot;
<commit_msg>TeleBot function to class<commit_after>'use strict';

const
  request = require('request'),
  mime = require('mime-db');

/* Globals */

const MESSAGE_TYPES = [
  'text', 'audio', 'voice', 'document', 'photo',
  'sticker', 'video', 'contact', 'location', 'query'
];

const ANSWER_METHODS = {
  addArticle: 'article', addPhoto: 'photo', addVideo: 'video',
  addGif: 'gif', addVideoGif: 'mpeg4_gif'
};

const REGEX = {
  cmd: /^\/([а-я\w\d]+)/,
  url: /^https?\:\/\/|www\./,
  name: /[^/\\&\?]+\.\w{3,4}(?=([\?&].*$|$))/
};

/* Telegram Bot */

class TeleBot {
  constructor(cfg) {
    this.cfg = cfg;
    this.token = cfg.token;
    this.id = this.token.split(':')[0];
    this.api = 'https://api.telegram.org/bot' + this.token;
    this.fileLink = 'https://api.telegram.org/file/bot' + this.token + '/';
    this.limit = Number(cfg.limit) || 100;
    this.timeout = cfg.timeout >= 0 ? cfg.timeout : 0;
    this.retryTimeout = cfg.retryTimeout >= 0 ? cfg.retryTimeout : 5000;
    this.retry = false;
    this.pool = true;
    this.loopFn = null;
    this.looping = false;
    this.sleep = Number(cfg.sleep) || 1000;
    this.updateId = 0;
    this.eventList = {};
    this.modList = {};
  }
  /* Modules */
  use(fn) {
    return fn.call(this, this);
  }
  /* Keyboard */
  keyboard(keyboard, opt) {
    opt = opt || {};
    const markup = { keyboard };
    if (opt.resize === true) markup['resize_keyboard'] = true;
    if (opt.once === true) markup['one_time_keyboard'] = true;
    if (opt.selective) markup['selective'] = opt.selective;
    return JSON.stringify(markup);
  }
  /* Answer */
  answerList(id) {
    return answerList(id);
  }
  /* Actions */
  getMe() {
    this.event('getMe', arguments);
    return this.request('/getMe');
  }
  answerQuery(answers, opt) {
    this.event('answerQuery', arguments);
    return this.request('/answerInlineQuery', {
      inline_query_id: answers.id, results: answers.results(),
    });
  }
  getFile(fileId) {
    this.event('getFile', arguments);
    const self = this;
    return this.request('/getFile', { file_id: fileId }).then(function(file) {
      const result = file.result;
      result.fileLink = self.fileLink + result.file_path;
      return result;
    });
  }
  forwardMessage(id, fromId, messageId) {
    this.event('forwardMessage', arguments);
    return this.request('/forwardMessage', {
      chat_id: id, from_chat_id: fromId, message_id: messageId
    });
  }
  getUserPhoto(id, opt) {
    this.event('getUserPhoto', arguments);
    opt = opt || {};
    const form = { user_id: id };
    if (opt.offset) form['offset'] = opt.offset;
    if (opt.limit) form['limit'] = opt.limit;
    return this.request('/getUserProfilePhotos', form);
  }
  sendAction(id, action) {
    this.event('sendAction', arguments);
    return this.request('/sendChatAction', { chat_id: id, action });
  }
  sendMessage(id, text, opt) {
    this.event('sendMessage', arguments);
    opt = opt || {};
    const form = props({ chat_id: id, text }, opt);
    if (opt.preview === false) form['disable_web_page_preview'] = true;
    return this.request('/sendMessage', form);
  }
  sendLocation(id, position, opt) {
    this.event('sendLocation', arguments);
    opt = opt || {};
    const form = props({
      chat_id: id, latitude: position[0], longitude: position[1]
    }, opt);
    return this.request('/sendLocation', form);
  }
  sendPhoto(id, photo, opt) {
    return sendFile.call(this, 'photo', id,  photo, opt);
  }
  sendAudio(id, audio, opt) {
    return sendFile.call(this, 'audio', id, audio, opt);
  }
  sendVoice(id, voice, opt) {
    return sendFile.call(this, 'voice', id, voice, opt);
  }
  sendDocument(id, doc, opt) {
    return sendFile.call(this, 'document', id, doc, opt);
  }
  sendSticker(id, sticker, opt) {
    return sendFile.call(this, 'sticker', id, sticker, opt);
  }
  sendVideo(id, video, opt) {
    return sendFile.call(this, 'video', id, video, opt);
  }
  setWebhook(url, certificate) {
    this.event('setWebhook', arguments);
    return this.request('/setWebhook', { url, certificate });
  }
  /* Send request to server */
  request(url, form, data) {
    const self = this, options = { url: self.api + url, json: true };
    if (form) { options.form = form; } else { options.formData = data; };
    return new Promise((resolve, reject) => {
      request.post(options, (error, response, body) => {
        if (error || !body.ok || response.statusCode == 404) {
          return reject(error || body.description || body.error_code || 404);
        }
        return resolve(body);
      });
    });
  }
  /* Connection */
  connect() {
    const self = this;
    self.looping = true;
    console.log('[info] bot started');
    self.event('connect');
    self.loopFn = setInterval(x => {
      if (!self.looping) clearInterval(self.loopFn);
      if (!self.pool) return;
      self.pool = false;
      self.getUpdate().then(x => {
        if (self.retry) {
          const now = Date.now();
          const diff = (now - self.retry) / 1000;
          console.log('[info.update] reconnected after ' + diff + ' seconds');
          self.event('reconnected', {
            startTime: self.retry, endTime: now, diffTime: diff
          });
          self.retry = false;
        }
        return self.event('tick');
      }).then(x => {
        self.pool = true;
      }).catch(error => {
        if (self.retry === false) self.retry = Date.now();
        console.error('[error.update]', error.stack || error);
        self.event('error', { error });
        return Promise.reject();
      }).catch(x => {
        const seconds = self.retryTimeout / 1000;
        console.log('[info.update] reconnecting in ' + seconds + ' seconds...');
        self.event('reconnecting');
        setTimeout(x => (self.pool = true), self.retryTimeout);
      });
    }, self.sleep);
  }
  disconnect(message) {
    this.looping = false;
    console.log('[info] bot disconnected' + (message ? ': ' + message : ''));
    this.event('disconnect', message);
  }
  /* Fetch updates */
  getUpdate() {
    const self = this;
    // Request an update
    return self.request('/getUpdates', {
      offset: self.updateId, limit: self.limit, timeout: self.timeout
    }).then(function(body) {
      // Check for update
      var data = body.result;
      if (!data.length) return Promise.resolve();
      return new Promise((resolve, reject) => {
        self.event('update', data).then(output => {
          var me = extend({}, output);
          // Run update processors
          var temp = self.modRun('update', { data, me });
          data = temp.data, me = temp.me;
          // Check every message in update
          for (let update of data) {
            // Set update ID
            let nextId = ++update['update_id'];
            if (self.updateId < nextId) self.updateId = nextId;
            // Run message processors
            let temp = self.modRun('message', {
              me, msg:
                update['message'] || update['inline_query'] ||
                update['chosen_inline_result'] || {}
            });
            var msg = temp.msg, me = temp.me;
            for (let type of MESSAGE_TYPES) {
              // Check for Telegram API documented types
              if (!(type in msg)) continue;
              me.type = type;
              // Send type event
              self.event(['*', type], msg, me);
              // Check for command
              if (type == 'text') {
                const match = REGEX.cmd.exec(msg.text);
                if (!match) continue;
                // Command found
                me.cmd = msg.text.split(' ');
                self.event(['/*', '/' + match[1]], msg, me);
              }
            }
          }
        }).then(resolve).catch(reject);
      });
    });
  }
  get(url, json) {
    return new Promise((resolve, reject) => {
      request.get({ url, json: !!json }, (error, response, data) => {
        if (error || !data) return reject(response);
        return resolve(data);
      });
    });
  }
  mod(name, fn) {
    if (!this.modList[name]) this.modList[name] = [];
    if (this.modList[name].indexOf(fn) !== -1) return;
    this.modList[name].push(fn);
  }
  modRun(name, data) {
    const self = this, list = self.modList[name];
    if (!list || !list.length) return data;
    for (let fn of list) data = fn.call(self, data);
    return data;
  }
  /* Events */
  on(types, fn) {
    const self = this;
    if (typeof types == 'string') types = [types];
    for (let type of types) {
      let event = self.eventList[type];
      if (!event) {
        self.eventList[type] = { fired: null, list: [] };
      } else if (event.fired) {
        const fired = event.fired;
        const out = fn.call(fired.self, fired.data, fired.details);
        if (out instanceof Promise) out.catch(error => {
          console.error('[error.event.fired]', error.stack || error);
          if (type != 'error')
            self.event('error', { error, data: fired.data });
        });
      }
      event = self.eventList[type].list;
      if (event.indexOf(fn) !== -1) return;
      event.push(fn);
    }
  }
  event(types, data, me) {
    const self = this, promises = [];
    if (typeof types == 'string') types = [types];
    for (let type of types) {
      let event = this.eventList[type];
      const details = { type, time: Date.now() };
      const props = { self: me, data, details };
      if (!event) {
        this.eventList[type] = { fired: props, list: [] };
        continue;
      }
      event.fired = props;
      event = event.list;
      for (let fn of event) {
        promises.push(new Promise((resolve, reject) => {
          try {
            fn = fn.call(me, data, details);
            if (fn instanceof Promise)
              return fn.then(resolve).catch(errorHandler);
            return resolve(fn);
          } catch(error) {
            return errorHandler(error);
          }
          function errorHandler(error) {
            console.error('[error.event]', error.stack || error);
            if (type != 'error')
              self.event('error', { error, data });
            return reject(error);
          }
        }));
      }
    }
    return Promise.all(promises);
  }
  clean(type) {
    if (!this.eventList.hasOwnProperty(type)) return;
    this.eventList[type].fired = null;
  }
  remove(type, fn) {
    if (!this.eventList.hasOwnProperty(type)) return;
    const event = this.eventList[type].list;
    const index = event.indexOf(fn);
    if (index === -1) return;
    event.splice(index, 1);
  }
  destroy(type) {
    if (!this.eventList.hasOwnProperty(type)) return;
    delete this.eventList[type];
  }
};

/* Answer List */

function answerList(queryId) {
  this.id = queryId;
  this.list = [];
};

answerList.prototype = {
  results() {
    return JSON.stringify(this.list);
  },
  add(type, set) {
    set = set || {};
    set.type = type;
    this.list.push(set);
    return set;
  }
};

// Add answer methods
{
  for (let prop in ANSWER_METHODS) {
    answerList.prototype[prop] = (name => {
      return function(set) {
        return this.add(name, set);
      };
    })(ANSWER_METHODS[prop]);
  }
}

/* Functions */

function props(form, opt) {
  opt = opt || {};
  form = form || {};
  // Reply to message
  if (opt.reply) form['reply_to_message_id'] = opt.reply;
  // Markdown/HTML support for message (bold, italic, urls and preformatted text)
  if (opt.parse) form['parse_mode'] = opt.parse;
  // Markup object
  if (opt.markup !== undefined) {
    if (opt.markup == 'hide' || opt.markup === false) {
      // Hide keyboard
      form['reply_markup'] = JSON.stringify({ hide_keyboard: true });
    } else if (opt.markup == 'reply') {
      // Fore reply
      form['reply_markup'] = JSON.stringify({ force_reply: true });
    } else {
      // JSON keyboard
      form['reply_markup'] = opt.markup;
    }
  }
  return form;
}

function sendFile(type, id, file, opt) {
  opt = opt || {};
  const self = this;
  const form = props({ chat_id: id }, opt);
  let url = 'send' + type.charAt(0).toUpperCase() + type.slice(1);
  // Send bot action event
  self.event(url, [].slice.call(arguments).splice(0, 1));
  // Add caption to photo
  if (type == 'photo' && opt.caption) form.caption = opt.caption;
  url = '/' + url;
  if (typeof file == 'string' && REGEX.url.test(file)) {
    // If url, get blob and send to user
    return getBlob(file).then(data => {
      if (!opt.name) {
        const match = REGEX.name.exec(file);
        opt.name = match ? match[0] : type + '.' + mime[data.type].extensions[0];
      }
      form[type] = {
        value: data.buffer,
        options: { filename: opt.name, contentType: data.type }
      };
      return self.request(url, null, form);
    });
  } else {
    // String as 'file_id'
    form[type] = file;
    return self.request(url, null, form);
  }
}

function getBlob(url) {
  return new Promise((resolve, reject) => {
    request.get({ url, encoding: null }, (error, response, buffer) => {
      if (error || !buffer) return reject(error);
      return resolve({ buffer, type: response.headers['content-type'] });
    });
  });
}

function extend(me, input) {
  for (let obj of input) {
    for (let name in obj) {
      const key = me[name], value = obj[name];
      if (key !== undefined) {
        if (!Array.isArray(key)) me[name] = [key];
        me[name].push(value);
        continue;
      }
      me[name] = value;
    }
  }
  return me;
}

/* Exports */

module.exports = TeleBot;
<|endoftext|>


<commit_before>/*
 *  Copyright (c) Codiad & Kent Safranski (codiad.com), distributed
 *  as-is and without warranty under the MIT License. See
 *  [root]/license.txt for more. This information must remain intact.
 */

var VirtualRenderer = require('ace/virtual_renderer').VirtualRenderer;
var Editor = require('ace/editor').Editor;

editor_modes = {}; // Loaded modes
cursorpoll = null;

var editor = {

    // Array of all instances - there is one editor instance
    // corresponding to each split.
    instances: [],

    // Editor-wide settings
    settings: {
        theme: 'twilight',
        font_size: 15,
        print_margin: false,
        highlight_line: true,
        indent_guides: true,
        wrap_mode: false,
    },

    add_instance: function(session){
        var i  = ace.edit('editor');

        // Apply the current configuration settings:
        i.setTheme('ace/theme/' + this.settings.theme);
        i.setFontSize(this.settings.font_size);
        i.setShowPrintMargin(this.settings.print_margin);
        i.setHighlightActiveLine(this.settings.highlight_line);
        i.setDisplayIndentGuides(this.settings.indent_guides);

        this.change_listener(i);
        this.cursor_tracking(i);
        this.bind_keys(i);

        this.instances.push(i);
        return i;
    },

    exterminate: function(){
        $('#editor-region').html('').append($("<div>").attr('id', 'editor'));
        this.instances = [];
    },

    remove_session: function(session, replacement_session){
        for (var k = 0; k < this.instances.length; k++) {
            if (this.instances[k].getSession() === session) {
                this.instances[k].setSession(replacement_session);
            }
        }
    },

    for_each: function(fn){
        for (var k = 0; k < this.instances.length; k++) {
            fn.call(this, this.instances[k]);
        }
    },

    //////////////////////////////////////////////////////////////////
    // Get the currently active Editor
    //////////////////////////////////////////////////////////////////

    get_active: function() {
        if (this.instances.length > 0)
            // While there is no implementation for splitting
            // there can be at most one editor instance.
            return this.instances[0];
        else
            return null;
    },

    set_session: function(session, i) {
        i = i || this.get_active();
        if (! i) i = this.add_instance(session);
        i.setSession(session);
    },

    //////////////////////////////////////////////////////////////////
    // Select mode from extension
    //////////////////////////////////////////////////////////////////

    select_mode: function(e) {
        switch (e) {
        case 'html':
        case 'htm':
        case 'tpl':
            return 'html';
            break;
        case 'js':
            return 'javascript';
            break;
        case 'css':
            return 'css';
            break;
        case 'scss':
        case 'sass':
            return 'scss';
            break;
        case 'less':
            return 'less';
            break;
        case 'php':
        case 'php5':
            return 'php';
            break;
        case 'json':
            return 'json';
            break;
        case 'xml':
            return 'xml';
            break;
        case 'sql':
            return 'sql';
            break;
        case 'md':
            return 'markdown';
            break;
        default:
            return 'text';
        }
    },

    //////////////////////////////////////////////////////////////////
    // Set editor mode/language
    //////////////////////////////////////////////////////////////////

    set_mode: function(m, i) {
        i = i || this.get_active();
        if (!editor_modes[m]) { // Check if mode is already loaded
            $.loadScript("components/editor/ace-editor/mode-" + m + ".js", function() {
                editor_modes[m] = true; // Mark to not load again
                var EditorMode = require("ace/mode/" + m)
                    .Mode;
                i.getSession()
                    .setMode(new EditorMode());
            }, true);
        } else {
            var EditorMode = require("ace/mode/" + m)
                .Mode;
            i.getSession()
                .setMode(new EditorMode());
        }
    },

    //////////////////////////////////////////////////////////////////
    // Set editor theme
    //////////////////////////////////////////////////////////////////

    set_theme: function(t, i) {
        if (i) {
            // If a specific instance is specified, change the theme for
            // this instance
            i.setTheme("ace/theme/"+t);
        } else {
            // Change the theme for the existing editor instances
            // and make it the default for new instances
            this.settings['theme'] = t;
            for (var k = 0; k < this.instances.length; k++) {
                this.instances[k].setTheme("ace/theme/"+t);
            }
        }
    },

    //////////////////////////////////////////////////////////////////
    // Set content of editor
    //////////////////////////////////////////////////////////////////

    set_content: function(c, i) {
        i = i || this.get_active();
        i.getSession().setValue(c);
    },

    //////////////////////////////////////////////////////////////////
    // Set Font Size
    //////////////////////////////////////////////////////////////////

    set_font_size: function(s, i) {
        if (i) {
            i.setFontSize(s);
        } else {
            this.settings['font_size'] = s;
            this.for_each(function(i) {
                i.setFontSize(s);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Highlight active line
    //////////////////////////////////////////////////////////////////

    set_highlight_line: function(h, i) {
        if (i) {
            i.setHighlightActiveLine(h)
        } else {
            this.settings['highlight_line'] = h;
            this.for_each(function(i) {
                i.setHighlightActiveLine(h);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Show/Hide print margin indicator
    //////////////////////////////////////////////////////////////////

    set_print_margin: function(p, i) {
        if (i) {
            i.setShowPrintMargin(p);
        } else {
            this.settings['print_margin'] = p;
            this.for_each(function(i) {
                i.setPrintMargin(p);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Show/Hide indent guides
    //////////////////////////////////////////////////////////////////

    set_indent_guides: function(g, i) {
        if (i) {
            i.setDisplayIndentGuides(g);
        } else {
            this.settings['indent_guides'] = g;
            this.for_each(function(i) {
                i.setDisplayIndentGuides(g);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Code Folding
    //////////////////////////////////////////////////////////////////

    set_code_folding: function(f, i) {
        if (i) {
            i.setFoldStyle(f);
        } else {
            this.for_each(function(i){
                i.setFoldStyle(f);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Set Line Wrapping
    //////////////////////////////////////////////////////////////////

    set_wrap_mode: function(w, i) {
        i = i || this.get_active();
        if (! i) return;
        i.getSession()
            .setUseWrapMode(w);
    },

    //////////////////////////////////////////////////////////////////
    // Get content from editor by ID
    //////////////////////////////////////////////////////////////////

    get_content: function(i) {
        i = i || this.get_active();
        if (! i) return;
        var content = i.getSession().getValue();
        if (!content) {
            content = ' ';
        } // Pass something through
        return content;
    },

    //////////////////////////////////////////////////////////////////
    // Resize
    //////////////////////////////////////////////////////////////////

    resize: function(i) {
        i = i || this.get_active();
        if (! i) return;
        i.resize();
    },

    //////////////////////////////////////////////////////////////////
    // Change Listener
    //////////////////////////////////////////////////////////////////

    change_listener: function(i) {
        var _this = this;
        i.on('change', function() {
            active.mark_changed(_this.get_active().getSession().path);
        });
    },

    //////////////////////////////////////////////////////////////////
    // Get Selected Text
    //////////////////////////////////////////////////////////////////

    get_selected_text: function(i) {
        i = i || this.get_active();
        if (! i) return;
        return i.getCopyText();
    },

    //////////////////////////////////////////////////////////////////
    // Insert text
    //////////////////////////////////////////////////////////////////

    insert_text: function(val, i) {
        i = i || this.get_active();
        if (! i) return;
        i.insert(val);
    },

    //////////////////////////////////////////////////////////////////
    // Goto Line
    //////////////////////////////////////////////////////////////////

    goto_line: function(line, i) {
        i = i || this.get_active();
        if (! i) return;
        i.gotoLine(line, 0, true);
    },

    //////////////////////////////////////////////////////////////////
    // Focus
    //////////////////////////////////////////////////////////////////

    focus: function(i) {
        i = i || this.get_active();
        if (! i) return;
        i.focus();
    },

    //////////////////////////////////////////////////////////////////
    // Cursor Tracking
    //////////////////////////////////////////////////////////////////

    cursor_tracking: function(i) {
        i = i || this.get_active();
        if (! i) return;
        clearInterval(cursorpoll);
        cursorpoll = setInterval(function() {
            $('#cursor-position')
                .html('Ln: '
                      + (i.getCursorPosition().row + 1)
                      + ' · Col: '
                      + i.getCursorPosition().column
                     );
        }, 100);
    },

    //////////////////////////////////////////////////////////////////
    // Bind Keys
    //////////////////////////////////////////////////////////////////

    bind_keys: function(i) {

        // Find
        i.commands.addCommand({
            name: 'Find',
            bindKey: {
                win: 'Ctrl-F',
                mac: 'Command-F'
            },
            exec: function(e) {
                editor.open_search('find');
            }
        });

        // Find + Replace
        i.commands.addCommand({
            name: 'Replace',
            bindKey: {
                win: 'Ctrl-R',
                mac: 'Command-R'
            },
            exec: function(e) {
                editor.open_search('replace');
            }
        });

        i.commands.addCommand({
            name: 'Move Up',
            bindKey: {
                win: 'Ctrl-up',
                mac: 'Command-up'
            },
            exec: function(e) {
                active.move('up');
            }
        });

        i.commands.addCommand({
            name: 'Move Down',
            bindKey: {
                win: 'Ctrl-down',
                mac: 'Command-up'
            },
            exec: function(e) {
                active.move('down');
            }
        });

    },

    //////////////////////////////////////////////////////////////////
    // Search (Find + Replace)
    //////////////////////////////////////////////////////////////////

    open_search: function(type) {
        if (this.get_active()) {
            modal.load(400, 'components/editor/dialog.php?action=search&type=' + type);
            modal.hide_overlay();
        } else {
            message.error('No Open Files');
        }
    },

    search: function(action, i) {
        i = i || this.get_active();
        if (! i) return;
        var find = $('#modal input[name="find"]')
            .val();
        var replace = $('#modal input[name="replace"]')
            .val();
        switch (action) {
        case 'find':

            i.find(find, {
                backwards: false,
                wrap: true,
                caseSensitive: false,
                wholeWord: false,
                regExp: false
            });

            break;

        case 'replace':

            i.find(find, {
                backwards: false,
                wrap: true,
                caseSensitive: false,
                wholeWord: false,
                regExp: false
            });
            i.replace(replace);

            break;

        case 'replace_all':

            i.find(find, {
                backwards: false,
                wrap: true,
                caseSensitive: false,
                wholeWord: false,
                regExp: false
            });
            i.replaceAll(replace);

            break;
        }
    }

};
<commit_msg>Cleanup mode selector<commit_after>/*
 *  Copyright (c) Codiad & Kent Safranski (codiad.com), distributed
 *  as-is and without warranty under the MIT License. See
 *  [root]/license.txt for more. This information must remain intact.
 */

var VirtualRenderer = require('ace/virtual_renderer').VirtualRenderer;
var Editor = require('ace/editor').Editor;

editor_modes = {}; // Loaded modes
cursorpoll = null;

var editor = {

    // Array of all instances - there is one editor instance
    // corresponding to each split.
    instances: [],

    // Editor-wide settings
    settings: {
        theme: 'twilight',
        font_size: 15,
        print_margin: false,
        highlight_line: true,
        indent_guides: true,
        wrap_mode: false,
    },

    add_instance: function(session){
        var i  = ace.edit('editor');

        // Apply the current configuration settings:
        i.setTheme('ace/theme/' + this.settings.theme);
        i.setFontSize(this.settings.font_size);
        i.setShowPrintMargin(this.settings.print_margin);
        i.setHighlightActiveLine(this.settings.highlight_line);
        i.setDisplayIndentGuides(this.settings.indent_guides);

        this.change_listener(i);
        this.cursor_tracking(i);
        this.bind_keys(i);

        this.instances.push(i);
        return i;
    },

    exterminate: function(){
        $('#editor-region').html('').append($("<div>").attr('id', 'editor'));
        this.instances = [];
    },

    remove_session: function(session, replacement_session){
        for (var k = 0; k < this.instances.length; k++) {
            if (this.instances[k].getSession() === session) {
                this.instances[k].setSession(replacement_session);
            }
        }
    },

    for_each: function(fn){
        for (var k = 0; k < this.instances.length; k++) {
            fn.call(this, this.instances[k]);
        }
    },

    //////////////////////////////////////////////////////////////////
    // Get the currently active Editor
    //////////////////////////////////////////////////////////////////

    get_active: function() {
        if (this.instances.length > 0)
            // While there is no implementation for splitting
            // there can be at most one editor instance.
            return this.instances[0];
        else
            return null;
    },

    set_session: function(session, i) {
        i = i || this.get_active();
        if (! i) i = this.add_instance(session);
        i.setSession(session);
    },

    //////////////////////////////////////////////////////////////////
    // Select mode from extension
    //////////////////////////////////////////////////////////////////

    select_mode: function(e) {
        switch (e) {
        case 'html':
        case 'htm':
        case 'tpl':
            return 'html';
        case 'js':
            return 'javascript';
        case 'css':
            return 'css';
        case 'scss':
        case 'sass':
            return 'scss';
        case 'less':
            return 'less';
        case 'php':
        case 'php5':
            return 'php';
        case 'json':
            return 'json';
        case 'xml':
            return 'xml';
        case 'sql':
            return 'sql';
        case 'md':
            return 'markdown';
        default:
            return 'text';
        }
    },

    //////////////////////////////////////////////////////////////////
    // Set editor mode/language
    //////////////////////////////////////////////////////////////////

    set_mode: function(m, i) {
        i = i || this.get_active();
        if (!editor_modes[m]) { // Check if mode is already loaded
            $.loadScript("components/editor/ace-editor/mode-" + m + ".js", function() {
                editor_modes[m] = true; // Mark to not load again
                var EditorMode = require("ace/mode/" + m)
                    .Mode;
                i.getSession()
                    .setMode(new EditorMode());
            }, true);
        } else {
            var EditorMode = require("ace/mode/" + m)
                .Mode;
            i.getSession()
                .setMode(new EditorMode());
        }
    },

    //////////////////////////////////////////////////////////////////
    // Set editor theme
    //////////////////////////////////////////////////////////////////

    set_theme: function(t, i) {
        if (i) {
            // If a specific instance is specified, change the theme for
            // this instance
            i.setTheme("ace/theme/"+t);
        } else {
            // Change the theme for the existing editor instances
            // and make it the default for new instances
            this.settings['theme'] = t;
            for (var k = 0; k < this.instances.length; k++) {
                this.instances[k].setTheme("ace/theme/"+t);
            }
        }
    },

    //////////////////////////////////////////////////////////////////
    // Set content of editor
    //////////////////////////////////////////////////////////////////

    set_content: function(c, i) {
        i = i || this.get_active();
        i.getSession().setValue(c);
    },

    //////////////////////////////////////////////////////////////////
    // Set Font Size
    //////////////////////////////////////////////////////////////////

    set_font_size: function(s, i) {
        if (i) {
            i.setFontSize(s);
        } else {
            this.settings['font_size'] = s;
            this.for_each(function(i) {
                i.setFontSize(s);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Highlight active line
    //////////////////////////////////////////////////////////////////

    set_highlight_line: function(h, i) {
        if (i) {
            i.setHighlightActiveLine(h)
        } else {
            this.settings['highlight_line'] = h;
            this.for_each(function(i) {
                i.setHighlightActiveLine(h);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Show/Hide print margin indicator
    //////////////////////////////////////////////////////////////////

    set_print_margin: function(p, i) {
        if (i) {
            i.setShowPrintMargin(p);
        } else {
            this.settings['print_margin'] = p;
            this.for_each(function(i) {
                i.setPrintMargin(p);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Show/Hide indent guides
    //////////////////////////////////////////////////////////////////

    set_indent_guides: function(g, i) {
        if (i) {
            i.setDisplayIndentGuides(g);
        } else {
            this.settings['indent_guides'] = g;
            this.for_each(function(i) {
                i.setDisplayIndentGuides(g);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Code Folding
    //////////////////////////////////////////////////////////////////

    set_code_folding: function(f, i) {
        if (i) {
            i.setFoldStyle(f);
        } else {
            this.for_each(function(i){
                i.setFoldStyle(f);
            });
        }
    },

    //////////////////////////////////////////////////////////////////
    // Set Line Wrapping
    //////////////////////////////////////////////////////////////////

    set_wrap_mode: function(w, i) {
        i = i || this.get_active();
        if (! i) return;
        i.getSession()
            .setUseWrapMode(w);
    },

    //////////////////////////////////////////////////////////////////
    // Get content from editor by ID
    //////////////////////////////////////////////////////////////////

    get_content: function(i) {
        i = i || this.get_active();
        if (! i) return;
        var content = i.getSession().getValue();
        if (!content) {
            content = ' ';
        } // Pass something through
        return content;
    },

    //////////////////////////////////////////////////////////////////
    // Resize
    //////////////////////////////////////////////////////////////////

    resize: function(i) {
        i = i || this.get_active();
        if (! i) return;
        i.resize();
    },

    //////////////////////////////////////////////////////////////////
    // Change Listener
    //////////////////////////////////////////////////////////////////

    change_listener: function(i) {
        var _this = this;
        i.on('change', function() {
            active.mark_changed(_this.get_active().getSession().path);
        });
    },

    //////////////////////////////////////////////////////////////////
    // Get Selected Text
    //////////////////////////////////////////////////////////////////

    get_selected_text: function(i) {
        i = i || this.get_active();
        if (! i) return;
        return i.getCopyText();
    },

    //////////////////////////////////////////////////////////////////
    // Insert text
    //////////////////////////////////////////////////////////////////

    insert_text: function(val, i) {
        i = i || this.get_active();
        if (! i) return;
        i.insert(val);
    },

    //////////////////////////////////////////////////////////////////
    // Goto Line
    //////////////////////////////////////////////////////////////////

    goto_line: function(line, i) {
        i = i || this.get_active();
        if (! i) return;
        i.gotoLine(line, 0, true);
    },

    //////////////////////////////////////////////////////////////////
    // Focus
    //////////////////////////////////////////////////////////////////

    focus: function(i) {
        i = i || this.get_active();
        if (! i) return;
        i.focus();
    },

    //////////////////////////////////////////////////////////////////
    // Cursor Tracking
    //////////////////////////////////////////////////////////////////

    cursor_tracking: function(i) {
        i = i || this.get_active();
        if (! i) return;
        clearInterval(cursorpoll);
        cursorpoll = setInterval(function() {
            $('#cursor-position')
                .html('Ln: '
                      + (i.getCursorPosition().row + 1)
                      + ' · Col: '
                      + i.getCursorPosition().column
                     );
        }, 100);
    },

    //////////////////////////////////////////////////////////////////
    // Bind Keys
    //////////////////////////////////////////////////////////////////

    bind_keys: function(i) {

        // Find
        i.commands.addCommand({
            name: 'Find',
            bindKey: {
                win: 'Ctrl-F',
                mac: 'Command-F'
            },
            exec: function(e) {
                editor.open_search('find');
            }
        });

        // Find + Replace
        i.commands.addCommand({
            name: 'Replace',
            bindKey: {
                win: 'Ctrl-R',
                mac: 'Command-R'
            },
            exec: function(e) {
                editor.open_search('replace');
            }
        });

        i.commands.addCommand({
            name: 'Move Up',
            bindKey: {
                win: 'Ctrl-up',
                mac: 'Command-up'
            },
            exec: function(e) {
                active.move('up');
            }
        });

        i.commands.addCommand({
            name: 'Move Down',
            bindKey: {
                win: 'Ctrl-down',
                mac: 'Command-up'
            },
            exec: function(e) {
                active.move('down');
            }
        });

    },

    //////////////////////////////////////////////////////////////////
    // Search (Find + Replace)
    //////////////////////////////////////////////////////////////////

    open_search: function(type) {
        if (this.get_active()) {
            modal.load(400, 'components/editor/dialog.php?action=search&type=' + type);
            modal.hide_overlay();
        } else {
            message.error('No Open Files');
        }
    },

    search: function(action, i) {
        i = i || this.get_active();
        if (! i) return;
        var find = $('#modal input[name="find"]')
            .val();
        var replace = $('#modal input[name="replace"]')
            .val();
        switch (action) {
        case 'find':

            i.find(find, {
                backwards: false,
                wrap: true,
                caseSensitive: false,
                wholeWord: false,
                regExp: false
            });

            break;

        case 'replace':

            i.find(find, {
                backwards: false,
                wrap: true,
                caseSensitive: false,
                wholeWord: false,
                regExp: false
            });
            i.replace(replace);

            break;

        case 'replace_all':

            i.find(find, {
                backwards: false,
                wrap: true,
                caseSensitive: false,
                wholeWord: false,
                regExp: false
            });
            i.replaceAll(replace);

            break;
        }
    }

};
<|endoftext|>


<commit_before>/**
 * Shows general gene info.
 * Such as its name, synonyms, annotation, publications, etc.
 *
 * Gene "instance" info (e.g. coordinates on a particular strain's genome)
 * is in a different widget.
 */
(function( $, undefined ) {
    $.KBWidget({
        name: "KBaseGeneStructureMatches",
        parent: "kbaseWidget",
        version: "1.0.0",

        options: {
            featureID: null,
            embedInCard: false,
            auth: null,
            loadingImage: "../../widgets/images/ajax-loader.gif",
            genomeID: null,
            workspaceID: null,
            kbCache: null,
        },

        cdmiURL: "https://kbase.us/services/cdmi_api",
        //kbprotstructURL: "http://140.221.85.122:7088",
        kbprotstructURL: "http://140.221.67.170:7088",

        init: function(options) {
            this._super(options);

            if (this.options.featureID === null) {
                //throw an error.
                return this;
            }
            this.cdmiClient = new CDMI_API(this.cdmiURL);
            this.entityClient = new CDMI_EntityAPI(this.cdmiURL);

            this.kbprotstruct = new KBaseProteinStructure( this.kbprotstructURL );
            this.render();
            if (this.options.workspaceID) {
                this.renderWorkspace();
            }
            else
                this.renderCentralStore();

            return this;
        },

        render: function() {
            this.$messagePane = $("
")
                                .addClass("kbwidget-message-pane kbwidget-hide-message");
            this.$elem.append(this.$messagePane);
            //this.showMessage( "
TUBE  TUBE    TUBE
" ).delay(5000);

            this.$infoPanel = $("
");
            //this.$infoTable = $("
")
            //                  .addClass("table table-striped table-bordered");
            //this.$elem.append(this.$infoPanel.append(this.$infoTable));
            this.$infoPara = $("
");
            this.$morePara = $("
");
            this.$structTable = $("
");
            this.$elem.append(this.$infoPanel.append(this.$infoPara).append(this.$morePara).append(this.$structTable));
        },

        renderCentralStore: function()
           {
            this.$infoPanel.hide();
            lookup_prom = this.kbprotstruct.lookup_pdb_by_fid( [ this.options.featureID ] );

            this.pdburl = function( pdbid, chains )
                             {
                              var r;
                              r = "" + pdbid + "";
                              if ( ! chains.match( /^\s*$/ ) )
                                 { r = r + " " + chains; }
                              return( r );
                             };
            this.pdbimage = function( pdbid )
                             {
                              //return( "" );
                              return( "");
                             };
            self = this;
            this.matchtab = [];   // array of row objects to go into the kbaseTable
            $.when(lookup_prom).done(
                                      function( lookup_res )
                                         {
                                           var fidkey;
                                           var i;
                                           var nhits;
                                           var max_show = 5;
                                           //console.log( "lookup done, lookup_res is " );
                                           //console.log( lookup_res );

                                           // lookup_pdb_by_fid() returns an object with keys
                                           // corresponding to the fids given to it.   The value
                                           // for each fid "key" is a list of objects.
                                           // Since we only send one fid, we really only need to get
                                           // the first key, but I'm putting into a loop anyway:
                                           for ( fidkey in lookup_res )
                                               {
                                                if ( lookup_res.hasOwnProperty( fidkey ) )
                                                    {
                                                     //console.log( "processing key" );
                                                     //console.log( fidkey );
                                                     hits = lookup_res[fidkey];  // hits is array of hit objects
                                                     //console.log( "number of hits is");
                                                     //console.log( hits.length );
                                                     nhits = hits.length;
                                                     for ( i = 0; i < hits.length; i++ )
                                                        {
                                                         //console.log( hits[i].pdb_id );
                                                         if ( i < max_show )
                                                             self.matchtab.push( { 'image': self.pdbimage( hits[i].pdb_id ),
                                                             	                  'PDB id': self.pdburl( hits[i].pdb_id, hits[i].chains ),
                                                                                '% identity': hits[i].percent_id.toString(),
                                                                                'align. len.': hits[i].align_length.toString()
                                                                                }
                                                                                );
                                                        }
                                                    }
                                               }
                                           //console.log( "self.matchtab is");
                                           //console.log( self.matchtab );
                                           if ( nhits <= 0 )
                                              {
                                               self.$infoPara.append( "No PDB Sequence matches");
                                              }
                                           else
                                           	  {
                                        	   self.$infoPara.append( "PDB Sequence matches");
                                               self.$structTable.kbaseTable(
                                                                             {
                                                                               structure :
                                                                                {
                                                                                header : [
                                                                                { 'value' : 'image' },
                                                                                { 'value' : 'PDB id',    'sortable' : true },
                                                                                { 'value' : '% identity', 'sortable' : true },
                                                                                { 'value' : 'align. len.',  'sortable' : true }
                                                                                ],
                                                                                rows : self.matchtab
                                                                                }
                                                                            }
                                                                          );
                                                if ( nhits >= max_show )
                                                	self.$infoPara.append( "
(" + max_show + " of " + nhits + " matches shown)")
                                               }
                                           self.hideMessage();
                                           self.$infoPanel.show();
                                         }
                                    );
            // console.log("done renderCentralStore");
           },

        makeRow: function(name, value) {
            var $row = $("
")
                       .append($("").append(name))
                       .append($("").append(value));
            return $row;
        },

        renderWorkspace: function() {
            this.showMessage("");
            this.$infoPanel.hide();

            if (!this.options.kbCache) {
                if (kb)
                    this.options.kbCache = kb;
                else
                    console.debug("No cache service found. D'oh!");
            }
            var obj = this.buildObjectIdentity(this.options.workspaceID, this.options.genomeID);

            var prom = this.options.kbCache.req('ws', 'get_objects', [obj]);
            // on ws error
            $.when(prom).fail($.proxy(function(error) {
                this.renderError(error);
            }, this));
            // on cache success
            $.when(prom).done($.proxy(function(genome) {
                genome = genome[0];
                if (genome.data.features) {
                    var feature = null;
                    for (var i=0; i<genome.data.features.length; i++) {
                        if (genome.data.features[i].id === this.options.featureID) {
                            feature = genome.data.features[i];
                            break;
                        }
                    }

                    var subsysStr = "No subsystem info found.";
                    if (feature.subsystems) {

                    }
                    this.$infoTable.append(this.makeRow("Subsystems", subsysStr));

                    var rolesStr = "No roles info found.";
                    if (feature.roles) {

                    }
                    this.$infoTable.append(this.makeRow("Roles", rolesStr));

                }
                else {
                    this.renderError({ error: "No genetic features found in the genome with object id: " +
                                              this.options.workspaceID + "/" +
                                              this.options.genomeID });
                }

                this.hideMessage();
                this.$infoPanel.show();
            }, this));

        },

        buildObjectIdentity: function(workspaceID, objectID) {
            var obj = {};
            if (/^\d+$/.exec(workspaceID))
                obj['wsid'] = workspaceID;
            else
                obj['workspace'] = workspaceID;

            // same for the id
            if (/^\d+$/.exec(objectID))
                obj['objid'] = objectID;
            else
                obj['name'] = objectID;
            return obj;
        },

        getData: function() {
            return {
                type: "Feature",
                id: this.options.featureID,
                workspace: this.options.workspaceID,
                title: "Matching Structures"
            };
        },

        showMessage: function(message) {
            var span = $("").append(message);

            this.$messagePane.empty()
                             .append(span)
                             .removeClass("kbwidget-hide-message");
        },

        hideMessage: function() {
            this.$messagePane.addClass("kbwidget-hide-message");
        },

        renderError: function(error) {
            errString = "Sorry, an unknown error occurred";
            if (typeof error === "string")
                errString = error;
            else if (error.error && error.error.message)
                errString = error.error.message;

            var $errorDiv = $("
")
                            .addClass("alert alert-danger")
                            .append("Error:")
                            .append("
" + errString);
            this.$elem.empty();
            this.$elem.append($errorDiv);
        },
    })
})( jQuery );<commit_msg>service has been moved into production, so I've changed the URL in src/widgets/genomes/kbaseGeneStructureMatches.js to point to the official production service.<commit_after>/**
 * Shows general gene info.
 * Such as its name, synonyms, annotation, publications, etc.
 *
 * Gene "instance" info (e.g. coordinates on a particular strain's genome)
 * is in a different widget.
 */
(function( $, undefined ) {
    $.KBWidget({
        name: "KBaseGeneStructureMatches",
        parent: "kbaseWidget",
        version: "1.0.0",

        options: {
            featureID: null,
            embedInCard: false,
            auth: null,
            loadingImage: "../../widgets/images/ajax-loader.gif",
            genomeID: null,
            workspaceID: null,
            kbCache: null,
        },

        cdmiURL: "https://kbase.us/services/cdmi_api",
        // kbprotstructURL: "http://140.221.67.170:7088",
        kbprotstructURL: "https://kbase.us/services/protein_structure_service",

        init: function(options) {
            this._super(options);

            if (this.options.featureID === null) {
                //throw an error.
                return this;
            }
            this.cdmiClient = new CDMI_API(this.cdmiURL);
            this.entityClient = new CDMI_EntityAPI(this.cdmiURL);

            this.kbprotstruct = new KBaseProteinStructure( this.kbprotstructURL );
            this.render();
            if (this.options.workspaceID) {
                this.renderWorkspace();
            }
            else
                this.renderCentralStore();

            return this;
        },

        render: function() {
            this.$messagePane = $("
")
                                .addClass("kbwidget-message-pane kbwidget-hide-message");
            this.$elem.append(this.$messagePane);
            //this.showMessage( "
TUBE  TUBE    TUBE
" ).delay(5000);

            this.$infoPanel = $("
");
            //this.$infoTable = $("
")
            //                  .addClass("table table-striped table-bordered");
            //this.$elem.append(this.$infoPanel.append(this.$infoTable));
            this.$infoPara = $("
");
            this.$morePara = $("
");
            this.$structTable = $("
");
            this.$elem.append(this.$infoPanel.append(this.$infoPara).append(this.$morePara).append(this.$structTable));
        },

        renderCentralStore: function()
           {
            this.$infoPanel.hide();
            lookup_prom = this.kbprotstruct.lookup_pdb_by_fid( [ this.options.featureID ] );

            this.pdburl = function( pdbid, chains )
                             {
                              var r;
                              r = "" + pdbid + "";
                              if ( ! chains.match( /^\s*$/ ) )
                                 { r = r + " " + chains; }
                              return( r );
                             };
            this.pdbimage = function( pdbid )
                             {
                              //return( "" );
                              return( "");
                             };
            self = this;
            this.matchtab = [];   // array of row objects to go into the kbaseTable
            $.when(lookup_prom).done(
                                      function( lookup_res )
                                         {
                                           var fidkey;
                                           var i;
                                           var nhits;
                                           var max_show = 5;
                                           //console.log( "lookup done, lookup_res is " );
                                           //console.log( lookup_res );

                                           // lookup_pdb_by_fid() returns an object with keys
                                           // corresponding to the fids given to it.   The value
                                           // for each fid "key" is a list of objects.
                                           // Since we only send one fid, we really only need to get
                                           // the first key, but I'm putting into a loop anyway:
                                           for ( fidkey in lookup_res )
                                               {
                                                if ( lookup_res.hasOwnProperty( fidkey ) )
                                                    {
                                                     //console.log( "processing key" );
                                                     //console.log( fidkey );
                                                     hits = lookup_res[fidkey];  // hits is array of hit objects
                                                     //console.log( "number of hits is");
                                                     //console.log( hits.length );
                                                     nhits = hits.length;
                                                     for ( i = 0; i < hits.length; i++ )
                                                        {
                                                         //console.log( hits[i].pdb_id );
                                                         if ( i < max_show )
                                                             self.matchtab.push( { 'image': self.pdbimage( hits[i].pdb_id ),
                                                             	                  'PDB id': self.pdburl( hits[i].pdb_id, hits[i].chains ),
                                                                                '% identity': hits[i].percent_id.toString(),
                                                                                'align. len.': hits[i].align_length.toString()
                                                                                }
                                                                                );
                                                        }
                                                    }
                                               }
                                           //console.log( "self.matchtab is");
                                           //console.log( self.matchtab );
                                           if ( nhits <= 0 )
                                              {
                                               self.$infoPara.append( "No PDB Sequence matches");
                                              }
                                           else
                                           	  {
                                        	   self.$infoPara.append( "PDB Sequence matches");
                                               self.$structTable.kbaseTable(
                                                                             {
                                                                               structure :
                                                                                {
                                                                                header : [
                                                                                { 'value' : 'image' },
                                                                                { 'value' : 'PDB id',    'sortable' : true },
                                                                                { 'value' : '% identity', 'sortable' : true },
                                                                                { 'value' : 'align. len.',  'sortable' : true }
                                                                                ],
                                                                                rows : self.matchtab
                                                                                }
                                                                            }
                                                                          );
                                                if ( nhits >= max_show )
                                                	self.$infoPara.append( "
(" + max_show + " of " + nhits + " matches shown)")
                                               }
                                           self.hideMessage();
                                           self.$infoPanel.show();
                                         }
                                    );
            // console.log("done renderCentralStore");
           },

        makeRow: function(name, value) {
            var $row = $("
")
                       .append($("").append(name))
                       .append($("").append(value));
            return $row;
        },

        renderWorkspace: function() {
            this.showMessage("");
            this.$infoPanel.hide();

            if (!this.options.kbCache) {
                if (kb)
                    this.options.kbCache = kb;
                else
                    console.debug("No cache service found. D'oh!");
            }
            var obj = this.buildObjectIdentity(this.options.workspaceID, this.options.genomeID);

            var prom = this.options.kbCache.req('ws', 'get_objects', [obj]);
            // on ws error
            $.when(prom).fail($.proxy(function(error) {
                this.renderError(error);
            }, this));
            // on cache success
            $.when(prom).done($.proxy(function(genome) {
                genome = genome[0];
                if (genome.data.features) {
                    var feature = null;
                    for (var i=0; i<genome.data.features.length; i++) {
                        if (genome.data.features[i].id === this.options.featureID) {
                            feature = genome.data.features[i];
                            break;
                        }
                    }

                    var subsysStr = "No subsystem info found.";
                    if (feature.subsystems) {

                    }
                    this.$infoTable.append(this.makeRow("Subsystems", subsysStr));

                    var rolesStr = "No roles info found.";
                    if (feature.roles) {

                    }
                    this.$infoTable.append(this.makeRow("Roles", rolesStr));

                }
                else {
                    this.renderError({ error: "No genetic features found in the genome with object id: " +
                                              this.options.workspaceID + "/" +
                                              this.options.genomeID });
                }

                this.hideMessage();
                this.$infoPanel.show();
            }, this));

        },

        buildObjectIdentity: function(workspaceID, objectID) {
            var obj = {};
            if (/^\d+$/.exec(workspaceID))
                obj['wsid'] = workspaceID;
            else
                obj['workspace'] = workspaceID;

            // same for the id
            if (/^\d+$/.exec(objectID))
                obj['objid'] = objectID;
            else
                obj['name'] = objectID;
            return obj;
        },

        getData: function() {
            return {
                type: "Feature",
                id: this.options.featureID,
                workspace: this.options.workspaceID,
                title: "Matching Structures"
            };
        },

        showMessage: function(message) {
            var span = $("").append(message);

            this.$messagePane.empty()
                             .append(span)
                             .removeClass("kbwidget-hide-message");
        },

        hideMessage: function() {
            this.$messagePane.addClass("kbwidget-hide-message");
        },

        renderError: function(error) {
            errString = "Sorry, an unknown error occurred";
            if (typeof error === "string")
                errString = error;
            else if (error.error && error.error.message)
                errString = error.error.message;

            var $errorDiv = $("
")
                            .addClass("alert alert-danger")
                            .append("Error:")
                            .append("
" + errString);
            this.$elem.empty();
            this.$elem.append($errorDiv);
        },
    })
})( jQuery );<|endoftext|>


<commit_before>var combine = require('stream-combiner')
var glslify = require('glslify-stream')
var concat = require('concat-stream')
var map = require('map-stream')
var split = require('split')
var eol = require('os').EOL
var fs = require('fs')

module.exports = include

function include(file) {
  var stream = combine(split(), map(write))
  var output = ''

  return stream

  function write(line, next) {
    var match

    line = String(line)
    line = line.replace(/#pragma\s+import\:(.+)$/g, function(full, name) {
      match = name.trim()
      return ''
    })

    if (!match) return next(null, line + eol)

    glslify.resolve(file, match, function(err, dest) {
      if (err) return stream.emit('error', err)

      // Handle imports recursively too!
      fs.createReadStream(dest)
        .pipe(include(dest))
        .pipe(concat(function(data) {
          next(null, data + eol)
        }))
        .on('error', function(err) {
          return stream.emit('error', err)
        })
    })
  }
}
<commit_msg>tweak<commit_after>var combine = require('stream-combiner')
var glslify = require('glslify-stream')
var concat = require('concat-stream')
var map = require('map-stream')
var split = require('split')
var eol = require('os').EOL
var fs = require('fs')

module.exports = include

function include(file) {
  var stream = combine(split(), map(write))

  return stream

  function write(line, next) {
    var match

    line = String(line)
    line = line.replace(/#pragma\s+import\:(.+)$/g, function(full, name) {
      match = name.trim()
      return ''
    })

    if (!match) return next(null, line + eol)

    glslify.resolve(file, match, function(err, dest) {
      if (err) return stream.emit('error', err)

      // Handle imports recursively too!
      fs.createReadStream(dest)
        .pipe(include(dest))
        .pipe(concat(function(data) {
          next(null, data + eol)
        }))
        .on('error', function(err) {
          return stream.emit('error', err)
        })
    })
  }
}
<|endoftext|>