From d7dc7612e4a457131bd7065be9e76713a1af95e0 Mon Sep 17 00:00:00 2001 From: Guillaume Sarthou Date: Mon, 22 Jan 2024 15:09:29 +0100 Subject: [PATCH] [Doc] Tutorial 3 python with ROS2 --- .../tutorial3/InsertNewKnowledge.html | 607 +++++++++++++----- .../tutorial3/MakeItProactive.html | 16 +- .../tutorial3/Presentation.html | 122 +++- 3 files changed, 569 insertions(+), 176 deletions(-) diff --git a/docs/python_Tutorials/tutorial3/InsertNewKnowledge.html b/docs/python_Tutorials/tutorial3/InsertNewKnowledge.html index e5f5e33e..dc852ad4 100644 --- a/docs/python_Tutorials/tutorial3/InsertNewKnowledge.html +++ b/docs/python_Tutorials/tutorial3/InsertNewKnowledge.html @@ -4,10 +4,12 @@ Feed and generalize (python) : Insert new knowledge + + @@ -137,23 +139,63 @@

Insert new knowledge

Before starting, here are some imports, an ontology manipulator object, a small function that removes the s of the plural of a word when it is present.

-
-
#!/usr/bin/env python
-

-
import re
-
import time
-

-
import rospy
-
from std_msgs.msg import String
-

-
from ontologenius import OntologyManipulator
-

-
_onto = None
-

-
def singular(word):
-
if word[len(word) - 1 ] == 's':
-
word = word[0 : len(word) - 1]
-
return word
+
+
+ + +
+ +
+
+
+
#!/usr/bin/env python
+

+
import re
+
import time
+

+
import rospy
+
from std_msgs.msg import String
+

+
from ontologenius import OntologyManipulator
+

+
_onto = None
+

+
def singular(word):
+
if word[len(word) - 1 ] == 's':
+
word = word[0 : len(word) - 1]
+
return word
+

+
def say(text):
+
print('[SAY]' + text)
+
+
+
+ +

In the next step, we will define five regexes that correspond to the five types of sentences that our chatbot @@ -177,120 +219,120 @@

Insert new knowledge

We will now write the callback function of a ROS topic that will determine the type of sentence and perform the actions corresponding to each type of sentence.

-
-
def testIsA(text):
-
global _onto
-
match = re.search(r"^(a\s|the\s)?(\w+)\s(is\sa|is\san|are)\s(\w+)$", text)
-
if match != None:
-
_onto.feeder.addInheritage(singular(match.group(2)), singular(match.group(4)))
+
+
def testIsA(text):
+
global _onto
+
match = re.search(r"^(a\s|the\s)?(\w+)\s(is\sa|is\san|are)\s(\w+)$", text)
+
if match != None:
+
_onto.feeder.addInheritage(singular(match.group(2)), singular(match.group(4)))
return 'ok'
else:
-
return None
+
return None

-
def testProperty(text):
-
global _onto
-
match = re.search(r"^(a\s)?(\w+)\scan\s(not\s)?(\w+)$", text)
-
if match != None:
-
if match.group(3) == None:
-
_onto.feeder.removeDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'False')
-
_onto.feeder.addDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'True')
+
def testProperty(text):
+
global _onto
+
match = re.search(r"^(a\s)?(\w+)\scan\s(not\s)?(\w+)$", text)
+
if match != None:
+
if match.group(3) == None:
+
_onto.feeder.removeDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'False')
+
_onto.feeder.addDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'True')
else:
-
_onto.feeder.removeDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'True')
-
_onto.feeder.addDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'False')
+
_onto.feeder.removeDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'True')
+
_onto.feeder.addDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'False')
return 'ok'
else:
-
return None
+
return None

