From a2f82b31a7e298ee4fa09a12a7b1014bf0194245 Mon Sep 17 00:00:00 2001
From: Jan-Pascal van Best <janpascal@vanbest.org>
Date: Wed, 9 Nov 2016 02:32:56 +0100
Subject: [PATCH 1/6] Loiter new meaning (#5697)

* Implement loiter option in FollowPath, loitering meaning not moving at all

* More informative progress logging for FollowPath
---
 docs/configuration_files.md               | 16 +++++++++++++-
 pokemongo_bot/cell_workers/follow_path.py | 27 ++++++++++++++---------
 2 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/docs/configuration_files.md b/docs/configuration_files.md
index 27b14d4728..c897fc3227 100644
--- a/docs/configuration_files.md
+++ b/docs/configuration_files.md
@@ -883,7 +883,15 @@ This task is an upgrade version of the MoveToMapPokemon task. It will fetch poke
 ### Description
 [[back to top](#table-of-contents)]
 
-Walk to the specified locations loaded from .gpx or .json file. It is highly recommended to use website such as [GPSies](http://www.gpsies.com) which allow you to export your created track in JSON file. Note that you'll have to first convert its JSON file into the format that the bot can understand. See [Example of pier39.json] below for the content. I had created a simple python script to do the conversion.
+Walk to the specified locations loaded from .gpx or .json file. It is highly 
+recommended to use website such as [GPSies](http://www.gpsies.com) which allow 
+you to export your created track in JSON file. Note that you'll have to first 
+convert its JSON file into the format that the bot can understand. See [Example 
+of pier39.json] below for the content. I had created a simple python script to 
+do the conversion.
+
+The `location` fields in the `.json` file can also contain a street address. In
+this case the `location` is interpreted by the Google Maps API.
 
 The json file can contain for each point an optional `wander` field. This
 indicated the number of seconds the bot should wander after reaching the point.
@@ -891,6 +899,12 @@ During this time, the next Task in the configuration file is executed, e.g. a
 MoveToFort task. This allows the bot to walk around the waypoint looking for
 forts for a limited time.
 
+The `loiter` field, also optional for each point in the json file, works
+similarly to the `wander` field. The difference is that with `loiter` the 
+next `Task` in the configuration file is /not/ executed, meaning the bot 
+will wait, without moving, at the point in the json file with the `loiter` 
+option.
+
 ### Options
 [[back to top](#table-of-contents)]
 * `path_mode` - linear, loop, single
diff --git a/pokemongo_bot/cell_workers/follow_path.py b/pokemongo_bot/cell_workers/follow_path.py
index d0819531eb..6b3274c4b4 100644
--- a/pokemongo_bot/cell_workers/follow_path.py
+++ b/pokemongo_bot/cell_workers/follow_path.py
@@ -18,8 +18,9 @@
 from datetime import datetime as dt, timedelta
 
 STATUS_MOVING = 0
-STATUS_WANDERING = 1
-STATUS_FINISHED = 2
+STATUS_LOITERING = 1
+STATUS_WANDERING = 2
+STATUS_FINISHED = 3
  
 class FollowPath(BaseTask):
     SUPPORTED_TASK_API_VERSION = 1
@@ -28,7 +29,7 @@ def initialize(self):
         self._process_config()
         self.points = self.load_path()
         self.status = STATUS_MOVING
-        self.wander_end_time = 0
+        self.waiting_end_time = 0
         self.distance_unit = self.bot.config.distance_unit
         self.append_unit = False
 
@@ -143,8 +144,11 @@ def work(self):
         if self.status == STATUS_FINISHED:
             return WorkerResult.SUCCESS
 
-        if self.status == STATUS_WANDERING and time.time() < self.wander_end_time:
-            return WorkerResult.SUCCESS
+        if time.time() < self.waiting_end_time:
+            if self.status == STATUS_WANDERING:
+                return WorkerResult.SUCCESS
+            elif self.status == STATUS_LOITERING:
+                return WorkerResult.RUNNING
 
         last_lat, last_lng, last_alt = self.bot.position
 
@@ -184,19 +188,22 @@ def work(self):
             formatted="Walking from {last_position} to {current_position}, distance left: ({distance} {distance_unit}) ..",
             data={
                 'last_position': (last_lat, last_lng, last_alt),
-                'current_position': (lat, lng, alt),
+                'current_position': point["location"],
                 'distance': format_dist(dist,self.distance_unit,self.append_unit),
                 'distance_unit': self.distance_unit
             }
         )
         
-        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 (self.bot.config.walk_min > 0 and is_at_destination) or (self.status in [STATUS_WANDERING, STATUS_LOITERING] and time.time() >= self.waiting_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.waiting_end_time = time.time() + point["loiter"]
+                return WorkerResult.RUNNING
             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"]
+                self.waiting_end_time = time.time() + point["wander"]
                 return WorkerResult.SUCCESS
             if (self.ptr + 1) == len(self.points):
                 if self.path_mode == 'single':

From e4b73f85c0d8b9c09f99d4333f1645650baca6ae Mon Sep 17 00:00:00 2001
From: mudmud2k <mudmud2k@mt2015.com>
Date: Wed, 9 Nov 2016 02:36:32 +0100
Subject: [PATCH 2/6] pokecli.py: wait_time for every exception randomized
 (#5704)

* pokecli.py: wait_time for every exception randomized

randint(min,max)
config.reconnecting -> min
config.reconnection * 60 -> max

* randint(timeout * 0.8 * 60, timeout * 1.2 * 60; docs update
---
 docs/configuration_files.md | 23 ++++++++++++-----------
 pokecli.py                  | 11 ++++++-----
 2 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/docs/configuration_files.md b/docs/configuration_files.md
index c897fc3227..2c1b663388 100644
--- a/docs/configuration_files.md
+++ b/docs/configuration_files.md
@@ -84,7 +84,7 @@ Document the configuration options of PokemonGo-Bot.
 | `action_wait_min`   | 1       | Set the minimum time setting for anti-ban time randomizer
 | `action_wait_max`   | 4       | Set the maximum time setting for anti-ban time randomizer
 | `debug`            | false   | Let the default value here except if you are developer                                                                                                                                      |
-| `test`             | false   | Let the default value here except if you are developer                                                                                                                                      |  
+| `test`             | false   | Let the default value here except if you are developer                                                                                                                                      |
 | `walker_limit_output`             | false   | Reduce output from walker functions                                                                                                                                      |                                                                                       |
 | `location_cache`   | true    | Bot will start at last known location if you do not have location set in the config                                                                                                         |
 | `distance_unit`    | km      | Set the unit to display distance in (km for kilometers, mi for miles, ft for feet)                                                                                                          |
@@ -97,6 +97,7 @@ Document the configuration options of PokemonGo-Bot.
 | `live_config_update.enabled`            | false     | Enable live config update
 | `live_config_update.tasks_only`            | false     | True: quick update for Tasks only (without re-login). False: slower update for entire config file.
 | `enable_social`            | true     | True: to chat with other pokemon go bot users [more information](https://github.com/PokemonGoF/PokemonGo-Bot/pull/4596)
+| `reconnecting_timeout`   |  5      | Set the wait time for the bot between tries, time will be randomized by 40%
 
 ## Logging configuration
 [[back to top](#table-of-contents)]
@@ -163,7 +164,7 @@ The behaviors of the bot are configured via the `tasks` key in the `config.json`
 ### Task Options:
 [[back to top](#table-of-contents)]
 * CatchPokemon
-  * `enabled`: Default "true" | Enable/Disable the task. 
+  * `enabled`: Default "true" | Enable/Disable the task.
   * `treat_unseen_as_vip`: Default `"true"` | If true, treat new to dex as VIP
   * `catch_visible_pokemon`:  Default "true" | If enabled, attempts to catch "visible" pokemon that are reachable
   * `catch_lured_pokemon`: Default "true" | If enabled, attempts to catch "lured" pokemon that are reachable
@@ -201,7 +202,7 @@ The behaviors of the bot are configured via the `tasks` key in the `config.json`
   * `log_interval`: `Default: 120`. Time (in seconds) to periodically print how far you are from having enough pokemon to evolve (more than `min_pokemon_to_be_evolved`)
   * `evolve_list`: Default `all` | Set to all, or specifiy different pokemon seperated by a comma
   * `donot_evolve_list`: Default `none` | Pokemon seperated by comma, will be ignored from evolve_list
-  * `min_evolve_speed`: Default `25` | Minimum seconds to wait between each evolution 
+  * `min_evolve_speed`: Default `25` | Minimum seconds to wait between each evolution
   * `max_evolve_speed`: Default `30` | Maximum seconds to wait between each evolution
   * `min_pokemon_to_be_evolved`: Default: `1` | Minimum pokemon to be evolved
   * `use_lucky_egg`: Default: `False` | Only evolve if we can use a lucky egg
@@ -220,8 +221,8 @@ The behaviors of the bot are configured via the `tasks` key in the `config.json`
 * IncubateEggs
   * `enable`: Disable or enable this task.
   * `longer_eggs_first`: Depreciated
-  * `infinite_longer_eggs_first`:  Default `true` | Prioritize longer eggs in perminent incubators. 
-  * `breakable_longer_eggs_first`:  Default `false` | Prioritize longer eggs in breakable incubators. 
+  * `infinite_longer_eggs_first`:  Default `true` | Prioritize longer eggs in perminent incubators.
+  * `breakable_longer_eggs_first`:  Default `false` | Prioritize longer eggs in breakable incubators.
   * `min_interval`: Default `120` | Minimum number of seconds between incubation updates.
   * `infinite`: Default `[2,5,10]` | Types of eggs to be incubated in permanent incubators.
   * `breakable`: Default `[2,5,10]` | Types of eggs to be incubated in breakable incubators.
@@ -276,10 +277,10 @@ The behaviors of the bot are configured via the `tasks` key in the `config.json`
   * `level_limit`: Default `-1` | Bot will stop automatically after trainer reaches level limit. Set to `-1` to disable.
 * All tasks
   * `log_interval`: Default `0` | Minimum seconds interval before next log of the current task will be printed
-  
-  
+
+
 ### Specify a custom log_interval for specific task
-  
+
   ```
     {
       "type": "MoveToFort",
@@ -292,9 +293,9 @@ The behaviors of the bot are configured via the `tasks` key in the `config.json`
       }
     }
    ```
-      
+
    Result:
-    
+
     2016-08-26 11:43:18,199 [MoveToFort] [INFO] [moving_to_fort] Moving towards pokestop ... - 0.07km
     2016-08-26 11:43:23,641 [MoveToFort] [INFO] [moving_to_fort] Moving towards pokestop ... - 0.06km
     2016-08-26 11:43:28,198 [MoveToFort] [INFO] [moving_to_fort] Moving towards pokestop ... - 0.05km
@@ -917,7 +918,7 @@ option.
 * `path_file` - "/path/to/your/path.json"
 
 ### Notice
-If you use the `single` `path_mode` without e.g. a `MoveToFort` task, your bot 
+If you use the `single` `path_mode` without e.g. a `MoveToFort` task, your bot
 with /not move at all/ when the path is finished. Similarly, if you use the
 `wander` option in your json path file without a following `MoveToFort` or
 similar task, your bot will not move during the wandering period. Please
diff --git a/pokecli.py b/pokecli.py
index d3c9353956..36df60566c 100644
--- a/pokecli.py
+++ b/pokecli.py
@@ -40,6 +40,7 @@
 import subprocess
 
 from logging import Formatter
+from random import randint
 
 codecs.register(lambda name: codecs.lookup("utf-8") if name == "cp65001" else None)
 
@@ -185,7 +186,7 @@ def get_commit_hash():
         finished = False
 
         while not finished:
-            wait_time = config.reconnecting_timeout * 60
+            wait_time = randint((config.reconnecting_timeout * 0.8 * 60), (config.reconnecting_timeout *  1.2 * 60))
             try:
                 bot = initialize(config)
                 bot = start_bot(bot, config)
@@ -233,7 +234,7 @@ def get_commit_hash():
                     'api_error',
                     sender=bot,
                     level='info',
-                    formatted='Server busy or offline'
+                    formatted='Server busy or offline, reconnecting in {:d} seconds'.format(wait_time)
                 )
                 time.sleep(wait_time)
             except ServerSideRequestThrottlingException:
@@ -241,9 +242,9 @@ def get_commit_hash():
                     'api_error',
                     sender=bot,
                     level='info',
-                    formatted='Server is throttling, reconnecting in 30 seconds'
+                    formatted='Server is throttling, reconnecting in {:d} seconds'.format(wait_time)
                 )
-                time.sleep(30)
+                time.sleep(wait_time)
             except PermaBannedException:
                 bot.event_manager.emit(
                     'api_error',
@@ -257,7 +258,7 @@ def get_commit_hash():
                     'api_error',
                     sender=bot,
                     level='info',
-                    formatted='No player position set'
+                    formatted='No player position set, reconnecting in {:d} seconds'.format(wait_time)
                 )
                 time.sleep(wait_time)
 

From 58c236120f16265b0f1d4c6e1397dfb87581bf35 Mon Sep 17 00:00:00 2001
From: Stuart Travers <gobberwart@gmail.com>
Date: Thu, 10 Nov 2016 07:57:48 +1100
Subject: [PATCH 3/6] Fix ValueError crash

ValueError, "non-integer arg 1 for randrange()"
---
 pokecli.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/pokecli.py b/pokecli.py
index 36df60566c..f80dfc5edc 100644
--- a/pokecli.py
+++ b/pokecli.py
@@ -186,7 +186,9 @@ def get_commit_hash():
         finished = False
 
         while not finished:
-            wait_time = randint((config.reconnecting_timeout * 0.8 * 60), (config.reconnecting_timeout *  1.2 * 60))
+            min_wait_time = int(config.reconnecting_timeout * 0.8 * 60)
+            max_wait_time = int(config.reconnecting_timeout *  1.2 * 60)
+            wait_time = randint(min_wait_time, max_wait_time)
             try:
                 bot = initialize(config)
                 bot = start_bot(bot, config)

From f6fec583f1ef53fa82586cb2653503555e329250 Mon Sep 17 00:00:00 2001
From: Stuart Travers <Gobberwart@users.noreply.github.com>
Date: Fri, 11 Nov 2016 05:28:59 +1100
Subject: [PATCH 4/6] Fix hash/encrypt library searching (#5804)

* Corrected maxos niantic lib filename

Filename is libniantichash-macos-64.dylib not libniantichash-osx-64.so

* Better search for encrypt/hash files

Instead of just looking in root, or encrypt_location, or whatever the
heck the last person did... will first search local or encrypt_location.
If not found, will search pgoapi/lib. If still not found, abort.
---
 pokemongo_bot/__init__.py | 42 +++++++++++++++++++++++----------------
 requirements.txt          |  2 +-
 2 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/pokemongo_bot/__init__.py b/pokemongo_bot/__init__.py
index c0a27effe4..b3f497ec3b 100644
--- a/pokemongo_bot/__init__.py
+++ b/pokemongo_bot/__init__.py
@@ -979,25 +979,29 @@ def get_encryption_lib(self):
         if _platform == "Windows" or _platform == "win32":
             # Check if we are on 32 or 64 bit
             if sys.maxsize > 2**32:
-                file_name = 'src/pgoapi/pgoapi/lib/encrypt64.dll'
+                file_name = 'encrypt64.dll'
             else:
-                file_name = 'src/pgoapi/pgoapi/lib/encrypt32.dll'
+                file_name = 'encrypt32.dll'
         if _platform.lower() == "darwin":
-            file_name= 'src/pgoapi/pgoapi/lib/libencrypt-osx-64.so'
+            file_name= 'libencrypt-osx-64.so'
         if _platform.lower() == "linux" or _platform.lower() == "linux2":
-            file_name = 'src/pgoapi/pgoapi/lib/libencrypt-linux-x86-64.so'
+            file_name = 'libencrypt-linux-x86-64.so'
         if self.config.encrypt_location == '':
             path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
         else:
             path = self.config.encrypt_location
 
-        full_path = path + '/'+ file_name
-        if not os.path.isfile(full_path):
+        full_path = ''
+        if os.path.isfile(path + '/' + file_name): # check encrypt_location or local dir first
+            full_path = path + '/' + file_name
+        elif os.path.isfile(path + '/src/pgoapi/pgoapi/lib/' + file_name): # if not found, check pgoapi lib folder
+            full_path = path + '/src/pgoapi/pgoapi/lib/' + file_name
+            
+        if full_path == '':
             self.logger.error(file_name + ' is not found! Please place it in the bots root directory or set encrypt_location in config.')
-            self.logger.info('Platform: '+ _platform + ' ' + file_name + ' directory: '+ path)
             sys.exit(1)
         else:
-            self.logger.info('Found '+ file_name +'! Platform: ' + _platform + ' ' + file_name + ' directory: ' + path)
+            self.logger.info('Found '+ file_name +'! Platform: ' + _platform + ' ' + file_name + ' directory: ' + full_path)
 
         return full_path
 
@@ -1005,25 +1009,29 @@ def get_hash_lib(self):
         if _platform == "Windows" or _platform == "win32":
             # Check if we are on 32 or 64 bit
             if sys.maxsize > 2**32:
-                file_name = 'src/pgoapi/pgoapi/lib/niantichash64.dll'
+                file_name = 'niantichash64.dll'
             else:
-                file_name = 'src/pgoapi/pgoapi/lib/niantichash32.dll'
+                file_name = 'niantichash32.dll'
         if _platform.lower() == "darwin":
-            file_name= 'src/pgoapi/pgoapi/lib/libniantichash-osx-64.so'
+            file_name= 'libniantichash-macos-64.dylib'
         if _platform.lower() == "linux" or _platform.lower() == "linux2":
-            file_name = 'src/pgoapi/pgoapi/lib/libniantichash-linux-x86-64.so'
+            file_name = 'libniantichash-linux-x86-64.so'
         if self.config.encrypt_location == '':
             path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
         else:
             path = self.config.encrypt_location
 
-        full_path = path + '/'+ file_name
-        if not os.path.isfile(full_path):
-            self.logger.error(file_name + ' is not found! Please place it in the bots root directory')
-            self.logger.info('Platform: '+ _platform + ' ' + file_name + ' directory: '+ path)
+        full_path = ''
+        if os.path.isfile(path + '/' + file_name): # check encrypt_location or local dir first
+            full_path = path + '/'+ file_name
+        elif os.path.isfile(path + '/src/pgoapi/pgoapi/lib/' + file_name): # if not found, check pgoapi lib folder
+            full_path = path + '/src/pgoapi/pgoapi/lib/' + file_name
+            
+        if full_path == '':
+            self.logger.error(file_name + ' is not found! Please place it in the bots root directory or set encrypt_location in config.')
             sys.exit(1)
         else:
-            self.logger.info('Found '+ file_name +'! Platform: ' + _platform + ' ' + file_name + ' directory: ' + path)
+            self.logger.info('Found '+ file_name +'! Platform: ' + _platform + ' ' + file_name + ' directory: ' + full_path)
 
         return full_path
 
diff --git a/requirements.txt b/requirements.txt
index 8f0a4ea255..74aee95ae5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,6 @@
 numpy==1.11.0
 networkx==1.11
--e git+https://github.com/pogodevorg/pgoapi.git/@v0.43.3-alpha#egg=pgoapi
+-e git+https://github.com/sebastienvercammen/pgoapi.git#egg=pgoapi
 geopy==1.11.0
 geographiclib==1.46.3
 protobuf==3.0.0b4

From d6fbe9e67abda4c614f3d2edfbd63867a966b0bf Mon Sep 17 00:00:00 2001
From: Simba Zhang <solderzzc@users.noreply.github.com>
Date: Sat, 12 Nov 2016 21:03:54 -0800
Subject: [PATCH 5/6] Update to the 0.45 of offical API.

---
 pokemongo_bot/__init__.py | 17 ++++++++---------
 requirements.txt          |  2 +-
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/pokemongo_bot/__init__.py b/pokemongo_bot/__init__.py
index b3f497ec3b..08cac0b70b 100644
--- a/pokemongo_bot/__init__.py
+++ b/pokemongo_bot/__init__.py
@@ -122,7 +122,7 @@ def __init__(self, db, config):
         self.inventory_refresh_threshold = 10
         self.inventory_refresh_counter = 0
         self.last_inventory_refresh = time.time()
-        
+
         # Catch on/off
         self.catch_disabled = False
 
@@ -167,7 +167,7 @@ def _setup_event_system(self):
             if self.config.websocket_start_embedded_server:
                 self.sio_runner = SocketIoRunner(self.config.websocket_server_url)
                 self.sio_runner.start_listening_async()
-        
+
             websocket_handler = SocketIoHandler(
                 self,
                 self.config.websocket_server_url
@@ -738,11 +738,11 @@ def _register_events(self):
         self.event_manager.register_event('sniper_log', parameters=('message', 'message'))
         self.event_manager.register_event('sniper_error', parameters=('message', 'message'))
         self.event_manager.register_event('sniper_teleporting', parameters=('latitude', 'longitude', 'name'))
-        
+
         # Catch-limiter
         self.event_manager.register_event('catch_limit_on')
         self.event_manager.register_event('catch_limit_off')
-        
+
 
     def tick(self):
         self.health_record.heartbeat()
@@ -996,7 +996,7 @@ def get_encryption_lib(self):
             full_path = path + '/' + file_name
         elif os.path.isfile(path + '/src/pgoapi/pgoapi/lib/' + file_name): # if not found, check pgoapi lib folder
             full_path = path + '/src/pgoapi/pgoapi/lib/' + file_name
-            
+
         if full_path == '':
             self.logger.error(file_name + ' is not found! Please place it in the bots root directory or set encrypt_location in config.')
             sys.exit(1)
@@ -1026,7 +1026,7 @@ def get_hash_lib(self):
             full_path = path + '/'+ file_name
         elif os.path.isfile(path + '/src/pgoapi/pgoapi/lib/' + file_name): # if not found, check pgoapi lib folder
             full_path = path + '/src/pgoapi/pgoapi/lib/' + file_name
-            
+
         if full_path == '':
             self.logger.error(file_name + ' is not found! Please place it in the bots root directory or set encrypt_location in config.')
             sys.exit(1)
@@ -1045,8 +1045,8 @@ def _setup_api(self):
         self.login()
         # chain subrequests (methods) into one RPC call
 
-        self.api.set_signature_lib(self.get_encryption_lib())
-        self.api.set_hash_lib(self.get_hash_lib())
+        #self.api.set_signature_lib(self.get_encryption_lib())
+        #self.api.set_hash_lib(self.get_hash_lib())
 
         self.logger.info('')
         # send empty map_cells and then our position
@@ -1540,4 +1540,3 @@ def _refresh_inventory(self):
             inventory.refresh_inventory()
             self.last_inventory_refresh = now
             self.inventory_refresh_counter += 1
-
diff --git a/requirements.txt b/requirements.txt
index 74aee95ae5..fc7af4ddd9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,6 @@
 numpy==1.11.0
 networkx==1.11
--e git+https://github.com/sebastienvercammen/pgoapi.git#egg=pgoapi
+-e git+https://github.com/pogodevorg/pgoapi#egg=pgoapi
 geopy==1.11.0
 geographiclib==1.46.3
 protobuf==3.0.0b4

From 71e1f268237af267183e9869b4e7bc5a199c6af0 Mon Sep 17 00:00:00 2001
From: Simba Zhang <solderzzc@users.noreply.github.com>
Date: Sat, 12 Nov 2016 21:09:10 -0800
Subject: [PATCH 6/6] updated to .git of pgoapi.

---
 requirements.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/requirements.txt b/requirements.txt
index fc7af4ddd9..62c16aae25 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,6 @@
 numpy==1.11.0
 networkx==1.11
--e git+https://github.com/pogodevorg/pgoapi#egg=pgoapi
+-e git+https://github.com/pogodevorg/pgoapi.git#egg=pgoapi
 geopy==1.11.0
 geographiclib==1.46.3
 protobuf==3.0.0b4