jam-cloud/web/app/assets/javascripts/networkTestHelper.js

855 lines
29 KiB
JavaScript

(function (context, $) {
"use strict";
context.JK = context.JK || {};
context.JK.NetworkTest = function (app) {
var NETWORK_TEST_TYPES = {
RestPhase: 0,
PktTest100NormalLatency: 1,
PktTest200MediumLatency: 2,
PktTest400LowLatency: 3,
PktTestRateSweep: 4,
RcvOnly: 5
}
var STARTING_NUM_CLIENTS = 4;
var PAYLOAD_SIZE = gon.global.ftue_network_test_packet_size;
var MINIMUM_ACCEPTABLE_SESSION_SIZE = 2;
var RETRY_THRESHOLD = 2;
var gearUtils = context.JK.GearUtils;
var rest = context.JK.Rest();
var logger = context.JK.logger;
var $step = null;
var TEST_SUCCESS_CALLBACK = 'JK.HandleNetworkTestSuccess';
var TEST_TIMEOUT_CALLBACK = 'JK.HandleNetworkTestTimeout';
var $startNetworkTestBtn = null;
var $testResults = null;
var $testScore = null;
var $testText = null;
var testedSuccessfully = false;
var $scoringBar = null;
var $goodMarker = null;
var $goodLine = null;
var $currentScore = null;
var $scoredClients = null;
var $subscore = null;
var $watchVideo = null;
var backendGuardTimeout = null;
var primeGuardTimeout = null;
var primeDeferred = null;
var serverClientId = '';
var scoring = false;
var numClientsToTest = STARTING_NUM_CLIENTS;
var testSummary = {attempts: [], final: null}
var $self = $(this);
var scoringZoneWidth = 100;//px
var inGearWizard = false;
var operatingSystem = null;
var PRIME_PUMP_TIME = 1;
// these try to make it such that we only pass a NetworkTest Pass/Failed one time in a new user flow
var trackedPass = false;
var lastNetworkFailure = null;
var bandwidthSamples = [];
var NETWORK_TEST_START = 'network_test.start';
var NETWORK_TEST_DONE = 'network_test.done';
var NETWORK_TEST_FAIL = 'network_test.fail';
var NETWORK_TEST_CANCEL = 'network_test.cancel';
function createSuccessCallbackName(priming) {
if (priming) {
if (inGearWizard) {
return TEST_SUCCESS_CALLBACK + 'ForPumpPrimingGW';
}
else {
return TEST_SUCCESS_CALLBACK + 'ForPumpPrimingDialog';
}
}
else {
if (inGearWizard) {
return TEST_SUCCESS_CALLBACK + 'ForGearWizard';
}
else {
return TEST_SUCCESS_CALLBACK + 'ForDialog';
}
}
}
function createTimeoutCallbackName(priming) {
if (priming) {
if (inGearWizard) {
return TEST_TIMEOUT_CALLBACK + 'ForPumpPrimingGW';
}
else {
return TEST_TIMEOUT_CALLBACK + 'ForPumpPrimingDialog';
}
}
else {
if (inGearWizard) {
return TEST_TIMEOUT_CALLBACK + 'ForGearWizard';
}
else {
return TEST_TIMEOUT_CALLBACK + 'ForDialog';
}
}
}
// this averages bandwidthSamples; this method is meant just for GA data
function avgBandwidth(num_others) {
if (bandwidthSamples.length == 0) {
return 0;
}
else {
var total = 0;
context._.each(bandwidthSamples, function (sample) {
total += (sample * num_others * 400 * (100 + 28)); // sample is a percentage of 400. So sample * 400 gives us how many packets/sec. 100 is payload; 28 is UDP+ETHERNET overhead, to give us bandwidth
})
return total / bandwidthSamples.length;
}
}
function reset() {
trackedPass = false;
lastNetworkFailure = null;
resetTestState();
}
function resetTestState() {
serverClientId = '';
scoring = false;
numClientsToTest = STARTING_NUM_CLIENTS;
testSummary = {attempts: []};
configureStartButton();
$scoredClients.empty();
$testResults.removeClass('good acceptable bad testing');
$testText.empty();
$subscore.empty();
$currentScore.width(0);
bandwidthSamples = [];
}
function renderStartTest() {
configureStartButton();
$testResults.addClass('testing');
$goodLine.css('left', (gon.ftue_packet_rate_treshold * 100) + '%');
$goodMarker.css('left', (gon.ftue_packet_rate_treshold * 100) + '%');
}
function renderStopTest(score, text) {
$scoredClients.html(score);
$testText.html(text);
$testResults.removeClass('testing');
}
function postDiagnostic() {
rest.createDiagnostic({
type: 'NETWORK_TEST_RESULT',
data: {client_type: context.JK.clientType(), client_id: context.JK.JamServer.clientID, summary: testSummary}
});
}
function appendContextualStatement() {
if (inGearWizard) {
return "You can skip this step for now."
}
else {
return '';
}
}
function getLastNetworkFailure() {
return lastNetworkFailure;
}
function storeLastNetworkFailure(reason, data) {
if (!trackedPass) {
lastNetworkFailure = {reason: reason, data: data};
}
}
function testFinished() {
var attempt = getCurrentAttempt();
if (!testSummary.final) {
testSummary.final = {reason: attempt.reason};
}
var reason = testSummary.final.reason;
var success = false;
if (reason == "success") {
renderStopTest(attempt.num_clients, "Your router and Internet service will support sessions of up to " + attempt.num_clients + " JamKazam musicians.")
testedSuccessfully = true;
if (!testSummary.final.num_clients) {
testSummary.final.num_clients = attempt.num_clients;
}
// context.jamClient.GetNetworkTestScore() == 0 is a rough approximation if the user has passed the FTUE before
if (inGearWizard || context.jamClient.GetNetworkTestScore() == 0) {
trackedPass = true;
lastNetworkFailure = null;
context.JK.GA.trackNetworkTest(context.JK.detectOS(), testSummary.final.num_clients);
}
context.jamClient.SetNetworkTestScore(attempt.num_clients);
if (testSummary.final.num_clients == 2) {
$testResults.addClass('acceptable');
}
else {
$testResults.addClass('good');
}
success = true;
}
else if (reason == "minimum_client_threshold") {
context.jamClient.SetNetworkTestScore(0);
renderStopTest('', "We're sorry, but your router and Internet service will not effectively support JamKazam sessions. Please click the HELP button for more information.")
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.bandwidth, avgBandwidth(attempt.num_clients - 1));
}
else if (reason == "unreachable" || reason == "no-transmit") {
context.jamClient.SetNetworkTestScore(0);
renderStopTest('', "We're sorry, but your router will not support JamKazam in its current configuration. Please click the HELP button for more information.");
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.stun, attempt.num_clients);
}
else if (reason == "internal_error") {
context.JK.alertSupportedNeeded("The JamKazam client software had an unexpected problem while scoring your Internet connection.");
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if (reason == "remote_peer_cant_test") {
context.JK.alertSupportedNeeded("The JamKazam service is experiencing technical difficulties.");
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if (reason == "server_comm_timeout") {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("Communication with the JamKazam network service has timed out." + appendContextualStatement());
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if (reason == 'backend_gone') {
context.JK.alertSupportedNeeded("The JamKazam client is experiencing technical difficulties.");
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if (reason == "invalid_response") {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("The JamKazam client software had an unexpected problem while scoring your Internet connection.<br/><br/>Reason: " + attempt.backend_data.reason + '.');
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if (reason == 'no_servers') {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("No network test servers are available." + appendContextualStatement());
renderStopTest('', '');
testedSuccessfully = true;
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if (reason == 'no_network') {
context.JK.Banner.showAlert("Please try again later. Your network appears down.");
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.noNetwork);
}
else if (reason == "rest_api_error") {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("Unable to acquire a network test server." + appendContextualStatement());
testedSuccessfully = true;
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if (reason == "timeout") {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("Communication with the JamKazam network service timed out." + appendContextualStatement());
testedSuccessfully = true;
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("The JamKazam client software had a logic error while scoring your Internet connection.");
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
numClientsToTest = STARTING_NUM_CLIENTS;
scoring = false;
configureStartButton();
postDiagnostic();
if (success) {
$self.triggerHandler(NETWORK_TEST_DONE)
}
else {
$self.triggerHandler(NETWORK_TEST_FAIL)
}
}
function getCurrentAttempt() {
return testSummary.attempts[testSummary.attempts.length - 1];
}
function isFirstAttempt() {
return testSummary.attempts.length == 0 || testSummary.attempts.length == 1;
}
function hasGoneDown() {
var goneDown = false;
context._.each(testSummary.attempts, function(attempt) {
if(attempt.num_clients == STARTING_NUM_CLIENTS - 1) {
goneDown = true
return false;
}
});
return goneDown;
}
// is this a retry attempt? If so, how many times now has it been.
// 0 = this is the 1st attempt
// > 0 indicates the number of retries.
function numRetryAttempts() {
// starting at the end of the attempts array, see how many have the same session count, which is implicitely
// indicative of a retry
var i = 0;
var testSessionSize = null;
var numSameSizeTests = 0;
for(i = testSummary.attempts.length - 1; i >= 0; i--) {
var attempt = testSummary.attempts[i];
if(testSessionSize === null) {
// this is the 1st loop through. just recording the testSessionSize
testSessionSize = attempt.num_clients;
}
else {
if(testSessionSize == attempt.num_clients) {
numSameSizeTests++;
}
else {
break; // different size session found, so we are digging back into non-retry territory. bail out
}
}
}
return numSameSizeTests;
}
function hasTooManyRetries() {
return numRetryAttempts() >= RETRY_THRESHOLD;
return false;
}
function primeTimedOut() {
logger.warn("backend never completed priming pump phase");
scoring = false;
primeDeferred.reject();
}
function backendTimedOut() {
testSummary.final = {reason: 'backend_gone'}
testFinished();
}
function cancel() {
}
function clearBackendGuard() {
if (backendGuardTimeout) {
clearTimeout(backendGuardTimeout);
backendGuardTimeout = null;
}
}
// we know we are attempting a pass if the backend or prime guard timeout is not null
function isAttemptingPass() {
return backendGuardTimeout != null || primeGuardTimeout != null;
}
function clearPrimeGuard() {
if (primeGuardTimeout) {
clearTimeout(primeGuardTimeout);
primeGuardTimeout = null;
}
}
function setPrimeGuard() {
clearPrimeGuard();
primeGuardTimeout = setTimeout(function () {
clearPrimeGuard();
primeTimedOut()
}, (PRIME_PUMP_TIME + 10) * 1000);
}
function setBackendGuard() {
clearBackendGuard();
backendGuardTimeout = setTimeout(function () {
clearBackendGuard();
backendTimedOut()
}, (gon.ftue_network_test_duration + 1) * 1000);
}
function attemptTestPass() {
var attempt = {};
attempt.payload_size = PAYLOAD_SIZE;
attempt.duration = gon.ftue_network_test_duration;
attempt.test_type = 'PktTest400LowLatency';
attempt.num_clients = numClientsToTest;
attempt.server_client_id = serverClientId;
attempt.received_progress = false;
testSummary.attempts.push(attempt);
//context.jamClient.StopNetworkTest('');
$testText.text("Simulating the network traffic of a " + numClientsToTest + "-person session.");
updateProgress(0, false);
setBackendGuard();
logger.debug("network test attempt: " + numClientsToTest + "-person session, 400 packets/s, " + PAYLOAD_SIZE + " byte payload")
context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(false), createTimeoutCallbackName(false),
NETWORK_TEST_TYPES.PktTest400LowLatency,
gon.ftue_network_test_duration,
numClientsToTest - 1,
PAYLOAD_SIZE, gon.global.ftue_network_test_backend_retries);
}
// you have to score a little to 'prime' the logic to know whether it's on wireless or not
function primePump() {
scoring = true;
primeDeferred = new $.Deferred();
setPrimeGuard();
context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(true), createTimeoutCallbackName(true),
NETWORK_TEST_TYPES.PktTest400LowLatency,
PRIME_PUMP_TIME,
2,
PAYLOAD_SIZE, gon.global.ftue_network_test_backend_retries);
return primeDeferred;
}
function cancelTest() {
scoring = false;
configureStartButton();
renderStopTest();
$self.triggerHandler(NETWORK_TEST_CANCEL)
}
function postPumpRun() {
// check if on Wifi 1st
var isWireless = context.jamClient.IsMyNetworkWireless();
if (isWireless == -1) {
logger.warn("unable to determine if the user is on wireless or not for network test. skipping prompt.")
}
if (isWireless == 1) {
context.JK.Banner.showAlert({buttons: [
{name: 'CANCEL', click: function () {
cancelTest();
}},
{name: 'RUN NETWORK TEST ANYWAY', click: function () {
attemptTestPass();
;
}}
],
html: "<p>It appears that your computer is connected to your network using WiFi.</p>" +
"<p>We strongly advise against running the JamKazam application on a WiFi connection. " +
"We recommend using a wired Ethernet connection from your computer to your router. " +
"A WiFi connection is likely to cause significant issues in both latency and audio quality.</p>"})
}
else {
attemptTestPass();
}
}
function prepareNetworkTest() {
if (scoring) return false;
logger.info("starting network test");
resetTestState();
scoring = true;
$self.triggerHandler(NETWORK_TEST_START);
renderStartTest();
rest.getLatencyTester()
.done(function (response) {
// ensure there are no tests ongoing
serverClientId = response.client_id;
testSummary.serverClientId = serverClientId;
logger.info("beginning network test against client_id: " + serverClientId);
primePump()
.done(function () {
postPumpRun();
})
.fail(function () {
logger.debug("unable to determine user's network type. primePump failed.")
context.JK.Banner.showAlert({
title: 'Unable to Determine Network Type',
buttons: [
{name: 'CANCEL', click: function () {
cancelTest();
}},
{name: 'RUN NETWORK TEST ANYWAY', click: function () {
attemptTestPass();
;
}}
],
html: "<p>We are unable to determine if your computer is connected to your network using WiFi.</p>" +
"<p>We strongly advise against running the JamKazam application on a WiFi connection. " +
"We recommend using a wired Ethernet connection from your computer to your router. " +
"A WiFi connection is likely to cause significant issues in both latency and audio quality.</p>"})
});
})
.fail(function (jqXHR) {
if (jqXHR.status == 404) {
// means there are no network testers available.
// we have to skip this part of the UI
testSummary.final = {reason: 'no_servers'}
}
else {
if (context.JK.isNetworkError(arguments)) {
testSummary.final = {reason: 'no_network'}
}
else {
testSummary.final = {reason: 'rest_api_error'}
}
}
testFinished();
})
return false;
}
function updateProgress(throughput, showSubscore) {
var width = throughput * 100;
$currentScore.stop().data('showSubscore', showSubscore);
if (!showSubscore) {
$subscore.text('');
}
$currentScore.animate({
duration: 1000,
width: width + '%'
}, {
step: function (now, fx) {
if (showSubscore) {
var newWidth = ( 100 * parseFloat($currentScore.css('width')) / parseFloat($currentScore.parent().css('width')) );
$subscore.text((Math.round(newWidth * 10) / 10) + '%');
}
}
}).css('overflow', 'visible');
;
}
function primePumpTimeout(data) {
if(!isAttemptingPass()) {
logger.error("primePumpTimeout: already completed the test pass. indicates backend sent > 1 final event");
return;
}
clearPrimeGuard();
scoring = false;
logger.debug("the prime pump routine timed out")
primeDeferred.reject();
}
function primePumpComplete(data) {
if(!isAttemptingPass()) {
logger.error("primePumpComplete: already completed the test pass. indicates backend sent > 1 final event");
return;
}
if (data.progress === true) {
// waiting...
logger.debug("pump prime progress report");
setPrimeGuard();
}
else {
clearPrimeGuard();
// we could check for errors, but it's confusing to do so. we just want to let the backend figure out if
// the interface is wireless, or not
setTimeout(function () {
logger.debug("pump primed");
scoring = false;
primeDeferred.resolve();
}, 500); // give backend room to breath for timing/race issues
}
}
function networkTestComplete(data) {
if(!isAttemptingPass()) {
logger.error("networkTestComplete: already completed the test pass. indicates backend sent > 1 final event");
return;
}
var attempt = getCurrentAttempt();
function refineTest(up) {
if (up === null) {
logger.debug("retrying test at size: " + numClientsToTest);
setTimeout(attemptTestPass, 500); // wait a second to avoid race conditions with client/server comm
}
else if (up) {
if (numClientsToTest == gon.ftue_network_test_max_clients) {
attempt.reason = "success";
testFinished();
}
else if(hasGoneDown()) {
// this means we've gone up before... so don't go back down (i.e., creating a loop)
attempt.reason = "success";
testSummary.final = { reason: 'success', num_clients: numClientsToTest }
testFinished();
}
else {
numClientsToTest++;
logger.debug("increasing number of clients to " + numClientsToTest);
setTimeout(attemptTestPass, 500); // wait a second to avoid race conditions with client/server comm
}
}
else {
// reduce numclients if we can
if (numClientsToTest == MINIMUM_ACCEPTABLE_SESSION_SIZE) {
// we are too low already. fail the user
attempt.reason = "minimum_client_threshold";
testFinished();
}
else if (numClientsToTest > STARTING_NUM_CLIENTS) {
// this means we've gone up before... so don't go back down (i.e., creating a loop)
attempt.reason = "success";
testSummary.final = { reason: 'success', num_clients: numClientsToTest - 1 }
testFinished();
}
else {
numClientsToTest--;
logger.debug("reducing number of clients to " + numClientsToTest);
setTimeout(attemptTestPass, 500); // wait a second to avoid race conditions with client/server comm
}
}
}
attempt.backend_data = data;
if (data.progress === true) {
setBackendGuard();
var animate = true;
if (data.downthroughput && data.upthroughput) {
if (data.downthroughput > 0 || data.upthroughput > 0) {
attempt.received_progress = true;
animate = true;
}
if (attempt.received_progress) {
// take the lower
var throughput = data.downthroughput < data.upthroughput ? data.downthroughput : data.upthroughput;
bandwidthSamples.push(data.upthroughput);
updateProgress(throughput, true);
}
}
}
else {
clearBackendGuard();
logger.debug("network test pass completed. data: ", data);
if (data.reason == "unreachable") {
logger.debug("network test: unreachable (STUN issue or similar)")
attempt.reason = data.reason;
testFinished();
}
else if (data.reason == "no-transmit") {
logger.debug("network test: no-transmit (STUN issue or similar)");
attempt.reason = data.reason;
testFinished();
}
else if (data.reason == "internal_error") {
// oops
logger.debug("network test: internal_error (client had a unexpected problem)");
attempt.reason = data.reason;
testFinished();
}
else if (data.reason == "remote_peer_cant_test") {
// old client
logger.debug("network test: remote_peer_cant_test (old client)")
attempt.reason = data.reason;
testFinished();
}
else if (data.reason == "server_comm_timeout") {
logger.debug("network test: server_comm_timeout (communication with server problem)")
attempt.reason = data.reason;
testFinished();
}
else {
if (!data.downthroughput || !data.upthroughput) {
// we have to assume this is bad. just not a reason we know about in code
logger.debug("network test: no test data (unknown issue? " + data.reason + ")")
attempt.reason = "invalid_response";
testFinished();
}
else {
// success... but we still have to verify if this data is within threshold
if (data.downthroughput < gon.ftue_packet_rate_treshold) {
logger.debug("network test: downthroughput too low. downthroughput: " + data.downthroughput + ", threshold: " + gon.ftue_packet_rate_treshold);
refineTest(false);
}
else if (data.upthroughput < gon.ftue_packet_rate_treshold) {
logger.debug("network test: upthroughput too low. upthroughput: " + data.upthroughput + ", threshold: " + gon.ftue_packet_rate_treshold);
refineTest(false);
}
else {
// true success. we can accept this score
logger.debug("network test: success")
refineTest(true);
}
}
}
// VRFS-1742
// context.jamClient.StopNetworkTest(serverClientId);
}
}
function networkTestTimeout(data) {
if(!isAttemptingPass()) {
logger.error("networkTestTimeout: already completed the test pass. indicates backend sent > 1 final event");
return;
}
clearBackendGuard();
logger.warn("network timeout when testing latency test: " + data);
var attempt = getCurrentAttempt();
attempt.reason = 'timeout';
attempt.backend_data = data;
testFinished();
}
function hasScoredNetworkSuccessfully() {
return testedSuccessfully;
}
function configureStartButton() {
if (scoring) {
$startNetworkTestBtn.text('NETWORK TEST RUNNING...').removeClass('button-orange').addClass('button-grey')
}
else {
$startNetworkTestBtn.text('START NETWORK TEST').removeClass('button-grey').addClass('button-orange');
}
}
function initializeNextButtonState() {
$dialog.setNextState(hasScoredNetworkSuccessfully() && !scoring);
}
function initializeBackButtonState() {
$dialog.setBackState(!scoring);
}
function beforeHide() {
}
function initializeVideoWatchButton() {
if (operatingSystem == "Win32") {
$watchVideo.attr('href', 'https://www.youtube.com/watch?v=rhAdCVuwhBc');
}
else {
$watchVideo.attr('href', 'https://www.youtube.com/watch?v=0r1py0AYJ4Y');
}
}
function initialize(_$step, _inGearWizard) {
$step = _$step;
inGearWizard = _inGearWizard;
$startNetworkTestBtn = $step.find('.start-network-test');
if ($startNetworkTestBtn.length == 0) throw 'no start network test button found in network-test'
$testResults = $step.find('.network-test-results');
$testScore = $step.find('.network-test-score');
$testText = $step.find('.network-test-text');
$scoringBar = $step.find('.scoring-bar');
$goodMarker = $step.find('.good-marker');
$goodLine = $step.find('.good-line');
$currentScore = $step.find('.current-score');
$scoredClients = $step.find('.scored-clients');
$subscore = $step.find('.subscore');
$watchVideo = $step.find('.watch-video');
$startNetworkTestBtn.on('click', function () {
prepareNetworkTest();
});
operatingSystem = context.JK.GetOSAsString();
initializeVideoWatchButton();
// if this network test is instantiated anywhere else than the gearWizard, or a dialog, then this will have to be expanded
if (inGearWizard) {
context.JK.HandleNetworkTestSuccessForPumpPrimingGW = function (data) {
primePumpComplete(data)
};
context.JK.HandleNetworkTestTimeoutForPumpPrimingGW = function (data) {
primePumpTimeout(data)
};
context.JK.HandleNetworkTestSuccessForGearWizard = function (data) {
networkTestComplete(data)
}; // pin to global for bridge callback
context.JK.HandleNetworkTestTimeoutForGearWizard = function (data) {
networkTestTimeout(data)
}; // pin to global for bridge callback
}
else {
context.JK.HandleNetworkTestSuccessForPumpPrimingDialog = function (data) {
primePumpComplete(data)
};
context.JK.HandleNetworkTestTimeoutForPumpPrimingDialog = function (data) {
primePumpTimeout(data)
};
context.JK.HandleNetworkTestSuccessForDialog = function (data) {
networkTestComplete(data)
}; // pin to global for bridge callback
context.JK.HandleNetworkTestTimeoutForDialog = function (data) {
networkTestTimeout(data)
}; // pin to global for bridge callback
}
}
this.isScoring = function () {
return scoring;
};
this.hasScoredNetworkSuccessfully = hasScoredNetworkSuccessfully;
this.initialize = initialize;
this.reset = reset;
this.cancel = cancel;
this.getLastNetworkFailure = getLastNetworkFailure;
this.NETWORK_TEST_START = NETWORK_TEST_START;
this.NETWORK_TEST_DONE = NETWORK_TEST_DONE;
this.NETWORK_TEST_FAIL = NETWORK_TEST_FAIL;
this.NETWORK_TEST_CANCEL = NETWORK_TEST_CANCEL;
return this;
}
})(window, jQuery);