<commit_before>const huddle_data = require("./huddle_data");

const consts = {
    backfill_idle_time: 10 * 1000,
    error_retry_time: 5000,
    backfill_batch_size: 1000,
    narrow_before: 50,
    narrow_after: 50,
    num_before_home_anchor: 200,
    num_after_home_anchor: 200,
    backward_batch_size: 100,
    forward_batch_size: 100,
    catch_up_batch_size: 1000,
};

function process_result(data, opts) {
    let messages = data.messages;

    if (!$('#connection-error').hasClass('get-events-error')) {
        ui_report.hide_error($("#connection-error"));
    }

    if (messages.length === 0 && current_msg_list === message_list.narrowed &&
        message_list.narrowed.empty()) {
        // Even after trying to load more messages, we have no
        // messages to display in this narrow.
        narrow.show_empty_narrow_message();
    }

    messages.forEach(message_store.set_message_booleans);
    messages = messages.map(message_store.add_message_metadata);

    // In case any of the newly fetched messages are new, add them to
    // our unread data structures.  It's important that this run even
    // when fetching in a narrow, since we might return unread
    // messages that aren't in the home view data set (e.g. on a muted
    // stream).
    message_util.do_unread_count_updates(messages);

    // If we're loading more messages into the home view, save them to
    // the message_list.all as well, as the home_msg_list is reconstructed
    // from message_list.all.
    if (opts.msg_list === home_msg_list) {
        message_util.add_old_messages(messages, message_list.all);
    }

    if (messages.length !== 0) {
        message_util.add_old_messages(messages, opts.msg_list);
    }

    huddle_data.process_loaded_messages(messages);
    stream_list.update_streams_sidebar();
    pm_list.update_private_messages();
    recent_topics.process_messages(messages);

    stream_list.maybe_scroll_narrow_into_view();

    if (opts.cont !== undefined) {
        opts.cont(data, opts);
    }
}

function get_messages_success(data, opts) {
    const update_loading_indicator = opts.msg_list === current_msg_list;
    if (opts.num_before > 0) {
        opts.msg_list.data.fetch_status.finish_older_batch({
            update_loading_indicator: update_loading_indicator,
            found_oldest: data.found_oldest,
            history_limited: data.history_limited,
        });
        if (opts.msg_list === home_msg_list) {
            // When we update home_msg_list, we need to also update
            // the fetch_status data structure for message_list.all,
            // which is never rendered (and just used for
            // prepopulating narrowed views).
            message_list.all.data.fetch_status.finish_older_batch({
                update_loading_indicator: false,
                found_oldest: data.found_oldest,
                history_limited: data.history_limited,
            });
        }
        message_scroll.update_top_of_narrow_notices(opts.msg_list);
    }

    if (opts.num_after > 0) {
        opts.fetch_again = opts.msg_list.data.fetch_status.finish_newer_batch(
            data.messages, {
                update_loading_indicator: update_loading_indicator,
                found_newest: data.found_newest,
            });
        if (opts.msg_list === home_msg_list) {
            // When we update home_msg_list, we need to also update
            // the fetch_status data structure for message_list.all,
            // which is never rendered (and just used for
            // prepopulating narrowed views).
            opts.fetch_again = message_list.all.data.fetch_status.finish_newer_batch(
                data.messages, {
                    update_loading_indicator: false,
                    found_newest: data.found_newest,
                });
        }
    }

    if (opts.msg_list.narrowed && opts.msg_list !== current_msg_list) {
        // We unnarrowed before receiving new messages so
        // don't bother processing the newly arrived messages.
        return;
    }
    if (!data) {
        // The server occasionally returns no data during a
        // restart.  Ignore those responses and try again
        setTimeout(function () {
            exports.load_messages(opts);
        }, 0);
        return;
    }

    process_result(data, opts);
}

// This function modifies the data.narrow filters to use user IDs
// instead of emails string if it is supported. We currently don't set
// or convert the emails string to user IDs directly into the Filter code
// because doing so breaks the app in various modules that expect emails string.
function handle_operators_supporting_id_based_api(data) {
    const operators_supporting_ids = ['pm-with'];
    const operators_supporting_id = ['sender', 'group-pm-with', 'stream'];

    if (data.narrow === undefined) {
        return data;
    }

    data.narrow = JSON.parse(data.narrow);
    data.narrow = data.narrow.map(filter => {
        if (operators_supporting_ids.includes(filter.operator)) {
            filter.operand = people.emails_strings_to_user_ids_array(filter.operand);
        }

        if (operators_supporting_id.includes(filter.operator)) {
            if (filter.operator === 'stream') {
                const stream_id = stream_data.get_stream_id(filter.operand);
                if (stream_id !== undefined) {
                    filter.operand = stream_id;
                }

                return filter;
            }

            // The other operands supporting object IDs all work with user objects.
            const person = people.get_by_email(filter.operand);
            if (person !== undefined) {
                filter.operand = person.user_id;
            }
        }

        return filter;
    });

    data.narrow = JSON.stringify(data.narrow);
    return data;
}

exports.load_messages = function (opts) {
    let data = {anchor: opts.anchor,
                num_before: opts.num_before,
                num_after: opts.num_after};

    if (opts.msg_list.narrowed && narrow_state.active()) {
        let operators = narrow_state.public_operators();
        if (page_params.narrow !== undefined) {
            operators = operators.concat(page_params.narrow);
        }
        data.narrow = JSON.stringify(operators);
    }
    if (opts.msg_list === home_msg_list && page_params.narrow_stream !== undefined) {
        data.narrow = JSON.stringify(page_params.narrow);
    }

    let update_loading_indicator = opts.msg_list === current_msg_list;
    if (opts.num_before > 0) {
        opts.msg_list.data.fetch_status.start_older_batch({
            update_loading_indicator: update_loading_indicator,
        });
        if (opts.msg_list === home_msg_list) {
            message_list.all.data.fetch_status.start_older_batch({
                update_loading_indicator: update_loading_indicator,
            });
        }
    }

    if (opts.num_after > 0) {
        // We hide the bottom loading indicator when we're fetching both top and bottom messages.
        update_loading_indicator = update_loading_indicator && opts.num_before === 0;
        opts.msg_list.data.fetch_status.start_newer_batch({
            update_loading_indicator: update_loading_indicator,
        });
        if (opts.msg_list === home_msg_list) {
            message_list.all.data.fetch_status.start_newer_batch({
                update_loading_indicator: update_loading_indicator,
            });
        }
    }

    data.client_gravatar = true;
    data = handle_operators_supporting_id_based_api(data);

    channel.get({
        url: '/json/messages',
        data: data,
        idempotent: true,
        success: function (data) {
            get_messages_success(data, opts);
        },
        error: function (xhr) {
            if (opts.msg_list.narrowed && opts.msg_list !== current_msg_list) {
                // We unnarrowed before getting an error so don't
                // bother trying again or doing further processing.
                return;
            }
            if (xhr.status === 400) {
                // Bad request: We probably specified a narrow operator
                // for a nonexistent stream or something.  We shouldn't
                // retry or display a connection error.
                //
                // FIXME: Warn the user when this has happened?
                const data = {
                    messages: [],
                };
                process_result(data, opts);
                return;
            }

            // We might want to be more clever here
            $('#connection-error').addClass("show");
            setTimeout(function () {
                exports.load_messages(opts);
            }, consts.error_retry_time);
        },
    });
};

exports.load_messages_for_narrow = function (opts) {
    const msg_list = message_list.narrowed;

    exports.load_messages({
        anchor: opts.anchor,
        num_before: consts.narrow_before,
        num_after: consts.narrow_after,
        msg_list: msg_list,
        cont: opts.cont,
    });
};

exports.get_backfill_anchor = function (msg_list) {
    if (msg_list === home_msg_list) {
        msg_list = message_list.all;
    }

    const oldest_msg = msg_list.first();
    if (oldest_msg) {
        return oldest_msg.id;
    }

    // msg_list is empty, which is an impossible
    // case, raise a fatal error.
    blueslip.fatal("There are no message available to backfill.");
    return;
};

exports.get_frontfill_anchor = function (msg_list) {
    if (msg_list === home_msg_list) {
        msg_list = message_list.all;
    }

    const last_msg = msg_list.last();

    if (last_msg) {
        return last_msg.id;
    }

    // Although it is impossible that we reach here since we
    // are already checking `msg_list.fetch_status.can_load_newer_messages`
    // and user cannot be scrolling down on an empty message_list to
    // fetch more data, and if user is, then the available data is wrong
    // and we raise a fatal error.
    blueslip.fatal("There are no message available to frontfill.");
    return;
};

exports.maybe_load_older_messages = function (opts) {
    // This function gets called when you scroll to the top
    // of your window, and you want to get messages older
    // than what the browsers originally fetched.
    const msg_list = opts.msg_list;
    if (!msg_list.data.fetch_status.can_load_older_messages()) {
        // We may already be loading old messages or already
        // got the oldest one.
        return;
    }

    exports.do_backfill({
        msg_list: msg_list,
        num_before: consts.backward_batch_size,
    });
};

exports.do_backfill = function (opts) {
    const msg_list = opts.msg_list;
    const anchor = exports.get_backfill_anchor(msg_list).toFixed();

    exports.load_messages({
        anchor: anchor,
        num_before: opts.num_before,
        num_after: 0,
        msg_list: msg_list,
        cont: function () {
            if (opts.cont) {
                opts.cont();
            }
        },
    });
};

exports.maybe_load_newer_messages = function (opts) {
    // This function gets called when you scroll to the bottom
    // of your window, and you want to get messages newer
    // than what the browsers originally fetched.
    const msg_list = opts.msg_list;

    if (!msg_list.data.fetch_status.can_load_newer_messages()) {
        // We may already be loading new messages or already
        // got the newest one.
        return;
    }

    const anchor = exports.get_frontfill_anchor(msg_list).toFixed();

    function load_more(data, args) {
        if (args.fetch_again && args.msg_list === current_msg_list) {
            exports.maybe_load_newer_messages({ msg_list: current_msg_list });
        }
    }

    exports.load_messages({
        anchor: anchor,
        num_before: 0,
        num_after: consts.forward_batch_size,
        msg_list: msg_list,
        cont: load_more,
    });
};

