We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add keywords for search
### Where on docs.platform.sh should be changed?

/configuration/app/app-reference.html

### What exactly should be updated?

We'd like specific pages to be findable by searching for specific words. For example, the app reference when searching for `.platform.app.yaml` (this may also involve a problem with escaping characters like `.`). Add keywords or other to make these pages findable.

### Additional context

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `search/main.py`
Content:
```
1 import os
2 import glob
3 import json
4 import meilisearch
5 from platformshconfig import Config
6 
7 class Search:
8     def __init__(self):
9         self.default = {
10             "host": "http://127.0.0.1",
11             "key": None,
12             "port": 7700
13         }
14 
15         self.scrape_dir = "output"
16         self.scrape_config = "config/scrape.json"
17         self.docs_index = "docs"
18         self.primaryKey = "documentId"
19         self.index_name = "Docs"
20 
21         # Below are Platform.sh custom settings for how the search engine functions.
22 
23         # Data available to the dropdown React app in docs, used to fill out autocomplete results.
24         self.displayed_attributes = ['title', 'text', 'url', 'site', 'section']
25         # Data actually searchable by our queries.
26         self.searchable_attributes = ['title', 'pageUrl', 'section', 'url', 'text']
27 
28         # Show results for one query with the listed pages, when they by default would not show up as best results.
29         # Note: these aren't automatically two-way, which is why they're all defined twice.
30         self.synonyms = {
31             "cron": ["crons"],
32             "crons": ["cron tasks", "cron jobs"],
33             "e-mail": ["email"],
34             "routes.yaml": ["routes"],
35             "routes": ["routes.yaml"],
36             "services": ["services.yaml"],
37             "services.yaml": ["services"],
38             "application": [".platform.app.yaml", "app.yaml", "applications.yaml"],
39             ".platform.app.yaml": ["application"],
40             "app.yaml": ["application"],
41             "applications.yaml": ["application", "multi-app"],
42             "multi-app": ["applications.yaml"],
43             "regions": ["public ip addresses"],
44             "public ip addresses": ["regions"],
45             "ssl": ["https", "tls"],
46             "https": ["ssl"],
47         }
48 
49         # Ranking rules:
50         #
51         #   - Default order: ["words", "typo", "proximity", "attribute", "sort", "exactness"]
52         #
53         #   - words: number of times query is in document (greater number gets priority)
54         #   - typo: fewer typos > more typos
55         #   - proximity: smaller distance between multiple occurences of query in same document > larger distances
56         #   - attribute: sorted according to order of importance of attributes (searchable_attributes). terms in
57         #       more important attributes first.
58         #   - sort: queries are sorted at query time
59         #   - exactness: similarity of matched words in document with query
60 
61         self.ranking_rules = ["rank:asc", "attribute", "typo", "words", "proximity", "exactness"]
62 
63         self.updated_settings = {
64             "rankingRules": self.ranking_rules,
65             "searchableAttributes": self.searchable_attributes,
66             "displayedAttributes": self.displayed_attributes
67         }
68 
69         # Group results by page
70         self.distinct_attribute = "pageUrl"
71 
72     def getConnectionString(self):
73         """
74         Sets the Meilisearch host string, depending on the environment.
75 
76         Returns:
77             string: Meilisearch host string.
78         """
79         if os.environ.get('PORT'):
80             return "{}:{}".format(self.default["host"], os.environ['PORT'])
81         else:
82             return "{}:{}".format(self.default["host"], self.default["port"])
83 
84     def getMasterKey(self):
85         """
86         Retrieves the Meilisearch master key, either from the Platform.sh environment or locally.
87         """
88         config = Config()
89         if config.is_valid_platform():
90             return config.projectEntropy
91         elif os.environ.get("MEILI_MASTER_KEY"):
92             return os.environ["MEILI_MASTER_KEY"]
93         else:
94             return self.default["key"]
95 
96     def add_documents(self, index):
97         """
98         Cycle through the individual site indexes in /outputs so their individual documents can be added to Meilisearch.
99         """
100         documents = [f for f in glob.glob("{}/*.json".format(self.scrape_dir))]
101         for doc in documents:
102             self.add(doc, index)
103 
104     def add(self, doc, index):
105         """
106         Add an individual site's index to the Meilisearch service.
107         """
108         with open(doc) as scraped_index:
109             data = json.load(scraped_index)
110             index.add_documents(data)
111 
112     def update(self):
113         """
114         Updates the Meilisearch index.
115         """
116         # Create a Meilisearch client.
117         client = meilisearch.Client(self.getConnectionString(), self.getMasterKey())
118 
119         # Delete previous index
120         if len(client.get_indexes()):
121             client.get_index(self.docs_index).delete()
122 
123         # Create a new index
124         index = client.create_index(uid=self.docs_index, options={'primaryKey': self.primaryKey, 'uid': self.index_name})
125 
126         # Add synonyms for the index
127         index.update_synonyms(self.synonyms)
128 
129         # Update its settings: what can be searched, what's displayable, and how results should be ranked.
130         index.update_settings(self.updated_settings)
131 
132         # Update distinct attribute.
133         index.update_distinct_attribute(self.distinct_attribute)
134 
135         # Add documents to the index
136         self.add_documents(index)
137 
138 if __name__ == "__main__":
139     meili = Search()
140     meili.update()
141
```
--- 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/search/main.py b/search/main.py
--- a/search/main.py
+++ b/search/main.py
@@ -21,9 +21,9 @@
         # Below are Platform.sh custom settings for how the search engine functions.
 
         # Data available to the dropdown React app in docs, used to fill out autocomplete results.
