W3C home > Mailing lists > Public > www-validator-cvs@w3.org > August 2009

2006/unicorn/src/org/w3c/unicorn/action ObserveAction.java,1.1,1.2 IndexAction.java,1.1,1.2 TestAction.java,1.1,1.2 InitAction.java,1.1,1.2 Action.java,1.1,1.2

From: Jean-Guilhem Rouel via cvs-syncmail <cvsmail@w3.org>
Date: Fri, 28 Aug 2009 12:40:11 +0000
To: www-validator-cvs@w3.org
Message-Id: <E1Mh0kV-00065b-9F@lionel-hutz.w3.org>
Update of /sources/public/2006/unicorn/src/org/w3c/unicorn/action
In directory hutz:/tmp/cvs-serv22368/src/org/w3c/unicorn/action

Added Files:
	ObserveAction.java IndexAction.java TestAction.java 
	InitAction.java Action.java 
Log Message:
Merging dev2 in HEAD

--- NEW FILE: IndexAction.java ---
package org.w3c.unicorn.action;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;
import org.w3c.unicorn.language.Language;
import org.w3c.unicorn.util.Property;
import org.w3c.unicorn.util.Templates;
import org.w3c.unicorn.Framework;

public class IndexAction extends Action {

	private static final long serialVersionUID = 1L;
	private static Logger logger = Logger.getLogger(IndexAction.class);
	private VelocityContext velocityContext;
	
	@Override
	public void init() throws ServletException {
		super.init();
	}
	
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		
		resp.setContentType("text/html; charset=UTF-8");
		
		// Language negotiation
		String langParameter = req.getParameter(Property.get("UNICORN_PARAMETER_PREFIX") + "lang");
		if (langParameter == null || !Framework.getLanguageProperties().containsKey(langParameter))
			langParameter = Language.negociate(req.getLocales());
		
		velocityContext = new VelocityContext(Language.getContext(langParameter));
		
		String taskParameter = req.getParameter(Property.get("UNICORN_PARAMETER_PREFIX") + "task");
		if (taskParameter == null || !Framework.mapOfTask.containsKey(taskParameter))
			taskParameter = Framework.mapOfTask.getDefaultTaskId();
		
		velocityContext.put("current_task", Framework.mapOfTask.get(taskParameter));
		
		if (req.getHeader("X-Requested-With") != null && req.getHeader("X-Requested-With").equals("XMLHttpRequest")) {
			//for JavaScript testing purposes
			/*long s = System.currentTimeMillis();
			long t;
			do {
				 t = System.currentTimeMillis();
			} while ((t - s) < 3000);*/
			// -----------------
			Templates.write("parameters.vm", velocityContext, resp.getWriter());
			resp.getWriter().close();
		} else {
			Templates.write("index.vm", velocityContext, resp.getWriter());
			resp.getWriter().close();
		}
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doGet(req, resp);
	}
	
}

--- NEW FILE: InitAction.java ---
package org.w3c.unicorn.action;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.w3c.unicorn.Framework;
import org.w3c.unicorn.util.Property;

/**
 * Servlet implementation class InitAction
 */
public class InitAction extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public InitAction() {
		Framework.init();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// If PROPERTY_INIT_ACTION is not set or set to true, InitAction is only accessible from localhost.
		// If PROPERTY_INIT_ACTION is set to true, any IP can initialize Unicorn. This should not be set in production environment.
		String isProtected = Property.get("PROTECT_INIT_ACTION");
		if ((isProtected == null || isProtected.equals("true")) && (request.getRemoteAddr().equals("0:0:0:0:0:0:0:1") || request.getRemoteAddr().equals("127.0.0.1"))
				|| (isProtected != null && isProtected.equals("false"))) {
			response.setContentType("text/plain");
			PrintWriter out = response.getWriter();
			out.write("Initializing core: ");
			response.flushBuffer();
			Framework.initCore();
			
			out.write("OK\nLoading config files: ");
			response.flushBuffer();
			Framework.initConfig();
			
			out.write("OK\nInitializing unmarshallers: ");
			response.flushBuffer();
			Framework.initUnmarshallers();
			
			out.write("OK\nInitializing response parsers: ");
			response.flushBuffer();
			Framework.initResponseParsers();
			
			out.write("OK\nLoading observers: ");
			response.flushBuffer();
			Framework.initObservers();
			
			out.write("OK\nLoading tasklist: ");
			response.flushBuffer();
			Framework.initTasklists();
			
			out.write("OK\nLoading language files: ");
			response.flushBuffer();
			Framework.initLanguages();
			
			out.write("OK\nInitializing Velocity: ");
			response.flushBuffer();
			Framework.initVelocity();
			out.write("OK");
			out.close();
		}
		else
			response.sendError(403, "You are not allowed to execute this action.");
	}



}