exports.start_backfilling_messages = function () {
    // backfill more messages after the user is idle
    $(document).idle({idle: consts.backfill_idle_time,
                      onIdle: function () {
                          exports.do_backfill({
                              num_before: consts.backfill_batch_size,
                              msg_list: home_msg_list,
                          });
                      }});
};

exports.initialize = function () {
    // get the initial message list
    function load_more(data) {
        // If we haven't selected a message in the home view yet, and
        // the home view isn't empty, we select the anchor message here.
        if (home_msg_list.selected_id() === -1 && !home_msg_list.empty()) {
            // We fall back to the closest selected id, as the user
            // may have removed a stream from the home view while we
            // were loading data.
            home_msg_list.select_id(data.anchor,
                                    {then_scroll: true, use_closest: true,
                                     target_scroll_offset: page_params.initial_offset});
        }

        if (data.found_newest) {
            server_events.home_view_loaded();
            exports.start_backfilling_messages();
            return;
        }

        // If we fall through here, we need to keep fetching more data, and
        // we'll call back to the function we're in.
        const messages = data.messages;
        const latest_id = messages[messages.length - 1].id;

        exports.load_messages({
            anchor: latest_id.toFixed(),
            num_before: 0,
            num_after: consts.catch_up_batch_size,
            msg_list: home_msg_list,
            cont: load_more,
        });

    }

    let anchor;
    if (page_params.initial_pointer) {
        // If we're doing a server-initiated reload, similar to a
        // near: narrow query, we want to select a specific message.
        anchor = page_params.initial_pointer;
    } else {
        // Otherwise, we should just use the first unread message in
        // the user's unmuted history as our anchor.
        anchor = "first_unread";
    }
    exports.load_messages({
        anchor: anchor,
        num_before: consts.num_before_home_anchor,
        num_after: consts.num_after_home_anchor,
        msg_list: home_msg_list,
        cont: load_more,
    });
};

window.message_fetch = exports;
<commit_msg>message fetch: Fix anchor parameter before fetching messages.<commit_after>const huddle_data = require("./huddle_data");

const consts = {
    backfill_idle_time: 10 * 1000,
    error_retry_time: 5000,
    backfill_batch_size: 1000,
    narrow_before: 50,
    narrow_after: 50,
    num_before_home_anchor: 200,
    num_after_home_anchor: 200,
    backward_batch_size: 100,
    forward_batch_size: 100,
    catch_up_batch_size: 1000,
};

function process_result(data, opts) {
    let messages = data.messages;

    if (!$('#connection-error').hasClass('get-events-error')) {
        ui_report.hide_error($("#connection-error"));
    }

    if (messages.length === 0 && current_msg_list === message_list.narrowed &&
        message_list.narrowed.empty()) {
        // Even after trying to load more messages, we have no
        // messages to display in this narrow.
        narrow.show_empty_narrow_message();
    }

    messages.forEach(message_store.set_message_booleans);
    messages = messages.map(message_store.add_message_metadata);

    // In case any of the newly fetched messages are new, add them to
    // our unread data structures.  It's important that this run even
    // when fetching in a narrow, since we might return unread
    // messages that aren't in the home view data set (e.g. on a muted
    // stream).
    message_util.do_unread_count_updates(messages);

    // If we're loading more messages into the home view, save them to
    // the message_list.all as well, as the home_msg_list is reconstructed
    // from message_list.all.
    if (opts.msg_list === home_msg_list) {
        message_util.add_old_messages(messages, message_list.all);
    }

    if (messages.length !== 0) {
        message_util.add_old_messages(messages, opts.msg_list);
    }

    huddle_data.process_loaded_messages(messages);
    stream_list.update_streams_sidebar();
    pm_list.update_private_messages();
    recent_topics.process_messages(messages);

    stream_list.maybe_scroll_narrow_into_view();

    if (opts.cont !== undefined) {
        opts.cont(data, opts);
    }
}

function get_messages_success(data, opts) {
    const update_loading_indicator = opts.msg_list === current_msg_list;
    if (opts.num_before > 0) {
        opts.msg_list.data.fetch_status.finish_older_batch({
            update_loading_indicator: update_loading_indicator,
            found_oldest: data.found_oldest,
            history_limited: data.history_limited,
        });
        if (opts.msg_list === home_msg_list) {
            // When we update home_msg_list, we need to also update
            // the fetch_status data structure for message_list.all,
            // which is never rendered (and just used for
            // prepopulating narrowed views).
            message_list.all.data.fetch_status.finish_older_batch({
                update_loading_indicator: false,
                found_oldest: data.found_oldest,
                history_limited: data.history_limited,
            });
        }
        message_scroll.update_top_of_narrow_notices(opts.msg_list);
    }

    if (opts.num_after > 0) {
        opts.fetch_again = opts.msg_list.data.fetch_status.finish_newer_batch(
            data.messages, {
                update_loading_indicator: update_loading_indicator,
                found_newest: data.found_newest,
            });
        if (opts.msg_list === home_msg_list) {
            // When we update home_msg_list, we need to also update
            // the fetch_status data structure for message_list.all,
            // which is never rendered (and just used for
            // prepopulating narrowed views).
            opts.fetch_again = message_list.all.data.fetch_status.finish_newer_batch(
                data.messages, {
                    update_loading_indicator: false,
                    found_newest: data.found_newest,
                });
        }
    }

    if (opts.msg_list.narrowed && opts.msg_list !== current_msg_list) {
        // We unnarrowed before receiving new messages so
        // don't bother processing the newly arrived messages.
        return;
    }
    if (!data) {
        // The server occasionally returns no data during a
        // restart.  Ignore those responses and try again
        setTimeout(function () {
            exports.load_messages(opts);
        }, 0);
        return;
    }

    process_result(data, opts);
}

// This function modifies the data.narrow filters to use user IDs
// instead of emails string if it is supported. We currently don't set
// or convert the emails string to user IDs directly into the Filter code
// because doing so breaks the app in various modules that expect emails string.
function handle_operators_supporting_id_based_api(data) {
    const operators_supporting_ids = ['pm-with'];
    const operators_supporting_id = ['sender', 'group-pm-with', 'stream'];

    if (data.narrow === undefined) {
        return data;
    }

    data.narrow = JSON.parse(data.narrow);
    data.narrow = data.narrow.map(filter => {
        if (operators_supporting_ids.includes(filter.operator)) {
            filter.operand = people.emails_strings_to_user_ids_array(filter.operand);
        }

        if (operators_supporting_id.includes(filter.operator)) {
            if (filter.operator === 'stream') {
                const stream_id = stream_data.get_stream_id(filter.operand);
                if (stream_id !== undefined) {
                    filter.operand = stream_id;
                }

                return filter;
            }

            // The other operands supporting object IDs all work with user objects.
            const person = people.get_by_email(filter.operand);
            if (person !== undefined) {
                filter.operand = person.user_id;
            }
        }

        return filter;
    });

    data.narrow = JSON.stringify(data.narrow);
    return data;
}

exports.load_messages = function (opts) {
    if (typeof opts.anchor === "number") {
        // Messages that have been locally echoed messages have
        // floating point temporary IDs, which is intended to be a.
        // completely client-side detail.  We need to round these to
        // the nearest integer before sending a request to the server.
        opts.anchor = opts.anchor.toFixed();
    }
    let data = {anchor: opts.anchor,
                num_before: opts.num_before,
                num_after: opts.num_after};

    if (opts.msg_list.narrowed && narrow_state.active()) {
        let operators = narrow_state.public_operators();
        if (page_params.narrow !== undefined) {
            operators = operators.concat(page_params.narrow);
        }
        data.narrow = JSON.stringify(operators);
    }
    if (opts.msg_list === home_msg_list && page_params.narrow_stream !== undefined) {
        data.narrow = JSON.stringify(page_params.narrow);
    }

    let update_loading_indicator = opts.msg_list === current_msg_list;
    if (opts.num_before > 0) {
        opts.msg_list.data.fetch_status.start_older_batch({
            update_loading_indicator: update_loading_indicator,
        });
        if (opts.msg_list === home_msg_list) {
            message_list.all.data.fetch_status.start_older_batch({
                update_loading_indicator: update_loading_indicator,
            });
        }
    }

    if (opts.num_after > 0) {
        // We hide the bottom loading indicator when we're fetching both top and bottom messages.
        update_loading_indicator = update_loading_indicator && opts.num_before === 0;
        opts.msg_list.data.fetch_status.start_newer_batch({
            update_loading_indicator: update_loading_indicator,
        });
        if (opts.msg_list === home_msg_list) {
            message_list.all.data.fetch_status.start_newer_batch({
                update_loading_indicator: update_loading_indicator,
            });
        }
    }

    data.client_gravatar = true;
    data = handle_operators_supporting_id_based_api(data);

    channel.get({
        url: '/json/messages',
        data: data,
        idempotent: true,
        success: function (data) {
            get_messages_success(data, opts);
        },
        error: function (xhr) {
            if (opts.msg_list.narrowed && opts.msg_list !== current_msg_list) {
                // We unnarrowed before getting an error so don't
                // bother trying again or doing further processing.
                return;
            }
            if (xhr.status === 400) {
                // Bad request: We probably specified a narrow operator
                // for a nonexistent stream or something.  We shouldn't
                // retry or display a connection error.
                //
                // FIXME: Warn the user when this has happened?
                const data = {
                    messages: [],
                };
                process_result(data, opts);
                return;
            }

            // We might want to be more clever here
            $('#connection-error').addClass("show");
            setTimeout(function () {
                exports.load_messages(opts);
            }, consts.error_retry_time);
        },
    });
};

exports.load_messages_for_narrow = function (opts) {
    const msg_list = message_list.narrowed;

    exports.load_messages({
        anchor: opts.anchor,
        num_before: consts.narrow_before,
        num_after: consts.narrow_after,
        msg_list: msg_list,
        cont: opts.cont,
    });
};

exports.get_backfill_anchor = function (msg_list) {
    if (msg_list === home_msg_list) {
        msg_list = message_list.all;
    }

    const oldest_msg = msg_list.first();
    if (oldest_msg) {
        return oldest_msg.id;
    }

    // msg_list is empty, which is an impossible
    // case, raise a fatal error.
    blueslip.fatal("There are no message available to backfill.");
    return;
};

