<commit_before>import DefaultHandler from './default';
import constants from '../../constants';

export const supportedPages = constants.PAGE_NAMES
  .filter(p => p.includes('.json'))
  .map(p => p.replace('.json', ''));

export const pageNameMap = {
  guardian_multifactor: 'guardian_mfa_page',
  password_reset: 'change_password',
  error_page: 'error_page'
};

// With this schema, we can only validate property types but not valid properties on per type basis
export const schema = {
  type: 'array',
  items: {
    type: 'object',
    properties: {
      name: { type: 'string', enum: supportedPages },
      html: { type: 'string', default: '' },
      url: { type: 'string' },
      show_log_link: { type: 'boolean' },
      enabled: { type: 'boolean' }
    },
    required: [ 'name' ]
  }
};

export default class PageHandler extends DefaultHandler {
  constructor(options) {
    super({
      ...options,
      type: 'pages'
    });
  }

  objString(page) {
    return super.objString({ name: page.name, enabled: page.enabled });
  }

  async updateLoginPage(page) {
    const globalClient = await this.client.clients.getAll({ is_global: true });

    if (!globalClient[0]) {
      throw new Error('Unable to find global client id when trying to update the login page');
    }

    await this.client.clients.update(
      { client_id: globalClient[0].client_id },
      {
        custom_login_page: page.html,
        custom_login_page_on: page.enabled
      }
    );
    this.updated += 1;
    this.didUpdate(page);
  }

  async updatePages(pages) {
    const toUpdate = pages.filter(p => supportedPages.includes(p.name));
    const update = toUpdate.reduce((accum, page) => {
      if (supportedPages.includes(page.name)) {
        const pageName = pageNameMap[page.name];
        if (!pageName) {
          throw new Error(`Unable to map page ${page.name} into tenant level page setting`);
        }
        accum[pageName] = { ...page };
        delete accum[pageName].name;
      }
      return accum;
    }, {});

    if (Object.keys(update).length) {
      await this.client.tenant.updateSettings(update);
    }

    toUpdate.forEach((page) => {
      this.updated += 1;
      this.didUpdate(page);
    });
  }

  async getType() {
    const pages = [];

    // Login page is handled via the global client
    const globalClient = await this.client.clients.getAll({ is_global: true });
    if (!globalClient[0]) {
      throw new Error('Unable to find global client id when trying to dump the login page');
    }

    if (globalClient[0].custom_login_page) {
      pages.push({
        name: 'login',
        enabled: globalClient[0].custom_login_page_on,
        html: globalClient[0].custom_login_page
      });
    }

    const tenantSettings = await this.client.tenant.getSettings();

    Object.entries(pageNameMap).forEach(([ key, name ]) => {
      const page = tenantSettings[name];
      if (tenantSettings[name]) {
        pages.push({
          ...page,
          name: key
        });
      }
    });

    return pages;
  }

  async processChanges(assets) {
    const { pages } = assets;

    // Do nothing if not set
    if (!pages) return;

    // Login page is handled via the global client
    const loginPage = pages.find(p => p.name === 'login');
    if (loginPage) {
      await this.updateLoginPage(loginPage);
    }

    // Rest of pages are on tenant level settings
    await this.updatePages(pages.filter(p => p.name !== 'login'));
  }
}
<commit_msg>fix: use paginate for getting global client<commit_after>import DefaultHandler from './default';
import constants from '../../constants';

export const supportedPages = constants.PAGE_NAMES
  .filter(p => p.includes('.json'))
  .map(p => p.replace('.json', ''));

export const pageNameMap = {
  guardian_multifactor: 'guardian_mfa_page',
  password_reset: 'change_password',
  error_page: 'error_page'
};

// With this schema, we can only validate property types but not valid properties on per type basis
export const schema = {
  type: 'array',
  items: {
    type: 'object',
    properties: {
      name: { type: 'string', enum: supportedPages },
      html: { type: 'string', default: '' },
      url: { type: 'string' },
      show_log_link: { type: 'boolean' },
      enabled: { type: 'boolean' }
    },
    required: [ 'name' ]
  }
};

export default class PageHandler extends DefaultHandler {
  constructor(options) {
    super({
      ...options,
      type: 'pages'
    });
  }

  objString(page) {
    return super.objString({ name: page.name, enabled: page.enabled });
  }

  async updateLoginPage(page) {
    const globalClient = await this.client.clients.getAll({ is_global: true, paginate: true });

    if (!globalClient[0]) {
      throw new Error('Unable to find global client id when trying to update the login page');
    }

    await this.client.clients.update(
      { client_id: globalClient[0].client_id },
      {
        custom_login_page: page.html,
        custom_login_page_on: page.enabled
      }
    );
    this.updated += 1;
    this.didUpdate(page);
  }

  async updatePages(pages) {
    const toUpdate = pages.filter(p => supportedPages.includes(p.name));
    const update = toUpdate.reduce((accum, page) => {
      if (supportedPages.includes(page.name)) {
        const pageName = pageNameMap[page.name];
        if (!pageName) {
          throw new Error(`Unable to map page ${page.name} into tenant level page setting`);
        }
        accum[pageName] = { ...page };
        delete accum[pageName].name;
      }
      return accum;
    }, {});

    if (Object.keys(update).length) {
      await this.client.tenant.updateSettings(update);
    }

    toUpdate.forEach((page) => {
      this.updated += 1;
      this.didUpdate(page);
    });
  }

  async getType() {
    const pages = [];

    // Login page is handled via the global client
    const globalClient = await this.client.clients.getAll({ is_global: true, paginate: true });
    if (!globalClient[0]) {
      throw new Error('Unable to find global client id when trying to dump the login page');
    }

    if (globalClient[0].custom_login_page) {
      pages.push({
        name: 'login',
        enabled: globalClient[0].custom_login_page_on,
        html: globalClient[0].custom_login_page
      });
    }

    const tenantSettings = await this.client.tenant.getSettings();

    Object.entries(pageNameMap).forEach(([ key, name ]) => {
      const page = tenantSettings[name];
      if (tenantSettings[name]) {
        pages.push({
          ...page,
          name: key
        });
      }
    });

    return pages;
  }

  async processChanges(assets) {
    const { pages } = assets;

    // Do nothing if not set
    if (!pages) return;

    // Login page is handled via the global client
    const loginPage = pages.find(p => p.name === 'login');
    if (loginPage) {
      await this.updateLoginPage(loginPage);
    }

    // Rest of pages are on tenant level settings
    await this.updatePages(pages.filter(p => p.name !== 'login'));
  }
}
<|endoftext|>