-
def testQuestion(text):
-
global _onto
-
match = re.search(r"^can\s(a\s)?(\w+)\s(\w+)\s?\?$", text)
-
if match != None:
-
res = _onto.individuals.getOn(singular(match.group(2)), 'can_' + singular(match.group(3)))
-
if len(res) == 0:
-
res = _onto.classes.getOn(singular(match.group(2)), 'can_' + singular(match.group(3)))
+
def testQuestion(text):
+
global _onto
+
match = re.search(r"^can\s(a\s)?(\w+)\s(\w+)\s?\?$", text)
+
if match != None:
+
res = _onto.individuals.getOn(singular(match.group(2)), 'can_' + singular(match.group(3)))
+
if len(res) == 0:
+
res = _onto.classes.getOn(singular(match.group(2)), 'can_' + singular(match.group(3)))

-
if len(res) != 0:
-
if res[0] == 'bool#True':
+
if len(res) != 0:
+
if res[0] == 'bool#True':
return 'yes'
else:
return 'no'
else:
return 'I do not know'
else:
-
return None
+
return None

-
def testWhatIs(text):
-
global _onto
-
match = re.search(r"^what\s(is|are)\s(a\s)?(\w+)\s?\?$", text)
-
if match != None:
-
res = _onto.individuals.getUp(singular(match.group(3)), 1)
-
if len(res) == 0:
-
res = _onto.classes.getUp(singular(match.group(3)), 1)
+
def testWhatIs(text):
+
global _onto
+
match = re.search(r"^what\s(is|are)\s(a\s)?(\w+)\s?\?$", text)
+
if match != None:
+
res = _onto.individuals.getUp(singular(match.group(3)), 1)
+
if len(res) == 0:
+
res = _onto.classes.getUp(singular(match.group(3)), 1)

-
if len(res) == 0:
+
if len(res) == 0:
return 'I do not know'
else:
-
return 'It is a : ' + str(res)
+
return 'It is a : ' + str(res)

else:
-
return None
+
return None

-
def testIsItA(text):
-
global _onto
-
match = re.search(r"^(is\sa|are)\s(\w+)\s(is\sa\s|is\san\s|a\s|an\s)?(\w+)\s?\?$", text)
-
if match != None:
-
res = _onto.individuals.getUp(singular(match.group(2)), selector = singular(match.group(4)))
-
if len(res) == 0:
-
res = _onto.classes.getUp(singular(match.group(2)), selector = singular(match.group(4)))
+
def testIsItA(text):
+
global _onto
+
match = re.search(r"^(is\sa|are)\s(\w+)\s(is\sa\s|is\san\s|a\s|an\s)?(\w+)\s?\?$", text)
+
if match != None:
+
res = _onto.individuals.getUp(singular(match.group(2)), selector = singular(match.group(4)))
+
if len(res) == 0:
+
res = _onto.classes.getUp(singular(match.group(2)), selector = singular(match.group(4)))

-
if len(res) == 0:
+
if len(res) == 0:
return 'no'
else:
return 'yes'

else:
-
return None
+
return None

-
def inputCallback(msg):
-
print msg.data
+
def inputCallback(msg):
+
say(msg.data)

-
response = testIsA(msg.data)
-
if response == None:
-
response = testProperty(msg.data)
-
if response == None:
-
response = testQuestion(msg.data)
-
if response == None:
-
response = testWhatIs(msg.data)
-
if response == None:
-
response = testIsItA(msg.data)
-
if response == None:
-
response = 'I do not understand'
+
response = testIsA(msg.data)
+
if response == None:
+
response = testProperty(msg.data)
+
if response == None:
+
response = testQuestion(msg.data)
+
if response == None:
+
response = testWhatIs(msg.data)
+
if response == None:
+
response = testIsItA(msg.data)
+
if response == None:
+
response = 'I do not understand'

-
if response != '':
-
print '=> ' + response
+
if response != '':
+
say('=> ' + response)

Let's break down the code:

-
-
match = re.search(r"^(a\s|the\s)?(\w+)\s(is\sa|is\san|are)\s(\w+)$", text)
+
+
match = re.search(r"^(a\s|the\s)?(\w+)\s(is\sa|is\san|are)\s(\w+)$", text)