exports.get_frontfill_anchor = function (msg_list) {
    if (msg_list === home_msg_list) {
        msg_list = message_list.all;
    }

    const last_msg = msg_list.last();

    if (last_msg) {
        return last_msg.id;
    }

    // Although it is impossible that we reach here since we
    // are already checking `msg_list.fetch_status.can_load_newer_messages`
    // and user cannot be scrolling down on an empty message_list to
    // fetch more data, and if user is, then the available data is wrong
    // and we raise a fatal error.
    blueslip.fatal("There are no message available to frontfill.");
    return;
};

exports.maybe_load_older_messages = function (opts) {
    // This function gets called when you scroll to the top
    // of your window, and you want to get messages older
    // than what the browsers originally fetched.
    const msg_list = opts.msg_list;
    if (!msg_list.data.fetch_status.can_load_older_messages()) {
        // We may already be loading old messages or already
        // got the oldest one.
        return;
    }

    exports.do_backfill({
        msg_list: msg_list,
        num_before: consts.backward_batch_size,
    });
};

exports.do_backfill = function (opts) {
    const msg_list = opts.msg_list;
    const anchor = exports.get_backfill_anchor(msg_list);

    exports.load_messages({
        anchor: anchor,
        num_before: opts.num_before,
        num_after: 0,
        msg_list: msg_list,
        cont: function () {
            if (opts.cont) {
                opts.cont();
            }
        },
    });
};

exports.maybe_load_newer_messages = function (opts) {
    // This function gets called when you scroll to the bottom
    // of your window, and you want to get messages newer
    // than what the browsers originally fetched.
    const msg_list = opts.msg_list;

    if (!msg_list.data.fetch_status.can_load_newer_messages()) {
        // We may already be loading new messages or already
        // got the newest one.
        return;
    }

    const anchor = exports.get_frontfill_anchor(msg_list);

    function load_more(data, args) {
        if (args.fetch_again && args.msg_list === current_msg_list) {
            exports.maybe_load_newer_messages({ msg_list: current_msg_list });
        }
    }

    exports.load_messages({
        anchor: anchor,
        num_before: 0,
        num_after: consts.forward_batch_size,
        msg_list: msg_list,
        cont: load_more,
    });
};

exports.start_backfilling_messages = function () {
    // backfill more messages after the user is idle
    $(document).idle({idle: consts.backfill_idle_time,
                      onIdle: function () {
                          exports.do_backfill({
                              num_before: consts.backfill_batch_size,
                              msg_list: home_msg_list,
                          });
                      }});
};

exports.initialize = function () {
    // get the initial message list
    function load_more(data) {
        // If we haven't selected a message in the home view yet, and
        // the home view isn't empty, we select the anchor message here.
        if (home_msg_list.selected_id() === -1 && !home_msg_list.empty()) {
            // We fall back to the closest selected id, as the user
            // may have removed a stream from the home view while we
            // were loading data.
            home_msg_list.select_id(data.anchor,
                                    {then_scroll: true, use_closest: true,
                                     target_scroll_offset: page_params.initial_offset});
        }

        if (data.found_newest) {
            server_events.home_view_loaded();
            exports.start_backfilling_messages();
            return;
        }

        // If we fall through here, we need to keep fetching more data, and
        // we'll call back to the function we're in.
        const messages = data.messages;
        const latest_id = messages[messages.length - 1].id;

        exports.load_messages({
            anchor: latest_id,
            num_before: 0,
            num_after: consts.catch_up_batch_size,
            msg_list: home_msg_list,
            cont: load_more,
        });

    }

    let anchor;
    if (page_params.initial_pointer) {
        // If we're doing a server-initiated reload, similar to a
        // near: narrow query, we want to select a specific message.
        anchor = page_params.initial_pointer;
    } else {
        // Otherwise, we should just use the first unread message in
        // the user's unmuted history as our anchor.
        anchor = "first_unread";
    }
    exports.load_messages({
        anchor: anchor,
        num_before: consts.num_before_home_anchor,
        num_after: consts.num_after_home_anchor,
        msg_list: home_msg_list,
        cont: load_more,
    });
};

window.message_fetch = exports;
<|endoftext|>


<commit_before>// retrieve a JSON from a url
//***************************************
function grabJSON (url) {
  return $.ajax({
    url: url,
  });
}
//***************************************

//build bootstrap-select dropdown using json
//***************************************
function dropdownFromJSON (div_id, ajax_response) {
  $.each(ajax_response, function(name, file) {
       $(div_id).append($('<option/>').attr("value", file).text(name));
    });
  $('.selectpicker').selectpicker('refresh');
}
//***************************************

//build bootstrap-select dropdown using json
//***************************************
function dropdownCtxtSelectFromJSON (div_id, ajax_response) {
  $.each(ajax_response, function(name, file) {
       $(div_id).append($('<option/>').attr("value", file).text(file));
    });
}
//***************************************

//download a model
//***************************************
function download(filename, text) {
    var element = document.createElement('a');
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    element.setAttribute('download', filename);

    element.style.display = 'none';
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);
}
//***************************************

//send text to a reading system, get back stmts
//***************************************
function txtProcess(txt, parser) {
  var input_txt = {'text':txt};
  stmts = $.ajax({
    url: indra_server_addr + "/"+ parser + "/process_text",
    type: "POST",
    dataType: "json",
    data: JSON.stringify(input_txt),
    });
  return stmts
}

// send stmts to grounding mapper, get grounded stmts
//***************************************
function groundingMapper(res) {
  stmts = $.ajax({
    url: indra_server_addr + "/preassembly/map_grounding",
    type: "POST",
    dataType: "json",
    data: JSON.stringify(res),
    });
  return stmts
}
//***************************************

// query db for support to single statement
//***************************************
function getEvidence(res) {
  stmts_db = $.ajax({
    url: indra_server_addr + "/indra_db_rest/get_evidence",
    type: "POST",
    dataType: "json",
    data: JSON.stringify(res),
    });
  return stmts_db
}
//***************************************

