We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Stored XSS / Frame injection
In (probably) all versions including latest 2.18.5 is it possible to find one example file which is vulnerable to XSS(reflected, stored) and frame injection. (I do not want to publicly disclose attack vector and specific file because is it still possible to exploit)



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gluon/serializers.py`
Content:
```
1 """
2 This file is part of the web2py Web Framework
3 Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
4 License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
5 """
6 import datetime
7 import decimal
8 from gluon.storage import Storage
9 from gluon.html import TAG, XmlComponent, xmlescape
10 from gluon.languages import lazyT
11 import gluon.contrib.rss2 as rss2
12 import json as json_parser
13 from gluon._compat import long, to_native, unicodeT, integer_types
14 
15 have_yaml = True
16 try:
17     import yaml as yamlib
18 except ImportError:
19     have_yaml = False
20 
21 
22 def cast_keys(o, cast=str, encoding="utf-8"):
23     """
24     Builds a new object with <cast> type keys.
25     Use this function if you are in Python < 2.6.5
26     This avoids syntax errors when unpacking dictionary arguments.
27 
28     Args:
29         o: is the object input
30         cast:  (defaults to str) is an object type or function
31             which supports conversion such as:
32 
33                 converted = cast(o)
34 
35         encoding: (defaults to utf-8) is the encoding for unicode
36             keys. This is not used for custom cast functions
37 
38     """
39 
40     if isinstance(o, (dict, Storage)):
41         if isinstance(o, dict):
42             newobj = dict()
43         else:
44             newobj = Storage()
45         for k, v in o.items():
46             if (cast == str) and isinstance(k, unicodeT):
47                 key = k.encode(encoding)
48             else:
49                 key = cast(k)
50             newobj[key] = cast_keys(v, cast=cast, encoding=encoding)
51     elif isinstance(o, (tuple, set, list)):
52         newobj = []
53         for item in o:
54             newobj.append(cast_keys(item, cast=cast, encoding=encoding))
55         if isinstance(o, tuple):
56             newobj = tuple(newobj)
57         elif isinstance(o, set):
58             newobj = set(newobj)
59     else:
60         # no string cast (unknown object)
61         newobj = o
62     return newobj
63 
64 
65 def loads_json(o, unicode_keys=True, **kwargs):
66     # deserialize a json string
67     result = json_parser.loads(o, **kwargs)
68     if not unicode_keys:
69         # filter non-str keys in dictionary objects
70         result = cast_keys(result,
71                            encoding=kwargs.get("encoding", "utf-8"))
72     return result
73 
74 
75 def custom_json(o):
76     if hasattr(o, 'custom_json') and callable(o.custom_json):
77         return o.custom_json()
78     if isinstance(o, (datetime.date,
79                       datetime.datetime,
80                       datetime.time)):
81         return o.isoformat()[:19].replace('T', ' ')
82     elif isinstance(o, integer_types):
83         return int(o)
84     elif isinstance(o, decimal.Decimal):
85         return str(o)
86     elif isinstance(o, (bytes, bytearray)):
87         return str(o)
88     elif isinstance(o, lazyT):
89         return str(o)
90     elif isinstance(o, XmlComponent):
91         return to_native(o.xml())
92     elif isinstance(o, set):
93         return list(o)
94     elif hasattr(o, 'as_list') and callable(o.as_list):
95         return o.as_list()
96     elif hasattr(o, 'as_dict') and callable(o.as_dict):
97         return o.as_dict()
98     else:
99         raise TypeError(repr(o) + " is not JSON serializable")
100 
101 
102 def xml_rec(value, key, quote=True):
103     if hasattr(value, 'custom_xml') and callable(value.custom_xml):
104         return value.custom_xml()
105     elif isinstance(value, (dict, Storage)):
106         return TAG[key](*[TAG[k](xml_rec(v, '', quote))
107                           for k, v in value.items()])
108     elif isinstance(value, list):
109         return TAG[key](*[TAG.item(xml_rec(item, '', quote)) for item in value])
110     elif hasattr(value, 'as_list') and callable(value.as_list):
111         return str(xml_rec(value.as_list(), '', quote))
112     elif hasattr(value, 'as_dict') and callable(value.as_dict):
113         return str(xml_rec(value.as_dict(), '', quote))
114     else:
115         return xmlescape(value, quote)
116 
117 
118 def xml(value, encoding='UTF-8', key='document', quote=True):
119     return ('<?xml version="1.0" encoding="%s"?>' % encoding) + str(xml_rec(value, key, quote))
120 
121 
122 def json(value, default=custom_json, indent=None, sort_keys=False):
123     value = json_parser.dumps(value, default=default, sort_keys=sort_keys, indent=indent)
124     # replace JavaScript incompatible spacing
125     # http://timelessrepo.com/json-isnt-a-javascript-subset
126     # PY3 FIXME
127     # return value.replace(ur'\u2028', '\\u2028').replace(ur'\2029', '\\u2029')
128     return value
129 
130 def csv(value):
131     return ''
132 
133 
134 def ics(events, title=None, link=None, timeshift=0, calname=True,
135         **ignored):
136     title = title or '(unknown)'
137     if link and not callable(link):
138         link = lambda item, prefix=link: prefix.replace(
139             '[id]', str(item['id']))
140     s = 'BEGIN:VCALENDAR'
141     s += '\nVERSION:2.0'
142     if not calname is False:
143         s += '\nX-WR-CALNAME:%s' % (calname or title)
144     s += '\nSUMMARY:%s' % title
145     s += '\nPRODID:Generated by web2py'
146     s += '\nCALSCALE:GREGORIAN'
147     s += '\nMETHOD:PUBLISH'
148     for item in events:
149         s += '\nBEGIN:VEVENT'
150         s += '\nUID:%s' % item['id']
151         if link:
152             s += '\nURL:%s' % link(item)
153         shift = datetime.timedelta(seconds=3600 * timeshift)
154         start = item['start_datetime'] + shift
155         stop = item['stop_datetime'] + shift
156         s += '\nDTSTART:%s' % start.strftime('%Y%m%dT%H%M%S')
157         s += '\nDTEND:%s' % stop.strftime('%Y%m%dT%H%M%S')
158         s += '\nSUMMARY:%s' % item['title']
159         s += '\nEND:VEVENT'
160     s += '\nEND:VCALENDAR'
161     return s
162 
163 def safe_encode(text):
164     if not isinstance(text, (str, unicodeT)):
165         text = str(text)
166     try:
167         text = text.encode('utf8','replace')
168     except ValueError:
169         new_text = ''
170         for c in text:
171             try:
172                 new_text += c.encode('utf8')
173             except:
174                 new_text += '?'
175         text = new_text
176     return text
177 
178 def rss(feed):
179     if not 'entries' in feed and 'items' in feed:
180         feed['entries'] = feed['items']
181 
182     def safestr(obj, key, default=''):
183         return safe_encode(obj.get(key,''))
184 
185     now = datetime.datetime.now()
186     rss = rss2.RSS2(title=safestr(feed,'title'),
187                     link=safestr(feed,'link'),
188                     description=safestr(feed,'description'),
189                     lastBuildDate=feed.get('created_on', now),
190                     items=[rss2.RSSItem(
191                            title=safestr(entry,'title','(notitle)'),
192                            link=safestr(entry,'link'),
193                            description=safestr(entry,'description'),
194                            pubDate=entry.get('created_on', now)
195                            ) for entry in feed.get('entries', [])])
196     return rss.to_xml(encoding='utf8')
197 
198 
199 def yaml(data):
200     if have_yaml:
201         return yamlib.dump(data)
202     else:
203         raise ImportError("No YAML serializer available")
204 
205 
206 def loads_yaml(data):
207     if have_yaml:
208         return yamlib.load(data)
209     else:
210         raise ImportError("No YAML serializer available")
211
```
--- 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/gluon/serializers.py b/gluon/serializers.py
--- a/gluon/serializers.py
+++ b/gluon/serializers.py
@@ -119,13 +119,43 @@
     return ('<?xml version="1.0" encoding="%s"?>' % encoding) + str(xml_rec(value, key, quote))
 
 
-def json(value, default=custom_json, indent=None, sort_keys=False):
-    value = json_parser.dumps(value, default=default, sort_keys=sort_keys, indent=indent)
-    # replace JavaScript incompatible spacing
-    # http://timelessrepo.com/json-isnt-a-javascript-subset
-    # PY3 FIXME
-    # return value.replace(ur'\u2028', '\\u2028').replace(ur'\2029', '\\u2029')
-    return value
+class JSONEncoderForHTML(json_parser.JSONEncoder):
+    """An encoder that produces JSON safe to embed in HTML.
+    To embed JSON content in, say, a script tag on a web page, the
+    characters &, < and > should be escaped. They cannot be escaped
+    with the usual entities (e.g. &amp;) because they are not expanded
+    within <script> tags.
+    This class also escapes the line separator and paragraph separator
+    characters U+2028 and U+2029, irrespective of the ensure_ascii setting,
+    as these characters are not valid in JavaScript strings (see
+    http://timelessrepo.com/json-isnt-a-javascript-subset).
+    """
+
+    def encode(self, o):
+        # Override JSONEncoder.encode because it has hacks for
+        # performance that make things more complicated.
+        chunks = self.iterencode(o, True)
+        if self.ensure_ascii:
+            return ''.join(chunks)
+        else:
+            return u''.join(chunks)
+
+    def iterencode(self, o, _one_shot=False):
+        chunks = super(JSONEncoderForHTML, self).iterencode(o, _one_shot)
+        for chunk in chunks:
+            chunk = chunk.replace('&', '\\u0026')
+            chunk = chunk.replace('<', '\\u003c')
+            chunk = chunk.replace('>', '\\u003e')
+
+            if not self.ensure_ascii:
+                chunk = chunk.replace(u'\u2028', '\\u2028')
+                chunk = chunk.replace(u'\u2029', '\\u2029')
+
+            yield chunk
+
+
+def json(value, default=custom_json, indent=None, sort_keys=False, cls=JSONEncoderForHTML):
+    return json_parser.dumps(value, default=default, cls=cls, sort_keys=sort_keys, indent=indent)
 
 def csv(value):
     return ''

{"golden_diff": "diff --git a/gluon/serializers.py b/gluon/serializers.py\n--- a/gluon/serializers.py\n+++ b/gluon/serializers.py\n@@ -119,13 +119,43 @@\n     return ('<?xml version=\"1.0\" encoding=\"%s\"?>' % encoding) + str(xml_rec(value, key, quote))\n \n \n-def json(value, default=custom_json, indent=None, sort_keys=False):\n-    value = json_parser.dumps(value, default=default, sort_keys=sort_keys, indent=indent)\n-    # replace JavaScript incompatible spacing\n-    # http://timelessrepo.com/json-isnt-a-javascript-subset\n-    # PY3 FIXME\n-    # return value.replace(ur'\\u2028', '\\\\u2028').replace(ur'\\2029', '\\\\u2029')\n-    return value\n+class JSONEncoderForHTML(json_parser.JSONEncoder):\n+    \"\"\"An encoder that produces JSON safe to embed in HTML.\n+    To embed JSON content in, say, a script tag on a web page, the\n+    characters &, < and > should be escaped. They cannot be escaped\n+    with the usual entities (e.g. &amp;) because they are not expanded\n+    within <script> tags.\n+    This class also escapes the line separator and paragraph separator\n+    characters U+2028 and U+2029, irrespective of the ensure_ascii setting,\n+    as these characters are not valid in JavaScript strings (see\n+    http://timelessrepo.com/json-isnt-a-javascript-subset).\n+    \"\"\"\n+\n+    def encode(self, o):\n+        # Override JSONEncoder.encode because it has hacks for\n+        # performance that make things more complicated.\n+        chunks = self.iterencode(o, True)\n+        if self.ensure_ascii:\n+            return ''.join(chunks)\n+        else:\n+            return u''.join(chunks)\n+\n+    def iterencode(self, o, _one_shot=False):\n+        chunks = super(JSONEncoderForHTML, self).iterencode(o, _one_shot)\n+        for chunk in chunks:\n+            chunk = chunk.replace('&', '\\\\u0026')\n+            chunk = chunk.replace('<', '\\\\u003c')\n+            chunk = chunk.replace('>', '\\\\u003e')\n+\n+            if not self.ensure_ascii:\n+                chunk = chunk.replace(u'\\u2028', '\\\\u2028')\n+                chunk = chunk.replace(u'\\u2029', '\\\\u2029')\n+\n+            yield chunk\n+\n+\n+def json(value, default=custom_json, indent=None, sort_keys=False, cls=JSONEncoderForHTML):\n+    return json_parser.dumps(value, default=default, cls=cls, sort_keys=sort_keys, indent=indent)\n \n def csv(value):\n     return ''\n", "issue": "Stored XSS / Frame injection\nIn (probably) all versions including latest 2.18.5 is it possible to find one example file which is vulnerable to XSS(reflected, stored) and frame injection. (I do not want to publicly disclose attack vector and specific file because is it still possible to exploit)\r\n\r\n\n", "before_files": [{"content": "\"\"\"\nThis file is part of the web2py Web Framework\nCopyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>\nLicense: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)\n\"\"\"\nimport datetime\nimport decimal\nfrom gluon.storage import Storage\nfrom gluon.html import TAG, XmlComponent, xmlescape\nfrom gluon.languages import lazyT\nimport gluon.contrib.rss2 as rss2\nimport json as json_parser\nfrom gluon._compat import long, to_native, unicodeT, integer_types\n\nhave_yaml = True\ntry:\n    import yaml as yamlib\nexcept ImportError:\n    have_yaml = False\n\n\ndef cast_keys(o, cast=str, encoding=\"utf-8\"):\n    \"\"\"\n    Builds a new object with <cast> type keys.\n    Use this function if you are in Python < 2.6.5\n    This avoids syntax errors when unpacking dictionary arguments.\n\n    Args:\n        o: is the object input\n        cast:  (defaults to str) is an object type or function\n            which supports conversion such as:\n\n                converted = cast(o)\n\n        encoding: (defaults to utf-8) is the encoding for unicode\n            keys. This is not used for custom cast functions\n\n    \"\"\"\n\n    if isinstance(o, (dict, Storage)):\n        if isinstance(o, dict):\n            newobj = dict()\n        else:\n            newobj = Storage()\n        for k, v in o.items():\n            if (cast == str) and isinstance(k, unicodeT):\n                key = k.encode(encoding)\n            else:\n                key = cast(k)\n            newobj[key] = cast_keys(v, cast=cast, encoding=encoding)\n    elif isinstance(o, (tuple, set, list)):\n        newobj = []\n        for item in o:\n            newobj.append(cast_keys(item, cast=cast, encoding=encoding))\n        if isinstance(o, tuple):\n            newobj = tuple(newobj)\n        elif isinstance(o, set):\n            newobj = set(newobj)\n    else:\n        # no string cast (unknown object)\n        newobj = o\n    return newobj\n\n\ndef loads_json(o, unicode_keys=True, **kwargs):\n    # deserialize a json string\n    result = json_parser.loads(o, **kwargs)\n    if not unicode_keys:\n        # filter non-str keys in dictionary objects\n        result = cast_keys(result,\n                           encoding=kwargs.get(\"encoding\", \"utf-8\"))\n    return result\n\n\ndef custom_json(o):\n    if hasattr(o, 'custom_json') and callable(o.custom_json):\n        return o.custom_json()\n    if isinstance(o, (datetime.date,\n                      datetime.datetime,\n                      datetime.time)):\n        return o.isoformat()[:19].replace('T', ' ')\n    elif isinstance(o, integer_types):\n        return int(o)\n    elif isinstance(o, decimal.Decimal):\n        return str(o)\n    elif isinstance(o, (bytes, bytearray)):\n        return str(o)\n    elif isinstance(o, lazyT):\n        return str(o)\n    elif isinstance(o, XmlComponent):\n        return to_native(o.xml())\n    elif isinstance(o, set):\n        return list(o)\n    elif hasattr(o, 'as_list') and callable(o.as_list):\n        return o.as_list()\n    elif hasattr(o, 'as_dict') and callable(o.as_dict):\n        return o.as_dict()\n    else:\n        raise TypeError(repr(o) + \" is not JSON serializable\")\n\n\ndef xml_rec(value, key, quote=True):\n    if hasattr(value, 'custom_xml') and callable(value.custom_xml):\n        return value.custom_xml()\n    elif isinstance(value, (dict, Storage)):\n        return TAG[key](*[TAG[k](xml_rec(v, '', quote))\n                          for k, v in value.items()])\n    elif isinstance(value, list):\n        return TAG[key](*[TAG.item(xml_rec(item, '', quote)) for item in value])\n    elif hasattr(value, 'as_list') and callable(value.as_list):\n        return str(xml_rec(value.as_list(), '', quote))\n    elif hasattr(value, 'as_dict') and callable(value.as_dict):\n        return str(xml_rec(value.as_dict(), '', quote))\n    else:\n        return xmlescape(value, quote)\n\n\ndef xml(value, encoding='UTF-8', key='document', quote=True):\n    return ('<?xml version=\"1.0\" encoding=\"%s\"?>' % encoding) + str(xml_rec(value, key, quote))\n\n\ndef json(value, default=custom_json, indent=None, sort_keys=False):\n    value = json_parser.dumps(value, default=default, sort_keys=sort_keys, indent=indent)\n    # replace JavaScript incompatible spacing\n    # http://timelessrepo.com/json-isnt-a-javascript-subset\n    # PY3 FIXME\n    # return value.replace(ur'\\u2028', '\\\\u2028').replace(ur'\\2029', '\\\\u2029')\n    return value\n\ndef csv(value):\n    return ''\n\n\ndef ics(events, title=None, link=None, timeshift=0, calname=True,\n        **ignored):\n    title = title or '(unknown)'\n    if link and not callable(link):\n        link = lambda item, prefix=link: prefix.replace(\n            '[id]', str(item['id']))\n    s = 'BEGIN:VCALENDAR'\n    s += '\\nVERSION:2.0'\n    if not calname is False:\n        s += '\\nX-WR-CALNAME:%s' % (calname or title)\n    s += '\\nSUMMARY:%s' % title\n    s += '\\nPRODID:Generated by web2py'\n    s += '\\nCALSCALE:GREGORIAN'\n    s += '\\nMETHOD:PUBLISH'\n    for item in events:\n        s += '\\nBEGIN:VEVENT'\n        s += '\\nUID:%s' % item['id']\n        if link:\n            s += '\\nURL:%s' % link(item)\n        shift = datetime.timedelta(seconds=3600 * timeshift)\n        start = item['start_datetime'] + shift\n        stop = item['stop_datetime'] + shift\n        s += '\\nDTSTART:%s' % start.strftime('%Y%m%dT%H%M%S')\n        s += '\\nDTEND:%s' % stop.strftime('%Y%m%dT%H%M%S')\n        s += '\\nSUMMARY:%s' % item['title']\n        s += '\\nEND:VEVENT'\n    s += '\\nEND:VCALENDAR'\n    return s\n\ndef safe_encode(text):\n    if not isinstance(text, (str, unicodeT)):\n        text = str(text)\n    try:\n        text = text.encode('utf8','replace')\n    except ValueError:\n        new_text = ''\n        for c in text:\n            try:\n                new_text += c.encode('utf8')\n            except:\n                new_text += '?'\n        text = new_text\n    return text\n\ndef rss(feed):\n    if not 'entries' in feed and 'items' in feed:\n        feed['entries'] = feed['items']\n\n    def safestr(obj, key, default=''):\n        return safe_encode(obj.get(key,''))\n\n    now = datetime.datetime.now()\n    rss = rss2.RSS2(title=safestr(feed,'title'),\n                    link=safestr(feed,'link'),\n                    description=safestr(feed,'description'),\n                    lastBuildDate=feed.get('created_on', now),\n                    items=[rss2.RSSItem(\n                           title=safestr(entry,'title','(notitle)'),\n                           link=safestr(entry,'link'),\n                           description=safestr(entry,'description'),\n                           pubDate=entry.get('created_on', now)\n                           ) for entry in feed.get('entries', [])])\n    return rss.to_xml(encoding='utf8')\n\n\ndef yaml(data):\n    if have_yaml:\n        return yamlib.dump(data)\n    else:\n        raise ImportError(\"No YAML serializer available\")\n\n\ndef loads_yaml(data):\n    if have_yaml:\n        return yamlib.load(data)\n    else:\n        raise ImportError(\"No YAML serializer available\")\n", "path": "gluon/serializers.py"}], "after_files": [{"content": "\"\"\"\nThis file is part of the web2py Web Framework\nCopyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>\nLicense: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)\n\"\"\"\nimport datetime\nimport decimal\nfrom gluon.storage import Storage\nfrom gluon.html import TAG, XmlComponent, xmlescape\nfrom gluon.languages import lazyT\nimport gluon.contrib.rss2 as rss2\nimport json as json_parser\nfrom gluon._compat import long, to_native, unicodeT, integer_types\n\nhave_yaml = True\ntry:\n    import yaml as yamlib\nexcept ImportError:\n    have_yaml = False\n\n\ndef cast_keys(o, cast=str, encoding=\"utf-8\"):\n    \"\"\"\n    Builds a new object with <cast> type keys.\n    Use this function if you are in Python < 2.6.5\n    This avoids syntax errors when unpacking dictionary arguments.\n\n    Args:\n        o: is the object input\n        cast:  (defaults to str) is an object type or function\n            which supports conversion such as:\n\n                converted = cast(o)\n\n        encoding: (defaults to utf-8) is the encoding for unicode\n            keys. This is not used for custom cast functions\n\n    \"\"\"\n\n    if isinstance(o, (dict, Storage)):\n        if isinstance(o, dict):\n            newobj = dict()\n        else:\n            newobj = Storage()\n        for k, v in o.items():\n            if (cast == str) and isinstance(k, unicodeT):\n                key = k.encode(encoding)\n            else:\n                key = cast(k)\n            newobj[key] = cast_keys(v, cast=cast, encoding=encoding)\n    elif isinstance(o, (tuple, set, list)):\n        newobj = []\n        for item in o:\n            newobj.append(cast_keys(item, cast=cast, encoding=encoding))\n        if isinstance(o, tuple):\n            newobj = tuple(newobj)\n        elif isinstance(o, set):\n            newobj = set(newobj)\n    else:\n        # no string cast (unknown object)\n        newobj = o\n    return newobj\n\n\ndef loads_json(o, unicode_keys=True, **kwargs):\n    # deserialize a json string\n    result = json_parser.loads(o, **kwargs)\n    if not unicode_keys:\n        # filter non-str keys in dictionary objects\n        result = cast_keys(result,\n                           encoding=kwargs.get(\"encoding\", \"utf-8\"))\n    return result\n\n\ndef custom_json(o):\n    if hasattr(o, 'custom_json') and callable(o.custom_json):\n        return o.custom_json()\n    if isinstance(o, (datetime.date,\n                      datetime.datetime,\n                      datetime.time)):\n        return o.isoformat()[:19].replace('T', ' ')\n    elif isinstance(o, integer_types):\n        return int(o)\n    elif isinstance(o, decimal.Decimal):\n        return str(o)\n    elif isinstance(o, (bytes, bytearray)):\n        return str(o)\n    elif isinstance(o, lazyT):\n        return str(o)\n    elif isinstance(o, XmlComponent):\n        return to_native(o.xml())\n    elif isinstance(o, set):\n        return list(o)\n    elif hasattr(o, 'as_list') and callable(o.as_list):\n        return o.as_list()\n    elif hasattr(o, 'as_dict') and callable(o.as_dict):\n        return o.as_dict()\n    else:\n        raise TypeError(repr(o) + \" is not JSON serializable\")\n\n\ndef xml_rec(value, key, quote=True):\n    if hasattr(value, 'custom_xml') and callable(value.custom_xml):\n        return value.custom_xml()\n    elif isinstance(value, (dict, Storage)):\n        return TAG[key](*[TAG[k](xml_rec(v, '', quote))\n                          for k, v in value.items()])\n    elif isinstance(value, list):\n        return TAG[key](*[TAG.item(xml_rec(item, '', quote)) for item in value])\n    elif hasattr(value, 'as_list') and callable(value.as_list):\n        return str(xml_rec(value.as_list(), '', quote))\n    elif hasattr(value, 'as_dict') and callable(value.as_dict):\n        return str(xml_rec(value.as_dict(), '', quote))\n    else:\n        return xmlescape(value, quote)\n\n\ndef xml(value, encoding='UTF-8', key='document', quote=True):\n    return ('<?xml version=\"1.0\" encoding=\"%s\"?>' % encoding) + str(xml_rec(value, key, quote))\n\n\nclass JSONEncoderForHTML(json_parser.JSONEncoder):\n    \"\"\"An encoder that produces JSON safe to embed in HTML.\n    To embed JSON content in, say, a script tag on a web page, the\n    characters &, < and > should be escaped. They cannot be escaped\n    with the usual entities (e.g. &amp;) because they are not expanded\n    within <script> tags.\n    This class also escapes the line separator and paragraph separator\n    characters U+2028 and U+2029, irrespective of the ensure_ascii setting,\n    as these characters are not valid in JavaScript strings (see\n    http://timelessrepo.com/json-isnt-a-javascript-subset).\n    \"\"\"\n\n    def encode(self, o):\n        # Override JSONEncoder.encode because it has hacks for\n        # performance that make things more complicated.\n        chunks = self.iterencode(o, True)\n        if self.ensure_ascii:\n            return ''.join(chunks)\n        else:\n            return u''.join(chunks)\n\n    def iterencode(self, o, _one_shot=False):\n        chunks = super(JSONEncoderForHTML, self).iterencode(o, _one_shot)\n        for chunk in chunks:\n            chunk = chunk.replace('&', '\\\\u0026')\n            chunk = chunk.replace('<', '\\\\u003c')\n            chunk = chunk.replace('>', '\\\\u003e')\n\n            if not self.ensure_ascii:\n                chunk = chunk.replace(u'\\u2028', '\\\\u2028')\n                chunk = chunk.replace(u'\\u2029', '\\\\u2029')\n\n            yield chunk\n\n\ndef json(value, default=custom_json, indent=None, sort_keys=False, cls=JSONEncoderForHTML):\n    return json_parser.dumps(value, default=default, cls=cls, sort_keys=sort_keys, indent=indent)\n\ndef csv(value):\n    return ''\n\n\ndef ics(events, title=None, link=None, timeshift=0, calname=True,\n        **ignored):\n    title = title or '(unknown)'\n    if link and not callable(link):\n        link = lambda item, prefix=link: prefix.replace(\n            '[id]', str(item['id']))\n    s = 'BEGIN:VCALENDAR'\n    s += '\\nVERSION:2.0'\n    if not calname is False:\n        s += '\\nX-WR-CALNAME:%s' % (calname or title)\n    s += '\\nSUMMARY:%s' % title\n    s += '\\nPRODID:Generated by web2py'\n    s += '\\nCALSCALE:GREGORIAN'\n    s += '\\nMETHOD:PUBLISH'\n    for item in events:\n        s += '\\nBEGIN:VEVENT'\n        s += '\\nUID:%s' % item['id']\n        if link:\n            s += '\\nURL:%s' % link(item)\n        shift = datetime.timedelta(seconds=3600 * timeshift)\n        start = item['start_datetime'] + shift\n        stop = item['stop_datetime'] + shift\n        s += '\\nDTSTART:%s' % start.strftime('%Y%m%dT%H%M%S')\n        s += '\\nDTEND:%s' % stop.strftime('%Y%m%dT%H%M%S')\n        s += '\\nSUMMARY:%s' % item['title']\n        s += '\\nEND:VEVENT'\n    s += '\\nEND:VCALENDAR'\n    return s\n\ndef safe_encode(text):\n    if not isinstance(text, (str, unicodeT)):\n        text = str(text)\n    try:\n        text = text.encode('utf8','replace')\n    except ValueError:\n        new_text = ''\n        for c in text:\n            try:\n                new_text += c.encode('utf8')\n            except:\n                new_text += '?'\n        text = new_text\n    return text\n\ndef rss(feed):\n    if not 'entries' in feed and 'items' in feed:\n        feed['entries'] = feed['items']\n\n    def safestr(obj, key, default=''):\n        return safe_encode(obj.get(key,''))\n\n    now = datetime.datetime.now()\n    rss = rss2.RSS2(title=safestr(feed,'title'),\n                    link=safestr(feed,'link'),\n                    description=safestr(feed,'description'),\n                    lastBuildDate=feed.get('created_on', now),\n                    items=[rss2.RSSItem(\n                           title=safestr(entry,'title','(notitle)'),\n                           link=safestr(entry,'link'),\n                           description=safestr(entry,'description'),\n                           pubDate=entry.get('created_on', now)\n                           ) for entry in feed.get('entries', [])])\n    return rss.to_xml(encoding='utf8')\n\n\ndef yaml(data):\n    if have_yaml:\n        return yamlib.dump(data)\n    else:\n        raise ImportError(\"No YAML serializer available\")\n\n\ndef loads_yaml(data):\n    if have_yaml:\n        return yamlib.load(data)\n    else:\n        raise ImportError(\"No YAML serializer available\")\n", "path": "gluon/serializers.py"}]}