From scribe at crosswire.org  Thu Mar 23 19:39:13 2017
From: scribe at crosswire.org (scribe at crosswire.org)
Date: Thu, 23 Mar 2017 19:39:13 -0700
Subject: [Ils-source] r1529 - in trunk: src/com/resolutions/ils/data webapp
Message-ID: <E1crF8D-0002id-3O@crosswire.org>

Author: scribe
Date: 2017-03-23 19:39:12 -0700 (Thu, 23 Mar 2017)
New Revision: 1529

Added:
   trunk/webapp/genbackcerts.jsp
Modified:
   trunk/src/com/resolutions/ils/data/CourseAttempt.java
   trunk/src/com/resolutions/ils/data/UserProfile.java
   trunk/webapp/report_employeecourseatt.jsp
Log:
Fixed report display bugs when user has no courses assigned
Added genbackcerts to ils


Modified: trunk/src/com/resolutions/ils/data/CourseAttempt.java
===================================================================
--- trunk/src/com/resolutions/ils/data/CourseAttempt.java	2017-02-15 01:16:28 UTC (rev 1528)
+++ trunk/src/com/resolutions/ils/data/CourseAttempt.java	2017-03-24 02:39:12 UTC (rev 1529)
@@ -360,13 +360,77 @@
 	public void passAllAssociatedCurriculum(ILSSession session, HttpServletRequest request) {
 		passAllAssociatedCurriculum(session, request, null);
 	}