function assembleCyJS(res) {
  var res_json = res;
  return $.ajax({
      url: indra_server_addr + "/assemblers/cyjs",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function assembleEnglish(res) {
  var res_json = res;
  return $.ajax({
      url: indra_server_addr + "/assemblers/english",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function requestPySB(res, export_format=null) {
  var res_json = res;
  res_json['line'] = $('#cellSelectDynamic').val().slice(6,-5);
  if (export_format){
    res_json['export_format'] = export_format;
    }
  return $.ajax({
      url: indra_server_addr + "/assemblers/pysb",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function assembleCX(res) {
  var res_json = res;
  res_json['cyjs_model'] = JSON.stringify(cy.json())
  return $.ajax({
      url: indra_server_addr + "/assemblers/cx",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function shareNDEX(res) {
  var res_json = res;
  res_json['cyjs_model'] = JSON.stringify(cy.json())
  return $.ajax({
      url: indra_server_addr + "/share_model",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function assemblePySB(res) {
  return requestPySB(res);
  }

function assembleSBML(res) {
    return requestPySB(res, 'sbml');
    }

function assembleSBGN(res) {
    return requestPySB(res, 'sbgn');
    }

function assembleBNGL(res) {
    return requestPySB(res, 'bngl');
    }

function assembleKappa(res) {
    return requestPySB(res, 'kappa');
    }

function assembleLoopy(res) {
  var res_json = res;
  return $.ajax({
      url: indra_server_addr + "/assemblers/sif/loopy",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

var mrna;
function get_ccle_mrna(gene_list, cell_line) {
  var input_txt = {'gene_list': gene_list,
                   'cell_lines': [cell_line]};
  return $.ajax({
            url: indra_server_addr + "/databases/cbio/get_ccle_mrna",
            type: "POST",
            dataType: "json",
            data: JSON.stringify(input_txt),
           }).then(function(res){
                      res = res["mrna_amounts"];
                      res = res[cell_line];
                      mrna = res;
                  });
}

var cna;
function get_ccle_cna(gene_list, cell_line) {
  var input_txt = {'gene_list': gene_list,
                   'cell_lines': [cell_line]};
  return $.ajax({
            url: indra_server_addr + "/databases/cbio/get_ccle_cna",
            type: "POST",
            dataType: "json",
            data: JSON.stringify(input_txt),
           }).then(function(res){
                      res = res["cna"];
                      res = res[cell_line];
                      cna = res;
                  });
}

var mutations;
function get_ccle_mutations(gene_list, cell_line) {
  var input_txt = {'gene_list': gene_list,
                   'cell_lines': [cell_line]};
  return $.ajax({
            url: indra_server_addr + "/databases/cbio/get_ccle_mutations",
            type: "POST",
            dataType: "json",
            data: JSON.stringify(input_txt),
           }).then(function(res){
                      res = res["mutations"];
                      res = res[cell_line];
                      mutations = res;
                  });
}
<commit_msg>change download function to use FileSaver.js `saveAs()`<commit_after>// retrieve a JSON from a url
//***************************************
function grabJSON (url) {
  return $.ajax({
    url: url,
  });
}
//***************************************

//build bootstrap-select dropdown using json
//***************************************
function dropdownFromJSON (div_id, ajax_response) {
  $.each(ajax_response, function(name, file) {
       $(div_id).append($('<option/>').attr("value", file).text(name));
    });
  $('.selectpicker').selectpicker('refresh');
}
//***************************************

//build bootstrap-select dropdown using json
//***************************************
function dropdownCtxtSelectFromJSON (div_id, ajax_response) {
  $.each(ajax_response, function(name, file) {
       $(div_id).append($('<option/>').attr("value", file).text(file));
    });
}
//***************************************

//download a model
//***************************************
function download(exportName, exportObj){
  if (exportName.includes('.png')){
    encoding_type = "image/png";
    var data = atob( exportObj.substring( "data:image/png;base64,".length ) ),
    asArray = new Uint8Array(data.length);
    for( var i = 0, len = data.length; i < len; ++i ) {
        asArray[i] = data.charCodeAt(i);
    }
    var blob = new Blob( [ asArray.buffer ], {type: "image/png"} );
  }
  else {
    var blob = new Blob([exportObj], {type: "text/plain;charset=utf-8"});
  }
  saveAs(blob, exportName);
}
//***************************************

//send text to a reading system, get back stmts
//***************************************
function txtProcess(txt, parser) {
  var input_txt = {'text':txt};
  stmts = $.ajax({
    url: indra_server_addr + "/"+ parser + "/process_text",
    type: "POST",
    dataType: "json",
    data: JSON.stringify(input_txt),
    });
  return stmts
}

// send stmts to grounding mapper, get grounded stmts
//***************************************
function groundingMapper(res) {
  stmts = $.ajax({
    url: indra_server_addr + "/preassembly/map_grounding",
    type: "POST",
    dataType: "json",
    data: JSON.stringify(res),
    });
  return stmts
}
//***************************************

// query db for support to single statement
//***************************************
function getEvidence(res) {
  stmts_db = $.ajax({
    url: indra_server_addr + "/indra_db_rest/get_evidence",
    type: "POST",
    dataType: "json",
    data: JSON.stringify(res),
    });
  return stmts_db
}
//***************************************

function assembleCyJS(res) {
  var res_json = res;
  return $.ajax({
      url: indra_server_addr + "/assemblers/cyjs",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function assembleEnglish(res) {
  var res_json = res;
  return $.ajax({
      url: indra_server_addr + "/assemblers/english",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function requestPySB(res, export_format=null) {
  var res_json = res;
  res_json['line'] = $('#cellSelectDynamic').val().slice(6,-5);
  if (export_format){
    res_json['export_format'] = export_format;
    }
  return $.ajax({
      url: indra_server_addr + "/assemblers/pysb",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function assembleCX(res) {
  var res_json = res;
  res_json['cyjs_model'] = JSON.stringify(cy.json())
  return $.ajax({
      url: indra_server_addr + "/assemblers/cx",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function shareNDEX(res) {
  var res_json = res;
  res_json['cyjs_model'] = JSON.stringify(cy.json())
  return $.ajax({
      url: indra_server_addr + "/share_model",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

function assemblePySB(res) {
  return requestPySB(res);
  }

function assembleSBML(res) {
    return requestPySB(res, 'sbml');
    }

function assembleSBGN(res) {
    return requestPySB(res, 'sbgn');
    }

function assembleBNGL(res) {
    return requestPySB(res, 'bngl');
    }

function assembleKappa(res) {
    return requestPySB(res, 'kappa');
    }

function assembleLoopy(res) {
  var res_json = res;
  return $.ajax({
      url: indra_server_addr + "/assemblers/sif/loopy",
      type: "POST",
      dataType: "json",
      data: JSON.stringify(res_json),
  });
}

var mrna;
function get_ccle_mrna(gene_list, cell_line) {
  var input_txt = {'gene_list': gene_list,
                   'cell_lines': [cell_line]};
  return $.ajax({
            url: indra_server_addr + "/databases/cbio/get_ccle_mrna",
            type: "POST",
            dataType: "json",
            data: JSON.stringify(input_txt),
           }).then(function(res){
                      res = res["mrna_amounts"];
                      res = res[cell_line];
                      mrna = res;
                  });
}

var cna;
function get_ccle_cna(gene_list, cell_line) {
  var input_txt = {'gene_list': gene_list,
                   'cell_lines': [cell_line]};
  return $.ajax({
            url: indra_server_addr + "/databases/cbio/get_ccle_cna",
            type: "POST",
            dataType: "json",
            data: JSON.stringify(input_txt),
           }).then(function(res){
                      res = res["cna"];
                      res = res[cell_line];
                      cna = res;
                  });
}

var mutations;
function get_ccle_mutations(gene_list, cell_line) {
  var input_txt = {'gene_list': gene_list,
                   'cell_lines': [cell_line]};
  return $.ajax({
            url: indra_server_addr + "/databases/cbio/get_ccle_mutations",
            type: "POST",
            dataType: "json",
            data: JSON.stringify(input_txt),
           }).then(function(res){
                      res = res["mutations"];
                      res = res[cell_line];
                      mutations = res;
                  });
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

import { useTheme } from '../util/useTheme';
import ValidationContext from './ValidationContext';

const FlexControl = styled.div`
  color: ${props => props.textColor};
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  margin-bottom: 25px;

  select {
    border-color: ${props => props.borderColor};
    box-shadow: ${props => props.boxShadow};
  }

  input:focus,
  select:focus {
    border-color: ${props => props.focusBorderColor};
    box-shadow: ${props => props.focusBoxShadow};
  }
`;

const InlineControl = styled(FlexControl)`
  align-items: center;
  flex-direction: row;

  @media (max-width: ${props => props.theme.screenSize.tablet}) {
    align-items: flex-start;
    flex-direction: column;
  }
`;

function Control(props) {
  const { validationState, orientation, children } = props;
  const ControlWrapper = orientation === 'inline' ? InlineControl : FlexControl;

  const theme = useTheme();
  const textColor = theme.validationTextColor[validationState];

  return (
    <ControlWrapper
      textColor={textColor}
      {...theme.validationInputColor[validationState]}
      className={props.className}
    >
      <ValidationContext.Provider value={validationState}>
        {children}
      </ValidationContext.Provider>
    </ControlWrapper>
  );
}

Control.propTypes = {
  orientation: PropTypes.oneOf(['stacked', 'inline']),
  validationState: PropTypes.oneOf(['default', 'success', 'warning', 'danger']),
  children: PropTypes.node
};

Control.defaultProps = {
  orientation: 'stacked',
  validationState: 'default',
  children: null
};

export default Control;
<commit_msg>Update: swapped control media queries to mobile-first<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

import { useTheme } from '../util/useTheme';
import ValidationContext from './ValidationContext';

const FlexControl = styled.div`
  color: ${props => props.textColor};
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  margin-bottom: 25px;

  select {
    border-color: ${props => props.borderColor};
    box-shadow: ${props => props.boxShadow};
  }

  input:focus,
  select:focus {
    border-color: ${props => props.focusBorderColor};
    box-shadow: ${props => props.focusBoxShadow};
  }
`;

const InlineControl = styled(FlexControl)`
  align-items: flex-start;
  flex-direction: column;

  @media (min-width: ${props => props.theme.screenSize.tablet}) {
    align-items: baseline;
    flex-direction: row;
  }
`;

function Control(props) {
  const { validationState, orientation, children } = props;
  const ControlWrapper = orientation === 'inline' ? InlineControl : FlexControl;

  const theme = useTheme();
  const textColor = theme.validationTextColor[validationState];

  return (
    <ControlWrapper
      textColor={textColor}
      {...theme.validationInputColor[validationState]}
      className={props.className}
    >
      <ValidationContext.Provider value={validationState}>
        {children}
      </ValidationContext.Provider>
    </ControlWrapper>
  );
}

Control.propTypes = {
  orientation: PropTypes.oneOf(['stacked', 'inline']),
  validationState: PropTypes.oneOf(['default', 'success', 'warning', 'danger']),
  children: PropTypes.node
};

Control.defaultProps = {
  orientation: 'stacked',
  validationState: 'default',
  children: null
};

export default Control;
<|endoftext|>


<commit_before>var diagram_initialized = false;
var plotline_timestamp = null;
var sensor_count = 0;

// READY
function technician_overview_ready() {
    initialize_technician_diagram();
    initialize_technician_tuning_form();
    initialize_technician_editor();
    if (status_data['system_mode'] == 'demo') {
        initialize_forward_buttons();
    }
}

// Diagram
function initialize_technician_diagram() {
    Highcharts.setOptions({
        global: {
            useUTC: false
        }
    });

    var series = [];
    $.getJSON(api_base_url + 'data/', function(data) {
        var table_headlines = ['Sensor', 'Device', 'Value'];
        var table_rows = [];
        var latest_date = 0;
        $.each(data, function(index, sensor) {
            series.push({
                name: sensor.name + ' (' + sensor.device + ')',
                data: sensor.data,
                color: colors_past[index],
                tooltip: {
                    valueSuffix: ' ' + sensor.unit
                }
            });
            latest_value = Math.round(sensor.data[sensor.data.length - 1][1] * 100) / 100;
            latest_date = sensor.data[sensor.data.length - 1][0];
            table_rows.push([sensor.name, sensor.device, latest_value + ' ' + sensor.unit]);
        });
        update_now_table(table_rows, latest_date);
        sensor_count = series.length;
    }).done(function () {
        $.getJSON(api_base_url + 'forecast/', function(forecast_data) {
            $.each(forecast_data, function(index, sensor) {
                $.merge(series[index].data, sensor.data);
            });
            plotline_timestamp = forecast_data[0].data[0][0];
        }).done(function () {
            // Create the chart
            $('#simulation_diagram').highcharts('StockChart', {
                chart: {
                    height: 500,
                    zoomType: 'xy',
                    events: {
                        load: update_now_line,
                        setExtremes: update_now_line
                    }
                },
                legend: {
                    enabled: true
                },
                rangeSelector: {
                    buttons: [{
                        count: 6,
                        type: 'hour',
                        text: '6H'
                    }, {
                        count: 12,
                        type: 'hour',
                        text: '12H'
                    }, {
                        count: 1,
                        type: 'day',
                        text: '1D'
                    }, {
                        count: 1,
                        type: 'week',
                        text: '1W'
                    }, {
                        count: 2,
                        type: 'week',
                        text: '2W'
                    }, {
                        count: 1,
                        type: 'month',
                        text: '1M'
                    }, {
                        type: 'all',
                        text: 'All'
                    }],
                    selected: 4,
                    inputEnabled: false
                },
                xAxis: {
                    plotLines: [{
                        id: 'now',
                    }],
                    PlotBands: [{
                        id: 'now_band',
                    }]
                },
                tooltip: {
                    valueDecimals: 2
                },
                lang: {
                    noData: "Loading data..."
                },
                plotOptions: {
                    series: {
                        marker: {
                            enabled: false
                        },
                        lineWidth: 1.5,
                    },
                    line: {
                        animation: false
                    }
                },
                series: series,
                credits: {
                    enabled: false
                }
            });

            setTimeout(function() {
                refresh_technician_diagram(true);
            }, 10000);
        });
    });

    $('#live_data_export_button').click(function(event) {
        event.preventDefault();
        export_table($('#live_data_table_container'));
    });
}

function refresh_technician_diagram(repeat) {
    var chart = $('#simulation_diagram').highcharts();
    var series_data = []
    $.getJSON(api_base_url + 'data/', function(data) {
        var table_rows = [];
        var latest_date = 0;
        $.each(data, function(index, sensor) {
            series_data.push(sensor.data);
            latest_value = Math.round(sensor.data[sensor.data.length - 1][1] * 100) / 100;
            latest_date = sensor.data[sensor.data.length - 1][0];
            table_rows.push([sensor.name, sensor.device, latest_value + ' ' + sensor.unit]);
        });
        update_now_table(table_rows, latest_date);
    }).done(function () {
        $.getJSON(api_base_url + 'forecast/', function(forecast_data) {
            $.each(forecast_data, function(index, sensor) {
                chart.series[index].setData($.merge(series_data[index], sensor.data), false);
            });
            plotline_timestamp = forecast_data[0].data[0][0];
        }).done(function () {
            chart.redraw();

            if (repeat && get_current_page() == 'overview') {
                setTimeout(refresh_technician_diagram, 10000);
            }
        });
    });
}

function update_now_table(rows, date) {
    var headlines = ['Sensor', 'Device', 'Value'];
    draw_table($('#live_data_table_container'), headlines, rows);
    $('#live_data_table_container').prepend('
' + $.format.date(new Date(date), "dd.MM.yyyy HH:MM") + '
');
}

function update_now_line() {
    var chart = $(this)[0];

    chart.xAxis[0].removePlotBand('now_band');
    chart.xAxis[0].addPlotBand({
        id: 'now_band',
        from: plotline_timestamp,
        to: plotline_timestamp + 14 * 24 * 60 * 60 * 1000,
        color: '#F0F0F0',
        label: {
            text: 'Forecast',
            rotation: 0,
            align: 'center',
            y: 32,
            x: 6
        }
    });
    chart.xAxis[0].removePlotLine('now');
    chart.xAxis[0].addPlotLine({
        id: 'now',
        value: plotline_timestamp,
        width: 2,
        color: 'red',
        label: {
            text: 'Now',
            align: 'right',
            y: 32,
            x: 6
        }
    });

    if (!diagram_initialized) {
        chart.xAxis[0].setExtremes(new Date(plotline_timestamp - 7 * 24 * 60 * 60 * 1000), new Date(plotline_timestamp + 7 * 24 * 60 * 60 * 1000));
        diagram_initialized = true;
    }
}

function initialize_forward_buttons() {
    var forward_options = {
        buttons: [
        {
            value: 1,
            text: '1 Day'
        }, {
            value: 7,
            text: '1 Week'
        }, {
            value: 14,
            text: '2 Weeks'
        }, {
            value: 4 * 7,
            text: '1 Month'
        }]
    };

    var output = Mustache.render($('#snippet_forward_buttons').html(), forward_options);
    $('#live_diagram_header').append(output);

    $('#live_diagram_header button').click(function() {
        $.ajax({
            type: 'POST',
            contentType: 'application/json',
            url: api_base_url + 'forward/',
            data: JSON.stringify({
                forward_time: $(this).val()
            }),
            dataType: 'json',
            success: function(data) {
                refresh_technician_diagram(false);
                console.log(data);
            }
        });
    });
}

// Tuning
function initialize_technician_tuning_form() {
    $.getJSON(api_base_url + 'settings/tunable/', function(data) {
        var item = $('#tuning_form');
        $.each(data, function(device_id, device_configurations) {
            $.each(device_configurations, function(key, config_data) {
                var namespace = namespaces[device_id];
                item.append(get_input_field_code(namespace, key, config_data));
            });
        });
        $('#tuning_form').change(generate_immediate_feedback);
        $('#tuning_button').click(apply_changes);
        $('#tuning_reset_button').click(function() {
            $('#tuning_form')[0].reset();
        })
    });
}

function generate_immediate_feedback() {
    $('#immediate_notice').show();
    $('#tuning_button').prop('disabled', true);

    var post_data = [];
    $('.configuration').each(function () {
        post_data.push({
            device: $(this).attr('data-device'),
            key: $(this).attr('data-key'),
            type: $(this).attr('data-type'),
            unit: $(this).attr('data-unit'),
            value: $(this).val()
        });
    });
    $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: api_base_url + 'forecast/',
        data: JSON.stringify(post_data),
        dataType: 'json',
        success: function(data) {
            update_immediate_forecast(data);
            $('#immediate_notice').hide();
            $('#tuning_button').prop('disabled', false);
        }
    });
}

function apply_changes() {
    $('#tuning_button').removeClass('btn-primary').addClass('btn-success');
    var post_data = [];
    $('.configuration').each(function () {
        post_data.push({
            device: $(this).attr('data-device'),
            key: $(this).attr('data-key'),
            type: $(this).attr('data-type'),
            unit: $(this).attr('data-unit'),
            value: $(this).val()
        });
    });
    $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: api_base_url + 'configure/',
        data: JSON.stringify(post_data),
        dataType: 'json',
        success: function(data) {
            setTimeout(function() {
                $('#tuning_button').removeClass('btn-success').addClass('btn-primary');
            }, 500);
            console.log(data);
        }
    }).done(function() {
        cleanup_diagram();
    });
}

function update_immediate_forecast(data) {
    var chart = $('#simulation_diagram').highcharts();

    cleanup_diagram();

    $.each(data, function(index, sensor) {
        chart.addSeries({
            name: sensor.name + ' (' + sensor.device + ') (predicted)',
            data: sensor.data,
            color: colors_modified[index],
            dashStyle: 'shortdot',
            tooltip: {
                valueSuffix: ' ' + sensor.unit
            }
        }, false);
    });
    chart.redraw();
}

function cleanup_diagram(chart) {
    var chart = $('#simulation_diagram').highcharts();
    var i = 0
    while(chart.series.length > sensor_count + 1) {
        if (chart.series[i].name.indexOf('predicted') != -1) {
            chart.series[i].remove(false);
        } else {
            i++;
        }
    };
    return true;
}

function get_input_field_code(namespace, key, data) {
    var device_id = namespaces.indexOf(namespace);
    var output =
            '

' +
                '' + get_text(key) + ' (Device #' + device_id + ')';
    if (data.unit == '') {
        output +=
                '<input type="text" class="configuration form-control" id="' + namespace + '_' + key + '" data-device="' + device_id + '" data-key="' + key + '" data-type="' + data.type + '" data-unit="' + data.unit + '"  value="' + data.value + '">';
    } else {
        output +=
                '
' +
                    '<input type="text" class="configuration form-control" id="' + namespace + '_' + key + '" data-device="' + device_id + '" data-key="' + key + '" data-type="' + data.type + '" data-unit="' + data.unit + '"  value="' + data.value + '">' +
                    '' + data.unit + '' +
                '
';
    }
    output += '

';
    return output;
}

// Code Editor
function initialize_technician_editor() {
    ace.require("ace/ext/language_tools");
    editor = ace.edit("editor");
    editor.setTheme("ace/theme/github");
    editor.getSession().setMode("ace/mode/python");
    editor.setOptions({
        enableBasicAutocompletion: true,
        enableSnippets: true
    });
    ace.config.loadModule('ace/snippets/snippets', function() {
        var snippetManager = ace.require('ace/snippets').snippetManager;
        ace.config.loadModule('ace/snippets/python', function(m) {
            if (m) {
                m.snippets = m.snippets.concat(custom_snippets);
                snippetManager.register(m.snippets, m.scope);
            }
        });
    });

    update_snippet_list();

    $("#save_snippet").submit(function(event) {
        event.preventDefault();
        $.postJSON(api_base_url + "snippets/", {
            name: $("#snippet_name").val(),
            code: editor.getValue()
        }, function(data) {
            editor.setValue(data['code'], 1);
            update_snippet_list();
        });
    });

    $("#load_snippet").submit(function(event) {
        event.preventDefault();
        $.postJSON(api_base_url + "snippets/", {
            name: $("#code_snippets").val()
        }, function(data) {
            editor.setValue(data['code'], 1);
        });
        $('#snippet_name').val($("#code_snippets").val());
    });
}

function update_snippet_list() {
    $("#code_snippets").empty();
    $.getJSON(api_base_url + 'snippets/', function(data) {
        $.each(data, function(index, snippet) {
             $("#code_snippets").append('<option>' + snippet + '</option>');
        });
    });
}<commit_msg>Make sure data undefined error can't occur in frontend. Addresses #270. [ci skip]<commit_after>var diagram_initialized = false;
var plotline_timestamp = null;
var sensor_count = 0;

// READY
function technician_overview_ready() {
    initialize_technician_diagram();
    initialize_technician_tuning_form();
    initialize_technician_editor();
    if (status_data['system_mode'] == 'demo') {
        initialize_forward_buttons();
    }
}

// Diagram
function initialize_technician_diagram() {
    Highcharts.setOptions({
        global: {
            useUTC: false
        }
    });

    var series = [];
    $.getJSON(api_base_url + 'data/', function(data) {
        var table_headlines = ['Sensor', 'Device', 'Value'];
        var table_rows = [];
        var latest_date = 0;
        $.each(data, function(index, sensor) {
            series.push({
                name: sensor.name + ' (' + sensor.device + ')',
                data: sensor.data,
                color: colors_past[index],
                tooltip: {
                    valueSuffix: ' ' + sensor.unit
                }
            });
            latest_value = Math.round(sensor.data[sensor.data.length - 1][1] * 100) / 100;
            latest_date = sensor.data[sensor.data.length - 1][0];
            table_rows.push([sensor.name, sensor.device, latest_value + ' ' + sensor.unit]);
        });
        update_now_table(table_rows, latest_date);
        sensor_count = series.length;
    }).done(function () {
        $.getJSON(api_base_url + 'forecast/', function(forecast_data) {
            $.each(forecast_data, function(index, sensor) {
                if (index < series.length) {
                    $.merge(series[index].data, sensor.data);
                }
            });
            plotline_timestamp = forecast_data[0].data[0][0];
        }).done(function () {
            // Create the chart
            $('#simulation_diagram').highcharts('StockChart', {
                chart: {
                    height: 500,
                    zoomType: 'xy',
                    events: {
                        load: update_now_line,
                        setExtremes: update_now_line
                    }
                },
                legend: {
                    enabled: true
                },
                rangeSelector: {
                    buttons: [{
                        count: 6,
                        type: 'hour',
                        text: '6H'
                    }, {
                        count: 12,
                        type: 'hour',
                        text: '12H'
                    }, {
                        count: 1,
                        type: 'day',
                        text: '1D'
                    }, {
                        count: 1,
                        type: 'week',
                        text: '1W'
                    }, {
                        count: 2,
                        type: 'week',
                        text: '2W'
                    }, {
                        count: 1,
                        type: 'month',
                        text: '1M'
                    }, {
                        type: 'all',
                        text: 'All'
                    }],
                    selected: 4,
                    inputEnabled: false
                },
                xAxis: {
                    plotLines: [{
                        id: 'now',
                    }],
                    PlotBands: [{
                        id: 'now_band',
                    }]
                },
                tooltip: {
                    valueDecimals: 2
                },
                lang: {
                    noData: "Loading data..."
                },
                plotOptions: {
                    series: {
                        marker: {
                            enabled: false
                        },
                        lineWidth: 1.5,
                    },
                    line: {
                        animation: false
                    }
                },
                series: series,
                credits: {
                    enabled: false
                }
            });

            setTimeout(function() {
                refresh_technician_diagram(true);
            }, 10000);
        });
    });

    $('#live_data_export_button').click(function(event) {
        event.preventDefault();
        export_table($('#live_data_table_container'));
    });
}

function refresh_technician_diagram(repeat) {
    var chart = $('#simulation_diagram').highcharts();
    var series_data = []
    $.getJSON(api_base_url + 'data/', function(data) {
        var table_rows = [];
        var latest_date = 0;
        $.each(data, function(index, sensor) {
            series_data.push(sensor.data);
            latest_value = Math.round(sensor.data[sensor.data.length - 1][1] * 100) / 100;
            latest_date = sensor.data[sensor.data.length - 1][0];
            table_rows.push([sensor.name, sensor.device, latest_value + ' ' + sensor.unit]);
        });
        update_now_table(table_rows, latest_date);
    }).done(function () {
        $.getJSON(api_base_url + 'forecast/', function(forecast_data) {
            $.each(forecast_data, function(index, sensor) {
                if (index < series.length) {
                    chart.series[index].setData($.merge(series_data[index], sensor.data), false);
                }
            });
            plotline_timestamp = forecast_data[0].data[0][0];
        }).done(function () {
            chart.redraw();

            if (repeat && get_current_page() == 'overview') {
                setTimeout(refresh_technician_diagram, 10000);
            }
        });
    });
}

function update_now_table(rows, date) {
    var headlines = ['Sensor', 'Device', 'Value'];
    draw_table($('#live_data_table_container'), headlines, rows);
    $('#live_data_table_container').prepend('
' + $.format.date(new Date(date), "dd.MM.yyyy HH:MM") + '
');
}

function update_now_line() {
    var chart = $(this)[0];

    chart.xAxis[0].removePlotBand('now_band');
    chart.xAxis[0].addPlotBand({
        id: 'now_band',
        from: plotline_timestamp,
        to: plotline_timestamp + 14 * 24 * 60 * 60 * 1000,
        color: '#F0F0F0',
        label: {
            text: 'Forecast',
            rotation: 0,
            align: 'center',
            y: 32,
            x: 6
        }
    });
    chart.xAxis[0].removePlotLine('now');
    chart.xAxis[0].addPlotLine({
        id: 'now',
        value: plotline_timestamp,
        width: 2,
        color: 'red',
        label: {
            text: 'Now',
            align: 'right',
            y: 32,
            x: 6
        }
    });

    if (!diagram_initialized) {
        chart.xAxis[0].setExtremes(new Date(plotline_timestamp - 7 * 24 * 60 * 60 * 1000), new Date(plotline_timestamp + 7 * 24 * 60 * 60 * 1000));
        diagram_initialized = true;
    }
}

function initialize_forward_buttons() {
    var forward_options = {
        buttons: [
        {
            value: 1,
            text: '1 Day'
        }, {
            value: 7,
            text: '1 Week'
        }, {
            value: 14,
            text: '2 Weeks'
        }, {
            value: 4 * 7,
            text: '1 Month'
        }]
    };

    var output = Mustache.render($('#snippet_forward_buttons').html(), forward_options);
    $('#live_diagram_header').append(output);

    $('#live_diagram_header button').click(function() {
        $.ajax({
            type: 'POST',
            contentType: 'application/json',
            url: api_base_url + 'forward/',
            data: JSON.stringify({
                forward_time: $(this).val()
            }),
            dataType: 'json',
            success: function(data) {
                refresh_technician_diagram(false);
                console.log(data);
            }
        });
    });
}

// Tuning
function initialize_technician_tuning_form() {
    $.getJSON(api_base_url + 'settings/tunable/', function(data) {
        var item = $('#tuning_form');
        $.each(data, function(device_id, device_configurations) {
            $.each(device_configurations, function(key, config_data) {
                var namespace = namespaces[device_id];
                item.append(get_input_field_code(namespace, key, config_data));
            });
        });
        $('#tuning_form').change(generate_immediate_feedback);
        $('#tuning_button').click(apply_changes);
        $('#tuning_reset_button').click(function() {
            $('#tuning_form')[0].reset();
        })
    });
}

function generate_immediate_feedback() {
    $('#immediate_notice').show();
    $('#tuning_button').prop('disabled', true);

    var post_data = [];
    $('.configuration').each(function () {
        post_data.push({
            device: $(this).attr('data-device'),
            key: $(this).attr('data-key'),
            type: $(this).attr('data-type'),
            unit: $(this).attr('data-unit'),
            value: $(this).val()
        });
    });
    $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: api_base_url + 'forecast/',
        data: JSON.stringify(post_data),
        dataType: 'json',
        success: function(data) {
            update_immediate_forecast(data);
            $('#immediate_notice').hide();
            $('#tuning_button').prop('disabled', false);
        }
    });
}

function apply_changes() {
    $('#tuning_button').removeClass('btn-primary').addClass('btn-success');
    var post_data = [];
    $('.configuration').each(function () {
        post_data.push({
            device: $(this).attr('data-device'),
            key: $(this).attr('data-key'),
            type: $(this).attr('data-type'),
            unit: $(this).attr('data-unit'),
            value: $(this).val()
        });
    });
    $.ajax({
        type: 'POST',
        contentType: 'application/json',
        url: api_base_url + 'configure/',
        data: JSON.stringify(post_data),
        dataType: 'json',
        success: function(data) {
            setTimeout(function() {
                $('#tuning_button').removeClass('btn-success').addClass('btn-primary');
            }, 500);
            console.log(data);
        }
    }).done(function() {
        cleanup_diagram();
    });
}

function update_immediate_forecast(data) {
    var chart = $('#simulation_diagram').highcharts();

    cleanup_diagram();

    $.each(data, function(index, sensor) {
        chart.addSeries({
            name: sensor.name + ' (' + sensor.device + ') (predicted)',
            data: sensor.data,
            color: colors_modified[index],
            dashStyle: 'shortdot',
            tooltip: {
                valueSuffix: ' ' + sensor.unit
            }
        }, false);
    });
    chart.redraw();
}

function cleanup_diagram(chart) {
    var chart = $('#simulation_diagram').highcharts();
    var i = 0
    while(chart.series.length > sensor_count + 1) {
        if (chart.series[i].name.indexOf('predicted') != -1) {
            chart.series[i].remove(false);
        } else {
            i++;
        }
    };
    return true;
}

function get_input_field_code(namespace, key, data) {
    var device_id = namespaces.indexOf(namespace);
    var output =
            '

' +
                '' + get_text(key) + ' (Device #' + device_id + ')';
    if (data.unit == '') {
        output +=
                '<input type="text" class="configuration form-control" id="' + namespace + '_' + key + '" data-device="' + device_id + '" data-key="' + key + '" data-type="' + data.type + '" data-unit="' + data.unit + '"  value="' + data.value + '">';
    } else {
        output +=
                '
' +
                    '<input type="text" class="configuration form-control" id="' + namespace + '_' + key + '" data-device="' + device_id + '" data-key="' + key + '" data-type="' + data.type + '" data-unit="' + data.unit + '"  value="' + data.value + '">' +
                    '' + data.unit + '' +
                '
';
    }
    output += '

';
    return output;
}

// Code Editor
function initialize_technician_editor() {
    ace.require("ace/ext/language_tools");
    editor = ace.edit("editor");
    editor.setTheme("ace/theme/github");
    editor.getSession().setMode("ace/mode/python");
    editor.setOptions({
        enableBasicAutocompletion: true,
        enableSnippets: true
    });
    ace.config.loadModule('ace/snippets/snippets', function() {
        var snippetManager = ace.require('ace/snippets').snippetManager;
        ace.config.loadModule('ace/snippets/python', function(m) {
            if (m) {
                m.snippets = m.snippets.concat(custom_snippets);
                snippetManager.register(m.snippets, m.scope);
            }
        });
    });

    update_snippet_list();

    $("#save_snippet").submit(function(event) {
        event.preventDefault();
        $.postJSON(api_base_url + "snippets/", {
            name: $("#snippet_name").val(),
            code: editor.getValue()
        }, function(data) {
            editor.setValue(data['code'], 1);
            update_snippet_list();
        });
    });

    $("#load_snippet").submit(function(event) {
        event.preventDefault();
        $.postJSON(api_base_url + "snippets/", {
            name: $("#code_snippets").val()
        }, function(data) {
            editor.setValue(data['code'], 1);
        });
        $('#snippet_name').val($("#code_snippets").val());
    });
}

function update_snippet_list() {
    $("#code_snippets").empty();
    $.getJSON(api_base_url + 'snippets/', function(data) {
        $.each(data, function(index, snippet) {
             $("#code_snippets").append('<option>' + snippet + '</option>');
        });
    });
}<|endoftext|>


<commit_before>/*******************************************************************************/
/*                                                                             */
/*                                YouTubeAnnotation                               */
/*                                                                             */
/*******************************************************************************/

function YouTubeAnnotation(annotext, ai, data) {
	Annotation.call(this, annotext, ai, data);
	if (this.data.code === undefined) {
		this.data.code = '';
	}
	if (this.data.caption === undefined) {
		this.data.caption = '';
	}
	this.data.type = YouTubeAnnotation.slug;
	this.view_window = new YouTubeAnnotViewWindow(this);
	this.edit_window = new YouTubeAnnotEditWindow(this);
	this.thumb_window = new YouTubeAnnotThumbWindow(this);
	this.view_screen = new AnViewScreen(this);
	this.edit_screen = new AnEditScreen(this);
}
make_subclass(YouTubeAnnotation, Annotation);

YouTubeAnnotation.prototype.name = "YouTube Video";
YouTubeAnnotation.slug = "youtube";
annot_types[YouTubeAnnotation.slug] = YouTubeAnnotation;

YouTubeAnnotation.prototype.is_empty = function() {
	return (!this.data.code && !this.data.caption);
};

YouTubeAnnotation.prototype.set_code = function(code) {
	this.thumb_window.altered = true;
	this.view_window.altered = true;
	this.annotated_item.view_window.altered = true;
	this.data.code = code;
	this.annotext.set_altered();
};

YouTubeAnnotation.prototype.set_caption = function(caption) {
	this.view_window.altered = true;
	this.data.caption = caption;
	this.annotext.set_altered();
};

function YouTubeAnnotEditWindow(an) {
	this.annotation = an;
	this.node = YouTubeAnnotEditWindow.template.clone();
	this.code_field = this.node.find(".youtube_annot_edit_window_code").first();
	this.caption_field = this.node.find(".youtube_annot_edit_window_caption").first();
	this.code_field.append(this.annotation.data.code);
	this.caption_field.append(this.annotation.data.caption);
	// Things appear to work only if code_field and caption_field are
	// not properties of 'this' when passed into function.
	var code_field = this.code_field;
	var caption_field = this.caption_field;
	this.code_field.blur(function() {
			an.set_code(code_field.val());
			an.view_window.update();
		});
	this.caption_field.keyup(function() {
			an.set_caption(caption_field.val());
			an.view_window.update();
		});
	AnEditWindow.call(this, an);
}
make_subclass(YouTubeAnnotEditWindow, AnEditWindow);

Window.all.push(YouTubeAnnotEditWindow);

YouTubeAnnotEditWindow.template_id = "youtube_annot_edit_window_template";

function YouTubeAnnotViewWindow(an) {
	this.node = YouTubeAnnotViewWindow.template.clone();
	this.title = this.node.find(".youtube_annot_view_window_title").first();
	this.iframe = this.node.find("iframe").first();
	this.caption = this.node.find(".youtube_annot_view_window_caption").first();
	this.old_code = null;
	AnViewWindow.call(this, an);
}
make_subclass(YouTubeAnnotViewWindow, AnViewWindow);

Window.all.push(YouTubeAnnotViewWindow);

YouTubeAnnotViewWindow.template_id = "youtube_annot_view_window_template";

YouTubeAnnotViewWindow.prototype.update = function() {
	if (!this.altered) {
		return;
	}
	this.title.empty();
	this.title.append(this.annotation.annotated_item.link_text);
	console.log("new code " + this.annotation.data.code + " old code " + this.old_code);
	if (this.annotation.data.code !== this.old_code) {
		this.iframe.attr("src", "http://www.youtube.com/embed/"+this.annotation.data.code);
		this.old_code = this.annotation.data.code;
	}
	this.caption.empty();
	this.caption.append(this.annotation.data.caption);
	this.altered = false;
};

function YouTubeAnnotThumbWindow(an) {
	this.annotation = an;
	this.node = YouTubeAnnotThumbWindow.template.clone();
	this.img = this.node.find("img").first();
	AnThumbWindow.call(this, an);
}
make_subclass(YouTubeAnnotThumbWindow, AnThumbWindow);

Window.all.push(YouTubeAnnotThumbWindow);

YouTubeAnnotThumbWindow.template_id = "youtube_annot_thumb_window_template";

YouTubeAnnotThumbWindow.prototype.update = function() {
	if (!this.altered) {
		return;
	}
	this.img.attr("src", "http://img.youtube.com/vi/"+this.annotation.data.code+"/2.jpg");
	this.altered = false;
};
<commit_msg>Removing more debugging statements.<commit_after>/*******************************************************************************/
/*                                                                             */
/*                                YouTubeAnnotation                               */
/*                                                                             */
/*******************************************************************************/

function YouTubeAnnotation(annotext, ai, data) {
	Annotation.call(this, annotext, ai, data);
	if (this.data.code === undefined) {
		this.data.code = '';
	}
	if (this.data.caption === undefined) {
		this.data.caption = '';
	}
	this.data.type = YouTubeAnnotation.slug;
	this.view_window = new YouTubeAnnotViewWindow(this);
	this.edit_window = new YouTubeAnnotEditWindow(this);
	this.thumb_window = new YouTubeAnnotThumbWindow(this);
	this.view_screen = new AnViewScreen(this);
	this.edit_screen = new AnEditScreen(this);
}
make_subclass(YouTubeAnnotation, Annotation);

YouTubeAnnotation.prototype.name = "YouTube Video";
YouTubeAnnotation.slug = "youtube";
annot_types[YouTubeAnnotation.slug] = YouTubeAnnotation;

YouTubeAnnotation.prototype.is_empty = function() {
	return (!this.data.code && !this.data.caption);
};

YouTubeAnnotation.prototype.set_code = function(code) {
	this.thumb_window.altered = true;
	this.view_window.altered = true;
	this.annotated_item.view_window.altered = true;
	this.data.code = code;
	this.annotext.set_altered();
};

YouTubeAnnotation.prototype.set_caption = function(caption) {
	this.view_window.altered = true;
	this.data.caption = caption;
	this.annotext.set_altered();
};

function YouTubeAnnotEditWindow(an) {
	this.annotation = an;
	this.node = YouTubeAnnotEditWindow.template.clone();
	this.code_field = this.node.find(".youtube_annot_edit_window_code").first();
	this.caption_field = this.node.find(".youtube_annot_edit_window_caption").first();
	this.code_field.append(this.annotation.data.code);
	this.caption_field.append(this.annotation.data.caption);
	// Things appear to work only if code_field and caption_field are
	// not properties of 'this' when passed into function.
	var code_field = this.code_field;
	var caption_field = this.caption_field;
	this.code_field.blur(function() {
			an.set_code(code_field.val());
			an.view_window.update();
		});
	this.caption_field.keyup(function() {
			an.set_caption(caption_field.val());
			an.view_window.update();
		});
	AnEditWindow.call(this, an);
}
make_subclass(YouTubeAnnotEditWindow, AnEditWindow);

Window.all.push(YouTubeAnnotEditWindow);

YouTubeAnnotEditWindow.template_id = "youtube_annot_edit_window_template";

function YouTubeAnnotViewWindow(an) {
	this.node = YouTubeAnnotViewWindow.template.clone();
	this.title = this.node.find(".youtube_annot_view_window_title").first();
	this.iframe = this.node.find("iframe").first();
	this.caption = this.node.find(".youtube_annot_view_window_caption").first();
	this.old_code = null;
	AnViewWindow.call(this, an);
}
make_subclass(YouTubeAnnotViewWindow, AnViewWindow);

Window.all.push(YouTubeAnnotViewWindow);

YouTubeAnnotViewWindow.template_id = "youtube_annot_view_window_template";

YouTubeAnnotViewWindow.prototype.update = function() {
	if (!this.altered) {
		return;
	}
	this.title.empty();
	this.title.append(this.annotation.annotated_item.link_text);
	if (this.annotation.data.code !== this.old_code) {
		this.iframe.attr("src", "http://www.youtube.com/embed/"+this.annotation.data.code);
		this.old_code = this.annotation.data.code;
	}
	this.caption.empty();
	this.caption.append(this.annotation.data.caption);
	this.altered = false;
};

function YouTubeAnnotThumbWindow(an) {
	this.annotation = an;
	this.node = YouTubeAnnotThumbWindow.template.clone();
	this.img = this.node.find("img").first();
	AnThumbWindow.call(this, an);
}
make_subclass(YouTubeAnnotThumbWindow, AnThumbWindow);

Window.all.push(YouTubeAnnotThumbWindow);

YouTubeAnnotThumbWindow.template_id = "youtube_annot_thumb_window_template";

YouTubeAnnotThumbWindow.prototype.update = function() {
	if (!this.altered) {
		return;
	}
	this.img.attr("src", "http://img.youtube.com/vi/"+this.annotation.data.code+"/2.jpg");
	this.altered = false;
};
<|endoftext|>


<commit_before>// Copyright (c) 2018, Compiler Explorer Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
"use strict";

function definition() {
    return {
        keywords: [
            'module', 'import', 'Start', 'where', 'otherwise',
            'definition', 'implementation', 'from', 'class', 'instance', 'abort'
        ],

        builtintypes: [
            'Int', 'Real', 'String', 'Char'
        ],

        operators: [
            '=', '==', '>=', '<=', '+', '-', '*', '/', '::', ':==', '->', '=:', '=>', '|', '\\\\'
        ],

        numbers: /-?[0-9.]/,

        tokenizer: {
            root: [
                { include: '@whitespace' },

                [/->/, 'operators'],

                [/\|/, 'operators'],

                [/(\w*)(\s?)(::)/, ['keyword', 'white', 'operators']],

                [/[+\-*/=<>\\]/, 'operators'],

                [/[a-zA-Z_][a-zA-Z0-9_]*/, {
                    cases: {
                        '@builtintypes': 'type',
                        '@keywords': 'keyword',
                        '@default': ''
                    }
                }],

                [/[()[\],:]/, 'delimiter'],

                [/@numbers/, 'number'],

                [/(")(.*)(")/, ['string', 'string', 'string']]
            ],

            comment: [
                [/[^/*]+/, 'comment'],
                [/\*\//, 'comment', '@pop'],
                [/[/*]/, 'comment']
            ],

            whitespace: [
                [/[ \t\r\n]+/, 'white'],
                [/\/\*/, 'comment', '@comment'],
                [/\/\/.*$/, 'comment']
            ],
        }
    };
}

monaco.languages.register({ id: 'clean' });
monaco.languages.setMonarchTokensProvider('clean', definition());
<commit_msg>complex<commit_after>// Copyright (c) 2018, Compiler Explorer Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
"use strict";

function definition() {
    return {
        keywords: [
            'module', 'import', 'Start', 'where', 'otherwise',
            'definition', 'implementation', 'from', 'class', 'instance', 'abort'
        ],

        builtintypes: [
            'Int', 'Real', 'String', 'Char', 'Complex'
        ],

        operators: [
            '=', '==', '>=', '<=', '+', '-', '*', '/', '::', ':==', '->', '=:', '=>', '|', '\\\\'
        ],

        numbers: /-?[0-9.]/,

        tokenizer: {
            root: [
                { include: '@whitespace' },

                [/->/, 'operators'],

                [/\|/, 'operators'],

                [/(\w*)(\s?)(::)/, ['keyword', 'white', 'operators']],

                [/[+\-*/=<>\\]/, 'operators'],

                [/[a-zA-Z_][a-zA-Z0-9_]*/, {
                    cases: {
                        '@builtintypes': 'type',
                        '@keywords': 'keyword',
                        '@default': ''
                    }
                }],

                [/[()[\],:]/, 'delimiter'],

                [/@numbers/, 'number'],

                [/(")(.*)(")/, ['string', 'string', 'string']]
            ],

            comment: [
                [/[^/*]+/, 'comment'],
                [/\*\//, 'comment', '@pop'],
                [/[/*]/, 'comment']
            ],

            whitespace: [
                [/[ \t\r\n]+/, 'white'],
                [/\/\*/, 'comment', '@comment'],
                [/\/\/.*$/, 'comment']
            ],
        }
    };
}

monaco.languages.register({ id: 'clean' });
monaco.languages.setMonarchTokensProvider('clean', definition());
<|endoftext|>


<commit_before>import Debug from 'debug'

/**
 * Debug mutations function.
 *
 * @type {Function}
 */

const debug = Debug('slate:mutations')

/**
 * Properties on a MutationRecord
 *
 * @type {Object}
 */

const MUTATION_PROPERTIES = [
  'type',
  'oldValue',
  'target',
  'addedNodes',
  'removedNodes',
  'attributeName',
  'attributeNamespace',
  'nextSibling',
  'previousSibling',
]

/**
 * A plugin that sends short easy to digest debug info about each dom mutation
 * to browser.
 *
 * More information about mutations here:
 *
 * <https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver>
 * <https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord>
 *
 * @param {Object} options
 */

function DebugMutationsPlugin({ editor }) {
  const observer = new window.MutationObserver(mutations => {
    const array = Array.from(mutations).map(mutationRecord => {
      const object = {}

      // Only add properties that provide meaningful values to the object
      // to make the debug info easier to read
      MUTATION_PROPERTIES.forEach(key => {
        const value = mutationRecord[key]
        if (value == null) return
        if (value instanceof window.NodeList && value.length === 0) return
        object[key] = value
      })

      return object
    })

    // The first argument must not be the array as `debug` renders the first
    // argument in a different way than the rest
    debug(`${array.length} Mutations`, ...array)
  })

  /**
   * The previously observed DOM node
   *
   * @type {DOMNode}
   */

  let prevRootEl = null

  /**
   * Start observing the DOM node for mutations if it isn't being observed
   */

  function start() {
    const rootEl = editor.findDOMNode([])

    if (rootEl === prevRootEl) return

    debug('start')

    observer.observe(rootEl, {
      childList: true,
      characterData: true,
      attributes: true,
      subtree: true,
      characterDataOldValue: true,
    })

    prevRootEl = rootEl
  }

  /**
   * Stop observing the DOM node for mutations
   */

  function stop() {
    debug('stop')

    observer.disconnect()
    prevRootEl = null
  }

  return {
    onComponentDidMount: start,
    onComponentDidUpdate: start,
    onComponentWillUnmount: stop,
  }
}

export default DebugMutationsPlugin
<commit_msg>Improve debug mutations plugin (#2844)<commit_after>import Debug from 'debug'

/**
 * Debug mutations function.
 *
 * @type {Function}
 */

const debug = Debug('slate:mutations')

/**
 * Properties on a MutationRecord
 *
 * @type {Object}
 */

const MUTATION_PROPERTIES = [
  'type',
  'oldValue',
  'target',
  'addedNodes',
  'removedNodes',
  'attributeName',
  'attributeNamespace',
  'nextSibling',
  'previousSibling',
]

/**
 * A plugin that sends short easy to digest debug info about each dom mutation
 * to browser.
 *
 * More information about mutations here:
 *
 * <https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver>
 * <https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord>
 *
 * @param {Object} options
 */

function DebugMutationsPlugin() {
  const observer = new window.MutationObserver(mutations => {
    const array = Array.from(mutations).map(mutationRecord => {
      const object = {}

      // Only add properties that provide meaningful values to the object
      // to make the debug info easier to read
      MUTATION_PROPERTIES.forEach(key => {
        const value = mutationRecord[key]
        if (value == null) return

        // Make NodeList easier to read
        if (value instanceof window.NodeList) {
          if (value.length === 0) return

          object[key] = Array.from(value)
            .map(node => {
              const { outerHTML, innerHTML } = node
              if (outerHTML == null) return JSON.stringify(node.textContent)
              return outerHTML.slice(0, outerHTML.indexOf(innerHTML))
            })
            .join(', ')
          return
        }

        object[key] = value
      })

      return object
    })

    // The first argument must not be the array as `debug` renders the first
    // argument in a different way than the rest
    debug(`${array.length} Mutations`, ...array)
  })

  /**
   * The previously observed DOM node
   *
   * @type {DOMNode}
   */

  let prevRootEl = null

  /**
   * Start observing the DOM node for mutations if it isn't being observed
   */

  function start(event, editor, next) {
    const rootEl = editor.findDOMNode([])

    if (rootEl === prevRootEl) return next()

    debug('start')

    observer.observe(rootEl, {
      childList: true,
      characterData: true,
      attributes: true,
      subtree: true,
      characterDataOldValue: true,
    })

    prevRootEl = rootEl

    next()
  }

  /**
   * Stop observing the DOM node for mutations
   */

  function stop(event, editor, next) {
    debug('stop')

    observer.disconnect()
    prevRootEl = null
    next()
  }

  return {
    onComponentDidMount: start,
    onComponentDidUpdate: start,
    onComponentWillUnmount: stop,
  }
}

export default DebugMutationsPlugin
<|endoftext|>


<commit_before>function consumeService(path, service, type) {
  var field_id = "input#" + service + "ServiceLoaded_" + type;
  var loaded = $(field_id).val();
  var appName = "";

  if (location.pathname.startsWith('/verbumdomini')) {
    appName = '/verbumdomini';
  }

  if (loaded == 'false') {
    if (type == 'xml') {
      consumeXml(appName, path, service, field_id);
    } else if (type == 'json') {
      consumeJson(appName, path, service, field_id);
    } else {
      alert('Unsupported render type ' + type);
    }
  }
}

function consumeJson(appName, path, service, field_id) {
  $('#loading').show();

  var type = 'json';
  var url = location.protocol + '//' + location.host + appName + '/apirest' + path;
  var dataField = service + '_' + type;

  $.getJSON(url, function(data) {
    $('#' + dataField).append('
' + JSON.stringify(data, null, 2) + '
');
    $(field_id).val('true');
  }).done(function() {
    $('#loading').hide();
  }).error(function(jqXHR, textStatus, errorThrown) {
    alert('Service ' + url + ' unavailable. Try again later. ' + errorThrown);
  	$('#loading').hide();
  });
}

function consumeXml(appName, path, service, field_id) {
  $('#loading').show();

  var type = 'xml';
  var url = location.protocol + '//' + location.host + appName + '/apirest' + path;
  var dataField = service + '_' + type;

  $.get(url, function(data) {
    var xml = vkbeautify.xml(data, 2);
    xml = xml.replace(/</g, '<').replace(/>/g, '>');

    $('#' + dataField).append('
' + xml + '
');
    $(field_id).val('true');
  }, 'text').done(function() {
    $('#loading').hide();
  }).error(function(jqXHR, textStatus, errorThrown) {
    alert('Service ' + url + ' unavailable. Try again later. ' + errorThrown);
  	$('#loading').hide();
  });
}<commit_msg>Replace call to unexistent startsWith method by search method.<commit_after>function consumeService(path, service, type) {
  var field_id = "input#" + service + "ServiceLoaded_" + type;
  var loaded = $(field_id).val();
  var appName = "";

  if (location.pathname.search('/verbumdomini') == 0) {
    appName = '/verbumdomini';
  }

  if (loaded == 'false') {
    if (type == 'xml') {
      consumeXml(appName, path, service, field_id);
    } else if (type == 'json') {
      consumeJson(appName, path, service, field_id);
    } else {
      alert('Unsupported render type ' + type);
    }
  }
}

function consumeJson(appName, path, service, field_id) {
  $('#loading').show();

  var type = 'json';
  var url = location.protocol + '//' + location.host + appName + '/apirest' + path;
  var dataField = service + '_' + type;

  $.getJSON(url, function(data) {
    $('#' + dataField).append('
' + JSON.stringify(data, null, 2) + '
');
    $(field_id).val('true');
  }).done(function() {
    $('#loading').hide();
  }).error(function(jqXHR, textStatus, errorThrown) {
    alert('Service ' + url + ' unavailable. Try again later. ' + errorThrown);
  	$('#loading').hide();
  });
}

function consumeXml(appName, path, service, field_id) {
  $('#loading').show();

  var type = 'xml';
  var url = location.protocol + '//' + location.host + appName + '/apirest' + path;
  var dataField = service + '_' + type;

  $.get(url, function(data) {
    var xml = vkbeautify.xml(data, 2);
    xml = xml.replace(/</g, '<').replace(/>/g, '>');

    $('#' + dataField).append('
' + xml + '
');
    $(field_id).val('true');
  }, 'text').done(function() {
    $('#loading').hide();
  }).error(function(jqXHR, textStatus, errorThrown) {
    alert('Service ' + url + ' unavailable. Try again later. ' + errorThrown);
  	$('#loading').hide();
  });
}<|endoftext|>


<commit_before>
<commit_msg>Delete initiate_model.js<commit_after><|endoftext|>