<commit_before>var compose_fade = (function () {

var exports = {};

var focused_recipient;
var normal_display = false;

exports.should_fade_message =  function (message) {
    return !util.same_recipient(focused_recipient, message);
};

exports.set_focused_recipient = function (msg_type) {
    if (msg_type === undefined) {
        focused_recipient = undefined;
    }

    // Construct focused_recipient as a mocked up element which has all the
    // fields of a message used by util.same_recipient()
    focused_recipient = {
        type: msg_type,
    };

    if (focused_recipient.type === "stream") {
        var stream_name = $('#stream').val();
        focused_recipient.subject = $('#subject').val();
        focused_recipient.stream = stream_name;
        var sub = stream_data.get_sub(stream_name);
        if (sub) {
            focused_recipient.stream_id = sub.stream_id;
        }
    } else {
        // Normalize the recipient list so it matches the one used when
        // adding the message (see message_store.add_message_metadata()).
        var reply_to = util.normalize_recipients(
                $('#private_message_recipient').val());
        focused_recipient.reply_to = reply_to;
        focused_recipient.to_user_ids = people.reply_to_to_user_ids_string(reply_to);
    }
};

function _display_messages_normally() {
    rows.get_table(current_msg_list.table_name).find(".recipient_row, .message_row")
                                               .removeClass("faded").removeClass("unfaded");

    normal_display = true;
    floating_recipient_bar.update();
}

function _display_users_normally() {
    $('.user_sidebar_entry').removeClass('faded').removeClass('unfaded');
}

function change_fade_state(elt, should_fade_group) {
    if (should_fade_group) {
        elt.removeClass("unfaded").addClass("faded");
    } else {
        elt.removeClass("faded").addClass("unfaded");
    }
}

function _fade_messages() {
    var i;
    var first_message;
    var first_row;
    var should_fade_group = false;
    var visible_groups = viewport.visible_groups(false);

    normal_display = false;

    // Update the visible messages first, before the compose box opens
    for (i = 0; i < visible_groups.length; i += 1) {
        first_row = rows.first_message_in_group(visible_groups[i]);
        first_message = current_msg_list.get(rows.id(first_row));
        should_fade_group = exports.should_fade_message(first_message);

        change_fade_state($(visible_groups[i]), should_fade_group);
    }

    // Defer updating all message groups so that the compose box can open sooner
    setTimeout(function (expected_msg_list, expected_recipient) {
        var all_groups = rows.get_table(current_msg_list.table_name).find(".recipient_row");

        if (current_msg_list !== expected_msg_list ||
            !compose.composing() ||
            compose.recipient() !== expected_recipient) {
            return;
        }

        should_fade_group = false;

        // Note: The below algorithm relies on the fact that all_elts is
        // sorted as it would be displayed in the message view
        for (i = 0; i < all_groups.length; i += 1) {
            var group_elt = $(all_groups[i]);
            should_fade_group = exports.should_fade_message(rows.recipient_from_group(group_elt));
            change_fade_state(group_elt, should_fade_group);
        }

        floating_recipient_bar.update();
    }, 0, current_msg_list, compose.recipient());
}

exports.would_receive_message = function (email) {
    // Given the current focused_recipient, this function returns true if
    // the user in question would definitely receive this message, false if
    // they would definitely not receive this message, and undefined if we
    // don't know (e.g. the recipient is a stream we're not subscribed to).
    //
    // Yes it's slightly weird to have three return values, but this will be
    // helpful if we want to emphasize the '.unfaded' class later (applied
    // to users who will definitely receive the message).

    if (people.is_current_user(email)) {
        // We never want to fade you yourself, so pretend it's true even if
        // it's not.
        return true;
    }

    if (focused_recipient.type === 'stream') {
        var user = people.realm_get(email);
        var sub = stream_data.get_sub(focused_recipient.stream);
        if (user && sub && user.is_bot && !sub.invite_only) {
            // Bots may receive messages on public streams even if they are
            // not subscribed.
            return undefined;
        }
        return stream_data.user_is_subscribed(focused_recipient.stream, email);
    }

    // PM, so check if the given email is in the recipients list.
    return util.is_pm_recipient(email, focused_recipient);
};

function _fade_users() {
    _.forEach($('.user_sidebar_entry'), function (elt) {
        elt = $(elt);
        var user_id = elt.attr('data-user-id');
        var email = people.get_person_from_user_id(user_id).email;
        var would_receive = exports.would_receive_message(email);
        if (would_receive === true) {
            elt.addClass('unfaded').removeClass('faded');
        } else if (would_receive === false) {
            elt.addClass('faded').removeClass('unfaded');
        } else {
            elt.removeClass('faded').removeClass('unfaded');
        }
    });
}

function _want_normal_display() {
    // If we're not composing show a normal display.
    if (focused_recipient === undefined) {
        return true;
    }

    // If the user really hasn't specified anything let, then we want a normal display
    if (focused_recipient.type === "stream") {
        // If a stream doesn't exist, there is no real chance of a mix, so fading
        // is just noise to the user.
        if (!stream_data.get_sub(focused_recipient.stream)) {
            return true;
        }

        // This is kind of debatable.  If the topic is empty, it could be that
        // the user simply hasn't started typing it yet, but disabling fading here
        // means the feature doesn't help realms where topics aren't mandatory
        // (which is most realms as of this writing).
        if (focused_recipient.subject === "") {
            return true;
        }
    }

    return focused_recipient.type === "private" && focused_recipient.reply_to === "";
}

function _update_faded_messages() {
    // See also update_faded_messages(), which just wraps this with a debounce.
    // FIXME: This fades users too now, as well as messages, so should have
    // a better name.
    if (_want_normal_display()) {
        if (!normal_display) {
            _display_messages_normally();
            _display_users_normally();
        }
    } else {
        _fade_messages();
        _fade_users();
    }
}

// This one only updates the users, not both, like update_faded_messages.
// This is for when new presence information comes in, redrawing the presence
// list.
exports.update_faded_users = function () {
    if (_want_normal_display()) {
        _display_users_normally();
    } else {
        _fade_users();
    }
};

// See trac #1633.  For fast typists, calls to _update_faded_messages can
// cause typing sluggishness.
exports.update_faded_messages = _.debounce(_update_faded_messages, 50);

exports.start_compose = function (msg_type) {
    exports.set_focused_recipient(msg_type);
    _update_faded_messages();
};

exports.clear_compose = function () {
    focused_recipient = undefined;
    _display_messages_normally();
    _display_users_normally();
};

exports.update_message_list = function () {
    if (_want_normal_display()) {
       _display_messages_normally();
    } else {
        _fade_messages();
    }
};

exports.update_rendered_message_groups = function (message_groups, get_element) {
    if (_want_normal_display()) {
        return;
    }

    // This loop is superficially similar to some code in _fade_messages, but an
    // important difference here is that we look at each message individually, whereas
    // the other code takes advantage of blocks beneath recipient bars.
    _.each(message_groups, function (message_group) {
        var elt = get_element(message_group);
        var first_message = message_group.message_containers[0].msg;
        var should_fade = exports.should_fade_message(first_message);
        change_fade_state(elt, should_fade);
    });
};

$(function () {
    $(document).on('peer_subscribe.zulip', function () {
        exports.update_faded_users();
    });
    $(document).on('peer_unsubscribe.zulip', function () {
        exports.update_faded_users();
    });
});

return exports;

}());

if (typeof module !== 'undefined') {
    module.exports = compose_fade;
}
<commit_msg>Extract update_user_row_when_fading().<commit_after>var compose_fade = (function () {

var exports = {};

var focused_recipient;
var normal_display = false;

exports.should_fade_message =  function (message) {
    return !util.same_recipient(focused_recipient, message);
};

exports.set_focused_recipient = function (msg_type) {
    if (msg_type === undefined) {
        focused_recipient = undefined;
    }

    // Construct focused_recipient as a mocked up element which has all the
    // fields of a message used by util.same_recipient()
    focused_recipient = {
        type: msg_type,
    };

    if (focused_recipient.type === "stream") {
        var stream_name = $('#stream').val();
        focused_recipient.subject = $('#subject').val();
        focused_recipient.stream = stream_name;
        var sub = stream_data.get_sub(stream_name);
        if (sub) {
            focused_recipient.stream_id = sub.stream_id;
        }
    } else {
        // Normalize the recipient list so it matches the one used when
        // adding the message (see message_store.add_message_metadata()).
        var reply_to = util.normalize_recipients(
                $('#private_message_recipient').val());
        focused_recipient.reply_to = reply_to;
        focused_recipient.to_user_ids = people.reply_to_to_user_ids_string(reply_to);
    }
};

function _display_messages_normally() {
    rows.get_table(current_msg_list.table_name).find(".recipient_row, .message_row")
                                               .removeClass("faded").removeClass("unfaded");

    normal_display = true;
    floating_recipient_bar.update();
}

function _display_users_normally() {
    $('.user_sidebar_entry').removeClass('faded').removeClass('unfaded');
}

function change_fade_state(elt, should_fade_group) {
    if (should_fade_group) {
        elt.removeClass("unfaded").addClass("faded");
    } else {
        elt.removeClass("faded").addClass("unfaded");
    }
}

function _fade_messages() {
    var i;
    var first_message;
    var first_row;
    var should_fade_group = false;
    var visible_groups = viewport.visible_groups(false);

    normal_display = false;

    // Update the visible messages first, before the compose box opens
    for (i = 0; i < visible_groups.length; i += 1) {
        first_row = rows.first_message_in_group(visible_groups[i]);
        first_message = current_msg_list.get(rows.id(first_row));
        should_fade_group = exports.should_fade_message(first_message);

        change_fade_state($(visible_groups[i]), should_fade_group);
    }

    // Defer updating all message groups so that the compose box can open sooner
    setTimeout(function (expected_msg_list, expected_recipient) {
        var all_groups = rows.get_table(current_msg_list.table_name).find(".recipient_row");

        if (current_msg_list !== expected_msg_list ||
            !compose.composing() ||
            compose.recipient() !== expected_recipient) {
            return;
        }

        should_fade_group = false;

        // Note: The below algorithm relies on the fact that all_elts is
        // sorted as it would be displayed in the message view
        for (i = 0; i < all_groups.length; i += 1) {
            var group_elt = $(all_groups[i]);
            should_fade_group = exports.should_fade_message(rows.recipient_from_group(group_elt));
            change_fade_state(group_elt, should_fade_group);
        }

        floating_recipient_bar.update();
    }, 0, current_msg_list, compose.recipient());
}

exports.would_receive_message = function (email) {
    // Given the current focused_recipient, this function returns true if
    // the user in question would definitely receive this message, false if
    // they would definitely not receive this message, and undefined if we
    // don't know (e.g. the recipient is a stream we're not subscribed to).
    //
    // Yes it's slightly weird to have three return values, but this will be
    // helpful if we want to emphasize the '.unfaded' class later (applied
    // to users who will definitely receive the message).

    if (people.is_current_user(email)) {
        // We never want to fade you yourself, so pretend it's true even if
        // it's not.
        return true;
    }

    if (focused_recipient.type === 'stream') {
        var user = people.realm_get(email);
        var sub = stream_data.get_sub(focused_recipient.stream);
        if (user && sub && user.is_bot && !sub.invite_only) {
            // Bots may receive messages on public streams even if they are
            // not subscribed.
            return undefined;
        }
        return stream_data.user_is_subscribed(focused_recipient.stream, email);
    }

    // PM, so check if the given email is in the recipients list.
    return util.is_pm_recipient(email, focused_recipient);
};

function update_user_row_when_fading(elt) {
    var user_id = elt.attr('data-user-id');
    var email = people.get_person_from_user_id(user_id).email;
    var would_receive = exports.would_receive_message(email);
    if (would_receive === true) {
        elt.addClass('unfaded').removeClass('faded');
    } else if (would_receive === false) {
        elt.addClass('faded').removeClass('unfaded');
    } else {
        elt.removeClass('faded').removeClass('unfaded');
    }
}

function _fade_users() {
    _.forEach($('.user_sidebar_entry'), function (elt) {
        elt = $(elt);
        update_user_row_when_fading(elt);
    });
}

function _want_normal_display() {
    // If we're not composing show a normal display.
    if (focused_recipient === undefined) {
        return true;
    }

    // If the user really hasn't specified anything let, then we want a normal display
    if (focused_recipient.type === "stream") {
        // If a stream doesn't exist, there is no real chance of a mix, so fading
        // is just noise to the user.
        if (!stream_data.get_sub(focused_recipient.stream)) {
            return true;
        }

        // This is kind of debatable.  If the topic is empty, it could be that
        // the user simply hasn't started typing it yet, but disabling fading here
        // means the feature doesn't help realms where topics aren't mandatory
        // (which is most realms as of this writing).
        if (focused_recipient.subject === "") {
            return true;
        }
    }

    return focused_recipient.type === "private" && focused_recipient.reply_to === "";
}

function _update_faded_messages() {
    // See also update_faded_messages(), which just wraps this with a debounce.
    // FIXME: This fades users too now, as well as messages, so should have
    // a better name.
    if (_want_normal_display()) {
        if (!normal_display) {
            _display_messages_normally();
            _display_users_normally();
        }
    } else {
        _fade_messages();
        _fade_users();
    }
}

// This one only updates the users, not both, like update_faded_messages.
// This is for when new presence information comes in, redrawing the presence
// list.
exports.update_faded_users = function () {
    if (_want_normal_display()) {
        _display_users_normally();
    } else {
        _fade_users();
    }
};

// See trac #1633.  For fast typists, calls to _update_faded_messages can
// cause typing sluggishness.
exports.update_faded_messages = _.debounce(_update_faded_messages, 50);

exports.start_compose = function (msg_type) {
    exports.set_focused_recipient(msg_type);
    _update_faded_messages();
};

exports.clear_compose = function () {
    focused_recipient = undefined;
    _display_messages_normally();
    _display_users_normally();
};

exports.update_message_list = function () {
    if (_want_normal_display()) {
       _display_messages_normally();
    } else {
        _fade_messages();
    }
};

exports.update_rendered_message_groups = function (message_groups, get_element) {
    if (_want_normal_display()) {
        return;
    }

    // This loop is superficially similar to some code in _fade_messages, but an
    // important difference here is that we look at each message individually, whereas
    // the other code takes advantage of blocks beneath recipient bars.
    _.each(message_groups, function (message_group) {
        var elt = get_element(message_group);
        var first_message = message_group.message_containers[0].msg;
        var should_fade = exports.should_fade_message(first_message);
        change_fade_state(elt, should_fade);
    });
};

$(function () {
    $(document).on('peer_subscribe.zulip', function () {
        exports.update_faded_users();
    });
    $(document).on('peer_unsubscribe.zulip', function () {
        exports.update_faded_users();
    });
});

return exports;

}());

