We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Misconfigured plugins should not be selectable
It's possible to select a misconfigured plugin and proceed with the auth/install/run. This is a bug, not a feature. Stuff should be displayed, but not selectable.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `letsencrypt/display/ops.py`
Content:
```
1 """Contains UI methods for LE user operations."""
2 import logging
3 import os
4 
5 import zope.component
6 
7 from letsencrypt import interfaces
8 from letsencrypt import le_util
9 from letsencrypt.display import util as display_util
10 
11 
12 logger = logging.getLogger(__name__)
13 
14 # Define a helper function to avoid verbose code
15 util = zope.component.getUtility
16 
17 
18 def choose_plugin(prepared, question):
19     """Allow the user to choose their plugin.
20 
21     :param list prepared: List of `~.PluginEntryPoint`.
22     :param str question: Question to be presented to the user.
23 
24     :returns: Plugin entry point chosen by the user.
25     :rtype: `~.PluginEntryPoint`
26 
27     """
28     opts = [plugin_ep.description_with_name +
29             (" [Misconfigured]" if plugin_ep.misconfigured else "")
30             for plugin_ep in prepared]
31 
32     while True:
33         code, index = util(interfaces.IDisplay).menu(
34             question, opts, help_label="More Info")
35 
36         if code == display_util.OK:
37             return prepared[index]
38         elif code == display_util.HELP:
39             if prepared[index].misconfigured:
40                 msg = "Reported Error: %s" % prepared[index].prepare()
41             else:
42                 msg = prepared[index].init().more_info()
43             util(interfaces.IDisplay).notification(
44                 msg, height=display_util.HEIGHT)
45         else:
46             return None
47 
48 
49 def pick_plugin(config, default, plugins, question, ifaces):
50     """Pick plugin.
51 
52     :param letsencrypt.interfaces.IConfig: Configuration
53     :param str default: Plugin name supplied by user or ``None``.
54     :param letsencrypt.plugins.disco.PluginsRegistry plugins:
55         All plugins registered as entry points.
56     :param str question: Question to be presented to the user in case
57         multiple candidates are found.
58     :param list ifaces: Interfaces that plugins must provide.
59 
60     :returns: Initialized plugin.
61     :rtype: IPlugin
62 
63     """
64     if default is not None:
65         # throw more UX-friendly error if default not in plugins
66         filtered = plugins.filter(lambda p_ep: p_ep.name == default)
67     else:
68         filtered = plugins.visible().ifaces(ifaces)
69 
70     filtered.init(config)
71     verified = filtered.verify(ifaces)
72     verified.prepare()
73     prepared = verified.available()
74 
75     if len(prepared) > 1:
76         logger.debug("Multiple candidate plugins: %s", prepared)
77         plugin_ep = choose_plugin(prepared.values(), question)
78         if plugin_ep is None:
79             return None
80         else:
81             return plugin_ep.init()
82     elif len(prepared) == 1:
83         plugin_ep = prepared.values()[0]
84         logger.debug("Single candidate plugin: %s", plugin_ep)
85         if plugin_ep.misconfigured:
86             return None
87         return plugin_ep.init()
88     else:
89         logger.debug("No candidate plugin")
90         return None
91 
92 
93 def pick_authenticator(
94         config, default, plugins, question="How would you "
95         "like to authenticate with the Let's Encrypt CA?"):
96     """Pick authentication plugin."""
97     return pick_plugin(
98         config, default, plugins, question, (interfaces.IAuthenticator,))
99 
100 
101 def pick_installer(config, default, plugins,
102                    question="How would you like to install certificates?"):
103     """Pick installer plugin."""
104     return pick_plugin(
105         config, default, plugins, question, (interfaces.IInstaller,))
106 
107 
108 def pick_configurator(
109         config, default, plugins,
110         question="How would you like to authenticate and install "
111                  "certificates?"):
112     """Pick configurator plugin."""
113     return pick_plugin(
114         config, default, plugins, question,
115         (interfaces.IAuthenticator, interfaces.IInstaller))
116 
117 
118 def get_email():
119     """Prompt for valid email address.
120 
121     :returns: Email or ``None`` if cancelled by user.
122     :rtype: str
123 
124     """
125     while True:
126         code, email = zope.component.getUtility(interfaces.IDisplay).input(
127             "Enter email address (used for urgent notices and lost key recovery)")
128 
129         if code == display_util.OK:
130             if le_util.safe_email(email):
131                 return email
132         else:
133             return None
134 
135 
136 def choose_account(accounts):
137     """Choose an account.
138 
139     :param list accounts: Containing at least one
140         :class:`~letsencrypt.account.Account`
141 
142     """
143     # Note this will get more complicated once we start recording authorizations
144     labels = [acc.slug for acc in accounts]
145 
146     code, index = util(interfaces.IDisplay).menu(
147         "Please choose an account", labels)
148     if code == display_util.OK:
149         return accounts[index]
150     else:
151         return None
152 
153 
154 def choose_names(installer):
155     """Display screen to select domains to validate.
156 
157     :param installer: An installer object
158     :type installer: :class:`letsencrypt.interfaces.IInstaller`
159 
160     :returns: List of selected names
161     :rtype: `list` of `str`
162 
163     """
164     if installer is None:
165         logger.debug("No installer, picking names manually")
166         return _choose_names_manually()
167 
168     names = list(installer.get_all_names())
169 
170     if not names:
171         manual = util(interfaces.IDisplay).yesno(
172             "No names were found in your configuration files.{0}You should "
173             "specify ServerNames in your config files in order to allow for "
174             "accurate installation of your certificate.{0}"
175             "If you do use the default vhost, you may specify the name "
176             "manually. Would you like to continue?{0}".format(os.linesep))
177 
178         if manual:
179             return _choose_names_manually()
180         else:
181             return []
182 
183     code, names = _filter_names(names)
184     if code == display_util.OK and names:
185         return names
186     else:
187         return []
188 
189 
190 def _filter_names(names):
191     """Determine which names the user would like to select from a list.
192 
193     :param list names: domain names
194 
195     :returns: tuple of the form (`code`, `names`) where
196         `code` - str display exit code
197         `names` - list of names selected
198     :rtype: tuple
199 
200     """
201     code, names = util(interfaces.IDisplay).checklist(
202         "Which names would you like to activate HTTPS for?",
203         tags=names)
204     return code, [str(s) for s in names]
205 
206 
207 def _choose_names_manually():
208     """Manually input names for those without an installer."""
209 
210     code, input_ = util(interfaces.IDisplay).input(
211         "Please enter in your domain name(s) (comma and/or space separated) ")
212 
213     if code == display_util.OK:
214         return display_util.separate_list_input(input_)
215     return []
216 
217 
218 def success_installation(domains):
219     """Display a box confirming the installation of HTTPS.
220 
221     .. todo:: This should be centered on the screen
222 
223     :param list domains: domain names which were enabled
224 
225     """
226     util(interfaces.IDisplay).notification(
227         "Congratulations! You have successfully enabled {0}!{1}{1}"
228         "You should test your configuration at:{1}{2}".format(
229             _gen_https_names(domains),
230             os.linesep,
231             os.linesep.join(_gen_ssl_lab_urls(domains))),
232         height=(10 + len(domains)),
233         pause=False)
234 
235 
236 def success_renewal(domains):
237     """Display a box confirming the renewal of an existing certificate.
238 
239     .. todo:: This should be centered on the screen
240 
241     :param list domains: domain names which were renewed
242 
243     """
244     util(interfaces.IDisplay).notification(
245         "Your existing certificate has been successfully renewed, and the "
246         "new certificate has been installed.{1}{1}"
247         "The new certificate covers the following domains: {0}{1}{1}"
248         "You should test your configuration at:{1}{2}".format(
249             _gen_https_names(domains),
250             os.linesep,
251             os.linesep.join(_gen_ssl_lab_urls(domains))),
252         height=(14 + len(domains)),
253         pause=False)
254 
255 
256 def _gen_ssl_lab_urls(domains):
257     """Returns a list of urls.
258 
259     :param list domains: Each domain is a 'str'
260 
261     """
262     return ["https://www.ssllabs.com/ssltest/analyze.html?d=%s" % dom for dom in domains]
263 
264 
265 def _gen_https_names(domains):
266     """Returns a string of the https domains.
267 
268     Domains are formatted nicely with https:// prepended to each.
269 
270     :param list domains: Each domain is a 'str'
271 
272     """
273     if len(domains) == 1:
274         return "https://{0}".format(domains[0])
275     elif len(domains) == 2:
276         return "https://{dom[0]} and https://{dom[1]}".format(dom=domains)
277     elif len(domains) > 2:
278         return "{0}{1}{2}".format(
279             ", ".join("https://%s" % dom for dom in domains[:-1]),
280             ", and https://",
281             domains[-1])
282 
283     return ""
284
```
--- 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/letsencrypt/display/ops.py b/letsencrypt/display/ops.py
--- a/letsencrypt/display/ops.py
+++ b/letsencrypt/display/ops.py
@@ -34,7 +34,15 @@
             question, opts, help_label="More Info")
 
         if code == display_util.OK:
