Beef-up docs and tests for itertools.  Fix-up end-case for product().
diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst
index 68a4ffd..3f2abdc 100644
--- a/Doc/library/itertools.rst
+++ b/Doc/library/itertools.rst
@@ -89,6 +89,7 @@
 
    .. versionadded:: 2.6
 
+
 .. function:: combinations(iterable, r)
 
    Return successive *r* length combinations of elements in the *iterable*.
@@ -123,6 +124,17 @@
                     indices[j] = indices[j-1] + 1
                 yield tuple(pool[i] for i in indices)
 
+   The code for :func:`combinations` can be also expressed as a subsequence
+   of :func:`permutations` after filtering entries where the elements are not
+   in sorted order (according to their position in the input pool)::
+
+        def combinations(iterable, r):
+            pool = tuple(iterable)
+            n = len(pool)
+            for indices in permutations(range(n), r):
+                if sorted(indices) == list(indices):
+                    yield tuple(pool[i] for i in indices)
+
    .. versionadded:: 2.6
 
 .. function:: count([n])
@@ -391,6 +403,18 @@
                 else:
                     return
 
+   The code for :func:`permutations` can be also expressed as a subsequence of 
+   :func:`product`, filtered to exclude entries with repeated elements (those
+   from the same position in the input pool)::
+
+        def permutations(iterable, r=None):
+            pool = tuple(iterable)
+            n = len(pool)
+            r = n if r is None else r
+            for indices in product(range(n), repeat=r):
+                if len(set(indices)) == r:
+                    yield tuple(pool[i] for i in indices)
+
    .. versionadded:: 2.6
 
 .. function:: product(*iterables[, repeat])
@@ -401,9 +425,9 @@
    ``product(A, B)`` returns the same as ``((x,y) for x in A for y in B)``.
 
    The leftmost iterators are in the outermost for-loop, so the output tuples
-   cycle in a manner similar to an odometer (with the rightmost element
-   changing on every iteration).  This results in a lexicographic ordering
-   so that if the inputs iterables are sorted, the product tuples are emitted
+   cycle like an odometer (with the rightmost element changing on every 
+   iteration).  This results in a lexicographic ordering so that if the 
+   inputs iterables are sorted, the product tuples are emitted
    in sorted order.
 
    To compute the product of an iterable with itself, specify the number of
@@ -415,12 +439,11 @@
 
        def product(*args, **kwds):
            pools = map(tuple, args) * kwds.get('repeat', 1)
-           if pools:            
-               result = [[]]
-               for pool in pools:
-                   result = [x+[y] for x in result for y in pool]
-               for prod in result:
-                   yield tuple(prod)
+           result = [[]]
+           for pool in pools:
+               result = [x+[y] for x in result for y in pool]
+           for prod in result:
+               yield tuple(prod)
 
    .. versionadded:: 2.6