<commit_before>"use strict";

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

const {set_global, zrequire} = require("../zjsunit/namespace");
const {make_stub, with_stub} = require("../zjsunit/stub");
const {run_test} = require("../zjsunit/test");
const {make_zjquery} = require("../zjsunit/zjquery");

const noop = function () {};
const return_true = function () {
    return true;
};
set_global("$", make_zjquery());
const _settings_notifications = {
    update_page: () => {},
};
set_global("settings_notifications", _settings_notifications);

set_global("color_data", {});
set_global("current_msg_list", {});
set_global("message_util", {});
set_global("stream_color", {});
set_global("stream_list", {});
set_global("stream_muting", {});
set_global("subs", {});

const people = zrequire("people");
zrequire("stream_data");
zrequire("stream_events");
zrequire("Filter", "js/filter");
zrequire("narrow_state");
zrequire("message_view_header");

const george = {
    email: "george@zulip.com",
    full_name: "George",
    user_id: 103,
};
people.add_active_user(george);

const frontend = {
    subscribed: false,
    color: "yellow",
    name: "frontend",
    stream_id: 1,
    is_muted: true,
    invite_only: false,
};

stream_data.add_sub(frontend);

const frontend_filter_terms = [{operator: "stream", operand: "frontend"}];

const frontend_filter = new Filter(frontend_filter_terms);

run_test("update_property", (override) => {
    // Invoke error for non-existent stream/property
    {
        let errors = 0;
        override("blueslip.warn", () => {
            errors += 1;
        });

        stream_events.update_property(99, "color", "blue");
        assert.equal(errors, 1);

        stream_events.update_property(1, "not_real", 42);
        assert.equal(errors, 2);
    }

    // Test update color
    {
        with_stub((stub) => {
            override("stream_color.update_stream_color", stub.f);
            stream_events.update_property(1, "color", "blue");
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, "blue");
        });
    }

    // Test in home view
    {
        with_stub((stub) => {
            override("stream_muting.update_is_muted", stub.f);
            stream_events.update_property(1, "in_home_view", false);
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, true);
        });
    }

    // Test desktop notifications
    stream_events.update_property(1, "desktop_notifications", true);
    assert.equal(frontend.desktop_notifications, true);
    let checkbox = $("#desktop_notifications_1");
    assert.equal(checkbox.prop("checked"), true);

    // Tests audible notifications
    stream_events.update_property(1, "audible_notifications", true);
    assert.equal(frontend.audible_notifications, true);
    checkbox = $("#audible_notifications_1");
    assert.equal(checkbox.prop("checked"), true);

    // Tests push notifications
    stream_events.update_property(1, "push_notifications", true);
    assert.equal(frontend.push_notifications, true);
    checkbox = $("#push_notifications_1");
    assert.equal(checkbox.prop("checked"), true);

    // Tests email notifications
    stream_events.update_property(1, "email_notifications", true);
    assert.equal(frontend.email_notifications, true);
    checkbox = $("#email_notifications_1");
    assert.equal(checkbox.prop("checked"), true);

    // Tests wildcard_mentions_notify notifications
    stream_events.update_property(1, "wildcard_mentions_notify", true);
    assert.equal(frontend.wildcard_mentions_notify, true);
    checkbox = $("#wildcard_mentions_notify_1");
    assert.equal(checkbox.prop("checked"), true);

    // Test name change
    {
        with_stub((stub) => {
            override("subs.update_stream_name", stub.f);
            stream_events.update_property(1, "name", "the frontend");
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, "the frontend");
        });
    }

    // Test description change
    {
        with_stub((stub) => {
            override("subs.update_stream_description", stub.f);
            stream_events.update_property(1, "description", "we write code", {
                rendered_description: "we write code",
            });
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, "we write code");
        });
    }

    // Test email address change
    stream_events.update_property(1, "email_address", "zooly@zulip.com");
    assert.equal(frontend.email_address, "zooly@zulip.com");

    // Test pin to top
    {
        override("stream_list.refresh_pinned_or_unpinned_stream", noop);
        stream_events.update_property(1, "pin_to_top", true);
        checkbox = $("#pin_to_top_1");
        assert.equal(checkbox.prop("checked"), true);
    }

    // Test stream privacy change event
    {
        with_stub((stub) => {
            override("subs.update_stream_privacy", stub.f);
            stream_events.update_property(1, "invite_only", true, {
                history_public_to_subscribers: true,
            });
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.deepEqual(args.val, {
                invite_only: true,
                history_public_to_subscribers: true,
            });
        });
    }

    // Test stream stream_post_policy change event
    {
        with_stub((stub) => {
            override("subs.update_stream_post_policy", stub.f);
            stream_events.update_property(
                1,
                "stream_post_policy",
                stream_data.stream_post_policy_values.admins.code,
            );
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, stream_data.stream_post_policy_values.admins.code);
        });
    }

    // Test stream message_retention_days change event
    {
        with_stub((stub) => {
            override("subs.update_message_retention_setting", stub.f);
            stream_events.update_property(1, "message_retention_days", 20);
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, 20);
        });
    }
});

run_test("marked_subscribed", (override) => {
    override("stream_data.subscribe_myself", noop);
    override("stream_data.set_subscribers", noop);
    override("stream_data.update_calculated_fields", noop);

    // Test undefined error
    {
        let errors = 0;
        override("blueslip.error", () => {
            errors += 1;
        });
        stream_events.mark_subscribed(undefined, [], "yellow");
        assert.equal(errors, 1);
    }

    // Test early return if subscribed
    {
        let completed = false;
        override("message_util.do_unread_count_updates", () => {
            completed = true; // This gets run if we continue and don't early return
        });
        const subscribed = {subscribed: true};
        stream_events.mark_subscribed(subscribed, [], "yellow");
        assert.equal(completed, false);

        // prevent warning about spurious override
        message_util.do_unread_count_updates();
    }

    set_global("message_list", {
        all: {
            all_messages() {
                return ["msg"];
            },
        },
    });

    set_global("subs", {update_settings_for_subscribed: noop});
    set_global("overlays", {streams_open: return_true});

    // Test basic dispatching and updating stream color
    narrow_state.set_current_filter(frontend_filter);
    {
        let args;
        let list_updated = false;

        const stream_list_stub = make_stub();
        const message_view_header_stub = make_stub();
        const message_util_stub = make_stub();

        override("stream_color.update_stream_color", noop);
        override("stream_list.add_sidebar_row", stream_list_stub.f);
        override("message_util.do_unread_count_updates", message_util_stub.f);
        override("message_view_header.render_title_area", message_view_header_stub.f);
        override("current_msg_list.update_trailing_bookend", () => {
            list_updated = true;
        });

        stream_events.mark_subscribed(frontend, [], "blue");

        args = message_util_stub.get_args("messages");
        assert.deepEqual(args.messages, ["msg"]);

        args = stream_list_stub.get_args("sub");
        assert.equal(args.sub.stream_id, 1);
        assert.equal(message_view_header_stub.num_calls, 1);

        assert.equal(list_updated, true);

        assert.equal(frontend.color, "blue");
    }
    narrow_state.reset_current_filter();

    // Test assigning generated color
    {
        frontend.color = undefined;
        override("color_data.pick_color", () => "green");
        let warnings = 0;
        override("blueslip.warn", () => {
            warnings += 1;
        });

        // narrow state is undefined
        with_stub((stub) => {
            override("message_util.do_unread_count_updates", noop);
            override("stream_list.add_sidebar_row", noop);
            override("subs.set_color", stub.f);
            stream_events.mark_subscribed(frontend, [], undefined);
            const args = stub.get_args("id", "color");
            assert.equal(args.id, 1);
            assert.equal(args.color, "green");
            assert.equal(warnings, 1);
        });
    }

    // Test assigning subscriber emails
    // narrow state is undefined
    {
        override("stream_color.update_stream_color", noop);
        override("message_util.do_unread_count_updates", noop);
        override("stream_list.add_sidebar_row", noop);

        with_stub((stub) => {
            override("stream_data.set_subscribers", stub.f);
            const user_ids = [15, 20, 25];
            stream_events.mark_subscribed(frontend, user_ids, "");
            const args = stub.get_args("sub", "subscribers");
            assert.deepEqual(frontend, args.sub);
            assert.deepEqual(user_ids, args.subscribers);
        });

        // assign self as well
        with_stub((stub) => {
            override("stream_data.subscribe_myself", stub.f);
            stream_events.mark_subscribed(frontend, [], "");
            const args = stub.get_args("sub");
            assert.deepEqual(frontend, args.sub);
        });

        // and finally update subscriber settings
        with_stub((stub) => {
            override("subs.update_settings_for_subscribed", stub.f);
            stream_events.mark_subscribed(frontend, [], "");
            const args = stub.get_args("sub");
            assert.deepEqual(frontend, args.sub);
        });
    }
});

run_test("mark_unsubscribed", (override) => {
    override("stream_data.update_calculated_fields", noop);

    {
        let removed_sub = false;
        override("stream_list.remove_sidebar_row", () => {
            removed_sub = true;
        });

        // take no action if no sub specified
        stream_events.mark_unsubscribed();
        assert.equal(removed_sub, false);

        // take no action if already unsubscribed
        frontend.subscribed = false;
        stream_events.mark_unsubscribed(frontend);
        assert.equal(removed_sub, false);

        // prevent warning about spurious mock
        stream_list.remove_sidebar_row();
    }

    // Test unsubscribe
    frontend.subscribed = true;
    {
        with_stub((stub) => {
            override("stream_data.unsubscribe_myself", stub.f);
            override("subs.update_settings_for_unsubscribed", noop);
            override("stream_list.remove_sidebar_row", noop);
            stream_events.mark_unsubscribed(frontend);
            const args = stub.get_args("sub");
            assert.deepEqual(args.sub, frontend);
        });
    }

    // Test update settings after unsubscribe
    {
        with_stub((stub) => {
            override("subs.update_settings_for_unsubscribed", stub.f);
            override("stream_data.unsubscribe_myself", noop);
            override("stream_list.remove_sidebar_row", noop);
            stream_events.mark_unsubscribed(frontend);
            const args = stub.get_args("sub");
            assert.deepEqual(args.sub, frontend);
        });
    }

    // Test update bookend and remove done event
    narrow_state.set_current_filter(frontend_filter);
    {
        const message_view_header_stub = make_stub();
        override("message_view_header.render_title_area", message_view_header_stub.f);
        override("stream_data.unsubscribe_myself", noop);
        override("subs.update_settings_for_unsubscribed", noop);

        let updated = false;
        override("current_msg_list.update_trailing_bookend", () => {
            updated = true;
        });

        let event_triggered = false;
        override("stream_list.remove_sidebar_row", (stream_id) => {
            assert.equal(stream_id, frontend.stream_id);
            event_triggered = true;
        });

        stream_events.mark_unsubscribed(frontend);

        assert.equal(message_view_header_stub.num_calls, 1);
        assert.equal(updated, true);
        assert.equal(event_triggered, true);
    }
    narrow_state.reset_current_filter();
});

