def components(models, wrap_script=True, wrap_plot_info=True, theme=FromCurdoc):
    ''' Return HTML components to embed a Bokeh plot. The data for the plot is
    stored directly in the returned HTML.

    An example can be found in examples/embed/embed_multiple.py

    The returned components assume that BokehJS resources are **already loaded**.
    The html template in which they will be embedded needs to include the following
    links and scripts tags. The widgets and tables resources are only necessary if
    the components make use of widgets and tables.

    .. code-block:: html

        <link
            href="http://cdn.pydata.org/bokeh/release/bokeh-x.y.z.min.css"
            rel="stylesheet" type="text/css">
        <link
            href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-x.y.z.min.css"
            rel="stylesheet" type="text/css">
        <link
            href="http://cdn.pydata.org/bokeh/release/bokeh-tables-x.y.z.min.css"
            rel="stylesheet" type="text/css">

        <script src="http://cdn.pydata.org/bokeh/release/bokeh-x.y.z.min.js"></script>
        <script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-x.y.z.min.js"></script>
        <script src="http://cdn.pydata.org/bokeh/release/bokeh-tables-x.y.z.min.js"></script>

    Note that in Jupyter Notebooks, it is not possible to use components and show in
    the same notebook cell.

    Args:
        models (Model|list|dict|tuple) :
            A single Model, a list/tuple of Models, or a dictionary of keys and Models.

        wrap_script (boolean, optional) :
            If True, the returned javascript is wrapped in a script tag.
            (default: True)

        wrap_plot_info (boolean, optional) : If True, returns ``<div>`` strings.
            Otherwise, return dicts that can be used to build your own divs.
            (default: True)

            If False, the returned dictionary contains the following information:

            .. code-block:: python

                {
                    'modelid':  'The model ID, used with Document.get_model_by_id',
                    'elementid': 'The css identifier the BokehJS will look for to target the plot',
                    'docid': 'Used by Bokeh to find the doc embedded in the returned script',
                }

        theme (Theme, optional) :
            Defaults to the ``Theme`` instance in the current document.
            Setting this to ``None`` uses the default theme or the theme
            already specified in the document. Any other value must be an
            instance of the ``Theme`` class.

    Returns:
        UTF-8 encoded *(script, div[s])* or *(raw_script, plot_info[s])*

    Examples:

        With default wrapping parameter values:

        .. code-block:: python

            components(plot)
            # => (script, plot_div)

            components((plot1, plot2))
            # => (script, (plot1_div, plot2_div))

            components({"Plot 1": plot1, "Plot 2": plot2})
            # => (script, {"Plot 1": plot1_div, "Plot 2": plot2_div})

    Examples:

        With wrapping parameters set to ``False``:

        .. code-block:: python

            components(plot, wrap_script=False, wrap_plot_info=False)
            # => (javascript, plot_dict)

            components((plot1, plot2), wrap_script=False, wrap_plot_info=False)
            # => (javascript, (plot1_dict, plot2_dict))

            components({"Plot 1": plot1, "Plot 2": plot2}, wrap_script=False, wrap_plot_info=False)
            # => (javascript, {"Plot 1": plot1_dict, "Plot 2": plot2_dict})

    '''
    # 1) Convert single items and dicts into list

    was_single_object = isinstance(models, Model) or isinstance(models, Document)

    models = _check_models_or_docs(models)

    # now convert dict to list, saving keys in the same order
    model_keys = None
    dict_type = None
    if isinstance(models, dict):
        model_keys = models.keys()
        dict_type = models.__class__
        values = []
        # don't just use .values() to ensure we are in the same order as key list
        for k in model_keys:
            values.append(models[k])
        models = values

    # 2) Append models to one document. Either pre-existing or new and render
    with OutputDocumentFor(models, apply_theme=theme):
        (docs_json, [render_item]) = standalone_docs_json_and_render_items(models)

    script  = bundle_all_models() or ""
    script += script_for_render_items(docs_json, [render_item])
    if wrap_script:
        script = wrap_in_script_tag(script)
    script = encode_utf8(script)

    def div_for_root(root):
        return ROOT_DIV.render(root=root, macros=MACROS)

    if wrap_plot_info:
        results = list(div_for_root(root) for root in render_item.roots)
    else:
        results = render_item.roots

    # 3) convert back to the input shape

    if was_single_object:
        result = results[0]
    elif model_keys is not None:
        result = dict_type(zip(model_keys, results))
    else:
        result = tuple(results)

    return script, result
Return HTML components to embed a Bokeh plot. The data for the plot is
    stored directly in the returned HTML.

    An example can be found in examples/embed/embed_multiple.py

    The returned components assume that BokehJS resources are **already loaded**.
    The html template in which they will be embedded needs to include the following
    links and scripts tags. The widgets and tables resources are only necessary if
    the components make use of widgets and tables.

    .. code-block:: html

        <link
            href="http://cdn.pydata.org/bokeh/release/bokeh-x.y.z.min.css"
            rel="stylesheet" type="text/css">
        <link
            href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-x.y.z.min.css"
            rel="stylesheet" type="text/css">
        <link
            href="http://cdn.pydata.org/bokeh/release/bokeh-tables-x.y.z.min.css"
            rel="stylesheet" type="text/css">

        <script src="http://cdn.pydata.org/bokeh/release/bokeh-x.y.z.min.js"></script>
        <script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-x.y.z.min.js"></script>
        <script src="http://cdn.pydata.org/bokeh/release/bokeh-tables-x.y.z.min.js"></script>

    Note that in Jupyter Notebooks, it is not possible to use components and show in
    the same notebook cell.

    Args:
        models (Model|list|dict|tuple) :
            A single Model, a list/tuple of Models, or a dictionary of keys and Models.

        wrap_script (boolean, optional) :
            If True, the returned javascript is wrapped in a script tag.
            (default: True)

        wrap_plot_info (boolean, optional) : If True, returns ``<div>`` strings.
            Otherwise, return dicts that can be used to build your own divs.
            (default: True)

            If False, the returned dictionary contains the following information:

            .. code-block:: python

                {
                    'modelid':  'The model ID, used with Document.get_model_by_id',
                    'elementid': 'The css identifier the BokehJS will look for to target the plot',
                    'docid': 'Used by Bokeh to find the doc embedded in the returned script',
                }

        theme (Theme, optional) :
            Defaults to the ``Theme`` instance in the current document.
            Setting this to ``None`` uses the default theme or the theme
            already specified in the document. Any other value must be an
            instance of the ``Theme`` class.

    Returns:
        UTF-8 encoded *(script, div[s])* or *(raw_script, plot_info[s])*

    Examples:

        With default wrapping parameter values:

        .. code-block:: python

            components(plot)
            # => (script, plot_div)

            components((plot1, plot2))
            # => (script, (plot1_div, plot2_div))

            components({"Plot 1": plot1, "Plot 2": plot2})
            # => (script, {"Plot 1": plot1_div, "Plot 2": plot2_div})

    Examples:

        With wrapping parameters set to ``False``:

        .. code-block:: python

            components(plot, wrap_script=False, wrap_plot_info=False)
            # => (javascript, plot_dict)

            components((plot1, plot2), wrap_script=False, wrap_plot_info=False)
            # => (javascript, (plot1_dict, plot2_dict))

            components({"Plot 1": plot1, "Plot 2": plot2}, wrap_script=False, wrap_plot_info=False)
            # => (javascript, {"Plot 1": plot1_dict, "Plot 2": plot2_dict})