We test here if the sentence sent to the topic corresponds to the first regexp. If so, then the different matches will be put in the match variable. We will do the same for all the regexp.

-
-
_onto.feeder.addInheritage(singular(match.group(2)), singular(match.group(4)))
+
+
_onto.feeder.addInheritage(singular(match.group(2)), singular(match.group(4)))

If the sentence matches a heritage relationship, we add the inheritance relationship via the member feeder of the ontology manipulator.

Note that we do not directly pass the matches in the parameters but their singular version.

-
-
if match.group(3) == None:
-
_onto.feeder.removeDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'False')
-
_onto.feeder.addDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'True')
+
+
if match.group(3) == None:
+
_onto.feeder.removeDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'False')
+
_onto.feeder.addDataProperty(singular(match.group(2)), 'can_' + singular(match.group(4)), 'bool', 'True')

The third match must contain "not" if the sentence is in its negative form and None if it is @@ -309,13 +351,13 @@

Insert new knowledge

property it will create it alone by determining its type with respect to the data pointed. For all times after, the property will exist and will be reused.

-
-
res = _onto.individuals.getOn(singular(match.group(2)), 'can_' + singular(match.group(3)))
-
if len(res) == 0:
-
res = _onto.classes.getOn(singular(match.group(2)), 'can_' + singular(match.group(3)))
+
+
res = _onto.individuals.getOn(singular(match.group(2)), 'can_' + singular(match.group(3)))
+
if len(res) == 0:
+
res = _onto.classes.getOn(singular(match.group(2)), 'can_' + singular(match.group(3)))

-
if len(res) != 0:
-
if res[0] == 'bool#True':
+
if len(res) != 0:
+
if res[0] == 'bool#True':
return 'yes'
else:
return 'no'
@@ -331,10 +373,10 @@

Insert new knowledge

If we got an answer, it will be in the form "type#value".

-
-
res = _onto.individuals.getUp(singular(match.group(3)), 1)
-
if len(res) == 0:
-
res = _onto.classes.getUp(singular(match.group(3)), 1)
+
+
res = _onto.individuals.getUp(singular(match.group(3)), 1)
+
if len(res) == 0:
+
res = _onto.classes.getUp(singular(match.group(3)), 1)

Here we try to answer a question such as "what is a kiwi?" You should directly think about using @@ -343,10 +385,10 @@

Insert new knowledge

as 1. This value corresponds to the depth of exploration of the inheritance tree. By setting this parameter to 1, we ask to have only direct inheritances.

-
-
res = _onto.individuals.getUp(singular(match.group(2)), selector = singular(match.group(4)))
-
if len(res) == 0:
-
res = _onto.classes.getUp(singular(match.group(2)), selector = singular(match.group(4)))
+
+
res = _onto.individuals.getUp(singular(match.group(2)), selector = singular(match.group(4)))
+
if len(res) == 0:
+
res = _onto.classes.getUp(singular(match.group(2)), selector = singular(match.group(4)))

Finally, we finish with a question of the type "is a kiwi is an animal?". To answer this we could recover all the heritage tree and we look if the concept of @@ -357,21 +399,67 @@

Insert new knowledge

Finally, we can write our main function which creates the ontology manipulator, close the ontology, and subscribes to the topic "feed_and_generalize/in".

-
-
if __name__ == '__main__':
-
global _onto
-

-
rospy.init_node('feed_and_generalize')
-

-
_onto = OntologyManipulator()
-
_onto.close()
-
time.sleep(1)
-

-
_onto.feeder.addConcept('bird')
-

-
rospy.Subscriber('feed_and_generalize/in', String, inputCallback)
-

-
rospy.spin()
+
+
+ + +
+ +
+
+
+
def main():
+
global _onto
+

+
rospy.init_node('feed_and_generalize')
+

+
_onto = OntologyManipulator()
+
_onto.close()
+
time.sleep(1)
+

+
_onto.feeder.addConcept('bird')
+

+
rospy.Subscriber('feed_and_generalize/in', String, inputCallback)
+

+
rospy.spin()
+