if (typeof module !== 'undefined') {
    module.exports = compose_fade;
}
<|endoftext|>


<commit_before>var formMethods = function(options) {
    options = options || {update: false};

    [].forEach.call(document.querySelectorAll('form'),
    function(form) {
        // Create request
        var request = new XMLHttpRequest();

        // On form submission...
        var onsubmit = form.onsubmit;
        form.onsubmit = function(event) {
            // Stop the form from submitting
            event.preventDefault();
            // Do the onsubmit events
            if (onsubmit)
                onsubmit();
            // Perform request
            request.open(form.attributes.method.value, form.action);
            request.send(new FormData(form));
        };

        // When the request is done...
        var loadPage = function() {
            if (options.update) {
                // Update page
                document.body.innerHTML = this.response;

                // Fake history
                window.history.pushState(null, form.attributes.method.value, form.action);
                window.onpopstate = function() {
                    window.location.reload();
                };
            }
        };

        request.addEventListener("load", loadPage, false);
        request.addEventListener("error", loadPage, false);
    });
};

formMethods({update: true});
<commit_msg>Fixed form-methods.js browser history behaviour<commit_after>var formMethods = function(options) {
    options = options || {update: false};

    [].forEach.call(document.querySelectorAll('form'),
    function(form) {
        // Create request
        var request = new XMLHttpRequest();

        // Update the [page with completed request...
        var updatePage = function(options) {
            // Update page
            document.body.innerHTML = this.response;

            // Fake history
            if (options.history)
                window.history.pushState({
                    method: form.attributes.method.value,
                    action: form.action
                }, form.attributes.method.value, form.action);
        };

        // On form submission...
        var onsubmit = form.onsubmit;
        var doRequest = function(event) {
            // Stop the form from submitting
            if (event)
                event.preventDefault();
            // Do the onsubmit events
            if (onsubmit)
                onsubmit();
            // Update the page on request completion
            if (options.update) {
                var update = function() {
                    // Only replace history if part of onsubmit event
                    if (event)
                        updatePage.call(this, {history: true});
                    // Otherwise just update the page and don't modify the history
                    else
                        updatePage.call(this, {history: false});
                };
                request.addEventListener("load", update, false);
                request.addEventListener("error", update, false);
            }
            // Perform request
            request.open(form.attributes.method.value, form.action);
            request.send(new FormData(form));
        };

        form.onsubmit = doRequest;

        // Deal with fake history
        window.onpopstate = function(event) {
            // If history is a request then replicate the request
            if (event.state && event.state.method)
                doRequest();
            // Otherwise just reload the page
            else
                window.location.reload();
        };
    });
};

formMethods({update: true});
<|endoftext|>


<commit_before>macgifer = macgifer || {};
macgifer.extensions = macgifer.extensions || {};
macgifer.extensions.active = macgifer.extensions.active || [];

/**
 * App
 */
macgifer.App = function () {
  this.events_ = {};
  this.events_[macgifer.App.EVT_FRAME] = [];

  this.extensions_ = {};
  this.gifId_ = null;
  this.started_ = false;
  this.interval_ = null;
  this.canvas_ = this.createCanvas_();
  this.video_ = this.createVideo_();
  var loadExtension = this.loadExtension_.bind(this);
  var extensions = macgifer.extensions.active.slice();
  macgifer.extensions.active = {'push': loadExtension};
  extensions.forEach(loadExtension);

  document.getElementById('extension-add').addEventListener(
          'click', this.addExtension_.bind(this));

  document.getElementById('rec-button').addEventListener('click',
    this.startRecording_.bind(this));

  var gifLink = document.getElementById('gif-link');
  gifLink.addEventListener('click', gifLink.select.bind(gifLink));

  this.worker_ = new Worker('/js/macgifer/worker.js');
  this.worker_.addEventListener('message', this.onWorkerMessage_.bind(this));

  this.connection_ = new macgifer.Connection(this.getHost_());
  this.connection_.on(common.events.EVT_NEW_ID, this.setGifId.bind(this));
  this.connection_.connect();
};

// Event on frame added
macgifer.App.EVT_FRAME = 'frame';

/**
 * Add extension.
 */
macgifer.App.prototype.addExtension_ = function() {
  var src = prompt('Path to javascript file:');
  if (src) {
    var script = document.createElement('script');
    script.src = src;
    document.body.appendChild(script);
  }
};

/**
 * Enable extension.
 */
macgifer.App.prototype.enableExtension_ = function(event) {
    var id = event.target['data-id'];
    this.extensions_[id].enable = event.target.checked;
};

/**
 * Load extension.
 */
macgifer.App.prototype.loadExtension_ = function(extension) {
  var instance = new extension(this);
  if (this.extensions_[instance.getId()]) {
      return;
  }
  this.extensions_[instance.getId()] = {extension: instance, enable: false};
};

/**
 * Remove extension.
 */
macgifer.App.prototype.removeExtension_ = function(id) {
  var that = this;
  for(var name in this.events_) {
    this.events_[name].filter(function(definition){
      return definition.id != id;
    });
  }
  var panel = document.getElementById('extension-' + id);
  if (panel) {
    panel.remove();
  }
  delete this.extensions_[id];
};

/**
 * Add event listener.
 */
macgifer.App.prototype.on = function(id, name, callback) {
  this.events_[name].push({id: id, callback: callback});
};

/**
 * Get panel of extensions.
 */
macgifer.App.prototype.createExtensionPanel = function(extension) {
  var id = extension.getId();
  var boxId = 'extension-' + id;
  var panelId = 'extension-' + id + '-panel';
  var enableId = 'extension-' + id + '-enable';
  var panel = document.getElementById(panelId);
  if (panel) {
    return panel;
  }

  var box = document.createElement('div');
  box['id'] = boxId;
  box['data-id'] = id;
  box.className = 'extension';

  var toolbar = document.createElement('div');
  toolbar.className = 'toolbar';
  var checkbox = document.createElement('input');
  checkbox['id'] = enableId;
  checkbox['type'] = 'checkbox';
  checkbox['data-id'] = id;
  checkbox.addEventListener('click', this.enableExtension_.bind(this));
  toolbar.appendChild(checkbox);
  var label = document.createElement('label');
  label.setAttribute('for', enableId);
  label.innerHTML = 'Enable';
  toolbar.appendChild(label);
  var header = document.createElement('div');
  header.className = 'header';
  header.appendChild(toolbar);
  var title = document.createElement('h4');
  title.innerHTML = extension.getTitle();
  header.appendChild(title);
  box.appendChild(header);

  var panel = document.createElement('div.panel');
  panel['id'] = panelId;
  box.appendChild(panel);

  document.getElementById('extensions').insertBefore(box,
    document.getElementById('extensions').firstChild);

  return panel;
};

/**
 * Handle message from worker.
 */
macgifer.App.prototype.onWorkerMessage_ = function(e) {
  var frame = e.data;
  date = new Date().getTime();
  this.connection_.send(common.events.EVT_FRAME, frame);
};

/**
 * Get host name and port.
 */
macgifer.App.prototype.getHost_ = function() {
  var host = window.location.hostname;
  if (window.location.port) {
    host += ':' + window.location.port;
  }
  return host;
};

/**
 * Create video.
 */
macgifer.App.prototype.createVideo_ = function() {
  var video = document.createElement('video');
  video.width = common.WIDTH;
  video.height = common.HEIGHT;
  video.autoplay = true;
  return video;
};
/**
 * Create canvas.
 */