+
+	public static CourseAttempt makeCurriculumCourseAttemptIfPassed(ILSSession session, int userProfileID, Course cur, Set<Integer> limitToCASIDs) {
+		boolean isPassed = false;
+		Vector<Course> courses = cur.getCurriculumCourses();
+		if (courses != null) {
+			// if so, then let's check if all courses are passed
+			int  timeframe   = 0;
+			long startDate   = 0;
+			long endDate     = 0;
+			int  score       = 0;
+			int  courseCount = 0;
+
+			for (Course c : courses) {
+				isPassed = false;
+
+				timeframe += c.getCourseSeatMinutes();
+				Vector<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(session, userProfileID, c.getCourseID(), limitToCASIDs != null);
+				if (cas != null) {
+					for (CourseAttempt ca : cas) {
+						if (limitToCASIDs != null && !limitToCASIDs.contains(ca.getCourseAttemptID())) continue;
+						Date d = ca.getCourseAttemptStartDate();
+						startDate = (d != null && (startDate == 0 || startDate > d.getTime())) ? d.getTime() : startDate;
+						d = ca.getCourseAttemptCompleteDate();
+						endDate = (d != null && (endDate == 0 || endDate < d.getTime())) ? d.getTime() : endDate;
+
+						boolean finished = !c.isCourseRequiresManagerApproval() || ca.isCourseAttemptManagerApproved();
+						if (finished && ca.getCourseAttemptStatusID() == STATUS_PASSED) {
+							int s = ca.getCourseAttemptScore();
+							if (s > -1) {
+								++courseCount;
+								score += s;
+							}
+							isPassed = true;
+logger.info("course is passed: " + c.getCourseName());
+							break;
+						}
+					}
+				}
+				if (!isPassed) {
+					break;
+				}
+			}
+			// if we have a curriculum of which our course is a member and all courses in this curriculum are passed,
+			// then create a passed course attempt for this curriculum
+			if (isPassed) {
+
+				if (courseCount != 0) score /= courseCount;
+
+				CourseAttempt ca = new CourseAttempt();
+				ca.defaultAll();
+				ca.setCourseAttemptStartDate(new Date(startDate));
+				ca.setCourseAttemptCompleteDate(new Date(endDate));
+				ca.setCourseAttemptCourseID(cur.getCourseID());
+				ca.setCourseAttemptUserProfileID(userProfileID);
+				ca.setCourseAttemptStatusID(ca.STATUS_PASSED);
+				ca.setCourseAttemptScore(score);
+
+				// TODO: timeframe?
+
+				return ca;
+			}
+		}
+		return null;
+	}
+
 	public void passAllAssociatedCurriculum(ILSSession session, HttpServletRequest request, String forcePassReason) {
 		Collection<Course> curs = Course.getUserCurricula(session, getCourseAttemptUserProfileID());
 		if (curs != null) {
 			// find all curricula our user is assigned and check each one
 			for (Course cur : curs) {
 
-				boolean isPassed = false;
 				Vector<Course> courses = cur.getCurriculumCourses();
 				if (courses != null) {
 					// is this course a member of the tested curriculum?
@@ -386,67 +450,25 @@
 					int  courseCount = 0;
 
 					if (isPertinent) {
-						for (Course c : courses) {
-							isPassed = false;
+						CourseAttempt ca = makeCurriculumCourseAttemptIfPassed(session, getCourseAttemptUserProfileID(), cur, null);
+						// if we have a curriculum of which our course is a member and all courses in this curriculum are passed,
+						// then create a passed course attempt for this curriculum
+						if (ca != null) {
+							if (forcePassReason != null) ca.setCourseAttemptForcePass(forcePassReason);
+							ca = ca.saveNew(session);
+logger.info("passing curriulum: " + cur.getCourseName());
 
-							timeframe += c.getCourseSeatMinutes();
-							Vector<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(session, getCourseAttemptUserProfileID(), c.getCourseID(), false);
-							if (cas != null) {
-								for (CourseAttempt ca : cas) {
-									Date d = ca.getCourseAttemptStartDate();
-									startDate = (d != null && (startDate == 0 || startDate > d.getTime())) ? d.getTime() : startDate;
-									d = ca.getCourseAttemptCompleteDate();
-									endDate = (d != null && (endDate == 0 || endDate < d.getTime())) ? d.getTime() : endDate;
-
-									boolean finished = !c.isCourseRequiresManagerApproval() || ca.isCourseAttemptManagerApproved();
-									if (finished && ca.getCourseAttemptStatusID() == STATUS_PASSED) {
-										int s = ca.getCourseAttemptScore();
-										if (s > -1) {
-											++courseCount;
-											score += s;
-										}
-										isPassed = true;
-logger.info("course is passed: " + c.getCourseName());
-										break;
-									}
+							// render certificate
+							if (cur.isCourseCertificateStore()) {
+								try {
+									ca.saveCertificate(ca.generateCertificate(session, request));
 								}
+								catch (Exception e) {
+									logger.error(e, e);
+								}
 							}
-							if (!isPassed) {
-								break;
-							}
 						}
 					}
-					// if we have a curriculum of which our course is a member and all courses in this curriculum are passed,
-					// then create a passed course attempt for this curriculum
-					if (isPertinent && isPassed) {
-
-						if (courseCount != 0) score /= courseCount;
-
-						CourseAttempt ca = new CourseAttempt();
-						ca.defaultAll();
-						if (forcePassReason != null) ca.setCourseAttemptForcePass(forcePassReason);
-						ca.setCourseAttemptStartDate(new Date(startDate));
-						ca.setCourseAttemptCompleteDate(new Date(endDate));
-						ca.setCourseAttemptCourseID(cur.getCourseID());
-						ca.setCourseAttemptUserProfileID(getCourseAttemptUserProfileID());
-						ca.setCourseAttemptStatusID(ca.STATUS_PASSED);
-						ca.setCourseAttemptScore(score);
-
-						// TODO: timeframe?
-
-						ca = ca.saveNew(session);
-logger.info("passing curriulum: " + cur.getCourseName());
-
-						// render certificate
-						if (cur.isCourseCertificateStore()) {
-							try {
-								ca.saveCertificate(ca.generateCertificate(session, request));
-							}
-							catch (Exception e) {
-								logger.error(e, e);
-							}
-						}
-					}
 				}
 			}
 		}
@@ -1070,6 +1092,9 @@
 	}
 
 	public byte[] generateCertificate(ILSSession ilsSession, HttpServletRequest request) throws Exception {
+		return generateCertificate(ilsSession, request, null);
+	}
+	public byte[] generateCertificate(ILSSession ilsSession, HttpServletRequest request, Set<Integer> limitToCAIDs) throws Exception {
 
 
 		Course c = Course.getCourse(ilsSession, getCourseAttemptCourseID());
@@ -1104,6 +1129,7 @@
 		urlString += "?ca=" + getCourseAttemptID();
 		urlString += "&c=" + c.getCourseID();
 		urlString += "&up=" + getCourseAttemptUserProfileID();
+		if (limitToCAIDs != null) urlString += "&caids="+CourseAttempt.join(",", limitToCAIDs);
 
 		if (!urlString.startsWith("http:") &&
 				!urlString.startsWith("ftp:") &&
@@ -1248,4 +1274,15 @@
 		return data;
 	}
 
+	public static String join(String delimeter, Collection items) {
+		if (items == null || items.size() == 0) return "";
+
+		StringBuilder sb = new StringBuilder();
+		for (Object o: items) {
+			if (sb.length() > 0) sb.append(delimeter);
+			sb.append(o.toString());
+		}
+		return sb.toString();
+	}
+
 }

Modified: trunk/src/com/resolutions/ils/data/UserProfile.java
===================================================================
--- trunk/src/com/resolutions/ils/data/UserProfile.java	2017-02-15 01:16:28 UTC (rev 1528)
+++ trunk/src/com/resolutions/ils/data/UserProfile.java	2017-03-24 02:39:12 UTC (rev 1529)
@@ -319,7 +319,7 @@
 	" (SELECT MAX(GROUPNAME) FROM USERGROUP UG JOIN ILSGROUP IG ON UG.ILSGROUPID=IG.ILSGROUPID AND UG.USERPRID=U.USERPRID AND GROUPTYPEID=2) WORKGROUP, " +
 	" (SELECT MAX(GROUPNAME) FROM USERGROUP UG JOIN ILSGROUP IG ON UG.ILSGROUPID=IG.ILSGROUPID AND UG.USERPRID=U.USERPRID AND GROUPTYPEID=1) ROLE, " +
 	" SUM(COALESCE(CA.CRS_COMPLETED, 0)) COURSESCOMPLETED, " +
-	" SUM(COALESCE(CA.CRS_OPEN, 1)) AS COURSESOPEN, " +
+	" CASE WHEN not exists (select 1 from USERCOURSEASSIGNMENTS T2 where T2.COMPANYID=U.COMPANYID AND T2.USERPRID=U.USERPRID) THEN 0 ELSE SUM(COALESCE(CA.CRS_OPEN, 1)) END AS COURSESOPEN, " +
 	" SUM(COALESCE(CA.CRS_FAILED, 0)) COURSESFAILED, " +
 	" MAX(CA.CACOMPLETEDATE) COURSESLASTATTEMPT " +
 	" FROM USERPROFILE  U" +

Added: trunk/webapp/genbackcerts.jsp
===================================================================
--- trunk/webapp/genbackcerts.jsp	                        (rev 0)
+++ trunk/webapp/genbackcerts.jsp	2017-03-24 02:39:12 UTC (rev 1529)
@@ -0,0 +1,768 @@
+<%@ page
+    language="java"
+    contentType="text/html;charset=utf-8"
+%>
+<%@ page import="com.resolutions.ils.*" %>
+<%@ page import="com.resolutions.ils.data.*" %>
+<%@ page import="java.io.File" %>
+<%@ page import="java.io.StringWriter" %>
+<%@ page import="java.net.URL" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+<%@ page import="org.apache.log4j.Logger" %>
+<%@ page import="java.util.*" %>
+
+<%!
+	class Pair<A, B> {
+		A a;
+		B b;
+		public Pair(A a, B b) {
+			this.a = a;
+			this.b = b;
+		}
+		public A getKey() { return a; }
+		public B getValue() { return b; }
+	}
+%>
+
+<%
+    ILSSession ilsSession = (ILSSession)session.getAttribute("ilsSession");
+    if (ilsSession == null) {
+        out.print("<html><head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL=login.jsp\"></head></html>");
+        return;
+    }
+    Vector<UserProfile> userProfiles = (Vector<UserProfile>)session.getAttribute("lastDataset");
+
+    UserProfile user    = ilsSession.getCurrentUserProfile();
+
+    boolean managing    = true;
+    String action	= request.getParameter("action");
+	if (managing && "removeCert".equals(action) && (user.getUserProfileAccessLevel() > UserProfile.ACCESS_MANAGER || user.hasAccess(UserProfile.ACCESS_MODE_STUDENTREC_PASS_OVERRIDE))) {
+		if (CourseAttempt.deleteCourseAttempt(ilsSession, Integer.parseInt(request.getParameter("caid"))) > 0) {
+			out.print("Deleted");
+		}
+		else	out.print("Failed to delete.");
+		return;
+	}
+	if (managing && "genBackCert".equals(action) && (user.getUserProfileAccessLevel() > UserProfile.ACCESS_MANAGER || user.hasAccess(UserProfile.ACCESS_MODE_STUDENTREC_PASS_OVERRIDE))) {
+		String userProfileIDString = request.getParameter("userProfileID");
+		String genCurID = request.getParameter("genCurID");
+		String genCAIDs = request.getParameter("genCAIDs");
+logger.info("genbackcert: " + userProfileIDString + ", " + genCurID + ", " + genCAIDs);
+		int curID = -1; try { curID = Integer.parseInt(genCurID); } catch (Exception e) {}
+		int userProfileID = -1; try { userProfileID = Integer.parseInt(userProfileIDString); } catch (Exception e) {}
+    		Course cur = Course.getCourse(ilsSession, curID);
+		Set<Integer> caids = new HashSet<Integer>();
+		for (String caid : genCAIDs.split(",")) {
+			try { caids.add(Integer.parseInt(caid)); } catch (Exception e) {}
+		}
+		CourseAttempt ca = CourseAttempt.makeCurriculumCourseAttemptIfPassed(ilsSession, userProfileID, cur, caids);
+		// if we have a curriculum of which our course is a member and all courses in this curriculum are passed,
+		// then create a passed course attempt for this curriculum
+		if (ca != null) {
+			ca = ca.saveNew(ilsSession);
+logger.info("passing curriulum: " + cur.getCourseName());
+
+			// render certificate
+			if (cur.isCourseCertificateStore()) {
+				try {
+					ca.saveCertificate(ca.generateCertificate(ilsSession, request, caids));
+				}
+				catch (Exception e) {
+					logger.error(e, e);
+				}
+			}
+//logger.info("cur.getCoursePassExpireDays(): " + cur.getCoursePassExpireDays());
+//logger.info("ca.getCourseAttemptCompleteDate(): " + ca.getCourseAttemptCompleteDate());
+			if (cur.getCoursePassExpireDays() > 0) {
+				Date expireOn = new Date(ca.getCourseAttemptCompleteDate().getTime() + (1000L * 60 * 60 * 24 * cur.getCoursePassExpireDays()));
+//logger.info("expireOn: " + expireOn);
+				if (expireOn.getTime() < new Date().getTime()) {
+					CourseAttempt ca2 = (CourseAttempt)ca.clone();
+					ca2.setCourseAttemptExpired("Recurrent Training Assigned");
+					ca2.setTSValue("CAEXPIREDON", expireOn);
+					ca2.save(ca);
+				}
+			}
+		}
+		out.print("Generated");
+		return;
+	}
+%>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<title><%= ilsSession.getCurrentCompany().getCompanyName() %> eLearning Portal</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link href="lms_style.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+
+<%@ include file="header.jsp" %>
+
+<script type="text/javascript">
+var rcid=0;
+function retake(inCID) {
+	rcid=inCID;
+	inputBox('Please Type the Reason For Re-take', 3, 80, 3, 'retakeComplete');
+}
+
+function retakeComplete(resultObject) {
+	$.blockUI({ message: '<h3><img width=&quot;30&quot; height=&quot;30&quot; style=&quot;margin-right:10px;vertical-align:middle;&quot; src=&quot;images/loading.gif&quot;/> Generating Report...</h3>' });
+	reason = resultObject.value;
+	document.getElementById('revokeCID').value=rcid;
+	if (reason.length > 0) reason = reason + ' / ';
+	document.getElementById('revokeReason').value=reason + 'Retake Assigned';
+	document.revokeForm.submit();
+}
+
+var pcid=0;
+var pcourseid=0;
+function forcePass(inCID, inCourseID) {
+	pcid=inCID;
+	pcourseid=inCourseID;
+	inputBox('Please Type the Reason For Forcing Pass', 3, 80, 3, 'forcePassComplete');
+}
+
+function forcePassComplete(resultObject) {
+	$.blockUI({ message: '<h3><img width=&quot;30&quot; height=&quot;30&quot; style=&quot;margin-right:10px;vertical-align:middle;&quot; src=&quot;images/loading.gif&quot;/> Generating Report...</h3>' });
+	reason = resultObject.value;
+	document.getElementById('passCID').value=pcid;
+	document.getElementById('passCourseID').value=pcourseid;
+	if (reason.length > 0) reason = reason + ' / ';
+	document.getElementById('passReason').value=reason + 'Pass Forced';
+	document.forcePassForm.submit();
+}
+
+function genAllCerts(userProfileID) {
+	var i = 0;
+	while (true) {
+		++i;
+		if (!$('#cert_'+userProfileID+'_'+i).length) break;
+		$('#cert_'+userProfileID+'_'+i).children('a').trigger('click');
+	}
+}
+
+function removeCert(caid) {
+	var data = {
+		caid : caid,
+		action   : 'removeCert'
+	}
+	$('#ca_'+caid).html('<img height="18" src="images/loading.gif"/> Deleting...');
+	$.post('genbackcerts.jsp', data, function(result) {
+		$('#ca_'+caid).html('<b>'+result+'</b>');
+	}, 'text');
+}
+
+function genCert(userProfileID, curID, caids, count, needsForce) {
+	if (needsForce) return;
+	//$.blockUI({ message: '<h3><img width="30" height="30" style="margin-right:10px;vertical-align:middle;" src="images/loading.gif"/> Generating Back Cert...</h3>' });
+	var data = {
+		userProfileID : userProfileID,
+		genCurID : curID,
+		genCAIDs : caids,
+		action   : 'genBackCert'
+	}
+	$('#cert_'+userProfileID+'_'+count).html('<img height="18" src="images/loading.gif"/> Generating...');
+	$.post('genbackcerts.jsp', data, function(result) {
+		$('#cert_'+userProfileID+'_'+count).html('<b>'+result+'</b>');
+	}, 'text');
+}
+
+function toggleCourseDetails(courseID) {
+	if ($('.subCourseID_'+courseID+':first').is(":visible")) {
+		$('#courseHeader_'+courseID).html('+');
+		$('.subCourseID_'+courseID).hide();
+	}
+	else {
+		$('#courseHeader_'+courseID).html('&ndash;');
+		$('.subCourseID_'+courseID).show();
+	}
+}
+function toggleCurriculumDetails(courseID) {
+	if ($('.subCurriculumID_'+courseID+':first').is(":visible")) {
+		$('#curriculumHeader_'+courseID).html('?<br>?');
+		$('.subCurriculumID_'+courseID).hide();
+		$('.historyDetail').hide();
+		$('.courseHeader').html('+');
+	}
+	else {
+		$('#curriculumHeader_'+courseID).html('?<br>?');
+		$('.subCurriculumID_'+courseID).show();
+		$('.historyDetail').hide();
+		$('.courseHeader').html('+');
+	}
+}
+
+$(document).ready(function() {
+//	$('.historyDetail').hide();
+//	$('.subCourseHeaderRow').hide();
+});
+
+
+</script>
+
+  <div id="pageContainer">
+<%@ include file="menu.jsp" %>
+<div id="content">
+<div id="pageTitles">Reports </div>
+
+
+<%!
+	static SimpleDateFormat df  = new SimpleDateFormat("MM/dd/yyyy");
+	static Logger logger = Logger.getLogger("report/employee/course/attempt");
+%>
+<%
+	for (UserProfile current: userProfiles) {
+logger.info("**** " + current.getUserProfileLastName() + ", " + current.getUserProfileFirstName());
+
+    int profileID       = current.getUserProfileID();
+	int count = 0;
+    
+
+	Vector<Course> courses       = Course.getAllUserCourses(ilsSession, current.getUserProfileID());
+	int wordNum = 0;
+
+	Collection<Course> curricula = Course.getUserCurricula(ilsSession, current.getUserProfileID());
+
+	// map all courses to their parent curriculum
+	HashMap<Integer, Integer> courseCurriculum = new HashMap<Integer, Integer>();
+	HashMap<Integer, Boolean> courseSupressRetake = new HashMap<Integer, Boolean>();
+	HashMap<Integer, Course> curriculaList = new HashMap<Integer, Course>();
+	HashMap<Integer, HashSet<CourseAttempt>> courseCourseAttempts = new HashMap<Integer, HashSet<CourseAttempt>>();
+
+	Map<Course, List<List<Pair<Course, CourseAttempt>>>> curriculaEval = new HashMap<Course, List<List<Pair<Course, CourseAttempt>>>>();
+	for (Course cur : curricula) {
+		List<List<Pair<Course, CourseAttempt>>> associated = new ArrayList<List<Pair<Course, CourseAttempt>>>();
+		Set<Integer> usedCourses = new HashSet<Integer>();
+logger.info("CUR: (" + cur.getCourseNum() + " : " + cur.getCourseID() + ") " + cur.getCourseName());
+		curriculaList.put(cur.getCourseID(), cur);
+		boolean passed = true;
+		boolean missed = false;
+		while (passed) {
+			List<Pair<Course, CourseAttempt>> associatedCourseAttempts = new ArrayList<Pair<Course, CourseAttempt>>();
+			passed = false;
+			for (Course c : Course.getCurriculumCourses(ilsSession, cur.getCourseID())) {
+logger.debug(" - COURSE: (" + c.getCourseNum() + " : " + c.getCourseID() + ") " + c.getCourseName());
+				Vector<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(ilsSession, current.getUserProfileID(), c.getCourseID());
+
+    java.util.Collections.sort(cas, new Comparator<CourseAttempt>() {
+        public int compare(CourseAttempt o1, CourseAttempt o2) {
+                Date d1 = o1.getCourseAttemptCompleteDate();
+                if (d1 == null) d1 = o1.getCourseAttemptStartDate();
+                Date d2 = o2.getCourseAttemptCompleteDate();
+                if (d2 == null) d2 = o2.getCourseAttemptStartDate();
+                long i1 = (d1 == null) ? 0 : d1.getTime();
+                long i2 = (d2 == null) ? 0 : d2.getTime();
+                return (i1 < i2) ? -1 : (i1 == i2) ? 0 : 1;
+        }
+    });
+				passed = false;
+				for (CourseAttempt ca : cas) {
+					if (ca.getCourseAttemptStatusID() == 1 && !usedCourses.contains(ca.getCourseAttemptID())) {
+logger.debug("     .COURSEATTEMPT: " + ca.getCourseAttemptCompleteDate() + "; STATUS: " + ca.getCourseAttemptStatusID());
+						usedCourses.add(ca.getCourseAttemptID());
+						associatedCourseAttempts.add(new Pair(c,ca));
+						passed = true;
+						break;
+					}
+				}
+				if (!passed) {
+					associatedCourseAttempts.add(new Pair(c,null));
+logger.debug("    -- Missing: " + c.getCourseName());
+					missed = true;
+				}
+				courseCurriculum.put(c.getCourseID(), cur.getCourseID());
+				courseSupressRetake.put(c.getCourseID(), !cur.isCourseAllowCurriculumPartRetake());
+			}
+			if (!missed) {
+
+    java.util.Collections.sort(associatedCourseAttempts, new Comparator<Pair<Course, CourseAttempt>>() {
+        public int compare(Pair<Course, CourseAttempt> p1, Pair<Course, CourseAttempt> p2) {
+		CourseAttempt o1 = p1.getValue();
+		CourseAttempt o2 = p2.getValue();
+		if (o1 == null && o1 == null) return 0;
+		if (o1 == null) return -1;
+		if (o2 == null) return 1;
+                Date d1 = o1.getCourseAttemptCompleteDate();
+                if (d1 == null) d1 = o1.getCourseAttemptStartDate();
+                Date d2 = o2.getCourseAttemptCompleteDate();
+                if (d2 == null) d2 = o2.getCourseAttemptStartDate();
+                long i1 = (d1 == null) ? 0 : d1.getTime();
+                long i2 = (d2 == null) ? 0 : d2.getTime();
+                return (i1 < i2) ? -1 : (i1 == i2) ? 0 : 1;
+        }
+    });
+logger.info("------ CUR - PASSED; startDate: " + associatedCourseAttempts.get(0).getValue().getCourseAttemptStartDate() + "; completeDate: " + associatedCourseAttempts.get(associatedCourseAttempts.size() - 1).getValue().getCourseAttemptCompleteDate());
+			}
+			if (passed) associated.add(associatedCourseAttempts);
+		}
+		curriculaEval.put(cur, associated);
+	}
+
+	courses.addAll(curricula);
+	Vector<CourseAttempt> courseAttempts = new Vector<CourseAttempt>();
+	for (int j = 0; j < courses.size(); j++) {
+		Course mainCourse = (Course)courses.get(j);
+		HashSet<CourseAttempt> meCourseAttempts = new HashSet<CourseAttempt>();
+		courseCourseAttempts.put(mainCourse.getCourseID(), meCourseAttempts);
+logger.debug("processing course: " + mainCourse.getCourseName());
+		Vector cas = CourseAttempt.getUserCourseAttempts(ilsSession, current.getUserProfileID(), mainCourse.getCourseID());
+		boolean nonExpired = false;
+		for (int i = 0; i < cas.size() + 1; i++) {
+			CourseAttempt ca  = null;
+			if (i == cas.size()) {
+				// we've finished our course attempts and we already have a status, we're done
+				if (nonExpired) break;
+				else {
+					ca = new CourseAttempt();
+					ca.setCourseAttemptID(-1);
+					ca.setIntValue("COMPANYID", ilsSession.getCompanyID());
+				}
+			}
+			else {
+				ca = (CourseAttempt)cas.get(i);
+				// we've already populated our main course, let's add a dup
+				if (!ca.isCourseAttemptExpired()) {
+					nonExpired = true;
+				}
+			}
+			String score   = "";
+			String status   = "";
+			int statusSort = ca.getCourseAttemptStatusID();
+			boolean finished = false;
+			switch (ca.getCourseAttemptStatusID()) {
+			case CourseAttempt.STATUS_IN_PROGRESS:
+			    status   = "In Progress";
+			    statusSort = 1;
+			    break;
+			case CourseAttempt.STATUS_PASSED:
+			    finished = !((mainCourse.isCourseRequiresManagerApproval()) && (!ca.isCourseAttemptManagerApproved()));
+			    status   = (finished) ? "Passed" : "Awaiting <t:t>Manager</t:t> Approval";
+			    score = Integer.toString(ca.getCourseAttemptScore());
+			    if ("-1".equals(score)) score = "";
+			    statusSort = 4;
+			    break;
+			case CourseAttempt.STATUS_FAILED:
+			    status   = "Failed";
+			    score = Integer.toString(ca.getCourseAttemptScore());
+			    if ("-1".equals(score)) score = "";
+			    statusSort = 2;
+			    break;
+			case CourseAttempt.STATUS_NEW:
+			    status   = "New";
+			    statusSort = 3;
+			}
+			ca.setValue("status", status);
+			ca.setIntValue("statusSort", statusSort);
+			ca.setValue("score", score);
+			ca.setValue("coursenum", mainCourse.getCourseNum());
+			ca.setValue("coursename", mainCourse.getCourseName());
+			ca.setValue("seattimetext", mainCourse.getCourseSeatTimeText());
+			ca.setCourseAttemptCourseID(mainCourse.getCourseID());
+			if (mainCourse.isCourseActive() || (ca.getCourseAttemptStatusID() == CourseAttempt.STATUS_FAILED) || (finished && ca.getCourseAttemptStatusID() == CourseAttempt.STATUS_PASSED)) {
+				courseAttempts.add(ca);
+				meCourseAttempts.add(ca);
+			}
+		}
+	}
+
+
+    java.util.Collections.sort(courseAttempts, new Comparator<CourseAttempt>() {
+        public int compare(CourseAttempt o1, CourseAttempt o2) {
+            int a1 = o1.getIntValue("statusSort");
+            int a2 = o2.getIntValue("statusSort");
+            if ((a1 - a2) == 0) {
+                Date d1 = o1.getCourseAttemptCompleteDate();
+                if (d1 == null) d1 = o1.getCourseAttemptStartDate();
+                Date d2 = o2.getCourseAttemptCompleteDate();
+                if (d2 == null) d2 = o2.getCourseAttemptStartDate();
+                long i1 = (d1 == null) ? 0 : d1.getTime();
+                long i2 = (d2 == null) ? 0 : d2.getTime();
+                return (i1 > i2) ? -1 : (i1 == i2) ? 0 : 1;
+            }
+            return (a1 - a2);
+        }
+    });
+
+
+%>
+
+
+
+
+        <table cellpadding="0" cellspacing="0" class="tableMain">
+<tr>
+                        <td><table class="tableMain" style="margin-bottom:0px">
+                            <tr>
+                              <th><div style="float:left;"><%=current.getUserProfileFirstName()%> <%=current.getUserProfileLastName()%></div><div style="text-align:right; float:right; color:#7D7D7D; font-weight:bold; padding-right:5px"><%=df.format(new Date())%> </div></th>
+
+                            </tr>
+                        </table></td>
+          </tr>
+                      <tr>
+                        <td valign="top">
+                          <table class="tableBTN">
+                            <tr>
+                              <td ><table>
+                                  <tr>
+                                    <td><a href="javascript:void(window.print())" target="_top"><img border="0" src="images/print_btn.gif" width="24" height="24" alt=""/></a></td>
+                                    <td><a class="formButtons" href="#" onclick="genAllCerts(<%=current.getUserProfileID()%>);return false;" target="_top">Generate All</a></td>
+                                  </tr>
+                              </table></td>
+                            </tr>
+                          </table>
+                        </td>
+                      </tr>
+
+                      <tr>
+                        <td><table class="tableDataList tableDataListStudentRecords">
+				<thead>
+                            <tr>
+                              <th style="width: 16px !important;" title="Hide/Show Courses within Curriculum"></th>
+                              <th style="width: 22px !important;" title="Hide/Show All History for an Item"></th>
+<% if (managing) { %>                            
+                              <th style="width: 160px !important;">Comments</th>
+<% } %>                              
+                              <th style="width: 60px !important;">Status</th>
+                              <th style="width: 60px !important;">No.</th>
+                              <th style="width: 160px !important;">Course Name</th>
+                              <th style="width: 70px !important;">Timeframe</th>
+                              <th style="width: 70px !important;">Start Date </th>
+                              <th style="width: 70px !important;">End Date</th>
+                              <th style="width: 50px !important;">Score %</th>
+                              <th style="width: 35px !important;">Cert</th>
+                            </tr>
+				</thead>
+				<tbody>
+<%
+// TODO
+//	This is a little convoluted. We do this in the order of courseAttempt because they may sort things in some order and we'd like those results to have priority, pulling in their dependencies as we work through the queue.
+    for (Course cur : curriculaEval.keySet()) {
+    	%>
+<tr class="curriculumHeaderRow">
+	<td></td>
+	<td></td>
+	<td></td>
+	<td></td>
+	<td><%=cur.getCourseNum()%></td>
+	<td><%=cur.getCourseName()%></td>
+	<td></td>
+	<td></td>
+	<td></td>
+	<td></td>
+	<td></td>
+</tr>
+<%
+	// existing course attempts
+	for (CourseAttempt curriculaAttempt : (Vector<CourseAttempt>)CourseAttempt.getUserCourseAttempts(ilsSession, current.getUserProfileID(), cur.getCourseID())) {
+		String comments = "";
+		if (curriculaAttempt.isCourseAttemptExpired()) {
+			comments += curriculaAttempt.getCourseAttemptExpiredReason() + "<br/>" + df.format(curriculaAttempt.getCourseAttemptExpiredDate());
+		}
+		if (curriculaAttempt.isCourseAttemptForcePass()) {
+			if (comments.length() > 0) comments += "<br/>";
+			comments += curriculaAttempt.getCourseAttemptForcePassReason() + "<br/>" + df.format(curriculaAttempt.getCourseAttemptForcePassDate());
+		}
+%>
+<tr class="curriculumDetailRow historyDetail subCourseID_<%=curriculaAttempt.getCourseAttemptID()%>">
+	<td></td>
+	<td></td>
+	<td><%=comments%></td>
+	<td id="ca_<%=curriculaAttempt.getCourseAttemptID()%>">Passed (<a href="#" onclick="removeCert(<%=curriculaAttempt.getCourseAttemptID()%>); return false;">delete</a>)</td>
+	<td></td>
+	<td></td>
+	<td></td>
+	<td><%=df.format(curriculaAttempt.getCourseAttemptStartDate())%></td>
+	<td><%=df.format(curriculaAttempt.getCourseAttemptCompleteDate())%></td>
+	<td><%=curriculaAttempt.getCourseAttemptScore()%></td>
+	<td></td>
+</tr>
+<%
+	}
+
+	// possible course attempts
+	List<List<Pair<Course, CourseAttempt>>> curriculaAttempts = curriculaEval.get(cur);
+	for (List<Pair<Course, CourseAttempt>> curriculaAttempt : curriculaAttempts) {
+		++count;
+		List<Pair<Course, CourseAttempt>> finished = new ArrayList<Pair<Course, CourseAttempt>>();
+ 		for (Pair<Course, CourseAttempt> p : curriculaAttempt) { if (p.getValue() != null) finished.add(p); }
+		String startDate = finished.size() == 0 ? "" : df.format(finished.get(0).getValue().getCourseAttemptStartDate());
+		String completeDate = finished.size() == 0 ? "" : df.format(finished.get(finished.size() - 1).getValue().getCourseAttemptCompleteDate());
+		String cas = "";
+		if (curriculaAttempt.size() > 0) {
+			for (Pair<Course, CourseAttempt> x : curriculaAttempt) {
+				if (x.getValue() != null) {
+					cas += ((cas.length() > 0 ? "," : "") + x.getValue().getCourseAttemptID());
+				}
+			}
+		}
+%>
+
+<tr class="curriculumDetailRow historyDetail">
+	<td></td>
+	<td></td>
+	<td></td>
+	<td id="cert_<%=current.getUserProfileID()%>_<%=count%>"><a href="#" onclick="genCert(<%=current.getUserProfileID()%>, <%=cur.getCourseID()%>, '<%=cas%>', <%=count%>, <%=finished.size() != curriculaAttempt.size()%>); return false;">Generate<%=finished.size() != curriculaAttempt.size() ? " Anyway":""%></a></td>
+	<td><%=cur.getCourseNum()%></td>
+	<td><%=cur.getCourseName()%></td>
+	<td></td>
+	<td><%=startDate%></td>
+	<td><%=completeDate%></td>
+	<td></td>
+	<td></td>
+</tr>
+
+<%
+    for (Pair<Course, CourseAttempt> ca :  curriculaAttempt) {
+%>
+<tr class="subCurriculumID_<%=cur.getCourseID()%> subCourseHeaderRow">
+	<td></td>
+<td></td>
+<td></td>
+<td><%=ca.getValue() == null ? "MISSING" : "PASSED"%></td>
+<td><%=ca.getKey().getCourseNum()%></td>
+<td><%=ca.getKey().getCourseName()%></td>
+<td><%=ca.getKey().getCourseSeatTimeText()%></td>
+<td><%=ca.getValue() == null ? "" : df.format(ca.getValue().getCourseAttemptStartDate())%></td>
+<td><%=ca.getValue() == null ? "" : df.format(ca.getValue().getCourseAttemptCompleteDate())%></td>
+<td><%=ca.getValue() == null ? "" : Integer.toString(ca.getValue().getCourseAttemptScore())%></td>
+<td></td>
+</tr>
+<%
+    }
+	}
+	}
+%>
+			</tbody>
+                        </table></td>
+                      </tr>
+    </table>
+</div>
+
+<%
+logger.info("**** END " + current.getUserProfileLastName() + ", " + current.getUserProfileFirstName());
+}
+logger.info("**** footer");
+%>
+<%@ include file="footer.jsp" %>
+</div>
+
+</body>
+</html>
+
+<%!
+
+public static String getCourseHTML(Vector<CourseAttempt> courseAttempts, CourseAttempt ca, boolean managing, UserProfile user, int wordNum, String headerAddition, String subClassAddition, boolean supressRetake, HashMap<Integer, Integer> courseCurriculum, HashMap<Integer, Course> curriculaList, Vector<Course>courses, HashMap<Integer, HashSet<CourseAttempt>>courseCourseAttempts) {
+
+	if (subClassAddition == null) subClassAddition = "";
+	else subClassAddition += " ";
+
+	boolean isCurriculum = curriculaList.get(ca.getCourseAttemptCourseID()) != null;
+	StringWriter out = new StringWriter();
+	String html = getCourseAttemptHTML(ca, managing, user, wordNum, supressRetake, courseCurriculum, curriculaList, courses, courseCourseAttempts);
+	courseAttempts.remove(ca);
+	String moreHTML = "";
+	for (int j = 0; j < courseAttempts.size(); ++j) {
+		CourseAttempt ca2 = courseAttempts.get(j);
+		if (ca2.getCourseAttemptCourseID() == ca.getCourseAttemptCourseID()) {
+			moreHTML += "<tr class=\""+(subClassAddition.trim().length() > 0?"subC":"c")+(isCurriculum?"urriculum":"ourse")+"DetailRow historyDetail subCourseID_"+ca2.getCourseAttemptCourseID()+"\"><td></td><td></td>"+getCourseAttemptHTML(ca2, managing, user, ++wordNum, supressRetake, courseCurriculum, curriculaList, courses, courseCourseAttempts)+"</tr>";
+			courseAttempts.remove(ca2);
+			--j;
+		}
+	}
+
+	out.write("<tr class=\""+subClassAddition+(subClassAddition.trim().length() > 0?"subC":"c")+(isCurriculum?"urriculum":"ourse")+"HeaderRow\">");
+	out.write("<td>");
+	if (headerAddition != null) out.write(headerAddition);
+	out.write("</td><td>");
+	if (moreHTML.length() > 0) {
+		out.write("<span class=\"courseHeader\" title=\"Show / Hide history for this record.\" id=\"courseHeader_"+ca.getCourseAttemptCourseID()+"\" onclick=\"toggleCourseDetails('"+ca.getCourseAttemptCourseID()+"');return false;\">+</span>");
+	}
+	out.write("</td>");
+	out.write(html);
+	out.write("</tr>");
+	out.write(moreHTML);
+
+	return out.toString();
+}
+
+public static String getCurriculumHTML(HashMap<Integer, Boolean> courseSupressRetake, HashMap<Integer, Integer> courseCurriculum, Vector<CourseAttempt> courseAttempts, CourseAttempt caCur, boolean managing, UserProfile user, int wordNum, HashMap<Integer, Course> curriculaList, Vector<Course>courses, HashMap<Integer, HashSet<CourseAttempt>>courseCourseAttempts) {
+
+	Logger logger = Logger.getLogger("getCurriculumHTML");
+
+	StringWriter out = new StringWriter();
+	String headerAddition = ("<span class=\"curHeader\" id=\"curriculumHeader_"+caCur.getCourseAttemptCourseID()+"\" title=\"Show / Hide Courses within this Curriculum\" onclick=\"toggleCurriculumDetails('"+caCur.getCourseAttemptCourseID()+"');return false;\">?<br>?</span>");
+	String html = getCourseHTML(courseAttempts, caCur, managing, user, wordNum, headerAddition, null, false, courseCurriculum, curriculaList, courses, courseCourseAttempts);
+	String moreHTML = "";
+	for (int j = 0; j < courseAttempts.size(); ++j) {
+		CourseAttempt ca2 = courseAttempts.get(j);
+
+		// see if this course attempt is in our curriculum
+		Integer curriculumID = courseCurriculum.get(ca2.getCourseAttemptCourseID());
+		if (curriculumID != null && caCur.getCourseAttemptCourseID() == curriculumID.intValue()) {
+logger.info("cours is in cur.");
+			String subClassAddition = "subCurriculumID_"+caCur.getCourseAttemptCourseID();
+			Boolean supressRetake = courseSupressRetake.get(ca2.getCourseAttemptCourseID());
+			moreHTML += getCourseHTML(courseAttempts, ca2, managing, user, ++wordNum, null, subClassAddition, supressRetake != null && supressRetake.booleanValue(), courseCurriculum, curriculaList, courses, courseCourseAttempts);
+			--j;
+		}
+		else {
+logger.info("cours NOT is in cur. CourseID:"+ca2.getCourseAttemptCourseID()+"; curParent: " + curriculumID);
+		}
+	}
+
+	out.write(html);
+	out.write(moreHTML);
+
+	return out.toString();
+}
+
+
+public static String getCourseAttemptHTML(CourseAttempt ca, boolean managing, UserProfile user, int wordNum, boolean supressRetake, HashMap<Integer, Integer> courseCurriculum, HashMap<Integer, Course> curriculaList, Vector<Course>courses, HashMap<Integer, HashSet<CourseAttempt>>courseCourseAttempts) {
+
+	boolean supressCert = false;
+	// are we IN a curriculum?
+	Integer curriculumID = courseCurriculum.get(ca.getCourseAttemptCourseID());
+	if (curriculumID != null) {
+		Course curr = curriculaList.get(curriculumID);
+		supressCert = curr.isCourseCurriculumCertificate();
+	}
+
+	// are we a curriculum?
+	Course curr = curriculaList.get(ca.getCourseAttemptCourseID());
+	if (curr != null) {
+		supressCert = !curr.isCourseCurriculumCertificate();
+		HashMap<String, Object>values = new HashMap<String, Object>();
+		computeCurriculumStats(curr.getCourseID(), courses, courseCurriculum, courseCourseAttempts, values);
+		int  timeFrame         = (Integer)values.get("timeFrame");
+		long sDate         = (Long)values.get("startDate");
+		long eDate           = (Long)values.get("endDate");
+		int  score             = (Integer)values.get("score");
+		int  inProgressCourseCount = (Integer)values.get("inProgressCourseCount");
+		int  passedCourseCount = (Integer)values.get("passedCourseCount");
+		int  totalCourseCount  = (Integer)values.get("totalCourseCount");
+		ca.setValue("seattimetext", Course.getNiceTimeText(timeFrame));
+		boolean finished = !((curr.isCourseRequiresManagerApproval()) && (!ca.isCourseAttemptManagerApproved()));
+		// if we have a stored history of passed or failed, use it.  Otherwise, compute curriculum status based on course progress
+		if (
+			   (!finished || ca.getCourseAttemptStatusID() != CourseAttempt.STATUS_PASSED)
+			&& ca.getCourseAttemptStatusID() != CourseAttempt.STATUS_FAILED
+		) {
+			ca.setValue("status", passedCourseCount == totalCourseCount ? "Passed" : (inProgressCourseCount == 0 && passedCourseCount == 0) ? "New" : "In Progress");
+		}
+		if ("In Progress".equals(ca.getValue("status"))) ca.setCourseAttemptStartDate(new Date(sDate));
+	}
+
+	StringWriter out = new StringWriter();
+	Date tDate = ca.getCourseAttemptStartDate();
+	String startDate = (tDate != null) ? df.format(tDate) : "";
+	tDate = ca.getCourseAttemptCompleteDate();
+	String endDate = (tDate != null) ? df.format(tDate) : "";
+	String status = ca.getStringValue("status");
+	if (managing) {
+		out.write("<td>");
+		if ("Passed".equals(status)) {
+			if (!ca.isCourseAttemptExpired() && !supressRetake) {
+				out.write("<a href=\"#\" onClick=\"retake("+ca.getCourseAttemptID()+");return false;\" class=\"Assign\">Assign Retake</a><br>");
+			}
+		}
+		else if (!"Awaiting <t:t>Manager</t:t> Approval".equals(status) && user.getUserProfileAccessLevel() > UserProfile.ACCESS_MANAGER || user.hasAccess(UserProfile.ACCESS_MODE_STUDENTREC_PASS_OVERRIDE)) {
+			out.write("<a href=\"#\" onClick=\"forcePass("+ca.getCourseAttemptID()+", "+ca.getCourseAttemptCourseID()+");return false;\" class=\"Assign\">Force Pass</a>");
+	
+		}
+
+		String val = "";
+		if (ca.isCourseAttemptExpired()) {
+			val += ca.getCourseAttemptExpiredReason() + "<br/>" + df.format(ca.getCourseAttemptExpiredDate());
+		}
+		if (ca.isCourseAttemptForcePass()) {
+			if (val.length() > 0) val += "<br/>";
+			val += ca.getCourseAttemptForcePassReason() + "<br/>" + df.format(ca.getCourseAttemptForcePassDate());
+		}
+		out.write(val+"</td>");
+	}
+
+
+	out.write("<td>"+status+"</td>");
+	out.write("<td>"+ca.getStringValue("coursenum")+"</td>");
+	out.write("<td><a href=\"#\" onclick=\"p('course','"+ca.getCourseAttemptCourseID()+"','"+wordNum+"');\">"+ca.getStringValue("coursename")+"</a></td>");
+	out.write("<td>"+ca.getStringValue("seattimetext")+"</td>");
+	out.write("<td>"+startDate+"</td>");
+	out.write("<td>"+endDate+"</td>");
+	out.write("<td>"+ca.getStringValue("score")+"</td>");
+	out.write("<td>");
+
+	if (ca.getSavedCertificate() != null) {
+		out.write("<a target=\"_blank\" href=\"api/courseattempt/cert/get?courseAttemptID="+ca.getCourseAttemptID()+"\"><img src=\"images/certificate_saved.png\"/></a>");
+	}
+	else if ("Passed".equals(status) && !supressCert) {
+		Course c = Course.getCourse(ca.getCompanyID(), ca.getCourseAttemptCourseID());
+		String urlString = c.getCourseCertificateGenerator();
+		if (urlString == null || urlString.length() < 1) urlString = (c.isCourseCurriculum() ? "certificate_curriculum.jsp" : "certificate.jsp");
+		urlString += "?ca=" + ca.getCourseAttemptID();
+		urlString += "&c=" + c.getCourseID();
+		urlString += "&up=" + ca.getCourseAttemptUserProfileID();
+		out.write("<a target=\"_blank\" href=\""+urlString+"\"><img src=\"images/print_certficate.png\"/></a>");
+	}
+	out.write("</td>");
+
+	return out.toString();
+}
+public static void computeCurriculumStats(int curriculumID, Vector<Course> courses, HashMap<Integer, Integer> courseCurriculum, HashMap<Integer, HashSet<CourseAttempt>> courseCourseAttempts, HashMap<String, Object>values) {
+	int  timeFrame         = 0;
+	long startDate         = 0;
+	long endDate           = 0;
+	int  score             = 0;
+	int  inProgressCourseCount = 0;
+	int  passedCourseCount = 0;
+	int  totalCourseCount  = 0;
+	int  scoredCourseCount  = 0;
+
+	for (Course c : courses) {
+		// are we a course in our curriculum?
+		Integer thisCourseCurriculum = courseCurriculum.get(c.getCourseID());
+		if (thisCourseCurriculum != null && curriculumID == thisCourseCurriculum) {
+			++totalCourseCount;
+
+			timeFrame += c.getCourseSeatMinutes();
+			Set<CourseAttempt> cas = courseCourseAttempts.get(c.getCourseID());
+			if (cas != null) {
+				boolean inProgress = false;
+				for (CourseAttempt ca : cas) {
+					Date d = ca.getCourseAttemptStartDate();
+					startDate = (d != null && (startDate == 0 || startDate > d.getTime())) ? d.getTime() : startDate;
+					d = ca.getCourseAttemptCompleteDate();
+					endDate = (d != null && (endDate == 0 || endDate < d.getTime())) ? d.getTime() : endDate;
+
+					boolean finished = !((c.isCourseRequiresManagerApproval()) && (!ca.isCourseAttemptManagerApproved()));
+					if (finished && ca.getCourseAttemptStatusID() == CourseAttempt.STATUS_PASSED && !ca.isCourseAttemptExpired()) {
+						int s = ca.getCourseAttemptScore();
+						++passedCourseCount;
+						if (s > -1) {
+							++scoredCourseCount;
+							score += s;
+							inProgress = false;
+						}
+						break;
+					}
+					else if (ca.getCourseAttemptStatusID() == CourseAttempt.STATUS_IN_PROGRESS) inProgress = true;
+				}
+				if (inProgress) ++inProgressCourseCount;
+			}
+		}
+	}
+
+	if (scoredCourseCount != 0) score /= scoredCourseCount;
+	values.put("timeFrame", timeFrame);
+	values.put("startDate", startDate);
+	values.put("endDate", endDate);
+	values.put("score", score);
+	values.put("inProgressCourseCount", inProgressCourseCount);
+	values.put("passedCourseCount", passedCourseCount);
+	values.put("totalCourseCount", totalCourseCount);
+	values.put("timeFrame", timeFrame);
+
+logger.debug("curriculum: " + curriculumID + "; values: " + values);
+}
+%>

Modified: trunk/webapp/report_employeecourseatt.jsp
===================================================================
--- trunk/webapp/report_employeecourseatt.jsp	2017-02-15 01:16:28 UTC (rev 1528)
+++ trunk/webapp/report_employeecourseatt.jsp	2017-03-24 02:39:12 UTC (rev 1529)
@@ -275,7 +275,7 @@
 <tr>
                         <td><table class="tableMain" style="margin-bottom:0px">
                             <tr>
-                              <th><div style="float:left;"><%=current.getUserProfileFirstName()%> <%=current.getUserProfileLastName()%></div><div style="text-align:right; float:right; color:#7D7D7D; font-weight:bold; padding-right:5px"><%=df.format(new Date())%> </div></th>
+                              <th><div style="float:left;"><%=current.getUserProfileFirstName()%> <%=current.getUserProfileLastName()%> </div> <div style="text-align:right; float:right; color:#7D7D7D; font-weight:bold; padding-right:5px"><%=df.format(new Date())%> </div></th>
 
                             </tr>
                         </table></td>
@@ -322,7 +322,7 @@
 		// first see if we're a course in a Curriculum
 		CourseAttempt ca = courseAttempts.get(0);
 		boolean isCurriculum = curriculaList.get(ca.getCourseAttemptCourseID()) != null;
-		Integer curriculumID = isCurriculum ? ca.getCourseAttemptCourseID() : courseCurriculum.get(ca.getCourseAttemptCourseID());
+		Integer curriculumID = isCurriculum ? (Integer)ca.getCourseAttemptCourseID() : (Integer)courseCurriculum.get(ca.getCourseAttemptCourseID());
 		String html = "";
 		int startSize = courseAttempts.size();
 		// process curriculum first



From scribe at crosswire.org  Thu Mar 23 19:41:48 2017
From: scribe at crosswire.org (scribe at crosswire.org)
Date: Thu, 23 Mar 2017 19:41:48 -0700
Subject: [Ils-source] r1530 - trunk/webapp
Message-ID: <E1crFAi-0002l9-F7@crosswire.org>

Author: scribe
Date: 2017-03-23 19:41:48 -0700 (Thu, 23 Mar 2017)
New Revision: 1530

Added:
   trunk/webapp/certificate_alt.jsp
   trunk/webapp/certificate_curriculum_alt.jsp
Log:
added more certificate examples to ils


Added: trunk/webapp/certificate_alt.jsp
===================================================================
--- trunk/webapp/certificate_alt.jsp	                        (rev 0)
+++ trunk/webapp/certificate_alt.jsp	2017-03-24 02:41:48 UTC (rev 1530)
@@ -0,0 +1,201 @@
+<%@ page
+    language="java"
+    contentType="text/html;charset=utf-8"
+%>
+<%@ page import="com.resolutions.ils.*" %>
+<%@ page import="com.resolutions.ils.data.*" %>
+<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.Date" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+
+<%
+    ILSSession ilsSession = (ILSSession)session.getAttribute("ilsSession");
+    if (ilsSession == null) {
+        out.print("<html><head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL=login.jsp\"></head></html>");
+        return;
+    }
+    int caID = -1;
+    try {
+        caID = Integer.parseInt(request.getParameter("ca"));
+    }
+    catch (Exception e) {}
+
+    if (caID < 0) {
+        out.print("<html><body><h1>Invalid Request</h1></body></html>");
+        return;
+    }
+    CourseAttempt ca = CourseAttempt.getCourseAttempt(ilsSession, caID);
+    Course cc = Course.getCourse(ilsSession, ca.getCourseAttemptCourseID());
+    UserProfile up = UserProfile.getUserProfile(ilsSession, ca.getCourseAttemptUserProfileID());
+
+    SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
+
+%>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<title>Untitled Document</title>
+
+<style type="text/css" media="print">
+<!--
+.noprint {
+     display:none;
+};
+-->
+</style>
+
+<style type="text/css">
+<!--
+.cert_text {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-size: 34px;
+    color: #333333;
+    text-align: center;
+    border-bottom-width: thin;
+    border-bottom-style: solid;
+    border-bottom-color: #CCCCCC;
+    font-style: oblique;
+    border-top-width: thin;
+    border-top-style: solid;
+    border-top-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+.text {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-size: 14px;
+    font-style: normal;
+    color: #333333;
+    text-align: center;
+    padding: 15px;
+}
+.nametxt {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-style: normal;
+    line-height: 25px;
+    text-transform: uppercase;
+    color: #333333;
+    text-align: center;
+    font-weight: bold;
+    font-size: 18px;
+}
+.coursetxt {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-style: normal;
+    line-height: 25px;
+    text-transform: uppercase;
+    color: #333333;
+    text-align: center;
+    font-weight: bold;
+    font-size: 16px;
+}
+.tableoutline {
+    border: thin solid ##333333;
+    background-repeat: repeat;
+}
+.sigline {
+    border-bottom-width: thin;
+    border-bottom-style: solid;
+    border-bottom-color: #999999;
+}
+.siglinetxt {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-size: 10px;
+    text-transform: uppercase;
+    color: #333333;
+    text-align: center;
+}
+.formbtn {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 12px;
+	text-transform: none;
+	color: #666666;
+	padding: 4px 4px 8px;
+	font-weight: bold;
+	text-decoration: none;
+	border: none;
+}
+
+.formbtn:hover {
+	text-decoration: underline;
+}
+-->
+</style>
+</head>
+
+<body>
+
+<div class="noprint">
+    <table width="100%" border="0">
+      <tr>
+        <td width="75%"><div align="right"><a href="javascript:void(window.print())" target="_top"><img border="0" src="images/print_btn.gif" width="24" height="24" alt=""/></a></div></td>
+        <td width="15%"><a class="formbtn" href="javascript:void(window.print())" target="_top">Print Certificate </a></td>
+      </tr>
+    </table>
+</div>
+
+<table width="600" border="0" align="center">
+  <tr>
+    <td class="tableoutline"><table width="100%" border="0" cellspacing="1">
+      <tr>
+        <td bgcolor="#FFFFFF"><table width="100%" border="0" cellspacing="1" class="tableoutline">
+            <tr>
+              <td colspan="2" bgcolor="#283C7A">&nbsp;</td>
+            </tr>
+            <tr>
+              <td colspan="2" class="cert_text">Alternate Certificate of Completion </td>
+            </tr>
+            <tr>
+              <td colspan="2" class="text">This Certifies that </td>
+            </tr>
+            <tr>
+              <td colspan="2" class="nametxt"><%=up.getUserProfileFirstName() %> <%=up.getUserProfileLastName()%></td>
+            </tr>
+            <tr>
+              <td colspan="2" class="text">has successfully completed the following course </td>
+            </tr>
+            <tr>
+              <td colspan="2" class="coursetxt"><%=cc.getCourseName() %></td>
+            </tr>
+            <tr>
+              <td colspan="2" class="text">on</td>
+            </tr>
+            <tr>
+              <td colspan="2" class="coursetxt"><%= ca.getCourseAttemptCompleteDate() != null ? df.format(ca.getCourseAttemptCompleteDate()) : "" %></td>
+            </tr>
+            <tr>
+              <td colspan="2" class="coursetxt">&nbsp;</td>
+            </tr>
+            <tr>
+              <td width="50%"><table width="250" border="0" align="center" cellspacing="1">
+                <tr>
+                  <td class="sigline">&nbsp;</td>
+                </tr>
+                <tr>
+                  <td class="siglinetxt">Signature</td>
+                </tr>
+              </table></td>
+              <td width="50%"><div align="center">
+                <table width="250" border="0" cellspacing="1">
+                    <tr>
+                      <td class="sigline">&nbsp;</td>
+                    </tr>
+                    <tr>
+                      <td class="siglinetxt">Title</td>
+                    </tr>
+                    </table>
+              </div></td>
+            </tr>
+            <tr>
+              <td colspan="2" align="right"><img src="<%=ilsSession.getCurrentCompany().getCompanyLogoURL()%>" alt="Company Logo" width="147" height="67" /></td>
+            </tr>
+            <tr>
+              <td colspan="2" align="right" bgcolor="#283C7A">&nbsp;</td>
+            </tr>
+        </table></td>
+      </tr>
+    </table></td>
+  </tr>
+</table>
+</body>
+</html>

Added: trunk/webapp/certificate_curriculum_alt.jsp
===================================================================
--- trunk/webapp/certificate_curriculum_alt.jsp	                        (rev 0)
+++ trunk/webapp/certificate_curriculum_alt.jsp	2017-03-24 02:41:48 UTC (rev 1530)
@@ -0,0 +1,623 @@
+<%@ page
+    language="java"
+    contentType="text/html;charset=utf-8"
+%>
+<%@ page import="com.resolutions.ils.*" %>
+<%@ page import="com.resolutions.ils.data.*" %>
+<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.HashMap" %>
+<%@ page import="java.util.Date" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+<%
+    ILSSession ilsSession = (ILSSession)session.getAttribute("ilsSession");
+    if (ilsSession == null) {
+        out.print("<html><head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL=login.jsp\"></head></html>");
+        return;
+    }
+
+// So, this now allows us to get the curriculum and user in a number of ways.  Ideally, moving forward,
+// since we are saving a Course Attempt record now when a curriculum is complete, we will get the 
+// Curriculum and User from the Course Attempt record.
+//
+// But... so that we can work the old way, we allow the Curriculum to be passed in directly, as before
+// with the 'c' parameter.  This has other problems, as this assumes that we want the currently logged
+// in user's information about this curriculum, but this is not true any longer because an admin can
+// ask for a certificate for a specific user now.  So, we also allow the User Profile ID to be passed
+// in with the 'up' parameter.  I don't think anyone is using this yet and no one ever should because if
+// they are going to change anything to make things work correctly, they should change to use Course
+// Attempt :)
+//
+    int caID = -1; try { caID = Integer.parseInt(request.getParameter("ca")); } catch (Exception e) {}
+    int cID = -1; try { cID = Integer.parseInt(request.getParameter("c")); } catch (Exception e) {}
+    int upID = -1; try { upID = Integer.parseInt(request.getParameter("up")); } catch (Exception e) {}
+
+    if (caID < 0 && cID < 0) {
+        out.print("<html><body><h1>Invalid Request</h1></body></html>");
+        return;
+    }
+    CourseAttempt ca = caID > -1 ? CourseAttempt.getCourseAttempt(ilsSession, caID) : null;
+    Course cc = Course.getCourse(ilsSession, ca != null ? ca.getCourseAttemptCourseID() : cID);
+    UserProfile up     = UserProfile.getUserProfile(ilsSession, ca != null ? ca.getCourseAttemptUserProfileID() : upID > -1 ? upID : ilsSession.getCurrentUserProfile().getUserProfileID());
+
+    SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
+
+%>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<title>Untitled Document</title>
+<style type="text/css" media="print">
+<!--
+.noprint {
+	display:none;
+}
+;
+-->
+</style>
+<style type="text/css">
+<!--
+.courseTable {
+	font-size:12px;
+	border-collapse: collapse;
+}
+.courseTable td, .courseTable th {
+	border: solid 1px;
+	padding: 2px;
+	font-family: Arial, Helvetica, sans-serif;
+}
+.cert_text {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 1.2em;
+	color: #333333;
+	text-align: center;
+	border-bottom-width: thin;
+	border-bottom-style: solid;
+	border-bottom-color: #CCCCCC;
+	font-style: oblique;
+	border-top-width: thin;
+	border-top-style: solid;
+	border-top-color: #CCCCCC;
+	background-color: #F4F4F4;
+}
+.heading {
+	font-weight: bold;
+	white-space:nowrap;
+}
+.text {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 14px;
+	font-style: normal;
+	color: #333333;
+	padding: 10px;
+}
+.SubText {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 10px;
+	font-style: normal;
+	color: #333333;
+	text-align: left;
+	padding-left:10px;
+	padding-right:10px;
+	padding-top:15;
+	padding-bottom:5px;
+}
+.nametxt {
+	font-family: Arial, Helvetica, sans-serif;
+	font-style: normal;
+	line-height: 25px;
+	text-transform: uppercase;
+	color: #333333;
+	text-align: center;
+	font-weight: bold;
+	font-size: 18px;
+}
+.coursetxt {
+	font-family: Arial, Helvetica, sans-serif;
+	font-style: normal;
+	line-height: 25px;
+	text-transform: uppercase;
+	color: #333333;
+	text-align: center;
+	font-weight: bold;
+	font-size: 16px;
+}
+.tableoutline {
+	border: thin solid ##333333;
+	background-repeat: repeat;
+}
+.sigline {
+	border-bottom-width: thin;
+	border-bottom-style: solid;
+	border-bottom-color: #999999;
+}
+.siglinetxt {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 10px;
+	text-transform: uppercase;
+	color: #333333;
+	text-align: center;
+}
+.formbtn {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 12px;
+	text-transform: none;
+	color: #666666;
+	padding: 4px 4px 8px;
+	font-weight: bold;
+	text-decoration: none;
+	border: none;
+}
+.formbtn:hover {
+	text-decoration: underline;
+}
+-->
+</style>
+</head>
+<body>
+<div class="noprint" style="margin-top:0px; padding-top:0px;">
+  <table width="100%" border="0">
+    <tr>
+      <td width="75%"><div align="right"><a href="javascript:void(window.print())" target="_top"><img border="0" src="images/print_btn.gif" width="24" height="24" alt=""/></a></div></td>
+      <td width="15%"><a class="formbtn" href="javascript:void(window.print())" target="_top">Print Alternative Certificate </a></td>
+    </tr>
+  </table>
+</div>
+<!-- Start New Miner Certificate -->
+    <!-- Start Check Full Address -->
+		<% 
+            boolean FullAddress = false;
+            String Addr1 = up.getUserProfileAddr1();
+            String Addr2 = up.getUserProfileAddr2();
+            String City = up.getUserProfileCity();
+            String State = up.getUserProfileState();
+            String Zip = up.getUserProfileZip();
+            String Country = up.getUserProfileCountry();
+            
+            if (Addr1.equals("") || Addr2.equals("") || City.equals("") || State.equals("") || Zip.equals("") || Country.equals("")) {
+                FullAddress = false;
+            } else {
+                FullAddress = true;
+            }
+			
+			boolean FullName = false;
+			
+			String FirstName = up.getUserProfileFirstName();
+			String MiddleName = up.getUserProfileMiddleName();
+			String LastName = up.getUserProfileLastName();
+			String SuffixName = up.getUserProfileSuffixName();
+
+            if (FirstName.equals("") || MiddleName.equals("") || LastName.equals("")) {
+                FullName = false;
+            } else {
+                FullName = true;
+            }
+        %>
+    <!-- End Check Full Address -->
+    <!-- Start Get Course End Date -->
+		<%!
+			public static String GetCourseEndDate(HttpSession session, ILSSession ilsSession, UserProfile user, int CourseID)
+			{
+				Vector cas = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), CourseID, false);
+				CourseAttempt ca = (CourseAttempt)cas.get(0);
+				
+				SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
+				
+				Date tDate = ca.getCourseAttemptCompleteDate();
+				String endDate = (tDate != null) ? df.format(tDate) : "";
+				
+				return endDate;
+			}
+		%> 
+    <!-- End Get Course End Date -->
+    <!-- Start Display New Miner Certificate -->
+    	<% if ("12".equals(request.getParameter("c"))) { %>
+            <table width="700" border="0" align="center" style="margin-top:0px; padding-top:0px;">
+              <tr>
+                <td class="tableoutline"><table width="100%" border="0" cellspacing="1">
+                    <tr>
+                      <td bgcolor="#FFFFFF"><table width="100%" border="0" cellspacing="1" class="tableoutline">
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading" style="text-align:center; font-size:16px;">NEW MINER TRAINING RECORD/CERTIFICATE</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading">Miner's Full Name (Print): </td>
+                                  <td class="sigline" style="width:100%;"><% if (FullName) { %><%= FirstName + " " + MiddleName + " " + LastName + " " + SuffixName %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Full Name</span><% } %></td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading">Mine or Contractor Name: </td>
+                                  <td class="sigline" style="width:100%;">&nbsp;</td>
+                                  <td class="heading"> I.D.#</td>
+                                  <td class="sigline">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2"><table class="courseTable" style="width:100%;">
+                                <thead>
+                                  <tr>
+                                    <th width="210">Subject<br/>30CFR Part 46.5</th>
+                                    <th width="170">Competent<br/>Person</th>
+                                    <th>Date</th>
+                                    <th width="130">Location<br/><span style="font-weight:normal; font-size:10px;">(Name &amp; Address)</span></th>
+                                    <th>Time</th>
+                                    <th>Miner's<br/>Initials</th>
+                                  </tr>
+                                </thead>
+                                <tbody>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">The minor received no less than 4 hours in the following, before beginning work:</td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(1) Introduction to the work environment, mine tour, mining method/operation - On the job training</td>
+                                    <td></td>
+                                    <td></td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span></td>
+                                    <td></td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(1) Introduction to the work environment, mine tour, mining method/operation - Online training</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 15) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>10 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(2) Instruction on recognition and avoidance of electrical and other hazards</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 28) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>4 Hrs<br/>42 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(3) Emergency procedures, escape, and firefighting</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 6) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>18 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(4) Health and Safety aspects<br/>of the tasks assigned - On the job training</td>
+                                    <td></td>
+                                    <td></td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span></td>
+                                    <td></td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(4) Health and Safety aspects of the tasks assigned - Online training</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 5) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>34 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(5) Instruction on statutory rights of miners and their representatives</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 7) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>32 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(6) Authority &amp; responsibility of supervisors and miners' representatives</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 8) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>2 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(7) Introduction to you rules and procedures for reporting hazards</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 9) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>58 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">No later than 60 days:</td>
+                                  </tr>
+                                  <tr>
+                                    <td>(c)(1) Self-rescue, respiratory devices, if used</td>
+                                    <td style="padding-left:0px; padding-right:0px; text-align:right;"><div style="width:120px; float:right; height:6px; border-bottom:#000 solid 3px;">&nbsp;</div><div style="float:right; font-weight:bold; padding-right:5px;">N/A</div></td>
+                                    <td style="padding-left:0px; padding-right:0px;"><div style="width:100%; border-bottom:#000 solid 3px; height:0px;">&nbsp;</div></td>
+                                    <td style="padding-left:0px; padding-right:0px;"><div style="width:100%; border-bottom:#000 solid 3px; height:0px;">&nbsp;</div></td>
+                                    <td style="padding-left:0px; padding-right:0px;"><div style="width:100%; border-bottom:#000 solid 3px; height:0px;">&nbsp;</div></td>
+                                    <td style="padding-left:0px; padding-right:0px; text-align:left;"><div style="width:25px; float:left; height:9px; border-bottom:#000 solid 3px;">&nbsp;</div><div style="float:left; font-weight:bold; padding-left:0px; font-size: 16px;">&gt;</div></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Emergency plans, and firefighting</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 10) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>6 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">No later than 90 days: (the balance of the 24 hours of training)</td>
+                                  </tr>
+                                  <tr>
+                                    <td>Hazcom</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 11) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>44 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                </tbody>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="coursetxt"><span style="line-height:10px;">&nbsp;</span></td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" width="100%" style="border:solid 2px;"><table width="90%" border="0" align="center" cellspacing="1">
+                                <tr>
+                                  <td colspan="2" width="100%;" class="text" style="font-size:12px;"><strong>False certification is punishable under 110 (a) and (f) of the Federal Mine Safety and Health Act</strong><br/>I certify that the above training has been completed.</td>
+                                </tr>
+                                <tr>
+                                  <td colspan="2" class="sigline" width="100%;">&nbsp;</td>
+                                </tr>
+                                <tr>
+                                  <td width="70%" class="siglinetxt">(Signature of person responsible for health and safety training)</td>
+                                  <td class="siglinetxt">(Date)</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                        </table>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+        <% } else if ("43".equals(request.getParameter("c"))) { %>
+    <!-- End Display New Miner Certificate -->
+    <!-- Start Display Annual Refresher Certificate -->
+            <table width="700" border="0" align="center" style="margin-top:0px; padding-top:0px;">
+              <tr>
+                <td class="tableoutline"><table width="100%" border="0" cellspacing="1">
+                    <tr>
+                      <td bgcolor="#FFFFFF"><table width="100%" border="0" cellspacing="1" class="tableoutline">
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading" style="text-align:center; font-size:14px;">ANNUAL REFRESHER TRAINING RECORD/CERTIFICATE</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading">Miner's Full Name (Print): </td>
+                                  <td class="sigline" style="width:100%;"><% if (FullName) { %><%= FirstName + " " + MiddleName + " " + LastName + " " + SuffixName %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Full Name</span><% } %></td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom: 0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading">Mine or Contractor Name: </td>
+                                  <td class="sigline" style="width:100%;">&nbsp;</td>
+                                  <td class="heading"> I.D.#</td>
+                                  <td class="sigline">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2"><table class="courseTable" style="width:100%;">
+                                <thead>
+                                  <tr>
+                                    <th width="175">Subject<br/>
+                                    30CFR Part 46.8</th>
+                                    <th width="200">Competent<br/>Person</th>
+                                    <th>Date</th>
+                                    <th width="130">Location<br/><span style="font-weight:normal; font-size:10px;">(Name &amp; Address)</span></th>
+                                    <th>Time</th>
+                                    <th>Miner's<br/>Initials</th>
+                                  </tr>
+                                </thead>
+                                <tbody>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">The miner received no less than 8 hours of annual refresher training in the following:</td>
+                                  </tr>
+                                  <tr>
+                                    <td>Instruction on changes at the mine that could adversely affect the miner's health or safety</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 29) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>9 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>H & S standards and applicable requirements</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 30) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>1 hour<br/>27 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">Health and safety subjects relevant to mining operations at the mine</td>
+                                  </tr>
+                                  <tr>
+                                    <td>Transportation controls and communication systems</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 31) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>2 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Emergency plans, and firefighting</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 32) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>17 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Ground conditions and control</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 33) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>2 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Working in areas of highwalls</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 34) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>6 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Water hazards, pits, and spoil banks</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 35) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>4 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Basic First-aid/ CPR</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 36) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>7 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Accident Prevention</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 37) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>3 hours<br/>23 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Mobile Equipment</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 38) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>7 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Health</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 39) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>35 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Maintenance & Repair, Material Handling, Fall protection</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 40) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>31 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Electrical hazards</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 41) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>26 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Hazcom</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 42) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>44 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                </tbody>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="coursetxt"><span style="line-height:10px;">&nbsp;</span></td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" width="100%" style="border:solid 2px;"><table width="90%" border="0" align="center" cellspacing="1">
+                                <tr>
+                                  <td colspan="2" width="100%;" class="text" style="font-size:12px; padding-top:0px; padding-bottom:0px;"><strong>False certification is punishable under 110 (a) and (f) of the Federal Mine Safety and Health Act</strong><br/>I certify that the above training has been completed.</td>
+                                </tr>
+                                <tr>
+                                  <td colspan="2" class="sigline" width="100%;">&nbsp;</td>
+                                </tr>
+                                <tr>
+                                  <td width="70%" class="siglinetxt">(Signature of person responsible for health and safety training)</td>
+                                  <td class="siglinetxt">(Date)</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                        </table>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+    	<% } %>
+    <!-- End Display Annual Refresher Certificate -->
+<!-- End New Miner Certificate -->
+</body>
+</html>
+<%!
+public static HashMap<String, Long> processCourseRow(HttpSession session, ILSSession ilsSession, UserProfile user, Course cc) {
+	HashMap<String, Long> values = new HashMap<String, Long>();
+        Vector cas        = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID(), false);
+        CourseAttempt ca  = null;
+        if (cas.size() == 0) {
+        	// see if a past attempt exists
+        	cas = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID());
+        	ca = new CourseAttempt();
+        }
+        else {
+            ca  = (CourseAttempt)cas.get(0);
+        }
+        values.put("timeframe", (long)cc.getCourseSeatMinutes());
+        Date tDate = ca.getCourseAttemptStartDate();
+        values.put("startdate", tDate != null ? tDate.getTime() : 0);
+        tDate = ca.getCourseAttemptCompleteDate();
+        values.put("enddate", tDate !=  null ? tDate.getTime() : 0);
+        values.put("status", (long)ca.getCourseAttemptStatusID());
+        switch (ca.getCourseAttemptStatusID()) {
+        case CourseAttempt.STATUS_PASSED:
+            values.put("score", (long)ca.getCourseAttemptScore());
+            break;
+        }
+	return values;
+}
+%>



