<commit_before>var composebox_typeahead = (function () {

//************************************
// AN IMPORTANT NOTE ABOUT TYPEAHEADS
//************************************
// They do not do any HTML escaping, at all.
// And your input to them is rendered as though it were HTML by
// the default highlighter.
//
// So if you are not using trusted input, you MUST use the a
// highlighter that escapes (i.e. one that calls
// typeahead_helper.highlight_with_escaping).

var exports = {};

function get_pm_recipients(query_string) {
    // Assumes email addresses don't have commas or semicolons in them
    return query_string.split(/\s*[,;]\s*/);
}

// Returns an array of private message recipients, removing empty elements.
// For example, "a,,b, " => ["a", "b"]
exports.get_cleaned_pm_recipients = function (query_string) {
    var recipients = get_pm_recipients(query_string);
    recipients = _.filter(recipients, function (elem) {
        return elem.match(/\S/);
    });
    return recipients;
};

var seen_topics = new Dict();

exports.add_topic = function (uc_stream, uc_topic) {
    // For Denmark/FooBar, we set
    // seen_topics['denmark']['foobar'] to 'FooBar',
    // where seen_topics is a Dict of Dicts
    var stream = uc_stream.toLowerCase();
    var topic = uc_topic.toLowerCase();

    if (! seen_topics.has(stream)) {
        seen_topics.set(stream, new Dict());
    }
    var topic_dict = seen_topics.get(stream);
    if (! topic_dict.has(topic)) {
        topic_dict.set(topic, uc_topic);
    }
};

exports.topics_seen_for = function (stream) {
    stream = stream.toLowerCase();
    if (seen_topics.has(stream)) {
        return seen_topics.get(stream).values().sort();
    }
    return [];
};

function get_last_recipient_in_pm(query_string) {
    var recipients = get_pm_recipients(query_string);
    return recipients[recipients.length-1];
}

function composebox_typeahead_highlighter(item) {
    return typeahead_helper.highlight_with_escaping(this.query, item);
}

function query_matches_person(query, person) {
    // Case-insensitive.
    query = query.toLowerCase();

    return ( person.email    .toLowerCase().indexOf(query) !== -1
         ||  person.full_name.toLowerCase().indexOf(query) !== -1);

}

function query_matches_emoji(query, emoji) {
    return (emoji.emoji_name.indexOf(query.toLowerCase()) !== -1);
}

// nextFocus is set on a keydown event to indicate where we should focus on keyup.
// We can't focus at the time of keydown because we need to wait for typeahead.
// And we can't compute where to focus at the time of keyup because only the keydown
// has reliable information about whether it was a tab or a shift+tab.
var nextFocus = false;

function handle_keydown(e) {
    var code = e.keyCode || e.which;

    if (code === 13 || (code === 9 && !e.shiftKey)) { // Enter key or tab key
        if (e.target.id === "stream" || e.target.id === "subject" || e.target.id === "private_message_recipient") {
            // For enter, prevent the form from submitting
            // For tab, prevent the focus from changing again
            e.preventDefault();
        }

        // In the new_message_content box, preventDefault() for tab but not for enter
        if (e.target.id === "new_message_content" && code !== 13) {
            e.preventDefault();
        }

        if (e.target.id === "stream") {
            nextFocus = "subject";
        } else if (e.target.id === "subject") {
            if (code === 13) {
                e.preventDefault();
            }
            nextFocus = "new_message_content";
        } else if (e.target.id === "private_message_recipient") {
            nextFocus = "new_message_content";
        } else if (e.target.id === "new_message_content") {
            if (code === 13) {
                nextFocus = false;
            } else {
                nextFocus = "compose-send-button";
            }
        } else {
            nextFocus = false;
        }

        // If no typeaheads are shown...
        if (!($("#subject").data().typeahead.shown ||
              $("#stream").data().typeahead.shown ||
              $("#private_message_recipient").data().typeahead.shown ||
              $("#new_message_content").data().typeahead.shown)) {

            // If no typeaheads are shown and the user is tabbing from the message content box,
            // then there's no need to wait and we can change the focus right away.
            // Without this code to change the focus right away, if the user presses enter
            // before they fully release the tab key, the tab will be lost.  Note that we don't
            // want to change focus right away in the private_message_recipient box since it
            // takes the typeaheads a little time to open after the user finishes typing, which
            // can lead to the focus moving without the autocomplete having a chance to happen.
            if ((page_params.domain === "zulip.com" && nextFocus === "compose-send-button") ||
                (page_params.domain !== "zulip.com" && nextFocus)) {
                ui.focus_on(nextFocus);
                nextFocus = false;
            }

            // Send the message on Ctrl/Cmd-Enter or if the user has configured enter to
            // send and the shift key is not pressed.
            if (e.target.id === "new_message_content" && code === 13 &&
                (e.metaKey || e.ctrlKey || (page_params.enter_sends && !e.shiftKey))
               ) {
                e.preventDefault();
                if ($("#compose-send-button").attr('disabled') !== "disabled") {
                    $("#compose-send-button").attr('disabled', 'disabled');
                    compose.finish();
                }
            }
        }
    }
}

function handle_keyup(e) {
    var code = e.keyCode || e.which;
    if (code === 13 || (code === 9 && !e.shiftKey)) { // Enter key or tab key
        if (nextFocus) {
            ui.focus_on(nextFocus);
            nextFocus = false;
        }
    }
}

// http://stackoverflow.com/questions/3380458/looking-for-a-better-workaround-to-chrome-select-on-focus-bug
function select_on_focus(field_id) {
    // A select event appears to trigger a focus event under certain
    // conditions in Chrome so we need to protect against infinite
    // recursion.
    var in_handler = false;
    $("#" + field_id).focus(function (e) {
        if (in_handler) {
            return;
        }
        in_handler = true;
        $("#" + field_id).select().one('mouseup', function (e) {
            e.preventDefault();
        });
        in_handler = false;
    });
}

exports.split_at_cursor = function (query, input) {
    var cursor = input.caret().start;
    return [query.slice(0, cursor), query.slice(cursor)];
};

exports.compose_content_begins_typeahead = function (query) {
    var q = exports.split_at_cursor(query, this.$element)[0];

    var strings = q.split(/[\s*(){}\[\]]/);
    if (strings.length < 1) {
        return false;
    }
    var current_token = strings[strings.length-1];

    // Only start the emoji autocompleter if : is directly after one
    // of the whitespace or punctuation chars we split on.
    if (this.options.completions.emoji && current_token[0] === ':') {
        // We don't want to match non-emoji emoticons such
        // as :P or :-p
        // Also, if the user has only typed a colon and nothing after,
        // no need to match yet.
        if (/^:-?.?$/.test(current_token)) {
            return false;
        }
        this.completing = 'emoji';
        this.token = current_token.substring(1);
        return emoji.emojis;
    }

    if (!this.options.completions.mention) {
        return false;
    }

    // Don't autocomplete more than this many characters.
    var max_chars = 30;
    var last_at = q.lastIndexOf('@');
    if (last_at === -1 || last_at < q.length-1 - max_chars) {
        return false;  // No '@', or too far back
    }

    // Only match if the @ follows a space, various punctuation,
    // or is at the beginning of the string.
    if (last_at > 0 && "\n\t \"'(){}[]".indexOf(q[last_at-1]) === -1) {
        return false;
    }

    current_token = q.substring(last_at + 1);
    if (current_token.length < 1 || current_token.lastIndexOf('*') !== -1) {
        return false;
    }

    this.completing = 'mention';
    this.token = current_token.substring(current_token.indexOf("@")+1);
    var all_item = {
        special_item_text: "all (Notify everyone)",
        email: "all",
        // Always sort above, under the assumption that names will
        // be longer and only contain "all" as a substring.
        pm_recipient_count: Infinity,
        full_name: "all"
    };
    return page_params.people_list.concat([all_item]);
};

exports.content_highlighter = function (item) {
    if (this.completing === 'emoji') {
        return "<img class='emoji' src='" + item.emoji_url + "' /> " + item.emoji_name;
    } else if (this.completing === 'mention') {
        var item_formatted = typeahead_helper.render_person(item);
        return typeahead_helper.highlight_with_escaping(this.token, item_formatted);
    }
};

exports.content_typeahead_selected = function (item) {
    var pieces = exports.split_at_cursor(this.query, this.$element);
    var beginning = pieces[0];
    var rest = pieces[1];

    if (this.completing === 'emoji') {
        //leading and trailing spaces are required for emoji, except if it begins a message.
        if (beginning.lastIndexOf(":") === 0 || beginning.charAt(beginning.lastIndexOf(":") - 1) === " ") {
            beginning = beginning.replace(/:\S+$/, "") + ":" + item.emoji_name + ": ";
        } else {
            beginning = beginning.replace(/:\S+$/, "") + " :" + item.emoji_name + ": ";
        }
    } else if (this.completing === 'mention') {
        beginning = (beginning.substring(0, beginning.length - this.token.length-1)
                + '@**' + item.full_name + '** ');

        // We insert a special `all` item to the autocompleter above
        // Don't consider it a user mention
        if (item.email !== 'all') {
            $(document).trigger('usermention_completed.zulip', {mentioned: item});
        }
    }

    // Keep the cursor after the newly inserted text, as Bootstrap will call textbox.change() to overwrite the text
    // in the textbox.
    setTimeout(function () {
        $('#new_message_content').caret(beginning.length, beginning.length);
    }, 0);
    return beginning + rest;
};

exports.initialize_compose_typeahead = function (selector, completions) {
    completions = $.extend({mention: false, emoji: false}, completions);

    $(selector).typeahead({
        items: 5,
        dropup: true,
        fixed: true,
        source: exports.compose_content_begins_typeahead,
        highlighter: exports.content_highlighter,
        matcher: function (item) {
            if (this.completing === 'emoji') {
                return query_matches_emoji(this.token, item);
            } else if (this.completing === 'mention') {
                return query_matches_person(this.token, item);
            }
        },
        sorter: function (matches) {
            if (this.completing === 'emoji') {
                return typeahead_helper.sort_emojis(matches, this.token);
            } else if (this.completing === 'mention') {
                return typeahead_helper.sort_recipients(matches, this.token);
            }
        },
        updater: exports.content_typeahead_selected,
        stopAdvance: true, // Do not advance to the next field on a tab or enter
        completions: completions
    });
};

exports.initialize = function () {
    select_on_focus("stream");
    select_on_focus("subject");
    select_on_focus("private_message_recipient");

    // These handlers are at the "form" level so that they are called after typeahead
    $("form#send_message_form").keydown(handle_keydown);
    $("form#send_message_form").keyup(handle_keyup);

    $("#enter_sends").click(function () {
        var send_button = $("#compose-send-button");
        page_params.enter_sends = $("#enter_sends").is(":checked");
        if (page_params.enter_sends) {
            send_button.fadeOut();
        } else {
            send_button.fadeIn();
        }

        // Refocus in the content box so you can continue typing or
        // press Enter to send.
        $("#new_message_content").focus();

        return $.ajax({
            dataType: 'json',
            url: '/json/change_enter_sends',
            type: 'POST',
            data: {'enter_sends': page_params.enter_sends}
        });
    });
    $("#enter_sends").prop('checked', page_params.enter_sends);
    if (page_params.enter_sends) {
        $("#compose-send-button").hide();
    }

    // limit number of items so the list doesn't fall off the screen
    $( "#stream" ).typeahead({
        source: function (query, process) {
            return stream_data.subscribed_streams();
        },
        items: 3,
        fixed: true,
        highlighter: function (item) {
            var query = this.query;
            return typeahead_helper.highlight_query_in_phrase(query, item);
        },
        matcher: function (item) {
            // The matcher for "stream" is strictly prefix-based,
            // because we want to avoid mixing up streams.
            var q = this.query.trim().toLowerCase();
            return (item.toLowerCase().indexOf(q) === 0);
        }
    });

    $( "#subject" ).typeahead({
        source: function (query, process) {
            var stream_name = $("#stream").val();
            return exports.topics_seen_for(stream_name);
        },
        items: 3,
        fixed: true,
        highlighter: composebox_typeahead_highlighter,
        sorter: function (items) {
            var sorted = typeahead_helper.sorter(this.query, items, function (x){return x;});
            if (sorted.length > 0 && sorted.indexOf(this.query) === -1) {
                sorted.unshift(this.query);
            }
            return sorted;
        }
    });

    $( "#private_message_recipient" ).typeahead({
        source: page_params.people_list,
        items: 5,
        dropup: true,
        fixed: true,
        highlighter: function (item) {
            var query = get_last_recipient_in_pm(this.query);
            var item_formatted = typeahead_helper.render_person(item);
            return typeahead_helper.highlight_with_escaping(query, item_formatted);
        },
        matcher: function (item) {
            var current_recipient = get_last_recipient_in_pm(this.query);
            // If the name is only whitespace (does not contain any non-whitespace),
            // we're between typing names; don't autocomplete anything for us.
            if (! current_recipient.match(/\S/)) {
                return false;
            }

            return query_matches_person(current_recipient, item);
        },
        sorter: typeahead_helper.sort_recipientbox_typeahead,
        updater: function (item) {
            var previous_recipients = exports.get_cleaned_pm_recipients(this.query);
            previous_recipients.pop();
            previous_recipients = previous_recipients.join(", ");
            if (previous_recipients.length !== 0) {
                previous_recipients += ", ";
            }
            return previous_recipients + item.email + ", ";
        },
        stopAdvance: true // Do not advance to the next field on a tab or enter
    });

    exports.initialize_compose_typeahead("#new_message_content", {mention: true, emoji: true});

    $( "#private_message_recipient" ).blur(function (event) {
        var val = $(this).val();
        var recipients = exports.get_cleaned_pm_recipients(val);
        $(this).val(recipients.join(", "));
    });
};

return exports;

}());
if (typeof module !== 'undefined') {
    module.exports = composebox_typeahead;
}
<commit_msg>Add @-everyone to the composebox autocomplete.<commit_after>var composebox_typeahead = (function () {

//************************************
// AN IMPORTANT NOTE ABOUT TYPEAHEADS
//************************************
// They do not do any HTML escaping, at all.
// And your input to them is rendered as though it were HTML by
// the default highlighter.
//
// So if you are not using trusted input, you MUST use the a
// highlighter that escapes (i.e. one that calls
// typeahead_helper.highlight_with_escaping).

var exports = {};

function get_pm_recipients(query_string) {
    // Assumes email addresses don't have commas or semicolons in them
    return query_string.split(/\s*[,;]\s*/);
}

// Returns an array of private message recipients, removing empty elements.
// For example, "a,,b, " => ["a", "b"]
exports.get_cleaned_pm_recipients = function (query_string) {
    var recipients = get_pm_recipients(query_string);
    recipients = _.filter(recipients, function (elem) {
        return elem.match(/\S/);
    });
    return recipients;
};

var seen_topics = new Dict();

exports.add_topic = function (uc_stream, uc_topic) {
    // For Denmark/FooBar, we set
    // seen_topics['denmark']['foobar'] to 'FooBar',
    // where seen_topics is a Dict of Dicts
    var stream = uc_stream.toLowerCase();
    var topic = uc_topic.toLowerCase();

    if (! seen_topics.has(stream)) {
        seen_topics.set(stream, new Dict());
    }
    var topic_dict = seen_topics.get(stream);
    if (! topic_dict.has(topic)) {
        topic_dict.set(topic, uc_topic);
    }
};

exports.topics_seen_for = function (stream) {
    stream = stream.toLowerCase();
    if (seen_topics.has(stream)) {
        return seen_topics.get(stream).values().sort();
    }
    return [];
};

function get_last_recipient_in_pm(query_string) {
    var recipients = get_pm_recipients(query_string);
    return recipients[recipients.length-1];
}

function composebox_typeahead_highlighter(item) {
    return typeahead_helper.highlight_with_escaping(this.query, item);
}

function query_matches_person(query, person) {
    // Case-insensitive.
    query = query.toLowerCase();

    return ( person.email    .toLowerCase().indexOf(query) !== -1
         ||  person.full_name.toLowerCase().indexOf(query) !== -1);

}

function query_matches_emoji(query, emoji) {
    return (emoji.emoji_name.indexOf(query.toLowerCase()) !== -1);
}

// nextFocus is set on a keydown event to indicate where we should focus on keyup.
// We can't focus at the time of keydown because we need to wait for typeahead.
// And we can't compute where to focus at the time of keyup because only the keydown
// has reliable information about whether it was a tab or a shift+tab.
var nextFocus = false;

function handle_keydown(e) {
    var code = e.keyCode || e.which;

    if (code === 13 || (code === 9 && !e.shiftKey)) { // Enter key or tab key
        if (e.target.id === "stream" || e.target.id === "subject" || e.target.id === "private_message_recipient") {
            // For enter, prevent the form from submitting
            // For tab, prevent the focus from changing again
            e.preventDefault();
        }

        // In the new_message_content box, preventDefault() for tab but not for enter
        if (e.target.id === "new_message_content" && code !== 13) {
            e.preventDefault();
        }

        if (e.target.id === "stream") {
            nextFocus = "subject";
        } else if (e.target.id === "subject") {
            if (code === 13) {
                e.preventDefault();
            }
            nextFocus = "new_message_content";
        } else if (e.target.id === "private_message_recipient") {
            nextFocus = "new_message_content";
        } else if (e.target.id === "new_message_content") {
            if (code === 13) {
                nextFocus = false;
            } else {
                nextFocus = "compose-send-button";
            }
        } else {
            nextFocus = false;
        }

        // If no typeaheads are shown...
        if (!($("#subject").data().typeahead.shown ||
              $("#stream").data().typeahead.shown ||
              $("#private_message_recipient").data().typeahead.shown ||
              $("#new_message_content").data().typeahead.shown)) {

            // If no typeaheads are shown and the user is tabbing from the message content box,
            // then there's no need to wait and we can change the focus right away.
            // Without this code to change the focus right away, if the user presses enter
            // before they fully release the tab key, the tab will be lost.  Note that we don't
            // want to change focus right away in the private_message_recipient box since it
            // takes the typeaheads a little time to open after the user finishes typing, which
            // can lead to the focus moving without the autocomplete having a chance to happen.
            if ((page_params.domain === "zulip.com" && nextFocus === "compose-send-button") ||
                (page_params.domain !== "zulip.com" && nextFocus)) {
                ui.focus_on(nextFocus);
                nextFocus = false;
            }

            // Send the message on Ctrl/Cmd-Enter or if the user has configured enter to
            // send and the shift key is not pressed.
            if (e.target.id === "new_message_content" && code === 13 &&
                (e.metaKey || e.ctrlKey || (page_params.enter_sends && !e.shiftKey))
               ) {
                e.preventDefault();
                if ($("#compose-send-button").attr('disabled') !== "disabled") {
                    $("#compose-send-button").attr('disabled', 'disabled');
                    compose.finish();
                }
            }
        }
    }
}

function handle_keyup(e) {
    var code = e.keyCode || e.which;
    if (code === 13 || (code === 9 && !e.shiftKey)) { // Enter key or tab key
        if (nextFocus) {
            ui.focus_on(nextFocus);
            nextFocus = false;
        }
    }
}

// http://stackoverflow.com/questions/3380458/looking-for-a-better-workaround-to-chrome-select-on-focus-bug
function select_on_focus(field_id) {
    // A select event appears to trigger a focus event under certain
    // conditions in Chrome so we need to protect against infinite
    // recursion.
    var in_handler = false;
    $("#" + field_id).focus(function (e) {
        if (in_handler) {
            return;
        }
        in_handler = true;
        $("#" + field_id).select().one('mouseup', function (e) {
            e.preventDefault();
        });
        in_handler = false;
    });
}

exports.split_at_cursor = function (query, input) {
    var cursor = input.caret().start;
    return [query.slice(0, cursor), query.slice(cursor)];
};

exports.compose_content_begins_typeahead = function (query) {
    var q = exports.split_at_cursor(query, this.$element)[0];

    var strings = q.split(/[\s*(){}\[\]]/);
    if (strings.length < 1) {
        return false;
    }
    var current_token = strings[strings.length-1];

    // Only start the emoji autocompleter if : is directly after one
    // of the whitespace or punctuation chars we split on.
    if (this.options.completions.emoji && current_token[0] === ':') {
        // We don't want to match non-emoji emoticons such
        // as :P or :-p
        // Also, if the user has only typed a colon and nothing after,
        // no need to match yet.
        if (/^:-?.?$/.test(current_token)) {
            return false;
        }
        this.completing = 'emoji';
        this.token = current_token.substring(1);
        return emoji.emojis;
    }

    if (!this.options.completions.mention) {
        return false;
    }

    // Don't autocomplete more than this many characters.
    var max_chars = 30;
    var last_at = q.lastIndexOf('@');
    if (last_at === -1 || last_at < q.length-1 - max_chars) {
        return false;  // No '@', or too far back
    }

    // Only match if the @ follows a space, various punctuation,
    // or is at the beginning of the string.
    if (last_at > 0 && "\n\t \"'(){}[]".indexOf(q[last_at-1]) === -1) {
        return false;
    }

    current_token = q.substring(last_at + 1);
    if (current_token.length < 1 || current_token.lastIndexOf('*') !== -1) {
        return false;
    }

    this.completing = 'mention';
    this.token = current_token.substring(current_token.indexOf("@")+1);
    var all_item = {
        special_item_text: "all (Notify everyone)",
        email: "all",
        // Always sort above, under the assumption that names will
        // be longer and only contain "all" as a substring.
        pm_recipient_count: Infinity,
        full_name: "all"
    };
    var everyone_item = {
        special_item_text: "everyone (Notify everyone)",
        email: "everyone",
        full_name: "everyone"
    };
    return page_params.people_list.concat([all_item, everyone_item]);
};

exports.content_highlighter = function (item) {
    if (this.completing === 'emoji') {
        return "<img class='emoji' src='" + item.emoji_url + "' /> " + item.emoji_name;
    } else if (this.completing === 'mention') {
        var item_formatted = typeahead_helper.render_person(item);
        return typeahead_helper.highlight_with_escaping(this.token, item_formatted);
    }
};

exports.content_typeahead_selected = function (item) {
    var pieces = exports.split_at_cursor(this.query, this.$element);
    var beginning = pieces[0];
    var rest = pieces[1];

    if (this.completing === 'emoji') {
        //leading and trailing spaces are required for emoji, except if it begins a message.
        if (beginning.lastIndexOf(":") === 0 || beginning.charAt(beginning.lastIndexOf(":") - 1) === " ") {
            beginning = beginning.replace(/:\S+$/, "") + ":" + item.emoji_name + ": ";
        } else {
            beginning = beginning.replace(/:\S+$/, "") + " :" + item.emoji_name + ": ";
        }
    } else if (this.completing === 'mention') {
        beginning = (beginning.substring(0, beginning.length - this.token.length-1)
                + '@**' + item.full_name + '** ');

        // We insert a special `all` item to the autocompleter above
        // Don't consider it a user mention
        if (item.email !== 'all' && item.email !== "everyone") {
            $(document).trigger('usermention_completed.zulip', {mentioned: item});
        }
    }

    // Keep the cursor after the newly inserted text, as Bootstrap will call textbox.change() to overwrite the text
    // in the textbox.
    setTimeout(function () {
        $('#new_message_content').caret(beginning.length, beginning.length);
    }, 0);
    return beginning + rest;
};

exports.initialize_compose_typeahead = function (selector, completions) {
    completions = $.extend({mention: false, emoji: false}, completions);

    $(selector).typeahead({
        items: 5,
        dropup: true,
        fixed: true,
        source: exports.compose_content_begins_typeahead,
        highlighter: exports.content_highlighter,
        matcher: function (item) {
            if (this.completing === 'emoji') {
                return query_matches_emoji(this.token, item);
            } else if (this.completing === 'mention') {
                return query_matches_person(this.token, item);
            }
        },
        sorter: function (matches) {
            if (this.completing === 'emoji') {
                return typeahead_helper.sort_emojis(matches, this.token);
            } else if (this.completing === 'mention') {
                return typeahead_helper.sort_recipients(matches, this.token);
            }
        },
        updater: exports.content_typeahead_selected,
        stopAdvance: true, // Do not advance to the next field on a tab or enter
        completions: completions
    });
};

exports.initialize = function () {
    select_on_focus("stream");
    select_on_focus("subject");
    select_on_focus("private_message_recipient");

    // These handlers are at the "form" level so that they are called after typeahead
    $("form#send_message_form").keydown(handle_keydown);
    $("form#send_message_form").keyup(handle_keyup);

    $("#enter_sends").click(function () {
        var send_button = $("#compose-send-button");
        page_params.enter_sends = $("#enter_sends").is(":checked");
        if (page_params.enter_sends) {
            send_button.fadeOut();
        } else {
            send_button.fadeIn();
        }

        // Refocus in the content box so you can continue typing or
        // press Enter to send.
        $("#new_message_content").focus();

        return $.ajax({
            dataType: 'json',
            url: '/json/change_enter_sends',
            type: 'POST',
            data: {'enter_sends': page_params.enter_sends}
        });
    });
    $("#enter_sends").prop('checked', page_params.enter_sends);
    if (page_params.enter_sends) {
        $("#compose-send-button").hide();
    }

    // limit number of items so the list doesn't fall off the screen
    $( "#stream" ).typeahead({
        source: function (query, process) {
            return stream_data.subscribed_streams();
        },
        items: 3,
        fixed: true,
        highlighter: function (item) {
            var query = this.query;
            return typeahead_helper.highlight_query_in_phrase(query, item);
        },
        matcher: function (item) {
            // The matcher for "stream" is strictly prefix-based,
            // because we want to avoid mixing up streams.
            var q = this.query.trim().toLowerCase();
            return (item.toLowerCase().indexOf(q) === 0);
        }
    });

    $( "#subject" ).typeahead({
        source: function (query, process) {
            var stream_name = $("#stream").val();
            return exports.topics_seen_for(stream_name);
        },
        items: 3,
        fixed: true,
        highlighter: composebox_typeahead_highlighter,
        sorter: function (items) {
            var sorted = typeahead_helper.sorter(this.query, items, function (x){return x;});
            if (sorted.length > 0 && sorted.indexOf(this.query) === -1) {
                sorted.unshift(this.query);
            }
            return sorted;
        }
    });

    $( "#private_message_recipient" ).typeahead({
        source: page_params.people_list,
        items: 5,
        dropup: true,
        fixed: true,
        highlighter: function (item) {
            var query = get_last_recipient_in_pm(this.query);
            var item_formatted = typeahead_helper.render_person(item);
            return typeahead_helper.highlight_with_escaping(query, item_formatted);
        },
        matcher: function (item) {
            var current_recipient = get_last_recipient_in_pm(this.query);
            // If the name is only whitespace (does not contain any non-whitespace),
            // we're between typing names; don't autocomplete anything for us.
            if (! current_recipient.match(/\S/)) {
                return false;
            }

            return query_matches_person(current_recipient, item);
        },
        sorter: typeahead_helper.sort_recipientbox_typeahead,
        updater: function (item) {
            var previous_recipients = exports.get_cleaned_pm_recipients(this.query);
            previous_recipients.pop();
            previous_recipients = previous_recipients.join(", ");
            if (previous_recipients.length !== 0) {
                previous_recipients += ", ";
            }
            return previous_recipients + item.email + ", ";
        },
        stopAdvance: true // Do not advance to the next field on a tab or enter
    });

    exports.initialize_compose_typeahead("#new_message_content", {mention: true, emoji: true});

    $( "#private_message_recipient" ).blur(function (event) {
        var val = $(this).val();
        var recipients = exports.get_cleaned_pm_recipients(val);
        $(this).val(recipients.join(", "));
    });
};

return exports;

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


<commit_before><commit_msg>recaptcha_moar<commit_after><|endoftext|>


<commit_before>var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io-client');
var getCpuUsage = require("./top.js");

var run = true;

http.listen(3005, function(){
  console.log('listening on *:3005');
});

//Arbitary calculation to simulate load when user makes a request
function doCalculations(){
    var x = 0;
    for(var i = 0; i < 100; i++){
        x += Math.random();
    }
    return x;
}

app.get('/', function(req, res){
    res.end("Here is a website " + doCalculations());
});

console.log('connecting')
var socket = io.connect('http://192.168.56.101:3000');

socket.on('connect', function () {
    console.log('connected')
    getCpuUsage(sendCPUUsage);
});

socket.on('connect_failed', function(){
    console.log('Connection Failed');
});

function sendCPUUsage(usage){
    console.log('emit' + usage)
    socket.emit('cpu-usage', usage);
};
<commit_msg>Modified calculation function to take longer<commit_after>var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io-client');
var getCpuUsage = require("./top.js");

var run = true;

http.listen(3005, function(){
  console.log('listening on *:3005');
});

//Arbitary calculation to simulate load when user makes a request
function doCalculations(){
    var x = 0;
    for(var i = 0; i < Math.pow(10, 8) * 5; i++){
        x += Math.random();
    }
    return x;
}

app.get('/', function(req, res){
    res.end("Here is a website " + doCalculations());
});

console.log('connecting')
var socket = io.connect('http://192.168.56.101:3000');

socket.on('connect', function () {
    console.log('connected')
    getCpuUsage(sendCPUUsage);
});

socket.on('connect_failed', function(){
    console.log('Connection Failed');
});

function sendCPUUsage(usage){
    console.log('emit' + usage)
    socket.emit('cpu-usage', usage);
};
<|endoftext|>


<commit_before>/*
    ___ usage ___ en_US ___
    usage: node monitor.bin.js

        -c, --configuration <string>    json configuration path
        -s, --supervisor <string>       pid of supervisor
            --help                      display this message

    ___ . ___
*/
require('arguable')(module, function (program, callback) {
    program.required('configuration', 'supervisor')

    // Node.js API.
    var assert = require('assert')

    // Route messages through a process hierarchy using Node.js IPC.
    var Descendent = require('descendent')

    // Controlled demolition of objects.
    var Destructible = require('destructible')

    var Signal = require('signal')
    var cadence = require('cadence')

    var Consolidator = require('prolific.consolidator')

    var descendent = require('foremost')('descendent')

    var destructible = new Destructible(4000, 'prolific.monitor')

    descendent.process = program
    descendent.increment()
    destructible.destruct.wait(descendent, 'decrement')

    var logger = require('prolific.logger').createLogger('prolific')
    function memoryUsage () { logger.notice('memory', process.memoryUsage()) }
    memoryUsage()
    setInterval(memoryUsage, 1000).unref()

    var Processor = require('./processor')

    var Turnstile = require('turnstile')
    Turnstile.Queue = require('turnstile/queue')

    destructible.completed.wait(callback)

    var cadence = require('cadence')

    // TODO Goodness this is silly. Just add a signal to arugable. Or maybe just
    // use `process` now that it has settled.
    destructible.destruct.wait(destructible.durable('exit').bind(null, null, 0))

    cadence(function (async) {
        async([function () {
            program.ready.unlatch()
        }], function () {
            setImmediate(async()) // allows test to get handle
        }, function () {
            var reloaded = descendent.up.bind(descendent, +program.ultimate.supervisor, 'prolific:accept')
            destructible.durable('processor', Processor, program.ultimate.configuration, reloaded, async())
        }, function (processor) {
            // Drain all chunks immediately into a turnstile.
            var turnstile = new Turnstile
            var queue = new Turnstile.Queue(processor, 'process', turnstile)
            turnstile.listen(destructible.durable('turnstile'))
            destructible.destruct.wait(turnstile, 'destroy')

            program.stdin.resume()

            // Listen to our asynchronous pipe.
            var socket = new program.attributes.net.Socket({ fd: 3, readable: true })
            var consolidator = new Consolidator(socket, program.stdin, queue)

            consolidator.asynchronous(destructible.ephemeral('asynchronous'))
            consolidator.synchronous(destructible.ephemeral('synchronous'))

            destructible.destruct.wait(consolidator, 'exit')

            destructible.destruct.wait(socket, 'destroy')

            // Let the supervisor know that we're ready. It will send our
            // asynchronous pipe down to the monitored process.
            descendent.up(+program.ultimate.supervisor, 'prolific:pipe', true)
        })
    })(destructible.ephemeral('initialize'))
}, { net: require('net') })
<commit_msg>Capture `SIGINT` and `SIGTERM` in monitor.<commit_after>/*
    ___ usage ___ en_US ___
    usage: node monitor.bin.js

        -c, --configuration <string>    json configuration path
        -s, --supervisor <string>       pid of supervisor
            --help                      display this message

    ___ . ___
*/
require('arguable')(module, function (program, callback) {
    program.required('configuration', 'supervisor')

    // Node.js API.
    var assert = require('assert')

    // Route messages through a process hierarchy using Node.js IPC.
    var Descendent = require('descendent')

    // Controlled demolition of objects.
    var Destructible = require('destructible')

    var Signal = require('signal')
    var cadence = require('cadence')

    var Consolidator = require('prolific.consolidator')

    var descendent = require('foremost')('descendent')

    var destructible = new Destructible(4000, 'prolific.monitor')

    descendent.process = program
    descendent.increment()
    destructible.destruct.wait(descendent, 'decrement')

    var logger = require('prolific.logger').createLogger('prolific')
    function memoryUsage () { logger.notice('memory', process.memoryUsage()) }
    memoryUsage()
    setInterval(memoryUsage, 1000).unref()

    var Processor = require('./processor')

    var Turnstile = require('turnstile')
    Turnstile.Queue = require('turnstile/queue')

    destructible.completed.wait(callback)

    var cadence = require('cadence')

    process.on('SIGINT', function () {})
    process.on('SIGTERM', function () {})

    // TODO Goodness this is silly. Just add a signal to arugable. Or maybe just
    // use `process` now that it has settled.
    destructible.destruct.wait(destructible.durable('exit').bind(null, null, 0))

    cadence(function (async) {
        async([function () {
            program.ready.unlatch()
        }], function () {
            setImmediate(async()) // allows test to get handle
        }, function () {
            var reloaded = descendent.up.bind(descendent, +program.ultimate.supervisor, 'prolific:accept')
            destructible.durable('processor', Processor, program.ultimate.configuration, reloaded, async())
        }, function (processor) {
            // Drain all chunks immediately into a turnstile.
            var turnstile = new Turnstile
            var queue = new Turnstile.Queue(processor, 'process', turnstile)
            turnstile.listen(destructible.durable('turnstile'))
            destructible.destruct.wait(turnstile, 'destroy')

            program.stdin.resume()

            // Listen to our asynchronous pipe.
            var socket = new program.attributes.net.Socket({ fd: 3, readable: true })
            var consolidator = new Consolidator(socket, program.stdin, queue)

            consolidator.asynchronous(destructible.ephemeral('asynchronous'))
            consolidator.synchronous(destructible.ephemeral('synchronous'))

            destructible.destruct.wait(consolidator, 'exit')

            destructible.destruct.wait(socket, 'destroy')

            // Let the supervisor know that we're ready. It will send our
            // asynchronous pipe down to the monitored process.
            descendent.up(+program.ultimate.supervisor, 'prolific:pipe', true)
        })
    })(destructible.ephemeral('initialize'))
}, { net: require('net') })
<|endoftext|>


<commit_before>(function($) {
   $.jqmCalendar = function(element, options) {

      var defaults = {
         // Array of events
         events : [],
         // Default properties for events
         begin : "begin",
         end : "end",
         summary : "summary",
         icon: "icon",
         url: "url",
         // Theme
         theme : "c",
         // Date variable to determine which month to show and which date to select
         date : new Date(),
         // Version
         version: "1.0.0",
         // Array of month strings (calendar header)
         months : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
         // Array of day strings (calendar header)
         days : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
         // Most months contain 5 weeks, some 6. Set this to six if you don't want the amount of rows to change when switching months.
         weeksInMonth : undefined,
         // Start the week at the day of your preference, 0 for sunday, 1 for monday, and so on.
         startOfWeek : 0
         // List Item formatter, allows a callback to be passed to alter the contect of the list item
         listItemFormatter : listItemFormatter
      }

      var plugin = this;
      plugin.settings = null;

      var $element = $(element).addClass("jq-calendar-wrapper"),
          element = element,
          $table,
          $header,
          $tbody,
          $listview;

      function init() {
         plugin.settings = $.extend({}, defaults, options);
         plugin.settings.theme = $.mobile.getInheritedTheme($element, plugin.settings.theme);

         $table = $("
");

         // Build the header
         var $thead = $("
").appendTo($table),
            $tr = $("
").appendTo($thead),
            $th = $("");

         $previous = $("Previous").click(function(event) {
            refresh(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() - 1, plugin.settings.date.getDate()));
         }).appendTo($th);

         $header = $("").appendTo($th);

         $previous = $("Next").click(function(event) {
            refresh(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() + 1, plugin.settings.date.getDate()));
         }).appendTo($th);

         $th.appendTo($tr);

         $tr = $("
").appendTo($thead);

         // The way of determing the labels for the days is a bit awkward, but works.
         for ( var i = 0, days = [].concat(plugin.settings.days, plugin.settings.days).splice(plugin.settings.startOfWeek, 7); i < 7; i++ ) {
            $tr.append(""  + days[i] + "	");
         }

         $tbody = $("
").appendTo($table);

         $table.appendTo($element);
         $listview = $("
").insertAfter($table);

         // Call refresh to fill the calendar with dates
         refresh(plugin.settings.date);
      }

      function _firstDayOfMonth(date) {
         // [0-6] Sunday is 0, Monday is 1, and so on.
         return ( new Date(date.getFullYear(), date.getMonth(), 1) ).getDay();
      }

      function _daysBefore(date, fim) {
          // Returns [0-6], 0 when firstDayOfMonth is equal to startOfWeek, else the amount of days of the previous month included in the week.
         var firstDayInMonth = ( fim || _firstDayOfMonth(date) ),
             diff = firstDayInMonth - plugin.settings.startOfWeek;
         return ( diff > 0 ) ? diff : ( 7 + diff );
      }

      function _daysInMonth(date) {
         // [1-31]
         return ( new Date ( date.getFullYear(), date.getMonth() + 1, 0 )).getDate();
      }

      function _daysAfter(date, wim, dim, db) {
         // Returns [0-6] amount of days from the next month
         return    (( wim || _weeksInMonth(date) ) * 7 ) - ( dim || _daysInMonth(date) ) - ( db || _daysBefore(date));
      }

      function _weeksInMonth(date, dim, db) {
         // Returns [5-6];
         return ( plugin.settings.weeksInMonth ) ? plugin.settings.weeksInMonth : Math.ceil( ( ( dim || _daysInMonth(date) ) + ( db || _daysBefore(date)) ) / 7 );
      }

      function addCell($row, date, hidden, selected) {
         var $td = $("").appendTo($row),
             $a = $("")
                  .html(date.getDate().toString())
                  .data('date', date)
                  .click(cellClickHandler)
                  .appendTo($td);

         if ( selected ) $a.click();

         if ( hidden ) {
             $td.addClass("hidden");
         } else {
            var importance = 0;

            // Find events for this date
            for ( var i = 0,
                      event,
                      begin = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0),
                      end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1, 0, 0, 0, 0);
                  event = plugin.settings.events[i]; i++ ) {
               if ( event[plugin.settings.end] > begin && event[plugin.settings.begin] < end ) {
                  importance++;
                  if ( importance > 2 ) break;
               }
            }

            if ( importance > 0 ) {
                $a.append("•").addClass("importance-" + importance.toString() );
            }
         }
      }

      function cellClickHandler(event) {
         var $this = $(this),
            date = $this.data('date');
         $tbody.find("a.ui-btn-active").removeClass("ui-btn-active");
         $this.addClass("ui-btn-active");

         if ( date.getMonth() !== plugin.settings.date.getMonth() ) {
            // Go to previous/next month
            refresh(date);
         } else {
            // Select new date
            $element.trigger('change', date);
         }
      }

      function refresh(date) {
         plugin.settings.date = date = date ||  plugin.settings.date || new Date();

         var year = date.getFullYear(),
            month = date.getMonth(),
            daysBefore = _daysBefore(date),
            daysInMonth = _daysInMonth(date),
            weeksInMonth = plugin.settings.weeksInMonth || _weeksInMonth(date, daysInMonth, daysBefore);

         if (((daysInMonth + daysBefore) / 7 ) - weeksInMonth === 0)
             weeksInMonth++;

         // Empty the table body, we start all over...
         $tbody.empty();
         // Change the header to match the current month
         $header.html( plugin.settings.months[month] + " " + year.toString() );

         for (    var   weekIndex = 0,
                  daysInMonthCount = 1,
                  daysAfterCount = 1; weekIndex < weeksInMonth; weekIndex++ ) {

            var daysInWeekCount = 0,
               row = $("
").appendTo($tbody);

            // Previous month
            while ( daysBefore > 0 ) {
               addCell(row, new Date(year, month, 1 - daysBefore), true);
               daysBefore--;
               daysInWeekCount++;
            }

            // Current month
            while ( daysInWeekCount < 7 && daysInMonthCount <= daysInMonth ) {
               addCell(row, new Date(year, month, daysInMonthCount), false, daysInMonthCount === date.getDate() );
               daysInWeekCount++;
               daysInMonthCount++;
            }

            // Next month
            while ( daysInMonthCount > daysInMonth && daysInWeekCount < 7 ) {
               addCell(row, new Date(year, month, daysInMonth + daysAfterCount), true);
               daysInWeekCount++;
               daysAfterCount++;
            }
         }

         $element.trigger('create');
      }

      $element.bind('change', function(event, begin) {
         var end = new Date(begin.getFullYear(), begin.getMonth(), begin.getDate() + 1, 0,0,0,0);
         // Empty the list
         $listview.empty();

         // Find events for this date
         for ( var i = 0, event; event = plugin.settings.events[i]; i++ ) {
            if ( event[plugin.settings.end] >= begin && event[plugin.settings.begin] <= end ) {
               // Append matches to list
               var summary    = event[plugin.settings.summary],
                   beginTime  = (( event[plugin.settings.begin] > begin ) ? event[plugin.settings.begin] : begin ).toTimeString().substr(0,5),
                   endTime    = (( event[plugin.settings.end] < end ) ? event[plugin.settings.end] : end ).toTimeString().substr(0,5),
                   timeString = beginTime + "-" + endTime,
                   $listItem  = $("

").appendTo($listview);

               plugin.settings.listItemFormatter( $listItem, timeString, summary, event );

            }
         }

         $listview.trigger('create').filter(".ui-listview").listview('refresh');
      });

      function listItemFormatter($listItem, timeString, summary, event) {
         var text = ( ( timeString != "00:00-00:00" ) ? timeString : "" ) + " " + summary;
         if (event[plugin.settings.icon]) {
            item.attr('data-icon', event.icon);
         }
         if (event[plugin.settings.url]) {
            $('').text( text ).attr( 'href', event[plugin.settings.url] ).appendTo($listItem);
         } else {
            $listItem.text( text );
         }

      }

      $element.bind('refresh', function(event, date) {
         refresh(date);
      });

      init();
   }

   $.fn.jqmCalendar = function(options) {
      return this.each(function() {
         if (!$(this).data('jqmCalendar')) {
             $(this).data('jqmCalendar', new $.jqmCalendar(this, options));
         }
      });
   }

})(jQuery);
<commit_msg>Update: Add setting "allDayTimeString", sort entries at start<commit_after>(function($) {
   $.jqmCalendar = function(element, options) {

      var defaults = {
         // Array of events
         events : [],
         // Default properties for events
         begin : "begin",
         end : "end",
         summary : "summary",
         icon: "icon",
         url: "url",
         // Sting to use when event is all day
         allDayTimeString: '',
         // Theme
         theme : "c",
         // Date variable to determine which month to show and which date to select
         date : new Date(),
         // Version
         version: "1.0.0",
         // Array of month strings (calendar header)
         months : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
         // Array of day strings (calendar header)
         days : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
         // Most months contain 5 weeks, some 6. Set this to six if you don't want the amount of rows to change when switching months.
         weeksInMonth : undefined,
         // Start the week at the day of your preference, 0 for sunday, 1 for monday, and so on.
         startOfWeek : 0,
         // List Item formatter, allows a callback to be passed to alter the contect of the list item
         listItemFormatter : listItemFormatter
      }

      var plugin = this;
      plugin.settings = null;

      var $element = $(element).addClass("jq-calendar-wrapper"),
          element = element,
          $table,
          $header,
          $tbody,
          $listview;

      function init() {
         plugin.settings = $.extend({}, defaults, options);
         plugin.settings.theme = $.mobile.getInheritedTheme($element, plugin.settings.theme);

         $table = $("
");

         // Build the header
         var $thead = $("
").appendTo($table),
            $tr = $("
").appendTo($thead),
            $th = $("");

         $previous = $("Previous").click(function(event) {
            refresh(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() - 1, plugin.settings.date.getDate()));
         }).appendTo($th);

         $header = $("").appendTo($th);

         $previous = $("Next").click(function(event) {
            refresh(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() + 1, plugin.settings.date.getDate()));
         }).appendTo($th);

         $th.appendTo($tr);

         $tr = $("
").appendTo($thead);

         // The way of determing the labels for the days is a bit awkward, but works.
         for ( var i = 0, days = [].concat(plugin.settings.days, plugin.settings.days).splice(plugin.settings.startOfWeek, 7); i < 7; i++ ) {
            $tr.append(""  + days[i] + "	");
         }

         $tbody = $("
").appendTo($table);

         $table.appendTo($element);
         $listview = $("
").insertAfter($table);

         // Stort the events
         plugin.settings.events.sort(function(a,b) {return a.start_date.getTime()-b.start_date.getTime()} );

         // Call refresh to fill the calendar with dates
         refresh(plugin.settings.date);
      }

      function _firstDayOfMonth(date) {
         // [0-6] Sunday is 0, Monday is 1, and so on.
         return ( new Date(date.getFullYear(), date.getMonth(), 1) ).getDay();
      }

      function _daysBefore(date, fim) {
          // Returns [0-6], 0 when firstDayOfMonth is equal to startOfWeek, else the amount of days of the previous month included in the week.
         var firstDayInMonth = ( fim || _firstDayOfMonth(date) ),
             diff = firstDayInMonth - plugin.settings.startOfWeek;
         return ( diff > 0 ) ? diff : ( 7 + diff );
      }

      function _daysInMonth(date) {
         // [1-31]
         return ( new Date ( date.getFullYear(), date.getMonth() + 1, 0 )).getDate();
      }

      function _daysAfter(date, wim, dim, db) {
         // Returns [0-6] amount of days from the next month
         return    (( wim || _weeksInMonth(date) ) * 7 ) - ( dim || _daysInMonth(date) ) - ( db || _daysBefore(date));
      }

      function _weeksInMonth(date, dim, db) {
         // Returns [5-6];
         return ( plugin.settings.weeksInMonth ) ? plugin.settings.weeksInMonth : Math.ceil( ( ( dim || _daysInMonth(date) ) + ( db || _daysBefore(date)) ) / 7 );
      }

      function addCell($row, date, hidden, selected) {
         var $td = $("").appendTo($row),
             $a = $("")
                  .html(date.getDate().toString())
                  .data('date', date)
                  .click(cellClickHandler)
                  .appendTo($td);

         if ( selected ) $a.click();

         if ( hidden ) {
             $td.addClass("hidden");
         } else {
            var importance = 0;

            // Find events for this date
            for ( var i = 0,
                      event,
                      begin = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0),
                      end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1, 0, 0, 0, 0);
                  event = plugin.settings.events[i]; i++ ) {
               if ( event[plugin.settings.end] >= begin && event[plugin.settings.begin] < end ) {
                  importance++;
                  if ( importance > 2 ) break;
               }
            }

            if ( importance > 0 ) {
                $a.append("•").addClass("importance-" + importance.toString() );
            }
         }
      }

      function cellClickHandler(event) {
         var $this = $(this),
            date = $this.data('date');
         $tbody.find("a.ui-btn-active").removeClass("ui-btn-active");
         $this.addClass("ui-btn-active");

         if ( date.getMonth() !== plugin.settings.date.getMonth() ) {
            // Go to previous/next month
            refresh(date);
         } else {
            // Select new date
            $element.trigger('change', date);
         }
      }

      function refresh(date) {
         plugin.settings.date = date = date ||  plugin.settings.date || new Date();

         var year = date.getFullYear(),
            month = date.getMonth(),
            daysBefore = _daysBefore(date),
            daysInMonth = _daysInMonth(date),
            weeksInMonth = plugin.settings.weeksInMonth || _weeksInMonth(date, daysInMonth, daysBefore);

         if (((daysInMonth + daysBefore) / 7 ) - weeksInMonth === 0)
             weeksInMonth++;

         // Empty the table body, we start all over...
         $tbody.empty();
         // Change the header to match the current month
         $header.html( plugin.settings.months[month] + " " + year.toString() );

         for (    var   weekIndex = 0,
                  daysInMonthCount = 1,
                  daysAfterCount = 1; weekIndex < weeksInMonth; weekIndex++ ) {

            var daysInWeekCount = 0,
               row = $("
").appendTo($tbody);

            // Previous month
            while ( daysBefore > 0 ) {
               addCell(row, new Date(year, month, 1 - daysBefore), true);
               daysBefore--;
               daysInWeekCount++;
            }

            // Current month
            while ( daysInWeekCount < 7 && daysInMonthCount <= daysInMonth ) {
               addCell(row, new Date(year, month, daysInMonthCount), false, daysInMonthCount === date.getDate() );
               daysInWeekCount++;
               daysInMonthCount++;
            }

            // Next month
            while ( daysInMonthCount > daysInMonth && daysInWeekCount < 7 ) {
               addCell(row, new Date(year, month, daysInMonth + daysAfterCount), true);
               daysInWeekCount++;
               daysAfterCount++;
            }
         }

         $element.trigger('create');
      }

      $element.bind('change', function(event, begin) {
         var end = new Date(begin.getFullYear(), begin.getMonth(), begin.getDate() + 1, 0,0,0,0), daysEvents = [];
         // Empty the list
         $listview.empty();

         // Find events for this date
         for ( var i = 0, event; event = plugin.settings.events[i]; i++ ) {
            if ( event[plugin.settings.end] >= begin && event[plugin.settings.begin] < end ) {
               // Append matches to list
               var summary    = event[plugin.settings.summary],
                   beginTime  = (( event[plugin.settings.begin] > begin ) ? event[plugin.settings.begin] : begin ).toTimeString().substr(0,5),
                   endTime    = (( event[plugin.settings.end] < end ) ? event[plugin.settings.end] : end ).toTimeString().substr(0,5),
                   timeString = beginTime + "-" + endTime,
                   $listItem  = $("

").appendTo($listview);

               plugin.settings.listItemFormatter( $listItem, timeString, summary, event );

               daysEvents.push($listItem);
            }
         }

         $listview.trigger('create').filter(".ui-listview").listview('refresh');
      });

      function listItemFormatter($listItem, timeString, summary, event) {
         var text = ( ( timeString != "00:00-00:00" ) ? timeString : plugin.settings.allDayTimeString ) + " " + summary;
         if (event[plugin.settings.icon]) {
            $listItem.attr('data-icon', event.icon);
         }
         if (event[plugin.settings.url]) {
            $('').text( text ).attr( 'href', event[plugin.settings.url] ).appendTo($listItem);
         } else {
            $listItem.text( text );
         }

      }

      $element.bind('refresh', function(event, date) {
         refresh(date);
      });

      init();
   }

   $.fn.jqmCalendar = function(options) {
      return this.each(function() {
         if (!$(this).data('jqmCalendar')) {
             $(this).data('jqmCalendar', new $.jqmCalendar(this, options));
         }
      });
   }

})(jQuery);
<|endoftext|>


<commit_before>var toString = Object.prototype.toString;
var nodeListType = typeof NodeList !== 'undefined' ? true : false;
var TypedArray = typeof Int8Array !== 'undefined' ? Object.getPrototypeOf(Int8Array) : null;

export default function isArrayLike(obj) {
    if (
        typeof obj === 'string' ||                              // String
        obj instanceof Array ||                                 // Arrays
        (TypedArray && obj instanceof TypedArray) ||            // typed-array
        (nodeListType && obj instanceof NodeList)) {            // NodeList: document.querySelectorAll
        return true;
    }
    else if (obj !== null &&
        typeof obj === 'object' &&
        typeof obj.length === 'number') {                       // Array-likes have 'length' property (excelude 'function' type)

        if (typeof obj.splice === 'function' ||                 // third party libraries. eg. jQuery
            toString.call(obj) === '[object Arguments]') {      // arguments
            return true;
        }
    }

    return false;
}
<commit_msg>simplify implementation<commit_after>var toString = Object.prototype.toString;

export default function isArrayLike(obj) {
    if (obj !== null &&
        typeof obj === 'object' &&
        typeof obj.length === 'number') {                                       // Array-likes have 'length' property

        if (
            (typeof NodeList === 'function' && obj instanceof NodeList) ||      // NodeList: document.querySelectorAll
            typeof obj.splice === 'function' ||                                 // third party libraries. eg. jQuery
            toString.call(obj) === '[object Arguments]') {                      // arguments
            return true;
        }
    }

    return false;
}
<|endoftext|>


<commit_before><commit_msg>update basic example to demonstrate how to use duration<commit_after><|endoftext|>


<commit_before>module.exports = function (config) {
  var configuration = {

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jspm', 'jasmine'],

    jspm: {
      // Edit this to your needs
      loadFiles: ['test/setup.js', 'test/**/*.js'],
      serveFiles: ['src/**/*.js'],
    },

    // list of files / patterns to load in the browser
    files: [],

    // list of files to exclude
    exclude: [],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'test/**/*.js': ['babel'],
      'src/**/*.js': ['babel']
    },
    'babelPreprocessor': {
      options: {
        sourceMap: 'inline',
        presets: [ 'es2015-loose', 'stage-1'],
        plugins: [
          'syntax-flow',
          'transform-decorators-legacy',
          'transform-flow-strip-types'
        ]
      }
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome', 'Firefox', 'ChromeCanary'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false
  };

  if (process.env.TRAVIS) {
    configuration.browsers = ['Firefox'];
  }

  config.set(configuration);
};
<commit_msg>chore(test): consistent file naming and loading<commit_after>module.exports = function(config) {
  var configuration = {

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jspm', 'jasmine'],

    jspm: {
      // Edit this to your needs
      loadFiles: ['test/setup.js', 'test/**/*.spec.js'],
      serveFiles: ['src/**/*.js']
    },

    // list of files / patterns to load in the browser
    files: [],

    // list of files to exclude
    exclude: [],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'test/**/*.js': ['babel'],
      'src/**/*.js': ['babel']
    },
    'babelPreprocessor': {
      options: {
        sourceMap: 'inline',
        presets: [ 'es2015-loose', 'stage-1'],
        plugins: [
          'syntax-flow',
          'transform-decorators-legacy',
          'transform-flow-strip-types'
        ]
      }
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome', 'Firefox', 'ChromeCanary'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false
  };

  if (process.env.TRAVIS) {
    configuration.browsers = ['Firefox'];
  }

  config.set(configuration);
};
<|endoftext|>


<commit_before>module.exports = function(config) {
  const configuration = {
    basePath: '',
    frameworks: ['mocha', 'chai'],
    files: [
      { pattern: 'build/resources/*.wav', included: false, served: true },
      'build/omnitone.min.js',
      'test/test-setup.js',
      'test/*.js'
    ],
    reporters: ['mocha'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['Chrome'],
    customLaunchers: {
      Chrome_travis_ci: {
        base: 'Chrome',
        flags: ['--no-sandbox']
      }
    },
    singleRun: false,
    concurrency: Infinity
  };

  // For Travis CI.
  if (process.env.TRAVIS) {
    configuration.browsers = ['Chrome_travis_ci'];
  }

  config.set(configuration);
};
<commit_msg>Karma test config fixed<commit_after>module.exports = function(config) {
  const configuration = {
    basePath: '',
    frameworks: ['mocha', 'chai'],
    files: [
      { pattern: 'build/resources/*.wav', included: false, served: true },
      'build/omnitone.min.js',
      'test/test-setup.js',
      'test/*.js'
    ],
    reporters: ['mocha'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['Chrome'],
    customLaunchers: {
      Chrome_travis_ci: {
        base: 'Chrome',
        flags: ['--no-sandbox']
      }
    },
    singleRun: true,
    concurrency: Infinity
  };

  // For Travis CI.
  if (process.env.TRAVIS) {
    configuration.browsers = ['Chrome_travis_ci'];
  }

  config.set(configuration);
};
<|endoftext|>