We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Loitering does not seem to work properly
<!--

STOP ! ! !

Read the following before creating anything (or you will have your issue/feature request closed without notice)

1. Please only create an ISSUE or a FEATURE REQUEST - don't mix the two together in one item
2. For a Feature Request please only fill out the FEATURE REQUEST section
3. For a Issue please only fill out the ISSUE section
4. Issues are NOT to be used for help/config problems/support - use the relevant slack channels as per the README
5. Provide a good summary in the title, don't just write problem, or awesome idea!
6. Delete all irrelevant sections not related to your issue/feature request (including this top section)

===============ISSUE SECTION===============

Before you create an Issue, please check the following:

1. Have you validated that your config.json is valid JSON? Use http://jsonlint.com/ to check.
2. Have you [searched our issue tracker](https://github.com/PokemonGoF/PokemonGo-Bot/issues?q=is%3Aissue+sort%3Aupdated-desc) to see if the issue already exists? If so, comment on that issue instead rather than creating a new issue.
3. Are you running on the `master` branch? We work on the `dev` branch and then add that functionality to `master` when it is stable. Your issue may be fixed on `dev` and there is no need for this issue, just wait and it will eventually be merged to `master`.
4. All Issue sections MUST be completed to help us determine the actual problem and find its cause
-->
### Expected Behavior

<!-- Tell us what you expect to happen -->

Run the bot, go to the next point as in my path file, then, while loitering, move to forts, spin the pokestop and catch pokemons.
### Actual Behavior

<!-- Tell us what is happening -->

only while is following a path spin the pokestops, while is loitering it does nothing.
### Your FULL config.json (remove your username, password, gmapkey and any other private info)

<!-- Provide your FULL config file, feel free to use services such as pastebin.com to reduce clutter -->

http://pastebin.com/HDWecKDg
### Output when issue occurred

<!-- Provide a reasonable sample from your output log (not just the error message), feel free to use services such as pastebin.com to reduce clutter -->

http://pastebin.com/2fY2XXBC
in the line 40 and 426 start to loiter.
### Steps to Reproduce

<!-- Tell us the steps you have taken to reproduce the issue -->

./run.sh
### Other Information

OS: Ubuntu 16.04

<!-- Tell us what Operating system you're using --> 

Branch: master

<!-- dev or master --> 

Git Commit: a8ee31256d412413b107cce81b62059634e8c802

<!-- run 'git log -n 1 --pretty=format:"%H"' --> 

Python Version: Python 2.7.12

<!-- run 'python -V' and paste it here) --> 

Any other relevant files/configs (eg: path files) 

<!-- Anything else which may be of relevance -->

path file
[
    {"location": "40.7814675, -73.9741015, 33", "loiter": 300},
  {"location": "40.7795502, -73.9632225, 46", "loiter": 300},
  {"location": "40.7739931, -73.9665484, 23", "loiter": 300},
  {"location": "40.7741881, -73.9707756, 25", "loiter": 300},
  {"location": "40.7757805, -73.9717841, 26", "loiter": 300},
  {"location": "40.7772429, -73.9712047, 29", "loiter": 300},
  {"location": "40.7678016, -73.9717411, 18", "loiter": 300},
  {"location": "40.7663878, -73.9732003, 21", "loiter": 300},
  {"location": "40.7647626, -73.9732003, 32", "loiter": 300},
  {"location": "40.7653802, -73.9750671, 26", "loiter": 300},
  {"location": "40.7665015, -73.9748954, 14", "loiter": 300},
  {"location": "40.7762842, -73.9740157, 32", "loiter": 300}
]

<!-- ===============END OF ISSUE SECTION=============== -->