stream_data.clear_subscriptions();
const dev_help = {
    subscribed: true,
    color: "blue",
    name: "dev help",
    stream_id: 2,
    is_muted: true,
    invite_only: false,
};
stream_data.add_sub(dev_help);

run_test("remove_deactivated_user_from_all_streams", () => {
    const subs_stub = make_stub();
    subs.update_subscribers_ui = subs_stub.f;

    dev_help.can_access_subscribers = true;

    // assert starting state
    assert(!stream_data.is_user_subscribed(dev_help.stream_id, george.user_id));

    // verify that deactivating user should unsubscribe user from all streams
    assert(stream_data.add_subscriber(dev_help.stream_id, george.user_id));
    assert(stream_data.is_user_subscribed(dev_help.stream_id, george.user_id));

    stream_events.remove_deactivated_user_from_all_streams(george.user_id);

    // verify that we issue a call to update subscriber count/list UI
    assert.equal(subs_stub.num_calls, 1);
});
<commit_msg>node tests: Eliminate set_subscribers mock.<commit_after>"use strict";

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

const {set_global, zrequire} = require("../zjsunit/namespace");
const {make_stub, with_stub} = require("../zjsunit/stub");
const {run_test} = require("../zjsunit/test");
const {make_zjquery} = require("../zjsunit/zjquery");

const noop = function () {};
const return_true = function () {
    return true;
};
set_global("$", make_zjquery());
const _settings_notifications = {
    update_page: () => {},
};
set_global("settings_notifications", _settings_notifications);

set_global("color_data", {});
set_global("current_msg_list", {});
set_global("message_util", {});
set_global("stream_color", {});
set_global("stream_list", {});
set_global("stream_muting", {});
set_global("subs", {});

const people = zrequire("people");
zrequire("stream_data");
zrequire("stream_events");
zrequire("Filter", "js/filter");
zrequire("narrow_state");
zrequire("message_view_header");

const george = {
    email: "george@zulip.com",
    full_name: "George",
    user_id: 103,
};
people.add_active_user(george);

const frontend = {
    subscribed: false,
    color: "yellow",
    name: "frontend",
    stream_id: 1,
    is_muted: true,
    invite_only: false,
};

stream_data.add_sub(frontend);

const frontend_filter_terms = [{operator: "stream", operand: "frontend"}];

const frontend_filter = new Filter(frontend_filter_terms);

run_test("update_property", (override) => {
    // Invoke error for non-existent stream/property
    {
        let errors = 0;
        override("blueslip.warn", () => {
            errors += 1;
        });

        stream_events.update_property(99, "color", "blue");
        assert.equal(errors, 1);

        stream_events.update_property(1, "not_real", 42);
        assert.equal(errors, 2);
    }

    // Test update color
    {
        with_stub((stub) => {
            override("stream_color.update_stream_color", stub.f);
            stream_events.update_property(1, "color", "blue");
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, "blue");
        });
    }

    // Test in home view
    {
        with_stub((stub) => {
            override("stream_muting.update_is_muted", stub.f);
            stream_events.update_property(1, "in_home_view", false);
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, true);
        });
    }

    // Test desktop notifications
    stream_events.update_property(1, "desktop_notifications", true);
    assert.equal(frontend.desktop_notifications, true);
    let checkbox = $("#desktop_notifications_1");
    assert.equal(checkbox.prop("checked"), true);

    // Tests audible notifications
    stream_events.update_property(1, "audible_notifications", true);
    assert.equal(frontend.audible_notifications, true);
    checkbox = $("#audible_notifications_1");
    assert.equal(checkbox.prop("checked"), true);

    // Tests push notifications
    stream_events.update_property(1, "push_notifications", true);
    assert.equal(frontend.push_notifications, true);
    checkbox = $("#push_notifications_1");
    assert.equal(checkbox.prop("checked"), true);

    // Tests email notifications
    stream_events.update_property(1, "email_notifications", true);
    assert.equal(frontend.email_notifications, true);
    checkbox = $("#email_notifications_1");
    assert.equal(checkbox.prop("checked"), true);

    // Tests wildcard_mentions_notify notifications
    stream_events.update_property(1, "wildcard_mentions_notify", true);
    assert.equal(frontend.wildcard_mentions_notify, true);
    checkbox = $("#wildcard_mentions_notify_1");
    assert.equal(checkbox.prop("checked"), true);

    // Test name change
    {
        with_stub((stub) => {
            override("subs.update_stream_name", stub.f);
            stream_events.update_property(1, "name", "the frontend");
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, "the frontend");
        });
    }

    // Test description change
    {
        with_stub((stub) => {
            override("subs.update_stream_description", stub.f);
            stream_events.update_property(1, "description", "we write code", {
                rendered_description: "we write code",
            });
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, "we write code");
        });
    }

    // Test email address change
    stream_events.update_property(1, "email_address", "zooly@zulip.com");
    assert.equal(frontend.email_address, "zooly@zulip.com");

    // Test pin to top
    {
        override("stream_list.refresh_pinned_or_unpinned_stream", noop);
        stream_events.update_property(1, "pin_to_top", true);
        checkbox = $("#pin_to_top_1");
        assert.equal(checkbox.prop("checked"), true);
    }

    // Test stream privacy change event
    {
        with_stub((stub) => {
            override("subs.update_stream_privacy", stub.f);
            stream_events.update_property(1, "invite_only", true, {
                history_public_to_subscribers: true,
            });
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.deepEqual(args.val, {
                invite_only: true,
                history_public_to_subscribers: true,
            });
        });
    }

    // Test stream stream_post_policy change event
    {
        with_stub((stub) => {
            override("subs.update_stream_post_policy", stub.f);
            stream_events.update_property(
                1,
                "stream_post_policy",
                stream_data.stream_post_policy_values.admins.code,
            );
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, stream_data.stream_post_policy_values.admins.code);
        });
    }

    // Test stream message_retention_days change event
    {
        with_stub((stub) => {
            override("subs.update_message_retention_setting", stub.f);
            stream_events.update_property(1, "message_retention_days", 20);
            const args = stub.get_args("sub", "val");
            assert.equal(args.sub.stream_id, 1);
            assert.equal(args.val, 20);
        });
    }
});

run_test("marked_subscribed", (override) => {
    override("stream_data.subscribe_myself", noop);
    override("stream_data.update_calculated_fields", noop);

    // Test undefined error
    {
        let errors = 0;
        override("blueslip.error", () => {
            errors += 1;
        });
        stream_events.mark_subscribed(undefined, [], "yellow");
        assert.equal(errors, 1);
    }

    // Test early return if subscribed
    {
        let completed = false;
        override("message_util.do_unread_count_updates", () => {
            completed = true; // This gets run if we continue and don't early return
        });
        const subscribed = {subscribed: true};
        stream_events.mark_subscribed(subscribed, [], "yellow");
        assert.equal(completed, false);

        // prevent warning about spurious override
        message_util.do_unread_count_updates();
    }

    set_global("message_list", {
        all: {
            all_messages() {
                return ["msg"];
            },
        },
    });

    set_global("subs", {update_settings_for_subscribed: noop});
    set_global("overlays", {streams_open: return_true});

    // Test basic dispatching and updating stream color
    narrow_state.set_current_filter(frontend_filter);
    {
        let args;
        let list_updated = false;

        const stream_list_stub = make_stub();
        const message_view_header_stub = make_stub();
        const message_util_stub = make_stub();

        override("stream_color.update_stream_color", noop);
        override("stream_list.add_sidebar_row", stream_list_stub.f);
        override("message_util.do_unread_count_updates", message_util_stub.f);
        override("message_view_header.render_title_area", message_view_header_stub.f);
        override("current_msg_list.update_trailing_bookend", () => {
            list_updated = true;
        });

        stream_events.mark_subscribed(frontend, [], "blue");

        args = message_util_stub.get_args("messages");
        assert.deepEqual(args.messages, ["msg"]);

        args = stream_list_stub.get_args("sub");
        assert.equal(args.sub.stream_id, 1);
        assert.equal(message_view_header_stub.num_calls, 1);

        assert.equal(list_updated, true);

        assert.equal(frontend.color, "blue");
    }
    narrow_state.reset_current_filter();

    // Test assigning generated color
    {
        frontend.color = undefined;
        override("color_data.pick_color", () => "green");
        let warnings = 0;
        override("blueslip.warn", () => {
            warnings += 1;
        });

        // narrow state is undefined
        with_stub((stub) => {
            override("message_util.do_unread_count_updates", noop);
            override("stream_list.add_sidebar_row", noop);
            override("subs.set_color", stub.f);
            stream_events.mark_subscribed(frontend, [], undefined);
            const args = stub.get_args("id", "color");
            assert.equal(args.id, 1);
            assert.equal(args.color, "green");
            assert.equal(warnings, 1);
        });
    }

    // Test assigning subscriber emails
    // narrow state is undefined
    {
        override("stream_color.update_stream_color", noop);
        override("message_util.do_unread_count_updates", noop);
        override("stream_list.add_sidebar_row", noop);

        const user_ids = [15, 20, 25];
        stream_events.mark_subscribed(frontend, user_ids, "");
        assert.deepEqual(
            new Set(stream_data.get_subscribers(frontend.stream_id)),
            new Set(user_ids),
        );

        // assign self as well
        with_stub((stub) => {
            override("stream_data.subscribe_myself", stub.f);
            stream_events.mark_subscribed(frontend, [], "");
            const args = stub.get_args("sub");
            assert.deepEqual(frontend, args.sub);
        });

        // and finally update subscriber settings
        with_stub((stub) => {
            override("subs.update_settings_for_subscribed", stub.f);
            stream_events.mark_subscribed(frontend, [], "");
            const args = stub.get_args("sub");
            assert.deepEqual(frontend, args.sub);
        });
    }
});