From scribe at crosswire.org  Thu Mar 23 19:45:35 2017
From: scribe at crosswire.org (scribe at crosswire.org)
Date: Thu, 23 Mar 2017 19:45:35 -0700
Subject: [Ils-source] r1531 - in branches/1.6: .
	src/com/resolutions/ils/data webapp webapp/WEB-INF/classes
	webapp/WEB-INF/lib
Message-ID: <E1crFEN-0002nu-5s@crosswire.org>

Author: scribe
Date: 2017-03-23 19:45:34 -0700 (Thu, 23 Mar 2017)
New Revision: 1531

Added:
   branches/1.6/webapp/certificate_alt.jsp
   branches/1.6/webapp/certificate_curriculum_alt.jsp
   branches/1.6/webapp/genbackcerts.jsp
Modified:
   branches/1.6/
   branches/1.6/src/com/resolutions/ils/data/CourseAttempt.java
   branches/1.6/src/com/resolutions/ils/data/UserProfile.java
   branches/1.6/webapp/WEB-INF/classes/versions.properties
   branches/1.6/webapp/WEB-INF/lib/ils.jar
   branches/1.6/webapp/report_employeecourseatt.jsp
Log:
1.81.2 genbackcert and a few small bug fixes



Property changes on: branches/1.6
___________________________________________________________________
Modified: svn:mergeinfo
   - /trunk:796-1502,1504-1505,1507,1509-1510,1512,1514-1515,1518,1527
   + /trunk:796-1502,1504-1505,1507,1509-1510,1512,1514-1515,1518,1527,1529-1530