<!-- Note: Delete these lines and everything BELOW if creating an Issue -->


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pokemongo_bot/cell_workers/follow_path.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 from __future__ import absolute_import
4 import gpxpy
5 import gpxpy.gpx
6 import json
7 import time
8 from pokemongo_bot.base_task import BaseTask
9 from pokemongo_bot.cell_workers.utils import distance
10 from pokemongo_bot.cell_workers.utils import format_dist
11 from pokemongo_bot.cell_workers.utils import i2f
12 from pokemongo_bot.human_behaviour import sleep
13 from pokemongo_bot.walkers.walker_factory import walker_factory
14 from pokemongo_bot.worker_result import WorkerResult
15 from pgoapi.utilities import f2i
16 from random import uniform
17 from .utils import getSeconds, format_dist
18 from datetime import datetime as dt, timedelta
19 
20 STATUS_MOVING = 0
21 STATUS_LOITERING = 1
22 STATUS_FINISHED = 2
23  
24 class FollowPath(BaseTask):
25     SUPPORTED_TASK_API_VERSION = 1
26 
27     def initialize(self):
28         self._process_config()
29         self.points = self.load_path()
30         self.status = STATUS_MOVING
31         self.loiter_end_time = 0
32         self.distance_unit = self.bot.config.distance_unit
33         self.append_unit = False
34 
35         if self.path_start_mode == 'closest':
36             self.ptr = self.find_closest_point_idx(self.points)
37 
38         else:
39             self.ptr = 0
40 
41     def _process_config(self):
42         self.path_file = self.config.get("path_file", None)
43         self.path_mode = self.config.get("path_mode", "linear")
44         self.path_start_mode = self.config.get("path_start_mode", "first")
45         self.number_lap_max = self.config.get("number_lap", -1) # if < 0, then the number is inf.
46         self.timer_restart_min = getSeconds(self.config.get("timer_restart_min", "00:20:00"))
47         self.timer_restart_max = getSeconds(self.config.get("timer_restart_max", "02:00:00"))
48         self.walker = self.config.get('walker', 'StepWalker')
49 
50         if self.timer_restart_min > self.timer_restart_max:
51             raise ValueError('path timer_restart_min is bigger than path timer_restart_max') #TODO there must be a more elegant way to do it...
52         
53         #var not related to configs
54         self.number_lap = 0
55         
56     def load_path(self):
57         if self.path_file is None:
58             raise RuntimeError('You need to specify a path file (json or gpx)')
59 
60         if self.path_file.endswith('.json'):
61             return self.load_json()
62         elif self.path_file.endswith('.gpx'):
63             return self.load_gpx()
64 
65     def load_json(self):
66         with open(self.path_file) as data_file:
67             points=json.load(data_file)
68         # Replace Verbal Location with lat&lng.
69         for _, point in enumerate(points):
70             point_tuple = self.bot.get_pos_by_name(point['location'])
71             self.emit_event(
72                 'location_found',
73                 level='debug',
74                 formatted="Location found: {location} {position}",
75                 data={
76                     'location': point,
77                     'position': point_tuple
78                 }
79             )
80             # Keep point['location']
81             point["lat"] = float(point_tuple[0])
82             point["lng"] = float(point_tuple[1])
83             point["alt"] = float(point_tuple[2])
84         return points
85 
86     def load_gpx(self):
87         gpx_file = open(self.path_file, 'r')
88         gpx = gpxpy.parse(gpx_file)
89 
90         if len(gpx.tracks) == 0:
91             raise RuntimeError('GPX file does not contain a track')
92 
93         points = []
94         track = gpx.tracks[0]
95         for segment in track.segments:
96             for point in segment.points:
97                 points.append({"lat": point.latitude, "lng": point.longitude,
98                     "alt": point.elevation, "location": point.name})
99 
100         return points
101 
102     def find_closest_point_idx(self, points):
103         return_idx = 0
104         min_distance = float("inf");
105         
106         for index in range(len(points)):
107             point = points[index]
108             lat = point['lat']
109             lng = point['lng']
110 
111             dist = distance(
112                 self.bot.position[0],
113                 self.bot.position[1],
114                 lat,
115                 lng
116             )
117 
118             if dist < min_distance:
119                 min_distance = dist
120                 return_idx = index
121 
122         return return_idx
123 
124     def endLaps(self):
125         duration = int(uniform(self.timer_restart_min, self.timer_restart_max))
126         resume = dt.now() + timedelta(seconds=duration)
127         
128         self.emit_event(
129             'path_lap_end',
130             formatted="Great job, lot of calories burned! Taking a break now for {duration}, will resume at {resume}.",
131             data={
132                 'duration': str(timedelta(seconds=duration)),
133                 'resume': resume.strftime("%H:%M:%S")
134             }
135         )
136         
137         self.number_lap = 0 # at the end of the break, start again
138         sleep(duration)
139         self.bot.login()
140 
141     def work(self):
142         # If done or loitering allow the next task to run
143         if self.status == STATUS_FINISHED:
144             return WorkerResult.SUCCESS
145 
146         if self.status == STATUS_LOITERING and time.time() < self.loiter_end_time:
147             return WorkerResult.RUNNING
148 
149         last_lat, last_lng, last_alt = self.bot.position
150 
151         point = self.points[self.ptr]
152         lat = point['lat']
153         lng = point['lng']
154 
155         if 'alt' in point:
156             alt = float(point['alt'])
157         else:
158             alt = uniform(self.bot.config.alt_min, self.bot.config.alt_max)
159 
160         if self.bot.config.walk_max > 0:
161             step_walker = walker_factory(self.walker,
162                 self.bot,
163                 lat,
164                 lng,
165                 alt
166             )
167 
168             is_at_destination = False
169             if step_walker.step():
170                 is_at_destination = True
171 
172         else:
173             self.bot.api.set_position(lat, lng, alt)
174 
175         dist = distance(
176             last_lat,
177             last_lng,
178             lat,
179             lng
180         )
181 
182         self.emit_event(
183             'position_update',
184             formatted="Walking from {last_position} to {current_position}, distance left: ({distance} {distance_unit}) ..",
185             data={
186                 'last_position': (last_lat, last_lng, last_alt),
187                 'current_position': (lat, lng, alt),
188                 'distance': format_dist(dist,self.distance_unit,self.append_unit),
189                 'distance_unit': self.distance_unit
190             }
191         )
192         
193         if (self.bot.config.walk_min > 0 and is_at_destination) or (self.status == STATUS_LOITERING and time.time() >= self.loiter_end_time):
194             if "loiter" in point and self.status != STATUS_LOITERING:
195                 self.logger.info("Loitering for {} seconds...".format(point["loiter"]))
196                 self.status = STATUS_LOITERING
197                 self.loiter_end_time = time.time() + point["loiter"]
198                 return WorkerResult.RUNNING
199             if (self.ptr + 1) == len(self.points):
200                 if self.path_mode == 'single':
201                     self.status = STATUS_FINISHED
202                     return WorkerResult.SUCCESS
203                 self.ptr = 0
204                 if self.path_mode == 'linear':
205                     self.points = list(reversed(self.points))
206                 if self.number_lap_max >= 0:
207                     self.number_lap+=1
208                     self.emit_event(
209                         'path_lap_update',
210                         formatted="number lap : {number_lap} / {number_lap_max}",
211                         data={
212                             'number_lap': str(self.number_lap),
213                             'number_lap_max': str(self.number_lap_max)
214                         }
215                     )
216                     if self.number_lap >= self.number_lap_max:
217                         self.endLaps()
218             else:
219                 self.ptr += 1
220         
221         self.status = STATUS_MOVING
222         return WorkerResult.RUNNING
223
```
--- 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/pokemongo_bot/cell_workers/follow_path.py b/pokemongo_bot/cell_workers/follow_path.py
--- a/pokemongo_bot/cell_workers/follow_path.py
+++ b/pokemongo_bot/cell_workers/follow_path.py
@@ -18,7 +18,7 @@
 from datetime import datetime as dt, timedelta
 
 STATUS_MOVING = 0
-STATUS_LOITERING = 1
+STATUS_WANDERING = 1
 STATUS_FINISHED = 2
  
 class FollowPath(BaseTask):
@@ -28,7 +28,7 @@
         self._process_config()
         self.points = self.load_path()
         self.status = STATUS_MOVING
-        self.loiter_end_time = 0
+        self.wander_end_time = 0
         self.distance_unit = self.bot.config.distance_unit
         self.append_unit = False
 
@@ -139,12 +139,12 @@
         self.bot.login()
 
     def work(self):
-        # If done or loitering allow the next task to run
+        # If done or wandering allow the next task to run
         if self.status == STATUS_FINISHED:
             return WorkerResult.SUCCESS
 
-        if self.status == STATUS_LOITERING and time.time() < self.loiter_end_time:
-            return WorkerResult.RUNNING
+        if self.status == STATUS_WANDERING and time.time() < self.wander_end_time:
+            return WorkerResult.SUCCESS
 
         last_lat, last_lng, last_alt = self.bot.position
 
@@ -190,12 +190,14 @@
             }
         )
         
-        if (self.bot.config.walk_min > 0 and is_at_destination) or (self.status == STATUS_LOITERING and time.time() >= self.loiter_end_time):
-            if "loiter" in point and self.status != STATUS_LOITERING:
-                self.logger.info("Loitering for {} seconds...".format(point["loiter"]))
-                self.status = STATUS_LOITERING
-                self.loiter_end_time = time.time() + point["loiter"]
-                return WorkerResult.RUNNING
+        if (self.bot.config.walk_min > 0 and is_at_destination) or (self.status == STATUS_WANDERING and time.time() >= self.wander_end_time):
+            if "loiter" in point:
+                self.logger.warning("'loiter' is obsolete, please change to 'wander' in {}".format(self.path_file))
+            if "wander" in point and self.status != STATUS_WANDERING:
+                self.logger.info("Wandering for {} seconds...".format(point["wander"]))
+                self.status = STATUS_WANDERING
+                self.wander_end_time = time.time() + point["wander"]
+                return WorkerResult.SUCCESS
             if (self.ptr + 1) == len(self.points):
                 if self.path_mode == 'single':
                     self.status = STATUS_FINISHED

{"golden_diff": "diff --git a/pokemongo_bot/cell_workers/follow_path.py b/pokemongo_bot/cell_workers/follow_path.py\n--- a/pokemongo_bot/cell_workers/follow_path.py\n+++ b/pokemongo_bot/cell_workers/follow_path.py\n@@ -18,7 +18,7 @@\n from datetime import datetime as dt, timedelta\n \n STATUS_MOVING = 0\n-STATUS_LOITERING = 1\n+STATUS_WANDERING = 1\n STATUS_FINISHED = 2\n  \n class FollowPath(BaseTask):\n@@ -28,7 +28,7 @@\n         self._process_config()\n         self.points = self.load_path()\n         self.status = STATUS_MOVING\n-        self.loiter_end_time = 0\n+        self.wander_end_time = 0\n         self.distance_unit = self.bot.config.distance_unit\n         self.append_unit = False\n \n@@ -139,12 +139,12 @@\n         self.bot.login()\n \n     def work(self):\n-        # If done or loitering allow the next task to run\n+        # If done or wandering allow the next task to run\n         if self.status == STATUS_FINISHED:\n             return WorkerResult.SUCCESS\n \n-        if self.status == STATUS_LOITERING and time.time() < self.loiter_end_time:\n-            return WorkerResult.RUNNING\n+        if self.status == STATUS_WANDERING and time.time() < self.wander_end_time:\n+            return WorkerResult.SUCCESS\n \n         last_lat, last_lng, last_alt = self.bot.position\n \n@@ -190,12 +190,14 @@\n             }\n         )\n         \n-        if (self.bot.config.walk_min > 0 and is_at_destination) or (self.status == STATUS_LOITERING and time.time() >= self.loiter_end_time):\n-            if \"loiter\" in point and self.status != STATUS_LOITERING:\n-                self.logger.info(\"Loitering for {} seconds...\".format(point[\"loiter\"]))\n-                self.status = STATUS_LOITERING\n-                self.loiter_end_time = time.time() + point[\"loiter\"]\n-                return WorkerResult.RUNNING\n+        if (self.bot.config.walk_min > 0 and is_at_destination) or (self.status == STATUS_WANDERING and time.time() >= self.wander_end_time):\n+            if \"loiter\" in point:\n+                self.logger.warning(\"'loiter' is obsolete, please change to 'wander' in {}\".format(self.path_file))\n+            if \"wander\" in point and self.status != STATUS_WANDERING:\n+                self.logger.info(\"Wandering for {} seconds...\".format(point[\"wander\"]))\n+                self.status = STATUS_WANDERING\n+                self.wander_end_time = time.time() + point[\"wander\"]\n+                return WorkerResult.SUCCESS\n             if (self.ptr + 1) == len(self.points):\n                 if self.path_mode == 'single':\n                     self.status = STATUS_FINISHED\n", "issue": "Loitering does not seem to work properly\n<!--\n\nSTOP ! ! !\n\nRead the following before creating anything (or you will have your issue/feature request closed without notice)\n\n1. Please only create an ISSUE or a FEATURE REQUEST - don't mix the two together in one item\n2. For a Feature Request please only fill out the FEATURE REQUEST section\n3. For a Issue please only fill out the ISSUE section\n4. Issues are NOT to be used for help/config problems/support - use the relevant slack channels as per the README\n5. Provide a good summary in the title, don't just write problem, or awesome idea!\n6. Delete all irrelevant sections not related to your issue/feature request (including this top section)\n\n===============ISSUE SECTION===============\n\nBefore you create an Issue, please check the following:\n\n1. Have you validated that your config.json is valid JSON? Use http://jsonlint.com/ to check.\n2. Have you [searched our issue tracker](https://github.com/PokemonGoF/PokemonGo-Bot/issues?q=is%3Aissue+sort%3Aupdated-desc) to see if the issue already exists? If so, comment on that issue instead rather than creating a new issue.\n3. Are you running on the `master` branch? We work on the `dev` branch and then add that functionality to `master` when it is stable. Your issue may be fixed on `dev` and there is no need for this issue, just wait and it will eventually be merged to `master`.\n4. All Issue sections MUST be completed to help us determine the actual problem and find its cause\n-->\n### Expected Behavior\n\n<!-- Tell us what you expect to happen -->\n\nRun the bot, go to the next point as in my path file, then, while loitering, move to forts, spin the pokestop and catch pokemons.\n### Actual Behavior\n\n<!-- Tell us what is happening -->\n\nonly while is following a path spin the pokestops, while is loitering it does nothing.\n### Your FULL config.json (remove your username, password, gmapkey and any other private info)\n\n<!-- Provide your FULL config file, feel free to use services such as pastebin.com to reduce clutter -->\n\nhttp://pastebin.com/HDWecKDg\n### Output when issue occurred\n\n<!-- Provide a reasonable sample from your output log (not just the error message), feel free to use services such as pastebin.com to reduce clutter -->\n\nhttp://pastebin.com/2fY2XXBC\nin the line 40 and 426 start to loiter.\n### Steps to Reproduce\n\n<!-- Tell us the steps you have taken to reproduce the issue -->\n\n./run.sh\n### Other Information\n\nOS: Ubuntu 16.04\n\n<!-- Tell us what Operating system you're using --> \n\nBranch: master\n\n<!-- dev or master --> \n\nGit Commit: a8ee31256d412413b107cce81b62059634e8c802\n\n<!-- run 'git log -n 1 --pretty=format:\"%H\"' --> \n\nPython Version: Python 2.7.12\n\n<!-- run 'python -V' and paste it here) --> \n\nAny other relevant files/configs (eg: path files) \n\n<!-- Anything else which may be of relevance -->\n\npath file\n[\n    {\"location\": \"40.7814675, -73.9741015, 33\", \"loiter\": 300},\n  {\"location\": \"40.7795502, -73.9632225, 46\", \"loiter\": 300},\n  {\"location\": \"40.7739931, -73.9665484, 23\", \"loiter\": 300},\n  {\"location\": \"40.7741881, -73.9707756, 25\", \"loiter\": 300},\n  {\"location\": \"40.7757805, -73.9717841, 26\", \"loiter\": 300},\n  {\"location\": \"40.7772429, -73.9712047, 29\", \"loiter\": 300},\n  {\"location\": \"40.7678016, -73.9717411, 18\", \"loiter\": 300},\n  {\"location\": \"40.7663878, -73.9732003, 21\", \"loiter\": 300},\n  {\"location\": \"40.7647626, -73.9732003, 32\", \"loiter\": 300},\n  {\"location\": \"40.7653802, -73.9750671, 26\", \"loiter\": 300},\n  {\"location\": \"40.7665015, -73.9748954, 14\", \"loiter\": 300},\n  {\"location\": \"40.7762842, -73.9740157, 32\", \"loiter\": 300}\n]\n\n<!-- ===============END OF ISSUE SECTION=============== -->\n\n<!-- Note: Delete these lines and everything BELOW if creating an Issue -->\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\nfrom __future__ import absolute_import\nimport gpxpy\nimport gpxpy.gpx\nimport json\nimport time\nfrom pokemongo_bot.base_task import BaseTask\nfrom pokemongo_bot.cell_workers.utils import distance\nfrom pokemongo_bot.cell_workers.utils import format_dist\nfrom pokemongo_bot.cell_workers.utils import i2f\nfrom pokemongo_bot.human_behaviour import sleep\nfrom pokemongo_bot.walkers.walker_factory import walker_factory\nfrom pokemongo_bot.worker_result import WorkerResult\nfrom pgoapi.utilities import f2i\nfrom random import uniform\nfrom .utils import getSeconds, format_dist\nfrom datetime import datetime as dt, timedelta\n\nSTATUS_MOVING = 0\nSTATUS_LOITERING = 1\nSTATUS_FINISHED = 2\n \nclass FollowPath(BaseTask):\n    SUPPORTED_TASK_API_VERSION = 1\n\n    def initialize(self):\n        self._process_config()\n        self.points = self.load_path()\n        self.status = STATUS_MOVING\n        self.loiter_end_time = 0\n        self.distance_unit = self.bot.config.distance_unit\n        self.append_unit = False\n\n        if self.path_start_mode == 'closest':\n            self.ptr = self.find_closest_point_idx(self.points)\n\n        else:\n            self.ptr = 0\n\n    def _process_config(self):\n        self.path_file = self.config.get(\"path_file\", None)\n        self.path_mode = self.config.get(\"path_mode\", \"linear\")\n        self.path_start_mode = self.config.get(\"path_start_mode\", \"first\")\n        self.number_lap_max = self.config.get(\"number_lap\", -1) # if < 0, then the number is inf.\n        self.timer_restart_min = getSeconds(self.config.get(\"timer_restart_min\", \"00:20:00\"))\n        self.timer_restart_max = getSeconds(self.config.get(\"timer_restart_max\", \"02:00:00\"))\n        self.walker = self.config.get('walker', 'StepWalker')\n\n        if self.timer_restart_min > self.timer_restart_max:\n            raise ValueError('path timer_restart_min is bigger than path timer_restart_max') #TODO there must be a more elegant way to do it...\n        \n        #var not related to configs\n        self.number_lap = 0\n        \n    def load_path(self):\n        if self.path_file is None:\n            raise RuntimeError('You need to specify a path file (json or gpx)')\n\n        if self.path_file.endswith('.json'):\n            return self.load_json()\n        elif self.path_file.endswith('.gpx'):\n            return self.load_gpx()\n\n    def load_json(self):\n        with open(self.path_file) as data_file:\n            points=json.load(data_file)\n        # Replace Verbal Location with lat&lng.\n        for _, point in enumerate(points):\n            point_tuple = self.bot.get_pos_by_name(point['location'])\n            self.emit_event(\n                'location_found',\n                level='debug',\n                formatted=\"Location found: {location} {position}\",\n                data={\n                    'location': point,\n                    'position': point_tuple\n                }\n            )\n            # Keep point['location']\n            point[\"lat\"] = float(point_tuple[0])\n            point[\"lng\"] = float(point_tuple[1])\n            point[\"alt\"] = float(point_tuple[2])\n        return points\n\n    def load_gpx(self):\n        gpx_file = open(self.path_file, 'r')\n        gpx = gpxpy.parse(gpx_file)\n\n        if len(gpx.tracks) == 0:\n            raise RuntimeError('GPX file does not contain a track')\n\n        points = []\n        track = gpx.tracks[0]\n        for segment in track.segments:\n            for point in segment.points:\n                points.append({\"lat\": point.latitude, \"lng\": point.longitude,\n                    \"alt\": point.elevation, \"location\": point.name})\n\n        return points\n\n    def find_closest_point_idx(self, points):\n        return_idx = 0\n        min_distance = float(\"inf\");\n        \n        for index in range(len(points)):\n            point = points[index]\n            lat = point['lat']\n            lng = point['lng']\n\n            dist = distance(\n                self.bot.position[0],\n                self.bot.position[1],\n                lat,\n                lng\n            )\n\n            if dist < min_distance:\n                min_distance = dist\n                return_idx = index\n\n        return return_idx\n\n    def endLaps(self):\n        duration = int(uniform(self.timer_restart_min, self.timer_restart_max))\n        resume = dt.now() + timedelta(seconds=duration)\n        \n        self.emit_event(\n            'path_lap_end',\n            formatted=\"Great job, lot of calories burned! Taking a break now for {duration}, will resume at {resume}.\",\n            data={\n                'duration': str(timedelta(seconds=duration)),\n                'resume': resume.strftime(\"%H:%M:%S\")\n            }\n        )\n        \n        self.number_lap = 0 # at the end of the break, start again\n        sleep(duration)\n        self.bot.login()\n\n    def work(self):\n        # If done or loitering allow the next task to run\n        if self.status == STATUS_FINISHED:\n            return WorkerResult.SUCCESS\n\n        if self.status == STATUS_LOITERING and time.time() < self.loiter_end_time:\n            return WorkerResult.RUNNING\n\n        last_lat, last_lng, last_alt = self.bot.position\n\n        point = self.points[self.ptr]\n        lat = point['lat']\n        lng = point['lng']\n\n        if 'alt' in point:\n            alt = float(point['alt'])\n        else:\n            alt = uniform(self.bot.config.alt_min, self.bot.config.alt_max)\n\n        if self.bot.config.walk_max > 0:\n            step_walker = walker_factory(self.walker,\n                self.bot,\n                lat,\n                lng,\n                alt\n            )\n\n            is_at_destination = False\n            if step_walker.step():\n                is_at_destination = True\n\n        else:\n            self.bot.api.set_position(lat, lng, alt)\n\n        dist = distance(\n            last_lat,\n            last_lng,\n            lat,\n            lng\n        )\n\n        self.emit_event(\n            'position_update',\n            formatted=\"Walking from {last_position} to {current_position}, distance left: ({distance} {distance_unit}) ..\",\n            data={\n                'last_position': (last_lat, last_lng, last_alt),\n                'current_position': (lat, lng, alt),\n                'distance': format_dist(dist,self.distance_unit,self.append_unit),\n                'distance_unit': self.distance_unit\n            }\n        )\n        \n        if (self.bot.config.walk_min > 0 and is_at_destination) or (self.status == STATUS_LOITERING and time.time() >= self.loiter_end_time):\n            if \"loiter\" in point and self.status != STATUS_LOITERING:\n                self.logger.info(\"Loitering for {} seconds...\".format(point[\"loiter\"]))\n                self.status = STATUS_LOITERING\n                self.loiter_end_time = time.time() + point[\"loiter\"]\n                return WorkerResult.RUNNING\n            if (self.ptr + 1) == len(self.points):\n                if self.path_mode == 'single':\n                    self.status = STATUS_FINISHED\n                    return WorkerResult.SUCCESS\n                self.ptr = 0\n                if self.path_mode == 'linear':\n                    self.points = list(reversed(self.points))\n                if self.number_lap_max >= 0:\n                    self.number_lap+=1\n                    self.emit_event(\n                        'path_lap_update',\n                        formatted=\"number lap : {number_lap} / {number_lap_max}\",\n                        data={\n                            'number_lap': str(self.number_lap),\n                            'number_lap_max': str(self.number_lap_max)\n                        }\n                    )\n                    if self.number_lap >= self.number_lap_max:\n                        self.endLaps()\n            else:\n                self.ptr += 1\n        \n        self.status = STATUS_MOVING\n        return WorkerResult.RUNNING\n", "path": "pokemongo_bot/cell_workers/follow_path.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\nfrom __future__ import absolute_import\nimport gpxpy\nimport gpxpy.gpx\nimport json\nimport time\nfrom pokemongo_bot.base_task import BaseTask\nfrom pokemongo_bot.cell_workers.utils import distance\nfrom pokemongo_bot.cell_workers.utils import format_dist\nfrom pokemongo_bot.cell_workers.utils import i2f\nfrom pokemongo_bot.human_behaviour import sleep\nfrom pokemongo_bot.walkers.walker_factory import walker_factory\nfrom pokemongo_bot.worker_result import WorkerResult\nfrom pgoapi.utilities import f2i\nfrom random import uniform\nfrom .utils import getSeconds, format_dist\nfrom datetime import datetime as dt, timedelta\n\nSTATUS_MOVING = 0\nSTATUS_WANDERING = 1\nSTATUS_FINISHED = 2\n \nclass FollowPath(BaseTask):\n    SUPPORTED_TASK_API_VERSION = 1\n\n    def initialize(self):\n        self._process_config()\n        self.points = self.load_path()\n        self.status = STATUS_MOVING\n        self.wander_end_time = 0\n        self.distance_unit = self.bot.config.distance_unit\n        self.append_unit = False\n\n        if self.path_start_mode == 'closest':\n            self.ptr = self.find_closest_point_idx(self.points)\n\n        else:\n            self.ptr = 0\n\n    def _process_config(self):\n        self.path_file = self.config.get(\"path_file\", None)\n        self.path_mode = self.config.get(\"path_mode\", \"linear\")\n        self.path_start_mode = self.config.get(\"path_start_mode\", \"first\")\n        self.number_lap_max = self.config.get(\"number_lap\", -1) # if < 0, then the number is inf.\n        self.timer_restart_min = getSeconds(self.config.get(\"timer_restart_min\", \"00:20:00\"))\n        self.timer_restart_max = getSeconds(self.config.get(\"timer_restart_max\", \"02:00:00\"))\n        self.walker = self.config.get('walker', 'StepWalker')\n\n        if self.timer_restart_min > self.timer_restart_max:\n            raise ValueError('path timer_restart_min is bigger than path timer_restart_max') #TODO there must be a more elegant way to do it...\n        \n        #var not related to configs\n        self.number_lap = 0\n        \n    def load_path(self):\n        if self.path_file is None:\n            raise RuntimeError('You need to specify a path file (json or gpx)')\n\n        if self.path_file.endswith('.json'):\n            return self.load_json()\n        elif self.path_file.endswith('.gpx'):\n            return self.load_gpx()\n\n    def load_json(self):\n        with open(self.path_file) as data_file:\n            points=json.load(data_file)\n        # Replace Verbal Location with lat&lng.\n        for _, point in enumerate(points):\n            point_tuple = self.bot.get_pos_by_name(point['location'])\n            self.emit_event(\n                'location_found',\n                level='debug',\n                formatted=\"Location found: {location} {position}\",\n                data={\n                    'location': point,\n                    'position': point_tuple\n                }\n            )\n            # Keep point['location']\n            point[\"lat\"] = float(point_tuple[0])\n            point[\"lng\"] = float(point_tuple[1])\n            point[\"alt\"] = float(point_tuple[2])\n        return points\n\n    def load_gpx(self):\n        gpx_file = open(self.path_file, 'r')\n        gpx = gpxpy.parse(gpx_file)\n\n        if len(gpx.tracks) == 0:\n            raise RuntimeError('GPX file does not contain a track')\n\n        points = []\n        track = gpx.tracks[0]\n        for segment in track.segments:\n            for point in segment.points:\n                points.append({\"lat\": point.latitude, \"lng\": point.longitude,\n                    \"alt\": point.elevation, \"location\": point.name})\n\n        return points\n\n    def find_closest_point_idx(self, points):\n        return_idx = 0\n        min_distance = float(\"inf\");\n        \n        for index in range(len(points)):\n            point = points[index]\n            lat = point['lat']\n            lng = point['lng']\n\n            dist = distance(\n                self.bot.position[0],\n                self.bot.position[1],\n                lat,\n                lng\n            )\n\n            if dist < min_distance:\n                min_distance = dist\n                return_idx = index\n\n        return return_idx\n\n    def endLaps(self):\n        duration = int(uniform(self.timer_restart_min, self.timer_restart_max))\n        resume = dt.now() + timedelta(seconds=duration)\n        \n        self.emit_event(\n            'path_lap_end',\n            formatted=\"Great job, lot of calories burned! Taking a break now for {duration}, will resume at {resume}.\",\n            data={\n                'duration': str(timedelta(seconds=duration)),\n                'resume': resume.strftime(\"%H:%M:%S\")\n            }\n        )\n        \n        self.number_lap = 0 # at the end of the break, start again\n        sleep(duration)\n        self.bot.login()\n\n    def work(self):\n        # If done or wandering allow the next task to run\n        if self.status == STATUS_FINISHED:\n            return WorkerResult.SUCCESS\n\n        if self.status == STATUS_WANDERING and time.time() < self.wander_end_time:\n            return WorkerResult.SUCCESS\n\n        last_lat, last_lng, last_alt = self.bot.position\n\n        point = self.points[self.ptr]\n        lat = point['lat']\n        lng = point['lng']\n\n        if 'alt' in point:\n            alt = float(point['alt'])\n        else:\n            alt = uniform(self.bot.config.alt_min, self.bot.config.alt_max)\n\n        if self.bot.config.walk_max > 0:\n            step_walker = walker_factory(self.walker,\n                self.bot,\n                lat,\n                lng,\n                alt\n            )\n\n            is_at_destination = False\n            if step_walker.step():\n                is_at_destination = True\n\n        else:\n            self.bot.api.set_position(lat, lng, alt)\n\n        dist = distance(\n            last_lat,\n            last_lng,\n            lat,\n            lng\n        )\n\n        self.emit_event(\n            'position_update',\n            formatted=\"Walking from {last_position} to {current_position}, distance left: ({distance} {distance_unit}) ..\",\n            data={\n                'last_position': (last_lat, last_lng, last_alt),\n                'current_position': (lat, lng, alt),\n                'distance': format_dist(dist,self.distance_unit,self.append_unit),\n                'distance_unit': self.distance_unit\n            }\n        )\n        \n        if (self.bot.config.walk_min > 0 and is_at_destination) or (self.status == STATUS_WANDERING and time.time() >= self.wander_end_time):\n            if \"loiter\" in point:\n                self.logger.warning(\"'loiter' is obsolete, please change to 'wander' in {}\".format(self.path_file))\n            if \"wander\" in point and self.status != STATUS_WANDERING:\n                self.logger.info(\"Wandering for {} seconds...\".format(point[\"wander\"]))\n                self.status = STATUS_WANDERING\n                self.wander_end_time = time.time() + point[\"wander\"]\n                return WorkerResult.SUCCESS\n            if (self.ptr + 1) == len(self.points):\n                if self.path_mode == 'single':\n                    self.status = STATUS_FINISHED\n                    return WorkerResult.SUCCESS\n                self.ptr = 0\n                if self.path_mode == 'linear':\n                    self.points = list(reversed(self.points))\n                if self.number_lap_max >= 0:\n                    self.number_lap+=1\n                    self.emit_event(\n                        'path_lap_update',\n                        formatted=\"number lap : {number_lap} / {number_lap_max}\",\n                        data={\n                            'number_lap': str(self.number_lap),\n                            'number_lap_max': str(self.number_lap_max)\n                        }\n                    )\n                    if self.number_lap >= self.number_lap_max:\n                        self.endLaps()\n            else:\n                self.ptr += 1\n        \n        self.status = STATUS_MOVING\n        return WorkerResult.RUNNING\n", "path": "pokemongo_bot/cell_workers/follow_path.py"}]}