run_test("mark_unsubscribed", (override) => {
    override("stream_data.update_calculated_fields", noop);

    {
        let removed_sub = false;
        override("stream_list.remove_sidebar_row", () => {
            removed_sub = true;
        });

        // take no action if no sub specified
        stream_events.mark_unsubscribed();
        assert.equal(removed_sub, false);

        // take no action if already unsubscribed
        frontend.subscribed = false;
        stream_events.mark_unsubscribed(frontend);
        assert.equal(removed_sub, false);

        // prevent warning about spurious mock
        stream_list.remove_sidebar_row();
    }

    // Test unsubscribe
    frontend.subscribed = true;
    {
        with_stub((stub) => {
            override("stream_data.unsubscribe_myself", stub.f);
            override("subs.update_settings_for_unsubscribed", noop);
            override("stream_list.remove_sidebar_row", noop);
            stream_events.mark_unsubscribed(frontend);
            const args = stub.get_args("sub");
            assert.deepEqual(args.sub, frontend);
        });
    }

    // Test update settings after unsubscribe
    {
        with_stub((stub) => {
            override("subs.update_settings_for_unsubscribed", stub.f);
            override("stream_data.unsubscribe_myself", noop);
            override("stream_list.remove_sidebar_row", noop);
            stream_events.mark_unsubscribed(frontend);
            const args = stub.get_args("sub");
            assert.deepEqual(args.sub, frontend);
        });
    }

    // Test update bookend and remove done event
    narrow_state.set_current_filter(frontend_filter);
    {
        const message_view_header_stub = make_stub();
        override("message_view_header.render_title_area", message_view_header_stub.f);
        override("stream_data.unsubscribe_myself", noop);
        override("subs.update_settings_for_unsubscribed", noop);

        let updated = false;
        override("current_msg_list.update_trailing_bookend", () => {
            updated = true;
        });

        let event_triggered = false;
        override("stream_list.remove_sidebar_row", (stream_id) => {
            assert.equal(stream_id, frontend.stream_id);
            event_triggered = true;
        });

        stream_events.mark_unsubscribed(frontend);

        assert.equal(message_view_header_stub.num_calls, 1);
        assert.equal(updated, true);
        assert.equal(event_triggered, true);
    }
    narrow_state.reset_current_filter();
});

stream_data.clear_subscriptions();
const dev_help = {
    subscribed: true,
    color: "blue",
    name: "dev help",
    stream_id: 2,
    is_muted: true,
    invite_only: false,
};
stream_data.add_sub(dev_help);

run_test("remove_deactivated_user_from_all_streams", () => {
    const subs_stub = make_stub();
    subs.update_subscribers_ui = subs_stub.f;

    dev_help.can_access_subscribers = true;

    // assert starting state
    assert(!stream_data.is_user_subscribed(dev_help.stream_id, george.user_id));

    // verify that deactivating user should unsubscribe user from all streams
    assert(stream_data.add_subscriber(dev_help.stream_id, george.user_id));
    assert(stream_data.is_user_subscribed(dev_help.stream_id, george.user_id));

    stream_events.remove_deactivated_user_from_all_streams(george.user_id);

    // verify that we issue a call to update subscriber count/list UI
    assert.equal(subs_stub.num_calls, 1);
});
<|endoftext|>


<commit_before>'use strict';

import fs from 'fs';
import path from 'path';
import {} from './core/think.js';

export default class {
  /**
   * init
   * @param  {Object} options [project options]
   * @return {}         []
   */
  constructor(options = {}){
    //extend options to think
    think.extend(think, this.getPath(), options);
    //parse data from process arguments
    let i = 2;
    let argv = process.argv[i];
    //get app mode from argv
    if (argv === 'production' || argv === 'development') {
      think.env = argv;
      i++;
    }
    argv = process.argv[i];
    //get port or cli url from argv
    if (argv) {
      if (/^\d+$/.test(argv)) {
        think.port = argv;
      }else{
        think.cli = argv;
      }
    }
    //get app mode
    think.mode = this.getMode();
  }
  /**
   * get app mode
   * @return {Number} [app mode]
   */
  getMode(){
    let filepath = `${think.APP_PATH}/${think.dirname.controller}`;
    if (think.isDir(filepath)) {
      let files = fs.readdirSync(filepath);
      let flag = files.some(file => {
        if (think.isFile(`${filepath}/${file}`)) {
          return true;
        }
      });
      return flag ? think.mode_mini : think.mode_normal;
    }
    return think.mode_module;
  }
  /**
   * get app path
   * @return {Object} []
   */
  getPath(){
    let filepath = process.argv[1];
    let ROOT_PATH = path.dirname(filepath);
    let APP_PATH = `${path.dirname(ROOT_PATH)}/app`;
    return {
      APP_PATH,
      RESOURCE_PATH: ROOT_PATH,
      ROOT_PATH
    };
  }
  /**
   * check node env
   * @return {Boolean} []
   */
  checkEnv(){
    let packageFile = `${think.THINK_PATH}/package.json`;
    let {engines} = JSON.parse(fs.readFileSync(packageFile, 'utf-8'));
    let needVersion = engines.node.substr(2);
    let nodeVersion = process.version.substr(1);
    if(needVersion > nodeVersion){
      throw new Error(`ThinkJS need node version >= ${needVersion}, current version is ${nodeVersion}, please upgrade it.`);
    }
  }
  /**
   * check application filename is lower
   * @return {} []
   */
  checkFileName(){
    let files = think.getFiles(think.APP_PATH);
    let reg = /\.(js|html|tpl)$/;
    let fileReg = /^[\\\/_\.a-z0-9]+$/;
    let filter = item => {
      if(!reg.test(item)){
        return;
      }
      //ignore files in config/locale
      if(item.indexOf(think.dirname.locale) > -1){
        return;
      }
      return true;
    };
    files.forEach(item => {
      if(filter(item) && !fileReg.test(item)){
        think.log(colors => {
          return colors.yellow(`[WARNING]`) + ` filepath \`${item}\` has uppercase chars.`;
        });
      }
    });
  }
  /**
   * get app module list
   * @return {} []
   */
  getModule(){
    //only have default module in mini mode
    if (think.mode === think.mode_mini) {
      think.module = [think.config('default_module')];
      return think.module;
    }
    let modulePath = think.APP_PATH;
    if (think.mode === think.mode_normal) {
      modulePath += `/${think.dirname.controller}`;
    }
    if(!think.isDir(modulePath)){
      return [];
    }
    let modules = fs.readdirSync(modulePath);
    let denyModuleList = think.config('deny_module_list') || [];
    if (denyModuleList.length > 0) {
      modules = modules.filter(module => {
        if (denyModuleList.indexOf(module) === -1) {
          return module;
        }
      });
    }
    think.module = modules;
    return modules;
  }
  /**
   * load alias
   * @return {} []
   */
  loadAlias(){
    let aliasPath = `${think.THINK_LIB_PATH}/config/sys/alias.js`;
    thinkCache(thinkCache.ALIAS, require(aliasPath));
  }
  /**
   * load alias module export
   * @return {} []
   */
  loadAliasExport(){
    var alias = thinkCache(thinkCache.ALIAS);
    for(let key in alias){
      if (thinkCache(thinkCache.ALIAS_EXPORT, key)) {
        continue;
      }
      thinkCache(thinkCache.ALIAS_EXPORT, key, think.require(key));
    }
  }
  /**
   * load config
   * @return {} []
   */
  loadConfig(){
    //sys config
    let config = think.getModuleConfig(true);
    //common module config
    let commonConfig = think.getModuleConfig();
    let configs = think.extend(config, commonConfig);
    thinkCache(thinkCache.CONFIG, configs);
    let modules = this.getModule();
    //load modules config
    modules.forEach(module => {
      think.getModuleConfig(module);
    });
  }
  /**
   * load route
   * @return {} []
   */
  loadRoute(){
    think.route();
  }
  /**
   * load adapter
   * @return {} []
   */
  loadAdapter(){
    think.loadAdapter();
  }
  /**
   * load middleware
   * @return {} []
   */
  loadMiddleware(){
    let paths = [
      `${think.THINK_LIB_PATH}/middleware`,
      `${think.getPath(undefined, think.dirname.middleware)}`
    ];
    think.alias('middleware', paths);
    //middleware base class
    think.middleware.base = think.require('middleware_base');
  }
  /**
   * load hook
   * @return {} []
   */
  loadHook(){
    let hookPath = `${think.THINK_LIB_PATH}/config/hook.js`;
    let hook = require(hookPath);
    let file = `${think.getPath(undefined, think.dirname.config)}/hook.js`;
    let data = think.safeRequire(file) || {};
    let key, value;
    for(key in data){
      value = data[key];
      if (!(key in hook)) {
        hook[key] = data[key];
      }else if (think.isBoolean(data[0])) {
        let flag = value.shift();
        if (flag) {
          hook[key] = value;
        }else{
          hook[key] = value.concat(hook[key]);
        }
      }else{
        hook[key] = hook[key].concat(value);
      }
    }
    thinkCache(thinkCache.HOOK, hook);
  }
  /**
   * load controller, model, logic, service files
   * @return {} []
   */
  loadMVC(){
    let types = {
      model: ['base', 'relation'],
      controller: ['base', 'rest'],
      logic: ['base'],
      service: ['base']
    };
    for(let type in types){
      think.alias(type, `${think.THINK_LIB_PATH}/${type}`);
      types[type].forEach(item => {
        think[type][item] = think.require(`${type}_${item}`);
      });
      think.module.forEach(module => {
        let moduleType = `${module}/${type}`;
        let filepath = think.getPath(module, think.dirname[type]);
        think.alias(moduleType, filepath, true);
      });
    }
  }
  /**
   * load bootstrap
   * @return {} []
   */
  loadBootstrap(){
    let paths = [
      `${think.THINK_LIB_PATH}/bootstrap`,
      `${think.APP_PATH}/${think.dirname.common}/${think.dirname.bootstrap}`
    ];
    paths.forEach(item => {
      if (!think.isDir(item)) {
        return;
      }
      let files = fs.readdirSync(item);
      files.forEach(file => {
        think.safeRequire(`${item}/${file}`);
      });
    });
  }
  /**
   * load template file
   * add template files to cache
   * @return {} []
   */
  loadTemplate(){
    let data = {};

    let add = filepath => {
      if (!think.isDir(filepath)) {
        return;
      }
      let files = think.getFiles(filepath);
      files.forEach(file => {
        let key = path.normalize(`${filepath}/${file}`);
        data[key] = true;
      });
    };
    let {root_path} = think.config('view');
    if(root_path){
      add(root_path);
    }else{
      think.module.forEach(module => {
        add(think.getPath(module, think.dirname.view));
      });
    }
    thinkCache(thinkCache.TEMPLATE, data);
  }
  /**
   * load system error message
   * @return {} []
   */
  loadError(){
    let message = require(think.THINK_LIB_PATH + '/config/sys/error.js');
    thinkCache(thinkCache.ERROR, message);
  }
  /**
   * load all config or modules
   * @return {} []
   */
  load(){
    //clear all cache for reload
    thinkCache(thinkCache.ALIAS, null);
    thinkCache(thinkCache.ALIAS_EXPORT, null);
    thinkCache(thinkCache.MODULE_CONFIG, null);

    this.loadConfig();
    this.loadRoute();
    this.loadAlias();
    this.loadAdapter();
    this.loadMiddleware();
    this.loadMVC();
    this.loadHook();
    this.loadTemplate();
    this.loadError();

    this.loadBootstrap();

    //load alias export at last
    //this.loadAliasExport();
  }
  /**
   * auto reload user modified files
   * @return {} []
   */
  autoReload(){
    let autoReload = thinkCache(thinkCache.AUTO_RELOAD);
    //clear file cache
    let clearFileCache = file => {
      let mod = require.cache[file];
      //remove from parent module
      if(mod && mod.parent){
        mod.parent.children.splice(mod.parent.children.indexOf(mod), 1);
      }
      //remove children
      if(mod && mod.children){
        mod.children.length = 0;
      }
      //remove require cache
      require.cache[file] = null;
    };
    let fn = () => {
      let hasChange = false;
      for(let file in require.cache){
        let mTime = fs.statSync(file).mtime.getTime();
        if(!autoReload[file]){
          autoReload[file] = mTime;
          continue;
        }
        if(mTime > autoReload[file]){
          clearFileCache(file);
          autoReload[file] = mTime;
          hasChange = true;
        }
      }
      if(hasChange){
        this.load();
      }
    };
    setInterval(fn.bind(this), 1000);
  }
  /**
   * capture error
   * @return {} []
   */
  captureError(){
    process.on('uncaughtException', function(err){
      err = think.error(err, 'port:' + think.config('port'));
      think.log(err);
    });
  }
  /**
   * start
   * @return {} []
   */
  start(){
    this.checkEnv();
    this.checkFileName();
    this.load();
    this.captureError();
    if (think.config('auto_reload')) {
      this.autoReload();
    }
  }
  /**
   * run
   * @return {} []
   */
  run(){
    this.start();
    return think.require('app').run();
  }
}<commit_msg>fix merge hook error<commit_after>'use strict';