Modified: branches/1.6/src/com/resolutions/ils/data/CourseAttempt.java
===================================================================
--- branches/1.6/src/com/resolutions/ils/data/CourseAttempt.java	2017-03-24 02:41:48 UTC (rev 1530)
+++ branches/1.6/src/com/resolutions/ils/data/CourseAttempt.java	2017-03-24 02:45:34 UTC (rev 1531)
@@ -360,13 +360,77 @@
 	public void passAllAssociatedCurriculum(ILSSession session, HttpServletRequest request) {
 		passAllAssociatedCurriculum(session, request, null);
 	}
+
+	public static CourseAttempt makeCurriculumCourseAttemptIfPassed(ILSSession session, int userProfileID, Course cur, Set<Integer> limitToCASIDs) {
+		boolean isPassed = false;
+		Vector<Course> courses = cur.getCurriculumCourses();
+		if (courses != null) {
+			// if so, then let's check if all courses are passed
+			int  timeframe   = 0;
+			long startDate   = 0;
+			long endDate     = 0;
+			int  score       = 0;
+			int  courseCount = 0;
+
+			for (Course c : courses) {
+				isPassed = false;
+
+				timeframe += c.getCourseSeatMinutes();
+				Vector<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(session, userProfileID, c.getCourseID(), limitToCASIDs != null);
+				if (cas != null) {
+					for (CourseAttempt ca : cas) {
+						if (limitToCASIDs != null && !limitToCASIDs.contains(ca.getCourseAttemptID())) continue;
+						Date d = ca.getCourseAttemptStartDate();
+						startDate = (d != null && (startDate == 0 || startDate > d.getTime())) ? d.getTime() : startDate;
+						d = ca.getCourseAttemptCompleteDate();
+						endDate = (d != null && (endDate == 0 || endDate < d.getTime())) ? d.getTime() : endDate;
+
+						boolean finished = !c.isCourseRequiresManagerApproval() || ca.isCourseAttemptManagerApproved();
+						if (finished && ca.getCourseAttemptStatusID() == STATUS_PASSED) {
+							int s = ca.getCourseAttemptScore();
+							if (s > -1) {
+								++courseCount;
+								score += s;
+							}
+							isPassed = true;
+logger.info("course is passed: " + c.getCourseName());
+							break;
+						}
+					}
+				}
+				if (!isPassed) {
+					break;
+				}
+			}
+			// if we have a curriculum of which our course is a member and all courses in this curriculum are passed,
+			// then create a passed course attempt for this curriculum
+			if (isPassed) {
+
+				if (courseCount != 0) score /= courseCount;
+
+				CourseAttempt ca = new CourseAttempt();
+				ca.defaultAll();
+				ca.setCourseAttemptStartDate(new Date(startDate));
+				ca.setCourseAttemptCompleteDate(new Date(endDate));
+				ca.setCourseAttemptCourseID(cur.getCourseID());
+				ca.setCourseAttemptUserProfileID(userProfileID);
+				ca.setCourseAttemptStatusID(ca.STATUS_PASSED);
+				ca.setCourseAttemptScore(score);
+
+				// TODO: timeframe?
+
+				return ca;
+			}
+		}
+		return null;
+	}
+
 	public void passAllAssociatedCurriculum(ILSSession session, HttpServletRequest request, String forcePassReason) {
 		Collection<Course> curs = Course.getUserCurricula(session, getCourseAttemptUserProfileID());
 		if (curs != null) {
 			// find all curricula our user is assigned and check each one
 			for (Course cur : curs) {
 
-				boolean isPassed = false;
 				Vector<Course> courses = cur.getCurriculumCourses();
 				if (courses != null) {
 					// is this course a member of the tested curriculum?
@@ -386,67 +450,25 @@
 					int  courseCount = 0;
 
 					if (isPertinent) {
-						for (Course c : courses) {
-							isPassed = false;
+						CourseAttempt ca = makeCurriculumCourseAttemptIfPassed(session, getCourseAttemptUserProfileID(), cur, null);
+						// if we have a curriculum of which our course is a member and all courses in this curriculum are passed,
+						// then create a passed course attempt for this curriculum
+						if (ca != null) {
+							if (forcePassReason != null) ca.setCourseAttemptForcePass(forcePassReason);
+							ca = ca.saveNew(session);
+logger.info("passing curriulum: " + cur.getCourseName());
 
-							timeframe += c.getCourseSeatMinutes();
-							Vector<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(session, getCourseAttemptUserProfileID(), c.getCourseID(), false);
-							if (cas != null) {
-								for (CourseAttempt ca : cas) {
-									Date d = ca.getCourseAttemptStartDate();
-									startDate = (d != null && (startDate == 0 || startDate > d.getTime())) ? d.getTime() : startDate;
-									d = ca.getCourseAttemptCompleteDate();
-									endDate = (d != null && (endDate == 0 || endDate < d.getTime())) ? d.getTime() : endDate;
-
-									boolean finished = !c.isCourseRequiresManagerApproval() || ca.isCourseAttemptManagerApproved();
-									if (finished && ca.getCourseAttemptStatusID() == STATUS_PASSED) {
-										int s = ca.getCourseAttemptScore();
-										if (s > -1) {
-											++courseCount;
-											score += s;
-										}
-										isPassed = true;
-logger.info("course is passed: " + c.getCourseName());
-										break;
-									}
+							// render certificate
+							if (cur.isCourseCertificateStore()) {
+								try {
+									ca.saveCertificate(ca.generateCertificate(session, request));
 								}
+								catch (Exception e) {
+									logger.error(e, e);
+								}
 							}
-							if (!isPassed) {
-								break;
-							}
 						}
 					}
-					// if we have a curriculum of which our course is a member and all courses in this curriculum are passed,
-					// then create a passed course attempt for this curriculum
-					if (isPertinent && isPassed) {
-
-						if (courseCount != 0) score /= courseCount;
-
-						CourseAttempt ca = new CourseAttempt();
-						ca.defaultAll();
-						if (forcePassReason != null) ca.setCourseAttemptForcePass(forcePassReason);
-						ca.setCourseAttemptStartDate(new Date(startDate));
-						ca.setCourseAttemptCompleteDate(new Date(endDate));
-						ca.setCourseAttemptCourseID(cur.getCourseID());
-						ca.setCourseAttemptUserProfileID(getCourseAttemptUserProfileID());
-						ca.setCourseAttemptStatusID(ca.STATUS_PASSED);
-						ca.setCourseAttemptScore(score);
-
-						// TODO: timeframe?
-
-						ca = ca.saveNew(session);
-logger.info("passing curriulum: " + cur.getCourseName());
-
-						// render certificate
-						if (cur.isCourseCertificateStore()) {
-							try {
-								ca.saveCertificate(ca.generateCertificate(session, request));
-							}
-							catch (Exception e) {
-								logger.error(e, e);
-							}
-						}
-					}
 				}
 			}
 		}
@@ -1070,6 +1092,9 @@
 	}
 
 	public byte[] generateCertificate(ILSSession ilsSession, HttpServletRequest request) throws Exception {
+		return generateCertificate(ilsSession, request, null);
+	}
+	public byte[] generateCertificate(ILSSession ilsSession, HttpServletRequest request, Set<Integer> limitToCAIDs) throws Exception {
 
 
 		Course c = Course.getCourse(ilsSession, getCourseAttemptCourseID());
@@ -1104,6 +1129,7 @@
 		urlString += "?ca=" + getCourseAttemptID();
 		urlString += "&c=" + c.getCourseID();
 		urlString += "&up=" + getCourseAttemptUserProfileID();
+		if (limitToCAIDs != null) urlString += "&caids="+CourseAttempt.join(",", limitToCAIDs);
 
 		if (!urlString.startsWith("http:") &&
 				!urlString.startsWith("ftp:") &&
@@ -1248,4 +1274,15 @@
 		return data;
 	}
 
+	public static String join(String delimeter, Collection items) {
+		if (items == null || items.size() == 0) return "";
+
+		StringBuilder sb = new StringBuilder();
+		for (Object o: items) {
+			if (sb.length() > 0) sb.append(delimeter);
+			sb.append(o.toString());
+		}
+		return sb.toString();
+	}
+
 }

Modified: branches/1.6/src/com/resolutions/ils/data/UserProfile.java
===================================================================
--- branches/1.6/src/com/resolutions/ils/data/UserProfile.java	2017-03-24 02:41:48 UTC (rev 1530)
+++ branches/1.6/src/com/resolutions/ils/data/UserProfile.java	2017-03-24 02:45:34 UTC (rev 1531)
@@ -319,7 +319,7 @@
 	" (SELECT MAX(GROUPNAME) FROM USERGROUP UG JOIN ILSGROUP IG ON UG.ILSGROUPID=IG.ILSGROUPID AND UG.USERPRID=U.USERPRID AND GROUPTYPEID=2) WORKGROUP, " +
 	" (SELECT MAX(GROUPNAME) FROM USERGROUP UG JOIN ILSGROUP IG ON UG.ILSGROUPID=IG.ILSGROUPID AND UG.USERPRID=U.USERPRID AND GROUPTYPEID=1) ROLE, " +
 	" SUM(COALESCE(CA.CRS_COMPLETED, 0)) COURSESCOMPLETED, " +
-	" SUM(COALESCE(CA.CRS_OPEN, 1)) AS COURSESOPEN, " +
+	" CASE WHEN not exists (select 1 from USERCOURSEASSIGNMENTS T2 where T2.COMPANYID=U.COMPANYID AND T2.USERPRID=U.USERPRID) THEN 0 ELSE SUM(COALESCE(CA.CRS_OPEN, 1)) END AS COURSESOPEN, " +
 	" SUM(COALESCE(CA.CRS_FAILED, 0)) COURSESFAILED, " +
 	" MAX(CA.CACOMPLETEDATE) COURSESLASTATTEMPT " +
 	" FROM USERPROFILE  U" +

Modified: branches/1.6/webapp/WEB-INF/classes/versions.properties
===================================================================
--- branches/1.6/webapp/WEB-INF/classes/versions.properties	2017-03-24 02:41:48 UTC (rev 1530)
+++ branches/1.6/webapp/WEB-INF/classes/versions.properties	2017-03-24 02:45:34 UTC (rev 1531)
@@ -1 +1 @@
-LMS=V1.81.1
+LMS=V1.81.2

Modified: branches/1.6/webapp/WEB-INF/lib/ils.jar
===================================================================
(Binary files differ)

Copied: branches/1.6/webapp/certificate_alt.jsp (from rev 1530, trunk/webapp/certificate_alt.jsp)
===================================================================
--- branches/1.6/webapp/certificate_alt.jsp	                        (rev 0)
+++ branches/1.6/webapp/certificate_alt.jsp	2017-03-24 02:45:34 UTC (rev 1531)
@@ -0,0 +1,201 @@
+<%@ page
+    language="java"
+    contentType="text/html;charset=utf-8"
+%>
+<%@ page import="com.resolutions.ils.*" %>
+<%@ page import="com.resolutions.ils.data.*" %>
+<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.Date" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+
+<%
+    ILSSession ilsSession = (ILSSession)session.getAttribute("ilsSession");
+    if (ilsSession == null) {
+        out.print("<html><head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL=login.jsp\"></head></html>");
+        return;
+    }
+    int caID = -1;
+    try {
+        caID = Integer.parseInt(request.getParameter("ca"));
+    }
+    catch (Exception e) {}
+
+    if (caID < 0) {
+        out.print("<html><body><h1>Invalid Request</h1></body></html>");
+        return;
+    }
+    CourseAttempt ca = CourseAttempt.getCourseAttempt(ilsSession, caID);
+    Course cc = Course.getCourse(ilsSession, ca.getCourseAttemptCourseID());
+    UserProfile up = UserProfile.getUserProfile(ilsSession, ca.getCourseAttemptUserProfileID());
+
+    SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
+
+%>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<title>Untitled Document</title>
+
+<style type="text/css" media="print">
+<!--
+.noprint {
+     display:none;
+};
+-->
+</style>
+
+<style type="text/css">
+<!--
+.cert_text {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-size: 34px;
+    color: #333333;
+    text-align: center;
+    border-bottom-width: thin;
+    border-bottom-style: solid;
+    border-bottom-color: #CCCCCC;
+    font-style: oblique;
+    border-top-width: thin;
+    border-top-style: solid;
+    border-top-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+.text {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-size: 14px;
+    font-style: normal;
+    color: #333333;
+    text-align: center;
+    padding: 15px;
+}
+.nametxt {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-style: normal;
+    line-height: 25px;
+    text-transform: uppercase;
+    color: #333333;
+    text-align: center;
+    font-weight: bold;
+    font-size: 18px;
+}
+.coursetxt {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-style: normal;
+    line-height: 25px;
+    text-transform: uppercase;
+    color: #333333;
+    text-align: center;
+    font-weight: bold;
+    font-size: 16px;
+}
+.tableoutline {
+    border: thin solid ##333333;
+    background-repeat: repeat;
+}
+.sigline {
+    border-bottom-width: thin;
+    border-bottom-style: solid;
+    border-bottom-color: #999999;
+}
+.siglinetxt {
+    font-family: Georgia, "Times New Roman", Times, serif;
+    font-size: 10px;
+    text-transform: uppercase;
+    color: #333333;
+    text-align: center;
+}
+.formbtn {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 12px;
+	text-transform: none;
+	color: #666666;
+	padding: 4px 4px 8px;
+	font-weight: bold;
+	text-decoration: none;
+	border: none;
+}
+
+.formbtn:hover {
+	text-decoration: underline;
+}
+-->
+</style>
+</head>
+
+<body>
+
+<div class="noprint">
+    <table width="100%" border="0">
+      <tr>
+        <td width="75%"><div align="right"><a href="javascript:void(window.print())" target="_top"><img border="0" src="images/print_btn.gif" width="24" height="24" alt=""/></a></div></td>
+        <td width="15%"><a class="formbtn" href="javascript:void(window.print())" target="_top">Print Certificate </a></td>
+      </tr>
+    </table>
+</div>
+
+<table width="600" border="0" align="center">
+  <tr>
+    <td class="tableoutline"><table width="100%" border="0" cellspacing="1">
+      <tr>
+        <td bgcolor="#FFFFFF"><table width="100%" border="0" cellspacing="1" class="tableoutline">
+            <tr>
+              <td colspan="2" bgcolor="#283C7A">&nbsp;</td>
+            </tr>
+            <tr>
+              <td colspan="2" class="cert_text">Alternate Certificate of Completion </td>
+            </tr>
+            <tr>
+              <td colspan="2" class="text">This Certifies that </td>
+            </tr>
+            <tr>
+              <td colspan="2" class="nametxt"><%=up.getUserProfileFirstName() %> <%=up.getUserProfileLastName()%></td>
+            </tr>
+            <tr>
+              <td colspan="2" class="text">has successfully completed the following course </td>
+            </tr>
+            <tr>
+              <td colspan="2" class="coursetxt"><%=cc.getCourseName() %></td>
+            </tr>
+            <tr>
+              <td colspan="2" class="text">on</td>
+            </tr>
+            <tr>
+              <td colspan="2" class="coursetxt"><%= ca.getCourseAttemptCompleteDate() != null ? df.format(ca.getCourseAttemptCompleteDate()) : "" %></td>
+            </tr>
+            <tr>
+              <td colspan="2" class="coursetxt">&nbsp;</td>
+            </tr>
+            <tr>
+              <td width="50%"><table width="250" border="0" align="center" cellspacing="1">
+                <tr>
+                  <td class="sigline">&nbsp;</td>
+                </tr>
+                <tr>
+                  <td class="siglinetxt">Signature</td>
+                </tr>
+              </table></td>
+              <td width="50%"><div align="center">
+                <table width="250" border="0" cellspacing="1">
+                    <tr>
+                      <td class="sigline">&nbsp;</td>
+                    </tr>
+                    <tr>
+                      <td class="siglinetxt">Title</td>
+                    </tr>
+                    </table>
+              </div></td>
+            </tr>
+            <tr>
+              <td colspan="2" align="right"><img src="<%=ilsSession.getCurrentCompany().getCompanyLogoURL()%>" alt="Company Logo" width="147" height="67" /></td>
+            </tr>
+            <tr>
+              <td colspan="2" align="right" bgcolor="#283C7A">&nbsp;</td>
+            </tr>
+        </table></td>
+      </tr>
+    </table></td>
+  </tr>
+</table>
+</body>
+</html>

Copied: branches/1.6/webapp/certificate_curriculum_alt.jsp (from rev 1530, trunk/webapp/certificate_curriculum_alt.jsp)
===================================================================
--- branches/1.6/webapp/certificate_curriculum_alt.jsp	                        (rev 0)
+++ branches/1.6/webapp/certificate_curriculum_alt.jsp	2017-03-24 02:45:34 UTC (rev 1531)
@@ -0,0 +1,623 @@
+<%@ page
+    language="java"
+    contentType="text/html;charset=utf-8"
+%>
+<%@ page import="com.resolutions.ils.*" %>
+<%@ page import="com.resolutions.ils.data.*" %>
+<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.HashMap" %>
+<%@ page import="java.util.Date" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+<%
+    ILSSession ilsSession = (ILSSession)session.getAttribute("ilsSession");
+    if (ilsSession == null) {
+        out.print("<html><head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL=login.jsp\"></head></html>");
+        return;
+    }
+
+// So, this now allows us to get the curriculum and user in a number of ways.  Ideally, moving forward,
+// since we are saving a Course Attempt record now when a curriculum is complete, we will get the 
+// Curriculum and User from the Course Attempt record.
+//
+// But... so that we can work the old way, we allow the Curriculum to be passed in directly, as before
+// with the 'c' parameter.  This has other problems, as this assumes that we want the currently logged
+// in user's information about this curriculum, but this is not true any longer because an admin can
+// ask for a certificate for a specific user now.  So, we also allow the User Profile ID to be passed
+// in with the 'up' parameter.  I don't think anyone is using this yet and no one ever should because if
+// they are going to change anything to make things work correctly, they should change to use Course
+// Attempt :)
+//
+    int caID = -1; try { caID = Integer.parseInt(request.getParameter("ca")); } catch (Exception e) {}
+    int cID = -1; try { cID = Integer.parseInt(request.getParameter("c")); } catch (Exception e) {}
+    int upID = -1; try { upID = Integer.parseInt(request.getParameter("up")); } catch (Exception e) {}
+
+    if (caID < 0 && cID < 0) {
+        out.print("<html><body><h1>Invalid Request</h1></body></html>");
+        return;
+    }
+    CourseAttempt ca = caID > -1 ? CourseAttempt.getCourseAttempt(ilsSession, caID) : null;
+    Course cc = Course.getCourse(ilsSession, ca != null ? ca.getCourseAttemptCourseID() : cID);
+    UserProfile up     = UserProfile.getUserProfile(ilsSession, ca != null ? ca.getCourseAttemptUserProfileID() : upID > -1 ? upID : ilsSession.getCurrentUserProfile().getUserProfileID());
+
+    SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
+
+%>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<title>Untitled Document</title>
+<style type="text/css" media="print">
+<!--
+.noprint {
+	display:none;
+}
+;
+-->
+</style>
+<style type="text/css">
+<!--
+.courseTable {
+	font-size:12px;
+	border-collapse: collapse;
+}
+.courseTable td, .courseTable th {
+	border: solid 1px;
+	padding: 2px;
+	font-family: Arial, Helvetica, sans-serif;
+}
+.cert_text {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 1.2em;
+	color: #333333;
+	text-align: center;
+	border-bottom-width: thin;
+	border-bottom-style: solid;
+	border-bottom-color: #CCCCCC;
+	font-style: oblique;
+	border-top-width: thin;
+	border-top-style: solid;
+	border-top-color: #CCCCCC;
+	background-color: #F4F4F4;
+}
+.heading {
+	font-weight: bold;
+	white-space:nowrap;
+}
+.text {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 14px;
+	font-style: normal;
+	color: #333333;
+	padding: 10px;
+}
+.SubText {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 10px;
+	font-style: normal;
+	color: #333333;
+	text-align: left;
+	padding-left:10px;
+	padding-right:10px;
+	padding-top:15;
+	padding-bottom:5px;
+}
+.nametxt {
+	font-family: Arial, Helvetica, sans-serif;
+	font-style: normal;
+	line-height: 25px;
+	text-transform: uppercase;
+	color: #333333;
+	text-align: center;
+	font-weight: bold;
+	font-size: 18px;
+}
+.coursetxt {
+	font-family: Arial, Helvetica, sans-serif;
+	font-style: normal;
+	line-height: 25px;
+	text-transform: uppercase;
+	color: #333333;
+	text-align: center;
+	font-weight: bold;
+	font-size: 16px;
+}
+.tableoutline {
+	border: thin solid ##333333;
+	background-repeat: repeat;
+}
+.sigline {
+	border-bottom-width: thin;
+	border-bottom-style: solid;
+	border-bottom-color: #999999;
+}
+.siglinetxt {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 10px;
+	text-transform: uppercase;
+	color: #333333;
+	text-align: center;
+}
+.formbtn {
+	font-family: Arial, Helvetica, sans-serif;
+	font-size: 12px;
+	text-transform: none;
+	color: #666666;
+	padding: 4px 4px 8px;
+	font-weight: bold;
+	text-decoration: none;
+	border: none;
+}
+.formbtn:hover {
+	text-decoration: underline;
+}
+-->
+</style>
+</head>
+<body>
+<div class="noprint" style="margin-top:0px; padding-top:0px;">
+  <table width="100%" border="0">
+    <tr>
+      <td width="75%"><div align="right"><a href="javascript:void(window.print())" target="_top"><img border="0" src="images/print_btn.gif" width="24" height="24" alt=""/></a></div></td>
+      <td width="15%"><a class="formbtn" href="javascript:void(window.print())" target="_top">Print Alternative Certificate </a></td>
+    </tr>
+  </table>
+</div>
+<!-- Start New Miner Certificate -->
+    <!-- Start Check Full Address -->
+		<% 
+            boolean FullAddress = false;
+            String Addr1 = up.getUserProfileAddr1();
+            String Addr2 = up.getUserProfileAddr2();
+            String City = up.getUserProfileCity();
+            String State = up.getUserProfileState();
+            String Zip = up.getUserProfileZip();
+            String Country = up.getUserProfileCountry();
+            
+            if (Addr1.equals("") || Addr2.equals("") || City.equals("") || State.equals("") || Zip.equals("") || Country.equals("")) {
+                FullAddress = false;
+            } else {
+                FullAddress = true;
+            }
+			
+			boolean FullName = false;
+			
+			String FirstName = up.getUserProfileFirstName();
+			String MiddleName = up.getUserProfileMiddleName();
+			String LastName = up.getUserProfileLastName();
+			String SuffixName = up.getUserProfileSuffixName();
+
+            if (FirstName.equals("") || MiddleName.equals("") || LastName.equals("")) {
+                FullName = false;
+            } else {
+                FullName = true;
+            }
+        %>
+    <!-- End Check Full Address -->
+    <!-- Start Get Course End Date -->
+		<%!
+			public static String GetCourseEndDate(HttpSession session, ILSSession ilsSession, UserProfile user, int CourseID)
+			{
+				Vector cas = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), CourseID, false);
+				CourseAttempt ca = (CourseAttempt)cas.get(0);
+				
+				SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
+				
+				Date tDate = ca.getCourseAttemptCompleteDate();
+				String endDate = (tDate != null) ? df.format(tDate) : "";
+				
+				return endDate;
+			}
+		%> 
+    <!-- End Get Course End Date -->
+    <!-- Start Display New Miner Certificate -->
+    	<% if ("12".equals(request.getParameter("c"))) { %>
+            <table width="700" border="0" align="center" style="margin-top:0px; padding-top:0px;">
+              <tr>
+                <td class="tableoutline"><table width="100%" border="0" cellspacing="1">
+                    <tr>
+                      <td bgcolor="#FFFFFF"><table width="100%" border="0" cellspacing="1" class="tableoutline">
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading" style="text-align:center; font-size:16px;">NEW MINER TRAINING RECORD/CERTIFICATE</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading">Miner's Full Name (Print): </td>
+                                  <td class="sigline" style="width:100%;"><% if (FullName) { %><%= FirstName + " " + MiddleName + " " + LastName + " " + SuffixName %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Full Name</span><% } %></td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading">Mine or Contractor Name: </td>
+                                  <td class="sigline" style="width:100%;">&nbsp;</td>
+                                  <td class="heading"> I.D.#</td>
+                                  <td class="sigline">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2"><table class="courseTable" style="width:100%;">
+                                <thead>
+                                  <tr>
+                                    <th width="210">Subject<br/>30CFR Part 46.5</th>
+                                    <th width="170">Competent<br/>Person</th>
+                                    <th>Date</th>
+                                    <th width="130">Location<br/><span style="font-weight:normal; font-size:10px;">(Name &amp; Address)</span></th>
+                                    <th>Time</th>
+                                    <th>Miner's<br/>Initials</th>
+                                  </tr>
+                                </thead>
+                                <tbody>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">The minor received no less than 4 hours in the following, before beginning work:</td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(1) Introduction to the work environment, mine tour, mining method/operation - On the job training</td>
+                                    <td></td>
+                                    <td></td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span></td>
+                                    <td></td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(1) Introduction to the work environment, mine tour, mining method/operation - Online training</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 15) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>10 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(2) Instruction on recognition and avoidance of electrical and other hazards</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 28) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>4 Hrs<br/>42 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(3) Emergency procedures, escape, and firefighting</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 6) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>18 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(4) Health and Safety aspects<br/>of the tasks assigned - On the job training</td>
+                                    <td></td>
+                                    <td></td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span></td>
+                                    <td></td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(4) Health and Safety aspects of the tasks assigned - Online training</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 5) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>34 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(5) Instruction on statutory rights of miners and their representatives</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 7) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>32 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(6) Authority &amp; responsibility of supervisors and miners' representatives</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 8) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>2 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>(b)(7) Introduction to you rules and procedures for reporting hazards</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 9) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>58 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">No later than 60 days:</td>
+                                  </tr>
+                                  <tr>
+                                    <td>(c)(1) Self-rescue, respiratory devices, if used</td>
+                                    <td style="padding-left:0px; padding-right:0px; text-align:right;"><div style="width:120px; float:right; height:6px; border-bottom:#000 solid 3px;">&nbsp;</div><div style="float:right; font-weight:bold; padding-right:5px;">N/A</div></td>
+                                    <td style="padding-left:0px; padding-right:0px;"><div style="width:100%; border-bottom:#000 solid 3px; height:0px;">&nbsp;</div></td>
+                                    <td style="padding-left:0px; padding-right:0px;"><div style="width:100%; border-bottom:#000 solid 3px; height:0px;">&nbsp;</div></td>
+                                    <td style="padding-left:0px; padding-right:0px;"><div style="width:100%; border-bottom:#000 solid 3px; height:0px;">&nbsp;</div></td>
+                                    <td style="padding-left:0px; padding-right:0px; text-align:left;"><div style="width:25px; float:left; height:9px; border-bottom:#000 solid 3px;">&nbsp;</div><div style="float:left; font-weight:bold; padding-left:0px; font-size: 16px;">&gt;</div></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Emergency plans, and firefighting</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 10) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>6 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">No later than 90 days: (the balance of the 24 hours of training)</td>
+                                  </tr>
+                                  <tr>
+                                    <td>Hazcom</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 11) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>44 Min</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                </tbody>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="coursetxt"><span style="line-height:10px;">&nbsp;</span></td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" width="100%" style="border:solid 2px;"><table width="90%" border="0" align="center" cellspacing="1">
+                                <tr>
+                                  <td colspan="2" width="100%;" class="text" style="font-size:12px;"><strong>False certification is punishable under 110 (a) and (f) of the Federal Mine Safety and Health Act</strong><br/>I certify that the above training has been completed.</td>
+                                </tr>
+                                <tr>
+                                  <td colspan="2" class="sigline" width="100%;">&nbsp;</td>
+                                </tr>
+                                <tr>
+                                  <td width="70%" class="siglinetxt">(Signature of person responsible for health and safety training)</td>
+                                  <td class="siglinetxt">(Date)</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                        </table>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+        <% } else if ("43".equals(request.getParameter("c"))) { %>
+    <!-- End Display New Miner Certificate -->
+    <!-- Start Display Annual Refresher Certificate -->
+            <table width="700" border="0" align="center" style="margin-top:0px; padding-top:0px;">
+              <tr>
+                <td class="tableoutline"><table width="100%" border="0" cellspacing="1">
+                    <tr>
+                      <td bgcolor="#FFFFFF"><table width="100%" border="0" cellspacing="1" class="tableoutline">
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading" style="text-align:center; font-size:14px;">ANNUAL REFRESHER TRAINING RECORD/CERTIFICATE</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom:0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading">Miner's Full Name (Print): </td>
+                                  <td class="sigline" style="width:100%;"><% if (FullName) { %><%= FirstName + " " + MiddleName + " " + LastName + " " + SuffixName %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Full Name</span><% } %></td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="text" style="padding-top:0px; padding-bottom: 0px;"><table style="width:100%;">
+                                <tr>
+                                  <td class="heading">Mine or Contractor Name: </td>
+                                  <td class="sigline" style="width:100%;">&nbsp;</td>
+                                  <td class="heading"> I.D.#</td>
+                                  <td class="sigline">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2"><table class="courseTable" style="width:100%;">
+                                <thead>
+                                  <tr>
+                                    <th width="175">Subject<br/>
+                                    30CFR Part 46.8</th>
+                                    <th width="200">Competent<br/>Person</th>
+                                    <th>Date</th>
+                                    <th width="130">Location<br/><span style="font-weight:normal; font-size:10px;">(Name &amp; Address)</span></th>
+                                    <th>Time</th>
+                                    <th>Miner's<br/>Initials</th>
+                                  </tr>
+                                </thead>
+                                <tbody>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">The miner received no less than 8 hours of annual refresher training in the following:</td>
+                                  </tr>
+                                  <tr>
+                                    <td>Instruction on changes at the mine that could adversely affect the miner's health or safety</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 29) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>9 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>H & S standards and applicable requirements</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 30) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>1 hour<br/>27 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td colspan="6" style="background:#c0c0c0; font-size: 11px; font-weight: bold;">Health and safety subjects relevant to mining operations at the mine</td>
+                                  </tr>
+                                  <tr>
+                                    <td>Transportation controls and communication systems</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 31) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>2 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Emergency plans, and firefighting</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 32) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>17 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Ground conditions and control</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 33) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>2 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Working in areas of highwalls</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 34) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>6 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Water hazards, pits, and spoil banks</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 35) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>4 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Basic First-aid/ CPR</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 36) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>7 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Accident Prevention</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 37) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>3 hours<br/>23 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Mobile Equipment</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 38) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>7 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Health</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 39) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>35 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Maintenance & Repair, Material Handling, Fall protection</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 40) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>31 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Electrical hazards</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 41) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>26 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                  <tr>
+                                    <td>Hazcom</td>
+                                    <td></td>
+                                    <td><%= GetCourseEndDate(session, ilsSession, up, 42) %></td>
+                                    <td style="text-align:center;"><% if (FullAddress) { %><%= Addr1 + "<br/>" + Addr2 + "<br/>" + City + ", " + State + " " + Zip + ", " + Country %><% } else { %><span style="color: #d9d9d9; font-weight: bold;">Enter Location<br/>Name &amp; Address</span><% } %></td>
+                                    <td>44 Mins.</td>
+                                    <td style="text-align:center;"><span style="color: #d9d9d9; font-weight: bold;">Initial<br/>Here</span></td>
+                                  </tr>
+                                </tbody>
+                              </table>
+                            </td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" class="coursetxt"><span style="line-height:10px;">&nbsp;</span></td>
+                          </tr>
+                          <tr>
+                            <td colspan="2" width="100%" style="border:solid 2px;"><table width="90%" border="0" align="center" cellspacing="1">
+                                <tr>
+                                  <td colspan="2" width="100%;" class="text" style="font-size:12px; padding-top:0px; padding-bottom:0px;"><strong>False certification is punishable under 110 (a) and (f) of the Federal Mine Safety and Health Act</strong><br/>I certify that the above training has been completed.</td>
+                                </tr>
+                                <tr>
+                                  <td colspan="2" class="sigline" width="100%;">&nbsp;</td>
+                                </tr>
+                                <tr>
+                                  <td width="70%" class="siglinetxt">(Signature of person responsible for health and safety training)</td>
+                                  <td class="siglinetxt">(Date)</td>
+                                </tr>
+                              </table>
+                            </td>
+                          </tr>
+                        </table>
+                      </td>
+                    </tr>
+                  </table>
+                </td>
+              </tr>
+            </table>
+    	<% } %>
+    <!-- End Display Annual Refresher Certificate -->
+<!-- End New Miner Certificate -->
+</body>
+</html>
+<%!
+public static HashMap<String, Long> processCourseRow(HttpSession session, ILSSession ilsSession, UserProfile user, Course cc) {
+	HashMap<String, Long> values = new HashMap<String, Long>();
+        Vector cas        = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID(), false);
+        CourseAttempt ca  = null;
+        if (cas.size() == 0) {
+        	// see if a past attempt exists
+        	cas = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID());
+        	ca = new CourseAttempt();
+        }
+        else {
+            ca  = (CourseAttempt)cas.get(0);
+        }
+        values.put("timeframe", (long)cc.getCourseSeatMinutes());
+        Date tDate = ca.getCourseAttemptStartDate();
+        values.put("startdate", tDate != null ? tDate.getTime() : 0);
+        tDate = ca.getCourseAttemptCompleteDate();
+        values.put("enddate", tDate !=  null ? tDate.getTime() : 0);
+        values.put("status", (long)ca.getCourseAttemptStatusID());
+        switch (ca.getCourseAttemptStatusID()) {
+        case CourseAttempt.STATUS_PASSED:
+            values.put("score", (long)ca.getCourseAttemptScore());
+            break;
+        }
+	return values;
+}
+%>

