Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormkersten2006-08-25 03:59:32 +0000
committermkersten2006-08-25 03:59:32 +0000
commitf032ec390866831a55500bfb87d329a2100ea929 (patch)
tree905ce0baa81bb984178c853dc002ac689ae4151d
parent04c3ba72b1ee24dc875d13f32d8657b342fcdb45 (diff)
downloadorg.eclipse.mylyn.tasks-f032ec390866831a55500bfb87d329a2100ea929.tar.gz
org.eclipse.mylyn.tasks-f032ec390866831a55500bfb87d329a2100ea929.tar.xz
org.eclipse.mylyn.tasks-f032ec390866831a55500bfb87d329a2100ea929.zip
Completed: 155145: priorities for Trac tasks not displayed correctlyR_0_6_1_prerefactoring
https://bugs.eclipse.org/bugs/show_bug.cgi?id=155145
-rw-r--r--org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/AllTracTests.java2
-rw-r--r--org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracQueryHitTest.java35
-rw-r--r--org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracRepositoryConnectorTest.java13
-rw-r--r--org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracTaskTest.java44
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracQueryHit.java8
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java60
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracTask.java52
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/ui/editor/TracTaskEditor.java30
8 files changed, 174 insertions, 70 deletions
diff --git a/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/AllTracTests.java b/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/AllTracTests.java
index 6e29dde2c..d01300bcb 100644
--- a/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/AllTracTests.java
+++ b/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/AllTracTests.java
@@ -40,6 +40,8 @@ public class AllTracTests {
suite.addTestSuite(TracAttachmentHandlerTest.class);
suite.addTestSuite(RepositorySearchQueryTest.class);
suite.addTestSuite(TracOfflineTaskHandlerTest.class);
+ suite.addTestSuite(TracTaskTest.class);
+ suite.addTestSuite(TracQueryHitTest.class);
// $JUnit-END$
return suite;
}
diff --git a/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracQueryHitTest.java b/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracQueryHitTest.java
new file mode 100644
index 000000000..a89085c9e
--- /dev/null
+++ b/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracQueryHitTest.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2006 - 2006 Mylar eclipse.org project and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mylar project committers - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.trac.tests;
+
+import junit.framework.TestCase;
+
+import org.eclipse.mylar.internal.trac.TracQueryHit;
+import org.eclipse.mylar.internal.trac.TracTask;
+
+/**
+ * @author Steffen Pingel
+ */
+public class TracQueryHitTest extends TestCase {
+
+ public void testAttributes() {
+ TracQueryHit hit = new TracQueryHit("url", "description", "123");
+ hit.setPriority("P1");
+ hit.setCompleted(true);
+
+ TracTask task = (TracTask) hit.getOrCreateCorrespondingTask();
+ assertEquals("url-123", task.getHandleIdentifier());
+ assertEquals("P1", task.getPriority());
+ assertEquals(true, task.isCompleted());
+ }
+
+}
diff --git a/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracRepositoryConnectorTest.java b/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracRepositoryConnectorTest.java
index 32f84982a..2336698d7 100644
--- a/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracRepositoryConnectorTest.java
+++ b/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracRepositoryConnectorTest.java
@@ -42,6 +42,7 @@ import org.eclipse.mylar.internal.trac.model.TracVersion;
import org.eclipse.mylar.internal.trac.model.TracTicket.Key;
import org.eclipse.mylar.internal.trac.ui.wizard.TracRepositorySettingsPage;
import org.eclipse.mylar.tasks.core.AbstractQueryHit;
+import org.eclipse.mylar.tasks.core.AbstractRepositoryTask;
import org.eclipse.mylar.tasks.core.ITask;
import org.eclipse.mylar.tasks.core.RepositoryAttachment;
import org.eclipse.mylar.tasks.core.TaskList;
@@ -200,9 +201,11 @@ public class TracRepositoryConnectorTest extends TestCase {
ticket.putBuiltinValue(Key.SUMMARY, "mysummary");
ticket.putBuiltinValue(Key.TYPE, "mytype");
- TracTask task = new TracTask("", "", true);
- TracRepositoryConnector.updateTaskDetails(Constants.TEST_TRAC_010_URL, task, ticket, false);
-
+ TracTask task = new TracTask(AbstractRepositoryTask.getHandle(Constants.TEST_TRAC_010_URL, 123), "desc", true);
+ assertEquals(Constants.TEST_TRAC_010_URL + ITracClient.TICKET_URL + "123", task.getUrl());
+ assertEquals("desc", task.getDescription());
+
+ TracRepositoryConnector.updateTaskDetails(task, ticket, false);
assertEquals(Constants.TEST_TRAC_010_URL + ITracClient.TICKET_URL + "123", task.getUrl());
assertEquals("123: mysummary", task.getDescription());
assertEquals("P3", task.getPriority());
@@ -213,9 +216,9 @@ public class TracRepositoryConnectorTest extends TestCase {
TracTicket ticket = new TracTicket(456);
ticket.putBuiltinValue(Key.SUMMARY, "mysummary");
- TracTask task = new TracTask("", "", true);
- TracRepositoryConnector.updateTaskDetails(Constants.TEST_TRAC_010_URL, task, ticket, false);
+ TracTask task = new TracTask(AbstractRepositoryTask.getHandle(Constants.TEST_TRAC_010_URL, 456), "desc", true);
+ TracRepositoryConnector.updateTaskDetails(task, ticket, false);
assertEquals(Constants.TEST_TRAC_010_URL + ITracClient.TICKET_URL + "456", task.getUrl());
assertEquals("456: mysummary", task.getDescription());
assertEquals("P3", task.getPriority());
diff --git a/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracTaskTest.java b/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracTaskTest.java
new file mode 100644
index 000000000..b6199e30b
--- /dev/null
+++ b/org.eclipse.mylyn.trac.tests/src/org/eclipse/mylyn/trac/tests/TracTaskTest.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2006 - 2006 Mylar eclipse.org project and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mylar project committers - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.trac.tests;
+
+import junit.framework.TestCase;
+
+import org.eclipse.mylar.internal.trac.TracTask;
+
+/**
+ * @author Steffen Pingel
+ */
+public class TracTaskTest extends TestCase {
+
+ public void testIsCompleted() {
+ assertTrue(TracTask.isCompleted("closed"));
+ assertFalse(TracTask.isCompleted("Closed"));
+ assertFalse(TracTask.isCompleted("new"));
+ assertFalse(TracTask.isCompleted("assigned"));
+ assertFalse(TracTask.isCompleted("reopened"));
+ assertFalse(TracTask.isCompleted("foobar"));
+ assertFalse(TracTask.isCompleted(""));
+ assertFalse(TracTask.isCompleted(null));
+ }
+
+ public void testGetMylarPriority() {
+ assertEquals("P1", TracTask.getMylarPriority("blocker"));
+ assertEquals("P2", TracTask.getMylarPriority("critical"));
+ assertEquals("P3", TracTask.getMylarPriority("major"));
+ assertEquals("P3", TracTask.getMylarPriority(null));
+ assertEquals("P3", TracTask.getMylarPriority(""));
+ assertEquals("P3", TracTask.getMylarPriority("foo bar"));
+ assertEquals("P4", TracTask.getMylarPriority("minor"));
+ assertEquals("P5", TracTask.getMylarPriority("trivial"));
+ }
+}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracQueryHit.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracQueryHit.java
index cc8ba341c..89c7d16ba 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracQueryHit.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracQueryHit.java
@@ -25,11 +25,11 @@ public class TracQueryHit extends AbstractQueryHit {
private TracTask task;
private boolean completed;
- protected TracQueryHit(String repositoryUrl, String description, String id) {
+ public TracQueryHit(String repositoryUrl, String description, String id) {
super(repositoryUrl, description, id);
}
- protected TracQueryHit(String handle) {
+ public TracQueryHit(String handle) {
super(AbstractRepositoryTask.getRepositoryUrl(handle), "", AbstractRepositoryTask.getTaskId(handle));
}
@@ -46,8 +46,8 @@ public class TracQueryHit extends AbstractQueryHit {
this.task = (TracTask)existingTask;
} else {
this.task = new TracTask(getHandleIdentifier(), getDescription(), true);
- task.setCompleted(isCompleted());
- task.setPriority(getPriority());
+ task.setCompleted(completed);
+ task.setPriority(priority);
TasksUiPlugin.getTaskListManager().getTaskList().addTask(task);
}
return task;
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java
index b966e136c..3fd8c6990 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java
@@ -27,7 +27,6 @@ import org.eclipse.mylar.context.core.MylarStatusHandler;
import org.eclipse.mylar.internal.tasks.ui.wizards.AbstractRepositorySettingsPage;
import org.eclipse.mylar.internal.tasks.ui.wizards.NewWebTaskWizard;
import org.eclipse.mylar.internal.trac.TracTask.Kind;
-import org.eclipse.mylar.internal.trac.TracTask.PriorityLevel;
import org.eclipse.mylar.internal.trac.core.ITracClient;
import org.eclipse.mylar.internal.trac.core.TracClientManager;
import org.eclipse.mylar.internal.trac.core.ITracClient.Version;
@@ -43,7 +42,6 @@ import org.eclipse.mylar.tasks.core.AbstractRepositoryTask;
import org.eclipse.mylar.tasks.core.IAttachmentHandler;
import org.eclipse.mylar.tasks.core.IOfflineTaskHandler;
import org.eclipse.mylar.tasks.core.ITask;
-import org.eclipse.mylar.tasks.core.Task;
import org.eclipse.mylar.tasks.core.TaskRepository;
import org.eclipse.mylar.tasks.ui.AbstractRepositoryConnector;
import org.eclipse.mylar.tasks.ui.TasksUiPlugin;
@@ -201,17 +199,10 @@ public class TracRepositoryConnector extends AbstractRepositoryConnector {
}
for (TracTicket ticket : tickets) {
-// String handleIdentifier = AbstractRepositoryTask.getHandle(url, ticket.getId());
-// ITask task = TasksUiPlugin.getTaskListManager().getTaskList().getTask(handleIdentifier);
-// if (!(task instanceof TracTask)) {
-// task = createTask(ticket, handleIdentifier);
-// }
-// updateTaskDetails(url, (TracTask) task, ticket, false);
-
- String description = ticket.getValue(Key.SUMMARY);
- TracQueryHit hit = new TracQueryHit(query.getRepositoryUrl(), description, ticket.getId() + "");
- hit.setCompleted(isCompleted(ticket));
- hit.setPriority(getPriority(ticket));
+ TracQueryHit hit = new TracQueryHit(query.getRepositoryUrl(), getTicketDescription(ticket), ticket.getId()
+ + "");
+ hit.setCompleted(TracTask.isCompleted(ticket.getValue(Key.STATUS)));
+ hit.setPriority(TracTask.getMylarPriority(ticket.getValue(Key.PRIORITY)));
hits.add(hit);
}
queryStatus.add(Status.OK_STATUS);
@@ -230,7 +221,7 @@ public class TracRepositoryConnector extends AbstractRepositoryConnector {
String handleIdentifier = AbstractRepositoryTask.getHandle(repository.getUrl(), ticket.getId());
TracTask task = createTask(ticket, handleIdentifier);
- updateTaskDetails(repository.getUrl(), task, ticket, true);
+ updateTaskDetails(task, ticket, true);
return task;
} catch (Exception e) {
@@ -256,21 +247,21 @@ public class TracRepositoryConnector extends AbstractRepositoryConnector {
if (existingTask instanceof TracTask) {
task = (TracTask) existingTask;
} else {
- task = new TracTask(handleIdentifier, ticket.getValue(Key.SUMMARY), true);
+ task = new TracTask(handleIdentifier, getTicketDescription(ticket), true);
TasksUiPlugin.getTaskListManager().getTaskList().addTask(task);
}
return task;
}
-
+
/**
* Updates fields of <code>task</code> from <code>ticket</code>.
*/
- public static void updateTaskDetails(String repositoryUrl, TracTask task, TracTicket ticket, boolean notify) {
+ public static void updateTaskDetails(TracTask task, TracTicket ticket, boolean notify) {
if (ticket.getValue(Key.SUMMARY) != null) {
- task.setDescription(ticket.getId() + ": " + ticket.getValue(Key.SUMMARY));
+ task.setDescription(getTicketDescription(ticket));
}
- task.setCompleted(isCompleted(ticket));
- task.setPriority(getPriority(ticket));
+ task.setCompleted(TracTask.isCompleted(ticket.getValue(Key.STATUS)));
+ task.setPriority(TracTask.getMylarPriority(ticket.getValue(Key.PRIORITY)));
if (ticket.getValue(Key.TYPE) != null) {
Kind kind = TracTask.Kind.fromType(ticket.getValue(Key.TYPE));
task.setKind((kind != null) ? kind.toString() : ticket.getValue(Key.TYPE));
@@ -284,23 +275,8 @@ public class TracRepositoryConnector extends AbstractRepositoryConnector {
}
}
- public static boolean isCompleted(TracTicket ticket) {
- if (ticket.getValue(Key.STATUS) != null) {
- TracTask.Status status = TracTask.Status.fromStatus(ticket.getValue(Key.STATUS));
- return status != null && status == TracTask.Status.CLOSED;
- }
- return false;
- }
-
- private static String getPriority(TracTicket ticket) {
- if (ticket.getValue(Key.PRIORITY) != null) {
- PriorityLevel priority = TracTask.PriorityLevel.fromPriority(ticket.getValue(Key.PRIORITY));
- if (priority != null) {
- return priority.toString();
- }
- // else return ticket.getValue(Key.PRIORITY)
- }
- return Task.PriorityLevel.P3.toString();
+ private static String getTicketDescription(TracTicket ticket) {
+ return ticket.getId() + ": " + ticket.getValue(Key.SUMMARY);
}
@Override
@@ -329,14 +305,14 @@ public class TracRepositoryConnector extends AbstractRepositoryConnector {
}
public boolean hasRichEditor(AbstractRepositoryTask task) {
- TaskRepository repository = TasksUiPlugin.getRepositoryManager().getRepository(
- TracUiPlugin.REPOSITORY_KIND, task.getRepositoryUrl());
+ TaskRepository repository = TasksUiPlugin.getRepositoryManager().getRepository(TracUiPlugin.REPOSITORY_KIND,
+ task.getRepositoryUrl());
return Version.XML_RPC.name().equals(repository.getVersion());
}
public boolean hasAttachmentSupport(AbstractRepositoryTask task) {
- TaskRepository repository = TasksUiPlugin.getRepositoryManager().getRepository(
- TracUiPlugin.REPOSITORY_KIND, task.getRepositoryUrl());
+ TaskRepository repository = TasksUiPlugin.getRepositoryManager().getRepository(TracUiPlugin.REPOSITORY_KIND,
+ task.getRepositoryUrl());
return Version.XML_RPC.name().equals(repository.getVersion());
}
@@ -357,5 +333,5 @@ public class TracRepositoryConnector extends AbstractRepositoryConnector {
}
return repository.getUserName();
}
-
+
} \ No newline at end of file
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracTask.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracTask.java
index 95b1ce1b8..1f7107724 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracTask.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracTask.java
@@ -11,8 +11,11 @@
package org.eclipse.mylar.internal.trac;
+import org.eclipse.mylar.internal.trac.TracAttributeFactory.Attribute;
import org.eclipse.mylar.internal.trac.core.ITracClient;
import org.eclipse.mylar.tasks.core.AbstractRepositoryTask;
+import org.eclipse.mylar.tasks.core.RepositoryTaskAttribute;
+import org.eclipse.mylar.tasks.core.Task;
/**
* @author Steffen Pingel
@@ -89,7 +92,7 @@ public class TracTask extends AbstractRepositoryTask {
}
public enum Status {
- NEW, ASSIGNED, CLOSED;
+ NEW, ASSIGNED, REOPENED, CLOSED;
@Override
public String toString() {
@@ -98,6 +101,8 @@ public class TracTask extends AbstractRepositoryTask {
return "New";
case ASSIGNED:
return "Assigned";
+ case REOPENED:
+ return "Reopened";
case CLOSED:
return "Closed";
default:
@@ -112,6 +117,8 @@ public class TracTask extends AbstractRepositoryTask {
return NEW;
if (status.equals("assigned"))
return ASSIGNED;
+ if (status.equals("reopened"))
+ return REOPENED;
if (status.equals("closed"))
return CLOSED;
return null;
@@ -121,14 +128,15 @@ public class TracTask extends AbstractRepositoryTask {
public TracTask(String handle, String label, boolean newTask) {
super(handle, label, newTask);
-
- setUrl(AbstractRepositoryTask.getRepositoryUrl(handle) + ITracClient.TICKET_URL + AbstractRepositoryTask.getTaskId(handle));
+
+ setUrl(AbstractRepositoryTask.getRepositoryUrl(handle) + ITracClient.TICKET_URL
+ + AbstractRepositoryTask.getTaskId(handle));
}
-
+
@Override
public boolean isCompleted() {
if (taskData != null) {
- return Status.CLOSED.toString().toLowerCase().equals(taskData.getStatus());
+ return isCompleted(taskData.getStatus());
} else {
return super.isCompleted();
}
@@ -139,4 +147,38 @@ public class TracTask extends AbstractRepositoryTask {
return TracUiPlugin.REPOSITORY_KIND;
}
+ @Override
+ public String getPriority() {
+ if (taskData != null && taskData.getAttribute(Attribute.PRIORITY.getTracKey()) != null) {
+ return getMylarPriority(taskData.getAttributeValue(Attribute.PRIORITY.getTracKey()));
+ } else {
+ return super.getPriority();
+ }
+ }
+
+ @Override
+ public String getOwner() {
+ if (taskData != null && taskData.getAttribute(RepositoryTaskAttribute.USER_OWNER) != null) {
+ return taskData.getAttributeValue(RepositoryTaskAttribute.USER_OWNER);
+ } else {
+ return super.getOwner();
+ }
+ }
+
+ // TODO use priority attributes from repository instead of hard coded enum
+ public static String getMylarPriority(String tracPriority) {
+ if (tracPriority != null) {
+ PriorityLevel priority = PriorityLevel.fromPriority(tracPriority);
+ if (priority != null) {
+ return priority.toString();
+ }
+ }
+ return Task.PriorityLevel.P3.toString();
+ }
+
+ public static boolean isCompleted(String tracStatus) {
+ TracTask.Status status = TracTask.Status.fromStatus(tracStatus);
+ return status == TracTask.Status.CLOSED;
+ }
+
}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/ui/editor/TracTaskEditor.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/ui/editor/TracTaskEditor.java
index dfc07abd0..36ab35058 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/ui/editor/TracTaskEditor.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/ui/editor/TracTaskEditor.java
@@ -182,20 +182,22 @@ public class TracTaskEditor extends AbstractRepositoryTaskEditor {
}
RepositoryOperation operation = data.getSelectedOperation();
- String action = operation.getKnobName();
- if (!"leave".equals(action)) {
- if ("accept".equals(action)) {
- ticket.putValue("status", "assigned");
- ticket.putValue("owner", TracRepositoryConnector.getDisplayUsername(repository));
- } else if ("resolve".equals(action)) {
- ticket.putValue("status", "closed");
- ticket.putValue("resolution", operation.getOptionSelection());
- } else if ("reopen".equals(action)) {
- ticket.putValue("status", "reopened");
- ticket.putValue("resolution", "");
- } else if ("reassign".equals(operation.getKnobName())) {
- ticket.putValue("status", "new");
- ticket.putValue("owner", operation.getInputValue());
+ if (operation != null) {
+ String action = operation.getKnobName();
+ if (!"leave".equals(action)) {
+ if ("accept".equals(action)) {
+ ticket.putValue("status", "assigned");
+ ticket.putValue("owner", TracRepositoryConnector.getDisplayUsername(repository));
+ } else if ("resolve".equals(action)) {
+ ticket.putValue("status", "closed");
+ ticket.putValue("resolution", operation.getOptionSelection());
+ } else if ("reopen".equals(action)) {
+ ticket.putValue("status", "reopened");
+ ticket.putValue("resolution", "");
+ } else if ("reassign".equals(operation.getKnobName())) {
+ ticket.putValue("status", "new");
+ ticket.putValue("owner", operation.getInputValue());
+ }
}
}

Back to the top