-        self.displayed_attributes = ['title', 'text', 'url', 'site', 'section']
+        self.displayed_attributes = ['keywords', 'title', 'text', 'url', 'site', 'section']
         # Data actually searchable by our queries.
-        self.searchable_attributes = ['title', 'pageUrl', 'section', 'url', 'text']
+        self.searchable_attributes = ['keywords', 'title', 'pageUrl', 'section', 'text', 'url']
 
         # Show results for one query with the listed pages, when they by default would not show up as best results.
         # Note: these aren't automatically two-way, which is why they're all defined twice.

{"golden_diff": "diff --git a/search/main.py b/search/main.py\n--- a/search/main.py\n+++ b/search/main.py\n@@ -21,9 +21,9 @@\n         # Below are Platform.sh custom settings for how the search engine functions.\n \n         # Data available to the dropdown React app in docs, used to fill out autocomplete results.\n-        self.displayed_attributes = ['title', 'text', 'url', 'site', 'section']\n+        self.displayed_attributes = ['keywords', 'title', 'text', 'url', 'site', 'section']\n         # Data actually searchable by our queries.\n-        self.searchable_attributes = ['title', 'pageUrl', 'section', 'url', 'text']\n+        self.searchable_attributes = ['keywords', 'title', 'pageUrl', 'section', 'text', 'url']\n \n         # Show results for one query with the listed pages, when they by default would not show up as best results.\n         # Note: these aren't automatically two-way, which is why they're all defined twice.\n", "issue": "Add keywords for search\n### Where on docs.platform.sh should be changed?\n\n/configuration/app/app-reference.html\n\n### What exactly should be updated?\n\nWe'd like specific pages to be findable by searching for specific words. For example, the app reference when searching for `.platform.app.yaml` (this may also involve a problem with escaping characters like `.`). Add keywords or other to make these pages findable.\n\n### Additional context\n\n_No response_\n", "before_files": [{"content": "import os\nimport glob\nimport json\nimport meilisearch\nfrom platformshconfig import Config\n\nclass Search:\n    def __init__(self):\n        self.default = {\n            \"host\": \"http://127.0.0.1\",\n            \"key\": None,\n            \"port\": 7700\n        }\n\n        self.scrape_dir = \"output\"\n        self.scrape_config = \"config/scrape.json\"\n        self.docs_index = \"docs\"\n        self.primaryKey = \"documentId\"\n        self.index_name = \"Docs\"\n\n        # Below are Platform.sh custom settings for how the search engine functions.\n\n        # Data available to the dropdown React app in docs, used to fill out autocomplete results.\n        self.displayed_attributes = ['title', 'text', 'url', 'site', 'section']\n        # Data actually searchable by our queries.\n        self.searchable_attributes = ['title', 'pageUrl', 'section', 'url', 'text']\n\n        # Show results for one query with the listed pages, when they by default would not show up as best results.\n        # Note: these aren't automatically two-way, which is why they're all defined twice.\n        self.synonyms = {\n            \"cron\": [\"crons\"],\n            \"crons\": [\"cron tasks\", \"cron jobs\"],\n            \"e-mail\": [\"email\"],\n            \"routes.yaml\": [\"routes\"],\n            \"routes\": [\"routes.yaml\"],\n            \"services\": [\"services.yaml\"],\n            \"services.yaml\": [\"services\"],\n            \"application\": [\".platform.app.yaml\", \"app.yaml\", \"applications.yaml\"],\n            \".platform.app.yaml\": [\"application\"],\n            \"app.yaml\": [\"application\"],\n            \"applications.yaml\": [\"application\", \"multi-app\"],\n            \"multi-app\": [\"applications.yaml\"],\n            \"regions\": [\"public ip addresses\"],\n            \"public ip addresses\": [\"regions\"],\n            \"ssl\": [\"https\", \"tls\"],\n            \"https\": [\"ssl\"],\n        }\n\n        # Ranking rules:\n        #\n        #   - Default order: [\"words\", \"typo\", \"proximity\", \"attribute\", \"sort\", \"exactness\"]\n        #\n        #   - words: number of times query is in document (greater number gets priority)\n        #   - typo: fewer typos > more typos\n        #   - proximity: smaller distance between multiple occurences of query in same document > larger distances\n        #   - attribute: sorted according to order of importance of attributes (searchable_attributes). terms in\n        #       more important attributes first.\n        #   - sort: queries are sorted at query time\n        #   - exactness: similarity of matched words in document with query\n\n        self.ranking_rules = [\"rank:asc\", \"attribute\", \"typo\", \"words\", \"proximity\", \"exactness\"]\n\n        self.updated_settings = {\n            \"rankingRules\": self.ranking_rules,\n            \"searchableAttributes\": self.searchable_attributes,\n            \"displayedAttributes\": self.displayed_attributes\n        }\n\n        # Group results by page\n        self.distinct_attribute = \"pageUrl\"\n\n    def getConnectionString(self):\n        \"\"\"\n        Sets the Meilisearch host string, depending on the environment.\n\n        Returns:\n            string: Meilisearch host string.\n        \"\"\"\n        if os.environ.get('PORT'):\n            return \"{}:{}\".format(self.default[\"host\"], os.environ['PORT'])\n        else:\n            return \"{}:{}\".format(self.default[\"host\"], self.default[\"port\"])\n\n    def getMasterKey(self):\n        \"\"\"\n        Retrieves the Meilisearch master key, either from the Platform.sh environment or locally.\n        \"\"\"\n        config = Config()\n        if config.is_valid_platform():\n            return config.projectEntropy\n        elif os.environ.get(\"MEILI_MASTER_KEY\"):\n            return os.environ[\"MEILI_MASTER_KEY\"]\n        else:\n            return self.default[\"key\"]\n\n    def add_documents(self, index):\n        \"\"\"\n        Cycle through the individual site indexes in /outputs so their individual documents can be added to Meilisearch.\n        \"\"\"\n        documents = [f for f in glob.glob(\"{}/*.json\".format(self.scrape_dir))]\n        for doc in documents:\n            self.add(doc, index)\n\n    def add(self, doc, index):\n        \"\"\"\n        Add an individual site's index to the Meilisearch service.\n        \"\"\"\n        with open(doc) as scraped_index:\n            data = json.load(scraped_index)\n            index.add_documents(data)\n\n    def update(self):\n        \"\"\"\n        Updates the Meilisearch index.\n        \"\"\"\n        # Create a Meilisearch client.\n        client = meilisearch.Client(self.getConnectionString(), self.getMasterKey())\n\n        # Delete previous index\n        if len(client.get_indexes()):\n            client.get_index(self.docs_index).delete()\n\n        # Create a new index\n        index = client.create_index(uid=self.docs_index, options={'primaryKey': self.primaryKey, 'uid': self.index_name})\n\n        # Add synonyms for the index\n        index.update_synonyms(self.synonyms)\n\n        # Update its settings: what can be searched, what's displayable, and how results should be ranked.\n        index.update_settings(self.updated_settings)\n\n        # Update distinct attribute.\n        index.update_distinct_attribute(self.distinct_attribute)\n\n        # Add documents to the index\n        self.add_documents(index)\n\nif __name__ == \"__main__\":\n    meili = Search()\n    meili.update()\n", "path": "search/main.py"}], "after_files": [{"content": "import os\nimport glob\nimport json\nimport meilisearch\nfrom platformshconfig import Config\n\nclass Search:\n    def __init__(self):\n        self.default = {\n            \"host\": \"http://127.0.0.1\",\n            \"key\": None,\n            \"port\": 7700\n        }\n\n        self.scrape_dir = \"output\"\n        self.scrape_config = \"config/scrape.json\"\n        self.docs_index = \"docs\"\n        self.primaryKey = \"documentId\"\n        self.index_name = \"Docs\"\n\n        # Below are Platform.sh custom settings for how the search engine functions.\n\n        # Data available to the dropdown React app in docs, used to fill out autocomplete results.\n        self.displayed_attributes = ['keywords', 'title', 'text', 'url', 'site', 'section']\n        # Data actually searchable by our queries.\n        self.searchable_attributes = ['keywords', 'title', 'pageUrl', 'section', 'text', 'url']\n\n        # Show results for one query with the listed pages, when they by default would not show up as best results.\n        # Note: these aren't automatically two-way, which is why they're all defined twice.\n        self.synonyms = {\n            \"cron\": [\"crons\"],\n            \"crons\": [\"cron tasks\", \"cron jobs\"],\n            \"e-mail\": [\"email\"],\n            \"routes.yaml\": [\"routes\"],\n            \"routes\": [\"routes.yaml\"],\n            \"services\": [\"services.yaml\"],\n            \"services.yaml\": [\"services\"],\n            \"application\": [\".platform.app.yaml\", \"app.yaml\", \"applications.yaml\"],\n            \".platform.app.yaml\": [\"application\"],\n            \"app.yaml\": [\"application\"],\n            \"applications.yaml\": [\"application\", \"multi-app\"],\n            \"multi-app\": [\"applications.yaml\"],\n            \"regions\": [\"public ip addresses\"],\n            \"public ip addresses\": [\"regions\"],\n            \"ssl\": [\"https\", \"tls\"],\n            \"https\": [\"ssl\"],\n        }\n\n        # Ranking rules:\n        #\n        #   - Default order: [\"words\", \"typo\", \"proximity\", \"attribute\", \"sort\", \"exactness\"]\n        #\n        #   - words: number of times query is in document (greater number gets priority)\n        #   - typo: fewer typos > more typos\n        #   - proximity: smaller distance between multiple occurences of query in same document > larger distances\n        #   - attribute: sorted according to order of importance of attributes (searchable_attributes). terms in\n        #       more important attributes first.\n        #   - sort: queries are sorted at query time\n        #   - exactness: similarity of matched words in document with query\n\n        self.ranking_rules = [\"rank:asc\", \"attribute\", \"typo\", \"words\", \"proximity\", \"exactness\"]\n\n        self.updated_settings = {\n            \"rankingRules\": self.ranking_rules,\n            \"searchableAttributes\": self.searchable_attributes,\n            \"displayedAttributes\": self.displayed_attributes\n        }\n\n        # Group results by page\n        self.distinct_attribute = \"pageUrl\"\n\n    def getConnectionString(self):\n        \"\"\"\n        Sets the Meilisearch host string, depending on the environment.\n\n        Returns:\n            string: Meilisearch host string.\n        \"\"\"\n        if os.environ.get('PORT'):\n            return \"{}:{}\".format(self.default[\"host\"], os.environ['PORT'])\n        else:\n            return \"{}:{}\".format(self.default[\"host\"], self.default[\"port\"])\n\n    def getMasterKey(self):\n        \"\"\"\n        Retrieves the Meilisearch master key, either from the Platform.sh environment or locally.\n        \"\"\"\n        config = Config()\n        if config.is_valid_platform():\n            return config.projectEntropy\n        elif os.environ.get(\"MEILI_MASTER_KEY\"):\n            return os.environ[\"MEILI_MASTER_KEY\"]\n        else:\n            return self.default[\"key\"]\n\n    def add_documents(self, index):\n        \"\"\"\n        Cycle through the individual site indexes in /outputs so their individual documents can be added to Meilisearch.\n        \"\"\"\n        documents = [f for f in glob.glob(\"{}/*.json\".format(self.scrape_dir))]\n        for doc in documents:\n            self.add(doc, index)\n\n    def add(self, doc, index):\n        \"\"\"\n        Add an individual site's index to the Meilisearch service.\n        \"\"\"\n        with open(doc) as scraped_index:\n            data = json.load(scraped_index)\n            index.add_documents(data)\n\n    def update(self):\n        \"\"\"\n        Updates the Meilisearch index.\n        \"\"\"\n        # Create a Meilisearch client.\n        client = meilisearch.Client(self.getConnectionString(), self.getMasterKey())\n\n        # Delete previous index\n        if len(client.get_indexes()):\n            client.get_index(self.docs_index).delete()\n\n        # Create a new index\n        index = client.create_index(uid=self.docs_index, options={'primaryKey': self.primaryKey, 'uid': self.index_name})\n\n        # Add synonyms for the index\n        index.update_synonyms(self.synonyms)\n\n        # Update its settings: what can be searched, what's displayable, and how results should be ranked.\n        index.update_settings(self.updated_settings)\n\n        # Update distinct attribute.\n        index.update_distinct_attribute(self.distinct_attribute)\n\n        # Add documents to the index\n        self.add_documents(index)\n\nif __name__ == \"__main__\":\n    meili = Search()\n    meili.update()\n", "path": "search/main.py"}]}