function RuleProgressBar(handler_id, ajaxURL) {
    'use strict';
    var self = this;

    self.in_progress = ko.observable(false);
    self.current = ko.observable(0);
    self.total = ko.observable(0);

    self.progress_pct = ko.computed(function() {
        if(self.total() > 0) {
            return Math.round((self.current() / self.total()) * 100) + "%";
        } else {
            return "0%";
        }
    });

    self.progress_display = ko.computed(function() {
        return (self.current() || "?") + " / " + (self.total() || "?");
    });

    self.update_progress = function() {
        var request = $.ajax({
            url: ajaxURL,
            type: "GET",
            async: false,
            dataType: "json",
            data: {
                "handler_id": handler_id,
            },
        }).done(function(data, textStatus, jqXHR) {
            if(data.success) {
                self.in_progress(!data.complete);
                if(self.in_progress()) {
                    self.current(data.current);
                    self.total(data.total);
                }
            }
        }).always(function(data, textStatus, jqXHR) {
            setTimeout(self.update_progress, 15000);
        });
    }

    self.update_progress();

}

@@ -1,16 +1,1384 @@
+var PROGRESS_BAR_UPDATE_INTERVAL = 15000;%0A%0A%0Afunction RuleProgressBarList() %7B%0A    'use strict';%0A    var self = this;%0A%0A    self.progress_bars = %5B%5D;%0A    self.index = 0;%0A%0A    self.add = function(progress_bar) %7B%0A        self.progress_bars.push(progress_bar);%0A    %7D;%0A%0A    self.update_progress = function() %7B%0A        if(self.progress_bars.length === 0) %7B%0A            // If there are no RuleProgressBars in the list, then just call%0A            // this method again, and keep doing so until there is at least%0A            // one RuleProgressBar.%0A            setTimeout(self.update_progress, PROGRESS_BAR_UPDATE_INTERVAL);%0A        %7D else %7B%0A            // Now that there is at least one element, we're going to call%0A            // update_progress() on the next RuleProgressBar in the list,%0A            // and since each call to update_progress() sets the next timeout,%0A            // we're calling update_progress() on each RuleProgressBar one at a%0A            // time every PROGRESS_BAR_UPDATE_INTERVAL milliseconds.%0A            var next = self.progress_bars%5Bself.index%5D;%0A            self.index++;%0A            if(self.index %3E= self.progress_bars.length) %7B%0A                self.index = 0;%0A            %7D%0A            next.update_progress();%0A        %7D%0A    %7D;%0A%0A    // Start the update progress loop%0A    self.update_progress();%0A%7D%0A%0A%0Avar progress_bar_list = new RuleProgressBarList();%0A%0A%0A
 function RulePro
@@ -2541,95 +2541,367 @@
     
-setTimeout(self.update_progress, 15000);%0A        %7D);%0A    %7D%0A%0A    self.update_progress(
+// Setup the call to update_progress() which will update the next%0A            // RuleProgressBar in the list. We have to do this here to make%0A            // sure we always wait until the ajax request is completely done.%0A            setTimeout(progress_bar_list.update_progress, PROGRESS_BAR_UPDATE_INTERVAL);%0A        %7D);%0A    %7D%0A%0A    progress_bar_list.add(self
 );%0A
-%0A
 %7D%0A

Make rule progress bars update one at a time