We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add tests for all adventure, start and demo programs
Sometimes little errors happen in the code we ship in various examples, f.e. a typo, or when we change the grammar. Going forward, these should all be tested too. 

This entails more or less:

* Parse adventure yamls and extract all code between ```'s
* Parse level defaults yamls and extract all start code 
* Parse level defaults yamls and extract all demo code in all commands

Parse all these as a unittest and see if they all parse (in a later stage we could even define outcome to test against, but for now just seeing that they parse is ok)

We also need to think about proper reporting, so not just a failing test but "story adventure fails in Hungarian" as output.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `utils.py`
Content:
```
1 import contextlib
2 import datetime
3 import time
4 import pickle
5 import functools
6 import os
7 import re
8 import string
9 import random
10 from ruamel import yaml
11 from website import querylog
12 
13 
14 IS_WINDOWS = os.name == 'nt'
15 
16 
17 class Timer:
18   """A quick and dirty timer."""
19   def __init__(self, name):
20     self.name = name
21 
22   def __enter__(self):
23     self.start = time.time()
24 
25   def __exit__(self, type, value, tb):
26     delta = time.time() - self.start
27     print(f'{self.name}: {delta}s')
28 
29 
30 def timer(fn):
31   """Decoractor for fn."""
32   @functools.wraps(fn)
33   def wrapper(*args, **kwargs):
34     with Timer(fn.__name__):
35       return fn(*args, **kwargs)
36   return wrapper
37 
38 
39 
40 def timems ():
41     return int (round (time.time () * 1000))
42 
43 def times ():
44     return int (round (time.time ()))
45 
46 
47 
48 
49 DEBUG_MODE = False
50 
51 def is_debug_mode():
52     """Return whether or not we're in debug mode.
53 
54     We do more expensive things that are better for development in debug mode.
55     """
56     return DEBUG_MODE
57 
58 
59 def set_debug_mode(debug_mode):
60     """Switch debug mode to given value."""
61     global DEBUG_MODE
62     DEBUG_MODE = debug_mode
63 
64 
65 YAML_CACHE = {}
66 
67 @querylog.timed
68 def load_yaml(filename):
69     """Load the given YAML file.
70 
71     The file load will be cached in production, but reloaded everytime in
72     development mode for much iterating. Because YAML loading is still
73     somewhat slow, in production we'll have two levels of caching:
74 
75     - In-memory cache: each of the N processes on the box will only need to
76       load the YAML file once (per restart).
77 
78     - On-disk pickle cache: "pickle" is a more efficient Python serialization
79       format, and loads 400x quicker than YAML. We will prefer loading a pickle
80       file to loading the source YAML file if possible. Hopefully only 1/N
81       processes on the box will have to do the full load per deploy.
82 
83     We should be generating the pickled files at build time, but Heroku doesn't
84     make it easy to have a build/deploy time... so for now let's just make sure
85     we only do it once per box per deploy.
86     """
87     if is_debug_mode():
88         return load_yaml_uncached(filename)
89 
90     # Production mode, check our two-level cache
91     if filename not in YAML_CACHE:
92         data = load_yaml_pickled(filename)
93         YAML_CACHE[filename] = data
94         return data
95     else:
96         return YAML_CACHE[filename]
97 
98 
99 def load_yaml_pickled(filename):
100     # Let's not even attempt the pickling on Windows, because we have
101     # no pattern to atomatically write the pickled result file.
102     if IS_WINDOWS:
103         return load_yaml_uncached(filename)
104 
105     pickle_file = f'{filename}.pickle'
106     if not os.path.exists(pickle_file):
107         data = load_yaml_uncached(filename)
108 
109         # Write a pickle file, first write to a tempfile then rename
110         # into place because multiple processes might try to do this in parallel,
111         # plus we only want `path.exists(pickle_file)` to return True once the
112         # file is actually complete and readable.
113         with atomic_write_file(pickle_file) as f:
114             pickle.dump(data, f)
115 
116         return data
117     else:
118         with open(pickle_file, 'rb') as f:
119             return pickle.load(f)
120 
121 
122 def load_yaml_uncached(filename):
123     try:
124         y = yaml.YAML(typ='safe', pure=True)
125         with open(filename, 'r', encoding='utf-8') as f:
126             return y.load(f)
127     except IOError:
128         return {}
129 
130 
131 def load_yaml_rt(filename):
132     """Load YAML with the round trip loader."""
133     try:
134         with open(filename, 'r', encoding='utf-8') as f:
135             return yaml.round_trip_load(f, preserve_quotes=True)
136     except IOError:
137         return {}
138 
139 
140 def dump_yaml_rt(data):
141     """Dump round-tripped YAML."""
142     return yaml.round_trip_dump(data, indent=4, width=999)
143 
144 def slash_join(*args):
145     ret = []
146     for arg in args:
147         if not arg: continue
148 
149         if ret and not ret[-1].endswith('/'):
150             ret.append('/')
151         ret.append(arg.lstrip('/') if ret else arg)
152     return ''.join(ret)
153 
154 def is_testing_request(request):
155     return bool ('X-Testing' in request.headers and request.headers ['X-Testing'])
156 
157 def extract_bcrypt_rounds (hash):
158     return int (re.match ('\$2b\$\d+', hash) [0].replace ('$2b$', ''))
159 
160 def isoformat(timestamp):
161     """Turn a timestamp into an ISO formatted string."""
162     dt = datetime.datetime.utcfromtimestamp(timestamp)
163     return dt.isoformat() + 'Z'
164 
165 
166 def is_production():
167     """Whether we are serving production traffic."""
168     return os.getenv('IS_PRODUCTION', '') != ''
169 
170 
171 def is_heroku():
172     """Whether we are running on Heroku.
173 
174     Only use this flag if you are making a decision that really has to do with
175     Heroku-based hosting or not.
176 
177     If you are trying to make a decision whether something needs to be done
178     "for real" or not, prefer using:
179 
180     - `is_production()` to see if we're serving customer traffic and trying to
181       optimize for safety and speed.
182     - `is_debug_mode()` to see if we're on a developer machine and we're trying
183       to optimize for developer productivity.
184 
185     """
186     return os.getenv('DYNO', '') != ''
187 
188 
189 def version():
190     """Get the version from the Heroku environment variables."""
191     if not is_heroku():
192         return 'DEV'
193 
194     vrz = os.getenv('HEROKU_RELEASE_CREATED_AT')
195     the_date = datetime.date.fromisoformat(vrz[:10]) if vrz else datetime.date.today()
196 
197     commit = os.getenv('HEROKU_SLUG_COMMIT', '????')[0:6]
198     return the_date.strftime('%b %d') + f' ({commit})'
199 
200 def valid_email(s):
201     return bool (re.match ('^(([a-zA-Z0-9_+\.\-]+)@([\da-zA-Z\.\-]+)\.([a-zA-Z\.]{2,6})\s*)$', s))
202 
203 
204 @contextlib.contextmanager
205 def atomic_write_file(filename, mode='wb'):
206     """Write to a filename atomically.
207 
208     First write to a unique tempfile, then rename the tempfile into
209     place. Use as a context manager:
210 
211         with atomic_write_file('file.txt') as f:
212             f.write('hello')
213 
214     THIS WON'T WORK ON WINDOWS -- atomic file renames don't overwrite
215     on Windows. We could potentially do something else to make it work
216     (just swallow the exception, someone else already wrote the file?)
217     but for now we just don't support it.
218     """
219     if IS_WINDOWS:
220         raise RuntimeError('Cannot use atomic_write_file() on Windows!')
221 
222     tmp_file = f'{filename}.{os.getpid()}'
223     with open(tmp_file, mode) as f:
224         yield f
225 
226     os.rename(tmp_file, filename)
227 
228 # This function takes a date in milliseconds from the Unix epoch and transforms it into a printable date
229 # It operates by converting the date to a string, removing its last 3 digits, converting it back to an int
230 # and then invoking the `isoformat` date function on it
231 def mstoisostring(date):
232     return datetime.datetime.fromtimestamp (int (str (date) [:-3])).isoformat ()
233 
234 # https://stackoverflow.com/a/2257449
235 def random_id_generator(size=6, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):
236     return ''.join (random.choice (chars) for _ in range (size))
237
```
--- 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/utils.py b/utils.py
--- a/utils.py
+++ b/utils.py
@@ -9,7 +9,10 @@
 import random
 from ruamel import yaml
 from website import querylog
-
+import commonmark
+commonmark_parser = commonmark.Parser ()
+commonmark_renderer = commonmark.HtmlRenderer ()
+from bs4 import BeautifulSoup
 
 IS_WINDOWS = os.name == 'nt'
 
@@ -234,3 +237,10 @@
 # https://stackoverflow.com/a/2257449
 def random_id_generator(size=6, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):
     return ''.join (random.choice (chars) for _ in range (size))
+
+# This function takes a markdown string and returns a list with each of the HTML elements obtained
+# by rendering the markdown into HTML.
+def markdown_to_html_tags (markdown):
+    _html = commonmark_renderer.render(commonmark_parser.parse (markdown))
+    soup = BeautifulSoup(_html, 'html.parser')
+    return soup.find_all ()

{"golden_diff": "diff --git a/utils.py b/utils.py\n--- a/utils.py\n+++ b/utils.py\n@@ -9,7 +9,10 @@\n import random\n from ruamel import yaml\n from website import querylog\n-\n+import commonmark\n+commonmark_parser = commonmark.Parser ()\n+commonmark_renderer = commonmark.HtmlRenderer ()\n+from bs4 import BeautifulSoup\n \n IS_WINDOWS = os.name == 'nt'\n \n@@ -234,3 +237,10 @@\n # https://stackoverflow.com/a/2257449\n def random_id_generator(size=6, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):\n     return ''.join (random.choice (chars) for _ in range (size))\n+\n+# This function takes a markdown string and returns a list with each of the HTML elements obtained\n+# by rendering the markdown into HTML.\n+def markdown_to_html_tags (markdown):\n+    _html = commonmark_renderer.render(commonmark_parser.parse (markdown))\n+    soup = BeautifulSoup(_html, 'html.parser')\n+    return soup.find_all ()\n", "issue": "Add tests for all adventure, start and demo programs\nSometimes little errors happen in the code we ship in various examples, f.e. a typo, or when we change the grammar. Going forward, these should all be tested too. \r\n\r\nThis entails more or less:\r\n\r\n* Parse adventure yamls and extract all code between ```'s\r\n* Parse level defaults yamls and extract all start code \r\n* Parse level defaults yamls and extract all demo code in all commands\r\n\r\nParse all these as a unittest and see if they all parse (in a later stage we could even define outcome to test against, but for now just seeing that they parse is ok)\r\n\r\nWe also need to think about proper reporting, so not just a failing test but \"story adventure fails in Hungarian\" as output.\r\n\r\n\n", "before_files": [{"content": "import contextlib\nimport datetime\nimport time\nimport pickle\nimport functools\nimport os\nimport re\nimport string\nimport random\nfrom ruamel import yaml\nfrom website import querylog\n\n\nIS_WINDOWS = os.name == 'nt'\n\n\nclass Timer:\n  \"\"\"A quick and dirty timer.\"\"\"\n  def __init__(self, name):\n    self.name = name\n\n  def __enter__(self):\n    self.start = time.time()\n\n  def __exit__(self, type, value, tb):\n    delta = time.time() - self.start\n    print(f'{self.name}: {delta}s')\n\n\ndef timer(fn):\n  \"\"\"Decoractor for fn.\"\"\"\n  @functools.wraps(fn)\n  def wrapper(*args, **kwargs):\n    with Timer(fn.__name__):\n      return fn(*args, **kwargs)\n  return wrapper\n\n\n\ndef timems ():\n    return int (round (time.time () * 1000))\n\ndef times ():\n    return int (round (time.time ()))\n\n\n\n\nDEBUG_MODE = False\n\ndef is_debug_mode():\n    \"\"\"Return whether or not we're in debug mode.\n\n    We do more expensive things that are better for development in debug mode.\n    \"\"\"\n    return DEBUG_MODE\n\n\ndef set_debug_mode(debug_mode):\n    \"\"\"Switch debug mode to given value.\"\"\"\n    global DEBUG_MODE\n    DEBUG_MODE = debug_mode\n\n\nYAML_CACHE = {}\n\n@querylog.timed\ndef load_yaml(filename):\n    \"\"\"Load the given YAML file.\n\n    The file load will be cached in production, but reloaded everytime in\n    development mode for much iterating. Because YAML loading is still\n    somewhat slow, in production we'll have two levels of caching:\n\n    - In-memory cache: each of the N processes on the box will only need to\n      load the YAML file once (per restart).\n\n    - On-disk pickle cache: \"pickle\" is a more efficient Python serialization\n      format, and loads 400x quicker than YAML. We will prefer loading a pickle\n      file to loading the source YAML file if possible. Hopefully only 1/N\n      processes on the box will have to do the full load per deploy.\n\n    We should be generating the pickled files at build time, but Heroku doesn't\n    make it easy to have a build/deploy time... so for now let's just make sure\n    we only do it once per box per deploy.\n    \"\"\"\n    if is_debug_mode():\n        return load_yaml_uncached(filename)\n\n    # Production mode, check our two-level cache\n    if filename not in YAML_CACHE:\n        data = load_yaml_pickled(filename)\n        YAML_CACHE[filename] = data\n        return data\n    else:\n        return YAML_CACHE[filename]\n\n\ndef load_yaml_pickled(filename):\n    # Let's not even attempt the pickling on Windows, because we have\n    # no pattern to atomatically write the pickled result file.\n    if IS_WINDOWS:\n        return load_yaml_uncached(filename)\n\n    pickle_file = f'{filename}.pickle'\n    if not os.path.exists(pickle_file):\n        data = load_yaml_uncached(filename)\n\n        # Write a pickle file, first write to a tempfile then rename\n        # into place because multiple processes might try to do this in parallel,\n        # plus we only want `path.exists(pickle_file)` to return True once the\n        # file is actually complete and readable.\n        with atomic_write_file(pickle_file) as f:\n            pickle.dump(data, f)\n\n        return data\n    else:\n        with open(pickle_file, 'rb') as f:\n            return pickle.load(f)\n\n\ndef load_yaml_uncached(filename):\n    try:\n        y = yaml.YAML(typ='safe', pure=True)\n        with open(filename, 'r', encoding='utf-8') as f:\n            return y.load(f)\n    except IOError:\n        return {}\n\n\ndef load_yaml_rt(filename):\n    \"\"\"Load YAML with the round trip loader.\"\"\"\n    try:\n        with open(filename, 'r', encoding='utf-8') as f:\n            return yaml.round_trip_load(f, preserve_quotes=True)\n    except IOError:\n        return {}\n\n\ndef dump_yaml_rt(data):\n    \"\"\"Dump round-tripped YAML.\"\"\"\n    return yaml.round_trip_dump(data, indent=4, width=999)\n\ndef slash_join(*args):\n    ret = []\n    for arg in args:\n        if not arg: continue\n\n        if ret and not ret[-1].endswith('/'):\n            ret.append('/')\n        ret.append(arg.lstrip('/') if ret else arg)\n    return ''.join(ret)\n\ndef is_testing_request(request):\n    return bool ('X-Testing' in request.headers and request.headers ['X-Testing'])\n\ndef extract_bcrypt_rounds (hash):\n    return int (re.match ('\\$2b\\$\\d+', hash) [0].replace ('$2b$', ''))\n\ndef isoformat(timestamp):\n    \"\"\"Turn a timestamp into an ISO formatted string.\"\"\"\n    dt = datetime.datetime.utcfromtimestamp(timestamp)\n    return dt.isoformat() + 'Z'\n\n\ndef is_production():\n    \"\"\"Whether we are serving production traffic.\"\"\"\n    return os.getenv('IS_PRODUCTION', '') != ''\n\n\ndef is_heroku():\n    \"\"\"Whether we are running on Heroku.\n\n    Only use this flag if you are making a decision that really has to do with\n    Heroku-based hosting or not.\n\n    If you are trying to make a decision whether something needs to be done\n    \"for real\" or not, prefer using:\n\n    - `is_production()` to see if we're serving customer traffic and trying to\n      optimize for safety and speed.\n    - `is_debug_mode()` to see if we're on a developer machine and we're trying\n      to optimize for developer productivity.\n\n    \"\"\"\n    return os.getenv('DYNO', '') != ''\n\n\ndef version():\n    \"\"\"Get the version from the Heroku environment variables.\"\"\"\n    if not is_heroku():\n        return 'DEV'\n\n    vrz = os.getenv('HEROKU_RELEASE_CREATED_AT')\n    the_date = datetime.date.fromisoformat(vrz[:10]) if vrz else datetime.date.today()\n\n    commit = os.getenv('HEROKU_SLUG_COMMIT', '????')[0:6]\n    return the_date.strftime('%b %d') + f' ({commit})'\n\ndef valid_email(s):\n    return bool (re.match ('^(([a-zA-Z0-9_+\\.\\-]+)@([\\da-zA-Z\\.\\-]+)\\.([a-zA-Z\\.]{2,6})\\s*)$', s))\n\n\n@contextlib.contextmanager\ndef atomic_write_file(filename, mode='wb'):\n    \"\"\"Write to a filename atomically.\n\n    First write to a unique tempfile, then rename the tempfile into\n    place. Use as a context manager:\n\n        with atomic_write_file('file.txt') as f:\n            f.write('hello')\n\n    THIS WON'T WORK ON WINDOWS -- atomic file renames don't overwrite\n    on Windows. We could potentially do something else to make it work\n    (just swallow the exception, someone else already wrote the file?)\n    but for now we just don't support it.\n    \"\"\"\n    if IS_WINDOWS:\n        raise RuntimeError('Cannot use atomic_write_file() on Windows!')\n\n    tmp_file = f'{filename}.{os.getpid()}'\n    with open(tmp_file, mode) as f:\n        yield f\n\n    os.rename(tmp_file, filename)\n\n# This function takes a date in milliseconds from the Unix epoch and transforms it into a printable date\n# It operates by converting the date to a string, removing its last 3 digits, converting it back to an int\n# and then invoking the `isoformat` date function on it\ndef mstoisostring(date):\n    return datetime.datetime.fromtimestamp (int (str (date) [:-3])).isoformat ()\n\n# https://stackoverflow.com/a/2257449\ndef random_id_generator(size=6, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):\n    return ''.join (random.choice (chars) for _ in range (size))\n", "path": "utils.py"}], "after_files": [{"content": "import contextlib\nimport datetime\nimport time\nimport pickle\nimport functools\nimport os\nimport re\nimport string\nimport random\nfrom ruamel import yaml\nfrom website import querylog\nimport commonmark\ncommonmark_parser = commonmark.Parser ()\ncommonmark_renderer = commonmark.HtmlRenderer ()\nfrom bs4 import BeautifulSoup\n\nIS_WINDOWS = os.name == 'nt'\n\n\nclass Timer:\n  \"\"\"A quick and dirty timer.\"\"\"\n  def __init__(self, name):\n    self.name = name\n\n  def __enter__(self):\n    self.start = time.time()\n\n  def __exit__(self, type, value, tb):\n    delta = time.time() - self.start\n    print(f'{self.name}: {delta}s')\n\n\ndef timer(fn):\n  \"\"\"Decoractor for fn.\"\"\"\n  @functools.wraps(fn)\n  def wrapper(*args, **kwargs):\n    with Timer(fn.__name__):\n      return fn(*args, **kwargs)\n  return wrapper\n\n\n\ndef timems ():\n    return int (round (time.time () * 1000))\n\ndef times ():\n    return int (round (time.time ()))\n\n\n\n\nDEBUG_MODE = False\n\ndef is_debug_mode():\n    \"\"\"Return whether or not we're in debug mode.\n\n    We do more expensive things that are better for development in debug mode.\n    \"\"\"\n    return DEBUG_MODE\n\n\ndef set_debug_mode(debug_mode):\n    \"\"\"Switch debug mode to given value.\"\"\"\n    global DEBUG_MODE\n    DEBUG_MODE = debug_mode\n\n\nYAML_CACHE = {}\n\n@querylog.timed\ndef load_yaml(filename):\n    \"\"\"Load the given YAML file.\n\n    The file load will be cached in production, but reloaded everytime in\n    development mode for much iterating. Because YAML loading is still\n    somewhat slow, in production we'll have two levels of caching:\n\n    - In-memory cache: each of the N processes on the box will only need to\n      load the YAML file once (per restart).\n\n    - On-disk pickle cache: \"pickle\" is a more efficient Python serialization\n      format, and loads 400x quicker than YAML. We will prefer loading a pickle\n      file to loading the source YAML file if possible. Hopefully only 1/N\n      processes on the box will have to do the full load per deploy.\n\n    We should be generating the pickled files at build time, but Heroku doesn't\n    make it easy to have a build/deploy time... so for now let's just make sure\n    we only do it once per box per deploy.\n    \"\"\"\n    if is_debug_mode():\n        return load_yaml_uncached(filename)\n\n    # Production mode, check our two-level cache\n    if filename not in YAML_CACHE:\n        data = load_yaml_pickled(filename)\n        YAML_CACHE[filename] = data\n        return data\n    else:\n        return YAML_CACHE[filename]\n\n\ndef load_yaml_pickled(filename):\n    # Let's not even attempt the pickling on Windows, because we have\n    # no pattern to atomatically write the pickled result file.\n    if IS_WINDOWS:\n        return load_yaml_uncached(filename)\n\n    pickle_file = f'{filename}.pickle'\n    if not os.path.exists(pickle_file):\n        data = load_yaml_uncached(filename)\n\n        # Write a pickle file, first write to a tempfile then rename\n        # into place because multiple processes might try to do this in parallel,\n        # plus we only want `path.exists(pickle_file)` to return True once the\n        # file is actually complete and readable.\n        with atomic_write_file(pickle_file) as f:\n            pickle.dump(data, f)\n\n        return data\n    else:\n        with open(pickle_file, 'rb') as f:\n            return pickle.load(f)\n\n\ndef load_yaml_uncached(filename):\n    try:\n        y = yaml.YAML(typ='safe', pure=True)\n        with open(filename, 'r', encoding='utf-8') as f:\n            return y.load(f)\n    except IOError:\n        return {}\n\n\ndef load_yaml_rt(filename):\n    \"\"\"Load YAML with the round trip loader.\"\"\"\n    try:\n        with open(filename, 'r', encoding='utf-8') as f:\n            return yaml.round_trip_load(f, preserve_quotes=True)\n    except IOError:\n        return {}\n\n\ndef dump_yaml_rt(data):\n    \"\"\"Dump round-tripped YAML.\"\"\"\n    return yaml.round_trip_dump(data, indent=4, width=999)\n\ndef slash_join(*args):\n    ret = []\n    for arg in args:\n        if not arg: continue\n\n        if ret and not ret[-1].endswith('/'):\n            ret.append('/')\n        ret.append(arg.lstrip('/') if ret else arg)\n    return ''.join(ret)\n\ndef is_testing_request(request):\n    return bool ('X-Testing' in request.headers and request.headers ['X-Testing'])\n\ndef extract_bcrypt_rounds (hash):\n    return int (re.match ('\\$2b\\$\\d+', hash) [0].replace ('$2b$', ''))\n\ndef isoformat(timestamp):\n    \"\"\"Turn a timestamp into an ISO formatted string.\"\"\"\n    dt = datetime.datetime.utcfromtimestamp(timestamp)\n    return dt.isoformat() + 'Z'\n\n\ndef is_production():\n    \"\"\"Whether we are serving production traffic.\"\"\"\n    return os.getenv('IS_PRODUCTION', '') != ''\n\n\ndef is_heroku():\n    \"\"\"Whether we are running on Heroku.\n\n    Only use this flag if you are making a decision that really has to do with\n    Heroku-based hosting or not.\n\n    If you are trying to make a decision whether something needs to be done\n    \"for real\" or not, prefer using:\n\n    - `is_production()` to see if we're serving customer traffic and trying to\n      optimize for safety and speed.\n    - `is_debug_mode()` to see if we're on a developer machine and we're trying\n      to optimize for developer productivity.\n\n    \"\"\"\n    return os.getenv('DYNO', '') != ''\n\n\ndef version():\n    \"\"\"Get the version from the Heroku environment variables.\"\"\"\n    if not is_heroku():\n        return 'DEV'\n\n    vrz = os.getenv('HEROKU_RELEASE_CREATED_AT')\n    the_date = datetime.date.fromisoformat(vrz[:10]) if vrz else datetime.date.today()\n\n    commit = os.getenv('HEROKU_SLUG_COMMIT', '????')[0:6]\n    return the_date.strftime('%b %d') + f' ({commit})'\n\ndef valid_email(s):\n    return bool (re.match ('^(([a-zA-Z0-9_+\\.\\-]+)@([\\da-zA-Z\\.\\-]+)\\.([a-zA-Z\\.]{2,6})\\s*)$', s))\n\n\n@contextlib.contextmanager\ndef atomic_write_file(filename, mode='wb'):\n    \"\"\"Write to a filename atomically.\n\n    First write to a unique tempfile, then rename the tempfile into\n    place. Use as a context manager:\n\n        with atomic_write_file('file.txt') as f:\n            f.write('hello')\n\n    THIS WON'T WORK ON WINDOWS -- atomic file renames don't overwrite\n    on Windows. We could potentially do something else to make it work\n    (just swallow the exception, someone else already wrote the file?)\n    but for now we just don't support it.\n    \"\"\"\n    if IS_WINDOWS:\n        raise RuntimeError('Cannot use atomic_write_file() on Windows!')\n\n    tmp_file = f'{filename}.{os.getpid()}'\n    with open(tmp_file, mode) as f:\n        yield f\n\n    os.rename(tmp_file, filename)\n\n# This function takes a date in milliseconds from the Unix epoch and transforms it into a printable date\n# It operates by converting the date to a string, removing its last 3 digits, converting it back to an int\n# and then invoking the `isoformat` date function on it\ndef mstoisostring(date):\n    return datetime.datetime.fromtimestamp (int (str (date) [:-3])).isoformat ()\n\n# https://stackoverflow.com/a/2257449\ndef random_id_generator(size=6, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):\n    return ''.join (random.choice (chars) for _ in range (size))\n\n# This function takes a markdown string and returns a list with each of the HTML elements obtained\n# by rendering the markdown into HTML.\ndef markdown_to_html_tags (markdown):\n    _html = commonmark_renderer.render(commonmark_parser.parse (markdown))\n    soup = BeautifulSoup(_html, 'html.parser')\n    return soup.find_all ()\n", "path": "utils.py"}]}