+
if __name__ == '__main__':
+
main()
+
+
+
+ +

Before moving on, note that we add the concept "bird" before all. This is because to @@ -379,8 +467,8 @@

Insert new knowledge

add the fact that a bird is an animal, Ontologenius must know either bird or animal and will automatically create the second if it does not exist yet.

-
-
_onto.feeder.addConcept('bird')
+
+
_onto.feeder.addConcept('bird')

Let's test!

@@ -388,18 +476,60 @@

Let's test!

Now that everything is ready, let's launch our program and in another terminal explain to it that a kiwi is a bird and that it can not fly:

-
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a kiwi is a bird'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a kiwi can not fly'"
+
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a kiwi is a bird'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a kiwi can not fly'"
+
+
+
+ +

We can already ask it some questions to evaluate what it knows thanks to this new information:

-
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'what is a kiwi?'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a kiwi fly ?'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'is a kiwi an animal?'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'what is a kiwi?'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a kiwi fly ?'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'is a kiwi an animal?'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+
+
+
+ +

It should answer you (in the terminal where the program is launched) that a kiwi is a bird and @@ -408,9 +538,29 @@

Let's test!

We can explain to it that a bird is an animal and ask it again if a kiwi is an animal:

-
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'birds are animals'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'is a kiwi an animal?'"
+
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'birds are animals'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'is a kiwi an animal?'"
+
+
+
+ +

It is obvious but now our program responds to us that a kiwi is an animal as a kiwi is a bird and a @@ -419,10 +569,31 @@

Let's test!

So let's learn the concept of a penguin who is a bird that can not fly and then ask it again if a bird can fly:

-
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a penguin is a bird'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a penguin can not fly'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a penguin is a bird'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a penguin can not fly'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+
+
+
+ +

Surprisingly, our program now responds to the fact that birds can not fly, which is wrong, but @@ -442,23 +613,65 @@

Let's test!

Before continuing, kill Ontologenius and so your program then restarts it and ask it again if the birds can fly.

-
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+
+
+
+ +

It should answer you again no. Yet you have stopped Ontologenius... This is where we understand its long-term memory principle as well as the usefulness of the internal file. When stopping Ontologenius, it stored all its knowledge in the internal file that is reloaded at the restart.

-

We will now teach it the principle of a parrot and a dove that are birds capable of flying and ask it again if - the birds can fly.

- -
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a parrot is a bird'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a parrot can fly'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a dove is a bird'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a dove can fly'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+

We will now teach it the principle of a parrot and a dove that are birds capable of flying and ask it again if + the birds can fly.

+ +
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a parrot is a bird'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a parrot can fly'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a dove is a bird'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a dove can fly'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+
+
+
+ +

You had to suspect that the 60% condition is no longer true and our program finds itself in @@ -466,26 +679,87 @@

Let's test!

Let's learn five new birds that can all fly to reach the threshold of 60%.

-
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a heron is a bird'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a heron can fly'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a gull is a bird'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a gull can fly'"
+
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a heron is a bird'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a heron can fly'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a gull is a bird'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a gull can fly'"
+
+
+
+ +

By asking it one last time if the birds can fly you should finally have a good answer from it and this without ever having explicitly told it.

-
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a bird fly ?'"
+
+
+
+ +

As I did in the introduction of this tutorial, simply teach it that a phalarope is a bird and ask it if it can fly:

-
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a phalarope is a bird'"
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a phalarope fly ?'"
+
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'a phalarope is a bird'"
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a phalarope fly ?'"
+
+
+
+ +

Since it has no information about this and because thinking that birds can fly in general, it @@ -494,8 +768,27 @@

Let's test!

However, by asking if a kiwi can fly, you should always have the answer that not that you have explicitly given this knowledge.

-
-
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a kiwi fly ?'"
+
+
+ + +
+ +
+
+
+
rostopic pub -1 /feed_and_generalize/in std_msgs/String "data: 'can a kiwi fly ?'"
+
+
+
+ +

So we have seen here how to add new knowledge during the execution of the program and the impact of @@ -504,8 +797,8 @@