macgifer.App.prototype.createCanvas_ = function() {
  var canvas = document.getElementById('canvas');
  canvas.width = common.WIDTH;
  canvas.height = common.HEIGHT;
  return canvas;
};

/**
 * Start gif transmission
 */
macgifer.App.prototype.startRecording_ = function() {
  this.initializeCamera(function(){
    var elements = document.querySelectorAll('.camera canvas, .camera .url');
    for (var i = 0; i < elements.length; i++) {
      elements[i].style.display = 'block';
    }
    document.getElementById('rec-button').style.display = 'none';
  });
};

/**
 * Initialize video source.
 */
macgifer.App.prototype.initializeCamera = function(callback) {
  var that = this;

  getUserMedia({video: true}, function(stream){
    that.video_.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
    if (!this.started_) {
      that.start();
      setInterval(that.updateCanvas_.bind(that), 200);
    }
    callback();
  }, function(err) {
    console.log(err);
  });
};

/**
 * Start capture.
 */
macgifer.App.prototype.start = function() {
  this.started_ = true;
  if (!this.interval_) {
    this.interval_ = setInterval(this.onFrame_.bind(this),
                                 1000 / common.FRAMERATE);
  }
};

/**
 * Stop capture.
 */
macgifer.App.prototype.stop = function() {
  this.started_ = false;
  clearInterval(this.interval_);
  this.interval_ = null;
};

/**
 * Update the canvas context with video and apply extensions
 */
macgifer.App.prototype.updateCanvas_ = function() {
  var extensions = this.extensions_;
  var canvas = this.canvas_;
  var context = canvas.getContext('2d');
  context.translate(canvas.width, 0);
  context.scale(-1, 1);
  context.drawImage(this.video_, 0, 0, this.video_.width, this.video_.height);
  context.translate(canvas.width, 0);
  context.scale(-1, 1);
  this.events_[macgifer.App.EVT_FRAME].forEach(function(definition){
    if (extensions[definition.id].enable) {
      try {
        definition.callback({canvas: canvas});
      } catch(e) {
        console.log(e);
      }
    }
  });
};

/**
 * Handle frame.
 */
macgifer.App.prototype.onFrame_ = function() {
  if (this.started_) {
    var context = this.canvas_.getContext('2d');
    var imageData = context.getImageData(0, 0, common.WIDTH, common.HEIGHT);
    this.worker_.postMessage({
      imageData: imageData.data,
    });
  }
};

/**
 * Get ID.
 */
macgifer.App.prototype.getGifId = function() {
  return this.gifId_;
};

/**
 * Set ID.
 */
macgifer.App.prototype.setGifId = function(id) {
  var url = window.location.origin + '/' + id + '.gif';

  // Watch link
  var link = document.getElementById('gif-link');
  link.value = url;

  // Twitter sharer
  var sharer = document.getElementById('twitter-link');
  sharerUrl = 'http://twitter.com/home?status=' +
              'Watch+me+live+on+this+%23MacGifer+GIF+' + encodeURIComponent(url);
  sharer.value = 'Share';
  sharer.onclick = function() {
    window.open(sharerUrl, 'name','height=300,width=400');
  };

  this.gifId_ = id;
};

macgifer.app = macgifer.app || new macgifer.App();
<commit_msg>Better framerate<commit_after>macgifer = macgifer || {};
macgifer.extensions = macgifer.extensions || {};
macgifer.extensions.active = macgifer.extensions.active || [];

/**
 * App
 */
macgifer.App = function () {
  this.events_ = {};
  this.events_[macgifer.App.EVT_FRAME] = [];

  this.extensions_ = {};
  this.gifId_ = null;
  this.started_ = false;
  this.interval_ = null;
  this.canvas_ = this.createCanvas_();
  this.video_ = this.createVideo_();
  var loadExtension = this.loadExtension_.bind(this);
  var extensions = macgifer.extensions.active.slice();
  macgifer.extensions.active = {'push': loadExtension};
  extensions.forEach(loadExtension);

  document.getElementById('extension-add').addEventListener(
          'click', this.addExtension_.bind(this));

  document.getElementById('rec-button').addEventListener('click',
    this.startRecording_.bind(this));

  var gifLink = document.getElementById('gif-link');
  gifLink.addEventListener('click', gifLink.select.bind(gifLink));

  this.worker_ = new Worker('/js/macgifer/worker.js');
  this.worker_.addEventListener('message', this.onWorkerMessage_.bind(this));

  this.connection_ = new macgifer.Connection(this.getHost_());
  this.connection_.on(common.events.EVT_NEW_ID, this.setGifId.bind(this));
  this.connection_.connect();
};

// Event on frame added
macgifer.App.EVT_FRAME = 'frame';

/**
 * Add extension.
 */
macgifer.App.prototype.addExtension_ = function() {
  var src = prompt('Path to javascript file:');
  if (src) {
    var script = document.createElement('script');
    script.src = src;
    document.body.appendChild(script);
  }
};

/**
 * Enable extension.
 */
macgifer.App.prototype.enableExtension_ = function(event) {
    var id = event.target['data-id'];
    this.extensions_[id].enable = event.target.checked;
};

/**
 * Load extension.
 */
macgifer.App.prototype.loadExtension_ = function(extension) {
  var instance = new extension(this);
  if (this.extensions_[instance.getId()]) {
      return;
  }
  this.extensions_[instance.getId()] = {extension: instance, enable: false};
};

/**
 * Remove extension.
 */
macgifer.App.prototype.removeExtension_ = function(id) {
  var that = this;
  for(var name in this.events_) {
    this.events_[name].filter(function(definition){
      return definition.id != id;
    });
  }
  var panel = document.getElementById('extension-' + id);
  if (panel) {
    panel.remove();
  }
  delete this.extensions_[id];
};

/**
 * Add event listener.
 */
macgifer.App.prototype.on = function(id, name, callback) {
  this.events_[name].push({id: id, callback: callback});
};

/**
 * Get panel of extensions.
 */
macgifer.App.prototype.createExtensionPanel = function(extension) {
  var id = extension.getId();
  var boxId = 'extension-' + id;
  var panelId = 'extension-' + id + '-panel';
  var enableId = 'extension-' + id + '-enable';
  var panel = document.getElementById(panelId);
  if (panel) {
    return panel;
  }

  var box = document.createElement('div');
  box['id'] = boxId;
  box['data-id'] = id;
  box.className = 'extension';

  var toolbar = document.createElement('div');
  toolbar.className = 'toolbar';
  var checkbox = document.createElement('input');
  checkbox['id'] = enableId;
  checkbox['type'] = 'checkbox';
  checkbox['data-id'] = id;
  checkbox.addEventListener('click', this.enableExtension_.bind(this));
  toolbar.appendChild(checkbox);
  var label = document.createElement('label');
  label.setAttribute('for', enableId);
  label.innerHTML = 'Enable';
  toolbar.appendChild(label);
  var header = document.createElement('div');
  header.className = 'header';
  header.appendChild(toolbar);
  var title = document.createElement('h4');
  title.innerHTML = extension.getTitle();
  header.appendChild(title);
  box.appendChild(header);

  var panel = document.createElement('div.panel');
  panel['id'] = panelId;
  box.appendChild(panel);

  document.getElementById('extensions').insertBefore(box,
    document.getElementById('extensions').firstChild);

  return panel;
};

/**
 * Handle message from worker.
 */
macgifer.App.prototype.onWorkerMessage_ = function(e) {
  var frame = e.data;
  date = new Date().getTime();
  this.connection_.send(common.events.EVT_FRAME, frame);
};

/**
 * Get host name and port.
 */
macgifer.App.prototype.getHost_ = function() {
  var host = window.location.hostname;
  if (window.location.port) {
    host += ':' + window.location.port;
  }
  return host;
};

/**
 * Create video.
 */
macgifer.App.prototype.createVideo_ = function() {
  var video = document.createElement('video');
  video.width = common.WIDTH;
  video.height = common.HEIGHT;
  video.autoplay = true;
  return video;
};
/**
 * Create canvas.
 */
macgifer.App.prototype.createCanvas_ = function() {
  var canvas = document.getElementById('canvas');
  canvas.width = common.WIDTH;
  canvas.height = common.HEIGHT;
  return canvas;
};

/**
 * Start gif transmission
 */
macgifer.App.prototype.startRecording_ = function() {
  this.initializeCamera(function(){
    var elements = document.querySelectorAll('.camera canvas, .camera .url');
    for (var i = 0; i < elements.length; i++) {
      elements[i].style.display = 'block';
    }
    document.getElementById('rec-button').style.display = 'none';
  });
};

/**
 * Initialize video source.
 */
macgifer.App.prototype.initializeCamera = function(callback) {
  var that = this;

  getUserMedia({video: true}, function(stream){
    that.video_.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
    if (!this.started_) {
      that.start();
      setInterval(that.updateCanvas_.bind(that), 50);
    }
    callback();
  }, function(err) {
    console.log(err);
  });
};

/**
 * Start capture.
 */
macgifer.App.prototype.start = function() {
  this.started_ = true;
  if (!this.interval_) {
    this.interval_ = setInterval(this.onFrame_.bind(this),
                                 1000 / common.FRAMERATE);
  }
};

/**
 * Stop capture.
 */
macgifer.App.prototype.stop = function() {
  this.started_ = false;
  clearInterval(this.interval_);
  this.interval_ = null;
};

/**
 * Update the canvas context with video and apply extensions
 */
