prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  xkcd outputs link even if triggered by one
  The `xkcd` plugin shouldn't output a link to the comic if it was triggered by a link.
  
  See `wikipedia`, for example. This is an anti-cycling measure in case multiple bots handling the same link(s) are present in the channel.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `sopel/modules/xkcd.py`
  Content:
  ```
  1 # coding=utf-8
  2 """
  3 xkcd.py - Sopel xkcd Module
  4 Copyright 2010, Michael Yanovich (yanovich.net), and Morgan Goose
  5 Copyright 2012, Lior Ramati
  6 Copyright 2013, Elsie Powell (embolalia.com)
  7 Licensed under the Eiffel Forum License 2.
  8 
  9 https://sopel.chat
  10 """
  11 from __future__ import unicode_literals, absolute_import, print_function, division
  12 
  13 import random
  14 import re
  15 
  16 import requests
  17 
  18 from sopel.modules.search import bing_search
  19 from sopel.module import commands, url
  20 
  21 
  22 ignored_sites = [
  23     # For searching the web
  24     'almamater.xkcd.com',
  25     'blog.xkcd.com',
  26     'blag.xkcd.com',
  27     'forums.xkcd.com',
  28     'fora.xkcd.com',
  29     'forums3.xkcd.com',
  30     'store.xkcd.com',
  31     'wiki.xkcd.com',
  32     'what-if.xkcd.com',
  33 ]
  34 sites_query = ' site:xkcd.com -site:' + ' -site:'.join(ignored_sites)
  35 
  36 
  37 def get_info(number=None):
  38     if number:
  39         url = 'https://xkcd.com/{}/info.0.json'.format(number)
  40     else:
  41         url = 'https://xkcd.com/info.0.json'
  42     data = requests.get(url).json()
  43     data['url'] = 'https://xkcd.com/' + str(data['num'])
  44     return data
  45 
  46 
  47 def web_search(query):
  48     url = bing_search(query + sites_query)
  49     if not url:
  50         return None
  51     match = re.match(r'(?:https?://)?xkcd.com/(\d+)/?', url)
  52     if match:
  53         return match.group(1)
  54 
  55 
  56 @commands('xkcd')
  57 def xkcd(bot, trigger):
  58     """.xkcd - Finds an xkcd comic strip.
  59 
  60     Takes one of 3 inputs:
  61 
  62       * If no input is provided it will return a random comic
  63       * If numeric input is provided it will return that comic, or the
  64         nth-latest comic if the number is non-positive
  65       * If non-numeric input is provided it will return the first search result
  66         for those keywords on the xkcd.com site
  67     """
  68     # get latest comic for rand function and numeric input
  69     latest = get_info()
  70     max_int = latest['num']
  71 
  72     # if no input is given (pre - lior's edits code)
  73     if not trigger.group(2):  # get rand comic
  74         random.seed()
  75         requested = get_info(random.randint(1, max_int + 1))
  76     else:
  77         query = trigger.group(2).strip()
  78 
  79         numbered = re.match(r"^(#|\+|-)?(\d+)$", query)
  80         if numbered:
  81             query = int(numbered.group(2))
  82             if numbered.group(1) == "-":
  83                 query = -query
  84             return numbered_result(bot, query, latest)
  85         else:
  86             # Non-number: search the web.
  87             if (query.lower() == "latest" or query.lower() == "newest"):
  88                 requested = latest
  89             else:
  90                 number = web_search(query)
  91                 if not number:
  92                     bot.say('Could not find any comics for that query.')
  93                     return
  94                 requested = get_info(number)
  95 
  96     say_result(bot, requested)
  97 
  98 
  99 def numbered_result(bot, query, latest):
  100     max_int = latest['num']
  101     if query > max_int:
  102         bot.say(("Sorry, comic #{} hasn't been posted yet. "
  103                  "The last comic was #{}").format(query, max_int))
  104         return
  105     elif query <= -max_int:
  106         bot.say(("Sorry, but there were only {} comics "
  107                  "released yet so far").format(max_int))
  108         return
  109     elif abs(query) == 0:
  110         requested = latest
  111     elif query == 404 or max_int + query == 404:
  112         bot.say("404 - Not Found")  # don't error on that one
  113         return
  114     elif query > 0:
  115         requested = get_info(query)
  116     else:
  117         # Negative: go back that many from current
  118         requested = get_info(max_int + query)
  119 
  120     say_result(bot, requested)
  121 
  122 
  123 def say_result(bot, result):
  124     message = '{} | {} | Alt-text: {}'.format(result['url'], result['title'],
  125                                               result['alt'])
  126     bot.say(message)
  127 
  128 
  129 @url(r'xkcd.com/(\d+)')
  130 def get_url(bot, trigger, match):
  131     latest = get_info()
  132     numbered_result(bot, int(match.group(1)), latest)
  133
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/sopel/modules/xkcd.py b/sopel/modules/xkcd.py
  --- a/sopel/modules/xkcd.py
  +++ b/sopel/modules/xkcd.py
  @@ -96,7 +96,7 @@
       say_result(bot, requested)
   
   
  -def numbered_result(bot, query, latest):
  +def numbered_result(bot, query, latest, commanded=True):
       max_int = latest['num']
       if query > max_int:
           bot.say(("Sorry, comic #{} hasn't been posted yet. "
  @@ -117,16 +117,18 @@
           # Negative: go back that many from current
           requested = get_info(max_int + query)
   
  -    say_result(bot, requested)
  +    say_result(bot, requested, commanded)
   
   
  -def say_result(bot, result):
  -    message = '{} | {} | Alt-text: {}'.format(result['url'], result['title'],
  -                                              result['alt'])
  +def say_result(bot, result, commanded=True):
  +    message = '{}{} | Alt-text: {}'.format(
  +        result['url'] + ' | ' if commanded else '',
  +        result['title'], result['alt']
  +    )
       bot.say(message)
   
   
   @url(r'xkcd.com/(\d+)')
   def get_url(bot, trigger, match):
       latest = get_info()
  -    numbered_result(bot, int(match.group(1)), latest)
  +    numbered_result(bot, int(match.group(1)), latest, commanded=False)
  
verification_info: {"golden_diff": "diff --git a/sopel/modules/xkcd.py b/sopel/modules/xkcd.py\n--- a/sopel/modules/xkcd.py\n+++ b/sopel/modules/xkcd.py\n@@ -96,7 +96,7 @@\n     say_result(bot, requested)\n \n \n-def numbered_result(bot, query, latest):\n+def numbered_result(bot, query, latest, commanded=True):\n     max_int = latest['num']\n     if query > max_int:\n         bot.say((\"Sorry, comic #{} hasn't been posted yet. \"\n@@ -117,16 +117,18 @@\n         # Negative: go back that many from current\n         requested = get_info(max_int + query)\n \n-    say_result(bot, requested)\n+    say_result(bot, requested, commanded)\n \n \n-def say_result(bot, result):\n-    message = '{} | {} | Alt-text: {}'.format(result['url'], result['title'],\n-                                              result['alt'])\n+def say_result(bot, result, commanded=True):\n+    message = '{}{} | Alt-text: {}'.format(\n+        result['url'] + ' | ' if commanded else '',\n+        result['title'], result['alt']\n+    )\n     bot.say(message)\n \n \n @url(r'xkcd.com/(\\d+)')\n def get_url(bot, trigger, match):\n     latest = get_info()\n-    numbered_result(bot, int(match.group(1)), latest)\n+    numbered_result(bot, int(match.group(1)), latest, commanded=False)\n", "issue": "xkcd outputs link even if triggered by one\nThe `xkcd` plugin shouldn't output a link to the comic if it was triggered by a link.\r\n\r\nSee `wikipedia`, for example. This is an anti-cycling measure in case multiple bots handling the same link(s) are present in the channel.\n", "before_files": [{"content": "# coding=utf-8\n\"\"\"\nxkcd.py - Sopel xkcd Module\nCopyright 2010, Michael Yanovich (yanovich.net), and Morgan Goose\nCopyright 2012, Lior Ramati\nCopyright 2013, Elsie Powell (embolalia.com)\nLicensed under the Eiffel Forum License 2.\n\nhttps://sopel.chat\n\"\"\"\nfrom __future__ import unicode_literals, absolute_import, print_function, division\n\nimport random\nimport re\n\nimport requests\n\nfrom sopel.modules.search import bing_search\nfrom sopel.module import commands, url\n\n\nignored_sites = [\n    # For searching the web\n    'almamater.xkcd.com',\n    'blog.xkcd.com',\n    'blag.xkcd.com',\n    'forums.xkcd.com',\n    'fora.xkcd.com',\n    'forums3.xkcd.com',\n    'store.xkcd.com',\n    'wiki.xkcd.com',\n    'what-if.xkcd.com',\n]\nsites_query = ' site:xkcd.com -site:' + ' -site:'.join(ignored_sites)\n\n\ndef get_info(number=None):\n    if number:\n        url = 'https://xkcd.com/{}/info.0.json'.format(number)\n    else:\n        url = 'https://xkcd.com/info.0.json'\n    data = requests.get(url).json()\n    data['url'] = 'https://xkcd.com/' + str(data['num'])\n    return data\n\n\ndef web_search(query):\n    url = bing_search(query + sites_query)\n    if not url:\n        return None\n    match = re.match(r'(?:https?://)?xkcd.com/(\\d+)/?', url)\n    if match:\n        return match.group(1)\n\n\n@commands('xkcd')\ndef xkcd(bot, trigger):\n    \"\"\".xkcd - Finds an xkcd comic strip.\n\n    Takes one of 3 inputs:\n\n      * If no input is provided it will return a random comic\n      * If numeric input is provided it will return that comic, or the\n        nth-latest comic if the number is non-positive\n      * If non-numeric input is provided it will return the first search result\n        for those keywords on the xkcd.com site\n    \"\"\"\n    # get latest comic for rand function and numeric input\n    latest = get_info()\n    max_int = latest['num']\n\n    # if no input is given (pre - lior's edits code)\n    if not trigger.group(2):  # get rand comic\n        random.seed()\n        requested = get_info(random.randint(1, max_int + 1))\n    else:\n        query = trigger.group(2).strip()\n\n        numbered = re.match(r\"^(#|\\+|-)?(\\d+)$\", query)\n        if numbered:\n            query = int(numbered.group(2))\n            if numbered.group(1) == \"-\":\n                query = -query\n            return numbered_result(bot, query, latest)\n        else:\n            # Non-number: search the web.\n            if (query.lower() == \"latest\" or query.lower() == \"newest\"):\n                requested = latest\n            else:\n                number = web_search(query)\n                if not number:\n                    bot.say('Could not find any comics for that query.')\n                    return\n                requested = get_info(number)\n\n    say_result(bot, requested)\n\n\ndef numbered_result(bot, query, latest):\n    max_int = latest['num']\n    if query > max_int:\n        bot.say((\"Sorry, comic #{} hasn't been posted yet. \"\n                 \"The last comic was #{}\").format(query, max_int))\n        return\n    elif query <= -max_int:\n        bot.say((\"Sorry, but there were only {} comics \"\n                 \"released yet so far\").format(max_int))\n        return\n    elif abs(query) == 0:\n        requested = latest\n    elif query == 404 or max_int + query == 404:\n        bot.say(\"404 - Not Found\")  # don't error on that one\n        return\n    elif query > 0:\n        requested = get_info(query)\n    else:\n        # Negative: go back that many from current\n        requested = get_info(max_int + query)\n\n    say_result(bot, requested)\n\n\ndef say_result(bot, result):\n    message = '{} | {} | Alt-text: {}'.format(result['url'], result['title'],\n                                              result['alt'])\n    bot.say(message)\n\n\n@url(r'xkcd.com/(\\d+)')\ndef get_url(bot, trigger, match):\n    latest = get_info()\n    numbered_result(bot, int(match.group(1)), latest)\n", "path": "sopel/modules/xkcd.py"}], "after_files": [{"content": "# coding=utf-8\n\"\"\"\nxkcd.py - Sopel xkcd Module\nCopyright 2010, Michael Yanovich (yanovich.net), and Morgan Goose\nCopyright 2012, Lior Ramati\nCopyright 2013, Elsie Powell (embolalia.com)\nLicensed under the Eiffel Forum License 2.\n\nhttps://sopel.chat\n\"\"\"\nfrom __future__ import unicode_literals, absolute_import, print_function, division\n\nimport random\nimport re\n\nimport requests\n\nfrom sopel.modules.search import bing_search\nfrom sopel.module import commands, url\n\n\nignored_sites = [\n    # For searching the web\n    'almamater.xkcd.com',\n    'blog.xkcd.com',\n    'blag.xkcd.com',\n    'forums.xkcd.com',\n    'fora.xkcd.com',\n    'forums3.xkcd.com',\n    'store.xkcd.com',\n    'wiki.xkcd.com',\n    'what-if.xkcd.com',\n]\nsites_query = ' site:xkcd.com -site:' + ' -site:'.join(ignored_sites)\n\n\ndef get_info(number=None):\n    if number:\n        url = 'https://xkcd.com/{}/info.0.json'.format(number)\n    else:\n        url = 'https://xkcd.com/info.0.json'\n    data = requests.get(url).json()\n    data['url'] = 'https://xkcd.com/' + str(data['num'])\n    return data\n\n\ndef web_search(query):\n    url = bing_search(query + sites_query)\n    if not url:\n        return None\n    match = re.match(r'(?:https?://)?xkcd.com/(\\d+)/?', url)\n    if match:\n        return match.group(1)\n\n\n@commands('xkcd')\ndef xkcd(bot, trigger):\n    \"\"\".xkcd - Finds an xkcd comic strip.\n\n    Takes one of 3 inputs:\n\n      * If no input is provided it will return a random comic\n      * If numeric input is provided it will return that comic, or the\n        nth-latest comic if the number is non-positive\n      * If non-numeric input is provided it will return the first search result\n        for those keywords on the xkcd.com site\n    \"\"\"\n    # get latest comic for rand function and numeric input\n    latest = get_info()\n    max_int = latest['num']\n\n    # if no input is given (pre - lior's edits code)\n    if not trigger.group(2):  # get rand comic\n        random.seed()\n        requested = get_info(random.randint(1, max_int + 1))\n    else:\n        query = trigger.group(2).strip()\n\n        numbered = re.match(r\"^(#|\\+|-)?(\\d+)$\", query)\n        if numbered:\n            query = int(numbered.group(2))\n            if numbered.group(1) == \"-\":\n                query = -query\n            return numbered_result(bot, query, latest)\n        else:\n            # Non-number: search the web.\n            if (query.lower() == \"latest\" or query.lower() == \"newest\"):\n                requested = latest\n            else:\n                number = web_search(query)\n                if not number:\n                    bot.say('Could not find any comics for that query.')\n                    return\n                requested = get_info(number)\n\n    say_result(bot, requested)\n\n\ndef numbered_result(bot, query, latest, commanded=True):\n    max_int = latest['num']\n    if query > max_int:\n        bot.say((\"Sorry, comic #{} hasn't been posted yet. \"\n                 \"The last comic was #{}\").format(query, max_int))\n        return\n    elif query <= -max_int:\n        bot.say((\"Sorry, but there were only {} comics \"\n                 \"released yet so far\").format(max_int))\n        return\n    elif abs(query) == 0:\n        requested = latest\n    elif query == 404 or max_int + query == 404:\n        bot.say(\"404 - Not Found\")  # don't error on that one\n        return\n    elif query > 0:\n        requested = get_info(query)\n    else:\n        # Negative: go back that many from current\n        requested = get_info(max_int + query)\n\n    say_result(bot, requested, commanded)\n\n\ndef say_result(bot, result, commanded=True):\n    message = '{}{} | Alt-text: {}'.format(\n        result['url'] + ' | ' if commanded else '',\n        result['title'], result['alt']\n    )\n    bot.say(message)\n\n\n@url(r'xkcd.com/(\\d+)')\ndef get_url(bot, trigger, match):\n    latest = get_info()\n    numbered_result(bot, int(match.group(1)), latest, commanded=False)\n", "path": "sopel/modules/xkcd.py"}]}