Let's test!

If you wish, you can delete the internal file Ontologenius has created and try again by adding the following line just before closing the ontology in the main function.

-
-
_onto.reasoners.deactivate('ReasonerGeneralize');
+
+
_onto.reasoners.deactivate('ReasonerGeneralize')

In fact, the generalization mechanism is a reasoning plugin that like all these mechanisms can be diff --git a/docs/python_Tutorials/tutorial3/MakeItProactive.html b/docs/python_Tutorials/tutorial3/MakeItProactive.html index 28a07279..426a9d40 100644 --- a/docs/python_Tutorials/tutorial3/MakeItProactive.html +++ b/docs/python_Tutorials/tutorial3/MakeItProactive.html @@ -146,19 +146,19 @@

Make our agent proactive

Here is the callback function:

-
def proactiveCallback(msg):
-
match = re.search(r"^\[NEW\](\w+)>can_(\w+):bool#(\w+)$", msg.data)
-
if match != None:
-
if match.group(3) == 'True':
-
print 'I think that a ' + match.group(1) + ' can ' + match.group(2)
+
def proactiveCallback(msg):
+
match = re.search(r"^\[NEW\](\w+)>can_(\w+):bool#(\w+)$", msg)
+
if match != None:
+
if match.group(3) == 'True':
+
say('I think that a ' + match.group(1) + ' can ' + match.group(2))
else:
-
print 'I think that a ' + match.group(1) + ' can not ' + match.group(2)
+
say('I think that a ' + match.group(1) + ' can not ' + match.group(2))
-

And finally, the new ros subscriber to put in the main function:

+

And finally, in the main function, we subscribe to the notification topic using the OntologyManipulator:

-
rospy.Subscriber('ontologenius/reasoner_notifications', String, proactiveCallback)
+
_onto.feeder.registerNotificationCallback(proactiveCallback)

You can now delete the internal file and learn again to your program that birds can fly diff --git a/docs/python_Tutorials/tutorial3/Presentation.html b/docs/python_Tutorials/tutorial3/Presentation.html index 03579f7d..cb0f4674 100644 --- a/docs/python_Tutorials/tutorial3/Presentation.html +++ b/docs/python_Tutorials/tutorial3/Presentation.html @@ -4,10 +4,12 @@ Feed and generalize (python) : Presentation of the problem + + @@ -161,20 +163,118 @@

Before you start

Before moving on, you can create a new launch file, set the "files" argument with an empty quotation mark to make sure you do not load an - existing ontology, and then set the "intern_file" argument to "$(find ontologenius_tutorial)/birds.owl". + existing ontology, and then set the "intern_file" argument to a file named "birds.owl".

-
-
<launch>
-
<node name="feed_and_generalize" pkg="ontologenius_tutorial" type="feed_and_generalize.py" output="screen"/>
-
<include file="$(find ontologenius)/launch/ontologenius_empty.launch">
-
<arg name="intern_file" default="$(find ontologenius_tutorial)/birds.owl"/>
-
<arg name="files" default=""/>
-
<arg name="config_file" default="$(find ontologenius)/configuration/config_generalization.yaml"/>
-
</include>
-
</launch>
-
+
+
+ + + + +
+ +
+
+
+
<launch>
+
<node name="feed_and_generalize" pkg="ontologenius_tutorial" type="feed_and_generalize.py" output="screen"/>
+
<include file="$(find ontologenius)/launch/ontologenius_empty.launch">
+
<arg name="intern_file" default="$(find ontologenius_tutorial)/birds.owl"/>
+
<arg name="files" default=""/>
+
<arg name="config_file" default="$(find ontologenius)/configuration/config_generalization.yaml"/>
+
</include>
+
</launch>
+
+

Let's call this file generalize.launch and put it in our package in the folder launch.

+
+
+ + + + + + + +

By specifying an internal file, Ontologenius is allowed to save the ontology it contains in a file when it is stopped and to reload it on its next start. We will see the usefulness of this later.