# Source code for sagenb.notebook.interact

    # -*- coding: utf-8 -*
    #############################################################################
    #       Copyright (C) 2008 William Stein <wstein@gmail.com>
    #  Distributed under the terms of the GNU General Public License (GPL)
    #  The full text of the GPL is available at:
    #                  http://www.gnu.org/licenses/
    #############################################################################

    r"""
    Interact Functions in the Notebook

    This module implements an :func:`interact` function decorator for the Sage
    notebook.

    AUTHORS:

    - William Stein (2008-03-02): version 1.0 at Sage/Enthought Days
      8 in Texas

    - Jason Grout (2008-03): discussion and first few prototypes

    - Jason Grout (2008-05): :class:`input_grid` control
    """

    """
     ** PLANNING **

    NOTES:

       * There is no testing of pickling anywhere in this file.  This is
         because there is no reason one would ever pickle anything in this
         file, since everything is associated with particular state
         information of a notebook.

    BUGS:

       [x] have default values set from the get go
       [x] spacing around sliders; also need to have labels
       [x] when re-evaluate input, make sure to clear output so cell-interact-id div is gone.
       [x] two interacts in one cell -- what to do?
       [x] draw initial state
       [x] make interact canvas resizable
       [x] if you  use a interact control after restarting, doesn't work.   Need to reset it.  How?
       [x] display html parts of output as html
       [x] default slider pos doesn't work, eg. def _(q1=(-1,(-3,3)), q2=(1,(-3,3))):
       [x] change from interact to interact everywhere.
       [x] edit/save breaks interact mode
              * picking up images that shouldn't.
              * controls completely stop working.
       [x] problems with html/pre/text formatting, e.g., in TEXT mode and in interact cells
       [x] tab completion in interact broken formatting
       [x] error exception reporting broken
       [x] replace special %interact by something very obfuscated to keep from having
           really weird mistakes that are hard for people to debug.
       [x] cell order corruption
       [x] cross-platform testing (good enough -- it's jquery)
       [x] can't enter "foo" in input_box now because of how strings are
           passed back and forth using single quotes.
       [x] possible issue with page title being undefined; don't know why
           or if that is connected with interactives
       [x] autorunning interact cells on load is being injected into the
           i/o pexpect stream way too early.
       [x] what do published worksheets do??

    VERSION 1:

       [X] get sliders to work; values after move slider
       [x] default values
       [x] NO -- autoswitch to 1-cell mode:
               put                  slide_mode(); jump_to_slide(%s);   in wrap_in_outside_frame
            but feels all wrong.
       [x] completely get rid of left clicking to switch wrap mode for
               interact objects: always in word wrap mode or hide.
       [x] shortcut ('label', v)
       [x] test saving and loading whole notebook to a file
       [x] collection of about 20 good examples of how to use interact (doctested)
       [x] interact(f) should also work; i.e., no need to use decorators -- done; won't be advertised, but
           at least fixing this improves code quality.
       [x] obfuscate ?START and ?END much more.
       [x] type checked input box
       [x] line up all the control in a single table so all labels and all
           controls exactly match up
       [x] button bar
       [x] drop down menu
       [x] checkbox
       [x] color selector
       [x] something to avoid server flood, e.g., any %interact request removes all other
           such requests from the queue in worksheet.py

       DOCS:

       [x] 100% documentation and doctest coverage
       [ ] put the docs for this in the reference manual
       [ ] put summary doc in notebook help page

    VERSION 2:

       [ ] vertical scroll bars (maybe very easy via jsquery)
       [ ] small version of color selector
       [ ] button -- block of code gets run when it is clicked
       [ ] when click a button in a button bar it is highlighted and
           other buttons are not (via some sort of javascript)
       [ ] much more fine control over style of all controls
       [ ] safe/secure evaluation mode
       [ ] slider is too narrow -- need to expand to window width?
       [ ] fix the flicker resize during update (hard???)
       [ ] make option for text input that correctly gives something of
           the same type as the default input.
       [ ] matrix input control (method of matrix space) -- a spreadsheet like thing
       [ ] a 2-D slider:
              u = ((xmin,xmax),(ymin,ymax))  2-D slider   -- NOT IMPLEMENTED
       [ ] locator in a 2-D graphic
       [ ] tab_view -- represents an object in which clicking the tab
                       with label lbl[i] displays expr[i]
       [ ] controls: make them easy to customize as below --
              location -- where to put the slider (?)
              align -- left, right, top, texttop, middle, absmiddle, baseline, bottom, absbottom
              background -- the color of the background for the cell
              frame -- draw a frame around
              disabled -- disables the input element when it first loads
                          so that the user can not write text in it, or
                          select it.
              editable -- bool
              font_size -- integer
              maxlength -- the maximum number of characters allowed in a text field.
              name -- defines a unique name for the input element
              size -- the size of the input element
              type -- button, checkbox, file, password, radio, slider, text, setter_bar

    VERSION 3:
       [ ] protocol for objects to have their own interact function; make
           it so for any object obj in sage, one can do
                 {{{
                 interact(obj)
                 }}}
           and get something useful as a result.
       [ ] flot -- some pretty but very simple javascript only graphics  (maybe don't do... unclear)
       [ ] zorn -- similar (maybe don't do... unclear)
       [ ] color sliders (?):
              u = color(...)         a color slider
              http://interface.eyecon.ro/demos/slider_colorpicker.html
              http://jqueryfordesigners.com/demo/slider-gallery.html
       [ ] tag_cell('foo') -- makes it so one can refer to the current cell
           from elsewhere using the tag foo instead of the cell id number
           This involves doing something with SAGE_CELL_ID and the cell_id() method.
       [ ] framed -- put a frame around an object
    """

    # Standard system libraries
    import inspect
    import math
    import types
    import collections
    from base64 import standard_b64decode

    # Sage libraries
    from sagenb.misc.misc import sage_eval, Color, is_Matrix
    from sage.arith.srange import srange
    from sage.misc.cachefunc import cached_method

    # SAGE_CELL_ID is a module scope variable that is always set equal to
    # the current cell id (of the executing cell).  Code that sets this is
    # inserted by the notebook server each time a worksheet cell is
    # evaluated.
    SAGE_CELL_ID = 0

    # Prefixed to cell input, signals an interact update.
    INTERACT_UPDATE_PREFIX = '%__sage_interact__'

    # If this special message appears in an interact cell's output, it
    # should trigger an automatic re-evaluation of the ambient cell.
    INTERACT_RESTART = '__SAGE_INTERACT_RESTART__'

    # Place-holder markers/fields, replaced in cell.py and
    # notebook_lib.js.
    INTERACT_START = '<?__SAGE__START>'
    INTERACT_TEXT = '<?__SAGE__TEXT>'
    INTERACT_HTML = '<?__SAGE__HTML>'
    INTERACT_END = '<?__SAGE__END>'

    # Dictionary that stores the state of all active interact cells.
    state = {}

    def reset_state():
        """
        Reset the :func:`interact` state of this sage process.

        EXAMPLES::

            sage: sagenb.notebook.interact.state  # random output
            {1: {'function': <function g at 0x72aaab0>, 'variables': {'m': 3, 'n': 5}, 'adapt': {1: <bound method Slider._adaptor of Slider Interact Control: n [1--|1|---10].>, 2: <bound method Slider._adaptor of Slider Interact Control: m [1--|1|---10].>}}}
            sage: from sagenb.notebook.interact import reset_state
            sage: reset_state()
            sage: sagenb.notebook.interact.state
            {}
        """
        global state
        state = {}

    _k = 0
    def new_adapt_number():
        """
        Return an integer, always counting up, and starting with 0.  This
        is used for saving the adapt methods for controls.  An adapt
        method is just a function that coerces data into some object,
        e.g., makes sure the control always produces int's.

        OUTPUT:

        - an integer

        EXAMPLES::

            sage: sagenb.notebook.interact.new_adapt_number()   # random output -- depends on when called
            1
        """
        global _k
        _k += 1
        return _k

    def html(s):
        """
        Print the input string ``s`` in a form that tells the notebook to
        display it in the HTML portion of the output.  This function has
        no return value.

        INPUT:

        - ``s`` - a string

        EXAMPLES::

            sage: sagenb.notebook.interact.html('hello')
            <html>hello</html>
        """
        print("<html>%s</html>" % s)

    def html_slider(id, values, callback, steps, default=0, margin=0):
        """
        Return the HTML representation of a jQuery slider.

        INPUT:

        - ``id`` - a string; the DOM ID of the slider (better be unique)

        - ``values`` - a string; 'null' or JavaScript string containing
          array of values on slider

        - ``callback`` - a string; JavaScript that is executed whenever
          the slider is done moving

        - ``steps`` - an integer; number of steps from minimum to maximum
          value

        - ``default`` - an integer (default: 0); the default position of
          the slider

        - ``margin`` - an integer (default: 0); size of margin to insert
          around the slider

        OUTPUT:

        - a string - HTML format

        EXAMPLES:

        We create a jQuery HTML slider.  If you do the following in the
        notebook you should obtain a slider that when moved pops up a
        window showing its current position::

            sage: from sagenb.notebook.interact import html_slider, html
            sage: html(html_slider('slider-007', 'null', 'alert(position)', steps=5, default=2, margin=5))
            <html>...slider...</html>
        """
        val_html = ''
        if values != 'null':
            val_html = """
                <td>
                  <font color="black" id="%s-lbl"></font>
                </td>""" % id

        s = """
            <table>
              <tr>
                <td>
                  <div id="%s" style="margin:%spx; margin-left: 1.0em; margin-right: 1.0em; width: 15.0em;"></div>
                </td>
                %s
              </tr>
            </table>""" % (id, int(margin), val_html)

        # We now generate javascript that gets run after the above div
        # gets inserted. This happens because of the setTimeout function
        # below which gets passed an anonymous function.
        s += """<script>
        (function() {
            var values = %(values)s;
            setTimeout(function() {
                $('#%(id)s').slider({
                    step: 1,
                    min: 0,
                    max: %(maxvalue)s,
                    value: %(startvalue)s,
                    change: function (e, ui) {
                        var position = ui.value;
                        if (values != null) {
                            $('#%(id)s-lbl').text(values[position]);
                            %(callback)s;
                        }
                    },
                    slide: function (e, ui) {
                        if (values != null) {
                            $('#%(id)s-lbl').text(values[ui.value]);
                        }
                    }
                });
                if (values != null) {
                    $('#%(id)s-lbl').text(values[$('#%(id)s').slider('value')]);
                }
            }, 1);
        })();
        </script>""" % {'values': values, 'id': id, 'maxvalue': steps - 1,
                        'startvalue': default, 'callback': callback}

        # change 'change' to 'slide' and it changes the slider every time it moves;
        # needs much more work to actually work, since server gets flooded by
        # requests.

        return s

    def html_rangeslider(id, values, callback, steps, default_l=0, default_r=1,
                         margin=0):
        """
        Return the HTML representation of a jQuery range slider.

        INPUT:

        - ``id`` - a string; the DOM ID of the slider (better be unique)

        - ``values`` - a string; 'null' or JavaScript string containing
          array of values on slider

        - ``callback`` - a string; JavaScript that is executed whenever
          the slider is done moving

        - ``steps`` - an integer; number of steps from minimum to maximum
          value

        - ``default_l`` - an integer (default: 0); the default position of
          the left edge of the slider

        - ``default_r`` - an integer (default: 1); the default position of
          the right edge of the slider

        - ``margin`` - an integer (default: 0); size of margin to insert
          around the slider

        OUTPUT:

        - a string - HTML format

        EXAMPLES:

        We create a jQuery range slider. If you do the following in the
        notebook you should obtain a slider that when moved pops up a
        window showing its current position::

            sage: from sagenb.notebook.interact import html_rangeslider, html
            sage: html(html_rangeslider('slider-007', 'null', 'alert(pos[0]+", "+pos[1])', steps=5, default_l=2, default_r=3, margin=5))
            <html>...slider...range...</html>
        """
        val_html = ''
        if values != 'null':
            val_html = """
              <tr>
                <td>
                  <font color="black" id="%s-lbl"></font>
                </td>
              </tr>""" % id

        s = """
            <table>
              <tr>
                <td>
                  <div id="%s" style="margin:%spx; margin-left: 1.0em; margin-right: 1.0em; width: 20.0em;"></div>
                </td>
              </tr>
              %s
            </table>
            """ % (id, int(margin), val_html)

        # We now generate javascript that gets run after the above div
        # gets inserted. This happens because of the setTimeout function
        # below which gets passed an anonymous function.
        s += """<script>
             (function() {
                 var values = %s, pos = [%s, %s], sel = '#%s', updatePos;
                 updatePos = function() {
                     pos[0] = $(sel).slider('values', 0);
                     pos[1] = $(sel).slider('values', 1);
                     if (values != null) {
                         $(sel + '-lbl').text('(' + values[pos[0]] + ', ' +
                                              values[pos[1]] + ')');
                     }
                 };
                 setTimeout(function() {
                     $(sel).slider({
                         range: true,
                         step: 1,
                         min: 0,
                         max: %s,
                         values: [%s, %s],
                         change: function (e, ui) {
                             updatePos();
                             %s;
                         },
                         slide: updatePos
                     });
                     updatePos();
                 }, 1);
             })();
             </script>""" % (values, default_l, default_r, id, steps - 1,
                             default_l, default_r, callback)

        # Note: Change 'change' to 'slide' and it changes the slider every
        # time it moves; needs much more work to actually work, since
        # server gets flooded by requests.

        return s

    def html_color_selector(id, change, input_change, default='000000',
                            widget='colorpicker', hide_box=False):
        """
        Return HTML representation of a jQuery color selector.

        INPUT:

        - ``id`` - an integer or string; an identifier (e.g., cell ID) for
          this selector

        - ``change`` - a string; JavaScript code to execute when the color
          selector changes.

        - ``default`` - a string (default: ``'000000'``); default color as
          a 6-character HTML hexadecimal string.

        - ``widget`` - a string (default: 'colorpicker'); the color
          selector widget to use; choices are 'colorpicker', 'farbtastic' and
          'jpicker' (currently broken)

        - ``hide_box`` - a boolean (default: False); whether to hide the
          input box associated with the color selector widget

        OUTPUT:

        - a string - HTML that creates the slider.

        EXAMPLES::

            sage: sagenb.notebook.interact.html_color_selector(0, 'alert("changed")', '', default='0afcac')
            '...<table>...colorpicker...'
            sage: sagenb.notebook.interact.html_color_selector(99, 'console.log(color);', '', default='fedcba', widget='farbtastic', hide_box=True)
            '...<table>...farbtastic...'
        """
        input_style = ''
        if hide_box:
            input_style = 'display: none;'

        if widget == 'farbtastic':
            # HTML
            s = """
                <table>
                  <tr>
                    <td>
                      <div id="%s-picker"></div>
                    </td>
                    <td>
                      <input type="text"
                             id="%s"
                             name="color"
                             onchange="%s; $(this).css({backgroundColor: this.value, color: ''}); $.farbtastic('#%s-picker').setColor(this.value);"
                             value="%s"
                             style="%s"/>
                    </td>
                  </tr>
                </table>""" % (id, id, input_change, id, default, input_style)

            # We now generate javascript that gets run after the above div
            # gets inserted. This happens because of the setTimeout
            # function below which gets passed an anonymous function.
            # Figuring out the below took understanding jQuery much
            # better, and took me surprisingly long, especially the part
            # involving linkTo which sets the callback.
            s += """<script>
                 setTimeout(function () {
                     var input = $('#%s'), picker = $.farbtastic('#%s-picker');
                     picker.linkTo('#%s').linkTo(function (color) {
                         if (input.val() !== color) {
                             input.val(color);
                             input.css({
                                 backgroundColor: color,
                                 color: picker.hsl[2] > 0.5 ? '#000000' : '#ffffff'
                             });
                             %s;
                         }
                     })
                 }, 1);
                 </script>""" % (id, id, id, change)

        elif widget == 'colorpicker':
            # HTML
            select = 'background: url(/javascript/jquery/plugins/colorpicker/images/select.png)'
            style1 = 'position: relative; width: 36px; height: 36px; %s;' % select
            style2 = 'position: absolute; top: 3px; left: 3px; width: 30px; height: 30px; %s center; background-color: %s' % (select, default)

            s = """
                <table>
                  <tr>
                    <td>
                      <input type="text"
                             id="%s"
                             name="color"
                             onchange="%s; $(this).css({backgroundColor: this.value}); $('#%s-picker').ColorPickerSetColor(this.value.slice(1)); $('#%s-picker div').css({backgroundColor: this.value});"
                             value="%s"
                             style="%s" />
                    </td>
                    <td>
                      <div id="%s-picker" style="%s">
                        <div style="%s"></div>
                      </div>
                    </td>
                  </tr>
                </table>""" % (id, input_change, id, id, default, input_style,
                               id, style1, style2)

            # JS
            s += """<script>
                 setTimeout(function () {
                     var def = '%s'.slice(1), div = $('#%s-picker div'),
                         input = $('#%s'), picker = $('#%s-picker');
                     input.css({
                         backgroundColor: '%s',
                         // Should be good enough:
                         color: (parseInt(def.slice(0, 2), 16) + parseInt(def.slice(2, 4), 16) + parseInt(def.slice(4, 6), 16)) / 3 > 127 ? '#000000' : '#ffffff'
                     });
                     picker.ColorPicker({
                         color : '%s',
                         onShow : function (pkr) {
                             $(pkr).css({zIndex: '10'}).show();
                             return false;
                         },
                         onChange : function (hsb, hex, rgb) {
                             color = '#' + hex;
                             if (input.val() !== color) {
                                 input.val(color);
                                 input.css({
                                     backgroundColor: color,
                                     color: hsb.b > 50 ? '#000000' : '#ffffff'
                                 });
                                 div.css({backgroundColor: color});
                                 %s;
                             }
                         },
                         onSubmit : function (hsb, hex, rgb, el) {
                             $(el).ColorPickerHide();
                         }
                     });
                 }, 1);
                 </script>""" % (default, id, id, id, default, default, change)

        elif widget == 'jpicker':
            # HTML.
            s = """
                <table>
                  <tr>
                    <td>
                      <input type="text"
                             id="%s"
                             name="color"
                             onchange="%s; $(this).css({backgroundColor: this.value}); $('.jPicker_HexText', $('#%s-picker').next()).val(this.value.slice(1)).trigger('keyup');"
                             value="%s"
                             style="%s" />
                    </td>
                    <td>
                      <div id="%s-picker"></div>
                    </td>
                  </tr>
                </table>
                """ % (id, input_change, id, default, input_style, id)

            # JS.  Note: jPicker uses, e.g., 'abcdef' instead of '#abcdef'
            # for bound input fields.  To maintain consistency with the
            # Farbtastic and ColorPicker implementations above, we do not
            # simply call $('#%s').jPicker({...}).
            s += """<script>
                 setTimeout(function () {
                     var def = '%s'.slice(1), input = $('#%s'),
                         picker = $('#%s-picker');
                     input.css({
                         backgroundColor: '%s',
                         // Should be good enough:
                         color: (parseInt(def.slice(0, 2), 16) + parseInt(def.slice(2, 4), 16) + parseInt(def.slice(4, 6), 16)) / 3 > 127 ? '#000000' : '#ffffff'
                     });
                     picker.jPicker(
                         // Settings.
                         {
                             window: {
                                 expandable: true,
                                 position: { x: 20, y: 20 },
                                 title: 'Select a color'
                             },
                             color: {
                                 active: '%s'
                             },
                             images: {
                                 clientPath: '/javascript/jquery/plugins/jpicker/images/'
                             }
                         },
                         // commitCallback
                         function (color) {},
                         // liveCallback
                         function (color_arg) {
                             color = '#' + color_arg.hex;
                             if (input.val() !== color) {
                                 input.val(color);
                                 input.css({
                                     backgroundColor: color,
                                     color: color_arg.v > 50 ? '#000000' : '#ffffff'
                                 });
                                 %s;
                             }
                         },
                         // cancelCallback
                         function (color) {}
                     );
                 }, 1);
                 </script>""" % (default, id, id, default, default, change)

        return s

    class InteractElement(object):
        def label(self):
            """
            Returns an empty label for this element. This should be
            overridden for subclasses that need a label.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: from sagenb.notebook.interact import UpdateButton, InteractElement
                sage: b = UpdateButton(1, 'autoupdate')
                sage: isinstance(b, InteractElement)
                True
                sage: b.label()
                ''
            """
            return ""

        def set_canvas(self, canvas):
            """
            Sets the :class:`InteractCanvas` on which this element
            appears.  This method is primarily called in the constructor
            for :class:`InteractCanvas`.

            EXAMPLES::

                sage: from sagenb.notebook.interact import InputBox, InteractCanvas
                sage: B = InputBox('x',2)
                sage: canvas1 = InteractCanvas([B], 3)
                sage: canvas2 = InteractCanvas([B], 3)
                sage: B.canvas() is canvas2
                True
                sage: B.set_canvas(canvas1)
                sage: B.canvas() is canvas1
                True
            """
            self._canvas = canvas

        def canvas(self):
            """
            Returns the :class:`InteractCanvas` associated to this
            element.  If no canvas has been set (via the
            :meth:`set_canvas` method), then raise a ValueError.

            EXAMPLES::

                sage: from sagenb.notebook.interact import InputBox, InteractCanvas
                sage: B = InputBox('x',2)
                sage: canvas1 = InteractCanvas([B], 3)
                sage: canvas2 = InteractCanvas([B], 3)
                sage: B.canvas() is canvas2
                True
            """
            if hasattr(self, '_canvas'):
                return self._canvas
            else:
                raise ValueError("this element does not have a canvas associated with it")

    class InteractControl(InteractElement):
        def __init__(self, var, default_value, label=None):
            """
            Abstract base class for :func:`interact` controls.  These are
            controls that are used in a specific :func:`interact`.  They
            have internal state information about the specific function
            being interacted, etc.

            INPUT:

            - ``var`` - a string; name of variable that this control
              interacts

            - ``default_value`` - the default value of the variable
              corresponding to this control.

            - ``label`` - a string (default: None); label for this
              control; if None then defaults to ``var``.

            EXAMPLES::

                sage: from sagenb.notebook.interact import InteractControl
                sage: InteractControl('x', default_value=5)
                A InteractControl (abstract base class)
            """
            self.__var = var
            self.__cell_id = SAGE_CELL_ID
            self.__default_value = default_value
            self.__adapt_number = new_adapt_number()
            if label is None:
                self.__label = var
            else:
                self.__label = label

            InteractElement.__init__(self)

        def __repr__(self):
            """
            String representation of :func:`interact` control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: from sagenb.notebook.interact import InteractControl
                sage: InteractControl('x', default_value=5).__repr__()
                'A InteractControl (abstract base class)'
            """
            return "A InteractControl (abstract base class)"

        def value_js(self):
            """
            JavaScript that when evaluated gives the current value of this
            control.  This should be redefined in a derived class.

            OUTPUT:

            - a string - defaults to 'NULL' - this should be redefined.

            EXAMPLES::

                sage: sagenb.notebook.interact.InteractControl('x', default_value=5).value_js()
                'NULL'
            """
            return 'NULL'

        def label(self):
            """
            Return the text label of this :func:`interact` control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: from sagenb.notebook.interact import InteractControl
                sage: InteractControl('x', default_value=5, label='the x value').label()
                'the x value'
            """
            return self.__label

        def default_value(self):
            """
            Return the default value of the variable corresponding to this
            :func:`interact` control.

            OUTPUT:

            - an object

            EXAMPLES::

                sage: from sagenb.notebook.interact import InteractControl
                sage: InteractControl('x', 19/3).default_value()
                19/3
            """
            return self.__default_value

        def html_escaped_default_value(self):
            """
            Returns the HTML escaped default value of the variable
            corresponding to this :func:`interact` control.  Note that any
            HTML that uses quotes around this should use double quotes and
            not single quotes.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: from sagenb.notebook.interact import InteractControl
                sage: InteractControl('x', '"cool"').html_escaped_default_value()
                '&quot;cool&quot;'
                sage: InteractControl('x',"'cool'").html_escaped_default_value()
                "'cool'"
                sage: x = var('x')
                sage: InteractControl('x', x^2).html_escaped_default_value()
                'x^2'
            """
            s = self.default_value()
            if not isinstance(s, str):
                s = repr(s)
            import cgi
            return cgi.escape(s, quote=True)

        def adapt_number(self):
            """
            Return integer index into adapt dictionary of function that is
            called to adapt the values of this control to Python.

            OUTPUT:

            - an integer

            EXAMPLES::

                sage: from sagenb.notebook.interact import InteractControl
                sage: InteractControl('x', 19/3).adapt_number()       # random -- depends on call order
                2
            """
            return self.__adapt_number

        def _adaptor(self, value, globs):
            """
            Adapt a user input, which is a string, to be an element selected
            by this control.

            INPUT:

            - ``value`` - the string the user typed in

            - ``globs`` - a string:object dictionary; the globals
              interpreter variables, e.g., :func:`globals`, which is
              useful for evaluating value.

            OUTPUT:

            - an object

            EXAMPLES::

                sage: sagenb.notebook.interact.InteractControl('x', 1)._adaptor('2/3', globals())
                2/3
            """
            return sage_eval(value, globs)

        def interact(self, *args):
            r"""
            Return a string that when evaluated in JavaScript calls the
            JavaScript :func:`interact` function with appropriate inputs for
            this control.

            This method will check to see if there is a canvas attached to
            this control and whether or not controls should automatically
            update the output when their values change.  If no canvas is
            associated with this control, then the control will
            automatically update.

            OUTPUT:

            - a string - that is meant to be evaluated in JavaScript

            EXAMPLES::

                sage: sagenb.notebook.interact.InteractControl('x', 1).interact()
                "...interact...x...1..."
            """
            # We have to do a try/except block here since the control may
            # not have a canvas associated with it.
            try:
                auto_update = self.canvas().is_auto_update()
            except ValueError:
                auto_update = True

            recompute = 0

            if auto_update:
                recompute = 1

            update = "{variable: '%s', adapt_number: %s, value: encode64(%s)}" % (
                self.var(), self.adapt_number(), self.value_js(*args))

            return "interact(%r, %s, %s)" % (self.cell_id(), update, recompute)

        def var(self):
            """
            Return the name of the variable that this control interacts.

            OUTPUT:

            - a string - name of a variable as a string.

            EXAMPLES::

                sage: sagenb.notebook.interact.InteractControl('theta', 1).var()
                'theta'
            """
            return self.__var

        def cell_id(self):
            """
            Return the ID of the cell that contains this :func:`interact` control.

            OUTPUT:

            - an integer or a string

            EXAMPLES:

            The output below should equal the ID of the current cell::

                sage: sagenb.notebook.interact.InteractControl('theta', 1).cell_id()
                0
            """
            return self.__cell_id

    class InputBox(InteractControl):
        def __init__(self, var, default_value, label=None, type=None, width=80, height = 1, **kwargs):
            """
            An input box :func:`interact` control.

            INPUT:

            - ``var`` - a string; name of variable that this control
              interacts

            - ``default_value`` - the default value of the variable
              corresponding to this control

            - ``label`` - a string (default: None); label for this
              control

            - ``type`` - a type (default: None); the type of this control,
              e.g., the type 'bool'

            - ``height`` - an integer (default: 1); the number of rows.
              If greater than 1 a value won't be returned until something
              outside the textarea is clicked.

            - ``width`` - an integer (default: 80); the character width of
              this control

            - ``kwargs`` - a dictionary; additional keyword options

            EXAMPLES::

                sage: sagenb.notebook.interact.InputBox('theta', 1, 'theta')
                An InputBox interactive control with theta=1 and label 'theta'
                sage: sagenb.notebook.interact.InputBox('theta', 1, 'theta', int)
                An InputBox interactive control with theta=1 and label 'theta'
            """
            InteractControl.__init__(self, var, default_value, label)
            self.__type = type
            self.__width = width
            self.__height = height
            self._kwargs = kwargs

        def __repr__(self):
            """
            String representation of an :class:`InputBox` interactive control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.InputBox('theta', 1).__repr__()
                "An InputBox interactive control with theta=1 and label 'theta'"
            """
            return 'An InputBox interactive control with %s=%r and label %r' % (
                self.var(), self.default_value(), self.label())

        def _adaptor(self, value, globs):
            """
            Adapt a user input, which is the text they enter, to be an
            element selected by this control.

            INPUT:

            - ``value`` - text entered by user

            - ``globs`` - a string:object dictionary; the :func:`globals`
              interpreter variables (not used here).

            OUTPUT:

            - an object

            EXAMPLES::

                sage: sagenb.notebook.interact.InputBox('theta', Color('red'), type=Color)._adaptor('#aaaaaa',globals())
                RGB color (0.66..., 0.66..., 0.66...)
            """
            if self.__type is None:
                return sage_eval(value, globs)
            elif self.__type is str:
                return value
            elif self.__type is Color:
                try:
                    return Color(value)
                except ValueError:
                    try:
                        return Color('#' + value)
                    except ValueError:
                        print("Invalid color '%s', using default Color()" % value)
                        return Color()
            else:
                return self.__type(sage_eval(value, globs))

        def value_js(self):
            """
            Return JavaScript string that will give the value of this
            control element.

            OUTPUT:

            - a string - JavaScript

            EXAMPLES::

                sage: sagenb.notebook.interact.InputBox('theta', 1).value_js()
                'this.value'
            """
            if self.__type is bool:
                return 'this.checked'
            else:
                return 'this.value'

        def render(self):
            r"""
            Render this control as a string.

            OUTPUT:

            - a string - HTML format

            EXAMPLES::

                sage: sagenb.notebook.interact.InputBox('theta', 1).render()
                '...input...value="1"...theta...'
            """
            if self.__type is bool:
                return """<input type="checkbox" %s width=200px onchange="%s"></input>"""%(
                    'checked' if self.default_value() else '',  self.interact())
            elif self.__type is str and self.__height ==1:
                return """<input type="text" value="%s" size=%s onchange="%s"></input>"""%(
                    self.html_escaped_default_value(), self.__width, self.interact())
            elif self.__type is str and self.__height > 1:
                textval = self.html_escaped_default_value()
                return """<textarea type="text" value="%s" rows="%s" cols="%s" onchange="%s">%s</textarea>"""%(
                    textval, self.__height, self.__width, self.interact(), textval)
            else:
                return """<input type="text" value="%s" size=%s onchange="%s"></input>"""%(
                    self.html_escaped_default_value(), self.__width,  self.interact())

    class ColorInput(InputBox):
        def value_js(self, n):
            """
            Return JavaScript that evaluates to value of this control.
            If ``n`` is 0, return code for evaluation by the actual color
            control.  If ``n`` is 1, return code for the text area that
            displays the current color.

            INPUT:

            - ``n`` - integer, either 0 or 1.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: C = sagenb.notebook.interact.ColorInput('c', Color('red'))
                sage: C.value_js(0)
                'color'
                sage: C.value_js(1)
                'this.value'
            """
            if n == 0:
                return 'color'
            else:
                return 'this.value'

        def render(self):
            """
            Render this color input box to HTML.

            OUTPUT:

            - a string - HTML format

            EXAMPLES::

                sage: sagenb.notebook.interact.ColorInput('c', Color('red')).render()
                '...table...color...'
            """
            return html_color_selector('color-selector-%s-%s' % (self.var(),
                                                                 self.cell_id()),
                                       change=self.interact(0),
                                       input_change=self.interact(1),
                                       default=self.default_value().html_color(),
                                       **self._kwargs)

    class InputGrid(InteractControl):
        def __init__(self, var, rows, columns, default_value=None, label=None,
                     to_value=lambda x: x, width=4):
            """
            A grid interact control.

            INPUT:

            - ``var`` - an object; the variable

            - ``rows`` - an integer; the number of rows

            - ``columns`` - an integer; the number of columns

            - ``default_value`` - an object; if this is a scalar, it is
              put in every cell; if it is a list, it is filled into the
              cells row by row; if it is a nested list, then it is filled
              into the cells according to the nesting structure.

            - ``label`` - a string; the label for the control

            - ``to_value`` - a function applied to the nested list from
              user input when assigning the variable

            - ``width`` - an integer; the width of the input boxes

            EXAMPLES::

                sage: sagenb.notebook.interact.InputGrid('M', 2,2, default_value = 0, label='M')
                A 2 x 2 InputGrid interactive control with M=[[0, 0], [0, 0]] and label 'M'
                sage: sagenb.notebook.interact.InputGrid('M', 2,2, default_value = [[1,2],[3,4]], label='M')
                A 2 x 2 InputGrid interactive control with M=[[1, 2], [3, 4]] and label 'M'
                sage: sagenb.notebook.interact.InputGrid('M', 2,2, default_value = [[1,2],[3,4]], label='M', to_value=MatrixSpace(ZZ,2,2))
                A 2 x 2 InputGrid interactive control with M=[1 2]
                [3 4] and label 'M'
                sage: sagenb.notebook.interact.InputGrid('M', 1, 3, default_value=[1,2,3], to_value=lambda x: vector(flatten(x)))
                A 1 x 3 InputGrid interactive control with M=(1, 2, 3) and label 'M'
            """
            self.__rows = rows
            self.__columns = columns
            self.__to_value = to_value
            self.__width = width

            if type(default_value) != list:
                default_value = [[default_value for _ in range(columns)] for _ in range(rows)]
            elif not all(type(elt) == list for elt in default_value):
                default_value = [[default_value[i * columns + j] for j in xrange(columns)] for i in xrange(rows)]

            self.__default_value_grid = default_value

            InteractControl.__init__(self, var, self.__to_value(default_value), label)

        def __repr__(self):
            """
            String representation of an :class:`InputGrid` interactive control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.InputGrid('M', 2,2).__repr__()
                "A 2 x 2 InputGrid interactive control with M=[[None, None], [None, None]] and label 'M'"
            """

            return 'A %r x %r InputGrid interactive control with %s=%r and label %r' % (
                self.__rows, self.__columns, self.var(),  self.default_value(),
                self.label())

        def _adaptor(self, value, globs):
            """
            Adapt a user input, which is the text they enter, to be an
            element selected by this control.

            INPUT:

            - ``value`` - text entered by user

            - ``globs`` - a string:object dictionary; the :func:`globals`
              interpreter variables (not used here).

            OUTPUT:

            - an object

            EXAMPLES::

                sage: sagenb.notebook.interact.InputGrid('M', 1,3, default_value=[[1,2,3]], to_value=lambda x: vector(flatten(x)))._adaptor("[[4,5,6]]", globals())
                (4, 5, 6)
            """
            return self.__to_value(sage_eval(value, globs))

        def value_js(self):
            """
            Return JavaScript string that will give the value of this
            control element.

            OUTPUT:

            - string - JavaScript

            EXAMPLES::

                sage: sagenb.notebook.interact.InputGrid('M', 2,2).value_js()
                "...jQuery...table...map...val...join..."
            """
            # Basically, given an input element in a table, it constructs
            # a python string representation of a list of lists from the
            # rows in the table.
            return """
            '[[' +
                jQuery(this).parents('table').eq(0).find('tr').map(function() {
                    return jQuery(this).find('input').map(function() {
                        return jQuery(this).val();
                    }).get().join(',');
                }).get().join('],[') +
            ']]' """

        def render(self):
            """
            Render this control as a string.

            OUTPUT:

            - string - HTML format

            EXAMPLES::

                sage: sagenb.notebook.interact.InputGrid('M', 1,2).render()
                '...table...input...M...'
            """
            s = "<table>"

            for i in range(self.__rows):
                s += "  <tr>"
                for j in range(self.__columns):
                    s += '    <td>\n'
                    s += '      <input type="text" value="%r" size="%s" onchange="%s" />\n' % (self.__default_value_grid[i][j], self.__width, self.interact())
                    s += '    </td>\n'
                s += '  </tr>\n'
            s += '</table>\n'

            return s

    class Selector(InteractControl):
        def __init__(self, var, values, label=None, default=0,
                     nrows=None, ncols=None, width=None, buttons=False):
            """
            A drop down menu or a button bar that when pressed sets a
            variable to a given value.

            INPUT:

            - ``var`` - a string; variable name

            - ``values`` - a list; button values

            - ``label`` - a string (default: None); label off to the left
              for this button group

            - ``default`` - an integer (default: 0); position of default
              value in values list.

            - ``nrows`` - an integer (default: None); number of rows

            - ``ncols`` - an integer (default: None); number of columns

            - ``width`` - an integer (default: None); width of all the
              buttons

            - ``buttons`` - a bool (default: False); if True use buttons
                instead of dropdown

            EXAMPLES::

                sage: sagenb.notebook.interact.Selector('x', [1..5], 'alpha', default=2)
                Selector with 5 options for variable 'x'
                sage: sagenb.notebook.interact.Selector('x', [1..4], 'alpha', default=2, nrows=2, ncols=2, width=10, buttons=True)
                Selector with 4 options for variable 'x'
            """
            if (len(values) > 0 and isinstance(values[0], tuple) and
                len(values[0]) == 2):
                vals = [z[0] for z in values]
                lbls = [repr(z[1]) if z[1] is not None else None for z in values]
            else:
                vals = values
                lbls = [None] * len(vals)

            default = int(default)
            if default < 0 or default >= len(vals):
                default = 0

            InteractControl.__init__(self, var, vals[default], label)

            self.__default = default
            self.__buttons = buttons
            self.__values = vals
            self.__labels = lbls
            if nrows is None:
                if ncols is not None:
                    nrows = len(values) // ncols
                    if ncols * nrows < len(values):
                        nrows += 1
                else:
                    nrows = 1 # temporary
            else:
                nrows = int(nrows)
                if nrows <= 0:
                    nrows = 1
            if ncols is None:
                ncols = len(values) // nrows
                if ncols * nrows < len(values):
                    ncols += 1

            self.__nrows = nrows
            self.__ncols = ncols

            if width is not None:
                self.__width = "width:%sex;" % width
            else:
                self.__width = ''

            self.__selected = 'background-color:orange;'

        def __repr__(self):
            """
            String representation of a :class:`Selector` interactive control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.Selector('x', [1..5]).__repr__()
                "Selector with 5 options for variable 'x'"
            """
            return "Selector with %s options for variable '%s'" % (
                len(self.__values), self.var())

        def _adaptor(self, value, globs):
            """
            Adapt value of button or menu selection.  The button value is
            just an integer, and this function adapts it to be the value
            that we associate with that button.

            INPUT:

            - ``value` - an integer; value sent in via JavaScript

            - ``globs`` - a string:object dictionary; the :func:`globals`
              interpreter variables (not used here).

            OUTPUT:

            - an object

            EXAMPLES::

                sage: S = sagenb.notebook.interact.Selector('x', ['first',x^3+5])
                sage: S._adaptor(0,globals())
                'first'
                sage: S._adaptor(1,globals())
                x^3 + 5
            """
            return self.__values[int(value)]

        def use_buttons(self):
            """
            Whether or not to use buttons instead of a drop down menu for
            this select list.

            OUTPUT:

            - a bool

            EXAMPLES::

                sage: sagenb.notebook.interact.Selector('x', [1..5]).use_buttons()
                False
                sage: sagenb.notebook.interact.Selector('x', [1..5], buttons=True).use_buttons()
                True
            """
            return self.__buttons

        def value_js(self):
            """
            Return JavaScript string that will give the value of this
            control element.

            OUTPUT:

            - a string - JavaScript

            EXAMPLES::

                sage: sagenb.notebook.interact.Selector('x', [1..5]).value_js()
                'this.options[this.selectedIndex].value'
                sage: sagenb.notebook.interact.Selector('x', [1..5], buttons=True).value_js()
                'this.value'
            """
            if self.use_buttons():
                return 'this.value'
            else:
                # Now we have to use a option selector.
                return 'this.options[this.selectedIndex].value'

        def render(self):
            """
            Render this control as a string.

            OUTPUT:

            - a string - HTML format

            EXAMPLES::

                sage: sagenb.notebook.interact.Selector('x', [1..5]).render()
                '...select...x...'
                sage: sagenb.notebook.interact.Selector('x', [1..5], buttons=True).render()
                '...table...button...x...'
            """
            width = self.__width
            vals = self.__values
            lbls = self.__labels
            default = self.__default
            use_buttons = self.use_buttons()
            event = self.interact()
            if use_buttons:
                #On selected buttons, border is set to inset, on
                #unselected boxes - outset. This usually is default
                #rendering.
                if len(vals) > 1:
                        event = """$('BUTTON', this.parentNode).css('border-style', 'outset'); $(this).css('border-style', 'inset'); %s""" % event
                s = """<table style="border:1px solid #dfdfdf; background-color:#efefef;">"""
            else:
                s = """<select onchange="%s;">""" % event
            i = 0
            for r in range(self.__nrows):
                if use_buttons:
                    s += '\n<tr><td>'
                for c in range(self.__ncols):
                    if i >= len(vals):
                        i += 1
                        continue
                    style = width
                    #if i == default:
                    #    style += self.__selected
                    if lbls[i] is None:
                        if isinstance(vals[i], str):
                            lbl = vals[i]
                        else:
                            lbl = repr(vals[i])
                    else:
                        lbl = lbls[i]
                    if use_buttons:
                        s += """<button style="%s%s" value="%s" onclick="%s">%s</button>\n""" % ('border-style:inset;' if i == default and len(vals) > 1 else 'border-style:outset;', style, i, event, lbl)
                    else:
                        s += '<option value="%s" %s>%s</option>\n' % (i, 'selected' if i == default else '', lbl)
                    i += 1
                if use_buttons:
                    s += '</td></tr>'
            if use_buttons:
                s += '</table>'
            else:
                s += '</select>'
            return s

    class SliderGeneric(InteractControl):
        def __init__(self, var, values, default_value, label=None,
                     display_value=True):
            """
            An abstract slider :func:`interact` control that takes on the
            given list of values.

            INPUT:

            - ``var`` - a string; name of variable being interacted

            - ``values`` - a list; a list of the values that the slider
                will take on

            - ``default_value`` - an object; default value of the slider.

            - ``label`` - a string; alternative label to the left of the
              slider, instead of the variable.

              - ``display_value`` - a bool; whether to display the current
                value on the slider

            EXAMPLES::

                sage: sagenb.notebook.interact.SliderGeneric('x', [1..5], 2, 'alpha')
                Abstract Slider Interact Control: alpha [1--|2|---5]
            """
            InteractControl.__init__(self, var, default_value, label=label)
            self.__values = values
            self.__display_value = display_value

        def __repr__(self):
            """
            Return string representation of this slider control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.SliderGeneric('x', [1..5], 2, 'alpha').__repr__()
                'Abstract Slider Interact Control: alpha [1--|2|---5]'
            """
            return "Abstract Slider Interact Control: %s [%s--|%s|---%s]" % (
                self.label(), self.__values[0],
                self.default_value(), self.__values[-1])

        def values(self):
            """
            Return list of values the slider acts on.

            OUTPUT:

            - a list

            EXAMPLES::

                sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha').values()
                [1, 2, 3, 4, 5]
            """
            return self.__values

        def display_value(self):
            """
            Returns whether to display the value on the slider.

            OUTPUT:

            - a bool

            EXAMPLES::

                sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha').display_value()
                True
            """
            return self.__display_value

        def values_js(self):
            """
            Returns JavaScript array representation of values or 'null' if
            display_value=False

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha').values_js()
                '["1","2","3","4","5"]'
                sage: sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha', False).values_js()
                'null'
                sage: sagenb.notebook.interact.Slider('x', [pi..2*pi], 2, 'alpha').values_js()
                '["pi","pi + 1","pi + 2","pi + 3"]'
            """
            if self.__display_value == False:
                return "null"
            s = "["
            for i in self.__values:
                ie = repr(i).replace("\\", "\\\\").replace("\"", "\\\"").replace("'", "\\'")
                s += "\"%s\"," % ie
            s = s[:-1] + ']'
            return s

    class Slider(SliderGeneric):
        def __init__(self, var, values, default_position, label=None,
                     display_value=True):
            """
            A slider :func:`interact` control that takes on the given list of
            values.

            INPUT:

            - ``var`` - a string; name of variable being interacted

            - ``values`` - a list; a list of the values that the slider
              will take on

            - ``default_position`` - an integer; default location that the
              slider is set to.

            - ``label`` - a string; alternative label to the left of the
              slider, instead of the variable.

              - ``display_value`` - a bool, whether to display the current
                value right of the slider

            EXAMPLES::

                sage: sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha')
                Slider Interact Control: alpha [1--|3|---5]
            """
            SliderGeneric.__init__(self, var, values, values[default_position],
                                   label=label, display_value=display_value)
            self.__default_position = default_position

        def __repr__(self):
            """
            Return string representation of this slider control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha').__repr__()
                'Slider Interact Control: alpha [1--|3|---5]'
            """
            return "Slider Interact Control: %s [%s--|%s|---%s]" % (
                self.label(), self.values()[0],
                self.default_value(), self.values()[-1])

        def default_position(self):
            """
            Return the default position (as an integer) of the slider.

            OUTPUT:

            - an integer

            EXAMPLES::

                sage: sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha').default_position()
                2
            """
            return self.__default_position

        def value_js(self):
            """
            Return JavaScript string that will give the value of this
            control element.

            OUTPUT:

            - a string - JavaScript

            EXAMPLES::

                sage: sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha').value_js()
                'position'
            """
            return "position"

        def _adaptor(self, position, globs):
            """
            Adapt a user input, which is the slider position, to be an
            element selected by this control.

            INPUT:

            - ``position`` - an object; position of the slider

            - ``globs`` - a string:object dictionary; the :func:`globals`
              interpreter variables (not used here).

            OUTPUT:

            - an object

            EXAMPLES::

                sage: sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha')._adaptor(2,globals())
                3
            """
            v = self.values()
            # We have to cast to int, since it comes back as a float that
            # is too big.
            return v[int(position)]

        def render(self):
            """
            Render this control as an HTML string.

            OUTPUT:

            - a string - HTML format

            EXAMPLES::

                sage: sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha').render()
                '...table...slider...["1","2","3","4","5"]...'

                sage: sagenb.notebook.interact.Slider('x', [1..5], 2, 'alpha', display_value=False).render()
                '...table...slider...null...'
            """

            return html_slider('slider-%s-%s'%(self.var(), self.cell_id()),
                               self.values_js(), self.interact(),
                               steps=len(self.values()),
                               default=self.default_position())

    class RangeSlider(SliderGeneric):
        def __init__(self, var, values, default_position, label=None,
                     display_value=True):
            """
            A range slider :func:`interact` control that takes on the given
            list of values.

            INPUT:

            - ``var`` - a string; name of variable being interacted

            - ``values`` - a list; a list of the values that the slider
              will take on

            - ``default_position`` - an integer 2-tuple; default location
              that the slider is set to.

            - ``label`` - a string; alternative label to the left of the
              slider, instead of the variable.

            - ``display_value`` - a bool, whether to display the current
              value below the slider

            EXAMPLES::

                sage: sagenb.notebook.interact.RangeSlider('x', [1..5], (2,3), 'alpha')
                Range Slider Interact Control: alpha [1--|3==4|---5]
            """
            SliderGeneric.__init__(self, var, values, (values[default_position[0]], values[default_position[1]]), label=label, display_value=display_value)
            self.__default_position = default_position

        def __repr__(self):
            """
            Return string representation of this slider control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.RangeSlider('x', [1..5], (2,3), 'alpha').__repr__()
                'Range Slider Interact Control: alpha [1--|3==4|---5]'
            """
            return "Range Slider Interact Control: %s [%s--|%s==%s|---%s]" % (
                self.label(), self.values()[0],
                self.default_value()[0], self.default_value()[1], self.values()[-1])

        def default_position(self):
            """
            Return the default position (as an integer) of the slider.

            OUTPUT:

            - an integer 2-tuple

            EXAMPLES::

                sage: sagenb.notebook.interact.RangeSlider('x', [1..5], (2,3), 'alpha').default_position()
                (2, 3)
            """
            return self.__default_position

        def value_js(self):
            """
            Return JavaScript string that will give the value of this
            control element.

            OUTPUT:

            - a string - JavaScript

            EXAMPLES::

                sage: sagenb.notebook.interact.RangeSlider('x', [1..5], (2,3), 'alpha').value_js()
                "pos[0]+' '+pos[1]"
            """
            return "pos[0]+' '+pos[1]"

        def _adaptor(self, position, globs):
            """
            Adapt a user input, which is the slider position, to be an
            element selected by this control.

            INPUT:

            - ``position`` - an object; position of the slider

            - ``globs` - a string:object dictionary; the :func:`globals`
              interpreter variables (not used here).

            OUTPUT:

            - an object

            EXAMPLES::

                sage: sagenb.notebook.interact.RangeSlider('x', [1..5], (2,3), 'alpha')._adaptor("2 3",globals())
                (3, 4)
            """
            v = self.values()
            s = position.split(' ')
            # Use of int() here matches it's use in Slider._adaptor
            return (v[int(s[0])], v[int(s[1])])

        def render(self):
            """
            Render this control as an HTML string.

            OUTPUT:

            - string - HTML format

            EXAMPLES::

                sage: sagenb.notebook.interact.RangeSlider('x', [1..5], (2,3), 'alpha').render()
                '...table...slider...["1","2","3","4","5"]...range...'

                sage: sagenb.notebook.interact.RangeSlider('x', [1..5], (2,3), 'alpha', display_value=False).render()
                '...table...slider...null...range...
            """

            return html_rangeslider('slider-%s-%s'%(self.var(), self.cell_id()),
                                    self.values_js(), self.interact(),
                                    steps=len(self.values()),
                                    default_l=self.default_position()[0],
                                    default_r=self.default_position()[1])

    class TextControl(InteractControl):
        def __init__(self, var, data):
            """
            A text field :func:`interact` control

            INPUT:

            - ``data`` - a string; the HTML value of the text field

            EXAMPLES::

                sage: sagenb.notebook.interact.TextControl('x', 'something')
                Text Interact Control: something
            """
            InteractControl.__init__(self, var, data, label='')
            self.__data = data

        def __repr__(self):
            """
            Return string representation of this control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.TextControl('x', 'something').__repr__()
                'Text Interact Control: something'
            """
            return 'Text Interact Control: %s' % self.default_value()

        def render(self):
            """
            Render this control as an HTML string.

            OUTPUT:

            - a string - HTML format

            EXAMPLES::

                sage: sagenb.notebook.interact.TextControl('x', 'something').render()
                '...div...something...'
            """
            return '<div style="color:black; padding-bottom:5px">%s</div>' % self.default_value()

    class InteractCanvas(object):
        def __init__(self, controls, id, layout=None, width=None, **options):
            """
            Base class for :func:`interact` canvases. This is where all
            the controls along with the output of the interacted function
            are laid out and rendered.

            INPUT:

            - ``controls`` - a list of :class:`InteractControl` instances.

            - ``id`` - an integer or a string; the ID of the cell that
              contains this InteractCanvas.

            - ``layout`` - a dictionary with keys
              'top','bottom','left','right' and values lists of rows of
              control variable names.  If a dictionary is not passed in,
              then the value of layout is set to the 'top' value.  If
              ``None``, then all control names are put on separate rows in
              the 'top' value.

            - ``width`` - the width of the interact control

            - ``options`` - any additional keyword arguments (for example,
              auto_update=False)

            EXAMPLES::

                sage: B = sagenb.notebook.interact.InputBox('x',2)
                sage: sagenb.notebook.interact.InteractCanvas([B], 3)
                Interactive canvas in cell 3 with 1 controls
            """
            for control in controls:
                control.set_canvas(self)

            self.__controls = controls
            self.__cell_id = id
            self.__width = width
            self.__options = options

            if layout is None:
                layout = [[c.var()] for c in self.__controls]
            if not isinstance(layout, dict):
                layout={'top': layout}
            self.__layout = layout

        def __repr__(self):
            """
            Print representation of an interactive canvas.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: B = sagenb.notebook.interact.InputBox('x',2)
                sage: sagenb.notebook.interact.InteractCanvas([B], 3).__repr__()
                'Interactive canvas in cell 3 with 1 controls'
            """
            return "Interactive canvas in cell %s with %s controls" % (
                self.__cell_id, len(self.__controls))

        def cell_id(self):
            """
            Return the ID of the cell that contains this :func:`interact` control.

            OUTPUT:

            - an integer or a string

            EXAMPLES:

            The output below should equal the ID of the current cell::

                sage: B = sagenb.notebook.interact.InputBox('x',2)
                sage: C = sagenb.notebook.interact.InteractCanvas([B], 3); C
                Interactive canvas in cell 3 with 1 controls
                sage: C.cell_id()
                3
            """
            return self.__cell_id

        def is_auto_update(self):
            r"""
            Returns True if any change of the values for the controls on
            this canvas should cause an update.  If ``auto_update=False`` was
            not specified in the constructor for this canvas, then this
            will default to True.

            OUTPUT:

            - a bool

            EXAMPLES::

                sage: B = sagenb.notebook.interact.InputBox('x',2)
                sage: canvas = sagenb.notebook.interact.InteractCanvas([B], 3)
                sage: canvas.is_auto_update()
                True
                sage: canvas = sagenb.notebook.interact.InteractCanvas([B], 3, auto_update=False)
                sage: canvas.is_auto_update()
                False
            """
            return self.__options.get('auto_update', True)

        def controls(self):
            """
            Return a list of controls in this canvas.

            OUTPUT:

            - list of controls

            .. note::

                Returns a reference to a mutable list.

            EXAMPLES::

                sage: B = sagenb.notebook.interact.InputBox('x',2)
                sage: sagenb.notebook.interact.InteractCanvas([B], 3).controls()
                [An InputBox interactive control with x=2 and label 'x']
            """
            return self.__controls

        def render_output(self):
            """
            Render in text (HTML) form the output portion of the
            :func:`interact` canvas.

            The output contains two special tags, <?TEXT> and <?HTML>,
            which get replaced at runtime by the text and HTML parts
            of the output of running the function.

            OUTPUT:

            - a string - HTML format

            EXAMPLES::

                sage: B = sagenb.notebook.interact.InputBox('x',2)
                sage: sagenb.notebook.interact.InteractCanvas([B], 3).render_output()
                '...div...interact...3...'
            """
            return """
            <div id="cell-interact-{0}">{1}
              <table border=0 bgcolor="white" width=100%>
                <tr>
                  <td bgcolor="white" align=left valign=top>
                    <pre>{2}</pre>
                  </td>
                </tr>
                <tr>
                  <td align=left valign=top>{3}</td>
                </tr>
              </table>{4}
            </div>""".format(self.cell_id(), INTERACT_START, INTERACT_TEXT,
                             INTERACT_HTML, INTERACT_END)

        def render_controls(self, side='top'):
            """
            Render in text (HTML) form all the input controls.

            OUTPUT:

            - a string - HTML format

            EXAMPLES::

                sage: B = sagenb.notebook.interact.InputBox('x',2)
                sage: sagenb.notebook.interact.InteractCanvas([B], 3).render_controls()
                '...table...x...input...2...'
            """
            if side not in self.__layout:
                return ''

            tbl_body = ''
            controls = dict([c.var(), c] for c in self.__controls)
            for row in self.__layout[side]:
                tbl_body += '<tr>'
                for c_name in row:
                    c = controls[c_name]
                    if c.label() == '':
                        tbl_body += '<td colspan=2>{0}</td>\n'.format(c.render())
                    else:
                        tbl_body += '<td align=right><font color="black">{0}&nbsp;</font></td><td>{1}</td>\n'.format(c.label(), c.render())

                tbl_body += '</tr>'

            return '<table>' + tbl_body + '</table>'

        def wrap_in_outside_frame(self, inside):
            """
            Return the entire HTML for the interactive canvas, obtained by
            wrapping all the inside HTML of the canvas in a div and a
            table.

            INPUT:

            - ``inside`` - a string; HTML

            OUTPUT:

            - a string - HTML format

            EXAMPLES::

                sage: B = sagenb.notebook.interact.InputBox('x',2)
                sage: sagenb.notebook.interact.InteractCanvas([B], 3).wrap_in_outside_frame('<!--inside-->')
                '...notruncate...div...interact...table...inside...'
            """
            return """<!--notruncate-->
            <div padding=6 id="div-interact-%s">
              <table width=800px height=20px bgcolor="#c5c5c5" cellpadding=15>
                <tr>
                  <td bgcolor="#f9f9f9" valign=top align=left>%s</td>
                </tr>
              </table>
            </div>""" % (self.cell_id(), inside)

        # The following could be used to make the interact frame resizable
        # and/or draggable.  Neither effect is as cool as it sounds!

        #    <script>
        #        setTimeout(function() {
        #            $('#div-interact-%s').resizable();
        #            $('#div-interact-%s').draggable();
        #        }, 1);
        #    </script>

        def render(self):
            """
            Render in text (HTML) the entire :func:`interact` canvas.

            OUTPUT:

            - string - HTML format

            EXAMPLES::

                sage: B = sagenb.notebook.interact.InputBox('x',2)
                sage: sagenb.notebook.interact.InteractCanvas([B], 3).render()
                '...notruncate...div...interact...table...x...'
            """
            html_controls={}
            for side in ('top','left','right','bottom'):
                html_controls[side] = self.render_controls(side=side)

            s = """
                <table>
                  <tr><td colspan=3>{top}</td></tr>
                  <tr><td>{left}</td><td style='width: 100%;'>{output}</td><td>{right}</td></tr>
                  <tr><td colspan=3>{bottom}</td></tr>
                </table>""".format(output=self.render_output(), **html_controls)

            s = self.wrap_in_outside_frame(s)
            return s

    class JavascriptCodeButton(InteractElement):
        def __init__(self, label, code):
            """
            This :func:`interact` element displays a button which when clicked
            executes JavaScript code in the notebook.

            EXAMPLES::

                sage: b = sagenb.notebook.interact.JavascriptCodeButton('Push me', 'alert("2")')
            """
            self.__label = label
            self.__code = code
            InteractElement.__init__(self)

        def render(self):
            r"""
            Returns the HTML to display this button.

            OUTPUT:

            - a string - HTML format

            EXAMPLES::

                sage: b = sagenb.notebook.interact.JavascriptCodeButton('Push me', 'alert("2")')
                sage: b.render()
                '...input...button...Push me...alert("2")...'
            """
            return """<input type="button" value="%s" onclick="%s">\n""" % (
                self.__label, self.__code)

    class UpdateButton(JavascriptCodeButton):
        def __init__(self, cell_id, var):
            r"""
            Creates an :func:`interact` button element.  A click on the
            button triggers recomputation of the cell with the current
            values of the variables.

            INPUT:

            - ``cell_id`` - an integer or string; the ambient cell's ID

            - ``var``` - a variable which is used in the layout

            EXAMPLES::

                sage: b = sagenb.notebook.interact.UpdateButton(0, 'auto_update')
                sage: b.render()
                '...input...button...Update...0...'
            """
            s = "interact(%r, {}, 1)" % cell_id
            JavascriptCodeButton.__init__(self, "Update", s)

            self.__var = var

        def var(self):
            """
            Return the name of the variable that this control interacts.

            OUTPUT:

            - a string - name of a variable as a string.

            EXAMPLES::

                sage: sagenb.notebook.interact.UpdateButton(1, 'auto_update').var()
                'auto_update'
            """
            return self.__var

    from sage.misc.decorators import decorator_defaults

    @decorator_defaults
    def interact(f, layout=None, width='800px'):
        r"""
        Use interact as a decorator to create interactive Sage notebook
        cells with sliders, text boxes, radio buttons, check boxes, and
        color selectors.  Simply put ``@interact`` on the line before a
        function definition in a cell by itself, and choose appropriate
        defaults for the variable names to determine the types of
        controls (see tables below).

        INPUT:

        - ``f`` - a Python function

        - ``layout`` (optional) - a dictionary with keys 'top', 'bottom', 'left', 'right' and values lists of rows of control variable names.  Controls are laid out according to this pattern.  If ``layout`` is not a dictionary, it is assumed to be the 'top' value.  If ``layout`` is None, then all controls are assigned separate rows in the ``top`` value.

        EXAMPLES:

        In each example below we use a single underscore for the function
        name.  You can use *any* name you want; it does not have to
        be an underscore.

        We create an interact control with two inputs, a text input for
        the variable ``a`` and a ``y`` slider that runs through the range of
        integers from `0` to `19`.

        ::

            sage: @interact
            ....: def _(a=5, y=(0..20)): print(a + y)
            ....:
            <html>...

        ::

            sage: @interact(layout=[['a','b'],['d']])
            ....: def _(a=x^2, b=(0..20), c=100, d=x+1): print(a+b+c+d)
            ....:
            <html>...

        ::

            sage: @interact(layout={'top': [['a', 'b']], 'left': [['c']], 'bottom': [['d']]})
            ....: def _(a=x^2, b=(0..20), c=100, d=x+1): print(a+b+c+d)
            ....:
            <html>...

        Draw a plot interacting with the "continuous" variable ``a``.  By
        default continuous variables have exactly 50 possibilities.

        ::

            sage: @interact
            ....: def _(a=(0,2)):
            ....:     show(plot(sin(x*(1+a*x)), (x,0,6)), figsize=4)
            <html>...

        Interact a variable in steps of 1 (we also use an unnamed
        function)::

            sage: @interact
            ....: def _(n=(10,100,1)):
            ....:     show(factor(x^n - 1))
            <html>...

        Interact two variables::

            sage: @interact
            ....: def _(a=(1,4), b=(0,10)):
            ....:     show(plot(sin(a*x+b), (x,0,6)), figsize=3)
            <html>...

        Place a block of text among the controls::

            sage: @interact
            ....: def _(t1=text_control("Factors an integer."), n="1"):
            ....:     print(factor(Integer(n)))
            <html>...

        If your the time to evaluate your function takes awhile, you may
        not want to have it reevaluated every time the inputs change.  In
        order to prevent this, you can add a keyword ``auto_update=False`` to
        your function to prevent it from updating whenever the values are
        changed.  This will cause a button labeled 'Update' to appear
        which you can click on to re-evaluate your function.

        ::

            sage: @interact
            ....: def _(n=(10,100,1), auto_update=False):
            ....:     show(factor(x^n - 1))
            <html>...

        DEFAULTS:

        Defaults for the variables of the input function determine
        interactive controls.  The standard controls are ``input_box``,
        ``slider``, ``range_slider``, ``checkbox``, ``selector``,
        ``input_grid``, and ``color_selector``.  There is also a text
        control (see the defaults below).

        * ``u = input_box(default=None, label=None, type=None)`` -
          input box with given ``default``; use ``type=str`` to get
          input as an arbitrary string

        * ``u = slider(vmin, vmax=None, step_size=1, default=None,
          label=None)`` - slider with given list of possible values;
          ``vmin`` can be a list

        * ``u = range_slider(vmin, vmax=None, step_size=1,
          default=None, label=None)`` - range slider with given list
          of possible values; ``vmin`` can be a list

        * ``u = checkbox(default=True, label=None)`` - a checkbox

        * ``u = selector(values, label=None, nrows=None, ncols=None,
          buttons=False)`` - a dropdown menu or buttons (get buttons
          if ``nrows``, ``ncols``, or ``buttons`` is set, otherwise a
          dropdown menu)

        * ``u = input_grid(nrows, ncols, default=None, label=None,
          to_value=lambda x:x, width=4)`` - an editable grid of
          objects (a matrix or array)

        * ``u = color_selector(default=(0,0,1), label=None,
          widget='colorpicker', hide_box=False)`` - a color selector with a
          possibly hidden input box; the ``widget`` can also be ``'farbtastic'``
          or ``'jpicker'`` (currently not working properly)

        * ``u = text_control(value='')`` - a block of text

        You can also create a color selector by setting the default value for
        an ``input_box`` to ``Color(...)``.

        There are also some convenient defaults that allow you to make
        controls automatically without having to explicitly specify them.
        E.g., you can make ``x`` a continuous slider of values between ``u``
        and ``v`` by just writing ``x=(u,v)`` in the argument list of
        your function.  These are all just convenient shortcuts for
        creating the controls listed above.

        * ``u`` - blank input_box field

        * ``u = element`` - input_box with ``default=element``, if
          element not below.

        * ``u = (umin,umax)`` - continuous slider (really `100` steps)

        * ``u = (umin,umax,du)`` - slider with step size ``du``

        * ``u = list`` - buttons if ``len(list)`` at most `5`;
          otherwise, drop down

        * ``u = iterator`` (e.g. a generator) - a slider (up to `10000`
          steps)

        * ``u = bool`` - a checkbox

        * ``u = Color('blue')`` - a color selector; returns ``Color``
          object

        * ``u = (default, v)`` - ``v`` as above, with given
          ``default`` value

        * ``u = (label, v)`` - ``v`` as above, with given ``label``
          (a string)

        * ``u = matrix`` - an ``input_grid`` with ``to_value`` set to
          ``matrix.parent()`` and default values given by the matrix

        .. note::

            Suppose you would like to make an interactive with a default
            RGB color of ``(1,0,0)``, so the function would have signature
            ``f(color=(1,0,0))``.  Unfortunately, the above shortcuts
            reinterpret the ``(1,0,0)`` as a discrete slider with step
            size 0 between 1 and 0.  Instead you should do the
            following::

                sage: @interact
                ....: def _(v = input_box((1,0,0))):
                ....:       show(plot(sin,color=v))
                <html>...

            An alternative::

                sage: @interact
                ....: def _(c = color_selector((1, 0, 0))):
                ....:       show(plot(sin, color = c))
                <html>...

        MORE EXAMPLES:

        We give an input box that allows one to enter completely arbitrary
        strings::

            sage: @interact
            ....: def _(a=input_box('sage', label="Enter your name", type=str)):
            ....:        print("Hello there %s"%a.capitalize())
            <html>...

        The scope of variables that you control via :func:`interact` are local
        to the scope of the function being interacted with. However, by
        using the ``global`` Python keyword, you can still modify global
        variables as follows::

            sage: xyz = 10
            sage: @interact
            ....: def _(a=('xyz',5)):
            ....:       global xyz
            ....:       xyz = a
            <html>...

        If you enter the above you obtain an :func:`interact` canvas.
        Entering values in the box changes the global variable ``xyz``.
        Here's a example with several controls::

            sage: @interact
            ....: def _(title=["A Plot Demo", "Something silly", "something tricky"], a=input_box(sin(x*sin(x*sin(x))), 'function'),
            ....:     clr = Color('red'), thickness=[1..30], zoom=(1,0.95,..,0.1), plot_points=(200..2000)):
            ....:     html('<h1 align=center>%s</h1>'%title)
            ....:     print(plot_points)
            ....:     show(plot(a, -zoom*pi,zoom*pi, color=clr, thickness=thickness, plot_points=plot_points))
            <html>...

        For a more compact color control, use an empty label and
        hide the input box::

            sage: @interact
            ....: def _(color=color_selector((1,0,1), label='', hide_box=True)):
            ....:     show(plot(x/(8/7+sin(x)), (x,-50,50), fill=True, fillcolor=color))
            <html>...

        We give defaults and name the variables::

            sage: @interact
            ....: def _(a=('first', (1,4)), b=(0,10)):
            ....:     show(plot(sin(a*x+sin(b*x)), (x,0,6)), figsize=3)
            <html>...

        Another example involving labels, defaults, and the slider
        command::

            sage: @interact
            ....: def _(a = slider(1, 4, default=2, label='Multiplier'),
            ....:     b = slider(0, 10, default=0, label='Phase Variable')):
            ....:     show(plot(sin(a*x+b), (x,0,6)), figsize=4)
            <html>...

        An example where the range slider control is useful::

            sage: @interact
            ....: def _(b = range_slider(-20, 20, 1, default=(-19,3), label='Range')):
            ....:     plot(sin(x)/x, b[0], b[1]).show(xmin=b[0],xmax=b[1])
            <html>...

        An example using checkboxes, obtained by making the default values
        bools::

            sage: @interact
            ....: def _(axes=('Show axes', True), square=False):
            ....:     show(plot(sin, -5,5), axes=axes, aspect_ratio = (1 if square else None))
            <html>...

        An example generating a random walk that uses a checkbox control
        to determine whether points are placed at each step::

            sage: @interact
            ....: def foo(pts = checkbox(True, "points"), n = (50,(10..100))):
            ....:     s = 0; v = [(0,0)]
            ....:     for i in range(n):
            ....:          s += random() - 0.5
            ....:          v.append((i, s))
            ....:     L = line(v, rgbcolor='#4a8de2')
            ....:     if pts: L += points(v, pointsize=20, rgbcolor='black')
            ....:     show(L)
            <html>...

        You can rotate and zoom into 3-D graphics while interacting with a
        variable::

            sage: @interact
            ....: def _(a=(0,1)):
            ....:     x,y = var('x,y')
            ....:     show(plot3d(sin(x*cos(y*a)), (x,0,5), (y,0,5)), figsize=4)
            <html>...

        A random polygon::

            sage: pts = [(random(), random()) for _ in xrange(20)]
            sage: @interact
            ....: def _(n = (4..len(pts)), c=Color('purple') ):
            ....:     G = points(pts[:n],pointsize=60) + polygon(pts[:n], rgbcolor=c)
            ....:     show(G, figsize=5, xmin=0, ymin=0)
            <html>...

        Two "sinks" displayed simultaneously via a contour plot and a 3-D
        interactive plot::

            sage: @interact
            ....: def _(q1=(-1,(-3,3)), q2=(-2,(-3,3))):
            ....:     x,y = var('x,y')
            ....:     f = q1/sqrt((x+1)^2 + y^2) + q2/sqrt((x-1)^2+(y+0.5)^2)
            ....:     C = contour_plot(f, (-2,2), (-2,2), plot_points=30, contours=15, cmap='cool')
            ....:     show(C, figsize=3, aspect_ratio=1)
            ....:     show(plot3d(f, (x,-2,2), (y,-2,2)), figsize=4)
            <html>...

        This is similar to above, but you can select the color map from a
        dropdown menu::

            sage: @interact
            ....: def _(q1=(-1,(-3,3)), q2=(-2,(-3,3)),
            ....:     cmap=['autumn', 'bone', 'cool', 'copper', 'gray', 'hot', 'hsv',
            ....:           'jet', 'pink', 'prism', 'spring', 'summer', 'winter']):
            ....:     x,y = var('x,y')
            ....:     f = q1/sqrt((x+1)^2 + y^2) + q2/sqrt((x-1)^2+(y+0.5)^2)
            ....:     C = contour_plot(f, (x,-2,2), (y,-2,2), plot_points=30, contours=15, cmap=cmap)
            ....:     show(C, figsize=3, aspect_ratio=1)
            <html>...

        A quadratic roots etch-a-sketch::

            sage: v = []
            sage: html('<h2>Quadratic Root Etch-a-sketch</h2>')
            <html>...<h2>Quadratic Root Etch-a-sketch</h2>...</html>
            sage: @interact
            ....: def _(a=[-10..10], b=[-10..10], c=[-10..10]):
            ....:     f = a*x^2 + b*x + c == 0; show(f)
            ....:     soln = solve(a*x^2 + b*x + c == 0, x)[0].rhs()
            ....:     show(soln)
            ....:     P = tuple(CDF(soln))
            ....:     v.append(P)
            ....:     show(line(v, rgbcolor='purple') + point(P, pointsize=200))
            <html>...

        In the following example, we only generate data for a given ``n``
        once, so that as one varies ``p`` the data does not randomly change.
        We do this by simply caching the results for each ``n`` in a
        dictionary.::

            sage: data = {}
            sage: @interact
            ....: def _(n=(500,(100,5000,1)), p=(1,(0.1,10))):
            ....:     n = int(n)
            ....:     if n not in data:
            ....:         data[n] = [(random(), random()) for _ in xrange(n)]
            ....:     show(points([(x^p,y^p) for x,y in data[n]], rgbcolor='black'), xmin=0, ymin=0, axes=False)
            <html>...

        A conchoid::

            sage: @interact
            ....: def _(k=(1.2,(1.1,2)), k_2=(1.2,(1.1,2)), a=(1.5,(1.1,2))):
            ....:     u, v = var('u,v')
            ....:     f = (k^u*(1+cos(v))*cos(u), k^u*(1+cos(v))*sin(u), k^u*sin(v)-a*k_2^u)
            ....:     show(parametric_plot3d(f, (u,0,6*pi), (v,0,2*pi), plot_points=[40,40], texture=(0,0.5,0)))
            <html>...

        An input grid::

            sage: @interact
            ....: def _(A=matrix(QQ,3,3,range(9)), v=matrix(QQ,3,1,range(3))):
            ....:     try:
            ....:         x = A\v
            ....:         html('$$%s %s = %s$$'%(latex(A), latex(x), latex(v)))
            ....:     except:
            ....:         html('There is no solution to $$%s x=%s$$'%(latex(A), latex(v)))
            <html>...
        """
        if not isinstance(f, types.FunctionType) and callable(f):
            f = f.__call__
        (args, varargs, varkw, defaults) = inspect.getargspec(f)

        if defaults is None:
            defaults = []

        n = len(args) - len(defaults)
        controls = [automatic_control(defaults[i - n] if i >= n else None).render(arg)
                    for i, arg in enumerate(args)]

        variables = {}
        adapt = {}
        state[SAGE_CELL_ID] = {'variables': variables, 'adapt': adapt}

        for control in controls:
            variables[control.var()] = control.default_value()
            adapt[control.adapt_number()] = control._adaptor

        # Replace the auto_update checkbox with a button that will cause
        # the cell to recompute itself.
        # TODO: Should auto_update=True yield a checkbox?
        auto_update = variables.get('auto_update', True)
        if auto_update is False:
            i = args.index('auto_update')
            controls[i] = UpdateButton(SAGE_CELL_ID, 'auto_update')

        C = InteractCanvas(controls, SAGE_CELL_ID, auto_update=auto_update, layout=layout,
                           width=width)
        html(C.render())

        def _():
            z = f(*[variables[arg] for arg in args])
            if z:
                print(z)

        state[SAGE_CELL_ID]['function'] = _

        return f

    ######################################################
    # Actual control objects that the user passes in
    ######################################################
    class control:
        def __init__(self, label=None):
            """
            An interactive control object used with the :func:`interact` command.
            This is the abstract base class.

            INPUTS:

            - ``label`` - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.control('a control')
                Interative control 'a control' (abstract base class)
            """
            self.__label = label

        def __repr__(self):
            """
            Return string representation of this control.  (It just
            mentions the label and that this is an abstract base class.)

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.control('a control').__repr__()
                "Interative control 'a control' (abstract base class)"
            """
            return "Interative control '%s' (abstract base class)" % self.__label

        def label(self):
            """
            Return the label of this control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: sagenb.notebook.interact.control('a control').label()
                'a control'
                sage: selector([1,2,7], 'alpha').label()
                'alpha'
            """
            return self.__label

        def set_label(self, label):
            """
            Set the label of this control.

            INPUT:

            - ``label`` - a string

            EXAMPLES::

                sage: C = sagenb.notebook.interact.control('a control')
                sage: C.set_label('sage'); C
                Interative control 'sage' (abstract base class)
            """
            self.__label = label

    class input_box(control):
        def __init__(self, default=None, label=None, type=None, width=80, height=1, **kwargs):
            r"""
            An input box interactive control.  Use this in conjunction
            with the :func:`interact` command.

            INPUT:

            - ``default`` - an object; the default put in this input box

            - ``label`` - a string; the label rendered to the left of the
              box.

            - ``type`` - a type; coerce inputs to this; this doesn't
              have to be an actual type, since anything callable will do.

            - ``height`` - an integer (default: 1); the number of rows.
              If greater than 1 a value won't be returned until something
              outside the textarea is clicked.

            - ``width`` - an integer; width of text box in characters

            - ``kwargs`` - a dictionary; additional keyword options

            EXAMPLES::

                sage: input_box("2+2", 'expression')
                Interact input box labeled 'expression' with default value '2+2'
                sage: input_box('sage', label="Enter your name", type=str)
                Interact input box labeled 'Enter your name' with default value 'sage'
                sage: input_box('Multiline\nInput',label='Click to change value',type=str,height=5)
                Interact input box labeled 'Click to change value' with default value 'Multiline\nInput'
            """
            self.__default = default
            self.__type = type
            control.__init__(self, label)
            self.__width = width
            self.__height = height
            self.__kwargs = kwargs

        def __repr__(self):
            """
            Return print representation of this input box.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: input_box("2+2", 'expression').__repr__()
                "Interact input box labeled 'expression' with default value '2+2'"
            """
            return "Interact input box labeled %r with default value %r"%(
                self.label(), self.__default)

        def default(self):
            """
            Return the default value of this input box.

            OUTPUT:

            - an object

            EXAMPLES::

                sage: input_box('2+2', 'Expression').default()
                '2+2'
                sage: input_box(x^2 + 1, 'Expression').default()
                x^2 + 1
                sage: checkbox(True, "Points").default()
                True
            """
            return self.__default

        def type(self):
            """
            Return the type that elements of this input box are coerced to
            or None if they are not coerced (they have whatever type
            they evaluate to).

            OUTPUT:

            - a type

            EXAMPLES::

                sage: input_box("2+2", 'expression', type=int).type()
                <type 'int'>
                sage: input_box("2+2", 'expression').type() is None
                True
            """
            return self.__type

        def render(self, var):
            r"""
            Return rendering of this input box as an :class:`InputBox` to be
            used for an :func:`interact` canvas.  Basically this specializes
            this input to be used for a specific function and variable.

            INPUT:

            - ``var`` - a string (variable; one of the variable names
              input to ``f``)

            OUTPUT:

            - an :class:`InputBox` instance

            EXAMPLES::

                sage: input_box("2+2", 'Exp').render('x')
                An InputBox interactive control with x='2+2' and label 'Exp'
            """
            if self.__type is Color:
                return ColorInput(var, default_value=self.__default,
                                  label=self.label(), type=self.__type,
                                  **self.__kwargs)
            else:
                return InputBox(var, default_value=self.__default,
                                height=self.__height,
                                label=self.label(), type=self.__type,
                                width=self.__width, **self.__kwargs)

    class color_selector(input_box):
        def __init__(self, default=(0, 0, 1), label=None,
                     widget='colorpicker', hide_box=False):
            r"""
            A color selector (also called a color chooser, picker, or
            tool) interactive control.  Use this with the :func:`interact`
            command.

            INPUT:

            - ``default`` - an instance of or valid constructor argument
              to :class:`Color` (default: (0,0,1)); the selector's default
              color; a string argument must be a valid color name (e.g.,
              'red') or HTML hex color (e.g., '#abcdef')

            - ``label`` - a string (default: None); the label rendered to
              the left of the selector.

            - ``widget`` - a string (default: 'colorpicker'); the color
              selector widget to use; choices are 'colorpicker', 'farbtastic',
              and 'jpicker' (currently broken)

            - ``hide_box`` - a boolean (default: False); whether to hide
              the input box associated with the color selector widget

            EXAMPLES::

                sage: color_selector()
                Interact color selector labeled None, with default RGB color (0.0, 0.0, 1.0), widget 'colorpicker', and visible input box
                sage: color_selector((0.5, 0.5, 1.0), widget='jpicker')
                Interact color selector labeled None, with default RGB color (0.5, 0.5, 1.0), widget 'jpicker', and visible input box
                sage: color_selector(default = Color(0, 0.5, 0.25))
                Interact color selector labeled None, with default RGB color (0.0, 0.5, 0.25), widget 'colorpicker', and visible input box
                sage: color_selector('purple', widget = 'colorpicker')
                Interact color selector labeled None, with default RGB color (0.50..., 0.0, 0.50...), widget 'colorpicker', and visible input box
                sage: color_selector('crayon', widget = 'colorpicker')
                Traceback (most recent call last):
                ...
                ValueError: unknown color 'crayon'
                sage: color_selector('#abcdef', label='height', widget='jpicker')
                Interact color selector labeled 'height', with default RGB color (0.6..., 0.8..., 0.9...), widget 'jpicker', and visible input box
                sage: color_selector('abcdef', label='height', widget='jpicker')
                Traceback (most recent call last):
                ...
                ValueError: unknown color 'abcdef'
            """
            input_box.__init__(self, default=Color(default), label=label,
                               type=Color, widget=widget, hide_box=hide_box)
            self.__widget = widget
            self.__hide_box = hide_box

        def __repr__(self):
            """
            Return the print representation of this color selector.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: color_selector(Color('red'), 'line color').__repr__()
                "Interact color selector labeled 'line color', with default RGB color (1.0, 0.0, 0.0), widget 'colorpicker', and visible input box"
                sage: color_selector(Color((1,0,1)), 'circle color', widget='jpicker', hide_box=True).__repr__()
                "Interact color selector labeled 'circle color', with default RGB color (1.0, 0.0, 1.0), widget 'jpicker', and hidden input box"
            """
            s = "Interact color selector labeled %r, with default %r, widget %r, and " % (self.label(), self.default(), self.widget())
            if self.hide_box():
                return s + "hidden input box"
            else:
                return s + "visible input box"

        def widget(self):
            """
            Return the name of the HTML widget for this color selector.

            OUTPUT:

            - a string; the widget's name

            EXAMPLES::

                sage: color_selector().widget()
                'colorpicker'
                sage: color_selector('#abcdef', hide_box=True, widget='farbtastic').widget()
                'farbtastic'
                sage: color_selector(widget='jpicker').widget()
                'jpicker'
                sage: color_selector(default=Color(0,0.5,0.25)).widget()
                'colorpicker'
            """
            return self.__widget

        def hide_box(self):
            """
            Return whether to hide the input box associated with this color
            selector.

            OUTPUT:

            - a boolean

            EXAMPLES::

                sage: color_selector().hide_box()
                False
                sage: color_selector('green', hide_box=True, widget='jpicker').hide_box()
                True
                sage: color_selector((0.75,0.5,0.25)).hide_box()
                False
            """
            return self.__hide_box

    class input_grid(control):
        def __init__(self, nrows, ncols, default=None, label=None,
                     to_value=lambda x: x, width=4):
            r"""
            An input grid interactive control.  Use this in conjunction
            with the :func:`interact` command.

            INPUT:

            - ``nrows`` - an integer

            - ``ncols`` - an integer

            - ``default`` - an object; the default put in this input box

            - ``label`` - a string; the label rendered to the left of the
              box.

            - ``to_value`` - a list; the grid output (list of rows) is
              sent through this function.  This may reformat the data or
              coerce the type.

            - ``width`` - an integer; size of each input box in characters

            NOTEBOOK EXAMPLE::

                @interact
                def _(m = input_grid(2,2, default = [[1,7],[3,4]],
                                     label='M=', to_value=matrix),
                      v = input_grid(2,1, default=[1,2],
                                     label='v=', to_value=matrix)):
                    try:
                        x = m\v
                        html('$$%s %s = %s$$'%(latex(m), latex(x), latex(v)))
                    except:
                        html('There is no solution to $$%s x=%s$$'%(latex(m), latex(v)))

            EXAMPLES::

                sage: input_grid(2,2, default = 0, label='M')
                Interact 2 x 2 input grid control labeled M with default value 0
                sage: input_grid(2,2, default = [[1,2],[3,4]], label='M')
                Interact 2 x 2 input grid control labeled M with default value [[1, 2], [3, 4]]
                sage: input_grid(2,2, default = [[1,2],[3,4]], label='M', to_value=MatrixSpace(ZZ,2,2))
                Interact 2 x 2 input grid control labeled M with default value [[1, 2], [3, 4]]
                sage: input_grid(1, 3, default=[[1,2,3]], to_value=lambda x: vector(flatten(x)))
                Interact 1 x 3 input grid control labeled None with default value [[1, 2, 3]]
            """
            self.__default = default
            self.__rows = nrows
            self.__columns = ncols
            self.__to_value = to_value
            self.__width = width
            control.__init__(self, label)

        def __repr__(self):
            """
            Return print representation of this input box.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: input_grid(2,2, label='M').__repr__()
                'Interact 2 x 2 input grid control labeled M with default value None'
            """
            return 'Interact %r x %r input grid control labeled %s with default value %s'%(
                self.__rows, self.__columns, self.label(),  self.default())

        def default(self):
            """
            Return the default value of this input grid.

            OUTPUT:

            - an object

            EXAMPLES::

                sage: input_grid(2,2, default=1).default()
                1
            """
            return self.__default

        def render(self, var):
            r"""
            Return rendering of this input grid as an :class:`InputGrid` to be
            used for an :func:`interact` canvas.  Basically this specializes
            this input to be used for a specific function and variable.

            INPUT:

            - ``var`` - a string (variable; one of the variable names
              input to ``f``)

            OUTPUT:

            - an :class:`InputGrid` instance.

            EXAMPLES::

                sage: input_grid(2,2).render('x')
                A 2 x 2 InputGrid interactive control with x=[[None, None], [None, None]] and label 'x'

            """
            return InputGrid(var, rows=self.__rows, columns=self.__columns,
                             default_value=self.__default, label=self.label(),
                             to_value=self.__to_value, width=self.__width)

    class checkbox(input_box):
        def __init__(self, default=True, label=None):
            """
            A checkbox interactive control.  Use this in conjunction with
            the :func:`interact` command.

            INPUT:

            - ``default`` - a bool (default: True); whether box should be
              checked or not

            - ``label`` - a string (default: None) text label rendered to
              the left of the box

            EXAMPLES::

                sage: checkbox(False, "Points")
                Interact checkbox labeled 'Points' with default value False
                sage: checkbox(True, "Points")
                Interact checkbox labeled 'Points' with default value True
                sage: checkbox(True)
                Interact checkbox labeled None with default value True
                sage: checkbox()
                Interact checkbox labeled None with default value True
            """
            input_box.__init__(self, bool(default), label=label, type=bool)

        def __repr__(self):
            """
            Print representation of this checkbox.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: checkbox(True, "Points").__repr__()
                "Interact checkbox labeled 'Points' with default value True"
            """
            return "Interact checkbox labeled %r with default value %r"% (
                self.label(), self.default())

    class slider_generic(control):
        def __init__(self, vmin, vmax=None, step_size=None, label=None,
                     display_value=True):
            control.__init__(self, label=label)
            self.__display_value = display_value
            self.__vmin = vmin
            self.__vmax = vmax
            self.__step_size = step_size

        @cached_method
        def values(self):
            """
            Returns list of values that this slider takes on, in order.

            OUTPUT:

            - a list

            .. note:: This is a reference to a mutable list.

            EXAMPLES::

                sage: sagenb.notebook.interact.slider(1,10,1/2).values()
                [1, 3/2, 2, 5/2, 3, 7/2, 4, 9/2, 5, 11/2, 6, 13/2, 7, 15/2, 8, 17/2, 9, 19/2, 10]
            """
            if isinstance(self.__vmin, list):
                vals = self.__vmin
            else:
                if self.__vmax is None:
                    self.__vmax = self.__vmin
                    self.__vmin = 0

                # Compute step size; vmin and vmax are both defined here
                # 500 is the length of the slider (in px)
                if self.__step_size is None:
                    self.__step_size = (self.__vmax-self.__vmin) / 499.0
                elif self.__step_size <= 0:
                    raise ValueError("invalid negative step size -- step size must be positive")

                #Compute list of values
                num_steps = int(math.ceil((self.__vmax-self.__vmin)/float(self.__step_size)))
                if num_steps <= 1:
                    vals = [self.__vmin, self.__vmax]
                else:
                    vals = srange(self.__vmin, self.__vmax, self.__step_size, include_endpoint=True)
                    if vals[-1] != self.__vmax:
                        try:
                            if vals[-1] > self.__vmax:
                                vals[-1] = self.__vmax
                            else:
                                vals.append(self.__vmax)
                        except (ValueError, TypeError):
                            pass

            # Is the list of values is small (len < =50), use the whole
            # list.  Otherwise, use part of the list.
            if len(vals) == 0:
                return [0]
            elif(len(vals) <= 500):
                return vals
            else:
                vlen = (len(vals)-1) / 499.0
                return [vals[(int)(i*vlen)] for i in range(500)]

        def display_value(self):
            """
            Returns whether to display the value on the slider.

            OUTPUT:

            - a bool

            EXAMPLES::

                sagenb.notebook.interact.slider_generic(1,10,1/2).display_value()
                True
            """
            return self.__display_value

    class slider(slider_generic):
        def __init__(self, vmin, vmax=None, step_size=None, default=None,
                     label=None, display_value=True):
            r"""
            An interactive slider control, which can be used in conjunction
            with the :func:`interact` command.

            INPUT:

            - ``vmin`` - an object

            - ``vmax`` - an object (default: None); if None then ``vmin``
              must be a list, and the slider then varies over elements of
              the list.

            - ``step_size`` - an integer (default: 1)

            - ``default`` - an object (default: None); default value is
              "closest" in ``vmin`` or range to this default.

            - ``label`` - a string

            - ``display_value`` - a bool, whether to display the current
              value to the right of the slider

            EXAMPLES:

            We specify both ``vmin`` and ``vmax``.  We make the default
            `3`, but since `3` isn't one of `3/17`-th spaced values
            between `2` and `5`, `52/17` is instead chosen as the
            default (it is closest)::

                sage: slider(2, 5, 3/17, 3, 'alpha')
                Slider: alpha [2--|52/17|---5]

            Here we give a list::

                sage: slider([1..10], None, None, 3, 'alpha')
                Slider: alpha [1--|3|---10]

            The elements of the list can be anything::

                sage: slider([1, 'x', 'abc', 2/3], None, None, 'x', 'alpha')
                Slider: alpha [1--|x|---2/3]
            """
            slider_generic.__init__(self, vmin, vmax, step_size, label,
                                    display_value)
            self.__default = default

        def __repr__(self):
            """
            Return string representation of this slider.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: slider(2, 5, 1/5, 3, 'alpha').__repr__()
                'Slider: alpha [2--|3|---5]'
            """
            return "Slider: %s [%s--|%s|---%s]" % (
                self.label(), self.values()[0],
                self.values()[self.default_index()], self.values()[-1])

        @cached_method
        def default_index(self):
            """
            Return default index into the list of values.

            OUTPUT:

            - an integer

            EXAMPLES::

                sage: slider(2, 5, 1/2, 3, 'alpha').default_index()
                2
            """
            # determine the best choice of index into the list of values
            # for the user-selected default
            if self.__default is None:
                return 0
            else:
                try:
                    i = self.values().index(self.__default)
                except ValueError:
                    # here no index matches - which is best?
                    try:
                        v = [(abs(self.__default - self.values()[j]), j) for j in range(len(self.values()))]
                        m = min(v)
                        i = m[1]
                    except TypeError: # abs not defined on everything, so give up
                        i = 0
                return i

        def render(self, var):
            """
            Render the :func:`interact` control for the given function and
            variable.

            INPUT:

             - ``var`` - a string; variable name

            OUTPUT:

            - a :class:`Slider` instance

            EXAMPLES::

                sage: S = slider(0, 10, 1, default=3, label='theta'); S
                Slider: theta [0--|3|---10]
                sage: S.render('x')
                Slider Interact Control: theta [0--|3|---10]
                sage: slider(2, 5, 2/7, 3, 'alpha').render('x')
                Slider Interact Control: alpha [2--|20/7|---5]
            """
            return Slider(var, self.values(), self.default_index(),
                          label=self.label(), display_value=self.display_value())

    class range_slider(slider_generic):
        def __init__(self, vmin, vmax=None, step_size=None, default=None, label=None,
                     display_value=True):
            r"""
            An interactive range slider control, which can be used in conjunction
            with the :func:`interact` command.

            INPUT:

            - ``vmin`` - an object

            - ``vmax`` - object or None; if None then ``vmin`` must be a
              list, and the slider then varies over elements of the list.

            - ``step_size`` - integer (default: 1)

            - ``default`` - a 2-tuple of objects (default: None); default
              range is "closest" in ``vmin`` or range to this default.

            - ``label`` - a string

            - ``display_value`` - a bool, whether to display the current
              value below the slider

            EXAMPLES:

            We specify both ``vmin`` and ``vmax``.  We make the default
            `(3,4)` but since neither is one of `3/17`-th spaced
            values between `2` and `5`, the closest values: `52/17`
            and `67/17`, are instead chosen as the default::

                sage: range_slider(2, 5, 3/17, (3,4), 'alpha')
                Range Slider: alpha [2--|52/17==67/17|---5]

            Here we give a list::

                sage: range_slider([1..10], None, None, (3,7), 'alpha')
                Range Slider: alpha [1--|3==7|---10]
            """
            slider_generic.__init__(self, vmin, vmax, step_size, label,
                                    display_value)
            self.__default = default

        def __repr__(self):
            """
            Return string representation of this slider.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: range_slider(2, 5, 1/5, (3,4), 'alpha').__repr__()
                'Range Slider: alpha [2--|3==4|---5]'
            """
            return "Range Slider: %s [%s--|%s==%s|---%s]" % (
                self.label(), self.values()[0],
                self.values()[self.default_index()[0]],
                self.values()[self.default_index()[1]], self.values()[-1])

        @cached_method
        def default_index(self):
            """
            Return default index into the list of values.

            OUTPUT:

            - an integer 2-tuple

            EXAMPLES::

                sage: range_slider(2, 5, 1/2, (3,4), 'alpha').default_index()
                (2, 4)
            """
            # Determine the best choice of index into the list of values
            # for the user-selected default.
            if self.__default is None:
                return (0,1)
            elif not isinstance(self.__default, tuple) or len(self.__default) != 2:
                raise TypeError("default value must be None or a 2-tuple.")
            else:
                dlist = []
                for i in [0, 1]:
                    try:
                        d = self.values().index(self.__default[i])
                    except ValueError:
                        # Here no index matches -- which is best?
                        try:
                            v = [(abs(self.__default[i] - self.values()[j]), j) for j in range(len(self.values()))]
                            m = min(v)
                            d = m[1]
                        except TypeError:
                            # abs not defined on everything, so give up
                            d = 0
                    dlist.append(d)
                return (dlist[0], dlist[1])

        def render(self, var):
            """
            Render the :func:`interact` control for the given function and
            variable.

            INPUT:

            - ``var`` - string; variable name

            OUTPUT:

            - a :class:`RangeSlider` instance

            EXAMPLES::

                sage: S = range_slider(0, 10, 1, default=(3,7), label='theta'); S
                Range Slider: theta [0--|3==7|---10]
                sage: S.render('x')
                Range Slider Interact Control: theta [0--|3==7|---10]
                sage: range_slider(2, 5, 2/7, (3,4), 'alpha').render('x')
                Range Slider Interact Control: alpha [2--|20/7==4|---5]
            """
            return RangeSlider(var, self.values(), self.default_index(),
                               label=self.label(),
                               display_value=self.display_value())

    class selector(control):
        def __init__(self, values, label=None, default=None,
                     nrows=None, ncols=None, width=None, buttons=False):
            r"""
            A drop down menu or a button bar that when pressed sets a
            variable to a given value.  Use this in conjunction with the
            :func:`interact` command.

            We use the same command to create either a drop down menu or
            selector bar of buttons, since conceptually the two controls
            do exactly the same thing - they only look different.  If
            either ``nrows`` or ``ncols`` is given, then you get a buttons
            instead of a drop down menu.

            INPUT:

            - ``values`` - [val0, val1, val2, ...] or [(val0, lbl0),
              (val1,lbl1), ...] where all labels must be given or given as
              None.

            - ``label`` - a string (default: None); if given, this label
              is placed to the left of the entire button group

            - ``default`` - an object (default: 0); default value in values
              list

            - ``nrows`` - an integer (default: None); if given determines
              the number of rows of buttons; if given buttons option below
              is set to True

            - ``ncols`` - an integer (default: None); if given determines
              the number of columns of buttons; if given buttons option
              below is set to True

            - ``width`` - an integer (default: None); if given, all
              buttons are the same width, equal to this in HTML ex
              units's.

            - ``buttons`` - a bool (default: False); if True, use buttons

            EXAMPLES::

                sage: selector([1..5])
                Drop down menu with 5 options
                sage: selector([1,2,7], default=2)
                Drop down menu with 3 options
                sage: selector([1,2,7], nrows=2)
                Button bar with 3 buttons
                sage: selector([1,2,7], ncols=2)
                Button bar with 3 buttons
                sage: selector([1,2,7], width=10)
                Drop down menu with 3 options
                sage: selector([1,2,7], buttons=True)
                Button bar with 3 buttons

            We create an :func:`interact` that involves computing charpolys of
            matrices over various rings::

                sage: @interact
                ....: def _(R=selector([ZZ,QQ,GF(17),RDF,RR]), n=(1..10)):
                ....:      M = random_matrix(R, n)
                ....:      show(M)
                ....:      show(matrix_plot(M,cmap='Oranges'))
                ....:      f = M.charpoly()
                ....:      print(f)
                <html>...

            Here we create a drop-down::

                sage: @interact
                ....: def _(a=selector([(2,'second'), (3,'third')])):
                ....:       print(a)
                <html>...
            """
            if nrows is not None or ncols is not None:
                buttons = True
            if default is None:
                default = 0
            else:
                try:
                    default = values.index(default)
                except IndexError:
                    default = 0
            self.__values = values
            self.__nrows = nrows
            self.__ncols = ncols
            self.__width = width
            self.__default = default
            self.__buttons = buttons
            control.__init__(self, label)

        def __repr__(self):
            """
            Return print representation of this button.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: selector([1,2,7], default=2).__repr__()
                'Drop down menu with 3 options'
            """
            if self.__buttons:
                return "Button bar with %s buttons" % len(self.__values)
            else:
                return "Drop down menu with %s options" % len(self.__values)

        def values(self):
            """
            Return the list of values or (val, lbl) pairs that this
            selector can take on.

            OUTPUT:

            - a list

            EXAMPLES::

                sage: selector([1..5]).values()
                [1, 2, 3, 4, 5]
                sage: selector([(5,'fifth'), (8,'eight')]).values()
                [(5, 'fifth'), (8, 'eight')]
            """
            return self.__values

        def default(self):
            """
            Return the default choice for this control.

            OUTPUT:

            - an integer, with 0 corresponding to the first choice.

            EXAMPLES::

                sage: selector([1,2,7], default=2).default()
                1
            """
            return self.__default

        def render(self, var):
            r"""
            Return rendering of this button as a :class:`Selector`
            instance to be used for an :func:`interact` canvas.

            INPUT:

            - ``var`` - a string (variable; one of the variable names
              input to ``f``)

            OUTPUT:

            - a :class:`Selector` instance

            EXAMPLES::

                sage: selector([1..5]).render('alpha')
                Selector with 5 options for variable 'alpha'
            """
            return Selector(var, values=self.__values, label=self.label(),
                            default=self.__default, nrows=self.__nrows,
                            ncols=self.__ncols, width=self.__width,
                            buttons=self.__buttons)

    class text_control(control):
        def __init__(self, value=''):
            """
            Text that can be inserted among other :func:`interact` controls.

            INPUT:

            - ``value`` - HTML for the control

            EXAMPLES::

                sage: text_control('something')
                Text field: something
            """
            self.__default = value
            control.__init__(self, '')

        def __repr__(self):
            """
            Return print representation of this control.

            OUTPUT:

            - a string

            EXAMPLES::

                sage: text_control('something')
                Text field: something
            """
            return "Text field: %s" % self.__default

        def render(self, var):
            """
            Return rendering of the text field

            INPUT:

            - ``var`` - a string (variable; one of the variable names
              input to ``f``)

            OUTPUT:

            - a :class:`TextControl` instance
            """
            return TextControl(var, self.__default)

    def automatic_control(default):
        """
        Automagically determine the type of control from the default
        value of the variable.

        INPUT:

        - ``default`` - the default value for ``v`` given by the function;
          see the documentation to :func:`interact` for details.

        OUTPUT:

        - an :func:`interact` control

        EXAMPLES::

            sage: sagenb.notebook.interact.automatic_control('')
            Interact input box labeled None with default value ''
            sage: sagenb.notebook.interact.automatic_control(15)
            Interact input box labeled None with default value 15
            sage: sagenb.notebook.interact.automatic_control(('start', 15))
            Interact input box labeled 'start' with default value 15
            sage: sagenb.notebook.interact.automatic_control((1,250))
            Slider: None [1.0--|1.0|---250.0]
            sage: sagenb.notebook.interact.automatic_control(('alpha', (1,250)))
            Slider: alpha [1.0--|1.0|---250.0]
            sage: sagenb.notebook.interact.automatic_control((2,(0,250)))
            Slider: None [0.0--|2.00400801603|---250.0]
            sage: sagenb.notebook.interact.automatic_control(('alpha label', (2,(0,250))))
            Slider: alpha label [0.0--|2.00400801603|---250.0]
            sage: sagenb.notebook.interact.automatic_control((2, ('alpha label',(0,250))))
            Slider: alpha label [0.0--|2.00400801603|---250.0]
            sage: C = sagenb.notebook.interact.automatic_control((1,52, 5)); C
            Slider: None [1--|1|---52]
            sage: C.values()
            [1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 52]
            sage: sagenb.notebook.interact.automatic_control((17, (1,100,5)))
            Slider: None [1--|16|---100]
            sage: sagenb.notebook.interact.automatic_control([1..4])
            Button bar with 4 buttons
            sage: sagenb.notebook.interact.automatic_control([1..100])
            Drop down menu with 100 options
            sage: sagenb.notebook.interact.automatic_control((1..100))
            Slider: None [1--|1|---100]
            sage: sagenb.notebook.interact.automatic_control((5, (1..100)))
            Slider: None [1--|5|---100]
            sage: sagenb.notebook.interact.automatic_control(matrix(2,2))
            Interact 2 x 2 input grid control labeled None with default value [0, 0, 0, 0]
        """
        label = None
        default_value = None

        for _ in range(2):
            if isinstance(default, tuple) and len(default) == 2 and isinstance(default[0], str):
                label, default = default
            if isinstance(default, tuple) and len(default) == 2 and isinstance(default[1], (tuple, list, collections.Iterator)):
                default_value, default = default

        if isinstance(default, control):
            C = default
            if label:
                C.set_label(label)
        elif isinstance(default, str):
            C = input_box(default, label=label, type=str)
        elif isinstance(default, bool):
            C = input_box(default, label=label, type=bool)
        elif isinstance(default, list):
            C = selector(default, default=default_value, label=label, buttons=len(default) <= 5)
        elif isinstance(default, collections.Iterator):
            C = slider(list_of_first_n(default, 10000), default=default_value, label=label)
        elif isinstance(default, Color):
            C = input_box(default, label=label, type=Color)
        elif isinstance(default, tuple):
            if len(default) == 2:
                C = slider(default[0], default[1], default=default_value, label=label)
            elif len(default) == 3:
                C = slider(default[0], default[1], default[2], default=default_value, label=label)
            else:
                C = slider(list(default), default=default_value, label=label)
        elif is_Matrix(default):
            C = input_grid(default.nrows(), default.ncols(), default=default.list(), to_value=default.parent(), label=label)
        else:
            C = input_box(default, label=label)

        return C

    def list_of_first_n(v, n):
        """
        Given an iterator v, return first n elements it produces as a list.

        INPUT:

        - ``v`` - an iterator

        - ``n`` - an integer

        OUTPUT:

        - a list

        EXAMPLES::

            sage: from itertools import takewhile
            sage: p100 = takewhile(lambda x: x < 100, Primes())
            sage: sagenb.notebook.interact.list_of_first_n(p100, 10)
            [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
            sage: sagenb.notebook.interact.list_of_first_n((1..5), 10)
            [1, 2, 3, 4, 5]
            sage: sagenb.notebook.interact.list_of_first_n(QQ, 10)
            [0, 1, -1, 1/2, -1/2, 2, -2, 1/3, -1/3, 3]
        """
        if not hasattr(v, 'next'):
            v = v.__iter__()
        w = []
        while n > 0:
            try:
                w.append(v.next())
            except StopIteration:
                return w
            n -= 1
        return w

    def update(cell_id, var, adapt, value, globs):
        r"""
        Called when updating the positions of an interactive control.
        Note that this just causes the values of the variables to be
        updated; it does not reevaluate the function with the new values.

        INPUT:

        - ``cell_id`` - an integer or string; the ID of an
          :func:`interact` cell

        - ``var`` - an object; a variable associated to that cell

        - ``adapt`` - in integer; the number of the adapt function

        - ``value`` - an object; new value of the control

        - ``globs`` - global variables.

        EXAMPLES:

        The following outputs __SAGE_INTERACT_RESTART__ to indicate that
        not all the state of the :func:`interact` canvas has been set up yet
        (this setup happens when JavaScript calls certain functions)::

            sage: sagenb.notebook.interact.update(0, 'a', 0, '5', globals())
            __SAGE_INTERACT_RESTART__
        """
        # We cast the id to an integer, if it's an integer.
        try:
            cell_id = int(cell_id)
        except ValueError:
            pass

        try:
            S = state[cell_id]
            # Look up the function that adapts inputs to have the right
            # type
            adapt_function = S["adapt"][adapt]
            # Apply that function and save the result in the appropriate
            # variables dictionary.
            S["variables"][var] = adapt_function(value, globs)
        except KeyError:
            # If you change this, make sure to change notebook_lib.js as
            # well.
            print(INTERACT_RESTART)

    def recompute(cell_id):
        """
        Evaluates the :func:`interact` function associated to the cell
        ``cell_id``. This typically gets called after a call to
        :func:`update`.

        INPUT:

        - ``cell_id`` - a string or an integer; the ID of an
          :func:`interact` cell

        EXAMPLES:

        The following outputs __SAGE_INTERACT_RESTART__ to indicate that
        not all the state of the :func:`interact` canvas has been set up yet
        (this setup happens when JavaScript calls certain functions)::

            sage: sagenb.notebook.interact.recompute(10)
            __SAGE_INTERACT_RESTART__

        """
        # We cast the id to an integer, if it's an integer.
        try:
            cell_id = int(cell_id)
        except ValueError:
            pass

        try:
            S = state[cell_id]
            # Finally call the interactive function, which will use the
            # above variables.
            S['function']()
        except KeyError:
            # If you change this, make sure to change notebook_lib.js as
            # well.
            print(INTERACT_RESTART)