<commit_before>"use strict";

const {strict: assert} = require("assert");

const {mock_cjs, mock_esm, with_field, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery");
const {page_params} = require("../zjsunit/zpage_params");

page_params.stop_words = ["what", "about"];

mock_cjs("jquery", $);
const stream_topic_history = mock_esm("../../static/js/stream_topic_history");

const hash_util = zrequire("hash_util");
const compose_state = zrequire("compose_state");
const narrow_banner = zrequire("narrow_banner");
const narrow_state = zrequire("narrow_state");
const people = zrequire("people");
const stream_data = zrequire("stream_data");
const {Filter} = zrequire("../js/filter");
const narrow = zrequire("narrow");

function set_filter(operators) {
    operators = operators.map((op) => ({
        operator: op[0],
        operand: op[1],
    }));
    narrow_state.set_current_filter(new Filter(operators));
}

const me = {
    email: "me@example.com",
    user_id: 5,
    full_name: "Me Myself",
};

const alice = {
    email: "alice@example.com",
    user_id: 23,
    full_name: "Alice Smith",
};

const ray = {
    email: "ray@example.com",
    user_id: 22,
    full_name: "Raymond",
};

function hide_all_empty_narrow_messages() {
    const all_empty_narrow_messages = [
        ".empty_feed_notice",
        "#empty_narrow_message",
        "#nonsubbed_private_nonexistent_stream_narrow_message",
        "#nonsubbed_stream_narrow_message",
        "#empty_star_narrow_message",
        "#empty_narrow_all_mentioned",
        "#empty_narrow_all_private_message",
        "#no_unread_narrow_message",
        "#non_existing_user",
        "#non_existing_users",
        "#empty_narrow_private_message",
        "#empty_narrow_self_private_message",
        "#empty_narrow_multi_private_message",
        "#empty_narrow_group_private_message",
        "#silent_user",
        "#empty_search_narrow_message",
    ];
    for (const selector of all_empty_narrow_messages) {
        $(selector).hide();
    }
}

run_test("uris", () => {
    people.add_active_user(ray);
    people.add_active_user(alice);
    people.add_active_user(me);
    people.initialize_current_user(me.user_id);

    let uri = hash_util.pm_with_uri(ray.email);
    assert.equal(uri, "#narrow/pm-with/22-ray");

    uri = hash_util.huddle_with_uri("22,23");
    assert.equal(uri, "#narrow/pm-with/22,23-group");

    uri = hash_util.by_sender_uri(ray.email);
    assert.equal(uri, "#narrow/sender/22-ray");

    let emails = hash_util.decode_operand("pm-with", "22,23-group");
    assert.equal(emails, "alice@example.com,ray@example.com");

    emails = hash_util.decode_operand("pm-with", "5,22,23-group");
    assert.equal(emails, "alice@example.com,ray@example.com");

    emails = hash_util.decode_operand("pm-with", "5-group");
    assert.equal(emails, "me@example.com");
});

run_test("show_empty_narrow_message", () => {
    $("#left_bar_compose_reply_button_big").prop("disabled", false);
    narrow_state.reset_current_filter();
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert.equal($(".empty_feed_notice").visible(), false);
    assert($("#empty_narrow_message").visible());
    assert.equal(
        $("#left_bar_compose_reply_button_big").attr("title"),
        "translated: There are no messages to reply to.",
    );
    assert($("#left_bar_compose_reply_button_big").prop("disabled"));

    // for non-existent or private stream
    set_filter([["stream", "Foo"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#nonsubbed_private_nonexistent_stream_narrow_message").visible());

    // for non sub public stream
    stream_data.add_sub({name: "ROME", stream_id: 99});
    stream_data.update_calculated_fields(stream_data.get_sub("ROME"));
    set_filter([["stream", "Rome"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#nonsubbed_stream_narrow_message").visible());

    set_filter([["is", "starred"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_star_narrow_message").visible());

    set_filter([["is", "mentioned"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_all_mentioned").visible());

    set_filter([["is", "private"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_all_private_message").visible());

    set_filter([["is", "unread"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#no_unread_narrow_message").visible());

    set_filter([["pm-with", ["Yo"]]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#non_existing_user").visible());

    people.add_active_user(alice);
    set_filter([["pm-with", ["alice@example.com", "Yo"]]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#non_existing_users").visible());

    set_filter([["pm-with", "alice@example.com"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_private_message").visible());

    set_filter([["group-pm-with", "alice@example.com"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_group_private_message").visible());

    set_filter([["sender", "ray@example.com"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#silent_user").visible());

    set_filter([["sender", "sinwar@example.com"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#non_existing_user").visible());

    const display = $("#empty_search_stop_words_string");

    const items = [];
    display.append = (html) => {
        items.push(html);
    };

    set_filter([["search", "grail"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());

    assert.equal(items.length, 2);
    assert.equal(items[0], " ");
    assert.equal(items[1].text(), "grail");

    set_filter([
        ["sender", "alice@example.com"],
        ["stream", "Rome"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_message").visible());

    set_filter([["is", "invalid"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_message").visible());
});

run_test("hide_empty_narrow_message", () => {
    $(".empty_feed_notice").show();
    narrow_banner.hide_empty_narrow_message();
    assert(!$(".empty_feed_notice").visible());
    assert.equal($("#left_bar_compose_reply_button_big").attr("title"), "translated: Reply (r)");
    assert(!$("#left_bar_compose_reply_button_big").prop("disabled"));
});

run_test("show_search_stopwords", () => {
    narrow_state.reset_current_filter();
    let items = [];

    const display = $("#empty_search_stop_words_string");

    display.append = (html) => {
        if (html.text) {
            items.push(html.selector + html.text());
        }
    };

    set_filter([["search", "what about grail"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());

    assert.equal(items.length, 3);
    assert.equal(items[0], "what");
    assert.equal(items[1], "about");
    assert.equal(items[2], "grail");

    items = [];
    set_filter([
        ["stream", "streamA"],
        ["search", "what about grail"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());

    assert.equal(items.length, 4);
    assert.equal(items[0], "stream: streamA");
    assert.equal(items[1], "what");
    assert.equal(items[2], "about");
    assert.equal(items[3], "grail");

    items = [];
    set_filter([
        ["stream", "streamA"],
        ["topic", "topicA"],
        ["search", "what about grail"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());

    assert.equal(items.length, 4);
    assert.equal(items[0], "stream: streamA topic: topicA");
    assert.equal(items[1], "what");
    assert.equal(items[2], "about");
    assert.equal(items[3], "grail");
});

run_test("show_invalid_narrow_message", () => {
    narrow_state.reset_current_filter();
    const display = $("#empty_search_stop_words_string");

    stream_data.add_sub({name: "streamA", stream_id: 88});
    stream_data.add_sub({name: "streamB", stream_id: 77});

    set_filter([
        ["stream", "streamA"],
        ["stream", "streamB"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());
    assert.equal(
        display.text(),
        "translated: You are searching for messages that belong to more than one stream, which is not possible.",
    );

    set_filter([
        ["topic", "topicA"],
        ["topic", "topicB"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());
    assert.equal(
        display.text(),
        "translated: You are searching for messages that belong to more than one topic, which is not possible.",
    );

    people.add_active_user(ray);
    people.add_active_user(alice);

    set_filter([
        ["sender", "alice@example.com"],
        ["sender", "ray@example.com"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());
    assert.equal(
        display.text(),
        "translated: You are searching for messages that are sent by more than one person, which is not possible.",
    );
});

run_test("narrow_to_compose_target errors", () => {
    function test() {
        with_field(
            narrow,
            "activate",
            () => {
                throw new Error("should not activate!");
            },
            () => {
                narrow.to_compose_target();
            },
        );
    }

    // No-op when not composing.
    compose_state.set_message_type(false);
    test();

    // No-op when empty stream.
    compose_state.set_message_type("stream");
    compose_state.stream_name("");
    test();
});

run_test("narrow_to_compose_target streams", (override) => {
    const args = {called: false};
    override(narrow, "activate", (operators, opts) => {
        args.operators = operators;
        args.opts = opts;
        args.called = true;
    });

    compose_state.set_message_type("stream");
    stream_data.add_sub({name: "ROME", stream_id: 99});
    compose_state.stream_name("ROME");
    override(stream_topic_history, "get_recent_topic_names", () => ["one", "two", "three"]);

    // Test with existing topic
    compose_state.topic("one");
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.equal(args.opts.trigger, "narrow_to_compose_target");
    assert.deepEqual(args.operators, [
        {operator: "stream", operand: "ROME"},
        {operator: "topic", operand: "one"},
    ]);

    // Test with new topic
    compose_state.topic("four");
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "stream", operand: "ROME"}]);

    // Test with blank topic
    compose_state.topic("");
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "stream", operand: "ROME"}]);

    // Test with no topic
    compose_state.topic(undefined);
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "stream", operand: "ROME"}]);
});

run_test("narrow_to_compose_target PMs", (override) => {
    const args = {called: false};
    override(narrow, "activate", (operators, opts) => {
        args.operators = operators;
        args.opts = opts;
        args.called = true;
    });

    let emails;
    override(compose_state, "private_message_recipient", () => emails);

    compose_state.set_message_type("private");
    people.add_active_user(ray);
    people.add_active_user(alice);
    people.add_active_user(me);

    // Test with valid person
    emails = "alice@example.com";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "pm-with", operand: "alice@example.com"}]);

    // Test with valid persons
    emails = "alice@example.com,ray@example.com";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [
        {operator: "pm-with", operand: "alice@example.com,ray@example.com"},
    ]);

    // Test with some invalid persons
    emails = "alice@example.com,random,ray@example.com";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "is", operand: "private"}]);

    // Test with all invalid persons
    emails = "alice,random,ray";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "is", operand: "private"}]);

    // Test with no persons
    emails = "";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "is", operand: "private"}]);
});
<commit_msg>narrow_banner: Add test for empty stream operand, empty narrow msg.<commit_after>"use strict";

const {strict: assert} = require("assert");

const {mock_cjs, mock_esm, with_field, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery");
const {page_params} = require("../zjsunit/zpage_params");

page_params.stop_words = ["what", "about"];

mock_cjs("jquery", $);
const stream_topic_history = mock_esm("../../static/js/stream_topic_history");

const hash_util = zrequire("hash_util");
const compose_state = zrequire("compose_state");
const narrow_banner = zrequire("narrow_banner");
const narrow_state = zrequire("narrow_state");
const people = zrequire("people");
const stream_data = zrequire("stream_data");
const {Filter} = zrequire("../js/filter");
const narrow = zrequire("narrow");

function set_filter(operators) {
    operators = operators.map((op) => ({
        operator: op[0],
        operand: op[1],
    }));
    narrow_state.set_current_filter(new Filter(operators));
}

const me = {
    email: "me@example.com",
    user_id: 5,
    full_name: "Me Myself",
};

const alice = {
    email: "alice@example.com",
    user_id: 23,
    full_name: "Alice Smith",
};

const ray = {
    email: "ray@example.com",
    user_id: 22,
    full_name: "Raymond",
};

function hide_all_empty_narrow_messages() {
    const all_empty_narrow_messages = [
        ".empty_feed_notice",
        "#empty_narrow_message",
        "#nonsubbed_private_nonexistent_stream_narrow_message",
        "#nonsubbed_stream_narrow_message",
        "#empty_star_narrow_message",
        "#empty_narrow_all_mentioned",
        "#empty_narrow_all_private_message",
        "#no_unread_narrow_message",
        "#non_existing_user",
        "#non_existing_users",
        "#empty_narrow_private_message",
        "#empty_narrow_self_private_message",
        "#empty_narrow_multi_private_message",
        "#empty_narrow_group_private_message",
        "#silent_user",
        "#empty_search_narrow_message",
    ];
    for (const selector of all_empty_narrow_messages) {
        $(selector).hide();
    }
}

run_test("uris", () => {
    people.add_active_user(ray);
    people.add_active_user(alice);
    people.add_active_user(me);
    people.initialize_current_user(me.user_id);

    let uri = hash_util.pm_with_uri(ray.email);
    assert.equal(uri, "#narrow/pm-with/22-ray");

    uri = hash_util.huddle_with_uri("22,23");
    assert.equal(uri, "#narrow/pm-with/22,23-group");

    uri = hash_util.by_sender_uri(ray.email);
    assert.equal(uri, "#narrow/sender/22-ray");

    let emails = hash_util.decode_operand("pm-with", "22,23-group");
    assert.equal(emails, "alice@example.com,ray@example.com");

    emails = hash_util.decode_operand("pm-with", "5,22,23-group");
    assert.equal(emails, "alice@example.com,ray@example.com");

    emails = hash_util.decode_operand("pm-with", "5-group");
    assert.equal(emails, "me@example.com");
});

run_test("show_empty_narrow_message", () => {
    $("#left_bar_compose_reply_button_big").prop("disabled", false);
    narrow_state.reset_current_filter();
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert.equal($(".empty_feed_notice").visible(), false);
    assert($("#empty_narrow_message").visible());
    assert.equal(
        $("#left_bar_compose_reply_button_big").attr("title"),
        "translated: There are no messages to reply to.",
    );
    assert($("#left_bar_compose_reply_button_big").prop("disabled"));

    // for non-existent or private stream
    set_filter([["stream", "Foo"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#nonsubbed_private_nonexistent_stream_narrow_message").visible());

    // for non sub public stream
    stream_data.add_sub({name: "ROME", stream_id: 99});
    stream_data.update_calculated_fields(stream_data.get_sub("ROME"));
    set_filter([["stream", "Rome"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#nonsubbed_stream_narrow_message").visible());

    set_filter([["is", "starred"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_star_narrow_message").visible());

    set_filter([["is", "mentioned"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_all_mentioned").visible());

    set_filter([["is", "private"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_all_private_message").visible());

    set_filter([["is", "unread"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#no_unread_narrow_message").visible());

    set_filter([["pm-with", ["Yo"]]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#non_existing_user").visible());

    people.add_active_user(alice);
    set_filter([["pm-with", ["alice@example.com", "Yo"]]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#non_existing_users").visible());

    set_filter([["pm-with", "alice@example.com"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_private_message").visible());

    set_filter([["group-pm-with", "alice@example.com"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_group_private_message").visible());

    set_filter([["sender", "ray@example.com"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#silent_user").visible());

    set_filter([["sender", "sinwar@example.com"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#non_existing_user").visible());

    const display = $("#empty_search_stop_words_string");

    const items = [];
    display.append = (html) => {
        items.push(html);
    };

    set_filter([["search", "grail"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());

    assert.equal(items.length, 2);
    assert.equal(items[0], " ");
    assert.equal(items[1].text(), "grail");

    set_filter([
        ["sender", "alice@example.com"],
        ["stream", "Rome"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_message").visible());

    set_filter([["is", "invalid"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_narrow_message").visible());

    set_filter([["stream", ""]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#nonsubbed_private_nonexistent_stream_narrow_message").visible());
});

run_test("hide_empty_narrow_message", () => {
    $(".empty_feed_notice").show();
    narrow_banner.hide_empty_narrow_message();
    assert(!$(".empty_feed_notice").visible());
    assert.equal($("#left_bar_compose_reply_button_big").attr("title"), "translated: Reply (r)");
    assert(!$("#left_bar_compose_reply_button_big").prop("disabled"));
});

run_test("show_search_stopwords", () => {
    narrow_state.reset_current_filter();
    let items = [];

    const display = $("#empty_search_stop_words_string");

    display.append = (html) => {
        if (html.text) {
            items.push(html.selector + html.text());
        }
    };

    set_filter([["search", "what about grail"]]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());

    assert.equal(items.length, 3);
    assert.equal(items[0], "what");
    assert.equal(items[1], "about");
    assert.equal(items[2], "grail");

    items = [];
    set_filter([
        ["stream", "streamA"],
        ["search", "what about grail"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());

    assert.equal(items.length, 4);
    assert.equal(items[0], "stream: streamA");
    assert.equal(items[1], "what");
    assert.equal(items[2], "about");
    assert.equal(items[3], "grail");

    items = [];
    set_filter([
        ["stream", "streamA"],
        ["topic", "topicA"],
        ["search", "what about grail"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());

    assert.equal(items.length, 4);
    assert.equal(items[0], "stream: streamA topic: topicA");
    assert.equal(items[1], "what");
    assert.equal(items[2], "about");
    assert.equal(items[3], "grail");
});

run_test("show_invalid_narrow_message", () => {
    narrow_state.reset_current_filter();
    const display = $("#empty_search_stop_words_string");

    stream_data.add_sub({name: "streamA", stream_id: 88});
    stream_data.add_sub({name: "streamB", stream_id: 77});

    set_filter([
        ["stream", "streamA"],
        ["stream", "streamB"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());
    assert.equal(
        display.text(),
        "translated: You are searching for messages that belong to more than one stream, which is not possible.",
    );

    set_filter([
        ["topic", "topicA"],
        ["topic", "topicB"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());
    assert.equal(
        display.text(),
        "translated: You are searching for messages that belong to more than one topic, which is not possible.",
    );

    people.add_active_user(ray);
    people.add_active_user(alice);

    set_filter([
        ["sender", "alice@example.com"],
        ["sender", "ray@example.com"],
    ]);
    hide_all_empty_narrow_messages();
    narrow_banner.show_empty_narrow_message();
    assert($("#empty_search_narrow_message").visible());
    assert.equal(
        display.text(),
        "translated: You are searching for messages that are sent by more than one person, which is not possible.",
    );
});

run_test("narrow_to_compose_target errors", () => {
    function test() {
        with_field(
            narrow,
            "activate",
            () => {
                throw new Error("should not activate!");
            },
            () => {
                narrow.to_compose_target();
            },
        );
    }

    // No-op when not composing.
    compose_state.set_message_type(false);
    test();

    // No-op when empty stream.
    compose_state.set_message_type("stream");
    compose_state.stream_name("");
    test();
});

run_test("narrow_to_compose_target streams", (override) => {
    const args = {called: false};
    override(narrow, "activate", (operators, opts) => {
        args.operators = operators;
        args.opts = opts;
        args.called = true;
    });

    compose_state.set_message_type("stream");
    stream_data.add_sub({name: "ROME", stream_id: 99});
    compose_state.stream_name("ROME");
    override(stream_topic_history, "get_recent_topic_names", () => ["one", "two", "three"]);

    // Test with existing topic
    compose_state.topic("one");
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.equal(args.opts.trigger, "narrow_to_compose_target");
    assert.deepEqual(args.operators, [
        {operator: "stream", operand: "ROME"},
        {operator: "topic", operand: "one"},
    ]);

    // Test with new topic
    compose_state.topic("four");
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "stream", operand: "ROME"}]);

    // Test with blank topic
    compose_state.topic("");
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "stream", operand: "ROME"}]);

    // Test with no topic
    compose_state.topic(undefined);
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "stream", operand: "ROME"}]);
});

run_test("narrow_to_compose_target PMs", (override) => {
    const args = {called: false};
    override(narrow, "activate", (operators, opts) => {
        args.operators = operators;
        args.opts = opts;
        args.called = true;
    });

    let emails;
    override(compose_state, "private_message_recipient", () => emails);

    compose_state.set_message_type("private");
    people.add_active_user(ray);
    people.add_active_user(alice);
    people.add_active_user(me);

    // Test with valid person
    emails = "alice@example.com";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "pm-with", operand: "alice@example.com"}]);

    // Test with valid persons
    emails = "alice@example.com,ray@example.com";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [
        {operator: "pm-with", operand: "alice@example.com,ray@example.com"},
    ]);

    // Test with some invalid persons
    emails = "alice@example.com,random,ray@example.com";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "is", operand: "private"}]);

    // Test with all invalid persons
    emails = "alice,random,ray";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "is", operand: "private"}]);

    // Test with no persons
    emails = "";
    args.called = false;
    narrow.to_compose_target();
    assert.equal(args.called, true);
    assert.deepEqual(args.operators, [{operator: "is", operand: "private"}]);
});
<|endoftext|>


<commit_before><commit_msg>cleaning up state on mouse out<commit_after><|endoftext|>


<commit_before>var NAME = "Crazy Penguins";
module.exports = {

  VERSION: "0.0.1",

  bet_request: function (game_state, bet) {
    //var player = game_state.players[]
    bet(game_state.minimum_raise);
  },

  showdown: function (game_state) {

  }
};
<commit_msg>add logic for min bet in round<commit_after>var NAME = "Crazy Penguins";
module.exports = {

  VERSION: "0.0.1",

  bet_request: function (game_state, bet) {
    //var player = game_state.players[]
    var maxbet = game_state.players.reduce(function (p, n) { return n.bet > p ? n.bet : p }, 0);
    bet(maxbet + game_state.minimum_raise);
  },

  showdown: function (game_state) {

  }
};
<|endoftext|>


<commit_before>var gulp = require('gulp'),
    gutil = require('gulp-util'),
    jscs = require('gulp-jscs'),
    jshint = require('gulp-jshint'),
    cached = require('gulp-cached'),
    coverage = require('gulp-jsx-coverage'),
    fs = require('fs'),
    React = require('react-tools'),
    through = require('through2'),
    buffer = require('vinyl-buffer'),
    source = require('vinyl-source-stream'),
    aliasify = require('aliasify'),
    browserify = require('browserify'),
    uglify = require('gulp-uglify'),
    nodemon = require('nodemon'),
    browserSync = require('browser-sync'),
    serverStarted = false,

// If you use vim and watch tasks be triggered 2 times when saving
// You can :set nowritebackup in vim to prevent this
// Reference: https://github.com/joyent/node/issues/3172
configs = {
    static_dir: 'static/',
    mainjs: require(process.cwd() + '/package.json').main,
    appjs: process.cwd() + '/fluxexapp.js',
    nodemon_restart_delay: 200,
    nodemon_delay: 2000,
    gulp_watch: {debounceDelay: 500},
    watchify: {debug: true, delay: 500},
    jshint_jsx: {quotmark: false},
    jslint_fail: false,
    jscs_fail: false,
    aliasify: {
        aliases: {
            request: 'browser-request'
        }
    },
    test_coverage: {
        default: {
            src: ['test/**/*.js', 'test/components/*.js*'],
            istanbul: {
                coverageVariable: '__FLUXEX_COVERAGE__',
                exclude: /node_modules\/|test\//
            },
            coverage: {
                directory: 'coverage'
            },
            mocha: {},
            react: {
                sourceMap: true
            },
            coffee: {
                sourceMap: true
            }
        },
        console: {
            coverage: {
                reporters: ['text-summary']
            },
            mocha: {
                reporter: 'spec'
            }
        },
        report: {
            coverage: {
                reporters: ['lcov', 'json']
            },
            mocha: {
                reporter: 'tap'
            }
        }
    }
},

build_files = {
    js: ['actions/*.js', 'stores/*.js'],
    jsx: ['components/*.jsx']
},

restart_nodemon = function () {
    setTimeout(function () {
        nodemon.emit('restart');
    }, configs.nodemon_restart_delay);
},

lint_chain = function (task) {
    task = task.pipe(jshint.reporter('jshint-stylish'));

    if (configs.github) {
        task = task.pipe(require('gulp-github')(configs.github));
    }

    if (configs.jslint_fail) {
        task = task.pipe(jshint.reporter('fail'));
    }

    return task;
},

// Stop using gulp-react because it do not keep original file name
react_compiler = function (options) {
    return through.obj(function (file, enc, callback) {
        try {
            file.contents = new Buffer(React.transform(file.contents.toString(), options));
            this.push(file);
        } catch (E) {
            gutil.log('[jsx ERROR]', gutil.colors.red(file.path));
            gutil.log('[jsx ERROR]', gutil.colors.red(E.message));
        }
        callback();
    });
},

// Do testing tasks
get_testing_task = function (options) {
    var cfg = JSON.parse(JSON.stringify(configs.test_coverage.default));

    cfg.istanbul.exclude = configs.test_coverage.default.istanbul.exclude;
    cfg.coverage.reporters = options.coverage.reporters;
    cfg.mocha = options.mocha;

    return coverage.createTask(cfg);
},

handleJSCSError = function (E) {
    if (!configs.jscs_fail) {
        return;
    }

    if ('function' === typeof configs.jscs_fail) {
        return configs.jscs_fail(E);
    }

    this.emit('error', E);
},

bundleAll = function (b, noSave) {
    var B = b.bundle()
    .on('error', function (E) {
        gutil.log('[browserify ERROR]', gutil.colors.red(E));
    });

    if (!noSave) {
        B.pipe(source('main.js'))
        .pipe(gulp.dest(configs.static_dir + 'js/'))
        .on('end', restart_nodemon);
    }

    return B;
},

buildApp = function (watch, fullpath, nosave, disc) {
    var b = browserify(configs.appjs, {
        cache: {},
        packageCache: {},
        require: (disc ? process.cwd() : '.') + '/components/Html.jsx',
        standalone: 'Fluxex',
        fullPaths: fullpath ? true: false,
        debug: watch
    });

    b.transform('reactify');
    b.transform(aliasify.configure(configs.aliasify), {global: true});

    if (watch) {
        b = require('watchify')(b, configs.watchify);
        b.on('update', function (F) {
            gutil.log('[browserify] ' + F[0] + ' updated');
            bundleAll(b);
        });
    }

    return bundleAll(b, nosave);
};

gulp.task('build_app', function () {
    return buildApp(false, false, true)
        .pipe(source('main.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest(configs.static_dir + 'js/'));
});

gulp.task('disc_app', function () {
    return buildApp(false, true, true, true)
        .pipe(require('disc')())
        .pipe(fs.createWriteStream(configs.static_dir + 'disc.html'));
});

gulp.task('watch_app', function () {
    return buildApp(true, true);
});

gulp.task('watch_flux_js', ['lint_flux_js'], function () {
    gulp.watch(build_files.js, configs.gulp_watch, ['lint_flux_js']);
});

gulp.task('lint_flux_js', function () {
    return lint_chain(
        gulp.src(build_files.js)
        .pipe(cached('jshint'))
        .pipe(jscs()).on('error', handleJSCSError)
        .pipe(jshint())
    );
});

gulp.task('watch_jsx', ['lint_jsx'], function () {
    gulp.watch(build_files.jsx, configs.gulp_watch, ['lint_jsx']);
});

gulp.task('lint_jsx', function () {
    return lint_chain(
        gulp.src(build_files.jsx)
        .pipe(cached('jshint'))
        .pipe(react_compiler({sourceMap: true}))
        .pipe(jscs()).on('error', handleJSCSError)
        .pipe(jshint(configs.jshint_jsx))
    );
});

gulp.task('watch_server', ['lint_server'], function () {
    gulp.watch(configs.mainjs, configs.gulp_watch, ['lint_server'])
    .on('change', function () {
        nodemon.emit('restart');
    });
});

gulp.task('lint_server', function () {
    return gulp.src(configs.mainjs)
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('nodemon_server', ['watch_flux_js', 'watch_jsx', 'watch_app', 'watch_server'], function () {
    nodemon({
        ignore: '*',
        script: configs.mainjs,
        ext: 'do_not_watch'
    })
    .on('log', function (log) {
        gutil.log(log.colour);
    })
    .on('start', function () {
        if (serverStarted) {
            setTimeout(browserSync.reload, configs.nodemon_delay);
        } else {
            browserSync.init(null, {
                proxy: 'http://localhost:3000',
                files: [configs.static_dir + 'css/*.css'],
                port: 3001,
                online: false,
                open: false
            });

            serverStarted = true;
        }
    });
});

gulp.task('test_app', get_testing_task(configs.test_coverage.console));
gulp.task('save_test_app', get_testing_task(configs.test_coverage.report));
gulp.task('develop', ['nodemon_server']);
gulp.task('lint_all', ['lint_server', 'lint_flux_js', 'lint_jsx']);
gulp.task('buildall', ['lint_all', 'build_app']);
gulp.task('default',['buildall']);

module.exports = configs;
<commit_msg>rename jslint_fail to jshint_fail<commit_after>var gulp = require('gulp'),
    gutil = require('gulp-util'),
    jscs = require('gulp-jscs'),
    jshint = require('gulp-jshint'),
    cached = require('gulp-cached'),
    coverage = require('gulp-jsx-coverage'),
    fs = require('fs'),
    React = require('react-tools'),
    through = require('through2'),
    buffer = require('vinyl-buffer'),
    source = require('vinyl-source-stream'),
    aliasify = require('aliasify'),
    browserify = require('browserify'),
    uglify = require('gulp-uglify'),
    nodemon = require('nodemon'),
    browserSync = require('browser-sync'),
    serverStarted = false,

// If you use vim and watch tasks be triggered 2 times when saving
// You can :set nowritebackup in vim to prevent this
// Reference: https://github.com/joyent/node/issues/3172
configs = {
    static_dir: 'static/',
    mainjs: require(process.cwd() + '/package.json').main,
    appjs: process.cwd() + '/fluxexapp.js',
    nodemon_restart_delay: 200,
    nodemon_delay: 2000,
    gulp_watch: {debounceDelay: 500},
    watchify: {debug: true, delay: 500},
    jshint_jsx: {quotmark: false},
    jshint_fail: false,
    jscs_fail: false,
    aliasify: {
        aliases: {
            request: 'browser-request'
        }
    },
    test_coverage: {
        default: {
            src: ['test/**/*.js', 'test/components/*.js*'],
            istanbul: {
                coverageVariable: '__FLUXEX_COVERAGE__',
                exclude: /node_modules\/|test\//
            },
            coverage: {
                directory: 'coverage'
            },
            mocha: {},
            react: {
                sourceMap: true
            },
            coffee: {
                sourceMap: true
            }
        },
        console: {
            coverage: {
                reporters: ['text-summary']
            },
            mocha: {
                reporter: 'spec'
            }
        },
        report: {
            coverage: {
                reporters: ['lcov', 'json']
            },
            mocha: {
                reporter: 'tap'
            }
        }
    }
},

build_files = {
    js: ['actions/*.js', 'stores/*.js'],
    jsx: ['components/*.jsx']
},

restart_nodemon = function () {
    setTimeout(function () {
        nodemon.emit('restart');
    }, configs.nodemon_restart_delay);
},

lint_chain = function (task) {
    task = task.pipe(jshint.reporter('jshint-stylish'));

    if (configs.github) {
        task = task.pipe(require('gulp-github')(configs.github));
    }

    if (configs.jshint_fail) {
        task = task.pipe(('function' === typeof configs.jshint_fail) ? configs.jshint_fail : jshint.reporter('fail'));
    }

    return task;
},

// Stop using gulp-react because it do not keep original file name
react_compiler = function (options) {
    return through.obj(function (file, enc, callback) {
        try {
            file.contents = new Buffer(React.transform(file.contents.toString(), options));
            this.push(file);
        } catch (E) {
            gutil.log('[jsx ERROR]', gutil.colors.red(file.path));
            gutil.log('[jsx ERROR]', gutil.colors.red(E.message));
        }
        callback();
    });
},

// Do testing tasks
get_testing_task = function (options) {
    var cfg = JSON.parse(JSON.stringify(configs.test_coverage.default));

    cfg.istanbul.exclude = configs.test_coverage.default.istanbul.exclude;
    cfg.coverage.reporters = options.coverage.reporters;
    cfg.mocha = options.mocha;

    return coverage.createTask(cfg);
},

handleJSCSError = function (E) {
    if (!configs.jscs_fail) {
        return;
    }

    if ('function' === typeof configs.jscs_fail) {
        return configs.jscs_fail(E);
    }

    this.emit('error', E);
},

bundleAll = function (b, noSave) {
    var B = b.bundle()
    .on('error', function (E) {
        gutil.log('[browserify ERROR]', gutil.colors.red(E));
    });

    if (!noSave) {
        B.pipe(source('main.js'))
        .pipe(gulp.dest(configs.static_dir + 'js/'))
        .on('end', restart_nodemon);
    }

    return B;
},

buildApp = function (watch, fullpath, nosave, disc) {
    var b = browserify(configs.appjs, {
        cache: {},
        packageCache: {},
        require: (disc ? process.cwd() : '.') + '/components/Html.jsx',
        standalone: 'Fluxex',
        fullPaths: fullpath ? true: false,
        debug: watch
    });

    b.transform('reactify');
    b.transform(aliasify.configure(configs.aliasify), {global: true});

    if (watch) {
        b = require('watchify')(b, configs.watchify);
        b.on('update', function (F) {
            gutil.log('[browserify] ' + F[0] + ' updated');
            bundleAll(b);
        });
    }

    return bundleAll(b, nosave);
};

gulp.task('build_app', function () {
    return buildApp(false, false, true)
        .pipe(source('main.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest(configs.static_dir + 'js/'));
});

gulp.task('disc_app', function () {
    return buildApp(false, true, true, true)
        .pipe(require('disc')())
        .pipe(fs.createWriteStream(configs.static_dir + 'disc.html'));
});

gulp.task('watch_app', function () {
    return buildApp(true, true);
});

gulp.task('watch_flux_js', ['lint_flux_js'], function () {
    gulp.watch(build_files.js, configs.gulp_watch, ['lint_flux_js']);
});

gulp.task('lint_flux_js', function () {
    return lint_chain(
        gulp.src(build_files.js)
        .pipe(cached('jshint'))
        .pipe(jscs()).on('error', handleJSCSError)
        .pipe(jshint())
    );
});

gulp.task('watch_jsx', ['lint_jsx'], function () {
    gulp.watch(build_files.jsx, configs.gulp_watch, ['lint_jsx']);
});

gulp.task('lint_jsx', function () {
    return lint_chain(
        gulp.src(build_files.jsx)
        .pipe(cached('jshint'))
        .pipe(react_compiler({sourceMap: true}))
        .pipe(jscs()).on('error', handleJSCSError)
        .pipe(jshint(configs.jshint_jsx))
    );
});

gulp.task('watch_server', ['lint_server'], function () {
    gulp.watch(configs.mainjs, configs.gulp_watch, ['lint_server'])
    .on('change', function () {
        nodemon.emit('restart');
    });
});

gulp.task('lint_server', function () {
    return gulp.src(configs.mainjs)
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('nodemon_server', ['watch_flux_js', 'watch_jsx', 'watch_app', 'watch_server'], function () {
    nodemon({
        ignore: '*',
        script: configs.mainjs,
        ext: 'do_not_watch'
    })
    .on('log', function (log) {
        gutil.log(log.colour);
    })
    .on('start', function () {
        if (serverStarted) {
            setTimeout(browserSync.reload, configs.nodemon_delay);
        } else {
            browserSync.init(null, {
                proxy: 'http://localhost:3000',
                files: [configs.static_dir + 'css/*.css'],
                port: 3001,
                online: false,
                open: false
            });

            serverStarted = true;
        }
    });
});

gulp.task('test_app', get_testing_task(configs.test_coverage.console));
gulp.task('save_test_app', get_testing_task(configs.test_coverage.report));
gulp.task('develop', ['nodemon_server']);
gulp.task('lint_all', ['lint_server', 'lint_flux_js', 'lint_jsx']);
gulp.task('buildall', ['lint_all', 'build_app']);
gulp.task('default',['buildall']);

module.exports = configs;
<|endoftext|>


<commit_before>$(function() {
    var gifLab = new GifLab();

    // init modules
    new GifLabMenu(gifLab);
    new GifLabControls(gifLab);

    // auto-load image in parameters
    var url = document.URL;
    var urlFragIndex = url.indexOf('#');
    if (urlFragIndex !== -1) {
        var gifUrl = url.substring(urlFragIndex + 1);
        gifLab.loadGifUrl(gifUrl);
    }
});

function GifLab() {

    var domViewport = $('#viewport');
    domViewport.hide();

    //Handles menu drop down
    $('.form-menu').click(function (e) {
        e.stopPropagation();
    });

    var player = null;

    return {
        events: new Events(),
        loadGifData: function(data) {
            if (player) {
                player.stop();
                player.clear();
                player = null;
            }

            domViewport.show();

            player = new GifPlayer(domViewport[0]);
            this.events.emit('initPlayer', player);
            player.load(data);
        },
        loadGifFile: function(file) {
            var loader = new GifLoader();
            loader.loadFile(file, function (data) {
                this.loadGifData(data);
            }.bind(this));
        },
        loadGifBuffer: function(buffer) {
            var loader = new GifLoader();
            loader.loadBuffer(buffer, function (data) {
                this.loadGifData(data);
            }.bind(this));
        },
        loadGifUrl: function(url) {
            var domImg = $('<img>');
            domImg.attr('src', url);
            domImg.on('load', function() {
                // Note: jQuery's .ajax() doesn't really support binary files, so
                // use a XHR level 2 object directly instead
                try {
                    var xhr = new XMLHttpRequest();
                    xhr.open('GET', url, true);
                    xhr.responseType = 'arraybuffer';

                    xhr.addEventListener("load", function (evt) {
                        this.loadGifBuffer(xhr.response);
                    }.bind(this), false);

                    xhr.send();
                } catch (err) {
                    console.error(err);
                }
            }.bind(this));
        }
    };
}

function GifLabMenu(gifLab) {

    var domToolbarMenu = $('#toolbar-menu');
    var domFileLink = domToolbarMenu.find('.file-link');
    var domCheckboxRenderRaw = domToolbarMenu.find('#checkbox-render-raw');
    var domFileInput = $('<input type="file">');

    domFileInput.on('change', function(event) {
        var file = event.target.files[0];
        if (!file) {
            return;
        }

        gifLab.loadGif(file);
    });

    domFileLink.on('click', function(event) {
        domFileInput.trigger('click');
    });

    var domModal = $('#modal-url');
    var domButtonUrl = domModal.find('#button-url');
    var domInputUrl = domModal.find('#input-url');

    domButtonUrl.on('click', function() {
        gifLab.loadGifUrl(domInputUrl.val());
    });

    gifLab.events.on('initPlayer', function(gifPlayer) {
        domCheckboxRenderRaw.off();
        domCheckboxRenderRaw.on('change', function(event) {
            if (gifPlayer.isReady()) {
                gifPlayer.setRenderRaw(event.target.checked);
            }
        });

        gifPlayer.events.on('ready', function() {
            gifPlayer.setRenderRaw(domCheckboxRenderRaw.prop('checked'));
        });
    });
}

function GifLabControls(gifLab) {

    var domControls = $('#toolbar-controls');
    var domButtons = domControls.find('button[data-command]');

    var domIconPlay = domButtons.find('.icon-play');
    var domIconPause = domButtons.find('.icon-pause');

    var domSliderContainer = domControls.find('.slider-container');
    var domSlider = domSliderContainer.find('.slider');

    var domSliderValueContainer = domControls.find('.slider-value-container');
    var domSliderValue = domSliderValueContainer.find('.slider-value');

    function updateIcon(playing) {
        if (playing) {
            domIconPlay.hide();
            domIconPause.show();
        } else {
            domIconPlay.show();
            domIconPause.hide();
        }
    }

    function updateTooltip(frameIndex) {
        domSliderValue.html(frameIndex);
    }

    // hide controls on default
    domControls.hide();

    // start in "paused" state
    updateIcon(false);

    gifLab.events.on('initPlayer', function(gifPlayer) {

        updateIcon(false);

        // player events
        gifPlayer.events.on('play', function() {
            updateIcon(true);
        });

        gifPlayer.events.on('pause', function() {
            updateIcon(false);
        });

        gifPlayer.events.on('update', function(frameIndex, frameIndexPrev) {
            domSlider.val(frameIndex);
            updateTooltip(frameIndex);
        });

        gifPlayer.events.on('ready', function() {
            var frameCount = gifPlayer.getFrameCount();

            if (frameCount > 1) {
                domControls.fadeIn();
                gifPlayer.play();
            } else {
                domControls.fadeOut();
            }

            // update slider range and value
            domSlider.prop('min', 0);
            domSlider.prop('max', frameCount - 1);
            domSlider.val(0);

            updateTooltip(0);
        });

        // DOM events
        domButtons.off();
        domButtons.on('click', function(event) {
            var cmd = event.target.dataset.command;

            // pause playback when pressing one of the frame control buttons
            if (cmd !== 'toggle') {
                gifPlayer.pause();
            }

            // run function based on the button ID name
            gifPlayer[cmd] && gifPlayer[cmd]();
        });

        domSlider.off();
        domSlider.on('input', function(event) {
            gifPlayer.pause();
            gifPlayer.setFrameIndex(parseInt(event.target.value));
            updateTooltip(event.target.value);
        });
    });
}<commit_msg>Some XHR improvements<commit_after>$(function() {
    var gifLab = new GifLab();

    // init modules
    new GifLabMenu(gifLab);
    new GifLabControls(gifLab);

    // auto-load image in parameters
    var url = document.URL;
    var urlFragIndex = url.indexOf('#');
    if (urlFragIndex !== -1) {
        var gifUrl = url.substring(urlFragIndex + 1);
        gifLab.loadGifUrl(gifUrl);
    }
});

function GifLab() {

    var domViewport = $('#viewport');
    domViewport.hide();

    //Handles menu drop down
    $('.form-menu').click(function (e) {
        e.stopPropagation();
    });

    var player = null;

    return {
        events: new Events(),
        loadGifData: function(data) {
            if (player) {
                player.stop();
                player.clear();
                player = null;
            }

            domViewport.show();

            player = new GifPlayer(domViewport[0]);
            this.events.emit('initPlayer', player);
            player.load(data);
        },
        loadGifFile: function(file) {
            var loader = new GifLoader();
            loader.loadFile(file, function (data) {
                this.loadGifData(data);
            }.bind(this));
        },
        loadGifBuffer: function(buffer) {
            var loader = new GifLoader();
            loader.loadBuffer(buffer, function (data) {
                this.loadGifData(data);
            }.bind(this));
        },
        loadGifUrl: function(url) {
            // many sites don't provide a wildcard ACAO header, so use a CORS proxy
            //url = 'https://cors-anywhere.herokuapp.com/' + url;

            // Note: jQuery's .ajax() doesn't support binary files well, therefore
            // a direct XHR level 2 object is used instead
            var xhr = new XMLHttpRequest();

            xhr.onload = function (evt) {
                if (xhr.status === 200) {
                    this.loadGifBuffer(xhr.response);
                } else {
                    // handle error
                }
            }.bind(this);

            xhr.onerror = function(evt) {
                console.error(evt);
            };

            xhr.open('GET', url, true);
            xhr.responseType = 'arraybuffer';
            xhr.send();
        }
    };
}

function GifLabMenu(gifLab) {

    var domToolbarMenu = $('#toolbar-menu');
    var domFileLink = domToolbarMenu.find('.file-link');
    var domCheckboxRenderRaw = domToolbarMenu.find('#checkbox-render-raw');
    var domFileInput = $('<input type="file">');

    domFileInput.on('change', function(event) {
        var file = event.target.files[0];
        if (!file) {
            return;
        }

        gifLab.loadGifFile(file);
    });

    domFileLink.on('click', function(event) {
        domFileInput.trigger('click');
    });

    var domModal = $('#modal-url');
    var domButtonUrl = domModal.find('#button-url');
    var domInputUrl = domModal.find('#input-url');

    domButtonUrl.on('click', function() {
        gifLab.loadGifUrl(domInputUrl.val());
    });

    gifLab.events.on('initPlayer', function(gifPlayer) {
        domCheckboxRenderRaw.off();
        domCheckboxRenderRaw.on('change', function(event) {
            if (gifPlayer.isReady()) {
                gifPlayer.setRenderRaw(event.target.checked);
            }
        });

        gifPlayer.events.on('ready', function() {
            gifPlayer.setRenderRaw(domCheckboxRenderRaw.prop('checked'));
        });
    });
}

function GifLabControls(gifLab) {

    var domControls = $('#toolbar-controls');
    var domButtons = domControls.find('button[data-command]');

    var domIconPlay = domButtons.find('.icon-play');
    var domIconPause = domButtons.find('.icon-pause');

    var domSliderContainer = domControls.find('.slider-container');
    var domSlider = domSliderContainer.find('.slider');

    var domSliderValueContainer = domControls.find('.slider-value-container');
    var domSliderValue = domSliderValueContainer.find('.slider-value');

    function updateIcon(playing) {
        if (playing) {
            domIconPlay.hide();
            domIconPause.show();
        } else {
            domIconPlay.show();
            domIconPause.hide();
        }
    }

    function updateTooltip(frameIndex) {
        domSliderValue.html(frameIndex);
    }

    // hide controls on default
    domControls.hide();

    // start in "paused" state
    updateIcon(false);

    gifLab.events.on('initPlayer', function(gifPlayer) {

        updateIcon(false);

        // player events
        gifPlayer.events.on('play', function() {
            updateIcon(true);
        });

        gifPlayer.events.on('pause', function() {
            updateIcon(false);
        });

        gifPlayer.events.on('update', function(frameIndex, frameIndexPrev) {
            domSlider.val(frameIndex);
            updateTooltip(frameIndex);
        });

        gifPlayer.events.on('ready', function() {
            var frameCount = gifPlayer.getFrameCount();

            if (frameCount > 1) {
                domControls.fadeIn();
                gifPlayer.play();
            } else {
                domControls.fadeOut();
            }

            // update slider range and value
            domSlider.prop('min', 0);
            domSlider.prop('max', frameCount - 1);
            domSlider.val(0);

            updateTooltip(0);
        });

        // DOM events
        domButtons.off();
        domButtons.on('click', function(event) {
            var cmd = event.target.dataset.command;

            // pause playback when pressing one of the frame control buttons
            if (cmd !== 'toggle') {
                gifPlayer.pause();
            }

            // run function based on the button ID name
            gifPlayer[cmd] && gifPlayer[cmd]();
        });

        domSlider.off();
        domSlider.on('input', function(event) {
            gifPlayer.pause();
            gifPlayer.setFrameIndex(parseInt(event.target.value));
            updateTooltip(event.target.value);
        });
    });
}<|endoftext|>


<commit_before> import firebaseModule from 'firebase-config';
 let db = (function() {
     var itemsHomes = [{
             'url': 'https://static.pexels.com/photos/106399/pexels-photo-106399.jpeg',
             'head': 'Sale hose',
             'price': '12345 $',
             'subheading': '2 bed end terrace house for sale',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 0.8 miles to Maidenhead town centre and mainline railway station (Future Crossrail).',
             id: 1
         },
         {
             'url': 'https://static.pexels.com/photos/261187/pexels-photo-261187.jpeg',
             'head': 'Sale beauty mouse',
             'price': '5435 $',
             'subheading': '2 bed end terrace house for sale',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 0.8 miles to Maidenhead town centre and mainline railway station (Future Crossrail).',
             'id': 2
         },
         {
             'url': 'https://static.pexels.com/photos/259597/pexels-photo-259597.jpeg',
             'head': 'Sale small house',
             'price': '187945 $',
             'subheading': '2 bed end terrace house for sale',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 0.8 miles to Maidenhead town centre and mainline railway station (Future Crossrail).',
             'id': 3
         }
     ];

     /*  var ref = firebaseModule.database; //tuka sa dwa varianta na wzimane-i otdolu
       //var homes = firebaseModule.database.child(`homes/`);

       let promis = new Promise((resolve, reject) => {
           ref.on('value', function(snap) {
               if (snap.val() == null) {
                   reject(null);
               } else {
                   var items = {
                       pets: snap.val().pets['-KikZyXR-KSWMlLJbzLL'],
                       homes: snap.val().homes['-KikZyXDlybDnC6Ulsy4'],
                       cars: snap.val().cars['-KikZyXO22U5zrl4jzH6']
                   };

                   resolve(items);
               }
           });
       });

       promis.then(items => {

            console.log(items.pets[0])
       })
       console.log()*/
     /* let homes = promis.then(items.homes[0]);
      let cars = promis.then(items.cars[0]);
      console.log(pets, cars, homes)*/

     let itemsPets = {};

     /*[{
             'url': 'http://static.baubau.bg/resources/haski.jpg',
             'head': 'Sale dog',
             'price': '123 $',
             'subheading': 'Husky',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 0.8 miles to Maidenhead town centre and mainline railway station (Future Crossrail).',
             id: 1
         },
         {
             'url': 'http://gradcontent.com/lib/500x350/turkish-angora1.jpg',
             'head': 'Sale cat',
             'price': '543 $',
             'subheading': 'Angorska',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 0.8 miles to Maidenhead town centre and mainline railway station (Future Crossrail).',
             'id': 2
         },
         {
             'url': 'http://www.petsfoto.com/wp-content/uploads/2011/03/Charming-Rabbits13.jpg',
             'head': 'Sale rabbits',
             'price': '187 $',
             'subheading': 'Bunny',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 0.8 miles to Maidenhead town centre and mainline railway station (Future Crossrail).',
             'id': 3
         }
     ];*/
     let itemsCars = [{
             'url': 'http://buyersguide.caranddriver.com/media/assets/submodel/6937.jpg',
             'head': 'Sale BMW',
             'price': '1979 $',
             'subheading': 'z4',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 0.8 miles to Maidenhead town centre and mainline railway station (Future Crossrail).',
             'id': 1
         },
         {
             'url': 'http://pop.h-cdn.co/assets/cm/15/05/54cb1a4276b40_-_retro-car-flops-01-0913-lgn.jpg',
             'head': 'Sale retro Ford',
             'price': '123 $',
             'subheading': 'Airbeg ABS',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 0.8 miles to Maidenhead town centre and mainline railway station (Future Crossrail).',
             'id': 2
         }, {
             'url': 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/BMW_Z3_%285746806085%29.jpg/800px-BMW_Z3_%285746806085%29.jpg',
             'head': 'Sale BMW',
             'price': '1879 $',
             'subheading': 'z3',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 0.8 miles to Maidenhead town centre and mainline railway station (Future Crossrail).',
             'id': 3
         }
     ];

     /*   function get() {
            //eto tuk get raboti s pormis dolu-v momenta e lokalno no v drug slochai towa shte e zaqwka kum servera
            var promise = new Promise(function(resolve, reject) {
                resolve(items);
            })
            return promise;
        }*/
     //to sushtiq get no s ajax zaqvka
     /* function getAjax() {//towa she mi e s zaqwkite kum syrvyra
          var promise = new Promise(function(resolve, reject) {
              $.ajax({
                  url: 'api/items',
                  type: 'GET',
                  contentType: 'application/json',
                  success: function(res) {
                      resolve(res)
                  },
                  error: function(err) {
                      reject(err);
                  }
              })
          });
      }*/

     /*function getById(id) {
         id = +id; //taka shtoto otdolu ot sami mi idva "100"i ne sa ravni poneje e string
         var promise = new Promise(function(resolve, reject) {
             items.find(function(item) {
                 if (item.id === id) {
                     resolve(item)
                 } else {
                     reject: 'Nmq takova id'
                 }
             });
         });
         return promise;
     }
     var lastId = 0;*/

     /* function save(item) {//towa e post kum survura
          var promise = new Promise(function(resolve, reject) {
              item.id = lastId += 1;
              items.push(item);
              resolve(item);
          })
          return promise;
      }*/
     return { itemsHomes: itemsHomes, itemsPets, itemsCars }
     /* get,
      getById,*/

     //save

 }());
 export default db;<commit_msg>Fixing typos<commit_after> import firebaseModule from 'firebase-config';
 let db = (function() {
     var itemsHomes = [{
             'url': 'https://static.pexels.com/photos/106399/pexels-photo-106399.jpeg',
             'head': 'A wonderful house',
             'price': '€ 529,200',
             'subheading': '4 Bedroom house',
             'body': 'Meticulously maintained throughout the years, this enchanting home is a showcase of beautiful original detail combined with custom craftsmanship. The main level features a spacious front living room. The elegant formal dining room features original built-in china cabinet, gorgeous decorative fireplace. Off the dining room is a sunroom, the perfect spot to enjoy your morning coffee. The kitchen features granite counters, wolf range and pantry offering plenty of storage. Journey up the elegant staircase and you will find a large central bath, four rooms + sunroom offering flexible use..',
             id: 1
         },
         {
             'url': 'https://static.pexels.com/photos/261187/pexels-photo-261187.jpeg',
             'head': '2 Bedroom house for sale',
             'price': '€ 150,000',
             'subheading': '2 Bedroom house',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner. The property is only 12 km. to Sofia town centre.',
             'id': 2
         },
         {
             'url': 'https://static.pexels.com/photos/259597/pexels-photo-259597.jpeg',
             'head': '2 Bedroom house for sale',
             'price': '€ 187,945',
             'subheading': '2 Bedroom house',
             'body': 'Summary Positioned within a no through road in a popular residential area is this spacious character cottage which has been fully renovated to a high standard by the current owner.',
             'id': 3
         }
     ];

     var itemsPets = [{
             'url': 'http://static.baubau.bg/resources/haski.jpg',
             'head': 'Siberian Husky Puppies',
             'price': '€ 250',
             'subheading': '16 WEEKS OLD Husky',
             'body': 'Siberian Huskies are strong, hard-working dogs. As their name suggests, they come originally from Northeast Siberia.',
             id: 1
         },
         {
             'url': 'http://gradcontent.com/lib/500x350/turkish-angora1.jpg',
             'head': 'Angora Female cat',
             'price': '€ 200',
             'subheading': 'Beautiful Pure White Turkish Angora Female',
             'body': ' have for sale last twofold Turkish Angora white (and one white and black)kitten.',
             'id': 2
         },
         {
             'url': 'http://www.petsfoto.com/wp-content/uploads/2011/03/Charming-Rabbits13.jpg',
             'head': 'Rabbits',
             'price': '€ 30',
             'subheading': 'French Lop',
             'body': 'We have 4 lovely French lops available to reserve. Male chocolate and male choc white ear. Female agouti white ear and chocolate v.m. Friendly well handled with blue eyes. Will come with change over food.',
             'id': 3
         }
 ];
    var itemsCars = [{
             'url': 'http://buyersguide.caranddriver.com/media/assets/submodel/6937.jpg',
             'head': 'BMW',
             'price': '€ 12,000',
             'subheading': 'z4',
             'body': '2007 BMW Z4 M.This car is mechanically stock OEM. Cosmetic modifications are limited to powder coated wheels, stubby antenna, black kidney grilles, and de-badging .',
             'id': 1
         },
         {
             'url': 'http://pop.h-cdn.co/assets/cm/15/05/54cb1a4276b40_-_retro-car-flops-01-0913-lgn.jpg',
             'head': 'Retro Ford',
             'price': '€ 2,000',
             'subheading': '1985 Ford Thunderbird',
             'body': '2dr, first year for this body style, one family owned since new, great shape, nice body and paint, nice orig int, big block V8, auto, ps, pb, hide away headlights, swing away column, nice orig vinyl top, runs/drives great',
             'id': 2
         }, {
             'url': 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/BMW_Z3_%285746806085%29.jpg/800px-BMW_Z3_%285746806085%29.jpg',
             'head': 'BMW Z3 1.9 Roadster 2dr',
             'price': '€ 12,000',
             'subheading': 'A truly wonderful Z3 Roadster',
             'body': 'Cross Spoke Alloys - 16in, Black Leather Upholstery, Interior Chrome Pack, Traction Control, Air-Conditioning, Black Hood, Electric Hood Operation, BMW Six Disc CD Autochanger, Front Fog Lights, In Car Entertainment (Radio/CD), Alarm, Electric Windows (Front)',
             'id': 3
         }
     ];

     return { itemsHomes: itemsHomes, itemsPets, itemsCars }

 }());
 export default db;<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var path = require('path');
var os = require("os");
var userController = require('../controllers/user_controller');
var debug = require('debug')('docker-chat:routes');
const multer = require('multer')
const storage_volume = process.env.STORAGE_VOLUME || '/uploads';
const avatar_path = '/avatars';
const upload_location = path.join(storage_volume, avatar_path);

var storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, path.join(__dirname, '..', upload_location))
    },
    filename: function (req, file, cb) {
        let ext = path.extname(file.originalname);
        cb(null, file.fieldname.replace(/\W+/g, '-').toLowerCase() + '-' + Date.now() + ext)
    }
})

if (!fs.existsSync(storage_volume)) {
    fs.mkdirSync(storage_volume);
    if (!fs.existsSync(upload_location)) {
        fs.mkdirSync(upload_location);
    }
}

var upload = multer({
    storage: storage
})

/* GET home page. */
router.get('/', function (req, res, next) {
    if (!req.session.user) {
        res.redirect('/login');
    } else {
        res.render('index', {
            title: 'SocketIO Chat Demo',
            number_connected: req.userCount,
            host: os.hostname(),
            parse: process.env.PARSE_MSG
        });
    }
});

/* POST home page. */
router.post('/', function (req, res, next) {
    user = req.body.user;
    debug('User: ' + user + " LOGIN");
    userController.getUser(user, function (foundUser) {
        debug(foundUser.name);
        req.session.user = foundUser;
        res.redirect('/');
    });
});

/* GET login page. */
router.get('/login', function (req, res, next) {
    if (req.session.user) {
        res.redirect('/');
    } else {
        res.render('login', {
            title: 'SocketIO Chat Demo',
            host: os.hostname()
        });
    }
});

/* POST avatar. */
router.post('/avatar', upload.single('avatar'), function (req, res, next) {
    if (!req.session.user) {
        res.redirect('/login');
    } else {
        let file = path.join(avatar_path, req.file.filename);
        userController.uploadAvatar(req.session.user.name, file, function (user) {
            req.session.user = user;
            res.redirect('/');
        });
    }
});

/* GET logout page. */
router.get('/logout', function (req, res, next) {
    delete req.session.user;
    res.redirect('/');
});

router.get('/healthcheck', function (req, res, next) {
    res.send(200);
});

module.exports = router;<commit_msg>fix: add fs<commit_after>var express = require('express');
var router = express.Router();
var path = require('path');
var os = require("os");
var fs = require("fs");
var userController = require('../controllers/user_controller');
var debug = require('debug')('docker-chat:routes');
const multer = require('multer')
const storage_volume = process.env.STORAGE_VOLUME || '/uploads';
const avatar_path = '/avatars';
const upload_location = path.join(storage_volume, avatar_path);

var storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, path.join(__dirname, '..', upload_location))
    },
    filename: function (req, file, cb) {
        let ext = path.extname(file.originalname);
        cb(null, file.fieldname.replace(/\W+/g, '-').toLowerCase() + '-' + Date.now() + ext)
    }
})

if (!fs.existsSync(storage_volume)) {
    fs.mkdirSync(storage_volume);
    if (!fs.existsSync(upload_location)) {
        fs.mkdirSync(upload_location);
    }
}

var upload = multer({
    storage: storage
})

/* GET home page. */
router.get('/', function (req, res, next) {
    if (!req.session.user) {
        res.redirect('/login');
    } else {
        res.render('index', {
            title: 'SocketIO Chat Demo',
            number_connected: req.userCount,
            host: os.hostname(),
            parse: process.env.PARSE_MSG
        });
    }
});

/* POST home page. */
router.post('/', function (req, res, next) {
    user = req.body.user;
    debug('User: ' + user + " LOGIN");
    userController.getUser(user, function (foundUser) {
        debug(foundUser.name);
        req.session.user = foundUser;
        res.redirect('/');
    });
});

/* GET login page. */
router.get('/login', function (req, res, next) {
    if (req.session.user) {
        res.redirect('/');
    } else {
        res.render('login', {
            title: 'SocketIO Chat Demo',
            host: os.hostname()
        });
    }
});

/* POST avatar. */
router.post('/avatar', upload.single('avatar'), function (req, res, next) {
    if (!req.session.user) {
        res.redirect('/login');
    } else {
        let file = path.join(avatar_path, req.file.filename);
        userController.uploadAvatar(req.session.user.name, file, function (user) {
            req.session.user = user;
            res.redirect('/');
        });
    }
});

/* GET logout page. */
router.get('/logout', function (req, res, next) {
    delete req.session.user;
    res.redirect('/');
});

router.get('/healthcheck', function (req, res, next) {
    res.send(200);
});

module.exports = router;<|endoftext|>


<commit_before>"use strict";

const actual_load = require("module")._load;
const path = require("path");

const new_globals = new Set();
let old_globals = {};

let objs_installed;
let mock_paths = {};
let mocked_paths;
let mock_names;

exports.start = () => {
    objs_installed = false;
    mock_paths = {};
    mocked_paths = new Set();
    mock_names = new Set();
};

exports.mock_module = (short_fn, obj) => {
    if (obj === undefined) {
        obj = {};
    }

    if (typeof obj !== "object") {
        throw new TypeError("We expect you to stub with an object.");
    }

    if (mock_names.has(short_fn)) {
        throw new Error(`You already set up a mock for ${short_fn}`);
    }

    if (short_fn.startsWith("/") || short_fn.includes(".")) {
        throw new Error(`
            There is no need for a path like ${short_fn}.
            We just assume the file is under static/js.
        `);
    }
    if (objs_installed) {
        throw new Error(`
            It is too late to install this mock.  Consider instead:

                foo.__Rewire__("${short_fn}", ...)

            Or call this earlier.
        `);
    }

    const base_path = path.resolve("./static/js");
    const long_fn = path.join(base_path, short_fn);

    obj.__esModule = true;
    mock_paths[long_fn] = obj;
    mock_names.add(short_fn);
    return obj;
};

exports.set_global = function (name, val) {
    if (val === null) {
        throw new Error(`
            We try to avoid using null in our codebase.
        `);
    }

    if (!(name in old_globals)) {
        if (!(name in global)) {
            new_globals.add(name);
        }
        old_globals[name] = global[name];
    }
    global[name] = val;
    return val;
};

exports.zrequire = function (fn) {
    objs_installed = true;

    // Because we do lazy compilation, we don't reset the
    // _load hook until our test runners calls `finish()`.
    require("module")._load = (request, parent, isMain) => {
        const long_fn = path.resolve(path.join(path.dirname(parent.filename), request));
        if (mock_paths[long_fn]) {
            mocked_paths.add(long_fn);
            return mock_paths[long_fn];
        }

        return actual_load(request, parent, isMain);
    };
    const full_path = path.resolve(path.join("static/js", fn));
    return require(full_path);
};

const staticPath = path.resolve(__dirname, "../../static") + path.sep;
const templatesPath = staticPath + "templates" + path.sep;

exports.finish = function () {
    /*
        Handle cleanup tasks after we've run one module.

        Note that we currently do lazy compilation of modules,
        so we need to wait till the module tests finish
        running to do things like detecting pointless mocks
        and resetting our _load hook.
    */
    for (const fn of Object.keys(mock_paths)) {
        if (!mocked_paths.has(fn)) {
            throw new Error(`
                You asked to mock ${fn} but we never
                saw it during compilation.
            `);
        }
    }

    require("module")._load = actual_load;
    for (const path of Object.keys(require.cache)) {
        if (path.startsWith(staticPath) && !path.startsWith(templatesPath)) {
            delete require.cache[path];
        }
    }
    Object.assign(global, old_globals);
    old_globals = {};
    for (const name of new_globals) {
        delete global[name];
    }
    new_globals.clear();
};

exports.with_field = function (obj, field, val, f) {
    if ("__esModule" in obj && "__Rewire__" in obj) {
        const old_val = field in obj ? obj[field] : obj.__GetDependency__(field);
        try {
            obj.__Rewire__(field, val);
            return f();
        } finally {
            obj.__Rewire__(field, old_val);
        }
    } else {
        const had_val = Object.prototype.hasOwnProperty.call(obj, field);
        const old_val = obj[field];
        try {
            obj[field] = val;
            return f();
        } finally {
            if (had_val) {
                obj[field] = old_val;
            } else {
                delete obj[field];
            }
        }
    }
};

exports.with_overrides = function (test_function) {
    // This function calls test_function() and passes in
    // a way to override the namespace temporarily.

    const restore_callbacks = [];
    const unused_funcs = new Map();
    const funcs = new Map();

    const override = function (obj, func_name, f) {
        // Given an object `obj` (which is usually a module object),
        // we re-map `obj[func_name]` to the `f` passed in by the caller.
        // Then the outer function here (`with_overrides`) automatically
        // restores the original value of `obj[func_name]` as its last
        // step.  Generally our code calls `run_test`, which wraps
        // `with_overrides`.
        if (typeof f !== "function") {
            throw new TypeError(
                "You can only override with a function. Use with_field for non-functions.",
            );
        }

        if (typeof obj !== "object" && typeof obj !== "function") {
            throw new TypeError(`We cannot override a function for ${typeof obj} objects`);
        }

        if (obj[func_name] !== undefined && typeof obj[func_name] !== "function") {
            throw new TypeError(`
                You are overriding a non-function with a function.
                This is almost certainly an error.
            `);
        }

        if (!funcs.has(obj)) {
            funcs.set(obj, new Map());
        }

        if (funcs.get(obj).has(func_name)) {
            // Prevent overriding the same function twice, so that
            // it's super easy to reason about our logic to restore
            // the original function.  Usually if somebody sees this
            // error, it's a symptom of not breaking up tests enough.
            throw new Error(
                "You can only override a function one time. Use with_field for more granular control.",
            );
        }

        funcs.get(obj).set(func_name, true);

        if (!unused_funcs.has(obj)) {
            unused_funcs.set(obj, new Map());
        }

        unused_funcs.get(obj).set(func_name, true);

        let old_f =
            "__esModule" in obj && "__Rewire__" in obj && !(func_name in obj)
                ? obj.__GetDependency__(func_name)
                : obj[func_name];
        if (old_f === undefined) {
            // Create a dummy function so that we can
            // attach _patched_with_override to it.
            old_f = () => {
                throw new Error(`There is no ${func_name}() field for this object.`);
            };
        }

        const new_f = function (...args) {
            unused_funcs.get(obj).delete(func_name);
            return f.apply(this, args);
        };

        // Let zjquery know this function was patched with override,
        // so it doesn't complain about us modifying it.  (Other
        // code can also use this, as needed.)
        new_f._patched_with_override = true;

        if ("__esModule" in obj && "__Rewire__" in obj) {
            obj.__Rewire__(func_name, new_f);
            restore_callbacks.push(() => {
                obj.__Rewire__(func_name, old_f);
            });
        } else {
            obj[func_name] = new_f;
            restore_callbacks.push(() => {
                old_f._patched_with_override = true;
                obj[func_name] = old_f;
                delete old_f._patched_with_override;
            });
        }
    };

    try {
        test_function(override);
    } finally {
        restore_callbacks.reverse();
        for (const restore_callback of restore_callbacks) {
            restore_callback();
        }
    }

    for (const module_unused_funcs of unused_funcs.values()) {
        for (const unused_name of module_unused_funcs.keys()) {
            throw new Error(unused_name + " never got invoked!");
        }
    }
};
<commit_msg>zjsunit: Allow multiple overrides again.<commit_after>"use strict";

const actual_load = require("module")._load;
const path = require("path");

const new_globals = new Set();
let old_globals = {};

let objs_installed;
let mock_paths = {};
let mocked_paths;
let mock_names;

exports.start = () => {
    objs_installed = false;
    mock_paths = {};
    mocked_paths = new Set();
    mock_names = new Set();
};

exports.mock_module = (short_fn, obj) => {
    if (obj === undefined) {
        obj = {};
    }

    if (typeof obj !== "object") {
        throw new TypeError("We expect you to stub with an object.");
    }

    if (mock_names.has(short_fn)) {
        throw new Error(`You already set up a mock for ${short_fn}`);
    }

    if (short_fn.startsWith("/") || short_fn.includes(".")) {
        throw new Error(`
            There is no need for a path like ${short_fn}.
            We just assume the file is under static/js.
        `);
    }
    if (objs_installed) {
        throw new Error(`
            It is too late to install this mock.  Consider instead:

                foo.__Rewire__("${short_fn}", ...)

            Or call this earlier.
        `);
    }

    const base_path = path.resolve("./static/js");
    const long_fn = path.join(base_path, short_fn);

    obj.__esModule = true;
    mock_paths[long_fn] = obj;
    mock_names.add(short_fn);
    return obj;
};

exports.set_global = function (name, val) {
    if (val === null) {
        throw new Error(`
            We try to avoid using null in our codebase.
        `);
    }

    if (!(name in old_globals)) {
        if (!(name in global)) {
            new_globals.add(name);
        }
        old_globals[name] = global[name];
    }
    global[name] = val;
    return val;
};

exports.zrequire = function (fn) {
    objs_installed = true;

    // Because we do lazy compilation, we don't reset the
    // _load hook until our test runners calls `finish()`.
    require("module")._load = (request, parent, isMain) => {
        const long_fn = path.resolve(path.join(path.dirname(parent.filename), request));
        if (mock_paths[long_fn]) {
            mocked_paths.add(long_fn);
            return mock_paths[long_fn];
        }

        return actual_load(request, parent, isMain);
    };
    const full_path = path.resolve(path.join("static/js", fn));
    return require(full_path);
};

const staticPath = path.resolve(__dirname, "../../static") + path.sep;
const templatesPath = staticPath + "templates" + path.sep;

exports.finish = function () {
    /*
        Handle cleanup tasks after we've run one module.

        Note that we currently do lazy compilation of modules,
        so we need to wait till the module tests finish
        running to do things like detecting pointless mocks
        and resetting our _load hook.
    */
    for (const fn of Object.keys(mock_paths)) {
        if (!mocked_paths.has(fn)) {
            throw new Error(`
                You asked to mock ${fn} but we never
                saw it during compilation.
            `);
        }
    }

    require("module")._load = actual_load;
    for (const path of Object.keys(require.cache)) {
        if (path.startsWith(staticPath) && !path.startsWith(templatesPath)) {
            delete require.cache[path];
        }
    }
    Object.assign(global, old_globals);
    old_globals = {};
    for (const name of new_globals) {
        delete global[name];
    }
    new_globals.clear();
};

exports.with_field = function (obj, field, val, f) {
    if ("__esModule" in obj && "__Rewire__" in obj) {
        const old_val = field in obj ? obj[field] : obj.__GetDependency__(field);
        try {
            obj.__Rewire__(field, val);
            return f();
        } finally {
            obj.__Rewire__(field, old_val);
        }
    } else {
        const had_val = Object.prototype.hasOwnProperty.call(obj, field);
        const old_val = obj[field];
        try {
            obj[field] = val;
            return f();
        } finally {
            if (had_val) {
                obj[field] = old_val;
            } else {
                delete obj[field];
            }
        }
    }
};

exports.with_overrides = function (test_function) {
    // This function calls test_function() and passes in
    // a way to override the namespace temporarily.

    const restore_callbacks = [];
    const unused_funcs = new Map();
    const override = function (obj, func_name, f) {
        // Given an object `obj` (which is usually a module object),
        // we re-map `obj[func_name]` to the `f` passed in by the caller.
        // Then the outer function here (`with_overrides`) automatically
        // restores the original value of `obj[func_name]` as its last
        // step.  Generally our code calls `run_test`, which wraps
        // `with_overrides`.
        if (typeof f !== "function") {
            throw new TypeError(
                "You can only override with a function. Use with_field for non-functions.",
            );
        }

        if (typeof obj !== "object" && typeof obj !== "function") {
            throw new TypeError(`We cannot override a function for ${typeof obj} objects`);
        }

        if (obj[func_name] !== undefined && typeof obj[func_name] !== "function") {
            throw new TypeError(`
                You are overriding a non-function with a function.
                This is almost certainly an error.
            `);
        }

        if (!unused_funcs.has(obj)) {
            unused_funcs.set(obj, new Map());
        }

        unused_funcs.get(obj).set(func_name, true);

        let old_f =
            "__esModule" in obj && "__Rewire__" in obj && !(func_name in obj)
                ? obj.__GetDependency__(func_name)
                : obj[func_name];
        if (old_f === undefined) {
            // Create a dummy function so that we can
            // attach _patched_with_override to it.
            old_f = () => {
                throw new Error(`There is no ${func_name}() field for this object.`);
            };
        }

        const new_f = function (...args) {
            unused_funcs.get(obj).delete(func_name);
            return f.apply(this, args);
        };

        // Let zjquery know this function was patched with override,
        // so it doesn't complain about us modifying it.  (Other
        // code can also use this, as needed.)
        new_f._patched_with_override = true;

        if ("__esModule" in obj && "__Rewire__" in obj) {
            obj.__Rewire__(func_name, new_f);
            restore_callbacks.push(() => {
                obj.__Rewire__(func_name, old_f);
            });
        } else {
            obj[func_name] = new_f;
            restore_callbacks.push(() => {
                old_f._patched_with_override = true;
                obj[func_name] = old_f;
                delete old_f._patched_with_override;
            });
        }
    };

    try {
        test_function(override);
    } finally {
        restore_callbacks.reverse();
        for (const restore_callback of restore_callbacks) {
            restore_callback();
        }
    }

    for (const module_unused_funcs of unused_funcs.values()) {
        for (const unused_name of module_unused_funcs.keys()) {
            throw new Error(unused_name + " never got invoked!");
        }
    }
};
<|endoftext|>


<commit_before><commit_msg>fix: Fix type and default value of selectedTheme to be a string<commit_after><|endoftext|>


<commit_before>module.exports = {

    VERSION: "Default JavaScript folding player",

    bet_request: function(state, bet) {
        // Minimum raise amount. To raise you have to return at least:
        //     current_buy_in - players[in_action][bet] + minimum_raise

        var raise = state.current_buy_in - state.players[state.in_action].bet + state.minimum_raise
        console.log(state.players);
        bet(raise);
    },

    showdown: function(state) {

    }
};

/*

type Card struct {
    // Rank of the card. Possible values are numbers 2-10 and J,Q,K,A
    Rank string `json:"rank"`

    // Suit of the card. Possible values are: clubs,spades,hearts,diamonds
    Suit string `json:"suit"`
}

package leanpoker

type Game struct {
    // The small blind in the current round. The big blind is twice
    // the small blind
    SmallBlind int `json:"small_blind"`

    // The amount of the largest current bet from any one player
    CurrentBuyIn int `json:"current_buy_in"`

    // The size of the pot (sum of the player bets)
    Pot int `json:"pot"`

    // Minimum raise amount. To raise you have to return at least:
    //     current_buy_in - players[in_action][bet] + minimum_raise
    MinimumRaise int `json:"minimum_raise"`

    // The index of the player on the dealer button in this round
    // The first player is (dealer+1)%(players.length)
    Dealer int `json:"dealer"`

    // Number of orbits completed. (The number of times the dealer button
    // returned to the same player.)
    Orbits int `json:"orbits"`

    // The index of your player, in the players array
    InAction int `json:"in_action"`

    // An array of the players. The order stays the same during the
    // entire tournament
    Players []Player `json:"players"`

    // Finally the array of community cards.
    CommunityCards []Card `json:"community_cards"`
}

package leanpoker

const VERSION = "Default Go folding player"

type Player struct {
    // Id of the player (same as the index)
    Id int `json:"id"`

    // Name specified in the tournament config
    Name string `json:"name"`

    // Status of the player:
    //   - active: the player can make bets, and win the current pot
    //   - folded: the player folded, and gave up interest in
    //       the current pot. They can return in the next round.
    //   - out: the player lost all chips, and is out of this sit'n'go
    Status string `json:"status"`

    // Version identifier returned by the player
    Version string `json:"version"`

    // Amount of chips still available for the player.
    // (Not including the chips the player bet in this round)
    Stack int `json:"stack"`

    // The amount of chips the player put into the pot
    Bet int `json:"bet"`

    // The cards of the player. This is only visible for your own player
    // except after showdown, when cards revealed are also included.
    HoleCards []Card `json:"hole_cards"`
}

*/<commit_msg>player name<commit_after>module.exports = {

    VERSION: "Vivatious racoon",

    bet_request: function(state, bet) {
        // Minimum raise amount. To raise you have to return at least:
        //     current_buy_in - players[in_action][bet] + minimum_raise

        var raise = state.current_buy_in - state.players[state.in_action].bet + state.minimum_raise
        console.log(state.players);
        bet(raise);
    },

    showdown: function(state) {

    }
};

/*

type Card struct {
    // Rank of the card. Possible values are numbers 2-10 and J,Q,K,A
    Rank string `json:"rank"`

    // Suit of the card. Possible values are: clubs,spades,hearts,diamonds
    Suit string `json:"suit"`
}

package leanpoker

type Game struct {
    // The small blind in the current round. The big blind is twice
    // the small blind
    SmallBlind int `json:"small_blind"`

    // The amount of the largest current bet from any one player
    CurrentBuyIn int `json:"current_buy_in"`

    // The size of the pot (sum of the player bets)
    Pot int `json:"pot"`

    // Minimum raise amount. To raise you have to return at least:
    //     current_buy_in - players[in_action][bet] + minimum_raise
    MinimumRaise int `json:"minimum_raise"`

    // The index of the player on the dealer button in this round
    // The first player is (dealer+1)%(players.length)
    Dealer int `json:"dealer"`

    // Number of orbits completed. (The number of times the dealer button
    // returned to the same player.)
    Orbits int `json:"orbits"`

    // The index of your player, in the players array
    InAction int `json:"in_action"`

    // An array of the players. The order stays the same during the
    // entire tournament
    Players []Player `json:"players"`

    // Finally the array of community cards.
    CommunityCards []Card `json:"community_cards"`
}

package leanpoker

const VERSION = "Default Go folding player"

type Player struct {
    // Id of the player (same as the index)
    Id int `json:"id"`

    // Name specified in the tournament config
    Name string `json:"name"`

    // Status of the player:
    //   - active: the player can make bets, and win the current pot
    //   - folded: the player folded, and gave up interest in
    //       the current pot. They can return in the next round.
    //   - out: the player lost all chips, and is out of this sit'n'go
    Status string `json:"status"`

    // Version identifier returned by the player
    Version string `json:"version"`

    // Amount of chips still available for the player.
    // (Not including the chips the player bet in this round)
    Stack int `json:"stack"`

    // The amount of chips the player put into the pot
    Bet int `json:"bet"`

    // The cards of the player. This is only visible for your own player
    // except after showdown, when cards revealed are also included.
    HoleCards []Card `json:"hole_cards"`
}

*/<|endoftext|>