diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py
index 29227c3188449734307e47ce28f783ea415c1a6e..446078ffcf0d10a74f1fda19bb7ce56c7686b9e9 100644
--- a/common/lib/xmodule/setup.py
+++ b/common/lib/xmodule/setup.py
@@ -28,6 +28,7 @@ setup(
             "error = xmodule.error_module:ErrorDescriptor",
             "problem = xmodule.capa_module:CapaDescriptor",
             "problemset = xmodule.seq_module:SequenceDescriptor",
+            "randomize = xmodule.randomize_module:RandomizeDescriptor", 
             "section = xmodule.backcompat_module:SemanticSectionDescriptor",
             "sequential = xmodule.seq_module:SequenceDescriptor",
             "slides = xmodule.backcompat_module:TranslateCustomTagDescriptor",
diff --git a/common/lib/xmodule/xmodule/randomize_module.py b/common/lib/xmodule/xmodule/randomize_module.py
new file mode 100644
index 0000000000000000000000000000000000000000..0bc26c21bf0f8e83725876bed126f869cfabe509
--- /dev/null
+++ b/common/lib/xmodule/xmodule/randomize_module.py
@@ -0,0 +1,122 @@
+import json
+import logging
+import random
+
+from xmodule.mako_module import MakoModuleDescriptor
+from xmodule.x_module import XModule
+from xmodule.xml_module import XmlDescriptor
+from xmodule.modulestore import Location
+from xmodule.seq_module import SequenceDescriptor
+
+from pkg_resources import resource_string
+
+log = logging.getLogger('mitx.' + __name__)
+
+class RandomizeModule(XModule):
+    """
+    Chooses a random child module.  Chooses the same one every time for each student.
+
+     Example:
+     <randomize>
+     <problem url_name="problem1" />
+     <problem url_name="problem2" />
+     <problem url_name="problem3" />
+     </randomize>
+
+    User notes:
+
+      - If you're randomizing amongst graded modules, each of them MUST be worth the same
+        number of points.  Otherwise, the earth will be overrun by monsters from the
+        deeps.  You have been warned.
+
+    Technical notes:
+      - There is more dark magic in this code than I'd like.  The whole varying-children +
+        grading interaction is a tangle between super and subclasses of descriptors and
+        modules.
+"""
+
+    def __init__(self, system, location, definition, descriptor,
+                 instance_state=None, shared_state=None, **kwargs):
+        XModule.__init__(self, system, location, definition, descriptor,
+                         instance_state, shared_state, **kwargs)
+
+        # NOTE: calling self.get_children() creates a circular reference--
+        # it calls get_child_descriptors() internally, but that doesn't work until
+        # we've picked a choice
+        num_choices = len(self.descriptor.get_children())
+
+        self.choice = None
+        if instance_state is not None:
+            state = json.loads(instance_state)
+            self.choice = state.get('choice', None)
+            if self.choice > num_choices:
+                # Oops.  Children changed. Reset.
+                self.choice = None
+
+        if self.choice is None:
+            # choose one based on the system seed, or randomly if that's not available
+            if num_choices > 0:
+                if system.seed is not None:
+                    self.choice = system.seed % num_choices
+                else:
+                    self.choice = random.randrange(0, num_choices)
+
+        log.debug("********* self.choice = %s", self.choice)
+        if self.choice is not None:
+            self.child_descriptor = self.descriptor.get_children()[self.choice]
+            # Now get_children() should return a list with one element
+            log.debug("children of randomize module (should be only 1): %s",
+                      self.get_children())
+            self.child = self.get_children()[0]
+        else:
+            self.child_descriptor = None
+            self.child = None
+
+
+    def get_instance_state(self):
+        return json.dumps({'choice': self.choice})
+
+
+    def get_child_descriptors(self):
+        """
+        For grading--return just the chosen child.
+        """
+        if self.child_descriptor is None:
+            return []
+
+        return [self.child_descriptor]
+
+
+    def get_html(self):
+        if self.child is None:
+            # raise error instead?  In fact, could complain on descriptor load...
+            return "<div>Nothing to randomize between</div>"
+
+        return self.child.get_html()
+
+    def get_icon_class(self):
+        return self.child.get_icon_class() if self.child else 'other'
+
+    
+class RandomizeDescriptor(SequenceDescriptor):
+    # the editing interface can be the same as for sequences -- just a container
+    module_class = RandomizeModule
+
+    filename_extension = "xml"
+
+    stores_state = True
+
+    def definition_to_xml(self, resource_fs):
+        xml_object = etree.Element('randomize')
+        for child in self.get_children():
+            xml_object.append(
+                etree.fromstring(child.export_to_xml(resource_fs)))
+        return xml_object
+
+    def has_dynamic_children(self):
+        """
+        Grading needs to know that only one of the children is actually "real".  This
+        makes it use module.get_child_descriptors().
+        """
+        return True
+