import fs from 'fs';
import path from 'path';
import {} from './core/think.js';

export default class {
  /**
   * init
   * @param  {Object} options [project options]
   * @return {}         []
   */
  constructor(options = {}){
    //extend options to think
    think.extend(think, this.getPath(), options);
    //parse data from process arguments
    let i = 2;
    let argv = process.argv[i];
    //get app mode from argv
    if (argv === 'production' || argv === 'development') {
      think.env = argv;
      i++;
    }
    argv = process.argv[i];
    //get port or cli url from argv
    if (argv) {
      if (/^\d+$/.test(argv)) {
        think.port = argv;
      }else{
        think.cli = argv;
      }
    }
    //get app mode
    think.mode = this.getMode();
  }
  /**
   * get app mode
   * @return {Number} [app mode]
   */
  getMode(){
    let filepath = `${think.APP_PATH}/${think.dirname.controller}`;
    if (think.isDir(filepath)) {
      let files = fs.readdirSync(filepath);
      let flag = files.some(file => {
        if (think.isFile(`${filepath}/${file}`)) {
          return true;
        }
      });
      return flag ? think.mode_mini : think.mode_normal;
    }
    return think.mode_module;
  }
  /**
   * get app path
   * @return {Object} []
   */
  getPath(){
    let filepath = process.argv[1];
    let ROOT_PATH = path.dirname(filepath);
    let APP_PATH = `${path.dirname(ROOT_PATH)}/app`;
    return {
      APP_PATH,
      RESOURCE_PATH: ROOT_PATH,
      ROOT_PATH
    };
  }
  /**
   * check node env
   * @return {Boolean} []
   */
  checkEnv(){
    let packageFile = `${think.THINK_PATH}/package.json`;
    let {engines} = JSON.parse(fs.readFileSync(packageFile, 'utf-8'));
    let needVersion = engines.node.substr(2);
    let nodeVersion = process.version.substr(1);
    if(needVersion > nodeVersion){
      throw new Error(`ThinkJS need node version >= ${needVersion}, current version is ${nodeVersion}, please upgrade it.`);
    }
  }
  /**
   * check application filename is lower
   * @return {} []
   */
  checkFileName(){
    let files = think.getFiles(think.APP_PATH);
    let reg = /\.(js|html|tpl)$/;
    let fileReg = /^[\\\/_\.a-z0-9]+$/;
    let filter = item => {
      if(!reg.test(item)){
        return;
      }
      //ignore files in config/locale
      if(item.indexOf(think.dirname.locale) > -1){
        return;
      }
      return true;
    };
    files.forEach(item => {
      if(filter(item) && !fileReg.test(item)){
        think.log(colors => {
          return colors.yellow(`[WARNING]`) + ` filepath \`${item}\` has uppercase chars.`;
        });
      }
    });
  }
  /**
   * get app module list
   * @return {} []
   */
  getModule(){
    //only have default module in mini mode
    if (think.mode === think.mode_mini) {
      think.module = [think.config('default_module')];
      return think.module;
    }
    let modulePath = think.APP_PATH;
    if (think.mode === think.mode_normal) {
      modulePath += `/${think.dirname.controller}`;
    }
    if(!think.isDir(modulePath)){
      return [];
    }
    let modules = fs.readdirSync(modulePath);
    let denyModuleList = think.config('deny_module_list') || [];
    if (denyModuleList.length > 0) {
      modules = modules.filter(module => {
        if (denyModuleList.indexOf(module) === -1) {
          return module;
        }
      });
    }
    think.module = modules;
    return modules;
  }
  /**
   * load alias
   * @return {} []
   */
  loadAlias(){
    let aliasPath = `${think.THINK_LIB_PATH}/config/sys/alias.js`;
    thinkCache(thinkCache.ALIAS, require(aliasPath));
  }
  /**
   * load alias module export
   * @return {} []
   */
  loadAliasExport(){
    var alias = thinkCache(thinkCache.ALIAS);
    for(let key in alias){
      if (thinkCache(thinkCache.ALIAS_EXPORT, key)) {
        continue;
      }
      thinkCache(thinkCache.ALIAS_EXPORT, key, think.require(key));
    }
  }
  /**
   * load config
   * @return {} []
   */
  loadConfig(){
    //sys config
    let config = think.getModuleConfig(true);
    //common module config
    let commonConfig = think.getModuleConfig();
    let configs = think.extend(config, commonConfig);
    thinkCache(thinkCache.CONFIG, configs);
    let modules = this.getModule();
    //load modules config
    modules.forEach(module => {
      think.getModuleConfig(module);
    });
  }
  /**
   * load route
   * @return {} []
   */
  loadRoute(){
    think.route();
  }
  /**
   * load adapter
   * @return {} []
   */
  loadAdapter(){
    think.loadAdapter();
  }
  /**
   * load middleware
   * @return {} []
   */
  loadMiddleware(){
    let paths = [
      `${think.THINK_LIB_PATH}/middleware`,
      `${think.getPath(undefined, think.dirname.middleware)}`
    ];
    think.alias('middleware', paths);
    //middleware base class
    think.middleware.base = think.require('middleware_base');
  }
  /**
   * load hook
   * @return {} []
   */
  loadHook(){
    let hookPath = `${think.THINK_LIB_PATH}/config/hook.js`;
    let hook = require(hookPath);
    let file = `${think.getPath(undefined, think.dirname.config)}/hook.js`;
    let data = think.safeRequire(file) || {};
    let key, value;
    for(key in data){
      value = data[key];
      if (!(key in hook)) {
        hook[key] = data[key];
      }else if (value[0] === 'append' || value[0] === 'prepend') {
        let flag = value.shift();
        if (flag === 'append') {
          hook[key] = hook[key].concat(value);
        }else{
          hook[key] = value.concat(hook[key]);
        }
      }else{
        hook[key] = value;
      }
    }
    thinkCache(thinkCache.HOOK, hook);
  }
  /**
   * load controller, model, logic, service files
   * @return {} []
   */
  loadMVC(){
    let types = {
      model: ['base', 'relation'],
      controller: ['base', 'rest'],
      logic: ['base'],
      service: ['base']
    };
    for(let type in types){
      think.alias(type, `${think.THINK_LIB_PATH}/${type}`);
      types[type].forEach(item => {
        think[type][item] = think.require(`${type}_${item}`);
      });
      think.module.forEach(module => {
        let moduleType = `${module}/${type}`;
        let filepath = think.getPath(module, think.dirname[type]);
        think.alias(moduleType, filepath, true);
      });
    }
  }
  /**
   * load bootstrap
   * @return {} []
   */
  loadBootstrap(){
    let paths = [
      `${think.THINK_LIB_PATH}/bootstrap`,
      `${think.APP_PATH}/${think.dirname.common}/${think.dirname.bootstrap}`
    ];
    paths.forEach(item => {
      if (!think.isDir(item)) {
        return;
      }
      let files = fs.readdirSync(item);
      files.forEach(file => {
        think.safeRequire(`${item}/${file}`);
      });
    });
  }
  /**
   * load template file
   * add template files to cache
   * @return {} []
   */
  loadTemplate(){
    let data = {};

    let add = filepath => {
      if (!think.isDir(filepath)) {
        return;
      }
      let files = think.getFiles(filepath);
      files.forEach(file => {
        let key = path.normalize(`${filepath}/${file}`);
        data[key] = true;
      });
    };
    let {root_path} = think.config('view');
    if(root_path){
      add(root_path);
    }else{
      think.module.forEach(module => {
        add(think.getPath(module, think.dirname.view));
      });
    }
    thinkCache(thinkCache.TEMPLATE, data);
  }
  /**
   * load system error message
   * @return {} []
   */
  loadError(){
    let message = require(think.THINK_LIB_PATH + '/config/sys/error.js');
    thinkCache(thinkCache.ERROR, message);
  }
  /**
   * load all config or modules
   * @return {} []
   */
  load(){
    //clear all cache for reload
    thinkCache(thinkCache.ALIAS, null);
    thinkCache(thinkCache.ALIAS_EXPORT, null);
    thinkCache(thinkCache.MODULE_CONFIG, null);

    this.loadConfig();
    this.loadRoute();
    this.loadAlias();
    this.loadAdapter();
    this.loadMiddleware();
    this.loadMVC();
    this.loadHook();
    this.loadTemplate();
    this.loadError();

    this.loadBootstrap();

    //load alias export at last
    //this.loadAliasExport();
  }
  /**
   * auto reload user modified files
   * @return {} []
   */
  autoReload(){
    let autoReload = thinkCache(thinkCache.AUTO_RELOAD);
    //clear file cache
    let clearFileCache = file => {
      let mod = require.cache[file];
      //remove from parent module
      if(mod && mod.parent){
        mod.parent.children.splice(mod.parent.children.indexOf(mod), 1);
      }
      //remove children
      if(mod && mod.children){
        mod.children.length = 0;
      }
      //remove require cache
      require.cache[file] = null;
    };
    let fn = () => {
      let hasChange = false;
      for(let file in require.cache){
        let mTime = fs.statSync(file).mtime.getTime();
        if(!autoReload[file]){
          autoReload[file] = mTime;
          continue;
        }
        if(mTime > autoReload[file]){
          clearFileCache(file);
          autoReload[file] = mTime;
          hasChange = true;
        }
      }
      if(hasChange){
        this.load();
      }
    };
    setInterval(fn.bind(this), 1000);
  }
  /**
   * capture error
   * @return {} []
   */
  captureError(){
    process.on('uncaughtException', function(err){
      err = think.error(err, 'port:' + think.config('port'));
      think.log(err);
    });
  }
  /**
   * start
   * @return {} []
   */
  start(){
    this.checkEnv();
    this.checkFileName();
    this.load();
    this.captureError();
    if (think.config('auto_reload')) {
      this.autoReload();
    }
  }
  /**
   * run
   * @return {} []
   */
  run(){
    this.start();
    return think.require('app').run();
  }
}<|endoftext|>


