El sistema crea el contenido de la presentaci�n, lo que requiere el procesamiento de datos de negocio din�micos.
�Problema
Los cambios en la capa de presentaci�n ocurren muy frecuentemente y son dif�ciles de desarrollar y mantener cuando la l�gica de acceso a los datos de negocio y la l�gica del formateo de la presentaci�n se mezclan. Esto hace el sistema menos flexible, menos reutilizable, y generalmente menos adaptable a los cambios.
Mezclar la l�gica de negocio y de sistema con el procesamiento de la vista reduce la modularidad y tambi�n proporciona una pobre separaci�n de los roles entre los equipos de producci�n Web y de desarrollo de software.
�Causas
- Los requerimientos de asimilaci�n de datos de negocio no son triviales.
- Embeber la l�gica de negocio en la vista promueve un tipo de reutilizaci�n del tipo copiar-y-pegar. Esto causa problemas de mantenimiento y errores porque una pieza de l�gica se reutiliza en la misma vista o en otra diferente simplemente duplic�ndola en la nueva localizaci�n.
- Es deseable promover una separaci�n limpia de labores teniendo diferentes individuos cumpliendo los roles de miembros de un equipo de desarrollo de software y de producci�n Web.
- Una vista com�nmente se utiliza para responder a una petici�n de negocios particular.
�Soluci�n
Una vista contiene c�digo de formateo, delegando sus responsabilidades de procesamiento en sus clases de ayuda, implementadas como JavaBeans o etiquetas personalizadas. Las clases de ayuda o helpers tambi�n almacenan el modelo de datos intermedio de la vista y sirven como adaptadores de datos de negocio.
Hay varias estrategias para implementar el componente de la vista. La estrategia JSP View siguiere utilizar una JSP como el componente vista. Esta es la estrategia preferida, y es la que se utiliza m�s comunmente. La otra estrategia principal es la estrategia Servlet View, que utiliza un servlet como la vista.
Encapsular la l�gica de negocio en un helper en lugar de hacerlo en la vista hace que nuestra aplicaci�n sea m�s modular y facilita la reutilizaci�n de componentes. Varios clientes, como controladores y vistas, podr�an utilizar el mismo helper para recuperar y adaptar estados del modelo similares para su presentaci�n en varias vistas. La �nica forma de reutilizar la l�gica embebida en una vista es copiando y pegando en cualquier lugar. Adem�s, la duplicaci�n mediante copiar-y-pegar hace que un sistema sea dif�cil de mantener, ya que necesitamos corregir en muchos sitios el mismo error potencial.
Una se�al de que podr�amos necesitar aplicar este patr�n al c�digo existente es cuando el c�digo scriptlet domina en la vista JSP. Ya que el objetivo general cuando se aplica este patron, es el particionamiento de la l�gica de negocio fuera de la vista. Mientras alguna l�gica est� mejor cuando se encapsula dentro de objetos helper, otra l�gica est� mejor situ�ndola en un componente centralizado que se sit�a delante de las vistas y los helpers -- esta podr�a la l�gica que sea com�n entre varias peticiones, como los chequeos de autentificaci�n o servicios de logs, por ejemplo.
Si no se emplea un controlador separado en la arquitectura, o si no se utiliza para manejar todas las peticiones, entonces el componente vista se convierte en el punto de contacto inicial para manejar algunas peticiones. Para ciertas peticiones, particularmente aquellas que implican un procesamiento m�nimo, este escenario funcionar� bien. T�picamente, esta situaci�n ocurre cuando p�ginas que est�n basadas en informaci�n est�tica, como la primera de un conjunto de p�ginas que se servir�n a un usuario para obtener alguna informaci�n. .
El patr�n View Helper se enfoca en recomendar formas de particionar las responsabilidades de nuestras aplicaciones.
�Estructura
Abajo podemos observar el diagrama de clases que representa el patr�n View Helper.

�Participantes y Responsabilidades
La siguiente figura muestra el diagrama de secuencia que represetna el patr�n View Helper. Normalmente un controlador media entre el cliente y la vista. Aunque en algunos casos, no se utiliza un controlador y la vista se convierte en el punto de contacto inicial para manejar peticiones.