-            return prepared[index]
+            plugin_ep = prepared[index]
+            if plugin_ep.misconfigured:
+                util(interfaces.IDisplay).notification(
+                    "The selected plugin encountered an error while parsing "
+                    "your server configuration and cannot be used. The error "
+                    "was:\n\n{0}".format(plugin_ep.prepare()),
+                    height=display_util.HEIGHT, pause=False)
+            else:
+                return plugin_ep
         elif code == display_util.HELP:
             if prepared[index].misconfigured:
                 msg = "Reported Error: %s" % prepared[index].prepare()

{"golden_diff": "diff --git a/letsencrypt/display/ops.py b/letsencrypt/display/ops.py\n--- a/letsencrypt/display/ops.py\n+++ b/letsencrypt/display/ops.py\n@@ -34,7 +34,15 @@\n             question, opts, help_label=\"More Info\")\n \n         if code == display_util.OK:\n-            return prepared[index]\n+            plugin_ep = prepared[index]\n+            if plugin_ep.misconfigured:\n+                util(interfaces.IDisplay).notification(\n+                    \"The selected plugin encountered an error while parsing \"\n+                    \"your server configuration and cannot be used. The error \"\n+                    \"was:\\n\\n{0}\".format(plugin_ep.prepare()),\n+                    height=display_util.HEIGHT, pause=False)\n+            else:\n+                return plugin_ep\n         elif code == display_util.HELP:\n             if prepared[index].misconfigured:\n                 msg = \"Reported Error: %s\" % prepared[index].prepare()\n", "issue": "Misconfigured plugins should not be selectable\nIt's possible to select a misconfigured plugin and proceed with the auth/install/run. This is a bug, not a feature. Stuff should be displayed, but not selectable.\n\n", "before_files": [{"content": "\"\"\"Contains UI methods for LE user operations.\"\"\"\nimport logging\nimport os\n\nimport zope.component\n\nfrom letsencrypt import interfaces\nfrom letsencrypt import le_util\nfrom letsencrypt.display import util as display_util\n\n\nlogger = logging.getLogger(__name__)\n\n# Define a helper function to avoid verbose code\nutil = zope.component.getUtility\n\n\ndef choose_plugin(prepared, question):\n    \"\"\"Allow the user to choose their plugin.\n\n    :param list prepared: List of `~.PluginEntryPoint`.\n    :param str question: Question to be presented to the user.\n\n    :returns: Plugin entry point chosen by the user.\n    :rtype: `~.PluginEntryPoint`\n\n    \"\"\"\n    opts = [plugin_ep.description_with_name +\n            (\" [Misconfigured]\" if plugin_ep.misconfigured else \"\")\n            for plugin_ep in prepared]\n\n    while True:\n        code, index = util(interfaces.IDisplay).menu(\n            question, opts, help_label=\"More Info\")\n\n        if code == display_util.OK:\n            return prepared[index]\n        elif code == display_util.HELP:\n            if prepared[index].misconfigured:\n                msg = \"Reported Error: %s\" % prepared[index].prepare()\n            else:\n                msg = prepared[index].init().more_info()\n            util(interfaces.IDisplay).notification(\n                msg, height=display_util.HEIGHT)\n        else:\n            return None\n\n\ndef pick_plugin(config, default, plugins, question, ifaces):\n    \"\"\"Pick plugin.\n\n    :param letsencrypt.interfaces.IConfig: Configuration\n    :param str default: Plugin name supplied by user or ``None``.\n    :param letsencrypt.plugins.disco.PluginsRegistry plugins:\n        All plugins registered as entry points.\n    :param str question: Question to be presented to the user in case\n        multiple candidates are found.\n    :param list ifaces: Interfaces that plugins must provide.\n\n    :returns: Initialized plugin.\n    :rtype: IPlugin\n\n    \"\"\"\n    if default is not None:\n        # throw more UX-friendly error if default not in plugins\n        filtered = plugins.filter(lambda p_ep: p_ep.name == default)\n    else:\n        filtered = plugins.visible().ifaces(ifaces)\n\n    filtered.init(config)\n    verified = filtered.verify(ifaces)\n    verified.prepare()\n    prepared = verified.available()\n\n    if len(prepared) > 1:\n        logger.debug(\"Multiple candidate plugins: %s\", prepared)\n        plugin_ep = choose_plugin(prepared.values(), question)\n        if plugin_ep is None:\n            return None\n        else:\n            return plugin_ep.init()\n    elif len(prepared) == 1:\n        plugin_ep = prepared.values()[0]\n        logger.debug(\"Single candidate plugin: %s\", plugin_ep)\n        if plugin_ep.misconfigured:\n            return None\n        return plugin_ep.init()\n    else:\n        logger.debug(\"No candidate plugin\")\n        return None\n\n\ndef pick_authenticator(\n        config, default, plugins, question=\"How would you \"\n        \"like to authenticate with the Let's Encrypt CA?\"):\n    \"\"\"Pick authentication plugin.\"\"\"\n    return pick_plugin(\n        config, default, plugins, question, (interfaces.IAuthenticator,))\n\n\ndef pick_installer(config, default, plugins,\n                   question=\"How would you like to install certificates?\"):\n    \"\"\"Pick installer plugin.\"\"\"\n    return pick_plugin(\n        config, default, plugins, question, (interfaces.IInstaller,))\n\n\ndef pick_configurator(\n        config, default, plugins,\n        question=\"How would you like to authenticate and install \"\n                 \"certificates?\"):\n    \"\"\"Pick configurator plugin.\"\"\"\n    return pick_plugin(\n        config, default, plugins, question,\n        (interfaces.IAuthenticator, interfaces.IInstaller))\n\n\ndef get_email():\n    \"\"\"Prompt for valid email address.\n\n    :returns: Email or ``None`` if cancelled by user.\n    :rtype: str\n\n    \"\"\"\n    while True:\n        code, email = zope.component.getUtility(interfaces.IDisplay).input(\n            \"Enter email address (used for urgent notices and lost key recovery)\")\n\n        if code == display_util.OK:\n            if le_util.safe_email(email):\n                return email\n        else:\n            return None\n\n\ndef choose_account(accounts):\n    \"\"\"Choose an account.\n\n    :param list accounts: Containing at least one\n        :class:`~letsencrypt.account.Account`\n\n    \"\"\"\n    # Note this will get more complicated once we start recording authorizations\n    labels = [acc.slug for acc in accounts]\n\n    code, index = util(interfaces.IDisplay).menu(\n        \"Please choose an account\", labels)\n    if code == display_util.OK:\n        return accounts[index]\n    else:\n        return None\n\n\ndef choose_names(installer):\n    \"\"\"Display screen to select domains to validate.\n\n    :param installer: An installer object\n    :type installer: :class:`letsencrypt.interfaces.IInstaller`\n\n    :returns: List of selected names\n    :rtype: `list` of `str`\n\n    \"\"\"\n    if installer is None:\n        logger.debug(\"No installer, picking names manually\")\n        return _choose_names_manually()\n\n    names = list(installer.get_all_names())\n\n    if not names:\n        manual = util(interfaces.IDisplay).yesno(\n            \"No names were found in your configuration files.{0}You should \"\n            \"specify ServerNames in your config files in order to allow for \"\n            \"accurate installation of your certificate.{0}\"\n            \"If you do use the default vhost, you may specify the name \"\n            \"manually. Would you like to continue?{0}\".format(os.linesep))\n\n        if manual:\n            return _choose_names_manually()\n        else:\n            return []\n\n    code, names = _filter_names(names)\n    if code == display_util.OK and names:\n        return names\n    else:\n        return []\n\n\ndef _filter_names(names):\n    \"\"\"Determine which names the user would like to select from a list.\n\n    :param list names: domain names\n\n    :returns: tuple of the form (`code`, `names`) where\n        `code` - str display exit code\n        `names` - list of names selected\n    :rtype: tuple\n\n    \"\"\"\n    code, names = util(interfaces.IDisplay).checklist(\n        \"Which names would you like to activate HTTPS for?\",\n        tags=names)\n    return code, [str(s) for s in names]\n\n\ndef _choose_names_manually():\n    \"\"\"Manually input names for those without an installer.\"\"\"\n\n    code, input_ = util(interfaces.IDisplay).input(\n        \"Please enter in your domain name(s) (comma and/or space separated) \")\n\n    if code == display_util.OK:\n        return display_util.separate_list_input(input_)\n    return []\n\n\ndef success_installation(domains):\n    \"\"\"Display a box confirming the installation of HTTPS.\n\n    .. todo:: This should be centered on the screen\n\n    :param list domains: domain names which were enabled\n\n    \"\"\"\n    util(interfaces.IDisplay).notification(\n        \"Congratulations! You have successfully enabled {0}!{1}{1}\"\n        \"You should test your configuration at:{1}{2}\".format(\n            _gen_https_names(domains),\n            os.linesep,\n            os.linesep.join(_gen_ssl_lab_urls(domains))),\n        height=(10 + len(domains)),\n        pause=False)\n\n\ndef success_renewal(domains):\n    \"\"\"Display a box confirming the renewal of an existing certificate.\n\n    .. todo:: This should be centered on the screen\n\n    :param list domains: domain names which were renewed\n\n    \"\"\"\n    util(interfaces.IDisplay).notification(\n        \"Your existing certificate has been successfully renewed, and the \"\n        \"new certificate has been installed.{1}{1}\"\n        \"The new certificate covers the following domains: {0}{1}{1}\"\n        \"You should test your configuration at:{1}{2}\".format(\n            _gen_https_names(domains),\n            os.linesep,\n            os.linesep.join(_gen_ssl_lab_urls(domains))),\n        height=(14 + len(domains)),\n        pause=False)\n\n\ndef _gen_ssl_lab_urls(domains):\n    \"\"\"Returns a list of urls.\n\n    :param list domains: Each domain is a 'str'\n\n    \"\"\"\n    return [\"https://www.ssllabs.com/ssltest/analyze.html?d=%s\" % dom for dom in domains]\n\n\ndef _gen_https_names(domains):\n    \"\"\"Returns a string of the https domains.\n\n    Domains are formatted nicely with https:// prepended to each.\n\n    :param list domains: Each domain is a 'str'\n\n    \"\"\"\n    if len(domains) == 1:\n        return \"https://{0}\".format(domains[0])\n    elif len(domains) == 2:\n        return \"https://{dom[0]} and https://{dom[1]}\".format(dom=domains)\n    elif len(domains) > 2:\n        return \"{0}{1}{2}\".format(\n            \", \".join(\"https://%s\" % dom for dom in domains[:-1]),\n            \", and https://\",\n            domains[-1])\n\n    return \"\"\n", "path": "letsencrypt/display/ops.py"}], "after_files": [{"content": "\"\"\"Contains UI methods for LE user operations.\"\"\"\nimport logging\nimport os\n\nimport zope.component\n\nfrom letsencrypt import interfaces\nfrom letsencrypt import le_util\nfrom letsencrypt.display import util as display_util\n\n\nlogger = logging.getLogger(__name__)\n\n# Define a helper function to avoid verbose code\nutil = zope.component.getUtility\n\n\ndef choose_plugin(prepared, question):\n    \"\"\"Allow the user to choose their plugin.\n\n    :param list prepared: List of `~.PluginEntryPoint`.\n    :param str question: Question to be presented to the user.\n\n    :returns: Plugin entry point chosen by the user.\n    :rtype: `~.PluginEntryPoint`\n\n    \"\"\"\n    opts = [plugin_ep.description_with_name +\n            (\" [Misconfigured]\" if plugin_ep.misconfigured else \"\")\n            for plugin_ep in prepared]\n\n    while True:\n        code, index = util(interfaces.IDisplay).menu(\n            question, opts, help_label=\"More Info\")\n\n        if code == display_util.OK:\n            plugin_ep = prepared[index]\n            if plugin_ep.misconfigured:\n                util(interfaces.IDisplay).notification(\n                    \"The selected plugin encountered an error while parsing \"\n                    \"your server configuration and cannot be used. The error \"\n                    \"was:\\n\\n{0}\".format(plugin_ep.prepare()),\n                    height=display_util.HEIGHT, pause=False)\n            else:\n                return plugin_ep\n        elif code == display_util.HELP:\n            if prepared[index].misconfigured:\n                msg = \"Reported Error: %s\" % prepared[index].prepare()\n            else:\n                msg = prepared[index].init().more_info()\n            util(interfaces.IDisplay).notification(\n                msg, height=display_util.HEIGHT)\n        else:\n            return None\n\n\ndef pick_plugin(config, default, plugins, question, ifaces):\n    \"\"\"Pick plugin.\n\n    :param letsencrypt.interfaces.IConfig: Configuration\n    :param str default: Plugin name supplied by user or ``None``.\n    :param letsencrypt.plugins.disco.PluginsRegistry plugins:\n        All plugins registered as entry points.\n    :param str question: Question to be presented to the user in case\n        multiple candidates are found.\n    :param list ifaces: Interfaces that plugins must provide.\n\n    :returns: Initialized plugin.\n    :rtype: IPlugin\n\n    \"\"\"\n    if default is not None:\n        # throw more UX-friendly error if default not in plugins\n        filtered = plugins.filter(lambda p_ep: p_ep.name == default)\n    else:\n        filtered = plugins.visible().ifaces(ifaces)\n\n    filtered.init(config)\n    verified = filtered.verify(ifaces)\n    verified.prepare()\n    prepared = verified.available()\n\n    if len(prepared) > 1:\n        logger.debug(\"Multiple candidate plugins: %s\", prepared)\n        plugin_ep = choose_plugin(prepared.values(), question)\n        if plugin_ep is None:\n            return None\n        else:\n            return plugin_ep.init()\n    elif len(prepared) == 1:\n        plugin_ep = prepared.values()[0]\n        logger.debug(\"Single candidate plugin: %s\", plugin_ep)\n        if plugin_ep.misconfigured:\n            return None\n        return plugin_ep.init()\n    else:\n        logger.debug(\"No candidate plugin\")\n        return None\n\n\ndef pick_authenticator(\n        config, default, plugins, question=\"How would you \"\n        \"like to authenticate with the Let's Encrypt CA?\"):\n    \"\"\"Pick authentication plugin.\"\"\"\n    return pick_plugin(\n        config, default, plugins, question, (interfaces.IAuthenticator,))\n\n\ndef pick_installer(config, default, plugins,\n                   question=\"How would you like to install certificates?\"):\n    \"\"\"Pick installer plugin.\"\"\"\n    return pick_plugin(\n        config, default, plugins, question, (interfaces.IInstaller,))\n\n\ndef pick_configurator(\n        config, default, plugins,\n        question=\"How would you like to authenticate and install \"\n                 \"certificates?\"):\n    \"\"\"Pick configurator plugin.\"\"\"\n    return pick_plugin(\n        config, default, plugins, question,\n        (interfaces.IAuthenticator, interfaces.IInstaller))\n\n\ndef get_email():\n    \"\"\"Prompt for valid email address.\n\n    :returns: Email or ``None`` if cancelled by user.\n    :rtype: str\n\n    \"\"\"\n    while True:\n        code, email = zope.component.getUtility(interfaces.IDisplay).input(\n            \"Enter email address (used for urgent notices and lost key recovery)\")\n\n        if code == display_util.OK:\n            if le_util.safe_email(email):\n                return email\n        else:\n            return None\n\n\ndef choose_account(accounts):\n    \"\"\"Choose an account.\n\n    :param list accounts: Containing at least one\n        :class:`~letsencrypt.account.Account`\n\n    \"\"\"\n    # Note this will get more complicated once we start recording authorizations\n    labels = [acc.slug for acc in accounts]\n\n    code, index = util(interfaces.IDisplay).menu(\n        \"Please choose an account\", labels)\n    if code == display_util.OK:\n        return accounts[index]\n    else:\n        return None\n\n\ndef choose_names(installer):\n    \"\"\"Display screen to select domains to validate.\n\n    :param installer: An installer object\n    :type installer: :class:`letsencrypt.interfaces.IInstaller`\n\n    :returns: List of selected names\n    :rtype: `list` of `str`\n\n    \"\"\"\n    if installer is None:\n        logger.debug(\"No installer, picking names manually\")\n        return _choose_names_manually()\n\n    names = list(installer.get_all_names())\n\n    if not names:\n        manual = util(interfaces.IDisplay).yesno(\n            \"No names were found in your configuration files.{0}You should \"\n            \"specify ServerNames in your config files in order to allow for \"\n            \"accurate installation of your certificate.{0}\"\n            \"If you do use the default vhost, you may specify the name \"\n            \"manually. Would you like to continue?{0}\".format(os.linesep))\n\n        if manual:\n            return _choose_names_manually()\n        else:\n            return []\n\n    code, names = _filter_names(names)\n    if code == display_util.OK and names:\n        return names\n    else:\n        return []\n\n\ndef _filter_names(names):\n    \"\"\"Determine which names the user would like to select from a list.\n\n    :param list names: domain names\n\n    :returns: tuple of the form (`code`, `names`) where\n        `code` - str display exit code\n        `names` - list of names selected\n    :rtype: tuple\n\n    \"\"\"\n    code, names = util(interfaces.IDisplay).checklist(\n        \"Which names would you like to activate HTTPS for?\",\n        tags=names)\n    return code, [str(s) for s in names]\n\n\ndef _choose_names_manually():\n    \"\"\"Manually input names for those without an installer.\"\"\"\n\n    code, input_ = util(interfaces.IDisplay).input(\n        \"Please enter in your domain name(s) (comma and/or space separated) \")\n\n    if code == display_util.OK:\n        return display_util.separate_list_input(input_)\n    return []\n\n\ndef success_installation(domains):\n    \"\"\"Display a box confirming the installation of HTTPS.\n\n    .. todo:: This should be centered on the screen\n\n    :param list domains: domain names which were enabled\n\n    \"\"\"\n    util(interfaces.IDisplay).notification(\n        \"Congratulations! You have successfully enabled {0}!{1}{1}\"\n        \"You should test your configuration at:{1}{2}\".format(\n            _gen_https_names(domains),\n            os.linesep,\n            os.linesep.join(_gen_ssl_lab_urls(domains))),\n        height=(10 + len(domains)),\n        pause=False)\n\n\ndef success_renewal(domains):\n    \"\"\"Display a box confirming the renewal of an existing certificate.\n\n    .. todo:: This should be centered on the screen\n\n    :param list domains: domain names which were renewed\n\n    \"\"\"\n    util(interfaces.IDisplay).notification(\n        \"Your existing certificate has been successfully renewed, and the \"\n        \"new certificate has been installed.{1}{1}\"\n        \"The new certificate covers the following domains: {0}{1}{1}\"\n        \"You should test your configuration at:{1}{2}\".format(\n            _gen_https_names(domains),\n            os.linesep,\n            os.linesep.join(_gen_ssl_lab_urls(domains))),\n        height=(14 + len(domains)),\n        pause=False)\n\n\ndef _gen_ssl_lab_urls(domains):\n    \"\"\"Returns a list of urls.\n\n    :param list domains: Each domain is a 'str'\n\n    \"\"\"\n    return [\"https://www.ssllabs.com/ssltest/analyze.html?d=%s\" % dom for dom in domains]\n\n\ndef _gen_https_names(domains):\n    \"\"\"Returns a string of the https domains.\n\n    Domains are formatted nicely with https:// prepended to each.\n\n    :param list domains: Each domain is a 'str'\n\n    \"\"\"\n    if len(domains) == 1:\n        return \"https://{0}\".format(domains[0])\n    elif len(domains) == 2:\n        return \"https://{dom[0]} and https://{dom[1]}\".format(dom=domains)\n    elif len(domains) > 2:\n        return \"{0}{1}{2}\".format(\n            \", \".join(\"https://%s\" % dom for dom in domains[:-1]),\n            \", and https://\",\n            domains[-1])\n\n    return \"\"\n", "path": "letsencrypt/display/ops.py"}]}