We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
mycroft.conf silently overwritten
**Describe the bug**
When there's an error in mycroft.conf, it is silently overwritten.  This is bad because user settings should not be permanently deleted without consent. Instead, logs and/or the output of mycroft-start should show the error.

**To Reproduce**
Try the following mycroft.conf:
```
{
  "max_allowed_core_version": 20.8,
  "listener": {
    "wake_word": "Lazarus",
    "device_name": "default"
    "energy_ratio": 1.5
  },
  "hotwords": {
    "Lazarus": {
      "module": "pocketsphinx",
      "phonemes": "L AE Z ER AH S .",
    }
  }
}
```

Note the missing comma after "default" and incorrect use of the energy ratio parameter.

After running mycroft-start restart all, it is overwritten with the following:

```
{
  "max_allowed_core_version": 20.8
}
```

**Expected behavior**
One of the following:
"Mycroft failed to start because of an error in mycroft.conf."

or

The config file is copied to `mycroft.conf.old` (or `mycroft.conf.old.1`, etc.) and `mycroft.conf` is overwritten with the following:
```
# The previous mycroft.conf contained errors and was moved to mycroft.conf.old.
{
  "max_allowed_core_version": 20.8
}
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mycroft/configuration/config.py`
Content:
```
1 
2 # Copyright 2017 Mycroft AI Inc.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # 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 
17 import json
18 import os
19 import re
20 from os.path import exists, isfile, join, dirname
21 
22 import xdg.BaseDirectory
23 from requests import RequestException
24 
25 from mycroft.util.combo_lock import ComboLock
26 from mycroft.util.file_utils import get_temp_path
27 from mycroft.util import camel_case_split
28 from mycroft.util.json_helper import load_commented_json, merge_dict
29 from mycroft.util.log import LOG
30 
31 from .locations import (
32     DEFAULT_CONFIG,
33     OLD_USER_CONFIG,
34     SYSTEM_CONFIG,
35     USER_CONFIG
36 )
37 
38 
39 def is_remote_list(values):
40     """Check if list corresponds to a backend formatted collection of dicts
41     """
42     for v in values:
43         if not isinstance(v, dict):
44             return False
45         if "@type" not in v.keys():
46             return False
47     return True
48 
49 
50 def translate_remote(config, setting):
51     """Translate config names from server to equivalents for mycroft-core.
52 
53     Args:
54         config:     base config to populate
55         settings:   remote settings to be translated
56     """
57     IGNORED_SETTINGS = ["uuid", "@type", "active", "user", "device"]
58 
59     for k, v in setting.items():
60         if k not in IGNORED_SETTINGS:
61             # Translate the CamelCase values stored remotely into the
62             # Python-style names used within mycroft-core.
63             key = re.sub(r"Setting(s)?", "", k)
64             key = camel_case_split(key).replace(" ", "_").lower()
65             if isinstance(v, dict):
66                 config[key] = config.get(key, {})
67                 translate_remote(config[key], v)
68             elif isinstance(v, list):
69                 if is_remote_list(v):
70                     if key not in config:
71                         config[key] = {}
72                     translate_list(config[key], v)
73                 else:
74                     config[key] = v
75             else:
76                 config[key] = v
77 
78 
79 def translate_list(config, values):
80     """Translate list formated by mycroft server.
81 
82     Args:
83         config (dict): target config
84         values (list): list from mycroft server config
85     """
86     for v in values:
87         module = v["@type"]
88         if v.get("active"):
89             config["module"] = module
90         config[module] = config.get(module, {})
91         translate_remote(config[module], v)
92 
93 
94 class LocalConf(dict):
95     """Config dictionary from file."""
96     _lock = ComboLock(get_temp_path('local-conf.lock'))
97 
98     def __init__(self, path):
99         super(LocalConf, self).__init__()
100         if path:
101             self.path = path
102             self.load_local(path)
103 
104     def load_local(self, path):
105         """Load local json file into self.
106 
107         Args:
108             path (str): file to load
109         """
110         if exists(path) and isfile(path):
111             try:
112                 config = load_commented_json(path)
113                 for key in config:
114                     self.__setitem__(key, config[key])
115 
116                 LOG.debug("Configuration {} loaded".format(path))
117             except Exception as e:
118                 LOG.error("Error loading configuration '{}'".format(path))
119                 LOG.error(repr(e))
120         else:
121             LOG.debug("Configuration '{}' not defined, skipping".format(path))
122 
123     def store(self, path=None):
124         """Cache the received settings locally.
125 
126         The cache will be used if the remote is unreachable to load settings
127         that are as close to the user's as possible.
128         """
129         with self._lock:
130             path = path or self.path
131             config_dir = dirname(path)
132             if not exists(config_dir):
133                 os.makedirs(config_dir)
134 
135             with open(path, 'w') as f:
136                 json.dump(self, f, indent=2)
137 
138     def merge(self, conf):
139         merge_dict(self, conf)
140 
141 
142 class RemoteConf(LocalConf):
143     _lock = ComboLock(get_temp_path('remote-conf.lock'))
144     """Config dictionary fetched from mycroft.ai."""
145 
146     def __init__(self, cache=None):
147         super(RemoteConf, self).__init__(None)
148 
149         cache = cache or join(xdg.BaseDirectory.xdg_cache_home, 'mycroft',
150                               'web_cache.json')
151         from mycroft.api import is_paired
152         if not is_paired():
153             self.load_local(cache)
154             return
155 
156         try:
157             # Here to avoid cyclic import
158             from mycroft.api import DeviceApi
159             api = DeviceApi()
160             setting = api.get_settings()
161 
162             location = None
163             try:
164                 location = api.get_location()
165             except RequestException as e:
166                 LOG.error("RequestException fetching remote location: {}"
167                           .format(str(e)))
168                 if exists(cache) and isfile(cache):
169                     location = load_commented_json(cache).get('location')
170 
171             if location:
172                 setting["location"] = location
173             # Remove server specific entries
174             config = {}
175             translate_remote(config, setting)
176             for key in config:
177                 self.__setitem__(key, config[key])
178             self.store(cache)
179 
180         except RequestException as e:
181             LOG.error("RequestException fetching remote configuration: {}"
182                       .format(str(e)))
183             self.load_local(cache)
184 
185         except Exception as e:
186             LOG.error("Failed to fetch remote configuration: %s" % repr(e),
187                       exc_info=True)
188             self.load_local(cache)
189 
190 
191 def _log_old_location_deprecation():
192     LOG.warning("\n ===============================================\n"
193                 " ==             DEPRECATION WARNING           ==\n"
194                 " ===============================================\n"
195                 f" You still have a config file at {OLD_USER_CONFIG}\n"
196                 " Note that this location is deprecated and will"
197                 " not be used in the future\n"
198                 " Please move it to "
199                 f"{join(xdg.BaseDirectory.xdg_config_home, 'mycroft')}")
200 
201 
202 class Configuration:
203     """Namespace for operations on the configuration singleton."""
204     __config = {}  # Cached config
205     __patch = {}  # Patch config that skills can update to override config
206 
207     @staticmethod
208     def get(configs=None, cache=True, remote=True):
209         """Get configuration
210 
211         Returns cached instance if available otherwise builds a new
212         configuration dict.
213 
214         Args:
215             configs (list): List of configuration dicts
216             cache (boolean): True if the result should be cached
217             remote (boolean): False if the Remote settings shouldn't be loaded
218 
219         Returns:
220             (dict) configuration dictionary.
221         """
222         if Configuration.__config:
223             return Configuration.__config
224         else:
225             return Configuration.load_config_stack(configs, cache, remote)
226 
227     @staticmethod
228     def load_config_stack(configs=None, cache=False, remote=True):
229         """Load a stack of config dicts into a single dict
230 
231         Args:
232             configs (list): list of dicts to load
233             cache (boolean): True if result should be cached
234             remote (boolean): False if the Mycroft Home settings shouldn't
235                               be loaded
236         Returns:
237             (dict) merged dict of all configuration files
238         """
239         if not configs:
240             configs = []
241 
242             # First use the patched config
243             configs.append(Configuration.__patch)
244 
245             # Then use XDG config
246             # This includes both the user config and
247             # /etc/xdg/mycroft/mycroft.conf
248             for conf_dir in xdg.BaseDirectory.load_config_paths('mycroft'):
249                 configs.append(LocalConf(join(conf_dir, 'mycroft.conf')))
250 
251             # Then check the old user config
252             if isfile(OLD_USER_CONFIG):
253                 _log_old_location_deprecation()
254                 configs.append(LocalConf(OLD_USER_CONFIG))
255 
256             # Then use the system config (/etc/mycroft/mycroft.conf)
257             configs.append(LocalConf(SYSTEM_CONFIG))
258 
259             # Then use remote config
260             if remote:
261                 configs.append(RemoteConf())
262 
263             # Then use the config that comes with the package
264             configs.append(LocalConf(DEFAULT_CONFIG))
265 
266             # Make sure we reverse the array, as merge_dict will put every new
267             # file on top of the previous one
268             configs = reversed(configs)
269         else:
270             # Handle strings in stack
271             for index, item in enumerate(configs):
272                 if isinstance(item, str):
273                     configs[index] = LocalConf(item)
274 
275         # Merge all configs into one
276         base = {}
277         for c in configs:
278             merge_dict(base, c)
279 
280         # copy into cache
281         if cache:
282             Configuration.__config.clear()
283             for key in base:
284                 Configuration.__config[key] = base[key]
285             return Configuration.__config
286         else:
287             return base
288 
289     @staticmethod
290     def set_config_update_handlers(bus):
291         """Setup websocket handlers to update config.
292 
293         Args:
294             bus: Message bus client instance
295         """
296         bus.on("configuration.updated", Configuration.updated)
297         bus.on("configuration.patch", Configuration.patch)
298         bus.on("configuration.patch.clear", Configuration.patch_clear)
299 
300     @staticmethod
301     def updated(message):
302         """Handler for configuration.updated,
303 
304         Triggers an update of cached config.
305         """
306         Configuration.load_config_stack(cache=True)
307 
308     @staticmethod
309     def patch(message):
310         """Patch the volatile dict usable by skills
311 
312         Args:
313             message: Messagebus message should contain a config
314                      in the data payload.
315         """
316         config = message.data.get("config", {})
317         merge_dict(Configuration.__patch, config)
318         Configuration.load_config_stack(cache=True)
319 
320     @staticmethod
321     def patch_clear(message):
322         """Clear the config patch space.
323 
324         Args:
325             message: Messagebus message should contain a config
326                      in the data payload.
327         """
328         Configuration.__patch = {}
329         Configuration.load_config_stack(cache=True)
330
```
--- 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/mycroft/configuration/config.py b/mycroft/configuration/config.py
--- a/mycroft/configuration/config.py
+++ b/mycroft/configuration/config.py
@@ -97,6 +97,7 @@
 
     def __init__(self, path):
         super(LocalConf, self).__init__()
