r1981 - in trunk: wao-persistence/src/main/java/fr/ifremer/wao/entity wao-services/src/main/java/fr/ifremer/wao/services/service wao-services/src/main/resources/i18n wao-web/src/main/resources/fr/ifremer/wao/services/service wao-web/src/main/resources/i18n wao-web/src/main/webapp/WEB-INF/content/obsmer
Author: bleny Date: 2014-05-27 11:34:43 +0200 (Tue, 27 May 2014) New Revision: 1981 Url: http://forge.codelutin.com/projects/wao/repository/revisions/1981 Log: refs #4493 add boardings counts Modified: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ContactTopiaDao.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSynthesis.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/SynthesisService.java trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties trunk/wao-web/src/main/resources/fr/ifremer/wao/services/service/ObsMerSynthesis-conversion.properties trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/synthesis.jsp Modified: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ContactTopiaDao.java =================================================================== --- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ContactTopiaDao.java 2014-05-27 08:04:11 UTC (rev 1980) +++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ContactTopiaDao.java 2014-05-27 09:34:43 UTC (rev 1981) @@ -36,10 +36,15 @@ import org.nuiton.topia.persistence.pager.TopiaPagerBean; import org.nuiton.util.PagerBeanUtil; +import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; @@ -49,7 +54,7 @@ public List<Contact> findAll(ContactsFilter filter, boolean sort) { - HqlAndParametersBuilder<Contact> query = toSampleRowHqlAndParametersBuilder(filter); + HqlAndParametersBuilder<Contact> query = toContactHqlAndParametersBuilder(filter); if (sort) { if (filter.isSortedByBoardingDate()) { @@ -67,7 +72,7 @@ public List<Contact> find(ContactsFilter filter, TopiaPagerBean pager) { - HqlAndParametersBuilder<Contact> query = toSampleRowHqlAndParametersBuilder(filter); + HqlAndParametersBuilder<Contact> query = toContactHqlAndParametersBuilder(filter); // Note: pager alrady contains the sort List<Contact> boats = find(query.getHql(), query.getHqlParameters(), pager); @@ -76,7 +81,7 @@ public long count(ContactsFilter filter) { - HqlAndParametersBuilder<Contact> query = toSampleRowHqlAndParametersBuilder(filter); + HqlAndParametersBuilder<Contact> query = toContactHqlAndParametersBuilder(filter); long count = count("select count(topiaId) " + query.getHql(), query.getHqlParameters()); @@ -87,7 +92,7 @@ int pageSize, int pageIndex) { - HqlAndParametersBuilder<Contact> query = toSampleRowHqlAndParametersBuilder(filter); + HqlAndParametersBuilder<Contact> query = toContactHqlAndParametersBuilder(filter); TopiaPagerBean pager = newPager(query.getHql(), query.getHqlParameters(), pageSize); pager.setPageIndex(pageIndex); @@ -102,7 +107,7 @@ return pager; } - protected HqlAndParametersBuilder<Contact> toSampleRowHqlAndParametersBuilder(ContactsFilter filter) { + protected HqlAndParametersBuilder<Contact> toContactHqlAndParametersBuilder(ContactsFilter filter) { HqlAndParametersBuilder<Contact> query = newHqlAndParametersBuilder(); @@ -234,7 +239,7 @@ public SortedMap<Date, Integer> getActualObservationsByMonths(Date periodFromMonth, Date periodToMonth, ContactsFilter filter) { - HqlAndParametersBuilder<Contact> query = toSampleRowHqlAndParametersBuilder(filter); + HqlAndParametersBuilder<Contact> query = toContactHqlAndParametersBuilder(filter); query.addEquals(Contact.PROPERTY_STATE, ContactState.OBSERVATION_DONE.ordinal()); List<Contact> contacts = findAll(query.getHql(), query.getHqlParameters()); @@ -257,4 +262,60 @@ return actualObservationsMyMonths; } + + public Map<Boat, LinkedHashMap<String, List<Date>>> getBoardingBoats(ContactsFilter filter) { + + HqlAndParametersBuilder<Contact> hqlAndParametersBuilder = toContactHqlAndParametersBuilder(filter); + + hqlAndParametersBuilder.addEquals(Contact.PROPERTY_STATE, ContactState.OBSERVATION_DONE.ordinal()); + hqlAndParametersBuilder.addLowerOrEquals(Contact.PROPERTY_SAMPLE_ROW + "." + SampleRow.PROPERTY_AVERAGE_TIDE_TIME, 2.); + hqlAndParametersBuilder.setOrderByArguments("boat.name", "sampleRow.code", "observationBeginDate"); + + String hql = hqlAndParametersBuilder.getHql(); + + hql = "select c.boat, c.sampleRow.code, c.observationBeginDate " + hql; + + List<Object[]> boardingsByBoat = findAll(hql, hqlAndParametersBuilder.getHqlParameters()); + + if (log.isDebugEnabled()) { + for (Object[] row : boardingsByBoat) { + log.debug("result in boardingsByBoat " + Arrays.toString(row)); + } + } + + // results like (first column is a boat entity) + // [AN TUAZ COZ, 2010_0043, 2009-11-19 00:00:00.0] + // [AN TUAZ COZ, 2010_0043, 2009-11-20 00:00:00.0] + // [APHRODITE, 2009_0185, 2009-09-24 00:00:00.0] + // [APHRODITE, 2009_0186, 2009-05-26 00:00:00.0] + // [APHRODITE, 2009_0186, 2009-06-23 00:00:00.0] + // [APHRODITE, 2009_0186, 2009-07-23 00:00:00.0] + // [ARC EN CIEL, 2009_0172, 2009-09-23 00:00:00.0] + // [ARC EN CIEL, 2009_0200, 2010-01-16 00:00:00.0] + // [ARC EN CIEL, 2009_0200, 2010-01-17 00:00:00.0] + // [ARC EN CIEL, 2009_0200, 2010-02-13 00:00:00.0] + + Map<Boat, LinkedHashMap<String, List<Date>>> data = new HashMap<>(); + + for (Object[] row : boardingsByBoat) { + Boat boat = (Boat) row[0]; + String sampleRowCode = (String) row[1]; + Date tideBeginDate = (Date) row[2]; + + LinkedHashMap<String, List<Date>> value = data.get(boat); + if (value == null) { + value = new LinkedHashMap<>(); + data.put(boat, value); + } + + List<Date> dates = value.get(sampleRowCode); + if (dates == null) { + dates = new LinkedList<Date>(); + value.put(sampleRowCode, dates); + } + dates.add(tideBeginDate); + } + + return data; + } } Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSynthesis.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSynthesis.java 2014-05-27 08:04:11 UTC (rev 1980) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSynthesis.java 2014-05-27 09:34:43 UTC (rev 1981) @@ -1,16 +1,77 @@ package fr.ifremer.wao.services.service; +import fr.ifremer.wao.entity.Boat; import fr.ifremer.wao.services.utils.BarChartData; public class ObsMerSynthesis { protected BarChartData expectedVsActualObservationsByMonthsBarChartData; + protected BarChartData boardingBoatsBarChartData; + + protected int maxBoardingValue; + + protected Boat maxBoardingBoat; + + protected int boardingsCount; + + protected int invalidBoardingsCount; + + protected int validBoardingsCount; + + public BarChartData getExpectedVsActualObservationsByMonthsBarChartData() { + return expectedVsActualObservationsByMonthsBarChartData; + } + public void setExpectedVsActualObservationsByMonthsBarChartData(BarChartData expectedVsActualObservationsByMonthsBarChartData) { this.expectedVsActualObservationsByMonthsBarChartData = expectedVsActualObservationsByMonthsBarChartData; } - public BarChartData getExpectedVsActualObservationsByMonthsBarChartData() { - return expectedVsActualObservationsByMonthsBarChartData; + public BarChartData getBoardingBoatsBarChartData() { + return boardingBoatsBarChartData; } + + public void setBoardingBoatsBarChartData(BarChartData boardingBoatsBarChartData) { + this.boardingBoatsBarChartData = boardingBoatsBarChartData; + } + + public int getMaxBoardingValue() { + return maxBoardingValue; + } + + public void setMaxBoardingValue(int maxBoardingValue) { + this.maxBoardingValue = maxBoardingValue; + } + + public Boat getMaxBoardingBoat() { + return maxBoardingBoat; + } + + public void setMaxBoardingBoat(Boat maxBoardingBoat) { + this.maxBoardingBoat = maxBoardingBoat; + } + + public int getBoardingsCount() { + return boardingsCount; + } + + public void setBoardingsCount(int boardingsCount) { + this.boardingsCount = boardingsCount; + } + + public int getInvalidBoardingsCount() { + return invalidBoardingsCount; + } + + public void setInvalidBoardingsCount(int invalidBoardingsCount) { + this.invalidBoardingsCount = invalidBoardingsCount; + } + + public int getValidBoardingsCount() { + return validBoardingsCount; + } + + public void setValidBoardingsCount(int validBoardingsCount) { + this.validBoardingsCount = validBoardingsCount; + } } Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/SynthesisService.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/SynthesisService.java 2014-05-27 08:04:11 UTC (rev 1980) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/SynthesisService.java 2014-05-27 09:34:43 UTC (rev 1981) @@ -2,8 +2,10 @@ import fr.ifremer.wao.ContactsFilter; import fr.ifremer.wao.WaoUtils; +import fr.ifremer.wao.entity.Boat; import fr.ifremer.wao.entity.ContactTopiaDao; import fr.ifremer.wao.entity.SampleRowTopiaDao; +import fr.ifremer.wao.entity.SynthesisId; import fr.ifremer.wao.services.AuthenticatedWaoUser; import fr.ifremer.wao.services.utils.BarChartData; import fr.ifremer.wao.services.utils.ChartDataAxis; @@ -11,9 +13,12 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.i18n.I18n; +import org.nuiton.util.DateUtil; import java.util.Calendar; import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.SortedMap; @@ -36,9 +41,10 @@ ObsMerSynthesis obsMerSynthesis = new ObsMerSynthesis(); - BarChartData expectedVsActualObservationsByMonthsBarChartData = getExpectedVsActualObservationsByMonthsBarChartData(filter); - obsMerSynthesis.setExpectedVsActualObservationsByMonthsBarChartData(expectedVsActualObservationsByMonthsBarChartData); + setExpectedVsActualObservationsByMonthsBarChartData(obsMerSynthesis, filter); + setBoardingBoatsData(obsMerSynthesis, filter); + return obsMerSynthesis; } @@ -47,7 +53,7 @@ * Un graphique avec, pour chaque mois, deux barres qui représentent l'effort demandé * vs l'effort réalisé. */ - protected BarChartData getExpectedVsActualObservationsByMonthsBarChartData(ContactsFilter filter) { + protected void setExpectedVsActualObservationsByMonthsBarChartData(ObsMerSynthesis obsMerSynthesis, ContactsFilter filter) { Locale locale = serviceContext.getLocale(); @@ -94,7 +100,8 @@ actualObservationsMyMonthsBarChartDataSeries.addValue(tick, value); } - BarChartData expectedVsActualObservationsByMonthsBarChartData = new BarChartData(""); + BarChartData expectedVsActualObservationsByMonthsBarChartData = + new BarChartData(I18n.l(locale, SynthesisId.GRAPH_SAMPLING.getI18nKey())); ChartDataAxis yAxis = expectedVsActualObservationsByMonthsBarChartData.getYAxis(); yAxis.setLabel(I18n.l(locale, "wao.synthesis.observationsCount")); @@ -103,7 +110,124 @@ expectedVsActualObservationsByMonthsBarChartData.addDotChartDataSeries(expectedObservationsByMonthsBarChartDataSeries); expectedVsActualObservationsByMonthsBarChartData.addDotChartDataSeries(actualObservationsMyMonthsBarChartDataSeries); - return expectedVsActualObservationsByMonthsBarChartData; + obsMerSynthesis.setExpectedVsActualObservationsByMonthsBarChartData(expectedVsActualObservationsByMonthsBarChartData); } + + /** + * We need to select the boats and for each one, the number of boardings + * done. The number of boardings is calculated with the number of contacts + * finished linked with each boat. The {@code fromDate} is used to filter + * results since this date. For observer view, only results for his + * company is needed. + * + * @return a BoardingResult which contains the number of boats for boardings + * and for invalid boardings from 1 to {@code MAX_BOARDINGS}, the boat with + * the max boarding and its value. + */ + protected void setBoardingBoatsData(ObsMerSynthesis obsMerSynthesis, ContactsFilter filter) { + + Locale locale = serviceContext.getLocale(); + + ContactTopiaDao dao = getContactDao(); + + Map<Boat, LinkedHashMap<String, List<Date>>> data = dao.getBoardingBoats(filter); + + Map<String, Integer> mapBoarding = new LinkedHashMap<>(); + + // Prepare map which contains for each entry the number of boardings + // for the key and the number of boats for the value. + + int maxBoardingCount = -1; + Boat maxBoardingBoat = null; + + int invalidBoardingTotal = 0; + int boardingTotal = 0; + + for (Map.Entry<Boat, LinkedHashMap<String, List<Date>>> entry : data.entrySet()) { + Boat boat = entry.getKey(); + LinkedHashMap<String, List<Date>> codesAndTides = entry.getValue(); + + if (log.isDebugEnabled()) { + StringBuilder logMessage = new StringBuilder(); + logMessage.append("in data, for boat ").append(boat.getName()).append(" tides are :"); + for (Map.Entry<String, List<Date>> codeAndTides : codesAndTides.entrySet()) { + logMessage.append(codeAndTides.getKey()).append(" -> ").append(codeAndTides.getValue()); + } + log.debug(logMessage.toString()); + } + + int boardingCount = 0; + int invalidBoardingCount = 0; + + for (Map.Entry<String, List<Date>> codeAndTides : codesAndTides.entrySet()) { + List<Date> tides = codeAndTides.getValue(); + + boardingCount += tides.size(); + + Date lastTideBeginDate = null; + for (Date tideBeginDate : tides) { + + if (lastTideBeginDate != null && // prevent NPE for first iteration + DateUtil.getDifferenceInMonths(lastTideBeginDate, tideBeginDate) <= 3) { + + invalidBoardingCount += 1; + } + + lastTideBeginDate = tideBeginDate; + } + } + + invalidBoardingTotal += invalidBoardingCount; + boardingTotal += boardingCount; + + // update max + if (boardingCount > maxBoardingCount) { + maxBoardingCount = boardingCount; + maxBoardingBoat = boat; + } + + // update mapBoarding + String key = String.valueOf(boardingCount); + + Integer oldValue = mapBoarding.get(key); + if (oldValue == null) { + oldValue = 0; + } + // add one more boat for "key" number of boardings + mapBoarding.put(key, oldValue + 1); + + if (log.isTraceEnabled()) { + log.trace(boat + " made " + boardingCount + " boardings"); + log.trace("boat " + boat.getName() + " did " + invalidBoardingCount + + " invalid boardings on " + boardingCount); + } + } + + BarChartData.BarChartDataSeries numberOfBoatsWithBoardingsBarChartDataSeries = + new BarChartData.BarChartDataSeries(); + numberOfBoatsWithBoardingsBarChartDataSeries.setLabel(I18n.l(locale, "wao.ui.chart.numberOfBoatsWithBoardings")); + + for (Map.Entry<String, Integer> entry : mapBoarding.entrySet()) { + numberOfBoatsWithBoardingsBarChartDataSeries.addValue(entry.getKey(), entry.getValue()); + } + + BarChartData boardingBoatsBarChartData = + new BarChartData(I18n.l(locale, SynthesisId.GRAPH_BOARDING.getI18nKey())); + + ChartDataAxis yAxis = boardingBoatsBarChartData.getYAxis(); + yAxis.setLabel(I18n.l(locale, "wao.ui.chart.numberBoats")); + yAxis.setStep(10); + + boardingBoatsBarChartData.addDotChartDataSeries(numberOfBoatsWithBoardingsBarChartDataSeries); + + obsMerSynthesis.setMaxBoardingValue(maxBoardingCount); + obsMerSynthesis.setMaxBoardingBoat(maxBoardingBoat); + obsMerSynthesis.setBoardingsCount(boardingTotal); + obsMerSynthesis.setInvalidBoardingsCount(invalidBoardingTotal); + obsMerSynthesis.setValidBoardingsCount(boardingTotal - invalidBoardingTotal); + + obsMerSynthesis.setBoardingBoatsBarChartData(boardingBoatsBarChartData); + + } } Modified: trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties =================================================================== --- trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties 2014-05-27 08:04:11 UTC (rev 1980) +++ trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties 2014-05-27 09:34:43 UTC (rev 1981) @@ -87,5 +87,7 @@ wao.synthesis.estimated=Estimated wao.synthesis.observationsCount=Observations count wao.synthesis.planned=Planned +wao.ui.chart.numberBoats=Number of boats +wao.ui.chart.numberOfBoatsWithBoardings=Number of boats with x boardings wao.validation.sampleRow.conflictOnObserver=Observer %s cannot be associated to the line %s because he has to observer, on the same day, for row %s wao.validation.sampleRow.observerNotInCompany=Observer %s doesn't work for company %s Modified: trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties =================================================================== --- trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties 2014-05-27 08:04:11 UTC (rev 1980) +++ trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties 2014-05-27 09:34:43 UTC (rev 1981) @@ -84,5 +84,7 @@ wao.synthesis.estimated=Estimé wao.synthesis.observationsCount=Nombre d'observations wao.synthesis.planned=Planifié +wao.ui.chart.numberBoats=Nombre de navires +wao.ui.chart.numberOfBoatsWithBoardings=Nombres de navires avec x embarquements wao.validation.sampleRow.conflictOnObserver=L'observateur %s ne peut être associé à la ligne %s car il doit observer, le même jour, pour la ligne %s wao.validation.sampleRow.observerNotInCompany=L'observateur %s ne fait pas parti de la société %s Modified: trunk/wao-web/src/main/resources/fr/ifremer/wao/services/service/ObsMerSynthesis-conversion.properties =================================================================== --- trunk/wao-web/src/main/resources/fr/ifremer/wao/services/service/ObsMerSynthesis-conversion.properties 2014-05-27 08:04:11 UTC (rev 1980) +++ trunk/wao-web/src/main/resources/fr/ifremer/wao/services/service/ObsMerSynthesis-conversion.properties 2014-05-27 09:34:43 UTC (rev 1981) @@ -1 +1,2 @@ expectedVsActualObservationsByMonthsBarChartData=fr.ifremer.wao.web.converter.BarChartDataConverter +boardingBoatsBarChartData=fr.ifremer.wao.web.converter.BarChartDataConverter Modified: trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties =================================================================== --- trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-05-27 08:04:11 UTC (rev 1980) +++ trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-05-27 09:34:43 UTC (rev 1981) @@ -120,10 +120,6 @@ wao.ui.cartography.help=Click on the graphs to get the details. wao.ui.cartography.title=Dispatching of the contacts among boat districts wao.ui.cartography.title.company=Dispatching of the contacts among boat districts for company %s -wao.ui.chart.boardingsSince=Queries since %s -wao.ui.chart.numberBoats=No. boats -wao.ui.chart.numberObservations=No. observations -wao.ui.chart.numberOfBoatsWithBoardings=Number of boats with x observations wao.ui.chooseUserProfile=Choose your user profile wao.ui.contact.creation=Creation of a contact wao.ui.contact.edition=Edition of contact Modified: trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties =================================================================== --- trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-05-27 08:04:11 UTC (rev 1980) +++ trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-05-27 09:34:43 UTC (rev 1981) @@ -120,10 +120,6 @@ wao.ui.cartography.help=Cliquez sur les graphiques pour avoir le détail. wao.ui.cartography.title=Répartition des contacts par quartier des navires wao.ui.cartography.title.company=Répartition des contacts par quartier des navires pour la société %s -wao.ui.chart.boardingsSince=Nombre de sollicitations depuis le %s -wao.ui.chart.numberBoats=Nb navires -wao.ui.chart.numberObservations=Nb observations -wao.ui.chart.numberOfBoatsWithBoardings=Nombre de navires avec x embarquements wao.ui.chooseUserProfile=Choisissez votre rôle wao.ui.contact.creation=Création d'un contact wao.ui.contact.edition=Modification du contact Modified: trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/synthesis.jsp =================================================================== --- trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/synthesis.jsp 2014-05-27 08:04:11 UTC (rev 1980) +++ trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/synthesis.jsp 2014-05-27 09:34:43 UTC (rev 1981) @@ -46,6 +46,7 @@ $(document).ready(function() { $.jqplot('expected-vs-actual-observations-by-months-chart', <s:property value="synthesis.expectedVsActualObservationsByMonthsBarChartData" escapeHtml="false"/>); + $.jqplot('boarding-boats-chart', <s:property value="synthesis.boardingBoatsBarChartData" escapeHtml="false"/>); }); @@ -62,5 +63,64 @@ <div id="expected-vs-actual-observations-by-months-chart" class="chart"></div> </article> + <article> + <h2> + <s:text name="SynthesisId.GRAPH_BOARDING"/> + </h2> + <div id="boarding-boats-chart" class="chart"></div> + + <p> + <s:text name="wao.ui.synthesis.boarding.description"/> + </p> + + <p> + <s:text name="wao.ui.synthesis.boarding.mostUsedBoat"> + <s:param value="%{synthesis.maxBoardingValue}"/> + <s:param value="%{synthesis.maxBoardingBoat.name}"/> + <s:param value="%{synthesis.maxBoardingBoat.immatriculation}"/> + </s:text> + </p> + + <p> + <s:text name="wao.ui.synthesis.boarding.boardingCount"> + <s:param value="%{synthesis.invalidBoardingsCount}"/> + <s:param value="%{synthesis.boardingsCount}"/> + <%-- + <s:param value="%{synthesis.validBoardingsCount}"/> + --%> + </s:text> + </p> + + </article> + + <article> + <h2> + <s:text name="SynthesisId.IND_COMPLIANCE_BOARDING"/> + </h2> + + </article> + + <article> + <h2> + <s:text name="SynthesisId.IND_CONTACT_STATE"/> + </h2> + + </article> + + <article> + <h2> + <s:text name="SynthesisId.IND_ALLEGRO_REACTIVITY"/> + </h2> + + </article> + + <article> + <h2> + <s:text name="SynthesisId.IND_DATA_RELIABILITY"/> + </h2> + + </article> + + </html>
participants (1)
-
bleny@users.forge.codelutin.com