/// <summary>
        /// Register a client-side script to handle task activity messages from the SignalRTaskActivityReporter.
        /// </summary>
        public static void AddActivityReporterScripts(RockPage page, string taskCompletedCallbackFunctionName = null)
        {
            // Add SignalR framework scripts.
            page.AddScriptLink("~/Scripts/jquery.signalR-2.2.0.min.js", fingerprint: false);
            page.ClientScript.RegisterStartupScript(page.GetType(), "signalr", @"<script src=""/SignalR/hubs""></script>", false);

            // Add task activity notification script.
            string script = @"
<!-- SignalR Functions -->
$( function() {
    <!-- Create the SignalR proxy and message event handlers -->
    var proxy = $.connection.TaskActivityMessageHub;

    proxy.client.Reset = function () {
        <!--  Hide all task-related elements -->
        $( '.js-global-task-result' ).hide();
        $( '.js-global-task-progress' ).hide();
    };

    proxy.client.NotifyTaskStarted = function (taskInfo) {
        var log = $( ""[id$='_TaskActivityLog']"" );
        if ( taskInfo.HasActivityLog ) {
            log.show();
        }
        else {
            log.hide();
        }
        <!--  Set initial state of task-related elements -->
        $( '.js-global-task-result' ).hide();
        $( '.js-global-task-progress-long-running' ).hide();
        $( '.js-global-task-progress' ).show();
        <!--  Set elements associated with long-running tasks to appear after an initial delay of 5s. -->
        var barCtl = $( ""[id$='_TaskActivityBar']"" );
        if ( barCtl != null ) {
            setTimeout( function() {
                            barCtl.show();
                            $( '.js-global-task-progress-long-running' ).show();
                        }, 5000 );
        }
        proxy.client.UpdateTaskProgress({ Message: taskInfo.StatusMessage, CompletionPercentage: 0 });
    }

    proxy.client.NotifyTaskComplete = function (taskInfo) {
        var resultMessageCtl = $( ""[id$='_TaskActivityNotificationBox']"" );
        resultMessageCtl.html( taskInfo.StatusMessage );
        if ( taskInfo.HasErrors ) {
            resultMessageCtl.attr( 'class', 'alert alert-danger' );
        }
        else if ( taskInfo.HasWarnings ) {
            resultMessageCtl.attr( 'class', 'alert alert-warning' );
        }
        else {
            resultMessageCtl.attr( 'class', 'alert alert-success' );
        }

        <!--  Set final state of task-related elements -->
        $( '.js-global-task-progress' ).hide();
        $( '.js-global-task-progress-long-running' ).hide();
        $( '.js-global-task-result' ).show();

        <!-- Assign the callbackData object that will be used as the parameter for the callback function. -->
        var callbackData = taskInfo.Data;
        <taskCompletedCallbackFunction>
    }

    proxy.client.UpdateTaskProgress = function (taskActivity) {
        var messageCtl = $( ""[id$='_TaskActivityMessage']"" );
        if ( messageCtl != null ) {
            messageCtl.html( taskActivity.Message );
        }
        var elapsedTimeCtl = $( ""[id$='_TaskActivityTime']"" );
        if ( elapsedTimeCtl != null ) {
            elapsedTimeCtl.html( '[' + taskActivity.ElapsedTimeFormatted + ']' );
        }
        var barCtl = $( ""[id$='_TaskActivityBar']"" );
        if ( barCtl != null ) {
            var fillCtl = $( ""[id$='_TaskActivityBarFill']"" );
            fillCtl.css( 'width', taskActivity.CompletionPercentage + '%' );
            var percentCtl = $( ""[id$='_TaskActivityPercentage']"" );
            percentCtl.text( taskActivity.CompletionPercentage.toFixed( 1 ) + '% complete' );
        }
    }

    proxy.client.UpdateTaskLog = function (message) {
        var container = $( ""[id$='_messageContainer']"" );
        if ( !container.isVisible ) {
            return;
        }
        var maxBufferSize = 100;
        var messageCount = container.children().length;
        if ( messageCount >= maxBufferSize ) {
            container.children().slice( 0, messageCount - maxBufferSize + 1 ).remove();
        }
        container.append( message );
        var height = container[0].scrollHeight;
        container.scrollTop( height );
    }

    <!-- Hub disconnection handler -->
    $.connection.hub.disconnected(function () {
            $.connection.hub.start();
    });

    <!-- Start the SignalR hub proxy -->
    $.connection.hub.start();

    <!--  Set initial state of task-related elements -->
    $( '.js-global-task-result' ).hide();
    $( '.js-global-task-progress' ).hide();

    var progressMeterCtl = $( ""[id$='_TaskActivityBar']"" );
    if ( progressMeterCtl != null ) {
        progressMeterCtl.hide();
    }
})
";

            // Add an invocation of the specified callback function.
            var taskCompletedCallbackFunction = string.Empty;

            if (!string.IsNullOrWhiteSpace(taskCompletedCallbackFunctionName))
            {
                taskCompletedCallbackFunction = string.Format("{0}( callbackData );", taskCompletedCallbackFunctionName);
            }

            script = script.Replace("<taskCompletedCallbackFunction>", taskCompletedCallbackFunction);

            page.ClientScript.RegisterStartupScript(page.GetType(), "task-activity", script, true);
        }