+        self.is_valid = True  # is loaded json valid, updated when load occurs
         if path:
             self.path = path
             self.load_local(path)
@@ -117,23 +118,41 @@
             except Exception as e:
                 LOG.error("Error loading configuration '{}'".format(path))
                 LOG.error(repr(e))
+                self.is_valid = False
         else:
             LOG.debug("Configuration '{}' not defined, skipping".format(path))
 
-    def store(self, path=None):
-        """Cache the received settings locally.
+    def store(self, path=None, force=False):
+        """Save config to disk.
 
         The cache will be used if the remote is unreachable to load settings
         that are as close to the user's as possible.
+
+        path (str): path to store file to, if missing will use the path from
+                    where the config was loaded.
+        force (bool): Set to True if writing should occur despite the original
+                      was malformed.
+
+        Returns:
+            (bool) True if save was successful, else False.
         """
+        result = False
         with self._lock:
             path = path or self.path
             config_dir = dirname(path)
             if not exists(config_dir):
                 os.makedirs(config_dir)
 
-            with open(path, 'w') as f:
-                json.dump(self, f, indent=2)
+            if self.is_valid or force:
+                with open(path, 'w') as f:
+                    json.dump(self, f, indent=2)
+                result = True
+            else:
+                LOG.warning((f'"{path}" was not a valid config file when '
+                             'loaded, will not save config. Please correct '
+                             'the json or remove it to allow updates.'))
+                result = False
+        return result
 
     def merge(self, conf):
         merge_dict(self, conf)
@@ -175,7 +194,7 @@
             translate_remote(config, setting)
             for key in config:
                 self.__setitem__(key, config[key])
-            self.store(cache)
+            self.store(cache, force=True)
 
         except RequestException as e:
             LOG.error("RequestException fetching remote configuration: {}"

{"golden_diff": "diff --git a/mycroft/configuration/config.py b/mycroft/configuration/config.py\n--- a/mycroft/configuration/config.py\n+++ b/mycroft/configuration/config.py\n@@ -97,6 +97,7 @@\n \n     def __init__(self, path):\n         super(LocalConf, self).__init__()\n+        self.is_valid = True  # is loaded json valid, updated when load occurs\n         if path:\n             self.path = path\n             self.load_local(path)\n@@ -117,23 +118,41 @@\n             except Exception as e:\n                 LOG.error(\"Error loading configuration '{}'\".format(path))\n                 LOG.error(repr(e))\n+                self.is_valid = False\n         else:\n             LOG.debug(\"Configuration '{}' not defined, skipping\".format(path))\n \n-    def store(self, path=None):\n-        \"\"\"Cache the received settings locally.\n+    def store(self, path=None, force=False):\n+        \"\"\"Save config to disk.\n \n         The cache will be used if the remote is unreachable to load settings\n         that are as close to the user's as possible.\n+\n+        path (str): path to store file to, if missing will use the path from\n+                    where the config was loaded.\n+        force (bool): Set to True if writing should occur despite the original\n+                      was malformed.\n+\n+        Returns:\n+            (bool) True if save was successful, else False.\n         \"\"\"\n+        result = False\n         with self._lock:\n             path = path or self.path\n             config_dir = dirname(path)\n             if not exists(config_dir):\n                 os.makedirs(config_dir)\n \n-            with open(path, 'w') as f:\n-                json.dump(self, f, indent=2)\n+            if self.is_valid or force:\n+                with open(path, 'w') as f:\n+                    json.dump(self, f, indent=2)\n+                result = True\n+            else:\n+                LOG.warning((f'\"{path}\" was not a valid config file when '\n+                             'loaded, will not save config. Please correct '\n+                             'the json or remove it to allow updates.'))\n+                result = False\n+        return result\n \n     def merge(self, conf):\n         merge_dict(self, conf)\n@@ -175,7 +194,7 @@\n             translate_remote(config, setting)\n             for key in config:\n                 self.__setitem__(key, config[key])\n-            self.store(cache)\n+            self.store(cache, force=True)\n \n         except RequestException as e:\n             LOG.error(\"RequestException fetching remote configuration: {}\"\n", "issue": "mycroft.conf silently overwritten\n**Describe the bug**\r\nWhen there's an error in mycroft.conf, it is silently overwritten.  This is bad because user settings should not be permanently deleted without consent. Instead, logs and/or the output of mycroft-start should show the error.\r\n\r\n**To Reproduce**\r\nTry the following mycroft.conf:\r\n```\r\n{\r\n  \"max_allowed_core_version\": 20.8,\r\n  \"listener\": {\r\n    \"wake_word\": \"Lazarus\",\r\n    \"device_name\": \"default\"\r\n    \"energy_ratio\": 1.5\r\n  },\r\n  \"hotwords\": {\r\n    \"Lazarus\": {\r\n      \"module\": \"pocketsphinx\",\r\n      \"phonemes\": \"L AE Z ER AH S .\",\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nNote the missing comma after \"default\" and incorrect use of the energy ratio parameter.\r\n\r\nAfter running mycroft-start restart all, it is overwritten with the following:\r\n\r\n```\r\n{\r\n  \"max_allowed_core_version\": 20.8\r\n}\r\n```\r\n\r\n**Expected behavior**\r\nOne of the following:\r\n\"Mycroft failed to start because of an error in mycroft.conf.\"\r\n\r\nor\r\n\r\nThe config file is copied to `mycroft.conf.old` (or `mycroft.conf.old.1`, etc.) and `mycroft.conf` is overwritten with the following:\r\n```\r\n# The previous mycroft.conf contained errors and was moved to mycroft.conf.old.\r\n{\r\n  \"max_allowed_core_version\": 20.8\r\n}\r\n```\n", "before_files": [{"content": "\n# Copyright 2017 Mycroft AI Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# 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#\n\nimport json\nimport os\nimport re\nfrom os.path import exists, isfile, join, dirname\n\nimport xdg.BaseDirectory\nfrom requests import RequestException\n\nfrom mycroft.util.combo_lock import ComboLock\nfrom mycroft.util.file_utils import get_temp_path\nfrom mycroft.util import camel_case_split\nfrom mycroft.util.json_helper import load_commented_json, merge_dict\nfrom mycroft.util.log import LOG\n\nfrom .locations import (\n    DEFAULT_CONFIG,\n    OLD_USER_CONFIG,\n    SYSTEM_CONFIG,\n    USER_CONFIG\n)\n\n\ndef is_remote_list(values):\n    \"\"\"Check if list corresponds to a backend formatted collection of dicts\n    \"\"\"\n    for v in values:\n        if not isinstance(v, dict):\n            return False\n        if \"@type\" not in v.keys():\n            return False\n    return True\n\n\ndef translate_remote(config, setting):\n    \"\"\"Translate config names from server to equivalents for mycroft-core.\n\n    Args:\n        config:     base config to populate\n        settings:   remote settings to be translated\n    \"\"\"\n    IGNORED_SETTINGS = [\"uuid\", \"@type\", \"active\", \"user\", \"device\"]\n\n    for k, v in setting.items():\n        if k not in IGNORED_SETTINGS:\n            # Translate the CamelCase values stored remotely into the\n            # Python-style names used within mycroft-core.\n            key = re.sub(r\"Setting(s)?\", \"\", k)\n            key = camel_case_split(key).replace(\" \", \"_\").lower()\n            if isinstance(v, dict):\n                config[key] = config.get(key, {})\n                translate_remote(config[key], v)\n            elif isinstance(v, list):\n                if is_remote_list(v):\n                    if key not in config:\n                        config[key] = {}\n                    translate_list(config[key], v)\n                else:\n                    config[key] = v\n            else:\n                config[key] = v\n\n\ndef translate_list(config, values):\n    \"\"\"Translate list formated by mycroft server.\n\n    Args:\n        config (dict): target config\n        values (list): list from mycroft server config\n    \"\"\"\n    for v in values:\n        module = v[\"@type\"]\n        if v.get(\"active\"):\n            config[\"module\"] = module\n        config[module] = config.get(module, {})\n        translate_remote(config[module], v)\n\n\nclass LocalConf(dict):\n    \"\"\"Config dictionary from file.\"\"\"\n    _lock = ComboLock(get_temp_path('local-conf.lock'))\n\n    def __init__(self, path):\n        super(LocalConf, self).__init__()\n        if path:\n            self.path = path\n            self.load_local(path)\n\n    def load_local(self, path):\n        \"\"\"Load local json file into self.\n\n        Args:\n            path (str): file to load\n        \"\"\"\n        if exists(path) and isfile(path):\n            try:\n                config = load_commented_json(path)\n                for key in config:\n                    self.__setitem__(key, config[key])\n\n                LOG.debug(\"Configuration {} loaded\".format(path))\n            except Exception as e:\n                LOG.error(\"Error loading configuration '{}'\".format(path))\n                LOG.error(repr(e))\n        else:\n            LOG.debug(\"Configuration '{}' not defined, skipping\".format(path))\n\n    def store(self, path=None):\n        \"\"\"Cache the received settings locally.\n\n        The cache will be used if the remote is unreachable to load settings\n        that are as close to the user's as possible.\n        \"\"\"\n        with self._lock:\n            path = path or self.path\n            config_dir = dirname(path)\n            if not exists(config_dir):\n                os.makedirs(config_dir)\n\n            with open(path, 'w') as f:\n                json.dump(self, f, indent=2)\n\n    def merge(self, conf):\n        merge_dict(self, conf)\n\n\nclass RemoteConf(LocalConf):\n    _lock = ComboLock(get_temp_path('remote-conf.lock'))\n    \"\"\"Config dictionary fetched from mycroft.ai.\"\"\"\n\n    def __init__(self, cache=None):\n        super(RemoteConf, self).__init__(None)\n\n        cache = cache or join(xdg.BaseDirectory.xdg_cache_home, 'mycroft',\n                              'web_cache.json')\n        from mycroft.api import is_paired\n        if not is_paired():\n            self.load_local(cache)\n            return\n\n        try:\n            # Here to avoid cyclic import\n            from mycroft.api import DeviceApi\n            api = DeviceApi()\n            setting = api.get_settings()\n\n            location = None\n            try:\n                location = api.get_location()\n            except RequestException as e:\n                LOG.error(\"RequestException fetching remote location: {}\"\n                          .format(str(e)))\n                if exists(cache) and isfile(cache):\n                    location = load_commented_json(cache).get('location')\n\n            if location:\n                setting[\"location\"] = location\n            # Remove server specific entries\n            config = {}\n            translate_remote(config, setting)\n            for key in config:\n                self.__setitem__(key, config[key])\n            self.store(cache)\n\n        except RequestException as e:\n            LOG.error(\"RequestException fetching remote configuration: {}\"\n                      .format(str(e)))\n            self.load_local(cache)\n\n        except Exception as e:\n            LOG.error(\"Failed to fetch remote configuration: %s\" % repr(e),\n                      exc_info=True)\n            self.load_local(cache)\n\n\ndef _log_old_location_deprecation():\n    LOG.warning(\"\\n ===============================================\\n\"\n                \" ==             DEPRECATION WARNING           ==\\n\"\n                \" ===============================================\\n\"\n                f\" You still have a config file at {OLD_USER_CONFIG}\\n\"\n                \" Note that this location is deprecated and will\"\n                \" not be used in the future\\n\"\n                \" Please move it to \"\n                f\"{join(xdg.BaseDirectory.xdg_config_home, 'mycroft')}\")\n\n\nclass Configuration:\n    \"\"\"Namespace for operations on the configuration singleton.\"\"\"\n    __config = {}  # Cached config\n    __patch = {}  # Patch config that skills can update to override config\n\n    @staticmethod\n    def get(configs=None, cache=True, remote=True):\n        \"\"\"Get configuration\n\n        Returns cached instance if available otherwise builds a new\n        configuration dict.\n\n        Args:\n            configs (list): List of configuration dicts\n            cache (boolean): True if the result should be cached\n            remote (boolean): False if the Remote settings shouldn't be loaded\n\n        Returns:\n            (dict) configuration dictionary.\n        \"\"\"\n        if Configuration.__config:\n            return Configuration.__config\n        else:\n            return Configuration.load_config_stack(configs, cache, remote)\n\n    @staticmethod\n    def load_config_stack(configs=None, cache=False, remote=True):\n        \"\"\"Load a stack of config dicts into a single dict\n\n        Args:\n            configs (list): list of dicts to load\n            cache (boolean): True if result should be cached\n            remote (boolean): False if the Mycroft Home settings shouldn't\n                              be loaded\n        Returns:\n            (dict) merged dict of all configuration files\n        \"\"\"\n        if not configs:\n            configs = []\n\n            # First use the patched config\n            configs.append(Configuration.__patch)\n\n            # Then use XDG config\n            # This includes both the user config and\n            # /etc/xdg/mycroft/mycroft.conf\n            for conf_dir in xdg.BaseDirectory.load_config_paths('mycroft'):\n                configs.append(LocalConf(join(conf_dir, 'mycroft.conf')))\n\n            # Then check the old user config\n            if isfile(OLD_USER_CONFIG):\n                _log_old_location_deprecation()\n                configs.append(LocalConf(OLD_USER_CONFIG))\n\n            # Then use the system config (/etc/mycroft/mycroft.conf)\n            configs.append(LocalConf(SYSTEM_CONFIG))\n\n            # Then use remote config\n            if remote:\n                configs.append(RemoteConf())\n\n            # Then use the config that comes with the package\n            configs.append(LocalConf(DEFAULT_CONFIG))\n\n            # Make sure we reverse the array, as merge_dict will put every new\n            # file on top of the previous one\n            configs = reversed(configs)\n        else:\n            # Handle strings in stack\n            for index, item in enumerate(configs):\n                if isinstance(item, str):\n                    configs[index] = LocalConf(item)\n\n        # Merge all configs into one\n        base = {}\n        for c in configs:\n            merge_dict(base, c)\n\n        # copy into cache\n        if cache:\n            Configuration.__config.clear()\n            for key in base:\n                Configuration.__config[key] = base[key]\n            return Configuration.__config\n        else:\n            return base\n\n    @staticmethod\n    def set_config_update_handlers(bus):\n        \"\"\"Setup websocket handlers to update config.\n\n        Args:\n            bus: Message bus client instance\n        \"\"\"\n        bus.on(\"configuration.updated\", Configuration.updated)\n        bus.on(\"configuration.patch\", Configuration.patch)\n        bus.on(\"configuration.patch.clear\", Configuration.patch_clear)\n\n    @staticmethod\n    def updated(message):\n        \"\"\"Handler for configuration.updated,\n\n        Triggers an update of cached config.\n        \"\"\"\n        Configuration.load_config_stack(cache=True)\n\n    @staticmethod\n    def patch(message):\n        \"\"\"Patch the volatile dict usable by skills\n\n        Args:\n            message: Messagebus message should contain a config\n                     in the data payload.\n        \"\"\"\n        config = message.data.get(\"config\", {})\n        merge_dict(Configuration.__patch, config)\n        Configuration.load_config_stack(cache=True)\n\n    @staticmethod\n    def patch_clear(message):\n        \"\"\"Clear the config patch space.\n\n        Args:\n            message: Messagebus message should contain a config\n                     in the data payload.\n        \"\"\"\n        Configuration.__patch = {}\n        Configuration.load_config_stack(cache=True)\n", "path": "mycroft/configuration/config.py"}], "after_files": [{"content": "\n# Copyright 2017 Mycroft AI Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# 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#\n\nimport json\nimport os\nimport re\nfrom os.path import exists, isfile, join, dirname\n\nimport xdg.BaseDirectory\nfrom requests import RequestException\n\nfrom mycroft.util.combo_lock import ComboLock\nfrom mycroft.util.file_utils import get_temp_path\nfrom mycroft.util import camel_case_split\nfrom mycroft.util.json_helper import load_commented_json, merge_dict\nfrom mycroft.util.log import LOG\n\nfrom .locations import (\n    DEFAULT_CONFIG,\n    OLD_USER_CONFIG,\n    SYSTEM_CONFIG,\n    USER_CONFIG\n)\n\n\ndef is_remote_list(values):\n    \"\"\"Check if list corresponds to a backend formatted collection of dicts\n    \"\"\"\n    for v in values:\n        if not isinstance(v, dict):\n            return False\n        if \"@type\" not in v.keys():\n            return False\n    return True\n\n\ndef translate_remote(config, setting):\n    \"\"\"Translate config names from server to equivalents for mycroft-core.\n\n    Args:\n        config:     base config to populate\n        settings:   remote settings to be translated\n    \"\"\"\n    IGNORED_SETTINGS = [\"uuid\", \"@type\", \"active\", \"user\", \"device\"]\n\n    for k, v in setting.items():\n        if k not in IGNORED_SETTINGS:\n            # Translate the CamelCase values stored remotely into the\n            # Python-style names used within mycroft-core.\n            key = re.sub(r\"Setting(s)?\", \"\", k)\n            key = camel_case_split(key).replace(\" \", \"_\").lower()\n            if isinstance(v, dict):\n                config[key] = config.get(key, {})\n                translate_remote(config[key], v)\n            elif isinstance(v, list):\n                if is_remote_list(v):\n                    if key not in config:\n                        config[key] = {}\n                    translate_list(config[key], v)\n                else:\n                    config[key] = v\n            else:\n                config[key] = v\n\n\ndef translate_list(config, values):\n    \"\"\"Translate list formated by mycroft server.\n\n    Args:\n        config (dict): target config\n        values (list): list from mycroft server config\n    \"\"\"\n    for v in values:\n        module = v[\"@type\"]\n        if v.get(\"active\"):\n            config[\"module\"] = module\n        config[module] = config.get(module, {})\n        translate_remote(config[module], v)\n\n\nclass LocalConf(dict):\n    \"\"\"Config dictionary from file.\"\"\"\n    _lock = ComboLock(get_temp_path('local-conf.lock'))\n\n    def __init__(self, path):\n        super(LocalConf, self).__init__()\n        self.is_valid = True  # is loaded json valid, updated when load occurs\n        if path:\n            self.path = path\n            self.load_local(path)\n\n    def load_local(self, path):\n        \"\"\"Load local json file into self.\n\n        Args:\n            path (str): file to load\n        \"\"\"\n        if exists(path) and isfile(path):\n            try:\n                config = load_commented_json(path)\n                for key in config:\n                    self.__setitem__(key, config[key])\n\n                LOG.debug(\"Configuration {} loaded\".format(path))\n            except Exception as e:\n                LOG.error(\"Error loading configuration '{}'\".format(path))\n                LOG.error(repr(e))\n                self.is_valid = False\n        else:\n            LOG.debug(\"Configuration '{}' not defined, skipping\".format(path))\n\n    def store(self, path=None, force=False):\n        \"\"\"Save config to disk.\n\n        The cache will be used if the remote is unreachable to load settings\n        that are as close to the user's as possible.\n\n        path (str): path to store file to, if missing will use the path from\n                    where the config was loaded.\n        force (bool): Set to True if writing should occur despite the original\n                      was malformed.\n\n        Returns:\n            (bool) True if save was successful, else False.\n        \"\"\"\n        result = False\n        with self._lock:\n            path = path or self.path\n            config_dir = dirname(path)\n            if not exists(config_dir):\n                os.makedirs(config_dir)\n\n            if self.is_valid or force:\n                with open(path, 'w') as f:\n                    json.dump(self, f, indent=2)\n                result = True\n            else:\n                LOG.warning((f'\"{path}\" was not a valid config file when '\n                             'loaded, will not save config. Please correct '\n                             'the json or remove it to allow updates.'))\n                result = False\n        return result\n\n    def merge(self, conf):\n        merge_dict(self, conf)\n\n\nclass RemoteConf(LocalConf):\n    _lock = ComboLock(get_temp_path('remote-conf.lock'))\n    \"\"\"Config dictionary fetched from mycroft.ai.\"\"\"\n\n    def __init__(self, cache=None):\n        super(RemoteConf, self).__init__(None)\n\n        cache = cache or join(xdg.BaseDirectory.xdg_cache_home, 'mycroft',\n                              'web_cache.json')\n        from mycroft.api import is_paired\n        if not is_paired():\n            self.load_local(cache)\n            return\n\n        try:\n            # Here to avoid cyclic import\n            from mycroft.api import DeviceApi\n            api = DeviceApi()\n            setting = api.get_settings()\n\n            location = None\n            try:\n                location = api.get_location()\n            except RequestException as e:\n                LOG.error(\"RequestException fetching remote location: {}\"\n                          .format(str(e)))\n                if exists(cache) and isfile(cache):\n                    location = load_commented_json(cache).get('location')\n\n            if location:\n                setting[\"location\"] = location\n            # Remove server specific entries\n            config = {}\n            translate_remote(config, setting)\n            for key in config:\n                self.__setitem__(key, config[key])\n            self.store(cache, force=True)\n\n        except RequestException as e:\n            LOG.error(\"RequestException fetching remote configuration: {}\"\n                      .format(str(e)))\n            self.load_local(cache)\n\n        except Exception as e:\n            LOG.error(\"Failed to fetch remote configuration: %s\" % repr(e),\n                      exc_info=True)\n            self.load_local(cache)\n\n\ndef _log_old_location_deprecation():\n    LOG.warning(\"\\n ===============================================\\n\"\n                \" ==             DEPRECATION WARNING           ==\\n\"\n                \" ===============================================\\n\"\n                f\" You still have a config file at {OLD_USER_CONFIG}\\n\"\n                \" Note that this location is deprecated and will\"\n                \" not be used in the future\\n\"\n                \" Please move it to \"\n                f\"{join(xdg.BaseDirectory.xdg_config_home, 'mycroft')}\")\n\n\nclass Configuration:\n    \"\"\"Namespace for operations on the configuration singleton.\"\"\"\n    __config = {}  # Cached config\n    __patch = {}  # Patch config that skills can update to override config\n\n    @staticmethod\n    def get(configs=None, cache=True, remote=True):\n        \"\"\"Get configuration\n\n        Returns cached instance if available otherwise builds a new\n        configuration dict.\n\n        Args:\n            configs (list): List of configuration dicts\n            cache (boolean): True if the result should be cached\n            remote (boolean): False if the Remote settings shouldn't be loaded\n\n        Returns:\n            (dict) configuration dictionary.\n        \"\"\"\n        if Configuration.__config:\n            return Configuration.__config\n        else:\n            return Configuration.load_config_stack(configs, cache, remote)\n\n    @staticmethod\n    def load_config_stack(configs=None, cache=False, remote=True):\n        \"\"\"Load a stack of config dicts into a single dict\n\n        Args:\n            configs (list): list of dicts to load\n            cache (boolean): True if result should be cached\n            remote (boolean): False if the Mycroft Home settings shouldn't\n                              be loaded\n        Returns:\n            (dict) merged dict of all configuration files\n        \"\"\"\n        if not configs:\n            configs = []\n\n            # First use the patched config\n            configs.append(Configuration.__patch)\n\n            # Then use XDG config\n            # This includes both the user config and\n            # /etc/xdg/mycroft/mycroft.conf\n            for conf_dir in xdg.BaseDirectory.load_config_paths('mycroft'):\n                configs.append(LocalConf(join(conf_dir, 'mycroft.conf')))\n\n            # Then check the old user config\n            if isfile(OLD_USER_CONFIG):\n                _log_old_location_deprecation()\n                configs.append(LocalConf(OLD_USER_CONFIG))\n\n            # Then use the system config (/etc/mycroft/mycroft.conf)\n            configs.append(LocalConf(SYSTEM_CONFIG))\n\n            # Then use remote config\n            if remote:\n                configs.append(RemoteConf())\n\n            # Then use the config that comes with the package\n            configs.append(LocalConf(DEFAULT_CONFIG))\n\n            # Make sure we reverse the array, as merge_dict will put every new\n            # file on top of the previous one\n            configs = reversed(configs)\n        else:\n            # Handle strings in stack\n            for index, item in enumerate(configs):\n                if isinstance(item, str):\n                    configs[index] = LocalConf(item)\n\n        # Merge all configs into one\n        base = {}\n        for c in configs:\n            merge_dict(base, c)\n\n        # copy into cache\n        if cache:\n            Configuration.__config.clear()\n            for key in base:\n                Configuration.__config[key] = base[key]\n            return Configuration.__config\n        else:\n            return base\n\n    @staticmethod\n    def set_config_update_handlers(bus):\n        \"\"\"Setup websocket handlers to update config.\n\n        Args:\n            bus: Message bus client instance\n        \"\"\"\n        bus.on(\"configuration.updated\", Configuration.updated)\n        bus.on(\"configuration.patch\", Configuration.patch)\n        bus.on(\"configuration.patch.clear\", Configuration.patch_clear)\n\n    @staticmethod\n    def updated(message):\n        \"\"\"Handler for configuration.updated,\n\n        Triggers an update of cached config.\n        \"\"\"\n        Configuration.load_config_stack(cache=True)\n\n    @staticmethod\n    def patch(message):\n        \"\"\"Patch the volatile dict usable by skills\n\n        Args:\n            message: Messagebus message should contain a config\n                     in the data payload.\n        \"\"\"\n        config = message.data.get(\"config\", {})\n        merge_dict(Configuration.__patch, config)\n        Configuration.load_config_stack(cache=True)\n\n    @staticmethod\n    def patch_clear(message):\n        \"\"\"Clear the config patch space.\n\n        Args:\n            message: Messagebus message should contain a config\n                     in the data payload.\n        \"\"\"\n        Configuration.__patch = {}\n        Configuration.load_config_stack(cache=True)\n", "path": "mycroft/configuration/config.py"}]}