diff --git a/CHANGES.rst b/CHANGES.rst
index 18c8924..209e47d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -9,6 +9,8 @@ Changelog
 
 - No longer use icons which got deleted in Zope 4.
 
+- Fix sorting in <dtml-in> for duplicate entries in Python 3.
+
 
 3.0b2 (2017-11-03)
 ------------------
diff --git a/src/DocumentTemplate/DT_In.py b/src/DocumentTemplate/DT_In.py
index f9b8150..4c6872d 100644
--- a/src/DocumentTemplate/DT_In.py
+++ b/src/DocumentTemplate/DT_In.py
@@ -330,6 +330,7 @@
 
 '''
 
+from operator import itemgetter
 import sys
 import re
 
@@ -837,7 +838,10 @@ class InClass(object):
             by = SortBy(multsort, sf_list)
             s.sort(by)
         else:
-            s.sort()
+            # In python 3 a key is required when tuples in the list have
+            # the same sort key to prevent attempting to compare the second
+            # item which is dict.
+            s.sort(key=itemgetter(0))
 
         sequence = []
         for k, client in s:
diff --git a/src/TreeDisplay/TreeTag.py b/src/TreeDisplay/TreeTag.py
index 69e28b8..414200c 100644
--- a/src/TreeDisplay/TreeTag.py
+++ b/src/TreeDisplay/TreeTag.py
@@ -395,10 +395,10 @@ def tpRenderTABLE(self, id, root_url, url, state, substate, diff, data,
             if exp:
                 ptreeData['tree-item-expanded'] = 1
                 output('<a name="%s" href="%s?%stree-c=%s#%s">-</a>' %
-                       (id, root_url, param, s, id, script))
+                       (id, root_url, param, s, id))
             else:
                 output('<a name="%s" href="%s?%stree-e=%s#%s">+</a>' %
-                       (id, root_url, param, s, id, script))
+                       (id, root_url, param, s, id))
             output('</td>\n')
 
         else:

diff --git a/src/DocumentTemplate/tests/test_DT_In.py b/src/DocumentTemplate/tests/test_DT_In.py
new file mode 100644
index 0000000..ba517d2
--- /dev/null
+++ b/src/DocumentTemplate/tests/test_DT_In.py
@@ -0,0 +1,34 @@
+import unittest
+
+
+class DummySection(object):
+    blocks = ['dummy']
+
+
+class TestIn(unittest.TestCase):
+    """Testing ..DT_in.InClass."""
+
+    def _getTargetClass(self):
+        from DocumentTemplate.DT_In import InClass
+        return InClass
+
+    def _makeOne(self, *args):
+        blocks = [('in', ' '.join(args), DummySection())]
+        return self._getTargetClass()(blocks)
+
+    def test_sort_sequence(self):
+        """It does not break on duplicate sort keys at a list of dicts."""
+        stmt = self._makeOne('seq', 'mapping', 'sort=key')
+        seq = [
+            {'key': 'c', 'data': '3'},
+            {'key': 'a', 'data': '1'},
+            {'key': 'b', 'data': '2'},
+            {'key': 'a', 'data': '2'},
+        ]
+        result = stmt.sort_sequence(seq, 'key')
+        self.assertEqual([
+            {'key': 'a', 'data': '1'},
+            {'key': 'a', 'data': '2'},
+            {'key': 'b', 'data': '2'},
+            {'key': 'c', 'data': '3'},
+        ], result)
diff --git a/src/DocumentTemplate/tests/test_DT_Var.py b/src/DocumentTemplate/tests/test_DT_Var.py
index 3270824..c81051f 100644
--- a/src/DocumentTemplate/tests/test_DT_Var.py
+++ b/src/DocumentTemplate/tests/test_DT_Var.py
@@ -73,11 +73,11 @@ class TestUrlQuoting(unittest.TestCase):
         utf8_value = unicode_value.encode('UTF-8')
         quoted_utf8_value = b'G%C3%BCnther%20M%C3%BCller'
 
-        self.assertEquals(url_quote(unicode_value), quoted_unicode_value)
-        self.assertEquals(url_quote(utf8_value), quoted_utf8_value)
+        self.assertEqual(url_quote(unicode_value), quoted_unicode_value)
+        self.assertEqual(url_quote(utf8_value), quoted_utf8_value)
 
-        self.assertEquals(url_unquote(quoted_unicode_value), unicode_value)
-        self.assertEquals(url_unquote(quoted_utf8_value), utf8_value)
+        self.assertEqual(url_unquote(quoted_unicode_value), unicode_value)
+        self.assertEqual(url_unquote(quoted_utf8_value), utf8_value)
 
     def test_url_quoting_plus(self):
         from DocumentTemplate.DT_Var import url_quote_plus
@@ -87,10 +87,10 @@ class TestUrlQuoting(unittest.TestCase):
         utf8_value = unicode_value.encode('UTF-8')
         quoted_utf8_value = b'G%C3%BCnther+M%C3%BCller'
 
-        self.assertEquals(url_quote_plus(unicode_value), quoted_unicode_value)
-        self.assertEquals(url_quote_plus(utf8_value), quoted_utf8_value)
+        self.assertEqual(url_quote_plus(unicode_value), quoted_unicode_value)
+        self.assertEqual(url_quote_plus(utf8_value), quoted_utf8_value)
 
-        self.assertEquals(
+        self.assertEqual(
             url_unquote_plus(quoted_unicode_value), unicode_value)
-        self.assertEquals(
+        self.assertEqual(
             url_unquote_plus(quoted_utf8_value), utf8_value)

<dtml-in list_of_dicts mapping sort=name> breaks for duplicate names
Scenario:

```python
list_of_dicts = [{'name': 'a'}, {'name': 'b'}, {'name': 'a'}]
```

In DTML call:

```
<dtml-in list_of_dicts mapping sort=name>
```

It breaks because internally `dtml-in` changes the list to

```python
[('a', {'name': 'a'}), ('b', {'name': 'b'}), ('a', {'name': 'a'})]
```

There is no problem as long as the list does not contain duplicates of the sort key. If there are duplicates, Python has to compare the dicts when sorting. This works fine on Python 2 but it is no loner defined on Python 3.
src/DocumentTemplate/tests/test_DT_In.py::TestIn::test_sort_sequence
src/DocumentTemplate/tests/test_DT_Var.py::TestNewlineToBr::test_newline_to_br src/DocumentTemplate/tests/test_DT_Var.py::TestNewlineToBr::test_newline_to_br_tainted src/DocumentTemplate/tests/test_DT_Var.py::TestUrlQuoting::test_url_quoting src/DocumentTemplate/tests/test_DT_Var.py::TestUrlQuoting::test_url_quoting_plus