Copied: branches/1.6/webapp/genbackcerts.jsp (from rev 1529, trunk/webapp/genbackcerts.jsp)
===================================================================
--- branches/1.6/webapp/genbackcerts.jsp	                        (rev 0)
+++ branches/1.6/webapp/genbackcerts.jsp	2017-03-24 02:45:34 UTC (rev 1531)
@@ -0,0 +1,768 @@
+<%@ page
+    language="java"
+    contentType="text/html;charset=utf-8"
+%>
+<%@ page import="com.resolutions.ils.*" %>
+<%@ page import="com.resolutions.ils.data.*" %>
+<%@ page import="java.io.File" %>
+<%@ page import="java.io.StringWriter" %>
+<%@ page import="java.net.URL" %>
+<%@ page import="java.text.SimpleDateFormat" %>
+<%@ page import="org.apache.log4j.Logger" %>
+<%@ page import="java.util.*" %>
+
+<%!
+	class Pair<A, B> {
+		A a;
+		B b;
+		public Pair(A a, B b) {
+			this.a = a;
+			this.b = b;
+		}
+		public A getKey() { return a; }
+		public B getValue() { return b; }
+	}
+%>
+
+<%
+    ILSSession ilsSession = (ILSSession)session.getAttribute("ilsSession");
+    if (ilsSession == null) {
+        out.print("<html><head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL=login.jsp\"></head></html>");
+        return;
+    }
+    Vector<UserProfile> userProfiles = (Vector<UserProfile>)session.getAttribute("lastDataset");
+
+    UserProfile user    = ilsSession.getCurrentUserProfile();
+
+    boolean managing    = true;
+    String action	= request.getParameter("action");
+	if (managing && "removeCert".equals(action) && (user.getUserProfileAccessLevel() > UserProfile.ACCESS_MANAGER || user.hasAccess(UserProfile.ACCESS_MODE_STUDENTREC_PASS_OVERRIDE))) {
+		if (CourseAttempt.deleteCourseAttempt(ilsSession, Integer.parseInt(request.getParameter("caid"))) > 0) {
+			out.print("Deleted");
+		}
+		else	out.print("Failed to delete.");
+		return;
+	}
+	if (managing && "genBackCert".equals(action) && (user.getUserProfileAccessLevel() > UserProfile.ACCESS_MANAGER || user.hasAccess(UserProfile.ACCESS_MODE_STUDENTREC_PASS_OVERRIDE))) {
+		String userProfileIDString = request.getParameter("userProfileID");
+		String genCurID = request.getParameter("genCurID");
+		String genCAIDs = request.getParameter("genCAIDs");
+logger.info("genbackcert: " + userProfileIDString + ", " + genCurID + ", " + genCAIDs);
+		int curID = -1; try { curID = Integer.parseInt(genCurID); } catch (Exception e) {}
+		int userProfileID = -1; try { userProfileID = Integer.parseInt(userProfileIDString); } catch (Exception e) {}
+    		Course cur = Course.getCourse(ilsSession, curID);
+		Set<Integer> caids = new HashSet<Integer>();
+		for (String caid : genCAIDs.split(",")) {
+			try { caids.add(Integer.parseInt(caid)); } catch (Exception e) {}
+		}
+		CourseAttempt ca = CourseAttempt.makeCurriculumCourseAttemptIfPassed(ilsSession, userProfileID, cur, caids);
+		// if we have a curriculum of which our course is a member and all courses in this curriculum are passed,
+		// then create a passed course attempt for this curriculum
+		if (ca != null) {
+			ca = ca.saveNew(ilsSession);
+logger.info("passing curriulum: " + cur.getCourseName());
+
+			// render certificate
+			if (cur.isCourseCertificateStore()) {
+				try {
+					ca.saveCertificate(ca.generateCertificate(ilsSession, request, caids));
+				}
+				catch (Exception e) {
+					logger.error(e, e);
+				}
+			}
+//logger.info("cur.getCoursePassExpireDays(): " + cur.getCoursePassExpireDays());
+//logger.info("ca.getCourseAttemptCompleteDate(): " + ca.getCourseAttemptCompleteDate());
+			if (cur.getCoursePassExpireDays() > 0) {
+				Date expireOn = new Date(ca.getCourseAttemptCompleteDate().getTime() + (1000L * 60 * 60 * 24 * cur.getCoursePassExpireDays()));
+//logger.info("expireOn: " + expireOn);
+				if (expireOn.getTime() < new Date().getTime()) {
+					CourseAttempt ca2 = (CourseAttempt)ca.clone();
+					ca2.setCourseAttemptExpired("Recurrent Training Assigned");
+					ca2.setTSValue("CAEXPIREDON", expireOn);
+					ca2.save(ca);
+				}
+			}
+		}
+		out.print("Generated");
+		return;
+	}
+%>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<title><%= ilsSession.getCurrentCompany().getCompanyName() %> eLearning Portal</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link href="lms_style.css" rel="stylesheet" type="text/css">
+
+</head>
+<body>
+
+<%@ include file="header.jsp" %>
+
+<script type="text/javascript">
+var rcid=0;
+function retake(inCID) {
+	rcid=inCID;
+	inputBox('Please Type the Reason For Re-take', 3, 80, 3, 'retakeComplete');
+}
+
+function retakeComplete(resultObject) {
+	$.blockUI({ message: '<h3><img width=&quot;30&quot; height=&quot;30&quot; style=&quot;margin-right:10px;vertical-align:middle;&quot; src=&quot;images/loading.gif&quot;/> Generating Report...</h3>' });
+	reason = resultObject.value;
+	document.getElementById('revokeCID').value=rcid;
+	if (reason.length > 0) reason = reason + ' / ';
+	document.getElementById('revokeReason').value=reason + 'Retake Assigned';
+	document.revokeForm.submit();
+}
+
+var pcid=0;
+var pcourseid=0;
+function forcePass(inCID, inCourseID) {
+	pcid=inCID;
+	pcourseid=inCourseID;
+	inputBox('Please Type the Reason For Forcing Pass', 3, 80, 3, 'forcePassComplete');
+}
+
+function forcePassComplete(resultObject) {
+	$.blockUI({ message: '<h3><img width=&quot;30&quot; height=&quot;30&quot; style=&quot;margin-right:10px;vertical-align:middle;&quot; src=&quot;images/loading.gif&quot;/> Generating Report...</h3>' });
+	reason = resultObject.value;
+	document.getElementById('passCID').value=pcid;
+	document.getElementById('passCourseID').value=pcourseid;
+	if (reason.length > 0) reason = reason + ' / ';
+	document.getElementById('passReason').value=reason + 'Pass Forced';
+	document.forcePassForm.submit();
+}
+
+function genAllCerts(userProfileID) {
+	var i = 0;
+	while (true) {
+		++i;
+		if (!$('#cert_'+userProfileID+'_'+i).length) break;
+		$('#cert_'+userProfileID+'_'+i).children('a').trigger('click');
+	}
+}
+
+function removeCert(caid) {
+	var data = {
+		caid : caid,
+		action   : 'removeCert'
+	}
+	$('#ca_'+caid).html('<img height="18" src="images/loading.gif"/> Deleting...');
+	$.post('genbackcerts.jsp', data, function(result) {
+		$('#ca_'+caid).html('<b>'+result+'</b>');
+	}, 'text');
+}
+
+function genCert(userProfileID, curID, caids, count, needsForce) {
+	if (needsForce) return;
+	//$.blockUI({ message: '<h3><img width="30" height="30" style="margin-right:10px;vertical-align:middle;" src="images/loading.gif"/> Generating Back Cert...</h3>' });
+	var data = {
+		userProfileID : userProfileID,
+		genCurID : curID,
+		genCAIDs : caids,
+		action   : 'genBackCert'
+	}
+	$('#cert_'+userProfileID+'_'+count).html('<img height="18" src="images/loading.gif"/> Generating...');
+	$.post('genbackcerts.jsp', data, function(result) {
+		$('#cert_'+userProfileID+'_'+count).html('<b>'+result+'</b>');
+	}, 'text');
+}
+
+function toggleCourseDetails(courseID) {
+	if ($('.subCourseID_'+courseID+':first').is(":visible")) {
+		$('#courseHeader_'+courseID).html('+');
+		$('.subCourseID_'+courseID).hide();
+	}
+	else {
+		$('#courseHeader_'+courseID).html('&ndash;');
+		$('.subCourseID_'+courseID).show();
+	}
+}
+function toggleCurriculumDetails(courseID) {
+	if ($('.subCurriculumID_'+courseID+':first').is(":visible")) {
+		$('#curriculumHeader_'+courseID).html('?<br>?');
+		$('.subCurriculumID_'+courseID).hide();
+		$('.historyDetail').hide();
+		$('.courseHeader').html('+');
+	}
+	else {
+		$('#curriculumHeader_'+courseID).html('?<br>?');
+		$('.subCurriculumID_'+courseID).show();
+		$('.historyDetail').hide();
+		$('.courseHeader').html('+');
+	}
+}
+
+$(document).ready(function() {
+//	$('.historyDetail').hide();
+//	$('.subCourseHeaderRow').hide();
+});
+
+
+</script>
+
+  <div id="pageContainer">
+<%@ include file="menu.jsp" %>
+<div id="content">
+<div id="pageTitles">Reports </div>
+
+
+<%!
+	static SimpleDateFormat df  = new SimpleDateFormat("MM/dd/yyyy");
+	static Logger logger = Logger.getLogger("report/employee/course/attempt");
+%>
+<%
+	for (UserProfile current: userProfiles) {
+logger.info("**** " + current.getUserProfileLastName() + ", " + current.getUserProfileFirstName());
+
+    int profileID       = current.getUserProfileID();
+	int count = 0;
+    
+
+	Vector<Course> courses       = Course.getAllUserCourses(ilsSession, current.getUserProfileID());
+	int wordNum = 0;
+
+	Collection<Course> curricula = Course.getUserCurricula(ilsSession, current.getUserProfileID());
+
+	// map all courses to their parent curriculum
+	HashMap<Integer, Integer> courseCurriculum = new HashMap<Integer, Integer>();
+	HashMap<Integer, Boolean> courseSupressRetake = new HashMap<Integer, Boolean>();
+	HashMap<Integer, Course> curriculaList = new HashMap<Integer, Course>();
+	HashMap<Integer, HashSet<CourseAttempt>> courseCourseAttempts = new HashMap<Integer, HashSet<CourseAttempt>>();
+
+	Map<Course, List<List<Pair<Course, CourseAttempt>>>> curriculaEval = new HashMap<Course, List<List<Pair<Course, CourseAttempt>>>>();
+	for (Course cur : curricula) {
+		List<List<Pair<Course, CourseAttempt>>> associated = new ArrayList<List<Pair<Course, CourseAttempt>>>();
+		Set<Integer> usedCourses = new HashSet<Integer>();
+logger.info("CUR: (" + cur.getCourseNum() + " : " + cur.getCourseID() + ") " + cur.getCourseName());
+		curriculaList.put(cur.getCourseID(), cur);
+		boolean passed = true;
+		boolean missed = false;
+		while (passed) {
+			List<Pair<Course, CourseAttempt>> associatedCourseAttempts = new ArrayList<Pair<Course, CourseAttempt>>();
+			passed = false;
+			for (Course c : Course.getCurriculumCourses(ilsSession, cur.getCourseID())) {
+logger.debug(" - COURSE: (" + c.getCourseNum() + " : " + c.getCourseID() + ") " + c.getCourseName());
+				Vector<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(ilsSession, current.getUserProfileID(), c.getCourseID());
+
+    java.util.Collections.sort(cas, new Comparator<CourseAttempt>() {
+        public int compare(CourseAttempt o1, CourseAttempt o2) {
+                Date d1 = o1.getCourseAttemptCompleteDate();
+                if (d1 == null) d1 = o1.getCourseAttemptStartDate();
+                Date d2 = o2.getCourseAttemptCompleteDate();
+                if (d2 == null) d2 = o2.getCourseAttemptStartDate();
+                long i1 = (d1 == null) ? 0 : d1.getTime();
+                long i2 = (d2 == null) ? 0 : d2.getTime();
+                return (i1 < i2) ? -1 : (i1 == i2) ? 0 : 1;
+        }
+    });
+				passed = false;
+				for (CourseAttempt ca : cas) {
+					if (ca.getCourseAttemptStatusID() == 1 && !usedCourses.contains(ca.getCourseAttemptID())) {
+logger.debug("     .COURSEATTEMPT: " + ca.getCourseAttemptCompleteDate() + "; STATUS: " + ca.getCourseAttemptStatusID());
+						usedCourses.add(ca.getCourseAttemptID());
+						associatedCourseAttempts.add(new Pair(c,ca));
+						passed = true;
+						break;
+					}
+				}
+				if (!passed) {
+					associatedCourseAttempts.add(new Pair(c,null));
+logger.debug("    -- Missing: " + c.getCourseName());
+					missed = true;
+				}
+				courseCurriculum.put(c.getCourseID(), cur.getCourseID());
+				courseSupressRetake.put(c.getCourseID(), !cur.isCourseAllowCurriculumPartRetake());
+			}
+			if (!missed) {
+
+    java.util.Collections.sort(associatedCourseAttempts, new Comparator<Pair<Course, CourseAttempt>>() {
+        public int compare(Pair<Course, CourseAttempt> p1, Pair<Course, CourseAttempt> p2) {
+		CourseAttempt o1 = p1.getValue();
+		CourseAttempt o2 = p2.getValue();
+		if (o1 == null && o1 == null) return 0;
+		if (o1 == null) return -1;
+		if (o2 == null) return 1;
+                Date d1 = o1.getCourseAttemptCompleteDate();
+                if (d1 == null) d1 = o1.getCourseAttemptStartDate();
+                Date d2 = o2.getCourseAttemptCompleteDate();
+                if (d2 == null) d2 = o2.getCourseAttemptStartDate();
+                long i1 = (d1 == null) ? 0 : d1.getTime();
+                long i2 = (d2 == null) ? 0 : d2.getTime();
+                return (i1 < i2) ? -1 : (i1 == i2) ? 0 : 1;
+        }
+    });
+logger.info("------ CUR - PASSED; startDate: " + associatedCourseAttempts.get(0).getValue().getCourseAttemptStartDate() + "; completeDate: " + associatedCourseAttempts.get(associatedCourseAttempts.size() - 1).getValue().getCourseAttemptCompleteDate());
+			}
+			if (passed) associated.add(associatedCourseAttempts);
+		}
+		curriculaEval.put(cur, associated);
+	}
+
+	courses.addAll(curricula);
+	Vector<CourseAttempt> courseAttempts = new Vector<CourseAttempt>();
+	for (int j = 0; j < courses.size(); j++) {
+		Course mainCourse = (Course)courses.get(j);
+		HashSet<CourseAttempt> meCourseAttempts = new HashSet<CourseAttempt>();
+		courseCourseAttempts.put(mainCourse.getCourseID(), meCourseAttempts);
+logger.debug("processing course: " + mainCourse.getCourseName());
+		Vector cas = CourseAttempt.getUserCourseAttempts(ilsSession, current.getUserProfileID(), mainCourse.getCourseID());
+		boolean nonExpired = false;
+		for (int i = 0; i < cas.size() + 1; i++) {
+			CourseAttempt ca  = null;
+			if (i == cas.size()) {
+				// we've finished our course attempts and we already have a status, we're done
+				if (nonExpired) break;
+				else {
+					ca = new CourseAttempt();
+					ca.setCourseAttemptID(-1);
+					ca.setIntValue("COMPANYID", ilsSession.getCompanyID());
+				}
+			}
+			else {
+				ca = (CourseAttempt)cas.get(i);
+				// we've already populated our main course, let's add a dup
+				if (!ca.isCourseAttemptExpired()) {
+					nonExpired = true;
+				}
+			}
+			String score   = "";
+			String status   = "";
+			int statusSort = ca.getCourseAttemptStatusID();
+			boolean finished = false;
+			switch (ca.getCourseAttemptStatusID()) {
+			case CourseAttempt.STATUS_IN_PROGRESS:
+			    status   = "In Progress";
+			    statusSort = 1;
+			    break;
+			case CourseAttempt.STATUS_PASSED:
+			    finished = !((mainCourse.isCourseRequiresManagerApproval()) && (!ca.isCourseAttemptManagerApproved()));
+			    status   = (finished) ? "Passed" : "Awaiting <t:t>Manager</t:t> Approval";
+			    score = Integer.toString(ca.getCourseAttemptScore());
+			    if ("-1".equals(score)) score = "";
+			    statusSort = 4;
+			    break;
+			case CourseAttempt.STATUS_FAILED:
+			    status   = "Failed";
+			    score = Integer.toString(ca.getCourseAttemptScore());
+			    if ("-1".equals(score)) score = "";
+			    statusSort = 2;
+			    break;
+			case CourseAttempt.STATUS_NEW:
+			    status   = "New";
+			    statusSort = 3;
+			}
+			ca.setValue("status", status);
+			ca.setIntValue("statusSort", statusSort);
+			ca.setValue("score", score);
+			ca.setValue("coursenum", mainCourse.getCourseNum());
+			ca.setValue("coursename", mainCourse.getCourseName());
+			ca.setValue("seattimetext", mainCourse.getCourseSeatTimeText());
+			ca.setCourseAttemptCourseID(mainCourse.getCourseID());
+			if (mainCourse.isCourseActive() || (ca.getCourseAttemptStatusID() == CourseAttempt.STATUS_FAILED) || (finished && ca.getCourseAttemptStatusID() == CourseAttempt.STATUS_PASSED)) {
+				courseAttempts.add(ca);
+				meCourseAttempts.add(ca);
+			}
+		}
+	}
+
+
+    java.util.Collections.sort(courseAttempts, new Comparator<CourseAttempt>() {
+        public int compare(CourseAttempt o1, CourseAttempt o2) {
+            int a1 = o1.getIntValue("statusSort");
+            int a2 = o2.getIntValue("statusSort");
+            if ((a1 - a2) == 0) {
+                Date d1 = o1.getCourseAttemptCompleteDate();
+                if (d1 == null) d1 = o1.getCourseAttemptStartDate();
+                Date d2 = o2.getCourseAttemptCompleteDate();
+                if (d2 == null) d2 = o2.getCourseAttemptStartDate();
+                long i1 = (d1 == null) ? 0 : d1.getTime();
+                long i2 = (d2 == null) ? 0 : d2.getTime();
+                return (i1 > i2) ? -1 : (i1 == i2) ? 0 : 1;
+            }
+            return (a1 - a2);
+        }
+    });
+
+
+%>
+
+
+
+
+        <table cellpadding="0" cellspacing="0" class="tableMain">
+<tr>
+                        <td><table class="tableMain" style="margin-bottom:0px">
+                            <tr>
+                              <th><div style="float:left;"><%=current.getUserProfileFirstName()%> <%=current.getUserProfileLastName()%></div><div style="text-align:right; float:right; color:#7D7D7D; font-weight:bold; padding-right:5px"><%=df.format(new Date())%> </div></th>
+
+                            </tr>
+                        </table></td>
+          </tr>
+                      <tr>
+                        <td valign="top">
+                          <table class="tableBTN">
+                            <tr>
+                              <td ><table>
+                                  <tr>
+                                    <td><a href="javascript:void(window.print())" target="_top"><img border="0" src="images/print_btn.gif" width="24" height="24" alt=""/></a></td>
+                                    <td><a class="formButtons" href="#" onclick="genAllCerts(<%=current.getUserProfileID()%>);return false;" target="_top">Generate All</a></td>
+                                  </tr>
+                              </table></td>
+                            </tr>
+                          </table>
+                        </td>
+                      </tr>
+
+                      <tr>
+                        <td><table class="tableDataList tableDataListStudentRecords">
+				<thead>
+                            <tr>
+                              <th style="width: 16px !important;" title="Hide/Show Courses within Curriculum"></th>
+                              <th style="width: 22px !important;" title="Hide/Show All History for an Item"></th>
+<% if (managing) { %>                            
+                              <th style="width: 160px !important;">Comments</th>
+<% } %>                              
+                              <th style="width: 60px !important;">Status</th>
+                              <th style="width: 60px !important;">No.</th>
+                              <th style="width: 160px !important;">Course Name</th>
+                              <th style="width: 70px !important;">Timeframe</th>
+                              <th style="width: 70px !important;">Start Date </th>
+                              <th style="width: 70px !important;">End Date</th>
+                              <th style="width: 50px !important;">Score %</th>
+                              <th style="width: 35px !important;">Cert</th>
+                            </tr>
+				</thead>
+				<tbody>
+<%
+// TODO
+//	This is a little convoluted. We do this in the order of courseAttempt because they may sort things in some order and we'd like those results to have priority, pulling in their dependencies as we work through the queue.
+    for (Course cur : curriculaEval.keySet()) {
+    	%>
+<tr class="curriculumHeaderRow">
+	<td></td>
+	<td></td>
+	<td></td>
+	<td></td>
+	<td><%=cur.getCourseNum()%></td>
+	<td><%=cur.getCourseName()%></td>
+	<td></td>
+	<td></td>
+	<td></td>
+	<td></td>
+	<td></td>
+</tr>
+<%
+	// existing course attempts
+	for (CourseAttempt curriculaAttempt : (Vector<CourseAttempt>)CourseAttempt.getUserCourseAttempts(ilsSession, current.getUserProfileID(), cur.getCourseID())) {
+		String comments = "";
+		if (curriculaAttempt.isCourseAttemptExpired()) {
+			comments += curriculaAttempt.getCourseAttemptExpiredReason() + "<br/>" + df.format(curriculaAttempt.getCourseAttemptExpiredDate());
+		}
+		if (curriculaAttempt.isCourseAttemptForcePass()) {
+			if (comments.length() > 0) comments += "<br/>";
+			comments += curriculaAttempt.getCourseAttemptForcePassReason() + "<br/>" + df.format(curriculaAttempt.getCourseAttemptForcePassDate());
+		}
+%>
+<tr class="curriculumDetailRow historyDetail subCourseID_<%=curriculaAttempt.getCourseAttemptID()%>">
+	<td></td>
+	<td></td>
+	<td><%=comments%></td>
+	<td id="ca_<%=curriculaAttempt.getCourseAttemptID()%>">Passed (<a href="#" onclick="removeCert(<%=curriculaAttempt.getCourseAttemptID()%>); return false;">delete</a>)</td>
+	<td></td>
+	<td></td>
+	<td></td>
+	<td><%=df.format(curriculaAttempt.getCourseAttemptStartDate())%></td>
+	<td><%=df.format(curriculaAttempt.getCourseAttemptCompleteDate())%></td>
+	<td><%=curriculaAttempt.getCourseAttemptScore()%></td>
+	<td></td>
+</tr>
+<%
+	}
+
+	// possible course attempts
+	List<List<Pair<Course, CourseAttempt>>> curriculaAttempts = curriculaEval.get(cur);
+	for (List<Pair<Course, CourseAttempt>> curriculaAttempt : curriculaAttempts) {
+		++count;
+		List<Pair<Course, CourseAttempt>> finished = new ArrayList<Pair<Course, CourseAttempt>>();
+ 		for (Pair<Course, CourseAttempt> p : curriculaAttempt) { if (p.getValue() != null) finished.add(p); }
+		String startDate = finished.size() == 0 ? "" : df.format(finished.get(0).getValue().getCourseAttemptStartDate());
+		String completeDate = finished.size() == 0 ? "" : df.format(finished.get(finished.size() - 1).getValue().getCourseAttemptCompleteDate());
+		String cas = "";
+		if (curriculaAttempt.size() > 0) {
+			for (Pair<Course, CourseAttempt> x : curriculaAttempt) {
+				if (x.getValue() != null) {
+					cas += ((cas.length() > 0 ? "," : "") + x.getValue().getCourseAttemptID());
+				}
+			}
+		}
+%>
+
+<tr class="curriculumDetailRow historyDetail">
+	<td></td>
+	<td></td>
+	<td></td>
+	<td id="cert_<%=current.getUserProfileID()%>_<%=count%>"><a href="#" onclick="genCert(<%=current.getUserProfileID()%>, <%=cur.getCourseID()%>, '<%=cas%>', <%=count%>, <%=finished.size() != curriculaAttempt.size()%>); return false;">Generate<%=finished.size() != curriculaAttempt.size() ? " Anyway":""%></a></td>
+	<td><%=cur.getCourseNum()%></td>
+	<td><%=cur.getCourseName()%></td>
+	<td></td>
+	<td><%=startDate%></td>
+	<td><%=completeDate%></td>
+	<td></td>
+	<td></td>
+</tr>
+
+<%
+    for (Pair<Course, CourseAttempt> ca :  curriculaAttempt) {
+%>
+<tr class="subCurriculumID_<%=cur.getCourseID()%> subCourseHeaderRow">
+	<td></td>
+<td></td>
+<td></td>
+<td><%=ca.getValue() == null ? "MISSING" : "PASSED"%></td>
+<td><%=ca.getKey().getCourseNum()%></td>
+<td><%=ca.getKey().getCourseName()%></td>
+<td><%=ca.getKey().getCourseSeatTimeText()%></td>
+<td><%=ca.getValue() == null ? "" : df.format(ca.getValue().getCourseAttemptStartDate())%></td>
+<td><%=ca.getValue() == null ? "" : df.format(ca.getValue().getCourseAttemptCompleteDate())%></td>
+<td><%=ca.getValue() == null ? "" : Integer.toString(ca.getValue().getCourseAttemptScore())%></td>
+<td></td>
+</tr>
+<%
+    }
+	}
+	}
+%>
+			</tbody>
+                        </table></td>
+                      </tr>
+    </table>
+</div>
+
+<%
+logger.info("**** END " + current.getUserProfileLastName() + ", " + current.getUserProfileFirstName());
+}
+logger.info("**** footer");
+%>
+<%@ include file="footer.jsp" %>
+</div>
+
+</body>
+</html>
+
+<%!
+
+public static String getCourseHTML(Vector<CourseAttempt> courseAttempts, CourseAttempt ca, boolean managing, UserProfile user, int wordNum, String headerAddition, String subClassAddition, boolean supressRetake, HashMap<Integer, Integer> courseCurriculum, HashMap<Integer, Course> curriculaList, Vector<Course>courses, HashMap<Integer, HashSet<CourseAttempt>>courseCourseAttempts) {
+
+	if (subClassAddition == null) subClassAddition = "";
+	else subClassAddition += " ";
+
+	boolean isCurriculum = curriculaList.get(ca.getCourseAttemptCourseID()) != null;
+	StringWriter out = new StringWriter();
+	String html = getCourseAttemptHTML(ca, managing, user, wordNum, supressRetake, courseCurriculum, curriculaList, courses, courseCourseAttempts);
+	courseAttempts.remove(ca);
+	String moreHTML = "";
+	for (int j = 0; j < courseAttempts.size(); ++j) {
+		CourseAttempt ca2 = courseAttempts.get(j);
+		if (ca2.getCourseAttemptCourseID() == ca.getCourseAttemptCourseID()) {
+			moreHTML += "<tr class=\""+(subClassAddition.trim().length() > 0?"subC":"c")+(isCurriculum?"urriculum":"ourse")+"DetailRow historyDetail subCourseID_"+ca2.getCourseAttemptCourseID()+"\"><td></td><td></td>"+getCourseAttemptHTML(ca2, managing, user, ++wordNum, supressRetake, courseCurriculum, curriculaList, courses, courseCourseAttempts)+"</tr>";
+			courseAttempts.remove(ca2);
+			--j;
+		}
+	}
+
+	out.write("<tr class=\""+subClassAddition+(subClassAddition.trim().length() > 0?"subC":"c")+(isCurriculum?"urriculum":"ourse")+"HeaderRow\">");
+	out.write("<td>");
+	if (headerAddition != null) out.write(headerAddition);
+	out.write("</td><td>");
+	if (moreHTML.length() > 0) {
+		out.write("<span class=\"courseHeader\" title=\"Show / Hide history for this record.\" id=\"courseHeader_"+ca.getCourseAttemptCourseID()+"\" onclick=\"toggleCourseDetails('"+ca.getCourseAttemptCourseID()+"');return false;\">+</span>");
+	}
+	out.write("</td>");
+	out.write(html);
+	out.write("</tr>");
+	out.write(moreHTML);
+
+	return out.toString();
+}
+
+public static String getCurriculumHTML(HashMap<Integer, Boolean> courseSupressRetake, HashMap<Integer, Integer> courseCurriculum, Vector<CourseAttempt> courseAttempts, CourseAttempt caCur, boolean managing, UserProfile user, int wordNum, HashMap<Integer, Course> curriculaList, Vector<Course>courses, HashMap<Integer, HashSet<CourseAttempt>>courseCourseAttempts) {
+
+	Logger logger = Logger.getLogger("getCurriculumHTML");
+
+	StringWriter out = new StringWriter();
+	String headerAddition = ("<span class=\"curHeader\" id=\"curriculumHeader_"+caCur.getCourseAttemptCourseID()+"\" title=\"Show / Hide Courses within this Curriculum\" onclick=\"toggleCurriculumDetails('"+caCur.getCourseAttemptCourseID()+"');return false;\">?<br>?</span>");
+	String html = getCourseHTML(courseAttempts, caCur, managing, user, wordNum, headerAddition, null, false, courseCurriculum, curriculaList, courses, courseCourseAttempts);
+	String moreHTML = "";
+	for (int j = 0; j < courseAttempts.size(); ++j) {
+		CourseAttempt ca2 = courseAttempts.get(j);
+
+		// see if this course attempt is in our curriculum
+		Integer curriculumID = courseCurriculum.get(ca2.getCourseAttemptCourseID());
+		if (curriculumID != null && caCur.getCourseAttemptCourseID() == curriculumID.intValue()) {
+logger.info("cours is in cur.");
+			String subClassAddition = "subCurriculumID_"+caCur.getCourseAttemptCourseID();
+			Boolean supressRetake = courseSupressRetake.get(ca2.getCourseAttemptCourseID());
+			moreHTML += getCourseHTML(courseAttempts, ca2, managing, user, ++wordNum, null, subClassAddition, supressRetake != null && supressRetake.booleanValue(), courseCurriculum, curriculaList, courses, courseCourseAttempts);
+			--j;
+		}
+		else {
+logger.info("cours NOT is in cur. CourseID:"+ca2.getCourseAttemptCourseID()+"; curParent: " + curriculumID);
+		}
+	}
+
+	out.write(html);
+	out.write(moreHTML);
+
+	return out.toString();
+}
+
+
+public static String getCourseAttemptHTML(CourseAttempt ca, boolean managing, UserProfile user, int wordNum, boolean supressRetake, HashMap<Integer, Integer> courseCurriculum, HashMap<Integer, Course> curriculaList, Vector<Course>courses, HashMap<Integer, HashSet<CourseAttempt>>courseCourseAttempts) {
+
+	boolean supressCert = false;
+	// are we IN a curriculum?
+	Integer curriculumID = courseCurriculum.get(ca.getCourseAttemptCourseID());
+	if (curriculumID != null) {
+		Course curr = curriculaList.get(curriculumID);
+		supressCert = curr.isCourseCurriculumCertificate();
+	}
+
+	// are we a curriculum?
+	Course curr = curriculaList.get(ca.getCourseAttemptCourseID());
+	if (curr != null) {
+		supressCert = !curr.isCourseCurriculumCertificate();
+		HashMap<String, Object>values = new HashMap<String, Object>();
+		computeCurriculumStats(curr.getCourseID(), courses, courseCurriculum, courseCourseAttempts, values);
+		int  timeFrame         = (Integer)values.get("timeFrame");
+		long sDate         = (Long)values.get("startDate");
+		long eDate           = (Long)values.get("endDate");
+		int  score             = (Integer)values.get("score");
+		int  inProgressCourseCount = (Integer)values.get("inProgressCourseCount");
+		int  passedCourseCount = (Integer)values.get("passedCourseCount");
+		int  totalCourseCount  = (Integer)values.get("totalCourseCount");
+		ca.setValue("seattimetext", Course.getNiceTimeText(timeFrame));
+		boolean finished = !((curr.isCourseRequiresManagerApproval()) && (!ca.isCourseAttemptManagerApproved()));
+		// if we have a stored history of passed or failed, use it.  Otherwise, compute curriculum status based on course progress
+		if (
+			   (!finished || ca.getCourseAttemptStatusID() != CourseAttempt.STATUS_PASSED)
+			&& ca.getCourseAttemptStatusID() != CourseAttempt.STATUS_FAILED
+		) {
+			ca.setValue("status", passedCourseCount == totalCourseCount ? "Passed" : (inProgressCourseCount == 0 && passedCourseCount == 0) ? "New" : "In Progress");
+		}
+		if ("In Progress".equals(ca.getValue("status"))) ca.setCourseAttemptStartDate(new Date(sDate));
+	}
+
+	StringWriter out = new StringWriter();
+	Date tDate = ca.getCourseAttemptStartDate();
+	String startDate = (tDate != null) ? df.format(tDate) : "";
+	tDate = ca.getCourseAttemptCompleteDate();
+	String endDate = (tDate != null) ? df.format(tDate) : "";
+	String status = ca.getStringValue("status");
+	if (managing) {
+		out.write("<td>");
+		if ("Passed".equals(status)) {
+			if (!ca.isCourseAttemptExpired() && !supressRetake) {
+				out.write("<a href=\"#\" onClick=\"retake("+ca.getCourseAttemptID()+");return false;\" class=\"Assign\">Assign Retake</a><br>");
+			}
+		}
+		else if (!"Awaiting <t:t>Manager</t:t> Approval".equals(status) && user.getUserProfileAccessLevel() > UserProfile.ACCESS_MANAGER || user.hasAccess(UserProfile.ACCESS_MODE_STUDENTREC_PASS_OVERRIDE)) {
+			out.write("<a href=\"#\" onClick=\"forcePass("+ca.getCourseAttemptID()+", "+ca.getCourseAttemptCourseID()+");return false;\" class=\"Assign\">Force Pass</a>");
+	
+		}
+
+		String val = "";
+		if (ca.isCourseAttemptExpired()) {
+			val += ca.getCourseAttemptExpiredReason() + "<br/>" + df.format(ca.getCourseAttemptExpiredDate());
+		}
+		if (ca.isCourseAttemptForcePass()) {
+			if (val.length() > 0) val += "<br/>";
+			val += ca.getCourseAttemptForcePassReason() + "<br/>" + df.format(ca.getCourseAttemptForcePassDate());
+		}
+		out.write(val+"</td>");
+	}
+
+
+	out.write("<td>"+status+"</td>");
+	out.write("<td>"+ca.getStringValue("coursenum")+"</td>");
+	out.write("<td><a href=\"#\" onclick=\"p('course','"+ca.getCourseAttemptCourseID()+"','"+wordNum+"');\">"+ca.getStringValue("coursename")+"</a></td>");
+	out.write("<td>"+ca.getStringValue("seattimetext")+"</td>");
+	out.write("<td>"+startDate+"</td>");
+	out.write("<td>"+endDate+"</td>");
+	out.write("<td>"+ca.getStringValue("score")+"</td>");
+	out.write("<td>");
+
+	if (ca.getSavedCertificate() != null) {
+		out.write("<a target=\"_blank\" href=\"api/courseattempt/cert/get?courseAttemptID="+ca.getCourseAttemptID()+"\"><img src=\"images/certificate_saved.png\"/></a>");
+	}
+	else if ("Passed".equals(status) && !supressCert) {
+		Course c = Course.getCourse(ca.getCompanyID(), ca.getCourseAttemptCourseID());
+		String urlString = c.getCourseCertificateGenerator();
+		if (urlString == null || urlString.length() < 1) urlString = (c.isCourseCurriculum() ? "certificate_curriculum.jsp" : "certificate.jsp");
+		urlString += "?ca=" + ca.getCourseAttemptID();
+		urlString += "&c=" + c.getCourseID();
+		urlString += "&up=" + ca.getCourseAttemptUserProfileID();
+		out.write("<a target=\"_blank\" href=\""+urlString+"\"><img src=\"images/print_certficate.png\"/></a>");
+	}
+	out.write("</td>");
+
+	return out.toString();
+}
+public static void computeCurriculumStats(int curriculumID, Vector<Course> courses, HashMap<Integer, Integer> courseCurriculum, HashMap<Integer, HashSet<CourseAttempt>> courseCourseAttempts, HashMap<String, Object>values) {
+	int  timeFrame         = 0;
+	long startDate         = 0;
+	long endDate           = 0;
+	int  score             = 0;
+	int  inProgressCourseCount = 0;
+	int  passedCourseCount = 0;
+	int  totalCourseCount  = 0;
+	int  scoredCourseCount  = 0;
+
+	for (Course c : courses) {
+		// are we a course in our curriculum?
+		Integer thisCourseCurriculum = courseCurriculum.get(c.getCourseID());
+		if (thisCourseCurriculum != null && curriculumID == thisCourseCurriculum) {
+			++totalCourseCount;
+
+			timeFrame += c.getCourseSeatMinutes();
+			Set<CourseAttempt> cas = courseCourseAttempts.get(c.getCourseID());
+			if (cas != null) {
+				boolean inProgress = false;
+				for (CourseAttempt ca : cas) {
+					Date d = ca.getCourseAttemptStartDate();
+					startDate = (d != null && (startDate == 0 || startDate > d.getTime())) ? d.getTime() : startDate;
+					d = ca.getCourseAttemptCompleteDate();
+					endDate = (d != null && (endDate == 0 || endDate < d.getTime())) ? d.getTime() : endDate;
+
+					boolean finished = !((c.isCourseRequiresManagerApproval()) && (!ca.isCourseAttemptManagerApproved()));
+					if (finished && ca.getCourseAttemptStatusID() == CourseAttempt.STATUS_PASSED && !ca.isCourseAttemptExpired()) {
+						int s = ca.getCourseAttemptScore();
+						++passedCourseCount;
+						if (s > -1) {
+							++scoredCourseCount;
+							score += s;
+							inProgress = false;
+						}
+						break;
+					}
+					else if (ca.getCourseAttemptStatusID() == CourseAttempt.STATUS_IN_PROGRESS) inProgress = true;
+				}
+				if (inProgress) ++inProgressCourseCount;
+			}
+		}
+	}
+
+	if (scoredCourseCount != 0) score /= scoredCourseCount;
+	values.put("timeFrame", timeFrame);
+	values.put("startDate", startDate);
+	values.put("endDate", endDate);
+	values.put("score", score);
+	values.put("inProgressCourseCount", inProgressCourseCount);
+	values.put("passedCourseCount", passedCourseCount);
+	values.put("totalCourseCount", totalCourseCount);
+	values.put("timeFrame", timeFrame);
+
+logger.debug("curriculum: " + curriculumID + "; values: " + values);
+}
+%>