--- NEW FILE: ObserveAction.java ---
// $Id: ObserveAction.java,v 1.2 2009/08/28 12:40:08 jean-gui Exp $
// Author: Jean-Guilhem Rouel
// (c) COPYRIGHT MIT, ERCIM and Keio, 2006.
// Please first read the full copyright statement in file COPYRIGHT.html
package org.w3c.unicorn.action;

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.w3c.unicorn.Framework;
import org.w3c.unicorn.UnicornCall;
import org.w3c.unicorn.contract.EnumInputMethod;
import org.w3c.unicorn.exceptions.NoTaskException;
import org.w3c.unicorn.language.Language;
import org.w3c.unicorn.output.OutputFactory;
import org.w3c.unicorn.output.OutputFormater;
import org.w3c.unicorn.output.OutputModule;
import org.w3c.unicorn.util.Property;

/**
 * FirstServlet<br />
 * Created: Jun 26, 2006 2:04:11 PM<br />
 * 
 * @author Jean-Guilhem ROUEL
 */
public class ObserveAction extends HttpServlet {

	private static final Log logger = LogFactory.getLog(ObserveAction.class);

	private static final long serialVersionUID = -1375355420965607571L;

	private static final DiskFileItemFactory factory = new DiskFileItemFactory();

	/**
	 * Creates a new file upload handler.
	 */
	private static final ServletFileUpload upload = new ServletFileUpload(
			ObserveAction.factory);

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.servlet.GenericServlet#init()
	 */
	@Override
	public void init(final ServletConfig aServletConfig)
			throws ServletException {
		ObserveAction.logger.trace("init");

		ObserveAction.factory.setRepository(new File(Property
				.get("UPLOADED_FILES_REPOSITORY")));

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		ObserveAction.logger.trace("doGet");

		// Language negotiation
		String langParameter = req.getParameter(Property.get("UNICORN_PARAMETER_PREFIX") + "lang");	
		if (langParameter == null || !Framework.getLanguageProperties().containsKey(langParameter))
			langParameter = Language.negociate(req.getLocales());
		
		logger.debug("Lang Parameter: " + langParameter);
		
		//velocityContext = new VelocityContext(Language.getContext(langParameter));
		
		// Variables related to the output
		final Map<String, String[]> mapOfSpecificParameter = new Hashtable<String, String[]>();
		final Map<String, String> mapOfOutputParameter = new Hashtable<String, String>();
		mapOfOutputParameter.put("output", "simple");
		mapOfOutputParameter.put("format", "xhtml10");
		mapOfOutputParameter.put("charset", "UTF-8");
		mapOfOutputParameter.put("mimetype", "text/html");
		mapOfOutputParameter.put("lang", langParameter);
		
		final UnicornCall aUnicornCall = new UnicornCall();
		final String aLocale = convertEnumerationToString(req.getLocales());
		if (null == aLocale) {
			aUnicornCall.setLang(langParameter + "," + Property.get("DEFAULT_LANGUAGE"));
		} else {
			aUnicornCall.setLang(langParameter + "," + aLocale);
		}

		for (final Enumeration<?> aEnumParamName = req
				.getParameterNames(); aEnumParamName.hasMoreElements();) {
			final String sParamName = (String) aEnumParamName.nextElement();
			final String[] tStringParamValue = req
					.getParameterValues(sParamName);

			this.addParameter(sParamName, tStringParamValue, aUnicornCall,
					mapOfSpecificParameter, mapOfOutputParameter);
		} // For

		if (aUnicornCall.getTask() == null) {
			ObserveAction.logger.error("No task selected.");
			this.createError(resp, new NoTaskException(),
					mapOfSpecificParameter, mapOfOutputParameter);
			return;
		}

		try {
			aUnicornCall.doTask();

			this.createOutput(resp, aUnicornCall,
					mapOfSpecificParameter, mapOfOutputParameter);
		} catch (final Exception aException) {
			ObserveAction.logger.error("Exception : " + aException.getMessage(),
					aException);
			this.createError(resp, aException,
					mapOfSpecificParameter, mapOfOutputParameter);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doPost(final HttpServletRequest req,
			final HttpServletResponse resp)
			throws ServletException, IOException {
		ObserveAction.logger.trace("doPost");
		
		// Check that we have a file upload request
		final boolean bIsMultipart = ServletFileUpload.isMultipartContent(new ServletRequestContext(req));

		if (!bIsMultipart) {
			this.doGet(req, resp);
			return;
		}
		
		// Language negotiation
		String langParameter = req.getParameter(Property.get("UNICORN_PARAMETER_PREFIX") + "lang");
		if (langParameter == null || !Framework.getLanguageProperties().containsKey(langParameter))
			langParameter = Language.negociate(req.getLocales());
		
		// Variables related to the output
		final Map<String, String> mapOfOutputParameter = new Hashtable<String, String>();
		mapOfOutputParameter.put("output", "simple");
		mapOfOutputParameter.put("format", "xhtml10");
		mapOfOutputParameter.put("charset", "UTF-8");
		mapOfOutputParameter.put("mimetype", "text/html");
		mapOfOutputParameter.put("lang", langParameter);
		
		final UnicornCall aUnicornCall = new UnicornCall();
		final String aLocale = convertEnumerationToString(req.getLocales());
		if (null == aLocale) {
			aUnicornCall.setLang(langParameter + "," + Property.get("DEFAULT_LANGUAGE"));
		} else {
			aUnicornCall.setLang(langParameter + "," + aLocale);
		}
		
		// Parse the request
		final List<?> listOfItem;

		ObserveAction.logger.trace("doPost");

		final Map<String, String[]> mapOfSpecificParameter = new Hashtable<String, String[]>();

		FileItem aFileItemUploaded = null;

		try {
			listOfItem = ObserveAction.upload.parseRequest(req);

			// Process the uploaded items
			for (final Iterator<?> aIterator = listOfItem.iterator(); aIterator
					.hasNext();) {
				final FileItem aFileItem = (FileItem) aIterator.next();
				if (aFileItem.isFormField()) {

					addParameter(aFileItem.getFieldName(), aFileItem
							.getString(), aUnicornCall, mapOfSpecificParameter,
							mapOfOutputParameter);

				} else if (aFileItem.getFieldName().equals(
						Property.get("UNICORN_PARAMETER_PREFIX") + "file")) {
					aFileItemUploaded = aFileItem;
					aUnicornCall.setDocumentName(aFileItemUploaded.getName());
					aUnicornCall.setInputParameterValue(aFileItemUploaded);
					aUnicornCall.setEnumInputMethod(EnumInputMethod.UPLOAD);
				}
			}
		}

		catch (final FileUploadException aFileUploadException) {
			ObserveAction.logger.error("FileUploadException : "
					+ aFileUploadException.getMessage(), aFileUploadException);
			this.createError(resp, aFileUploadException,
					mapOfSpecificParameter, mapOfOutputParameter);
		}

		try {
			aUnicornCall.doTask();

			this.createOutput(resp, aUnicornCall,
					mapOfSpecificParameter, mapOfOutputParameter);
		} catch (final Exception aException) {
			ObserveAction.logger.error("Exception : " + aException.getMessage(),
					aException);
			this.createError(resp, aException,
					mapOfSpecificParameter, mapOfOutputParameter);
		} finally {
			if ("true".equals(Property.get("DELETE_UPLOADED_FILES"))
					&& aFileItemUploaded != null
					&& aFileItemUploaded instanceof FileItem) {
				aFileItemUploaded.delete();
			}
		}
	}

	/**
	 * Adds a parameter at the correct call.
	 * 
	 * @param sParamName
	 *            Name of the parameter.
	 * @param sParamValue
	 *            Value of the parameter.
	 * @param aUnicornCall
	 * @param mapOfSpecificParameter
	 * @param mapOfOutputParameter
	 */
	private void addParameter(final String sParamName,
			final String sParamValue, final UnicornCall aUnicornCall,
			final Map<String, String[]> mapOfSpecificParameter,
			final Map<String, String> mapOfOutputParameter) {
		final String[] tStringValues = { sParamValue };
		this.addParameter(sParamName, tStringValues, aUnicornCall,
				mapOfSpecificParameter, mapOfOutputParameter);
	}

	/**
	 * 
	 * @param sParamName
	 * @param tStringParamValue
	 * @param aUnicornCall
	 * @param mapOfSpecificParameter
	 * @param mapOfOutputParameter
	 */
	private void addParameter(String sParamName,
			final String[] tStringParamValue, final UnicornCall aUnicornCall,
			final Map<String, String[]> mapOfSpecificParameter,
			final Map<String, String> mapOfOutputParameter) {

		if (null == tStringParamValue || 0 == tStringParamValue.length) {
			// no value for this parameter
			// TODO log this info if necessary
			return;
		}

		if (!sParamName.startsWith(Property.get("UNICORN_PARAMETER_PREFIX"))) {
			// task parameter
			aUnicornCall.addParameter(sParamName, tStringParamValue);
			return;
		}

		// Unicorn parameter
		// TODO: Why is it here?
		sParamName = sParamName.substring(Property.get(
				"UNICORN_PARAMETER_PREFIX").length());

		// Output specific parameter
		if (sParamName.startsWith(Property
				.get("UNICORN_PARAMETER_OUTPUT_PREFIX"))) {
			sParamName = sParamName.substring(Property.get(
					"UNICORN_PARAMETER_OUTPUT_PREFIX").length());
			mapOfSpecificParameter.put(sParamName, tStringParamValue);
			return;
		}

		if (sParamName.equals("lang")) {
			aUnicornCall.addParameter(Property.get("UNICORN_PARAMETER_PREFIX")
					+ "lang", tStringParamValue);
		}

		// Global Unicorn parameter
		if (sParamName.equals("task")) {
			// FirstServlet.logger.debug("");
			aUnicornCall.setTask(tStringParamValue[0]);
		} else if (sParamName.equals("uri")) {
			aUnicornCall.setEnumInputMethod(EnumInputMethod.URI);
			// TODO First check that tStringParamValue[0] is at least 7 characters long
			if (tStringParamValue[0].length() < 7 || !tStringParamValue[0].substring(0, 7).equals("http://")) {
				ObserveAction.logger.info("URI missing protocol : "
						+ tStringParamValue[0]);
				tStringParamValue[0] = "http://" + tStringParamValue[0];
				ObserveAction.logger.info("URI modified to : "
						+ tStringParamValue[0]);
			}
			
			

			aUnicornCall.setDocumentName(tStringParamValue[0]);
			aUnicornCall.setInputParameterValue(tStringParamValue[0]);
		} else if (sParamName.equals("text")) {
			aUnicornCall.setEnumInputMethod(EnumInputMethod.DIRECT);
			aUnicornCall.setInputParameterValue(tStringParamValue[0]);
		}
		// TODO add upload handle when it work
		else if (sParamName.equals("output") || sParamName.equals("format")
				|| sParamName.equals("charset")
				|| sParamName.equals("mimetype") || sParamName.equals("lang")) {
			mapOfOutputParameter.put(sParamName, tStringParamValue[0]);
		} else if (sParamName.equals("text_mime")) {
			aUnicornCall.addParameter(Property.get("UNICORN_PARAMETER_PREFIX")
					+ "mime", tStringParamValue);
		}
	}

	private void createError(final HttpServletResponse aHttpServletResponse,
			final Exception aExceptionError,
			final Map<String, String[]> mapOfSpecificParameter,
			final Map<String, String> mapOfOutputParameter) throws IOException {
		aHttpServletResponse.setContentType(mapOfOutputParameter
				.get("mimetype")
				+ "; charset=" + mapOfOutputParameter.get("charset"));

		try {
			final OutputFormater aOutputFormater = OutputFactory
					.getOutputFormater(mapOfOutputParameter.get("format"),
							mapOfOutputParameter.get("lang"),
							mapOfOutputParameter.get("mimetype"));
			final OutputModule aOutputModule = OutputFactory
					.getOutputModule(mapOfOutputParameter.get("output"));
			aOutputModule.produceError(aOutputFormater, aExceptionError,
					mapOfSpecificParameter, aHttpServletResponse.getWriter());
		} catch (final ResourceNotFoundException e) {
			ObserveAction.logger.error("ResourceNotFoundException : "
					+ e.getMessage(), e);
			aHttpServletResponse.getWriter().println("<pre>");
			e.printStackTrace(aHttpServletResponse.getWriter());
			aHttpServletResponse.getWriter().println("</pre>");
		} catch (final ParseErrorException e) {
			ObserveAction.logger.error(
					"ParseErrorException : " + e.getMessage(), e);
			aHttpServletResponse.getWriter().println("<pre>");
			e.printStackTrace(aHttpServletResponse.getWriter());
			aHttpServletResponse.getWriter().println("</pre>");
		} catch (final Exception e) {
			ObserveAction.logger.error("Exception : " + e.getMessage(), e);
			aHttpServletResponse.getWriter().println("<pre>");
			e.printStackTrace(aHttpServletResponse.getWriter());
			aHttpServletResponse.getWriter().println("</pre>");
		}
	}

	private void createOutput(final HttpServletResponse aHttpServletResponse,
			final UnicornCall aUnicornCall,
			final Map<String, String[]> mapOfSpecificParameter,
			final Map<String, String> mapOfOutputParameter) throws IOException {
		aHttpServletResponse.setContentType(mapOfOutputParameter
				.get("mimetype")
				+ "; charset=" + mapOfOutputParameter.get("charset"));
		try {
			Map<String, Object> mapOfStringObject = new LinkedHashMap<String, Object>();
			mapOfStringObject.put("unicorncall", aUnicornCall);

			logger.debug("Request output formater with parameters: " 
					+ mapOfOutputParameter.get("format") + " "
					+ mapOfOutputParameter.get("lang") + " "
					+ mapOfOutputParameter.get("mimetype"));
			
			final OutputFormater aOutputFormater = OutputFactory
					.getOutputFormater(mapOfOutputParameter.get("format"),
							mapOfOutputParameter.get("lang"),
							mapOfOutputParameter.get("mimetype"));
			final OutputModule aOutputModule = OutputFactory
					.getOutputModule(mapOfOutputParameter.get("output"));
			aOutputModule.produceOutput(aOutputFormater, mapOfStringObject,
					mapOfSpecificParameter, aHttpServletResponse.getWriter());
		}

		catch (final ResourceNotFoundException e) {
			ObserveAction.logger.error("ResourceNotFoundException : "
					+ e.getMessage(), e);
			aHttpServletResponse.getWriter().println("<pre>");
			e.printStackTrace(aHttpServletResponse.getWriter());
			aHttpServletResponse.getWriter().println("</pre>");
		} catch (final ParseErrorException e) {
			ObserveAction.logger.error(
					"ParseErrorException : " + e.getMessage(), e);
			aHttpServletResponse.getWriter().println("<pre>");
			e.printStackTrace(aHttpServletResponse.getWriter());
			aHttpServletResponse.getWriter().println("</pre>");
		} catch (final Exception e) {
			ObserveAction.logger.error("Exception : " + e.getMessage(), e);
			aHttpServletResponse.getWriter().println("<pre>");
			e.printStackTrace(aHttpServletResponse.getWriter());
			aHttpServletResponse.getWriter().println("</pre>");
		}
	}

	/**
	 * Converts an Enumeration object to a string, the terms being separated by
	 * a coma.
	 * 
	 * @param myEnum
	 *            The enumeration to convert.
	 * @return The converted string.
	 */
	private String convertEnumerationToString(Enumeration<?> myEnum) {
		String ret = "";
		while (myEnum.hasMoreElements()) {
			ret += myEnum.nextElement().toString() + ",";
		}
		return ret.substring(0, ret.length() - 1);
	}

}

--- NEW FILE: Action.java ---
package org.w3c.unicorn.action;

import javax.servlet.http.HttpServlet;

public abstract class Action extends HttpServlet {
	
	private static final long serialVersionUID = 1L;

}

--- NEW FILE: TestAction.java ---
package org.w3c.unicorn.action;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.velocity.VelocityContext;
import org.w3c.unicorn.Framework;
import org.w3c.unicorn.language.Language;
import org.w3c.unicorn.util.Property;

/**
 * Servlet implementation class TestAction
 */
public class TestAction extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	
	private VelocityContext velocityContext;
    /**
     * @see HttpServlet#HttpServlet()
     */
    public TestAction() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		PrintWriter out = resp.getWriter();
		
		for (String key : Framework.mapOfTask.keySet()) {
			out.println(Framework.mapOfTask.get(key));
			
			
		}
		Enumeration en = req.getHeaderNames();
		while(en.hasMoreElements()) {
			out.println(en.nextElement());
		}
		
		/*resp.setContentType("text/html; charset=UTF-8");
		
		// Language negotiation
		
		velocityContext = new VelocityContext();
		
		velocityContext.put("task", Framework.mapOfTask.get("conformance"));
		
		Framework.getTemplate("parameters").merge(velocityContext, resp.getWriter());
		resp.getWriter().close();*/
		
	}

}
Received on Friday, 28 August 2009 12:40:21 UTC

This archive was generated by hypermail 2.3.1 : Wednesday, 7 January 2015 15:17:38 UTC