macgifer.App.prototype.updateCanvas_ = function() {
  var extensions = this.extensions_;
  var canvas = this.canvas_;
  var context = canvas.getContext('2d');
  context.translate(canvas.width, 0);
  context.scale(-1, 1);
  context.drawImage(this.video_, 0, 0, this.video_.width, this.video_.height);
  context.translate(canvas.width, 0);
  context.scale(-1, 1);
  this.events_[macgifer.App.EVT_FRAME].forEach(function(definition){
    if (extensions[definition.id].enable) {
      try {
        definition.callback({canvas: canvas});
      } catch(e) {
        console.log(e);
      }
    }
  });
};

/**
 * Handle frame.
 */
macgifer.App.prototype.onFrame_ = function() {
  if (this.started_) {
    var context = this.canvas_.getContext('2d');
    var imageData = context.getImageData(0, 0, common.WIDTH, common.HEIGHT);
    this.worker_.postMessage({
      imageData: imageData.data,
    });
  }
};

/**
 * Get ID.
 */
macgifer.App.prototype.getGifId = function() {
  return this.gifId_;
};

/**
 * Set ID.
 */
macgifer.App.prototype.setGifId = function(id) {
  var url = window.location.origin + '/' + id + '.gif';

  // Watch link
  var link = document.getElementById('gif-link');
  link.value = url;

  // Twitter sharer
  var sharer = document.getElementById('twitter-link');
  sharerUrl = 'http://twitter.com/home?status=' +
              'Watch+me+live+on+this+%23MacGifer+GIF+' + encodeURIComponent(url);
  sharer.value = 'Share';
  sharer.onclick = function() {
    window.open(sharerUrl, 'name','height=300,width=400');
  };

  this.gifId_ = id;
};

macgifer.app = macgifer.app || new macgifer.App();
<|endoftext|>


<commit_before>/* eslint indent: "off" */
import PerfectScrollbar from 'perfect-scrollbar';

function registerCodeSection($codeSection) {
    const $li = $codeSection.find("ul.nav li");
    const $blocks = $codeSection.find(".blocks div");

    $li.click(function () {
        const language = this.dataset.language;

        $li.removeClass("active");
        $li.filter("[data-language=" + language + "]").addClass("active");

        $blocks.removeClass("active");
        $blocks.filter("[data-language=" + language + "]").addClass("active");
    });

    $li.eq(0).click();
}

function highlight_current_article() {
    $('.help .sidebar a').removeClass('highlighted');
    var path = window.location.href.match(/\/(help|api)\/.*/);

    if (!path) {
        return;
    }

    var article = $('.help .sidebar a[href="' + path[0] + '"]');
    article.addClass('highlighted');
}

function adjust_mac_shortcuts() {
    var keys_map = new Map([
        ['Backspace', 'Delete'],
        ['Enter', 'Return'],
        ['Home', 'Fn + ⇽'],
        ['End', 'Fn + ⇾'],
        ['PgUp', 'Fn + ↑'],
        ['PgDn', 'Fn + ↓'],
    ]);

    $(".markdown .content code").each(function () {
        var text = $(this).text();

        if (!keys_map.has(text)) {
            return;
        }

        var key_string = keys_map.get(text);
        var keys = key_string.match(/[^\s\+]+/g);

        _.each(keys, function (key) {
            key_string = key_string.replace(key, '' + key + '');
        });

        $(this).replaceWith(key_string);
    });
}

function render_code_sections() {
    $(".code-section").each(function () {
        registerCodeSection($(this));
    });

    highlight_current_article();

    if (/Mac/i.test(navigator.userAgent)) {
        adjust_mac_shortcuts();
    }

    $("table").each(function () {
        $(this).addClass("table table-striped");
    });
}

function scrollToHash(container) {
    var hash = window.location.hash;
    if (hash !== '') {
        container.scrollTop = $(hash).position().top - $('.markdown .content').position().top;
    } else {
        container.scrollTop = 0;
    }
}