Modified: branches/1.6/webapp/report_employeecourseatt.jsp
===================================================================
--- branches/1.6/webapp/report_employeecourseatt.jsp	2017-03-24 02:41:48 UTC (rev 1530)
+++ branches/1.6/webapp/report_employeecourseatt.jsp	2017-03-24 02:45:34 UTC (rev 1531)
@@ -275,7 +275,7 @@
 <tr>
                         <td><table class="tableMain" style="margin-bottom:0px">
                             <tr>
-                              <th><div style="float:left;"><%=current.getUserProfileFirstName()%> <%=current.getUserProfileLastName()%></div><div style="text-align:right; float:right; color:#7D7D7D; font-weight:bold; padding-right:5px"><%=df.format(new Date())%> </div></th>
+                              <th><div style="float:left;"><%=current.getUserProfileFirstName()%> <%=current.getUserProfileLastName()%> </div> <div style="text-align:right; float:right; color:#7D7D7D; font-weight:bold; padding-right:5px"><%=df.format(new Date())%> </div></th>
 
                             </tr>
                         </table></td>
@@ -322,7 +322,7 @@
 		// first see if we're a course in a Curriculum
 		CourseAttempt ca = courseAttempts.get(0);
 		boolean isCurriculum = curriculaList.get(ca.getCourseAttemptCourseID()) != null;
-		Integer curriculumID = isCurriculum ? ca.getCourseAttemptCourseID() : courseCurriculum.get(ca.getCourseAttemptCourseID());
+		Integer curriculumID = isCurriculum ? (Integer)ca.getCourseAttemptCourseID() : (Integer)courseCurriculum.get(ca.getCourseAttemptCourseID());
 		String html = "";
 		int startSize = courseAttempts.size();
 		// process curriculum first



