We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Double encode escapes in HTML-safe JSON strings
This was overlooked in PR #7203.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bokeh/embed/util.py`
Content:
```
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2012 - 2017, Anaconda, Inc. All rights reserved.
3 #
4 # Powered by the Bokeh Development Team.
5 #
6 # The full license is in the file LICENSE.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
8 '''
9 
10 '''
11 
12 #-----------------------------------------------------------------------------
13 # Boilerplate
14 #-----------------------------------------------------------------------------
15 from __future__ import absolute_import, division, print_function, unicode_literals
16 
17 import logging
18 log = logging.getLogger(__name__)
19 
20 from bokeh.util.api import public, internal ; public, internal
21 
22 #-----------------------------------------------------------------------------
23 # Imports
24 #-----------------------------------------------------------------------------
25 
26 # Standard library imports
27 from collections import Sequence
28 
29 # External imports
30 from six import string_types
31 
32 # Bokeh imports
33 from ..core.json_encoder import serialize_json
34 from ..core.templates import DOC_JS, FILE, PLOT_DIV, SCRIPT_TAG
35 from ..document.document import DEFAULT_TITLE, Document
36 from ..model import Model
37 from ..settings import settings
38 from ..util.compiler import bundle_all_models
39 from ..util.serialization import make_id
40 from ..util.string import encode_utf8, indent
41 
42 #-----------------------------------------------------------------------------
43 # Globals and constants
44 #-----------------------------------------------------------------------------
45 
46 #-----------------------------------------------------------------------------
47 # Public API
48 #-----------------------------------------------------------------------------
49 
50 #-----------------------------------------------------------------------------
51 # Internal API
52 #-----------------------------------------------------------------------------
53 
54 @internal((1,0,0))
55 class FromCurdoc(object):
56     ''' This class merely provides a non-None default value for ``theme``
57     arguments, since ``None`` itself is a meaningful value for users to pass.
58 
59     '''
60     pass
61 
62 @internal((1,0,0))
63 def check_models_or_docs(models, allow_dict=False):
64     '''
65 
66     '''
67     input_type_valid = False
68 
69     # Check for single item
70     if isinstance(models, (Model, Document)):
71         models = [models]
72 
73     # Check for sequence
74     if isinstance(models, Sequence) and all(isinstance(x, (Model, Document)) for x in models):
75         input_type_valid = True
76 
77     if allow_dict:
78         if isinstance(models, dict) and \
79            all(isinstance(x, string_types) for x in models.keys()) and \
80            all(isinstance(x, (Model, Document)) for x in models.values()):
81             input_type_valid = True
82 
83     if not input_type_valid:
84         if allow_dict:
85             raise ValueError(
86                 'Input must be a Model, a Document, a Sequence of Models and Document, or a dictionary from string to Model and Document'
87             )
88         else:
89             raise ValueError('Input must be a Model, a Document, or a Sequence of Models and Document')
90 
91     return models
92 
93 @internal((1,0,0))
94 def check_one_model_or_doc(model):
95     '''
96 
97     '''
98     models = check_models_or_docs(model)
99     if len(models) != 1:
100         raise ValueError("Input must be exactly one Model or Document")
101     return models[0]
102 
103 @internal((1,0,0))
104 def div_for_render_item(item):
105     '''
106 
107     '''
108     return PLOT_DIV.render(elementid=item['elementid'])
109 
110 @internal((1,0,0))
111 def find_existing_docs(models):
112     '''
113 
114     '''
115     existing_docs = set(m if isinstance(m, Document) else m.document for m in models)
116     existing_docs.discard(None)
117 
118     if len(existing_docs) == 0:
119         # no existing docs, use the current doc
120         doc = Document()
121     elif len(existing_docs) == 1:
122         # all existing docs are the same, use that one
123         doc = existing_docs.pop()
124     else:
125         # conflicting/multiple docs, raise an error
126         msg = ('Multiple items in models contain documents or are '
127                'themselves documents. (Models must be owned by only a '
128                'single document). This may indicate a usage error.')
129         raise RuntimeError(msg)
130     return doc
131 
132 @internal((1,0,0))
133 def html_page_for_render_items(bundle, docs_json, render_items, title,
134                                 template=FILE, template_variables={}):
135     '''
136 
137     '''
138     if title is None:
139         title = DEFAULT_TITLE
140 
141     bokeh_js, bokeh_css = bundle
142 
143     json_id = make_id()
144     json = escape(serialize_json(docs_json), quote=False)
145     json = wrap_in_script_tag(json, "application/json", json_id)
146 
147     script = bundle_all_models()
148     script += script_for_render_items(json_id, render_items)
149     script = wrap_in_script_tag(script)
150 
151     template_variables_full = template_variables.copy()
152 
153     template_variables_full.update(dict(
154         title = title,
155         bokeh_js = bokeh_js,
156         bokeh_css = bokeh_css,
157         plot_script = json + script,
158         plot_div = "\n".join(div_for_render_item(item) for item in render_items)
159     ))
160 
161     html = template.render(template_variables_full)
162     return encode_utf8(html)
163 
164 @internal((1,0,0))
165 def script_for_render_items(docs_json_or_id, render_items, app_path=None, absolute_url=None):
166     '''
167 
168     '''
169     if isinstance(docs_json_or_id, string_types):
170         docs_json = "document.getElementById('%s').textContent" % docs_json_or_id
171     else:
172         # XXX: encodes &, <, > and ', but not ". This is because " is used a lot in JSON,
173         # and encoding it would significantly increase size of generated files. Doing so
174         # is safe, because " in strings was already encoded by JSON, and the semi-encoded
175         # JSON string is included in JavaScript in single quotes.
176         docs_json =  "'" + escape(serialize_json(docs_json_or_id, pretty=False), quote=("'",)) + "'"
177 
178     js = DOC_JS.render(
179         docs_json=docs_json,
180         render_items=serialize_json(render_items, pretty=False),
181         app_path=app_path,
182         absolute_url=absolute_url,
183     )
184 
185     if not settings.dev:
186         js = wrap_in_safely(js)
187 
188     return wrap_in_onload(js)
189 
190 @internal((1,0,0))
191 def standalone_docs_json_and_render_items(models):
192     '''
193 
194     '''
195     models = check_models_or_docs(models)
196 
197     render_items = []
198     docs_by_id = {}
199     for p in models:
200         modelid = None
201         if isinstance(p, Document):
202             doc = p
203         else:
204             if p.document is None:
205                 raise ValueError("To render a Model as HTML it must be part of a Document")
206             doc = p.document
207             modelid = p._id
208         docid = None
209         for key in docs_by_id:
210             if docs_by_id[key] == doc:
211                 docid = key
212         if docid is None:
213             docid = make_id()
214             docs_by_id[docid] = doc
215 
216         elementid = make_id()
217 
218         render_items.append({
219             'docid' : docid,
220             'elementid' : elementid,
221             # if modelid is None, that means the entire document
222             'modelid' : modelid
223             })
224 
225     docs_json = {}
226     for k, v in docs_by_id.items():
227         docs_json[k] = v.to_json()
228 
229     return (docs_json, render_items)
230 
231 @internal((1,0,0))
232 def wrap_in_onload(code):
233     '''
234 
235     '''
236     return _ONLOAD % dict(code=indent(code, 4))
237 
238 @internal((1,0,0))
239 def wrap_in_safely(code):
240     '''
241 
242     '''
243     return _SAFELY % dict(code=indent(code, 2))
244 
245 @internal((1,0,0))
246 def wrap_in_script_tag(js, type="text/javascript", id=None):
247     '''
248 
249     '''
250     return SCRIPT_TAG.render(js_code=indent(js, 2), type=type, id=id)
251 
252 # based on `html` stdlib module (3.2+)
253 @internal((1,0,0))
254 def escape(s, quote=("'", '"')):
255     """
256     Replace special characters "&", "<" and ">" to HTML-safe sequences.
257     If the optional flag quote is true (the default), the quotation mark
258     characters, both double quote (") and single quote (') characters are also
259     translated.
260     """
261     s = s.replace("&", "&amp;")
262     s = s.replace("<", "&lt;")
263     s = s.replace(">", "&gt;")
264     if quote:
265         if '"' in quote:
266             s = s.replace('"', "&quot;")
267         if "'" in quote:
268             s = s.replace("'", "&#x27;")
269     return s
270 
271 #-----------------------------------------------------------------------------
272 # Private API
273 #-----------------------------------------------------------------------------
274 
275 _ONLOAD = """\
276 (function() {
277   var fn = function() {
278 %(code)s
279   };
280   if (document.readyState != "loading") fn();
281   else document.addEventListener("DOMContentLoaded", fn);
282 })();\
283 """
284 
285 _SAFELY = """\
286 Bokeh.safely(function() {
287 %(code)s
288 });\
289 """
290 
291 #-----------------------------------------------------------------------------
292 # Code
293 #-----------------------------------------------------------------------------
294
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bokeh/embed/util.py b/bokeh/embed/util.py
--- a/bokeh/embed/util.py
+++ b/bokeh/embed/util.py
@@ -173,7 +173,10 @@
         # and encoding it would significantly increase size of generated files. Doing so
         # is safe, because " in strings was already encoded by JSON, and the semi-encoded
         # JSON string is included in JavaScript in single quotes.
-        docs_json =  "'" + escape(serialize_json(docs_json_or_id, pretty=False), quote=("'",)) + "'"
+        docs_json = serialize_json(docs_json_or_id, pretty=False) # JSON string
+        docs_json = escape(docs_json, quote=("'",))               # make HTML-safe
+        docs_json = docs_json.replace("\\", "\\\\")               # double encode escapes
+        docs_json =  "'" + docs_json + "'"                        # JS string
 
     js = DOC_JS.render(
         docs_json=docs_json,

{"golden_diff": "diff --git a/bokeh/embed/util.py b/bokeh/embed/util.py\n--- a/bokeh/embed/util.py\n+++ b/bokeh/embed/util.py\n@@ -173,7 +173,10 @@\n         # and encoding it would significantly increase size of generated files. Doing so\n         # is safe, because \" in strings was already encoded by JSON, and the semi-encoded\n         # JSON string is included in JavaScript in single quotes.\n-        docs_json =  \"'\" + escape(serialize_json(docs_json_or_id, pretty=False), quote=(\"'\",)) + \"'\"\n+        docs_json = serialize_json(docs_json_or_id, pretty=False) # JSON string\n+        docs_json = escape(docs_json, quote=(\"'\",))               # make HTML-safe\n+        docs_json = docs_json.replace(\"\\\\\", \"\\\\\\\\\")               # double encode escapes\n+        docs_json =  \"'\" + docs_json + \"'\"                        # JS string\n \n     js = DOC_JS.render(\n         docs_json=docs_json,\n", "issue": "Double encode escapes in HTML-safe JSON strings\nThis was overlooked in PR #7203.\n", "before_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2017, Anaconda, Inc. All rights reserved.\n#\n# Powered by the Bokeh Development Team.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n#-----------------------------------------------------------------------------\n'''\n\n'''\n\n#-----------------------------------------------------------------------------\n# Boilerplate\n#-----------------------------------------------------------------------------\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport logging\nlog = logging.getLogger(__name__)\n\nfrom bokeh.util.api import public, internal ; public, internal\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\n# Standard library imports\nfrom collections import Sequence\n\n# External imports\nfrom six import string_types\n\n# Bokeh imports\nfrom ..core.json_encoder import serialize_json\nfrom ..core.templates import DOC_JS, FILE, PLOT_DIV, SCRIPT_TAG\nfrom ..document.document import DEFAULT_TITLE, Document\nfrom ..model import Model\nfrom ..settings import settings\nfrom ..util.compiler import bundle_all_models\nfrom ..util.serialization import make_id\nfrom ..util.string import encode_utf8, indent\n\n#-----------------------------------------------------------------------------\n# Globals and constants\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Public API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Internal API\n#-----------------------------------------------------------------------------\n\n@internal((1,0,0))\nclass FromCurdoc(object):\n    ''' This class merely provides a non-None default value for ``theme``\n    arguments, since ``None`` itself is a meaningful value for users to pass.\n\n    '''\n    pass\n\n@internal((1,0,0))\ndef check_models_or_docs(models, allow_dict=False):\n    '''\n\n    '''\n    input_type_valid = False\n\n    # Check for single item\n    if isinstance(models, (Model, Document)):\n        models = [models]\n\n    # Check for sequence\n    if isinstance(models, Sequence) and all(isinstance(x, (Model, Document)) for x in models):\n        input_type_valid = True\n\n    if allow_dict:\n        if isinstance(models, dict) and \\\n           all(isinstance(x, string_types) for x in models.keys()) and \\\n           all(isinstance(x, (Model, Document)) for x in models.values()):\n            input_type_valid = True\n\n    if not input_type_valid:\n        if allow_dict:\n            raise ValueError(\n                'Input must be a Model, a Document, a Sequence of Models and Document, or a dictionary from string to Model and Document'\n            )\n        else:\n            raise ValueError('Input must be a Model, a Document, or a Sequence of Models and Document')\n\n    return models\n\n@internal((1,0,0))\ndef check_one_model_or_doc(model):\n    '''\n\n    '''\n    models = check_models_or_docs(model)\n    if len(models) != 1:\n        raise ValueError(\"Input must be exactly one Model or Document\")\n    return models[0]\n\n@internal((1,0,0))\ndef div_for_render_item(item):\n    '''\n\n    '''\n    return PLOT_DIV.render(elementid=item['elementid'])\n\n@internal((1,0,0))\ndef find_existing_docs(models):\n    '''\n\n    '''\n    existing_docs = set(m if isinstance(m, Document) else m.document for m in models)\n    existing_docs.discard(None)\n\n    if len(existing_docs) == 0:\n        # no existing docs, use the current doc\n        doc = Document()\n    elif len(existing_docs) == 1:\n        # all existing docs are the same, use that one\n        doc = existing_docs.pop()\n    else:\n        # conflicting/multiple docs, raise an error\n        msg = ('Multiple items in models contain documents or are '\n               'themselves documents. (Models must be owned by only a '\n               'single document). This may indicate a usage error.')\n        raise RuntimeError(msg)\n    return doc\n\n@internal((1,0,0))\ndef html_page_for_render_items(bundle, docs_json, render_items, title,\n                                template=FILE, template_variables={}):\n    '''\n\n    '''\n    if title is None:\n        title = DEFAULT_TITLE\n\n    bokeh_js, bokeh_css = bundle\n\n    json_id = make_id()\n    json = escape(serialize_json(docs_json), quote=False)\n    json = wrap_in_script_tag(json, \"application/json\", json_id)\n\n    script = bundle_all_models()\n    script += script_for_render_items(json_id, render_items)\n    script = wrap_in_script_tag(script)\n\n    template_variables_full = template_variables.copy()\n\n    template_variables_full.update(dict(\n        title = title,\n        bokeh_js = bokeh_js,\n        bokeh_css = bokeh_css,\n        plot_script = json + script,\n        plot_div = \"\\n\".join(div_for_render_item(item) for item in render_items)\n    ))\n\n    html = template.render(template_variables_full)\n    return encode_utf8(html)\n\n@internal((1,0,0))\ndef script_for_render_items(docs_json_or_id, render_items, app_path=None, absolute_url=None):\n    '''\n\n    '''\n    if isinstance(docs_json_or_id, string_types):\n        docs_json = \"document.getElementById('%s').textContent\" % docs_json_or_id\n    else:\n        # XXX: encodes &, <, > and ', but not \". This is because \" is used a lot in JSON,\n        # and encoding it would significantly increase size of generated files. Doing so\n        # is safe, because \" in strings was already encoded by JSON, and the semi-encoded\n        # JSON string is included in JavaScript in single quotes.\n        docs_json =  \"'\" + escape(serialize_json(docs_json_or_id, pretty=False), quote=(\"'\",)) + \"'\"\n\n    js = DOC_JS.render(\n        docs_json=docs_json,\n        render_items=serialize_json(render_items, pretty=False),\n        app_path=app_path,\n        absolute_url=absolute_url,\n    )\n\n    if not settings.dev:\n        js = wrap_in_safely(js)\n\n    return wrap_in_onload(js)\n\n@internal((1,0,0))\ndef standalone_docs_json_and_render_items(models):\n    '''\n\n    '''\n    models = check_models_or_docs(models)\n\n    render_items = []\n    docs_by_id = {}\n    for p in models:\n        modelid = None\n        if isinstance(p, Document):\n            doc = p\n        else:\n            if p.document is None:\n                raise ValueError(\"To render a Model as HTML it must be part of a Document\")\n            doc = p.document\n            modelid = p._id\n        docid = None\n        for key in docs_by_id:\n            if docs_by_id[key] == doc:\n                docid = key\n        if docid is None:\n            docid = make_id()\n            docs_by_id[docid] = doc\n\n        elementid = make_id()\n\n        render_items.append({\n            'docid' : docid,\n            'elementid' : elementid,\n            # if modelid is None, that means the entire document\n            'modelid' : modelid\n            })\n\n    docs_json = {}\n    for k, v in docs_by_id.items():\n        docs_json[k] = v.to_json()\n\n    return (docs_json, render_items)\n\n@internal((1,0,0))\ndef wrap_in_onload(code):\n    '''\n\n    '''\n    return _ONLOAD % dict(code=indent(code, 4))\n\n@internal((1,0,0))\ndef wrap_in_safely(code):\n    '''\n\n    '''\n    return _SAFELY % dict(code=indent(code, 2))\n\n@internal((1,0,0))\ndef wrap_in_script_tag(js, type=\"text/javascript\", id=None):\n    '''\n\n    '''\n    return SCRIPT_TAG.render(js_code=indent(js, 2), type=type, id=id)\n\n# based on `html` stdlib module (3.2+)\n@internal((1,0,0))\ndef escape(s, quote=(\"'\", '\"')):\n    \"\"\"\n    Replace special characters \"&\", \"<\" and \">\" to HTML-safe sequences.\n    If the optional flag quote is true (the default), the quotation mark\n    characters, both double quote (\") and single quote (') characters are also\n    translated.\n    \"\"\"\n    s = s.replace(\"&\", \"&amp;\")\n    s = s.replace(\"<\", \"&lt;\")\n    s = s.replace(\">\", \"&gt;\")\n    if quote:\n        if '\"' in quote:\n            s = s.replace('\"', \"&quot;\")\n        if \"'\" in quote:\n            s = s.replace(\"'\", \"&#x27;\")\n    return s\n\n#-----------------------------------------------------------------------------\n# Private API\n#-----------------------------------------------------------------------------\n\n_ONLOAD = \"\"\"\\\n(function() {\n  var fn = function() {\n%(code)s\n  };\n  if (document.readyState != \"loading\") fn();\n  else document.addEventListener(\"DOMContentLoaded\", fn);\n})();\\\n\"\"\"\n\n_SAFELY = \"\"\"\\\nBokeh.safely(function() {\n%(code)s\n});\\\n\"\"\"\n\n#-----------------------------------------------------------------------------\n# Code\n#-----------------------------------------------------------------------------\n", "path": "bokeh/embed/util.py"}], "after_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2017, Anaconda, Inc. All rights reserved.\n#\n# Powered by the Bokeh Development Team.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n#-----------------------------------------------------------------------------\n'''\n\n'''\n\n#-----------------------------------------------------------------------------\n# Boilerplate\n#-----------------------------------------------------------------------------\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport logging\nlog = logging.getLogger(__name__)\n\nfrom bokeh.util.api import public, internal ; public, internal\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\n# Standard library imports\nfrom collections import Sequence\n\n# External imports\nfrom six import string_types\n\n# Bokeh imports\nfrom ..core.json_encoder import serialize_json\nfrom ..core.templates import DOC_JS, FILE, PLOT_DIV, SCRIPT_TAG\nfrom ..document.document import DEFAULT_TITLE, Document\nfrom ..model import Model\nfrom ..settings import settings\nfrom ..util.compiler import bundle_all_models\nfrom ..util.serialization import make_id\nfrom ..util.string import encode_utf8, indent\n\n#-----------------------------------------------------------------------------\n# Globals and constants\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Public API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Internal API\n#-----------------------------------------------------------------------------\n\n@internal((1,0,0))\nclass FromCurdoc(object):\n    ''' This class merely provides a non-None default value for ``theme``\n    arguments, since ``None`` itself is a meaningful value for users to pass.\n\n    '''\n    pass\n\n@internal((1,0,0))\ndef check_models_or_docs(models, allow_dict=False):\n    '''\n\n    '''\n    input_type_valid = False\n\n    # Check for single item\n    if isinstance(models, (Model, Document)):\n        models = [models]\n\n    # Check for sequence\n    if isinstance(models, Sequence) and all(isinstance(x, (Model, Document)) for x in models):\n        input_type_valid = True\n\n    if allow_dict:\n        if isinstance(models, dict) and \\\n           all(isinstance(x, string_types) for x in models.keys()) and \\\n           all(isinstance(x, (Model, Document)) for x in models.values()):\n            input_type_valid = True\n\n    if not input_type_valid:\n        if allow_dict:\n            raise ValueError(\n                'Input must be a Model, a Document, a Sequence of Models and Document, or a dictionary from string to Model and Document'\n            )\n        else:\n            raise ValueError('Input must be a Model, a Document, or a Sequence of Models and Document')\n\n    return models\n\n@internal((1,0,0))\ndef check_one_model_or_doc(model):\n    '''\n\n    '''\n    models = check_models_or_docs(model)\n    if len(models) != 1:\n        raise ValueError(\"Input must be exactly one Model or Document\")\n    return models[0]\n\n@internal((1,0,0))\ndef div_for_render_item(item):\n    '''\n\n    '''\n    return PLOT_DIV.render(elementid=item['elementid'])\n\n@internal((1,0,0))\ndef find_existing_docs(models):\n    '''\n\n    '''\n    existing_docs = set(m if isinstance(m, Document) else m.document for m in models)\n    existing_docs.discard(None)\n\n    if len(existing_docs) == 0:\n        # no existing docs, use the current doc\n        doc = Document()\n    elif len(existing_docs) == 1:\n        # all existing docs are the same, use that one\n        doc = existing_docs.pop()\n    else:\n        # conflicting/multiple docs, raise an error\n        msg = ('Multiple items in models contain documents or are '\n               'themselves documents. (Models must be owned by only a '\n               'single document). This may indicate a usage error.')\n        raise RuntimeError(msg)\n    return doc\n\n@internal((1,0,0))\ndef html_page_for_render_items(bundle, docs_json, render_items, title,\n                                template=FILE, template_variables={}):\n    '''\n\n    '''\n    if title is None:\n        title = DEFAULT_TITLE\n\n    bokeh_js, bokeh_css = bundle\n\n    json_id = make_id()\n    json = escape(serialize_json(docs_json), quote=False)\n    json = wrap_in_script_tag(json, \"application/json\", json_id)\n\n    script = bundle_all_models()\n    script += script_for_render_items(json_id, render_items)\n    script = wrap_in_script_tag(script)\n\n    template_variables_full = template_variables.copy()\n\n    template_variables_full.update(dict(\n        title = title,\n        bokeh_js = bokeh_js,\n        bokeh_css = bokeh_css,\n        plot_script = json + script,\n        plot_div = \"\\n\".join(div_for_render_item(item) for item in render_items)\n    ))\n\n    html = template.render(template_variables_full)\n    return encode_utf8(html)\n\n@internal((1,0,0))\ndef script_for_render_items(docs_json_or_id, render_items, app_path=None, absolute_url=None):\n    '''\n\n    '''\n    if isinstance(docs_json_or_id, string_types):\n        docs_json = \"document.getElementById('%s').textContent\" % docs_json_or_id\n    else:\n        # XXX: encodes &, <, > and ', but not \". This is because \" is used a lot in JSON,\n        # and encoding it would significantly increase size of generated files. Doing so\n        # is safe, because \" in strings was already encoded by JSON, and the semi-encoded\n        # JSON string is included in JavaScript in single quotes.\n        docs_json = serialize_json(docs_json_or_id, pretty=False) # JSON string\n        docs_json = escape(docs_json, quote=(\"'\",))               # make HTML-safe\n        docs_json = docs_json.replace(\"\\\\\", \"\\\\\\\\\")               # double encode escapes\n        docs_json =  \"'\" + docs_json + \"'\"                        # JS string\n\n    js = DOC_JS.render(\n        docs_json=docs_json,\n        render_items=serialize_json(render_items, pretty=False),\n        app_path=app_path,\n        absolute_url=absolute_url,\n    )\n\n    if not settings.dev:\n        js = wrap_in_safely(js)\n\n    return wrap_in_onload(js)\n\n@internal((1,0,0))\ndef standalone_docs_json_and_render_items(models):\n    '''\n\n    '''\n    models = check_models_or_docs(models)\n\n    render_items = []\n    docs_by_id = {}\n    for p in models:\n        modelid = None\n        if isinstance(p, Document):\n            doc = p\n        else:\n            if p.document is None:\n                raise ValueError(\"To render a Model as HTML it must be part of a Document\")\n            doc = p.document\n            modelid = p._id\n        docid = None\n        for key in docs_by_id:\n            if docs_by_id[key] == doc:\n                docid = key\n        if docid is None:\n            docid = make_id()\n            docs_by_id[docid] = doc\n\n        elementid = make_id()\n\n        render_items.append({\n            'docid' : docid,\n            'elementid' : elementid,\n            # if modelid is None, that means the entire document\n            'modelid' : modelid\n            })\n\n    docs_json = {}\n    for k, v in docs_by_id.items():\n        docs_json[k] = v.to_json()\n\n    return (docs_json, render_items)\n\n@internal((1,0,0))\ndef wrap_in_onload(code):\n    '''\n\n    '''\n    return _ONLOAD % dict(code=indent(code, 4))\n\n@internal((1,0,0))\ndef wrap_in_safely(code):\n    '''\n\n    '''\n    return _SAFELY % dict(code=indent(code, 2))\n\n@internal((1,0,0))\ndef wrap_in_script_tag(js, type=\"text/javascript\", id=None):\n    '''\n\n    '''\n    return SCRIPT_TAG.render(js_code=indent(js, 2), type=type, id=id)\n\n# based on `html` stdlib module (3.2+)\n@internal((1,0,0))\ndef escape(s, quote=(\"'\", '\"')):\n    \"\"\"\n    Replace special characters \"&\", \"<\" and \">\" to HTML-safe sequences.\n    If the optional flag quote is true (the default), the quotation mark\n    characters, both double quote (\") and single quote (') characters are also\n    translated.\n    \"\"\"\n    s = s.replace(\"&\", \"&amp;\")\n    s = s.replace(\"<\", \"&lt;\")\n    s = s.replace(\">\", \"&gt;\")\n    if quote:\n        if '\"' in quote:\n            s = s.replace('\"', \"&quot;\")\n        if \"'\" in quote:\n            s = s.replace(\"'\", \"&#x27;\")\n    return s\n\n#-----------------------------------------------------------------------------\n# Private API\n#-----------------------------------------------------------------------------\n\n_ONLOAD = \"\"\"\\\n(function() {\n  var fn = function() {\n%(code)s\n  };\n  if (document.readyState != \"loading\") fn();\n  else document.addEventListener(\"DOMContentLoaded\", fn);\n})();\\\n\"\"\"\n\n_SAFELY = \"\"\"\\\nBokeh.safely(function() {\n%(code)s\n});\\\n\"\"\"\n\n#-----------------------------------------------------------------------------\n# Code\n#-----------------------------------------------------------------------------\n", "path": "bokeh/embed/util.py"}]}