Index: /issm/trunk-jpl/src/m/classes/clusters/generic.js
===================================================================
--- /issm/trunk-jpl/src/m/classes/clusters/generic.js	(revision 26345)
+++ /issm/trunk-jpl/src/m/classes/clusters/generic.js	(revision 26346)
@@ -115,6 +115,7 @@
 		
 		// Set request properties
-		request.position 	= 0; // Keep track of current parsing position in repsonseText
-		request.timeout 	= 1000 * 60 * 60 * 3; // 3 hrs (in milliseconds); NOTE: This should match FastCgiServer timeout in Apache conf
+		request.position 	 = 0; // Keep track of current parsing position in repsonseText
+		request.timeout 	= 1000 * 60 * 10; // in milliseconds; NOTE: Under current implementation, this should match 'Timeout' option in Apache conf (/etc/apache2/apache2.conf)
+		request.resultBegin = false;
 		
 		request.ontimeout = function(event) { //{{{
@@ -187,5 +188,14 @@
 					}
 				} else if (request.responseText.length >= endIndex) { // Ensure entire chunk is loaded
-					progress = parseInt(request.responseText.slice(startIndex, endIndex));
+					if (request.resultBegin) {
+						return;
+					}
+					chunk = request.responseText.slice(startIndex, endIndex)
+					if (chunk == 'RESULT_BEGIN') {
+						progress = 100;
+						request.resultBegin = true;
+					} else {
+						progress = parseInt(chunk);
+					}
 					if (hasCallout) {
 						callout.setHeader('Computing...');
@@ -221,14 +231,21 @@
 			
 			try {
-/*
-				console.log(request.responseText);
-				console.log('request.position : ' + request.position);
-				console.log('request.responseType : ' + request.responseType);
-				console.log('request.responseText.length : ' + request.responseText.length);
-*/
+				//Scan through buffer until progress updates stop and 'RESULT_BEGIN' string is received
+				let startIndex 	= request.position;
+				let endIndex 	= request.position + 10;
+				let chunkSize = 0;
+				let chunk = 0;
+				while (!request.resultBegin && chunk != 'RESULT_BEGIN') {
+					chunkSize = parseInt(request.responseText.slice(startIndex, endIndex));
+					startIndex 	= endIndex;
+					endIndex 	= startIndex + chunkSize;
+					chunk = request.responseText.slice(startIndex, endIndex);
+					startIndex 	= endIndex;
+					endIndex 	= startIndex + 10;
+					request.position = startIndex;
+				}
+
 				responseText 	= window.atob(request.responseText.slice(request.position + 10).replace(/\s/g, ''));
-// 				console.log('responseText.length : ' + responseText.length);
 				buffer 			= str2ab(responseText);
-// 				console.log('buffer.length : ' + buffer.length);
 /*
 	            bufferInflated 	= UZIP.inflate(buffer);
@@ -248,5 +265,5 @@
 				// Let front end script handle changes to callout
 				if (hasCallout) {
-					callout.set('Success!', '<p>Solve successful</p>');
+					callout.set('Success!', '<p>Request successful</p>');
 				} else {
 					solveButton.text(solveButtonText).prop('disabled', false);
@@ -255,5 +272,5 @@
 			} catch (e) {
 				console.log(e);
-				if (vesl.string.startsWith(responseText, 'Error')) {
+				if (vesl.strings.startsWith(responseText, 'Error')) {
 					if (hasCallout) {
 						callout.set(vesl.ERROR_HEADER_GENERAL, '<p>Something went wrong. ' + vesl.ERROR_CONTENT_TRY_AGAIN + '</p>');
@@ -272,5 +289,5 @@
 		}; //}}}
 		
-		request.responseType = 'application/octet-stream';
+		request.responseType = 'text';
 		
 		/* Construct request */