(function () {
    var html_map = {};
    var loading = {
        name: null,
    };

    var markdownPS = new PerfectScrollbar($(".markdown")[0], {
        suppressScrollX: true,
        useKeyboard: false,
        wheelSpeed: 0.68,
        scrollingThreshold: 50,
    });

    var fetch_page = function (path, callback) {
        $.get(path, function (res) {
            var $html = $(res).find(".markdown .content");
            $html.find(".back-to-home").remove();

            callback($html.html().trim());
            render_code_sections();
        });
    };

    new PerfectScrollbar($(".sidebar")[0], {
        suppressScrollX: true,
        useKeyboard: false,
        wheelSpeed: 0.68,
        scrollingThreshold: 50,
    });

    $(".sidebar.slide h2").click(function (e) {
        var $next = $(e.target).next();

        if ($next.is("ul")) {
            $next.slideToggle("fast", "swing", function () {
                markdownPS.update();
            });
        }
    });

    $(".sidebar a").click(function (e) {
        var path = $(this).attr("href");
        var path_dir = path.split('/')[1];
        var current_dir = window.location.pathname.split('/')[1];
        var container = $(".markdown")[0];

        // Do not block redirecting to external URLs
        if (path_dir !== current_dir) {
            return;
        }

        if (loading.name === path) {
            return;
        }

        history.pushState({}, "", path);

        if (html_map[path]) {
            $(".markdown .content").html(html_map[path]);
            render_code_sections();
            markdownPS.update();
            scrollToHash(container);
        } else {
            loading.name = path;

            fetch_page(path, function (res) {
                html_map[path] = res;
                $(".markdown .content").html(html_map[path]);
                loading.name = null;
                markdownPS.update();
                scrollToHash(container);
            });
        }

        $(".sidebar").removeClass("show");

        e.preventDefault();
    });

    // Show Guides user docs in sidebar by default
    $('.help .sidebar h2#guides + ul').css('display', 'block');

    // Remove ID attributes from sidebar links so they don't conflict with index page anchor links
    $('.help .sidebar h1, .help .sidebar h2, .help .sidebar h3').removeAttr('id');

    // Scroll to anchor link when clicked
    $('.markdown .content h1, .markdown .content h2, .markdown .content h3').on('click', function () {
        window.location.href = window.location.href.replace(/#.*/, '') + '#' + $(this).attr("id");
    });

    $(".hamburger").click(function () {
        $(".sidebar").toggleClass("show");
    });

    $(".markdown").click(function () {
        if ($(".sidebar.show").length) {
            $(".sidebar.show").toggleClass("show");
        }
    });

    render_code_sections();

    // Finally, make sure if we loaded a window with a hash, we scroll
    // to the right place.
    var container = $(".markdown")[0];
    scrollToHash(container);

    window.onresize = function () {
        markdownPS.update();
    };

    window.addEventListener("popstate", function () {
        var path = window.location.pathname;
        $(".markdown .content").html(html_map[path]);
    });

}());
<commit_msg>help: Extract code for updating the page.<commit_after>/* eslint indent: "off" */
import PerfectScrollbar from 'perfect-scrollbar';

function registerCodeSection($codeSection) {
    const $li = $codeSection.find("ul.nav li");
    const $blocks = $codeSection.find(".blocks div");

    $li.click(function () {
        const language = this.dataset.language;

        $li.removeClass("active");
        $li.filter("[data-language=" + language + "]").addClass("active");

        $blocks.removeClass("active");
        $blocks.filter("[data-language=" + language + "]").addClass("active");
    });

    $li.eq(0).click();
}

function highlight_current_article() {
    $('.help .sidebar a').removeClass('highlighted');
    var path = window.location.href.match(/\/(help|api)\/.*/);

    if (!path) {
        return;
    }

    var article = $('.help .sidebar a[href="' + path[0] + '"]');
    article.addClass('highlighted');
}

function adjust_mac_shortcuts() {
    var keys_map = new Map([
        ['Backspace', 'Delete'],
        ['Enter', 'Return'],
        ['Home', 'Fn + ⇽'],
        ['End', 'Fn + ⇾'],
        ['PgUp', 'Fn + ↑'],
        ['PgDn', 'Fn + ↓'],
    ]);

    $(".markdown .content code").each(function () {
        var text = $(this).text();

        if (!keys_map.has(text)) {
            return;
        }

        var key_string = keys_map.get(text);
        var keys = key_string.match(/[^\s\+]+/g);

        _.each(keys, function (key) {
            key_string = key_string.replace(key, '' + key + '');
        });

        $(this).replaceWith(key_string);
    });
}

function render_code_sections() {
    $(".code-section").each(function () {
        registerCodeSection($(this));
    });

    highlight_current_article();

    if (/Mac/i.test(navigator.userAgent)) {
        adjust_mac_shortcuts();
    }

    $("table").each(function () {
        $(this).addClass("table table-striped");
    });
}

function scrollToHash(container) {
    var hash = window.location.hash;
    if (hash !== '') {
        container.scrollTop = $(hash).position().top - $('.markdown .content').position().top;
    } else {
        container.scrollTop = 0;
    }
}

(function () {
    var html_map = {};
    var loading = {
        name: null,
    };

    var markdownPS = new PerfectScrollbar($(".markdown")[0], {
        suppressScrollX: true,
        useKeyboard: false,
        wheelSpeed: 0.68,
        scrollingThreshold: 50,
    });

    var fetch_page = function (path, callback) {
        $.get(path, function (res) {
            var $html = $(res).find(".markdown .content");
            $html.find(".back-to-home").remove();

            callback($html.html().trim());
            render_code_sections();
        });
    };

    var update_page = function (html_map, path, container) {
        if (html_map[path]) {
            $(".markdown .content").html(html_map[path]);
            render_code_sections();
            markdownPS.update();
            scrollToHash(container);
        } else {
            loading.name = path;
            fetch_page(path, function (res) {
                html_map[path] = res;
                $(".markdown .content").html(html_map[path]);
                loading.name = null;
                markdownPS.update();
                scrollToHash(container);
            });
        }
    };

    new PerfectScrollbar($(".sidebar")[0], {
        suppressScrollX: true,
        useKeyboard: false,
        wheelSpeed: 0.68,
        scrollingThreshold: 50,
    });

    $(".sidebar.slide h2").click(function (e) {
        var $next = $(e.target).next();

        if ($next.is("ul")) {
            $next.slideToggle("fast", "swing", function () {
                markdownPS.update();
            });
        }
    });

    $(".sidebar a").click(function (e) {
        var path = $(this).attr("href");
        var path_dir = path.split('/')[1];
        var current_dir = window.location.pathname.split('/')[1];
        var container = $(".markdown")[0];

        // Do not block redirecting to external URLs
        if (path_dir !== current_dir) {
            return;
        }

        if (loading.name === path) {
            return;
        }

        history.pushState({}, "", path);

        update_page(html_map, path, container);

        $(".sidebar").removeClass("show");

        e.preventDefault();
    });

    // Show Guides user docs in sidebar by default
    $('.help .sidebar h2#guides + ul').css('display', 'block');

    // Remove ID attributes from sidebar links so they don't conflict with index page anchor links
    $('.help .sidebar h1, .help .sidebar h2, .help .sidebar h3').removeAttr('id');

    // Scroll to anchor link when clicked
    $('.markdown .content h1, .markdown .content h2, .markdown .content h3').on('click', function () {
        window.location.href = window.location.href.replace(/#.*/, '') + '#' + $(this).attr("id");
    });

    $(".hamburger").click(function () {
        $(".sidebar").toggleClass("show");
    });

    $(".markdown").click(function () {
        if ($(".sidebar.show").length) {
            $(".sidebar.show").toggleClass("show");
        }
    });

    render_code_sections();

    // Finally, make sure if we loaded a window with a hash, we scroll
    // to the right place.
    var container = $(".markdown")[0];
    scrollToHash(container);

    window.onresize = function () {
        markdownPS.update();
    };

    window.addEventListener("popstate", function () {
        var path = window.location.pathname;
        $(".markdown .content").html(html_map[path]);
    });

}());
<|endoftext|>


<commit_before>$.fn.center = function() {
	this.css("top", Math.max(0, ((($(window).height()) - $(this).outerHeight())/2) - 200) + "px");
	this.css("left", Math.max(0, (($(window).width() - $(this).outerWidth())/2)) + "px");
	return this;
}

$(function() {

	// Load the Scalar API and cache it.
	$.ajax({
		url: "/static/js/scalarapi.js",
		dataType: "script",
		cache: true
	});

	// Initialise tooltips
	/* Note: The standard Lexos tooltip will have the following html:

	   @style may be used to adjust the size and placement of the trigger icon.
	   The default is margin-right:10px;font-size:14px;.
	*/

	$('[data-toggle="tooltip"]').tooltip();

	// Initialise popovers -- mouseleave handling from http://www.bootply.com/98529

	/* Note: The standard Lexos popover will have the following html:

	   @style may be used to give to adjust the size and placement of the trigger icon.
	   @title may be used to give the popover a header.
	*/

  	$("[data-toggle=popover]").popover({
	  	trigger: 'manual',
	  	animate: false,
	  	html: true,
	  	placement: 'right',
	  	template:
	  	  '
\

\

\

\

\

\

'
	}).click(function(e) {
		e.preventDefault();
	}).mouseenter(function(e) {
		$(this).popover('show');
	});

	// Handle exceptions for submitting forms and display error messages on screen
	$("form").submit(function() {
		if ($('#num_active_files').val() == "0") {
			$('#error-message').text("You must have active documents to proceed!");
			$('#error-message').show().fadeOut(3000); // Use easeInOutCubic effect can cause program crash on analyzer pages

			$("#status-prepare").hide();
			$("#status-analyze").hide();
			return false;
		} else
			return true;
	});

	// Add "selected" class to parent of selected link
	$(".sublist li .selected").parents('.headernavitem').addClass("selected");

	// display/hide expandable divs here
	$(".has-expansion .icon-arrow-right").click(function() {
		$(this).toggleClass("showing");

		$(this).parent('legend').siblings('.expansion').slideToggle(500);
	});

	// Gray out all disabled inputs
	$.each($('input'), function() {
		if ($(this).prop('disabled')) {
			$(this).parent('label').addClass('disabled');
		}
	});

	// Redirect all clicks on "Upload Buttons" to their file upload input
	$('.upload-bttn').click(function() {
		$(this).siblings('input[type=file]').click();
	});

	// Show the nested submenu of clustering when mouse hover over the corresponding navbar, otherwise hide the nested menu
	$("#clustering-menu, #clustering-submenu").mouseover(function(){
		$("#clustering-submenu").css({"opacity": 1, "visibility": "visible"});
	}).mouseleave(function(){
		$("#clustering-submenu").css({"opacity": 0, "visibility": "hidden"});
	});

	// Highlight the nested label of the navBar when nested pages are active
	if ($(".nestedElement").hasClass("selected")){
		$(".nestedLabel").addClass("selected");
	}

});

function getFormValues() {
	/* Gathers all the form values and returns them as a FormData object. In Flask,
	access form values through request.form and files through request.files. Returns
	a JSON object. */

	var formData = new FormData($('form')[0]);

	$.ajax({
	  url: '/previewScrubbing',
	  type: 'POST',
	  processData: false, // important
	  contentType: false, // important
	  data: formData,
	  "error": function () {alert("error");}
	}).done(function(response) {
		response = JSON.parse(response);
		return response;
	});
}<commit_msg>Replaced error message with error modal<commit_after>$.fn.center = function() {
	this.css("top", Math.max(0, ((($(window).height()) - $(this).outerHeight())/2) - 200) + "px");
	this.css("left", Math.max(0, (($(window).width() - $(this).outerWidth())/2)) + "px");
	return this;
}

$(function() {

	// Load the Scalar API and cache it.
	$.ajax({
		url: "/static/js/scalarapi.js",
		dataType: "script",
		cache: true
	});

	// Initialise tooltips
	/* Note: The standard Lexos tooltip will have the following html:

	   @style may be used to adjust the size and placement of the trigger icon.
	   The default is margin-right:10px;font-size:14px;.
	*/

	$('[data-toggle="tooltip"]').tooltip();

	// Initialise popovers -- mouseleave handling from http://www.bootply.com/98529

	/* Note: The standard Lexos popover will have the following html:

	   @style may be used to give to adjust the size and placement of the trigger icon.
	   @title may be used to give the popover a header.
	*/

  	$("[data-toggle=popover]").popover({
	  	trigger: 'manual',
	  	animate: false,
	  	html: true,
	  	placement: 'right',
	  	template:
	  	  '
\

\

\

\

\

\

'
	}).click(function(e) {
		e.preventDefault();
	}).mouseenter(function(e) {
		$(this).popover('show');
	});

	// Handle exceptions for submitting forms and display error messages on screen
	$("form").submit(function() {
		if ($('#num_active_files').val() == "0") {
			msg = 'You have no active documents. Please activate at least one document using the Manage tool or upload</> a new document.';
			$('#error-modal-message').html(msg);
			$('#error-modal').modal();
			return false;
		} else
			return true;
		}
	});

	// Add "selected" class to parent of selected link
	$(".sublist li .selected").parents('.headernavitem').addClass("selected");

	// display/hide expandable divs here
	$(".has-expansion .icon-arrow-right").click(function() {
		$(this).toggleClass("showing");

		$(this).parent('legend').siblings('.expansion').slideToggle(500);
	});

	// Gray out all disabled inputs
	$.each($('input'), function() {
		if ($(this).prop('disabled')) {
			$(this).parent('label').addClass('disabled');
		}
	});

	// Redirect all clicks on "Upload Buttons" to their file upload input
	$('.upload-bttn').click(function() {
		$(this).siblings('input[type=file]').click();
	});

	// Show the nested submenu of clustering when mouse hover over the corresponding navbar, otherwise hide the nested menu
	$("#clustering-menu, #clustering-submenu").mouseover(function(){
		$("#clustering-submenu").css({"opacity": 1, "visibility": "visible"});
	}).mouseleave(function(){
		$("#clustering-submenu").css({"opacity": 0, "visibility": "hidden"});
	});

	// Highlight the nested label of the navBar when nested pages are active
	if ($(".nestedElement").hasClass("selected")){
		$(".nestedLabel").addClass("selected");
	}

});

function getFormValues() {
	/* Gathers all the form values and returns them as a FormData object. In Flask,
	access form values through request.form and files through request.files. Returns
	a JSON object. */

	var formData = new FormData($('form')[0]);

	$.ajax({
	  url: '/previewScrubbing',
	  type: 'POST',
	  processData: false, // important
	  contentType: false, // important
	  data: formData,
	  "error": function () {alert("error");}
	}).done(function(response) {
		response = JSON.parse(response);
		return response;
	});
}<|endoftext|>


<commit_before>'use strict';

let underscore = require('underscore');
let logger = require('../../logging').getLogger(__filename);
let communication = require('./neo4jCommunication');

let Cypher = function (driver) {
    let chainedQuery = '', paramsToSend = {}, isWriteCommand = false;

    this.chainingQuery = function (condition, command, isWrite) {
        if (isWrite) {
            isWriteCommand = true;
        }
        chainedQuery = chainedQuery + command + condition;
        return this;
    };

    this.optionalMatch = function (condition) {
        return this.chainingQuery(condition, ' OPTIONAL MATCH ');
    };

    this.match = function (condition) {
        return this.chainingQuery(condition, ' MATCH ');
    };

    this.where = function (condition) {
        if (condition && condition.trim() !== '') {
            return this.chainingQuery(condition, ' WHERE ');
        }
        return this;
    };

    this.with = function (condition) {
        return this.chainingQuery(condition, ' WITH ');
    };

    this.create = function (condition) {
        return this.chainingQuery(condition, ' CREATE ', true);
    };

    this.createUnique = function (condition) {
        return this.chainingQuery(condition, ' CREATE UNIQUE ', true);
    };

    this.foreach = function (condition, isWrite = true) {
        return this.chainingQuery(condition, ' FOREACH ', isWrite);
    };

    this.merge = function (condition) {
        return this.chainingQuery(condition, ' MERGE ', true);
    };

    this.onCreate = function (condition) {
        return this.chainingQuery(condition, ' ON CREATE ');
    };

    this.onMatch = function (condition) {
        return this.chainingQuery(condition, ' ON MATCH ');
    };

    this.case = function (condition) {
        return this.chainingQuery(condition, ' CASE ');
    };

    this.when = function (condition) {
        return this.chainingQuery(condition, ' WHEN ');
    };

    this.then = function (condition) {
        return this.chainingQuery(condition, ' THEN ');
    };

    this.delete = function (condition) {
        return this.chainingQuery(condition, ' DELETE ', true);
    };

    this.remove = function (condition) {
        return this.chainingQuery(condition, ' REMOVE ', true);
    };

    this.orderBy = function (condition) {
        return this.chainingQuery(condition, ' ORDER BY ');
    };

    this.skip = function (condition) {
        return this.chainingQuery(condition, ' SKIP ');
    };

    this.limit = function (condition) {
        return this.chainingQuery(condition, ' LIMIT ');
    };

    this.unwind = function (condition) {
        return this.chainingQuery(condition, ' UNWIND ');
    };

    this.union = function () {
        chainedQuery = chainedQuery + ' UNION ';
        return this;
    };

    this.unionAll = function () {
        chainedQuery = chainedQuery + ' UNION ALL ';
        return this;
    };

    this.set = function (ref, objectToSet) {

        let setCondition = '', key, propertyAdded = false;
        for (key in objectToSet) {
            if (objectToSet.hasOwnProperty(key)) {
                setCondition = setCondition.concat(ref, '.', key, ' = {', key, '},');
                propertyAdded = true;
                if (objectToSet[key] === undefined) {
                    objectToSet[key] = null;
                }
                paramsToSend[key] = objectToSet[key];
            }
        }
        if (propertyAdded) {
            isWriteCommand = true;
            setCondition = setCondition.slice(0, -1);
            chainedQuery = chainedQuery + ' SET ' + setCondition;
        } else {
            logger.error('Empty object for set condition');
        }
        return this;
    };

    this.replaceArrayElement = function (ref, propertyName, oldElementValue, newElementValue, hasPreviousWhere) {
        let array = ref + '.' + propertyName;
        let oldValueName = propertyName + 'old';
        let newValueName = propertyName + 'new';
        let whereCondition = ' WHERE {' + oldValueName + '} IN ' + array;
        let setCondition = ' SET ' + array + ' = filter(x in ' + array + ' WHERE not(x={' + oldValueName + '})) + {' + newValueName + '}';
        if (hasPreviousWhere) {
            whereCondition = ' AND {' + oldValueName + '} IN ' + array;
        }
        paramsToSend[oldValueName] = oldElementValue;
        paramsToSend[newValueName] = newElementValue;
        chainedQuery = chainedQuery + whereCondition + setCondition;
        isWriteCommand = true;
        return this;
    };

    this.addCommand = function (command) {
        chainedQuery = chainedQuery + command;
        return this;
    };

    this.return = function (returnCondition) {
        chainedQuery = chainedQuery + ' RETURN ' + returnCondition;
        return this;
    };

    this.end = function (params) {
        if (params) {
            paramsToSend = underscore.extend(paramsToSend, params);
        }
        return this;
    };

    this.getCommand = function () {
        return {statement: chainedQuery, parameters: paramsToSend, isWriteCommand: isWriteCommand};
    };

    this.getCommandString = function () {
        return chainedQuery;
    };

    this.send = async function (statementsToSend) {
        if (!statementsToSend || !(statementsToSend instanceof Array)) {
            statementsToSend = [];
        }
        statementsToSend.push(this.getCommand());
        return await communication.send(statementsToSend, driver);
    };
};

module.exports = {
    Cypher: Cypher
};
<commit_msg>Added call for functions.<commit_after>'use strict';

let underscore = require('underscore');
let logger = require('../../logging').getLogger(__filename);
let communication = require('./neo4jCommunication');

let Cypher = function (driver) {
    let chainedQuery = '', paramsToSend = {}, isWriteCommand = false;

    this.chainingQuery = function (condition, command, isWrite) {
        if (isWrite) {
            isWriteCommand = true;
        }
        chainedQuery = chainedQuery + command + condition;
        return this;
    };

    this.optionalMatch = function (condition) {
        return this.chainingQuery(condition, ' OPTIONAL MATCH ');
    };

    this.match = function (condition) {
        return this.chainingQuery(condition, ' MATCH ');
    };

    this.where = function (condition) {
        if (condition && condition.trim() !== '') {
            return this.chainingQuery(condition, ' WHERE ');
        }
        return this;
    };

    this.with = function (condition) {
        return this.chainingQuery(condition, ' WITH ');
    };

    this.create = function (condition) {
        return this.chainingQuery(condition, ' CREATE ', true);
    };

    this.createUnique = function (condition) {
        return this.chainingQuery(condition, ' CREATE UNIQUE ', true);
    };

    this.foreach = function (condition, isWrite = true) {
        return this.chainingQuery(condition, ' FOREACH ', isWrite);
    };

    this.merge = function (condition) {
        return this.chainingQuery(condition, ' MERGE ', true);
    };

    this.onCreate = function (condition) {
        return this.chainingQuery(condition, ' ON CREATE ');
    };

    this.onMatch = function (condition) {
        return this.chainingQuery(condition, ' ON MATCH ');
    };

    this.case = function (condition) {
        return this.chainingQuery(condition, ' CASE ');
    };

    this.when = function (condition) {
        return this.chainingQuery(condition, ' WHEN ');
    };

    this.then = function (condition) {
        return this.chainingQuery(condition, ' THEN ');
    };

    this.delete = function (condition) {
        return this.chainingQuery(condition, ' DELETE ', true);
    };

    this.remove = function (condition) {
        return this.chainingQuery(condition, ' REMOVE ', true);
    };

    this.orderBy = function (condition) {
        return this.chainingQuery(condition, ' ORDER BY ');
    };

    this.skip = function (condition) {
        return this.chainingQuery(condition, ' SKIP ');
    };

    this.limit = function (condition) {
        return this.chainingQuery(condition, ' LIMIT ');
    };

    this.unwind = function (condition) {
        return this.chainingQuery(condition, ' UNWIND ');
    };

    this.call = function (condition) {
        return this.chainingQuery(condition, ' CALL ');
    };

    this.union = function () {
        chainedQuery = chainedQuery + ' UNION ';
        return this;
    };

    this.unionAll = function () {
        chainedQuery = chainedQuery + ' UNION ALL ';
        return this;
    };

    this.set = function (ref, objectToSet) {

        let setCondition = '', key, propertyAdded = false;
        for (key in objectToSet) {
            if (objectToSet.hasOwnProperty(key)) {
                setCondition = setCondition.concat(ref, '.', key, ' = {', key, '},');
                propertyAdded = true;
                if (objectToSet[key] === undefined) {
                    objectToSet[key] = null;
                }
                paramsToSend[key] = objectToSet[key];
            }
        }
        if (propertyAdded) {
            isWriteCommand = true;
            setCondition = setCondition.slice(0, -1);
            chainedQuery = chainedQuery + ' SET ' + setCondition;
        } else {
            logger.error('Empty object for set condition');
        }
        return this;
    };

    this.replaceArrayElement = function (ref, propertyName, oldElementValue, newElementValue, hasPreviousWhere) {
        let array = ref + '.' + propertyName;
        let oldValueName = propertyName + 'old';
        let newValueName = propertyName + 'new';
        let whereCondition = ' WHERE {' + oldValueName + '} IN ' + array;
        let setCondition = ' SET ' + array + ' = filter(x in ' + array + ' WHERE not(x={' + oldValueName + '})) + {' + newValueName + '}';
        if (hasPreviousWhere) {
            whereCondition = ' AND {' + oldValueName + '} IN ' + array;
        }
        paramsToSend[oldValueName] = oldElementValue;
        paramsToSend[newValueName] = newElementValue;
        chainedQuery = chainedQuery + whereCondition + setCondition;
        isWriteCommand = true;
        return this;
    };

    this.addCommand = function (command) {
        chainedQuery = chainedQuery + command;
        return this;
    };

    this.return = function (returnCondition) {
        chainedQuery = chainedQuery + ' RETURN ' + returnCondition;
        return this;
    };

    this.end = function (params) {
        if (params) {
            paramsToSend = underscore.extend(paramsToSend, params);
        }
        return this;
    };

    this.getCommand = function () {
        return {statement: chainedQuery, parameters: paramsToSend, isWriteCommand: isWriteCommand};
    };

    this.getCommandString = function () {
        return chainedQuery;
    };

    this.send = async function (statementsToSend) {
        if (!statementsToSend || !(statementsToSend instanceof Array)) {
            statementsToSend = [];
        }
        statementsToSend.push(this.getCommand());
        return await communication.send(statementsToSend, driver);
    };
};

module.exports = {
    Cypher: Cypher
};
<|endoftext|>


<commit_before>/*  Super Search
    Author: Kushagra Gour (http://kushagragour.in)
    MIT Licensed
*/

(function () {
    var isSearchOpen = false,
        searchEl = document.querySelector('#js-search'),
        searchInputEl = document.querySelector('#js-search__input'),
        searchResultsEl = document.querySelector('#js-search__results'),
        currentInputValue = '',
        lastSearchResultHash,
        posts = [],
        sitemap = 'http://www.abheyrana.me/sitemap.xml';

    // Changes XML to JSON
    // Modified version from here: http://davidwalsh.name/convert-xml-json
    function xmlToJson(xml) {

        // Create the return object
        var obj = {};

        if (xml.nodeType == 1) { // element
            // do attributes
            if (xml.attributes.length > 0) {
            obj["@attributes"] = {};
                for (var j = 0; j < xml.attributes.length; j++) {
                    var attribute = xml.attributes.item(j);
                    obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
                }
            }
        } else if (xml.nodeType == 3) { // text
            obj = xml.nodeValue;
        }

        // do children
        // If all text nodes inside, get concatenated text from them.
        var textNodes = [].slice.call(xml.childNodes).filter(function (node) { return node.nodeType === 3; });
        if (xml.hasChildNodes() && xml.childNodes.length === textNodes.length) {
            obj = [].slice.call(xml.childNodes).reduce(function (text, node) { return text + node.nodeValue; }, '');
        }
        else if (xml.hasChildNodes()) {
            for(var i = 0; i < xml.childNodes.length; i++) {
                var item = xml.childNodes.item(i);
                var nodeName = item.nodeName;
                if (typeof(obj[nodeName]) == "undefined") {
                    obj[nodeName] = xmlToJson(item);
                } else {
                    if (typeof(obj[nodeName].push) == "undefined") {
                        var old = obj[nodeName];
                        obj[nodeName] = [];
                        obj[nodeName].push(old);
                    }
                    obj[nodeName].push(xmlToJson(item));
                }
            }
        }
        return obj;
    }

    function getPostsFromXml(xml) {
        var json = xmlToJson(xml);
        return json.channel.item;
    }

    var xmlhttp=new XMLHttpRequest();
    xmlhttp.open("GET",sitemap);
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState != 4) return;
        if (xmlhttp.status != 200 && xmlhttp.status != 304) { return; }
        var node = (new DOMParser).parseFromString(xmlhttp.responseText, 'text/xml');
        node = node.children[0];
        posts = getPostsFromXml(node);
    }
    xmlhttp.send();

    window.toggleSearch = function toggleSearch() {
        _gaq.push(['_trackEvent', 'supersearch', searchEl.classList.contains('is-active')]);
        searchEl.classList.toggle('is-active');
        if (searchEl.classList.contains('is-active')) {
            // while opening
            searchInputEl.value = '';
        } else {
            // while closing
            searchResultsEl.classList.add('is-hidden');
        }
        setTimeout(function () {
            searchInputEl.focus();
        }, 210);
    }

    window.addEventListener('keyup', function onKeyPress(e) {
        if (e.which === 27) {
            toggleSearch();
        }
    });
    window.addEventListener('keypress', function onKeyPress(e) {
        if (e.which === 47 && !searchEl.classList.contains('is-active')) {
            toggleSearch();
        }
    });

    searchInputEl.addEventListener('input', function onInputChange() {
        var currentResultHash, d;

        currentInputValue = (searchInputEl.value + '').toLowerCase();
        if (!currentInputValue || currentInputValue.length < 3) {
            lastSearchResultHash = '';
            searchResultsEl.classList.add('is-hidden');
            return;
        }
        searchResultsEl.style.offsetWidth;

        var matchingPosts = posts.filter(function (post) {
            if ((post.title + '').toLowerCase().indexOf(currentInputValue) !== -1 || (post.description + '').toLowerCase().indexOf(currentInputValue) !== -1) {
                return true;
            }
        });
        if (!matchingPosts.length) {
            searchResultsEl.classList.add('is-hidden');
        }
        currentResultHash = matchingPosts.reduce(function(hash, post) { return post.title + hash; }, '');
        if (matchingPosts.length && currentResultHash !== lastSearchResultHash) {
            searchResultsEl.classList.remove('is-hidden');
            searchResultsEl.innerHTML = matchingPosts.map(function (post) {
                d = new Date(post.pubDate);
                str = post.link.substr(0,5);
                if(str == 'https')
                    return '
' + post.title + '' + d.toUTCString().replace(/.*(\d{2})\s+(\w{3})\s+(\d{4}).*/,'$2 $1, $3') + '
';
                else
                    return '
' + post.title + '' + d.toUTCString().replace(/.*(\d{2})\s+(\w{3})\s+(\d{4}).*/,'$2 $1, $3') + '
';
            }).join('');
        }
        lastSearchResultHash = currentResultHash;
    });

})();<commit_msg>Trying more to resolve super search bug - 5<commit_after>/*  Super Search
    Author: Kushagra Gour (http://kushagragour.in)
    MIT Licensed
*/

