aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch/src/main
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2015-02-04 17:18:05 +0100
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2015-02-04 17:58:21 +0100
commit070c3e240aec5697ef7e715fc18bacdb14fce9ef (patch)
treefb5ab1f7c13f1d90a5acb1fc0996cae7c7bed34a /sonar-batch/src/main
parent67d215ac9c43b048885d072e12de759855e4b80a (diff)
downloadsonarqube-070c3e240aec5697ef7e715fc18bacdb14fce9ef.tar.gz
sonarqube-070c3e240aec5697ef7e715fc18bacdb14fce9ef.zip
SONAR-5183 - analysis unsensitive to timezones - snapshots table
Diffstat (limited to 'sonar-batch/src/main')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java18
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/ProjectConfigurator.java12
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDate.java14
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDays.java16
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousAnalysis.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousVersion.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByVersion.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/components/PeriodsDefinition.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/components/TimeMachineConfiguration.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java21
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java5
12 files changed, 62 insertions, 57 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java
index 648b624bfa4..d026bfbb596 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultTimeMachine.java
@@ -38,12 +38,10 @@ import org.sonar.batch.index.DefaultIndex;
import javax.annotation.Nullable;
import javax.persistence.Query;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
+
+import static org.sonar.api.utils.DateUtils.dateToLong;
+import static org.sonar.api.utils.DateUtils.longToDate;
public class DefaultTimeMachine implements TimeMachine {
@@ -71,7 +69,7 @@ public class DefaultTimeMachine implements TimeMachine {
Integer characteristicId = model.getCharacteristicId();
Characteristic characteristic = techDebtModel.characteristicById(characteristicId);
Measure measure = toMeasure(model, metricById.get(model.getMetricId()), characteristic);
- measure.setDate((Date) object[1]);
+ measure.setDate(longToDate((Long) object[1]));
result.add(measure);
}
return result;
@@ -126,15 +124,15 @@ public class DefaultTimeMachine implements TimeMachine {
} else if (query.getFrom() != null) {
sb.append(" AND s.createdAt>=:from ");
- params.put("from", query.getFrom());
+ params.put("from", dateToLong(query.getFrom()));
}
if (query.isToCurrentAnalysis()) {
sb.append(" AND s.createdAt<=:to ");
- params.put("to", index.getProject().getAnalysisDate());
+ params.put("to", dateToLong(index.getProject().getAnalysisDate()));
} else if (query.getTo() != null) {
sb.append(" AND s.createdAt<=:to ");
- params.put("to", query.getTo());
+ params.put("to", dateToLong(query.getTo()));
}
if (query.isOnlyLastAnalysis()) {
sb.append(" AND s.last=:last ");
diff --git a/sonar-batch/src/main/java/org/sonar/batch/ProjectConfigurator.java b/sonar-batch/src/main/java/org/sonar/batch/ProjectConfigurator.java
index 75b4ce1722c..4447bf9e4b4 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/ProjectConfigurator.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/ProjectConfigurator.java
@@ -31,7 +31,6 @@ import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.ResourceModel;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Project;
-import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.System2;
@@ -39,13 +38,15 @@ import javax.annotation.Nullable;
import java.util.Date;
+import static org.sonar.api.utils.DateUtils.formatDateTime;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
public class ProjectConfigurator implements BatchComponent {
private static final Logger LOG = LoggerFactory.getLogger(ProjectConfigurator.class);
-
+ private final System2 system2;
private DatabaseSession databaseSession;
private Settings settings;
- private final System2 system2;
public ProjectConfigurator(@Nullable DatabaseSession databaseSession, Settings settings, System2 system2) {
this.databaseSession = databaseSession;
@@ -94,11 +95,12 @@ public class ProjectConfigurator implements BatchComponent {
ResourceModel persistedProject = databaseSession.getSingleResult(ResourceModel.class, "key", projectKey, "enabled", true);
if (persistedProject != null) {
Snapshot lastSnapshot = databaseSession.getSingleResult(Snapshot.class, "resourceId", persistedProject.getId(), "last", true);
- if (lastSnapshot != null && !lastSnapshot.getCreatedAt().before(analysisDate)) {
+ boolean analysisBeforeLastSnapshot = lastSnapshot != null && analysisDate.getTime() <= lastSnapshot.getCreatedAt();
+ if (analysisBeforeLastSnapshot) {
throw new IllegalArgumentException(
"'sonar.projectDate' property cannot be older than the date of the last known quality snapshot on this project. Value: '" +
settings.getString(CoreProperties.PROJECT_DATE_PROPERTY) + "'. " +
- "Latest quality snapshot: '" + DateUtils.formatDateTime(lastSnapshot.getCreatedAt())
+ "Latest quality snapshot: '" + formatDateTime(longToDate(lastSnapshot.getCreatedAt()))
+ "'. This property may only be used to rebuild the past in a chronological order.");
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java
index 378dffff16f..aaaca928970 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshot.java
@@ -26,10 +26,11 @@ import org.sonar.api.database.model.Snapshot;
import org.sonar.api.utils.DateUtils;
import javax.annotation.Nullable;
-
import java.util.Calendar;
import java.util.Date;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
public class PastSnapshot {
private int index;
@@ -74,7 +75,7 @@ public class PastSnapshot {
}
public Date getDate() {
- return projectSnapshot != null ? projectSnapshot.getCreatedAt() : null;
+ return projectSnapshot != null ? longToDate(projectSnapshot.getCreatedAt()) : null;
}
public PastSnapshot setMode(String mode) {
@@ -111,7 +112,7 @@ public class PastSnapshot {
return targetDate;
}
- public PastSnapshot clonePastSnapshot(){
+ public PastSnapshot clonePastSnapshot() {
PastSnapshot clone = new PastSnapshot(mode, targetDate, projectSnapshot);
clone.setIndex(index);
clone.setModeParameter(modeParameter);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDate.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDate.java
index 057122d76d6..fbae4382e43 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDate.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDate.java
@@ -31,6 +31,8 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
+import static org.sonar.api.utils.DateUtils.dateToLong;
+
public class PastSnapshotFinderByDate implements BatchExtension {
private DatabaseSession session;
@@ -57,12 +59,12 @@ public class PastSnapshotFinderByDate implements BatchExtension {
private Snapshot findSnapshot(Integer projectId, Date date) {
String hql = "from " + Snapshot.class.getSimpleName() + " where createdAt>=:date AND resourceId=:resourceId AND status=:status AND qualifier<>:lib order by createdAt asc";
List<Snapshot> snapshots = session.createQuery(hql)
- .setParameter("date", date)
- .setParameter("resourceId", projectId)
- .setParameter("status", Snapshot.STATUS_PROCESSED)
- .setParameter("lib", Qualifiers.LIBRARY)
- .setMaxResults(1)
- .getResultList();
+ .setParameter("date", dateToLong(date))
+ .setParameter("resourceId", projectId)
+ .setParameter("status", Snapshot.STATUS_PROCESSED)
+ .setParameter("lib", Qualifiers.LIBRARY)
+ .setMaxResults(1)
+ .getResultList();
return snapshots.isEmpty() ? null : snapshots.get(0);
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDays.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDays.java
index 07bc1e86342..a3aa8b8387f 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDays.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByDays.java
@@ -30,6 +30,8 @@ import javax.annotation.CheckForNull;
import java.util.Date;
import java.util.List;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
public class PastSnapshotFinderByDays implements BatchExtension {
private DatabaseSession session;
@@ -39,14 +41,14 @@ public class PastSnapshotFinderByDays implements BatchExtension {
}
PastSnapshot findFromDays(Snapshot projectSnapshot, int days) {
- Date targetDate = DateUtils.addDays(projectSnapshot.getCreatedAt(), -days);
+ Date targetDate = DateUtils.addDays(longToDate(projectSnapshot.getCreatedAt()), -days);
String hql = "from " + Snapshot.class.getSimpleName() + " where resourceId=:resourceId AND status=:status AND createdAt<:date AND qualifier<>:lib order by createdAt asc";
List<Snapshot> snapshots = session.createQuery(hql)
- .setParameter("date", projectSnapshot.getCreatedAt())
- .setParameter("resourceId", projectSnapshot.getResourceId())
- .setParameter("status", Snapshot.STATUS_PROCESSED)
- .setParameter("lib", Qualifiers.LIBRARY)
- .getResultList();
+ .setParameter("date", projectSnapshot.getCreatedAt())
+ .setParameter("resourceId", projectSnapshot.getResourceId())
+ .setParameter("status", Snapshot.STATUS_PROCESSED)
+ .setParameter("lib", Qualifiers.LIBRARY)
+ .getResultList();
Snapshot snapshot = getNearestToTarget(snapshots, targetDate);
return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_DAYS, targetDate, snapshot).setModeParameter(String.valueOf(days));
@@ -63,7 +65,7 @@ public class PastSnapshotFinderByDays implements BatchExtension {
long bestDistance = Long.MAX_VALUE;
Snapshot nearest = null;
for (Snapshot snapshot : snapshots) {
- long distance = distance(snapshot.getCreatedAt(), targetDate);
+ long distance = distance(longToDate(snapshot.getCreatedAt()), targetDate);
if (distance <= bestDistance) {
bestDistance = distance;
nearest = snapshot;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousAnalysis.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousAnalysis.java
index 750146974af..627e1943b0c 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousAnalysis.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousAnalysis.java
@@ -30,6 +30,8 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
public class PastSnapshotFinderByPreviousAnalysis implements BatchExtension {
private DatabaseSession session;
@@ -54,7 +56,7 @@ public class PastSnapshotFinderByPreviousAnalysis implements BatchExtension {
return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS);
}
Snapshot snapshot = snapshots.get(0);
- Date targetDate = snapshot.getCreatedAt();
+ Date targetDate = longToDate(snapshot.getCreatedAt());
SimpleDateFormat format = new SimpleDateFormat(DateUtils.DATE_FORMAT);
return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, targetDate, snapshot).setModeParameter(format.format(targetDate));
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousVersion.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousVersion.java
index ca7f9c5ea89..85fc0f855da 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousVersion.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByPreviousVersion.java
@@ -27,6 +27,8 @@ import org.sonar.api.database.model.Snapshot;
import java.util.List;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
public class PastSnapshotFinderByPreviousVersion implements BatchExtension {
private final DatabaseSession session;
@@ -55,7 +57,7 @@ public class PastSnapshotFinderByPreviousVersion implements BatchExtension {
Event previousVersionEvent = events.get(0);
Snapshot snapshot = session.getSingleResult(Snapshot.class, "id", previousVersionEvent.getSnapshot().getId());
- return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, snapshot.getCreatedAt(), snapshot).setModeParameter(snapshot.getVersion());
+ return new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, longToDate(snapshot.getCreatedAt()), snapshot).setModeParameter(snapshot.getVersion());
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByVersion.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByVersion.java
index 050ab1a4b78..3995c2cb69d 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByVersion.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastSnapshotFinderByVersion.java
@@ -28,6 +28,8 @@ import org.sonar.api.resources.Qualifiers;
import java.util.Date;
import java.util.List;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
public class PastSnapshotFinderByVersion implements BatchExtension {
private final DatabaseSession session;
@@ -51,7 +53,7 @@ public class PastSnapshotFinderByVersion implements BatchExtension {
result = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION);
} else {
Snapshot snapshot = snapshots.get(0);
- Date targetDate = snapshot.getCreatedAt();
+ Date targetDate = longToDate(snapshot.getCreatedAt());
result = new PastSnapshot(CoreProperties.TIMEMACHINE_MODE_VERSION, targetDate, snapshot).setModeParameter(version);
}
return result;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PeriodsDefinition.java b/sonar-batch/src/main/java/org/sonar/batch/components/PeriodsDefinition.java
index 392180d4fb4..9f75d86fcb6 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/components/PeriodsDefinition.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/components/PeriodsDefinition.java
@@ -28,11 +28,10 @@ import org.sonar.api.resources.Qualifiers;
import org.sonar.batch.ProjectTree;
import javax.persistence.Query;
-
-import java.util.Date;
import java.util.List;
import static com.google.common.collect.Lists.newLinkedList;
+import static org.sonar.api.utils.DateUtils.dateToLong;
public class PeriodsDefinition implements BatchComponent {
@@ -80,8 +79,8 @@ public class PeriodsDefinition implements BatchComponent {
if (projectId != null) {
snapshot = new Snapshot();
snapshot.setResourceId(projectId.intValue());
- snapshot.setCreatedAt(projectTree.getRootProject().getAnalysisDate());
- snapshot.setBuildDate(new Date());
+ snapshot.setCreatedAt(dateToLong(projectTree.getRootProject().getAnalysisDate()));
+ snapshot.setBuildDate(System.currentTimeMillis());
snapshot.setVersion(projectTree.getRootProject().getAnalysisVersion());
}
return snapshot;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/TimeMachineConfiguration.java b/sonar-batch/src/main/java/org/sonar/batch/components/TimeMachineConfiguration.java
index f5685852497..28c4957d89f 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/components/TimeMachineConfiguration.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/components/TimeMachineConfiguration.java
@@ -19,21 +19,20 @@
*/
package org.sonar.batch.components;
-import org.sonar.api.batch.RequiresDB;
-
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
+import org.sonar.api.batch.RequiresDB;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Qualifiers;
import javax.annotation.CheckForNull;
-
import java.util.List;
import static com.google.common.collect.Lists.newLinkedList;
+import static org.sonar.api.utils.DateUtils.longToDate;
@RequiresDB
public class TimeMachineConfiguration implements BatchComponent {
@@ -61,7 +60,7 @@ public class TimeMachineConfiguration implements BatchComponent {
PastSnapshot pastSnapshot = projectPastSnapshot.clonePastSnapshot();
modulePastSnapshots.add(pastSnapshot);
// When no snapshot is found, date of the period is null
- periods.add(new Period(pastSnapshot.getIndex(), snapshot != null ? snapshot.getCreatedAt() : null));
+ periods.add(new Period(pastSnapshot.getIndex(), snapshot != null ? longToDate(snapshot.getCreatedAt()) : null));
log(pastSnapshot);
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java
index d4a56676b58..7373053e2c0 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java
@@ -24,13 +24,7 @@ import org.apache.commons.lang.StringUtils;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.ResourceModel;
import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Library;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.ResourceUtils;
-import org.sonar.api.resources.Scopes;
+import org.sonar.api.resources.*;
import org.sonar.api.security.ResourcePermissions;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.internal.Uuids;
@@ -40,10 +34,11 @@ import org.sonar.core.component.ScanGraph;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
-
import java.util.Date;
import java.util.List;
+import static org.sonar.api.utils.DateUtils.dateToLong;
+
public class ResourcePersister implements ScanPersister {
private static final String RESOURCE_ID = "resourceId";
@@ -140,8 +135,8 @@ public class ResourcePersister implements ScanPersister {
Snapshot snapshot = new Snapshot(model, parentSnapshot);
snapshot.setVersion(project.getAnalysisVersion());
- snapshot.setCreatedAt(project.getAnalysisDate());
- snapshot.setBuildDate(new Date());
+ snapshot.setCreatedAt(dateToLong(project.getAnalysisDate()));
+ snapshot.setBuildDate(System.currentTimeMillis());
snapshot = session.save(snapshot);
session.commit();
@@ -175,8 +170,8 @@ public class ResourcePersister implements ScanPersister {
Snapshot snapshot = findLibrarySnapshot(model.getId(), library.getVersion());
if (snapshot == null) {
snapshot = new Snapshot(model, null);
- snapshot.setCreatedAt(analysisDate);
- snapshot.setBuildDate(new Date());
+ snapshot.setCreatedAt(dateToLong(analysisDate));
+ snapshot.setBuildDate(System.currentTimeMillis());
snapshot.setVersion(library.getVersion());
snapshot.setStatus(Snapshot.STATUS_PROCESSED);
@@ -224,7 +219,7 @@ public class ResourcePersister implements ScanPersister {
}
Snapshot snapshot = new Snapshot(model, parentSnapshot);
- snapshot.setBuildDate(new Date());
+ snapshot.setBuildDate(System.currentTimeMillis());
snapshot = session.save(snapshot);
session.commit();
return snapshot;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java
index 87cc1f19954..a4c455178f9 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java
@@ -41,13 +41,14 @@ import org.sonar.batch.rule.ModuleQProfiles;
import javax.annotation.CheckForNull;
import javax.persistence.NoResultException;
import javax.persistence.Query;
-
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoader {
private static final Logger LOG = LoggerFactory.getLogger(DefaultProjectRepositoriesLoader.class);
@@ -169,7 +170,7 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad
jpaQuery.setParameter(entry.getKey(), entry.getValue());
}
try {
- return (Date) jpaQuery.getSingleResult();
+ return longToDate((Long) jpaQuery.getSingleResult());
} catch (NoResultException e) {
return null;
}