We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
keep_best_iv should order by iv then cp
### Expected Behavior

If we have 3 pokemon of a type and wanted to keep the 2 best IV and two pokemon have the same low IV, we would like to keep the one with max CP
### Actual Behavior

[20:25:39] Keep 2 best Slowpoke, based on iv
[20:25:39] Slowpoke [CP 274] [Potential 0.56]
[20:25:39] Slowpoke [CP 172] [Potential 0.51]
[20:25:39] Exchange 1 pokemon(s)
[20:25:39] Exchanging Slowpoke [CP 392] [Potential 0.51] for candy!
### Steps to Reproduce

Farm pokemon and have some luck :)
### Other Information

OS: OSX 
Git Commit: (run 'git log -n 1 --pretty=format:"%H"' and paste it here)
34caa002a464b7665cdcfb531ea3d302632898ac


--- 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/pokemon_transfer_worker.py`
Content:
```
1 import json
2 
3 from pokemongo_bot.human_behaviour import sleep, action_delay
4 from pokemongo_bot import logger
5 
6 class PokemonTransferWorker(object):
7 
8     def __init__(self, bot):
9         self.config = bot.config
10         self.pokemon_list = bot.pokemon_list
11         self.api = bot.api
12         self.bot = bot
13 
14     def work(self):
15         if not self.config.release_pokemon:
16             return
17 
18         pokemon_groups = self._release_pokemon_get_groups()
19         for pokemon_id in pokemon_groups:
20             group = pokemon_groups[pokemon_id]
21 
22             if len(group) > 1:
23                 pokemon_name = self.pokemon_list[pokemon_id - 1]['Name']
24                 keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)
25 
26                 if keep_best:
27                     order_criteria = 'cp'
28                     limit = keep_best_cp
29 
30                     if keep_best_iv >= 1:
31                         order_criteria = 'iv'
32                         limit = keep_best_iv
33 
34                     best_pokemons = sorted(group, key=lambda x: x[order_criteria], reverse=True)[:limit]
35 
36                     # remove best pokemons from all pokemons array
37                     all_pokemons = group
38                     for best_pokemon in best_pokemons:
39                         for pokemon in all_pokemons:
40                             if best_pokemon['pokemon_data']['id'] == pokemon['pokemon_data']['id']:
41                                 all_pokemons.remove(pokemon)
42 
43                     if best_pokemons and all_pokemons:
44                         logger.log("Keep {} best {}, based on {}".format(len(best_pokemons),
45                                                                          pokemon_name,
46                                                                          order_criteria), "green")
47                         for best_pokemon in best_pokemons:
48                             logger.log("{} [CP {}] [Potential {}]".format(pokemon_name,
49                                                                           best_pokemon['cp'],
50                                                                           best_pokemon['iv']), 'green')
51 
52                         logger.log("Exchange {} pokemon(s)".format(len(all_pokemons)), "green")
53 
54                     for pokemon in all_pokemons:
55                         self.release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv'], pokemon['pokemon_data']['id'])
56                 else:
57                     group = sorted(group, key=lambda x: x['cp'], reverse=True)
58                     for item in group:
59                         pokemon_cp = item['cp']
60                         pokemon_potential = item['iv']
61 
62                         if self.should_release_pokemon(pokemon_name, pokemon_cp, pokemon_potential):
63                             self.release_pokemon(pokemon_name, item['cp'], item['iv'], item['pokemon_data']['id'])
64 
65     def _release_pokemon_get_groups(self):
66         pokemon_groups = {}
67         self.api.get_player().get_inventory()
68         inventory_req = self.api.call()
69 
70         if inventory_req.get('responses', False) is False:
71             return pokemon_groups
72 
73         inventory_dict = inventory_req['responses']['GET_INVENTORY']['inventory_delta']['inventory_items']
74 
75         user_web_inventory = 'web/inventory-%s.json' % (self.config.username)
76         with open(user_web_inventory, 'w') as outfile:
77             json.dump(inventory_dict, outfile)
78 
79         for pokemon in inventory_dict:
80             try:
81                 reduce(dict.__getitem__, [
82                     "inventory_item_data", "pokemon_data", "pokemon_id"
83                 ], pokemon)
84             except KeyError:
85                 continue
86 
87             pokemon_data = pokemon['inventory_item_data']['pokemon_data']
88             group_id = pokemon_data['pokemon_id']
89             group_pokemon_cp = pokemon_data['cp']
90             group_pokemon_iv = self.get_pokemon_potential(pokemon_data)
91 
92             if group_id not in pokemon_groups:
93                 pokemon_groups[group_id] = []
94 
95             pokemon_groups[group_id].append({
96                 'cp': group_pokemon_cp,
97                 'iv': group_pokemon_iv,
98                 'pokemon_data': pokemon_data
99             })
100 
101         return pokemon_groups
102 
103     def get_pokemon_potential(self, pokemon_data):
104         total_iv = 0
105         iv_stats = ['individual_attack', 'individual_defense', 'individual_stamina']
106         for individual_stat in iv_stats:
107             try:
108                 total_iv += pokemon_data[individual_stat]
109             except Exception:
110                 continue
111         return round((total_iv / 45.0), 2)
112 
113     def should_release_pokemon(self, pokemon_name, cp, iv):
114         release_config = self._get_release_config_for(pokemon_name)
115         cp_iv_logic = release_config.get('logic')
116         if not cp_iv_logic:
117             cp_iv_logic = self._get_release_config_for('any').get('logic', 'and')
118 
119         release_results = {
120             'cp': False,
121             'iv': False,
122         }
123 
124         if release_config.get('never_release', False):
125             return False
126 
127         if release_config.get('always_release', False):
128             return True
129 
130         release_cp = release_config.get('release_below_cp', 0)
131         if cp < release_cp:
132             release_results['cp'] = True
133 
134         release_iv = release_config.get('release_below_iv', 0)
135         if iv < release_iv:
136             release_results['iv'] = True
137 
138         logic_to_function = {
139             'or': lambda x, y: x or y,
140             'and': lambda x, y: x and y
141         }
142 
143         if logic_to_function[cp_iv_logic](*release_results.values()):
144             logger.log(
145                 "Releasing {} with CP {} and IV {}. Matching release rule: CP < {} {} IV < {}. ".format(
146                     pokemon_name,
147                     cp,
148                     iv,
149                     release_cp,
150                     cp_iv_logic.upper(),
151                     release_iv
152                 ), 'yellow'
153             )
154 
155         return logic_to_function[cp_iv_logic](*release_results.values())
156 
157     def release_pokemon(self, pokemon_name, cp, iv, pokemon_id):
158         logger.log('Exchanging {} [CP {}] [Potential {}] for candy!'.format(pokemon_name,
159                                                                             cp,
160                                                                             iv), 'green')
161         self.api.release_pokemon(pokemon_id=pokemon_id)
162         response_dict = self.api.call()
163         action_delay(self.config.action_wait_min, self.config.action_wait_max)
164 
165     def _get_release_config_for(self, pokemon):
166         release_config = self.config.release.get(pokemon)
167         if not release_config:
168             release_config = self.config.release.get('any')
169         if not release_config:
170             release_config = {}
171         return release_config
172 
173     def _validate_keep_best_config(self, pokemon_name):
174         keep_best = False
175 
176         release_config = self._get_release_config_for(pokemon_name)
177 
178         keep_best_cp = release_config.get('keep_best_cp', 0)
179         keep_best_iv = release_config.get('keep_best_iv', 0)
180 
181         if keep_best_cp or keep_best_iv:
182             keep_best = True
183             try:
184                 keep_best_cp = int(keep_best_cp)
185             except ValueError:
186                 keep_best_cp = 0
187 
188             try:
189                 keep_best_iv = int(keep_best_iv)
190             except ValueError:
191                 keep_best_iv = 0
192 
193             if keep_best_cp > 1 and keep_best_iv > 1:
194                 logger.log("keep_best_cp and keep_best_iv can't be > 0 at the same time. Ignore it.", "red")
195                 keep_best = False
196 
197             if keep_best_cp < 0 or keep_best_iv < 0:
198                 logger.log("Keep best can't be < 0. Ignore it.", "red")
199                 keep_best = False
200 
201             if keep_best_cp == 0 and keep_best_iv == 0:
202                 keep_best = False
203 
204         return keep_best, keep_best_cp, keep_best_iv
205
```
--- 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/pokemon_transfer_worker.py b/pokemongo_bot/cell_workers/pokemon_transfer_worker.py
--- a/pokemongo_bot/cell_workers/pokemon_transfer_worker.py
+++ b/pokemongo_bot/cell_workers/pokemon_transfer_worker.py
@@ -3,6 +3,7 @@
 from pokemongo_bot.human_behaviour import sleep, action_delay
 from pokemongo_bot import logger
 
+
 class PokemonTransferWorker(object):
 
     def __init__(self, bot):
@@ -24,21 +25,31 @@
                 keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)
 
                 if keep_best:
-                    order_criteria = 'cp'
-                    limit = keep_best_cp
+                    best_pokemon_ids = set()
+                    order_criteria = 'none'
+                    if keep_best_cp >= 1:
+                        cp_limit = keep_best_cp
+                        best_cp_pokemons = sorted(group, key=lambda x: (x['cp'], x['iv']), reverse=True)[:cp_limit]
+                        best_pokemon_ids = set(pokemon['pokemon_data']['id'] for pokemon in best_cp_pokemons)
+                        order_criteria = 'cp'
 
                     if keep_best_iv >= 1:
-                        order_criteria = 'iv'
-                        limit = keep_best_iv
-
-                    best_pokemons = sorted(group, key=lambda x: x[order_criteria], reverse=True)[:limit]
+                        iv_limit = keep_best_iv
+                        best_iv_pokemons = sorted(group, key=lambda x: (x['iv'], x['cp']), reverse=True)[:iv_limit]
+                        best_pokemon_ids |= set(pokemon['pokemon_data']['id'] for pokemon in best_iv_pokemons)
+                        if order_criteria == 'cp':
+                            order_criteria = 'cp and iv'
+                        else:
+                            order_criteria = 'iv'
 
                     # remove best pokemons from all pokemons array
                     all_pokemons = group
-                    for best_pokemon in best_pokemons:
+                    best_pokemons = []
+                    for best_pokemon_id in best_pokemon_ids:
                         for pokemon in all_pokemons:
-                            if best_pokemon['pokemon_data']['id'] == pokemon['pokemon_data']['id']:
+                            if best_pokemon_id == pokemon['pokemon_data']['id']:
                                 all_pokemons.remove(pokemon)
+                                best_pokemons.append(pokemon)
 
                     if best_pokemons and all_pokemons:
                         logger.log("Keep {} best {}, based on {}".format(len(best_pokemons),
@@ -190,10 +201,6 @@
             except ValueError:
                 keep_best_iv = 0
 
-            if keep_best_cp > 1 and keep_best_iv > 1:
-                logger.log("keep_best_cp and keep_best_iv can't be > 0 at the same time. Ignore it.", "red")
-                keep_best = False
-
             if keep_best_cp < 0 or keep_best_iv < 0:
                 logger.log("Keep best can't be < 0. Ignore it.", "red")
                 keep_best = False

{"golden_diff": "diff --git a/pokemongo_bot/cell_workers/pokemon_transfer_worker.py b/pokemongo_bot/cell_workers/pokemon_transfer_worker.py\n--- a/pokemongo_bot/cell_workers/pokemon_transfer_worker.py\n+++ b/pokemongo_bot/cell_workers/pokemon_transfer_worker.py\n@@ -3,6 +3,7 @@\n from pokemongo_bot.human_behaviour import sleep, action_delay\n from pokemongo_bot import logger\n \n+\n class PokemonTransferWorker(object):\n \n     def __init__(self, bot):\n@@ -24,21 +25,31 @@\n                 keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)\n \n                 if keep_best:\n-                    order_criteria = 'cp'\n-                    limit = keep_best_cp\n+                    best_pokemon_ids = set()\n+                    order_criteria = 'none'\n+                    if keep_best_cp >= 1:\n+                        cp_limit = keep_best_cp\n+                        best_cp_pokemons = sorted(group, key=lambda x: (x['cp'], x['iv']), reverse=True)[:cp_limit]\n+                        best_pokemon_ids = set(pokemon['pokemon_data']['id'] for pokemon in best_cp_pokemons)\n+                        order_criteria = 'cp'\n \n                     if keep_best_iv >= 1:\n-                        order_criteria = 'iv'\n-                        limit = keep_best_iv\n-\n-                    best_pokemons = sorted(group, key=lambda x: x[order_criteria], reverse=True)[:limit]\n+                        iv_limit = keep_best_iv\n+                        best_iv_pokemons = sorted(group, key=lambda x: (x['iv'], x['cp']), reverse=True)[:iv_limit]\n+                        best_pokemon_ids |= set(pokemon['pokemon_data']['id'] for pokemon in best_iv_pokemons)\n+                        if order_criteria == 'cp':\n+                            order_criteria = 'cp and iv'\n+                        else:\n+                            order_criteria = 'iv'\n \n                     # remove best pokemons from all pokemons array\n                     all_pokemons = group\n-                    for best_pokemon in best_pokemons:\n+                    best_pokemons = []\n+                    for best_pokemon_id in best_pokemon_ids:\n                         for pokemon in all_pokemons:\n-                            if best_pokemon['pokemon_data']['id'] == pokemon['pokemon_data']['id']:\n+                            if best_pokemon_id == pokemon['pokemon_data']['id']:\n                                 all_pokemons.remove(pokemon)\n+                                best_pokemons.append(pokemon)\n \n                     if best_pokemons and all_pokemons:\n                         logger.log(\"Keep {} best {}, based on {}\".format(len(best_pokemons),\n@@ -190,10 +201,6 @@\n             except ValueError:\n                 keep_best_iv = 0\n \n-            if keep_best_cp > 1 and keep_best_iv > 1:\n-                logger.log(\"keep_best_cp and keep_best_iv can't be > 0 at the same time. Ignore it.\", \"red\")\n-                keep_best = False\n-\n             if keep_best_cp < 0 or keep_best_iv < 0:\n                 logger.log(\"Keep best can't be < 0. Ignore it.\", \"red\")\n                 keep_best = False\n", "issue": "keep_best_iv should order by iv then cp\n### Expected Behavior\n\nIf we have 3 pokemon of a type and wanted to keep the 2 best IV and two pokemon have the same low IV, we would like to keep the one with max CP\n### Actual Behavior\n\n[20:25:39] Keep 2 best Slowpoke, based on iv\n[20:25:39] Slowpoke [CP 274] [Potential 0.56]\n[20:25:39] Slowpoke [CP 172] [Potential 0.51]\n[20:25:39] Exchange 1 pokemon(s)\n[20:25:39] Exchanging Slowpoke [CP 392] [Potential 0.51] for candy!\n### Steps to Reproduce\n\nFarm pokemon and have some luck :)\n### Other Information\n\nOS: OSX \nGit Commit: (run 'git log -n 1 --pretty=format:\"%H\"' and paste it here)\n34caa002a464b7665cdcfb531ea3d302632898ac\n\n", "before_files": [{"content": "import json\n\nfrom pokemongo_bot.human_behaviour import sleep, action_delay\nfrom pokemongo_bot import logger\n\nclass PokemonTransferWorker(object):\n\n    def __init__(self, bot):\n        self.config = bot.config\n        self.pokemon_list = bot.pokemon_list\n        self.api = bot.api\n        self.bot = bot\n\n    def work(self):\n        if not self.config.release_pokemon:\n            return\n\n        pokemon_groups = self._release_pokemon_get_groups()\n        for pokemon_id in pokemon_groups:\n            group = pokemon_groups[pokemon_id]\n\n            if len(group) > 1:\n                pokemon_name = self.pokemon_list[pokemon_id - 1]['Name']\n                keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)\n\n                if keep_best:\n                    order_criteria = 'cp'\n                    limit = keep_best_cp\n\n                    if keep_best_iv >= 1:\n                        order_criteria = 'iv'\n                        limit = keep_best_iv\n\n                    best_pokemons = sorted(group, key=lambda x: x[order_criteria], reverse=True)[:limit]\n\n                    # remove best pokemons from all pokemons array\n                    all_pokemons = group\n                    for best_pokemon in best_pokemons:\n                        for pokemon in all_pokemons:\n                            if best_pokemon['pokemon_data']['id'] == pokemon['pokemon_data']['id']:\n                                all_pokemons.remove(pokemon)\n\n                    if best_pokemons and all_pokemons:\n                        logger.log(\"Keep {} best {}, based on {}\".format(len(best_pokemons),\n                                                                         pokemon_name,\n                                                                         order_criteria), \"green\")\n                        for best_pokemon in best_pokemons:\n                            logger.log(\"{} [CP {}] [Potential {}]\".format(pokemon_name,\n                                                                          best_pokemon['cp'],\n                                                                          best_pokemon['iv']), 'green')\n\n                        logger.log(\"Exchange {} pokemon(s)\".format(len(all_pokemons)), \"green\")\n\n                    for pokemon in all_pokemons:\n                        self.release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv'], pokemon['pokemon_data']['id'])\n                else:\n                    group = sorted(group, key=lambda x: x['cp'], reverse=True)\n                    for item in group:\n                        pokemon_cp = item['cp']\n                        pokemon_potential = item['iv']\n\n                        if self.should_release_pokemon(pokemon_name, pokemon_cp, pokemon_potential):\n                            self.release_pokemon(pokemon_name, item['cp'], item['iv'], item['pokemon_data']['id'])\n\n    def _release_pokemon_get_groups(self):\n        pokemon_groups = {}\n        self.api.get_player().get_inventory()\n        inventory_req = self.api.call()\n\n        if inventory_req.get('responses', False) is False:\n            return pokemon_groups\n\n        inventory_dict = inventory_req['responses']['GET_INVENTORY']['inventory_delta']['inventory_items']\n\n        user_web_inventory = 'web/inventory-%s.json' % (self.config.username)\n        with open(user_web_inventory, 'w') as outfile:\n            json.dump(inventory_dict, outfile)\n\n        for pokemon in inventory_dict:\n            try:\n                reduce(dict.__getitem__, [\n                    \"inventory_item_data\", \"pokemon_data\", \"pokemon_id\"\n                ], pokemon)\n            except KeyError:\n                continue\n\n            pokemon_data = pokemon['inventory_item_data']['pokemon_data']\n            group_id = pokemon_data['pokemon_id']\n            group_pokemon_cp = pokemon_data['cp']\n            group_pokemon_iv = self.get_pokemon_potential(pokemon_data)\n\n            if group_id not in pokemon_groups:\n                pokemon_groups[group_id] = []\n\n            pokemon_groups[group_id].append({\n                'cp': group_pokemon_cp,\n                'iv': group_pokemon_iv,\n                'pokemon_data': pokemon_data\n            })\n\n        return pokemon_groups\n\n    def get_pokemon_potential(self, pokemon_data):\n        total_iv = 0\n        iv_stats = ['individual_attack', 'individual_defense', 'individual_stamina']\n        for individual_stat in iv_stats:\n            try:\n                total_iv += pokemon_data[individual_stat]\n            except Exception:\n                continue\n        return round((total_iv / 45.0), 2)\n\n    def should_release_pokemon(self, pokemon_name, cp, iv):\n        release_config = self._get_release_config_for(pokemon_name)\n        cp_iv_logic = release_config.get('logic')\n        if not cp_iv_logic:\n            cp_iv_logic = self._get_release_config_for('any').get('logic', 'and')\n\n        release_results = {\n            'cp': False,\n            'iv': False,\n        }\n\n        if release_config.get('never_release', False):\n            return False\n\n        if release_config.get('always_release', False):\n            return True\n\n        release_cp = release_config.get('release_below_cp', 0)\n        if cp < release_cp:\n            release_results['cp'] = True\n\n        release_iv = release_config.get('release_below_iv', 0)\n        if iv < release_iv:\n            release_results['iv'] = True\n\n        logic_to_function = {\n            'or': lambda x, y: x or y,\n            'and': lambda x, y: x and y\n        }\n\n        if logic_to_function[cp_iv_logic](*release_results.values()):\n            logger.log(\n                \"Releasing {} with CP {} and IV {}. Matching release rule: CP < {} {} IV < {}. \".format(\n                    pokemon_name,\n                    cp,\n                    iv,\n                    release_cp,\n                    cp_iv_logic.upper(),\n                    release_iv\n                ), 'yellow'\n            )\n\n        return logic_to_function[cp_iv_logic](*release_results.values())\n\n    def release_pokemon(self, pokemon_name, cp, iv, pokemon_id):\n        logger.log('Exchanging {} [CP {}] [Potential {}] for candy!'.format(pokemon_name,\n                                                                            cp,\n                                                                            iv), 'green')\n        self.api.release_pokemon(pokemon_id=pokemon_id)\n        response_dict = self.api.call()\n        action_delay(self.config.action_wait_min, self.config.action_wait_max)\n\n    def _get_release_config_for(self, pokemon):\n        release_config = self.config.release.get(pokemon)\n        if not release_config:\n            release_config = self.config.release.get('any')\n        if not release_config:\n            release_config = {}\n        return release_config\n\n    def _validate_keep_best_config(self, pokemon_name):\n        keep_best = False\n\n        release_config = self._get_release_config_for(pokemon_name)\n\n        keep_best_cp = release_config.get('keep_best_cp', 0)\n        keep_best_iv = release_config.get('keep_best_iv', 0)\n\n        if keep_best_cp or keep_best_iv:\n            keep_best = True\n            try:\n                keep_best_cp = int(keep_best_cp)\n            except ValueError:\n                keep_best_cp = 0\n\n            try:\n                keep_best_iv = int(keep_best_iv)\n            except ValueError:\n                keep_best_iv = 0\n\n            if keep_best_cp > 1 and keep_best_iv > 1:\n                logger.log(\"keep_best_cp and keep_best_iv can't be > 0 at the same time. Ignore it.\", \"red\")\n                keep_best = False\n\n            if keep_best_cp < 0 or keep_best_iv < 0:\n                logger.log(\"Keep best can't be < 0. Ignore it.\", \"red\")\n                keep_best = False\n\n            if keep_best_cp == 0 and keep_best_iv == 0:\n                keep_best = False\n\n        return keep_best, keep_best_cp, keep_best_iv\n", "path": "pokemongo_bot/cell_workers/pokemon_transfer_worker.py"}], "after_files": [{"content": "import json\n\nfrom pokemongo_bot.human_behaviour import sleep, action_delay\nfrom pokemongo_bot import logger\n\n\nclass PokemonTransferWorker(object):\n\n    def __init__(self, bot):\n        self.config = bot.config\n        self.pokemon_list = bot.pokemon_list\n        self.api = bot.api\n        self.bot = bot\n\n    def work(self):\n        if not self.config.release_pokemon:\n            return\n\n        pokemon_groups = self._release_pokemon_get_groups()\n        for pokemon_id in pokemon_groups:\n            group = pokemon_groups[pokemon_id]\n\n            if len(group) > 1:\n                pokemon_name = self.pokemon_list[pokemon_id - 1]['Name']\n                keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)\n\n                if keep_best:\n                    best_pokemon_ids = set()\n                    order_criteria = 'none'\n                    if keep_best_cp >= 1:\n                        cp_limit = keep_best_cp\n                        best_cp_pokemons = sorted(group, key=lambda x: (x['cp'], x['iv']), reverse=True)[:cp_limit]\n                        best_pokemon_ids = set(pokemon['pokemon_data']['id'] for pokemon in best_cp_pokemons)\n                        order_criteria = 'cp'\n\n                    if keep_best_iv >= 1:\n                        iv_limit = keep_best_iv\n                        best_iv_pokemons = sorted(group, key=lambda x: (x['iv'], x['cp']), reverse=True)[:iv_limit]\n                        best_pokemon_ids |= set(pokemon['pokemon_data']['id'] for pokemon in best_iv_pokemons)\n                        if order_criteria == 'cp':\n                            order_criteria = 'cp and iv'\n                        else:\n                            order_criteria = 'iv'\n\n                    # remove best pokemons from all pokemons array\n                    all_pokemons = group\n                    best_pokemons = []\n                    for best_pokemon_id in best_pokemon_ids:\n                        for pokemon in all_pokemons:\n                            if best_pokemon_id == pokemon['pokemon_data']['id']:\n                                all_pokemons.remove(pokemon)\n                                best_pokemons.append(pokemon)\n\n                    if best_pokemons and all_pokemons:\n                        logger.log(\"Keep {} best {}, based on {}\".format(len(best_pokemons),\n                                                                         pokemon_name,\n                                                                         order_criteria), \"green\")\n                        for best_pokemon in best_pokemons:\n                            logger.log(\"{} [CP {}] [Potential {}]\".format(pokemon_name,\n                                                                          best_pokemon['cp'],\n                                                                          best_pokemon['iv']), 'green')\n\n                        logger.log(\"Exchange {} pokemon(s)\".format(len(all_pokemons)), \"green\")\n\n                    for pokemon in all_pokemons:\n                        self.release_pokemon(pokemon_name, pokemon['cp'], pokemon['iv'], pokemon['pokemon_data']['id'])\n                else:\n                    group = sorted(group, key=lambda x: x['cp'], reverse=True)\n                    for item in group:\n                        pokemon_cp = item['cp']\n                        pokemon_potential = item['iv']\n\n                        if self.should_release_pokemon(pokemon_name, pokemon_cp, pokemon_potential):\n                            self.release_pokemon(pokemon_name, item['cp'], item['iv'], item['pokemon_data']['id'])\n\n    def _release_pokemon_get_groups(self):\n        pokemon_groups = {}\n        self.api.get_player().get_inventory()\n        inventory_req = self.api.call()\n\n        if inventory_req.get('responses', False) is False:\n            return pokemon_groups\n\n        inventory_dict = inventory_req['responses']['GET_INVENTORY']['inventory_delta']['inventory_items']\n\n        user_web_inventory = 'web/inventory-%s.json' % (self.config.username)\n        with open(user_web_inventory, 'w') as outfile:\n            json.dump(inventory_dict, outfile)\n\n        for pokemon in inventory_dict:\n            try:\n                reduce(dict.__getitem__, [\n                    \"inventory_item_data\", \"pokemon_data\", \"pokemon_id\"\n                ], pokemon)\n            except KeyError:\n                continue\n\n            pokemon_data = pokemon['inventory_item_data']['pokemon_data']\n            group_id = pokemon_data['pokemon_id']\n            group_pokemon_cp = pokemon_data['cp']\n            group_pokemon_iv = self.get_pokemon_potential(pokemon_data)\n\n            if group_id not in pokemon_groups:\n                pokemon_groups[group_id] = []\n\n            pokemon_groups[group_id].append({\n                'cp': group_pokemon_cp,\n                'iv': group_pokemon_iv,\n                'pokemon_data': pokemon_data\n            })\n\n        return pokemon_groups\n\n    def get_pokemon_potential(self, pokemon_data):\n        total_iv = 0\n        iv_stats = ['individual_attack', 'individual_defense', 'individual_stamina']\n        for individual_stat in iv_stats:\n            try:\n                total_iv += pokemon_data[individual_stat]\n            except Exception:\n                continue\n        return round((total_iv / 45.0), 2)\n\n    def should_release_pokemon(self, pokemon_name, cp, iv):\n        release_config = self._get_release_config_for(pokemon_name)\n        cp_iv_logic = release_config.get('logic')\n        if not cp_iv_logic:\n            cp_iv_logic = self._get_release_config_for('any').get('logic', 'and')\n\n        release_results = {\n            'cp': False,\n            'iv': False,\n        }\n\n        if release_config.get('never_release', False):\n            return False\n\n        if release_config.get('always_release', False):\n            return True\n\n        release_cp = release_config.get('release_below_cp', 0)\n        if cp < release_cp:\n            release_results['cp'] = True\n\n        release_iv = release_config.get('release_below_iv', 0)\n        if iv < release_iv:\n            release_results['iv'] = True\n\n        logic_to_function = {\n            'or': lambda x, y: x or y,\n            'and': lambda x, y: x and y\n        }\n\n        if logic_to_function[cp_iv_logic](*release_results.values()):\n            logger.log(\n                \"Releasing {} with CP {} and IV {}. Matching release rule: CP < {} {} IV < {}. \".format(\n                    pokemon_name,\n                    cp,\n                    iv,\n                    release_cp,\n                    cp_iv_logic.upper(),\n                    release_iv\n                ), 'yellow'\n            )\n\n        return logic_to_function[cp_iv_logic](*release_results.values())\n\n    def release_pokemon(self, pokemon_name, cp, iv, pokemon_id):\n        logger.log('Exchanging {} [CP {}] [Potential {}] for candy!'.format(pokemon_name,\n                                                                            cp,\n                                                                            iv), 'green')\n        self.api.release_pokemon(pokemon_id=pokemon_id)\n        response_dict = self.api.call()\n        action_delay(self.config.action_wait_min, self.config.action_wait_max)\n\n    def _get_release_config_for(self, pokemon):\n        release_config = self.config.release.get(pokemon)\n        if not release_config:\n            release_config = self.config.release.get('any')\n        if not release_config:\n            release_config = {}\n        return release_config\n\n    def _validate_keep_best_config(self, pokemon_name):\n        keep_best = False\n\n        release_config = self._get_release_config_for(pokemon_name)\n\n        keep_best_cp = release_config.get('keep_best_cp', 0)\n        keep_best_iv = release_config.get('keep_best_iv', 0)\n\n        if keep_best_cp or keep_best_iv:\n            keep_best = True\n            try:\n                keep_best_cp = int(keep_best_cp)\n            except ValueError:\n                keep_best_cp = 0\n\n            try:\n                keep_best_iv = int(keep_best_iv)\n            except ValueError:\n                keep_best_iv = 0\n\n            if keep_best_cp < 0 or keep_best_iv < 0:\n                logger.log(\"Keep best can't be < 0. Ignore it.\", \"red\")\n                keep_best = False\n\n            if keep_best_cp == 0 and keep_best_iv == 0:\n                keep_best = False\n\n        return keep_best, keep_best_cp, keep_best_iv\n", "path": "pokemongo_bot/cell_workers/pokemon_transfer_worker.py"}]}