Como se ha podido observar en el diagrama de clases, podr�an no haber helpers asociados con una vista. En este caso simple, la p�gina podr�a ser completamente est�tica o incluir una muy peque�a cantidad de scriptles. Este escenario se describe en el siguiente diagrama de secuencia:

�View
Una vista representa y muestra informaci�n al cliente. La informaci�n que se utiliza en un display din�mico se recupera de un modelo. Los helpers soportan vistas encapsulando y adaptando un modelo para utilizarlo en un display.
�Helper
Un helper es el responsable de ayudar a la vista o al controlador a completar su procesamiento. As� los helpers tienen numerosas responsabilidades, incluyendo la obtenci�n de los datos requeridos por la vista y su almacenamiento en el modelo intermedio, en cuyo caso algunas veces nos podemos referir al helper como un Bean de Valor. Adem�s, los helpers podr�an adaptar este modelo de datos para que los utilizara la vista. Los helpers pueden servir peticiones de datos desde la vista simplemente proporcionando acceso a los datos o fomateando los datos como contenido Web.
Una vista podr�a trabajar con cualquier n�mero de helpers, que normalmente est�n implementados como JavaBeans (JSP 1.0+) y etiquetas personalizadas (JSP 1.1+). Adem�s, un helper podr�a representar un objeto Command o un Tranformador XSL, que se utiliza en combinaci�n con una hoja de estilo para adaptar y convertir el modelo en el formato apropiado.
�ValueBean
Un Bean de Valor es un otro nombre para un helper que es responsable de contener el estado del modelo intermedio para que lo utilice una vista. Un caso t�pico, es el que tiene un servicio de negocio que devuelve un bean de valor en respuesta a esta petici�n. Este caso, el Bean de valor cumple el rol de un objeto Transfer.
�BusinessService
El servicio de negocio es un rol que cumple el servicio al que est� accediendo el cliente. T�picamente, se accede al servicio de negocio mediante un Delegado de Negocio. El rol del delegado de negocio es proporcionar control y protecci�n para el servicio de negocio (podremos ver el patr�n Business Delegate m�s adelante).
�Estrategias
�JSP View
La estrategia de Vista JSP sugiere la utilizaci�n de una JSP como el componente vista. Aunque sem�nticamente equivalente a la estrategia de Vista Servlet, es una soluci�n m�s elegante y m�s utilizada. Las vistas son el dominio de los dise�adores Web, que prefieren un lenguaje de marcas al c�digo Java. El siguiente ejemplo muestra un ejemplo de c�digo para esta estrategia. El fragmento es de un fichero fuente llamado welcome.jsp, al que nos reenvia un controlador servlet despu�s de situar el JavaBean WelcomeHelper en el �mbito de la peticion:
<jsp:useBean id="welcomeHelper" scope="request"
class="corepatterns.util.WelcomeHelper" />
<HTML>
<BODY bgcolor="FFFFFF">
<% if (welcomeHelper.nameExists())
{
%>
<center><H3> Welcome <destacar>
<jsp:getProperty name="welcomeHelper" property="name" />
</destacar><br><br> </H3></center>
<%
}
%>
<H4><center>Glad you are visiting our
site!</center></H4>
</BODY>
</HTML>
La estrategia alternativa de Vista Servlet normalmente se implementa embebiendo marcas HTML directamente dentro del c�digo Java. Mezclar c�digo Java y etiquetas de marcas crea una pobre separaci�n de los roles de usuario dentro de un proyecto e incrementa las dependencias de los mismos recursos entre varios miembros de diferentes equipos. Cuando un individuo trabaja en una plantilla que contiene c�digo o etiquetas no familiares, incrementa el riesgo de que un cambio accidental introduzca problemas en el sistema. Tambi�n hay una reducci�n de la eficiencia del entorno de trabajo (demasiada gente compartiendo los mismos recursos f�sicos) y un incremento en el manejo de control de fuentes.
Estos problemas ocurren m�s frecuentemente en grandes entornos empresariales que tienen requerimientos de sistemas m�s complicados y que utilizan equipos de desarrolladores. Tiene menos probabilidades de ocurrir en peque�os sistemas que tienen sencillos requerimientos y utilizan unos pocos desarrolladores porque el mismo individuo cumple los roles mencionados arriba. Sin embargo, debemos tener en mente que los proyectos suelen empezar peque�os -- con requerimiento sencillos y unos cuantos desarrolladores -- pero finalmente evolucionan y se convierten en suficientemente sofisticados como para beneficiarse de estas sugerencias.
�Servlet View
La estrategia de Vista Servlet utiliza un servlet como la vista. Es sem�nticametne equivalente al estrategia preferida de Vista JSP. Sin embargo, la estrategia de Vista Servlet, como vemos en el ejemplo siguiente, es m�s engorrosa para los equipos de desarrollo de software y de producci�n Web porque embebe etiquetas de marcas dentro del c�digo Java. Cuando las etiquetas se mezclan con el c�digo Jaba, la plantilla de la vista es m�s dif�cil de actualizar y modificar.
public class Controller extends HttpServlet {
public void init(ServletConfig config) throws
ServletException {
super.init(config);
}
public void destroy() { }
/** Processes requests for both HTTP
* <code>GET</code> and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
*/
protected void processRequest(HttpServletRequest
request, HttpServletResponse response)
throws ServletException, java.io.IOException {
String title = "Servlet View Strategy";
try {
response.setContentType("text/html");
java.io.PrintWriter out = response.getWriter();
out.println("<html><title>"+title+"</title>");
out.println("<body>");
out.println("<h2><center>Employees List</h2>");
EmployeeDelegate delegate =
new EmployeeDelegate();
/** ApplicationResources provides a simple API
* for retrieving constants and other
* preconfigured values**/
Iterator employees = delegate.getEmployees(
ApplicationResources.getInstance().
getAllDepartments());
out.println("<table border=2>");
out.println("<tr><th>First Name</th>" +
"<th>Last Name</th>" +
"<th>Designation</th><th>Id</th></tr>");
while (employees.hasNext()) {
out.println("<tr>");
EmployeeTO emp = (EmployeeTO)employees.next();
out.println("<td>"+emp.getFirstName()+
"</td>");
out.println("<td>"+emp.getLastName()+
"</td>");
out.println("<td>"+emp.getDesignation()+
"</td>");
out.println("<td>"+emp.getId()+"</td>");
out.println("</tr>");
}
out.println("</table>");
out.println("<br><br>");
out.println("</body>");
out.println("</html>");
out.close();
}
catch (Exception e) {
LogManager.logMessage("Handle this exception",
e.getMessage() );
}
}
/** Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, java.io.IOException {
processRequest(request, response);
}
/** Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, java.io.IOException {
processRequest(request, response);
}
/** Returns a short description of the servlet. */
public String getServletInfo() {
return "Example of Servlet View. " +
"JSP View is preferable.";
}
/** dispatcher method **/
protected void dispatch(HttpServletRequest request,
HttpServletResponse response, String page)
throws javax.servlet.ServletException,
java.io.IOException {
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher(page);
dispatcher.forward(request, response);
}
}
�JavaBean Helper
El helper se implementa como un JavaBean. La utilizaci�n de helpers resulta en una separaci�n limpia de la vista y el procesamiento de negocio en una aplicaci�n, ya que la l�gica de negocio est� construida fuera de la vista y dentro del componente helper. En este caso, la l�gica de negocio se encapsula en un JavaBean, que ayuda en la recuperaci�n de contenido y adapta y almacena el modelo para usarlo en la vista.
La utilizaci�n de la estrategia JavaBean Helper requiere menos trabajo que la estrategia Custom Tag Helper, ya que los JavaBeans se construyen e integran m�s facilmente en un entorno JSP. Adem�s, incluso los desarrolaldores novatos entienden los JavaBeans. En el siguiente c�digo podemos ver un ejemplo de esta estrategia:
<jsp:useBean id="welcomeHelper" scope="request"
class="corepatterns.util.WelcomeHelper" />
<HTML>
<BODY bgcolor="FFFFFF">
<% if (welcomeHelper.nameExists())
{
%>
<center><H3> Welcome <destacar>
<jsp:getProperty name="welcomeHelper" property="name" />
</destacar><br><br> </H3></center>
<%
}
%>
<H4><center>Glad you are visiting our
site!</center></H4>
</BODY>
</HTML>
�Custom Tag Helper
El helper se implementa como una etiqueta personalizada (s�lo JSP 1.1+). La utilizaci�n de helpers resulta en una separaci�n limpia de la vista y el procesamiento de negocio en una aplicaci�n, ya que la l�gica de negocio est� construida fuera de la vista y dentro del componente helper. En este caso, la l�gica de negocio se encapsula en un componente de etiqueta personalizada, que podr�a ayudar en la recuperaci�n de contenido y adaptar el modelo para su utilizaci�n en la vista.
Usar esta estrategia requier mucho m�s trabajo que hacerlo con la estrategia JavaBean Helper, ya que el desarrollo de etiquetas personalizadas es moderadamente complicado en relaci�n al desarrollo de JavaBeans. No solo es m�s complejo el proceso de desarrollo, sino que hay mucha complejidad con respecto a la integraci�n y el manejo de las etiquetas completadas. Para utilizar esta estrategia, debemos configurar el entorno con numerosos artefactos generados, incluyendo la propia etiqueta, un descriptor de librer�a de etiquetas, y los ficheros de configuraci�n. Abajo podemos ver un fragmento de una vista JSP que utiliza esta estrategia:
<%@ taglib uri="/web-INF/corepatternstaglibrary.tld"
prefix="corepatterns" %>
<html>
<head><title>Employee List</title></head>
<body>
<div align="center">
<h3> List of employees in <corepatterns:department
attribute="id"/> department - Using Custom Tag
Helper Strategy. </h3>
<table border="1" >
<tr>
<th> First Name </th>
<th> Last Name </th>
<th> Designation </th>
<th> Employee Id </th>
<th> Tax Deductibles </th>
<th> Performance Remarks </th>
<th> Yearly Salary</th>
</tr>
<corepatterns:employeelist id="employeelist_key">
<tr>
<td><corepatterns:employee
attribute="FirstName"/> </td>
<td><corepatterns:employee
attribute= "LastName"/></td>
<td><corepatterns:employee
attribute= "Designation"/> </td>
<td><corepatterns:employee
attribute= "Id"/></td>
<td><corepatterns:employee
attribute="NoOfDeductibles"/></td>
<td><corepatterns:employee
attribute="PerformanceRemarks"/></td>
<td><corepatterns:employee
attribute="YearlySalary"/></td>
<td>
</tr>
</corepatterns:employeelist>
</table>
</div>
</body>
</html>
�Business Delegate as Helper
Los componentes helper normalmente hacen llamadas distribuidas a la capa de negocio. Sugerimos la utilizaci�n de un delegado de negocio para poder ocultar los detalles de la implementaci�n subyacente, as� como dicho helper simplemente invoca un servicio de negocio sin conocer los detalles sobre su implementaci�n f�sica y su distribuci�n.
Tanto el helper como el delegado de negocio deben implementarse como JavaBeans. As�, se podr�a combinar la noci�n del componente helper y del delegado de negocio e implementar el delegado de negocio como un tipo de helper especializado. Hay una mayor distinci�n entre un helper y un delegado de negocio: Un desarrollador que trabaja en la capa de presentaci�n escribe un componente helper, mientras que el delegado normalmente lo escribe un desarrollador que trabaja en los servicios de la capa de negocio. (Nota: El delegado tambi�n se podr�a proporcionar como una parte del marco de trabajo). As�, est� estrategia trato mucho m�s sobre qui�n escribe realmente el delegado que sobre la propia implementaci�n. Si hay alg�n solapamiento en los roles de desarrollo, entonces deberiamos considerar la utilizaci�n de esta estrategia.
/**A servlet delegates to a command object helper, as shown in the following excerpt:**/ String resultPage = command.execute(request, response); /**The command object helper uses the business delegate, which is simply implemented as another JavaBean helper, as shown in the following excerpt:**/ AccountDelegate accountDelegate = new AccountDelegate();
| Una nota sobre los Helpers: |
|---|
|
Los helpers JavaBean se utilizan para ayudar en la recuperaci�n de contenido y en el almacenamiento y adaptaci�n del modelo para la vista. Los helpers JavaBean tambi�n se utilizan frecuentemente como objetos Command. Al igual que los helpers JavaBean, los helpers de etiquetas personalizadas podr�an cumplir cualquiera de estos roles, excepto el de actuar como un objeto command. Al contrario que los helpers JavaBean, los helpers de etiquetas personalizadas est�n bien dise�ados para el control de flujo y la interacci�n con la vista. Los helpers de etiquetas personalizadas utilizados de esta forma encapsulan l�gica que de otro modo podr�a embeberse directamente dentro de la p�gina JSP como c�digo scriptlet. Otra �rea donde es preferible utilizar helpers de etiquetas personalizadas es en el formato de datos para display. Una etiqueta personalizada puede iterar sobre una colecci�n de resultados, formatear esos resultados en un tabla HTML, y embeber la tabla dentro de la vista JSP sin requerir ning�n scriptlet Java. Consideremos un ejemplo en el que le pedimos a un cliente Web alguna informaci�n de la cuenta del sistema, como se ve en la siguiente figura. ![]() Podemos ver cinco helpers en este diagrama. Los cuatro helpers JavaBean son el objeto AccountCommand, el objeto Account, el objeto AccountDAO, y AccountDetails. El �nico helper de etiqueta personalizada es el objeto TableFormatter. El controlador maneja la petici�n. Crea o busca el objeto command apropiado, que est� implementado como un helper JavaBean. En este caso, es el objeto command que procesa las peticiones de informaci�n de la cuenta. El controlador invoca al objeto Command, que le pide la informaci�n sobre la cuenta a un objeto Account. El objeto Account invoca al servicio de negocio, pid�endole estos detalles, que se devuelven en forma de un objeto Transfer implementado como un JavaBean. �Entonces, como accede el objeto Account a los servicios de negocio? Examinemos dos casos, uno sencillo y otro un poco m�s complicado. En el caso sencillo, imaginemos que un proyecto est� en fase de aproximaci�n, enfasando Enterprise JavaBeans (EJB) dentro de la capa de negocio en el tiempo. Asumamos que est�mos en el momento en que se est� accediendo a la base de datos mediante llamadas JDBC desde la capa de presentaci�n. En ese caso, el objeto Account utiliza un objeto Data Access (en p�ginas posteriores veremos este patr�n), ocultando los detalles de implementaci�n para acceder a la base de datos. El objeto Data Access sabe qu� consultas SQL son las necesarias para recuperar la informaci�n. Estos detalles est�n ocultos del resto de la aplicaci�n, reduciendo el acoplamiento y haciendo que todos los componentes sean m�s modulares y reutilizables. Este es el caso descrito en el diagrama de secuencia anterior. Cuando la arquitectura se vuelve m�s sofisticada, se introduce un EJB en la capa de negocio, entonces el objeto Data Access se reemplaza con un Business Delegate (m�s adelante veremos este patr�n), que normalmente est� escrito por los desarrolladores de servicios de negocio. El delegado oculta los detalles de implementaci�n de la b�squeda EJB, de la invocaci�n y del manejo de excepciones. Tambi�n podr�a mejorar el rendimiento proporcionando servicio de cach�. De nuevo, el objeto reduce el acoplamiento entre las capas, mejorando la reutilizaci�n y la modularidad de varios componentes. Sin importar la implementaci�n espec�fica de este objeto, su interface podr�a permanecer invariable durante esta transici�n. La siguiente figura describe este escenario despu�s de la transici�n al delegado de negocio. ![]() Ahora el objeto command tiene que manejar el objeto AccountDetails, el cual almacena antes de devolver el control al controlador. El Controller lo reenvia a la vista apropiada, llamada AccountView.jsp. Entonces la vista obtiene una combinaci�n de datos en bruto y de datos formateados de los helpers AccountDetails y TableFormatter, respectivamente. TableFormatter est� implementado como una etiqueta personalizada que pasa a trav�s de los datos en bruto y los formatea en una tabla HTML para mostrarla. Como vimos, esta conversi�n no requiere escribir nig�n scriptlet en la vista, lo que s� ser�a necesario para realizar la misma funcionalidad con un helper JavaBean. Adem�s, el objeto Account o el helper AccountDetails podr�an proporcionar m�todos convenientes para adaptar los datos en bruto a otros formatos. Aunque dichos m�todos no introducir�an etiquetas HTML en los datos, podr�an proporcionar diferentes combinaciones de datos. Un ejemplo es entregar el nombre completo del usuario en varios formatos, como "Lastname, Firstname" o "Firstname Lastname", etc. |
�Transformer Helper
El helper se implementa como un eXtensible Stylesheet Language Transformer. Esto es particularmente �til con modelos que existen como marcas estructuradas, como el lenguaje eXtensible Markup Language (XML), bien nativamente dentro de sistemas legales o mediante alguna forma de conversi�n. Utilizar esta estrategia puede ayudarnos a forzar la separaci�n entre el modelo y la vista, ya que la mayor�a de las marcas de la vista se tienen que crear en una hoja de estilos separada. La siguiente figura describe una potencial implementaci�n de esta estrategia:

El controlador maneja la petici�n e invoca al objeto Command, implementado como un helper JavaBean. El objeto Command inicia la recuperaci�n de los datos de la cuenta. El objeto Account invoca al servicio de negocio, que devuelve los datos en forma de un objeto Transfer, implementado como un JavaBean.
Se completa la recuperaci�n de contenido y el control se pasa al AccountView, que utiliza su etiqueta personalizada transformer para manipular el estado del modelo. El transformer trata con un hoja de estilo, que describe c�mo transformar el modelo, normalmente describiendo c�mo formatearlo con etiquetas para mostrarlo en el cliente. La hoja de estilo normalmente se recupera como un fichero est�tico, aunque se podr�a generar din�micamente. Aqu� tenemos un ejemplo de lo que deber�a ser la etiqueta personalizada:
<xsl:transform model="accounthelper" stylesheet="/transform/styles/basicaccount.xsl"/>
�Consecuencias
- Mejora el Particionamiento de la Aplicaci�n, la Reutilizaci�n y el Mantenimiento
Utilizar helpers resulta en una clara separaci�n de la vista del procesamiento de negocio en una aplicaci�n. Los helpers, en forma de JavaBeans (JSP 1.0+) y etiquetas personalizadas (JSP 1.1+), proporcionan un lugar externo para que la vista encapsule la l�gica de negocio. Por el contrario, el c�digo en scriptlets dentro de las p�ginas JSP, emborrona ampliamente la situaci�n, especialmente en gandes proyectos.Adem�s, la l�gica de negocio que se construye fuera de las JSPs y dentro de los JavaBeans y las etiquetas personalizadas se reutiliza, reduciendo la duplicaci�n y facilitando el mantenimiento.
- Mejora la Separaci�n de Roles
Separar la l�gica del formateo de la l�gica de negocio de la aplicaci�n reduce las dependencias podr�an tener los individuos que juegan los diferentes roles en los mismos recursos. Por ejemplo, un desarrollador de software podr�a poseer c�digo que est� embebido dentro de marcas HTML, mientras que un miembro del equipo de producci�n Web podr�a necesitar modificar la distribuci�n de la p�gina y dise�ar componentes que est�n mezclados con la l�gia de negocios. Ning�n individuo que cumpla estos roles podr�a estar familiarizado con las implementaciones espec�ficas del trabajo del otro individuo, y asi se evita el riesgo de introducir bugs mediante modificaciones accidentales del sistema.
�Patrones Relacionados
- Business Delegate
Los componentes helper necesitan m�todos de acceso al API de servicios de negocio. Tambi�n es importante reducir el acoplamiento entre helpers en la capa de presentaci�n y entre servicios de negocio en la capa de negocio. Se recomienda que se utilice un delegate porque estas capas podr�an estar distribuidas f�sicamente por la red. El delegado le oculta al clinte los detalles subyacentes de la b�squeda y acceso a los servicios de negocio, y tambi�n podr�a proporcionar un cach� intermedio para reducir el tr�fico de la red. - Dispatcher View y Service to Worker
Cuando sea deseable el control centralizado para manejar problemas como la seguridad, el control del carga de trabajo, la recuperaci�n de contenidos y la navegaci�n, debemos considerar la utilizaci�n de los patrones Dispatcher View o Service to Worker. - Front Controller
Este patr�n est� emparejado con el patr�n View Helper para crear los patrones Dispatcher View o Service to Worker.