<commit_before>Kawaii = {

  // Two spaces for tabs is good!
  tab_format : "  ",

  initialize : function() {
    this.tab_view = new YAHOO.widget.TabView('console_tabs');
    this.tab_number = 1
    this.wrap_results = true
    this.authenticity_token = $('kawaii_content').getAttribute('authenticity_token')

    this.snippets_enabled = ($('snippets') != null)

    // Load our snippets if we have a div for them
    if (this.snippets_enabled) {
      $('snippets').show()
      new Ajax.Request('/kawaii/snippets', {parameters:'authenticity_token=' + encodeURIComponent(this.authenticity_token), asynchronous:true, evalScripts:true})
    }

    this.add_tab()

  },

  add_tab : function (name, value) {

    var whole_tab = new Element("div")
    var query_container = new Element("div", {'class' : 'query_container'})

    var close = new Element("input",
                            {'type': 'button',
                             'value': 'Close Tab',
                             'class': 'close_tab',
                             'onClick' : "Kawaii.close_tab(); return false;"})
    whole_tab.insert(new Element('div', {'class':'tab_header'}).insert(close))

    var query_id = "query_input_" + this.tab_number
    query_container.insert(new Element('div', {'class': 'text_area_container'}).insert(
      new Element('textarea', {'id': query_id, 'onkeypress': "Kawaii.text_area_keypress(event);", 'tab_number':this.tab_number}).update(value))
    )

    query_container.insert(new Element("input",
                                        {'type': 'button',
                                         'value': 'Execute',
                                         'class': 'execute',
                                         'onClick' : "Kawaii.execute(" + this.tab_number + "); return false;"}))
    query_container.insert(new Element('span', {'class':'keyboard_shortcut'}).update("Ctrl-Enter"))

    if (this.snippets_enabled) {
     query_container.insert(new Element("input",
                                         {'type': 'button',
                                          'value': 'Save Snippet',
                                          'class': 'save_query',
                                          'onClick' : "Kawaii.save_query(" + this.tab_number + "); return false;"}))
    }

    query_container.insert(new Element('div', {'id': 'loading_results_' + this.tab_number, 'style': 'display:none'}).update("
Loading...
"))
    query_container.insert(new Element('div', {'id': 'results_' + this.tab_number, 'class': 'results'}))

    var html = whole_tab.insert(query_container).innerHTML

    var this_tab = new YAHOO.widget.Tab({ label: (name || "Rails Code"), content: html, active: true })
    this.tab_view.addTab( this_tab )
    this.tab_number++

    $('tab_container').show()
    $(query_id).focus()
  },

  close_tab : function () {
      this.tab_view.removeTab(this.tab_view.get('activeTab'));

      if (this.tab_view.get('tabs').length == 0) {
        $('tab_container').hide()
      }

  },

  with_query : function (tab_number, with_query_function) {
    var query = $('query_input_' + tab_number).value
    if (query.length == 0) {
      alert('Your snippet is blank!')
    } else {
      with_query_function(query)
    }
  },

  execute : function (tab_number) {
    var authenticity_token = this.authenticity_token
    this.with_query(tab_number, function (query) {
      $('loading_results_' + tab_number).show()
      new Ajax.Request('/kawaii/query',
                       {asynchronous:true,
                        evalScripts:true,
                        parameters:{'query':query, 'tab_number': tab_number, 'authenticity_token': authenticity_token}})
    })
  },

  save_query : function (tab_number) {
    var authenticity_token = this.authenticity_token
    this.with_query(tab_number, function (query) {

      snippet_name = prompt("Type in a short name for the snippet")
      $('saving_snippet').show()
      new Ajax.Request('/kawaii/save_query',
                       {asynchronous:true,
                        evalScripts:true,
                        parameters:{'query':query, 'tab_number': tab_number, 'snippet_name': snippet_name, 'authenticity_token': authenticity_token}})
    })
  },

  show_grid : function (tab_number, columns, schema, data) {

    // Let's use client side paging!
    var oConfigs = {
            paginator: new YAHOO.widget.Paginator({rowsPerPage: 25}),
            scrollable: true,
            width: "100%",
            initialRequest: "results=504"
    };

    this.myDataSource = new YAHOO.util.DataSource(data);
    this.myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
    this.myDataSource.responseSchema = {
        fields: schema
    };

    winwidth=parseInt(document.all?document.body.clientwidth:window.innerwidth)
    winHeight=parseInt(document.all?document.body.clientHeight:window.innerHeight)

    this.myDataTable = new YAHOO.widget.DataTable("results_" + tab_number,
            columns, this.myDataSource, oConfigs);
    $('loading_results_' + tab_number).hide()
  },

  show_string : function (tab_number, string) {

    var results_div = $('results_' + tab_number)

    var formatted = string.replace(/\n/g, "
").replace(/ /g, " ")

    results_div.update(new Element('div', {'class': 'text_container'}).update(
      new Element('div', {'class':'result_text' + (this.wrap_results ? '' : ' avoid_wrap'), 'id': 'text_result_' + tab_number}).update(formatted))
    )
    results_div.insert(new Element('input', {'type': 'checkbox',
                                              'id': 'wrap_' + tab_number,
                                              'onclick':'Kawaii.toggle_wrap_results(' + tab_number + ")",
                                              'checked': (this.wrap_results ? 'true' : null)}))
    results_div.insert(new Element('label', {'for' : 'wrap_' + tab_number}).update("Wrap Text"))

    $('loading_results_' + tab_number).hide()
  },

  toggle_wrap_results : function(tab_number) {

    this.wrap_results = !this.wrap_results
    if (this.wrap_results == false) {
      $('text_result_' + tab_number).addClassName('avoid_wrap')
    } else {
      $('text_result_' + tab_number).removeClassName('avoid_wrap')
    }
  },

  text_area_keypress : function (evt) {
    var t = evt.target;
    var ss = t.selectionStart;
    var se = t.selectionEnd;

    var code;
    if (evt.keyCode) code = evt.keyCode;
    else if (evt.which) code = evt.which;

    // Ctrl+Return -> execute
    if (code == 13 && evt.ctrlKey) {
      this.execute(t.getAttribute('tab_number'))
      return true
    }

    // Thanks: http://ajaxian.com/archives/handling-tabs-in-textareas
    // Tab key - insert tab expansion
    if (evt.keyCode == 9) {
        evt.preventDefault();
        // Special case of multi line selection
        if (ss != se && t.value.slice(ss,se).indexOf("\n") != -1) {
            // In case selection was not of entire lines (e.g. selection begins in the middle of a line)
            // we ought to tab at the beginning as well as at the start of every following line.
            var pre = t.value.slice(0,ss);
            var sel = t.value.slice(ss,se).replace(/\n/g,"\n"+this.tab_format);
            var post = t.value.slice(se,t.value.length);
            t.value = pre.concat(this.tab_format).concat(sel).concat(post);
            t.selectionStart = ss + this.tab_format.length;
            t.selectionEnd = se + this.tab_format.length;
        }
        // "Normal" case (no selection or selection on one line only)
        else {
            t.value = t.value.slice(0,ss).concat(this.tab_format).concat(t.value.slice(ss,t.value.length));
            if (ss == se) {
                t.selectionStart = t.selectionEnd = ss + this.tab_format.length;
            }
            else {
                t.selectionStart = ss + this.tab_format.length;
                t.selectionEnd = se + this.tab_format.length;
            }
        }
    }
    // Backspace key - delete preceding tab expansion, if exists
   else if (evt.keyCode==8 && t.value.slice(ss - 4,ss) == this.tab_format) {
        evt.preventDefault();
        t.value = t.value.slice(0,ss - 4).concat(t.value.slice(ss,t.value.length));
        t.selectionStart = t.selectionEnd = ss - this.tab_format.length;
    }
    // Delete key - delete following tab expansion, if exists
    else if (evt.keyCode==46 && t.value.slice(se,se + 4) == this.tab_format) {
        evt.preventDefault();
        t.value = t.value.slice(0,ss).concat(t.value.slice(ss + 4,t.value.length));
        t.selectionStart = t.selectionEnd = ss;
    }
    // Left/right arrow keys - move across the tab in one go
    else if (evt.keyCode == 37 && t.value.slice(ss - 4,ss) == this.tab_format) {
        evt.preventDefault();
        t.selectionStart = t.selectionEnd = ss - 4;
    }
    else if (evt.keyCode == 39 && t.value.slice(ss,ss + 4) == this.tab_format) {
        evt.preventDefault();
        t.selectionStart = t.selectionEnd = ss + 4;
    }
  }

}

YAHOO.util.Event.onDOMReady(function() { Kawaii.initialize() })
<commit_msg>Kawaii now escapes HTML when it's displayed in a grid. Fixes Issue 7 in the google issue tracker.<commit_after>Kawaii = {

  // Two spaces for tabs is good!
  tab_format : "  ",

  initialize : function() {
    this.tab_view = new YAHOO.widget.TabView('console_tabs');
    this.tab_number = 1
    this.wrap_results = true
    this.authenticity_token = $('kawaii_content').getAttribute('authenticity_token')

    this.snippets_enabled = ($('snippets') != null)

    // Load our snippets if we have a div for them
    if (this.snippets_enabled) {
      $('snippets').show()
      new Ajax.Request('/kawaii/snippets', {parameters:'authenticity_token=' + encodeURIComponent(this.authenticity_token), asynchronous:true, evalScripts:true})
    }

    this.add_tab()

  },

  add_tab : function (name, value) {

    var whole_tab = new Element("div")
    var query_container = new Element("div", {'class' : 'query_container'})

    var close = new Element("input",
                            {'type': 'button',
                             'value': 'Close Tab',
                             'class': 'close_tab',
                             'onClick' : "Kawaii.close_tab(); return false;"})
    whole_tab.insert(new Element('div', {'class':'tab_header'}).insert(close))

    var query_id = "query_input_" + this.tab_number
    query_container.insert(new Element('div', {'class': 'text_area_container'}).insert(
      new Element('textarea', {'id': query_id, 'onkeypress': "Kawaii.text_area_keypress(event);", 'tab_number':this.tab_number}).update(value))
    )

    query_container.insert(new Element("input",
                                        {'type': 'button',
                                         'value': 'Execute',
                                         'class': 'execute',
                                         'onClick' : "Kawaii.execute(" + this.tab_number + "); return false;"}))
    query_container.insert(new Element('span', {'class':'keyboard_shortcut'}).update("Ctrl-Enter"))

    if (this.snippets_enabled) {
     query_container.insert(new Element("input",
                                         {'type': 'button',
                                          'value': 'Save Snippet',
                                          'class': 'save_query',
                                          'onClick' : "Kawaii.save_query(" + this.tab_number + "); return false;"}))
    }

    query_container.insert(new Element('div', {'id': 'loading_results_' + this.tab_number, 'style': 'display:none'}).update("
Loading...
"))
    query_container.insert(new Element('div', {'id': 'results_' + this.tab_number, 'class': 'results'}))

    var html = whole_tab.insert(query_container).innerHTML

    var this_tab = new YAHOO.widget.Tab({ label: (name || "Rails Code"), content: html, active: true })
    this.tab_view.addTab( this_tab )
    this.tab_number++

    $('tab_container').show()
    $(query_id).focus()
  },

  close_tab : function () {
      this.tab_view.removeTab(this.tab_view.get('activeTab'));

      if (this.tab_view.get('tabs').length == 0) {
        $('tab_container').hide()
      }

  },

  with_query : function (tab_number, with_query_function) {
    var query = $('query_input_' + tab_number).value
    if (query.length == 0) {
      alert('Your snippet is blank!')
    } else {
      with_query_function(query)
    }
  },

  execute : function (tab_number) {
    var authenticity_token = this.authenticity_token
    this.with_query(tab_number, function (query) {
      $('loading_results_' + tab_number).show()
      new Ajax.Request('/kawaii/query',
                       {asynchronous:true,
                        evalScripts:true,
                        parameters:{'query':query, 'tab_number': tab_number, 'authenticity_token': authenticity_token}})
    })
  },

  save_query : function (tab_number) {
    var authenticity_token = this.authenticity_token
    this.with_query(tab_number, function (query) {

      snippet_name = prompt("Type in a short name for the snippet")
      $('saving_snippet').show()
      new Ajax.Request('/kawaii/save_query',
                       {asynchronous:true,
                        evalScripts:true,
                        parameters:{'query':query, 'tab_number': tab_number, 'snippet_name': snippet_name, 'authenticity_token': authenticity_token}})
    })
  },

  show_grid : function (tab_number, columns, schema, data) {

    // Let's use client side paging!
    var oConfigs = {
            paginator: new YAHOO.widget.Paginator({rowsPerPage: 25}),
            scrollable: true,
            width: "100%",
            initialRequest: "results=504"
    };

    // Escape the contents of the data
    data.each(function (row) {
      schema.each(function (col) {
        if (row[col]) row[col] = row[col].toString().escapeHTML()
      })
    })

    this.myDataSource = new YAHOO.util.DataSource(data);
    this.myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
    this.myDataSource.responseSchema = {
        fields: schema
    };

    winwidth=parseInt(document.all?document.body.clientwidth:window.innerwidth)
    winHeight=parseInt(document.all?document.body.clientHeight:window.innerHeight)

    this.myDataTable = new YAHOO.widget.DataTable("results_" + tab_number,
            columns, this.myDataSource, oConfigs);
    $('loading_results_' + tab_number).hide()
  },

  show_string : function (tab_number, string) {

    var results_div = $('results_' + tab_number)

    var formatted = string.replace(/\n/g, "
").replace(/ /g, " ")

    results_div.update(new Element('div', {'class': 'text_container'}).update(
      new Element('div', {'class':'result_text' + (this.wrap_results ? '' : ' avoid_wrap'), 'id': 'text_result_' + tab_number}).update(formatted))
    )
    results_div.insert(new Element('input', {'type': 'checkbox',
                                              'id': 'wrap_' + tab_number,
                                              'onclick':'Kawaii.toggle_wrap_results(' + tab_number + ")",
                                              'checked': (this.wrap_results ? 'true' : null)}))
    results_div.insert(new Element('label', {'for' : 'wrap_' + tab_number}).update("Wrap Text"))

    $('loading_results_' + tab_number).hide()
  },

  toggle_wrap_results : function(tab_number) {

    this.wrap_results = !this.wrap_results
    if (this.wrap_results == false) {
      $('text_result_' + tab_number).addClassName('avoid_wrap')
    } else {
      $('text_result_' + tab_number).removeClassName('avoid_wrap')
    }
  },

  text_area_keypress : function (evt) {
    var t = evt.target;
    var ss = t.selectionStart;
    var se = t.selectionEnd;

    var code;
    if (evt.keyCode) code = evt.keyCode;
    else if (evt.which) code = evt.which;

    // Ctrl+Return -> execute
    if (code == 13 && evt.ctrlKey) {
      this.execute(t.getAttribute('tab_number'))
      return true
    }

    // Thanks: http://ajaxian.com/archives/handling-tabs-in-textareas
    // Tab key - insert tab expansion
    if (evt.keyCode == 9) {
        evt.preventDefault();
        // Special case of multi line selection
        if (ss != se && t.value.slice(ss,se).indexOf("\n") != -1) {
            // In case selection was not of entire lines (e.g. selection begins in the middle of a line)
            // we ought to tab at the beginning as well as at the start of every following line.
            var pre = t.value.slice(0,ss);
            var sel = t.value.slice(ss,se).replace(/\n/g,"\n"+this.tab_format);
            var post = t.value.slice(se,t.value.length);
            t.value = pre.concat(this.tab_format).concat(sel).concat(post);
            t.selectionStart = ss + this.tab_format.length;
            t.selectionEnd = se + this.tab_format.length;
        }
        // "Normal" case (no selection or selection on one line only)
        else {
            t.value = t.value.slice(0,ss).concat(this.tab_format).concat(t.value.slice(ss,t.value.length));
            if (ss == se) {
                t.selectionStart = t.selectionEnd = ss + this.tab_format.length;
            }
            else {
                t.selectionStart = ss + this.tab_format.length;
                t.selectionEnd = se + this.tab_format.length;
            }
        }
    }
    // Backspace key - delete preceding tab expansion, if exists
   else if (evt.keyCode==8 && t.value.slice(ss - 4,ss) == this.tab_format) {
        evt.preventDefault();
        t.value = t.value.slice(0,ss - 4).concat(t.value.slice(ss,t.value.length));
        t.selectionStart = t.selectionEnd = ss - this.tab_format.length;
    }
    // Delete key - delete following tab expansion, if exists
    else if (evt.keyCode==46 && t.value.slice(se,se + 4) == this.tab_format) {
        evt.preventDefault();
        t.value = t.value.slice(0,ss).concat(t.value.slice(ss + 4,t.value.length));
        t.selectionStart = t.selectionEnd = ss;
    }
    // Left/right arrow keys - move across the tab in one go
    else if (evt.keyCode == 37 && t.value.slice(ss - 4,ss) == this.tab_format) {
        evt.preventDefault();
        t.selectionStart = t.selectionEnd = ss - 4;
    }
    else if (evt.keyCode == 39 && t.value.slice(ss,ss + 4) == this.tab_format) {
        evt.preventDefault();
        t.selectionStart = t.selectionEnd = ss + 4;
    }
  }

}

YAHOO.util.Event.onDOMReady(function() { Kawaii.initialize() })
<|endoftext|>


<commit_before>/*
 *= require jquery
 *= require jquery.cookie
 *= require handlebars
 */

function add_video(video)
{
    var template = Handlebars.compile($("#video-template").html());
    var html = template(video);
    $(html).hide().appendTo($("#videos")).fadeIn(1000);
    $("#video-delete-" + video.id).click(function(e) {
        e.preventDefault();
        $.ajax("/videos/" + video.id + "/", {
            type: "DELETE",
            success: function(e) {
                $("#video-" + video.id).hide("slow");
            },
            error: function(e) {
                $("#video-" + video.id).
                    append("
Could not contact the server.
");
            }
        });
    });
}

$(document).ready(function() {
    var csrftoken = $.cookie('csrftoken');
    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type)
                && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    });

    $.ajax("/videos/", {
        type: "GET",
        success: function(data) {
            var videos = $.parseJSON(data);
            for (i in videos)
            {
                var video = videos[i];
                add_video(video);
            }
        },
        error: function() {
            var div = $("div#videos");
            div.append("
Critical Failure
");
            div.append("
Could not contact the server.
");
        }
    });

    $("#submit-button").click(function() {
        var url_value = $("#url").val();
        var desc_value = $("#desc").val();
        var obj = {url: url_value, description: desc_value};
        var post_data = "data=" + JSON.stringify(obj);
        $.ajax("/videos/", {
            type: 'POST',
            data: post_data,
            success: function(msg) {
                var message = $.parseJSON(msg);
                if (message.status === 0)
                {
                    obj.id = message.message;
                    $("div#content").append(add_video(obj));
                }
                else
                {
                    $("div#add-messages").append("
Could not post video: " + message.message + "
");
                }
            },
            error: function(msg) {
                $("div#add-messages").append("
Could not contact the server.
");
            }
        });
    });
});

<commit_msg>Gave videos with no description a default one.<commit_after>/*
 *= require jquery
 *= require jquery.cookie
 *= require handlebars
 */

function add_video(video)
{
    var template = Handlebars.compile($("#video-template").html());
    var html = template(video);
    $(html).hide().appendTo($("#videos")).fadeIn(1000);
    $("#video-delete-" + video.id).click(function(e) {
        e.preventDefault();
        $.ajax("/videos/" + video.id + "/", {
            type: "DELETE",
            success: function(e) {
                $("#video-" + video.id).hide("slow");
            },
            error: function(e) {
                $("#video-" + video.id).
                    append("
Could not contact the server.
");
            }
        });
    });
}

$(document).ready(function() {
    var csrftoken = $.cookie('csrftoken');
    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type)
                && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    });

    $.ajax("/videos/", {
        type: "GET",
        success: function(data) {
            var videos = $.parseJSON(data);
            for (i in videos)
            {
                var video = videos[i];
                add_video(video);
            }
        },
        error: function() {
            var div = $("div#videos");
            div.append("
Critical Failure
");
            div.append("
Could not contact the server.
");
        }
    });

    $("#submit-button").click(function() {
        var url_value = $("#url").val();
        var desc_value = $("#desc").val();
        if (!desc_value)
        {
            desc_value = "Some video.";
        }
        var obj = {url: url_value, description: desc_value};
        var post_data = "data=" + JSON.stringify(obj);
        $.ajax("/videos/", {
            type: 'POST',
            data: post_data,
            success: function(msg) {
                var message = $.parseJSON(msg);
                if (message.status === 0)
                {
                    obj.id = message.message;
                    $("div#content").append(add_video(obj));
                }
                else
                {
                    $("div#add-messages").append("
Could not post video: " + message.message + "
");
                }
            },
            error: function(msg) {
                $("div#add-messages").append("
Could not contact the server.
");
            }
        });
    });
});

<|endoftext|>


<commit_before>/* eslint-disable flowtype/require-valid-file-annotation */

export Surface from './Surface';
export NodeGroup from './NodeGroup';
export TickGroup from './TickGroup';
<commit_msg>update exports<commit_after>/* eslint-disable flowtype/require-valid-file-annotation */

export Surface from './Surface';

export NodeGroup from './NodeGroup';
export TickGroup from './TickGroup';
<|endoftext|>


<commit_before>const Promise     = require('bluebird');
const _           = require('lodash');

const telegramApi = require('./telegram-api');
const telegramParser = require('./telegram-parser');

const httpServer = require('./http-server');
const log      = require('./logger')(__filename);

const DEFAULT_HOSTNAME = 'localhost';
const DEFAULT_PORT = 3000;

class Core {
  constructor(port = DEFAULT_PORT, hostname = DEFAULT_HOSTNAME) {

    this._apis = [];
    this._webhookUrl = null;
    this._port = port;
    this._hostname = hostname;

    this._monitors = [];
    this._commanders = [];
    this._responders = [];

    // HTTP-server
    this._server = httpServer(port, hostname);

  }

  // Use this if you don't want to use "new" keyword
  static create(port, hostname) {
    return new Core(port, hostname);
  }

  setTelegramApiKey(apiKey) {
    this._apis.push({ name: 'telegram', api: new telegramApi(apiKey) });
  }

  subscribeWebhook(options, callback) {
    // TODO: remove existing webhook when creating a new one
    if (!this._webhookUrl) {
      this._webhookUrl = options.url;

      this._server.post(options.url, req => {

        // Do the callback when a webhook event is fired
        callback(req);

      });

      // Set webhook also to API if it is supported
      this._apis.forEach(api => {
        if (_.isFunction(api.setWebhook)) {
          api.setWebhook(options);
        }
      });
    }
  }

  addCommander(commanderInstance) {
    if (!_.isFunction(commanderInstance.getBidForEvent)) {
      log.error('No getBidForEvent defined for', commanderInstance, 'ignoring!');
    } else if (_.isFunction(commanderInstance.handleEvent)) {
      log.error('No handleEvent defined for', commanderInstance, 'ignoring!');
    } else {
      this._commanders.push(commanderInstance);
    }
  }

  // "The Pipeline"
  processMessage(message) {
    // TODO: call queue

    // TODO: Support multiple chat platforms
    //       (Check from which API message came from)
    const event = telegramParser(message);

    // TODO: send event to all monitors

    // # Command & Respond -loop
    const commandHandlerCandidates = _.map(this._commanders, cmdr =>
      cmdr.getBidForEvent(event)
    );

    // (http://stackoverflow.com/questions/30309273/keep-the-values-only-from-the-promises-that-resolve-and-ignore-the-rejected)
    Promise.all(
      commandHandlerCandidates
        .map(promise => promise.reflect())
        .filter(promise => promise.isFulfilled())
    ).then(handlerBids => {
      // only fulfilled promises in here.
      log.debug(handlerBids);

      // One commander was interested in the event,
      // allow that commander to decide the response
      if (handlerBids.length === 1) {
          // TODO: Run commander's `process` function
      }

      // More than one commander was interested in the event,
      // tell user about this conflict
      else if (handlerBids.length > 1) {
          // TODO: Make user to decide which commander will take the control
      }

      // There was no interested commanders, send event to responders
      else {
          // TODO: Create responder logic
      }

    });
  }
}

module.exports = Core;
<commit_msg>[WIP] Implement more bits of the "message pipeline"<commit_after>const Promise     = require('bluebird');
const _           = require('lodash');

const telegramApi = require('./telegram-api');
const telegramParser = require('./telegram-parser');

const httpServer = require('./http-server');
const log      = require('./logger')(__filename);

const DEFAULT_HOSTNAME = 'localhost';
const DEFAULT_PORT = 3000;

class Core {
  constructor(port = DEFAULT_PORT, hostname = DEFAULT_HOSTNAME) {

    this._apis = [];

    // The handlers
    this._monitors = [];
    this._commanders = [];
    this._responders = [];

    // Telegram-related variables
    this._tgApi = null;
    this._webhookUrl = null;
    this._port = port;
    this._hostname = hostname;

    // HTTP-server
    this._server = httpServer(port, hostname);

  }

  // Use this if you don't want to use "new" keyword
  static create(port, hostname) {
    return new Core(port, hostname);
  }

  setTelegramApiKey(apiKey) {
    this._apis.push({ name: 'telegram', api: new telegramApi(apiKey) });
  }

  // Telegram-specific
  subscribeWebhook(options, callback) {
    // TODO: remove existing webhook when creating a new one
    if (!this._webhookUrl) {
      this._webhookUrl = options.url;

      this._server.post(options.url, req => {

        // Do the callback when a webhook event is fired
        callback(req);

      });

      // Set webhook also to API if it is supported
      this._apis.forEach(api => {
        if (_.isFunction(api.setWebhook)) {
          api.setWebhook(options);
        }
      });
    }
  }

  addCommander(commanderInstance) {
    if (!_.isFunction(commanderInstance.getBidForEvent)) {
      log.error('No getBidForEvent defined for', commanderInstance, 'ignoring!');
    } else if (_.isFunction(commanderInstance.handleEvent)) {
      log.error('No handleEvent defined for', commanderInstance, 'ignoring!');
    } else {
      this._commanders.push(commanderInstance);
    }
  }

  // "The start of the Pipeline"
  processMessage(message) {
    // TODO: call queue

    // TODO: Support multiple chat platforms
    //       (Check from which API message came from)
    const event = telegramParser(message);

    // TODO: send event to all monitors

    return Promise.resolve()
      .then(this.getIntentsFromCommanders(event))
      .then(function checkAreRespondersNeeded(intents) {
        if (intents.length === 0) {
          // No intents from Commanders - check from Responders
          return this.getIntentsFromResponders(event);
        } else {
          log.debug('Intents from Commanders!', intents);
          return intents;
        }
      })
      .then(function handleIntents(intents) {
        // In here we should have an array of "intents".
        // These intents may have come from Commanders or Responders,
        // it shouldn't matter at this point.
        //
        // (The intents of Responders will have that "priority" thing since all Responders
        //  will handle all the events, but let's figure out that later)
        //
        // In here the Intents should be "cleared" by using whatever bot platform we
        // currently are using.
        log.debug('Got intents', intents);
      });
  }

  getIntentsFromCommanders(event) {
    // # Command & Respond -loop
    const commandHandlerCandidates = _.map(this._commanders, cmdr =>
      cmdr.getBidForEvent(event)
    );

    return Promise.all(
      commandHandlerCandidates
        // Hack to tet only solved promises
        // (http://stackoverflow.com/questions/30309273/keep-the-values-only-from-the-promises-that-resolve-and-ignore-the-rejected)
        .map(promise => promise.reflect())
        .filter(promise => promise.isFulfilled())
    ).then(function solveHandlerCommander(handlerBids) {
      let winningBid = null;

      if (handlerBids.length > 1) {
        // More than one commander was interested in the event,
        // tell user about this conflict

        // TODO: Make user to decide which commander will take the control
        //  (this will require the Core to have some internal state which
        //   will listen for the user's response, and block those messages
        //   from going on. How to do that platform agnostically?)

        winningBid = handlerBids[0]; // TODO temp hack

      } else if (handlerBids.length === 0) {
        // Take the only bid we got
        winningBid = handlerBids[0];
      }

      if (!_.isNull(winningBid)) {
        // Get intents from the "winning Commander"
        return winningBid.commander.handleEvent(event);
      } else {
        // There was no interested from commanders, send empty array to
        // state that there are no intents from commanders
        return [];
      }
    });
  }

  getIntentsFromResponders(event) {
    // TODO!
    return [];
  }
}

module.exports = Core;
<|endoftext|>


<commit_before>var express = require('express'); var app = express();
var path = require('path');
var https = require('https');

var port = process.env.PORT || 8080;

app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, '/public')));

app.get('/', function(request, response) {
    response.render(path.join(__dirname, 'views', 'index'));
});

app.post('/event-handler', function(request) {
    var payload = '';

    request.on('data', function(chunk) {
        payload += chunk.toString();
    });

    request.on('end', function() {
        var pullRequest = JSON.parse(payload).pull_request;
        var sha = pullRequest.head.sha;
        var postData = JSON.stringify(
            {
                'state': 'success',
                'target_url': 'https://example.com/build/status',
                'description': 'The build succeeded!',
                'context': 'repo-state'
            }
        );

        var options = {
            protocol: 'https:',
            host: 'api.github.com',
            path: '/repos/ratherblue/ramis/statuses/' +
                sha + '?access_token=' + process.env.GITHUB_AUTH_TOKEN,
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': Buffer.byteLength(postData),
                'User-Agent': 'Ramis-App'
            }
        };

        var req = https.request(options, function(res) {
            res.setEncoding('utf8');
        });

        req.write(postData);
        req.end();
    });
});

app.get('/oauth', function(request, response) {
    var params = [
        'client_id=368d97fad7902db3554c',
        'redirect_uri=http://localhost:8080/oauth-success',
        'scope=public_repo'
    ];

    var url = 'https://github.com/login/oauth/authorize?' + params.join('&');

    response.redirect(url);
});

app.get('/oauth-success', function(request, response) {
    response.render(path.join(__dirname, 'views', 'success'));
});

app.listen(port, function() {
    // eslint-disable-next-line no-console
    console.log('Running on http://localhost:' + port);
});

exports.init = function() {
    return false;
};
<commit_msg>Fix var order, switch port to const<commit_after>var express = require('express');
var path = require('path');
var https = require('https');

var app = express();

const port = process.env.PORT || 8080;

app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, '/public')));

app.get('/', function(request, response) {
    response.render(path.join(__dirname, 'views', 'index'));
});

app.post('/event-handler', function(request) {
    var payload = '';

    request.on('data', function(chunk) {
        payload += chunk.toString();
    });

    request.on('end', function() {
        var pullRequest = JSON.parse(payload).pull_request;
        var sha = pullRequest.head.sha;
        var postData = JSON.stringify(
            {
                'state': 'success',
                'target_url': 'https://example.com/build/status',
                'description': 'The build succeeded!',
                'context': 'repo-state'
            }
        );

        var options = {
            protocol: 'https:',
            host: 'api.github.com',
            path: '/repos/ratherblue/ramis/statuses/' +
                sha + '?access_token=' + process.env.GITHUB_AUTH_TOKEN,
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': Buffer.byteLength(postData),
                'User-Agent': 'Ramis-App'
            }
        };

        var req = https.request(options, function(res) {
            res.setEncoding('utf8');
        });

        req.write(postData);
        req.end();
    });
});

app.get('/oauth', function(request, response) {
    var params = [
        'client_id=368d97fad7902db3554c',
        'redirect_uri=http://localhost:8080/oauth-success',
        'scope=public_repo'
    ];

    var url = 'https://github.com/login/oauth/authorize?' + params.join('&');

    response.redirect(url);
});

app.get('/oauth-success', function(request, response) {
    response.render(path.join(__dirname, 'views', 'success'));
});

app.listen(port, function() {
    // eslint-disable-next-line no-console
    console.log('Running on http://localhost:' + port);
});

exports.init = function() {
    return false;
};
<|endoftext|>


<commit_before>'use strict';

const applyDefaultOpts = opts => Object.assign({}, {
	encoding: 'utf8',
	chunkSize: 3
}, opts);

const b64 = () => {

};

b64.encode = (input, opts) => new Promise(resolve => {
	opts = applyDefaultOpts(opts);

	if (!(input instanceof Buffer)) {
		input = Buffer.from(input, opts.encoding);
	}

	const bufferLength = input.length;
	let currentIndex = 0;
	let output = '';

	setImmediate(function encodeChunk() {
		const chunk = input.slice(currentIndex, currentIndex + opts.chunkSize);
		output += chunk.toString('base64');
		currentIndex += opts.chunkSize;
		if (currentIndex < bufferLength) {
			setImmediate(encodeChunk);
		} else {
			resolve(output);
		}
	});
});

module.exports = b64;
<commit_msg>Make sure encode chunk size is in multiples of three bytes<commit_after>'use strict';

const applyDefaultOpts = opts => Object.assign({}, {
	encoding: 'utf8',
	chunkSize: 3
}, opts);

const b64 = () => {

};

b64.encode = (input, opts) => new Promise(resolve => {
	opts = applyDefaultOpts(opts);

	if (!(input instanceof Buffer)) {
		input = Buffer.from(input, opts.encoding);
	}

	const chunkMultiple = 3;
	opts.chunkSize = Math.max(chunkMultiple, (Math.ceil(opts.chunkSize / chunkMultiple) * chunkMultiple));

	const bufferLength = input.length;
	let currentIndex = 0;
	let output = '';

	setImmediate(function encodeChunk() {
		const chunk = input.slice(currentIndex, currentIndex + opts.chunkSize);
		output += chunk.toString('base64');
		currentIndex += opts.chunkSize;
		if (currentIndex < bufferLength) {
			setImmediate(encodeChunk);
		} else {
			resolve(output);
		}
	});
});

module.exports = b64;
<|endoftext|>


<commit_before>/*!
 * tweensy - Copyright (c) 2017 Jacob Buck
 * https://github.com/jacobbuck/tweensy
 * Licensed under the terms of the MIT license.
 */
import now from "performance-now";
import rafq from "rafq";

const queue = rafq();

const lerp = (v0, v1, t) => (1 - t) * v0 + t * v1;

const tween = options => {
  const {
    duration = 0,
    easing = t => t,
    from,
    onComplete = () => {},
    onProgress = () => {},
    to,
  } = options;

  let isFinished = false;
  let startTime = null;

  const tick = () => {
    const time = now();

    if (startTime === null) {
      startTime = time;
    }

    const progress = isFinished
      ? 1
      : Math.min((time - startTime) / options.duration, 1);

    const t = options.easing(progress);

    if (typeof from === "number") {
      options.onProgress(lerp(from, to, t));
    } else if (Array.isArray(from)) {
      options.onProgress(from.map((v, i) => lerp(v, to[i], t)));
    } else {
      options.onProgress(
        Object.keys(from).reduce((memo, i) => {
          memo[key] = lerp(from[i], to[i], t);
          return memo;
        }, {})
      );
    }

    if (progress === 1) {
      options.onComplete(time);
    } else {
      queue.add(tick);
    }
  };

  const stop = finish => {
    isFinished = true;

    if (!finish) {
      queue.remove(tick);
    }
  };

  tick();

  return stop;
};
<commit_msg>Interpolate object better<commit_after>/*!
 * tweensy - Copyright (c) 2017 Jacob Buck
 * https://github.com/jacobbuck/tweensy
 * Licensed under the terms of the MIT license.
 */
import now from "performance-now";
import rafq from "rafq";

const queue = rafq();

const lerp = (v0, v1, t) => (1 - t) * v0 + t * v1;

const tween = options => {
  const {
    duration = 0,
    easing = t => t,
    from,
    onComplete = () => {},
    onProgress = () => {},
    to,
  } = options;

  let isFinished = false;
  let startTime = null;

  const tick = () => {
    const time = now();

    if (startTime === null) {
      startTime = time;
    }

    const progress = isFinished
      ? 1
      : Math.min((time - startTime) / options.duration, 1);

    const t = options.easing(progress);

    if (typeof from === "number") {
      options.onProgress(lerp(from, to, t));
    } else if (Array.isArray(from)) {
      options.onProgress(from.map((v, i) => lerp(v, to[i], t)));
    } else if (typeof from === "object") {
      options.onProgress(
        Object.keys(from).reduce((memo, i) => {
          memo[i] = lerp(from[i], to[i], t);
          return memo;
        }, {})
      );
    }

    if (progress === 1) {
      options.onComplete(time);
    } else {
      queue.add(tick);
    }
  };

  const stop = finish => {
    isFinished = true;

    if (!finish) {
      queue.remove(tick);
    }
  };

  tick();

  return stop;
};
<|endoftext|>


<commit_before>import clsify from 'cls-middleware';
import {createNamespace} from 'continuation-local-storage';

const DEFAULT_NAME = 'cls-isoflux';
const APP = 'app';

export default class Isoflux {
  constructor(name = DEFAULT_NAME) {
    this._namespace = createNamespace(name);
    this._boundClsify = clsify(this._namespace);
  }

  middleware = (req, res, next) => {
    this._boundClsify(req, res, this._middlewareInternal(next));
  };

  _middlewareInternal(next) {
    this._namespace.set(APP, this.createApp());
    next();
  }

  createApp() {
    throw Error('not implemented');
  }

  getApp() {
    return this._namespace.get(APP);
  }

  createProxy(Class, options) {
    const isoflux = this;

    class Proxy {
      _getProxiedObject() {
        return isoflux._getProxiedObject(Class, options);
      }
    }

    function defineProxiedProperty(propertyName) {
      Proxy.prototype[propertyName] = function (...args) {
        const proxiedObject = this._getProxiedObject();
        return proxiedObject[propertyName].apply(proxiedObject, args);
      };
    }

    for (let propertyName in Class.prototype) {
      // Intentially capture prototype properties as well here.
      defineProxiedProperty(propertyName);
    }

    return Proxy;
  }

  _getProxiedObject(Class, options) {  // eslint-disable-line no-unused-vars
    throw Error('not implemented');
  }
}
<commit_msg>Fix middleware and proxy creation<commit_after>import clsify from 'cls-middleware';
import {createNamespace} from 'continuation-local-storage';

const DEFAULT_NAME = 'cls-isoflux';
const APP = 'app';

export default class Isoflux {
  constructor(name = DEFAULT_NAME) {
    this._namespace = createNamespace(name);
    this._boundClsify = clsify(this._namespace);
  }

  middleware = (req, res, next) => {
    this._boundClsify(req, res, () => this._middlewareInternal(next));
  };

  _middlewareInternal(next) {
    this._namespace.set(APP, this.createApp());
    next();
  }

  createApp() {
    throw Error('not implemented');
  }

  getApp() {
    return this._namespace.get(APP);
  }

  createProxy(Class, options) {
    class Proxy {}
    const isoflux = this;

    function defineProxiedProperty(propertyName) {
      Proxy.prototype[propertyName] = function (...args) {
        const proxiedObject = isoflux._getProxiedObject(Class, options);
        return proxiedObject[propertyName].apply(proxiedObject, args);
      };
    }

    // Intentially capture prototype properties as well here.
    for (let propertyName in Class.prototype) {
      defineProxiedProperty(propertyName);
    }

    return Proxy;
  }

  _getProxiedObject(Class, options) {  // eslint-disable-line no-unused-vars
    throw Error('not implemented');
  }
}
<|endoftext|>