diff --git a/gsuid_core/utils/api/akashadata/__init__.py b/gsuid_core/utils/api/akashadata/__init__.py new file mode 100644 index 0000000..c03a643 --- /dev/null +++ b/gsuid_core/utils/api/akashadata/__init__.py @@ -0,0 +1,10 @@ +""" +虚空数据库 API 包装: +深渊出场数据; +""" +from .models import AkashaAbyssData as AkashaAbyssData # noqa: F401 +from .request import ( # noqa: F401 + get_akasha_abyss_info as get_akasha_abyss_info, +) + +__all__ = ["request", "models"] diff --git a/gsuid_core/utils/api/akashadata/api.py b/gsuid_core/utils/api/akashadata/api.py new file mode 100644 index 0000000..2044665 --- /dev/null +++ b/gsuid_core/utils/api/akashadata/api.py @@ -0,0 +1,9 @@ +AKASHA_ABYSS_URL = ( + 'https://akashadata.feixiaoqiu.com/static/data/abyss_total.js' +) +AKASHA_RANK_URL = ( + 'https://akashadata.feixiaoqiu.com/static/data/abyss_record_list.js' +) +AKASHA_CHAR_URL = ( + 'https://akashadata.feixiaoqiu.com/static/data/card_details.js?v=' +) diff --git a/gsuid_core/utils/api/akashadata/models.py b/gsuid_core/utils/api/akashadata/models.py new file mode 100644 index 0000000..1b12562 --- /dev/null +++ b/gsuid_core/utils/api/akashadata/models.py @@ -0,0 +1,134 @@ +from __future__ import annotations + +from typing import List, TypedDict + + +class TeamListItem(TypedDict): + ac: int + mr: str + uc: str + dc: str + ud: str + umr: str + dmr: str + tl: list[int] + + +class AbyssTotalView(TypedDict): + avg_star: str + avg_battle_count: str + avg_maxstar_battle_count: str + pass_rate: str + maxstar_rate: str + maxstar_12_rate: str + person_war: str + person_pass: int + maxstar_person: int + + +class LastRate(TypedDict): + avg_star: str + pass_rate: str + maxstar_rate: str + avg_battle_count: str + avg_maxstar_battle_count: str + maxstar_12_rate: str + + +class MaxstarPlayerData(TypedDict): + title: str + y_list: list[str] + x_list: list[str] + + +class PassPlayerData(TypedDict): + title: str + y_list: list[str] + x_list: list[str] + + +class PlayerLevelData(TypedDict): + maxstar_player_data: MaxstarPlayerData + pass_player_data: PassPlayerData + + +class PalyerCountLevelData(TypedDict): + player_count_data: list[int] + level_data: list[str] + + +class LevelData(TypedDict): + player_level_data: PlayerLevelData + palyer_count_level_data: PalyerCountLevelData + + +class CharacterUsedListItem(TypedDict): + avatar_id: int + maxstar_person_had_count: int + maxstar_person_use_count: int + value: float + used_index: int + name: str + en_name: str + icon: str + element: str + rarity: int + + +class AkashaAbyssData(TypedDict): + schedule_id: int + modify_time: str + schedule_version_desc: str + team_list: list[TeamListItem] + team_up_list: list[TeamListItem] + team_down_list: list[TeamListItem] + abyss_total_view: AbyssTotalView + last_rate: LastRate + level_data: LevelData + character_used_list: list[CharacterUsedListItem] + + +class AKaShaUsage(TypedDict): + i: int + v: str + d: str + r: int + + +class AKaShaRank(TypedDict): + usage_list: List[AKaShaUsage] + maxrate_list: List[AKaShaUsage] + out_list: List[AKaShaUsage] + + +class AKaShaWeaponRate(TypedDict): + name: str + id: int + weapon_icon: str + rarity: int + rate: str + + +class AKaShaOneEquipRate(TypedDict): + set: str + name: str + count: str + + +class AKaShaEquipRate(TypedDict): + rate: str + set_list: List[AKaShaOneEquipRate] + + +class AKaShaAbyssChar(TypedDict): + use_rate: str + maxstar_rate: str + come_rate: float + avg_level: float + avg_constellation: float + + +class AKaShaCharData(TypedDict): + weapons: List[AKaShaWeaponRate] + equips: List[AKaShaEquipRate] + abyss: AKaShaAbyssChar diff --git a/gsuid_core/utils/api/akashadata/request.py b/gsuid_core/utils/api/akashadata/request.py new file mode 100644 index 0000000..bab700f --- /dev/null +++ b/gsuid_core/utils/api/akashadata/request.py @@ -0,0 +1,71 @@ +''' +虚空数据库 API 请求模块。 +''' +from __future__ import annotations + +import json +from typing import Dict, Literal, Optional + +from httpx import AsyncClient + +from ..types import AnyDict +from ..utils import _HEADER +from .models import AKaShaRank, AKaShaCharData, AkashaAbyssData +from .api import AKASHA_CHAR_URL, AKASHA_RANK_URL, AKASHA_ABYSS_URL + + +async def get_akasha_abyss_info() -> AkashaAbyssData: + '''请求虚空数据库 API 深渊出场数据 + + Returns: + AkashaAbyssData: 虚空数据库 API 深渊出场数据响应数据 + ''' # noqa: E501 + raw_data = await _akasha_request(AKASHA_ABYSS_URL) + raw_data = raw_data.lstrip('var static_abyss_total =') + data = json.loads(raw_data) + return data + + +async def get_akasha_all_char_info() -> Dict[str, AKaShaCharData]: + raw_data = await _akasha_request(AKASHA_CHAR_URL) + raw_data = ( + raw_data.replace('\\', '') + .lstrip('var static_card_details =') + .replace('"[', '[') + .replace(']"', ']') + .replace('"{', '{') + .replace('}"', '}') + ) + data = json.loads(raw_data) + return data + + +async def get_akasha_abyss_rank(is_info: bool = False) -> AKaShaRank: + raw_data = await _akasha_request(AKASHA_RANK_URL) + raw_data = raw_data.lstrip('var static_abyss_total =') + data_list = raw_data.split(';') + data1 = data_list[0].lstrip('var static_schedule_version_dict =') + data2 = data_list[1].lstrip('var static_abyss_record_dict =') + schedule_version_dict = json.loads(data1) + abyss_record_dict = json.loads(data2) + if is_info: + return schedule_version_dict + return abyss_record_dict + + +async def _akasha_request( + url: str, + method: Literal['GET', 'POST'] = 'GET', + header: AnyDict = _HEADER, + params: Optional[AnyDict] = None, + data: Optional[AnyDict] = None, +) -> str: + async with AsyncClient( + headers=header, + verify=False, + timeout=None, + ) as client: + req = await client.request( + method=method, url=url, params=params, data=data + ) + return req.text diff --git a/gsuid_core/utils/api/ambr/__init__.py b/gsuid_core/utils/api/ambr/__init__.py new file mode 100644 index 0000000..3787ecc --- /dev/null +++ b/gsuid_core/utils/api/ambr/__init__.py @@ -0,0 +1,18 @@ +""" +安柏计划 API 包装: +书籍信息; +角色信息; +武器信息; +""" +from .models import AmbrBook as AmbrBook # noqa: F401 +from .models import AmbrWeapon as AmbrWeapon # noqa: F401 +from .models import AmbrCharacter as AmbrCharacter # noqa: F401 +from .models import AmbrBookDetail as AmbrBookDetail # noqa: F401 +from .request import get_story_data as get_story_data # noqa: F401 +from .request import get_all_book_id as get_all_book_id # noqa: F401 +from .request import get_book_volume as get_book_volume # noqa: F401 +from .request import get_ambr_char_data as get_ambr_char_data # noqa: F401 +from .request import get_ambr_event_info as get_ambr_event_info # noqa: F401 +from .request import get_ambr_weapon_data as get_ambr_weapon_data # noqa: F401 + +__all__ = ["request", "models", "utils"] diff --git a/gsuid_core/utils/api/ambr/api.py b/gsuid_core/utils/api/ambr/api.py new file mode 100644 index 0000000..1371543 --- /dev/null +++ b/gsuid_core/utils/api/ambr/api.py @@ -0,0 +1,10 @@ +AMBR_EVENT_URL = 'https://api.ambr.top/assets/data/event.json' +AMBR_CHAR_URL = 'https://api.ambr.top/v2/chs/avatar/{}?vh=32F2' +AMBR_WEAPON_URL = 'https://api.ambr.top/v2/CHS/weapon/{}?vh=32F6' +AMBR_BOOK_URL = 'https://api.ambr.top/v2/chs/book?vh=34F5' +AMBR_BOOK_DETAILS_URL = 'https://api.ambr.top/v2/CHS/book/{}?vh=34F5' +AMBR_BOOK_DATA_URL = 'https://api.ambr.top/v2/CHS/readable/Book{}?vh=34F5' +AMBR_MONSTER_URL = 'https://api.ambr.top/v2/chs/monster/{}?vh=37F4' +AMBR_GCG_LIST_URL = 'https://api.ambr.top/v2/chs/gcg?vh=37F4' +AMBR_GCG_DETAIL = 'https://api.ambr.top/v2/chs/gcg/{}?vh=37F4' +AMBR_MONSTER_LIST = 'https://api.ambr.top/v2/chs/monster?vh=37F4' diff --git a/gsuid_core/utils/api/ambr/models.py b/gsuid_core/utils/api/ambr/models.py new file mode 100644 index 0000000..eb1bd1f --- /dev/null +++ b/gsuid_core/utils/api/ambr/models.py @@ -0,0 +1,266 @@ +from __future__ import annotations + +from typing import Dict, List, Union, Literal, Optional, TypedDict + + +class AmbrLanguageData(TypedDict): + EN: str + RU: str + CHS: str + KR: str + JP: str + + +class AmbrEvent(TypedDict): + id: int + name: AmbrLanguageData + nameFull: AmbrLanguageData + description: AmbrLanguageData + banner: AmbrLanguageData + endAt: str + + +class AmbrFetter(TypedDict): + title: str + detail: str + constellation: str + native: str + cv: AmbrLanguageData + + +class AmbrProp(TypedDict): + propType: str + initValue: float + type: str + + +class AmbrPromote(TypedDict): + promoteLevel: int + costItems: Dict[str, int] + unlockMaxLevel: int + addProps: Dict[str, float] + requiredPlayerLevel: int + coinCost: int + + +class AmbrUpgrade(TypedDict): + prop: List[AmbrProp] + promote: List[AmbrPromote] + + +class AmbrWeaponUpgrade(AmbrUpgrade): + awakenCost: List[int] + + +class AmbrNameCard(TypedDict): + id: int + name: str + description: str + icon: str + + +class AmbrFood(TypedDict): + id: int + name: str + rank: int + effectIcon: str + icon: str + + +class AmbrCharOther(TypedDict): + nameCard: AmbrNameCard + specialFood: AmbrFood + + +class AmbrTalentPromote(TypedDict): + level: int + costItems: Optional[Dict[str, int]] + coinCost: Optional[int] + description: List[str] + params: List[int] + + +class AmbrTalent(TypedDict): + type: int + name: str + description: str + icon: str + promote: Dict[str, AmbrTalentPromote] + cooldown: int + cost: int + + +class AmbrConstellation(TypedDict): + name: str + description: str + icon: str + + +class AmbrCharacter(TypedDict): + id: int + rank: int + name: str + element: Literal[ + 'Electric', 'Ice', 'Wind', 'Grass', 'Water', 'Rock', 'Fire' + ] + weaponType: Literal[ + 'WEAPON_SWORD_ONE_HAND', + 'WEAPON_CATALYST', + 'WEAPON_CLAYMORE', + 'WEAPON_BOW', + 'WEAPON_POLE', + ] + icon: str + birthday: List[int] + release: int + route: str + fetter: AmbrFetter + upgrade: AmbrUpgrade + other: AmbrCharOther + ascension: Dict[str, int] + talent: Dict[str, AmbrTalent] + constellation: Dict[str, AmbrConstellation] + + +class AmbrAffix(TypedDict): + name: str + upgrade: Dict[str, str] + + +class AmbrWeapon(TypedDict): + id: int + rank: int + type: str + name: str + description: str + icon: str + storyId: int + affix: Dict[str, AmbrAffix] + route: str + upgrade: AmbrWeaponUpgrade + ascension: Dict[str, int] + + +class AmbrBook(TypedDict): + id: int + name: str + rank: int + icon: str + route: str + + +class AmbrVolume(TypedDict): + id: int + name: str + description: str + storyId: str + + +class AmbrBookDetail(TypedDict): + id: int + name: str + rank: int + icon: str + volume: List[AmbrVolume] + route: str + + +class AmbrMonsterAffix(TypedDict): + name: str + description: str + abilityName: List[str] + isCommon: bool + + +class AmbrHpDrop(TypedDict): + id: int + hpPercent: int + + +class AmbrReward(TypedDict): + rank: int + icon: str + count: str + + +class AmbrEntry(TypedDict): + id: str + type: str + affix: List[AmbrMonsterAffix] + hpDrops: List[AmbrHpDrop] + prop: List[AmbrProp] + resistance: Dict[str, float] + reward: Dict[str, AmbrReward] + + +class AmbrMonster(TypedDict): + id: int + name: str + icon: str + route: str + title: str + specialName: str + description: str + entries: Dict[str, AmbrEntry] + tips: Optional[str] + + +class AmbrMonsterSimple(TypedDict): + id: int + name: str + icon: str + route: str + type: str + + +class AmbrGCGList(TypedDict): + types: Dict[str, Literal['characterCard', 'actionCard']] + items: Dict[str, AmbrGCGCard] + + +class AmbrGCGCard(TypedDict): + id: int + name: str + type: Literal['characterCard', 'actionCard'] + tags: Dict[str, str] + props: Dict[str, int] + icon: str + route: str + sortOrder: int + + +class AmbrGCGDict(TypedDict): + name: str + description: str + + +class AmbrGCGTalent(TypedDict): + name: str + description: str + cost: Dict[str, int] + params: Dict[str, Union[int, str]] + tags: Dict[str, str] + icon: str + subSkills: Optional[str] + keywords: Dict[str, str] + + +class AmbrGCGEntry(TypedDict): + id: int + name: str + type: Literal['gcg'] + icon: str + + +class AmbrGCGDetail(AmbrGCGCard): + storyTitle: str + storyDetail: str + source: str + dictionary: Dict[str, AmbrGCGDict] + talent: Dict[str, AmbrGCGTalent] + relatedEntries: List[AmbrGCGCard] + + +class AmbrMonsterList(TypedDict): + types: Dict[str, str] + items: Dict[str, AmbrMonsterSimple] diff --git a/gsuid_core/utils/api/ambr/request.py b/gsuid_core/utils/api/ambr/request.py new file mode 100644 index 0000000..85cd347 --- /dev/null +++ b/gsuid_core/utils/api/ambr/request.py @@ -0,0 +1,129 @@ +''' +安柏计划 API 请求模块。 +''' +from __future__ import annotations + +from typing import Dict, Union, Literal, Optional, cast + +from httpx import AsyncClient + +from ..types import AnyDict +from ..utils import _HEADER +from .models import ( + AmbrBook, + AmbrEvent, + AmbrWeapon, + AmbrGCGList, + AmbrMonster, + AmbrCharacter, + AmbrGCGDetail, + AmbrBookDetail, + AmbrMonsterList, +) +from .api import ( + AMBR_BOOK_URL, + AMBR_CHAR_URL, + AMBR_EVENT_URL, + AMBR_GCG_DETAIL, + AMBR_WEAPON_URL, + AMBR_MONSTER_URL, + AMBR_GCG_LIST_URL, + AMBR_MONSTER_LIST, + AMBR_BOOK_DATA_URL, + AMBR_BOOK_DETAILS_URL, +) + + +async def get_ambr_event_info() -> Optional[Dict[str, AmbrEvent]]: + data = await _ambr_request(url=AMBR_EVENT_URL) + if isinstance(data, Dict): + return cast(Dict[str, AmbrEvent], data) + return None + + +async def get_ambr_char_data(id: Union[int, str]) -> Optional[AmbrCharacter]: + data = await _ambr_request(url=AMBR_CHAR_URL.format(id)) + if isinstance(data, Dict) and data['response'] == 200: + data = data['data'] + return cast(AmbrCharacter, data) + return None + + +async def get_ambr_monster_data(id: Union[int, str]) -> Optional[AmbrMonster]: + data = await _ambr_request(url=AMBR_MONSTER_URL.format(id)) + if isinstance(data, Dict) and data['response'] == 200: + data = data['data'] + return cast(AmbrMonster, data) + return None + + +async def get_ambr_gcg_detail(id: Union[int, str]) -> Optional[AmbrGCGDetail]: + data = await _ambr_request(url=AMBR_GCG_DETAIL.format(id)) + if isinstance(data, Dict) and data['response'] == 200: + data = data['data'] + return cast(AmbrGCGDetail, data) + return None + + +async def get_ambr_gcg_list() -> Optional[AmbrGCGList]: + data = await _ambr_request(url=AMBR_GCG_LIST_URL) + if isinstance(data, Dict) and data['response'] == 200: + data = data['data'] + return cast(AmbrGCGList, data) + return None + + +async def get_ambr_monster_list() -> Optional[AmbrMonsterList]: + data = await _ambr_request(url=AMBR_MONSTER_LIST) + if isinstance(data, Dict) and data['response'] == 200: + data = data['data'] + return cast(AmbrMonsterList, data) + return None + + +async def get_ambr_weapon_data(id: Union[int, str]) -> Optional[AmbrWeapon]: + data = await _ambr_request(url=AMBR_WEAPON_URL.format(id)) + if isinstance(data, Dict) and data['response'] == 200: + data = data['data'] + return cast(AmbrWeapon, data) + return None + + +async def get_all_book_id() -> Optional[Dict[str, AmbrBook]]: + data = await _ambr_request(url=AMBR_BOOK_URL) + if isinstance(data, Dict) and data['response'] == 200: + data = data['data']['items'] + return cast(Dict[str, AmbrBook], data) + return None + + +async def get_book_volume(id: Union[int, str]) -> Optional[AmbrBookDetail]: + data = await _ambr_request(url=AMBR_BOOK_DETAILS_URL.format(id)) + if isinstance(data, Dict) and data['response'] == 200: + data = data['data'] + return cast(AmbrBookDetail, data) + return None + + +async def get_story_data(story_id: Union[int, str]) -> Optional[str]: + data = await _ambr_request(url=AMBR_BOOK_DATA_URL.format(story_id)) + if isinstance(data, Dict) and data['response'] == 200: + return data['data'] + return None + + +async def _ambr_request( + url: str, + method: Literal['GET', 'POST'] = 'GET', + header: AnyDict = _HEADER, + params: Optional[AnyDict] = None, + data: Optional[AnyDict] = None, +) -> Optional[AnyDict]: + async with AsyncClient(timeout=None) as client: + req = await client.request( + method, url=url, headers=header, params=params, json=data + ) + data = req.json() + if data and 'code' in data: + data['response'] = data['code'] + return data diff --git a/gsuid_core/utils/api/ambr/utils.py b/gsuid_core/utils/api/ambr/utils.py new file mode 100644 index 0000000..f51042e --- /dev/null +++ b/gsuid_core/utils/api/ambr/utils.py @@ -0,0 +1,4727 @@ +GROW_CURVE_LIST = [ + { + 'level': 1, + 'curveInfos': [ + {'type': 'GROW_CURVE_HP_S4', 'arith': 'ARITH_MULTI', 'value': 1.0}, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.0, + }, + {'type': 'GROW_CURVE_HP_S5', 'arith': 'ARITH_MULTI', 'value': 1.0}, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.0, + }, + ], + }, + { + 'level': 2, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.0829999446868896, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.0829999446868896, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.0829999446868896, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.0829999446868896, + }, + ], + }, + { + 'level': 3, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.1649999618530273, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.1649999618530273, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.1660000085830688, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.1660000085830688, + }, + ], + }, + { + 'level': 4, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.2480000257492065, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.2480000257492065, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.25, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.25, + }, + ], + }, + { + 'level': 5, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.3300000429153442, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.3300000429153442, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.3329999446868896, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.3329999446868896, + }, + ], + }, + { + 'level': 6, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.4129999876022339, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.4129999876022339, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.4170000553131104, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.4170000553131104, + }, + ], + }, + { + 'level': 7, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.4950000047683716, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.4950000047683716, + }, + {'type': 'GROW_CURVE_HP_S5', 'arith': 'ARITH_MULTI', 'value': 1.5}, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.5, + }, + ], + }, + { + 'level': 8, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.5779999494552612, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.5779999494552612, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.5839999914169312, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.5839999914169312, + }, + ], + }, + { + 'level': 9, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.6610000133514404, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.6610000133514404, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.6679999828338623, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.6679999828338623, + }, + ], + }, + { + 'level': 10, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.7430000305175781, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.7430000305175781, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.7510000467300415, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.7510000467300415, + }, + ], + }, + { + 'level': 11, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.8259999752044678, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.8259999752044678, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.8350000381469727, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.8350000381469727, + }, + ], + }, + { + 'level': 12, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.9079999923706055, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.9079999923706055, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.9190000295639038, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 1.9190000295639038, + }, + ], + }, + { + 'level': 13, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.9910000562667847, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 1.9910000562667847, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.003000020980835, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.003000020980835, + }, + ], + }, + { + 'level': 14, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.072999954223633, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.072999954223633, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.0880000591278076, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.0880000591278076, + }, + ], + }, + { + 'level': 15, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.1559998989105225, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.1559998989105225, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.171999931335449, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.171999931335449, + }, + ], + }, + { + 'level': 16, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.239000082015991, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.239000082015991, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.25600004196167, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.25600004196167, + }, + ], + }, + { + 'level': 17, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.321000099182129, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.321000099182129, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.3410000801086426, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.3410000801086426, + }, + ], + }, + { + 'level': 18, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.4040000438690186, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.4040000438690186, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.424999952316284, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.424999952316284, + }, + ], + }, + { + 'level': 19, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.4860000610351562, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.4860000610351562, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.509999990463257, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.509999990463257, + }, + ], + }, + { + 'level': 20, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.569000005722046, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.569000005722046, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.5940001010894775, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.5940001010894775, + }, + ], + }, + { + 'level': 21, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.6510000228881836, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.6510000228881836, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.678999900817871, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.678999900817871, + }, + ], + }, + { + 'level': 22, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.7339999675750732, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.7339999675750732, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.7639999389648438, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.7639999389648438, + }, + ], + }, + { + 'level': 23, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.816999912261963, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.816999912261963, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.8489999771118164, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.8489999771118164, + }, + ], + }, + { + 'level': 24, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.8989999294281006, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.8989999294281006, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.934000015258789, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 2.934000015258789, + }, + ], + }, + { + 'level': 25, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.9820001125335693, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 2.9820001125335693, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.0190000534057617, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.0190000534057617, + }, + ], + }, + { + 'level': 26, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.063999891281128, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.063999891281128, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.1050000190734863, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.1050000190734863, + }, + ], + }, + { + 'level': 27, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.1470000743865967, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.1470000743865967, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.190000057220459, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.190000057220459, + }, + ], + }, + { + 'level': 28, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.2290000915527344, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.2290000915527344, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.2750000953674316, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.2750000953674316, + }, + ], + }, + { + 'level': 29, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.312000036239624, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.312000036239624, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.3610000610351562, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.3610000610351562, + }, + ], + }, + { + 'level': 30, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.3940000534057617, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.3940000534057617, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.446000099182129, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.446000099182129, + }, + ], + }, + { + 'level': 31, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.4769999980926514, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.4769999980926514, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.5320000648498535, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.5320000648498535, + }, + ], + }, + { + 'level': 32, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.559999942779541, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.559999942779541, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.618000030517578, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.618000030517578, + }, + ], + }, + { + 'level': 33, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.6419999599456787, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.6419999599456787, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.7039999961853027, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.7039999961853027, + }, + ], + }, + { + 'level': 34, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.7249999046325684, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.7249999046325684, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.7890000343322754, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.7890000343322754, + }, + ], + }, + { + 'level': 35, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.806999921798706, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.806999921798706, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.875, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.875, + }, + ], + }, + { + 'level': 36, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.890000104904175, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.890000104904175, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.9619998931884766, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 3.9619998931884766, + }, + ], + }, + { + 'level': 37, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.9719998836517334, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 3.9719998836517334, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.047999858856201, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.047999858856201, + }, + ], + }, + { + 'level': 38, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.054999828338623, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.054999828338623, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.133999824523926, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.133999824523926, + }, + ], + }, + { + 'level': 39, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.138000011444092, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.138000011444092, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.21999979019165, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.21999979019165, + }, + ], + }, + { + 'level': 40, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.21999979019165, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.21999979019165, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.307000160217285, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.307000160217285, + }, + ], + }, + { + 'level': 41, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.302999973297119, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.302999973297119, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.39300012588501, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.39300012588501, + }, + ], + }, + { + 'level': 42, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.385000228881836, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.385000228881836, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.480000019073486, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.480000019073486, + }, + ], + }, + { + 'level': 43, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.4679999351501465, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.4679999351501465, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.566999912261963, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.566999912261963, + }, + ], + }, + { + 'level': 44, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.550000190734863, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.550000190734863, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.6529998779296875, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.6529998779296875, + }, + ], + }, + { + 'level': 45, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.632999897003174, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.632999897003174, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.739999771118164, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.739999771118164, + }, + ], + }, + { + 'level': 46, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.716000080108643, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.716000080108643, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.827000141143799, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.827000141143799, + }, + ], + }, + { + 'level': 47, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.797999858856201, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.797999858856201, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.914000034332275, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 4.914000034332275, + }, + ], + }, + { + 'level': 48, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.88100004196167, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.88100004196167, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.000999927520752, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.000999927520752, + }, + ], + }, + { + 'level': 49, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.9629998207092285, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 4.9629998207092285, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.089000225067139, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.089000225067139, + }, + ], + }, + { + 'level': 50, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.046000003814697, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.046000003814697, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.176000118255615, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.176000118255615, + }, + ], + }, + { + 'level': 51, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.127999782562256, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.127999782562256, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.263000011444092, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.263000011444092, + }, + ], + }, + { + 'level': 52, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.210999965667725, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.210999965667725, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.35099983215332, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.35099983215332, + }, + ], + }, + { + 'level': 53, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.294000148773193, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.294000148773193, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.438000202178955, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.438000202178955, + }, + ], + }, + { + 'level': 54, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.375999927520752, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.375999927520752, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.526000022888184, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.526000022888184, + }, + ], + }, + { + 'level': 55, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.459000110626221, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.459000110626221, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.613999843597412, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.613999843597412, + }, + ], + }, + { + 'level': 56, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.540999889373779, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.540999889373779, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.702000141143799, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.702000141143799, + }, + ], + }, + { + 'level': 57, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.624000072479248, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.624000072479248, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.789999961853027, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.789999961853027, + }, + ], + }, + { + 'level': 58, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.705999851226807, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.705999851226807, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.877999782562256, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.877999782562256, + }, + ], + }, + { + 'level': 59, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.789000034332275, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.789000034332275, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.966000080108643, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 5.966000080108643, + }, + ], + }, + { + 'level': 60, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.872000217437744, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.872000217437744, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.053999900817871, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.053999900817871, + }, + ], + }, + { + 'level': 61, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.953999996185303, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 5.953999996185303, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.142000198364258, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.142000198364258, + }, + ], + }, + { + 'level': 62, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.0370001792907715, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.0370001792907715, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.230000019073486, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.230000019073486, + }, + ], + }, + { + 'level': 63, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.11899995803833, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.11899995803833, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.318999767303467, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.318999767303467, + }, + ], + }, + { + 'level': 64, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.202000141143799, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.202000141143799, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.4070000648498535, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.4070000648498535, + }, + ], + }, + { + 'level': 65, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.283999919891357, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.283999919891357, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.495999813079834, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.495999813079834, + }, + ], + }, + { + 'level': 66, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.367000102996826, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.367000102996826, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.585000038146973, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.585000038146973, + }, + ], + }, + { + 'level': 67, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.449999809265137, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.449999809265137, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.672999858856201, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.672999858856201, + }, + ], + }, + { + 'level': 68, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.5320000648498535, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.5320000648498535, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.76200008392334, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.76200008392334, + }, + ], + }, + { + 'level': 69, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.614999771118164, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.614999771118164, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.85099983215332, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.85099983215332, + }, + ], + }, + { + 'level': 70, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.697000026702881, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.697000026702881, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.940000057220459, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 6.940000057220459, + }, + ], + }, + { + 'level': 71, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.78000020980835, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.78000020980835, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.0289998054504395, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.0289998054504395, + }, + ], + }, + { + 'level': 72, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.861999988555908, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.861999988555908, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.11899995803833, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.11899995803833, + }, + ], + }, + { + 'level': 73, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.945000171661377, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 6.945000171661377, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.208000183105469, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.208000183105469, + }, + ], + }, + { + 'level': 74, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.0279998779296875, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.0279998779296875, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.296999931335449, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.296999931335449, + }, + ], + }, + { + 'level': 75, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.110000133514404, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.110000133514404, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.38700008392334, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.38700008392334, + }, + ], + }, + { + 'level': 76, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.192999839782715, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.192999839782715, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.47599983215332, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.47599983215332, + }, + ], + }, + { + 'level': 77, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.275000095367432, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.275000095367432, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.565999984741211, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.565999984741211, + }, + ], + }, + { + 'level': 78, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.357999801635742, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.357999801635742, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.656000137329102, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.656000137329102, + }, + ], + }, + { + 'level': 79, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.440000057220459, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.440000057220459, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.745999813079834, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.745999813079834, + }, + ], + }, + { + 'level': 80, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.5229997634887695, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.5229997634887695, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.835999965667725, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.835999965667725, + }, + ], + }, + { + 'level': 81, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.605999946594238, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.605999946594238, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.926000118255615, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 7.926000118255615, + }, + ], + }, + { + 'level': 82, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.688000202178955, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.688000202178955, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.015999794006348, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.015999794006348, + }, + ], + }, + { + 'level': 83, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.770999908447266, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.770999908447266, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.105999946594238, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.105999946594238, + }, + ], + }, + { + 'level': 84, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.853000164031982, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.853000164031982, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.196000099182129, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.196000099182129, + }, + ], + }, + { + 'level': 85, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.935999870300293, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 7.935999870300293, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.28600025177002, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.28600025177002, + }, + ], + }, + { + 'level': 86, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.017999649047852, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.017999649047852, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.376999855041504, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.376999855041504, + }, + ], + }, + { + 'level': 87, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.10099983215332, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.10099983215332, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.467000007629395, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.467000007629395, + }, + ], + }, + { + 'level': 88, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.182999610900879, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.182999610900879, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.557999610900879, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.557999610900879, + }, + ], + }, + { + 'level': 89, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.265999794006348, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.265999794006348, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.64900016784668, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.64900016784668, + }, + ], + }, + { + 'level': 90, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.348999977111816, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.348999977111816, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.73900032043457, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.73900032043457, + }, + ], + }, + { + 'level': 91, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.430999755859375, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.430999755859375, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.829999923706055, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.829999923706055, + }, + ], + }, + { + 'level': 92, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.513999938964844, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.513999938964844, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.920999526977539, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 8.920999526977539, + }, + ], + }, + { + 'level': 93, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.595999717712402, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.595999717712402, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.01200008392334, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.01200008392334, + }, + ], + }, + { + 'level': 94, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.678999900817871, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.678999900817871, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.102999687194824, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.102999687194824, + }, + ], + }, + { + 'level': 95, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.76099967956543, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.76099967956543, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.194999694824219, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.194999694824219, + }, + ], + }, + { + 'level': 96, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.843999862670898, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.843999862670898, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.28600025177002, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.28600025177002, + }, + ], + }, + { + 'level': 97, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.927000045776367, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 8.927000045776367, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.376999855041504, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.376999855041504, + }, + ], + }, + { + 'level': 98, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 9.008999824523926, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 9.008999824523926, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.468999862670898, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.468999862670898, + }, + ], + }, + { + 'level': 99, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 9.092000007629395, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 9.092000007629395, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.5600004196167, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.5600004196167, + }, + ], + }, + { + 'level': 100, + 'curveInfos': [ + { + 'type': 'GROW_CURVE_HP_S4', + 'arith': 'ARITH_MULTI', + 'value': 9.173999786376953, + }, + { + 'type': 'GROW_CURVE_ATTACK_S4', + 'arith': 'ARITH_MULTI', + 'value': 9.173999786376953, + }, + { + 'type': 'GROW_CURVE_HP_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.652000427246094, + }, + { + 'type': 'GROW_CURVE_ATTACK_S5', + 'arith': 'ARITH_MULTI', + 'value': 9.652000427246094, + }, + ], + }, +] + +WEAPON_GROW_CURVE = { + '1': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1, + 'GROW_CURVE_ATTACK_102': 1, + 'GROW_CURVE_ATTACK_103': 1, + 'GROW_CURVE_ATTACK_104': 1, + 'GROW_CURVE_ATTACK_105': 1, + 'GROW_CURVE_CRITICAL_101': 1, + 'GROW_CURVE_ATTACK_201': 1, + 'GROW_CURVE_ATTACK_202': 1, + 'GROW_CURVE_ATTACK_203': 1, + 'GROW_CURVE_ATTACK_204': 1, + 'GROW_CURVE_ATTACK_205': 1, + 'GROW_CURVE_CRITICAL_201': 1, + 'GROW_CURVE_ATTACK_301': 1, + 'GROW_CURVE_ATTACK_302': 1, + 'GROW_CURVE_ATTACK_303': 1, + 'GROW_CURVE_ATTACK_304': 1, + 'GROW_CURVE_ATTACK_305': 1, + 'GROW_CURVE_CRITICAL_301': 1, + } + }, + '2': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.076, + 'GROW_CURVE_ATTACK_102': 1.081, + 'GROW_CURVE_ATTACK_103': 1.086, + 'GROW_CURVE_ATTACK_104': 1.071, + 'GROW_CURVE_ATTACK_105': 1.065, + 'GROW_CURVE_CRITICAL_101': 1, + 'GROW_CURVE_ATTACK_201': 1.083, + 'GROW_CURVE_ATTACK_202': 1.088, + 'GROW_CURVE_ATTACK_203': 1.093, + 'GROW_CURVE_ATTACK_204': 1.077, + 'GROW_CURVE_ATTACK_205': 1.071, + 'GROW_CURVE_CRITICAL_201': 1, + 'GROW_CURVE_ATTACK_301': 1.086, + 'GROW_CURVE_ATTACK_302': 1.091, + 'GROW_CURVE_ATTACK_303': 1.097, + 'GROW_CURVE_ATTACK_304': 1.079, + 'GROW_CURVE_ATTACK_305': 1.073, + 'GROW_CURVE_CRITICAL_301': 1, + } + }, + '3': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.152, + 'GROW_CURVE_ATTACK_102': 1.162, + 'GROW_CURVE_ATTACK_103': 1.172, + 'GROW_CURVE_ATTACK_104': 1.141, + 'GROW_CURVE_ATTACK_105': 1.129, + 'GROW_CURVE_CRITICAL_101': 1, + 'GROW_CURVE_ATTACK_201': 1.165, + 'GROW_CURVE_ATTACK_202': 1.176, + 'GROW_CURVE_ATTACK_203': 1.186, + 'GROW_CURVE_ATTACK_204': 1.154, + 'GROW_CURVE_ATTACK_205': 1.141, + 'GROW_CURVE_CRITICAL_201': 1, + 'GROW_CURVE_ATTACK_301': 1.171, + 'GROW_CURVE_ATTACK_302': 1.183, + 'GROW_CURVE_ATTACK_303': 1.194, + 'GROW_CURVE_ATTACK_304': 1.159, + 'GROW_CURVE_ATTACK_305': 1.145, + 'GROW_CURVE_CRITICAL_301': 1, + } + }, + '4': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.228, + 'GROW_CURVE_ATTACK_102': 1.244, + 'GROW_CURVE_ATTACK_103': 1.259, + 'GROW_CURVE_ATTACK_104': 1.211, + 'GROW_CURVE_ATTACK_105': 1.193, + 'GROW_CURVE_CRITICAL_101': 1, + 'GROW_CURVE_ATTACK_201': 1.248, + 'GROW_CURVE_ATTACK_202': 1.264, + 'GROW_CURVE_ATTACK_203': 1.28, + 'GROW_CURVE_ATTACK_204': 1.23, + 'GROW_CURVE_ATTACK_205': 1.211, + 'GROW_CURVE_CRITICAL_201': 1, + 'GROW_CURVE_ATTACK_301': 1.257, + 'GROW_CURVE_ATTACK_302': 1.275, + 'GROW_CURVE_ATTACK_303': 1.292, + 'GROW_CURVE_ATTACK_304': 1.238, + 'GROW_CURVE_ATTACK_305': 1.217, + 'GROW_CURVE_CRITICAL_301': 1, + } + }, + '5': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.303, + 'GROW_CURVE_ATTACK_102': 1.325, + 'GROW_CURVE_ATTACK_103': 1.346, + 'GROW_CURVE_ATTACK_104': 1.28, + 'GROW_CURVE_ATTACK_105': 1.255, + 'GROW_CURVE_CRITICAL_101': 1.162, + 'GROW_CURVE_ATTACK_201': 1.33, + 'GROW_CURVE_ATTACK_202': 1.353, + 'GROW_CURVE_ATTACK_203': 1.374, + 'GROW_CURVE_ATTACK_204': 1.306, + 'GROW_CURVE_ATTACK_205': 1.28, + 'GROW_CURVE_CRITICAL_201': 1.162, + 'GROW_CURVE_ATTACK_301': 1.343, + 'GROW_CURVE_ATTACK_302': 1.368, + 'GROW_CURVE_ATTACK_303': 1.391, + 'GROW_CURVE_ATTACK_304': 1.317, + 'GROW_CURVE_ATTACK_305': 1.288, + 'GROW_CURVE_CRITICAL_301': 1.162, + } + }, + '6': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.379, + 'GROW_CURVE_ATTACK_102': 1.407, + 'GROW_CURVE_ATTACK_103': 1.433, + 'GROW_CURVE_ATTACK_104': 1.349, + 'GROW_CURVE_ATTACK_105': 1.317, + 'GROW_CURVE_CRITICAL_101': 1.162, + 'GROW_CURVE_ATTACK_201': 1.413, + 'GROW_CURVE_ATTACK_202': 1.442, + 'GROW_CURVE_ATTACK_203': 1.469, + 'GROW_CURVE_ATTACK_204': 1.382, + 'GROW_CURVE_ATTACK_205': 1.349, + 'GROW_CURVE_CRITICAL_201': 1.162, + 'GROW_CURVE_ATTACK_301': 1.429, + 'GROW_CURVE_ATTACK_302': 1.461, + 'GROW_CURVE_ATTACK_303': 1.49, + 'GROW_CURVE_ATTACK_304': 1.395, + 'GROW_CURVE_ATTACK_305': 1.359, + 'GROW_CURVE_CRITICAL_301': 1.162, + } + }, + '7': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.454, + 'GROW_CURVE_ATTACK_102': 1.489, + 'GROW_CURVE_ATTACK_103': 1.521, + 'GROW_CURVE_ATTACK_104': 1.417, + 'GROW_CURVE_ATTACK_105': 1.379, + 'GROW_CURVE_CRITICAL_101': 1.162, + 'GROW_CURVE_ATTACK_201': 1.495, + 'GROW_CURVE_ATTACK_202': 1.531, + 'GROW_CURVE_ATTACK_203': 1.565, + 'GROW_CURVE_ATTACK_204': 1.457, + 'GROW_CURVE_ATTACK_205': 1.417, + 'GROW_CURVE_CRITICAL_201': 1.162, + 'GROW_CURVE_ATTACK_301': 1.516, + 'GROW_CURVE_ATTACK_302': 1.554, + 'GROW_CURVE_ATTACK_303': 1.591, + 'GROW_CURVE_ATTACK_304': 1.474, + 'GROW_CURVE_ATTACK_305': 1.429, + 'GROW_CURVE_CRITICAL_301': 1.162, + } + }, + '8': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.529, + 'GROW_CURVE_ATTACK_102': 1.57, + 'GROW_CURVE_ATTACK_103': 1.609, + 'GROW_CURVE_ATTACK_104': 1.486, + 'GROW_CURVE_ATTACK_105': 1.439, + 'GROW_CURVE_CRITICAL_101': 1.162, + 'GROW_CURVE_ATTACK_201': 1.578, + 'GROW_CURVE_ATTACK_202': 1.621, + 'GROW_CURVE_ATTACK_203': 1.661, + 'GROW_CURVE_ATTACK_204': 1.533, + 'GROW_CURVE_ATTACK_205': 1.484, + 'GROW_CURVE_CRITICAL_201': 1.162, + 'GROW_CURVE_ATTACK_301': 1.602, + 'GROW_CURVE_ATTACK_302': 1.648, + 'GROW_CURVE_ATTACK_303': 1.692, + 'GROW_CURVE_ATTACK_304': 1.552, + 'GROW_CURVE_ATTACK_305': 1.499, + 'GROW_CURVE_CRITICAL_301': 1.162, + } + }, + '9': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.604, + 'GROW_CURVE_ATTACK_102': 1.652, + 'GROW_CURVE_ATTACK_103': 1.698, + 'GROW_CURVE_ATTACK_104': 1.553, + 'GROW_CURVE_ATTACK_105': 1.499, + 'GROW_CURVE_CRITICAL_101': 1.162, + 'GROW_CURVE_ATTACK_201': 1.661, + 'GROW_CURVE_ATTACK_202': 1.71, + 'GROW_CURVE_ATTACK_203': 1.757, + 'GROW_CURVE_ATTACK_204': 1.607, + 'GROW_CURVE_ATTACK_205': 1.551, + 'GROW_CURVE_CRITICAL_201': 1.162, + 'GROW_CURVE_ATTACK_301': 1.689, + 'GROW_CURVE_ATTACK_302': 1.743, + 'GROW_CURVE_ATTACK_303': 1.793, + 'GROW_CURVE_ATTACK_304': 1.631, + 'GROW_CURVE_ATTACK_305': 1.568, + 'GROW_CURVE_CRITICAL_301': 1.162, + } + }, + '10': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.679, + 'GROW_CURVE_ATTACK_102': 1.734, + 'GROW_CURVE_ATTACK_103': 1.786, + 'GROW_CURVE_ATTACK_104': 1.621, + 'GROW_CURVE_ATTACK_105': 1.558, + 'GROW_CURVE_CRITICAL_101': 1.363, + 'GROW_CURVE_ATTACK_201': 1.743, + 'GROW_CURVE_ATTACK_202': 1.8, + 'GROW_CURVE_ATTACK_203': 1.854, + 'GROW_CURVE_ATTACK_204': 1.682, + 'GROW_CURVE_ATTACK_205': 1.617, + 'GROW_CURVE_CRITICAL_201': 1.363, + 'GROW_CURVE_ATTACK_301': 1.775, + 'GROW_CURVE_ATTACK_302': 1.837, + 'GROW_CURVE_ATTACK_303': 1.895, + 'GROW_CURVE_ATTACK_304': 1.709, + 'GROW_CURVE_ATTACK_305': 1.637, + 'GROW_CURVE_CRITICAL_301': 1.363, + } + }, + '11': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.754, + 'GROW_CURVE_ATTACK_102': 1.816, + 'GROW_CURVE_ATTACK_103': 1.875, + 'GROW_CURVE_ATTACK_104': 1.688, + 'GROW_CURVE_ATTACK_105': 1.617, + 'GROW_CURVE_CRITICAL_101': 1.363, + 'GROW_CURVE_ATTACK_201': 1.826, + 'GROW_CURVE_ATTACK_202': 1.891, + 'GROW_CURVE_ATTACK_203': 1.952, + 'GROW_CURVE_ATTACK_204': 1.757, + 'GROW_CURVE_ATTACK_205': 1.683, + 'GROW_CURVE_CRITICAL_201': 1.363, + 'GROW_CURVE_ATTACK_301': 1.862, + 'GROW_CURVE_ATTACK_302': 1.933, + 'GROW_CURVE_ATTACK_303': 1.998, + 'GROW_CURVE_ATTACK_304': 1.787, + 'GROW_CURVE_ATTACK_305': 1.706, + 'GROW_CURVE_CRITICAL_301': 1.363, + } + }, + '12': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.828, + 'GROW_CURVE_ATTACK_102': 1.898, + 'GROW_CURVE_ATTACK_103': 1.965, + 'GROW_CURVE_ATTACK_104': 1.754, + 'GROW_CURVE_ATTACK_105': 1.675, + 'GROW_CURVE_CRITICAL_101': 1.363, + 'GROW_CURVE_ATTACK_201': 1.908, + 'GROW_CURVE_ATTACK_202': 1.981, + 'GROW_CURVE_ATTACK_203': 2.049, + 'GROW_CURVE_ATTACK_204': 1.831, + 'GROW_CURVE_ATTACK_205': 1.748, + 'GROW_CURVE_CRITICAL_201': 1.363, + 'GROW_CURVE_ATTACK_301': 1.949, + 'GROW_CURVE_ATTACK_302': 2.028, + 'GROW_CURVE_ATTACK_303': 2.102, + 'GROW_CURVE_ATTACK_304': 1.865, + 'GROW_CURVE_ATTACK_305': 1.774, + 'GROW_CURVE_CRITICAL_301': 1.363, + } + }, + '13': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.903, + 'GROW_CURVE_ATTACK_102': 1.981, + 'GROW_CURVE_ATTACK_103': 2.054, + 'GROW_CURVE_ATTACK_104': 1.82, + 'GROW_CURVE_ATTACK_105': 1.733, + 'GROW_CURVE_CRITICAL_101': 1.363, + 'GROW_CURVE_ATTACK_201': 1.991, + 'GROW_CURVE_ATTACK_202': 2.072, + 'GROW_CURVE_ATTACK_203': 2.147, + 'GROW_CURVE_ATTACK_204': 1.905, + 'GROW_CURVE_ATTACK_205': 1.813, + 'GROW_CURVE_CRITICAL_201': 1.363, + 'GROW_CURVE_ATTACK_301': 2.036, + 'GROW_CURVE_ATTACK_302': 2.124, + 'GROW_CURVE_ATTACK_303': 2.206, + 'GROW_CURVE_ATTACK_304': 1.942, + 'GROW_CURVE_ATTACK_305': 1.841, + 'GROW_CURVE_CRITICAL_301': 1.363, + } + }, + '14': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 1.977, + 'GROW_CURVE_ATTACK_102': 2.063, + 'GROW_CURVE_ATTACK_103': 2.144, + 'GROW_CURVE_ATTACK_104': 1.886, + 'GROW_CURVE_ATTACK_105': 1.79, + 'GROW_CURVE_CRITICAL_101': 1.363, + 'GROW_CURVE_ATTACK_201': 2.073, + 'GROW_CURVE_ATTACK_202': 2.162, + 'GROW_CURVE_ATTACK_203': 2.246, + 'GROW_CURVE_ATTACK_204': 1.979, + 'GROW_CURVE_ATTACK_205': 1.878, + 'GROW_CURVE_CRITICAL_201': 1.363, + 'GROW_CURVE_ATTACK_301': 2.124, + 'GROW_CURVE_ATTACK_302': 2.22, + 'GROW_CURVE_ATTACK_303': 2.31, + 'GROW_CURVE_ATTACK_304': 2.02, + 'GROW_CURVE_ATTACK_305': 1.909, + 'GROW_CURVE_CRITICAL_301': 1.363, + } + }, + '15': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.051, + 'GROW_CURVE_ATTACK_102': 2.145, + 'GROW_CURVE_ATTACK_103': 2.234, + 'GROW_CURVE_ATTACK_104': 1.952, + 'GROW_CURVE_ATTACK_105': 1.846, + 'GROW_CURVE_CRITICAL_101': 1.565, + 'GROW_CURVE_ATTACK_201': 2.156, + 'GROW_CURVE_ATTACK_202': 2.253, + 'GROW_CURVE_ATTACK_203': 2.345, + 'GROW_CURVE_ATTACK_204': 2.052, + 'GROW_CURVE_ATTACK_205': 1.942, + 'GROW_CURVE_CRITICAL_201': 1.565, + 'GROW_CURVE_ATTACK_301': 2.211, + 'GROW_CURVE_ATTACK_302': 2.317, + 'GROW_CURVE_ATTACK_303': 2.415, + 'GROW_CURVE_ATTACK_304': 2.098, + 'GROW_CURVE_ATTACK_305': 1.976, + 'GROW_CURVE_CRITICAL_301': 1.565, + } + }, + '16': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.125, + 'GROW_CURVE_ATTACK_102': 2.227, + 'GROW_CURVE_ATTACK_103': 2.324, + 'GROW_CURVE_ATTACK_104': 2.017, + 'GROW_CURVE_ATTACK_105': 1.902, + 'GROW_CURVE_CRITICAL_101': 1.565, + 'GROW_CURVE_ATTACK_201': 2.239, + 'GROW_CURVE_ATTACK_202': 2.345, + 'GROW_CURVE_ATTACK_203': 2.444, + 'GROW_CURVE_ATTACK_204': 2.126, + 'GROW_CURVE_ATTACK_205': 2.005, + 'GROW_CURVE_CRITICAL_201': 1.565, + 'GROW_CURVE_ATTACK_301': 2.299, + 'GROW_CURVE_ATTACK_302': 2.414, + 'GROW_CURVE_ATTACK_303': 2.521, + 'GROW_CURVE_ATTACK_304': 2.175, + 'GROW_CURVE_ATTACK_305': 2.043, + 'GROW_CURVE_CRITICAL_301': 1.565, + } + }, + '17': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.199, + 'GROW_CURVE_ATTACK_102': 2.31, + 'GROW_CURVE_ATTACK_103': 2.414, + 'GROW_CURVE_ATTACK_104': 2.082, + 'GROW_CURVE_ATTACK_105': 1.958, + 'GROW_CURVE_CRITICAL_101': 1.565, + 'GROW_CURVE_ATTACK_201': 2.321, + 'GROW_CURVE_ATTACK_202': 2.436, + 'GROW_CURVE_ATTACK_203': 2.544, + 'GROW_CURVE_ATTACK_204': 2.199, + 'GROW_CURVE_ATTACK_205': 2.068, + 'GROW_CURVE_CRITICAL_201': 1.565, + 'GROW_CURVE_ATTACK_301': 2.386, + 'GROW_CURVE_ATTACK_302': 2.511, + 'GROW_CURVE_ATTACK_303': 2.627, + 'GROW_CURVE_ATTACK_304': 2.253, + 'GROW_CURVE_ATTACK_305': 2.109, + 'GROW_CURVE_CRITICAL_301': 1.565, + } + }, + '18': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.273, + 'GROW_CURVE_ATTACK_102': 2.392, + 'GROW_CURVE_ATTACK_103': 2.505, + 'GROW_CURVE_ATTACK_104': 2.147, + 'GROW_CURVE_ATTACK_105': 2.013, + 'GROW_CURVE_CRITICAL_101': 1.565, + 'GROW_CURVE_ATTACK_201': 2.404, + 'GROW_CURVE_ATTACK_202': 2.527, + 'GROW_CURVE_ATTACK_203': 2.644, + 'GROW_CURVE_ATTACK_204': 2.272, + 'GROW_CURVE_ATTACK_205': 2.131, + 'GROW_CURVE_CRITICAL_201': 1.565, + 'GROW_CURVE_ATTACK_301': 2.474, + 'GROW_CURVE_ATTACK_302': 2.608, + 'GROW_CURVE_ATTACK_303': 2.734, + 'GROW_CURVE_ATTACK_304': 2.33, + 'GROW_CURVE_ATTACK_305': 2.175, + 'GROW_CURVE_CRITICAL_301': 1.565, + } + }, + '19': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.347, + 'GROW_CURVE_ATTACK_102': 2.474, + 'GROW_CURVE_ATTACK_103': 2.595, + 'GROW_CURVE_ATTACK_104': 2.211, + 'GROW_CURVE_ATTACK_105': 2.067, + 'GROW_CURVE_CRITICAL_101': 1.565, + 'GROW_CURVE_ATTACK_201': 2.486, + 'GROW_CURVE_ATTACK_202': 2.619, + 'GROW_CURVE_ATTACK_203': 2.744, + 'GROW_CURVE_ATTACK_204': 2.345, + 'GROW_CURVE_ATTACK_205': 2.194, + 'GROW_CURVE_CRITICAL_201': 1.565, + 'GROW_CURVE_ATTACK_301': 2.562, + 'GROW_CURVE_ATTACK_302': 2.706, + 'GROW_CURVE_ATTACK_303': 2.841, + 'GROW_CURVE_ATTACK_304': 2.408, + 'GROW_CURVE_ATTACK_305': 2.241, + 'GROW_CURVE_CRITICAL_301': 1.565, + } + }, + '20': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.42, + 'GROW_CURVE_ATTACK_102': 2.557, + 'GROW_CURVE_ATTACK_103': 2.686, + 'GROW_CURVE_ATTACK_104': 2.275, + 'GROW_CURVE_ATTACK_105': 2.121, + 'GROW_CURVE_CRITICAL_101': 1.767, + 'GROW_CURVE_ATTACK_201': 2.569, + 'GROW_CURVE_ATTACK_202': 2.711, + 'GROW_CURVE_ATTACK_203': 2.845, + 'GROW_CURVE_ATTACK_204': 2.417, + 'GROW_CURVE_ATTACK_205': 2.256, + 'GROW_CURVE_CRITICAL_201': 1.767, + 'GROW_CURVE_ATTACK_301': 2.65, + 'GROW_CURVE_ATTACK_302': 2.804, + 'GROW_CURVE_ATTACK_303': 2.949, + 'GROW_CURVE_ATTACK_304': 2.485, + 'GROW_CURVE_ATTACK_305': 2.307, + 'GROW_CURVE_CRITICAL_301': 1.767, + } + }, + '21': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.493, + 'GROW_CURVE_ATTACK_102': 2.639, + 'GROW_CURVE_ATTACK_103': 2.777, + 'GROW_CURVE_ATTACK_104': 2.339, + 'GROW_CURVE_ATTACK_105': 2.175, + 'GROW_CURVE_CRITICAL_101': 1.767, + 'GROW_CURVE_ATTACK_201': 2.651, + 'GROW_CURVE_ATTACK_202': 2.803, + 'GROW_CURVE_ATTACK_203': 2.946, + 'GROW_CURVE_ATTACK_204': 2.49, + 'GROW_CURVE_ATTACK_205': 2.318, + 'GROW_CURVE_CRITICAL_201': 1.767, + 'GROW_CURVE_ATTACK_301': 2.738, + 'GROW_CURVE_ATTACK_302': 2.903, + 'GROW_CURVE_ATTACK_303': 3.057, + 'GROW_CURVE_ATTACK_304': 2.562, + 'GROW_CURVE_ATTACK_305': 2.373, + 'GROW_CURVE_CRITICAL_301': 1.767, + } + }, + '22': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.567, + 'GROW_CURVE_ATTACK_102': 2.722, + 'GROW_CURVE_ATTACK_103': 2.868, + 'GROW_CURVE_ATTACK_104': 2.402, + 'GROW_CURVE_ATTACK_105': 2.228, + 'GROW_CURVE_CRITICAL_101': 1.767, + 'GROW_CURVE_ATTACK_201': 2.734, + 'GROW_CURVE_ATTACK_202': 2.895, + 'GROW_CURVE_ATTACK_203': 3.047, + 'GROW_CURVE_ATTACK_204': 2.562, + 'GROW_CURVE_ATTACK_205': 2.379, + 'GROW_CURVE_CRITICAL_201': 1.767, + 'GROW_CURVE_ATTACK_301': 2.827, + 'GROW_CURVE_ATTACK_302': 3.002, + 'GROW_CURVE_ATTACK_303': 3.165, + 'GROW_CURVE_ATTACK_304': 2.639, + 'GROW_CURVE_ATTACK_305': 2.438, + 'GROW_CURVE_CRITICAL_301': 1.767, + } + }, + '23': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.64, + 'GROW_CURVE_ATTACK_102': 2.804, + 'GROW_CURVE_ATTACK_103': 2.96, + 'GROW_CURVE_ATTACK_104': 2.466, + 'GROW_CURVE_ATTACK_105': 2.28, + 'GROW_CURVE_CRITICAL_101': 1.767, + 'GROW_CURVE_ATTACK_201': 2.817, + 'GROW_CURVE_ATTACK_202': 2.987, + 'GROW_CURVE_ATTACK_203': 3.148, + 'GROW_CURVE_ATTACK_204': 2.634, + 'GROW_CURVE_ATTACK_205': 2.44, + 'GROW_CURVE_CRITICAL_201': 1.767, + 'GROW_CURVE_ATTACK_301': 2.915, + 'GROW_CURVE_ATTACK_302': 3.101, + 'GROW_CURVE_ATTACK_303': 3.274, + 'GROW_CURVE_ATTACK_304': 2.717, + 'GROW_CURVE_ATTACK_305': 2.503, + 'GROW_CURVE_CRITICAL_301': 1.767, + } + }, + '24': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.713, + 'GROW_CURVE_ATTACK_102': 2.887, + 'GROW_CURVE_ATTACK_103': 3.051, + 'GROW_CURVE_ATTACK_104': 2.529, + 'GROW_CURVE_ATTACK_105': 2.333, + 'GROW_CURVE_CRITICAL_101': 1.767, + 'GROW_CURVE_ATTACK_201': 2.899, + 'GROW_CURVE_ATTACK_202': 3.08, + 'GROW_CURVE_ATTACK_203': 3.25, + 'GROW_CURVE_ATTACK_204': 2.707, + 'GROW_CURVE_ATTACK_205': 2.501, + 'GROW_CURVE_CRITICAL_201': 1.767, + 'GROW_CURVE_ATTACK_301': 3.004, + 'GROW_CURVE_ATTACK_302': 3.2, + 'GROW_CURVE_ATTACK_303': 3.384, + 'GROW_CURVE_ATTACK_304': 2.794, + 'GROW_CURVE_ATTACK_305': 2.568, + 'GROW_CURVE_CRITICAL_301': 1.767, + } + }, + '25': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.786, + 'GROW_CURVE_ATTACK_102': 2.969, + 'GROW_CURVE_ATTACK_103': 3.143, + 'GROW_CURVE_ATTACK_104': 2.591, + 'GROW_CURVE_ATTACK_105': 2.385, + 'GROW_CURVE_CRITICAL_101': 1.969, + 'GROW_CURVE_ATTACK_201': 2.982, + 'GROW_CURVE_ATTACK_202': 3.172, + 'GROW_CURVE_ATTACK_203': 3.352, + 'GROW_CURVE_ATTACK_204': 2.778, + 'GROW_CURVE_ATTACK_205': 2.562, + 'GROW_CURVE_CRITICAL_201': 1.969, + 'GROW_CURVE_ATTACK_301': 3.093, + 'GROW_CURVE_ATTACK_302': 3.3, + 'GROW_CURVE_ATTACK_303': 3.493, + 'GROW_CURVE_ATTACK_304': 2.871, + 'GROW_CURVE_ATTACK_305': 2.633, + 'GROW_CURVE_CRITICAL_301': 1.969, + } + }, + '26': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.859, + 'GROW_CURVE_ATTACK_102': 3.052, + 'GROW_CURVE_ATTACK_103': 3.234, + 'GROW_CURVE_ATTACK_104': 2.654, + 'GROW_CURVE_ATTACK_105': 2.436, + 'GROW_CURVE_CRITICAL_101': 1.969, + 'GROW_CURVE_ATTACK_201': 3.064, + 'GROW_CURVE_ATTACK_202': 3.265, + 'GROW_CURVE_ATTACK_203': 3.454, + 'GROW_CURVE_ATTACK_204': 2.85, + 'GROW_CURVE_ATTACK_205': 2.622, + 'GROW_CURVE_CRITICAL_201': 1.969, + 'GROW_CURVE_ATTACK_301': 3.182, + 'GROW_CURVE_ATTACK_302': 3.4, + 'GROW_CURVE_ATTACK_303': 3.604, + 'GROW_CURVE_ATTACK_304': 2.948, + 'GROW_CURVE_ATTACK_305': 2.697, + 'GROW_CURVE_CRITICAL_301': 1.969, + } + }, + '27': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 2.931, + 'GROW_CURVE_ATTACK_102': 3.134, + 'GROW_CURVE_ATTACK_103': 3.326, + 'GROW_CURVE_ATTACK_104': 2.716, + 'GROW_CURVE_ATTACK_105': 2.487, + 'GROW_CURVE_CRITICAL_101': 1.969, + 'GROW_CURVE_ATTACK_201': 3.147, + 'GROW_CURVE_ATTACK_202': 3.358, + 'GROW_CURVE_ATTACK_203': 3.557, + 'GROW_CURVE_ATTACK_204': 2.922, + 'GROW_CURVE_ATTACK_205': 2.682, + 'GROW_CURVE_CRITICAL_201': 1.969, + 'GROW_CURVE_ATTACK_301': 3.271, + 'GROW_CURVE_ATTACK_302': 3.5, + 'GROW_CURVE_ATTACK_303': 3.714, + 'GROW_CURVE_ATTACK_304': 3.026, + 'GROW_CURVE_ATTACK_305': 2.762, + 'GROW_CURVE_CRITICAL_301': 1.969, + } + }, + '28': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.004, + 'GROW_CURVE_ATTACK_102': 3.217, + 'GROW_CURVE_ATTACK_103': 3.418, + 'GROW_CURVE_ATTACK_104': 2.778, + 'GROW_CURVE_ATTACK_105': 2.538, + 'GROW_CURVE_CRITICAL_101': 1.969, + 'GROW_CURVE_ATTACK_201': 3.229, + 'GROW_CURVE_ATTACK_202': 3.451, + 'GROW_CURVE_ATTACK_203': 3.66, + 'GROW_CURVE_ATTACK_204': 2.993, + 'GROW_CURVE_ATTACK_205': 2.741, + 'GROW_CURVE_CRITICAL_201': 1.969, + 'GROW_CURVE_ATTACK_301': 3.36, + 'GROW_CURVE_ATTACK_302': 3.601, + 'GROW_CURVE_ATTACK_303': 3.825, + 'GROW_CURVE_ATTACK_304': 3.103, + 'GROW_CURVE_ATTACK_305': 2.826, + 'GROW_CURVE_CRITICAL_301': 1.969, + } + }, + '29': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.076, + 'GROW_CURVE_ATTACK_102': 3.299, + 'GROW_CURVE_ATTACK_103': 3.51, + 'GROW_CURVE_ATTACK_104': 2.84, + 'GROW_CURVE_ATTACK_105': 2.588, + 'GROW_CURVE_CRITICAL_101': 1.969, + 'GROW_CURVE_ATTACK_201': 3.312, + 'GROW_CURVE_ATTACK_202': 3.544, + 'GROW_CURVE_ATTACK_203': 3.762, + 'GROW_CURVE_ATTACK_204': 3.065, + 'GROW_CURVE_ATTACK_205': 2.801, + 'GROW_CURVE_CRITICAL_201': 1.969, + 'GROW_CURVE_ATTACK_301': 3.45, + 'GROW_CURVE_ATTACK_302': 3.701, + 'GROW_CURVE_ATTACK_303': 3.937, + 'GROW_CURVE_ATTACK_304': 3.18, + 'GROW_CURVE_ATTACK_305': 2.89, + 'GROW_CURVE_CRITICAL_301': 1.969, + } + }, + '30': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.148, + 'GROW_CURVE_ATTACK_102': 3.382, + 'GROW_CURVE_ATTACK_103': 3.602, + 'GROW_CURVE_ATTACK_104': 2.901, + 'GROW_CURVE_ATTACK_105': 2.638, + 'GROW_CURVE_CRITICAL_101': 2.171, + 'GROW_CURVE_ATTACK_201': 3.394, + 'GROW_CURVE_ATTACK_202': 3.637, + 'GROW_CURVE_ATTACK_203': 3.866, + 'GROW_CURVE_ATTACK_204': 3.136, + 'GROW_CURVE_ATTACK_205': 2.86, + 'GROW_CURVE_CRITICAL_201': 2.171, + 'GROW_CURVE_ATTACK_301': 3.539, + 'GROW_CURVE_ATTACK_302': 3.803, + 'GROW_CURVE_ATTACK_303': 4.049, + 'GROW_CURVE_ATTACK_304': 3.257, + 'GROW_CURVE_ATTACK_305': 2.954, + 'GROW_CURVE_CRITICAL_301': 2.171, + } + }, + '31': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.221, + 'GROW_CURVE_ATTACK_102': 3.464, + 'GROW_CURVE_ATTACK_103': 3.694, + 'GROW_CURVE_ATTACK_104': 2.962, + 'GROW_CURVE_ATTACK_105': 2.688, + 'GROW_CURVE_CRITICAL_101': 2.171, + 'GROW_CURVE_ATTACK_201': 3.477, + 'GROW_CURVE_ATTACK_202': 3.731, + 'GROW_CURVE_ATTACK_203': 3.969, + 'GROW_CURVE_ATTACK_204': 3.207, + 'GROW_CURVE_ATTACK_205': 2.919, + 'GROW_CURVE_CRITICAL_201': 2.171, + 'GROW_CURVE_ATTACK_301': 3.629, + 'GROW_CURVE_ATTACK_302': 3.904, + 'GROW_CURVE_ATTACK_303': 4.161, + 'GROW_CURVE_ATTACK_304': 3.334, + 'GROW_CURVE_ATTACK_305': 3.018, + 'GROW_CURVE_CRITICAL_301': 2.171, + } + }, + '32': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.293, + 'GROW_CURVE_ATTACK_102': 3.547, + 'GROW_CURVE_ATTACK_103': 3.787, + 'GROW_CURVE_ATTACK_104': 3.023, + 'GROW_CURVE_ATTACK_105': 2.737, + 'GROW_CURVE_CRITICAL_101': 2.171, + 'GROW_CURVE_ATTACK_201': 3.56, + 'GROW_CURVE_ATTACK_202': 3.824, + 'GROW_CURVE_ATTACK_203': 4.073, + 'GROW_CURVE_ATTACK_204': 3.278, + 'GROW_CURVE_ATTACK_205': 2.978, + 'GROW_CURVE_CRITICAL_201': 2.171, + 'GROW_CURVE_ATTACK_301': 3.719, + 'GROW_CURVE_ATTACK_302': 4.005, + 'GROW_CURVE_ATTACK_303': 4.273, + 'GROW_CURVE_ATTACK_304': 3.412, + 'GROW_CURVE_ATTACK_305': 3.082, + 'GROW_CURVE_CRITICAL_301': 2.171, + } + }, + '33': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.365, + 'GROW_CURVE_ATTACK_102': 3.629, + 'GROW_CURVE_ATTACK_103': 3.879, + 'GROW_CURVE_ATTACK_104': 3.084, + 'GROW_CURVE_ATTACK_105': 2.786, + 'GROW_CURVE_CRITICAL_101': 2.171, + 'GROW_CURVE_ATTACK_201': 3.642, + 'GROW_CURVE_ATTACK_202': 3.918, + 'GROW_CURVE_ATTACK_203': 4.177, + 'GROW_CURVE_ATTACK_204': 3.349, + 'GROW_CURVE_ATTACK_205': 3.036, + 'GROW_CURVE_CRITICAL_201': 2.171, + 'GROW_CURVE_ATTACK_301': 3.809, + 'GROW_CURVE_ATTACK_302': 4.107, + 'GROW_CURVE_ATTACK_303': 4.386, + 'GROW_CURVE_ATTACK_304': 3.489, + 'GROW_CURVE_ATTACK_305': 3.145, + 'GROW_CURVE_CRITICAL_301': 2.171, + } + }, + '34': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.437, + 'GROW_CURVE_ATTACK_102': 3.712, + 'GROW_CURVE_ATTACK_103': 3.972, + 'GROW_CURVE_ATTACK_104': 3.145, + 'GROW_CURVE_ATTACK_105': 2.835, + 'GROW_CURVE_CRITICAL_101': 2.171, + 'GROW_CURVE_ATTACK_201': 3.725, + 'GROW_CURVE_ATTACK_202': 4.011, + 'GROW_CURVE_ATTACK_203': 4.281, + 'GROW_CURVE_ATTACK_204': 3.42, + 'GROW_CURVE_ATTACK_205': 3.094, + 'GROW_CURVE_CRITICAL_201': 2.171, + 'GROW_CURVE_ATTACK_301': 3.899, + 'GROW_CURVE_ATTACK_302': 4.209, + 'GROW_CURVE_ATTACK_303': 4.499, + 'GROW_CURVE_ATTACK_304': 3.566, + 'GROW_CURVE_ATTACK_305': 3.209, + 'GROW_CURVE_CRITICAL_301': 2.171, + } + }, + '35': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.508, + 'GROW_CURVE_ATTACK_102': 3.794, + 'GROW_CURVE_ATTACK_103': 4.064, + 'GROW_CURVE_ATTACK_104': 3.205, + 'GROW_CURVE_ATTACK_105': 2.883, + 'GROW_CURVE_CRITICAL_101': 2.373, + 'GROW_CURVE_ATTACK_201': 3.807, + 'GROW_CURVE_ATTACK_202': 4.105, + 'GROW_CURVE_ATTACK_203': 4.385, + 'GROW_CURVE_ATTACK_204': 3.49, + 'GROW_CURVE_ATTACK_205': 3.152, + 'GROW_CURVE_CRITICAL_201': 2.373, + 'GROW_CURVE_ATTACK_301': 3.989, + 'GROW_CURVE_ATTACK_302': 4.312, + 'GROW_CURVE_ATTACK_303': 4.613, + 'GROW_CURVE_ATTACK_304': 3.644, + 'GROW_CURVE_ATTACK_305': 3.272, + 'GROW_CURVE_CRITICAL_301': 2.373, + } + }, + '36': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.58, + 'GROW_CURVE_ATTACK_102': 3.877, + 'GROW_CURVE_ATTACK_103': 4.157, + 'GROW_CURVE_ATTACK_104': 3.265, + 'GROW_CURVE_ATTACK_105': 2.931, + 'GROW_CURVE_CRITICAL_101': 2.373, + 'GROW_CURVE_ATTACK_201': 3.89, + 'GROW_CURVE_ATTACK_202': 4.199, + 'GROW_CURVE_ATTACK_203': 4.489, + 'GROW_CURVE_ATTACK_204': 3.561, + 'GROW_CURVE_ATTACK_205': 3.21, + 'GROW_CURVE_CRITICAL_201': 2.373, + 'GROW_CURVE_ATTACK_301': 4.08, + 'GROW_CURVE_ATTACK_302': 4.414, + 'GROW_CURVE_ATTACK_303': 4.727, + 'GROW_CURVE_ATTACK_304': 3.721, + 'GROW_CURVE_ATTACK_305': 3.336, + 'GROW_CURVE_CRITICAL_301': 2.373, + } + }, + '37': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.652, + 'GROW_CURVE_ATTACK_102': 3.959, + 'GROW_CURVE_ATTACK_103': 4.25, + 'GROW_CURVE_ATTACK_104': 3.325, + 'GROW_CURVE_ATTACK_105': 2.979, + 'GROW_CURVE_CRITICAL_101': 2.373, + 'GROW_CURVE_ATTACK_201': 3.972, + 'GROW_CURVE_ATTACK_202': 4.293, + 'GROW_CURVE_ATTACK_203': 4.594, + 'GROW_CURVE_ATTACK_204': 3.632, + 'GROW_CURVE_ATTACK_205': 3.268, + 'GROW_CURVE_CRITICAL_201': 2.373, + 'GROW_CURVE_ATTACK_301': 4.17, + 'GROW_CURVE_ATTACK_302': 4.517, + 'GROW_CURVE_ATTACK_303': 4.841, + 'GROW_CURVE_ATTACK_304': 3.798, + 'GROW_CURVE_ATTACK_305': 3.399, + 'GROW_CURVE_CRITICAL_301': 2.373, + } + }, + '38': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.723, + 'GROW_CURVE_ATTACK_102': 4.042, + 'GROW_CURVE_ATTACK_103': 4.342, + 'GROW_CURVE_ATTACK_104': 3.385, + 'GROW_CURVE_ATTACK_105': 3.027, + 'GROW_CURVE_CRITICAL_101': 2.373, + 'GROW_CURVE_ATTACK_201': 4.055, + 'GROW_CURVE_ATTACK_202': 4.387, + 'GROW_CURVE_ATTACK_203': 4.699, + 'GROW_CURVE_ATTACK_204': 3.702, + 'GROW_CURVE_ATTACK_205': 3.325, + 'GROW_CURVE_CRITICAL_201': 2.373, + 'GROW_CURVE_ATTACK_301': 4.261, + 'GROW_CURVE_ATTACK_302': 4.62, + 'GROW_CURVE_ATTACK_303': 4.956, + 'GROW_CURVE_ATTACK_304': 3.876, + 'GROW_CURVE_ATTACK_305': 3.462, + 'GROW_CURVE_CRITICAL_301': 2.373, + } + }, + '39': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.794, + 'GROW_CURVE_ATTACK_102': 4.124, + 'GROW_CURVE_ATTACK_103': 4.435, + 'GROW_CURVE_ATTACK_104': 3.445, + 'GROW_CURVE_ATTACK_105': 3.074, + 'GROW_CURVE_CRITICAL_101': 2.373, + 'GROW_CURVE_ATTACK_201': 4.138, + 'GROW_CURVE_ATTACK_202': 4.481, + 'GROW_CURVE_ATTACK_203': 4.803, + 'GROW_CURVE_ATTACK_204': 3.772, + 'GROW_CURVE_ATTACK_205': 3.382, + 'GROW_CURVE_CRITICAL_201': 2.373, + 'GROW_CURVE_ATTACK_301': 4.352, + 'GROW_CURVE_ATTACK_302': 4.723, + 'GROW_CURVE_ATTACK_303': 5.071, + 'GROW_CURVE_ATTACK_304': 3.953, + 'GROW_CURVE_ATTACK_305': 3.525, + 'GROW_CURVE_CRITICAL_301': 2.373, + } + }, + '40': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.866, + 'GROW_CURVE_ATTACK_102': 4.206, + 'GROW_CURVE_ATTACK_103': 4.528, + 'GROW_CURVE_ATTACK_104': 3.504, + 'GROW_CURVE_ATTACK_105': 3.121, + 'GROW_CURVE_CRITICAL_101': 2.575, + 'GROW_CURVE_ATTACK_201': 4.22, + 'GROW_CURVE_ATTACK_202': 4.575, + 'GROW_CURVE_ATTACK_203': 4.909, + 'GROW_CURVE_ATTACK_204': 3.842, + 'GROW_CURVE_ATTACK_205': 3.439, + 'GROW_CURVE_CRITICAL_201': 2.575, + 'GROW_CURVE_ATTACK_301': 4.443, + 'GROW_CURVE_ATTACK_302': 4.827, + 'GROW_CURVE_ATTACK_303': 5.186, + 'GROW_CURVE_ATTACK_304': 4.031, + 'GROW_CURVE_ATTACK_305': 3.588, + 'GROW_CURVE_CRITICAL_301': 2.575, + } + }, + '41': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 3.937, + 'GROW_CURVE_ATTACK_102': 4.289, + 'GROW_CURVE_ATTACK_103': 4.621, + 'GROW_CURVE_ATTACK_104': 3.564, + 'GROW_CURVE_ATTACK_105': 3.167, + 'GROW_CURVE_CRITICAL_101': 2.575, + 'GROW_CURVE_ATTACK_201': 4.303, + 'GROW_CURVE_ATTACK_202': 4.669, + 'GROW_CURVE_ATTACK_203': 5.014, + 'GROW_CURVE_ATTACK_204': 3.913, + 'GROW_CURVE_ATTACK_205': 3.496, + 'GROW_CURVE_CRITICAL_201': 2.575, + 'GROW_CURVE_ATTACK_301': 4.534, + 'GROW_CURVE_ATTACK_302': 4.931, + 'GROW_CURVE_ATTACK_303': 5.301, + 'GROW_CURVE_ATTACK_304': 4.109, + 'GROW_CURVE_ATTACK_305': 3.651, + 'GROW_CURVE_CRITICAL_301': 2.575, + } + }, + '42': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.008, + 'GROW_CURVE_ATTACK_102': 4.371, + 'GROW_CURVE_ATTACK_103': 4.714, + 'GROW_CURVE_ATTACK_104': 3.623, + 'GROW_CURVE_ATTACK_105': 3.214, + 'GROW_CURVE_CRITICAL_101': 2.575, + 'GROW_CURVE_ATTACK_201': 4.385, + 'GROW_CURVE_ATTACK_202': 4.763, + 'GROW_CURVE_ATTACK_203': 5.119, + 'GROW_CURVE_ATTACK_204': 3.983, + 'GROW_CURVE_ATTACK_205': 3.553, + 'GROW_CURVE_CRITICAL_201': 2.575, + 'GROW_CURVE_ATTACK_301': 4.625, + 'GROW_CURVE_ATTACK_302': 5.035, + 'GROW_CURVE_ATTACK_303': 5.417, + 'GROW_CURVE_ATTACK_304': 4.186, + 'GROW_CURVE_ATTACK_305': 3.714, + 'GROW_CURVE_CRITICAL_301': 2.575, + } + }, + '43': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.079, + 'GROW_CURVE_ATTACK_102': 4.454, + 'GROW_CURVE_ATTACK_103': 4.808, + 'GROW_CURVE_ATTACK_104': 3.682, + 'GROW_CURVE_ATTACK_105': 3.26, + 'GROW_CURVE_CRITICAL_101': 2.575, + 'GROW_CURVE_ATTACK_201': 4.468, + 'GROW_CURVE_ATTACK_202': 4.858, + 'GROW_CURVE_ATTACK_203': 5.225, + 'GROW_CURVE_ATTACK_204': 4.053, + 'GROW_CURVE_ATTACK_205': 3.609, + 'GROW_CURVE_CRITICAL_201': 2.575, + 'GROW_CURVE_ATTACK_301': 4.717, + 'GROW_CURVE_ATTACK_302': 5.139, + 'GROW_CURVE_ATTACK_303': 5.533, + 'GROW_CURVE_ATTACK_304': 4.264, + 'GROW_CURVE_ATTACK_305': 3.777, + 'GROW_CURVE_CRITICAL_301': 2.575, + } + }, + '44': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.15, + 'GROW_CURVE_ATTACK_102': 4.536, + 'GROW_CURVE_ATTACK_103': 4.901, + 'GROW_CURVE_ATTACK_104': 3.741, + 'GROW_CURVE_ATTACK_105': 3.306, + 'GROW_CURVE_CRITICAL_101': 2.575, + 'GROW_CURVE_ATTACK_201': 4.55, + 'GROW_CURVE_ATTACK_202': 4.952, + 'GROW_CURVE_ATTACK_203': 5.33, + 'GROW_CURVE_ATTACK_204': 4.122, + 'GROW_CURVE_ATTACK_205': 3.666, + 'GROW_CURVE_CRITICAL_201': 2.575, + 'GROW_CURVE_ATTACK_301': 4.808, + 'GROW_CURVE_ATTACK_302': 5.243, + 'GROW_CURVE_ATTACK_303': 5.65, + 'GROW_CURVE_ATTACK_304': 4.342, + 'GROW_CURVE_ATTACK_305': 3.84, + 'GROW_CURVE_CRITICAL_301': 2.575, + } + }, + '45': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.221, + 'GROW_CURVE_ATTACK_102': 4.618, + 'GROW_CURVE_ATTACK_103': 4.994, + 'GROW_CURVE_ATTACK_104': 3.799, + 'GROW_CURVE_ATTACK_105': 3.351, + 'GROW_CURVE_CRITICAL_101': 2.777, + 'GROW_CURVE_ATTACK_201': 4.633, + 'GROW_CURVE_ATTACK_202': 5.047, + 'GROW_CURVE_ATTACK_203': 5.436, + 'GROW_CURVE_ATTACK_204': 4.192, + 'GROW_CURVE_ATTACK_205': 3.722, + 'GROW_CURVE_CRITICAL_201': 2.777, + 'GROW_CURVE_ATTACK_301': 4.9, + 'GROW_CURVE_ATTACK_302': 5.348, + 'GROW_CURVE_ATTACK_303': 5.767, + 'GROW_CURVE_ATTACK_304': 4.419, + 'GROW_CURVE_ATTACK_305': 3.903, + 'GROW_CURVE_CRITICAL_301': 2.777, + } + }, + '46': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.291, + 'GROW_CURVE_ATTACK_102': 4.701, + 'GROW_CURVE_ATTACK_103': 5.087, + 'GROW_CURVE_ATTACK_104': 3.858, + 'GROW_CURVE_ATTACK_105': 3.397, + 'GROW_CURVE_CRITICAL_101': 2.777, + 'GROW_CURVE_ATTACK_201': 4.716, + 'GROW_CURVE_ATTACK_202': 5.142, + 'GROW_CURVE_ATTACK_203': 5.542, + 'GROW_CURVE_ATTACK_204': 4.262, + 'GROW_CURVE_ATTACK_205': 3.778, + 'GROW_CURVE_CRITICAL_201': 2.777, + 'GROW_CURVE_ATTACK_301': 4.992, + 'GROW_CURVE_ATTACK_302': 5.453, + 'GROW_CURVE_ATTACK_303': 5.884, + 'GROW_CURVE_ATTACK_304': 4.497, + 'GROW_CURVE_ATTACK_305': 3.966, + 'GROW_CURVE_CRITICAL_301': 2.777, + } + }, + '47': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.362, + 'GROW_CURVE_ATTACK_102': 4.783, + 'GROW_CURVE_ATTACK_103': 5.181, + 'GROW_CURVE_ATTACK_104': 3.916, + 'GROW_CURVE_ATTACK_105': 3.442, + 'GROW_CURVE_CRITICAL_101': 2.777, + 'GROW_CURVE_ATTACK_201': 4.798, + 'GROW_CURVE_ATTACK_202': 5.236, + 'GROW_CURVE_ATTACK_203': 5.648, + 'GROW_CURVE_ATTACK_204': 4.332, + 'GROW_CURVE_ATTACK_205': 3.834, + 'GROW_CURVE_CRITICAL_201': 2.777, + 'GROW_CURVE_ATTACK_301': 5.084, + 'GROW_CURVE_ATTACK_302': 5.558, + 'GROW_CURVE_ATTACK_303': 6.001, + 'GROW_CURVE_ATTACK_304': 4.575, + 'GROW_CURVE_ATTACK_305': 4.029, + 'GROW_CURVE_CRITICAL_301': 2.777, + } + }, + '48': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.433, + 'GROW_CURVE_ATTACK_102': 4.865, + 'GROW_CURVE_ATTACK_103': 5.274, + 'GROW_CURVE_ATTACK_104': 3.974, + 'GROW_CURVE_ATTACK_105': 3.487, + 'GROW_CURVE_CRITICAL_101': 2.777, + 'GROW_CURVE_ATTACK_201': 4.881, + 'GROW_CURVE_ATTACK_202': 5.331, + 'GROW_CURVE_ATTACK_203': 5.755, + 'GROW_CURVE_ATTACK_204': 4.401, + 'GROW_CURVE_ATTACK_205': 3.889, + 'GROW_CURVE_CRITICAL_201': 2.777, + 'GROW_CURVE_ATTACK_301': 5.176, + 'GROW_CURVE_ATTACK_302': 5.663, + 'GROW_CURVE_ATTACK_303': 6.118, + 'GROW_CURVE_ATTACK_304': 4.653, + 'GROW_CURVE_ATTACK_305': 4.092, + 'GROW_CURVE_CRITICAL_301': 2.777, + } + }, + '49': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.503, + 'GROW_CURVE_ATTACK_102': 4.948, + 'GROW_CURVE_ATTACK_103': 5.367, + 'GROW_CURVE_ATTACK_104': 4.032, + 'GROW_CURVE_ATTACK_105': 3.532, + 'GROW_CURVE_CRITICAL_101': 2.777, + 'GROW_CURVE_ATTACK_201': 4.963, + 'GROW_CURVE_ATTACK_202': 5.426, + 'GROW_CURVE_ATTACK_203': 5.861, + 'GROW_CURVE_ATTACK_204': 4.471, + 'GROW_CURVE_ATTACK_205': 3.945, + 'GROW_CURVE_CRITICAL_201': 2.777, + 'GROW_CURVE_ATTACK_301': 5.268, + 'GROW_CURVE_ATTACK_302': 5.768, + 'GROW_CURVE_ATTACK_303': 6.236, + 'GROW_CURVE_ATTACK_304': 4.731, + 'GROW_CURVE_ATTACK_305': 4.155, + 'GROW_CURVE_CRITICAL_301': 2.777, + } + }, + '50': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.574, + 'GROW_CURVE_ATTACK_102': 5.03, + 'GROW_CURVE_ATTACK_103': 5.461, + 'GROW_CURVE_ATTACK_104': 4.09, + 'GROW_CURVE_ATTACK_105': 3.576, + 'GROW_CURVE_CRITICAL_101': 2.979, + 'GROW_CURVE_ATTACK_201': 5.046, + 'GROW_CURVE_ATTACK_202': 5.521, + 'GROW_CURVE_ATTACK_203': 5.968, + 'GROW_CURVE_ATTACK_204': 4.54, + 'GROW_CURVE_ATTACK_205': 4, + 'GROW_CURVE_CRITICAL_201': 2.979, + 'GROW_CURVE_ATTACK_301': 5.36, + 'GROW_CURVE_ATTACK_302': 5.874, + 'GROW_CURVE_ATTACK_303': 6.354, + 'GROW_CURVE_ATTACK_304': 4.81, + 'GROW_CURVE_ATTACK_305': 4.217, + 'GROW_CURVE_CRITICAL_301': 2.979, + } + }, + '51': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.644, + 'GROW_CURVE_ATTACK_102': 5.112, + 'GROW_CURVE_ATTACK_103': 5.554, + 'GROW_CURVE_ATTACK_104': 4.148, + 'GROW_CURVE_ATTACK_105': 3.62, + 'GROW_CURVE_CRITICAL_101': 2.979, + 'GROW_CURVE_ATTACK_201': 5.128, + 'GROW_CURVE_ATTACK_202': 5.616, + 'GROW_CURVE_ATTACK_203': 6.074, + 'GROW_CURVE_ATTACK_204': 4.609, + 'GROW_CURVE_ATTACK_205': 4.056, + 'GROW_CURVE_CRITICAL_201': 2.979, + 'GROW_CURVE_ATTACK_301': 5.453, + 'GROW_CURVE_ATTACK_302': 5.98, + 'GROW_CURVE_ATTACK_303': 6.473, + 'GROW_CURVE_ATTACK_304': 4.888, + 'GROW_CURVE_ATTACK_305': 4.28, + 'GROW_CURVE_CRITICAL_301': 2.979, + } + }, + '52': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.714, + 'GROW_CURVE_ATTACK_102': 5.194, + 'GROW_CURVE_ATTACK_103': 5.648, + 'GROW_CURVE_ATTACK_104': 4.205, + 'GROW_CURVE_ATTACK_105': 3.665, + 'GROW_CURVE_CRITICAL_101': 2.979, + 'GROW_CURVE_ATTACK_201': 5.211, + 'GROW_CURVE_ATTACK_202': 5.711, + 'GROW_CURVE_ATTACK_203': 6.181, + 'GROW_CURVE_ATTACK_204': 4.679, + 'GROW_CURVE_ATTACK_205': 4.111, + 'GROW_CURVE_CRITICAL_201': 2.979, + 'GROW_CURVE_ATTACK_301': 5.546, + 'GROW_CURVE_ATTACK_302': 6.086, + 'GROW_CURVE_ATTACK_303': 6.592, + 'GROW_CURVE_ATTACK_304': 4.966, + 'GROW_CURVE_ATTACK_305': 4.343, + 'GROW_CURVE_CRITICAL_301': 2.979, + } + }, + '53': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.784, + 'GROW_CURVE_ATTACK_102': 5.277, + 'GROW_CURVE_ATTACK_103': 5.742, + 'GROW_CURVE_ATTACK_104': 4.263, + 'GROW_CURVE_ATTACK_105': 3.708, + 'GROW_CURVE_CRITICAL_101': 2.979, + 'GROW_CURVE_ATTACK_201': 5.294, + 'GROW_CURVE_ATTACK_202': 5.806, + 'GROW_CURVE_ATTACK_203': 6.288, + 'GROW_CURVE_ATTACK_204': 4.748, + 'GROW_CURVE_ATTACK_205': 4.166, + 'GROW_CURVE_CRITICAL_201': 2.979, + 'GROW_CURVE_ATTACK_301': 5.638, + 'GROW_CURVE_ATTACK_302': 6.192, + 'GROW_CURVE_ATTACK_303': 6.71, + 'GROW_CURVE_ATTACK_304': 5.044, + 'GROW_CURVE_ATTACK_305': 4.406, + 'GROW_CURVE_CRITICAL_301': 2.979, + } + }, + '54': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.855, + 'GROW_CURVE_ATTACK_102': 5.359, + 'GROW_CURVE_ATTACK_103': 5.835, + 'GROW_CURVE_ATTACK_104': 4.32, + 'GROW_CURVE_ATTACK_105': 3.752, + 'GROW_CURVE_CRITICAL_101': 2.979, + 'GROW_CURVE_ATTACK_201': 5.376, + 'GROW_CURVE_ATTACK_202': 5.901, + 'GROW_CURVE_ATTACK_203': 6.395, + 'GROW_CURVE_ATTACK_204': 4.817, + 'GROW_CURVE_ATTACK_205': 4.221, + 'GROW_CURVE_CRITICAL_201': 2.979, + 'GROW_CURVE_ATTACK_301': 5.731, + 'GROW_CURVE_ATTACK_302': 6.299, + 'GROW_CURVE_ATTACK_303': 6.83, + 'GROW_CURVE_ATTACK_304': 5.123, + 'GROW_CURVE_ATTACK_305': 4.469, + 'GROW_CURVE_CRITICAL_301': 2.979, + } + }, + '55': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.925, + 'GROW_CURVE_ATTACK_102': 5.441, + 'GROW_CURVE_ATTACK_103': 5.929, + 'GROW_CURVE_ATTACK_104': 4.377, + 'GROW_CURVE_ATTACK_105': 3.796, + 'GROW_CURVE_CRITICAL_101': 3.181, + 'GROW_CURVE_ATTACK_201': 5.459, + 'GROW_CURVE_ATTACK_202': 5.996, + 'GROW_CURVE_ATTACK_203': 6.502, + 'GROW_CURVE_ATTACK_204': 4.886, + 'GROW_CURVE_ATTACK_205': 4.275, + 'GROW_CURVE_CRITICAL_201': 3.181, + 'GROW_CURVE_ATTACK_301': 5.825, + 'GROW_CURVE_ATTACK_302': 6.406, + 'GROW_CURVE_ATTACK_303': 6.949, + 'GROW_CURVE_ATTACK_304': 5.201, + 'GROW_CURVE_ATTACK_305': 4.532, + 'GROW_CURVE_CRITICAL_301': 3.181, + } + }, + '56': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 4.995, + 'GROW_CURVE_ATTACK_102': 5.523, + 'GROW_CURVE_ATTACK_103': 6.023, + 'GROW_CURVE_ATTACK_104': 4.434, + 'GROW_CURVE_ATTACK_105': 3.839, + 'GROW_CURVE_CRITICAL_101': 3.181, + 'GROW_CURVE_ATTACK_201': 5.541, + 'GROW_CURVE_ATTACK_202': 6.092, + 'GROW_CURVE_ATTACK_203': 6.609, + 'GROW_CURVE_ATTACK_204': 4.955, + 'GROW_CURVE_ATTACK_205': 4.33, + 'GROW_CURVE_CRITICAL_201': 3.181, + 'GROW_CURVE_ATTACK_301': 5.918, + 'GROW_CURVE_ATTACK_302': 6.513, + 'GROW_CURVE_ATTACK_303': 7.069, + 'GROW_CURVE_ATTACK_304': 5.28, + 'GROW_CURVE_ATTACK_305': 4.594, + 'GROW_CURVE_CRITICAL_301': 3.181, + } + }, + '57': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.065, + 'GROW_CURVE_ATTACK_102': 5.605, + 'GROW_CURVE_ATTACK_103': 6.116, + 'GROW_CURVE_ATTACK_104': 4.491, + 'GROW_CURVE_ATTACK_105': 3.882, + 'GROW_CURVE_CRITICAL_101': 3.181, + 'GROW_CURVE_ATTACK_201': 5.624, + 'GROW_CURVE_ATTACK_202': 6.187, + 'GROW_CURVE_ATTACK_203': 6.717, + 'GROW_CURVE_ATTACK_204': 5.024, + 'GROW_CURVE_ATTACK_205': 4.384, + 'GROW_CURVE_CRITICAL_201': 3.181, + 'GROW_CURVE_ATTACK_301': 6.011, + 'GROW_CURVE_ATTACK_302': 6.62, + 'GROW_CURVE_ATTACK_303': 7.189, + 'GROW_CURVE_ATTACK_304': 5.359, + 'GROW_CURVE_ATTACK_305': 4.657, + 'GROW_CURVE_CRITICAL_301': 3.181, + } + }, + '58': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.134, + 'GROW_CURVE_ATTACK_102': 5.688, + 'GROW_CURVE_ATTACK_103': 6.21, + 'GROW_CURVE_ATTACK_104': 4.548, + 'GROW_CURVE_ATTACK_105': 3.925, + 'GROW_CURVE_CRITICAL_101': 3.181, + 'GROW_CURVE_ATTACK_201': 5.706, + 'GROW_CURVE_ATTACK_202': 6.282, + 'GROW_CURVE_ATTACK_203': 6.824, + 'GROW_CURVE_ATTACK_204': 5.093, + 'GROW_CURVE_ATTACK_205': 4.439, + 'GROW_CURVE_CRITICAL_201': 3.181, + 'GROW_CURVE_ATTACK_301': 6.105, + 'GROW_CURVE_ATTACK_302': 6.727, + 'GROW_CURVE_ATTACK_303': 7.309, + 'GROW_CURVE_ATTACK_304': 5.437, + 'GROW_CURVE_ATTACK_305': 4.72, + 'GROW_CURVE_CRITICAL_301': 3.181, + } + }, + '59': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.204, + 'GROW_CURVE_ATTACK_102': 5.77, + 'GROW_CURVE_ATTACK_103': 6.304, + 'GROW_CURVE_ATTACK_104': 4.605, + 'GROW_CURVE_ATTACK_105': 3.968, + 'GROW_CURVE_CRITICAL_101': 3.181, + 'GROW_CURVE_ATTACK_201': 5.789, + 'GROW_CURVE_ATTACK_202': 6.378, + 'GROW_CURVE_ATTACK_203': 6.932, + 'GROW_CURVE_ATTACK_204': 5.162, + 'GROW_CURVE_ATTACK_205': 4.493, + 'GROW_CURVE_CRITICAL_201': 3.181, + 'GROW_CURVE_ATTACK_301': 6.198, + 'GROW_CURVE_ATTACK_302': 6.835, + 'GROW_CURVE_ATTACK_303': 7.429, + 'GROW_CURVE_ATTACK_304': 5.516, + 'GROW_CURVE_ATTACK_305': 4.783, + 'GROW_CURVE_CRITICAL_301': 3.181, + } + }, + '60': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.274, + 'GROW_CURVE_ATTACK_102': 5.852, + 'GROW_CURVE_ATTACK_103': 6.398, + 'GROW_CURVE_ATTACK_104': 4.661, + 'GROW_CURVE_ATTACK_105': 4.01, + 'GROW_CURVE_CRITICAL_101': 3.383, + 'GROW_CURVE_ATTACK_201': 5.872, + 'GROW_CURVE_ATTACK_202': 6.473, + 'GROW_CURVE_ATTACK_203': 7.039, + 'GROW_CURVE_ATTACK_204': 5.231, + 'GROW_CURVE_ATTACK_205': 4.547, + 'GROW_CURVE_CRITICAL_201': 3.383, + 'GROW_CURVE_ATTACK_301': 6.292, + 'GROW_CURVE_ATTACK_302': 6.942, + 'GROW_CURVE_ATTACK_303': 7.55, + 'GROW_CURVE_ATTACK_304': 5.595, + 'GROW_CURVE_ATTACK_305': 4.846, + 'GROW_CURVE_CRITICAL_301': 3.383, + } + }, + '61': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.344, + 'GROW_CURVE_ATTACK_102': 5.934, + 'GROW_CURVE_ATTACK_103': 6.492, + 'GROW_CURVE_ATTACK_104': 4.718, + 'GROW_CURVE_ATTACK_105': 4.053, + 'GROW_CURVE_CRITICAL_101': 3.383, + 'GROW_CURVE_ATTACK_201': 5.954, + 'GROW_CURVE_ATTACK_202': 6.569, + 'GROW_CURVE_ATTACK_203': 7.147, + 'GROW_CURVE_ATTACK_204': 5.3, + 'GROW_CURVE_ATTACK_205': 4.601, + 'GROW_CURVE_CRITICAL_201': 3.383, + 'GROW_CURVE_ATTACK_301': 6.386, + 'GROW_CURVE_ATTACK_302': 7.05, + 'GROW_CURVE_ATTACK_303': 7.671, + 'GROW_CURVE_ATTACK_304': 5.674, + 'GROW_CURVE_ATTACK_305': 4.909, + 'GROW_CURVE_CRITICAL_301': 3.383, + } + }, + '62': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.413, + 'GROW_CURVE_ATTACK_102': 6.016, + 'GROW_CURVE_ATTACK_103': 6.586, + 'GROW_CURVE_ATTACK_104': 4.774, + 'GROW_CURVE_ATTACK_105': 4.095, + 'GROW_CURVE_CRITICAL_101': 3.383, + 'GROW_CURVE_ATTACK_201': 6.037, + 'GROW_CURVE_ATTACK_202': 6.664, + 'GROW_CURVE_ATTACK_203': 7.255, + 'GROW_CURVE_ATTACK_204': 5.368, + 'GROW_CURVE_ATTACK_205': 4.655, + 'GROW_CURVE_CRITICAL_201': 3.383, + 'GROW_CURVE_ATTACK_301': 6.48, + 'GROW_CURVE_ATTACK_302': 7.158, + 'GROW_CURVE_ATTACK_303': 7.792, + 'GROW_CURVE_ATTACK_304': 5.753, + 'GROW_CURVE_ATTACK_305': 4.972, + 'GROW_CURVE_CRITICAL_301': 3.383, + } + }, + '63': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.483, + 'GROW_CURVE_ATTACK_102': 6.098, + 'GROW_CURVE_ATTACK_103': 6.68, + 'GROW_CURVE_ATTACK_104': 4.83, + 'GROW_CURVE_ATTACK_105': 4.137, + 'GROW_CURVE_CRITICAL_101': 3.383, + 'GROW_CURVE_ATTACK_201': 6.119, + 'GROW_CURVE_ATTACK_202': 6.76, + 'GROW_CURVE_ATTACK_203': 7.363, + 'GROW_CURVE_ATTACK_204': 5.437, + 'GROW_CURVE_ATTACK_205': 4.709, + 'GROW_CURVE_CRITICAL_201': 3.383, + 'GROW_CURVE_ATTACK_301': 6.575, + 'GROW_CURVE_ATTACK_302': 7.267, + 'GROW_CURVE_ATTACK_303': 7.913, + 'GROW_CURVE_ATTACK_304': 5.833, + 'GROW_CURVE_ATTACK_305': 5.035, + 'GROW_CURVE_CRITICAL_301': 3.383, + } + }, + '64': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.552, + 'GROW_CURVE_ATTACK_102': 6.18, + 'GROW_CURVE_ATTACK_103': 6.774, + 'GROW_CURVE_ATTACK_104': 4.887, + 'GROW_CURVE_ATTACK_105': 4.179, + 'GROW_CURVE_CRITICAL_101': 3.383, + 'GROW_CURVE_ATTACK_201': 6.202, + 'GROW_CURVE_ATTACK_202': 6.856, + 'GROW_CURVE_ATTACK_203': 7.471, + 'GROW_CURVE_ATTACK_204': 5.506, + 'GROW_CURVE_ATTACK_205': 4.763, + 'GROW_CURVE_CRITICAL_201': 3.383, + 'GROW_CURVE_ATTACK_301': 6.669, + 'GROW_CURVE_ATTACK_302': 7.375, + 'GROW_CURVE_ATTACK_303': 8.035, + 'GROW_CURVE_ATTACK_304': 5.912, + 'GROW_CURVE_ATTACK_305': 5.098, + 'GROW_CURVE_CRITICAL_301': 3.383, + } + }, + '65': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.622, + 'GROW_CURVE_ATTACK_102': 6.262, + 'GROW_CURVE_ATTACK_103': 6.868, + 'GROW_CURVE_ATTACK_104': 4.943, + 'GROW_CURVE_ATTACK_105': 4.221, + 'GROW_CURVE_CRITICAL_101': 3.585, + 'GROW_CURVE_ATTACK_201': 6.284, + 'GROW_CURVE_ATTACK_202': 6.951, + 'GROW_CURVE_ATTACK_203': 7.579, + 'GROW_CURVE_ATTACK_204': 5.574, + 'GROW_CURVE_ATTACK_205': 4.816, + 'GROW_CURVE_CRITICAL_201': 3.585, + 'GROW_CURVE_ATTACK_301': 6.763, + 'GROW_CURVE_ATTACK_302': 7.484, + 'GROW_CURVE_ATTACK_303': 8.157, + 'GROW_CURVE_ATTACK_304': 5.991, + 'GROW_CURVE_ATTACK_305': 5.161, + 'GROW_CURVE_CRITICAL_301': 3.585, + } + }, + '66': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.691, + 'GROW_CURVE_ATTACK_102': 6.344, + 'GROW_CURVE_ATTACK_103': 6.962, + 'GROW_CURVE_ATTACK_104': 4.999, + 'GROW_CURVE_ATTACK_105': 4.263, + 'GROW_CURVE_CRITICAL_101': 3.585, + 'GROW_CURVE_ATTACK_201': 6.367, + 'GROW_CURVE_ATTACK_202': 7.047, + 'GROW_CURVE_ATTACK_203': 7.687, + 'GROW_CURVE_ATTACK_204': 5.643, + 'GROW_CURVE_ATTACK_205': 4.87, + 'GROW_CURVE_CRITICAL_201': 3.585, + 'GROW_CURVE_ATTACK_301': 6.858, + 'GROW_CURVE_ATTACK_302': 7.592, + 'GROW_CURVE_ATTACK_303': 8.279, + 'GROW_CURVE_ATTACK_304': 6.071, + 'GROW_CURVE_ATTACK_305': 5.225, + 'GROW_CURVE_CRITICAL_301': 3.585, + } + }, + '67': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.761, + 'GROW_CURVE_ATTACK_102': 6.427, + 'GROW_CURVE_ATTACK_103': 7.056, + 'GROW_CURVE_ATTACK_104': 5.054, + 'GROW_CURVE_ATTACK_105': 4.304, + 'GROW_CURVE_CRITICAL_101': 3.585, + 'GROW_CURVE_ATTACK_201': 6.45, + 'GROW_CURVE_ATTACK_202': 7.143, + 'GROW_CURVE_ATTACK_203': 7.795, + 'GROW_CURVE_ATTACK_204': 5.711, + 'GROW_CURVE_ATTACK_205': 4.923, + 'GROW_CURVE_CRITICAL_201': 3.585, + 'GROW_CURVE_ATTACK_301': 6.953, + 'GROW_CURVE_ATTACK_302': 7.701, + 'GROW_CURVE_ATTACK_303': 8.401, + 'GROW_CURVE_ATTACK_304': 6.15, + 'GROW_CURVE_ATTACK_305': 5.288, + 'GROW_CURVE_CRITICAL_301': 3.585, + } + }, + '68': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.83, + 'GROW_CURVE_ATTACK_102': 6.509, + 'GROW_CURVE_ATTACK_103': 7.15, + 'GROW_CURVE_ATTACK_104': 5.11, + 'GROW_CURVE_ATTACK_105': 4.346, + 'GROW_CURVE_CRITICAL_101': 3.585, + 'GROW_CURVE_ATTACK_201': 6.532, + 'GROW_CURVE_ATTACK_202': 7.239, + 'GROW_CURVE_ATTACK_203': 7.904, + 'GROW_CURVE_ATTACK_204': 5.78, + 'GROW_CURVE_ATTACK_205': 4.977, + 'GROW_CURVE_CRITICAL_201': 3.585, + 'GROW_CURVE_ATTACK_301': 7.048, + 'GROW_CURVE_ATTACK_302': 7.811, + 'GROW_CURVE_ATTACK_303': 8.524, + 'GROW_CURVE_ATTACK_304': 6.23, + 'GROW_CURVE_ATTACK_305': 5.351, + 'GROW_CURVE_CRITICAL_301': 3.585, + } + }, + '69': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.899, + 'GROW_CURVE_ATTACK_102': 6.591, + 'GROW_CURVE_ATTACK_103': 7.244, + 'GROW_CURVE_ATTACK_104': 5.166, + 'GROW_CURVE_ATTACK_105': 4.387, + 'GROW_CURVE_CRITICAL_101': 3.585, + 'GROW_CURVE_ATTACK_201': 6.615, + 'GROW_CURVE_ATTACK_202': 7.335, + 'GROW_CURVE_ATTACK_203': 8.012, + 'GROW_CURVE_ATTACK_204': 5.848, + 'GROW_CURVE_ATTACK_205': 5.03, + 'GROW_CURVE_CRITICAL_201': 3.585, + 'GROW_CURVE_ATTACK_301': 7.143, + 'GROW_CURVE_ATTACK_302': 7.92, + 'GROW_CURVE_ATTACK_303': 8.646, + 'GROW_CURVE_ATTACK_304': 6.31, + 'GROW_CURVE_ATTACK_305': 5.414, + 'GROW_CURVE_CRITICAL_301': 3.585, + } + }, + '70': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 5.968, + 'GROW_CURVE_ATTACK_102': 6.673, + 'GROW_CURVE_ATTACK_103': 7.338, + 'GROW_CURVE_ATTACK_104': 5.222, + 'GROW_CURVE_ATTACK_105': 4.428, + 'GROW_CURVE_CRITICAL_101': 3.786, + 'GROW_CURVE_ATTACK_201': 6.697, + 'GROW_CURVE_ATTACK_202': 7.431, + 'GROW_CURVE_ATTACK_203': 8.12, + 'GROW_CURVE_ATTACK_204': 5.916, + 'GROW_CURVE_ATTACK_205': 5.083, + 'GROW_CURVE_CRITICAL_201': 3.786, + 'GROW_CURVE_ATTACK_301': 7.238, + 'GROW_CURVE_ATTACK_302': 8.03, + 'GROW_CURVE_ATTACK_303': 8.769, + 'GROW_CURVE_ATTACK_304': 6.39, + 'GROW_CURVE_ATTACK_305': 5.478, + 'GROW_CURVE_CRITICAL_301': 3.786, + } + }, + '71': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.038, + 'GROW_CURVE_ATTACK_102': 6.755, + 'GROW_CURVE_ATTACK_103': 7.432, + 'GROW_CURVE_ATTACK_104': 5.277, + 'GROW_CURVE_ATTACK_105': 4.469, + 'GROW_CURVE_CRITICAL_101': 3.786, + 'GROW_CURVE_ATTACK_201': 6.78, + 'GROW_CURVE_ATTACK_202': 7.527, + 'GROW_CURVE_ATTACK_203': 8.229, + 'GROW_CURVE_ATTACK_204': 5.985, + 'GROW_CURVE_ATTACK_205': 5.136, + 'GROW_CURVE_CRITICAL_201': 3.786, + 'GROW_CURVE_ATTACK_301': 7.334, + 'GROW_CURVE_ATTACK_302': 8.139, + 'GROW_CURVE_ATTACK_303': 8.893, + 'GROW_CURVE_ATTACK_304': 6.47, + 'GROW_CURVE_ATTACK_305': 5.541, + 'GROW_CURVE_CRITICAL_301': 3.786, + } + }, + '72': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.107, + 'GROW_CURVE_ATTACK_102': 6.837, + 'GROW_CURVE_ATTACK_103': 7.527, + 'GROW_CURVE_ATTACK_104': 5.333, + 'GROW_CURVE_ATTACK_105': 4.51, + 'GROW_CURVE_CRITICAL_101': 3.786, + 'GROW_CURVE_ATTACK_201': 6.862, + 'GROW_CURVE_ATTACK_202': 7.623, + 'GROW_CURVE_ATTACK_203': 8.338, + 'GROW_CURVE_ATTACK_204': 6.053, + 'GROW_CURVE_ATTACK_205': 5.189, + 'GROW_CURVE_CRITICAL_201': 3.786, + 'GROW_CURVE_ATTACK_301': 7.429, + 'GROW_CURVE_ATTACK_302': 8.249, + 'GROW_CURVE_ATTACK_303': 9.016, + 'GROW_CURVE_ATTACK_304': 6.55, + 'GROW_CURVE_ATTACK_305': 5.605, + 'GROW_CURVE_CRITICAL_301': 3.786, + } + }, + '73': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.176, + 'GROW_CURVE_ATTACK_102': 6.919, + 'GROW_CURVE_ATTACK_103': 7.621, + 'GROW_CURVE_ATTACK_104': 5.388, + 'GROW_CURVE_ATTACK_105': 4.551, + 'GROW_CURVE_CRITICAL_101': 3.786, + 'GROW_CURVE_ATTACK_201': 6.945, + 'GROW_CURVE_ATTACK_202': 7.719, + 'GROW_CURVE_ATTACK_203': 8.446, + 'GROW_CURVE_ATTACK_204': 6.121, + 'GROW_CURVE_ATTACK_205': 5.242, + 'GROW_CURVE_CRITICAL_201': 3.786, + 'GROW_CURVE_ATTACK_301': 7.525, + 'GROW_CURVE_ATTACK_302': 8.359, + 'GROW_CURVE_ATTACK_303': 9.14, + 'GROW_CURVE_ATTACK_304': 6.63, + 'GROW_CURVE_ATTACK_305': 5.668, + 'GROW_CURVE_CRITICAL_301': 3.786, + } + }, + '74': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.245, + 'GROW_CURVE_ATTACK_102': 7.001, + 'GROW_CURVE_ATTACK_103': 7.715, + 'GROW_CURVE_ATTACK_104': 5.443, + 'GROW_CURVE_ATTACK_105': 4.592, + 'GROW_CURVE_CRITICAL_101': 3.786, + 'GROW_CURVE_ATTACK_201': 7.028, + 'GROW_CURVE_ATTACK_202': 7.815, + 'GROW_CURVE_ATTACK_203': 8.555, + 'GROW_CURVE_ATTACK_204': 6.189, + 'GROW_CURVE_ATTACK_205': 5.295, + 'GROW_CURVE_CRITICAL_201': 3.786, + 'GROW_CURVE_ATTACK_301': 7.621, + 'GROW_CURVE_ATTACK_302': 8.47, + 'GROW_CURVE_ATTACK_303': 9.263, + 'GROW_CURVE_ATTACK_304': 6.71, + 'GROW_CURVE_ATTACK_305': 5.732, + 'GROW_CURVE_CRITICAL_301': 3.786, + } + }, + '75': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.314, + 'GROW_CURVE_ATTACK_102': 7.083, + 'GROW_CURVE_ATTACK_103': 7.81, + 'GROW_CURVE_ATTACK_104': 5.498, + 'GROW_CURVE_ATTACK_105': 4.632, + 'GROW_CURVE_CRITICAL_101': 3.988, + 'GROW_CURVE_ATTACK_201': 7.11, + 'GROW_CURVE_ATTACK_202': 7.911, + 'GROW_CURVE_ATTACK_203': 8.664, + 'GROW_CURVE_ATTACK_204': 6.257, + 'GROW_CURVE_ATTACK_205': 5.347, + 'GROW_CURVE_CRITICAL_201': 3.988, + 'GROW_CURVE_ATTACK_301': 7.717, + 'GROW_CURVE_ATTACK_302': 8.58, + 'GROW_CURVE_ATTACK_303': 9.387, + 'GROW_CURVE_ATTACK_304': 6.791, + 'GROW_CURVE_ATTACK_305': 5.796, + 'GROW_CURVE_CRITICAL_301': 3.988, + } + }, + '76': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.383, + 'GROW_CURVE_ATTACK_102': 7.165, + 'GROW_CURVE_ATTACK_103': 7.904, + 'GROW_CURVE_ATTACK_104': 5.554, + 'GROW_CURVE_ATTACK_105': 4.673, + 'GROW_CURVE_CRITICAL_101': 3.988, + 'GROW_CURVE_ATTACK_201': 7.193, + 'GROW_CURVE_ATTACK_202': 8.007, + 'GROW_CURVE_ATTACK_203': 8.773, + 'GROW_CURVE_ATTACK_204': 6.326, + 'GROW_CURVE_ATTACK_205': 5.4, + 'GROW_CURVE_CRITICAL_201': 3.988, + 'GROW_CURVE_ATTACK_301': 7.813, + 'GROW_CURVE_ATTACK_302': 8.691, + 'GROW_CURVE_ATTACK_303': 9.512, + 'GROW_CURVE_ATTACK_304': 6.871, + 'GROW_CURVE_ATTACK_305': 5.859, + 'GROW_CURVE_CRITICAL_301': 3.988, + } + }, + '77': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.452, + 'GROW_CURVE_ATTACK_102': 7.247, + 'GROW_CURVE_ATTACK_103': 7.998, + 'GROW_CURVE_ATTACK_104': 5.609, + 'GROW_CURVE_ATTACK_105': 4.713, + 'GROW_CURVE_CRITICAL_101': 3.988, + 'GROW_CURVE_ATTACK_201': 7.275, + 'GROW_CURVE_ATTACK_202': 8.103, + 'GROW_CURVE_ATTACK_203': 8.882, + 'GROW_CURVE_ATTACK_204': 6.394, + 'GROW_CURVE_ATTACK_205': 5.453, + 'GROW_CURVE_CRITICAL_201': 3.988, + 'GROW_CURVE_ATTACK_301': 7.909, + 'GROW_CURVE_ATTACK_302': 8.802, + 'GROW_CURVE_ATTACK_303': 9.636, + 'GROW_CURVE_ATTACK_304': 6.952, + 'GROW_CURVE_ATTACK_305': 5.923, + 'GROW_CURVE_CRITICAL_301': 3.988, + } + }, + '78': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.521, + 'GROW_CURVE_ATTACK_102': 7.329, + 'GROW_CURVE_ATTACK_103': 8.093, + 'GROW_CURVE_ATTACK_104': 5.664, + 'GROW_CURVE_ATTACK_105': 4.753, + 'GROW_CURVE_CRITICAL_101': 3.988, + 'GROW_CURVE_ATTACK_201': 7.358, + 'GROW_CURVE_ATTACK_202': 8.199, + 'GROW_CURVE_ATTACK_203': 8.991, + 'GROW_CURVE_ATTACK_204': 6.462, + 'GROW_CURVE_ATTACK_205': 5.505, + 'GROW_CURVE_CRITICAL_201': 3.988, + 'GROW_CURVE_ATTACK_301': 8.005, + 'GROW_CURVE_ATTACK_302': 8.913, + 'GROW_CURVE_ATTACK_303': 9.761, + 'GROW_CURVE_ATTACK_304': 7.033, + 'GROW_CURVE_ATTACK_305': 5.987, + 'GROW_CURVE_CRITICAL_301': 3.988, + } + }, + '79': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.59, + 'GROW_CURVE_ATTACK_102': 7.411, + 'GROW_CURVE_ATTACK_103': 8.187, + 'GROW_CURVE_ATTACK_104': 5.719, + 'GROW_CURVE_ATTACK_105': 4.793, + 'GROW_CURVE_CRITICAL_101': 3.988, + 'GROW_CURVE_ATTACK_201': 7.44, + 'GROW_CURVE_ATTACK_202': 8.296, + 'GROW_CURVE_ATTACK_203': 9.1, + 'GROW_CURVE_ATTACK_204': 6.53, + 'GROW_CURVE_ATTACK_205': 5.558, + 'GROW_CURVE_CRITICAL_201': 3.988, + 'GROW_CURVE_ATTACK_301': 8.102, + 'GROW_CURVE_ATTACK_302': 9.024, + 'GROW_CURVE_ATTACK_303': 9.886, + 'GROW_CURVE_ATTACK_304': 7.113, + 'GROW_CURVE_ATTACK_305': 6.051, + 'GROW_CURVE_CRITICAL_301': 3.988, + } + }, + '80': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.659, + 'GROW_CURVE_ATTACK_102': 7.493, + 'GROW_CURVE_ATTACK_103': 8.282, + 'GROW_CURVE_ATTACK_104': 5.774, + 'GROW_CURVE_ATTACK_105': 4.834, + 'GROW_CURVE_CRITICAL_101': 4.19, + 'GROW_CURVE_ATTACK_201': 7.523, + 'GROW_CURVE_ATTACK_202': 8.392, + 'GROW_CURVE_ATTACK_203': 9.209, + 'GROW_CURVE_ATTACK_204': 6.598, + 'GROW_CURVE_ATTACK_205': 5.61, + 'GROW_CURVE_CRITICAL_201': 4.19, + 'GROW_CURVE_ATTACK_301': 8.199, + 'GROW_CURVE_ATTACK_302': 9.135, + 'GROW_CURVE_ATTACK_303': 10.011, + 'GROW_CURVE_ATTACK_304': 7.194, + 'GROW_CURVE_ATTACK_305': 6.115, + 'GROW_CURVE_CRITICAL_301': 4.19, + } + }, + '81': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.727, + 'GROW_CURVE_ATTACK_102': 7.575, + 'GROW_CURVE_ATTACK_103': 8.376, + 'GROW_CURVE_ATTACK_104': 5.828, + 'GROW_CURVE_ATTACK_105': 4.873, + 'GROW_CURVE_CRITICAL_101': 4.19, + 'GROW_CURVE_ATTACK_201': 7.606, + 'GROW_CURVE_ATTACK_202': 8.488, + 'GROW_CURVE_ATTACK_203': 9.319, + 'GROW_CURVE_ATTACK_204': 6.665, + 'GROW_CURVE_ATTACK_205': 5.662, + 'GROW_CURVE_CRITICAL_201': 4.19, + 'GROW_CURVE_ATTACK_301': 8.295, + 'GROW_CURVE_ATTACK_302': 9.247, + 'GROW_CURVE_ATTACK_303': 10.136, + 'GROW_CURVE_ATTACK_304': 7.275, + 'GROW_CURVE_ATTACK_305': 6.179, + 'GROW_CURVE_CRITICAL_301': 4.19, + } + }, + '82': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.796, + 'GROW_CURVE_ATTACK_102': 7.657, + 'GROW_CURVE_ATTACK_103': 8.471, + 'GROW_CURVE_ATTACK_104': 5.883, + 'GROW_CURVE_ATTACK_105': 4.913, + 'GROW_CURVE_CRITICAL_101': 4.19, + 'GROW_CURVE_ATTACK_201': 7.688, + 'GROW_CURVE_ATTACK_202': 8.585, + 'GROW_CURVE_ATTACK_203': 9.428, + 'GROW_CURVE_ATTACK_204': 6.733, + 'GROW_CURVE_ATTACK_205': 5.715, + 'GROW_CURVE_CRITICAL_201': 4.19, + 'GROW_CURVE_ATTACK_301': 8.392, + 'GROW_CURVE_ATTACK_302': 9.358, + 'GROW_CURVE_ATTACK_303': 10.261, + 'GROW_CURVE_ATTACK_304': 7.357, + 'GROW_CURVE_ATTACK_305': 6.243, + 'GROW_CURVE_CRITICAL_301': 4.19, + } + }, + '83': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.865, + 'GROW_CURVE_ATTACK_102': 7.739, + 'GROW_CURVE_ATTACK_103': 8.565, + 'GROW_CURVE_ATTACK_104': 5.938, + 'GROW_CURVE_ATTACK_105': 4.953, + 'GROW_CURVE_CRITICAL_101': 4.19, + 'GROW_CURVE_ATTACK_201': 7.771, + 'GROW_CURVE_ATTACK_202': 8.681, + 'GROW_CURVE_ATTACK_203': 9.537, + 'GROW_CURVE_ATTACK_204': 6.801, + 'GROW_CURVE_ATTACK_205': 5.767, + 'GROW_CURVE_CRITICAL_201': 4.19, + 'GROW_CURVE_ATTACK_301': 8.489, + 'GROW_CURVE_ATTACK_302': 9.47, + 'GROW_CURVE_ATTACK_303': 10.387, + 'GROW_CURVE_ATTACK_304': 7.438, + 'GROW_CURVE_ATTACK_305': 6.308, + 'GROW_CURVE_CRITICAL_301': 4.19, + } + }, + '84': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 6.934, + 'GROW_CURVE_ATTACK_102': 7.821, + 'GROW_CURVE_ATTACK_103': 8.66, + 'GROW_CURVE_ATTACK_104': 5.993, + 'GROW_CURVE_ATTACK_105': 4.993, + 'GROW_CURVE_CRITICAL_101': 4.19, + 'GROW_CURVE_ATTACK_201': 7.853, + 'GROW_CURVE_ATTACK_202': 8.777, + 'GROW_CURVE_ATTACK_203': 9.647, + 'GROW_CURVE_ATTACK_204': 6.869, + 'GROW_CURVE_ATTACK_205': 5.819, + 'GROW_CURVE_CRITICAL_201': 4.19, + 'GROW_CURVE_ATTACK_301': 8.587, + 'GROW_CURVE_ATTACK_302': 9.582, + 'GROW_CURVE_ATTACK_303': 10.513, + 'GROW_CURVE_ATTACK_304': 7.519, + 'GROW_CURVE_ATTACK_305': 6.372, + 'GROW_CURVE_CRITICAL_301': 4.19, + } + }, + '85': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.003, + 'GROW_CURVE_ATTACK_102': 7.904, + 'GROW_CURVE_ATTACK_103': 8.755, + 'GROW_CURVE_ATTACK_104': 6.047, + 'GROW_CURVE_ATTACK_105': 5.032, + 'GROW_CURVE_CRITICAL_101': 4.392, + 'GROW_CURVE_ATTACK_201': 7.936, + 'GROW_CURVE_ATTACK_202': 8.874, + 'GROW_CURVE_ATTACK_203': 9.756, + 'GROW_CURVE_ATTACK_204': 6.937, + 'GROW_CURVE_ATTACK_205': 5.871, + 'GROW_CURVE_CRITICAL_201': 4.392, + 'GROW_CURVE_ATTACK_301': 8.684, + 'GROW_CURVE_ATTACK_302': 9.694, + 'GROW_CURVE_ATTACK_303': 10.639, + 'GROW_CURVE_ATTACK_304': 7.601, + 'GROW_CURVE_ATTACK_305': 6.436, + 'GROW_CURVE_CRITICAL_301': 4.392, + } + }, + '86': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.071, + 'GROW_CURVE_ATTACK_102': 7.986, + 'GROW_CURVE_ATTACK_103': 8.849, + 'GROW_CURVE_ATTACK_104': 6.102, + 'GROW_CURVE_ATTACK_105': 5.072, + 'GROW_CURVE_CRITICAL_101': 4.392, + 'GROW_CURVE_ATTACK_201': 8.018, + 'GROW_CURVE_ATTACK_202': 8.97, + 'GROW_CURVE_ATTACK_203': 9.866, + 'GROW_CURVE_ATTACK_204': 7.005, + 'GROW_CURVE_ATTACK_205': 5.923, + 'GROW_CURVE_CRITICAL_201': 4.392, + 'GROW_CURVE_ATTACK_301': 8.782, + 'GROW_CURVE_ATTACK_302': 9.807, + 'GROW_CURVE_ATTACK_303': 10.765, + 'GROW_CURVE_ATTACK_304': 7.682, + 'GROW_CURVE_ATTACK_305': 6.501, + 'GROW_CURVE_CRITICAL_301': 4.392, + } + }, + '87': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.14, + 'GROW_CURVE_ATTACK_102': 8.068, + 'GROW_CURVE_ATTACK_103': 8.944, + 'GROW_CURVE_ATTACK_104': 6.156, + 'GROW_CURVE_ATTACK_105': 5.111, + 'GROW_CURVE_CRITICAL_101': 4.392, + 'GROW_CURVE_ATTACK_201': 8.101, + 'GROW_CURVE_ATTACK_202': 9.067, + 'GROW_CURVE_ATTACK_203': 9.975, + 'GROW_CURVE_ATTACK_204': 7.072, + 'GROW_CURVE_ATTACK_205': 5.975, + 'GROW_CURVE_CRITICAL_201': 4.392, + 'GROW_CURVE_ATTACK_301': 8.879, + 'GROW_CURVE_ATTACK_302': 9.919, + 'GROW_CURVE_ATTACK_303': 10.892, + 'GROW_CURVE_ATTACK_304': 7.764, + 'GROW_CURVE_ATTACK_305': 6.565, + 'GROW_CURVE_CRITICAL_301': 4.392, + } + }, + '88': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.209, + 'GROW_CURVE_ATTACK_102': 8.15, + 'GROW_CURVE_ATTACK_103': 9.039, + 'GROW_CURVE_ATTACK_104': 6.211, + 'GROW_CURVE_ATTACK_105': 5.151, + 'GROW_CURVE_CRITICAL_101': 4.392, + 'GROW_CURVE_ATTACK_201': 8.183, + 'GROW_CURVE_ATTACK_202': 9.163, + 'GROW_CURVE_ATTACK_203': 10.085, + 'GROW_CURVE_ATTACK_204': 7.14, + 'GROW_CURVE_ATTACK_205': 6.027, + 'GROW_CURVE_CRITICAL_201': 4.392, + 'GROW_CURVE_ATTACK_301': 8.977, + 'GROW_CURVE_ATTACK_302': 10.032, + 'GROW_CURVE_ATTACK_303': 11.018, + 'GROW_CURVE_ATTACK_304': 7.846, + 'GROW_CURVE_ATTACK_305': 6.63, + 'GROW_CURVE_CRITICAL_301': 4.392, + } + }, + '89': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.277, + 'GROW_CURVE_ATTACK_102': 8.232, + 'GROW_CURVE_ATTACK_103': 9.134, + 'GROW_CURVE_ATTACK_104': 6.265, + 'GROW_CURVE_ATTACK_105': 5.19, + 'GROW_CURVE_CRITICAL_101': 4.392, + 'GROW_CURVE_ATTACK_201': 8.266, + 'GROW_CURVE_ATTACK_202': 9.26, + 'GROW_CURVE_ATTACK_203': 10.195, + 'GROW_CURVE_ATTACK_204': 7.208, + 'GROW_CURVE_ATTACK_205': 6.078, + 'GROW_CURVE_CRITICAL_201': 4.392, + 'GROW_CURVE_ATTACK_301': 9.075, + 'GROW_CURVE_ATTACK_302': 10.145, + 'GROW_CURVE_ATTACK_303': 11.145, + 'GROW_CURVE_ATTACK_304': 7.928, + 'GROW_CURVE_ATTACK_305': 6.695, + 'GROW_CURVE_CRITICAL_301': 4.392, + } + }, + '90': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.346, + 'GROW_CURVE_ATTACK_102': 8.314, + 'GROW_CURVE_ATTACK_103': 9.229, + 'GROW_CURVE_ATTACK_104': 6.32, + 'GROW_CURVE_ATTACK_105': 5.229, + 'GROW_CURVE_CRITICAL_101': 4.594, + 'GROW_CURVE_ATTACK_201': 8.349, + 'GROW_CURVE_ATTACK_202': 9.356, + 'GROW_CURVE_ATTACK_203': 10.305, + 'GROW_CURVE_ATTACK_204': 7.275, + 'GROW_CURVE_ATTACK_205': 6.13, + 'GROW_CURVE_CRITICAL_201': 4.594, + 'GROW_CURVE_ATTACK_301': 9.173, + 'GROW_CURVE_ATTACK_302': 10.258, + 'GROW_CURVE_ATTACK_303': 11.272, + 'GROW_CURVE_ATTACK_304': 8.01, + 'GROW_CURVE_ATTACK_305': 6.76, + 'GROW_CURVE_CRITICAL_301': 4.594, + } + }, + '91': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.415, + 'GROW_CURVE_ATTACK_102': 8.396, + 'GROW_CURVE_ATTACK_103': 9.324, + 'GROW_CURVE_ATTACK_104': 6.374, + 'GROW_CURVE_ATTACK_105': 5.269, + 'GROW_CURVE_CRITICAL_101': 4.594, + 'GROW_CURVE_ATTACK_201': 8.431, + 'GROW_CURVE_ATTACK_202': 9.453, + 'GROW_CURVE_ATTACK_203': 10.414, + 'GROW_CURVE_ATTACK_204': 7.343, + 'GROW_CURVE_ATTACK_205': 6.182, + 'GROW_CURVE_CRITICAL_201': 4.594, + 'GROW_CURVE_ATTACK_301': 9.271, + 'GROW_CURVE_ATTACK_302': 10.371, + 'GROW_CURVE_ATTACK_303': 11.399, + 'GROW_CURVE_ATTACK_304': 8.092, + 'GROW_CURVE_ATTACK_305': 6.825, + 'GROW_CURVE_CRITICAL_301': 4.594, + } + }, + '92': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.483, + 'GROW_CURVE_ATTACK_102': 8.478, + 'GROW_CURVE_ATTACK_103': 9.418, + 'GROW_CURVE_ATTACK_104': 6.428, + 'GROW_CURVE_ATTACK_105': 5.308, + 'GROW_CURVE_CRITICAL_101': 4.594, + 'GROW_CURVE_ATTACK_201': 8.514, + 'GROW_CURVE_ATTACK_202': 9.55, + 'GROW_CURVE_ATTACK_203': 10.524, + 'GROW_CURVE_ATTACK_204': 7.411, + 'GROW_CURVE_ATTACK_205': 6.233, + 'GROW_CURVE_CRITICAL_201': 4.594, + 'GROW_CURVE_ATTACK_301': 9.37, + 'GROW_CURVE_ATTACK_302': 10.485, + 'GROW_CURVE_ATTACK_303': 11.527, + 'GROW_CURVE_ATTACK_304': 8.174, + 'GROW_CURVE_ATTACK_305': 6.89, + 'GROW_CURVE_CRITICAL_301': 4.594, + } + }, + '93': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.552, + 'GROW_CURVE_ATTACK_102': 8.561, + 'GROW_CURVE_ATTACK_103': 9.513, + 'GROW_CURVE_ATTACK_104': 6.483, + 'GROW_CURVE_ATTACK_105': 5.347, + 'GROW_CURVE_CRITICAL_101': 4.594, + 'GROW_CURVE_ATTACK_201': 8.596, + 'GROW_CURVE_ATTACK_202': 9.646, + 'GROW_CURVE_ATTACK_203': 10.634, + 'GROW_CURVE_ATTACK_204': 7.478, + 'GROW_CURVE_ATTACK_205': 6.285, + 'GROW_CURVE_CRITICAL_201': 4.594, + 'GROW_CURVE_ATTACK_301': 9.468, + 'GROW_CURVE_ATTACK_302': 10.598, + 'GROW_CURVE_ATTACK_303': 11.654, + 'GROW_CURVE_ATTACK_304': 8.257, + 'GROW_CURVE_ATTACK_305': 6.955, + 'GROW_CURVE_CRITICAL_301': 4.594, + } + }, + '94': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.621, + 'GROW_CURVE_ATTACK_102': 8.643, + 'GROW_CURVE_ATTACK_103': 9.608, + 'GROW_CURVE_ATTACK_104': 6.537, + 'GROW_CURVE_ATTACK_105': 5.386, + 'GROW_CURVE_CRITICAL_101': 4.594, + 'GROW_CURVE_ATTACK_201': 8.679, + 'GROW_CURVE_ATTACK_202': 9.743, + 'GROW_CURVE_ATTACK_203': 10.744, + 'GROW_CURVE_ATTACK_204': 7.546, + 'GROW_CURVE_ATTACK_205': 6.336, + 'GROW_CURVE_CRITICAL_201': 4.594, + 'GROW_CURVE_ATTACK_301': 9.567, + 'GROW_CURVE_ATTACK_302': 10.712, + 'GROW_CURVE_ATTACK_303': 11.782, + 'GROW_CURVE_ATTACK_304': 8.339, + 'GROW_CURVE_ATTACK_305': 7.02, + 'GROW_CURVE_CRITICAL_301': 4.594, + } + }, + '95': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.689, + 'GROW_CURVE_ATTACK_102': 8.725, + 'GROW_CURVE_ATTACK_103': 9.704, + 'GROW_CURVE_ATTACK_104': 6.591, + 'GROW_CURVE_ATTACK_105': 5.425, + 'GROW_CURVE_CRITICAL_101': 4.796, + 'GROW_CURVE_ATTACK_201': 8.761, + 'GROW_CURVE_ATTACK_202': 9.84, + 'GROW_CURVE_ATTACK_203': 10.854, + 'GROW_CURVE_ATTACK_204': 7.613, + 'GROW_CURVE_ATTACK_205': 6.388, + 'GROW_CURVE_CRITICAL_201': 4.796, + 'GROW_CURVE_ATTACK_301': 9.666, + 'GROW_CURVE_ATTACK_302': 10.826, + 'GROW_CURVE_ATTACK_303': 11.91, + 'GROW_CURVE_ATTACK_304': 8.422, + 'GROW_CURVE_ATTACK_305': 7.085, + 'GROW_CURVE_CRITICAL_301': 4.796, + } + }, + '96': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.758, + 'GROW_CURVE_ATTACK_102': 8.807, + 'GROW_CURVE_ATTACK_103': 9.799, + 'GROW_CURVE_ATTACK_104': 6.646, + 'GROW_CURVE_ATTACK_105': 5.464, + 'GROW_CURVE_CRITICAL_101': 4.796, + 'GROW_CURVE_ATTACK_201': 8.844, + 'GROW_CURVE_ATTACK_202': 9.936, + 'GROW_CURVE_ATTACK_203': 10.964, + 'GROW_CURVE_ATTACK_204': 7.681, + 'GROW_CURVE_ATTACK_205': 6.439, + 'GROW_CURVE_CRITICAL_201': 4.796, + 'GROW_CURVE_ATTACK_301': 9.765, + 'GROW_CURVE_ATTACK_302': 10.94, + 'GROW_CURVE_ATTACK_303': 12.038, + 'GROW_CURVE_ATTACK_304': 8.505, + 'GROW_CURVE_ATTACK_305': 7.151, + 'GROW_CURVE_CRITICAL_301': 4.796, + } + }, + '97': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.827, + 'GROW_CURVE_ATTACK_102': 8.89, + 'GROW_CURVE_ATTACK_103': 9.894, + 'GROW_CURVE_ATTACK_104': 6.7, + 'GROW_CURVE_ATTACK_105': 5.503, + 'GROW_CURVE_CRITICAL_101': 4.796, + 'GROW_CURVE_ATTACK_201': 8.927, + 'GROW_CURVE_ATTACK_202': 10.033, + 'GROW_CURVE_ATTACK_203': 11.074, + 'GROW_CURVE_ATTACK_204': 7.748, + 'GROW_CURVE_ATTACK_205': 6.491, + 'GROW_CURVE_CRITICAL_201': 4.796, + 'GROW_CURVE_ATTACK_301': 9.864, + 'GROW_CURVE_ATTACK_302': 11.054, + 'GROW_CURVE_ATTACK_303': 12.166, + 'GROW_CURVE_ATTACK_304': 8.588, + 'GROW_CURVE_ATTACK_305': 7.216, + 'GROW_CURVE_CRITICAL_301': 4.796, + } + }, + '98': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.895, + 'GROW_CURVE_ATTACK_102': 8.972, + 'GROW_CURVE_ATTACK_103': 9.989, + 'GROW_CURVE_ATTACK_104': 6.754, + 'GROW_CURVE_ATTACK_105': 5.542, + 'GROW_CURVE_CRITICAL_101': 4.796, + 'GROW_CURVE_ATTACK_201': 9.009, + 'GROW_CURVE_ATTACK_202': 10.13, + 'GROW_CURVE_ATTACK_203': 11.184, + 'GROW_CURVE_ATTACK_204': 7.816, + 'GROW_CURVE_ATTACK_205': 6.542, + 'GROW_CURVE_CRITICAL_201': 4.796, + 'GROW_CURVE_ATTACK_301': 9.963, + 'GROW_CURVE_ATTACK_302': 11.168, + 'GROW_CURVE_ATTACK_303': 12.295, + 'GROW_CURVE_ATTACK_304': 8.671, + 'GROW_CURVE_ATTACK_305': 7.282, + 'GROW_CURVE_CRITICAL_301': 4.796, + } + }, + '99': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 7.964, + 'GROW_CURVE_ATTACK_102': 9.054, + 'GROW_CURVE_ATTACK_103': 10.084, + 'GROW_CURVE_ATTACK_104': 6.808, + 'GROW_CURVE_ATTACK_105': 5.58, + 'GROW_CURVE_CRITICAL_101': 4.796, + 'GROW_CURVE_ATTACK_201': 9.092, + 'GROW_CURVE_ATTACK_202': 10.227, + 'GROW_CURVE_ATTACK_203': 11.295, + 'GROW_CURVE_ATTACK_204': 7.883, + 'GROW_CURVE_ATTACK_205': 6.593, + 'GROW_CURVE_CRITICAL_201': 4.796, + 'GROW_CURVE_ATTACK_301': 10.062, + 'GROW_CURVE_ATTACK_302': 11.283, + 'GROW_CURVE_ATTACK_303': 12.424, + 'GROW_CURVE_ATTACK_304': 8.754, + 'GROW_CURVE_ATTACK_305': 7.347, + 'GROW_CURVE_CRITICAL_301': 4.796, + } + }, + '100': { + 'curveInfos': { + 'GROW_CURVE_ATTACK_101': 8.033, + 'GROW_CURVE_ATTACK_102': 9.137, + 'GROW_CURVE_ATTACK_103': 10.18, + 'GROW_CURVE_ATTACK_104': 6.862, + 'GROW_CURVE_ATTACK_105': 5.619, + 'GROW_CURVE_CRITICAL_101': 4.998, + 'GROW_CURVE_ATTACK_201': 9.174, + 'GROW_CURVE_ATTACK_202': 10.324, + 'GROW_CURVE_ATTACK_203': 11.405, + 'GROW_CURVE_ATTACK_204': 7.95, + 'GROW_CURVE_ATTACK_205': 6.644, + 'GROW_CURVE_CRITICAL_201': 4.998, + 'GROW_CURVE_ATTACK_301': 10.162, + 'GROW_CURVE_ATTACK_302': 11.397, + 'GROW_CURVE_ATTACK_303': 12.552, + 'GROW_CURVE_ATTACK_304': 8.837, + 'GROW_CURVE_ATTACK_305': 7.413, + 'GROW_CURVE_CRITICAL_301': 4.998, + } + }, +} + +PROP_MAP = { + 'FIGHT_PROP_BASE_HP': '基础生命值', + 'FIGHT_PROP_HP': '总生命值', + 'FIGHT_PROP_HP_PERCENT': '生命值', + 'FIGHT_PROP_BASE_ATTACK': '基础攻击力', + 'FIGHT_PROP_ATTACK': '总攻击力', + 'FIGHT_PROP_ATTACK_PERCENT': '攻击力', + 'FIGHT_PROP_BASE_DEFENSE': '基础防御力', + 'FIGHT_PROP_DEFENSE': '总防御力', + 'FIGHT_PROP_DEFENSE_PERCENT': '防御力', + 'FIGHT_PROP_CRITICAL': '暴击率', + 'FIGHT_PROP_ANTI_CRITICAL': '暴击抵抗', + 'FIGHT_PROP_CRITICAL_HURT': '暴击伤害', + 'FIGHT_PROP_CHARGE_EFFICIENCY': '元素充能效率', + 'FIGHT_PROP_HEAL_ADD': '治疗加成', + 'FIGHT_PROP_HEALED_ADD': '受治疗加成', + 'FIGHT_PROP_ELEMENT_MASTERY': '元素精通', + 'FIGHT_PROP_PHYSICAL_ADD_HURT': '物理伤害加成', + 'FIGHT_PROP_FIRE_ADD_HURT': '火元素伤害加成', + 'FIGHT_PROP_ELEC_ADD_HURT': '雷元素伤害加成', + 'FIGHT_PROP_WATER_ADD_HURT': '水元素伤害加成', + 'FIGHT_PROP_GRASS_ADD_HURT': '草元素伤害加成', + 'FIGHT_PROP_WIND_ADD_HURT': '风元素伤害加成', + 'FIGHT_PROP_ROCK_ADD_HURT': '岩元素伤害加成', + 'FIGHT_PROP_ICE_ADD_HURT': '冰元素伤害加成', + 'FIGHT_PROP_FIRE_SUB_HURT': '火元素抗性', + 'FIGHT_PROP_ELEC_SUB_HURT': '雷元素抗性', + 'FIGHT_PROP_WATER_SUB_HURT': '水元素抗性', + 'FIGHT_PROP_GRASS_SUB_HURT': '草元素抗性', + 'FIGHT_PROP_WIND_SUB_HURT': '风元素抗性', + 'FIGHT_PROP_ROCK_SUB_HURT': '岩元素抗性', + 'FIGHT_PROP_ICE_SUB_HURT': '冰元素抗性', +} diff --git a/gsuid_core/utils/api/enka/__init__.py b/gsuid_core/utils/api/enka/__init__.py new file mode 100644 index 0000000..8f9f9ce --- /dev/null +++ b/gsuid_core/utils/api/enka/__init__.py @@ -0,0 +1,7 @@ +"""Enka Network 包装 +参考:https://api.enka.network +""" +from .models import EnkaData as EnkaData # noqa: F401 +from .request import get_enka_info as get_enka_info # noqa: F401 + +__all__ = ["request", "models"] diff --git a/gsuid_core/utils/api/enka/models.py b/gsuid_core/utils/api/enka/models.py new file mode 100644 index 0000000..b0b230c --- /dev/null +++ b/gsuid_core/utils/api/enka/models.py @@ -0,0 +1,113 @@ +from __future__ import annotations + +import sys +from typing import List, Literal, TypedDict + +# https://peps.python.org/pep-0655/#usage-in-python-3-11 +if sys.version_info >= (3, 11): + from typing import NotRequired +else: + from typing_extensions import NotRequired + + +class EnkaData(TypedDict): + playerInfo: PlayerInfo + avatarInfoList: List[AvatarInfoListItem] + ttl: int + uid: str + + +class PlayerInfo(TypedDict): + nickname: str + level: int + signature: str + worldLevel: int + nameCardId: int + finishAchievementNum: int + towerFloorIndex: int + towerLevelIndex: int + showAvatarInfoList: List[ShowAvatarInfoListItem] + showNameCardIdList: List[int] + profilePicture: ProfilePicture + + +class ShowAvatarInfoListItem(TypedDict): + avatarId: int + level: int + costumeId: NotRequired[int] + + +class ProfilePicture(TypedDict): + avatarId: int + + +class AvatarInfoListItem(TypedDict): + avatarId: int + propMap: dict[str, PropMap] + talentIdList: List[int] + fightPropMap: dict[str, float] + skillDepotId: int + inherentProudSkillList: List[int] + skillLevelMap: dict[str, int] + equipList: List[Equip] + fetterInfo: FetterInfo + + +class Equip(TypedDict): + itemId: int + reliquary: Reliquary + weapon: Weapon + flat: Flat + + +class Flat(TypedDict): + # l10n + nameTextMapHash: str + setNameTextMapHash: str + + # artifact + reliquaryMainstat: Stat + reliquarySubstats: List[Stat] + equipType: Literal[ + "EQUIP_BRACER", + "EQUIP_NECKLACE", + "EQUIP_SHOES", + "EQUIP_RING", + "EQUIP_DRESS", + ] + + # weapon + weaponStats: List[Stat] + + rankLevel: Literal[3, 4, 5] + itemType: Literal["ITEM_WEAPON", "ITEM_RELIQUARY"] + icon: str # https://enka.network/ui/{Icon}.png + + +class Stat(TypedDict): + mainPropId: str + appendPropId: str + statName: str + statValue: float | int + + +class Weapon(TypedDict): + level: int + promoteLevel: int + affixMap: dict[str, int] + + +class Reliquary(TypedDict): + level: int + mainPropId: int + appendPropIdList: List[int] + + +class PropMap(TypedDict): + type: int + ival: str # Ignore It! + val: str + + +class FetterInfo(TypedDict): + expLevel: int diff --git a/gsuid_core/utils/api/enka/request.py b/gsuid_core/utils/api/enka/request.py new file mode 100644 index 0000000..d850f66 --- /dev/null +++ b/gsuid_core/utils/api/enka/request.py @@ -0,0 +1,37 @@ +'''Enka Network 请求模块。 +MiniGG Enka 加速服务在此模块内。 +''' +from __future__ import annotations + +from typing import Literal + +from httpx import AsyncClient + +from ..utils import _HEADER +from .models import EnkaData + +ADDRESS = { + 'enka': 'https://enka.network', + 'microgg': 'http://profile.microgg.cn', +} + + +async def get_enka_info( + uid: str, address: Literal['enka', 'microgg'] = 'enka' +) -> EnkaData: + '''请求 Enka Network + + Args: + uid (str): 原神 UID + address (Literal["enka", "microgg", "minigg"], optional): API 地址. Defaults to 'enka'. + + Returns: + EnkaData: Enka Network 响应数据 + ''' # noqa: E501 + async with AsyncClient( + base_url=ADDRESS[address], + headers=_HEADER, + timeout=None, + ) as client: + req = await client.get(url=f'/api/uid/{uid}') + return req.json() diff --git a/gsuid_core/utils/api/hhw/__init__.py b/gsuid_core/utils/api/hhw/__init__.py new file mode 100644 index 0000000..4a54002 --- /dev/null +++ b/gsuid_core/utils/api/hhw/__init__.py @@ -0,0 +1,7 @@ +""" +内鬼网(hhw) API 包装: +深渊出场数据; +""" +from .request import get_abyss_review as get_abyss_review # noqa: F401 + +__all__ = ["request"] diff --git a/gsuid_core/utils/api/hhw/request.py b/gsuid_core/utils/api/hhw/request.py new file mode 100644 index 0000000..529d615 --- /dev/null +++ b/gsuid_core/utils/api/hhw/request.py @@ -0,0 +1,52 @@ +''' +内鬼网(hhw) API 请求模块。 +''' +from __future__ import annotations + +from typing import Dict, Union, Optional + +from httpx import AsyncClient +from bs4 import BeautifulSoup, NavigableString + +from ..utils import _HEADER + +HHW_ABYSS = 'https://genshin.honeyhunterworld.com/d_1001/?lang=CHS' + + +async def get_abyss_review( + raw_data: bytes, _id: Union[str, int], floor: Union[str, int] +) -> Optional[Dict[str, str]]: + '''请求内鬼网 API 深渊怪物数据 + + Returns: + Dict: 内鬼网 API 深渊怪物数据 + ''' # noqa: E501 + bs = BeautifulSoup(raw_data, 'lxml') + data = bs.find('section', {'id': f'Variant #{_id}'}) + + if data is None or isinstance(data, NavigableString): + return None + + floor_data = data.find_all('td') + abyss_list = [] + result = {} + for index, td in enumerate(floor_data): + temp = [] + if 'Monsters' in td.text: + monsters = floor_data[index + 1].find_all('a') + for monster in monsters: + if monster.text: + temp.append(monster.text) + if temp: + abyss_list.append(temp) + + for index, half in enumerate(['-1上', '-1下', '-2上', '-2下', '-3上', '-3下']): + result[f'{floor}{half}'] = abyss_list[index] + + return result + + +async def get_abyss_review_raw() -> bytes: + async with AsyncClient(headers=_HEADER, timeout=None) as client: + req = await client.get(url=HHW_ABYSS) + return req.read() diff --git a/gsuid_core/utils/api/minigg/__init__.py b/gsuid_core/utils/api/minigg/__init__.py new file mode 100644 index 0000000..13af556 --- /dev/null +++ b/gsuid_core/utils/api/minigg/__init__.py @@ -0,0 +1,36 @@ +""" +MiniGG API 包装: +原神基础信息 v4/v5; +原神语音; +原神地图; +""" +from .models import Food as Food # noqa: F401 +from .models import Costs as Costs # noqa: F401 +from .models import Enemy as Enemy # noqa: F401 +from .models import Domain as Domain # noqa: F401 +from .models import Weapon as Weapon # noqa: F401 +from .models import Artifact as Artifact # noqa: F401 +from .models import Material as Material # noqa: F401 +from .models import Character as Character # noqa: F401 +from .models import WeaponStats as WeaponStats # noqa: F401 +from .request import get_map_data as get_map_data # noqa: F401 +from .models import CharacterStats as CharacterStats # noqa: F401 +from .request import get_audio_info as get_audio_info # noqa: F401 +from .request import get_others_info as get_others_info # noqa: F401 +from .request import get_talent_info as get_talent_info # noqa: F401 +from .request import get_weapon_info as get_weapon_info # noqa: F401 +from .models import CharacterTalents as CharacterTalents # noqa: F401 +from .request import get_weapon_costs as get_weapon_costs # noqa: F401 +from .request import get_weapon_stats as get_weapon_stats # noqa: F401 +from .request import get_character_info as get_character_info # noqa: F401 +from .request import get_character_costs as get_character_costs # noqa: F401 +from .request import get_character_stats as get_character_stats # noqa: F401 +from .exception import MiniggNotFoundError as MiniggNotFoundError # noqa: F401 +from .request import ( # noqa: F401 + get_constellation_info as get_constellation_info, +) +from .models import ( # noqa: F401 + CharacterConstellations as CharacterConstellations, +) + +__all__ = ["request", "exception", "models"] diff --git a/gsuid_core/utils/api/minigg/exception.py b/gsuid_core/utils/api/minigg/exception.py new file mode 100644 index 0000000..3886145 --- /dev/null +++ b/gsuid_core/utils/api/minigg/exception.py @@ -0,0 +1,17 @@ +from typing import Any + +from ..types import AnyDict + + +class MiniggNotFoundError(Exception): + """MiniGG API 未找到报错""" + + def __init__(self, **raw: Any) -> None: + self.raw: AnyDict = raw + + def __repr__(self) -> str: + raw = self.raw + return f"" + + def __str__(self) -> str: + return repr(self) diff --git a/gsuid_core/utils/api/minigg/models.py b/gsuid_core/utils/api/minigg/models.py new file mode 100644 index 0000000..5cdbd6c --- /dev/null +++ b/gsuid_core/utils/api/minigg/models.py @@ -0,0 +1,363 @@ +""" +MiniGG API 响应模型。 +""" +# TODO: - @KimigaiiWuyi 补文档 +from __future__ import annotations + +import sys +from typing import Dict, List, Literal, TypedDict + +# https://peps.python.org/pep-0655/#usage-in-python-3-11 +if sys.version_info >= (3, 11): + from typing import NotRequired +else: + from typing_extensions import NotRequired + +# https://peps.python.org/pep-0613 +if sys.version_info >= (3, 10): + from typing import TypeAlias +else: + from typing_extensions import TypeAlias + +R: TypeAlias = List[str] + + +class FandomUrl(TypedDict): + fandom: str + + +class WeaponImage(TypedDict): + image: str + nameicon: str + namegacha: str + icon: str + nameawakenicon: str + awakenicon: str + + +class AscendItem(TypedDict): + name: str + count: int + + +class Costs(TypedDict): + ascend1: List[AscendItem] + ascend2: List[AscendItem] + ascend3: List[AscendItem] + ascend4: List[AscendItem] + ascend5: List[AscendItem] + ascend6: List[AscendItem] + + +class Weapon(TypedDict): + name: str + description: str + weapontype: str + rarity: str + baseatk: int + substat: str + subvalue: str + effectname: str + effect: str + r1: R + r2: R + r3: R + r4: R + r5: R + weaponmaterialtype: str + images: WeaponImage + url: NotRequired[FandomUrl] + version: str + costs: Costs + + +class WeaponStats(TypedDict): + level: int + ascension: int + attack: float + specialized: float + + +class Character(TypedDict): + name: str + fullname: str + title: str + description: str + rarity: str + element: str + weapontype: str + substat: str + gender: Literal['男', '女'] + body: str + association: str + region: Literal['蒙德', '璃月', '稻妻', '须弥', '枫丹', '纳塔', '至冬', '穆纳塔'] + affiliation: str + birthdaymmdd: str + birthday: str + constellation: str + cv: CharacterCv + costs: Costs + image: CharacterImage + url: FandomUrl + version: str + + +class CharacterCv(TypedDict): + english: str + chinese: str + japanese: str + korean: str + + +class CharacterImage(TypedDict): + card: str + portrait: str + icon: str + sideicon: str + cover1: str + cover2: str + hoyolab_avatar: str + nameicon: str + nameiconcard: str + namegachasplash: str + namegachaslice: str + namesideicon: str + + +class CharacterStats(TypedDict): + level: int + ascension: int + hp: float + attack: float + defense: float + specialized: float + + +class CharacterConstellations(TypedDict): + name: str + c1: CharacterConstellation + c2: CharacterConstellation + c3: CharacterConstellation + c4: CharacterConstellation + c5: CharacterConstellation + c6: CharacterConstellation + images: ConstellationsImage + version: str + + +class CharacterConstellation(TypedDict): + name: str + effect: str + + +class ConstellationsImage(TypedDict): + c1: str + c2: str + c3: str + c4: str + c5: str + c6: str + + +class MiniGGError(TypedDict): + retcode: int + error: str + + +class CharacterTalents(TypedDict): + name: str + combat1: TalentCombat + combat2: TalentCombat + combat3: TalentCombat + passive1: TalentPassive + passive2: TalentPassive + passive3: TalentPassive + passive4: NotRequired[TalentPassive] + costs: TalentsCosts + images: TalentsImages + + +class TalentsCosts(TypedDict): + lvl2: List[AscendItem] + lvl3: List[AscendItem] + lvl4: List[AscendItem] + lvl5: List[AscendItem] + lvl6: List[AscendItem] + lvl7: List[AscendItem] + lvl8: List[AscendItem] + lvl9: List[AscendItem] + lvl10: List[AscendItem] + + +class TalentsImages(TypedDict): + combat1: str + combat2: str + combat3: str + passive1: str + passive2: str + passive3: str + passive4: NotRequired[str] + + +class TalentCombat(TypedDict): + name: str + info: str + description: NotRequired[str] + attributes: TalentAttr + + +class TalentPassive(TypedDict): + name: str + info: str + + +class TalentAttr(TypedDict): + labels: List[str] + parameters: Dict[str, List[float]] + + +class Food(TypedDict): + name: str + rarity: str + foodtype: str + foodfilter: str + foodcategory: str + effect: str + description: str + suspicious: FoodEffect + normal: FoodEffect + delicious: FoodEffect + ingredients: List[AscendItem] + images: Image + url: FandomUrl + version: str + + +class FoodEffect(TypedDict): + effect: str + description: str + + +class Image(TypedDict): + nameicon: str + + +class Enemy(TypedDict): + name: str + specialname: str + enemytype: str + category: str + description: str + investigation: EnemyInvest + rewardpreview: List[EnemyReward] + images: Image + version: str + + +class EnemyReward(TypedDict): + name: str + count: NotRequired[float] + + +class EnemyInvest(TypedDict): + name: str + category: str + description: str + + +class Domain(TypedDict): + name: str + region: Literal['蒙德', '璃月', '稻妻', '须弥', '枫丹', '纳塔', '至冬', '穆纳塔'] + domainentrance: str + domaintype: str + description: str + recommendedlevel: int + recommendedelements: List[ + Literal['冰元素', '火元素', '雷元素', '水元素', '草元素', '岩元素', '风元素'] + ] + daysofweek: List[Literal['周日', '周一', '周二', '周三', '周四', '周五', '周六']] + unlockrank: int + rewardpreview: List[EnemyReward] + disorder: List[str] + monsterlist: List[str] + images: Image + version: str + + +class Piece(TypedDict): + name: str + description: str + story: str + + +class PieceFlower(Piece): + relictype: Literal['生之花'] + + +class PiecePlume(Piece): + relictype: Literal['死之羽'] + + +class PieceSands(Piece): + relictype: Literal['时之沙'] + + +class PieceGoblet(Piece): + relictype: Literal['空之杯'] + + +class PieceCirclet(Piece): + relictype: Literal['理之冠'] + + +class PieceImages(TypedDict): + flower: str + plume: str + sands: str + goblet: str + circlet: str + nameflower: str + nameplume: str + namesands: str + namegoblet: str + namecirclet: str + + +Artifact = TypedDict( + 'Artifact', + { + 'name': str, + 'rarity': List[str], + '1pc': str, + '2pc': str, + '4pc': str, + 'flower': PieceFlower, + 'plume': PiecePlume, + 'sands': PieceSands, + 'goblet': PieceGoblet, + 'circlet': PieceCirclet, + 'images': PieceImages, + 'url': FandomUrl, + 'version': str, + }, +) + + +class MaterialImage(TypedDict): + nameicon: str + redirect: str + + +class Material(TypedDict): + name: str + description: str + sortorder: int + rarity: str + category: str + materialtype: str + source: List[str] + images: MaterialImage + version: str + # 下面两个当且仅当materialtype是xx突破素材的情况才有 + dropdomain: str + daysofweek: List[str] diff --git a/gsuid_core/utils/api/minigg/request.py b/gsuid_core/utils/api/minigg/request.py new file mode 100644 index 0000000..5290007 --- /dev/null +++ b/gsuid_core/utils/api/minigg/request.py @@ -0,0 +1,452 @@ +''' +MiniGG API v4/v5 请求模块。 +参考:https://blog.minigg.cn/g/18 +MiniGG Enka 加速服务不在此模块内。 +''' +from __future__ import annotations + +import json +import warnings +from enum import Enum +from typing import Any, Dict, List, Union, Literal, Optional, cast, overload + +from httpx import AsyncClient + +from ..types import AnyDict +from .exception import MiniggNotFoundError +from .models import ( + Food, + Costs, + Enemy, + Domain, + Weapon, + Artifact, + Material, + Character, + WeaponStats, + CharacterStats, + CharacterTalents, + CharacterConstellations, +) + +MINIGG_AUDIO_URL = 'https://genshin.minigg.cn/' +MINIGG_URL = 'https://info.minigg.cn' +MINIGG_MAP_URL = 'https://map.minigg.cn/map/get_map' + + +class APILanguages(str, Enum): + '''API 语言列表''' + + CHS = 'CN' + '''简体中文''' + CN = 'CN' + '''简体中文''' + + JP = 'JP' + '''日语''' + JA = 'JP' + '''日语''' + + EN = 'EN' + '''英语''' + ENG = 'EN' + '''英语''' + + KR = 'KR' + '''韩语''' + KA = 'KR' + '''韩语''' + + CHT = 'CHT' + '''繁体中文''' + FR = 'FR' + '''法语''' + DE = 'DE' + '''德语''' + ID = 'ID' + '''印度尼西亚语''' + PT = 'PT' + '''葡萄牙语''' + RU = 'RU' + '''俄语''' + ES = 'ES' + '''西班牙语''' + TH = 'TH' + '''泰语''' + VI = 'VI' + '''越南语''' + + +async def get_map_data( + resource_name: str, map_id: str, is_cluster: bool = False +) -> bytes: + '''返回地图信息。 + + Args: + resource_name (str): 资源点名称。 + map_id (str): 地图ID。 + is_cluster (bool, optional): 是否使用 K-Means 聚类算法。 Defaults to False. + + Raises: + MiniggNotFoundError: 资源未找到。 + + Returns: + bytes: 图片。 + ''' + async with AsyncClient(timeout=None) as client: + req = await client.get( + url=MINIGG_MAP_URL, + params={ + 'resource_name': resource_name, + 'map_id': map_id, + 'is_cluster': is_cluster, + }, + ) + if req.headers['content-type'] == 'image/jpeg': + return req.content + else: + raise MiniggNotFoundError(**req.json()) + + +async def get_audio_info( + name: str, audio_id: str, language: str = 'cn' +) -> str: + '''`@deprecated: API is invalid` 访问 MiniGG API 获得原神角色音频信息。 + + Args: + name (str): 原神角色名称。 + audio_id (str): 语音id。 + language (str, optional): 语言。 Defaults to 'cn'. + + Returns: + str: 语音 URL。 + ''' + warnings.warn('Audio API is already deprecated.', DeprecationWarning) + async with AsyncClient(timeout=None) as client: + req = await client.get( + url=MINIGG_AUDIO_URL, + params={ + 'characters': name, + 'audioid': audio_id, + 'language': language, + }, + ) + return req.text + + +async def minigg_request( + endpoint: str, + query: str, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, + match_categories: bool = False, + **kwargs: Any, +) -> Union[AnyDict, List[str], int]: + '''请求 MiniGG API。 + + Args: + endpoint (str): 终结点。 + query (str): 查询名称。 + query_languages (APILanguages, optional): 查询语言。 + Defaults to APILanguages.CHS. + result_languages (APILanguages, optional): 返回语言。 + Defaults to APILanguages.CHS. + match_categories (bool, optional): 是否查询类别。 Defaults to False. + + Raises: + MiniggNotFoundError: 查询内容未找到。 + + Returns: + AnyDict | list[str]: 返回列表时,列表每一项元素都符合根据名称匹配的实际名称;返回字典则是此名称的实际数据。 + ''' + params = { + 'query': query, + 'queryLanguages': query_languages.value, + 'resultLanguage': result_languages.value, + **kwargs, + } + if match_categories: + params['matchCategories'] = '1' + async with AsyncClient(base_url=MINIGG_URL, timeout=1.3) as client: + req = await client.get(endpoint, params=params) + try: + data = req.json() + except json.decoder.JSONDecodeError: + return -11 + if 'retcode' in data: + retcode: int = data['retcode'] + return retcode + if req.status_code == 404: + raise MiniggNotFoundError(**data) + return data + + +async def get_weapon_info( + name: str, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, +) -> Union[Weapon, List[str], int]: + '''获取武器信息 + + Args: + name (str): 武器名称或类别名称。 + + **其他参数另见 `minigg_request`。** + + Raises: + MiniggNotFoundError: 武器未找到。 + + Returns: + Weapon | list[str]: 武器信息,如果为列表,则每个元素都是武器名。 + `get_weapon_costs` 和 `get_weapon_stats` 同 + ''' + data = await minigg_request( + '/weapons', + name, + query_languages=query_languages, + result_languages=result_languages, + ) + if isinstance(data, int): + return data + elif isinstance(data, Dict): + data = cast(Weapon, data) + return data + + +async def get_weapon_costs( + name: str, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, +) -> Union[Weapon, List[str], int]: + '''获取武器信息(花费) + + Args: + name (str): 武器名称或类别名称。 + + **其他参数另见 `minigg_request`。** + + Raises: + MiniggNotFoundError: 武器未找到。 + + Returns: + WeaponCosts | list[str]: 武器花费。 + ''' + data = await minigg_request( + '/weapons', + name, + query_languages=query_languages, + result_languages=result_languages, + costs=True, + ) + if isinstance(data, int): + return data + elif isinstance(data, Dict): + data = cast(Weapon, data) + return data + + +async def get_weapon_stats( + name: str, + stats: int, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, +) -> Union[WeaponStats, List[str], int]: + '''_summary_ + + Args: + name (str): 武器名称或类别名称。 + stats (int): 查询指定武器在这个等级的基础面板。 + + **其他参数另见 `minigg_request`。** + + Raises: + MiniggNotFoundError: 武器未找到。 + ValueError: stats 大于 90 或小于等于 0。 + + Returns: + WeaponStats: 武器等级基础面板。 + ''' + if stats > 90 or stats <= 0: + raise ValueError('stats must <= 90 and > 0') + + data = await minigg_request( + '/weapons', + name, + query_languages=query_languages, + result_languages=result_languages, + stats=stats, + ) + if isinstance(data, int): + return data + elif isinstance(data, Dict): + data = cast(WeaponStats, data) + return data + + +async def get_character_info( + name: str, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, +) -> Union[Character, List[str], int]: + data = await minigg_request( + '/characters', + name, + query_languages=query_languages, + result_languages=result_languages, + ) + if isinstance(data, int): + return data + elif isinstance(data, Dict): + data = cast(Character, data) + return data + + +async def get_character_costs( + name: str, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, +) -> Union[Costs, int]: + data = await minigg_request( + '/characters', + name, + query_languages=query_languages, + result_languages=result_languages, + Costs=True, + ) + if isinstance(data, int): + return data + elif isinstance(data, Dict): + return cast(Costs, data['costs']) + else: + return -1 + + +async def get_character_stats( + name: str, + stats: int, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, +) -> Union[CharacterStats, int]: + if stats > 90 or stats <= 0: + raise ValueError('stats must <= 90 and > 0') + + data = await minigg_request( + '/characters', + name, + query_languages=query_languages, + result_languages=result_languages, + stats=stats, + ) + if isinstance(data, int): + return data + elif isinstance(data, Dict): + return cast(CharacterStats, data) + else: + return -1 + + +async def get_constellation_info( + name: str, + c: Optional[int] = None, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, +) -> Union[CharacterConstellations, int]: + if c and (c > 6 or c <= 0): + raise ValueError('c must <= 6 and > 0') + + data = await minigg_request( + '/constellations', + name, + query_languages=query_languages, + result_languages=result_languages, + c=c, + ) + if isinstance(data, int): + return data + elif isinstance(data, Dict): + return cast(CharacterConstellations, data) + else: + return -1 + + +async def get_talent_info( + name: str, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, +) -> Union[CharacterTalents, int]: + data = await minigg_request( + '/talents', + name, + query_languages=query_languages, + result_languages=result_languages, + ) + if isinstance(data, int): + return data + elif isinstance(data, Dict): + return cast(CharacterTalents, data) + else: + return -1 + + +@overload +async def get_others_info( + type: Literal['foods'], name: str +) -> Union[Food, int]: + ... + + +@overload +async def get_others_info( + type: Literal['enemies'], name: str +) -> Union[Enemy, int]: + ... + + +@overload +async def get_others_info( + type: Literal['domains'], name: str +) -> Union[Domain, int]: + ... + + +@overload +async def get_others_info( + type: Literal['artifacts'], name: str +) -> Union[Artifact, int]: + ... + + +@overload +async def get_others_info( + type: Literal['materials'], name: str +) -> Union[Material, int]: + ... + + +async def get_others_info( + type: Literal['foods', 'enemies', 'domains', 'artifacts', 'materials'], + name: str, + query_languages: APILanguages = APILanguages.CHS, + result_languages: APILanguages = APILanguages.CHS, +) -> Union[Food, Material, Domain, Artifact, Enemy, int]: + data = await minigg_request( + f'/{type}', + name, + query_languages=query_languages, + result_languages=result_languages, + ) + if isinstance(data, int): + return data + elif isinstance(data, Dict): + if type == 'foods': + return cast(Food, data) + elif type == 'materials': + return cast(Material, data) + elif type == 'domains': + return cast(Domain, data) + elif type == 'artifacts': + return cast(Artifact, data) + elif type == 'enemies': + return cast(Enemy, data) + else: + return -1 diff --git a/gsuid_core/utils/api/mys/__init__.py b/gsuid_core/utils/api/mys/__init__.py new file mode 100644 index 0000000..ef372f7 --- /dev/null +++ b/gsuid_core/utils/api/mys/__init__.py @@ -0,0 +1,17 @@ +""" +米游社 API 包装 +""" + +from .request import MysApi # noqa: F401 +from .models import ( # noqa: F401 + AbyssData, + IndexData, + MihoyoRole, + MihoyoAvatar, + MihoyoWeapon, + DailyNoteData, + MihoyoReliquary, + MihoyoConstellation, +) + +__all__ = ["models", 'request'] diff --git a/gsuid_core/utils/api/mys/api.py b/gsuid_core/utils/api/mys/api.py new file mode 100644 index 0000000..e8598e0 --- /dev/null +++ b/gsuid_core/utils/api/mys/api.py @@ -0,0 +1,137 @@ +# flake8: noqa +OLD_URL = 'https://api-takumi.mihoyo.com' +NEW_URL = 'https://api-takumi-record.mihoyo.com' +BBS_URL = 'https://bbs-api.mihoyo.com' +HK4_URL = 'https://hk4e-api.mihoyo.com' +NEW_BBS_URL = 'https://bbs-api.miyoushe.com' + +OLD_URL_OS = 'https://api-os-takumi.mihoyo.com' +NEW_URL_OS = 'https://bbs-api-os.hoyolab.com' +BBS_URL_OS = 'https://bbs-api-os.hoyolab.com' +HK4_URL_OS = 'https://hk4e-api-os.hoyoverse.com' +SIGN_URL_OS = 'https://sg-hk4e-api.hoyolab.com' +ACT_URL_OS = 'https://sg-hk4e-api.hoyoverse.com' + +HK4E_LOGIN_URL = f'{OLD_URL}/common/badge/v1/login/account' +HK4E_LOGIN_URL_OS = f'{OLD_URL_OS}/common/badge/v1/login/account' + +BBS_TASKLIST = f'{BBS_URL}/apihub/sapi/getUserMissionsState' + +PASSPORT_URL = 'https://passport-api.mihoyo.com' +HK4_SDK_URL = 'https://hk4e-sdk.mihoyo.com' + +'''GT''' +# AJAX 无感验证 +GT_TEST = 'https://api.geetest.com/ajax.php?' +GT_TEST_V6 = 'https://apiv6.geetest.com/ajax.php?' +GT_QUERY = 'gt={}&challenge={}&lang=zh-cn&pt=3&client_type=web_mobile' + +GT_TEST_URL = GT_TEST + GT_QUERY +GT_TEST_URL_V6 = GT_TEST_V6 + GT_QUERY + +GT_TPYE_URL = 'https://api.geetest.com/gettype.php?gt={}' +VERIFICATION_URL = ( + f'{NEW_URL}/game_record/app/card/wapi/createVerification?is_high=false' +) +BBS_VERIFICATION_URL = ( + f'{NEW_BBS_URL}/game_record/app/card/wapi/createVerification?is_high=false' +) +VERIFY_URL = f'{NEW_URL}/game_record/app/card/wapi/verifyVerification' + +'''账号相关''' +# 通过LoginTicket获取Stoken +GET_STOKEN_URL = f'{OLD_URL}/auth/api/getMultiTokenByLoginTicket' +# 通过Stoken获取Cookie_token +GET_COOKIE_TOKEN_URL = f'{OLD_URL}/auth/api/getCookieAccountInfoBySToken' +# 通过Stoken获取AuthKey +GET_AUTHKEY_URL = f'{OLD_URL}/binding/api/genAuthKey' +# 通过AuthKey获取gachalogs +GET_GACHA_LOG_URL = f'{HK4_URL}/event/gacha_info/api/getGachaLog' +GET_GACHA_LOG_URL_OS = f'{HK4_URL_OS}/event/gacha_info/api/getGachaLog' +# 通过GameToken获取Stoken +GET_STOKEN = f'{PASSPORT_URL}/account/ma-cn-session/app/getTokenByGameToken' +# 创建登录URL +CREATE_QRCODE = f'{HK4_SDK_URL}/hk4e_cn/combo/panda/qrcode/fetch' +# 检查二维码扫描状态 +CHECK_QRCODE = f'{HK4_SDK_URL}/hk4e_cn/combo/panda/qrcode/query' +# 通过GameToken获取Cookie_token +GET_COOKIE_TOKEN_BY_GAME_TOKEN = ( + f'{OLD_URL}/auth/api/getCookieAccountInfoByGameToken' +) + +'''米游社相关''' +# 获取签到列表 +SIGN_LIST_URL = f'{OLD_URL}/event/bbs_sign_reward/home' +SIGN_LIST_URL_OS = f'{SIGN_URL_OS}/event/sol/home' +# 获取签到信息 +SIGN_INFO_URL = f'{OLD_URL}/event/bbs_sign_reward/info' +SIGN_INFO_URL_OS = f'{SIGN_URL_OS}/event/sol/info' +# 执行签到 +SIGN_URL = f'{OLD_URL}/event/bbs_sign_reward/sign' +SIGN_URL_OS += '/event/sol/sign' + +'''原神相关''' +# 每日信息 树脂 派遣等 +DAILY_NOTE_URL = f'{NEW_URL}/game_record/app/genshin/api/dailyNote' +DAILY_NOTE_URL_OS = f'{NEW_URL_OS}/game_record/genshin/api/dailyNote' +# 每月札记 +MONTHLY_AWARD_URL = f'{HK4_URL}/event/ys_ledger/monthInfo' +MONTHLY_AWARD_URL_OS = f'{HK4_URL_OS}/event/ysledgeros/month_info' +# 获取角色基本信息 +PLAYER_INFO_URL = f'{NEW_URL}/game_record/app/genshin/api/index' +PLAYER_INFO_URL_OS = f'{NEW_URL_OS}/game_record/genshin/api/index' +# 获取深渊信息 +PLAYER_ABYSS_INFO_URL = f'{NEW_URL}/game_record/app/genshin/api/spiralAbyss' +PLAYER_ABYSS_INFO_URL_OS = f'{NEW_URL_OS}/game_record/genshin/api/spiralAbyss' +# 获取详细角色信息 +PLAYER_DETAIL_INFO_URL = f'{NEW_URL}/game_record/app/genshin/api/character' +PLAYER_DETAIL_INFO_URL_OS = f'{NEW_URL_OS}/game_record/genshin/api/character' +# 天赋计算器API 获取天赋等级信息 +CALCULATE_INFO_URL = ( + f'{OLD_URL}/event/e20200928calculate/v1/sync/avatar/detail' +) +CALCULATE_INFO_URL_OS = ( + 'https://sg-public-api.hoyoverse.com/event/calculateos/sync/avatar/detail' +) +# 获取米游社内的角色信息 mysid -> uid +MIHOYO_BBS_PLAYER_INFO_URL = ( + f'{NEW_URL}/game_record/card/wapi/getGameRecordCard' +) +MIHOYO_BBS_PLAYER_INFO_URL_OS = ( + f'{NEW_URL_OS}/game_record/card/wapi/getGameRecordCard' +) + +# 获取七圣召唤相关信息 +GCG_INFO = f'{NEW_URL}/game_record/app/genshin/api/gcg/basicInfo' +GCG_INFO_OS = f'{NEW_URL_OS}/game_record/genshin/api/gcg/basicInfo' +GCG_DECK_URL = f'{NEW_URL}/game_record/app/genshin/api/gcg/deckList' +GCG_DECK_URL_OS = f'{NEW_URL_OS}/game_record/app/genshin/api/gcg/deckList' + +# 获取注册时间API 绘忆星辰 +REG_TIME = f'{HK4_URL}/event/e20220928anniversary/game_data?' +REG_TIME_OS = f'{ACT_URL_OS}/event/e20220928anniversary/game_data?' + +# 米游社的API列表 +BBS_TASKS_LIST = f'{BBS_URL}/apihub/sapi/getUserMissionsState' +BBS_SIGN_URL = f'{BBS_URL}/apihub/app/api/signIn' +BBS_LIST_URL = ( + BBS_URL + '/post/api/getForumPostList?' + 'forum_id={}&is_good=false&is_hot=false&page_size=20&sort_type=1' +) +BBS_DETAIL_URL = BBS_URL + '/post/api/getPostFull?post_id={}' +BBS_SHARE_URL = BBS_URL + '/apihub/api/getShareConf?entity_id={}&entity_type=1' +BBS_LIKE_URL = f'{BBS_URL}/apihub/sapi/upvotePost' + +# 原神充值中心 +fetchGoodsurl = f'{HK4_SDK_URL}/hk4e_cn/mdk/shopwindow/shopwindow/fetchGoods' +CreateOrderurl = f'{HK4_SDK_URL}/hk4e_cn/mdk/atropos/api/createOrder' +CheckOrderurl = f'{HK4_SDK_URL}/hk4e_cn/mdk/atropos/api/checkOrder' +PriceTierurl = f'{HK4_SDK_URL}/hk4e_cn/mdk/shopwindow/shopwindow/listPriceTier' + +# 留影叙佳期 +DRAW_BASE_URL = f'{HK4_URL}/event/birthdaystar/account' +CALENDAR_URL = f'{DRAW_BASE_URL}/calendar' +RECEIVE_URL = f'{DRAW_BASE_URL}/post_my_draw' +BS_INDEX_URL = f'{DRAW_BASE_URL}/index' + +_API = locals() diff --git a/gsuid_core/utils/api/mys/models.py b/gsuid_core/utils/api/mys/models.py new file mode 100644 index 0000000..d841e64 --- /dev/null +++ b/gsuid_core/utils/api/mys/models.py @@ -0,0 +1,780 @@ +from __future__ import annotations + +import sys +from typing import List, Literal, Optional, TypedDict + +# https://peps.python.org/pep-0655/#usage-in-python-3-11 +if sys.version_info >= (3, 11): + from typing import NotRequired +else: + from typing_extensions import NotRequired + + +# Response about +# https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index +# https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character +# 玩家、武器、圣遗物、角色模型 + + +class MihoyoRole(TypedDict): + AvatarUrl: str + nickname: str + region: str + level: int + + +class MihoyoWeapon(TypedDict): + id: int + name: str + icon: str + type: int + rarity: int + level: int + promote_level: int + type_name: Literal['单手剑', '双手剑', '长柄武器', '弓', '法器'] + desc: str + affix_level: int + + +class ReliquaryAffix(TypedDict): + activation_number: int + effect: str + + +class ReliquarySet(TypedDict): + id: int + name: str + affixes: List[ReliquaryAffix] + + +class MihoyoReliquary(TypedDict): + id: int + name: str + icon: str + pos: int + rarity: int + level: int + set: ReliquarySet + pos_name: str + + +class MihoyoConstellation(TypedDict): + id: int + name: str + icon: str + effect: str + is_actived: bool + pos: int + + +class MihoyoCostume(TypedDict): + id: int + name: str + icon: str + + +class MihoyoAvatar(TypedDict): + id: int + image: str + icon: str + '''在api/character接口有''' + name: str + element: Literal[ + 'Geo', 'Anemo', 'Dendro', 'Electro', 'Pyro', 'Cryo', 'Hydro' + ] + fetter: int + level: int + rarity: int + weapon: MihoyoWeapon + '''在api/character接口有''' + reliquaries: List[MihoyoReliquary] + '''在api/character接口有''' + constellations: List[MihoyoConstellation] + '''在api/character接口有''' + actived_constellation_num: int + costumes: List[MihoyoCostume] + '''在api/character接口有''' + card_image: str + '''在api/index接口有''' + is_chosen: bool + '''在api/index接口有''' + + +# Response +# https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/spiralAbyss + + +class AbyssAvatar(TypedDict): + avatar_id: int + avatar_icon: str + value: int + rarity: int + + +class AbyssBattleAvatar(TypedDict): + id: int + icon: str + level: int + rarity: int + + +class AbyssBattle(TypedDict): + index: int + timestamp: str + avatars: List[AbyssBattleAvatar] + + +class AbyssLevel(TypedDict): + index: int + star: int + max_star: int + battles: List[AbyssBattle] + + +class AbyssFloor(TypedDict): + index: int + icon: str + is_unlock: bool + settle_time: str + star: int + max_star: int + levels: List[AbyssLevel] + + +class AbyssData(TypedDict): + schedule_id: int + start_time: str + end_time: str + total_battle_times: int + total_win_times: int + max_floor: str + reveal_rank: List[AbyssAvatar] + defeat_rank: List[AbyssAvatar] + damage_rank: List[AbyssAvatar] + take_damage_rank: List[AbyssAvatar] + normal_skill_rank: List[AbyssAvatar] + energy_skill_rank: List[AbyssAvatar] + floors: List[AbyssFloor] + total_star: int + is_unlock: bool + + +# Response +# https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote + + +class Expedition(TypedDict): + avatar_side_icon: str + status: Literal['Ongoing', 'Finished'] + remained_time: int + + +class RecoveryTime(TypedDict): + Day: int + Hour: int + Minute: int + Second: int + reached: bool + + +class Transformer(TypedDict): + obtained: bool + recovery_time: RecoveryTime + wiki: str + noticed: bool + latest_job_id: str + + +class DailyNoteData(TypedDict): + current_resin: int + max_resin: int + resin_recovery_time: int + finished_task_num: int + total_task_num: int + is_extra_task_reward_received: bool + remain_resin_discount_num: int + resin_discount_num_limit: int + current_expedition_num: int + max_expedition_num: int + expeditions: List[Expedition] + current_home_coin: int + max_home_coin: int + home_coin_recovery_time: int + calendar_url: str + transformer: Transformer + + +# Response from https://api-takumi.mihoyo.com/game_record/app/genshin/api/index + + +class Stats(TypedDict): + active_day_number: int + achievement_number: int + anemoculus_number: int + geoculus_number: int + avatar_number: int + way_point_number: int + domain_number: int + spiral_abyss: str + precious_chest_number: int + luxurious_chest_number: int + exquisite_chest_number: int + common_chest_number: int + electroculus_number: int + magic_chest_number: int + dendroculus_number: int + + +class Offering(TypedDict): + name: str + level: int + icon: str + + +class WorldExploration(TypedDict): + level: int + exploration_percentage: int + icon: str + name: str + type: str + offerings: List[Offering] + id: int + parent_id: int + map_url: str + strategy_url: str + background_image: str + inner_icon: str + cover: str + + +class Home(TypedDict): + level: int + visit_num: int + comfort_num: int + item_num: int + name: str + icon: str + comfort_level_name: str + comfort_level_icon: str + + +class IndexData(TypedDict): + role: MihoyoRole + avatars: List[MihoyoAvatar] + stats: Stats + city_explorations: List + world_explorations: List[WorldExploration] + homes: List[Home] + + +class CharDetailData(TypedDict): + avatars: List[MihoyoAvatar] + + +################ +# Token Models # +################ + + +class CookieTokenInfo(TypedDict): + uid: str + cookie_token: str + + +class StokenInfo(TypedDict): + token_type: NotRequired[int] + name: NotRequired[str] + token: str + + +class GameTokenInfo(TypedDict): + token: StokenInfo + user_info: UserInfo + + +class LoginTicketInfo(TypedDict): + list: List[StokenInfo] + + +class AuthKeyInfo(TypedDict): + sign_type: int + authkey_ver: int + authkey: str + + +class Hk4eLoginInfo(TypedDict): + game: str + region: str + game_uid: str + game_biz: str + level: int + nickname: str + region_name: str + + +################ +# 扫码登录相关 # +################ + + +class QrCodeUrl(TypedDict): + url: str + + +class QrPayload(TypedDict): + proto: str + raw: str + ext: str + + +class QrCodeStatus(TypedDict): + stat: Literal['Init', 'Scanned', 'Confirmed'] + payload: QrPayload + + +################ +# UserInfo相关 # +################ + + +class UserLinks(TypedDict): + thirdparty: str + union_id: str + nickname: str + + +class UserInfo(TypedDict): + aid: str + mid: str + account_name: str + email: str + is_email_verify: int + area_code: str + mobile: str + safe_area_code: str + safe_mobile: str + realname: str + identity_code: str + rebind_area_code: str + rebind_mobile: str + rebind_mobile_time: str + links: List[UserLinks] + + +################ +# 抽卡记录相关 # +################ + + +class SingleGachaLog(TypedDict): + uid: str + gacha_type: str + item_id: str + count: str + time: str + name: str + lang: str + item_type: str + rank_type: str + id: str + + +class GachaLog(TypedDict): + page: str + size: str + total: str + list: List[SingleGachaLog] + region: str + + +################ +# 注册时间相关 # +################ + + +class CardOpts(TypedDict): + adjs: List[int] + titles: List[int] + items: List[int] + data_version: str + + +Props = TypedDict( + 'Props', + { + '66a': str, + '50a': str, + '53b': str, + 'pre_69b': str, + '49a': str, + '52b': str, + 'pre_71b': str, + '37': str, + '48a': str, + '57': str, + }, +) + + +class RegTime(TypedDict): + data: str + card_opts: CardOpts + props: Props + data_version: int + prop_version: int + + +################ +# 七圣召唤相关 # +################ + + +class CardCovers(TypedDict): + id: int + image: str + + +class GcgInfo(TypedDict): + level: int + nickname: str + avatar_card_num_gained: int + avatar_card_num_total: int + action_card_num_gained: int + action_card_num_total: int + covers: List[CardCovers] + + +################ +# 每月札记相关 # +################ + + +class DayData(TypedDict): + current_primogems: int + current_mora: int + last_primogems: int + last_mora: int + + +class GroupBy(TypedDict): + action_id: int + action: str + num: int + percent: int + + +class MonthData(TypedDict): + current_primogems: int + current_mora: int + last_primogems: int + last_mora: int + current_primogems_level: int + primogems_rate: int + mora_rate: int + group_by: List[GroupBy] + + +class MonthlyAward(TypedDict): + uid: int + region: str + account_id: str + nickname: str + date: str + month: str + optional_month: List[int] + data_month: int + data_last_month: int + day_data: DayData + month_data: MonthData + lantern: bool + + +################ +# 签到相关 # +################ + + +class MysSign(TypedDict): + code: str + risk_code: int + gt: str + challenge: str + success: int + message: str + + +class SignInfo(TypedDict): + total_sign_day: int + today: str + is_sign: bool + first_bind: bool + is_sub: bool + month_first: bool + sign_cnt_missed: int + month_last_day: bool + + +class SignAward(TypedDict): + icon: str + name: str + cnt: int + + +class SignList(TypedDict): + month: int + awards: List[SignAward] + resign: bool + + +################ +# 养成计算器部分 # +################ + + +class CalculateInfo(TypedDict): + skill_list: List[CalculateSkill] + weapon: CalculateWeapon + reliquary_list: List[CalculateReliquary] + + +class CalculateBaseData(TypedDict): + id: int + name: str + icon: str + max_level: int + level_current: int + + +class CalculateWeapon(CalculateBaseData): + weapon_cat_id: int + weapon_level: int + + +class CalculateReliquary(CalculateBaseData): + reliquary_cat_id: int + reliquary_level: int + + +class CalculateSkill(CalculateBaseData): + group_id: int + + +################ +# RecordCard # +################ + + +class MysGame(TypedDict): + has_role: bool + game_id: int # 2是原神 + game_role_id: str # UID + nickname: str + region: str + level: int + background_image: str + is_public: bool + data: List[MysGameData] + region_name: str + url: str + data_switches: List[MysGameSwitch] + h5_data_switches: Optional[List] + background_color: str # 十六进制颜色代码 + + +class MysGameData(TypedDict): + name: str + type: int + value: str + + +class MysGameSwitch(TypedDict): + switch_id: int + is_public: bool + switch_name: str + + +'''支付相关''' + + +class MysGoods(TypedDict): + goods_id: str + goods_name: str + goods_name_i18n_key: str + goods_desc: str + goods_desc_i18n_key: str + goods_type: Literal['Normal', 'Special'] + goods_unit: str + goods_icon: str + currency: Literal['CNY'] + price: str + symbol: Literal['¥'] + tier_id: Literal['Tier_1'] + bonus_desc: MysGoodsBonus + once_bonus_desc: MysGoodsBonus + available: bool + tips_desc: str + tips_i18n_key: str + battle_pass_limit: str + + +class MysGoodsBonus(TypedDict): + bonus_desc: str + bonus_desc_i18n_key: str + bonus_unit: int + bonus_goods_id: str + bonus_icon: str + + +class MysOrderCheck(TypedDict): + status: int # 900为成功 + amount: str + goods_title: str + goods_num: str + order_no: str + pay_plat: Literal['alipay', 'weixin'] + + +class MysOrder(TypedDict): + goods_id: str + order_no: str + currency: Literal['CNY'] + amount: str + redirect_url: str + foreign_serial: str + encode_order: str + account: str # mysid + create_time: str + ext_info: str + balance: str + method: str + action: str + session_cookie: str + + +'''七圣召唤牌组''' + + +class GcgDeckInfo(TypedDict): + deck_list: List[GcgDeck] + role_id: str # uid + level: int # 世界等级 + nickname: str + + +class GcgDeck(TypedDict): + id: int + name: str + is_valid: bool + avatar_cards: List[GcgAvatar] + action_cards: List[GcgAction] + + +class GcgAvatarSkill(TypedDict): + id: int + name: str + desc: str + tag: Literal['普通攻击', '元素战技', '元素爆发', '被动技能'] + + +class GcgAvatar(TypedDict): + id: int + name: str + image: str + desc: str + card_type: Literal['CardTypeCharacter'] + num: int + tags: List[str] # 元素和武器类型icon + proficiency: int + use_count: int + hp: int + card_skills: List[GcgAvatarSkill] + action_cost: List[GcgCost] + card_sources: List[str] + rank_id: int + deck_recommend: str + card_wiki: str + + +class GcgCost(TypedDict): + cost_type: Literal['CostTypeSame', 'CostTypeVoid'] + cost_value: int + + +class GcgAction(TypedDict): + id: int + name: str + image: str + desc: str + card_type: str + num: int + tags: List[str] # 元素和武器类型icon + proficiency: int + use_count: int + hp: int + card_skills: List[GcgAvatarSkill] + action_cost: List[GcgCost] + card_sources: List[str] + rank_id: int + deck_recommend: str + card_wiki: str + + +# 留影叙佳期 +class GsRoleBirthDay(TypedDict): + role_id: int + name: str + jump_tpye: str + jump_target: str + jump_start_time: str + jump_end_time: str + role_gender: int + take_picture: str + gal_xml: str + gal_resource: str + is_partake: bool + bgm: str + + +class BsIndex(TypedDict): + nick_name: str + uid: int + region: str + role: List[GsRoleBirthDay] + draw_notice: bool + CurrentTime: str + gender: int + is_show_remind: bool + + +class RolesCalendar(TypedDict): + calendar_role_infos: MonthlyRoleCalendar + is_pre: bool + is_next: bool + is_year_subscribe: bool + + +class RoleCalendar(TypedDict): + role_id: int + name: str + role_birthday: str + head_icon: str + is_subscribe: bool + + +MonthlyRoleCalendar = TypedDict( + 'MonthlyRoleCalendar', + { + '1': List[RoleCalendar], + '2': List[RoleCalendar], + '3': List[RoleCalendar], + '4': List[RoleCalendar], + '5': List[RoleCalendar], + '6': List[RoleCalendar], + '7': List[RoleCalendar], + '8': List[RoleCalendar], + '9': List[RoleCalendar], + '10': List[RoleCalendar], + '11': List[RoleCalendar], + '12': List[RoleCalendar], + }, +) diff --git a/gsuid_core/utils/api/mys/request.py b/gsuid_core/utils/api/mys/request.py new file mode 100644 index 0000000..a3c9077 --- /dev/null +++ b/gsuid_core/utils/api/mys/request.py @@ -0,0 +1,942 @@ +''' +米游社 API 请求模块。 +''' +from __future__ import annotations + +import copy +import time +import uuid +import random +from abc import abstractmethod +from string import digits, ascii_letters +from typing import Any, Dict, List, Union, Literal, Optional, cast + +from aiohttp import ClientSession, ContentTypeError + +from .api import _API +from .tools import ( + random_hex, + random_text, + get_ds_token, + generate_os_ds, + gen_payment_sign, + get_web_ds_token, + generate_passport_ds, +) +from .models import ( + BsIndex, + GcgInfo, + MysGame, + MysSign, + RegTime, + GachaLog, + MysGoods, + MysOrder, + SignInfo, + SignList, + AbyssData, + IndexData, + AuthKeyInfo, + GcgDeckInfo, + MonthlyAward, + QrCodeStatus, + CalculateInfo, + DailyNoteData, + GameTokenInfo, + MysOrderCheck, + RolesCalendar, + CharDetailData, + CookieTokenInfo, + LoginTicketInfo, +) + +RECOGNIZE_SERVER = { + '1': 'cn_gf01', + '2': 'cn_gf01', + '5': 'cn_qd01', + '6': 'os_usa', + '7': 'os_euro', + '8': 'os_asia', + '9': 'os_cht', +} + + +class MysApi: + proxy_url: Optional[str] = None + mysVersion = '2.44.1' + _HEADER = { + 'x-rpc-app_version': mysVersion, + 'User-Agent': ( + 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) ' + f'AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/{mysVersion}' + ), + 'x-rpc-client_type': '5', + 'Referer': 'https://webstatic.mihoyo.com/', + 'Origin': 'https://webstatic.mihoyo.com', + } + _HEADER_OS = { + 'x-rpc-app_version': '1.5.0', + 'x-rpc-client_type': '4', + 'x-rpc-language': 'zh-cn', + } + + @abstractmethod + async def _upass(self, header: Dict): + ... + + @abstractmethod + async def _pass(self, gt: str, ch: str, header: Dict): + ... + + @abstractmethod + async def get_ck( + self, uid: str, mode: Literal['OWNER', 'RANDOM'] = 'RANDOM' + ) -> Optional[str]: + ... + + @abstractmethod + async def get_stoken(self, uid: str) -> Optional[str]: + ... + + async def get_upass_link(self, header: Dict) -> Union[int, Dict]: + header['DS'] = get_ds_token('is_high=false') + return await self._mys_request( + url=_API['VERIFICATION_URL'], + method='GET', + header=header, + ) + + async def get_bbs_upass_link(self, header: Dict) -> Union[int, Dict]: + header['DS'] = get_ds_token('is_high=false') + return await self._mys_request( + url=_API['BBS_VERIFICATION_URL'], + method='GET', + header=header, + ) + + async def get_header_and_vl(self, header: Dict, ch, vl): + header['DS'] = get_ds_token( + '', + { + 'geetest_challenge': ch, + 'geetest_validate': vl, + 'geetest_seccode': f'{vl}|jordan', + }, + ) + _ = await self._mys_request( + url=_API['VERIFY_URL'], + method='POST', + header=header, + data={ + 'geetest_challenge': ch, + 'geetest_validate': vl, + 'geetest_seccode': f'{vl}|jordan', + }, + ) + + def check_os(self, uid: str) -> bool: + return False if int(str(uid)[0]) < 6 else True + + async def get_info(self, uid, ck: Optional[str]) -> Union[IndexData, int]: + data = await self.simple_mys_req('PLAYER_INFO_URL', uid, cookie=ck) + if isinstance(data, Dict): + data = cast(IndexData, data['data']) + return data + + async def get_daily_data(self, uid: str) -> Union[DailyNoteData, int]: + data = await self.simple_mys_req('DAILY_NOTE_URL', uid) + if isinstance(data, Dict): + data = cast(DailyNoteData, data['data']) + return data + + async def get_gcg_info(self, uid: str) -> Union[GcgInfo, int]: + data = await self.simple_mys_req('GCG_INFO', uid) + if isinstance(data, Dict): + data = cast(GcgInfo, data['data']) + return data + + async def get_gcg_deck(self, uid: str) -> Union[GcgDeckInfo, int]: + data = await self.simple_mys_req('GCG_DECK_URL', uid) + if isinstance(data, Dict): + data = cast(GcgDeckInfo, data['data']) + return data + + async def get_cookie_token( + self, token: str, uid: str + ) -> Union[CookieTokenInfo, int]: + data = await self._mys_request( + _API['GET_COOKIE_TOKEN_BY_GAME_TOKEN'], + 'GET', + params={ + 'game_token': token, + 'account_id': uid, + }, + ) + if isinstance(data, Dict): + data = cast(CookieTokenInfo, data['data']) + return data + + async def get_sign_list(self, uid) -> Union[SignList, int]: + is_os = self.check_os(uid) + if is_os: + params = { + 'act_id': 'e202102251931481', + 'lang': 'zh-cn', + } + else: + params = {'act_id': 'e202009291139501'} + data = await self._mys_req_get('SIGN_LIST_URL', is_os, params) + if isinstance(data, Dict): + data = cast(SignList, data['data']) + return data + + async def get_sign_info(self, uid) -> Union[SignInfo, int]: + server_id = RECOGNIZE_SERVER.get(str(uid)[0]) + is_os = self.check_os(uid) + if is_os: + params = { + 'act_id': 'e202102251931481', + 'lang': 'zh-cn', + 'region': server_id, + 'uid': uid, + } + header = { + 'DS': generate_os_ds(), + } + else: + params = { + 'act_id': 'e202009291139501', + 'region': server_id, + 'uid': uid, + } + header = {} + data = await self._mys_req_get('SIGN_INFO_URL', is_os, params, header) + if isinstance(data, Dict): + data = cast(SignInfo, data['data']) + return data + + async def mys_sign( + self, uid, header={}, server_id='cn_gf01' + ) -> Union[MysSign, int]: + server_id = RECOGNIZE_SERVER.get(str(uid)[0]) + ck = await self.get_ck(uid, 'OWNER') + if ck is None: + return -51 + if int(str(uid)[0]) < 6: + HEADER = copy.deepcopy(self._HEADER) + HEADER['Cookie'] = ck + HEADER['x-rpc-device_id'] = random_hex(32) + HEADER['x-rpc-app_version'] = '2.44.1' + HEADER['x-rpc-client_type'] = '5' + HEADER['X_Requested_With'] = 'com.mihoyo.hyperion' + HEADER['DS'] = get_web_ds_token(True) + HEADER['Referer'] = ( + 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html' + '?bbs_auth_required=true&act_id=e202009291139501' + '&utm_source=bbs&utm_medium=mys&utm_campaign=icon' + ) + HEADER.update(header) + data = await self._mys_request( + url=_API['SIGN_URL'], + method='POST', + header=HEADER, + data={ + 'act_id': 'e202009291139501', + 'uid': uid, + 'region': server_id, + }, + ) + else: + HEADER = copy.deepcopy(self._HEADER_OS) + HEADER['Cookie'] = ck + HEADER['DS'] = generate_os_ds() + HEADER.update(header) + data = await self._mys_request( + url=_API['SIGN_URL_OS'], + method='POST', + header=HEADER, + data={ + 'act_id': 'e202102251931481', + 'lang': 'zh-cn', + 'uid': uid, + 'region': server_id, + }, + use_proxy=True, + ) + if isinstance(data, Dict): + data = cast(MysSign, data['data']) + return data + + async def get_award(self, uid) -> Union[MonthlyAward, int]: + server_id = RECOGNIZE_SERVER.get(str(uid)[0]) + ck = await self.get_ck(uid, 'OWNER') + if ck is None: + return -51 + if int(str(uid)[0]) < 6: + HEADER = copy.deepcopy(self._HEADER) + HEADER['Cookie'] = ck + HEADER['DS'] = get_web_ds_token(True) + HEADER['x-rpc-device_id'] = random_hex(32) + data = await self._mys_request( + url=_API['MONTHLY_AWARD_URL'], + method='GET', + header=HEADER, + params={ + 'act_id': 'e202009291139501', + 'bind_region': server_id, + 'bind_uid': uid, + 'month': '0', + 'bbs_presentation_style': 'fullscreen', + 'bbs_auth_required': 'true', + 'utm_source': 'bbs', + 'utm_medium': 'mys', + 'utm_campaign': 'icon', + }, + ) + else: + HEADER = copy.deepcopy(self._HEADER_OS) + HEADER['Cookie'] = ck + HEADER['x-rpc-device_id'] = random_hex(32) + HEADER['DS'] = generate_os_ds() + data = await self._mys_request( + url=_API['MONTHLY_AWARD_URL_OS'], + method='GET', + header=HEADER, + params={ + 'act_id': 'e202009291139501', + 'region': server_id, + 'uid': uid, + 'month': '0', + }, + use_proxy=True, + ) + if isinstance(data, Dict): + data = cast(MonthlyAward, data['data']) + return data + + async def get_draw_calendar(self, uid: str) -> Union[int, RolesCalendar]: + server_id = RECOGNIZE_SERVER.get(uid[0]) + ck = await self.get_ck(uid, 'OWNER') + if ck is None: + return -51 + hk4e_token = await self.get_hk4e_token(uid) + header = {} + header['Cookie'] = f'{ck};{hk4e_token}' + params = { + 'lang': 'zh-cn', + 'badge_uid': uid, + 'badge_region': server_id, + 'game_biz': 'hk4e_cn', + 'activity_id': 20220301153521, + 'year': 2023, + } + data = await self._mys_request( + _API['CALENDAR_URL'], 'GET', header, params + ) + if isinstance(data, Dict): + return cast(RolesCalendar, data['data']) + return data + + async def get_bs_index(self, uid: str) -> Union[int, BsIndex]: + server_id = RECOGNIZE_SERVER.get(uid[0]) + ck = await self.get_ck(uid, 'OWNER') + if ck is None: + return -51 + hk4e_token = await self.get_hk4e_token(uid) + header = {} + header['Cookie'] = f'{ck};{hk4e_token}' + data = await self._mys_request( + _API['BS_INDEX_URL'], + 'GET', + header, + { + 'lang': 'zh-cn', + 'badge_uid': uid, + 'badge_region': server_id, + 'game_biz': 'hk4e_cn', + 'activity_id': 20220301153521, + }, + ) + if isinstance(data, Dict): + return cast(BsIndex, data['data']) + return data + + async def post_draw(self, uid: str, role_id: int) -> Union[int, Dict]: + server_id = RECOGNIZE_SERVER.get(uid[0]) + ck = await self.get_ck(uid, 'OWNER') + if ck is None: + return -51 + hk4e_token = await self.get_hk4e_token(uid) + header = {} + header['Cookie'] = f'{ck};{hk4e_token}' + data = await self._mys_request( + _API['RECEIVE_URL'], + 'POST', + header, + { + 'lang': 'zh-cn', + 'badge_uid': uid, + 'badge_region': server_id, + 'game_biz': 'hk4e_cn', + 'activity_id': 20220301153521, + }, + {'role_id': role_id}, + ) + if isinstance(data, Dict): + return data + elif data == -512009: + return {'data': None, 'message': '这张画片已经被收录啦~', 'retcode': -512009} + else: + return -999 + + async def get_spiral_abyss_info( + self, uid: str, schedule_type='1', ck: Optional[str] = None + ) -> Union[AbyssData, int]: + server_id = RECOGNIZE_SERVER.get(uid[0]) + data = await self.simple_mys_req( + 'PLAYER_ABYSS_INFO_URL', + uid, + { + 'role_id': uid, + 'schedule_type': schedule_type, + 'server': server_id, + }, + cookie=ck, + ) + if isinstance(data, Dict): + data = cast(AbyssData, data['data']) + return data + + async def get_character( + self, uid, character_ids, ck + ) -> Union[CharDetailData, int]: + server_id = RECOGNIZE_SERVER.get(str(uid)[0]) + if int(str(uid)[0]) < 6: + HEADER = copy.deepcopy(self._HEADER) + HEADER['Cookie'] = ck + HEADER['DS'] = get_ds_token( + '', + { + 'character_ids': character_ids, + 'role_id': uid, + 'server': server_id, + }, + ) + data = await self._mys_request( + _API['PLAYER_DETAIL_INFO_URL'], + 'POST', + HEADER, + data={ + 'character_ids': character_ids, + 'role_id': uid, + 'server': server_id, + }, + ) + else: + HEADER = copy.deepcopy(self._HEADER_OS) + HEADER['Cookie'] = ck + HEADER['DS'] = generate_os_ds() + data = await self._mys_request( + _API['PLAYER_DETAIL_INFO_URL_OS'], + 'POST', + HEADER, + data={ + 'character_ids': character_ids, + 'role_id': uid, + 'server': server_id, + }, + use_proxy=True, + ) + if isinstance(data, Dict): + data = cast(CharDetailData, data['data']) + return data + + async def get_calculate_info( + self, uid, char_id: int + ) -> Union[CalculateInfo, int]: + server_id = RECOGNIZE_SERVER.get(str(uid)[0]) + data = await self.simple_mys_req( + 'CALCULATE_INFO_URL', + uid, + {'avatar_id': char_id, 'uid': uid, 'region': server_id}, + ) + if isinstance(data, Dict): + data = cast(CalculateInfo, data['data']) + return data + + async def get_mihoyo_bbs_info( + self, + mys_id: str, + cookie: Optional[str] = None, + is_os: bool = False, + ) -> Union[List[MysGame], int]: + if not cookie: + cookie = await self.get_ck(mys_id, 'OWNER') + data = await self.simple_mys_req( + 'MIHOYO_BBS_PLAYER_INFO_URL', + is_os, + {'uid': mys_id}, + {'Cookie': cookie}, + ) + if isinstance(data, Dict): + data = cast(List[MysGame], data['data']['list']) + return data + + async def create_qrcode_url(self) -> Union[Dict, int]: + device_id: str = ''.join(random.choices(ascii_letters + digits, k=64)) + app_id: str = '8' + data = await self._mys_request( + _API['CREATE_QRCODE'], + 'POST', + header={}, + data={'app_id': app_id, 'device': device_id}, + ) + if isinstance(data, Dict): + url: str = data['data']['url'] + ticket = url.split('ticket=')[1] + return { + 'app_id': app_id, + 'ticket': ticket, + 'device': device_id, + 'url': url, + } + return data + + async def check_qrcode( + self, app_id: str, ticket: str, device: str + ) -> Union[QrCodeStatus, int]: + data = await self._mys_request( + _API['CHECK_QRCODE'], + 'POST', + data={ + 'app_id': app_id, + 'ticket': ticket, + 'device': device, + }, + ) + if isinstance(data, Dict): + data = cast(QrCodeStatus, data['data']) + return data + + async def get_gacha_log_by_authkey( + self, + uid: str, + gacha_type: str = '301', + page: int = 1, + end_id: str = '0', + ) -> Union[int, GachaLog]: + server_id = 'cn_qd01' if uid[0] == '5' else 'cn_gf01' + authkey_rawdata = await self.get_authkey_by_cookie(uid) + if isinstance(authkey_rawdata, int): + return authkey_rawdata + authkey = authkey_rawdata['authkey'] + data = await self._mys_request( + url=_API['GET_GACHA_LOG_URL'], + method='GET', + header=self._HEADER, + params={ + 'authkey_ver': '1', + 'sign_type': '2', + 'auth_appid': 'webview_gacha', + 'init_type': '200', + 'gacha_id': 'fecafa7b6560db5f3182222395d88aaa6aaac1bc', + 'timestamp': str(int(time.time())), + 'lang': 'zh-cn', + 'device_type': 'mobile', + 'plat_type': 'ios', + 'region': server_id, + 'authkey': authkey, + 'game_biz': 'hk4e_cn', + 'gacha_type': gacha_type, + 'page': page, + 'size': '20', + 'end_id': end_id, + }, + ) + if isinstance(data, Dict): + data = cast(GachaLog, data['data']) + return data + + async def get_cookie_token_by_game_token( + self, token: str, uid: str + ) -> Union[CookieTokenInfo, int]: + data = await self._mys_request( + _API['GET_COOKIE_TOKEN_BY_GAME_TOKEN'], + 'GET', + params={ + 'game_token': token, + 'account_id': uid, + }, + ) + if isinstance(data, Dict): + data = cast(CookieTokenInfo, data['data']) + return data + + async def get_cookie_token_by_stoken( + self, stoken: str, mys_id: str, full_sk: Optional[str] = None + ) -> Union[CookieTokenInfo, int]: + HEADER = copy.deepcopy(self._HEADER) + if full_sk: + HEADER['Cookie'] = full_sk + else: + HEADER['Cookie'] = f'stuid={mys_id};stoken={stoken}' + data = await self._mys_request( + url=_API['GET_COOKIE_TOKEN_URL'], + method='GET', + header=HEADER, + params={ + 'stoken': stoken, + 'uid': mys_id, + }, + ) + if isinstance(data, Dict): + data = cast(CookieTokenInfo, data['data']) + return data + + async def get_stoken_by_login_ticket( + self, lt: str, mys_id: str + ) -> Union[LoginTicketInfo, int]: + data = await self._mys_request( + url=_API['GET_STOKEN_URL'], + method='GET', + header=self._HEADER, + params={ + 'login_ticket': lt, + 'token_types': '3', + 'uid': mys_id, + }, + ) + if isinstance(data, Dict): + data = cast(LoginTicketInfo, data['data']) + return data + + async def get_stoken_by_game_token( + self, account_id: int, game_token: str + ) -> Union[GameTokenInfo, int]: + _data = { + 'account_id': account_id, + 'game_token': game_token, + } + data = await self._mys_request( + _API['GET_STOKEN'], + 'POST', + { + 'x-rpc-app_version': '2.41.0', + 'DS': generate_passport_ds(b=_data), + 'x-rpc-aigis': '', + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'x-rpc-game_biz': 'bbs_cn', + 'x-rpc-sys_version': '11', + 'x-rpc-device_id': uuid.uuid4().hex, + 'x-rpc-device_fp': ''.join( + random.choices(ascii_letters + digits, k=13) + ), + 'x-rpc-device_name': 'GenshinUid_login_device_lulu', + 'x-rpc-device_model': 'GenshinUid_login_device_lulu', + 'x-rpc-app_id': 'bll8iq97cem8', + 'x-rpc-client_type': '2', + 'User-Agent': 'okhttp/4.8.0', + }, + data=_data, + ) + if isinstance(data, Dict): + data = cast(GameTokenInfo, data['data']) + return data + + async def get_authkey_by_cookie(self, uid: str) -> Union[AuthKeyInfo, int]: + server_id = RECOGNIZE_SERVER.get(str(uid)[0]) + HEADER = copy.deepcopy(self._HEADER) + stoken = await self.get_stoken(uid) + if stoken is None: + return -51 + HEADER['Cookie'] = stoken + HEADER['DS'] = get_web_ds_token(True) + HEADER['User-Agent'] = 'okhttp/4.8.0' + HEADER['x-rpc-app_version'] = '2.44.1' + HEADER['x-rpc-sys_version'] = '12' + HEADER['x-rpc-client_type'] = '5' + HEADER['x-rpc-channel'] = 'mihoyo' + HEADER['x-rpc-device_id'] = random_hex(32) + HEADER['x-rpc-device_name'] = random_text(random.randint(1, 10)) + HEADER['x-rpc-device_model'] = 'Mi 10' + HEADER['Referer'] = 'https://app.mihoyo.com' + HEADER['Host'] = 'api-takumi.mihoyo.com' + data = await self._mys_request( + url=_API['GET_AUTHKEY_URL'], + method='POST', + header=HEADER, + data={ + 'auth_appid': 'webview_gacha', + 'game_biz': 'hk4e_cn', + 'game_uid': uid, + 'region': server_id, + }, + ) + if isinstance(data, Dict): + data = cast(AuthKeyInfo, data['data']) + return data + + async def get_hk4e_token(self, uid: str): + # 获取e_hk4e_token + server_id = RECOGNIZE_SERVER.get(uid[0]) + header = { + 'Cookie': await self.get_ck(uid, 'OWNER'), + 'Content-Type': 'application/json;charset=UTF-8', + 'Referer': 'https://webstatic.mihoyo.com/', + 'Origin': 'https://webstatic.mihoyo.com', + } + use_proxy = False + data = { + 'game_biz': 'hk4e_cn', + 'lang': 'zh-cn', + 'uid': f'{uid}', + 'region': f'{server_id}', + } + if int(str(uid)[0]) < 6: + url = _API['HK4E_LOGIN_URL'] + else: + url = _API['HK4E_LOGIN_URL_OS'] + data['game_biz'] = 'hk4e_global' + use_proxy = True + + async with ClientSession() as client: + async with client.request( + method='POST', + url=url, + headers=header, + json=data, + proxy=self.proxy_url if use_proxy else None, + timeout=300, + ) as resp: + raw_data = await resp.json() + if 'retcode' in raw_data and raw_data['retcode'] == 0: + _k = resp.cookies['e_hk4e_token'].key + _v = resp.cookies['e_hk4e_token'].value + ck = f'{_k}={_v}' + return ck + else: + return None + + async def get_regtime_data(self, uid: str) -> Union[RegTime, int]: + hk4e_token = await self.get_hk4e_token(uid) + ck_token = await self.get_ck(uid, 'OWNER') + params = { + 'game_biz': 'hk4e_cn', + 'lang': 'zh-cn', + 'badge_uid': uid, + 'badge_region': RECOGNIZE_SERVER.get(uid[0]), + } + data = await self.simple_mys_req( + 'REG_TIME', + uid, + params, + {'Cookie': f'{hk4e_token};{ck_token}' if int(uid[0]) <= 5 else {}}, + ) + if isinstance(data, Dict): + return cast(RegTime, data['data']) + else: + return data + + '''充值相关''' + + async def get_fetchgoods(self) -> Union[int, List[MysGoods]]: + data = { + 'released_flag': True, + 'game': 'hk4e_cn', + 'region': 'cn_gf01', + 'uid': '1', + 'account': '1', + } + resp = await self._mys_request( + url=_API['fetchGoodsurl'], + method='POST', + data=data, + ) + if isinstance(resp, int): + return resp + return cast(List[MysGoods], resp['data']['goods_list']) + + async def topup( + self, + uid: str, + goods: MysGoods, + method: Literal['weixin', 'alipay'] = 'alipay', + ) -> Union[int, MysOrder]: + device_id = str(uuid.uuid4()) + HEADER = copy.deepcopy(self._HEADER) + ck = await self.get_ck(uid, 'OWNER') + if ck is None: + return -51 + HEADER['Cookie'] = ck + account = HEADER['Cookie'].split('account_id=')[1].split(';')[0] + order = { + 'account': str(account), + 'region': 'cn_gf01', + 'uid': uid, + 'delivery_url': '', + 'device': device_id, + 'channel_id': 1, + 'client_ip': '', + 'client_type': 4, + 'game': 'hk4e_cn', + 'amount': goods['price'], + # 'amount': 600, + 'goods_num': 1, + 'goods_id': goods['goods_id'], + 'goods_title': f'{goods["goods_name"]}×{str(goods["goods_unit"])}' + if int(goods['goods_unit']) > 0 + else goods['goods_name'], + 'price_tier': goods['tier_id'], + # 'price_tier': 'Tier_1', + 'currency': 'CNY', + 'pay_plat': method, + } + data = {'order': order, 'sign': gen_payment_sign(order)} + HEADER['x-rpc-device_id'] = device_id + HEADER['x-rpc-client_type'] = '4' + resp = await self._mys_request( + url=_API['CreateOrderurl'], + method='POST', + header=HEADER, + data=data, + ) + if isinstance(resp, int): + return resp + return cast(MysOrder, resp['data']) + + async def check_order( + self, order: MysOrder, uid: str + ) -> Union[int, MysOrderCheck]: + HEADER = copy.deepcopy(self._HEADER) + ck = await self.get_ck(uid, 'OWNER') + if ck is None: + return -51 + HEADER['Cookie'] = ck + data = { + 'order_no': order['order_no'], + 'game': 'hk4e_cn', + 'region': 'cn_gf01', + 'uid': uid, + } + resp = await self._mys_request( + url=_API['CheckOrderurl'], + method='GET', + header=HEADER, + params=data, + ) + if isinstance(resp, int): + return resp + return cast(MysOrderCheck, resp['data']) + + async def simple_mys_req( + self, + URL: str, + uid: Union[str, bool], + params: Dict = {}, + header: Dict = {}, + cookie: Optional[str] = None, + ) -> Union[Dict, int]: + if isinstance(uid, bool): + is_os = uid + server_id = 'cn_qd01' if is_os else 'cn_gf01' + else: + server_id = RECOGNIZE_SERVER.get(uid[0]) + is_os = False if int(uid[0]) < 6 else True + ex_params = '&'.join([f'{k}={v}' for k, v in params.items()]) + if is_os: + _URL = _API[f'{URL}_OS'] + HEADER = copy.deepcopy(self._HEADER_OS) + HEADER['DS'] = generate_os_ds() + else: + _URL = _API[URL] + HEADER = copy.deepcopy(self._HEADER) + HEADER['DS'] = get_ds_token( + ex_params if ex_params else f'role_id={uid}&server={server_id}' + ) + HEADER.update(header) + if cookie is not None: + HEADER['Cookie'] = cookie + elif 'Cookie' not in HEADER and isinstance(uid, str): + ck = await self.get_ck(uid) + if ck is None: + return -51 + HEADER['Cookie'] = ck + data = await self._mys_request( + url=_URL, + method='GET', + header=HEADER, + params=params if params else {'server': server_id, 'role_id': uid}, + use_proxy=True if is_os else False, + ) + return data + + async def _mys_req_get( + self, + url: str, + is_os: bool, + params: Dict, + header: Optional[Dict] = None, + ) -> Union[Dict, int]: + if is_os: + _URL = _API[f'{url}_OS'] + HEADER = copy.deepcopy(self._HEADER_OS) + use_proxy = True + else: + _URL = _API[url] + HEADER = copy.deepcopy(self._HEADER) + use_proxy = False + if header: + HEADER.update(header) + + if 'Cookie' not in HEADER and 'uid' in params: + ck = await self.get_ck(params['uid']) + if ck is None: + return -51 + HEADER['Cookie'] = ck + data = await self._mys_request( + url=_URL, + method='GET', + header=HEADER, + params=params, + use_proxy=use_proxy, + ) + return data + + async def _mys_request( + self, + url: str, + method: Literal['GET', 'POST'] = 'GET', + header: Dict[str, Any] = _HEADER, + params: Optional[Dict[str, Any]] = None, + data: Optional[Dict[str, Any]] = None, + use_proxy: Optional[bool] = False, + ) -> Union[Dict, int]: + async with ClientSession() as client: + async with client.request( + method, + url=url, + headers=header, + params=params, + json=data, + proxy=self.proxy_url if use_proxy else None, + timeout=300, + ) as resp: + try: + raw_data = await resp.json() + except ContentTypeError: + _raw_data = await resp.text() + raw_data = {'retcode': -999, 'data': _raw_data} + print(raw_data) + if 'retcode' in raw_data: + retcode: int = raw_data['retcode'] + elif 'code' in raw_data: + retcode: int = raw_data['code'] + else: + retcode = 0 + if retcode == 1034: + await self._upass(header) + return retcode + elif retcode != 0: + return retcode + return raw_data diff --git a/gsuid_core/utils/api/mys/tools.py b/gsuid_core/utils/api/mys/tools.py new file mode 100644 index 0000000..66e31d0 --- /dev/null +++ b/gsuid_core/utils/api/mys/tools.py @@ -0,0 +1,95 @@ +import hmac +import json +import time +import random +import string +import hashlib +from typing import Any, Dict, Optional + +_S = { + '2.44.1': { + 'LK2': 'IEIZiKYaput2OCKQprNuGsog1NZc1FkS', + 'K2': 'dZAwGk4e9aC0MXXItkwnHamjA1x30IYw', + '22': 't0qEgfub6cvueAPgR5m9aQWWVciEer7v', + '25': 'xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs', + }, + 'os': '6cqshh5dhw73bzxn20oexa9k516chk7s', + 'PD': 'JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS', +} + + +def random_hex(length): + result = hex(random.randint(0, 16**length)).replace('0x', '').upper() + if len(result) < length: + result = '0' * (length - len(result)) + result + return result + + +def md5(text): + md5_func = hashlib.md5() + md5_func.update(text.encode()) + return md5_func.hexdigest() + + +def random_text(num: int) -> str: + return ''.join(random.sample(string.ascii_lowercase + string.digits, num)) + + +def _random_str_ds( + salt: str, + sets: str = string.ascii_lowercase + string.digits, + with_body: bool = False, + q: str = '', + b: Optional[Dict[str, Any]] = None, +): + i = str(int(time.time())) + r = ''.join(random.sample(sets, 6)) + s = f'salt={salt}&t={i}&r={r}' + if with_body: + s += f'&b={json.dumps(b) if b else ""}&q={q}' + c = md5(s) + return f'{i},{r},{c}' + + +def _random_int_ds(salt: str, q: str = '', b: Optional[Dict[str, Any]] = None): + br = json.dumps(b) if b else '' + s = salt + t = str(int(time.time())) + r = str(random.randint(100000, 200000)) + c = md5(f'salt={s}&t={t}&r={r}&b={br}&q={q}') + return f'{t},{r},{c}' + + +def get_ds_token( + q: str = '', + b: Optional[Dict[str, Any]] = None, + salt_id: str = '25', +): + salt = _S['2.44.1'][salt_id] + return _random_int_ds(salt, q, b) + + +def get_web_ds_token(web=False): + return _random_str_ds(_S['2.44.1']['LK2'] if web else _S['2.44.1']['K2']) + + +def generate_os_ds(salt: str = '') -> str: + return _random_str_ds(salt or _S['os'], sets=string.ascii_letters) + + +def generate_passport_ds(q: str = '', b: Optional[Dict[str, Any]] = None): + return _random_str_ds(_S['PD'], string.ascii_letters, True, q, b) + + +def HMCASHA256(data: str, key: str): + key_bytes = key.encode('utf-8') + message = data.encode('utf-8') + sign = hmac.new(key_bytes, message, digestmod=hashlib.sha256).digest() + return sign.hex() + + +def gen_payment_sign(data): + data = dict(sorted(data.items(), key=lambda x: x[0])) + value = ''.join([str(i) for i in data.values()]) + sign = HMCASHA256(value, '6bdc3982c25f3f3c38668a32d287d16b') + return sign diff --git a/gsuid_core/utils/api/types.py b/gsuid_core/utils/api/types.py new file mode 100644 index 0000000..66bcd33 --- /dev/null +++ b/gsuid_core/utils/api/types.py @@ -0,0 +1,5 @@ +from __future__ import annotations + +from typing import Any, Dict + +AnyDict = Dict[str, Any] diff --git a/gsuid_core/utils/api/utils.py b/gsuid_core/utils/api/utils.py new file mode 100644 index 0000000..3c6e170 --- /dev/null +++ b/gsuid_core/utils/api/utils.py @@ -0,0 +1,3 @@ +from gsuid_core.version import __version__ + +_HEADER = {'User-Agent': f'gsuid-utils/{__version__}'} diff --git a/gsuid_core/utils/colortext/ColorText.py b/gsuid_core/utils/colortext/ColorText.py new file mode 100644 index 0000000..acfe911 --- /dev/null +++ b/gsuid_core/utils/colortext/ColorText.py @@ -0,0 +1,148 @@ +from typing import Union + +from color import Color, check_if_color + + +class BaseTextContainer(list): + @property + def len(self): + _len_count = 0 + for i_ in self: + _len_count += len(i_) + return _len_count + + def __and__(self, other): + self.append(other) + + def __repr__(self): + return f'BaseTextContainer({list(self)})' + + +class ColorText: + def _set_color(self, color): + self.color = Color(color) + + def __init__(self, text: str, color: Union[str, tuple] = 'black'): + self._check_color = check_if_color + if not self._check_color(color): + print(f'Color: {color}\n' f'Type: {str(type(color))}') + + # assert self._check_color(color) + self._set_color(color) + self.text = text + + def __len__(self): + return len(self.text) + + def __repr__(self): + return f'ColorText(\'{self.text}\', {self.color})' + + def __str__(self): + return self.text + + def __format__(self, format_spec): + return self.__repr__() + + def __lshift__(self, other): + self._set_color(other) + + def __getitem__(self, index): + return ColorText(self.text[index], color=self.color) + + +class ColorTextGroup(BaseTextContainer): + def __init__(self, texts=None): + if texts is None: + texts = [] + super().__init__(texts) + + def append(self, text): + if isinstance(text, (str, ColorText)): + super().append(text) + else: + raise TypeError('The text parameter is neither str nor ColorText') + + +class TextBuffer(BaseTextContainer): + def __init__(self, seq, length: int): + super().__init__(seq) + self.max_length = length + + @property + def free_size(self): + return self.max_length - self.len + + +def split_ep( + text: Union[str, ColorText], length: int, pre_len: int = 0 +): # Cut strings by length but discard the first N characters + # https://github.com/PyCQA/pycodestyle/issues/373 + return text[:pre_len], [ + text[i : i + length] for i in range(pre_len, len(text), length) # noqa + ] + + +def split_ctg( + group: Union[list, ColorTextGroup], length: int +) -> list: # Cut strings from ColorTextGroup + result = [] + buffer = TextBuffer([], length) + + if isinstance(group, list): + group = ColorTextGroup(group) + for t in group: + if len(t) <= buffer.free_size: + # buffer & t + continue + if len(t) > buffer.free_size: + _long_text_result = split_ep(t, length, buffer.free_size) + # buffer & _long_text_result[0] + result.append(buffer.copy()) + buffer.clear() + if len(_long_text_result[1][-1]) < length: + buffer = TextBuffer(_long_text_result[1][-1:], length) + result.append(_long_text_result[1][:-1]) + else: + result.append(_long_text_result[1]) + if buffer.free_size == 0: + result.append(buffer.copy()) + buffer.clear() + + return result + + +if __name__ == '__main__': + from pprint import pformat + + from colorama import Fore, Style + + def test_ctg(length: int, *params): + print( + f'{Fore.GREEN}> running split_ctg(){Style.RESET_ALL}\ + \n length: {length}\ + \n texts: {params}' + ) + groups_ = ColorTextGroup(list(params)) + f_ = pformat(split_ctg(groups_, length)).split('\n') + print(Fore.CYAN, '\t', f_[0], '\n\t'.join(f_[0:])) + + print('*** ColorTextGroup cutting test ***') + test_ctg( + 5, + 'test', + ColorText('i am red', 'red'), + 'foo', + ColorText('bar', color='cyan'), + ) + test_ctg( + 10, + '获得', + ColorText('12%/15%/18%/21%/24%', color='rgb(69,113,236)'), + '所有元素伤害加成;队伍中附近的其他角色在施放元素战技时,' + '会为装备该武器的角色产生1层「波穗」效果,至多叠加2层,' + '每0.3秒最多触发1次。装备该武器的角色施放元素战技时,' + '如果有积累的「波穗」效果,则将消耗已有的「波穗」,' + '获得「波乱」:根据消耗的层数,每层提升', + ColorText('20%/25%/30%/35%/40%', (69, 113, 236)), + '普通攻击伤害,持续8秒。', + ) diff --git a/gsuid_core/utils/colortext/LICENSE b/gsuid_core/utils/colortext/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/gsuid_core/utils/colortext/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/gsuid_core/utils/colortext/README.md b/gsuid_core/utils/colortext/README.md new file mode 100644 index 0000000..4bebb50 --- /dev/null +++ b/gsuid_core/utils/colortext/README.md @@ -0,0 +1,2 @@ +# Image +Image utils split from GsUtils diff --git a/gsuid_core/utils/colortext/color.py b/gsuid_core/utils/colortext/color.py new file mode 100644 index 0000000..2720d5a --- /dev/null +++ b/gsuid_core/utils/colortext/color.py @@ -0,0 +1,123 @@ +from enum import Enum +from typing import Tuple, Union + +from PIL import ImageColor + + +class ColorCodes(Enum): + HEX = 'hex' + RGB = 'rgb' + HSV = 'hsv' + + +class ConvertableColor: + def __init__(self, v_color: tuple): + self.v_color = v_color + + def __call__(self, space): + if space == ColorCodes.HEX: + return self.hex + elif space == ColorCodes.RGB: + return self.rgb + elif space == ColorCodes.HSV: + return self.hsv + else: + raise ValueError('Invalid color-code type') + + @property + def hex(self): + if len(self.v_color) == 3: + r, g, b = self.v_color + return f'#{r:02x}{g:02x}{b:02x}' + elif len(self.v_color) == 4: + r, g, b, a = self.v_color + return f'#{r:02x}{g:02x}{b:02x}{a:02x}' + else: + raise ValueError('Invalid color value') + + @property + def rgb(self): + if len(self.v_color) == 3: + r, g, b = self.v_color + return f'rgb({r}, {g}, {b})' + elif len(self.v_color) == 4: + r, g, b, a = self.v_color + return f'rgba({r}, {g}, {b}, {a})' + else: + raise ValueError('Invalid color value') + + @property + def hsv(self): + r, g, b = self.v_color[:3] + r, g, b = r / 255.0, g / 255.0, b / 255.0 + mx = max(r, g, b) + mn = min(r, g, b) + df = mx - mn + if mx == mn: + h = 0 + elif mx == r: + h = (60 * ((g - b) / df) + 360) % 360 + elif mx == g: + h = (60 * ((b - r) / df) + 120) % 360 + elif mx == b: + h = (60 * ((r - g) / df) + 240) % 360 + else: + h = 360 + + if mx == 0: + s = 0 + else: + s = df / mx + v = mx + return f'hsv({h}, {s}, {v})' + + +class Color(tuple): + @property + def to(self): + return ConvertableColor(self) + + def __new__( + cls, + _color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]], + ): + assert check_if_color(_color) + if isinstance(_color, str): + _color = ImageColor.getrgb(_color) + return super().__new__(cls, _color) + + def __str__(self): + return self.to.hex + + def __repr__(self): + return f"Color('{self.to.rgb}')" + + def __setitem__(self, key, value): + if 0 <= value <= 255: + super().__setitem__(key, value) # type: ignore + else: + raise ValueError("Color value must be between 0 and 255") + + +def check_if_color(color: Union[str, tuple]): + if isinstance(color, str): + try: + return ImageColor.getrgb(color) + except ValueError: + return False + if isinstance(color, (tuple, Color)): + if len(color) <= 4: + return all(isinstance(d, int) and 0 <= d <= 255 for d in color) + return False + + +if __name__ == '__main__': + red = Color((1, 1, 1)) + print(f'HEX: {red.to.hex}\nHSV: {red.to.hsv}\nRGB: {red.to.rgb}') + print( + f'rgb(123, 23, -1) \ + {check_if_color("rgb(123, 23, -1)")}\ + \n(100, 200, 255): \ + {check_if_color((100, 200, 256))}' + ) + print(check_if_color('#ff0000')) diff --git a/gsuid_core/utils/database/dal.py b/gsuid_core/utils/database/dal.py new file mode 100644 index 0000000..62c6e0a --- /dev/null +++ b/gsuid_core/utils/database/dal.py @@ -0,0 +1,574 @@ +import re +import asyncio +import contextlib +from typing import Dict, List, Literal, Optional + +from sqlmodel import SQLModel +from sqlalchemy.sql import text +from sqlalchemy.future import select +from sqlalchemy import delete, update +from sqlalchemy.orm import sessionmaker +from sqlalchemy.sql.expression import func +from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine + +from .utils import SERVER +from .models import GsBind, GsPush, GsUser, GsCache + + +class SQLA: + def __init__(self, url: str, bot_id: str): + self.bot_id = bot_id + self.url = f'sqlite+aiosqlite:///{url}' + self.engine = create_async_engine(self.url, pool_recycle=1500) + self.async_session = sessionmaker( + self.engine, expire_on_commit=False, class_=AsyncSession + ) + + def create_all(self): + try: + asyncio.create_task(self._create_all()) + except RuntimeError: + loop = asyncio.get_event_loop() + loop.run_until_complete(self._create_all()) + loop.close() + + async def _create_all(self): + async with self.engine.begin() as conn: + await conn.run_sync(SQLModel.metadata.create_all) + await self.sr_adapter() + + async def sr_adapter(self): + exec_list = [ + 'ALTER TABLE GsBind ADD COLUMN sr_uid TEXT', + 'ALTER TABLE GsUser ADD COLUMN sr_uid TEXT', + 'ALTER TABLE GsCache ADD COLUMN sr_uid TEXT', + ] + with contextlib.suppress(Exception): + async with self.async_session() as session: + for _t in exec_list: + await session.execute(text(_t)) + await session.commit() + + ##################### + # GsBind 部分 # + ##################### + async def select_bind_data(self, user_id: str) -> Optional[GsBind]: + async with self.async_session() as session: + async with session.begin(): + result = await session.execute( + select(GsBind).where( + GsBind.user_id == user_id, GsBind.bot_id == self.bot_id + ) + ) + data = result.scalars().all() + return data[0] if data else None + + async def insert_bind_data(self, user_id: str, **data) -> int: + async with self.async_session() as session: + async with session.begin(): + new_uid: str = data['uid'] if 'uid' in data else '' + new_uid = new_uid.strip() + new_sr_uid: str = data['sr_uid'] if 'sr_uid' in data else '' + new_sr_uid = new_sr_uid.strip() + if len(new_uid) != 9 and len(new_sr_uid) != 9: + return -1 + elif not new_uid.isdigit() and new_sr_uid.isdigit(): + return -3 + if new_uid and await self.bind_exists(user_id): + uid_list = await self.get_bind_uid_list(user_id) + if new_uid not in uid_list: + uid_list.append(new_uid) + else: + return -2 + data['uid'] = '_'.join(uid_list) + await self.update_bind_data(user_id, data) + elif new_sr_uid and await self.bind_exists(user_id): + sr_uid_list = await self.get_bind_sruid_list(user_id) + if new_sr_uid not in sr_uid_list: + sr_uid_list.append(new_sr_uid) + else: + return -2 + data['sr_uid'] = '_'.join(sr_uid_list) + await self.update_bind_data(user_id, data) + else: + new_data = GsBind( + user_id=user_id, bot_id=self.bot_id, **data + ) + session.add(new_data) + await session.commit() + return 0 + + async def delete_bind_data(self, user_id: str, **data) -> int: + async with self.async_session() as session: + async with session.begin(): + _uid = data['uid'] if 'uid' in data else '' + if await self.bind_exists(user_id): + uid_list = await self.get_bind_uid_list(user_id) + if uid_list and _uid in uid_list: + uid_list.remove(_uid) + else: + return -1 + data['uid'] = '_'.join(uid_list) + await self.update_bind_data(user_id, data) + await session.commit() + return 0 + else: + return -1 + + async def update_bind_data(self, user_id: str, data: Optional[Dict]): + async with self.async_session() as session: + async with session.begin(): + sql = update(GsBind).where( + GsBind.user_id == user_id, GsBind.bot_id == self.bot_id + ) + if data is not None: + query = sql.values(**data) + query.execution_options(synchronize_session='fetch') + await session.execute(query) + + async def bind_exists(self, user_id: str) -> bool: + return bool(await self.select_bind_data(user_id)) + + async def get_all_uid_list(self) -> List[str]: + async with self.async_session() as session: + async with session.begin(): + sql = select(GsBind).where(GsBind.bot_id == self.bot_id) + result = await session.execute(sql) + data: List[GsBind] = result.scalars().all() + uid_list: List[str] = [] + for item in data: + uid_list.extend(item.uid.split("_") if item.uid else []) + return uid_list + + async def get_bind_uid_list(self, user_id: str) -> List[str]: + data = await self.select_bind_data(user_id) + return data.uid.split("_") if data and data.uid else [] + + async def get_bind_uid(self, user_id: str) -> Optional[str]: + data = await self.get_bind_uid_list(user_id) + return data[0] if data else None + + async def get_bind_sruid_list(self, user_id: str) -> List[str]: + data = await self.select_bind_data(user_id) + return data.sr_uid.split("_") if data and data.sr_uid else [] + + async def get_bind_sruid(self, user_id: str) -> Optional[str]: + data = await self.get_bind_sruid_list(user_id) + return data[0] if data else None + + async def switch_uid( + self, user_id: str, uid: Optional[str] = None + ) -> Optional[List]: + uid_list = await self.get_bind_uid_list(user_id) + if uid_list and len(uid_list) >= 1: + if uid and uid not in uid_list: + return None + elif uid: + pass + else: + uid = uid_list[1] + uid_list.remove(uid) + uid_list.insert(0, uid) + await self.update_bind_data(user_id, {'uid': '_'.join(uid_list)}) + return uid_list + else: + return None + + ##################### + # GsUser、GsCache 部分 # + ##################### + + async def select_user_data(self, uid: str) -> Optional[GsUser]: + async with self.async_session() as session: + async with session.begin(): + sql = select(GsUser).where(GsUser.uid == uid) + result = await session.execute(sql) + return data[0] if (data := result.scalars().all()) else None + + async def select_sr_user_data(self, sr_uid: str) -> Optional[GsUser]: + async with self.async_session() as session: + async with session.begin(): + sql = select(GsUser).where(GsUser.sr_uid == sr_uid) + result = await session.execute(sql) + return data[0] if (data := result.scalars().all()) else None + + async def select_cache_cookie(self, uid: str) -> Optional[str]: + async with self.async_session() as session: + async with session.begin(): + sql = select(GsCache).where(GsCache.uid == uid) + result = await session.execute(sql) + data: List[GsCache] = result.scalars().all() + return data[0].cookie if len(data) >= 1 else None + + async def delete_error_cache(self) -> bool: + async with self.async_session() as session: + async with session.begin(): + data = await self.get_all_error_cookie() + for cookie in data: + sql = delete(GsCache).where(GsCache.cookie == cookie) + await session.execute(sql) + return True + + async def insert_cache_data( + self, + cookie: str, + uid: Optional[str] = None, + sr_uid: Optional[str] = None, + mys_id: Optional[str] = None, + ) -> bool: + async with self.async_session() as session: + async with session.begin(): + new_data = GsCache( + cookie=cookie, uid=uid, sr_uid=sr_uid, mys_id=mys_id + ) + session.add(new_data) + await session.commit() + return True + + async def insert_user_data( + self, + user_id: str, + uid: Optional[str], + sr_uid: Optional[str], + cookie: str, + stoken: Optional[str] = None, + ) -> bool: + async with self.async_session() as session: + async with session.begin(): + if uid and await self.user_exists(uid): + sql = ( + update(GsUser) + .where(GsUser.uid == uid) + .values( + cookie=cookie, + status=None, + stoken=stoken, + bot_id=self.bot_id, + user_id=user_id, + ) + ) + await session.execute(sql) + elif sr_uid and await self.sr_user_exists(sr_uid): + sql = ( + update(GsUser) + .where(GsUser.sr_uid == sr_uid) + .values( + cookie=cookie, + status=None, + stoken=stoken, + bot_id=self.bot_id, + user_id=user_id, + ) + ) + await session.execute(sql) + else: + account_id = re.search(r'account_id=(\d*)', cookie) + assert account_id is not None + account_id = str(account_id.group(1)) + + user_data = GsUser( + uid=uid, + sr_uid=sr_uid, + mys_id=account_id, + cookie=cookie, + stoken=stoken if stoken else None, + user_id=user_id, + bot_id=self.bot_id, + sign_switch='off', + push_switch='off', + bbs_switch='off', + region=SERVER.get(uid[0], 'cn_gf01') if uid else None, + sr_region=None, + ) + session.add(user_data) + await session.commit() + return True + + async def update_user_data(self, uid: str, data: Optional[Dict]): + async with self.async_session() as session: + async with session.begin(): + sql = update(GsUser).where( + GsUser.uid == uid, GsUser.bot_id == self.bot_id + ) + if data is not None: + query = sql.values(**data) + query.execution_options(synchronize_session='fetch') + await session.execute(query) + await session.commit() + + async def delete_user_data(self, uid: str): + async with self.async_session() as session: + async with session.begin(): + if await self.user_exists(uid): + sql = delete(GsUser).where(GsUser.uid == uid) + await session.execute(sql) + await session.commit() + return True + return False + + async def delete_cache(self): + async with self.async_session() as session: + async with session.begin(): + sql = ( + update(GsUser) + .where(GsUser.status == 'limit30') + .values(status=None) + ) + empty_sql = delete(GsCache) + await session.execute(sql) + await session.execute(empty_sql) + await session.commit() + + async def mark_invalid(self, cookie: str, mark: str): + async with self.async_session() as session: + async with session.begin(): + sql = ( + update(GsUser) + .where(GsUser.cookie == cookie) + .values(status=mark) + ) + await session.execute(sql) + await session.commit() + + async def user_exists(self, uid: str) -> bool: + data = await self.select_user_data(uid) + return True if data else False + + async def sr_user_exists(self, sr_uid: str) -> bool: + data = await self.select_sr_user_data(sr_uid) + return True if data else False + + async def update_user_stoken( + self, uid: str, stoken: Optional[str] + ) -> bool: + async with self.async_session() as session: + async with session.begin(): + if await self.user_exists(uid): + sql = ( + update(GsUser) + .where(GsUser.uid == uid) + .values(stoken=stoken) + ) + await session.execute(sql) + await session.commit() + return True + return False + + async def update_user_cookie( + self, uid: str, cookie: Optional[str] + ) -> bool: + async with self.async_session() as session: + async with session.begin(): + if await self.user_exists(uid): + sql = ( + update(GsUser) + .where(GsUser.uid == uid) + .values(cookie=cookie) + ) + await session.execute(sql) + await session.commit() + return True + return False + + async def update_switch_status(self, uid: str, data: Dict) -> bool: + async with self.async_session() as session: + async with session.begin(): + if await self.user_exists(uid): + sql = ( + update(GsUser).where(GsUser.uid == uid).values(**data) + ) + await session.execute(sql) + await session.commit() + return True + return False + + async def update_error_status(self, cookie: str, err: str) -> bool: + async with self.async_session() as session: + async with session.begin(): + sql = ( + update(GsUser) + .where(GsUser.cookie == cookie) + .values(status=err) + ) + await session.execute(sql) + await session.commit() + return True + + async def get_user_cookie(self, uid: str) -> Optional[str]: + data = await self.select_user_data(uid) + return data.cookie if data else None + + async def cookie_validate(self, uid: str) -> bool: + data = await self.select_user_data(uid) + return True if data and data.status is None else False + + async def get_user_stoken(self, uid: str) -> Optional[str]: + data = await self.select_user_data(uid) + return data.stoken if data and data.stoken else None + + async def get_all_user(self) -> List[GsUser]: + async with self.async_session() as session: + async with session.begin(): + sql = select(GsUser).where( + GsUser.cookie is not None, GsUser.cookie != '' + ) + result = await session.execute(sql) + data: List[GsUser] = result.scalars().all() + return data + + async def get_all_cookie(self) -> List[str]: + data = await self.get_all_user() + return [_u.cookie for _u in data if _u.cookie] + + async def get_all_stoken(self) -> List[str]: + data = await self.get_all_user() + return [_u.stoken for _u in data if _u.stoken] + + async def get_all_error_cookie(self) -> List[str]: + data = await self.get_all_user() + return [_u.cookie for _u in data if _u.cookie and _u.status] + + async def get_all_push_user_list(self) -> List[GsUser]: + data = await self.get_all_user() + return [user for user in data if user.push_switch != 'off'] + + async def get_random_cookie(self, uid: str) -> Optional[str]: + async with self.async_session() as session: + async with session.begin(): + # 有绑定自己CK 并且该CK有效的前提下,优先使用自己CK + if await self.user_exists(uid) and await self.cookie_validate( + uid + ): + return await self.get_user_cookie(uid) + # 自动刷新缓存 + await self.delete_error_cache() + # 获得缓存库Ck + cache_data = await self.select_cache_cookie(uid) + if cache_data is not None: + return cache_data + # 随机取CK + server = SERVER.get(uid[0], 'cn_gf01') + sql = ( + select(GsUser) + .where(GsUser.region == server) + .order_by(func.random()) + ) + data = await session.execute(sql) + user_list: List[GsUser] = data.scalars().all() + for user in user_list: + if not user.status and user.cookie: + await self.insert_cache_data(user.cookie, uid) # 进入缓存 + return user.cookie + continue + else: + return None + + async def get_switch_status_list( + self, switch: Literal['push', 'sign', 'bbs'] + ) -> List[GsUser]: + async with self.async_session() as session: + async with session.begin(): + _switch = getattr(GsUser, switch, GsUser.push_switch) + sql = select(GsUser).filter(_switch != 'off') + data = await session.execute(sql) + data_list: List[GsUser] = data.scalars().all() + return [user for user in data_list] + + ##################### + # GsPush 部分 # + ##################### + async def insert_push_data(self, uid: str): + async with self.async_session() as session: + async with session.begin(): + push_data = GsPush( + bot_id=self.bot_id, + uid=uid, + coin_push='off', + coin_value=2100, + coin_is_push='off', + resin_push='on', + resin_value=140, + resin_is_push='off', + go_push='off', + go_value=120, + go_is_push='off', + transform_push='off', + transform_value=140, + transform_is_push='off', + ) + session.add(push_data) + await session.commit() + + async def update_push_data(self, uid: str, data: dict) -> bool: + async with self.async_session() as session: + async with session.begin(): + await self.push_exists(uid) + sql = ( + update(GsPush) + .where(GsPush.uid == uid, GsPush.bot_id == self.bot_id) + .values(**data) + ) + await session.execute(sql) + await session.commit() + return True + + async def change_push_status( + self, + mode: Literal['coin', 'resin', 'go', 'transform'], + uid: str, + status: str, + ): + await self.update_push_data(uid, {f'{mode}_is_push': status}) + + async def select_push_data(self, uid: str) -> Optional[GsPush]: + async with self.async_session() as session: + async with session.begin(): + await self.push_exists(uid) + sql = select(GsPush).where( + GsPush.uid == uid, GsPush.bot_id == self.bot_id + ) + result = await session.execute(sql) + data = result.scalars().all() + return data[0] if len(data) >= 1 else None + + async def push_exists(self, uid: str) -> bool: + async with self.async_session() as session: + async with session.begin(): + sql = select(GsPush).where( + GsPush.uid == uid, GsPush.bot_id == self.bot_id + ) + result = await session.execute(sql) + data = result.scalars().all() + if not data: + await self.insert_push_data(uid) + return True + + ##################### + # 杂项部分 # + ##################### + + async def refresh_cache(self, uid: str): + async with self.async_session() as session: + async with session.begin(): + sql = delete(GsCache).where(GsCache.uid == uid) + await session.execute(sql) + return True + + async def close(self): + async with self.async_session() as session: + async with session.begin(): + await session.close() + + async def insert_new_bind(self, **kwargs): + async with self.async_session() as session: + async with session.begin(): + new_data = GsBind(**kwargs) + session.add(new_data) + await session.commit() + + async def insert_new_user(self, **kwargs): + async with self.async_session() as session: + async with session.begin(): + new_data = GsUser(**kwargs) + session.add(new_data) + await session.commit() diff --git a/gsuid_core/utils/database/models.py b/gsuid_core/utils/database/models.py new file mode 100644 index 0000000..eddff00 --- /dev/null +++ b/gsuid_core/utils/database/models.py @@ -0,0 +1,59 @@ +from typing import Optional + +from sqlmodel import Field, SQLModel + + +class GsBind(SQLModel, table=True): + __table_args__ = {'keep_existing': True} + id: Optional[int] = Field(default=None, primary_key=True, title='序号') + bot_id: str = Field(title='平台') + user_id: str = Field(title='账号') + uid: Optional[str] = Field(default=None, title='原神UID') + sr_uid: Optional[str] = Field(default=None, title='星铁UID') + mys_id: Optional[str] = Field(default=None, title='米游社通行证') + + +class GsUser(SQLModel, table=True): + __table_args__ = {'keep_existing': True} + id: Optional[int] = Field(default=None, primary_key=True, title='序号') + bot_id: str = Field(title='平台') + uid: Optional[str] = Field(default=None, title='原神UID') + sr_uid: Optional[str] = Field(default=None, title='星铁UID') + mys_id: Optional[str] = Field(default=None, title='米游社通行证') + region: Optional[str] = Field(default=None, title='原神地区') + sr_region: Optional[str] = Field(default=None, title='星铁地区') + cookie: Optional[str] = Field(default=None, title='Cookie') + stoken: Optional[str] = Field(default=None, title='Stoken') + user_id: str = Field(title='账号') + push_switch: str = Field(title='全局推送开关') + sign_switch: str = Field(title='自动签到') + bbs_switch: str = Field(title='自动米游币') + status: Optional[str] = Field(default=None, title='状态') + + +class GsCache(SQLModel, table=True): + __table_args__ = {'keep_existing': True} + id: Optional[int] = Field(default=None, primary_key=True, title='序号') + cookie: str = Field(default=None, title='Cookie') + uid: Optional[str] = Field(default=None, title='原神UID') + sr_uid: Optional[str] = Field(default=None, title='星铁UID') + mys_id: Optional[str] = Field(default=None, title='米游社通行证') + + +class GsPush(SQLModel, table=True): + __table_args__ = {'keep_existing': True} + id: Optional[int] = Field(default=None, primary_key=True, title='序号') + bot_id: str = Field(title='平台') + uid: str = Field(default=None, title='原神UID') + coin_push: Optional[str] = Field(title='洞天宝钱推送') + coin_value: Optional[int] = Field(title='洞天宝钱阈值') + coin_is_push: Optional[str] = Field(title='洞天宝钱是否已推送') + resin_push: Optional[str] = Field(title='体力推送') + resin_value: Optional[int] = Field(title='体力阈值') + resin_is_push: Optional[str] = Field(title='体力是否已推送') + go_push: Optional[str] = Field(title='派遣推送') + go_value: Optional[int] = Field(title='派遣阈值') + go_is_push: Optional[str] = Field(title='派遣是否已推送') + transform_push: Optional[str] = Field(title='质变仪推送') + transform_value: Optional[int] = Field(title='质变仪阈值') + transform_is_push: Optional[str] = Field(title='质变仪是否已推送') diff --git a/gsuid_core/utils/database/utils.py b/gsuid_core/utils/database/utils.py new file mode 100644 index 0000000..2a7315b --- /dev/null +++ b/gsuid_core/utils/database/utils.py @@ -0,0 +1,9 @@ +SERVER = { + '1': 'cn_gf01', + '2': 'cn_gf01', + '5': 'cn_qd01', + '6': 'os_usa', + '7': 'os_euro', + '8': 'os_asia', + '9': 'os_cht', +} diff --git a/gsuid_core/webconsole/mount_app.py b/gsuid_core/webconsole/mount_app.py index 8295f3e..34c79f8 100644 --- a/gsuid_core/webconsole/mount_app.py +++ b/gsuid_core/webconsole/mount_app.py @@ -41,6 +41,7 @@ from gsuid_core.webconsole.html import gsuid_webconsole_help from gsuid_core.webconsole.create_sv_panel import get_sv_page from gsuid_core.webconsole.create_config_panel import get_config_page from gsuid_core.plugins.GenshinUID.GenshinUID.utils.database import db_url +from gsuid_core.utils.database.models import GsBind, GsPush, GsUser, GsCache from gsuid_core.plugins.GenshinUID.GenshinUID.version import GenshinUID_version from gsuid_core.plugins.GenshinUID.GenshinUID.genshinuid_user.add_ck import ( _deal_ck, @@ -50,12 +51,6 @@ from gsuid_core.webconsole.login_page import ( # noqa # 不要删 amis_admin, user_auth_admin, ) -from gsuid_core.plugins.GenshinUID.GenshinUID.gsuid_utils.database.models import ( - GsBind, - GsPush, - GsUser, - GsCache, -) class GsLoginFormAdmin(UserLoginFormAdmin): diff --git a/poetry.lock b/poetry.lock index e6e4bb6..9a84480 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1054,14 +1054,14 @@ reference = "mirrors" [[package]] name = "identify" -version = "2.5.22" +version = "2.5.23" description = "File identification library for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "identify-2.5.22-py2.py3-none-any.whl", hash = "sha256:f0faad595a4687053669c112004178149f6c326db71ee999ae4636685753ad2f"}, - {file = "identify-2.5.22.tar.gz", hash = "sha256:f7a93d6cf98e29bd07663c60728e7a4057615068d7a639d132dc883b2d54d31e"}, + {file = "identify-2.5.23-py2.py3-none-any.whl", hash = "sha256:17d9351c028a781456965e781ed2a435755cac655df1ebd930f7186b54399312"}, + {file = "identify-2.5.23.tar.gz", hash = "sha256:50b01b9d5f73c6b53e5fa2caf9f543d3e657a9d0bbdeb203ebb8d45960ba7433"}, ] [package.extras] @@ -1608,19 +1608,19 @@ reference = "mirrors" [[package]] name = "platformdirs" -version = "3.2.0" +version = "3.3.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.2.0-py3-none-any.whl", hash = "sha256:ebe11c0d7a805086e99506aa331612429a72ca7cd52a1f0d277dc4adc20cb10e"}, - {file = "platformdirs-3.2.0.tar.gz", hash = "sha256:d5b638ca397f25f979350ff789db335903d7ea010ab28903f57b27e1b16c2b08"}, + {file = "platformdirs-3.3.0-py3-none-any.whl", hash = "sha256:ea61fd7b85554beecbbd3e9b37fb26689b227ffae38f73353cbcc1cf8bd01878"}, + {file = "platformdirs-3.3.0.tar.gz", hash = "sha256:64370d47dc3fca65b4879f89bdead8197e93e05d696d6d1816243ebae8595da5"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [package.source] type = "legacy" @@ -1929,14 +1929,14 @@ reference = "mirrors" [[package]] name = "setuptools" -version = "67.7.1" +version = "67.7.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.7.1-py3-none-any.whl", hash = "sha256:6f0839fbdb7e3cfef1fc38d7954f5c1c26bf4eebb155a55c9bf8faf997b9fb67"}, - {file = "setuptools-67.7.1.tar.gz", hash = "sha256:bb16732e8eb928922eabaa022f881ae2b7cdcfaf9993ef1f5e841a96d32b8e0c"}, + {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, + {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, ] [package.extras] @@ -2351,6 +2351,28 @@ type = "legacy" url = "https://mirrors.bfsu.edu.cn/pypi/web/simple" reference = "mirrors" +[[package]] +name = "urllib3" +version = "1.26.15" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"}, + {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[package.source] +type = "legacy" +url = "https://mirrors.bfsu.edu.cn/pypi/web/simple" +reference = "mirrors" + [[package]] name = "uvicorn" version = "0.21.1" @@ -2507,86 +2529,86 @@ reference = "mirrors" [[package]] name = "yarl" -version = "1.9.1" +version = "1.9.2" description = "Yet another URL library" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "yarl-1.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e124b283a04cc06d22443cae536f93d86cd55108fa369f22b8fe1f2288b2fe1c"}, - {file = "yarl-1.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:56956b13ec275de31fe4fb991510b735c4fb3e1b01600528c952b9ac90464430"}, - {file = "yarl-1.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ecaa5755a39f6f26079bf13f336c67af589c222d76b53cd3824d3b684b84d1f1"}, - {file = "yarl-1.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92a101f6d5a9464e86092adc36cd40ef23d18a25bfb1eb32eaeb62edc22776bb"}, - {file = "yarl-1.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92e37999e36f9f3ded78e9d839face6baa2abdf9344ea8ed2735f495736159de"}, - {file = "yarl-1.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef7e2f6c47c41e234600a02e1356b799761485834fe35d4706b0094cb3a587ee"}, - {file = "yarl-1.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d7a0075a55380b19aa43b9e8056e128b058460d71d75018a4f9d60ace01e78c"}, - {file = "yarl-1.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f01351b7809182822b21061d2a4728b7b9e08f4585ba90ee4c5c4d3faa0812"}, - {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6cf47fe9df9b1ededc77e492581cdb6890a975ad96b4172e1834f1b8ba0fc3ba"}, - {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:098bdc06ffb4db39c73883325b8c738610199f5f12e85339afedf07e912a39af"}, - {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:6cdb47cbbacae8e1d7941b0d504d0235d686090eef5212ca2450525905e9cf02"}, - {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:73a4b46689f2d59c8ec6b71c9a0cdced4e7863dd6eb98a8c30ea610e191f9e1c"}, - {file = "yarl-1.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:65d952e464df950eed32bb5dcbc1b4443c7c2de4d7abd7265b45b1b3b27f5fa2"}, - {file = "yarl-1.9.1-cp310-cp310-win32.whl", hash = "sha256:39a7a9108e9fc633ae381562f8f0355bb4ba00355218b5fb19cf5263fcdbfa68"}, - {file = "yarl-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b63d41e0eecf3e3070d44f97456cf351fff7cb960e97ecb60a936b877ff0b4f6"}, - {file = "yarl-1.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4295790981630c4dab9d6de7b0f555a4c8defe3ed7704a8e9e595a321e59a0f5"}, - {file = "yarl-1.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b2b2382d59dec0f1fdca18ea429c4c4cee280d5e0dbc841180abb82e188cf6e9"}, - {file = "yarl-1.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:575975d28795a61e82c85f114c02333ca54cbd325fd4e4b27598c9832aa732e7"}, - {file = "yarl-1.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bb794882818fae20ff65348985fdf143ea6dfaf6413814db1848120db8be33e"}, - {file = "yarl-1.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89da1fd6068553e3a333011cc17ad91c414b2100c32579ddb51517edc768b49c"}, - {file = "yarl-1.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d817593d345fefda2fae877accc8a0d9f47ada57086da6125fa02a62f6d1a94"}, - {file = "yarl-1.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85aa6fd779e194901386709e0eedd45710b68af2709f82a84839c44314b68c10"}, - {file = "yarl-1.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eed9827033b7f67ad12cb70bd0cb59d36029144a7906694317c2dbf5c9eb5ddd"}, - {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:df747104ef27ab1aa9a1145064fa9ea26ad8cf24bfcbdba7db7abf0f8b3676b9"}, - {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:efec77851231410125cb5be04ec96fa4a075ca637f415a1f2d2c900b09032a8a"}, - {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:d5c407e530cf2979ea383885516ae79cc4f3c3530623acf5e42daf521f5c2564"}, - {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f76edb386178a54ea7ceffa798cb830c3c22ab50ea10dfb25dc952b04848295f"}, - {file = "yarl-1.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:75676110bce59944dd48fd18d0449bd37eaeb311b38a0c768f7670864b5f8b68"}, - {file = "yarl-1.9.1-cp311-cp311-win32.whl", hash = "sha256:9ba5a18c4fbd408fe49dc5da85478a76bc75c1ce912d7fd7b43ed5297c4403e1"}, - {file = "yarl-1.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:b20a5ddc4e243cbaa54886bfe9af6ffc4ba4ef58f17f1bb691e973eb65bba84d"}, - {file = "yarl-1.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:791357d537a09a194f92b834f28c98d074e7297bac0a8f1d5b458a906cafa17c"}, - {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89099c887338608da935ba8bee027564a94f852ac40e472de15d8309517ad5fe"}, - {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:395ea180257a3742d09dcc5071739682a95f7874270ebe3982d6696caec75be0"}, - {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90ebaf448b5f048352ec7c76cb8d452df30c27cb6b8627dfaa9cf742a14f141a"}, - {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f878a78ed2ccfbd973cab46dd0933ecd704787724db23979e5731674d76eb36f"}, - {file = "yarl-1.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74390c2318d066962500045aa145f5412169bce842e734b8c3e6e3750ad5b817"}, - {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f8e73f526140c1c32f5fca4cd0bc3b511a1abcd948f45b2a38a95e4edb76ca72"}, - {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ac8e593df1fbea820da7676929f821a0c7c2cecb8477d010254ce8ed54328ea8"}, - {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:01cf88cb80411978a14aa49980968c1aeb7c18a90ac978c778250dd234d8e0ba"}, - {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:97d76a3128f48fa1c721ef8a50e2c2f549296b2402dc8a8cde12ff60ed922f53"}, - {file = "yarl-1.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:01a073c9175481dfed6b40704a1b67af5a9435fc4a58a27d35fd6b303469b0c7"}, - {file = "yarl-1.9.1-cp37-cp37m-win32.whl", hash = "sha256:ecad20c3ef57c513dce22f58256361d10550a89e8eaa81d5082f36f8af305375"}, - {file = "yarl-1.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f5bcb80006efe9bf9f49ae89711253dd06df8053ff814622112a9219346566a7"}, - {file = "yarl-1.9.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e7ddebeabf384099814353a2956ed3ab5dbaa6830cc7005f985fcb03b5338f05"}, - {file = "yarl-1.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:13a1ad1f35839b3bb5226f59816b71e243d95d623f5b392efaf8820ddb2b3cd5"}, - {file = "yarl-1.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f0cd87949d619157a0482c6c14e5011f8bf2bc0b91cb5087414d9331f4ef02dd"}, - {file = "yarl-1.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d21887cbcf6a3cc5951662d8222bc9c04e1b1d98eebe3bb659c3a04ed49b0eec"}, - {file = "yarl-1.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4764114e261fe49d5df9b316b3221493d177247825c735b2aae77bc2e340d800"}, - {file = "yarl-1.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3abe37fd89a93ebe0010417ca671f422fa6fcffec54698f623b09f46b4d4a512"}, - {file = "yarl-1.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fe3a1c073ab80a28a06f41d2b623723046709ed29faf2c56bea41848597d86"}, - {file = "yarl-1.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3b5f8da07a21f2e57551f88a6709c2d340866146cf7351e5207623cfe8aad16"}, - {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:88f6413ff5edfb9609e2769e32ce87a62353e66e75d264bf0eaad26fb9daa8f2"}, - {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b5d5fb6c94b620a7066a3adb7c246c87970f453813979818e4707ac32ce4d7bd"}, - {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f206adb89424dca4a4d0b31981869700e44cd62742527e26d6b15a510dd410a2"}, - {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:44fa6158e6b4b8ccfa2872c3900a226b29e8ce543ce3e48aadc99816afa8874d"}, - {file = "yarl-1.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:08c8599d6aa8a24425f8635f6c06fa8726afe3be01c8e53e236f519bcfa5db5b"}, - {file = "yarl-1.9.1-cp38-cp38-win32.whl", hash = "sha256:6b09cce412386ea9b4dda965d8e78d04ac5b5792b2fa9cced3258ec69c7d1c16"}, - {file = "yarl-1.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:09c56a32c26e24ef98d5757c5064e252836f621f9a8b42737773aa92936b8e08"}, - {file = "yarl-1.9.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b86e98c3021b7e2740d8719bf074301361bf2f51221ca2765b7a58afbfbd9042"}, - {file = "yarl-1.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5faf3ec98747318cb980aaf9addf769da68a66431fc203a373d95d7ee9c1fbb4"}, - {file = "yarl-1.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a21789bdf28549d4eb1de6910cabc762c9f6ae3eef85efc1958197c1c6ef853b"}, - {file = "yarl-1.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8b8d4b478a9862447daef4cafc89d87ea4ed958672f1d11db7732b77ead49cc"}, - {file = "yarl-1.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:307a782736ebf994e7600dcaeea3b3113083584da567272f2075f1540919d6b3"}, - {file = "yarl-1.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46c4010de941e2e1365c07fb4418ddca10fcff56305a6067f5ae857f8c98f3a7"}, - {file = "yarl-1.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bab67d041c78e305ff3eef5e549304d843bd9b603c8855b68484ee663374ce15"}, - {file = "yarl-1.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1baf8cdaaab65d9ccedbf8748d626ad648b74b0a4d033e356a2f3024709fb82f"}, - {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:27efc2e324f72df02818cd72d7674b1f28b80ab49f33a94f37c6473c8166ce49"}, - {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ca14b84091700ae7c1fcd3a6000bd4ec1a3035009b8bcb94f246741ca840bb22"}, - {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c3ca8d71b23bdf164b36d06df2298ec8a5bd3de42b17bf3e0e8e6a7489195f2c"}, - {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:8c72a1dc7e2ea882cd3df0417c808ad3b69e559acdc43f3b096d67f2fb801ada"}, - {file = "yarl-1.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d966cd59df9a4b218480562e8daab39e87e746b78a96add51a3ab01636fc4291"}, - {file = "yarl-1.9.1-cp39-cp39-win32.whl", hash = "sha256:518a92a34c741836a315150460b5c1c71ae782d569eabd7acf53372e437709f7"}, - {file = "yarl-1.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:78755ce43b6e827e65ec0c68be832f86d059fcf05d4b33562745ebcfa91b26b1"}, - {file = "yarl-1.9.1.tar.gz", hash = "sha256:5ce0bcab7ec759062c818d73837644cde567ab8aa1e0d6c45db38dfb7c284441"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8"}, + {file = "yarl-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608"}, + {file = "yarl-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3"}, + {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528"}, + {file = "yarl-1.9.2-cp310-cp310-win32.whl", hash = "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3"}, + {file = "yarl-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb"}, + {file = "yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7"}, + {file = "yarl-1.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7"}, + {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a"}, + {file = "yarl-1.9.2-cp311-cp311-win32.whl", hash = "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8"}, + {file = "yarl-1.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051"}, + {file = "yarl-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938"}, + {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04"}, + {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582"}, + {file = "yarl-1.9.2-cp37-cp37m-win32.whl", hash = "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b"}, + {file = "yarl-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4"}, + {file = "yarl-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417"}, + {file = "yarl-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc"}, + {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b"}, + {file = "yarl-1.9.2-cp38-cp38-win32.whl", hash = "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"}, + {file = "yarl-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8"}, + {file = "yarl-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955"}, + {file = "yarl-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3"}, + {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80"}, + {file = "yarl-1.9.2-cp39-cp39-win32.whl", hash = "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623"}, + {file = "yarl-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18"}, + {file = "yarl-1.9.2.tar.gz", hash = "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"}, ] [package.dependencies] @@ -2601,4 +2623,4 @@ reference = "mirrors" [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "f23c3aad6aaf8ec2e3156947be3383ee1f53b679a89674cb1001495ddd0e37e9" +content-hash = "8540b0f00e1f77e7adb32353cb16fa617b144380b307ffdcc36a3aebd402f3b6" diff --git a/pyproject.toml b/pyproject.toml index 97fd597..3beb61b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ msgspec = ">= 0.13.1" uvicorn = ">=0.20.0" websockets = "^10.4" loguru = "^0.6.0" +urllib3 = "^1.26.15" [tool.poetry.group.dev.dependencies] flake8 = "^6.0.0" diff --git a/requirements.txt b/requirements.txt index 78068d8..91b2f48 100644 --- a/requirements.txt +++ b/requirements.txt @@ -40,7 +40,7 @@ python-multipart==0.0.6 ; python_full_version >= "3.8.1" and python_full_version pytz-deprecation-shim==0.1.0.post0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pytz==2023.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" qrcode[pil]==7.4.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -setuptools==67.7.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +setuptools==67.7.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" six==1.16.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" smmap==5.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" sniffio==1.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" @@ -54,7 +54,8 @@ starlette==0.26.1 ; python_full_version >= "3.8.1" and python_full_version < "4. typing-extensions==4.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" tzdata==2023.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" tzlocal==4.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +urllib3==1.26.15 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" uvicorn==0.21.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" websockets==10.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" win32-setctime==1.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32" -yarl==1.9.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +yarl==1.9.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"