We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Error in alias format regex parsing once defaults are involved.
Based on some debugging to reduce problem reported in community by @tonybaloney.

Note : an extra print statement added for debugging purposes locally help point out the errant regex.

```
In [42]: format = "acl {{a}} {{b}} {{c}}"

In [43]: format = "acl {{a}} {{b}} {{c}} {{d=1}}"

In [44]: param_stream = 'acl "x" "y" "z"'

In [45]: p = action_alias_utils.ActionAliasFormatParser(format, param_stream)

In [46]: p.get_extracted_param_value()
^\s*acl\s*["\']?(?P<a}}\s*["\']?(?P<b>(?:(?<=\').+?(?=\')|(?<=").+?(?=")|{.+?}|.+?))["\']?(?:\s*["\']?(?P<c>(?:(?<=\').+?(?=\')|(?<=").+?(?>(?:(?<=\').+?(?=\')|(?<=").+?(?=")|{.+?}|.+?))["\']?\s+)?\s*\s*$
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-46-b3174c03dc30> in <module>()
----> 1 p.get_extracted_param_value()

/mnt/st2repos/st2/st2common/st2common/models/utils/action_alias_utils.py in get_extracted_param_value(self)
     80         # 2. Matched parameters
     81         # 3. Extra parameters
---> 82         matched_stream = re.match(reg, self._param_stream, re.DOTALL)
     83         if matched_stream:
     84             values = matched_stream.groupdict()

/mnt/st2repos/st2/virtualenv/lib/python2.7/re.pyc in match(pattern, string, flags)
    135     """Try to apply the pattern at the start of the string, returning
    136     a match object, or None if no match was found."""
--> 137     return _compile(pattern, flags).match(string)
    138
    139 def search(pattern, string, flags=0):

/mnt/st2repos/st2/virtualenv/lib/python2.7/re.pyc in _compile(*key)
    242         p = sre_compile.compile(pattern, flags)
    243     except error, v:
--> 244         raise error, v # invalid expression
    245     if not bypass_cache:
    246         if len(_cache) >= _MAXCACHE:

error: bad character in group name 'a}}\\s*["\\\']?(?P<b'


In [47]: format = "acl {{a}} {{b}} {{c}}"

In [48]: p = action_alias_utils.ActionAliasFormatParser(format, param_stream)

In [49]: p.get_extracted_param_value()
^\s*acl\s*["\']?(?P<a>(?:(?<=\').+?(?=\')|(?<=").+?(?=")|{.+?}|.+?))["\']? \s*["\']?(?P<b>(?:(?<=\').+?(?=\')|(?<=").+?(?=")|{.+?}|.+?))["\']? \s*["\']?(?P<c>(?:(?<=\').+?(?=\')|(?<=").+?(?=")|{.+?}|.+?))["\']?\s*$
Out[49]: {'a': 'x', 'b': 'y', 'c': 'z'}
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `st2common/st2common/models/utils/action_alias_utils.py`
Content:
```
1 # Licensed to the StackStorm, Inc ('StackStorm') under one or more
2 # contributor license agreements.  See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License.  You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 import re
17 from st2common.exceptions import content
18 
19 __all__ = [
20     'ActionAliasFormatParser'
21 ]
22 
23 
24 class ActionAliasFormatParser(object):
25 
26     def __init__(self, alias_format=None, param_stream=None):
27         self._format = alias_format or ''
28         self._param_stream = param_stream or ''
29 
30     def get_extracted_param_value(self):
31 
32         result = {}
33 
34         # As there's a lot of questions about using regular expressions,
35         # I'll try to be thorough when documenting this code.
36 
37         # We're parsing the arbitrary key-value pairs at the end of the stream
38         # to support passing of parameters not specified in the format string,
39         # and cutting them from the stream as they're no longer needed.
40         # Possible values are quoted strings, a word, or anything inside "{}".
41         pairs_match = r'(?:^|\s+)(\S+)=("(.*?)"|\'(.*?)\'|({.*?})|(\S+))'
42         extra = re.match(r'.*?((' + pairs_match + r'\s*)*)$',
43                          self._param_stream, re.DOTALL)
44         if extra:
45             kv_pairs = re.findall(pairs_match,
46                                   extra.group(1), re.DOTALL)
47             self._param_stream = self._param_stream.replace(extra.group(1), '')
48         self._param_stream = " %s " % self._param_stream
49 
50         # Now we'll match parameters with default values in form of
51         # {{ value = parameter }} (and all possible permutations of spaces),
52         # compiling them into a list.
53         # "test {{ url = http://google.com }} {{ extra = Test }}" will become
54         # [ ["url", "http://google.com"], ["extra", "Test"] ]
55         params = re.findall(r'{{\s*(.+?)\s*(?:=\s*[\'"]?({.+?}|.+?)[\'"]?)?\s*}}',
56                             self._format, re.DOTALL)
57 
58         # Now we're transforming our format string into a regular expression,
59         # substituting {{ ... }} with regex named groups, so that param_stream
60         # matched against this expression yields a dict of params with values.
61         param_match = r'["\']?(?P<\2>(?:(?<=\').+?(?=\')|(?<=").+?(?=")|{.+?}|.+?))["\']?'
62         reg = re.sub(r'(\s*){{\s*([^=]+?)\s*}}(?=\s+{{[^}]+?=)',
63                      r'\s*' + param_match + r'\s+',
64                      self._format)
65         reg = re.sub(r'(\s*){{\s*(\S+)\s*=\s*(?:{.+?}|.+?)\s*}}(\s*)',
66                      r'(?:\s*' + param_match + r'\s+)?\s*',
67                      reg)
68         reg = re.sub(r'(\s*){{\s*(.+?)\s*}}(\s*)',
69                      r'\s*' + param_match + r'\3',
70                      reg)
71         reg = '^\s*' + reg + r'\s*$'
72 
73         # Now we're matching param_stream against our format string regex,
74         # getting a dict of values. We'll also get default values from
75         # "params" list if something is not present.
76         # Priority, from lowest to highest:
77         # 1. Default parameters
78         # 2. Matched parameters
79         # 3. Extra parameters
80         matched_stream = re.match(reg, self._param_stream, re.DOTALL)
81         if matched_stream:
82             values = matched_stream.groupdict()
83         for param in params:
84             matched_value = values[param[0]] if matched_stream else None
85             result[param[0]] = matched_value or param[1]
86         if extra:
87             for pair in kv_pairs:
88                 result[pair[0]] = ''.join(pair[2:])
89 
90         if self._format and not (self._param_stream.strip() or any(result.values())):
91             raise content.ParseException('No value supplied and no default value found.')
92 
93         return result
94
```
--- 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/st2common/st2common/models/utils/action_alias_utils.py b/st2common/st2common/models/utils/action_alias_utils.py
--- a/st2common/st2common/models/utils/action_alias_utils.py
+++ b/st2common/st2common/models/utils/action_alias_utils.py
@@ -59,14 +59,14 @@
         # substituting {{ ... }} with regex named groups, so that param_stream
         # matched against this expression yields a dict of params with values.
         param_match = r'["\']?(?P<\2>(?:(?<=\').+?(?=\')|(?<=").+?(?=")|{.+?}|.+?))["\']?'
-        reg = re.sub(r'(\s*){{\s*([^=]+?)\s*}}(?=\s+{{[^}]+?=)',
-                     r'\s*' + param_match + r'\s+',
+        reg = re.sub(r'(\s*){{\s*([^=}]+?)\s*}}(?![\'"]?\s+}})',
+                     r'\1' + param_match,
                      self._format)
-        reg = re.sub(r'(\s*){{\s*(\S+)\s*=\s*(?:{.+?}|.+?)\s*}}(\s*)',
-                     r'(?:\s*' + param_match + r'\s+)?\s*',
+        reg = re.sub(r'(\s*){{\s*(\S+)\s*=\s*(?:{.+?}|.+?)\s*}}',
+                     r'(?:\1' + param_match + r')?',
                      reg)
-        reg = re.sub(r'(\s*){{\s*(.+?)\s*}}(\s*)',
-                     r'\s*' + param_match + r'\3',
+        reg = re.sub(r'(\s*){{\s*(.+?)\s*}}',
+                     r'\1' + param_match,
                      reg)
         reg = '^\s*' + reg + r'\s*$'

{"golden_diff": "diff --git a/st2common/st2common/models/utils/action_alias_utils.py b/st2common/st2common/models/utils/action_alias_utils.py\n--- a/st2common/st2common/models/utils/action_alias_utils.py\n+++ b/st2common/st2common/models/utils/action_alias_utils.py\n@@ -59,14 +59,14 @@\n         # substituting {{ ... }} with regex named groups, so that param_stream\n         # matched against this expression yields a dict of params with values.\n         param_match = r'[\"\\']?(?P<\\2>(?:(?<=\\').+?(?=\\')|(?<=\").+?(?=\")|{.+?}|.+?))[\"\\']?'\n-        reg = re.sub(r'(\\s*){{\\s*([^=]+?)\\s*}}(?=\\s+{{[^}]+?=)',\n-                     r'\\s*' + param_match + r'\\s+',\n+        reg = re.sub(r'(\\s*){{\\s*([^=}]+?)\\s*}}(?![\\'\"]?\\s+}})',\n+                     r'\\1' + param_match,\n                      self._format)\n-        reg = re.sub(r'(\\s*){{\\s*(\\S+)\\s*=\\s*(?:{.+?}|.+?)\\s*}}(\\s*)',\n-                     r'(?:\\s*' + param_match + r'\\s+)?\\s*',\n+        reg = re.sub(r'(\\s*){{\\s*(\\S+)\\s*=\\s*(?:{.+?}|.+?)\\s*}}',\n+                     r'(?:\\1' + param_match + r')?',\n                      reg)\n-        reg = re.sub(r'(\\s*){{\\s*(.+?)\\s*}}(\\s*)',\n-                     r'\\s*' + param_match + r'\\3',\n+        reg = re.sub(r'(\\s*){{\\s*(.+?)\\s*}}',\n+                     r'\\1' + param_match,\n                      reg)\n         reg = '^\\s*' + reg + r'\\s*$'\n", "issue": "Error in alias format regex parsing once defaults are involved.\nBased on some debugging to reduce problem reported in community by @tonybaloney.\n\nNote : an extra print statement added for debugging purposes locally help point out the errant regex.\n\n```\nIn [42]: format = \"acl {{a}} {{b}} {{c}}\"\n\nIn [43]: format = \"acl {{a}} {{b}} {{c}} {{d=1}}\"\n\nIn [44]: param_stream = 'acl \"x\" \"y\" \"z\"'\n\nIn [45]: p = action_alias_utils.ActionAliasFormatParser(format, param_stream)\n\nIn [46]: p.get_extracted_param_value()\n^\\s*acl\\s*[\"\\']?(?P<a}}\\s*[\"\\']?(?P<b>(?:(?<=\\').+?(?=\\')|(?<=\").+?(?=\")|{.+?}|.+?))[\"\\']?(?:\\s*[\"\\']?(?P<c>(?:(?<=\\').+?(?=\\')|(?<=\").+?(?>(?:(?<=\\').+?(?=\\')|(?<=\").+?(?=\")|{.+?}|.+?))[\"\\']?\\s+)?\\s*\\s*$\n---------------------------------------------------------------------------\nerror                                     Traceback (most recent call last)\n<ipython-input-46-b3174c03dc30> in <module>()\n----> 1 p.get_extracted_param_value()\n\n/mnt/st2repos/st2/st2common/st2common/models/utils/action_alias_utils.py in get_extracted_param_value(self)\n     80         # 2. Matched parameters\n     81         # 3. Extra parameters\n---> 82         matched_stream = re.match(reg, self._param_stream, re.DOTALL)\n     83         if matched_stream:\n     84             values = matched_stream.groupdict()\n\n/mnt/st2repos/st2/virtualenv/lib/python2.7/re.pyc in match(pattern, string, flags)\n    135     \"\"\"Try to apply the pattern at the start of the string, returning\n    136     a match object, or None if no match was found.\"\"\"\n--> 137     return _compile(pattern, flags).match(string)\n    138\n    139 def search(pattern, string, flags=0):\n\n/mnt/st2repos/st2/virtualenv/lib/python2.7/re.pyc in _compile(*key)\n    242         p = sre_compile.compile(pattern, flags)\n    243     except error, v:\n--> 244         raise error, v # invalid expression\n    245     if not bypass_cache:\n    246         if len(_cache) >= _MAXCACHE:\n\nerror: bad character in group name 'a}}\\\\s*[\"\\\\\\']?(?P<b'\n\n\nIn [47]: format = \"acl {{a}} {{b}} {{c}}\"\n\nIn [48]: p = action_alias_utils.ActionAliasFormatParser(format, param_stream)\n\nIn [49]: p.get_extracted_param_value()\n^\\s*acl\\s*[\"\\']?(?P<a>(?:(?<=\\').+?(?=\\')|(?<=\").+?(?=\")|{.+?}|.+?))[\"\\']? \\s*[\"\\']?(?P<b>(?:(?<=\\').+?(?=\\')|(?<=\").+?(?=\")|{.+?}|.+?))[\"\\']? \\s*[\"\\']?(?P<c>(?:(?<=\\').+?(?=\\')|(?<=\").+?(?=\")|{.+?}|.+?))[\"\\']?\\s*$\nOut[49]: {'a': 'x', 'b': 'y', 'c': 'z'}\n```\n\n", "before_files": [{"content": "# Licensed to the StackStorm, Inc ('StackStorm') under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport re\nfrom st2common.exceptions import content\n\n__all__ = [\n    'ActionAliasFormatParser'\n]\n\n\nclass ActionAliasFormatParser(object):\n\n    def __init__(self, alias_format=None, param_stream=None):\n        self._format = alias_format or ''\n        self._param_stream = param_stream or ''\n\n    def get_extracted_param_value(self):\n\n        result = {}\n\n        # As there's a lot of questions about using regular expressions,\n        # I'll try to be thorough when documenting this code.\n\n        # We're parsing the arbitrary key-value pairs at the end of the stream\n        # to support passing of parameters not specified in the format string,\n        # and cutting them from the stream as they're no longer needed.\n        # Possible values are quoted strings, a word, or anything inside \"{}\".\n        pairs_match = r'(?:^|\\s+)(\\S+)=(\"(.*?)\"|\\'(.*?)\\'|({.*?})|(\\S+))'\n        extra = re.match(r'.*?((' + pairs_match + r'\\s*)*)$',\n                         self._param_stream, re.DOTALL)\n        if extra:\n            kv_pairs = re.findall(pairs_match,\n                                  extra.group(1), re.DOTALL)\n            self._param_stream = self._param_stream.replace(extra.group(1), '')\n        self._param_stream = \" %s \" % self._param_stream\n\n        # Now we'll match parameters with default values in form of\n        # {{ value = parameter }} (and all possible permutations of spaces),\n        # compiling them into a list.\n        # \"test {{ url = http://google.com }} {{ extra = Test }}\" will become\n        # [ [\"url\", \"http://google.com\"], [\"extra\", \"Test\"] ]\n        params = re.findall(r'{{\\s*(.+?)\\s*(?:=\\s*[\\'\"]?({.+?}|.+?)[\\'\"]?)?\\s*}}',\n                            self._format, re.DOTALL)\n\n        # Now we're transforming our format string into a regular expression,\n        # substituting {{ ... }} with regex named groups, so that param_stream\n        # matched against this expression yields a dict of params with values.\n        param_match = r'[\"\\']?(?P<\\2>(?:(?<=\\').+?(?=\\')|(?<=\").+?(?=\")|{.+?}|.+?))[\"\\']?'\n        reg = re.sub(r'(\\s*){{\\s*([^=]+?)\\s*}}(?=\\s+{{[^}]+?=)',\n                     r'\\s*' + param_match + r'\\s+',\n                     self._format)\n        reg = re.sub(r'(\\s*){{\\s*(\\S+)\\s*=\\s*(?:{.+?}|.+?)\\s*}}(\\s*)',\n                     r'(?:\\s*' + param_match + r'\\s+)?\\s*',\n                     reg)\n        reg = re.sub(r'(\\s*){{\\s*(.+?)\\s*}}(\\s*)',\n                     r'\\s*' + param_match + r'\\3',\n                     reg)\n        reg = '^\\s*' + reg + r'\\s*$'\n\n        # Now we're matching param_stream against our format string regex,\n        # getting a dict of values. We'll also get default values from\n        # \"params\" list if something is not present.\n        # Priority, from lowest to highest:\n        # 1. Default parameters\n        # 2. Matched parameters\n        # 3. Extra parameters\n        matched_stream = re.match(reg, self._param_stream, re.DOTALL)\n        if matched_stream:\n            values = matched_stream.groupdict()\n        for param in params:\n            matched_value = values[param[0]] if matched_stream else None\n            result[param[0]] = matched_value or param[1]\n        if extra:\n            for pair in kv_pairs:\n                result[pair[0]] = ''.join(pair[2:])\n\n        if self._format and not (self._param_stream.strip() or any(result.values())):\n            raise content.ParseException('No value supplied and no default value found.')\n\n        return result\n", "path": "st2common/st2common/models/utils/action_alias_utils.py"}], "after_files": [{"content": "# Licensed to the StackStorm, Inc ('StackStorm') under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport re\nfrom st2common.exceptions import content\n\n__all__ = [\n    'ActionAliasFormatParser'\n]\n\n\nclass ActionAliasFormatParser(object):\n\n    def __init__(self, alias_format=None, param_stream=None):\n        self._format = alias_format or ''\n        self._param_stream = param_stream or ''\n\n    def get_extracted_param_value(self):\n\n        result = {}\n\n        # As there's a lot of questions about using regular expressions,\n        # I'll try to be thorough when documenting this code.\n\n        # We're parsing the arbitrary key-value pairs at the end of the stream\n        # to support passing of parameters not specified in the format string,\n        # and cutting them from the stream as they're no longer needed.\n        # Possible values are quoted strings, a word, or anything inside \"{}\".\n        pairs_match = r'(?:^|\\s+)(\\S+)=(\"(.*?)\"|\\'(.*?)\\'|({.*?})|(\\S+))'\n        extra = re.match(r'.*?((' + pairs_match + r'\\s*)*)$',\n                         self._param_stream, re.DOTALL)\n        if extra:\n            kv_pairs = re.findall(pairs_match,\n                                  extra.group(1), re.DOTALL)\n            self._param_stream = self._param_stream.replace(extra.group(1), '')\n        self._param_stream = \" %s \" % self._param_stream\n\n        # Now we'll match parameters with default values in form of\n        # {{ value = parameter }} (and all possible permutations of spaces),\n        # compiling them into a list.\n        # \"test {{ url = http://google.com }} {{ extra = Test }}\" will become\n        # [ [\"url\", \"http://google.com\"], [\"extra\", \"Test\"] ]\n        params = re.findall(r'{{\\s*(.+?)\\s*(?:=\\s*[\\'\"]?({.+?}|.+?)[\\'\"]?)?\\s*}}',\n                            self._format, re.DOTALL)\n\n        # Now we're transforming our format string into a regular expression,\n        # substituting {{ ... }} with regex named groups, so that param_stream\n        # matched against this expression yields a dict of params with values.\n        param_match = r'[\"\\']?(?P<\\2>(?:(?<=\\').+?(?=\\')|(?<=\").+?(?=\")|{.+?}|.+?))[\"\\']?'\n        reg = re.sub(r'(\\s*){{\\s*([^=}]+?)\\s*}}(?![\\'\"]?\\s+}})',\n                     r'\\1' + param_match,\n                     self._format)\n        reg = re.sub(r'(\\s*){{\\s*(\\S+)\\s*=\\s*(?:{.+?}|.+?)\\s*}}',\n                     r'(?:\\1' + param_match + r')?',\n                     reg)\n        reg = re.sub(r'(\\s*){{\\s*(.+?)\\s*}}',\n                     r'\\1' + param_match,\n                     reg)\n        reg = '^\\s*' + reg + r'\\s*$'\n\n        # Now we're matching param_stream against our format string regex,\n        # getting a dict of values. We'll also get default values from\n        # \"params\" list if something is not present.\n        # Priority, from lowest to highest:\n        # 1. Default parameters\n        # 2. Matched parameters\n        # 3. Extra parameters\n        matched_stream = re.match(reg, self._param_stream, re.DOTALL)\n        if matched_stream:\n            values = matched_stream.groupdict()\n        for param in params:\n            matched_value = values[param[0]] if matched_stream else None\n            result[param[0]] = matched_value or param[1]\n        if extra:\n            for pair in kv_pairs:\n                result[pair[0]] = ''.join(pair[2:])\n\n        if self._format and not (self._param_stream.strip() or any(result.values())):\n            raise content.ParseException('No value supplied and no default value found.')\n\n        return result\n", "path": "st2common/st2common/models/utils/action_alias_utils.py"}]}