(function () {
    var isSearchOpen = false,
        searchEl = document.querySelector('#js-search'),
        searchInputEl = document.querySelector('#js-search__input'),
        searchResultsEl = document.querySelector('#js-search__results'),
        currentInputValue = '',
        lastSearchResultHash,
        posts = [],
        sitemap = 'http://www.abheyrana.me/sitemap.xml';

    // Changes XML to JSON
    // Modified version from here: http://davidwalsh.name/convert-xml-json
    function xmlToJson(xml) {

        // Create the return object
        var obj = {};

        if (xml.nodeType == 1) { // element
            // do attributes
            if (xml.attributes.length > 0) {
            obj["@attributes"] = {};
                for (var j = 0; j < xml.attributes.length; j++) {
                    var attribute = xml.attributes.item(j);
                    obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
                }
            }
        } else if (xml.nodeType == 3) { // text
            obj = xml.nodeValue;
        }

        // do children
        // If all text nodes inside, get concatenated text from them.
        var textNodes = [].slice.call(xml.childNodes).filter(function (node) { return node.nodeType === 3; });
        if (xml.hasChildNodes() && xml.childNodes.length === textNodes.length) {
            obj = [].slice.call(xml.childNodes).reduce(function (text, node) { return text + node.nodeValue; }, '');
        }
        else if (xml.hasChildNodes()) {
            for(var i = 0; i < xml.childNodes.length; i++) {
                var item = xml.childNodes.item(i);
                var nodeName = item.nodeName;
                if (typeof(obj[nodeName]) == "undefined") {
                    obj[nodeName] = xmlToJson(item);
                } else {
                    if (typeof(obj[nodeName].push) == "undefined") {
                        var old = obj[nodeName];
                        obj[nodeName] = [];
                        obj[nodeName].push(old);
                    }
                    obj[nodeName].push(xmlToJson(item));
                }
            }
        }
        return obj;
    }

    function getPostsFromXml(xml) {
        var json = xmlToJson(xml);
        return json.channel.item;
    }

    var xmlhttp=new XMLHttpRequest();
    xmlhttp.open("GET",sitemap);
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState != 4) return;
        if (xmlhttp.status != 200 && xmlhttp.status != 304) { return; }
        var node = (new DOMParser).parseFromString(xmlhttp.responseText, 'text/xml');
        node = node.children[0];
        posts = getPostsFromXml(node);
    }
    xmlhttp.send();

    window.toggleSearch = function toggleSearch() {
        _gaq.push(['_trackEvent', 'supersearch', searchEl.classList.contains('is-active')]);
        searchEl.classList.toggle('is-active');
        if (searchEl.classList.contains('is-active')) {
            // while opening
            searchInputEl.value = '';
        } else {
            // while closing
            searchResultsEl.classList.add('is-hidden');
        }
        setTimeout(function () {
            searchInputEl.focus();
        }, 210);
    }

    window.addEventListener('keyup', function onKeyPress(e) {
        if (e.which === 27) {
            toggleSearch();
        }
    });
    window.addEventListener('keypress', function onKeyPress(e) {
        if (e.which === 47 && !searchEl.classList.contains('is-active')) {
            toggleSearch();
        }
    });

    searchInputEl.addEventListener('input', function onInputChange() {
        var currentResultHash, d;

        currentInputValue = (searchInputEl.value + '').toLowerCase();
        if (!currentInputValue || currentInputValue.length < 3) {
            lastSearchResultHash = '';
            searchResultsEl.classList.add('is-hidden');
            return;
        }
        searchResultsEl.style.offsetWidth;

        var matchingPosts = posts.filter(function (post) {
            if ((post.title + '').toLowerCase().indexOf(currentInputValue) !== -1 || (post.description + '').toLowerCase().indexOf(currentInputValue) !== -1) {
                return true;
            }
        });
        if (!matchingPosts.length) {
            searchResultsEl.classList.add('is-hidden');
        }
        currentResultHash = matchingPosts.reduce(function(hash, post) { return post.title + hash; }, '');
        if (matchingPosts.length && currentResultHash !== lastSearchResultHash) {
            searchResultsEl.classList.remove('is-hidden');
            searchResultsEl.innerHTML = matchingPosts.map(function (post) {
                d = new Date(post.pubDate);
                str = post.link.substr(0,8);
                if(str == 'https://'){
                    post.link = post.link.substr(8);
                    return '
' + post.title + '' + d.toUTCString().replace(/.*(\d{2})\s+(\w{3})\s+(\d{4}).*/,'$2 $1, $3') + '
';
                }
                else
                    return '
' + post.title + '' + d.toUTCString().replace(/.*(\d{2})\s+(\w{3})\s+(\d{4}).*/,'$2 $1, $3') + '
';
            }).join('');
        }
        lastSearchResultHash = currentResultHash;
    });

})();<|endoftext|>