We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Failing to load dialog and vocab should not be errors
Failure to load dialog files and vocab files are currently logged using the error log level. this should probably be debug or warnings since the ERROR text in the log confuses users.

--- 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/skills/core.py`
Content:
```
1 # Copyright 2016 Mycroft AI, Inc.
2 #
3 # This file is part of Mycroft Core.
4 #
5 # Mycroft Core is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Mycroft Core is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.
17 
18 
19 import abc
20 import imp
21 import time
22 
23 import os.path
24 import re
25 import time
26 from os.path import join, dirname, splitext, isdir
27 
28 from adapt.intent import Intent
29 
30 from mycroft.client.enclosure.api import EnclosureAPI
31 from mycroft.configuration import ConfigurationManager
32 from mycroft.dialog import DialogLoader
33 from mycroft.filesystem import FileSystemAccess
34 from mycroft.messagebus.message import Message
35 from mycroft.util.log import getLogger
36 from mycroft.skills.settings import SkillSettings
37 __author__ = 'seanfitz'
38 
39 skills_config = ConfigurationManager.instance().get("skills")
40 BLACKLISTED_SKILLS = skills_config.get("blacklisted_skills", [])
41 
42 SKILLS_DIR = "/opt/mycroft/skills"
43 
44 MainModule = '__init__'
45 
46 logger = getLogger(__name__)
47 
48 
49 def load_vocab_from_file(path, vocab_type, emitter):
50     if path.endswith('.voc'):
51         with open(path, 'r') as voc_file:
52             for line in voc_file.readlines():
53                 parts = line.strip().split("|")
54                 entity = parts[0]
55 
56                 emitter.emit(Message("register_vocab", {
57                     'start': entity, 'end': vocab_type
58                 }))
59                 for alias in parts[1:]:
60                     emitter.emit(Message("register_vocab", {
61                         'start': alias, 'end': vocab_type, 'alias_of': entity
62                     }))
63 
64 
65 def load_regex_from_file(path, emitter):
66     if path.endswith('.rx'):
67         with open(path, 'r') as reg_file:
68             for line in reg_file.readlines():
69                 re.compile(line.strip())
70                 emitter.emit(
71                     Message("register_vocab", {'regex': line.strip()}))
72 
73 
74 def load_vocabulary(basedir, emitter):
75     for vocab_type in os.listdir(basedir):
76         if vocab_type.endswith(".voc"):
77             load_vocab_from_file(
78                 join(basedir, vocab_type), splitext(vocab_type)[0], emitter)
79 
80 
81 def load_regex(basedir, emitter):
82     for regex_type in os.listdir(basedir):
83         if regex_type.endswith(".rx"):
84             load_regex_from_file(
85                 join(basedir, regex_type), emitter)
86 
87 
88 def open_intent_envelope(message):
89     intent_dict = message.data
90     return Intent(intent_dict.get('name'),
91                   intent_dict.get('requires'),
92                   intent_dict.get('at_least_one'),
93                   intent_dict.get('optional'))
94 
95 
96 def load_skill(skill_descriptor, emitter):
97     try:
98         logger.info("ATTEMPTING TO LOAD SKILL: " + skill_descriptor["name"])
99         if skill_descriptor['name'] in BLACKLISTED_SKILLS:
100             logger.info("SKILL IS BLACKLISTED " + skill_descriptor["name"])
101             return None
102         skill_module = imp.load_module(
103             skill_descriptor["name"] + MainModule, *skill_descriptor["info"])
104         if (hasattr(skill_module, 'create_skill') and
105                 callable(skill_module.create_skill)):
106             # v2 skills framework
107             skill = skill_module.create_skill()
108             skill.bind(emitter)
109             skill._dir = dirname(skill_descriptor['info'][1])
110             skill.load_data_files(dirname(skill_descriptor['info'][1]))
111             skill.initialize()
112             logger.info("Loaded " + skill_descriptor["name"])
113             return skill
114         else:
115             logger.warn(
116                 "Module %s does not appear to be skill" % (
117                     skill_descriptor["name"]))
118     except:
119         logger.error(
120             "Failed to load skill: " + skill_descriptor["name"], exc_info=True)
121     return None
122 
123 
124 def get_skills(skills_folder):
125     logger.info("LOADING SKILLS FROM " + skills_folder)
126     skills = []
127     possible_skills = os.listdir(skills_folder)
128     for i in possible_skills:
129         location = join(skills_folder, i)
130         if (isdir(location) and
131                 not MainModule + ".py" in os.listdir(location)):
132             for j in os.listdir(location):
133                 name = join(location, j)
134                 if (not isdir(name) or
135                         not MainModule + ".py" in os.listdir(name)):
136                     continue
137                 skills.append(create_skill_descriptor(name))
138         if (not isdir(location) or
139                 not MainModule + ".py" in os.listdir(location)):
140             continue
141 
142         skills.append(create_skill_descriptor(location))
143     skills = sorted(skills, key=lambda p: p.get('name'))
144     return skills
145 
146 
147 def create_skill_descriptor(skill_folder):
148     info = imp.find_module(MainModule, [skill_folder])
149     return {"name": os.path.basename(skill_folder), "info": info}
150 
151 
152 def load_skills(emitter, skills_root=SKILLS_DIR):
153     logger.info("Checking " + skills_root + " for new skills")
154     skill_list = []
155     for skill in get_skills(skills_root):
156         skill_list.append(load_skill(skill, emitter))
157 
158     return skill_list
159 
160 
161 def unload_skills(skills):
162     for s in skills:
163         s.shutdown()
164 
165 
166 class MycroftSkill(object):
167     """
168     Abstract base class which provides common behaviour and parameters to all
169     Skills implementation.
170     """
171 
172     def __init__(self, name, emitter=None):
173         self.name = name
174         self.bind(emitter)
175         self.config_core = ConfigurationManager.get()
176         self.config = self.config_core.get(name)
177         self.dialog_renderer = None
178         self.file_system = FileSystemAccess(join('skills', name))
179         self.registered_intents = []
180         self.log = getLogger(name)
181         self.reload_skill = True
182         self.events = []
183 
184     @property
185     def location(self):
186         """ Get the JSON data struction holding location information. """
187         # TODO: Allow Enclosure to override this for devices that
188         # contain a GPS.
189         return self.config_core.get('location')
190 
191     @property
192     def location_pretty(self):
193         """ Get a more 'human' version of the location as a string. """
194         loc = self.location
195         if type(loc) is dict and loc["city"]:
196             return loc["city"]["name"]
197         return None
198 
199     @property
200     def location_timezone(self):
201         """ Get the timezone code, such as 'America/Los_Angeles' """
202         loc = self.location
203         if type(loc) is dict and loc["timezone"]:
204             return loc["timezone"]["code"]
205         return None
206 
207     @property
208     def lang(self):
209         return self.config_core.get('lang')
210 
211     @property
212     def settings(self):
213         """ Load settings if not already loaded. """
214         try:
215             return self._settings
216         except:
217             self._settings = SkillSettings(join(self._dir, 'settings.json'))
218             return self._settings
219 
220     def bind(self, emitter):
221         if emitter:
222             self.emitter = emitter
223             self.enclosure = EnclosureAPI(emitter)
224             self.__register_stop()
225 
226     def __register_stop(self):
227         self.stop_time = time.time()
228         self.stop_threshold = self.config_core.get("skills").get(
229             'stop_threshold')
230         self.emitter.on('mycroft.stop', self.__handle_stop)
231 
232     def detach(self):
233         for (name, intent) in self.registered_intents:
234             name = self.name + ':' + name
235             self.emitter.emit(Message("detach_intent", {"intent_name": name}))
236 
237     def initialize(self):
238         """
239         Initialization function to be implemented by all Skills.
240 
241         Usually used to create intents rules and register them.
242         """
243         raise Exception("Initialize not implemented for skill: " + self.name)
244 
245     def register_intent(self, intent_parser, handler):
246         name = intent_parser.name
247         intent_parser.name = self.name + ':' + intent_parser.name
248         self.emitter.emit(Message("register_intent", intent_parser.__dict__))
249         self.registered_intents.append((name, intent_parser))
250 
251         def receive_handler(message):
252             try:
253                 handler(message)
254             except:
255                 # TODO: Localize
256                 self.speak(
257                     "An error occurred while processing a request in " +
258                     self.name)
259                 logger.error(
260                     "An error occurred while processing a request in " +
261                     self.name, exc_info=True)
262 
263         if handler:
264             self.emitter.on(intent_parser.name, receive_handler)
265             self.events.append((intent_parser.name, receive_handler))
266 
267     def disable_intent(self, intent_name):
268         """Disable a registered intent"""
269         logger.debug('Disabling intent ' + intent_name)
270         name = self.name + ':' + intent_name
271         self.emitter.emit(Message("detach_intent", {"intent_name": name}))
272 
273     def enable_intent(self, intent_name):
274         """Reenable a registered intent"""
275         for (name, intent) in self.registered_intents:
276             if name == intent_name:
277                 self.registered_intents.remove((name, intent))
278                 intent.name = name
279                 self.register_intent(intent, None)
280                 logger.debug('Enabling intent ' + intent_name)
281                 break
282             else:
283                 logger.error('Could not enable ' + intent_name +
284                              ', it hasn\'t been registered.')
285 
286     def register_vocabulary(self, entity, entity_type):
287         self.emitter.emit(Message('register_vocab', {
288             'start': entity, 'end': entity_type
289         }))
290 
291     def register_regex(self, regex_str):
292         re.compile(regex_str)  # validate regex
293         self.emitter.emit(Message('register_vocab', {'regex': regex_str}))
294 
295     def speak(self, utterance, expect_response=False):
296         data = {'utterance': utterance,
297                 'expect_response': expect_response}
298         self.emitter.emit(Message("speak", data))
299 
300     def speak_dialog(self, key, data={}, expect_response=False):
301         data['expect_response'] = expect_response
302         self.speak(self.dialog_renderer.render(key, data))
303 
304     def init_dialog(self, root_directory):
305         dialog_dir = join(root_directory, 'dialog', self.lang)
306         if os.path.exists(dialog_dir):
307             self.dialog_renderer = DialogLoader().load(dialog_dir)
308         else:
309             logger.error('No dialog loaded, ' + dialog_dir + ' does not exist')
310 
311     def load_data_files(self, root_directory):
312         self.init_dialog(root_directory)
313         self.load_vocab_files(join(root_directory, 'vocab', self.lang))
314         regex_path = join(root_directory, 'regex', self.lang)
315         if os.path.exists(regex_path):
316             self.load_regex_files(regex_path)
317 
318     def load_vocab_files(self, vocab_dir):
319         if os.path.exists(vocab_dir):
320             load_vocabulary(vocab_dir, self.emitter)
321         else:
322             logger.error('No vocab loaded, ' + vocab_dir + ' does not exist')
323 
324     def load_regex_files(self, regex_dir):
325         load_regex(regex_dir, self.emitter)
326 
327     def __handle_stop(self, event):
328         self.stop_time = time.time()
329         self.stop()
330 
331     @abc.abstractmethod
332     def stop(self):
333         pass
334 
335     def is_stop(self):
336         passed_time = time.time() - self.stop_time
337         return passed_time < self.stop_threshold
338 
339     def shutdown(self):
340         """
341         This method is intended to be called during the skill
342         process termination. The skill implementation must
343         shutdown all processes and operations in execution.
344         """
345         # Store settings
346         self.settings.store()
347 
348         # removing events
349         for e, f in self.events:
350             self.emitter.remove(e, f)
351 
352         self.emitter.emit(
353             Message("detach_skill", {"skill_name": self.name + ":"}))
354         self.stop()
355
```
--- 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/skills/core.py b/mycroft/skills/core.py
--- a/mycroft/skills/core.py
+++ b/mycroft/skills/core.py
@@ -306,7 +306,7 @@
         if os.path.exists(dialog_dir):
             self.dialog_renderer = DialogLoader().load(dialog_dir)
         else:
-            logger.error('No dialog loaded, ' + dialog_dir + ' does not exist')
+            logger.debug('No dialog loaded, ' + dialog_dir + ' does not exist')
 
     def load_data_files(self, root_directory):
         self.init_dialog(root_directory)
@@ -319,7 +319,7 @@
         if os.path.exists(vocab_dir):
             load_vocabulary(vocab_dir, self.emitter)
         else:
-            logger.error('No vocab loaded, ' + vocab_dir + ' does not exist')
+            logger.debug('No vocab loaded, ' + vocab_dir + ' does not exist')
 
     def load_regex_files(self, regex_dir):
         load_regex(regex_dir, self.emitter)

{"golden_diff": "diff --git a/mycroft/skills/core.py b/mycroft/skills/core.py\n--- a/mycroft/skills/core.py\n+++ b/mycroft/skills/core.py\n@@ -306,7 +306,7 @@\n         if os.path.exists(dialog_dir):\n             self.dialog_renderer = DialogLoader().load(dialog_dir)\n         else:\n-            logger.error('No dialog loaded, ' + dialog_dir + ' does not exist')\n+            logger.debug('No dialog loaded, ' + dialog_dir + ' does not exist')\n \n     def load_data_files(self, root_directory):\n         self.init_dialog(root_directory)\n@@ -319,7 +319,7 @@\n         if os.path.exists(vocab_dir):\n             load_vocabulary(vocab_dir, self.emitter)\n         else:\n-            logger.error('No vocab loaded, ' + vocab_dir + ' does not exist')\n+            logger.debug('No vocab loaded, ' + vocab_dir + ' does not exist')\n \n     def load_regex_files(self, regex_dir):\n         load_regex(regex_dir, self.emitter)\n", "issue": "Failing to load dialog and vocab should not be errors\nFailure to load dialog files and vocab files are currently logged using the error log level. this should probably be debug or warnings since the ERROR text in the log confuses users.\n", "before_files": [{"content": "# Copyright 2016 Mycroft AI, Inc.\n#\n# This file is part of Mycroft Core.\n#\n# Mycroft Core is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Mycroft Core is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.\n\n\nimport abc\nimport imp\nimport time\n\nimport os.path\nimport re\nimport time\nfrom os.path import join, dirname, splitext, isdir\n\nfrom adapt.intent import Intent\n\nfrom mycroft.client.enclosure.api import EnclosureAPI\nfrom mycroft.configuration import ConfigurationManager\nfrom mycroft.dialog import DialogLoader\nfrom mycroft.filesystem import FileSystemAccess\nfrom mycroft.messagebus.message import Message\nfrom mycroft.util.log import getLogger\nfrom mycroft.skills.settings import SkillSettings\n__author__ = 'seanfitz'\n\nskills_config = ConfigurationManager.instance().get(\"skills\")\nBLACKLISTED_SKILLS = skills_config.get(\"blacklisted_skills\", [])\n\nSKILLS_DIR = \"/opt/mycroft/skills\"\n\nMainModule = '__init__'\n\nlogger = getLogger(__name__)\n\n\ndef load_vocab_from_file(path, vocab_type, emitter):\n    if path.endswith('.voc'):\n        with open(path, 'r') as voc_file:\n            for line in voc_file.readlines():\n                parts = line.strip().split(\"|\")\n                entity = parts[0]\n\n                emitter.emit(Message(\"register_vocab\", {\n                    'start': entity, 'end': vocab_type\n                }))\n                for alias in parts[1:]:\n                    emitter.emit(Message(\"register_vocab\", {\n                        'start': alias, 'end': vocab_type, 'alias_of': entity\n                    }))\n\n\ndef load_regex_from_file(path, emitter):\n    if path.endswith('.rx'):\n        with open(path, 'r') as reg_file:\n            for line in reg_file.readlines():\n                re.compile(line.strip())\n                emitter.emit(\n                    Message(\"register_vocab\", {'regex': line.strip()}))\n\n\ndef load_vocabulary(basedir, emitter):\n    for vocab_type in os.listdir(basedir):\n        if vocab_type.endswith(\".voc\"):\n            load_vocab_from_file(\n                join(basedir, vocab_type), splitext(vocab_type)[0], emitter)\n\n\ndef load_regex(basedir, emitter):\n    for regex_type in os.listdir(basedir):\n        if regex_type.endswith(\".rx\"):\n            load_regex_from_file(\n                join(basedir, regex_type), emitter)\n\n\ndef open_intent_envelope(message):\n    intent_dict = message.data\n    return Intent(intent_dict.get('name'),\n                  intent_dict.get('requires'),\n                  intent_dict.get('at_least_one'),\n                  intent_dict.get('optional'))\n\n\ndef load_skill(skill_descriptor, emitter):\n    try:\n        logger.info(\"ATTEMPTING TO LOAD SKILL: \" + skill_descriptor[\"name\"])\n        if skill_descriptor['name'] in BLACKLISTED_SKILLS:\n            logger.info(\"SKILL IS BLACKLISTED \" + skill_descriptor[\"name\"])\n            return None\n        skill_module = imp.load_module(\n            skill_descriptor[\"name\"] + MainModule, *skill_descriptor[\"info\"])\n        if (hasattr(skill_module, 'create_skill') and\n                callable(skill_module.create_skill)):\n            # v2 skills framework\n            skill = skill_module.create_skill()\n            skill.bind(emitter)\n            skill._dir = dirname(skill_descriptor['info'][1])\n            skill.load_data_files(dirname(skill_descriptor['info'][1]))\n            skill.initialize()\n            logger.info(\"Loaded \" + skill_descriptor[\"name\"])\n            return skill\n        else:\n            logger.warn(\n                \"Module %s does not appear to be skill\" % (\n                    skill_descriptor[\"name\"]))\n    except:\n        logger.error(\n            \"Failed to load skill: \" + skill_descriptor[\"name\"], exc_info=True)\n    return None\n\n\ndef get_skills(skills_folder):\n    logger.info(\"LOADING SKILLS FROM \" + skills_folder)\n    skills = []\n    possible_skills = os.listdir(skills_folder)\n    for i in possible_skills:\n        location = join(skills_folder, i)\n        if (isdir(location) and\n                not MainModule + \".py\" in os.listdir(location)):\n            for j in os.listdir(location):\n                name = join(location, j)\n                if (not isdir(name) or\n                        not MainModule + \".py\" in os.listdir(name)):\n                    continue\n                skills.append(create_skill_descriptor(name))\n        if (not isdir(location) or\n                not MainModule + \".py\" in os.listdir(location)):\n            continue\n\n        skills.append(create_skill_descriptor(location))\n    skills = sorted(skills, key=lambda p: p.get('name'))\n    return skills\n\n\ndef create_skill_descriptor(skill_folder):\n    info = imp.find_module(MainModule, [skill_folder])\n    return {\"name\": os.path.basename(skill_folder), \"info\": info}\n\n\ndef load_skills(emitter, skills_root=SKILLS_DIR):\n    logger.info(\"Checking \" + skills_root + \" for new skills\")\n    skill_list = []\n    for skill in get_skills(skills_root):\n        skill_list.append(load_skill(skill, emitter))\n\n    return skill_list\n\n\ndef unload_skills(skills):\n    for s in skills:\n        s.shutdown()\n\n\nclass MycroftSkill(object):\n    \"\"\"\n    Abstract base class which provides common behaviour and parameters to all\n    Skills implementation.\n    \"\"\"\n\n    def __init__(self, name, emitter=None):\n        self.name = name\n        self.bind(emitter)\n        self.config_core = ConfigurationManager.get()\n        self.config = self.config_core.get(name)\n        self.dialog_renderer = None\n        self.file_system = FileSystemAccess(join('skills', name))\n        self.registered_intents = []\n        self.log = getLogger(name)\n        self.reload_skill = True\n        self.events = []\n\n    @property\n    def location(self):\n        \"\"\" Get the JSON data struction holding location information. \"\"\"\n        # TODO: Allow Enclosure to override this for devices that\n        # contain a GPS.\n        return self.config_core.get('location')\n\n    @property\n    def location_pretty(self):\n        \"\"\" Get a more 'human' version of the location as a string. \"\"\"\n        loc = self.location\n        if type(loc) is dict and loc[\"city\"]:\n            return loc[\"city\"][\"name\"]\n        return None\n\n    @property\n    def location_timezone(self):\n        \"\"\" Get the timezone code, such as 'America/Los_Angeles' \"\"\"\n        loc = self.location\n        if type(loc) is dict and loc[\"timezone\"]:\n            return loc[\"timezone\"][\"code\"]\n        return None\n\n    @property\n    def lang(self):\n        return self.config_core.get('lang')\n\n    @property\n    def settings(self):\n        \"\"\" Load settings if not already loaded. \"\"\"\n        try:\n            return self._settings\n        except:\n            self._settings = SkillSettings(join(self._dir, 'settings.json'))\n            return self._settings\n\n    def bind(self, emitter):\n        if emitter:\n            self.emitter = emitter\n            self.enclosure = EnclosureAPI(emitter)\n            self.__register_stop()\n\n    def __register_stop(self):\n        self.stop_time = time.time()\n        self.stop_threshold = self.config_core.get(\"skills\").get(\n            'stop_threshold')\n        self.emitter.on('mycroft.stop', self.__handle_stop)\n\n    def detach(self):\n        for (name, intent) in self.registered_intents:\n            name = self.name + ':' + name\n            self.emitter.emit(Message(\"detach_intent\", {\"intent_name\": name}))\n\n    def initialize(self):\n        \"\"\"\n        Initialization function to be implemented by all Skills.\n\n        Usually used to create intents rules and register them.\n        \"\"\"\n        raise Exception(\"Initialize not implemented for skill: \" + self.name)\n\n    def register_intent(self, intent_parser, handler):\n        name = intent_parser.name\n        intent_parser.name = self.name + ':' + intent_parser.name\n        self.emitter.emit(Message(\"register_intent\", intent_parser.__dict__))\n        self.registered_intents.append((name, intent_parser))\n\n        def receive_handler(message):\n            try:\n                handler(message)\n            except:\n                # TODO: Localize\n                self.speak(\n                    \"An error occurred while processing a request in \" +\n                    self.name)\n                logger.error(\n                    \"An error occurred while processing a request in \" +\n                    self.name, exc_info=True)\n\n        if handler:\n            self.emitter.on(intent_parser.name, receive_handler)\n            self.events.append((intent_parser.name, receive_handler))\n\n    def disable_intent(self, intent_name):\n        \"\"\"Disable a registered intent\"\"\"\n        logger.debug('Disabling intent ' + intent_name)\n        name = self.name + ':' + intent_name\n        self.emitter.emit(Message(\"detach_intent\", {\"intent_name\": name}))\n\n    def enable_intent(self, intent_name):\n        \"\"\"Reenable a registered intent\"\"\"\n        for (name, intent) in self.registered_intents:\n            if name == intent_name:\n                self.registered_intents.remove((name, intent))\n                intent.name = name\n                self.register_intent(intent, None)\n                logger.debug('Enabling intent ' + intent_name)\n                break\n            else:\n                logger.error('Could not enable ' + intent_name +\n                             ', it hasn\\'t been registered.')\n\n    def register_vocabulary(self, entity, entity_type):\n        self.emitter.emit(Message('register_vocab', {\n            'start': entity, 'end': entity_type\n        }))\n\n    def register_regex(self, regex_str):\n        re.compile(regex_str)  # validate regex\n        self.emitter.emit(Message('register_vocab', {'regex': regex_str}))\n\n    def speak(self, utterance, expect_response=False):\n        data = {'utterance': utterance,\n                'expect_response': expect_response}\n        self.emitter.emit(Message(\"speak\", data))\n\n    def speak_dialog(self, key, data={}, expect_response=False):\n        data['expect_response'] = expect_response\n        self.speak(self.dialog_renderer.render(key, data))\n\n    def init_dialog(self, root_directory):\n        dialog_dir = join(root_directory, 'dialog', self.lang)\n        if os.path.exists(dialog_dir):\n            self.dialog_renderer = DialogLoader().load(dialog_dir)\n        else:\n            logger.error('No dialog loaded, ' + dialog_dir + ' does not exist')\n\n    def load_data_files(self, root_directory):\n        self.init_dialog(root_directory)\n        self.load_vocab_files(join(root_directory, 'vocab', self.lang))\n        regex_path = join(root_directory, 'regex', self.lang)\n        if os.path.exists(regex_path):\n            self.load_regex_files(regex_path)\n\n    def load_vocab_files(self, vocab_dir):\n        if os.path.exists(vocab_dir):\n            load_vocabulary(vocab_dir, self.emitter)\n        else:\n            logger.error('No vocab loaded, ' + vocab_dir + ' does not exist')\n\n    def load_regex_files(self, regex_dir):\n        load_regex(regex_dir, self.emitter)\n\n    def __handle_stop(self, event):\n        self.stop_time = time.time()\n        self.stop()\n\n    @abc.abstractmethod\n    def stop(self):\n        pass\n\n    def is_stop(self):\n        passed_time = time.time() - self.stop_time\n        return passed_time < self.stop_threshold\n\n    def shutdown(self):\n        \"\"\"\n        This method is intended to be called during the skill\n        process termination. The skill implementation must\n        shutdown all processes and operations in execution.\n        \"\"\"\n        # Store settings\n        self.settings.store()\n\n        # removing events\n        for e, f in self.events:\n            self.emitter.remove(e, f)\n\n        self.emitter.emit(\n            Message(\"detach_skill\", {\"skill_name\": self.name + \":\"}))\n        self.stop()\n", "path": "mycroft/skills/core.py"}], "after_files": [{"content": "# Copyright 2016 Mycroft AI, Inc.\n#\n# This file is part of Mycroft Core.\n#\n# Mycroft Core is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Mycroft Core is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.\n\n\nimport abc\nimport imp\nimport time\n\nimport os.path\nimport re\nimport time\nfrom os.path import join, dirname, splitext, isdir\n\nfrom adapt.intent import Intent\n\nfrom mycroft.client.enclosure.api import EnclosureAPI\nfrom mycroft.configuration import ConfigurationManager\nfrom mycroft.dialog import DialogLoader\nfrom mycroft.filesystem import FileSystemAccess\nfrom mycroft.messagebus.message import Message\nfrom mycroft.util.log import getLogger\nfrom mycroft.skills.settings import SkillSettings\n__author__ = 'seanfitz'\n\nskills_config = ConfigurationManager.instance().get(\"skills\")\nBLACKLISTED_SKILLS = skills_config.get(\"blacklisted_skills\", [])\n\nSKILLS_DIR = \"/opt/mycroft/skills\"\n\nMainModule = '__init__'\n\nlogger = getLogger(__name__)\n\n\ndef load_vocab_from_file(path, vocab_type, emitter):\n    if path.endswith('.voc'):\n        with open(path, 'r') as voc_file:\n            for line in voc_file.readlines():\n                parts = line.strip().split(\"|\")\n                entity = parts[0]\n\n                emitter.emit(Message(\"register_vocab\", {\n                    'start': entity, 'end': vocab_type\n                }))\n                for alias in parts[1:]:\n                    emitter.emit(Message(\"register_vocab\", {\n                        'start': alias, 'end': vocab_type, 'alias_of': entity\n                    }))\n\n\ndef load_regex_from_file(path, emitter):\n    if path.endswith('.rx'):\n        with open(path, 'r') as reg_file:\n            for line in reg_file.readlines():\n                re.compile(line.strip())\n                emitter.emit(\n                    Message(\"register_vocab\", {'regex': line.strip()}))\n\n\ndef load_vocabulary(basedir, emitter):\n    for vocab_type in os.listdir(basedir):\n        if vocab_type.endswith(\".voc\"):\n            load_vocab_from_file(\n                join(basedir, vocab_type), splitext(vocab_type)[0], emitter)\n\n\ndef load_regex(basedir, emitter):\n    for regex_type in os.listdir(basedir):\n        if regex_type.endswith(\".rx\"):\n            load_regex_from_file(\n                join(basedir, regex_type), emitter)\n\n\ndef open_intent_envelope(message):\n    intent_dict = message.data\n    return Intent(intent_dict.get('name'),\n                  intent_dict.get('requires'),\n                  intent_dict.get('at_least_one'),\n                  intent_dict.get('optional'))\n\n\ndef load_skill(skill_descriptor, emitter):\n    try:\n        logger.info(\"ATTEMPTING TO LOAD SKILL: \" + skill_descriptor[\"name\"])\n        if skill_descriptor['name'] in BLACKLISTED_SKILLS:\n            logger.info(\"SKILL IS BLACKLISTED \" + skill_descriptor[\"name\"])\n            return None\n        skill_module = imp.load_module(\n            skill_descriptor[\"name\"] + MainModule, *skill_descriptor[\"info\"])\n        if (hasattr(skill_module, 'create_skill') and\n                callable(skill_module.create_skill)):\n            # v2 skills framework\n            skill = skill_module.create_skill()\n            skill.bind(emitter)\n            skill._dir = dirname(skill_descriptor['info'][1])\n            skill.load_data_files(dirname(skill_descriptor['info'][1]))\n            skill.initialize()\n            logger.info(\"Loaded \" + skill_descriptor[\"name\"])\n            return skill\n        else:\n            logger.warn(\n                \"Module %s does not appear to be skill\" % (\n                    skill_descriptor[\"name\"]))\n    except:\n        logger.error(\n            \"Failed to load skill: \" + skill_descriptor[\"name\"], exc_info=True)\n    return None\n\n\ndef get_skills(skills_folder):\n    logger.info(\"LOADING SKILLS FROM \" + skills_folder)\n    skills = []\n    possible_skills = os.listdir(skills_folder)\n    for i in possible_skills:\n        location = join(skills_folder, i)\n        if (isdir(location) and\n                not MainModule + \".py\" in os.listdir(location)):\n            for j in os.listdir(location):\n                name = join(location, j)\n                if (not isdir(name) or\n                        not MainModule + \".py\" in os.listdir(name)):\n                    continue\n                skills.append(create_skill_descriptor(name))\n        if (not isdir(location) or\n                not MainModule + \".py\" in os.listdir(location)):\n            continue\n\n        skills.append(create_skill_descriptor(location))\n    skills = sorted(skills, key=lambda p: p.get('name'))\n    return skills\n\n\ndef create_skill_descriptor(skill_folder):\n    info = imp.find_module(MainModule, [skill_folder])\n    return {\"name\": os.path.basename(skill_folder), \"info\": info}\n\n\ndef load_skills(emitter, skills_root=SKILLS_DIR):\n    logger.info(\"Checking \" + skills_root + \" for new skills\")\n    skill_list = []\n    for skill in get_skills(skills_root):\n        skill_list.append(load_skill(skill, emitter))\n\n    return skill_list\n\n\ndef unload_skills(skills):\n    for s in skills:\n        s.shutdown()\n\n\nclass MycroftSkill(object):\n    \"\"\"\n    Abstract base class which provides common behaviour and parameters to all\n    Skills implementation.\n    \"\"\"\n\n    def __init__(self, name, emitter=None):\n        self.name = name\n        self.bind(emitter)\n        self.config_core = ConfigurationManager.get()\n        self.config = self.config_core.get(name)\n        self.dialog_renderer = None\n        self.file_system = FileSystemAccess(join('skills', name))\n        self.registered_intents = []\n        self.log = getLogger(name)\n        self.reload_skill = True\n        self.events = []\n\n    @property\n    def location(self):\n        \"\"\" Get the JSON data struction holding location information. \"\"\"\n        # TODO: Allow Enclosure to override this for devices that\n        # contain a GPS.\n        return self.config_core.get('location')\n\n    @property\n    def location_pretty(self):\n        \"\"\" Get a more 'human' version of the location as a string. \"\"\"\n        loc = self.location\n        if type(loc) is dict and loc[\"city\"]:\n            return loc[\"city\"][\"name\"]\n        return None\n\n    @property\n    def location_timezone(self):\n        \"\"\" Get the timezone code, such as 'America/Los_Angeles' \"\"\"\n        loc = self.location\n        if type(loc) is dict and loc[\"timezone\"]:\n            return loc[\"timezone\"][\"code\"]\n        return None\n\n    @property\n    def lang(self):\n        return self.config_core.get('lang')\n\n    @property\n    def settings(self):\n        \"\"\" Load settings if not already loaded. \"\"\"\n        try:\n            return self._settings\n        except:\n            self._settings = SkillSettings(join(self._dir, 'settings.json'))\n            return self._settings\n\n    def bind(self, emitter):\n        if emitter:\n            self.emitter = emitter\n            self.enclosure = EnclosureAPI(emitter)\n            self.__register_stop()\n\n    def __register_stop(self):\n        self.stop_time = time.time()\n        self.stop_threshold = self.config_core.get(\"skills\").get(\n            'stop_threshold')\n        self.emitter.on('mycroft.stop', self.__handle_stop)\n\n    def detach(self):\n        for (name, intent) in self.registered_intents:\n            name = self.name + ':' + name\n            self.emitter.emit(Message(\"detach_intent\", {\"intent_name\": name}))\n\n    def initialize(self):\n        \"\"\"\n        Initialization function to be implemented by all Skills.\n\n        Usually used to create intents rules and register them.\n        \"\"\"\n        raise Exception(\"Initialize not implemented for skill: \" + self.name)\n\n    def register_intent(self, intent_parser, handler):\n        name = intent_parser.name\n        intent_parser.name = self.name + ':' + intent_parser.name\n        self.emitter.emit(Message(\"register_intent\", intent_parser.__dict__))\n        self.registered_intents.append((name, intent_parser))\n\n        def receive_handler(message):\n            try:\n                handler(message)\n            except:\n                # TODO: Localize\n                self.speak(\n                    \"An error occurred while processing a request in \" +\n                    self.name)\n                logger.error(\n                    \"An error occurred while processing a request in \" +\n                    self.name, exc_info=True)\n\n        if handler:\n            self.emitter.on(intent_parser.name, receive_handler)\n            self.events.append((intent_parser.name, receive_handler))\n\n    def disable_intent(self, intent_name):\n        \"\"\"Disable a registered intent\"\"\"\n        logger.debug('Disabling intent ' + intent_name)\n        name = self.name + ':' + intent_name\n        self.emitter.emit(Message(\"detach_intent\", {\"intent_name\": name}))\n\n    def enable_intent(self, intent_name):\n        \"\"\"Reenable a registered intent\"\"\"\n        for (name, intent) in self.registered_intents:\n            if name == intent_name:\n                self.registered_intents.remove((name, intent))\n                intent.name = name\n                self.register_intent(intent, None)\n                logger.debug('Enabling intent ' + intent_name)\n                break\n            else:\n                logger.error('Could not enable ' + intent_name +\n                             ', it hasn\\'t been registered.')\n\n    def register_vocabulary(self, entity, entity_type):\n        self.emitter.emit(Message('register_vocab', {\n            'start': entity, 'end': entity_type\n        }))\n\n    def register_regex(self, regex_str):\n        re.compile(regex_str)  # validate regex\n        self.emitter.emit(Message('register_vocab', {'regex': regex_str}))\n\n    def speak(self, utterance, expect_response=False):\n        data = {'utterance': utterance,\n                'expect_response': expect_response}\n        self.emitter.emit(Message(\"speak\", data))\n\n    def speak_dialog(self, key, data={}, expect_response=False):\n        data['expect_response'] = expect_response\n        self.speak(self.dialog_renderer.render(key, data))\n\n    def init_dialog(self, root_directory):\n        dialog_dir = join(root_directory, 'dialog', self.lang)\n        if os.path.exists(dialog_dir):\n            self.dialog_renderer = DialogLoader().load(dialog_dir)\n        else:\n            logger.debug('No dialog loaded, ' + dialog_dir + ' does not exist')\n\n    def load_data_files(self, root_directory):\n        self.init_dialog(root_directory)\n        self.load_vocab_files(join(root_directory, 'vocab', self.lang))\n        regex_path = join(root_directory, 'regex', self.lang)\n        if os.path.exists(regex_path):\n            self.load_regex_files(regex_path)\n\n    def load_vocab_files(self, vocab_dir):\n        if os.path.exists(vocab_dir):\n            load_vocabulary(vocab_dir, self.emitter)\n        else:\n            logger.debug('No vocab loaded, ' + vocab_dir + ' does not exist')\n\n    def load_regex_files(self, regex_dir):\n        load_regex(regex_dir, self.emitter)\n\n    def __handle_stop(self, event):\n        self.stop_time = time.time()\n        self.stop()\n\n    @abc.abstractmethod\n    def stop(self):\n        pass\n\n    def is_stop(self):\n        passed_time = time.time() - self.stop_time\n        return passed_time < self.stop_threshold\n\n    def shutdown(self):\n        \"\"\"\n        This method is intended to be called during the skill\n        process termination. The skill implementation must\n        shutdown all processes and operations in execution.\n        \"\"\"\n        # Store settings\n        self.settings.store()\n\n        # removing events\n        for e, f in self.events:\n            self.emitter.remove(e, f)\n\n        self.emitter.emit(\n            Message(\"detach_skill\", {\"skill_name\": self.name + \":\"}))\n        self.stop()\n", "path": "mycroft/skills/core.py"}]}