Full Code of SJTUwbl/MaCA for AI

master e8503f565a6b cached
56 files
381.0 KB
152.0k tokens
264 symbols
1 requests
Download .txt
Showing preview only (411K chars total). Download the full file or copy to clipboard to get everything.
Repository: SJTUwbl/MaCA
Branch: master
Commit: e8503f565a6b
Files: 56
Total size: 381.0 KB

Directory structure:
gitextract_qb55n16v/

├── .gitignore
├── README.md
├── agent/
│   ├── airc_homo_rule/
│   │   └── agent.py
│   ├── base_agent.py
│   ├── fix_rule/
│   │   ├── agent.py
│   │   ├── agent_core.py
│   │   ├── license.lic
│   │   ├── product.key
│   │   ├── pyshield.key
│   │   ├── pyshield.lic
│   │   └── pytransform.py
│   ├── fix_rule_no_att/
│   │   ├── agent.py
│   │   ├── agent_core.py
│   │   ├── license.lic
│   │   ├── product.key
│   │   ├── pyshield.key
│   │   ├── pyshield.lic
│   │   └── pytransform.py
│   └── simple/
│       ├── agent.py
│       └── dqn.py
├── common/
│   └── agent_process.py
├── configuration/
│   ├── reward.py
│   └── system.py
├── doc/
│   └── tutorial.md
├── environment/
│   ├── error_log.py
│   ├── interface.py
│   ├── license.lic
│   ├── product.key
│   ├── pyshield.key
│   ├── pyshield.lic
│   ├── pytransform.py
│   ├── render/
│   │   ├── __init__.py
│   │   ├── render_pic.py
│   │   └── render_pic2.py
│   └── world/
│       ├── __init__.py
│       ├── config.py
│       ├── detection_calc.py
│       ├── em_battle.py
│       ├── load_map.py
│       ├── log.py
│       ├── position_calc.py
│       ├── replay.py
│       └── strike_calc.py
├── fight.py
├── fight_mp.py
├── log/
│   └── readme
├── model/
│   └── README
├── obs_construct/
│   ├── airc_homo_rule/
│   │   └── construct.py
│   └── simple/
│       └── construct.py
├── replay.py
├── tournament/
│   ├── config.ini
│   ├── config_gen.py
│   └── tournament_mp.py
├── train/
│   └── simple/
│       ├── dqn.py
│       └── main.py
└── utility.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
.static_storage/
.media/
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/

# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
data
.idea
*.csv/application/api_demo_pygame.py
/application/pygameTest.py
*.csv
/application/api_demo2.py
/application/api_demo_pygame.py
/application/rule_test.py
/environment/render/render_th.py
/application/array.py
/environment/encryption/pyarmor
/environment/encryption/.pyarmor_capsule.zip
/environment/encryption/.pyarmor_config
*.macalog
*.pkl
/tournament/result


================================================
FILE: README.md
================================================
# MaCA
![](https://img.shields.io/badge/language-python-green.svg)
![](https://img.shields.io/badge/platform-windows-green.svg)
![](https://img.shields.io/badge/platform-linux-green.svg)
![](https://img.shields.io/badge/platform-mac-green.svg)
![](https://img.shields.io/badge/stability-experimental-green.svg)

Multi-agent Combat Arena (MaCA) is a heterogeneous multi-agent distributed decision and control technology reasearch platform produced by CETC-TFAI team. It focuses on the application of AI technologies e.g. reinforcement learning in multi-agent cooperation and confrontation

![](https://leonfg.github.io/maca/resource/maca.gif)

## System Requirements
- Linux 64-bit or Mac OS with Python 3.6
- numpy 1.14.2 or later
- pygame 1.9.3 or later

There is no limitation on agents' structure. You can write rule-based algorithms or use deep learning frameworks.
## Quick Start Guide
### Installation
```bash
pip install -U numpy pandas pygame
git clone https://github.com/CETC-TFAI/MaCA.git
cd MaCA
export PYTHONPATH=$(pwd)/environment:$PYTHONPATH
```
### Run a combat between two agents
[fight_mp.py](fight_mp.py) can execute two agents. It uses two instances of a fixed-rule agent to fight each other by default.
```bash
python fight_mp.py
```
You can specify agents and map by input arguments. In addition an agent should provide a call interface follows the MaCa platform specification.
### Replay
MaCa can record runtime log while playing and training. Use [replay.py](replay.py) to perform a replay.

First, run [fight_mp.py](fight_mp.py) and enable log record function
```bash
python fight_mp.py --log
```

Then, run [replay.py](replay.py) to replay the log
```bash
python replay.py fix_rule_vs_fix_rule
```
The log structure of MaCA is a set of .macalog files, they will be saved in path "log/log-name/".
When you run the [replay.py](replay.py), You must input a "log-name" as the parameter to specify which log you want to replay.

For more information, see [tutorial](/doc/tutorial.md)

================================================
FILE: agent/airc_homo_rule/agent.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Xunyun Liu
@contact: xunyunliu@gmail.com
@software: PyCharm
@file: agent.py
@time:
@desc: rule based agent
"""

from agent.base_agent import BaseAgent

import copy
import random
import utility as ut
import numpy as np

DETECTOR_NUM = 0
FIGHTER_NUM = 10
COURSE_NUM = 16
ATTACK_IND_NUM = (DETECTOR_NUM + FIGHTER_NUM) * 2 + 1  # long missile attack + short missile attack + no attack
ACTION_NUM = COURSE_NUM * ATTACK_IND_NUM
LONG_MISSILE_RANGE = 120
SHORT_MISSILE_RANGE = 50
SQUARE_SIZE = 50


class Agent(BaseAgent):
    def __init__(self):
        """
        Init this agent
        :param size_x: battlefield horizontal size
        :param size_y: battlefield vertical size
        :param detector_num: detector quantity of this side
        :param fighter_num: fighter quantity of this side
        """
        BaseAgent.__init__(self)
        self.obs_ind = 'airc_homo_rule'
        self.last_random_action_set = {}
        self.to_explore_set = {}
        self.explore_destination_set = {}
        self.rule_set = 'attack'

        # if not os.path.exists('model/simple/model.pkl'):
        #     print('Error: agent simple model data not exist!')
        #     exit(1)
        # self.fighter_model = dqn.RLFighter(ACTION_NUM)

    def set_map_info(self, size_x, size_y, detector_num, fighter_num):
        self.size_x = size_x
        self.size_y = size_y
        self.detector_num = detector_num
        self.fighter_num = fighter_num

        # some eligibility checks
        if self.detector_num != 0:
            print('Error: agents using airc_homo_rule can only be used in a homogeneous environment!')
            exit(1)
        if self.size_x % SQUARE_SIZE != 0 or self.size_y % SQUARE_SIZE != 0:
            print('Error, the map size is not a multiple of SQUARE_SIZE')
            exit(1)

        # initialise data structures for map exploration
        self.to_explore_set = set(range((size_x // SQUARE_SIZE) * (size_y // SQUARE_SIZE)))
        # initialise last_random_action_set
        for i in range(self.fighter_num):
            # it doesn't matter what the initial value is as it will be overwritten in the first round
            self.last_random_action_set[i] = [0, 1, 0, 0]

    def __reset(self):
        pass

    def get_action(self, obs_dict, step_cnt):
        """
        get actions
        :param detector_obs_list:
        :param fighter_obs_list:
        :param joint_obs_dict:
        :param step_cnt:
        :return:
        """
        # initialise the explore_destination_set based on the birthplace of the agent
        if step_cnt == 1:
            for i in range(self.fighter_num):
                self.explore_destination_set[i] = (self.size_x - obs_dict[i]['pos_x'], obs_dict[i]['pos_y'])
        detector_action = []
        fighter_action = []
        # loop over the fighter list to generate actions
        for index in range(self.fighter_num):
            # [0, 1, 0, 0] is just a placeholder
            tentative_action = np.array([0, 1, 0, 0], dtype=np.int32)
            if obs_dict[index]['alive']:
                try:
                    if self.rule_set == 'random':
                        tentative_action = self.choose_action_random(index, step_cnt)
                    elif self.rule_set == 'random_attack':
                        tentative_action = self.choose_action_random_attack(obs_dict, index, step_cnt)
                    elif self.rule_set == 'explore':
                        tentative_action = self.choose_action_explore(obs_dict, index)
                    elif self.rule_set == 'attack':
                        tentative_action = self.choose_action_attack(obs_dict, index)
                    elif self.rule_set == 'still':
                        tentative_action = self.choose_action_still(step_cnt)
                except AttributeError:
                    print("agent is missing a rule_set attribute. Now flying towards right as default.")
                # action formation
                # true_action[0] = int(360 / COURSE_NUM * int(tmp_action[0] / ATTACK_IND_NUM))
                # true_action[3] = int(tmp_action[0] % ATTACK_IND_NUM)
            # radar and interference logic

            tentative_action[1] = step_cnt % 10 + 1
            tentative_action[2] = step_cnt % 10 + 1
            tmp_action = {}
            tmp_action['course'] = tentative_action[0]
            tmp_action['r_iswork'] = True
            tmp_action['r_fre_point'] = 2
            tmp_action['j_iswork'] = True
            tmp_action['j_fre_point'] = 2
            if tentative_action[3] > self.fighter_num:
                tmp_action['hit_target'] = tentative_action[3] - self.fighter_num
                tmp_action['missile_type'] = 2
            else:
                tmp_action['hit_target'] = tentative_action[3]
                tmp_action['missile_type'] = 1
            fighter_action.append(copy.deepcopy(tmp_action))
        # fighter_action = np.array(fighter_action)
        return detector_action, fighter_action

    # the logic of engagement with enemies
    def engage_enemy(self, tmp_action, obs_dict, index):
        # default -- no attack allowed
        tmp_action[3] = 0
        if 'target_list' in obs_dict[index]:
            # flying towards the nearest enemy
            tmp_action[0] = obs_dict[index]['target_list'][0]['angle']
            target_id = obs_dict[index]['target_list'][0]['id']
            target_distance = obs_dict[index]['target_list'][0]['distance']
            # check if the nearest enemy has been attacked
            strike_list = obs_dict['strike_list']
            strike_target_id_set = set(ele['target_id'] for ele in strike_list)
            if target_id in strike_target_id_set:
                return tmp_action
            # perform attack while having enough ammunition
            if obs_dict[index]['s_missile_left'] + obs_dict[index]['l_missile_left'] == 0:
                return tmp_action
            elif target_distance <= SHORT_MISSILE_RANGE:
                if obs_dict[index]['s_missile_left'] > 0:
                    tmp_action[3] = target_id + 10
                else:
                    tmp_action[3] = target_id
            elif SHORT_MISSILE_RANGE < target_distance <= LONG_MISSILE_RANGE:
                if obs_dict[index]['l_missile_left'] > 0:
                    tmp_action[3] = target_id
        return tmp_action

    def choose_action_random(self, index, step_cnt):
        if step_cnt % 20 == 1:
            self.last_random_action_set[index][0] = random.randint(0, 359)
        return self.last_random_action_set[index]

    def choose_action_random_attack(self, obs_dict, index, step_cnt):
        random_action = self.choose_action_random(index, step_cnt)
        return self.engage_enemy(random_action, obs_dict, index)

    def choose_action_explore(self, obs_dict, index):
        # maintain the data structure for map exploration
        area_x = int(obs_dict[index]['pos_x'] / SQUARE_SIZE)
        area_y = int(obs_dict[index]['pos_y'] / SQUARE_SIZE)
        explored_index = area_x * (self.size_y / SQUARE_SIZE) + area_y
        if explored_index >= (self.size_x / SQUARE_SIZE) * (self.size_y / SQUARE_SIZE):
            print('explored_index out of range!')
            explored_index = (self.size_x / SQUARE_SIZE) * (self.size_y / SQUARE_SIZE) - 1
        if explored_index in self.to_explore_set:
            self.to_explore_set.remove(explored_index)
            if len(self.to_explore_set) == 0:
                self.to_explore_set = set(range(round((self.size_x / SQUARE_SIZE) * (self.size_y / SQUARE_SIZE))))
        # if agent has a destination to explore
        if index in self.explore_destination_set:
            # delete the destination when getting close enough
            if ut.distance(obs_dict[index]['pos_x'], obs_dict[index]['pos_y'], self.explore_destination_set[index][0],
                           self.explore_destination_set[index][1]) <= 5:
                # print('trying to delete the key')
                del self.explore_destination_set[index]
                # print('delete succesfully')

        # if the agent has no destination, randomly select a destination from the to_explore_set
        if index not in self.explore_destination_set:
            if len(self.to_explore_set) == 0:
                print('Error! to_explore_set is empty')
            selected_ele = random.sample(self.to_explore_set, 1)
            # print('selected_ele: ', selected_ele)
            ele_index_x = int(selected_ele[0] / (self.size_y / SQUARE_SIZE))
            # print('ele_index_x: ', ele_index_x)
            ele_index_y = int(selected_ele[0] % (self.size_y / SQUARE_SIZE))
            # print('ele_index_y', ele_index_y)
            ele_pos_x = int(ele_index_x * SQUARE_SIZE + SQUARE_SIZE / 2)
            ele_pos_y = int(ele_index_y * SQUARE_SIZE + SQUARE_SIZE / 2)
            # print('ele_pos_x: ', ele_pos_x, 'ele_pos_y', ele_pos_y)
            self.explore_destination_set[index] = (ele_pos_x, ele_pos_y)
            # print('self.explore_destination_set[index]: ', self.explore_destination_set[index])
            # print('angle: ',
            #      ut.angle(obs_dict[index]['pos_x'], obs_dict[index]['pos_y'], self.explore_destination_set[index][0],
            #               self.explore_destination_set[index][1]))

        # navigating towards the explore destination
        return [ut.angle(obs_dict[index]['pos_x'], obs_dict[index]['pos_y'], self.explore_destination_set[index][0],
                         self.explore_destination_set[index][1]), 1, 0, 0]

    def choose_action_attack(self, obs_dict, index):
        return self.engage_enemy(self.choose_action_explore(obs_dict, index), obs_dict, index)

    @staticmethod
    def choose_action_still(step_cnt):
        if 1 <= step_cnt % 40 <= 10:
            return [0, 1, 0, 0]
        elif 11 <= step_cnt % 40 <= 20:
            return [90, 1, 0, 0]
        elif 21 <= step_cnt % 40 <= 30:
            return [180, 1, 0, 0]
        else:
            return [270, 1, 0, 0]


================================================
FILE: agent/base_agent.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Gao Fang
@contact: gaofang@cetc.com.cn
@software: PyCharm
@file: base_agent.py
@time: 2018/3/22 0022 14:13
@desc: base class of agent
"""


class BaseAgent:
    def __init__(self):
        """
        init
        """
        self.obs_ind = 'raw'
        self.size_x = 0
        self.size_y = 0
        self.detector_num = 0
        self.fighter_num = 0

    def get_obs_ind(self):
        """
        get obs info
        :return: obs const class path.
        """
        return self.obs_ind


================================================
FILE: agent/fix_rule/agent.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from pytransform import pyarmor_runtime
pyarmor_runtime()
"""
@author: Gao Fang
@contact: gaofang@cetc.com.cn
@software: PyCharm
@file: agent.py
@time: 2018/3/13 0013 10:51
@desc: rule based agent
"""

from agent.fix_rule.agent_core import Agent as ag


class Agent:
    def __init__(self):
        """
        Init this agent
        """
        self.agent_core = ag()

    def set_map_info(self, size_x, size_y, detector_num, fighter_num):

        return self.agent_core.set_map_info(size_x, size_y, detector_num, fighter_num)

    def get_action(self, obs_dict, step_cnt):
        """
        get actions
        :param detector_obs_list:
        :param fighter_obs_list:
        :param joint_obs_dict:
        :param step_cnt:
        :return:
        """
        return self.agent_core.get_action(obs_dict, step_cnt)

    def get_obs_ind(self):
        return self.agent_core.get_obs_ind()


================================================
FILE: agent/fix_rule/agent_core.py
================================================
__pyarmor__(__name__, __file__, b'\xe7\x50\x8c\x64\x26\x42\xd6\x01\xb9\x4e\x3f\xdf\x40\x99\x74\xef\xb8\xc9\x91\x76\x3b\x40\xaa\xbe\x5d\xc5\xbd\x32\x0b\xf3\x42\x40\xe3\xce\x4f\x75\x5d\x9f\x4c\x04\x35\x6e\xf5\xb9\xdb\xfc\x44\xa8\x11\xd0\xdb\xb1\x0f\x62\xe2\x75\xc1\x38\x66\x9c\x65\x70\xe1\x0d\x2b\x57\x65\xd2\x85\x6d\x0e\x9d\xb5\x16\x6d\x19\x4c\x08\x05\x50\xe0\xd6\x28\xd8\xe5\x1b\x68\xb7\x96\xd4\x21\x0e\x87\x99\x7d\xc0\x18\x75\xb0\x67\x5d\x77\xba\xb0\xc6\xdf\x31\x69\x39\x6e\xd1\x45\x73\xec\xd7\xec\x65\x93\xcb\x46\x43\xd3\x68\x99\x09\xa8\x80\xd9\x28\xa0\xf6\xc2\xa2\xe5\xc3\xe7\x36\x9b\xec\xf2\x0f\x2a\xf1\x9d\xb6\x41\xae\x5c\x09\x7b\x21\x59\x72\xee\xc1\x98\x30\x0e\xb3\xe9\x7e\x44\x8a\x9b\x52\x69\x33\xac\x8f\x31\xb4\x23\xde\xcc\xe2\xad\xb2\x31\x53\x7a\x9b\xb1\x57\xd3\x1c\x71\x51\x17\x75\x19\x03\x24\x0c\x7a\x01\x93\x06\x9a\x0b\x6e\xee\xa6\xc5\xb4\xc2\x8d\x0a\x69\x52\xbf\xd2\xaf\xd4\xc5\xa7\x60\xb1\x44\xd6\xfa\xbb\xc3\x19\x93\x06\x7f\x83\x00\x59\x12\xb4\xaf\x74\x36\xa9\x34\x5a\x43\xc5\xd2\xdf\xa7\x6e\x78\x20\x07\x75\x3f\xae\x92\x75\x22\xd7\xc6\xc7\x4c\xc5\x2a\x22\x8d\xb0\x44\xe9\xeb\xf4\x69\x59\x8c\x53\x63\x94\xa7\x15\x85\x68\xfa\xc7\x20\x49\x9e\x36\x1e\x2b\x40\xe2\x98\x34\xa8\x51\x55\xfc\xc9\x13\xee\x24\x60\x57\x6c\xdf\xad\x56\x49\x4e\x38\x9d\x4d\x49\xda\x4d\x2e\xfe\xe2\x09\x0b\x42\xaf\x41\x88\x2a\x47\x73\xa7\x5f\x24\xcf\x2c\x1d\x84\xe7\x99\x71\x01\x66\xce\xdd\xaa\xb3\xf3\xfe\xab\xf7\x11\x30\x95\xbd\xc0\xfa\xbb\xa7\x7c\x06\xbe\xb6\x9c\x18\x0c\xac\x47\x43\xdd\x4a\x65\x10\x58\x25\x7a\x93\x57\x0d\x03\xeb\x9b\x25\x1c\xec\x3b\xb7\x91\x12\xac\xad\x85\xf6\x3b\x99\x7d\x4b\xe8\x89\x28\x3a\xd5\xa7\x92\x64\x06\xcb\xa3\x14\x52\xf2\x1b\x3e\xa3\x4a\x01\x0d\x59\x18\x76\x35\x10\x06\x55\x18\xcd\x7e\x34\x24\x70\x5d\xfc\xd1\x0a\x68\x16\xeb\xb1\x70\xb2\x6b\x17\xe3\xa9\x7a\xc5\xc1\x34\x37\x3b\xae\xe3\x00\xe0\x09\xf2\x1e\xb4\xca\xa2\x20\xef\xf8\xd9\x5b\x06\xd2\xa3\x50\xdb\xdd\x20\xfe\x0f\xc1\x43\x52\x48\x3c\xf9\x61\x17\xdb\x1a\xd2\xb3\xee\x0a\xe4\xf4\x9d\x8c\xe3\x37\xdd\x3d\x74\xf9\xaf\xe3\x99\x15\x41\x7d\xcd\x03\x08\x92\x92\x8b\xc1\x4d\x83\x4f\x89\x2f\x04\xf0\xcf\xae\x25\x5a\x92\x62\xa6\x94\x92\xdf\xe1\xa6\xe4\x15\x7b\xe2\x3b\xa8\x42\x1a\xe8\xfb\xa0\x38\x71\x46\xfa\xde\x4d\xad\x43\x60\x96\x6a\xd8\x03\x87\xa2\x30\x50\x2e\x68\xfb\xfa\xa4\xb9\x8c\xfd\x3a\x94\xe7\x82\x42\xce\x89\xc8\x8c\xa2\x17\x93\x75\x23\x46\xdf\xb6\x28\x32\x2d\xcf\x6d\xe0\xfb\x8e\xdd\x7f\xbe\x79\x67\x17\xae\x74\xc9\x0e\xec\x81\x52\x38\x1e\x78\x4b\x97\xe8\x61\xae\x16\x32\x97\xdb\x2b\xbe\x41\x00\xd4\xd6\x3a\xe0\xac\xd3\x85\x02\x95\x4a\x1d\x32\xab\xbb\x7b\x4c\xb0\x35\x26\x39\x31\x1b\xcc\xe8\xa6\xb3\xc8\x8d\x77\x42\x95\x26\x6d\xef\x37\xbf\x6c\x28\xa2\x21\xaf\xdd\xd4\x58\xcf\x52\xa0\x2f\x94\xf1\xe9\x2d\xef\xd4\x58\xf5\xa5\x79\xed\xb5\x9a\x7b\x95\xd0\x0c\xea\x45\x1c\xa0\xe8\x6f\x76\xfa\xcf\x8c\x63\x6a\x7a\xc7\x73\x36\x85\x4f\x7b\xde\x9f\x37\x18\x99\x0f\x97\x21\xd4\x78\x02\x8b\xbc\x55\x7a\x88\x32\x78\x13\xc6\x4d\xbf\x12\x9c\x52\xea\x83\x9e\x79\x33\xde\x63\x93\x1f\xfe\xf1\x15\x64\x87\x38\x26\x1b\x83\x5e\x80\x70\xfc\x85\x3d\x7c\xae\x2d\x4f\x0d\x13\xf4\xb4\xa4\x94\x3c\x6b\x5c\x85\xdc\xd4\xc7\xd2\x85\x3a\x9c\x10\x28\x25\x1f\xc3\x95\xd4\x11\x88\xe1\x3a\x5a\xfc\xc0\xde\x86\x4f\x7a\x8a\xb2\x06\x1a\x53\xbb\x46\x72\xe4\xec\xb8\x68\x4c\xa2\xf9\xda\xf5\x17\x6a\xb2\x76\xd3\x92\x36\x70\x6b\xcd\xeb\xa7\x22\x4f\x14\x48\xc2\x96\x10\xff\x36\xe1\xf3\xcc\x81\xec\xe2\x58\xc4\x56\x3c\x6a\x50\xb3\x5a\xb0\x59\xae\xce\x26\x54\xb0\xf6\x05\xf3\xb1\x7e\x8e\x2a\xa8\xc6\x2e\x22\x59\x55\x80\x2f\xe6\x6d\xee\xb7\xcd\xcc\xb1\x57\x67\xef\x7a\x5e\xf5\x23\xad\x2b\xaf\x7a\xcb\x4e\xad\x59\x46\xd7\xe1\xd0\x71\xad\xe6\xe9\x86\x41\x55\x15\x77\x86\x8c\xab\x4c\xf9\xa0\x3b\x20\x6b\x38\xc5\x68\x64\x24\x00\xca\x9d\xff\x20\x74\x60\xb4\x39\x6c\xc9\x9e\x99\xa7\x86\x0b\x92\xc6\xe4\xe4\x8d\x1f\x14\xe7\x08\x4e\x2b\x69\x3f\xdb\x71\x76\xaf\x2f\x40\xe7\x2a\xd8\x74\x06\x4a\xcb\xc4\x6c\x52\x08\xc8\xe3\x0e\x52\x8d\x3d\x5d\x2b\xfb\x32\x37\x5a\x8d\xed\x15\xe8\x64\xde\x88\xf7\x39\x73\x82\x91\xc5\x00\xa1\xe1\x4c\x8c\xd2\x38\x07\xff\xe5\xae\x9e\x17\xc4\xb2\xd6\xee\x53\x59\xcb\x17\xdf\xbe\x25\x63\xa1\x77\x3e\x31\xcf\xc8\x2f\x82\x3b\xcd\x20\xa6\xce\x49\x9d\x35\x53\xd5\x49\xc2\x5d\x4f\xd3\xaf\x12\x13\x6f\xff\x36\x26\xa7\x7b\xc4\xbe\xf3\x38\xe1\x6c\xd8\xb1\xe3\xa5\xd4\x8b\x32\xfd\xf6\xa0\x82\x0e\xd5\xc0\xa8\x0d\xf7\xc5\x23\x9a\x0f\xa2\xda\xa9\x31\x24\xf6\xe7\xe7\x60\x92\xf3\x86\xc6\x0f\x19\x67\xd3\x3e\x4e\x2c\x3f\xf4\x0e\xa8\xb1\xa5\xb5\xfe\xc6\x1b\xb8\xf4\x2e\x01\x2d\x7d\x3d\x9d\x7a\xa3\x18\x22\x48\xd0\x3c\xd7\xdd\x7e\x5f\x03\x9f\x93\xc7\x76\x67\x13\x0d\x46\x1a\xde\xdd\xd1\xd3\x6b\x84\xa1\x94\x58\x3f\xc7\x63\x5f\xca\xb6\xd8\x29\x29\x1f\xb5\x0e\xb2\x62\x62\x82\xe1\x60\x09\x3b\x0e\x5e\x4b\x3f\xe4\xe3\x3e\x28\x7a\x27\xbc\x13\xc3\xe5\x3b\x9d\xea\x47\xf6\x30\x89\xb1\x5e\xc4\x60\xc1\x2c\x40\x76\x3c\x50\x9e\xed\xc4\x2e\xf2\x8d\xca\xe1\x81\xff\xf0\xaf\xd4\xbe\x9f\x61\x58\x7c\xa3\x27\xb4\x06\x44\x43\xfe\x60\x76\x7c\x23\x01\x72\x86\x3d\x2f\xdc\xef\xd6\xd2\xc6\x53\xbe\xf6\x80\xfa\xdc\xe7\x0b\x1b\x8a\x5b\x0f\xd5\x20\xaa\x4b\x03\xe2\x42\x75\x56\x44\x8a\x4c\x8d\xe6\xa4\x58\x95\x6f\x01\x42\x45\x27\xc5\x00\x45\xba\x51\xad\x7f\x25\x15\x01\x9b\x5f\xdd\xf8\xeb\x5b\x35\x9f\xb5\x60\x70\x9e\x07\x70\x5b\xff\x15\xf2\x3d\xb7\xc6\xfb\xbe\xcf\x5b\xf5\x20\xdc\x09\xea\x28\x27\x66\xd7\xab\x34\xd1\x38\x2a\x62\x2a\x2f\xab\x58\xf1\xf4\x42\x2c\x5f\x10\x58\xf7\xd8\x36\x88\x25\x37\x93\xeb\x16\xab\xbd\x1a\x40\xc8\x44\xfa\x0f\xe4\x00\xfa\x98\x90\xb6\x7c\xc8\x7f\x5a\xb3\x83\xf7\x77\x61\xe6\xb9\x69\xf3\x96\x7a\xd0\xa0\xf8\xf9\xec\x57\x8c\xe3\xed\x1f\xea\x74\xb2\xcc\x14\xfb\xdb\x17\x5d\x89\x61\x96\x54\x1f\x9c\x6a\x63\x39\x80\x84\x01\x7c\x18\xad\x64\x1d\x0e\xae\xd9\x6a\x07\x2f\x21\x50\x26\x93\x0d\x68\xae\xe0\xc6\xe3\x1d\x18\xe4\x52\x2f\xe0\xae\x7f\xc1\x9c\x12\xf4\x42\x46\xdb\x5d\x9d\x31\x8a\xa9\xeb\x14\x20\x96\xf6\x4f\x08\xfe\x6a\xcf\x65\x7e\xb7\x97\xe9\xbc\xb3\xd1\xa9\x13\xaa\x70\x66\x73\x7d\x96\x42\xe5\x10\xa5\xb5\x36\x15\x12\x3e\x10\x60\x52\x39\xf2\x93\xc8\xaf\x8e\xe5\x83\x0b\xda\x64\xa4\x83\x9a\x0f\x83\x07\x7b\x0f\x93\x58\x29\xd6\x4b\x73\xd3\xb3\x71\xc5\xd0\xc2\x99\xdd\x5d\x41\x28\xa9\x3e\x57\x48\x2e\xdf\x33\x0e\xc7\xaa\xcb\x8b\x59\xfc\xd4\xd9\x42\x45\x37\x77\x03\xfb\x8f\x6e\x33\x29\x54\x01\xfa\xf7\x59\x8b\x3c\xa3\x9e\xee\x12\xc5\xb1\x82\x66\xcc\xfb\xcb\x5b\xee\x3d\xcc\x7c\x5d\xc2\xdb\x7f\xeb\x94\x33\xb7\xf9\x44\x48\x72\x32\xc9\xd7\x19\x2a\x7e\x30\x50\x1e\x68\x77\x77\xb1\xd4\xc9\x09\xe2\x07\x29\xfd\xf5\x1c\xc1\xa2\x02\x5d\x11\x33\xa7\x96\x8a\x90\x29\x5d\xfa\xb4\x3d\x82\x02\x4c\xf2\x59\x18\x79\x45\x21\x8c\x1b\x2b\x5b\x8a\xe5\x07\x00\xd7\x48\x79\xf0\xcc\xd0\xc9\x7a\x0f\x22\x3b\x4e\xdb\x15\x06\xc2\x3f\x9f\xe5\x25\x02\x9f\xdf\x26\x20\xec\xb5\xb6\x87\x30\x1f\xde\x48\x5b\x60\x8c\x13\x85\x20\xc1\x0f\xf4\x49\x90\x31\x11\xed\x23\xdd\xf9\xa5\xe6\x9e\xbc\x2e\x68\xf5\x95\x2b\x2b\x03\x65\xf4\xf9\x0d\x9d\xc4\x2a\xb0\xac\x14\x25\xa3\x78\xdf\x8b\xc6\x99\xfa\x67\x0f\xda\x5a\x63\x4e\x3c\x29\xe3\x25\x90\xd3\x93\x92\xdf\x51\xb8\xd1\x1e\x3f\x9f\xe8\x8b\x5f\xe4\xc7\x7b\x36\xba\xf6\x29\x3a\x08\x28\x53\xc6\x90\xa3\x6d\x44\x40\x3a\xd4\x37\xf7\xbc\x6d\x44\x19\xba\x00\xcb\x26\x02\x61\x6f\x42\xb5\x35\x1f\x22\x60\x69\x1e\x1c\x82\xff\x17\xa0\xe2\xb9\xd2\xdd\xbc\xd2\xe0\xce\xa4\x37\xb9\x59\xec\x52\x5e\x7b\x7c\x07\xc5\x48\x04\x0f\x8f\x6d\x06\x5c\x89\x32\x05\x00\x18\x91\x7e\xbe\x64\xc5\xfc\xf5\x3d\x22\xde\x34\xe3\xa3\xda\x9a\x39\x2e\x1b\x94\x6f\x8d\x3e\xbb\x2f\x6a\xd3\xfb\xa0\x2d\xf4\xaa\x66\x6a\x7d\xf4\x79\xe5\x3b\x84\xfd\xc6\x58\x76\x1e\xb3\xa6\xe6\x22\xb8\xcf\x65\x96\x0e\xe7\xcc\xb3\xbc\xf3\xe6\xa2\x3d\xf8\xa0\x04\x5b\x71\x72\x29\xa4\x79\xbf\xf1\x2e\x69\xe8\x65\x77\x54\x58\x8e\xf8\x28\x2d\x46\xbf\xe2\x1d\xe7\xb2\x08\xea\xa5\x38\xbc\x5b\x66\xa9\x37\xa2\x14\xe7\xc3\x89\x4d\xf4\xf7\xb6\xac\xee\x18\xad\xdd\xe3\xa4\x6c\x4a\xab\x1a\x8b\xee\xf9\x27\xbc\x25\xe2\xab\xf3\xd9\x3e\xba\x45\xe9\xb4\xa1\x98\xb0\x5e\xd5\x0f\x6d\x23\x1c\xb0\x1b\x57\xa6\x4b\x05\x06\x6d\x96\x57\xf3\x61\x8b\x10\x7d\x26\xd8\x54\xca\x53\x6b\xb6\x67\x08\x5b\xc6\x65\x45\x7c\x0b\x20\xcc\x63\x73\x45\x76\xe1\x4a\x9b\x90\x92\x25\x94\xac\x95\x06\xca\x7b\x6f\xec\x2d\x56\xf0\x81\xb2\x97\x31\x51\xec\x85\x32\x20\x5f\x3e\x45\x8d\x80\x11\xed\x33\xbd\x75\xe6\xdb\xb3\x51\x78\xa6\x75\x05\xb4\x67\xd3\xc1\x19\x90\x89\x49\xf4\xbf\x39\x9d\xfd\x4a\x05\x90\x0e\x54\xf8\x43\x2d\xeb\xa2\xfd\xfe\x88\xe0\xa5\xa3\x35\x45\x27\x49\x90\xae\x84\x0a\x74\x8d\x30\x2f\xde\x37\x1a\xc7\xd2\xd8\x7e\x30\x51\xb7\x3b\xf7\xb8\xe4\x13\xfb\x7f\xbb\x06\xea\xac\xa4\xd7\x6b\xc1\x20\x49\xf4\x2d\xa4\xb7\x67\x1f\x4c\xe4\x87\xc9\x3b\x01\xb8\xd9\x34\xe9\x80\xb0\xda\xf6\x10\xcd\xb4\xe0\xac\x1f\x6b\x26\x6c\xb9\xc3\x95\xd2\x76\x13\x52\xc9\x86\xee\x56\x07\x6d\x9d\xdf\x5c\x10\xd4\x82\x61\xb2\xa8\x2c\xf6\x40\x20\xdc\x46\x33\xf9\x92\xce\xa8\xf0\x84\xec\x24\x77\xa1\xe7\xed\x4c\x38\xd9\x64\x3d\xdd\x97\x3a\xe4\x48\x83\x94\xda\x9c\xb0\x6c\x67\xf9\xaf\x84\x7e\x6c\x90\x63\x46\x22\x1e\x25\xcc\x2a\xb4\x92\x8e\xb4\x8c\xda\x97\xb6\xc9\xe8\xf4\x7f\xcb\x1e\x98\x59\x0e\x1d\x2f\x55\xad\x8d\xeb\xa0\x33\x43\xf0\xdd\x57\x81\xb3\xa8\x19\xd8\xb8\x9c\x40\xd3\x8e\xa8\x42\x97\xb9\xea\xf3\x4b\x9f\x50\x59\xc0\x26\xeb\x1a\xfe\x43\xba\x90\x3a\xb9\x95\x22\x3d\x3f\xb0\xb5\x5b\x80\xba\xb8\xc1\xfd\x09\xf1\x8f\x4a\xc7\x60\x19\x41\xee\x30\x0d\xdc\x77\x7b\x7a\x3b\xfe\xe5\x2c\x44\xa7\xdf\x1b\xd3\x72\x2b\x36\x92\x06\xe3\xef\x3a\x4f\x44\xe2\xe9\xed\x3d\x41\x44\x2d\x89\x9b\xb4\x81\xa6\x6e\x22\x4e\x29\x67\xe8\x74\x86\x31\x4b\xdd\xde\xb3\x0e\x40\x47\xe4\xdc\xe4\x92\xf5\xf6\x2e\xd9\xc5\x86\xf3\x1b\x48\x30\xcc\x8a\x09\xd6\x61\x38\xc4\x94\xf0\x00\x62\xad\xb9\x5d\x57\x31\xf5\xa7\xff\x9c\x78\xc8\x47\xf1\x37\x9a\x8b\x92\x8e\xd0\x03\x8c\x6c\x7f\x15\x3d\xa0\xba\xc3\x69\x8a\x88\xa2\x7f\x7f\xe0\xc8\x78\x89\x6f\xa6\xfc\xc3\x71\x4e\x76\x9a\xdf\xfb\x89\x7e\x55\x96\x53\x34\xb3\xa2\x78\xf8\x2b\x87\x6b\x26\xa0\xb0\xf6\x14\x64\xd7\x69\x20\xfc\x54\x22\x7a\x9f\xb6\x72\xdc\xdd\x75\xbc\x68\xd2\x1f\x56\xac\xb1\x17\x0f\x49\x6e\x33\xf6\x12\x29\x44\x79\x11\xec\xea\x9c\x6d\x4d\xe7\x48\x29\xf9\x74\xa3\x91\x5a\xb7\x20\x59\x75\x99\x76\xcf\xa7\xca\xb5\x51\xee\xe7\x20\x64\x1e\x32\xd2\x00\xa4\x9f\x14\x5f\x1b\xd1\x4f\xc7\x1f\xe0\x87\xdf\xad\x6b\x56\xa8\xc8\x45\x9a\xbf\xf2\xff\xe5\x0f\x09\x46\x85\xdb\xe1\x5d\x77\x63\x45\x74\x55\x4d\x9e\x5c\xdb\x9b\x04\x2b\x86\x63\xe7\xe1\xf3\x82\x9d\x80\x76\x9b\xd4\x5b\x42\xbc\x47\x61\x50\xa8\xd9\x22\x9d\x7e\x35\x10\xf5\xeb\x0d\x0d\xb3\x74\xc4\x18\xd3\x82\x28\x15\x1a\xff\xdc\x81\x26\x72\x99\x07\x37\x9f\xc6\xff\xa4\x5b\x54\xb5\x2f\xc4\x79\x01\x1e\x8b\x54\x41\x9c\x41\x2e\x1c\x62\x98\x4d\xb7\x4b\x60\x62\xb6\x24\xf9\x33\x42\x26\xe3\xfc\xc7\x74\x9a\xfe\x02\x7e\x6d\x26\xac\xb6\x8e\xbd\xa7\x7a\x5d\xb0\xdf\x79\x81\xc1\x9b\x86\x8f\x07\x2a\x12\xa1\x4e\x15\xeb\x35\xf9\xc2\xe0\x9e\xad\xe7\x74\x32\x3c\x93\x0f\xcb\xc6\x3b\xd3\x65\xe7\x7a\xf1\x05\xa2\x10\x43\xe9\x2b\x9e\xc6\x15\xfe\xde\x9f\xf5\x57\x5e\x0c\x0b\xf6\xdf\x55\x52\xf5\x90\x91\x02\x60\xf1\xf1\xc6\x59\x17\x86\x61\x3c\x26\x2a\x73\x97\xe8\x2a\xa0\x37\xa4\x06\xa4\x95\xcc\xba\xca\x75\xaa\x17\x84\x4b\xa7\x15\x25\x28\xfc\xea\x1c\xba\x7c\x01\x6e\x56\x1d\x7f\x3e\x73\xbf\x04\x56\xf4\x73\xaa\xea\x53\xd6\x4e\xca\x49\xe1\x2f\xb8\x34\x76\x78\x3e\x7c\x41\xd4\x59\x7e\x75\x3e\xfb\x21\xcf\x5c\x6f\x64\x79\x90\xab\x3b\x96\x96\x62\x96\x6d\x53\x32\x4b\x41\x63\xc6\x11\x2e\xe2\xef\x47\x52\xd6\x0d\xa1\x06\xce\xea\x81\xb2\x18\x22\x26\xd0\x2b\x97\xb4\xe2\xc2\xf9\x61\xcb\x11\xec\xbf\x88\xfa\x29\xb6\xcb\x93\x11\x4f\x00\x10\xff\x2d\xa3\xb0\xef\x11\xc8\xe3\xbe\xfe\xd3\x2c\xbd\x02\xf1\xbf\x76\x93\x58\x69\x53\xcb\xc5\xd1\xfb\x95\x09\xd2\xa7\xbc\x2a\x1f\x02\x91\x5f\x6a\xe1\x8f\xf4\x40\x5c\xb9\x58\xfb\xcf\x21\xa0\x65\xb6\x11\x47\x73\x16\xbf\x75\x21\x08\x53\x7e\xdd\xd3\x62\x19\xe4\xb5\x99\xea\x67\xfb\x58\x45\xc3\x46\x9e\x8c\x68\x50\x99\x5b\x1a\xc5\xd0\x48\xbd\x1f\x62\xfa\x1f\x47\xc1\x1e\x00\x60\xaf\x11\xa4\x76\x86\xce\xea\x50\xa0\x1a\xe6\x36\x96\xc7\x64\x8b\x18\x91\x9f\xbf\xe8\x9b\x19\x24\xb6\x57\x5a\xaa\x84\x58\x87\xe0\x14\xb5\x76\x1b\x7a\x1a\xad\x00\xc7\x96\x8b\x3f\xa2\x33\x91\x2e\x57\x4b\x10\x34\x51\x04\xa8\x78\xfa\x99\xf2\x6e\x4c\x32\x6e\xc5\x52\xdb\x4b\x58\xe4\x74\x74\x56\x18\x26\xb5\x1b\xe5\x10\x5b\x35\x4e\xf0\x5b\x02\x90\x6b\x22\x7e\x60\x90\x5c\x78\xc5\xd0\x6d\xb5\x93\x50\x35\x59\xd5\x67\xe8\x0f\x26\x74\xc7\xf5\x9d\xc8\xd6\x30\x86\x83\xe3\x2e\xb9\xe1\x95\x7f\xe9\x96\xb9\xf9\xb5\xa0\x33\x56\x9f\xe7\xdf\xce\x28\xf3\x06\xdc\x1f\x7b\x73\x8a\xa1\x99\xd5\x3b\x18\x90\xbb\xba\x9f\x08\x66\xf2\x3e\xdc\xea\x29\xda\x58\xb3\xc1\xeb\xdf\xf0\xf7\x7b\xc9\x1e\x9c\x66\x09\x6c\x97\x83\x9f\xea\x80\x9c\x5e\x1a\x7e\x89\x92\x41\x50\xb9\xd0\x0f\xe5\x63\x3a\x05\xf9\x6e\x0f\x6f\x90\x56\x1d\x26\x51\xc6\x1c\x91\x86\x84\xbd\xa5\x69\xb6\x33\x3e\x94\xea\x2f\xa2\x94\x8b\x05\x00\x5a\xbb\xa4\x5a\x91\xf9\x32\x02\xb7\xb1\xf9\x60\x92\x03\x72\x66\x46\xd1\xf1\xdf\xfa\x90\x51\x94\x5e\x1b\xba\xe9\x65\x6a\x68\x4f\x71\x54\xbe\x93\x09\x3d\x23\x14\xdd\x0a\xb7\x89\xad\x87\x59\x99\xc2\xe3\xe7\x1d\x8a\xf5\x1c\xe3\xdd\x72\x62\xce\x11\x44\x8f\x18\x3d\xfd\x36\xc3\x1d\x78\x89\xe4\xfb\x57\x6a\x14\xa5\xdc\xb1\x32\x19\x59\x19\xae\x90\xfd\x22\xa6\xf2\xf5\x9a\xb7\xea\x9e\xef\xbd\x9d\xde\x5c\x11\xe4\x23\xd5\xc5\x56\x59\x11\xf3\x5c\x7b\xdd\xfa\x6e\x15\x93\xea\x26\xd2\xee\xde\xbd\xc7\xfa\xd6\x51\x72\xaa\x8c\xeb\x62\x10\x67\x14\x50\xed\xa1\xe3\x3a\x3b\x79\x23\x3f\x2d\xca\xc3\x3b\x5b\x6c\x90\xc2\xa7\x0a\xf7\x47\x77\x6d\xd2\x83\xe3\x2d\x04\x19\x18\xd7\x62\x80\xdf\xdf\x69\x06\xea\x1c\xe5\x75\x09\xfa\x7f\x99\xcb\xb3\x88\x28\xbc\x38\xfe\x58\xfc\xac\x3e\x33\xe5\x7a\xc3\x8d\x88\x86\x0b\x0d\xda\xf6\xf9\xff\x55\x20\xae\x64\x4a\x83\x6f\xd7\x1d\xf6\xac\x7c\x09\xde\x15\xc3\xb1\xec\x08\x1f\x23\x3f\xdb\x09\x41\x8c\xf8\x96\x62\xc7\x75\x21\xce\x19\x05\xae\xe7\x59\x66\xdf\x05\x34\x84\x93\x3e\x5a\xe2\x01\x39\x2d\xaa\xe4\x74\xa0\xd0\x03\x0d\xf3\x2f\x75\xdc\x2e\x32\xb2\x0e\xbc\x47\xbc\x95\xd6\x28\xf8\x12\xc9\x6b\x45\xb3\x36\x6f\x39\xfd\xae\x9c\xea\xae\x84\x23\x64\xa5\x3a\xea\x9c\xe4\xa8\x74\xa4\xf9\x4c\x59\x2d\x67\x03\x58\xa2\x61\x33\x1f\x13\x01\x30\x1f\xb5\x5e\x4d\x6b\x95\x45\x49\x41\x99\x99\xae\xd9\x3d\x62\x5b\x6f\x73\xce\x95\x67\x38\x41\xd5\x02\xed\x88\x51\xc3\x3a\x6b\x32\x19\x36\x08\x97\xe5\xf3\x53\xb9\x2c\xda\x2c\x7e\x57\xd7\xbc\xe0\x64\x0d\xa6\x22\x7b\xf0\xb4\xad\xc1\x4e\xba\xb8\x12\x2a\x0b\x7b\x43\xee\x79\x01\x90\xa0\x8e\x5e\xc1\x74\xb2\xee\x7b\x96\x98\x51\xfc\x58\xd2\x69\xcd\x5e\x52\x79\x95\x9a\x24\xc7\x93\x6f\x2c\x7a\x0f\xf1\x20\x3e\xca\x45\x53\xc9\xe7\x78\xd3\xa2\x64\x52\x1e\x7c\x77\xa1\x6f\x42\x64\x07\x9d\x59\xe0\xb8\x72\x93\xa6\x2d\x01\xf9\x99\x4b\x8f\xb6\xe7\x91\x4f\xc2\xb9\x03\x4f\xec\x16\x34\x84\x75\x58\xef\x44\xa0\x30\x4f\x9c\xe1\x9e\xce\xfe\x76\x2c\xb5\x2b\xf4\x13\x01\x5b\x7f\x26\xee\x12\x8d\x3c\xdf\x74\x4c\x1e\x73\xac\x83\x7c\x2e\x58\x58\xfb\x37\x7f\x6f\x02\x74\x0b\xf1\x95\x3a\xb1\x22\x2f\x93\x3d\x1f\x2a\x1a\x48\x51\x61\xfc\xf7\x3e\x57\x06\x3a\x8b\x91\x92\xf3\x3d\x95\x57\x1e\xb6\xd5\x82\x94\x6f\x26\xe1\xb1\xd8\x16\x10\x84\xc9\xde\xaf\x23\x1a\x6d\x92\x89\xbb\x1e\xe4\x22\xe6\xd7\x5d\x78\x76\xcd\xc0\xe9\xd9\x39\xb2\x97\x99\x4a\xa7\x70\x4f\x64\x2b\xa7\x24\x9b\xcd\x2b\x68\x06\xc6\x63\xc0\xaf\xac\x9f\xb7\x12\xe1\x8e\xea\x9c\x8e\x05\xa6\xe2\x0b\xad\x78\x8d\xc0\x83\xf6\xcd\x81\x7a\xca\xe7\x94\x96\xaa\x95\x31\x2c\xf1\x58\x5f\x92\x86\xc3\x0e\xa1\xfe\x00\xf5\x59\x66\x29\x39\xb1\x7b\x12\x59\x90\x42\xb1\xdd\x2c\x95\xa5\xc4\x0e\x5d\xf5\x7b\xc4\xe8\x42\x65\x54\xc2\xac\x62\xc0\xb0\x95\xec\x78\xf2\x45\xfe\x88\xee\x1c\xf1\x86\x80\x5c\x81\x22\xb3\x46\xa0\x8a\x28\xec\x9b\xae\xb6\xf9\x8d\x4f\x5b\x7d\xc5\x02\x22\x21\xce\x11\x18\x78\x11\x58\xdc\xbb\x18\x39\x02\x7c\x55\xd1\x33\x15\x72\x13\x5c\xc5\x29\xfd\x0c\xdd\x10\xf6\x29\xae\x5f\xe5\x34\xfa\xce\x3f\xdb\x1a\x42\xe5\x01\x66\xdd\x9e\x74\x95\x98\xfc\x10\x45\x05\x2b\x08\x84\x3c\x0f\x5f\xff\x09\x8e\x37\x7b\x65\xaa\xf0\xc2\x38\xb6\x70\x98\xdb\x67\xc2\xf1\x6d\xaa\xa9\xf3\xa9\x70\xda\x42\xe6\x41\xa6\x6e\xb8\x57\x4e\x67\x3e\xc4\x5b\x33\xcd\x5f\x34\x9c\x9b\x39\xab\x67\xb5\xd9\x82\x35\xc4\xc9\x8e\xdb\x5d\xdd\xe7\x9e\x8b\xb8\x1c\xf8\xb4\x17\x2e\x66\x0e\x36\xbb\x3a\x4e\xc0\xf8\x4d\x89\x23\xe2\xb6\x0d\x74\x46\x05\x97\x26\x55\xf0\x71\x3b\x80\x13\x2d\x99\xa4\x7f\xbc\xbf\x6a\xfe\x13\x6a\x9b\x46\xb3\x3d\xc8\x44\x92\xe1\xc7\x22\x35\x78\x4a\xe0\x10\x44\x7e\x89\xf2\xd6\x4d\x83\xd0\xf5\xab\x92\x56\x0a\x72\x0a\x3c\x72\x73\xc2\xb3\xef\xdf\x6d\x79\xdb\x6d\x90\x15\x95\x4a\x4c\x8f\x69\x4b\x40\x12\xf8\x7c\x72\xa5\x2a\x91\xa2\x27\x5c\x32\x14\x53\xd1\xf2\xf0\xaf\xfe\xbe\x3e\x82\x6b\x45\x80\xa5\x57\x41\xa9\x5b\xa4\x59\x03\x3c\x75\xb2\x77\x8e\xfd\x8f\xfd\x80\xe5\x4f\xb4\x8c\xd7\x00\xc6\x9b\x54\xa3\xca\x36\xb0\x01\x99\xc5\x02\x00\x39\x3e\x6b\x16\x7e\x2f\xa8\x36\x33\xa0\x35\x85\x02\x08\xe9\x1f\x66\x12\x96\xb1\xf6\xbc\xb6\x1e\x5b\x44\x20\x57\x4a\xb3\xb7\x48\x5d\x40\x21\x87\x69\xd1\x91\xd7\xff\xd6\x7c\xb7\x68\x38\x36\xe9\xa0\x39\x6a\x85\x8f\x24\x0d\xfc\x0e\xfd\x83\x8e\xf2\xcf\x5a\xa9\x06\x13\x9f\xdb\x36\xe6\x6e\xcc\x59\x23\x3d\x20\xf9\x37\x87\x6b\x84\x82\xb7\x34\xda\xc5\x06\x5d\x75\xea\x47\xeb\x77\xac\x98\x46\x4d\xb3\xaf\x47\x12\x78\xd4\x40\xb1\x2a\x43\x92\x1f\x9d\x48\x86\x8a\x0c\x18\xc9\x37\x2d\x79\x46\x39\x13\x26\xfe\xf9\x78\xd7\xdb\x92\x2d\xe6\x53\x2d\x3d\xd3\x35\x9c\x86\x0b\xd6\xfc\xfb\xad\x25\x01\xfc\xa4\xa2\xc0\x44\x25\x6e\x31\x10\x2f\xb6\x78\xd3\xfe\xac\x72\xf7\x3f\x4b\xb2\x84\x1d\xd4\x9b\x68\x55\xd9\x9d\x96\x68\x3e\x9b\x32\xdc\x46\xfb\x1c\xf2\x69\x51\x21\xf3\xe0\x21\x3c\x9c\xff\xa8\xd6\x05\x70\x7e\xb8\x3f\xef\x1a\x97\x7d\xf8\x18\xb3\xb3\x70\x80\xdf\x32\xf1\xd5\xac\xd5\x61\x47\x25\x95\x13\x60\x3d\x2e\x40\x23\x92\xd1\x42\xee\x05\x72\xa4\xd2\x6e\x72\xe3\x7e\xf4\x54\xb2\x2b\x57\x3c\xa4\x23\x38\xcd\x8b\x87\xed\xe5\x30\x2a\x0f\x2d\xdc\xc0\xdc\x1e\x50\xdd\x53\xff\x5f\x62\x9a\x68\x1b\x11\xbe\x59\xb5\xf4\xd3\xf6\x0e\xbb\x62\x3e\xf2\xcb\x44\xfe\x13\x09\x5c\xb1\x6b\x1c\xb7\x5f\xd6\xd5\xb7\xa4\xf2\x96\x0a\x91\x59\xf2\xa4\xc6\xde\xbe\x8f\xf2\x24\x5a\x84\x5f\xd7\x63\x75\x7c\x56\xf0\x85\x12\x0e\x47\xba\x57\xd7\x80\xf3\x56\xed\x04\x4d\xab\x0b\x7e\xdd\xbf\xd8\xf3\xa9\x4c\x41\xa0\x46\x1f\x34\x7d\xbb\x83\xaa\xdf\xa5\x17\xc0\x93\x5b\xa7\x5e\xa0\xae\x32\x3e\x87\x54\x01\xb8\xdf\x98\xd0\x79\x4b\xc5\x83\x3c\xbf\xdf\x30\x23\xd6\xcc\xf0\xc4\x4a\x07\x76\x0b\xb9\x4f\x43\xc5\xa3\x85\xca\x59\x7a\x23\xa7\x44\x09\x21\x01\x92\x5e\x0f\x49\x22\xb0\x9d\xca\xea\x10\x2c\x5a\xe1\x98\x3d\x2f\x59\xfb\x4b\xb7\xb6\xb7\x66\x4e\xcc\xea\x29\xa6\xa9\x3d\x12\xa1\x4f\xb1\x15\xed\xbf\x06\xef\xdb\x1d\xdb\xe9\xfd\x0c\x51\x35\x98\xbb\x12\xdb\x6a\x82\x5c\x29\xfc\x06\x73\xef\xd3\x25\xa1\x39\x49\xc2\xd4\x54\xc1\x13\x57\x71\xc1\xea\xa3\x63\x1f\xcb\xee\xb1\xbd\xc9\x74\x6e\x89\xbc\x6e\x28\xac\x54\x72\x3a\xba\xad\xfe\x14\x49\x04\x56\x56\xa8\x53\x2b\x74\x7b\xc7\x5f\xab\xaa\x60\xe5\x8c\xe9\x43\xda\x20\x65\x1c\xe8\xf9\x97\x01\xec\x7c\xa3\x3b\x48\x0a\x5e\xaf\x41\xf0\xe5\x5e\x62\x4f\x2e\x5b\xb8\x2e\x92\x23\x59\xe8\xb1\x79\x6a\xa1\x5d\x26\xdf\xf3\x3d\x30\xf2\x2f\xe8\x92\x45\xa4\xa5\xbc\x91\xe9\x72\x32\x0a\xa7\x4e\x43\x1e\xe9\xf1\x87\xad\x3e\x99\x94\x58\x82\xa0\x99\x63\xde\xe9\xf9\x61\xaf\x89\xd1\x47\x98\x2e\xca\x17\x61\xaa\x89\x6c\xc9\xde\x1b\xae\x00\xcf\x75\x8d\x73\x75\x76\x97\x7a\x57\xa4\x4a\x43\xd9\x2b\x03\xcc\xbb\xa2\x92\x38\x86\x5d\x0e\x62\x84\x4c\xaf\x2f\x79\x47\xd8\x0e\x9c\x9e\x60\x04\x09\x95\xe2\x35\xb3\xc2\xe2\xf7\x0b\x78\xa6\x79\x25\xb4\x5d\x79\xa5\x21\xdb\xf1\xf7\xcf\x9a\x49\x30\x7f\x9e\x90\x92\x80\xae\x0d\xae\x68\x64\x35\x83\x35\x90\x8c\x34\x8e\xe7\xb2\x51\x6b\xf7\xd2\xd0\x79\xcd\x61\x0e\x25\x64\xc2\x9c\xec\x5e\x76\x62\xf9\xc7\x25\x1a\xa0\xe5\x1c\x40\xe9\x4c\x2e\x55\x1f\x0c\xd3\x38\x6a\x71\x2b\xbf\x43\x48\x4a\x9a\xfd\x4b\x64\x4a\x09\x9f\x4b\xc1\x32\x52\x86\x79\x71\x6b\x60\xfa\x59\x3c\x1e\x35\x00\x9b\x81\x32\x6c\x35\x31\x18\xcc\x2f\x5a\x18\x84\x07\xe5\x9b\xc5\xc9\xee\xef\x8f\x8d\xaf\x8f\x92\xce\x1b\x6f\xee\xdb\xad\xa2\xfd\x1a\x6c\x7b\xfc\x04\xcc\x92\xe5\x40\xa1\xca\x70\x91\x4a\x2a\xb5\x92\x5b\x91\x1c\x04\x9f\xff\xdd\x7e\x02\xcc\x68\xea\x8e\xcb\x8d\xb5\x17\x37\x99\x1f\xd8\xbd\x25\xf8\xb0\x9a\x99\xad\x1d\x4d\x33\xf6\xec\xba\xf9\x1f\xa4\x7d\x24\x73\x53\x56\xda\xd1\x93\xfb\x21\xc5\x43\xd9\x00\x10\xf5\xb7\x3b\x3f\x05\x84\x6f\xb3\x8d\xcc\xa6\x6f\xb8\x2e\x66\x7b\x71\x9a\x3d\xc0\x15\x3e\x77\x61\xc0\x37\x02\x3c\xe7\x68\xcc\x3b\x57\x50\x6f\x2f\xdb\x35\x39\xe5\xd0\x37\xd4\x84\x8e\xa5\x98\xef\xfb\x01\x33\x3f\xc0\xec\x80\xe0\x74\xe0\x4b\xda\x86\x93\xcb\xa3\x31\x05\xe1\xfa\x6e\xd7\x5e\x2d\x10\x1e\xbc\xdb\xfa\x4d\xf7\xc1\xf1\x51\xf7\x31\x2b\x10\xfa\x34\x1d\x76\x36\x58\x9c\xca\x90\x96\x04\x79\xcd\xa6\x9b\xcf\x99\x09\x56\x79\x09\xfa\x28\x9a\x46\x21\x13\xdd\x2e\xf2\x51\xe8\x2f\x7b\x53\x4a\x03\x92\x0e\xc8\xb2\x55\xdc\x16\x3c\xb0\x09\x9e\xe5\x32\xc8\x09\xd7\xca\xcf\x27\x92\x44\x2e\x9c\xcd\x85\x19\x02\x57\x31\x77\x64\x05\x6c\x08\x91\xae\xa6\xf9\x2f\x5c\x97\x72\x32\x4c\x75\xf7\xef\x53\x27\x11\xb2\x25\xd1\x65\x85\x73\x13\xf4\xce\xa4\x08\xa4\xa4\x47\x3f\xce\xa4\x2d\xab\x41\x1b\x9b\x8a\x23\xa8\xd7\xa0\xa6\x1a\x85\xcc\xd1\x8b\xff\x0e\x6b\x1e\xf7\x90\x67\xf3\x54\x97\x48\x63\xec\x18\x5d\x24\x5b\x62\xed\xf2\x31\xc1\x45\x5d\xed\xbe\x42\xb3\x50\x01\xd0\x5d\x5d\x8b\x2e\x99\xe2\xef\x88\xce\xfc\x8a\x8a\x30\x1a\x6e\x12\xac\xdb\xee\x28\x73\xcf\xfc\x08\x83\xe3\x98\x36\x97\xbe\x9b\xee\x13\x54\x0e\x3e\x3f\x96\xd9\xbb\x37\xf4\xa1\x7d\xdd\x8d\x05\xbc\x62\x0b\x4e\x02\x4c\xe8\xa9\x40\xa6\xaf\xd4\xa9\x61\x1e\x74\x5e\x04\xfe\xee\x2b\x47\x1e\xd8\x73\x10\x3c\xea\x02\x6b\x6e\x64\xef\x36\x81\x31\x38\x77\x6f\xf7\x71\x79\xd8\x7a\xf1\xdb\xa6\x24\xa3\x2a\x08\x5b\xa6\xaa\x3b\xf2\x6c\x0d\x8d\xdd\xbb\xad\x77\x68\xdd\x2d\x06\x58\xb5\x5f\xbe\xe2\xbc\xb5\x7b\x43\xf7\xa0\x26\x80\xc1\x53\x46\xf0\x0c\xa1\x4f\x15\x33\x91\x45\x94\x1b\x8e\x20\xe8\x31\x45\x49\xdf\xc9\xb2\xa9\xa3\x93\x5c\x9f\x11\xa0\xd2\xf7\xc5\xf2\x89\x42\x88\xcf\x78\x35\x34\xdc\x64\xe4\x1d\x4d\xb1\xc1\x0f\x6b\xc5\xb3\xe0\x34\xfa\x91\x43\xbf\x60\xc1\x14\x89\x1a\x87\xf2\xdc\xd8\x56\x2a\xe6\x6d\x9e\x22\xf2\xf1\x11\xe6\x36\x07\xd8\xb1\xb4\x9d\xee\xaa\x72\x14\xe3\xf2\xfd\x95\x67\x8d\x72\x98\x85\xab\xe2\xab\x7e\x88\xcd\xb8\xc6\x1a\x0b\xec\x18\x09\x5a\xb5\x06\xdb\x88\x64\xbb\xf1\xdd\x5a\xb9\xe8\x36\x56\xcb\x0f\xa4\x5a\x72\x77\xae\x4e\x0d\x75\x1e\x4f\x22\x79\x01\xdc\xbf\x52\x00\xf3\xa6\xe2\x2d\x08\x9d\xcd\x60\xb3\xdf\x5c\xa1\x2b\x4f\x6f\x39\xd5\xb4\x15\x93\x7c\x62\x00\x37\x5d\x86\xf5\xab\x98\xdb\x62\xa6\x6b\xf3\xae\x44\xd8\x91\xd6\xa3\x24\x0c\x37\x32\x06\x02\xc8\x95\x9d\x12\x43\x0e\xdf\x1b\x02\x85\x0e\x02\x32\xfb\xa7\xe1\xca\xc4\xdd\x9d\x69\x4e\xb7\x33\x33\xa0\x81\x0a\x06\xe3\xa7\x1d\x04\x12\x97\x4f\x25\x7f\x75\xcf\x85\x4c\xd7\x5b\x97\xd7\x84\xf0\x62\x54\xe4\x60\x0b\xa5\x0b\x31\x67\x85\x55\xa5\xb9\x0f\x37\xb1\x71\x33\xda\x83\xcd\x6d\x56\xd6\xeb\x81\x0a\xae\xed\x27\xcb\xe7\xfa\x80\x67\x34\xc3\xf2\x31\x4b\xd1\x28\x2b\x7f\x27\x55\xe4\x20\xd0\x70\x51\x27\x38\x34\xae\x34\x51\x47\x93\xe1\x1c\x17\x23\x16\x2e\xdd\xb2\xc0\xa4\x9e\xe1\xc1\x5d\x0d\xe1\xed\x32\x9e\x72\xff\x7b\x3e\x8f\xc0\xd2\x57\x9a\xb7\x28\x29\x33\x22\x1f\x4e\xd5\x0e\xd9\x65\x4b\xb6\xc0\xa8\xf3\xa3\xfb\x98\x85\xb3\xbe\xbf\x9d\xcd\x51\xf7\x3f\xa3\x03\xbc\xba\x5f\x44\x14\xc4\x11\x8a\xb1\xeb\xad\xc8\x04\x48\x67\x1b\x96\x00\x81\xb6\xcc\xbe\x2a\x7f\x50\x4f\x99\x18\x83\x23\x72\xee\xb6\x5c\xb6\xef\xdb\x4b\xce\x9c\xec\xc4\xa3\x33\xa7\x23\xd9\x12\x96\x48\x93\x6a\x50\x7b\x58\x3d\x70\x8a\x8b\x01\xd2\x56\x86\xf8\x95\xab\x40\xd5\xee\x01\xb9\x0d\x56\xe2\x00\x53\x16\x25\x46\xe4\x93\xce\xa0\xbb\x9a\xc3\x2f\xd1\x44\x6d\xb6\x90\xfb\x01\x70\x19\xc2\xb2\x30\xf2\xe7\x36\x8a\x17\x18\x51\x24\xc3\xf2\xb7\x7c\xfc\x29\x52\xbd\x5f\x58\xd1\x3d\xf6\x1b\x38\xf8\x00\xea\x59\x0e\xc7\xd3\x84\x5f\x15\x1e\x1d\x11\xa4\xbd\xb3\xb7\x39\xa0\x10\xc9\x10\xd5\x86\xc9\x6e\xac\xed\x7d\xff\x97\x96\x19\xa9\x0c\x1a\x0a\x4f\x01\xe4\xe4\x48\xa8\xfe\x24\x69\x23\x4f\x82\x17\x25\xb0\x8f\x33\xd8\xe2\xca\xd6\xcb\x19\x58\x31\x9f\xd2\x41\xfb\xf7\xd4\x73\xfc\x2a\x6d\x29\x03\x5a\x17\x21\x7b\x94\x12\x62\xae\xfb\x4b\x1e\x25\xe1\xeb\xdf\xad\x8a\x81\x6d\xb7\x38\xe6\x52\x66\x08\x0a\xc8\x43\xf7\xdf\x5e\x1c\x87\x34\xb7\xa9\x7b\x99\xed\xf5\xb2\x8e\x6b\xb5\x29\x4a\x98\x35\x3d\xa6\x05\x97\x2b\x8a\x41\xfa\x61\x18\x58\x93\xe5\x26\x55\x01\xfd\x34\x02\xbb\x72\x53\xe8\x48\x19\x84\xe3\x84\xe8\x07\xde\x26\xed\xce\x6a\x9e\x58\x82\xb6\x53\x20\x09\xed\x6c\xe7\x30\xd5\x54\xb0\xc8\x31\x4d\x4b\xb4\xda\xce\xc6\x49\x80\x67\x1f\xb5\x1d\x3f\x3f\xa1\xbc\x68\x42\x2f\x87\x2b\xf6\x25\xbc\x97\xec\x2c\xfe\xab\x13\x1f\xcf\x61\x1b\xd4\x50\xe3\x2e\x44\xcb\xe3\x92\xf0\x77\x93\x13\xb3\x5d\xbd\x14\x51\x30\xa3\xbd\x2a\x64\xf4\x5a\xb4\x7d\xd9\xa1\xf2\xfe\xd7\x51\x44\x0c\xbe\xbf\x63\x27\x10\x56\x23\x66\xa3\x51\x09\xd9\xbf\x18\xed\xcc\x03\x31\x8f\x4a\xaa\x86\xea\xe9\x0c\x2b\x66\xe2\x9d\xf2\xfd\xf1\xe3\xaa\x90\xfa\xc5\x2f\xa7\xb8\x5f\x2a\x11\xc4\x9c\x9d\xdb\x2d\xb8\x2d\x72\x16\x16\x96\x3b\x4b\x5f\xa3\xe8\x15\xf0\x7a\x38\xcf\x0a\xe4\x2d\x27\x19\xd0\x05\x4d\x28\xe9\x0d\xc2\x69\xec\x13\xf6\x27\x0b\x26\x3b\x12\x09\x9d\x30\xf4\x8b\xc5\xef\x8a\x19\xdd\xdb\xc8\x6c\x8f\x65\x08\x9a\x80\x94\xfd\x9d\x47\x45\x37\xa1\xb2\x74\x0e\x88\x38\x24\xf5\x85\xe0\x01\x48\x35\xc6\x6f\x57\xd9\x1c\x8a\x44\x10\xcf\xc3\x7c\x02\x74\x37\x85\x77\x85\x0a\x66\x7b\x48\xc8\x33\xa5\x3c\xf4\x72\x0f\x59\x89\xed\xf1\x35\xc6\xe0\x10\x7d\x6a\xc8\xb1\xd7\x12\xb8\x2b\x66\x9c\xf5\x70\x72\x7e\x63\x7b\x12\xe1\xe6\x79\x99\xa9\xb9\xdd\x66\xf8\x01\xc5\x76\x9e\x3b\x2d\x70\x65\x7e\x20\x03\x05\x57\xa9\x04\xe1\x87\x21\x46\xa6\x5b\xea\x5a\x5f\x3d\x4b\x20\xb6\x74\xcb\x2a\x32\xa3\x58\x5a\x29\xc1\x1a\xe9\xfe\xcf\xfd\x60\x6c\xfc\x54\x88\xa3\x4f\x8c\x7f\x3a\x62\x4c\x67\x4b\x6e\xd1\x98\x28\xb1\x9b\x5d\xfe\x98\x12\x66\x2a\x72\xe4\x96\xb5\x25\x30\x74\x4a\xf9\xd8\x42\xee\x4a\x54\xf7\x64\xcf\x75\x98\x9b\xa7\x9b\xc2\x7b\xba\x7e\x30\xd0\xe6\x32\x0c\x3c\x88\x69\xfe\x0f\x89\x21\x3e\x8c\xc9\xef\x67\x37\x14\x98\x27\x12\xe9\xba\xeb\x12\x9e\xd3\x47\xfc\x25\x78\xa7\x90\xc3\x2b\x08\xae\x39\x86\xd0\xac\xdd\xc7\x6b\xcc\xe0\x3b\x51\x11\x59\x7d\x46\x19\xf5\xbc\xbc\xb8\x6a\x74\xa6\x9f\xd8\x44\x51\x0d\xf4\xed\x89\xc1\x44\xe1\xfb\x1d\x0a\x91\x9c\x3f\x87\xb5\xc3\x4f\xde\xc1\x93\x27\x6b\xb7\x6c\xb2\x5a\xda\xc9\xe2\xe0\x3d\x5a\xa0\x2b\x49\xe7\xc6\xbb\x48\x4d\x8a\x69\xbe\x17\x08\x99\x1a\x16\x10\xc7\xa8\xce\x8c\x0b\x3a\x24\xd1\x66\xb0\xd9\xc7\xf4\x22\xfa\x5c\xad\xdc\xc0\x25\x53\x5d\xc6\xaa\x8c\xc5\x89\xf7\x83\xa7\x54\xbe\xde\x47\xe2\x9b\x74\x31\xf1\xc3\x3d\x60\x20\xf3\x6d\xd0\xd7\xfe\x3b\xcb\x54\xcc\x3c\xff\xed\x25\x32\x9c\xf9\x22\xe1\xbd\xa7\x14\x56\x02\xec\x6b\x8d\x92\xe7\x4f\x22\x73\x0e\x1a\xce\x5f\x33\xea\xfc\xba\x05\x6b\xd1\x9c\x41\x0e\x8b\xb9\xed\x57\xc1\x65\x67\x26\x57\xa5\x9f\x6f\x07\xef\xca\x0b\xb0\xc5\xf3\x20\x24\xb7\xc0\x02\x33\x7d\x7a\xf4\x8a\x00\x3b\x89\x06\x5c\x6b\xf2\x17\x13\xed\x4f\xd7\x63\xfd\x7b\x59\x4d\x8e\x38\xc1\xe1\x10\x8d\x8b\xfe\xb5\xde\xd7\x98\x7c\xe3\x1b\xe2\x16\x17\x72\x55\xb7\x36\x0b\xbe\x90\x87\x9c\x52\x12\x3a\x79\x8c\xaf\x1e\xea\x66\x47\x20\x28\x70\x14\x74\x06\xc2\xd0\x03\xab\x26\xe7\xbd\xb2\xab\x70\x6e\x77\x7c\x99\x36\x25\x1c\x7f\x7d\xf0\x9c\x89\xb2\x5c\x8e\x7a\xb6\xf7\xf7\x45\x62\x38\x59\x0b\xa5\x80\x04\x0f\x7e\x6d\x96\x07\x59\x92\x73\xb9\x93\x07\x00\xde\x92\x8f\xfd\xc8\xb9\x9c\xae\x26\x05\xfb\x3b\x14\xfb\xd0\xb5\xc5\xae\xd9\xb1\x91\x4f\x7b\xe1\x0a\xa5\xf1\x11\xf3\x77\x20\x72\x77\x19\xca\x9e\xee\x29\xf0\xc2\x04\x73\x23\x8c\x53\xa4\xca\x14\xd4\x5d\x9a\x96\x9f\x41\xd5\x12\x1e\x6b\xd8\xb6\xe3\x1d\xdf\x8d\xd7\xe6\x54\x55\x02\x2c\xc6\xfe\x61\x17\x09\x5c\x51\x5a\xb9\x2d\xc8\xa6\x6f\x5f\xd1\x2e\xe8\x1d\x0d\xe5\x41\x47\xb0\x0c\x3c\x31\x12\x4d\xdb\x37\x2f\x0c\x6f\x7b\x66\x90\xc8\x17\xed\xe0\x60\x23\x35\xab\xf9\xcd\x93\x9a\x69\xee\x60\x00\x1a\xb7\xf5\xe5\x47\x7a\xcb\x9e\xdc\x75\x5c\x4b\xe1\x1b\xfc\x18\x40\x54\xb4\x96\xab\xdb\xf7\x07\x5b\x92\xc1\x07\xbd\x80\x4a\x90\x7b\x97\xd0\xe3\xad\xfa\x34\xe4\x24\x10\x47\xd0\xdf\xf1\x1a\x30\xa9\xae\x98\x3d\x2d\xb2\x15\xa4\x71\xf0\x7a\x85\x21\xa5\xea\x7b\xc3\x74\x08\x07\xb3\x4f\x80\x01\xd3\x85\x77\x2e\x94\xf7\x32\x69\x25\x73\xf5\x1b\xaa\x44\xd0\xb0\x0a\x32\x8e\xbd\x37\x0c\xaf\x62\x46\x07\xcd\xfa\x8f\x2b\x8a\x0e\xfe\xf8\x33\xde\x69\xd3\xe6\x31\x28\x76\x3d\x90\x47\x88\xf2\xee\x39\x6f\xae\xd0\x82\x82\xa8\xa5\x94\xb1\x75\x27\x2f\x08\xf5\xdf\x53\x41\xf5\xfa\xa0\x26\xcb\x1a\xa8\xb5\xde\xb5\x7e\x2b\xa7\x06\x39\x42\x38\x19\xea\x93\x17\x45\xd5\x25\x1c\x82\x0b\xe0\x0b\x3b\x90\x8b\xeb\x7d\x4b\xa7\xb4\xda\xc5\xe2\xcb\xde\xc4\xb6\x72\xc4\x03\x6d\xab\xe0\xad\xfe\x5a\x86\xbc\x61\x50\xfc\x53\xe1\x51\x6b\x9c\x42\xdb\xc8\x7c\x24\x3f\x48\x31\x5e\x46\x31\x2b\x45\x29\x78\x3d\x54\x02\x08\x60\x58\x42\x5a\x91\xbd\x20\x32\x93\xf2\xd2\x5f\x62\x3f\xd5\x4f\xaf\xde\xd7\x2e\x2d\x0b\x32\x9c\xf7\x60\xa8\x04\xf6\x72\xd8\xbf\xe1\x50\xab\xdf\x05\xd0\x6f\x8c\x98\x9f\x31\x55\x90\x41\xb2\xf0\xee\xb4\xce\x5b\x99\xa5\x19\x08\xbb\x02\x9a\x6c\x22\x7a\x2c\x59\xee\x78\xac\x4a\x10\x3d\x17\x52\x30\x30\x42\xe1\x6a\x04\x7a\xb3\x57\x76\x82\x06\xa2\x8f\x24\x3c\x40\xb2\x50\x6a\x08\x95\x5c\xc4\xc9\x89\x8f\x6a\x32\xe3\x87\x26\xb4\x1a\x69\x30\xe1\xda\x47\xdf\xd8\x4e\xc0\x6f\x52\xa1\x25\xa3\xd2\x4c\x84\x0c\x92\x75\x20\xc1\x61\x0b\x6f\x7e\x4f\x5d\x8a\xda\x2e\x1f\xb8\xe1\x80\x17\xfe\x91\x93\x3d\x30', 1)

================================================
FILE: agent/fix_rule/license.lic
================================================
HSpGTEFHUzoBKkNPREU6UHlhcm1vci1Qcm9qZWN0OHD4jbg3oaZPjPlTyiQyadr7bY7WVZJHSrbRS3HjpzdMKMC4qTYbE97ZIZZ8XWDTHSJrrOVqGCnWjuZ71LGMWNMESpvXwaRyL9WGqf9kmUO9iYDYVWwF8u/DddUuYjq4k/V1JEGKftwPFwieTkza8iiUts7xUu/dHRKLwANb/MU=

================================================
FILE: agent/fix_rule/product.key
================================================
Bې?CAk8a6WH0vY
y

}q#fRq+JBwzʱnƐS*TE`wN(RGy0tD&y
P:Cq\8SBV]

================================================
FILE: agent/fix_rule/pytransform.py
================================================
# Because ctypes is new from Python 2.5, so pytransform doesn't work
# before Python 2.5
#
from ctypes import cdll, c_char, c_char_p, c_int, c_void_p, \
                   pythonapi, py_object, PYFUNCTYPE
from ctypes.util import find_library

import os
import sys
import platform
import struct

#
# Global
#
_pytransform = None
_get_error_msg = None

#
# Options
#

# How to show error message return from dynamic library _pytransform.
#
# Each time call a dll function, if something is wrong, _get_error_msg
# will return the reason.
#
# Enable _verbose_mode will print the details got from _get_error_msg.
# Disable this options will print only a short message.
_verbose_mode = 1

# In debug mode, print trace stack when raise exception.
# Otherwise only show a short message.
#
# Run python with command option "-d", or set environment variable
# PYTHONDEBUG. For example
#
#   python -d pyarmor.py xxxx
#
_debug_mode = sys.flags.debug

class PytransformError(Exception):
    def __init__(self, *args, **kwargs):
        super(Exception, self).__init__(*args, **kwargs)
        if _debug_mode:
            self._print_stack()

    @classmethod
    def _print_stack(self):
        try:
            from traceback import print_stack
        except Exception:
            _debug_mode = 0
            sys.stderr.write('Disabled debug mode.\n')
        else:
            print_stack()

def dllmethod(func):
    def format_message(msg, *args, **kwargs):
        if _verbose_mode:
            s1 = str(args)[:-1]
            s2 = ', '.join(['%s=%s' % (k, repr(v)) for k, v in kwargs.items()])
            sep = ', ' if (s1 and s2) else ''
            line = 'Call with arguments: %s%s%s)' % (s1, sep, s2)
            return msg
        return msg.split('\n')[-1]
    def wrap(*args, **kwargs):
        args = [(s.encode() if isinstance(s, str) else s) for s in args]
        result = func(*args, **kwargs)
        errmsg = _get_error_msg()
        if errmsg:
            raise PytransformError(format_message(errmsg, *args, **kwargs))
        return result
    return wrap

@dllmethod
def init_pytransform():
    major, minor = sys.version_info[0:2]
    # Python2.5 no sys.maxsize but sys.maxint
    # bitness = 64 if sys.maxsize > 2**32 else 32
    prototype = PYFUNCTYPE(c_int, c_int, c_int, c_void_p)
    init_module = prototype(('init_module', _pytransform))
    init_module(major, minor, pythonapi._handle)

@dllmethod
def init_runtime(systrace=0, sysprofile=1, threadtrace=0, threadprofile=1):
    pyarmor_init()
    prototype = PYFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
    _init_runtime = prototype(('init_runtime', _pytransform))
    _init_runtime(systrace, sysprofile, threadtrace, threadprofile)

@dllmethod
def import_module(modname, filename):
    global _import_module
    if _import_module is None:
        prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
        _import_module = prototype(('import_module', _pytransform))
    return _import_module(modname, filename)
_import_module = None

@dllmethod
def exec_file(filename):
    global _exec_file
    if _exec_file is None:
        prototype = PYFUNCTYPE(c_int, c_char_p)
        _exec_file = prototype(('exec_file', _pytransform))
    return _exec_file(filename)
_exec_file = None

@dllmethod
def encrypt_project_files(proname, filelist, mode=0):
    prototype = PYFUNCTYPE(c_int, c_char_p, py_object, c_int)
    dlfunc = prototype(('encrypt_project_files', _pytransform))
    return dlfunc(proname, filelist, mode)

@dllmethod
def encrypt_files(key, filelist, mode=0):
    t_key = c_char * 32
    prototype = PYFUNCTYPE(c_int, t_key, py_object, c_int)
    dlfunc = prototype(('encrypt_files', _pytransform))
    return dlfunc(t_key(*key), filelist, mode)

def generate_project_capsule(licfile):
    prikey, pubkey, prolic = _generate_project_capsule()
    capkey = _encode_capsule_key_file(licfile)
    return prikey, pubkey, capkey, prolic

@dllmethod
def _generate_project_capsule():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('generate_project_capsule', _pytransform))
    return dlfunc()

@dllmethod
def _encode_capsule_key_file(licfile):
    prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
    dlfunc = prototype(('encode_capsule_key_file', _pytransform))
    return dlfunc(licfile, None)

@dllmethod
def generate_module_key(pubname, key):
    t_key = c_char * 32
    prototype = PYFUNCTYPE(py_object, c_char_p, t_key, c_char_p)
    dlfunc = prototype(('generate_module_key', _pytransform))
    return dlfunc(pubname, t_key(*key), None)

@dllmethod
def generate_license_file(filename, priname, rcode, start=-1, count=1):
    prototype = PYFUNCTYPE(c_int, c_char_p, c_char_p, c_char_p, c_int, c_int)
    dlfunc = prototype(('generate_project_license_files', _pytransform))
    return dlfunc(filename, priname, rcode, start, count)

@dllmethod
def get_registration_code():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('get_registration_code', _pytransform))
    return dlfunc()

@dllmethod
def get_expired_days():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('get_expired_days', _pytransform))
    return dlfunc()

@dllmethod
def get_trial_days():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('get_trial_days', _pytransform))
    return dlfunc()

@dllmethod
def version_info():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('version_info', _pytransform))
    return dlfunc()

def get_hd_sn():
    size = 256
    t_sn = c_char * size
    sn = t_sn()
    if (_pytransform.get_hd_sn(sn, size) == -1):
        return ''
    return sn.value.decode()

def show_hd_info():
    return _pytransform.show_hd_info()

def get_license_info():
    info = {
        'expired': 'Never',
        'restrict_mode': 'Enabled',
        'HARDDISK': 'Any',
        'IFMAC': 'Any',
        'IFIPV4': 'Any',
        'DOMAIN': 'Any',
        'CODE': '',
    }
    rcode = get_registration_code().decode()
    index = 0
    if rcode.startswith('*TIME:'):
        from time import ctime
        index = rcode.find('\n')
        info['expired'] = ctime(float(rcode[6:index]))
        index += 1

    if rcode[index:].startswith('*FLAGS:'):
        info['restrict_mode'] = 'Disabled'
        index += len('*FLAGS:') + 1

    prev = None
    start = index
    for k in ['HARDDISK', 'IFMAC', 'IFIPV4', 'DOMAIN', 'FIXKEY', 'CODE']:
        index = rcode.find('*%s:' % k)
        if index > -1:
            if prev is not None:
                info[prev] = rcode[start:index]
            prev = k
            start = index + len(k) + 2
    info['CODE'] = rcode[start:]

    return info

# Load _pytransform library
def _load_library(path=None):
    if path is None:
        path = os.path.dirname(__file__)
    plat = platform.system().lower()
    bitness = struct.calcsize('P'.encode()) * 8
    libpath = os.path.join(path, 'platforms', '%s%s' % (plat, bitness))
    if not os.path.isdir(libpath):
        libpath = path
    try:
        if plat == 'linux':
            if libpath == '':
                m = cdll.LoadLibrary(os.path.abspath('_pytransform.so'))
            else:
                m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.so'))
            m.set_option('libc'.encode(), find_library('c').encode())
        elif plat == 'darwin':
            m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.dylib'))
        elif plat == 'windows':
            m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.dll'))
        elif plat == 'freebsd':
            m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.so'))
        else:
            raise RuntimeError('Platform not supported')
    except Exception:
        raise PytransformError('Could not load _pytransform from "%s"', libpath)

    # Required from Python3.6
    m.set_option('byteorder'.encode(), sys.byteorder.encode())

    # m.set_option('enable_trace_log'.encode(), c_char_p(1))

    # # Deprecated from v3.4
    # m.set_option('enable_encrypt_generator'.encode(), c_char_p(1))
    # # Deprecated from v3.4
    # m.set_option('disable_obfmode_encrypt'.encode(), c_char_p(1))

    if not os.path.abspath('.') == os.path.abspath(path):
        m.set_option('pyshield_path'.encode(), path.encode())
    return m

def pyarmor_init(path=None):
    global _pytransform
    global _get_error_msg
    if _pytransform is None:
        _pytransform = _load_library(path)
        _get_error_msg = _pytransform.get_error_msg
        _get_error_msg.restype = c_char_p
        init_pytransform()

def pyarmor_runtime(path=None):
    pyarmor_init(path)
    init_runtime(0, 0, 0, 0)


================================================
FILE: agent/fix_rule_no_att/agent.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from pytransform import pyarmor_runtime
pyarmor_runtime()
"""
   Copyright 2018 Information Science Academy of China Electronics Technology Group Corporation

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

@author: Gao Fang
@contact: gaofang@cetc.com.cn
@software: PyCharm
@file: agent.py
@time: 2018/3/13 0013 10:51
@desc: rule based agent without attack ability
"""

from agent.fix_rule_no_att.agent_core import Agent as ag


class Agent:
    def __init__(self):
        """
        Init this agent
        """
        self.agent_core = ag()

    def set_map_info(self, size_x, size_y, detector_num, fighter_num):

        return self.agent_core.set_map_info(size_x, size_y, detector_num, fighter_num)

    def get_action(self, obs_dict, step_cnt):
        """
        get actions
        :param detector_obs_list:
        :param fighter_obs_list:
        :param joint_obs_dict:
        :param step_cnt:
        :return:
        """
        return self.agent_core.get_action(obs_dict, step_cnt)

    def get_obs_ind(self):
        return self.agent_core.get_obs_ind()


================================================
FILE: agent/fix_rule_no_att/agent_core.py
================================================
__pyarmor__(__name__, __file__, b'\xe7\x50\x8c\x64\x26\x42\xd6\x01\xb9\x4e\x3f\xdf\x40\x99\x74\xef\xb8\xc9\x91\x76\x3b\x40\xaa\xbe\x5d\xc5\xbd\x32\x0b\xf3\x42\x40\xe3\xce\x4f\x75\x5d\x9f\x4c\x04\x35\x6e\xf5\xb9\xdb\xfc\x44\xa8\x11\xd0\xdb\xb1\x0f\x62\xe2\x75\xc1\x38\x66\x9c\x65\x70\xe1\x0d\x2b\x57\x65\xd2\x85\x6d\x0e\x9d\xb5\x16\x6d\x19\x4c\x08\x05\x50\xe0\xd6\x28\xd8\xe5\x1b\x68\xb7\x96\xd4\x21\x0e\x87\x99\x7d\xc0\x18\x75\xb0\x67\x5d\x77\xba\xb0\xc6\xdf\x31\x69\x39\x6e\xca\xf0\x57\xec\xb8\x3a\xce\x56\xaf\x00\xa6\x55\x5c\x7e\xa5\x9a\xdd\x2a\xa9\x02\x64\x01\xd9\x77\x1a\x29\xd9\x74\xcf\x5b\x91\xc7\x0b\xda\xe7\xdc\x65\x49\x7c\x95\x35\x85\x75\x0c\x31\x79\x1a\x0e\xc3\x17\x86\x4d\xf0\x69\x33\x2f\x58\x15\x05\x13\x7b\xd9\x9a\x22\x0d\xce\x35\xad\x50\x98\xfc\x5d\x92\x7c\xbc\x4f\x9c\xe5\xf1\xb5\x08\x7f\x61\x2d\x11\x4f\xc9\x21\xd5\x96\x7b\x1b\x22\xeb\xe5\xd8\x44\x2f\x35\xa9\x76\x77\xaf\x82\xd0\xe9\x4f\x19\xe5\xe5\x90\x97\x8e\x68\xfa\x23\x61\xcc\xf0\x2f\x4b\x7a\xc4\x67\x87\x47\xd3\xf3\xf1\x87\x98\xb9\xcd\xea\xe2\x86\x45\x25\xda\xfb\xad\x72\x5f\x64\x27\x02\xb5\x28\xd5\x5e\xeb\x85\x6c\xcb\xed\xc7\x1c\xbb\x0d\x53\x03\xe1\x53\x57\x81\x56\x6b\x46\x8d\x6a\x78\xc6\x28\xcb\x0f\x12\x6f\x0b\x0f\xda\x71\x55\x4d\x6d\x91\x15\x10\x20\x55\x95\xca\x9d\xb5\x26\xda\x64\xfa\xb5\x4e\x11\xb2\x03\xaf\x3f\x38\x0c\x0a\x56\x47\x51\x1f\x89\x1a\x9f\xbc\x42\x90\x52\x98\xc4\x5f\x0e\x54\xeb\x6c\xa9\x11\x85\x6e\x19\x59\xae\x91\xcd\x33\x99\xc6\x0b\x53\x56\xd9\x72\xfe\x0b\x1a\xa7\xd5\xd8\xcc\x01\x7b\x78\x38\x8b\x49\xd1\x0a\xb9\xda\xe7\xbb\x9d\x0f\xc9\xdd\xda\x5b\xc5\x89\x36\x5d\x70\x09\x63\x35\xc0\x3f\xf5\x77\xbe\x32\xa2\xcf\x8e\xc6\xfc\x62\xf8\xe3\x63\xad\x47\x59\x99\xf7\x27\x5d\x7a\x56\x33\xa2\xb9\x64\xde\x6b\xeb\xe8\x04\x40\x14\x2b\xac\x68\x55\x62\xcc\x48\x36\x58\xad\xb4\x23\xc2\xfa\x26\xac\x49\xee\xca\xcc\xdf\x25\x4e\x99\xc9\x83\x31\x58\x5e\xfe\x30\xef\x4b\x78\xb2\x38\x13\x67\x43\x69\xb0\x75\xb3\x1b\xe6\x32\xbd\x42\xc0\x5b\x7b\x0e\x16\xc3\xfe\xb2\x23\xeb\xdd\x78\xa0\xde\x25\xf8\x4d\x43\xc9\xc8\xa9\x13\x5c\x50\x53\xb9\x2d\xc6\x67\x91\x42\x8e\x24\xde\xfe\x8c\x5e\x0a\x2a\x21\xab\xe2\xcc\x46\xea\x7d\x40\x6e\x83\xeb\xb4\x7b\xe0\x01\x37\x5b\x37\x05\xde\x71\xf2\x13\x13\x9c\x25\x23\x62\xa8\x27\x3f\x13\x4d\x65\xf8\x03\x33\xbb\xac\xc6\x56\x5b\x98\x1b\xc5\xac\xda\x3f\xbe\x25\xb8\xc9\xe9\x13\xb3\x29\x3c\x84\x52\x47\x74\xe2\x4d\x50\x73\xfc\xc1\xa3\x7e\xe1\x5e\xdb\x70\xce\xb0\x56\xe8\xc0\x0d\x40\x50\xf2\x60\x26\x92\xf8\x2c\x4a\xe5\xb8\xf2\xfb\x28\x84\x26\xb0\x4a\xc4\xf4\xa3\xd1\xc0\x37\xa1\xfa\x5a\x90\x20\xea\x23\xe9\xf5\xc5\xf3\xd5\x27\xe6\x1f\xab\xee\x90\xa5\x26\x11\x84\x5e\x1b\x37\x98\x6e\x89\x09\xa3\x49\xc8\xdb\x4c\x7e\x79\x8f\x00\x8a\x09\x80\xb4\x5b\xb4\x87\xef\xbb\x87\x99\x6f\x85\xc0\xfc\x24\xff\xe6\xfc\xc1\x4b\x78\x2e\x45\x7b\xe8\x4c\x96\x52\x1b\xdb\x38\x80\x64\xca\x35\x4b\x0b\x0c\xe1\xfb\x3f\x05\x3e\xac\xe7\x86\x44\x22\xa2\x14\x36\x60\x36\x9a\x8e\xe7\x83\xaa\xb1\x4f\xac\x54\x61\xb9\xcc\x4c\x01\x70\x79\x7b\x2a\x6c\xd8\xfd\xf9\xfd\x33\x49\x39\x13\x2b\xa2\xe2\x98\x29\x8e\xe6\x00\xe2\x20\xa6\x7b\x6e\x16\x14\x00\x61\x5c\xbf\xb4\x23\x79\xda\x3a\x6e\x72\xf7\x33\x83\x3a\x6e\xf2\x0a\x3d\xa0\x7a\x8b\xaa\x49\x40\xbe\x38\xeb\xe7\xae\x8a\x12\xad\x08\x69\x1b\x42\x78\x4c\x81\x7e\x23\x3e\xc3\xff\x3a\x33\xa1\x48\x14\xe7\xd2\x63\xb6\xa9\xff\x29\x34\x0a\xd9\x1c\x21\x32\xb9\x36\x72\x5d\x8c\x59\xc1\x75\xb9\x4a\xf9\x51\xf1\x47\x8a\x05\x4d\xe5\xca\x63\xce\xe2\x2f\x0e\xa7\x96\x02\x1d\x90\x6a\x11\x07\x98\x97\x2e\xcc\x00\x87\x6c\xf4\x0c\x87\x87\x77\xac\xa9\x8f\xb2\x2c\x51\x8f\xc1\x31\x6f\x1f\xb0\xe0\xfd\x4c\xcc\xc8\xa6\x36\xd1\x4d\x42\x90\x6d\x95\x4a\x73\x1b\x82\x72\xb1\xc4\x37\xac\xae\xf7\x6f\x76\xa3\x58\xe5\xf2\x9c\xfd\x51\xc8\x5d\x7c\x3e\x10\x79\xcd\x27\x3b\xa0\x95\x02\x5e\x91\xcf\x53\x55\x5d\x24\x0f\x0a\xaa\x4d\x58\x3c\x90\xc4\xfd\x31\xb0\xda\xc2\x62\xe0\x87\x8a\x0f\xa9\x5b\x3d\x1b\x46\xef\x14\x9a\xc0\x53\x92\x09\x0a\x99\x2e\x5e\xd8\x29\xe8\x7c\xde\x17\x71\x7e\xf7\xd0\xdd\xb9\x74\x1d\xd1\xf9\x20\xc9\x82\xa6\x73\x70\xf1\xbf\x33\x59\x0b\x18\x39\xc7\xa8\xb4\x55\x7c\x1f\x54\xa6\x0f\x0d\xb8\x6b\x01\x06\xbb\x93\xfb\xc9\xaa\xc2\x61\x1e\x64\xc2\x92\x9e\xf9\x48\xa4\x2b\x62\xe5\x58\x9d\x5b\x4f\xf6\x20\xab\x03\x2b\x9b\x22\x49\x61\x9a\x9a\x7d\x3d\x04\x4f\x58\xee\x07\x7a\xba\xf5\x32\x28\x47\xab\x99\xd1\x47\x88\x36\x76\xbd\xa2\xd5\xdc\xda\x93\x2f\x2a\xac\x15\x55\xff\x90\x8c\xf7\xdc\xf3\xff\x4a\x28\xef\x0e\x10\xe9\xc0\x13\x70\xa3\xb9\xef\x33\x00\xb8\x10\x27\x35\x89\xd5\x53\xc5\x8a\x65\xb8\x56\x44\xb1\x33\x1e\xce\xe8\xa9\x7d\x9f\x87\x35\x61\x72\x9c\x2f\x2a\x65\x2a\x9d\xad\x44\x3a\x20\xa2\x53\x8f\xd6\x9f\x8a\xab\xd4\x3c\xc5\xe8\x58\xff\xe5\x37\xb2\xcb\x5c\xa3\x50\xfc\x71\x6f\x59\x6a\x41\x26\xb9\x86\x77\x5b\x65\xf0\x3b\xc6\xb2\xca\x63\x10\x67\xb3\x54\x6c\x5d\x77\x8b\x17\xfd\x34\xc1\x48\xa9\x04\xc9\xeb\x08\xf6\xe0\xe4\x0f\xd8\xb6\x47\xe7\xe5\x5a\x0f\xc5\x86\xaf\xa8\xde\x49\x72\xc8\x9e\x74\x97\x32\xd0\x1d\x18\xb8\x41\xc6\x34\x15\x15\x9b\xd2\x37\xb8\xa0\xe4\x3e\x92\x44\xb7\xea\xb8\xb0\x06\x7a\xe8\x18\x9d\x94\xc5\xf0\x19\xd3\x8f\xa4\xb0\x8d\x87\x31\x31\x9f\xa5\x85\x24\x1b\x99\xe2\x7b\x31\xba\x3a\x63\x6a\xf4\xc8\xcb\x7e\x01\x05\x93\x00\xcb\x61\x42\x33\xa4\x6c\x89\x37\xf6\x8e\x8a\xf2\x72\xee\x9c\xd6\xdb\x58\x88\x16\xf2\x6f\x5e\x2b\x89\x57\x53\x2c\x4f\xf8\x85\x23\xd2\x88\xdf\x33\x34\x12\x49\x3c\x20\xf9\xa4\xf4\x4d\x2b\xa5\x33\x50\xf5\x5e\x19\xd6\x71\x11\x66\x0c\x3a\x9c\xed\x7b\xe7\xe1\xdc\xc5\x53\xb1\xdb\xbf\x1b\xf2\xc8\xa5\x4f\x41\x3d\x79\x88\x71\x2a\x08\xb4\xca\xd9\x22\xab\xf9\xfd\x59\xbb\x51\x28\x9a\xf9\x03\xa7\xfb\xf7\xdb\x91\x11\x4a\x58\xa6\xe5\xb6\x4a\xd6\xd9\xf4\x2f\xae\xdd\xf3\x53\x6f\xe0\x3d\xa3\x48\x4d\x96\xdb\x9b\xfe\x76\x23\xd3\xac\xe4\x4e\x1c\x90\xb8\x54\x5e\xea\x90\xb8\xc7\xad\x43\x00\x9d\xe4\x1d\x6d\x3d\xb5\x7d\xf6\xc7\xc5\xe5\x82\xb1\xa0\x97\xc0\x96\x5f\x39\x70\x20\x11\xc8\x73\x97\x1a\x8e\x06\x44\xd1\x5a\x02\x3f\x92\x86\x26\x1f\xff\x69\x89\xc6\x5a\x34\x47\x9c\xf9\xd0\xdc\x6c\xe7\x6a\x47\x1b\x3e\x79\xbb\x57\xbe\x5b\x3a\x22\x43\x1d\x29\xe8\x56\x23\x33\x2e\xd6\x3c\xb1\xa5\x16\xc3\x68\x44\x2d\xfd\x40\xd3\x44\x0b\x09\xa1\x06\x5d\x06\x8a\xea\x4d\xc0\xe5\x02\xc1\xf1\x21\xe4\x4d\xd1\x0f\x1d\xc1\x82\xcb\xdf\x87\x62\xf4\xfe\x64\xa5\xcc\x1c\xb6\x23\x94\x74\xaa\x49\x61\x8f\x9f\x5f\x9c\x28\xb5\x57\x2c\x34\xf3\x62\x47\x51\xad\xed\xd6\x67\x34\x2a\x44\x88\xde\xce\x19\x8c\xc2\x02\x2d\x7f\x2a\x76\xb6\x9d\xb6\x33\x77\xb5\x88\x1c\x8f\xa9\x4b\xc3\x35\xe9\xc8\x10\x69\xfd\x13\x19\x54\x82\xfe\xd1\x83\x47\x5e\xb4\xa3\x14\xfc\xcb\xfe\xcd\x01\xa8\x67\x37\x50\x64\x43\x0f\x0c\x4e\x69\xf3\x48\x02\xf8\xcd\xec\x3c\x34\x01\xa6\x30\x36\xf5\x05\xc9\x4f\x23\x1e\x05\xea\x3d\x2a\x55\xd6\xbc\xe9\xff\x37\x77\xa0\x3b\xb4\x2d\x37\x02\x8b\xd2\x56\xaa\xd9\xea\x3b\xd5\x32\xf1\x1e\x7a\x9b\x49\x1b\x2b\xf2\x03\xcb\x3a\xbf\x4b\x50\x01\x6f\xff\x40\x08\x20\xe9\x3e\x45\xd4\xa2\xb0\xd0\x98\x2c\xb4\x7e\xd0\x22\xfa\x5b\x98\xd7\x67\x90\xa3\xfb\x74\x7c\x2f\xea\xe4\x06\x6e\xb0\xbb\x9f\x6e\x54\x66\x2c\xd3\x69\xac\xb3\xd7\x71\xa8\x5d\xfa\x51\x33\x64\x98\x51\xf5\x52\xd9\xcf\xe7\xc2\x41\xde\xc3\x5c\xf1\x5c\x26\x37\x8f\xeb\xba\x7e\x07\xe0\x08\xb6\x6f\x9a\x89\x97\x1f\xd4\x77\x8a\x71\x69\x08\xd2\xd6\xbd\x61\xe8\x69\x57\x84\x54\x13\xdf\x05\x3f\x62\x61\x25\xf2\x1a\x76\x31\x38\x51\xd3\x33\xdc\x08\x12\x56\xb1\x36\x5d\x9c\xcc\x35\xd7\x4c\xc2\x52\x57\x80\xbd\x19\xe6\x98\x60\x16\xb1\xd9\x28\x03\x47\xb6\xa8\x6c\x9c\xab\xf5\x6d\x41\x36\x18\x90\xe8\x56\x1b\x23\x92\xba\x2c\x11\x3e\x9d\x26\x0b\x99\xce\x0b\x65\x63\xb8\xba\x92\xf6\x1e\xbf\xd4\xdd\x2b\x52\x7a\x34\x41\x59\xa9\x48\x98\x79\xe3\xf0\xd1\xdd\x0b\x10\x03\x5f\x76\x8d\x09\xf8\xc3\x64\x76\x82\xd6\x2d\xd9\xfc\x9d\x4a\x29\xa9\xf0\xd4\xb6\xd0\xab\x78\xf4\xc7\x64\x7d\xd0\x6d\xba\x3a\xb1\xe5\xac\xea\x95\x9d\x9f\x8f\x36\x20\x1d\x78\x0d\x7e\x97\xca\xaf\x8c\x1d\xb2\x33\xde\x52\xd2\xf7\xf6\xf3\xed\x97\x88\xc8\xb6\x81\xca\xb9\x55\x3e\x7f\x93\xca\xe5\x71\x9c\x97\x9e\x2c\xfa\xed\x98\x18\xb0\x2e\xf6\x4e\xec\x9d\xac\xe1\x15\xd5\x70\xb2\x7f\xe0\xc8\x5a\x4e\xb2\x3c\x39\xd8\x93\x4a\x36\xca\x0a\x20\x18\x11\xab\x76\x3a\xcf\x00\x79\x0a\xe0\xf9\x73\xbf\x5c\xd7\xf1\xda\xa3\x55\x21\xfb\x58\x61\xcc\xd0\x32\x11\x4f\xb0\x7a\x3c\xab\xbb\x3b\x49\xff\xe1\x3b\x21\x51\x16\xa1\xe6\x65\x9e\x7b\xc6\x09\xb2\xf9\xdf\x78\xe6\x00\x86\xbe\xda\x60\xbc\x82\x9c\xe8\x03\xc6\x79\xf3\x47\x3b\x36\xec\xcf\xf6\x0c\xeb\x85\x14\x6d\x20\x8a\x5d\x1a\x63\xb9\x4f\x56\x19\x46\xd5\xf9\x42\x6a\x89\x4c\xbe\x91\x9d\xf3\x83\x6d\x02\xee\x2c\xe3\x49\x50\xa2\xbe\x77\xf3\x64\x43\x1f\xdc\x67\x89\x28\x96\x2a\x0a\x6a\x23\x77\x44\xfd\x2f\x6e\xe0\x05\xca\x3d\x39\xfb\x9e\x98\xd8\xee\x7c\xf5\xf7\xf3\x34\x84\x7b\xb9\xf8\xac\x57\x41\x57\x16\x8b\x0b\x56\x15\x2b\xad\x4f\xc3\xb9\xce\x7b\x31\x6c\xca\xad\xf9\x08\x1b\x5e\xa5\x4d\xcd\x16\xbb\x85\x87\x20\xce\xa9\x42\xd4\x7f\x2b\x4b\xd8\x9c\xef\x9a\x87\xb5\xf9\x0d\xf0\xdb\xc0\x43\xa1\x7e\x1c\x8e\xe2\x01\xea\x28\xda\xd3\x6e\xcb\x9b\x5d\x6d\xde\x56\x21\x37\x8e\x7b\x8a\x4a\x7d\x1e\x2f\x1a\xf0\x77\x62\xaa\xc4\x34\x57\xc8\xdc\xdc\xa3\x4e\xb4\x97\x40\x22\xfb\x2c\x9e\x0c\x58\xfb\x98\xbb\x08\x46\xea\x05\x2f\x26\xcf\x3d\xf9\xfa\xc2\x9a\xed\xf9\xfd\xc5\x4c\x95\xe9\xc2\xd1\x5b\x00\x6e\xd3\xc0\xdd\xed\xcf\x53\xcb\x06\x54\x13\x24\x5b\x62\xcc\x71\xe4\x69\xf5\x9b\x8f\x7f\xd3\x3a\xf3\x86\x89\x7a\x6f\x68\x4e\x37\x6d\x6b\xee\x2d\x91\x2e\xd9\xf7\x2d\x7b\x23\x64\x36\xfd\x40\x9f\x6e\xf3\xdf\x55\x86\x57\xd1\x9e\x92\x8b\x15\xf1\xa2\xb1\x12\x4d\xe4\xe1\x02\xa3\x70\xd1\xf6\x45\x2b\xdc\x72\x9f\x69\x19\xb8\xff\x1b\x55\x27\xe7\x66\x1b\xa7\x48\xac\x23\x3e\xe4\x03\x29\x89\x0f\x33\x2d\xab\x9e\x2a\x66\xb0\xf3\x22\x4a\xbc\x59\x76\x42\xf9\x2e\x41\x02\x56\x2a\xbe\xfe\x25\x63\x4a\xcb\xed\x80\x5b\x80\xfd\xd0\xfc\x3d\xf7\xa4\x48\xa4\x89\x51\xf2\xbd\x6e\x8b\x9b\xe2\xd5\xe3\x14\xef\x98\xa1\x01\x72\x57\xbb\xe4\x71\x22\x97\xd0\x99\x0b\x8e\x51\x5c\x6b\xfd\xeb\x0f\x9d\x55\x4e\x33\xde\x24\x80\x35\x68\x67\x44\x8d\x17\xc7\xec\xb3\x7a\xe9\x4d\x53\x6e\x83\x1e\x8d\xc3\x3b\x29\x4a\x34\xb0\xca\xea\xbe\x10\xe7\x6d\x07\xaa\xf8\xf8\x43\x0a\x93\x0a\xfb\xde\x9e\x9a\xd4\x2b\x35\xaa\x7c\x54\x19\x4a\xde\xc3\xd7\x76\x59\xc1\x04\xad\xdb\x51\x6d\x47\x12\x62\xe9\xee\xd6\x86\x5e\x52\x1a\xa2\xcb\x88\xfd\x96\xdf\xbf\x54\xc0\x32\x70\x3a\x80\x76\x5c\xb5\x29\x26\xc8\x61\xe3\x6b\xed\x31\xb4\x33\x78\x23\x68\xbf\xad\x45\x5b\x98\x43\xbd\x93\x25\xd7\x43\x79\x08\x5d\xaf\x92\x28\x25\x62\xe9\x63\x8f\x78\x6f\xfc\xb0\xfa\x64\x8e\x9e\xf6\x06\xb6\xd4\xa5\xcc\x97\x53\xba\x62\xf0\x41\x06\xc0\xf2\x42\x45\x86\x25\xa8\x5c\xb1\xae\x13\x77\xde\x13\xf4\x30\x5a\x38\xfd\x98\xe7\x56\x28\x5c\x61\x56\x1d\x50\xbd\xd4\x4a\xe3\xaa\xeb\xce\xda\xc4\xc7\xe7\xb1\x46\x94\x2c\x51\x66\x99\x8a\xdc\xc1\x1e\xc3\xeb\xf4\xe1\xfa\x65\x3d\x23\x0c\xd2\x37\xdb\x93\x7a\xa1\x65\xc5\x17\x56\xc3\x8e\x84\x4b\x1c\x6a\x85\x83\x77\x6d\x4a\xe3\x39\x93\x0a\xce\x69\xbf\x64\x41\xfa\xf4\xbf\x2b\x92\x9c\xe0\x8a\xab\xab\x7c\x0f\xdc\xf6\x36\xe7\xaa\xbb\x11\x41\x6e\xfb\x80\x1d\xb8\x39\xa4\xea\x69\x38\xc9\x7e\xe1\xcc\xa0\x1a\xd5\xbf\x04\x65\xde\x1c\x06\x26\x8b\xfa\x82\xe4\xb0\x5e\x47\x53\x6d\xe8\xc5\x25\xde\xb8\x6f\x07\x4d\x21\xc7\x64\xb7\x57\xd2\xfd\x7b\xf0\xc1\x35\x59\xbe\xa1\x5b\xcd\xcf\xed\xac\x88\x0e\x69\xf5\xaa\x13\x88\x08\xac\x1d\x3a\xd5\x69\x4c\x22\x78\xe9\x3a\x11\x8e\x2c\x9c\x2d\xae\x9c\xed\xb1\x55\xe8\x14\x69\x44\xe1\x93\x25\x81\x5f\xe4\x1e\x93\xa9\x7f\x38\xad\xe5\xb5\x62\x28\xa7\x82\xf3\x77\x44\xe3\x41\xd9\x91\x59\x10\xac\xe7\xf3\xbc\xd3\xe4\x61\xcd\xa7\xb6\xfc\x60\x69\xf0\x89\x8e\x86\x48\x68\xc2\x72\x9b\xbc\xfc\x17\x53\xad\x40\x90\x30\xce\x8f\xe3\x88\xea\x16\x6b\xbd\xd8\xdc\x08\xe6\x37\xe1\x04\x29\xb6\x2a\xa9\xe5\x88\xa1\x5b\x09\x2e\x07\x64\x48\xc8\x35\x32\x07\x64\x7f\x87\x2c\x45\x46\xa1\x96\xa2\x3c\x8a\xcf\x2c\xb9\x2a\x83\x16\x87\x94\x9b\xc1\x38\x3a\x9b\x1c\x17\xfa\x34\x3a\x94\x47\x93\x3e\x0f\x08\xac\xb6\x64\x6a\x82\xa6\x75\x0f\xda\x44\xcf\xaa\x24\x34\xa6\xd7\x95\x67\x62\x19\xb1\x4d\x9a\xdb\x8c\xfd\x87\xca\xf9\x63\x8f\x32\x97\xb1\xe1\x96\x88\x25\xab\xf9\x7b\x24\x46\x0f\xe8\x8c\x95\x84\x0d\x64\x66\xb1\x4f\x31\xe6\xc0\x5f\x43\x5a\x30\x5e\x2c\xb1\xc8\x72\x8c\x29\xc7\xa4\x74\x41\x95\xd5\xad\x3b\x50\x28\x75\xe7\x70\x5e\xd8\x61\x4f\xff\x05\x77\x01\x1f\x31\xe9\x53\xfb\x1c\x6e\xcc\x18\xdc\x7b\x03\x8c\x29\x03\x55\xa1\x24\xbc\x80\x3e\xa0\xb6\xa8\x0d\xd2\x7f\x20\x3f\x19\x3e\x09\xdc\x19\x01\xa4\x4a\xe6\x07\x8e\x5e\xaa\xdf\x05\x2a\xe0\xc7\x56\xb9\x55\x00\x85\x9a\x21\x8d\xb7\x5a\x14\x08\x0e\xf0\x4b\xaa\xf9\x8a\x57\x77\x2d\x4a\x7c\x1c\x02\x27\x3a\xd5\x15\x89\xb6\x11\x47\x9d\x62\x88\xeb\x97\x7f\x54\xa4\xe6\x3f\x3b\xa4\x37\x61\xef\x97\xd7\x05\x63\xb4\xc3\xb4\x72\xae\x35\x24\x52\x23\x6c\xcf\xc8\x57\x17\xf4\xbc\x20\xde\x43\x74\x8b\x2c\x41\xf2\x68\x74\x64\xbe\x9c\x64\xe1\x93\x48\x5c\x65\xd7\x7e\x07\x46\xd0\xce\xfc\xf9\x2d\xf4\x03\x80\xbc\xe8\x41\x44\x97\xed\x72\x13\x09\xd6\x70\x84\x23\xe7\x1c\x44\x28\x56\x7c\x2e\xb6\xdc\x68\xe3\x4f\x15\x4c\xa1\x66\x03\x72\xa0\x6f\xb0\x34\x50\xba\x16\x33\xef\xed\x79\x70\xea\x20\x1e\xad\x7b\x33\x98\x4b\xd4\x18\x40\xdb\x13\x7b\xdf\x43\x0a\x52\xaa\xae\x00\x64\xa5\x04\xe6\xbc\x70\x8e\xf1\xd2\xbb\x50\x1c\x1e\x1d\x4b\xdc\x6c\x68\x66\x0f\x3c\x5a\xa2\x75\x92\xb3\x94\xc9\x22\xfb\x58\x17\xf6\x69\x28\xed\x6e\x99\xab\x4c\x74\x6e\x22\x1e\xf0\x2a\x40\x4a\xe9\x8f\xd8\xfa\x90\xca\x90\xcf\x1b\xe2\x82\xd4\x93\x18\x58\xdc\x4e\xb5\x12\x78\xed\xf0\xd1\x6b\x0d\xd7\x7d\xd1\x78\x53\xcb\x29\x21\x40\xa4\x2a\xcc\x72\x65\x43\x6a\xf5\x5e\x7d\xd2\xa2\xcd\x7e\xa7\x9f\xae\x44\x43\x1b\xbf\x2e\x10\x94\x4b\xf5\xca\x47\xb3\x82\xef\x1c\xb3\x28\x1a\xcd\x45\x13\x4a\x58\x10\x2f\x4e\x62\x1e\x3d\xcf\xc9\x13\x43\x0c\xdb\x0b\x8c\x44\x9e\xdb\x54\x50\x26\xb1\x87\x6c\x68\x46\x73\xa2\xb3\xf7\x99\xf7\xa5\x01\x3b\x13\xe2\x5a\xe4\xa3\x6b\x3d\xd8\x13\xb3\xa9\x73\xc8\x2e\xf0\xe4\xd2\x75\x83\xa6\xc3\xfd\xd6\x15\xde\x6b\x93\xda\x4e\x88\xd8\x8a\xa8\x5c\xbe\x45\xcc\x8d\x54\xcb\xa3\x0d\x9b\x89\x5f\x53\xd7\xb2\x5c\x6a\xb3\x04\x51\x5e\x9a\x52\xab\xa4\x02\x1f\x18\xca\x1b\x6e\x38\x62\x1b\xbb\x65\x6b\xf3\xf9\x0b\x6d\xa4\x8e\x23\x1b\xd9\xe1\xf7\xcb\x44\x55\xb5\xa7\xb0\xed\x1e\x68\x84\x1d\x69\x38\x31\x27\x94\x59\x72\x4f\xeb\x2b\x4b\x88\xea\x26\x62\x5f\x6b\x2d\x93\x6d\xd9\xca\xbe\xa7\x27\xc4\x8a\xba\xfd\xd4\x58\xe0\x51\x1f\x76\xda\x95\x53\x3e\xf5\x58\xea\xd3\x8c\x1a\x9e\x5f\xc1\xf7\x49\xd6\x1e\x56\x2e\xe1\x2a\x4a\x83\xa6\x64\x52\x0b\x1e\xd3\xe3\x98\xee\x32\x07\x49\x68\xc9\x6d\xc9\x06\x4b\xe8\xb6\x1d\xc7\x38\x22\xec\x65\x3b\x43\xfc\xef\x79\xc8\x9b\x80\xb1\x33\x7d\x94\x34\xbc\xeb\x03\x8b\xf4\x98\x52\x3d\x8b\x02\xf1\xf6\x23\x75\x6a\xb6\xec\x8f\x73\xd3\x71\x86\xf6\xa7\x3b\x86\xd5\x02\xa1\x75\xfd\x7c\x9c\x11\xe4\xab\xb4\xd6\xbb\xc5\xe4\xdc\x85\xec\x6b\xed\x25\xff\xec\xa9\x54\xd9\xe4\xa8\x5f\xd7\x00\x7f\xc0\xbe\xdb\x4b\x66\x0c\x0e\x78\xbd\xa5\x69\x6b\x17\x62\xc3\x2f\x58\x08\x27\x8d\x7e\xaa\x0e\x6d\xe9\xc7\xa4\xc0\xf6\x95\x0a\xe2\x4a\x17\xba\x70\x9c\x69\xa6\xf8\xb0\x07\xcc\xa7\xb6\x3c\x4e\x02\xff\xc6\xb8\x15\x52\xfa\x19\x06\x14\x9a\x50\x50\x52\x37\xe4\xa2\x5c\x25\xf4\x5d\x01\xb8\xf0\xee\x7d\xe5\x37\xcc\xac\xd8\x12\x92\x1e\x78\x69\x45\xc2\xd5\x43\xfa\xd3\xd6\x64\x81\x60\x60\x5f\xe6\x4f\xc9\xe0\x5f\x5a\xbd\x07\xa0\xb9\x22\x89\x21\x0b\x3c\x75\xcc\xa9\x49\x63\x09\x83\xf2\xe3\x4f\x9c\x29\x85\x66\xd2\xd9\x50\x82\x15\xe7\x59\x23\x46\xa5\xdc\x3b\xaa\x35\x37\xb3\x9f\x3c\x7f\x91\xb4\x52\x4a\xa1\xa8\xf6\xc4\xa8\x93\xa1\x8b\xc9\x9a\x8b\x71\xfd\x42\x7c\xbb\x98\xe6\xa5\xad\x76\xb0\x31\x06\xa0\x5a\x21\xf0\x00\x1d\x5c\xd7\x05\xe4\xc0\x1b\x62\x94\xaa\x94\x66\x7a\x06\x5c\x5e\x02\x7d\x91\x1d\xe2\xc8\xb2\x7f\x8f\xf2\xb0\xcb\x2f\xb5\x3a\x6c\xed\x98\x36\x00\x0b\x69\x61\xe4\x2d\x7a\x3f\xde\x7e\x90\x84\x17\x49\x88\x7e\xbe\x94\xdc\x13\x3f\xaf\x82\xec\x70\x5d\x3a\xd1\xf6\x6a\xd4\x61\xc4\x66\x5d\xaf\xc7\xfc\xe1\x37\x9d\xe5\x5b\xea\xdf\xe7\x66\xfe\xd2\x25\x86\xdb\xfb\xa9\xe2\xe4\x17\x36\x42\xa6\x72\x89\x92\xfb\x03\x01\xe1\xef\x62\x06\xfe\x0c\xa5\x79\xd9\x88\x4c\x28\x9b\xbf\x97\x48\xc5\x04\xac\xce\x47\xc0\x54\x22\xda\xcc\x90\xa6\x11\x86\xd6\x50\x39\xaa\x94\x3f\x66\xf6\x98\xd4\xe0\x46\xf6\x27\x72\x14\x1f\xbe\x8f\x24\xde\xcf\x81\x88\x1e\x19\x45\x00\x63\xc2\xf8\x76\x43\x1c\xf9\x8a\xa4\xc6\xa5\x47\x00\x0f\xd1\x2a\x07\x42\xa2\xfb\xa2\xad\x69\xfd\x27\x39\xa1\xfc\xec\xcc\x1e\x24\x7e\x15\xc0\xe1\x7e\x73\x80\x73\x8c\x39\x95\x9c\xad\xc0\x4c\xac\x99\x0b\x11\x38\xa4\x17\x9b\xf4\x63\xcf\x9f\x41\xdd\x89\x0a\xbc\x10\xd0\x4e\x6f\x2e\xc8\xbc\x3b\x75\x65\x33\xa0\xbc\x97\x78\x2f\x63\x59\xd6\x15\x64\x97\x57\x18\xad\x0f\x11\x34\x3e\x06\xef\x97\xf0\x4d\xec\x53\x60\x0d\xea\x43\x20\xd7\xce\xd6\x60\x94\x80\xbc\xe9\x15\x5a\x20\xbb\x85\xe6\x62\xe6\xb5\x98\x05\x35\xe4\xc6\xed\x5a\x0d\xb4\xd4\x97\x9e\x02\x24\x30\x94\x87\xad\xf1\xac\x5e\x18\x4c\x0a\x77\x5b\xf7\xb5\x0a\xf0\xa3\xfe\x18\xfe\x07\x6d\x11\x79\x26\x10\x7f\x1e\x63\x84\x71\x7b\xc9\xc2\x36\xf6\xcc\x93\x24\xe2\x3e\x26\xb6\x55\xda\xa4\xf1\xb4\x21\x38\x60\x8f\x80\x9c\x64\x23\xdc\xf8\xaa\x9f\x01\x39\xce\x94\xad\x42\x31\x9d\xa6\x12\x2d\xba\x66\x00\x1c\xe2\x8e\xbf\xc4\x1c\x4b\xa8\x0d\x74\x63\x1a\xd3\x08\x76\xe9\x4f\x23\x91\x2d\xb4\xb4\x77\xaa\xae\x55\xd6\xb6\x64\x68\x96\xb9\xcb\x43\x85\x7e\x71\x2d\x14\x59\x13\xa5\xca\xf0\xad\x56\x04\x5f\x99\x6e\x63\x1f\x5b\x34\xf9\xd0\x38\x47\x79\x15\x5a\xb3\x59\x45\x5f\x0e\xfd\xde\x8b\x0f\x2f\x88\xd8\xeb\x16\xd0\xaf\xa3\x6a\x67\x0a\x47\x6c\x81\x02\x5b\xc1\x15\xde\x7d\xc4\x99\xf2\x6e\x2d\xfc\x11\x8b\x13\x38\xbe\xdf\x50\xdd\xe0\x44\x35\xbd\x25\x62\xaf\x87\xb5\x47\x1e\x95\x1b\xff\x1e\xa0\x91\x99\x13\xf0\x1e\x34\xc7\xdf\x48\xe7\x16\x1d\xbf\xed\x31\x4c\x77\x76\xb6\xf5\xa7\x56\x61\xe5\xa1\xe8\x15\xbf\xdd\x9e\x91\x6c\xf6\x07\x82\x06\xd1\x35\x25\x57\x8b\xf4\xaf\xef\x3e\xb3\x31\x57\x04\xe4\xf5\x67\x36\xba\x81\xcd\x0a\x8d\x0a\xe4\xb9\xdf\x0b\x84\x2c\x42\x39\xfa\xec\x37\x6f\xa0\x5e\x0e\x83\xee\xe2\x17\x5e\xb4\x17\x23\x0b\xc7\x6a\x48\x4d\x0b\x04\xf0\xbe\xf7\x6f\xa3\x16\x8e\xe6\x0b\x87\x18\x5e\x70\x75\xad\xc0\xc5\xe7\x3d\x89\xc8\xd0\xcd\xfd\xf4\x3e\xa9\xeb\x68\xb5\x04\x30\x7b\x8a\x2e\xa3\x11\x1b\x53\x8f\xb2\x19\x0a\x54\x55\xda\xbb\xec\x7a\x85\xff\xac\x60\xa4\x65\x26\xbf\x8e\x48\xd7\x36\x72\x2d\xcb\xb2\x3f\x18\x1e\xe9\x5e\xfc\x60\x5c\x5e\x98\x2f\xee\x9a\xa7\x91\xe8\xcd\x21\xad\x85\xea\xd4\x3b\x8e\xb2\xb5\x60\xd1\x23\x62\xbc\x2e\xe1\xfd\x6e\x74\x84\x84\x73\xca\x64\x68\x85\x16\xbb\x13\xe2\x4d\x33\xae\x79\x29\x3e\xbc\xa7\x9c\x21\xce\xdf\x6c\xb4\x24\x13\xc1\x82\xcc\xfd\x38\x1c\x85\x6d\x03\x87\x9a\x7b\x3c\x57\x0f\x18\xbe\xf8\xfb\xd0\xa7\x9b\xbb\x55\x7e\xaf\xc3\x7f\xfa\x50\x87\x9a\x60\xc7\x57\x60\x26\x14\x4d\xe7\x7c\x51\x23\xfa\x4c\x5d\x4d\x6d\xf2\xbd\xfd\xfe\x34\x9d\xba\x8f\xde\x71\x99\x27\x61\x80\x57\x33\xde\xce\xfb\xe9\x5f\x92\xba\xb5\xad\x40\xd4\x70\x8d\xb5\x04\xea\x22\xfb\x5b\x98\x2b\x66\x5c\xa4\x8e\x7f\x16\xfe\x90\x29\xa9\xce\x73\xdd\x14\x23\x25\x46\xf2\xbd\x11\x2f\x6d\x9a\x24\xfe\x6d\x09\x02\x96\x86\x4e\x99\x4c\x8c\xdf\xeb\xe9\x10\x55\x0d\xad\x94\xe8\x18\xc3\x41\x22\xa9\xcf\xf5\x9c\xb9\x08\xcf\xf0\x24\x2a\x2a\x4b\x8e\xb0\x8b\x8c\x71\x38\x30\x6a\x84\x14\x60\x73\x90\x20\x0c\x63\xae\x80\x4a\x6f\xef\x2d\xcd\x5e\xe4\x79\x81\x40\x4b\x2c\x70\xe4\x76\xfe\xe0\x74\x61\x71\x72\xed\xd4\xeb\x15\x77\x8a\x5d\xca\x8e\x30\x54\xf8\x67\xcf\xe1\x60\x5a\x7d\x71\x4c\xa3\xde\xd5\x5a\x7d\xc0\x02\x79\xbe\x1c\x6e\xe2\x0a\x10\xb1\xf3\x8a\xe4\x8a\xaa\xce\x13\xc2\xb9\xb5\xa1\x67\x6b\x8e\xae\x3f\xa6\x6d\x52\x0e\xed\x50\x93\x2f\x7b\x81\x84\x04\x6a\x7d\x15\xd2\xf7\xeb\xf6\xfd\xad\x69\x57\x16\x17\xaf\x74\x9b\x0b\x78\xa1\x8d\x3f\x0e\x28\xf8\x4b\x08\x08\xa9\x3f\x05\x1d\xec\xc8\x88\xfc\xa9\x56\xaa\x81\x51\x11\x4c\x45\x89\xe6\x3a\xd3\x78\xc2\xad\xb2\xfc\xd0\x7a\xf0\xa9\x3a\xb5\x34\x5b\xf0\x12\x31\x91\xba\xa0\xac\x23\x6d\x34\xc4\x91\xf1\xec\x57\x39\xba\x92\x31\x5b\xfb\xe5\x87\x9f\xa9\xed\x98\x2d\x86\x6b\xc3\xee\x01\x90\x9b\xbd\xe2\xf1\x79\x12\x16\x90\xe6\x4d\x16\x6b\x8e\xd8\x66\xf1\x0c\xa0\x53\xb9\x7c\xc6\xd2\x1f\x7a\xff\xe5\xc4\x0c\x64\x5f\xe0\x3e\x6e\x26\xac\xe8\x2a\x08\x88\x6c\x9e\x39\xaf\x70\xf8\x80\xbf\x3e\xb8\x64\xb0\xc9\x40\x7a\x7c\xa4\xaa\xc3\xf3\xfc\xfd\x96\x69\x3e\xdb\xec\x56\x11\x11\x41\xd0\x53\x0e\xf3\xfe\x93\xba\x5c\x44\x49\xaf\x60\xa2\xb3\x93\x40\xd6\x95\x7b\x74\x92\x98\x69\x7f\xfe\x62\x9e\x6b\x23\xd3\x10\xab\x3b\x76\xc3\xd3\xf0\x42\x3c\xfe\xcf\x18\x3a\x05\x42\x15\xb1\x8d\x2c\x8a\x7d\x4f\x31\x77\x14\xcd\x5b\xe5\xb7\x99\xff\x61\xdf\xf5\x1d\x1d\xde\x55\x1b\xd9\x35\xf5\xde\xd2\xb2\xa1\xb0\x1d\xd7\xa3\xd9\x96\xd9\x66\xbb\xc0\x04\x1b\x00\x3d\x77\x3b\x01\x21\x75\xfd\x93\x59\xe8\xba\x4e\x11\x07\x3b\xd8\xe6\x3d\x6d\x59\xc3\x20\xf7\xfb\xdb\xa0\x90\x41\x61\x66\xf1\x15\x3f\x9e\xcc\x58\x32\x89\xd5\x60\x9d\xc2\xf5\xcc\xdc\x69\xec\xc2\x3d\xa4\x03\x05\x34\xab\x4a\x20\xd9\x5c\x6e\xe7\x49\xe3\xf5\x04\x81\x63\x28\x30\x32\x8d\xd8\x59\xff\x97\xfe\x33\xbe\x13\xd9\x9e\x75\x57\x29\x29\xf1\x06\x53\xc8\x38\x0e\x3f\x0c\xd8\x83\x66\x38\xd2\x5d\x7a\x29\xea\x53\xba\x33\x39\x75\xf4\xaa\x1a\x6f\xca\x18\x89\xfc\x7a\xb6\x80\xfc\xa1\x03\x58\x8b\xe5\x86\xa2\x15\x8f\xd1\x4e\x5e\xf8\x9d\x10\xe6\x34\x27\xcb\xb8\xcc\xd5\x88\x5c\xad\xaf\x19\x45\x47\xb3\x54\x90\xcb\xa8\x68\xd8\xb9\x2d\xd8\x02\x34\x12\xe4\xe7\x82\x6b\x23\xe2\xcf\xb9\xfe\x76\x25\x6e\xb4\x52\x99\x9d\xba\x98\xec\x0b\xc2\x83\x7b\x47\x8d\x0b\x0b\x01\x7c\xce\x2d\xf4\x80\x57\xeb\xb7\x56\xe0\x0a\x52\xfd\xf4\x2f\xb9\x50\xfc\x5c\x78\xd3\x64\x45\x69\xc2\xc7\x75\xf2\x03\x27\xc4\x52\xd1\xa7\x68\xc0\xb4\xc0\x25\x46\x97\x57\x7e\xde\xaa\x7f\x33\xfd\xc7\xbd\x7c\x36\xc6\xe3\x32\x1e\x73\x2b\x0f\x8e\x21\x12\x8f\x64\x17\x16\xa7\x1a\x74\x7a\xbe\x30\x6c\x58\x6e\xbe\x92\x80\x6e\x46\x28\xd1\x81\x30\x9c\x59\x50\x0a\x91\x19\x43\x29\x12\xb2\x89\x62\xf3\x60\x4a\xcf\xe5\x61\x60\x27\x18\xed\x49\x7d\x32\x05\x57\x9d\xe6\x4a\xa6\xd7\x2a\x86\x04\xf1\x82\x53\x32\x32\x8b\xf6\x2e\x2a\xf7\x7e\xde\xe2\xea\x34\xb4\x84\xe1\xcb\xee\xef\xa5\xd6\x0c\x50\x9a\x5d\x40\x94\x8e\x62\x90\x81\x38\x39\xaf\xa3\xb9\x41\x73\x1e\xec\xf5\xef\xbc\x43\xfc\xca\xae\x1b\x04\x60\xd4\x1d\xed\x79\x47\x06\xec\x86\x12\x20\x33\xb4\xb1\x24\x34\x61\x5d\x48\x5b\x57\x53\xb3\xc3\x9f\x37\xdf\x28\xac\x4e\x55\xe4\x60\x2f\xec\xe6\xf6\x55\x72\xd4\x01\x22\xdb\xfe\x48\xc0\x3d\x5a\x4b', 1)

================================================
FILE: agent/fix_rule_no_att/license.lic
================================================
HSpGTEFHUzoBKkNPREU6UHlhcm1vci1Qcm9qZWN0egMhJ6NNlQdmKa/iVehg0LovCYkZYgMtBOQo6jHlP0slLc0iYjbS9NAnZQslmFBVRWO6JERZBMANwGUlKeAdkFUMv/8JT6WquK7BFnlYcPnuhV6z5zP2O/hWCaJzDGRL4pWU7A1javZizykc2gPVHAnWW1cvuMMbeNlS2tMSCeo=

================================================
FILE: agent/fix_rule_no_att/product.key
================================================
Bې?CAk8a6WH0vY
y

}q#fRq+JBwzʱnƐS*TE`wN(RGy0tD&y
P:Cq\8SBV]

================================================
FILE: agent/fix_rule_no_att/pytransform.py
================================================
# Because ctypes is new from Python 2.5, so pytransform doesn't work
# before Python 2.5
#
from ctypes import cdll, c_char, c_char_p, c_int, c_void_p, \
                   pythonapi, py_object, PYFUNCTYPE
from ctypes.util import find_library

import os
import sys
import platform
import struct

#
# Global
#
_pytransform = None
_get_error_msg = None

#
# Options
#

# How to show error message return from dynamic library _pytransform.
#
# Each time call a dll function, if something is wrong, _get_error_msg
# will return the reason.
#
# Enable _verbose_mode will print the details got from _get_error_msg.
# Disable this options will print only a short message.
_verbose_mode = 1

# In debug mode, print trace stack when raise exception.
# Otherwise only show a short message.
#
# Run python with command option "-d", or set environment variable
# PYTHONDEBUG. For example
#
#   python -d pyarmor.py xxxx
#
_debug_mode = sys.flags.debug

class PytransformError(Exception):
    def __init__(self, *args, **kwargs):
        super(Exception, self).__init__(*args, **kwargs)
        if _debug_mode:
            self._print_stack()

    @classmethod
    def _print_stack(self):
        try:
            from traceback import print_stack
        except Exception:
            _debug_mode = 0
            sys.stderr.write('Disabled debug mode.\n')
        else:
            print_stack()

def dllmethod(func):
    def format_message(msg, *args, **kwargs):
        if _verbose_mode:
            s1 = str(args)[:-1]
            s2 = ', '.join(['%s=%s' % (k, repr(v)) for k, v in kwargs.items()])
            sep = ', ' if (s1 and s2) else ''
            line = 'Call with arguments: %s%s%s)' % (s1, sep, s2)
            return msg
        return msg.split('\n')[-1]
    def wrap(*args, **kwargs):
        args = [(s.encode() if isinstance(s, str) else s) for s in args]
        result = func(*args, **kwargs)
        errmsg = _get_error_msg()
        if errmsg:
            raise PytransformError(format_message(errmsg, *args, **kwargs))
        return result
    return wrap

@dllmethod
def init_pytransform():
    major, minor = sys.version_info[0:2]
    # Python2.5 no sys.maxsize but sys.maxint
    # bitness = 64 if sys.maxsize > 2**32 else 32
    prototype = PYFUNCTYPE(c_int, c_int, c_int, c_void_p)
    init_module = prototype(('init_module', _pytransform))
    init_module(major, minor, pythonapi._handle)

@dllmethod
def init_runtime(systrace=0, sysprofile=1, threadtrace=0, threadprofile=1):
    pyarmor_init()
    prototype = PYFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
    _init_runtime = prototype(('init_runtime', _pytransform))
    _init_runtime(systrace, sysprofile, threadtrace, threadprofile)

@dllmethod
def import_module(modname, filename):
    global _import_module
    if _import_module is None:
        prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
        _import_module = prototype(('import_module', _pytransform))
    return _import_module(modname, filename)
_import_module = None

@dllmethod
def exec_file(filename):
    global _exec_file
    if _exec_file is None:
        prototype = PYFUNCTYPE(c_int, c_char_p)
        _exec_file = prototype(('exec_file', _pytransform))
    return _exec_file(filename)
_exec_file = None

@dllmethod
def encrypt_project_files(proname, filelist, mode=0):
    prototype = PYFUNCTYPE(c_int, c_char_p, py_object, c_int)
    dlfunc = prototype(('encrypt_project_files', _pytransform))
    return dlfunc(proname, filelist, mode)

@dllmethod
def encrypt_files(key, filelist, mode=0):
    t_key = c_char * 32
    prototype = PYFUNCTYPE(c_int, t_key, py_object, c_int)
    dlfunc = prototype(('encrypt_files', _pytransform))
    return dlfunc(t_key(*key), filelist, mode)

def generate_project_capsule(licfile):
    prikey, pubkey, prolic = _generate_project_capsule()
    capkey = _encode_capsule_key_file(licfile)
    return prikey, pubkey, capkey, prolic

@dllmethod
def _generate_project_capsule():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('generate_project_capsule', _pytransform))
    return dlfunc()

@dllmethod
def _encode_capsule_key_file(licfile):
    prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
    dlfunc = prototype(('encode_capsule_key_file', _pytransform))
    return dlfunc(licfile, None)

@dllmethod
def generate_module_key(pubname, key):
    t_key = c_char * 32
    prototype = PYFUNCTYPE(py_object, c_char_p, t_key, c_char_p)
    dlfunc = prototype(('generate_module_key', _pytransform))
    return dlfunc(pubname, t_key(*key), None)

@dllmethod
def generate_license_file(filename, priname, rcode, start=-1, count=1):
    prototype = PYFUNCTYPE(c_int, c_char_p, c_char_p, c_char_p, c_int, c_int)
    dlfunc = prototype(('generate_project_license_files', _pytransform))
    return dlfunc(filename, priname, rcode, start, count)

@dllmethod
def get_registration_code():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('get_registration_code', _pytransform))
    return dlfunc()

@dllmethod
def get_expired_days():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('get_expired_days', _pytransform))
    return dlfunc()

@dllmethod
def get_trial_days():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('get_trial_days', _pytransform))
    return dlfunc()

@dllmethod
def version_info():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('version_info', _pytransform))
    return dlfunc()

def get_hd_sn():
    size = 256
    t_sn = c_char * size
    sn = t_sn()
    if (_pytransform.get_hd_sn(sn, size) == -1):
        return ''
    return sn.value.decode()

def show_hd_info():
    return _pytransform.show_hd_info()

def get_license_info():
    info = {
        'expired': 'Never',
        'restrict_mode': 'Enabled',
        'HARDDISK': 'Any',
        'IFMAC': 'Any',
        'IFIPV4': 'Any',
        'DOMAIN': 'Any',
        'CODE': '',
    }
    rcode = get_registration_code().decode()
    index = 0
    if rcode.startswith('*TIME:'):
        from time import ctime
        index = rcode.find('\n')
        info['expired'] = ctime(float(rcode[6:index]))
        index += 1

    if rcode[index:].startswith('*FLAGS:'):
        info['restrict_mode'] = 'Disabled'
        index += len('*FLAGS:') + 1

    prev = None
    start = index
    for k in ['HARDDISK', 'IFMAC', 'IFIPV4', 'DOMAIN', 'FIXKEY', 'CODE']:
        index = rcode.find('*%s:' % k)
        if index > -1:
            if prev is not None:
                info[prev] = rcode[start:index]
            prev = k
            start = index + len(k) + 2
    info['CODE'] = rcode[start:]

    return info

# Load _pytransform library
def _load_library(path=None):
    if path is None:
        path = os.path.dirname(__file__)
    plat = platform.system().lower()
    bitness = struct.calcsize('P'.encode()) * 8
    libpath = os.path.join(path, 'platforms', '%s%s' % (plat, bitness))
    if not os.path.isdir(libpath):
        libpath = path
    try:
        if plat == 'linux':
            if libpath == '':
                m = cdll.LoadLibrary(os.path.abspath('_pytransform.so'))
            else:
                m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.so'))
            m.set_option('libc'.encode(), find_library('c').encode())
        elif plat == 'darwin':
            m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.dylib'))
        elif plat == 'windows':
            m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.dll'))
        elif plat == 'freebsd':
            m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.so'))
        else:
            raise RuntimeError('Platform not supported')
    except Exception:
        raise PytransformError('Could not load _pytransform from "%s"', libpath)

    # Required from Python3.6
    m.set_option('byteorder'.encode(), sys.byteorder.encode())

    # m.set_option('enable_trace_log'.encode(), c_char_p(1))

    # # Deprecated from v3.4
    # m.set_option('enable_encrypt_generator'.encode(), c_char_p(1))
    # # Deprecated from v3.4
    # m.set_option('disable_obfmode_encrypt'.encode(), c_char_p(1))

    if not os.path.abspath('.') == os.path.abspath(path):
        m.set_option('pyshield_path'.encode(), path.encode())
    return m

def pyarmor_init(path=None):
    global _pytransform
    global _get_error_msg
    if _pytransform is None:
        _pytransform = _load_library(path)
        _get_error_msg = _pytransform.get_error_msg
        _get_error_msg.restype = c_char_p
        init_pytransform()

def pyarmor_runtime(path=None):
    pyarmor_init(path)
    init_runtime(0, 0, 0, 0)


================================================
FILE: agent/simple/agent.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Gao Fang
@contact: gaofang@cetc.com.cn
@software: PyCharm
@file: agent.py
@time: 2018/3/13 0013 10:51
@desc: rule based agent
"""

import os
from agent.base_agent import BaseAgent
from agent.simple import dqn
import interface
from world import config
import copy
import random
import numpy as np

DETECTOR_NUM = 0
FIGHTER_NUM = 10
COURSE_NUM = 16
ATTACK_IND_NUM = (DETECTOR_NUM + FIGHTER_NUM) * 2 + 1 # long missile attack + short missile attack + no attack
ACTION_NUM = COURSE_NUM * ATTACK_IND_NUM


class Agent(BaseAgent):
    def __init__(self):
        """
        Init this agent
        :param size_x: battlefield horizontal size
        :param size_y: battlefield vertical size
        :param detector_num: detector quantity of this side
        :param fighter_num: fighter quantity of this side
        """
        BaseAgent.__init__(self)
        self.obs_ind = 'simple'
        if not os.path.exists('model/simple/model.pkl'):
            print('Error: agent simple model data not exist!')
            exit(1)
        self.fighter_model = dqn.RLFighter(ACTION_NUM)

    def set_map_info(self, size_x, size_y, detector_num, fighter_num):
        self.size_x = size_x
        self.size_y = size_y
        self.detector_num = detector_num
        self.fighter_num = fighter_num

    def __reset(self):
        pass

    def get_action(self, obs_dict, step_cnt):
        """
        get actions
        :param detector_obs_list:
        :param fighter_obs_list:
        :param joint_obs_dict:
        :param step_cnt:
        :return:
        """

        detector_action = []
        fighter_action = []
        for y in range(self.fighter_num):
            true_action = np.array([0, 1, 0, 0], dtype=np.int32)
            if obs_dict['fighter'][y]['alive']:
                true_action = np.array([0, 1, 0, 0], dtype=np.int32)
                tmp_img_obs = obs_dict['fighter'][y]['screen']
                tmp_img_obs = tmp_img_obs.transpose(2, 0, 1)
                tmp_info_obs = obs_dict['fighter'][y]['info']
                tmp_action = self.fighter_model.choose_action(tmp_img_obs, tmp_info_obs)
                # action formation
                true_action[0] = int(360 / COURSE_NUM * int(tmp_action[0] / ATTACK_IND_NUM))
                true_action[3] = int(tmp_action[0] % ATTACK_IND_NUM)
            fighter_action.append(copy.deepcopy(true_action))
        fighter_action = np.array(fighter_action)

        return detector_action, fighter_action





================================================
FILE: agent/simple/dqn.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Gao Fang
@contact: gaofang@cetc.com.cn
@software: PyCharm
@file: dqn.py
@time: 2018/7/25 0025 13:38
@desc: 
"""
import torch
import torch.nn as nn
import numpy as np


class NetFighter(nn.Module):
    def __init__(self, n_actions):
        super(NetFighter, self).__init__()
        self.conv1 = nn.Sequential(     # 100 * 100 * 3
            nn.Conv2d(
                in_channels=5,
                out_channels=16,
                kernel_size=5,
                stride=1,
                padding=2,
            ),
            nn.ReLU(),
            nn.MaxPool2d(2),
        )
        self.conv2 = nn.Sequential(     # 50 * 50 * 16
            nn.Conv2d(16, 32, 5, 1, 2),
            nn.ReLU(),
            nn.MaxPool2d(2),            # 25 * 25 * 32
        )
        self.info_fc = nn.Sequential(
            nn.Linear(3, 256),
            nn.Tanh(),
        )
        self.feature_fc = nn.Sequential(    # 25 * 25 * 32 + 256
            nn.Linear((25 * 25 * 32 + 256), 512),
            nn.ReLU(),
        )
        self.decision_fc = nn.Linear(512, n_actions)

    def forward(self, img, info):
        img_feature = self.conv1(img)
        img_feature = self.conv2(img_feature)
        info_feature = self.info_fc(info)
        combined = torch.cat((img_feature.view(img_feature.size(0), -1), info_feature.view(info_feature.size(0), -1)),
                             dim=1)
        feature = self.feature_fc(combined)
        action = self.decision_fc(feature)
        return action

# Deep Q Network off-policy
class RLFighter:
    def __init__(
            self,
            n_actions,
    ):
        self.n_actions = n_actions
        self.gpu_enable = torch.cuda.is_available()

        self.target_net = NetFighter(self.n_actions)
        if self.gpu_enable:
            print('GPU Available!!')
            self.target_net = self.target_net.cuda()
            self.target_net.load_state_dict(torch.load('model/simple/model.pkl'))
        else:
            self.target_net.load_state_dict(torch.load('model/simple/model.pkl', map_location=lambda storage, loc: storage))

    def choose_action(self, img_obs, info_obs):
        img_obs = torch.unsqueeze(torch.FloatTensor(img_obs), 0)
        info_obs = torch.unsqueeze(torch.FloatTensor(info_obs), 0)
        if self.gpu_enable:
            img_obs = img_obs.cuda()
            info_obs = info_obs.cuda()
        actions_value = self.target_net(img_obs, info_obs)
        action = torch.max(actions_value, 1)[1]
        if self.gpu_enable:
            action = action.cpu()
        action = action.numpy()
        return action

class NetDetector(nn.Module):
    def __init__(self, n_actions):
        super(NetDetector, self).__init__()
        self.conv1 = nn.Sequential(     # 100 * 100 * 3
            nn.Conv2d(
                in_channels=3,
                out_channels=16,
                kernel_size=5,
                stride=1,
                padding=2,
            ),
            nn.ReLU(),
            nn.MaxPool2d(2),
        )
        self.conv2 = nn.Sequential(     # 50 * 50 * 16
            nn.Conv2d(16, 32, 5, 1, 2),
            nn.ReLU(),
            nn.MaxPool2d(2),            # 25 * 25 * 32
        )
        self.info_fc = nn.Sequential(
            nn.Linear(3, 256),
            nn.Tanh(),
        )
        self.feature_fc = nn.Sequential(    # 25 * 25 * 32 + 256
            nn.Linear((25 * 25 * 32 + 256), 512),
            nn.ReLU(),
        )
        self.decision_fc = nn.Linear(512, n_actions)

    def forward(self, img, info):
        img_feature = self.conv1(img)
        img_feature = self.conv2(img_feature)
        info_feature = self.info_fc(info)
        combined = torch.cat((img_feature.view(img_feature.size(0), -1), info_feature.view(info_feature.size(0), -1)),
                             dim=1)
        feature = self.feature_fc(combined)
        action = self.decision_fc(feature)
        return action



================================================
FILE: common/agent_process.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Gao Fang
@contact: gaofang@cetc.com.cn
@software: PyCharm
@file: fight.py
@time: 2019/3/12 0009 16:41
@desc: agent sub proc
"""
import importlib
import time
from multiprocessing import Process, Queue

AGENT_INIT_TIMEOUT = 60
AGENT_RESP_TIMEOUT = 60


class AgentProc(Process):
    '''
    agent子进程
    '''
    def __init__(self, agent_name, size_x, size_y, detector_num, fighter_num, recv_queue, send_queue):
        super().__init__()
        self.agent_name = agent_name
        self.size_x = size_x
        self.size_y = size_y
        self.detector_num = detector_num
        self.fighter_num = fighter_num
        self.recv_queue = recv_queue
        self.send_queue = send_queue
        self.agent = None
        self.obs_construct = None
        self.obs_ind = 'raw'

    def run(self):
        agent_import_path = 'agent.' + self.agent_name + '.agent'
        agent_module = importlib.import_module(agent_import_path)
        self.agent = agent_module.Agent()
        self.agent.set_map_info(self.size_x, self.size_y, self.detector_num,self.fighter_num)
        self.obs_ind = self.agent.get_obs_ind()
        if self.obs_ind != 'raw':
            obs_path = 'obs_construct.' + self.obs_ind + '.construct'
            obs_module = importlib.import_module(obs_path)
            self.obs_construct = obs_module.ObsConstruct(self.size_x, self.size_y, self.detector_num,self.fighter_num)
        # time.sleep(5)
        self.send_queue.put('Init OK')
        self.__decision_proc()

    def __decision_proc(self):
        while True:
            obs_data = self.recv_queue.get()
            obs_raw_dict = obs_data['obs_raw_dict']
            step_cnt = obs_data['step_cnt']
            if self.obs_ind == 'raw':
                obs_dict = obs_raw_dict
            else:
                obs_dict = self.obs_construct.obs_construct(obs_raw_dict)
            detector_action, fighter_action = self.agent.get_action(obs_dict, step_cnt)
            action_dict = {'detector_action': detector_action, 'fighter_action': fighter_action}
            self.send_queue.put(action_dict)


class AgentCtrl:
    '''
    agent子进程维护
    '''
    def __init__(self, agent_name, size_x, size_y, detector_num, fighter_num):
        self.agent_name = agent_name
        self.size_x = size_x
        self.size_y = size_y
        self.detector_num = detector_num
        self.fighter_num = fighter_num
        self.send_q = None
        self.recv_q = None
        self.agent = None

    def agent_init(self):
        self.send_q = Queue(1)
        self.recv_q = Queue(1)
        self.agent = AgentProc(self.agent_name, self.size_x, self.size_y, self.detector_num, self.fighter_num,
                               self.send_q, self.recv_q)
        self.agent.start()
        try:
            agent_msg = self.recv_q.get(True, AGENT_INIT_TIMEOUT)
        except:
            self.terminate()
            return False
        else:
            return True

    def terminate(self):
        if self.agent:
            if self.agent.is_alive():
                self.agent.terminate()
        self.agent = None
        if self.send_q:
            self.send_q.close()
        self.send_q = None
        if self.recv_q:
            self.recv_q.close()
        self.recv_q = None

    def get_action(self, obs_raw_dict, step_cnt):
        '''
        获得动作
        :param obs_raw_dict: raw obs
        :param step_cnt: step计数,从1开始
        :return: action: 动作信息
        :return: result: 0, 正常; 1, 崩溃; 2, 超时
        '''
        action = []
        result = 0
        self.send_q.put({'obs_raw_dict': obs_raw_dict, 'step_cnt': step_cnt})
        try:
            action = self.recv_q.get(True, AGENT_RESP_TIMEOUT)
        except:
            if not self.agent.is_alive():
                # 子进程不存在,崩溃
                result = 1
            else:
                # 子进程存在,卡死
                result = 2
            self.__agent_restart()
        return action, result

    def __agent_restart(self):
        '''
        重启agent。由于重启代表之前成功启动过,所以此处认为重启也会成功。但若重启不成功将导致程序卡死。若后续出现此类问题应重点排查此处。
        :return:
        '''
        self.terminate()
        self.send_q = Queue(1)
        self.recv_q = Queue(1)
        self.agent = AgentProc(self.agent_name, self.size_x, self.size_y, self.detector_num, self.fighter_num,
                               self.send_q, self.recv_q)
        self.agent.start()
        self.recv_q.get()


================================================
FILE: configuration/reward.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Gao Fang
@contact: gaofang@cetc.com.cn
@software: PyCharm
@file: reward.py
@time: 2018/4/19 0019 14:39
@desc: reward config
"""


class GlobalVar:
    # reward
    # detector radar see a detector
    reward_radar_detector_detector = 20
    # detector radar see a fighter
    reward_radar_detector_fighter = 10
    # fighter radar see a detector
    reward_radar_fighter_detector = 20
    # fighter radar see a fighter
    reward_radar_fighter_fighter = 10

    # Missile hit a detector
    reward_strike_detector_success = 100
    # Missile miss a detector
    reward_strike_detector_fail = 0
    # Missile hit a fighter
    reward_strike_fighter_success = 100
    # Missile miss a fighter
    reward_strike_fighter_fail = 0

    # A detector been destroyed
    reward_detector_destroyed = -100
    # A fighter been destroyed
    reward_fighter_destroyed = -100

    # A valid attack action
    reward_strike_act_valid = 10
    # An invalid attack action
    reward_strike_act_invalid = -10

    # Keep alive in a step
    reward_keep_alive_step = 0

    # Round reward:totally win
    reward_totally_win = 200
    # Round reward:totally lose
    reward_totally_lose = -200
    # Round reward:win
    reward_win = 100
    # Round reward:lose
    reward_lose = -100
    # Round reward:draw
    reward_draw = 0


def get_reward_radar_detector_detector():
    return GlobalVar.reward_radar_detector_detector


def get_reward_radar_detector_fighter():
    return GlobalVar.reward_radar_detector_fighter


def get_reward_radar_fighter_detector():
    return GlobalVar.reward_radar_fighter_detector


def get_reward_radar_fighter_fighter():
    return GlobalVar.reward_radar_fighter_fighter


def get_reward_strike_detector_success():
    return GlobalVar.reward_strike_detector_success


def get_reward_strike_detector_fail():
    return GlobalVar.reward_strike_detector_fail


def get_reward_strike_fighter_success():
    return GlobalVar.reward_strike_fighter_success


def get_reward_strike_fighter_fail():
    return GlobalVar.reward_strike_fighter_fail


def get_reward_detector_destroyed():
    return GlobalVar.reward_detector_destroyed


def get_reward_fighter_destroyed():
    return GlobalVar.reward_fighter_destroyed


def get_reward_strike_act_valid():
    return GlobalVar.reward_strike_act_valid


def get_reward_strike_act_invalid():
    return GlobalVar.reward_strike_act_invalid


def get_reward_keep_alive_step():
    return GlobalVar.reward_keep_alive_step


def get_reward_win():
    return GlobalVar.reward_win


def get_reward_lose():
    return GlobalVar.reward_lose


def get_reward_totally_win():
    return GlobalVar.reward_totally_win


def get_reward_totally_lose():
    return GlobalVar.reward_totally_lose


def get_reward_draw():
    return GlobalVar.reward_draw


================================================
FILE: configuration/system.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Gao Fang
@contact: gaofang@cetc.com.cn
@software: PyCharm
@file: system.py
@time: 2018/4/19 0019 14:46
@desc: system config
"""


class GlobalVar:
    # attack effect delay
    attack_effect_delay = True
    # hit probability enable
    hit_prob_enable = True


def get_attack_effect_delay():
    return GlobalVar.attack_effect_delay


def get_hit_prob_enable():
    return GlobalVar.hit_prob_enable



================================================
FILE: doc/tutorial.md
================================================
# 多智能体对抗仿真环境MaCA完全入门指南
[TOC]
## 1 前言
中国电子科技集团公司认知与智能技术重点实验室发布的MaCA(Multi-agent Combat Arena)环境,是国内首个可模拟军事作战的轻量级多智能体对抗与训练平台,是多智能体对抗算法研究、训练、测试和评估的绝佳环境,可支持作战场景和规模自定义,智能体数量和种类自定义,智能体特征和属性自定义,支持智能体行为回报规则和回报值自定义等。目前发布的MaCA环境中预设了两种智能体类型,探测单元和攻击单元:探测单元可模拟L、S波段雷达进行全向探测,支持多频点切换;攻击单元具备侦察、探测、干扰、打击等功能,可模拟X波段雷达进行指向性探测,模拟L、S、X频段干扰设备进行阻塞式和瞄准式电子干扰,支持多频点切换。攻击单元还可模拟对敌方进行火力攻击,同时具有无源侦测能力,可模拟多站无源协同定位和辐射源特征识别。
MaCA 环境为研究利用人工智能方法解决大规模多智能体分布式对抗问题提供了很好的支撑,专门面向多智能体深度强化学习开放了 RL-API 接口。环境支持使用 Python 语言进行算法实现,并支持Tensorflow、Pytorch 等常用深度学习框架的集成调用。

## 2 MaCA安装
### 2.1 系统要求
- Linux 64-bit 、Mac OS或windows10 x64操作系统
- Python 3.6及后续版本
- Numpy、Pandas、Pygame软件包

### 2.2 环境安装
1. 安装支撑软件包
```bash
pip install -U numpy pandas pygame
```
2. 下载环境
```bash
git clone https://github.com/CETC-TFAI/MaCA.git
```
3. 环境配置
- 命令行形式(适用于Linux、Mac)
```bash
cd MaCA
export PYTHONPATH=$(pwd)/environment:$PYTHONPATH
```
- Pycharm中配置(适用于Windows、Linux、Mac)
	- 在Pycharm打开MaCA
	- 将“[environment](/environment)”文件夹设置为“Sources Root”
	- 运行MaCA中任何py文件必须将其“Working Directory”设置为MaCA根目录

## 3 MaCA初探
### 3.1 运行一个对抗场景
运行[fight_mp.py](/fight_mp.py),即可开启一场基于预置规则的异构对抗
```bash
python fight_mp.py
```
对抗场景如下图:
![对抗示例](https://leonfg.github.io/maca/resource/maca.gif)
### 3.2 观看回放录像
1. 运行对抗时增加“--log”参数,即可在log路径下生成以“红方_名称vs_蓝方名称”命名的日志文件夹,其中存储本局对抗相关信息。
```bash
python fight_mp.py --log
```
2. 默认对抗示例的日志名称为“fix_rule_vs_fix_rule”,使用replay.py即可进行日志回放:
```bash
python replay.py fix_rule_vs_fix_rule
```
## 4 MaCA详解
### 4.1 MaCA架构简介
![MaCA架构图](https://leonfg.github.io/maca/resource/maca_arch_cn.png)

MaCA核心架构如上图所示,由推演引擎环境辅以对抗调度模块,对抗场景库(maps)构成。与外围的决策算法代码相结合,实现多智能体决策训练及对抗。主要模块功能如下:
- 推演环境:承担核心推演功能,负责载入作战场景,对外输出原始战场状态数据(raw obs),接收双方决策算法给出的动作控制信息,执行一系列位置更新、电磁传播、攻击决策算法,实现对抗推演,同时具有现实及日志记录功能。
- 调用接口:外部模块与推演环境的交互接口
- 对抗调度:负责启动红蓝对抗,可对对抗多方面参数进行自定义,如双方决策程序指定、对抗局数、场景选择、每局最高持续帧数等等,同时向决策进程转发推演环境输出的状态数据,接收决策进程输出的动作信息
- 决策进程:红蓝双方对抗控制决策以单独子进程形式存在,相互隔离,主要包括两个模块
	- 决策算法:智能体决策算法,接收观测数据,输出动作控制数据
	- 观测构建:每个决策算法对应的观测信息构建,由原始状态数据生成与决策算法需求对应的观测数据。

MaCA代码结构与上述模块划分一致,具体如下图:

![MaCA代码结构](https://leonfg.github.io/maca/resource/code_arch.png)
- [environment/](/environment/):推演环境
	- [interface.py](/environment/interface.py):环境调用接口
- [agent/](/agent/):用于存储封装好的可直接调用的智能体决策代码,每个决策代码可单独设立一个文件夹,按照标准封装,系统直接调用
	- [fix_rule/](/agent/fix_rule/):基于规则的同构异构对抗决策算法
	- [fix_rule_no_att/](/agent/fix_rule_no_att/):基于规则的同构异构对抗决策算法(无攻击能力)
	- [simple/](/agent/simple/):基于DQN的同构对抗决策示例算法,需使用pytorch
- [obs_construct/](/obs_construct/):观测值组织形式自定义,开发者可根据算法需要自定义obs结构
	- [simple/](/obs_construct/simple/):基于DQN的同构对抗决策示例对应的obs组织
- [fight_mp.py](/fight_mp.py):对抗调度程序
- [replay.py](/replay.py) 日志回放入口程序
- [maps/](/maps/):对抗场景库
	- [1000_1000_2_10_vs_2_10.map](/maps/1000_1000_2_10_vs_2_10.map):预置异构对抗场景
	- [1000_1000_fighter10v10.map](/maps/1000_1000_fighter10v10.map):预置同构对抗场景
- [configuration/](/configuration/):配置数据
	- [reward.py](/configuration/reward.py):部分预置回报检查点的赋值
	- [system.py](/configuration/system.py):部分系统推演规则定义
- [train/](/train):决策算法训练所在路径
	- [simple/](/train/simple/):simple决策模型训练代码
- [model/](/model/):决策模型数据存储路径
	- [simple/](model/simple/):simple决策模型数据存储路径
- [common/](/common):多模块复用代码
	- [agent_process.py](/common/agent_process.py):对抗调度和比赛调度模块公用子进程管理代码
- [log/](/log/):对抗日志存储路径
- [tournament/](/tournament/):多智能体比赛调度及结果统计模块
	- [tournament_mp.py](/tournament/tournament_mp.py):比赛调度程序
	- [config_gen.py](/tournament/config_gen.py):比赛配置辅助生成工具

### 4.2 环境调用接口说明
MaCA环境的接口定义在[interface.py ](/environment/interface.py )文件的Environment类中,其接口函数如下:

| 接口函数 | 描述 |
|  ---- |  ---- |
| init | 环境实例初始化 |
| reset | 环境重置 |
| step | 环境运行一步 |
| get_obs | 获得组合的观测信息 |
| get_done | 判断对抗是否结束 |
| get_alive_status | 获取各作战单元的存活状态 |
| get_map_size | 获取地图大小信息 |
| get_unit_num | 获取各类别作战单元数目 |
| get_unit_property_list | 获取各作战单元属性信息 |
| get_reward | 获取回报 |

#### 4.2.1 init
参数:

| 序号 | 参数名          | 功能                  | 存在性 | 赋值规则                                                     |
| ---- | --------------- | --------------------- | ------ | ------------------------------------------------------------ |
| 1 | map_path        | 地图路径              | 必选   | MaCA根目录下开始的完整地图文件路径,如“maps/1000_1000_fighter10v10.map” |
| 2 | side1_obs_ind   | 红方使用的obs构建模块 | 必选   | 使用raw obs则赋值为“raw”,使用其他自定义obs构建则输入对应构建模块所在文件夹名 |
| 3 | side2_obs_ind   | 蓝方使用的obs构建模块 | 必选   | 同side2_obs_ind                                              |
| 4 | max_step        | 每局最大步长          | 可选   | 正整数值,不赋值此参数则使用默认值5000                       |
| 5 | render          | 是否开启显示          | 可选   | True:开启显示,False:关闭显示。不使用此参数则为默认不开启  |
| 6 | render_interval | 每隔几步显示一帧      | 可选   | 正整数值,不赋值此参数则使用默认每步都显示                   |
| 7 | random_pos      | 是否使用随机出生位置  | 可选   | True:开启随机出生,False:关闭示。不使用此参数则为默认红方在左侧蓝方在右侧 |
| 8 | log             | 日志记录开启指示      | 可选   | False:不开启日志,其他字符串值:日志文件夹名称。不使用此参数则默认不开启 |
| 9 | random_seed     | 指定随机种子          | 可选   | -1:不指定随机种子,其他正整数:指定随机种子。不使用此参数则默认不指定,由环境生成。该参数主要用于回放时载入原始种子重现对抗场景,fight和train时不需考虑。 |

返回值:无
#### 4.2.2 reset
参数:无
返回值:无
#### 4.2.3 step
参数:

| 序号 | 参数名                | 功能                   | 存在性 | 赋值规则  |
| ---- | --------------------- | ---------------------- | ------ | --------- |
| 1 | side1_detector_action | 红方探测单元动作集     | 必选   | 参见动作结构 |
| 2 | side1_fighter_action  | 红方干扰打击单元动作集 | 必选   | 参见动作结构 |
| 3 | side2_detector_action | 蓝方探测单元动作集     | 必选   | 参见动作结构 |
| 4 | side2_fighter_action  | 蓝方干扰打击单元动作集 | 必选   | 参见动作结构 |

#### 4.2.4 get_obs
参数:无
返回值:

| 序号 | 返回值名  | 功能    | 数据形式                                |
| ---- | --------- | ------- | --------------------------------------- |
| 1 | side1_obs | 红方obs | 参见raw obs |
| 2 | side2_obs | 蓝方obs | 同上                                    |

#### 4.2.5 get_done
参数:无
返回值:无

#### 4.2.6 get_reward
参数:无
返回值:

| 序号 | 返回值名       | 功能                     | 数据形式  |
| ---- | -------------- | ------------------------ | --------- |
| 1 | side1_detector | 红方探测单元单步回报     | 整型 |
| 2 | side1_fighter  | 红方打击干扰单元单步回报 | 整型 |
| 3 | side1_round    | 红方本局输赢回报         | 整型 |
| 4 | side2_detector | 蓝方探测单元单步回报     | 整型 |
| 5 | side2_fighter  | 蓝方打击干扰单元单步回报 | 整型 |
| 6 | side2_round    | 蓝方本局输赢回报         | 整型 |

### 4.3 自定义obs信息统一接口
为使得环境能够返回Agent对抗或训练时自定义的状态信息,自组织状态信息的接口统一放在[obs_construct/](/obs_construct/)下,如simple智能体中指定obs_ind为simple,则应在obs_construct模块下构建simple文件夹,每一个信息组织形式文件夹下必须包含construct.py文件,且该文件定义ObsConstruct类及obs_construct成员函数,成员函数接口如下:
```python
def obs_construct(self, obs_raw_dict)
# obs_raw_dict为raw信息结构
```
### 4.4 多智能体对抗决策程序(agent)统一接口
为方便统一对抗调用形式,限定Agent必须包含如下成员、函数接口及固定格式的返回值。
```python
from agent.base_agent import BaseAgent
class Agent(BaseAgent):

def __init__(self):				#初始化接口
    BaseAgent.__init__(self)	#从BaseAgent继承
	self.obs_ind = 'raw'		#状态信息形式,’raw’表示原始信息形式
	#注:可根据原始信息自行组织新的信息,可参考simple

def set_map_info(self, size_x, size_y, detector_num, fighter_num):#读取地图信息
    pass						#根据需要自行选择函数实现形式

def get_action(self, obs_dict, step_cnt):	#obs_dict为状态,step_cnt为当前步数(从1开始)
	return detector_action, fighter_action
```

### 4.5 主要数据格式定义
#### 4.5.1 raw obs信息结构
环境底层原始观测数据Raw data Observation结构为字典,包含三部分内容分别为detector_obs_list、fighter_obs_list、join_obs_dict。
detector_obs_list表示探测单元信息,结构为detector数目的list。每一个元素为字典结构,表示当前detector的obs信息,具体内容如下:

| Key            | Value                                                        |
| -------------- | ------------------------------------------------------------ |
| id             | 探测单元id编号,从1开始                                       |
| alive          | 攻击单元存活状态                                             |
| pos_x          | 横向坐标(位置坐标体系圆点为左上角,水平向右为x,垂直向下为y) |
| pos_y          | 纵向坐标(位置坐标体系圆点为左上角,水平向右为x,垂直向下为y) |
| course         | 航向(0-359),水平向右为0度,顺时针旋转                       |
| r_iswork       | 雷达开关状态                                                 |
| r_fre_point    | 雷达频点                                                     |
| r_visible_list | 雷达观测到的敌方单位列表,每一元素字典,表示敌方单位信息,结构为   {‘id’:编号,’type’:类型(0:探测单元,1:攻击单元) ,‘pos_x’:横向坐标,’pos_y’:纵向坐标} |
| last_reward    | 上一个状态采用动作的回报                                     |
| last_action    | 上一个状态采用的动作(字典结构)   {‘course’:,’r_iswork’:,’r_fre_point’:   } |

fighter_obs_list表示攻击单元信息,结构为detector数目的list。每一个元素为字典结构,表示当前detector的obs信息,具体内容如下:

| Key                | Value                                                        |
| ------------------ | ------------------------------------------------------------ |
| id                 | 攻击单元id编号,编号从探测单元数目开始                        |
| alive              | 攻击单元存活状态                                             |
| pos_x              | 横向坐标(位置坐标体系圆点为左上角,水平向右为x,垂直向下为y) |
| pos_y              | 纵向坐标(位置坐标体系圆点为左上角,水平向右为x,垂直向下为y) |
| course             | 航向(0-359),水平向右为0度,顺时针旋转                       |
| r_iswork           | 雷达开关状态                                                 |
| r_fre_point        | 雷达频点                                                     |
| r_visible_list     | 雷达观测到的敌方单位列表,每一元素字典,表示敌方单位信息,结构为   {‘id’:编号,’type’:类型(0:探测单元,1:攻击单元) ,‘pos_x’:横向坐标,’pos_y’:纵向坐标} |
| j_iswork           | 干扰雷达开关                                                 |
| j_fre_point        | 干扰雷达频点                                                 |
| j_recv_list        | 雷达被动观测的敌方单位列表,每一元素字典,表示敌方单位信息,结构为   {‘id’:编号,’type’: 类型(0:探测单元,1:攻击单元) ,’direction’:目标相对自身的方向,’r_fp’:频点} |
| l_missle_left      | 远程导弹剩余数目                                             |
| s_missle_left      | 短程导弹剩余数目                                             |
| striking_list      | 打击列表[{'attacker_id': 攻击者编号, 'target_id': 目标编号, 'missile_type': 导弹类型(1:远程,2:中程), information_source_type: 信息来源类型(0:L探测单元,1:S探测单元,2:战机,3:被动侦测) step_count: step计数, op_count: 观测点计数, del_ind: 删除指示(默认false)}] |
| striking_dict_list | 攻击列表[{‘target_id’:目标编号,‘pos_x’:横向坐标,’pos_y’:纵向坐标,‘type’: 类型(0:探测单元,1:攻击单元) }] |
| last_reward        | 上一个状态采用动作的回报                                     |
| last_action        | 上一个状态采用的动作(字典结构)   {‘course’:,’r_iswork’:,’r_fre_point’:,’j_iswork’:,’j_fre_point’;,’hit_target’:,’missle_type’:} |

joint_obs_list为表示全局信息的字典{‘strike_list’:打击列表,’passive_detection_enemy_list’:被动侦测列表}。strike_list为每一个作战单元striking_list的并集,passive_detection_enemy_list:[{‘id’:敌方编号,’type’: 类型(0:探测单元,1:攻击单元),‘pos_x’:横向坐标,’pos_y’:纵向坐标}]

#### 4.5.2 动作信息结构
以2个探测单元,10个攻击单元为例,则:
**detector_action为2*2的数组,每一行表示每一个探测单元的两个动作:**

|       | 意义           | 取值范围                                          |
| ----- | -------------- | ------------------------------------------------- |
| 动作1 | 航向           | [0-359]离散值                                     |
| 动作2 | 雷达开关及频点 | 频点[0,频点总数],0表示雷达关,非0表示开机对应频点 |


**fighter_action为10*4的数组,每一行表示每一个攻击单元的四个动作:**

|       | 意义                       | 取值范围                                                     |
| ----- | -------------------------- | ------------------------------------------------------------ |
| 动作1 | 航向                       | [0-359]离散值                                                |
| 动作2 | 雷达开关及频点             | 频点[0,频点总数],0表示关,非0表示开机对应频点                |
| 动作3 | 干扰设备开关机频点         | 频点[0,频点总数+1],0表示关,[1,频点总数]表示开机对应频点   频点总数+1:阻塞干扰 |
| 动作4 | 是否发射导弹及攻击目标的id | [0,25]   0:表示不发射导弹   1-12: 表示远程导弹攻击敌方目标id   13-24: 表示中程导弹攻击敌方目标id+12 |

#### 4.5.3 回报结构
回报信息可以通过Environment 接口中的get_reward获得,具体结构如下:
**以2个探测单元,10个攻击单元为例,则:**
- detector_reward为(2,)的numpy数组,每一个元素表示每一个探测单元的动作回报
- fighter_reward为(10,)的numpy数组,每一个元素表示每一个攻击单元的动作回报
- round_reward为游戏输赢的回报,此回报只有当一局对抗结束才有效

## 5 多智能体算法
### 5.1 算法与MaCA环境交互关系
![工作流程](https://leonfg.github.io/maca/resource/workflow.png)
### 5.2 算法实现示例
#### 5.2.1 多智能体决策(agent)
决策的功能是接收观测量并处理,选择合适的动作,并与环境交互。这里将多智能体决策程序称为agent,代码存放在agent路径中,子文件夹名称作为该agent名称。其中,agent.base_agent模块定义了所有agent的基类BaseAgent,其中定义了一些基本数据以及观测信息构建类指示函数:
```python
def get_obs_ind(self):
    """
    obs indication
    :return: obs构建程序路径指示字符串。对应obs_construct中同名观测构建代码,若该项赋值为'raw'代表使用原始raw obs data
    """
    '''返回obs_ind的值'''

```
agent程序最主要的方法是get_action,即接收观测量并返回动作。
一个简单的agent应具有如下形式:
```python
class SimpleAgent(BaseAgent):
	def __init__(self):
    	BaseAgent.__init__(self)
        self.obs_ind = 'simple_agent'	# 指示本决策agent需要使用哪个观测构建类
        '''初始化数据'''

    def set_map_info(self, size_x, size_y, detector_num, fighter_num):
    	"""
        获取地图信息
        :param size_x: 横向尺寸
        :param size_y: 纵向尺寸
        :param detector_num: 探测单元数量
        :param fighter_num: 攻击单元数量
        :return: N/A
        """
    	'''初始化地图、作战实体相关信息'''

    def get_action(self, obs_data, step_cnt):
    	"""
        获取动作
        :param obs_data: obs数据
        :param step_cnt: 当前step数
        :return:
        detector_action:侦查单元动作
        fighter_action:攻击单元动作
        """
        '''由观测信息得到动作并输出'''
```
#### 5.2.2 观测信息构建
环境输出的底层观测信息称为raw obs,该数据包括红方或蓝方自身所有可知状态信息。对于不同技术思路的agent来说,可能并不需要所有信息,或者数据构建形式不能满足agent自身需求,此时需要agent编写者基于raw obs进行观测信息重构,环境提供此机制便于开发者自定义观测数据。
观测重构代码应存放于obs_construct/“obs_ind名称”/construct.py,其中“obs_ind名称”应与agent中obs_ind变量赋值相同。一个典型的obs重构代码应具有如下形式:
```python
class ObsConstruct:
    def __init__(self, size_x, size_y, detector_num, fighter_num):
        """
        obs construct init
        :param size_x: 战场横向尺寸
        :param size_y: 战场纵向尺寸
        :param detector_num: 探测单元数量
        :param fighter_num: 攻击单元数量
        """
        '''内部数据初始化'''

    def obs_construct(self, obs_raw_dict):
        '''
        obs构建调用接口
        :param obs_raw_dict: raw obs数据
        :return: 自定义obs数据
        '''
        '''接收raw obs,构建新obs'''
```
agent及配套obs construct按上述要求编写完成后,使用fight_mp进行对抗时会自动生成agent所需观测数据提供给agent进行动作决策。
#### 5.2.3 训练
对于使用强化学习等机器学习方法构建的agent程序,需要进行一系列的训练,形成模型数据,才可以实现较好的动作决策。推荐将训练代码存放于“train/agent同名子文件夹”路径下,生成的模型数据存放于“model/agent同名子文件夹”,便于管理使用。
由于不同技术思路下的agent训练过程各不相同,本环境无法提类似fight_mp的统一训练管控入口,需要开发者自己编写训练调度程序,调用环境接口进行训练。对抗执行流程如下:
1. 实例化双方agent
2. 获取双方obs_ind
3. 调用environment.interface.Environment()创建环境
4. environment.interface.get_map_info()获取地图信息
5. 将地图信息传给每个agent各自的set_map_info()
6. 进入step推进的循环
	- environment.interface.Environment.get_obs()获取obs信息
	- 使用agent的get_action()将obs传输给agent并获取动作指令
	- environment.interface.Environment.step()将动作返回环境,进行下一步推演
	- 每一step完成后通过environment.interface.Environment.get_reward()获得回报数据,通过每一step完成后通过environment.interface.Environment.get_done()判断本局是否结束。

具体训练流程可参考[train/simple/main.py](/train/simple/main.py)
## 6 小结
中国电子科技集团公司认知与智能技术重点实验室发布的MaCA环境为多智能体对抗算法研究领域带来了一个全新的实验、训练与评估验证平台,为广大研究者提供了更多的交流学习机会。众多军队科研机构,企业科研机构,高等院校都在这个“竞技场”上修炼升级,同台竞技,相互促进,共同提高,将极大地促进军事智能算法研究和重大基础科学问题的解决,实现军事智能跨越式发展和实质性突破,为军事智能未来应用打下坚实基础。

================================================
FILE: environment/error_log.py
================================================
{'speed': 3, 'r_band': 2, 'j_band': 2, 'l_missile_num': 2, 's_missile_num': 4, 'id': 3, 'alive': True, 'pos_x': 576, 'pos_y': 649, 'course': 20, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'l_missile_left': 0, 's_missile_left': 3, 'j_enable': True, 'j_fp': 0, 'j_receive_list': []} 

[{'speed': 1, 'r_band': 0, 'id': 1, 'alive': False, 'pos_x': 491, 'pos_y': 333, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 11, 'type': 1, 'pos_x': 464, 'pos_y': 361}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}, {'speed': 1, 'r_band': 1, 'id': 2, 'alive': False, 'pos_x': 330, 'pos_y': 666, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 2, 'type': 0, 'pos_x': 622, 'pos_y': 666}, {'id': 11, 'type': 1, 'pos_x': 363, 'pos_y': 654}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}] 

{'id': 2, 'alive': False, 'pos_x': 487, 'pos_y': 666, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 1, 'type': 0, 'pos_x': 491, 'pos_y': 333}, {'id': 3, 'type': 1, 'pos_x': 520, 'pos_y': 638}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} 

{'speed': 3, 'r_band': 2, 'j_band': 2, 'l_missile_num': 2, 's_missile_num': 4, 'id': 3, 'alive': True, 'pos_x': 578, 'pos_y': 650, 'course': 20, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'l_missile_left': 0, 's_missile_left': 2, 'j_enable': True, 'j_fp': 0, 'j_receive_list': []} 

[{'speed': 1, 'r_band': 0, 'id': 1, 'alive': False, 'pos_x': 491, 'pos_y': 333, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 11, 'type': 1, 'pos_x': 464, 'pos_y': 361}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}, {'speed': 1, 'r_band': 1, 'id': 2, 'alive': False, 'pos_x': 330, 'pos_y': 666, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 2, 'type': 0, 'pos_x': 622, 'pos_y': 666}, {'id': 11, 'type': 1, 'pos_x': 363, 'pos_y': 654}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}] 

{'id': 2, 'alive': False, 'pos_x': 487, 'pos_y': 666, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 1, 'type': 0, 'pos_x': 491, 'pos_y': 333}, {'id': 3, 'type': 1, 'pos_x': 520, 'pos_y': 638}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} 

{'speed': 3, 'r_band': 2, 'j_band': 2, 'l_missile_num': 2, 's_missile_num': 4, 'id': 3, 'alive': True, 'pos_x': 580, 'pos_y': 650, 'course': 19, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'l_missile_left': 0, 's_missile_left': 1, 'j_enable': True, 'j_fp': 0, 'j_receive_list': []} 

[{'speed': 1, 'r_band': 0, 'id': 1, 'alive': False, 'pos_x': 491, 'pos_y': 333, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 11, 'type': 1, 'pos_x': 464, 'pos_y': 361}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}, {'speed': 1, 'r_band': 1, 'id': 2, 'alive': False, 'pos_x': 330, 'pos_y': 666, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 2, 'type': 0, 'pos_x': 622, 'pos_y': 666}, {'id': 11, 'type': 1, 'pos_x': 363, 'pos_y': 654}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}] 

{'id': 2, 'alive': False, 'pos_x': 487, 'pos_y': 666, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 1, 'type': 0, 'pos_x': 491, 'pos_y': 333}, {'id': 3, 'type': 1, 'pos_x': 520, 'pos_y': 638}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} 

{'speed': 3, 'r_band': 2, 'j_band': 0, 'l_missile_num': 2, 's_missile_num': 4, 'id': 11, 'alive': True, 'pos_x': 526, 'pos_y': 329, 'course': 336, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'l_missile_left': 0, 's_missile_left': 1, 'j_enable': True, 'j_fp': 0, 'j_receive_list': []} 

[{'speed': 1, 'r_band': 0, 'id': 1, 'alive': False, 'pos_x': 669, 'pos_y': 333, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 1, 'type': 0, 'pos_x': 350, 'pos_y': 333}, {'id': 3, 'type': 1, 'pos_x': 570, 'pos_y': 310}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}, {'speed': 1, 'r_band': 1, 'id': 2, 'alive': False, 'pos_x': 487, 'pos_y': 666, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [{'id': 1, 'type': 0, 'pos_x': 491, 'pos_y': 333}, {'id': 3, 'type': 1, 'pos_x': 520, 'pos_y': 638}], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}] 

{'id': 3, 'alive': True, 'pos_x': 615, 'pos_y': 651, 'course': 0, 'radar_enable': True, 'radar_fp': 1, 'radar_visible_list': [], 'passive_location_ind': False, 'detection_count_list': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'l_missile_left': 0, 's_missile_left': 0, 'j_enable': True, 'j_fp': 0, 'j_receive_list': []} 

strike_context:  {'attacker_id': 11, 'target_id': 3, 'missile_type': 2, 'step_count': 1, 'op_count': 0, 'del_ind': False}
Traceback (most recent call last):
  File "fight.py", line 136, in <module>
    env.step(side1_detector_action, side1_fighter_action, side2_detector_action, side2_fighter_action)
  File "/home/boris/MaCA/environment/interface.py", line 151, in step
    return self.env.step(side1_detector_action, side1_fighter_action, side2_detector_action, side2_fighter_action)
  File "<frozen environment.world.em_battle>", line 1506, in step
  File "<frozen environment.world.em_battle>", line 401, in __step_list
  File "<frozen environment.world.em_battle>", line 441, in __under_strike_proc
  File "<frozen environment.world.em_battle>", line 693, in __under_strike_proc_delay
  File "/home/boris/MaCA/environment/world/strike_calc.py", line 97, in strike_judge
    if missile_type == config.get_s_missile_type() and step_count >= 4:
UnboundLocalError: local variable 'step_count' referenced before assignment


dis_update
dis_update(self, done, step, o_detector_data_obs_list, o_fighter_data_obs_list, e_detector_data_obs_list, e_fighter_data_obs_list, o_detector_data_reward_list, o_fighter_data_reward_list, e_detector_data_reward_list, e_fighter_data_reward_list, o_all_reward, e_all_reward)


dis_update_done_font
dis_update_done_font(self)


dis_update_font
dis_update_font(self, step, red_reward, blue_reward, red_detector_num, blue_detector_num, red_fighter_num, blue_fighter_num, red_missile_num, blue_missile_num)

dis_update_pos
dis_update_pos(self, o_detector_pos_list, o_fighter_pos_list, e_detector_pos_list, e_fighter_pos_list)


draw_course
draw_course(self, center_point_x, center_point_y, course, course_r)


draw_fight_rela
draw_fight_rela(self, center_point_x, center_point_y, striking_list, detector_list, fighter_list, line_colour)




================================================
FILE: environment/interface.py
================================================
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from pytransform import pyarmor_runtime
pyarmor_runtime()
"""
@author: Gao Fang
@contact: gaofang@cetc.com.cn
@software: PyCharm
@file: interface.py
@time: 2018/4/10 0010 8:52
@desc: environment interface
"""

import importlib
from world.em_battle import BattleField
from world.replay import Replay
from world.load_map import Map
import world.position_calc as position_calc
from render.render_pic import Render

class Environment:
    """
    Environment interface
    """
    def __init__(self, map_path, side1_obs_ind, side2_obs_ind, max_step=5000, render=False, render_interval=1,
                 random_pos=False, log=False, random_seed=-1):
        """
        Environment initiation
        :param size_x: battlefield horizontal size. got from LoadMap.get_map_size
        :param size_y: battlefield vertical size. got from LoadMap.get_map_size
        :param side1_detector_list: side 1 detector configuration. got from LoadMap.get_unit_property_list
        :param side1_fighter_list: side 1 fighter configuration. got from LoadMap.get_unit_property_list
        :param side2_detector_list: side 2 detector configuration. got from LoadMap.get_unit_property_list
        :param side2_fighter_list: side 2 fighter configuration. got from LoadMap.get_unit_property_list
        :param max_step: max step,0:unlimited
        :param render: display enable control, True: enable display, False: disable display
        :param render_interval: display interval, skip how many steps to display a frame
        :param random_pos: start location initial method. False: side 1 on right, side2 on left. True: random position on top, bottom, right and left)
        :param log: log control,False:disable log,other value:the folder name of log.
        :param random_seed: random digit,-1:generate a new one,other value:use an exist random digit value
        """

        # load map
        self.map = Map(map_path)
        self.size_x, self.size_y = self.map.get_map_size()
        self.side1_detector_num, self.side1_fighter_num, self.side2_detector_num, self.side2_fighter_num = self.map.get_unit_num()
        # make env
        self.side1_detector_list, self.side1_fighter_list, self.side2_detector_list, self.side2_fighter_list = self.map.get_unit_property_list()
        self.env = BattleField(self.size_x, self.size_y, self.side1_detector_list, self.side1_fighter_list,
                               self.side2_detector_list, self.side2_fighter_list, max_step, render, render_interval,
                               random_pos, log, random_seed)

        # for item in dir(Render):
        #     print(item)
        # return

        # print(help(Render.draw_fight_rela))
        # return


        # import obs construct class
        if 'raw' == side1_obs_ind:
            self.side1_obs_path = 'raw'
        else:
            self.side1_obs_path = 'obs_construct.' + side1_obs_ind + '.construct'
            self.agent1_obs_module = importlib.import_module(self.side1_obs_path)
            self.agent1_obs = self.agent1_obs_module.ObsConstruct(self.size_x, self.size_y, self.side1_detector_num,
                                                                  self.side1_fighter_num)
        if 'raw' == side2_obs_ind:
            self.side2_obs_path = 'raw'
        else:
            self.side2_obs_path = 'obs_construct.' + side2_obs_ind + '.construct'
            self.agent2_obs_module = importlib.import_module(self.side2_obs_path)
            self.agent2_obs = self.agent2_obs_module.ObsConstruct(self.size_x, self.size_y, self.side2_detector_num,
                                                                  self.side2_fighter_num)


    def get_done(self):
        """
        Get done
        :return: done: True, False
        """
        # TODO: modified
        return self.env.get_done()

    def get_obs(self):
        """
        Get image-based observation
        :return: side1_obs
        :return: side2_obs
        """
        side1_obs_raw_dict, side2_obs_raw_dict = self.get_obs_raw()
        if 'raw' == self.side1_obs_path:
            side1_obs = side1_obs_raw_dict
        else:
            side1_obs = self.agent1_obs.obs_construct(side1_obs_raw_dict)

        if 'raw' == self.side2_obs_path:
            side2_obs = side2_obs_raw_dict
        else:
            side2_obs = self.agent2_obs.obs_construct(side2_obs_raw_dict)

        return side1_obs, side2_obs

    def get_obs_raw(self):
        """
        Get raw data observation
        :return: side1_detector_data
        :return: side1_fighter_data
        :return: side2_detector_data
        :return: side2_fighter_data
        detector obs:{'id':id, 'alive': alive status, 'pos_x': horizontal coordinate, 'pos_y': vertical coordinate, 'course': course, 'r_iswork': radar enable status, 'r_fre_point': radar frequency point, 'r_visible_list': radar visible enemy}
        fighter obs:{'id':id, 'alive': alive status, 'pos_x': horizontal coordinate, 'pos_y': vertical coordinate, 'course': course, 'r_iswork': radar enable status, 'r_fre_point': radar frequency point, 'r_visible_list': radar visible enemy, 'j_iswork': jammer enable status, 'j_fre_point': jammer frequency point, 'j_recv_list': jammer received enemy, 'l_missile_left': long range missile left, 's_missile_left': short range missile left}
        """

        side1_obs_dict = {}
        side2_obs_dict = {}
        side1_detector_data_obs_list, side1_fighter_data_obs_list, side1_joint_data_obs_dict, \
        side2_detector_data_obs_list, side2_fighter_data_obs_list, side2_joint_data_obs_dict = self.env.get_obs_raw()
        side1_obs_dict.update({'detector_obs_list': side1_detector_data_obs_list})
        side1_obs_dict.update({'fighter_obs_list': side1_fighter_data_obs_list})
        side1_obs_dict.update({'joint_obs_dict': side1_joint_data_obs_dict})
        side2_obs_dict.update({'detector_obs_list': side2_detector_data_obs_list})
        side2_obs_dict.update({'fighter_obs_list': side2_fighter_data_obs_list})
        side2_obs_dict.update({'joint_obs_dict': side2_joint_data_obs_dict})
        return side1_obs_dict, side2_obs_dict

    def get_alive_status(self,side1_detector_obs_raw_list,side1_fighter_obs_raw_list,side2_detector_obs_raw_list,side2_fighter_obs_raw_list):
        return self.env.get_alive_status(side1_detector_obs_raw_list,side1_fighter_obs_raw_list,side2_detector_obs_raw_list,side2_fighter_obs_raw_list)

    def get_reward(self):
        """
        get reward
        :return:side1_detector:side1 detector reward,side1_fighter:side1 fighter reward,side1_round: side1 round reward, side2_detector:side2 detector reward,side2_fighter:side2 fighter reward,side2_round: side1 round reward
        """
        return self.env.get_reward()

    def reset(self):
        """
        Reset environment
        :return: none
        """
        self.env.reset()
    def step(self, side1_detector_action, side1_fighter_action, side2_detector_action, side2_fighter_action):
        """
        Run a step
        :param side1_detector_action: Numpy ndarray [detector_quantity, 2]
        :param side1_fighter_action: Numpy ndarray [fighter_quantity, 4]
        :param side2_detector_action: Numpy ndarray [detector_quantity, 2]
        :param side2_fighter_action: Numpy ndarray [fighter_quantity, 4]
        :return: True, run succeed, False, run Failed
        """
        return self.env.step(side1_detector_action, side1_fighter_action, side2_detector_action, side2_fighter_action)

    def get_map_size(self):
        """
        Get map size
        :return: size_x: horizontal size
        :return: size_y: vertical size
        """
        return self.map.get_map_size()

    def get_unit_num(self):
        """
        Get unit number
        :return: side1_detector_num
        :return: side1_fighter_num
        :return: side2_detector_num
        :return: side2_fighter_num
        """
        return self.map.get_unit_num()

    def get_unit_property_list(self):
        """
        Get unit config information
        :return: side1_detector_list, should be directly forward to Environment init interface
        :return: side1_fighter_list, should be directly forward to Environment init interface
        :return: side2_detector_list, should be directly forward to Environment init interface
        :return: side2_fighter_list, should be directly forward to Environment init interface
        """
        return self.map.get_unit_property_list()

    def set_surrender(self, side):
        '''
        surrender
        :param side: side1: 0, side2: 1
        :return:
        '''
        return self.env.set_surrender(side)


class PlayBack:
    """
    Replay
    """
    def __init__(self, log_name, display_delay_time=0):
        """
        Initial replay class
        :param log_name:
        :param display_delay_time:
        """
        self.rp = Replay(log_name, display_delay_time)

    def start(self):
        """
        Replay begin
        """
        self.rp.start()

# Utilities
def get_distance(a_x, a_y, b_x, b_y):
    """
    Get distance between two coordinates
    :param a_x: point a horizontal coordinate
    :param a_y: point a vertical coordinate
    :param b_x: point b horizontal coordinate
    :param b_y: point b vertical coordinate
    :return: distance value
    """
    return position_calc.get_distance(a_x, a_y, b_x, b_y)


def angle_cal(o_x, o_y, e_x, e_y):
    """
    Get a direction (angle) from a point to another point.
    :param o_x: starting point horizontal coordinate
    :param o_y: starting point vertical coordinate
    :param e_x: end point horizontal coordinate
    :param e_y: end point vertical coordinate
    :return: angle value
    """
    return position_calc.angle_cal(o_x, o_y, e_x, e_y)


================================================
FILE: environment/license.lic
================================================
FCpGTEFHUzoBKkNPREU6cHJvLTAyZ5BCrprWffXaRJeFaCw1aihFNyaQ/BLeHa7NWyCHrDf43ud9WKhQVbrO3PWhLjHKZEZE9FkBbDV440VAFJ+knAcuTEk5zc3I2eS0qAeZUKjiIb4i91gy9kKIfgyqOIg4cXwgasxk3icpOEj9B/yzhnDMXeZn4WUQGOKIbslIdcM=

================================================
FILE: environment/product.key
================================================
Bې?CAk8a6WH0vY
y

}q#fRq+JBwzʱnƐS*TE`wN(RGy0tD&y
P:Cq\8SBV]

================================================
FILE: environment/pytransform.py
================================================
# Because ctypes is new from Python 2.5, so pytransform doesn't work
# before Python 2.5
#
from ctypes import cdll, c_char, c_char_p, c_int, c_void_p, \
                   pythonapi, py_object, PYFUNCTYPE
from ctypes.util import find_library

import os
import sys
import platform
import struct

#
# Global
#
_pytransform = None
_get_error_msg = None

#
# Options
#

# How to show error message return from dynamic library _pytransform.
#
# Each time call a dll function, if something is wrong, _get_error_msg
# will return the reason.
#
# Enable _verbose_mode will print the details got from _get_error_msg.
# Disable this options will print only a short message.
_verbose_mode = 1

# In debug mode, print trace stack when raise exception.
# Otherwise only show a short message.
#
# Run python with command option "-d", or set environment variable
# PYTHONDEBUG. For example
#
#   python -d pyarmor.py xxxx
#
_debug_mode = sys.flags.debug

class PytransformError(Exception):
    def __init__(self, *args, **kwargs):
        super(Exception, self).__init__(*args, **kwargs)
        if _debug_mode:
            self._print_stack()

    @classmethod
    def _print_stack(self):
        try:
            from traceback import print_stack
        except Exception:
            _debug_mode = 0
            sys.stderr.write('Disabled debug mode.\n')
        else:
            print_stack()

def dllmethod(func):
    def format_message(msg, *args, **kwargs):
        if _verbose_mode:
            s1 = str(args)[:-1]
            s2 = ', '.join(['%s=%s' % (k, repr(v)) for k, v in kwargs.items()])
            sep = ', ' if (s1 and s2) else ''
            line = 'Call with arguments: %s%s%s)' % (s1, sep, s2)
            return msg
        return msg.split('\n')[-1]
    def wrap(*args, **kwargs):
        args = [(s.encode() if isinstance(s, str) else s) for s in args]
        result = func(*args, **kwargs)
        errmsg = _get_error_msg()
        if errmsg:
            raise PytransformError(format_message(errmsg, *args, **kwargs))
        return result
    return wrap

@dllmethod
def init_pytransform():
    major, minor = sys.version_info[0:2]
    # Python2.5 no sys.maxsize but sys.maxint
    # bitness = 64 if sys.maxsize > 2**32 else 32
    prototype = PYFUNCTYPE(c_int, c_int, c_int, c_void_p)
    init_module = prototype(('init_module', _pytransform))
    init_module(major, minor, pythonapi._handle)

@dllmethod
def init_runtime(systrace=0, sysprofile=1, threadtrace=0, threadprofile=1):
    pyarmor_init()
    prototype = PYFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
    _init_runtime = prototype(('init_runtime', _pytransform))
    _init_runtime(systrace, sysprofile, threadtrace, threadprofile)

@dllmethod
def import_module(modname, filename):
    global _import_module
    if _import_module is None:
        prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
        _import_module = prototype(('import_module', _pytransform))
    return _import_module(modname, filename)
_import_module = None

@dllmethod
def exec_file(filename):
    global _exec_file
    if _exec_file is None:
        prototype = PYFUNCTYPE(c_int, c_char_p)
        _exec_file = prototype(('exec_file', _pytransform))
    return _exec_file(filename)
_exec_file = None

@dllmethod
def encrypt_project_files(proname, filelist, mode=0):
    prototype = PYFUNCTYPE(c_int, c_char_p, py_object, c_int)
    dlfunc = prototype(('encrypt_project_files', _pytransform))
    return dlfunc(proname, filelist, mode)

@dllmethod
def encrypt_files(key, filelist, mode=0):
    t_key = c_char * 32
    prototype = PYFUNCTYPE(c_int, t_key, py_object, c_int)
    dlfunc = prototype(('encrypt_files', _pytransform))
    return dlfunc(t_key(*key), filelist, mode)

def generate_project_capsule(licfile):
    prikey, pubkey, prolic = _generate_project_capsule()
    capkey = _encode_capsule_key_file(licfile)
    return prikey, pubkey, capkey, prolic

@dllmethod
def _generate_project_capsule():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('generate_project_capsule', _pytransform))
    return dlfunc()

@dllmethod
def _encode_capsule_key_file(licfile):
    prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
    dlfunc = prototype(('encode_capsule_key_file', _pytransform))
    return dlfunc(licfile, None)

@dllmethod
def generate_module_key(pubname, key):
    t_key = c_char * 32
    prototype = PYFUNCTYPE(py_object, c_char_p, t_key, c_char_p)
    dlfunc = prototype(('generate_module_key', _pytransform))
    return dlfunc(pubname, t_key(*key), None)

@dllmethod
def generate_license_file(filename, priname, rcode, start=-1, count=1):
    prototype = PYFUNCTYPE(c_int, c_char_p, c_char_p, c_char_p, c_int, c_int)
    dlfunc = prototype(('generate_project_license_files', _pytransform))
    return dlfunc(filename, priname, rcode, start, count)

@dllmethod
def get_registration_code():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('get_registration_code', _pytransform))
    return dlfunc()

@dllmethod
def get_expired_days():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('get_expired_days', _pytransform))
    return dlfunc()

@dllmethod
def get_trial_days():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('get_trial_days', _pytransform))
    return dlfunc()

@dllmethod
def version_info():
    prototype = PYFUNCTYPE(py_object)
    dlfunc = prototype(('version_info', _pytransform))
    return dlfunc()

def get_hd_sn():
    size = 256
    t_sn = c_char * size
    sn = t_sn()
    if (_pytransform.get_hd_sn(sn, size) == -1):
        return ''
    return sn.value.decode()

def show_hd_info():
    return _pytransform.show_hd_info()

def get_license_info():
    info = {
        'expired': 'Never',
        'restrict_mode': 'Enabled',
        'HARDDISK': 'Any',
        'IFMAC': 'Any',
        'IFIPV4': 'Any',
        'DOMAIN': 'Any',
        'CODE': '',
    }
    rcode = get_registration_code().decode()
    index = 0
    if rcode.startswith('*TIME:'):
        from time import ctime
        index = rcode.find('\n')
        info['expired'] = ctime(float(rcode[6:index]))
        index += 1

    if rcode[index:].startswith('*FLAGS:'):
        info['restrict_mode'] = 'Disabled'
        index += len('*FLAGS:') + 1

    prev = None
    start = index
    for k in ['HARDDISK', 'IFMAC', 'IFIPV4', 'DOMAIN', 'FIXKEY', 'CODE']:
        index = rcode.find('*%s:' % k)
        if index > -1:
            if prev is not None:
                info[prev] = rcode[start:index]
            prev = k
            start = index + len(k) + 2
    info['CODE'] = rcode[start:]

    return info

# Load _pytransform library
def _load_library(path=None):
    if path is None:
        path = os.path.dirname(__file__)
    plat = platform.system().lower()
    bitness = struct.calcsize('P'.encode()) * 8
    libpath = os.path.join(path, 'platforms', '%s%s' % (plat, bitness))
    if not os.path.isdir(libpath):
        libpath = path
    try:
        if plat == 'linux':
            if libpath == '':
                m = cdll.LoadLibrary(os.path.abspath('_pytransform.so'))
            else:
                m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.so'))
            m.set_option('libc'.encode(), find_library('c').encode())
        elif plat == 'darwin':
            m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.dylib'))
        elif plat == 'windows':
            m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.dll'))
        elif plat == 'freebsd':
            m = cdll.LoadLibrary(os.path.join(libpath, '_pytransform.so'))
        else:
            raise RuntimeError('Platform not supported')
    except Exception:
        raise PytransformError('Could not load _pytransform from "%s"', libpath)

    # Required from Python3.6
    m.set_option('byteorder'.encode(), sys.byteorder.encode())

    # m.set_option('enable_trace_log'.encode(), c_char_p(1))

    # # Deprecated from v3.4
    # m.set_option('enable_encrypt_generator'.encode(), c_char_p(1))
    # # Deprecated from v3.4
    # m.set_option('disable_obfmode_encrypt'.encode(), c_char_p(1))

    if not os.path.abspath('.') == os.path.abspath(path):
        m.set_option('pyshield_path'.encode(), path.encode())
    return m

def pyarmor_init(path=None):
    global _pytransform
    global _get_error_msg
    if _pytransform is None:
        _pytransform = _load_library(path)
        _get_error_msg = _pytransform.get_error_msg
        _get_error_msg.restype = c_char_p
        init_pytransform()

def pyarmor_runtime(path=None):
    pyarmor_init(path)
    init_runtime(0, 0, 0, 0)


================================================
FILE: environment/render/__init__.py
================================================
__pyarmor__(__name__, __file__, b'\xec\x50\x8c\x64\x26\x42\xd6\x01\x10\x54\xca\x9c\xb6\x36\x84\x05\x6a\x0b\xf3\xc4\x16\x01\xb0\x49\xdd\x1c\xf4\xf8\x5a\xe1\xe0\xc4\xbe\x1b\x41\x5d\x2c\x21\x77\xb1\x53\x58\xd9\xeb\x22\xb3\x4c\x09\x12\xdb\x19\xce\x41\x3b\xeb\xb0\x0d\x17\x26\x12\xf9\x51\x94\x9e\xf1\xf5\x85\x77\xd0\x70\xdf\xce\x84\x05\x76\x90\x38\xf1\x10\xd7\x44\x53\x87\x32\x78\xa3\x65\xcd\x08\xcf\x45\x20\x53\x90\x31\x2c\x73\xa3\x04\x11\xfb\x6f\xf4\x36\xd1\x62\xd3\x8e\xcd\x56\x1e\xfa\x95\xb6\xcf\x95\xbc\x7b\x99\x14\x01\xd1\x68\x33\xcd\x33\xf0\x81\xb8\xc9\xea\x5c\x41\x40\x4e\xa4\xc6\x33\x22\x8b\xbe\x9f\x5e\x52\x39\x81\x68\x68\x4e\x6b\x3e\x50\xfa\xd3\xe2\x15', 1)

================================================
FILE: environment/render/render_pic.py
================================================
__pyarmor__(__name__, __file__, b'\xe7\x50\x8c\x64\x26\x42\xd6\x01\xb9\x4e\x3f\xdf\x40\x9b\x76\xef\x72\x6c\x30\x53\x5b\x51\x12\xe5\x74\x7d\x05\x68\xb6\x2a\x70\xff\x5a\x6c\xe7\x13\x67\xad\x90\xbb\xcf\x70\x39\x65\x6e\xea\x70\xef\xf9\xcc\xa6\x0c\xbc\x59\xd1\x77\xa1\x9a\x9a\xb6\x68\xa1\x4b\x30\x9d\x0c\xa4\x01\xb7\xfc\x29\xe8\x56\xe1\x9c\x8d\x63\x89\x24\xd9\x30\x14\xfd\x61\x5e\x83\x04\x18\xd3\x5d\xcd\xcc\x5c\x89\xe0\x07\xd2\xcb\xfe\x13\x0a\x78\x56\x02\x8a\x04\x02\x6a\x09\xef\x28\x22\xbb\x60\xf5\x30\xc8\x17\x27\xb2\xa2\xa9\x45\x38\x34\x79\x7c\xae\x0f\xf8\xce\x4f\x4b\x60\xaf\xcb\x51\xc7\xfc\xfb\xb9\xd5\xe6\x91\x62\xac\xd3\x5c\x55\xc3\xef\xbb\xd7\xe4\xe2\xac\xff\x0d\xf5\x8f\xac\xf6\xe9\x1c\x20\xbd\xa5\x8a\x81\x12\x3c\x4e\xb9\x90\xd7\x7e\xf8\xaf\x2b\xe5\xce\x65\x83\xd1\xe2\x99\xcb\x02\x83\x95\xfe\x0b\xa0\x16\x3d\x75\x65\xfb\x34\x5b\x6d\x04\xfa\xd5\x5b\x41\x7e\xe8\x91\x58\xe1\xe1\xd6\xbd\xa4\x6e\x64\x28\x93\x8c\x95\x49\xe4\x32\x1f\xf1\x96\x9e\x70\x58\x34\x18\x1a\x22\x24\x53\xd8\xdf\x59\x8f\x93\x37\x83\x40\xf9\x4c\x2b\x69\xad\x37\xfc\x92\xc9\x45\x3e\x5a\x13\x8f\xbd\x36\xd7\xdf\x8a\xa3\x1c\xdf\x4f\x36\xde\xfa\x23\x33\x36\x92\x40\xef\xdc\xf5\x15\x15\x6e\x35\x81\x54\x5a\x63\xbc\x92\xc8\x8f\x0e\x7f\x9d\x09\x73\x26\x51\xb9\x71\x34\xff\x1b\x58\x31\xdb\x2a\x5c\x4f\xab\xb7\x7a\xcc\x5d\x58\xca\xd4\x7d\x6d\x7d\x1d\x89\x0b\x1a\x41\x76\xed\x90\x0d\xd5\x93\x39\x9a\xa9\x74\x79\x25\x3b\x09\x39\x8b\xff\xc8\x3a\x60\x5b\x64\xa3\xb6\x31\x67\x31\x54\x14\xb2\x7d\x20\x11\x25\x1f\x6d\x0d\x5c\x7b\x59\xcc\x86\x94\xba\x11\x77\xbb\x37\xe7\xa6\xde\x89\x28\x0c\xb3\x4f\xd0\x6e\x84\x3c\x5b\xbd\x9c\x4b\x4d\x36\x1b\x92\x9e\x9d\x08\x8f\x40\x48\x86\x5b\x07\x2b\x1f\x0b\x1c\x68\xa1\xd1\xd4\x96\x90\xf0\x46\x51\x1d\x07\x82\x23\x5f\x23\x4b\xce\x28\x0e\xd2\x49\x87\x6e\xa5\x7e\xc3\x9d\x5f\x48\x44\x86\xdf\xae\x6a\xf1\xc4\x34\x48\xcc\xcc\x42\xc1\x13\x56\x4b\x08\x4c\xe4\x35\x1e\x65\x74\xc8\xa2\x68\x48\x99\xe3\x71\x9a\xa5\xb8\x5e\x02\x96\x8d\xdf\x01\x1e\x43\x9f\x56\xe0\x6a\xdc\xfb\x2a\x64\xde\x02\xea\xc9\xd0\xa3\x1a\xb0\x2a\x85\x14\x49\x6b\x99\x74\xef\xee\xac\x1b\x49\x63\xe9\x6a\x7d\x6e\xea\x70\x59\xef\x6a\x5d\x5c\x5c\x4b\xe9\xb9\xe4\xd8\xc7\x1a\x23\x4a\x54\xf3\x59\x0f\xb8\x0c\xe7\x8d\x72\x37\x16\x1b\xe0\x17\x43\x80\xf9\xb1\x72\x8b\x01\xf7\x1f\x34\x2c\x2a\x09\x47\xef\x49\xbd\xa1\x76\x1c\xd8\x3b\x85\xc0\x41\xf6\x5c\xaf\xf7\x07\x03\xd8\x05\xad\x2d\xb8\x14\x73\x7f\xe8\xb8\xab\x2e\x32\x01\xc8\xc6\xbf\xa1\xf5\xae\xf5\xb1\x47\x80\xe4\xb2\xbd\x7e\xd1\xb0\x7a\x42\x9a\xd3\x46\x26\x4a\x24\xcb\xb9\x8d\xfa\x46\x96\x27\x49\x57\x16\x35\x63\xfe\x90\xe6\x0f\x7e\x6b\x83\x61\x2f\xe9\x03\xd1\x08\x83\x9a\x39\x55\xd0\x62\x17\x6f\x38\x1f\x77\x10\x4f\xe1\x0f\x31\xae\x4e\xa6\x39\x06\xf8\xc9\x46\xca\xfc\x1f\x08\xec\x9f\xc3\xfd\xe6\x62\x64\xff\xae\x5f\x5e\x2a\x64\xbb\x35\x5d\x2f\x4c\x7c\xde\x9f\x05\xd5\x39\xd6\x38\x04\xdb\x03\xe5\xe7\x91\xc6\x4e\xa0\x1d\x14\x83\x74\xee\x0e\xfd\x07\xba\xc6\x15\xf7\x43\xf9\xf5\xfc\x3f\xec\x5c\x94\x6a\x01\xfc\x4d\x10\x9c\xab\x17\xc3\x46\xc3\xf9\x58\x83\x58\x5c\x19\x6a\x4d\xcc\xd1\x4c\x36\x9c\xc4\x7f\xc8\x1e\x81\x38\x25\x1f\x55\x8c\x6f\x20\x26\x29\x8a\x6b\x1e\xab\x71\x88\x33\x6a\x4e\xdd\x4f\xb9\x67\xe7\x49\xcf\xe6\xb2\x9d\x26\xad\xab\x00\x0f\x3b\x44\xab\xc3\x98\x5f\xbc\x5c\xbb\x7e\x25\xa0\xf9\x13\x88\xdf\xc7\x4f\xfa\xcd\x96\xfd\x0d\x12\x9f\x6f\x56\xe2\x59\x3b\x5a\x0a\xf8\xf6\xa6\xbc\xcd\x01\x95\x41\x2e\xa9\x7b\x5c\x05\x7b\xdf\x52\x22\xc8\x7d\xe4\xb2\x41\x0e\x38\xd7\x9f\x81\x63\xf9\x04\xba\x5e\xa4\xe3\x47\xbe\xe5\x25\x9f\x31\xb9\x24\xaa\x34\xd6\x81\xca\xba\xbf\x8b\x8c\x02\x18\xe6\xa1\x59\xbe\xea\x89\xa3\x13\x6b\x6c\xb9\x20\xcc\x58\x87\x12\x74\xe0\x75\x10\x5d\xfd\x31\x6f\x7c\xb6\xc7\xf0\x38\xc7\x9c\x70\x33\xd0\x56\xd8\x2e\x03\x45\x80\xdb\x08\x4d\xc2\x6b\xd0\x90\x95\x0b\xd8\x3f\xb7\x27\x24\xc6\x46\x93\x35\xb8\xa9\x69\x24\x86\xd3\xa0\x11\xb2\x22\xee\xbb\x3f\xa9\x28\x8e\xc9\x2a\x3d\xea\xe7\x6a\x9e\xcc\xc2\x92\x88\xdb\x8d\x32\x91\x22\x16\x79\xb6\x80\x97\x30\x34\x57\x3d\xe3\x73\xa3\x10\x4b\xb6\xb7\x99\xc8\x60\xb8\x8b\x22\x2f\xf2\xd4\xcc\xc5\xa4\xa5\x8c\x49\xf9\xed\xef\x5d\xfa\x77\xa3\xfd\x1c\x4a\xe9\x2a\x49\xea\x7d\xdd\x8d\x3a\x36\x39\x48\x25\x93\xd2\x7b\x7f\x14\x55\x59\x60\x13\x28\x05\x4a\xa1\x85\x69\xe2\x91\x70\x74\x22\x71\x24\x40\x28\xc5\xf9\x11\x74\xf8\x88\x51\x4c\x29\xa0\xcb\x15\xb8\x99\xcc\x9e\xa2\xb4\xec\x2c\x25\x0a\xee\xbd\x61\xbd\x33\x04\x27\xab\xaa\xcb\x08\x1e\x87\x77\x13\x78\xc7\x22\x6a\xae\x9d\x3b\xe6\xcb\x78\x9e\x59\xff\x77\x1c\xf5\xf2\x69\x02\x7d\xfa\xdc\x86\x13\x4d\x18\x3c\x4e\x04\x97\x81\x7c\x41\xe0\x67\x36\xe5\x57\xcb\x36\x51\xeb\xd3\x93\x48\x18\x39\xb9\x9a\xc8\x7e\xac\x54\x0c\x46\xc7\xd6\x2e\x00\xb0\x41\x0f\x59\x50\x8f\xc5\xbe\x50\x8a\x2f\x7e\x79\x1f\x06\x35\x6f\x3f\xd1\x17\x0f\x6c\xe3\x58\x34\x63\x29\x80\x0f\xa6\x43\xe0\x3c\x21\x59\x50\x34\xc9\xab\x94\x3a\x92\x12\x81\x4e\xbc\x0e\x2e\x52\xa6\xc8\x0d\x2e\xb3\x0a\xf5\xee\xe5\x6b\x9b\x71\x62\x04\x11\x4e\x55\xe4\xd5\x6c\xdc\xf9\x9d\xfe\xac\x2a\xa8\x22\x71\x7e\xca\xd6\x3f\xe0\x11\xd3\x43\x0f\xb1\xd9\xb4\x3f\x89\x4c\x15\x74\x94\xf0\x39\x11\x62\x2e\x2d\x8e\x68\xf9\x0b\x0f\x43\x3f\x89\x48\xb1\x43\x2e\xdc\xdf\xb2\x20\x3e\x8b\xcf\xaf\x8e\xaf\x1b\x31\xc6\x58\x61\x5c\x06\x81\xfe\x19\xe3\x22\x53\x1c\x0f\x6d\x14\x34\x51\xd3\x73\xb7\xd2\x9b\xc9\xf8\xc2\xc0\xfb\x7a\xd1\x25\x46\x18\xd1\xea\x4f\xe3\xf5\xfc\xd5\xe6\xb7\xcf\x52\x11\xd2\x17\xc5\x05\x29\xc4\xf9\x06\x3b\x12\x71\xf2\x19\xcc\x4c\xca\xa4\x9c\x9b\xd4\x20\xc5\xfe\x9f\x9f\x2b\x02\x2b\xbf\x1d\x86\x58\xfb\x27\x20\xe6\x45\xba\x7c\xe1\xc4\xa5\x3d\x33\xa2\xea\x2a\xa3\xd5\x0c\xfd\x0d\xbe\xd2\x00\xef\x5b\xe3\x36\xb1\x3d\xd8\x38\x62\x6e\xb9\xcb\x49\x67\xf0\x10\x01\xdb\x67\x30\xfa\xbf\xa6\xea\x15\x2f\x65\x70\x0b\x35\xe7\x7b\x19\x21\xaf\xcc\x76\x97\xf8\x5e\xd1\xd7\x0f\xe1\x6b\x61\x31\xb5\x08\x98\x35\x3d\x0f\x11\xec\xed\x6d\x89\x7e\xa3\x8a\x87\x09\x87\xe9\x8a\x03\xb7\xde\x89\x70\x39\x22\x77\xd9\x7e\xd3\xef\x91\xb5\x81\x62\xa6\x5d\xf3\x74\x97\x37\x40\xc7\xad\x0a\x73\x2a\x88\x76\x6f\xd5\x94\x00\xef\x1e\x41\x3a\x07\xf0\x28\xa2\x27\xdb\x79\xf8\xe5\xa1\xf7\xb6\x91\x48\xf4\x95\xc6\xd4\x4e\x65\x8b\x0a\x47\x23\x8a\xc2\xd7\x32\xe4\x02\x74\x44\x36\xad\xf0\xd5\x8b\xed\xbe\xe3\x5b\xbb\x13\x07\x11\x35\x52\xe2\xd7\x20\x01\x80\x54\xd1\x25\x13\x2c\x9b\x86\x3f\xc3\xbe\xd5\xac\x11\xf5\xf4\xb9\xd1\x53\x62\x7f\x4f\xf5\x62\xe0\xec\x8f\x81\xa8\xf2\xbe\xb4\x54\xbf\x7b\xbd\xcd\xb6\xb4\x94\x21\x94\xbe\xd1\xff\xf9\x37\x25\xfd\xe3\xce\x14\xb2\x1d\x96\x55\x89\x55\x5e\x75\xba\xfe\x08\x44\xc5\x06\xa5\xd5\x5e\x86\x14\x6a\xfe\x08\x47\xab\x31\x4f\x05\xab\x28\x1c\x7e\xdd\x78\x7a\xb2\x81\x27\x18\xf5\xdb\x45\x73\x1b\x69\xec\x86\x6c\x17\xe6\x2c\xde\x70\x97\x79\x2b\xa6\x6a\x05\xd8\x5f\x31\x61\x8d\xa4\x6f\x1b\x17\x49\xe5\x9f\x2c\x03\x14\xd6\x9b\x6f\xb9\x50\xfd\x2e\x18\x2d\xbf\x2f\xec\xd6\xd8\xc3\x87\x1d\x35\x9f\x1f\x43\x80\xdd\x28\xe0\x71\x4b\xd4\x72\xe1\x45\x62\x9c\xa5\x27\x03\xc2\xbe\x27\xed\x47\xc9\xd6\xe4\x18\x65\x08\xe4\x53\x51\x38\x40\xb3\xb2\x2e\x10\xd2\xe7\x06\x53\xbe\xb4\xdb\x91\x2f\xa6\xb6\x01\xb1\xa9\x27\xf0\xa6\xb9\x7c\x06\x32\xf6\xb1\x4f\x78\x4f\x31\xcc\x95\xbc\x62\x44\xb4\x75\x00\x3d\xfb\xbb\xfd\x17\x6f\x3b\x91\x29\xc6\xf4\x05\x0b\x52\xf2\xc3\xfe\x89\x8b\xde\x7e\x06\xb2\x09\x8d\x63\xcd\x6f\x8f\x66\x33\x25\x55\x18\xa7\xc9\xd4\xb5\xba\x62\x33\xbf\xf1\x84\x76\x98\x08\xae\x06\x1a\x56\x42\xd6\x83\xeb\x12\xd5\x1c\x02\xa3\xd6\x22\xb9\x47\x44\x41\x23\x93\xa7\xbe\x73\xa5\x90\x6f\xce\x56\x90\x27\x2a\x65\xda\x63\xff\x0d\xc8\x4f\xa5\xb1\xd1\x96\x84\xe4\x31\xbe\xfb\x4d\x16\x34\x3c\xdc\x47\x93\x84\x83\x89\xc5\x88\x85\x46\x5f\x50\xb5\xee\x1c\x8d\x8c\x30\x3c\x20\x61\x23\xd1\x1b\x39\x4f\xe1\xfd\x81\x8d\x4a\xe2\x33\x59\x68\x58\x90\x28\x64\x3a\xd6\x76\xb0\xf3\x04\x93\x8b\xb5\x99\xcb\xa7\xba\x38\x5b\x62\x39\xda\x5b\x79\x3e\x44\x9e\x5c\xff\xb7\xa7\x51\x69\xf1\x27\x5e\x0a\xa4\xf5\x8b\x4f\xe5\xb3\xe8\xfd\x1b\x95\x4d\x68\xc2\xb2\x8a\xe6\x28\xad\x32\xe6\x08\x58\xc4\x3c\xc5\x76\x51\xb5\xac\xf8\xc7\xf9\xfa\x4b\xe9\xc1\xc0\x72\x0d\x88\xd4\xf3\xc9\x5e\xe0\x2a\x64\x50\xaa\xa8\x5c\xe4\xa5\x63\xeb\x09\xb1\xe7\x5d\x0c\xcf\x07\x7b\x26\x42\xfc\xff\x54\xb8\xdf\x08\xa4\x4f\x87\x27\x24\xbf\x20\x8e\x9b\xd1\xb1\xfd\x49\x26\x6b\x89\x9f\x60\xec\x12\xf3\x30\xa3\x95\xb9\xc9\xcc\x54\xc8\x06\xe6\xda\x7c\x40\x27\x4e\x73\x3c\xb3\x1d\x70\x04\xd1\xba\x5b\x7c\xa1\x4c\x01\xe9\x23\xb6\xfc\x86\x8d\xe4\x93\xab\xea\xd0\xee\xa1\xf1\xaa\xef\x1c\x00\xe2\x05\x9d\xdb\xfa\xa3\xda\x1c\x60\xcd\xcc\x7d\x6c\x2c\x95\x94\x5d\x79\x2d\xdf\x58\x87\x95\x04\x89\x2c\x47\x8c\x28\xaa\x7c\x40\xc4\xfe\x36\x0b\xdf\xb8\x0a\xfe\x1a\x1f\x03\x6e\xde\xbe\xc7\x75\x6d\xf9\xbc\xa7\x10\x74\x70\xc4\xf7\x66\xac\x1e\x9d\x8d\xda\xde\x36\x1b\xd4\x0f\x87\xdf\x90\x30\x56\x90\x21\xa9\xec\x01\x17\x44\xb6\xab\x7f\xad\xf5\xb5\xa0\x40\x8e\x44\x92\xbe\xff\xc6\x7c\x82\x8f\x9f\x46\x9a\xc9\xd1\x50\x6c\xd9\x4c\xeb\x99\x06\xf2\x30\x9a\x7e\xcc\xf0\x1d\xc3\x7c\x97\xfe\x0e\x5e\x63\xd6\x81\xbc\x7f\xca\xf6\xf4\x8e\x7f\x26\x95\x77\x05\x64\x42\x53\x39\x55\xc6\xd5\x59\xf1\x4c\xb0\xd0\xc4\x65\xa6\x54\x1a\xe3\xc1\x62\xec\xa2\xa9\x29\x34\x42\xa9\xfb\xf9\x99\x25\x5b\xef\xfe\x03\x31\x42\x03\xc1\x49\xc7\x6b\x0d\xb4\xf4\x7e\x94\x84\x9c\x45\x44\xcf\xcf\x16\x6b\x51\x46\x9a\xc6\x97\x8e\xfd\x33\x9d\xfd\x9b\xda\xc6\x01\x68\xd2\x09\x84\x6e\x61\x2a\x7b\xff\xda\x3e\x9a\x0b\x4a\x89\x79\x58\xbe\xa7\xc3\xcc\x42\x26\xca\x9d\x25\x6c\xd0\x33\xba\xfc\x22\x52\x48\xc3\x42\xf9\x80\x0f\x85\xe3\x89\xaa\xbd\x20\x72\x31\xe1\xdd\x6f\xa5\xc5\xa6\x52\x44\x99\xd7\x05\x35\xe6\x43\xaf\x1b\xed\x30\xea\xa3\x5c\xa4\xf0\x9c\x8e\x04\x9b\x6a\xc0\x56\xb0\x2d\x00\x6a\x86\x64\x43\xd0\xee\xd4\xdb\xa3\xa3\x42\x6c\x5b\xdf\x10\x81\xf9\xd9\x11\x08\x96\xe6\x9a\x61\x3f\x2a\x1e\xdb\xf6\x64\xeb\xa5\x51\xa5\xea\x00\x24\x1c\x1d\x64\x00\xdb\x77\x70\xa8\xc9\x29\xf0\x36\xf4\xc5\xe2\x61\xda\xab\x78\x9a\x27\x90\xc1\x70\xfa\xbb\xea\xb6\xe4\x0f\xbe\xbf\x60\x98\x96\x15\x2f\xd7\xfc\xb7\x8f\x70\x82\x2a\x6e\x4a\x52\xf5\xcb\x8d\xc3\x8c\xd1\xea\x21\x6f\x1a\xe8\xfa\x57\xec\x02\x73\x79\x10\x8c\x83\x02\x18\xf3\x0a\xb4\xf1\x09\xe6\x08\xa3\x10\x4e\x1b\xcb\x2b\xcd\x3f\x4c\xcd\xfe\x4b\xf0\x0c\xb3\x7f\x86\x43\xec\x07\xf3\x47\x8f\x50\x2e\xb8\x4b\x28\x0c\x20\x47\xf8\x0f\x1f\x36\x00\xb7\xd3\xde\xc4\xdd\x49\xed\x2c\x6b\x17\x79\xdc\xf5\xde\xa4\x5d\x37\xae\xb8\xa8\xb1\x01\x7b\x2d\xb8\x3f\xdd\x15\xe5\x20\x44\xd3\x4c\xc1\xed\x31\x43\x17\x27\xa0\x59\x45\x17\x7b\x04\xd6\x62\x6f\x6c\xc9\xd1\x56\x97\xd7\x7c\x3c\x74\x10\xfd\x38\xba\x41\xa2\xae\xfb\xf0\x1d\xac\x73\x54\x44\xb5\x20\x79\x81\xa9\x05\x63\x3e\x2a\xbe\x35\x3e\x93\x56\x8d\x24\xbf\x3c\x80\x21\xf7\xda\xd8\x84\x51\x8c\xa6\x8c\xd8\x29\x66\xea\x94\xcb\x8a\xc2\x3c\x49\x12\x6a\x78\xce\x45\xa5\x82\xd6\x39\xa3\x69\x4e\x70\xdf\xb4\xd0\x6a\xd7\x42\xaa\x80\x48\xa0\xd9\x1d\xd2\x63\x55\xa5\x07\x11\x57\x3f\xf7\x45\xf1\x72\x47\x5f\x0f\x0f\xdf\xa7\x0f\xc0\x29\x14\xf9\xfd\x37\xc2\x65\x5e\x68\xc6\xe2\xdb\x7e\xb7\x37\xf2\x69\x90\x4c\xb2\xe7\x13\x4e\xc3\xa4\x36\xdd\x98\x80\x62\x20\xb1\x37\xb1\x01\x91\x2a\xa5\xb2\x51\x85\x51\xf2\xfe\x59\x45\xce\x48\x1d\xb0\xb7\x66\x97\x6a\xbd\x02\x0f\x33\x41\x6a\x67\x33\xf8\x01\xe9\x75\x7b\xbd\x94\x2f\x7e\x9a\x28\x97\xdc\x41\x4b\x29\xc5\xc8\xa8\x3a\x0f\xb0\xae\xdb\xcb\xd9\x51\x44\x89\x18\xc1\x9d\x99\x9c\x85\x06\x17\xa4\x38\x53\xb3\x95\x39\xf8\x74\x40\x57\xa0\x3f\xc6\x33\x95\x03\x96\x9e\x32\xd5\xe8\x1a\xd8\x7e\x01\xf7\x50\x31\x97\x08\xe4\x5b\x39\xdd\x02\x32\x50\x1b\xaa\x9f\xe1\x60\xb2\x06\x8a\x74\x01\xd5\xae\xa2\xe8\xb3\x37\xa9\x61\x81\xd5\x77\xd9\xe0\x7e\xc4\x13\x1d\x55\x8d\x38\xad\x65\xdd\x8f\x31\xcd\x64\x02\x5d\xf1\xf9\x32\x47\x31\x60\x24\xcf\x4e\x1d\xbd\x06\xc3\x31\xac\x00\xff\x90\xc9\x58\x46\x0d\xc4\xba\x4b\x5b\x63\x12\xeb\xc9\x95\x87\x2d\x60\xda\xcc\xb9\xf5\xd1\x17\xdd\x77\xc8\x2e\x74\x9e\x28\x34\x36\x2f\x63\x68\x36\x72\x50\xe7\x97\xf7\xfb\x7c\xe8\x40\xdb\x62\xff\x9f\xd1\xb4\x23\xe1\x84\x66\x70\x3b\x1f\x0a\xba\x11\x6e\xc1\x69\x26\x60\x8b\xa8\x1a\x55\xfe\x26\x45\x98\x8b\xa3\x27\xf9\xe2\x82\xa2\x0c\x1d\x28\x9b\xae\xc9\xca\xbc\xdd\x9e\x73\x5f\x73\xd9\x0f\x57\x62\x2e\x12\x22\xfc\x3b\x6b\x73\x40\x12\x64\x53\x76\x8e\x0b\xf0\x04\x45\x08\x0a\x4a\x9d\x56\x11\x5a\x05\x8d\x13\x2f\xcc\xa4\x58\xe3\x99\x1d\xac\x9b\x2f\x04\xb2\x09\x23\xf5\xf7\xbf\xdd\x93\xac\x97\x76\xa5\x77\xc6\x7b\xac\x87\xb1\x23\x4d\xb5\x0b\xea\x20\x1c\x7e\x02\x16\x8a\x2d\xec\x9d\xe8\x55\xa0\x71\x1d\xda\x68\xa2\xfa\x88\x15\xdc\x31\x5b\xc7\x61\xb3\x93\xca\x18\x4c\x94\x2c\x7f\x76\x8b\xa2\x65\xef\x9b\x69\xde\x8a\x6a\xa3\xf3\x27\x7b\x00\x42\xab\x6b\xca\x4d\xf8\x7a\x66\xeb\x19\x37\x0d\x56\x33\x76\x74\x69\x0f\x2b\x10\x7a\x4f\xb3\x43\x12\xeb\x9b\xca\x12\x9f\xf8\x81\xb1\xed\x4d\xdd\xae\xb9\x35\x8f\xab\xf5\x20\xdb\x76\x97\xfe\xd9\xc4\x36\xd1\x92\x1a\xe3\xc6\xd2\x95\xdd\xb0\xe4\x82\x0f\x46\x5f\x52\xe1\x8a\x21\x6f\x77\xa4\x6d\x7c\xb4\x79\xc8\xb7\x53\x30\x2b\x11\xa3\x31\xd2\xfc\x70\xd2\xa0\x7d\xef\x55\x4f\x06\x3c\xf9\xd4\x78\xa9\x12\xf2\xc7\x98\x80\x18\x65\x20\xa5\x9c\xdb\x8b\x26\x38\x6d\xa0\x43\x48\x06\x26\x28\x18\x26\x6c\x28\xaf\xe6\x1b\xb7\xc3\x97\x7e\x9a\x4b\x5e\x1b\xa0\xb5\xe5\x99\xe2\x9f\xb9\x71\x2b\xf7\x0a\x85\x66\xb1\x17\xb9\xa8\x31\x5b\xb4\xd1\xcd\x02\xa0\x75\x7b\x46\xe1\xd2\xf1\x9a\xc1\xbd\x4d\x14\x0a\xa4\xaf\x48\x91\xf6\x65\x14\x5d\xb0\xa6\xf3\xb5\x3a\x15\x3a\x7c\x85\x39\x36\xe9\xe7\x43\x1d\xb3\xcf\xcc\xbc\x27\xf6\x24\x1d\x0b\x6f\x4c\x6e\x1a\x39\xb9\xe3\xeb\xc0\xd5\x41\xa7\xca\x85\x34\xbe\xc1\x1d\xbd\xf0\xb0\x45\x9a\x8a\x7d\x9e\xb3\x9b\xc4\x84\xbc\x99\x95\x78\x3d\xf0\xac\x7b\xb0\x3b\x6e\x22\x3e\xd2\x76\xe8\x96\xae\x6d\xd7\x7d\xfd\xfd\x60\x4d\x68\xee\x83\x52\x5b\x7b\xc3\x9a\xb9\x05\xee\xf7\xd5\x80\x49\x4a\xd8\xd4\x1e\x61\x80\x51\x29\x07\xfa\x83\x3f\xed\xef\xe2\x63\x4d\x20\x83\x68\xc1\x1c\xc5\x3d\xa5\x14\xd8\x10\x21\xab\x34\xf5\x52\x2b\xcb\x80\x21\xba\x07\xb5\x31\xd5\x36\xca\xf3\xcd\x85\xf3\x84\x30\x58\x00\x7a\xaa\x64\xcc\xc7\x62\xa9\x25\x18\x50\xc7\xda\x08\x3b\x71\x60\x6f\x10\x36\xa7\x14\xe3\xe8\x9d\x02\x81\x97\xcc\x12\x1e\x2f\xc9\x15\x4d\x99\x74\x19\x21\xb3\x88\x6b\xba\x0e\x02\x99\x32\xa2\x97\x86\x47\x1b\xfc\x5b\xdf\x28\x55\xd6\xc3\x2c\x84\x42\xb7\x33\x54\x15\x47\xd6\x83\x3f\x80\x01\xe9\x23\x96\xc3\xe1\x79\x06\x21\x48\xa9\xd2\x96\xce\x0f\xfc\xbf\x7a\xed\x2c\x2f\xf2\x00\x40\xcf\x74\xec\xea\xe1\x07\x28\xfd\x01\x7d\xb4\xd5\xf9\x6d\x0b\xb2\xe1\x4b\xfa\xce\x0d\xd0\xe1\xd0\x9a\xf7\x9b\x89\x1a\x78\x52\x1f\xea\x5f\x7f\x13\x08\x98\xb1\x55\xb0\x15\x88\xba\x0a\xfa\x28\xe8\x37\xe8\x49\x6e\x77\x73\x8b\xb3\x3b\x2c\x1b\x08\x8f\xe5\x54\xc8\x1a\xba\x61\x2a\xdd\x6e\xed\x4c\xc4\xd9\x92\x32\x2b\x8b\x38\x0f\x6f\x36\xfb\x81\x8a\x7e\xc7\xdd\x4c\x86\xac\xd0\x35\xb4\xbb\x0b\xe3\x3c\xaf\x0e\x42\x3b\x49\x1c\x2f\x7c\xdc\x33\x25\x48\xe1\x76\x38\x66\x42\x08\xae\x16\xb2\x3c\x15\x91\x0e\x58\x52\xf2\xa3\x0c\x50\xcc\xec\x3a\xc3\xae\x33\x3f\x03\xfb\xa5\xa2\x01\xa9\x97\x46\xf7\x36\x12\x40\xff\x88\xcf\x03\x71\xc2\xf9\x05\xec\xf9\x10\xb9\x4e\x57\xf1\x20\xbd\x71\x49\x7b\x97\xe2\x25\x51\x38\x27\xd3\xd1\x1a\xba\x29\x22\x04\x23\x20\x36\x4a\xe9\x92\x40\xe2\xe2\xdc\x5a\x05\x62\x3c\x97\xfe\x8f\xed\x6f\xf5\x7f\xc8\xf7\x23\x9c\xe4\x0b\x01\x12\x70\xcf\x57\x87\x50\xee\x7a\x4b\x48\xc4\x6a\xbf\x11\xc9\x00\xfe\xd3\xd7\xd5\xaa\x0c\x57\xde\xfc\xb6\x4c\x53\xb7\xe3\x58\xa9\x31\x0c\xf1\xff\x1d\x18\x07\x30\xec\x1b\x56\x7b\x51\xa0\x1e\x8e\x41\x69\xea\x86\x84\x05\xb0\x4d\x5f\xdd\x45\xad\x4e\x3c\xa7\xf5\x4c\x17\x48\x5f\xaf\xf2\xcc\xf2\x7b\x84\x0a\x97\x51\x2a\xa7\x9e\xaf\x81\xcc\x1d\xf0\x73\x35\x81\x45\xda\xb9\xaa\x75\x1d\xe5\xa7\x9e\xf2\xdf\x8b\x4a\x32\x2e\xb5\x38\xe5\xc8\x15\xe9\x05\xa3\x2e\x4c\x8c\x75\x85\x24\x22\x9e\x9f\xf1\x17\x6e\x14\xe0\x41\x10\x1e\x6e\x4f\xcf\x8f\xd9\x12\xee\xbb\x28\x99\x74\xa0\x50\x87\x4d\x26\x66\xb8\xd5\x8b\x44\x57\xa3\x12\x12\x49\x41\x7c\xc0\x9a\x0e\x35\x9e\x94\xa2\x65\xa1\xdd\x0d\xc1\x18\x05\xa2\x59\x01\x0c\x87\xf1\x6a\x32\x33\xef\x4c\x97\x79\x16\xdb\x74\x56\x7a\xab\xfe\x11\x42\xb5\xcf\xf0\xfd\xb0\xc2\xc7\xc0\xce\xca\x7b\x3f\x6e\xd4\x92\xd4\xec\xcb\x0c\xd1\x4d\x04\xc3\xb0\xc0\x89\x4e\xa0\xa2\x9d\xbd\x48\x0d\x67\xbf\x99\x78\x99\x88\x3d\xe3\x58\x14\xe2\x2b\x79\xd5\x72\xa4\xe9\xcc\x09\xb1\xeb\x11\x29\x67\x57\x75\x46\x7b\x3a\x50\x48\x2b\xe4\x03\x2f\x71\x6c\x0f\x9d\x79\x6a\x7e\x59\xea\x0c\xae\xce\x8c\x55\x48\x68\xc2\xfa\x89\xc5\x53\x1d\xf3\x31\x6b\xf8\x7e\x41\xc3\x2d\xd9\x62\x32\x4f\x1d\x12\x5f\x04\xa8\x57\xd0\x3a\xef\xa5\xdb\x13\xc7\x42\x3e\x3c\x1d\x4d\xeb\x0f\xa0\x14\x21\x8e\x1e\x71\x5d\x04\x16\x17\xe8\x85\xaa\x11\x31\x41\x18\x72\xcc\x40\x70\x54\x2b\x36\x4f\x16\xe6\x47\x97\x96\xd6\xc9\x90\x08\x05\x5b\x4e\xb8\xe1\x74\xa6\xbb\xca\xd3\x76\x43\xd3\x74\xfe\x41\x99\x9d\xf0\x51\x7c\x6a\xd7\xa5\x75\x77\xc7\xad\xb7\x85\x94\xfb\x0d\xdf\x03\xa6\xa4\xaa\x03\x42\x2c\x1e\x3d\x80\x3d\x23\xe9\x01\x2b\xf3\x78\x4d\x48\x63\x2b\x59\xe1\x33\x6d\x9f\xad\xa2\xf4\x91\x15\xe5\xf2\xbd\x5b\xdd\x71\x96\x22\x01\x57\x01\x11\xb6\x83\x18\x00\xb6\x08\x52\xd0\xad\xf7\x74\xb4\x38\x6b\x96\x93\x52\x4b\x9b\xc4\x70\x3f\x6b\x3a\xe8\x63\x1b\x56\xeb\x68\x0b\x53\xee\xf7\x4b\xc5\x71\xd5\x78\x96\x73\xd2\x4a\x77\x52\xbf\x73\x32\x0c\x9e\x01\x32\x00\x2e\xd0\x33\x08\x33\x3c\x48\x8f\x02\xc6\xb4\xf9\x26\x66\x22\xc8\x0a\x30\xf2\x01\xa8\x21\x81\x6e\x40\xfa\x48\x0f\x0f\x04\xfb\xad\xca\xcc\xaa\x5c\x7e\xad\x3c\x8c\x3e\x9e\xc8\x14\xa6\x39\x03\x23\x4b\xdc\xb3\xb8\xfb\xa4\x81\xa8\x95\xbd\xb9\x01\xb2\x25\x25\xf1\xfb\x9e\x08\x5b\x60\x0e\xcd\x69\x0b\x51\x5b\xdf\x78\x95\x73\x41\xfd\xfe\xdd\xfb\x40\xba\xcc\x32\x92\x63\x14\xfe\xdf\x12\xce\x78\x04\x62\x23\xe1\xd9\xa5\xa1\xb7\x6e\x45\x0d\xa2\xf0\xfd\x16\x64\xa7\xca\x06\xab\xab\x7e\xef\xd0\xc3\x61\x9d\xd9\xa7\x64\xad\x8c\xdf\xed\x2a\x05\xa0\x19\xa8\x34\xbe\xbe\x18\xf5\x93\xd6\x51\x6a\x3a\x6d\x6c\xe1\x22\x74\xca\xe6\x1a\xb1\xc5\xfc\x1a\x8f\x4e\x56\x06\x16\x29\x25\x72\x1f\x06\x00\x76\x50\x51\xc3\xb4\xd8\x13\xed\xa5\xe5\xad\xd6\x8b\x00\x82\x09\x86\x5b\xfb\xdc\x89\xf8\x18\xea\x96\x09\x3a\xff\x76\xf7\x1a\xc6\x00\xc6\xe3\x4f\x20\x3b\x6e\x3b\xef\x84\x43\xb1\x81\x51\xc6\x00\x41\xf3\x2e\x36\xf1\xf0\x44\x05\x75\xff\x87\x14\x42\xc9\x0a\x92\x57\x3a\x31\x05\x8b\x64\xd8\xe7\x10\x1c\x5b\x9e\x5a\xad\x32\x88\x1d\x12\x7b\xea\x84\xeb\x3c\x7e\x3a\xbe\x40\xfb\xb4\x43\xb2\xd6\x20\xc4\x5c\x7a\x38\xe2\x8a\xd8\xa9\x66\xf8\x2d\x82\x6b\x74\x6d\x12\x73\xb7\x52\x9d\xa1\x1b\xfc\xc8\xcc\xbb\x4b\x1f\x77\x40\x88\x52\x91\xf9\xe5\x62\x17\x7e\xb2\x42\xa8\x1b\x80\x11\xf6\xda\x00\xe8\x53\xf8\xbe\xf4\x4c\xf3\x05\x58\x20\x28\x5c\xf2\x6a\xe5\xdd\xd7\x56\xe1\xd4\x12\x77\xac\x13\xe9\x5e\xbf\x92\x4e\xb9\x25\x12\x46\xf6\xdf\x33\x05\x02\xf8\xf5\x28\x32\x69\xfc\x0e\xf8\x9d\x2a\x13\x07\x6c\x0b\x22\x72\x58\x5d\x80\xde\xb4\x0e\xe3\x6f\xa5\x32\xcc\x6e\x73\xe1\xc6\xd4\x94\xa7\x94\xb1\x8a\x1e\xa1\x24\x4e\x1b\x11\xd7\xf7\xbd\xdc\x54\xb6\xb8\xa2\x51\x4b\x3c\xe9\x73\x74\x39\xc0\x15\xdf\xef\x03\x72\x95\x69\x6f\x8c\xd3\xe4\x68\x8b\x9b\x65\xac\x02\x9a\x49\x39\x0f\x74\x32\x94\x3a\xb2\xd3\xf6\xdf\x74\xfa\x17\x78\x0a\xcf\xb8\xbb\xd4\xcc\x93\x1c\x67\x01\xf4\xf9\xcf\x3e\xcd\xfd\x36\x05\x62\x12\x99\x30\xd5\xb4\x71\xf9\x27\xe4\x3b\x86\x26\x26\x21\x92\x84\x91\x11\x0c\xfb\x5b\xe5\x7c\x5f\xb4\xe6\x1a\xd9\xd8\x0f\x3d\x2d\x8f\x52\xc4\x14\xea\xcc\x14\x72\x3c\xcf\xd6\x43\x1c\xa6\x45\x50\xfc\x6b\xa7\xa2\x6e\x24\xc4\x25\x43\xe8\x9d\xc5\x32\x2e\x48\xba\x44\x02\x69\xaa\x61\x3b\xea\xa1\x6e\x22\x48\x06\xed\x30\xfa\xcf\x79\xd3\xa4\xea\x23\x27\xf6\x3f\x3d\xe9\x49\xfb\x1b\x99\xc8\xc3\x86\xba\x7f\x16\xcf\xfe\xe8\x2b\x64\x9c\x8b\x3f\x1f\xf4\x0f\x62\x79\x98\xc6\x7b\x82\x5e\x80\x8a\x82\xd6\x26\x5e\xbc\xb0\x84\x39\x6b\xd0\x72\x35\x70\x48\xd6\x04\x98\xe8\x1e\xbb\x93\x60\x3e\x47\x97\xbc\x0c\x78\x21\xce\xee\xb8\xf7\x34\x70\xd2\xa1\x55\x4f\xe0\x0c\x93\x77\xa1\x94\x67\x14\x4d\x8a\x41\x37\x9a\x87\x19\xa6\xec\x95\xd9\x3c\x6b\xbe\x1d\x1c\x39\x86\xf9\xd5\x1f\x05\xf6\x72\xdf\xa0\xa7\x90\xeb\x25\xac\xe3\xcc\x63\x2a\x3f\x82\x6e\x5b\x18\xbe\x4f\x04\x5a\xbc\x32\xda\x24\x2f\x21\xcb\xa4\x51\x40\xf4\xfe\x8c\x0b\xda\x82\x9b\xa4\x52\x29\xf9\xbd\x73\x49\x23\xca\x6e\xb1\xd9\xdd\x26\x1a\xd4\xb3\xac\xb7\xee\x48\x1d\x5b\xfa\x5b\x0f\x49\x03\x44\x2c\xc0\x41\x61\x43\x64\x11\x82\xe8\xd9\x8a\xfc\xd4\xf8\xe4\x12\xc1\x0f\x12\x80\x58\xc7\xfc\xc1\xca\xa1\x20\x90\x9a\x1f\x4d\x54\x1c\x2d\xd9\xfa\x2b\x34\x52\x3e\xc3\x77\x06\xb7\x5c\xa5\xb4\xd6\xa5\x1a\xc2\x89\x5c\x74\x93\xe5\x37\xd9\x92\x76\x94\xdb\x1a\x3a\xb0\x17\xd2\x8a\xb6\x11\x5c\xbd\x66\x11\xf1\x70\xd9\x73\x5c\x5e\x25\xe8\xbc\x13\x5e\x73\x3b\x3f\x18\x4c\x83\x4d\xf6\x29\x8e\x93\x51\x35\x89\xa1\x0e\xbd\xcd\xcc\x98\x38\x0b\xf8\x2c\x3f\x62\x96\x82\xa0\x4f\x30\xaf\x9b\x7a\x6b\x9c\x51\xa6\xf2\x20\xd3\xd7\xef\x1f\x8c\xea\xbd\xea\x26\x9a\x36\x45\x1d\x87\x89\xb7\xdc\x0a\xc1\x81\xb5\xc8\xe3\xa1\xdb\x7d\xb8\x52\xcb\x3a\x4f\x87\x4a\xa3\x83\xe8\x64\x76\x85\xe0\xca\xc2\xb5\xf7\x9a\x28\x3c\x79\xe0\x5a\x7c\x27\x6e\x3d\x80\x41\xd6\x6d\x5a\xb7\x74\x86\x36\xfe\xbd\x2c\x24\x6d\x9e\x34\x63\x85\xcd\x9a\x90\x58\x2e\x57\xf1\x5c\xfb\x06\xdb\xdd\x47\xbe\x82\x15\x73\x32\x11\x17\xc1\xe7\x60\xef\x76\x71\x5c\xa7\x3c\x53\x24\xfc\x0e\xe6\x8d\xcd\xdc\x87\x61\xd4\x4b\x14\xc0\xef\xc7\x6b\x48\x5e\x5f\xd3\xa3\x96\xdc\x25\xcd\x4a\x67\x2f\xc8\x51\xee\xa2\x8b\x4b\x57\xc5\xf0\x73\xe9\xf4\x9f\xc2\x94\xeb\x7b\x00\x6a\xd6\x8d\x2c\x57\xc8\xb3\xe6\x1b\x88\xe1\xed\x10\x72\x79\xde\xe2\x2a\xa4\xea\x2e\x62\xae\x84\xef\xa9\xba\xc9\x09\x9c\x92\x97\x56\x15\x2f\x5a\x5f\xa6\x1d\xff\x90\x4e\x18\xa4\xe6\x35\x3b\x0c\xae\x60\xf5\x2a\xdd\x0c\xcd\xe5\x1d\x39\x10\x8a\x77\x27\xff\x0e\xaf\xde\x9a\x2b\xf9\x88\x27\xaf\x28\xb2\xb0\x5e\x82\x96\x8d\xfa\xa7\xa6\xb0\x08\xf2\xd2\x0f\x91\xef\xb2\x72\xfb\x17\x9b\x60\xa1\xef\xfe\x63\x8c\x05\xab\x8d\x8f\xbc\xac\x53\x06\xa2\x51\x3c\xd0\x00\x61\x92\xa6\x41\x6d\x71\x2d\xee\xf6\x60\x4a\x9b\x67\x08\x11\x0d\xde\xd9\x60\x3e\x6a\xed\x8c\x7f\x49\xbe\xaf\x1e\x54\x20\xad\xc8\x56\x37\x94\xf3\xe0\x03\x53\x81\xbf\x98\x21\x47\x30\x87\xd3\x41\x79\xf9\x56\x77\x9f\x3e\xd5\x53\xd6\x04\xf0\x93\x78\x27\x64\x9b\x53\x15\xff\x3e\xa5\xcc\x5b\x90\xba\x63\x54\x78\xe4\x8f\x50\xbc\x53\x1b\x28\x3c\xe1\xd8\x49\x6f\x77\xc5\x59\x38\x98\x95\xe3\x0f\x10\x59\x43\x74\xf0\x42\xc5\xb4\x9e\xd5\x25\xca\xc6\xba\x0b\x34\x4b\x59\x06\x26\x65\x24\xf7\x2f\xbc\x03\xf2\x68\x89\xef\x97\xa7\xb3\x5a\x8d\xf5\xbc\x05\xe8\xca\x79\x37\x68\xbc\xae\x9d\xe5\x2f\xcc\x07\xde\xda\x97\x09\x2c\x1b\x28\x9c\x9e\x60\xca\x08\x0b\x62\x08\xde\x61\x5d\x49\x32\x7d\xe6\x30\x8f\x23\xed\x15\xd5\x6e\xdc\x0e\x4b\x0e\x6d\x89\xb5\x09\x82\x23\x55\xa1\xf7\x4e\x1b\x93\x43\xc7\x32\x56\xf9\x5d\x6a\x4d\x48\x01\x91\xa7\xb1\xf2\x26\xa7\xb5\xb2\xd6\xd0\xbf\x8d\x02\x6a\x2b\x83\xba\x4a\xf3\x0d\xbc\x7f\xba\xa3\x2d\x62\x74\xd5\x54\x89\xfc\x34\x49\xf9\xf1\xe9\xac\x4f\xb1\x1d\xc7\xc4\x6b\x43\x2d\xb1\x30\x9a\x62\x78\x2c\x7b\x9f\x27\xd8\x2d\xd8\x91\xc1\xd1\x89\xc6\x96\x3d\xa4\x8a\x96\x8c\x89\x5b\x83\x3b\x40\x58\x5e\xe9\x8d\xe0\x5e\xeb\x32\x80\x79\x70\x80\xfb\xdf\x35\x9a\xec\x33\x99\x12\x63\x11\xa7\x71\x4d\x08\xb7\x36\xab\x1c\x01\xc9\xca\xe4\x02\xe9\x37\xf6\x24\xa6\xec\x5a\xfa\x8a\x5b\xcf\x45\x3c\xda\xc9\x3b\x88\xbc\x12\xb7\xfc\xfe\x7c\x92\x85\x8b\x07\xdf\x8f\xb7\xcf\xa8\xbc\x16\x34\xa4\x25\xaf\xd2\xb3\x7c\xd3\x49\xa5\x56\xa2\xd4\x3c\x00\x23\xbb\xf6\x42\x23\x64\x59\x4e\xa4\xaf\x2b\x53\x63\xb3\xb3\x3d\x53\x2e\xed\x74\xca\xe2\xf9\x48\xc3\xae\x66\x95\x8f\x82\xcc\xc4\xbf\x22\x51\xbc\xd9\xe8\x27\x4d\x5c\xf7\x58\x9b\xfd\x33\x57\xaf\x93\xa4\xd1\xd8\x56\xb2\xb2\xee\x1e\xfa\x20\x7e\x1e\x24\xce\xf9\x4b\x4f\xc7\xef\x37\x1a\x32\x79\x30\xa0\xf4\xab\xf4\x0e\x0d\xa3\x09\x3f\x53\x16\xb9\x8a\x90\xaa\xef\x2a\x9a\xa9\x14\x2a\xcc\x90\x7e\xce\x7a\xc6\x97\x1e\xba\xa4\xcd\x2f\x37\xd4\xd2\xd4\x88\x3f\x67\xf8\xc9\xc9\x9d\x0d\xed\x9f\xc1\x9f\x75\x59\x60\xa7\x8f\x17\x49\xd9\xfb\x90\xce\xc5\x40\x9b\xe1\x8a\x0e\x61\xa1\x9a\x2a\xc4\x14\xbb\xc3\x28\x4c\x3e\x64\x15\x66\x6a\x43\xf5\x53\x3b\x31\xb7\x36\x33\x77\xbd\x66\x88\xdd\xe0\xb1\x4c\x2c\x21\x88\xbe\xdd\xeb\x26\x2b\x3d\xf6\x95\xf3\xa2\x65\x37\x33\x5a\x3e\xac\x7a\xaa\x2a\x59\x43\xd3\x3d\xbd\x67\xa6\xf5\x75\x84\x78\x51\x5f\x29\x3f\xae\x91\x5b\x6e\x68\x11\xed\x60\x4e\xa5\xf7\x06\xb9\x0d\x68\xa1\xf0\x06\xe2\x6d\xdd\x67\xf9\xae\xfe\xd9\x5a\xbf\x80\xbb\x97\x7b\x25\x54\x01\xb7\x08\xfb\x15\x6a\x4c\x73\x85\x5e\x74\x09\x97\x0e\x08\xde\x3d\x7d\x1a\x97\x92\x90\xe3\xdd\x26\x9e\xeb\xee\xb6\x6c\xa1\x15\xc1\xd6\x91\x47\x12\xcb\x55\x8f\x2e\xf7\xae\x1f\xb3\x60\xdb\xd4\x4f\xa1\xef\x53\xb2\xef\x6b\x59\x8c\x1a\x4e\xaf\x67\x8f\x54\xb5\x63\x03\xd9\x3d\xfa\xe8\x61\x4c\xb2\x1d\x02\xd8\x0a\xf8\x30\xe9\x2c\xfe\x76\x97\xb6\x68\xe1\x08\xe7\x6a\x37\xc3\xb7\x85\x74\x12\x5f\xe9\x31\xc2\xb5\x9c\x33\x3e\x9d\x72\x31\xc4\x68\xc7\x4a\x9a\x4d\xee\x68\x01\x54\xca\xba\x19\x52\x2c\x80\x64\xab\x17\x9a\xf5\x9c\xae\x95\xe4\x96\x8c\x95\x1d\xc5\x46\x7f\xeb\x5f\x99\x55\x63\xdd\x7f\x78\xc0\x4a\x70\x0d\xb0\x92\x7f\xaa\x76\xa1\x02\x0d\x05\xbf\x0b\x06\x1e\x7f\xc2\x61\xb6\x7a\xea\x02\xc5\xb2\xbd\x6f\x8a\x90\x28\x4e\xd7\x55\xfa\x8a\xc8\xe7\x9f\x47\x5f\xdc\x9f\x26\xdc\x63\xca\x27\xa8\x0f\xb9\xf4\xb0\xb8\x72\xcf\xe0\x86\xcf\x6c\x7c\x8e\x6a\xf4\xf8\x44\x43\x3e\x01\xd7\x08\xc8\x90\x0f\x4d\x40\xe6\x67\x0b\xaf\x70\x6a\xcb\x23\xb0\x29\x30\x91\x2e\x5c\x23\x7c\x1d\x98\xb4\x28\x34\x0b\x97\xfb\x6e\x65\xc8\x88\xe3\xbc\x73\xe5\x98\x34\x29\x8c\xd8\x81\x27\x22\x06\xe2\x8a\xc2\xc5\xb4\xf6\x1c\xfa\xf7\xd6\x32\xf9\x31\x68\xb2\x57\x31\x70\x7b\xbe\x50\xb6\x48\xf0\xaa\x61\xbf\xf3\x24\xb9\x82\x5e\xa0\xe3\x94\xb5\x9a\x56\x36\x89\x16\xd1\x74\x12\x67\x37\x8d\x5d\x3d\x55\xda\xca\x7d\x70\x5e\x71\xa0\x55\x13\x80\xe3\x38\xae\x1a\x80\x07\x13\xcc\x25\xad\xfa\x2d\xa5\x4d\xb1\xb9\xee\xc1\x86\xc3\xa0\x79\xa5\xb7\x0a\x1f\x5a\xe7\x8e\x7b\x10\x0f\x10\xe1\x4b\xd6\x42\xeb\xb7\x95\x1d\xf2\x2b\xa3\x22\x37\xa5\x0f\xf2\xe1\x91\x84\xcb\xa9\xd0\x60\xac\xa2\xdb\xd0\xcc\xcb\xc7\xf4\x0c\x59\x8a\xc0\x76\x89\x35\xb5\x02\x2c\x0a\x70\x0c\xb3\x73\xad\xfd\x42\x44\x4b\x31\xc8\x94\x05\x70\xdd\x6b\x8e\xb4\x36\xf9\x6a\xd4\x4e\xee\x54\x2a\x3b\x95\x85\x5f\x43\xdd\x94\x9b\x9d\x3c\x1d\x8f\x68\x80\xa2\xdc\x31\x98\x6b\x84\x6d\x81\xdf\xb5\xae\xe0\x00\xf4\xb1\xca\x5c\x8f\x66\xa8\x0f\xa3\x04\xe2\x61\x1b\x21\x67\x0e\x14\xe4\x56\x5c\x7e\x0d\xd5\x86\x61\x38\xc0\x85\x89\xea\x89\x68\x74\xc0\xa8\xc0\xa1\x59\x6b\xb6\x06\xb3\x23\xb4\xb9\x85\xf1\xce\x69\xd7\x29\x47\xec\xe2\x4a\x8f\x83\xd9\x65\x56\x66\x31\xd1\x10\x23\x7d\x45\xad\xd8\x15\x8f\x99\x14\x61\x34\xc3\x90\xf4\xf0\x49\x88\xa8\xb1\x4e\x7d\x39\xbe\xf9\x61\x62\x59\xff\xe8\x45\xbb\xf8\xcb\xad\x15\x4c\x7b\xd5\x42\xbc\x28\x87\x14\x4e\x8c\xfb\xc0\x62\x3d\x88\x13\x51\x35\x25\x0d\xf4\xd9\xee\xe5\xf3\xee\x84\xf7\x58\x4d\x1c\x4f\x7a\x0b\x8f\x82\xae\x8d\x19\x9b\x33\xfd\xd3\x14\x86\x0e\x73\x9c\x46\xce\x1e\x20\x7f\xa4\xb7\x86\xbd\x75\x57\x34\xc7\x98\x54\x41\x73\x96\x6f\xbf\x1d\x2a\x81\xad\x3b\x8c\x7a\xbb\xe6\x36\x02\x2b\x74\x09\xb7\xc2\x17\xc0\xe5\x57\x76\x5d\x6c\x76\xcf\x49\xdc\x72\x3c\x15\xee\xea\xe4\xb5\x29\x50\x14\x1d\x06\xd4\x06\xe1\xe8\x0c\xab\x1a\x16\x1d\xbf\xec\x41\x5e\xa4\xcc\xa4\x29\x34\xeb\x52\x85\xa2\xcc\x6d\x26\xc2\x76\xfb\xa4\x61\x8d\x65\x8d\xed\x26\x69\x39\xd5\xe6\x8a\x8c\xd7\x29\xe5\xb2\x03\x75\xeb\x74\x44\xfe\x1d\xc4\x02\x8f\x5e\x2d\x1f\x4a\xe0\x51\x59\x95\x1c\x80\x70\x8f\x51\xe2\x12\xbb\x54\x87\x46\x1c\xf1\xf6\x4c\xcd\x99\xb8\xe1\xb2\xc2\x5e\xc4\x1a\xe3\x88\x0b\x02\x7f\xdd\xde\xa0\x1c\x5b\x0d\xd6\xaf\xa1\x7e\x48\x17\xc1\xd4\x65\xd2\xff\x9f\x2a\xe1\xf0\xf4\x4c\xe0\x2f\x99\xb4\x72\x51\x87\xd9\x2b\x57\xd2\x2c\x5c\xbf\x76\xa9\xb4\x38\xaf\x4c\xd9\xd6\x1e\x57\x9e\x43\xc6\x8f\xb0\xdc\xa5\xaf\x1d\xf9\x00\x9a\x32\x78\x75\x59\x1c\x55\x22\xe8\x65\xc3\x14\x41\x4b\x92\xdb\x14\x26\x87\x76\xdb\x8f\x12\x53\xf3\x03\x92\x54\xf4\x60\x12\xbb\xed\x62\x16\x4d\x7f\x9f\x0e\xc6\xc5\x29\xd6\x9d\x99\x11\xfe\xea\x13\x5d\x3d\x04\x91\xa8\x04\x96\x77\x63\x57\x69\x9c\x1d\x07\xfb\x9c\x6a\xa2\x3f\xec\xdc\xb7\x60\x1b\x9e\xcf\x1c\xbd\x51\x5e\x08\x40\x07\x92\x95\x1b\xc6\x0a\xac\xac\xfa\x7e\x7d\xae\x21\x0d\x3c\x08\xca\xa6\xa7\x24\x23\xfe\x7f\x82\x2c\x53\x83\xbd\xd9\x01\xdb\xc6\xb4\x69\x94\x32\x33\x3d\xbf\x46\x1a\xb8\x7e\xe0\xc9\xa0\xa6\x23\xc2\xf8\xd9\x0e\x76\xc9\x3d\x41\x86\xc2\x43\xd9\x17\x83\xe3\x62\xe9\xaa\x9d\x28\x6b\xf5\x2c\x86\x66\xcf\x6b\xfa\xe3\x53\x68\xb4\xa6\x98\x08\x64\xbb\x3e\xaf\xb3\x3a\x83\x50\xd7\x14\xd0\xe9\x65\x97\xe4\xe9\x11\xa8\x8c\x3d\x83\xe9\xd8\xe6\x53\xa6\x6c\xe9\x70\xd1\x35\xbd\x6e\xa6\x50\xa1\xee\xc9\xc2\xc9\x21\x0a\xe1\x8b\xa7\xe1\xfc\x61\x07\xae\x5b\x08\x03\xf2\x24\x80\x5a\x28\x2d\xe9\x5b\xb3\x6f\x60\x55\xbb\x94\x9b\x6e\x75\x8e\x29\xbf\x5f\x10\x65\x35\xad\x6e\x0c\xcc\x45\x15\x5a\x36\x3b\x3d\x40\x62\x63\xa4\xdc\xde\x00\xdc\xde\x0d\x8c\xd3\x50\xf1\x33\x8a\x3c\x0f\xc8\xc6\xd2\x7f\xcb\x7d\x2a\x88\x7d\xf7\x88\x7e\x7f\xd2\x16\x72\x93\x5e\xc6\xbc\x70\x0b\x02\xf4\x22\x5f\xcc\xed\x3d\x3e\x21\x6a\x2c\x52\x4a\xb4\x3b\x51\x0a\xa4\x5f\x41\x61\xc2\xc9\xe8\xb7\x08\x7c\xff\xac\xae\x2c\xff\xb6\x72\xf6\x41\x6d\x6b\xda\xd6\xcb\x4c\xf4\x7e\xf3\x2b\x9e\xe1\x1e\x63\x0f\x08\xed\x20\x65\xb5\x8d\x56\x5c\x6a\xcc\x9d\x29\xfb\x24\x71\x15\x1f\x51\x14\xf1\x01\x0d\x2a\x55\x7e\x37\x5b\x5f\x5d\xa3\x01\x3a\x29\x3d\x80\x4a\xd7\xbd\xb0\x0f\xad\xfc\x66\x62\x49\x68\x84\x73\xd3\xf9\xf1\x41\xaf\x32\x96\x4b\x83\xba\xda\xe6\xc9\xfb\xe5\xf8\x41\x68\xdd\x12\x4d\x46\xc6\x72\xb8\x4d\x5c\x85\x1c\xa8\xce\x7d\x32\xe5\x18\xa4\x11\xb7\x93\x7d\x75\xca\xd0\x64\x06\x6d\xee\x14\x68\xe0\x37\xd5\x0a\x3a\x50\x66\x19\x3c\x9b\xd8\xc4\x80\x18\xed\x9b\x96\x79\x46\xa5\x63\xca\xfe\x26\x4b\xc9\xb8\x15\xec\x5e\xb2\xa7\x9d\x7a\xbf\xcc\xeb\x6b\x3d\x04\x9c\x47\xbd\x80\x50\x05\x34\x8f\xf9\x94\x9a\xb4\xa9\x01\x2d\x71\xfa\x63\x75\x61\x5e\x78\x79\xbb\xd4\x5f\x2e\x99\x0f\x51\x3d\x29\x06\x99\x34\x4f\xf9\x16\x87\x70\xca\x5f\x0b\x36\x06\xd0\x23\xf8\x3c\x09\x96\x1d\xad\x0b\x9f\xf0\xcd\x98\xe8\x96\x7a\xf3\x71\xfc\x92\xed\xf2\xa7\xa0\x44\xfa\xa2\x0d\x15\x92\x96\x5c\xe8\xc3\xa6\x28\xf2\xbf\xc3\x59\x98\xb3\x78\xf5\xb1\x4b\x95\x0b\x5a\xbd\x1a\x3c\xfd\x90\xc6\x80\xa3\xa3\x25\xbf\xcd\xd8\x54\x69\x22\x32\x81\x77\x83\xa4\x67\x8b\x16\xdb\xc7\x88\x2a\xde\xa0\x68\xb8\xdc\xe6\x0f\x6f\x34\x17\xdd\x27\x25\x61\xa5\xe3\xb7\xe1\xfe\xf7\x92\x58\x01\x07\xea\xc0\x23\x09\xa2\xbc\x5a\xcf\x12\x6f\xbd\xfc\x6a\x65\x71\x16\x02\x3f\x4c\x56\x89\xf9\xc6\x99\xd9\x4c\xa5\x70\xef\xcd\x8f\x39\x76\xaf\x1f\xf7\xa7\x7b\x07\x4d\xb9\x89\xaf\x26\x26\xd8\xbc\xcb\xce\x92\x3c\xdc\x0b\x12\x54\x61\xa8\x41\x9a\x75\x2a\x3f\xab\xf0\xe5\x1b\xa6\x43\xdd\x73\x14\x44\x0b\x54\x0d\x31\xd3\xa8\xd0\x3e\xfc\x54\x19\x32\x6e\x75\x31\x91\x07\xf7\xf2\xdb\x1a\x7a\x02\x43\xf2\x49\x8c\x57\xce\x31\x1c\x00\xb2\x08\xf8\xec\x00\xa3\xbc\x96\xab\x0f\xf4\xd8\xc9\xec\x32\x72\x73\x24\xef\x2c\x00\x3f\x6b\xbb\xe3\x0c\xff\xce\xca\xad\x96\x98\x63\xca\x01\x44\x69\x83\x10\x92\x0b\xae\xfa\x71\x20\x11\x5e\xaf\x7a\x92\x63\x4e\x11\xdb\x08\x5c\x3c\x2e\xb6\xf0\xf7\x96\x5e\xed\xd5\x27\x7b\xea\xea\x8c\x8f\xf8\x9f\xcc\xff\x85\x22\x6e\x1a\x47\x4d\x64\xd6\xee\x74\x7d\x83\x59\x34\xba\x1d\x7e\x20\x0c\xa0\x91\x38\x3b\xd2\x98\xb0\xe5\x2d\x6d\x62\x01\x35\x16\x77\x4a\x3c\xaa\x2e\xde\xe1\x32\xbd\x68\x9e\xed\x8a\xa5\xa3\xc1\xb1\xe2\xaa\xa2\x68\x4f\x94\x2e\x21\x55\xfd\xc3\xd2\xd2\xf9\x6e\xd1\x81\x02\x88\x7a\x47\x63\x46\x61\xee\x3c\x44\x6a\xc9\x76\x5a\xea\x67\x78\x80\x5b\x7d\x15\xb2\x73\x65\xbd\x81\x86\xaa\xc0\x0c\x26\x26\x9c\x25\x2c\x50\x82\xa4\x21\x2e\x9a\x0a\xcf\x77\xbc\x4b\x5c\xeb\x77\xdb\xf0\x2a\xe5\x02\x99\x05\xa8\xeb\x15\xa2\x68\x58\xb9\x74\xe8\xdc\x29\x06\xa6\x33\xee\x26\x66\x84\xa3\xcd\x8c\x89\xe6\xba\x5e\x4a\x85\x90\x6a\xfa\x71\x79\x18\x90\x3e\x71\xb1\xd8\x0b\xdb\xb0\x03\x50\x2b\x18\xff\x75\x41\x90\xa7\x8b\x09\x6e\x9a\x6b\xe8\x36\xaa\xab\xad\x1a\xbc\x3a\x9d\x3c\x38\x0c\x35\xa9\x4e\x06\x0b\xe5\x9d\x35\x96\x82\xd0\xa0\xa2\x79\x94\xdd\x14\x83\xdf\xb3\x7c\x2b\xa4\xa4\x2a\x85\x8a\xf3\xbf\x6d\x37\x31\xe7\x74\x9c\x7c\x6c\x9b\x5e\x14\x29\xb5\xdb\xe7\x77\xb6\x99\x37\xe0\xeb\xf0\x2c\x69\x40\x09\xb1\x69\x19\xc3\x5f\x06\x00\x4d\xed\xaa\x2a\xa9\x15\x94\x28\xe7\x32\x33\x29\xcd\x2c\x95\x8e\xa7\xc6\xca\xe8\x06\x29\xb0\x8d\x2e\x2b\x0d\xb6\x11\xb2\x10\x5b\xf6\x1e\xb0\x43\xe2\x78\x13\x90\x1d\xac\x74\x0a\x62\xb4\x81\xbe\x13\x33\x51\x78\xdf\x61\x1e\x96\xdf\xff\xe9\xf0\x39\xd5\xc1\x45\x0e\xfb\x33\x69\x8e\x4d\x70\x0f\xf3\xed\x52\x5f\xb4\xdc\xce\x23\x88\xb8\x19\x5c\x08\x79\xa8\xd4\xc3\x48\x36\x56\xd5\x01\xa1\x3c\x36\xc0\x6c\xc4\x5e\xff\xf4\xcf\x11\x37\x3a\x6e\x8e\xe7\xd0\xf0\xdf\x26\x8e\x79\xb8\x93\xe3\x68\x65\x33\xe1\x7e\xf2\x9b\xcf\x5b\x5c\x8e\x99\x49\x6f\xa4\x42\x73\x36\xcb\x0e\xf2\x74\x48\xbe\xb0\x5f\x84\x98\x83\xa7\x11\x13\x4d\x88\x93\x8b\x1e\x2c\x2c\x5d\x1d\x74\x28\x79\x64\xc7\x83\x5b\x85\x05\x27\xb4\xfc\x54\xd6\x50\x9c\x9b\x1c\x7c\x89\x13\x7c\xff\xd6\x47\xc9\x49\x40\xe8\xef\x53\xdb\x51\xde\xa1\xac\xb6\x95\xc3\xb0\x69\x8e\x98\x54\xd1\x71\xb2\x9f\x00\x1f\xa2\xe8\xf6\x12\xec\xed\xa6\xba\x8e\x0b\x1d\xa0\xaf\xbd\x21\x3b\xbc\x7a\x4f\x00\xe3\x08\x65\xd5\xd0\x05\xde\x94\xb7\x81\x3e\xa0\xd4\xab\x59\x40\xf0\x21\x40\x9d\xb5\xba\x87\x34\xd9\xea\x12\x34\x82\xe4\x7c\x07\x65\xb8\x7f\xd0\x2c\xf9\x88\x40\xf8\xda\xff\xf8\x6a\x3b\xd7\xf6\x97\x56\x36\x0c\xbf\xa9\xe0\xb4\xf6\x40\x08\xdf\x1a\xf8\xd9\x14\xb9\x35\x9f\x0d\xf3\x18\x55\x8d\x47\x23\x74\x27\x45\xf3\x68\x86\x7c\x6a\xd2\x29\x0a\x87\x34\x63\xc2\x98\xa9\x5e\xc5\xab\x94\x54\xc6\x90\x18\x66\xc9\x56\x4e\x82\x3b\x5e\x32\x72\xf1\x69\xa7\xb6\x03\x3d\xa3\x82\x6d\x88\x67\x21\x1d\xfc\x94\x49\xe1\x20\x69\x87\x79\x14\xdf\x81\x69\x2d\x27\x3a\xd8\x86\xc6\xfe\x32\xf0\x9c\x7c\x47\x4b\x58\xf7\xd4\xcd\xe7\x31\xc9\x0c\xd4\x46\xdb\x91\x0d\x95\x1a\x8e\xac\xcb\x09\xbf\xbd\x7c\x26\xd3\xf2\x74\xcd\x83\xe4\xa4\x60\xe5\xb5\x87\x12\x36\x00\xc5\xa4\x25\xc5\xde\x19\xe4\x64\x83\xad\xb6\x50\x52\xd8\x51\xcd\x0c\xad\x6a\x61\xf8\x22\x54\x81\x70\xe5\x2e\xd1\xd2\x77\xfb\x0c\x9d\xcd\xb2\xe2\x5b\x4f\x10\x2f\x27\x3e\x46\xe6\x6f\x87\x45\x80\x55\x72\xb2\x9a\x8e\xf8\xf0\x0f\x03\xd7\x8e\xa2\x48\x41\x52\xbc\xbb\x2b\x78\x05\x11\xb4\x50\x0c\xe8\x6a\x23\x6f\x55\x0c\xca\xc4\x91\xb1\xab\x1b\xb7\xec\x73\x44\x5a\xfb\x4b\x27\xcf\x06\x39\x6b\xcc\xbf\xd2\xea\x8a\xab\x6c\xf5\x52\x18\x61\xb9\x73\x64\x6d\x7f\x52\xd4\xec\xca\xce\x2b\xe7\x22\xd2\xe3\x56\xdd\x24\x6e\x16\xdb\xd8\xda\x98\x6d\x94\x00\x9d\xc8\x1a\x5c\xe6\xef\x88\x40\x05\xf3\x0c\xe7\x8c\x51\x80\x52\x50\x26\xad\x9a\x3a\x61\xff\x61\xb2\x8c\xa0\xa6\x2c\x87\x66\x17\xb1\xb7\x29\x06\x75\x4d\xd3\x8f\x14\x1a\xce\x3d\xbf\xe9\xe9\x7c\x84\xcf\x05\x48\xdb\x58\x16\x7f\x73\xcd\xb0\x3f\xc8\x02\x32\xd9\xc3\xe9\xd5\xc7\x40\x81\xbd\xdb\xa5\x96\xad\x78\x9a\x30\xf7\x73\x7f\xe8\xa3\x6a\x23\x8c\xc5\x0b\xc0\xb0\x46\x10\x0a\x46\x2a\xbf\xd7\xbb\x82\x27\xc9\xfb\xc3\xdf\xd8\x55\x32\x51\xb5\x1f\xf0\x4e\x8f\x3e\xac\x03\x00\xe7\xb6\x22\x59\xce\x64\x99\x1e\xb8\x86\x6b\xd8\xc3\x5c\x3a\x67\x16\xad\xd5\x95\x44\xa5\xc8\xb9\x3d\x5b\x5e\xae\x62\x2d\xfe\xb2\x13\xd6\x77\x69\xf6\x06\xaa\x51\xde\xc6\xd5\xf5\xc1\x3e\x79\x56\x08\x6a\x02\x12\x23\xd9\x1a\x99\xb1\x08\x74\x80\x7f\x86\x42\x14\xbd\xbe\x27\x4b\x63\x36\x30\x3f\x26\x56\x5e\x1c\x89\x38\xc6\xea\x54\x37\x73\x69\xf2\x7d\x50\xb1\x61\x9e\xa7\x0c\xa8\xec\xfa\xe7\x4e\x13\x5f\x8d\x43\x44\x31\x9d\x47\xa0\x30\x26\xce\xbc\x85\x7f\x05\x7b\xb7\xcd\x4d\xe4\x9d\x7d\x66\x04\x3d\xf5\x24\x15\x8a\xb7\x73\xf6\x27\xe1\x45\x90\x4c\x33\x8b\x2f\x61\xf0\xaa\x10\xd1\x66\x68\x5c\x11\x89\x8b\x90\xe8\xb5\xdf\xb5\xa8\xb5\xaf\x14\xea\xd8\xb8\xc8\x34\x98\xb9\x20\x0f\xd2\xdb\x08\x06\x93\xeb\xba\xbd\x6d\xe5\xe7\x70\xb9\x46\x03\x94\x99\x9c\x52\xae\x55\x51\x99\x71\x99\xae\x63\xbc\x48\x2a\xa6\x08\x85\x4d\xf1\xda\x15\xcf\x18\xa4\x97\x1c\xdf\xef\x09\x2d\x45\x66\x78\x20\x45\x4e\xc6\x1c\x0e\x7f\x80\xdc\xf6\x9b\xd4\xbc\x2c\x29\xd8\x5d\xef\x01\x1c\x73\xc7\x95\xf8\x28\x9a\xdd\xca\x3c\x5c\x87\x87\x93\x76\x4c\x7b\xd3\x2e\x0e\x58\xb2\xa6\x7e\xe8\x26\x74\x13\x29\x78\xf9\x13\x8e\xb7\x7d\xb6\xd8\x15\xbd\x84\x8c\x55\x74\x14\x6b\xe6\x9c\xa7\x41\x37\xb1\xe2\x6e\x69\x3b\x61\xa0\x61\xf8\x7e\xb2\x8e\x99\xbd\x8f\x58\x3e\xff\x1d\xb8\x8f\xed\xe4\xd6\x53\x9b\x37\xed\x0f\x85\xaf\x95\x0a\x81\xb8\x80\xfa\xc9\x64\xaf\x98\xca\xdf\x4d\xf4\xcf\xae\xd7\x31\x8d\x1e\x6d\xa2\xaf\x69\xb1\xc7\x8e\xd3\x15\x43\xe1\x65\xa2\x87\x6b\xb6\x39\xd5\x84\x91\xf7\xff\xb4\x30\x12\xb0\x28\xe5\xf5\x05\xa2\xce\x22\x3b\x9f\x2d\x78\x11\x01\xf7\x78\x8e\x94\xee\x58\x7b\x7e\x39\xba\x97\x9e\xaf\x39\x82\x54\x86\x08\xa1\xe2\x23\x61\x57\xc1\x2c\x42\x4d\x06\xc8\x7e\x65\xdb\x7c\xbf\xd3\x49\x41\x67\x66\x2e\x76\x0f\x89\xb8\x17\x46\x49\x83\xc2\xa2\xc5\x9d\x62\x3b\x9e\xee\xd2\x50\x56\x18\x75\xdd\xae\x6c\x91\x97\xb5\x41\x4b\x28\xa5\xf2\x7b\x31\x75\x0c\x4a\xc3\xad\x3e\x52\xea\x5e\x8f\x2f\xa1\xef\xfa\x37\x5f\x45\x3b\x2f\x7f\x16\xa6\x00\x19\xbf\x9d\x2b\xf2\x62\x1d\x06\x14\x85\x65\x23\x75\x6c\xce\xac\xec\x75\x37\x30\xfd\xf4\x8f\x12\x3e\x39\xe2\x8b\xeb\xa6\xde\x47\x91\x6e\x8c\xf4\xd0\x51\x63\x6c\xbb\x48\x8a\x7c\xb7\xbc\xc8\xee\x3a\xda\x93\x7b\x38\x34\xdb\x13\x0d\x9c\xc9\x97\x38\x26\xfc\xcb\x9d\x16\x85\xc2\x48\x42\x68\x5a\xae\x68\xf4\x4c\x99\x48\xc7\x2b\xc5\x13\x22\x57\xee\xad\xa8\xeb\x5b\xa3\x08\x2e\x04\xc2\xab\x33\xe2\x0a\x08\xa2\x47\x72\x7d\x66\xbf\x07\xe9\x2c\x7a\xf4\x34\xef\x1f\xee\x4d\xf6\xac\xf3\xab\x71\xd1\x08\xae\xad\x4f\xf3\x27\x08\x87\x62\x2e\x9e\x19\x9e\x03\x64\xea\x99\xd6\xcf\x72\x4b\xbc\xef\x5f\x4c\x66\xa0\xda\x17\x16\x48\x31\x57\x68\xf7\x60\x59\x06\xa6\x7d\xa2\x09\x6f\xd1\xbb\x3a\xee\x11\x0e\x1f\x98\x1a\x44\x55\x96\xf3\xe3\x22\x4f\xe2\xe7\x8c\xe1\xde\xa4\x6d\x30\x41\x16\xe0\xd3\x12\x15\xb9\xed\x66\x3b\xf9\xeb\x3f\x75\x4a\x01\x2b\x6c\x26\x78\xf9\xf6\x6d\xf2\xff\x69\xfa\x23\x5b\x43\x6a\xb3\xf5\x68\xd8\xa6\x43\x3e\x13\x8e\xef\x09\x47\xeb\xec\x42\x65\x19\x71\x77\x8e\xe7\x54\x2c\xeb\x3e\x1f\xf4\x20\x24\xd7\x43\xb2\x0f\x64\x7c\x00\xdb\x56\xe6\xfc\xf2\xef\x79\x57\xad\xed\x9d\x3e\x1a\x0a\x54\xeb\xb4\xa0\xe2\xb1\x74\x32\x7a\x09\xd6\x19\xe8\xbd\x9e\x21\x6a\xbc\x4c\x9c\xa3\x48\xbb\xa1\x3a\x72\x12\x16\x2e\xb6\x7a\x20\x1c\xab\xfb\xc8\xbd\x1b\xa5\x1f\xef\x1e\xc6\xaa\x06\xf7\x51\x6d\xf9\xec\xc4\x03\xbb\xb2\xbe\x2a\x1f\x30\x99\x35\xe1\x32\x01\xf9\xf3\x1e\x38\x0d\xb3\x02\x67\x07\x52\x30\xa4\xdc\x54\x75\x8f\xe6\x98\xde\x73\x45\x86\x5b\x53\x82\x05\xdf\x62\xdc\x82\xab\xef\xa1\xc7\xad\x9d\x5c\x04\xd3\x5a\xba\x23\x55\x4f\x8a\x55\xda\xb6\x23\x6b\x8c\x92\xb1\x9c\xc2\xd9\x23\x27\xd1\x93\xe3\x56\x38\x02\x0d\x49\x91\xfc\x7a\x24\xf3\xa9\xda\xf7\xce\xf8\x51\x49\x0c\x1d\xbf\x03\xf4\xa0\xa7\xef\xd6\xea\x64\xda\x18\x4f\x30\xb9\xb4\xdf\x03\xd1\x0a\x89\xad\xbe\x07\xf7\x61\x88\xb7\x79\x58\x5d\xac\x11\xd8\x66\xc5\x08\xf7\x93\xa4\x13\x87\x49\xe2\xfa\xfd\x64\x52\xb8\xd2\xfd\x7d\x50\x9c\x4e\x6e\x0e\x8f\xd7\x73\xbe\x61\x7b\x0b\xc1\x67\xee\xad\x1e\xe1\x57\x12\x56\xf8\x8b\xb0\x8b\xfb\xc3\xaf\x00\xd9\x9d\x85\x92\xfa\x50\x70\xf8\x0d\x44\xd6\xa3\xf5\xf5\x3d\xb2\xa7\x0e\xba\xbe\x11\x31\x62\x14\xc6\x8c\xf0\xa7\x12\xb7\x47\x86\x19\x52\xc1\x93\xbd\x80\x0a\x7a\x5e\xe0\xdf\x9d\x88\xab\x05\x6a\x55\x64\xc5\xfa\x50\x61\x0c\xb8\xde\x86\x09\xec\x28\xb1\xde\x89\x8d\xe5\x6f\x4c\x2b\x53\x84\x6b\xe0\x7e\x37\xc7\x88\x6e\x29\xdd\x41\x64\x80\xa5\x9e\x5e\xb4\x1f\x86\x0a\x3e\x99\x38\x56\x99\x80\x4b\x90\x6d\x25\xdd\xf4\xa0\x9d\x9c\xe7\xae\x9f\x03\x39\xc0\x4f\xb9\x7d\x63\xdc\xb4\xb0\x57\xe1\x92\x41\x84\xec\x01\x1a\xc0\x21\x05\x5f\x80\x34\x2c\xb1\xee\x06\x6d\x97\xdc\x8d\xde\x32\x67\x0c\x01\x65\xee\x80\x4e\x3c\x49\xdd\x5d\x92\xa6\xf7\x26\x9f\x2d\x9c\x54\xcc\x4f\x6d\x21\xfe\x93\x8e\x9e\xc4\x5d\x50\xbf\x27\x59\xef\x39\x47\x4e\x65\xed\xcd\xac\xdb\x1d\xd2\xdb\xde\x1b\xc7\xcb\xfd\x51\x28\x3e\xf9\x8e\x66\x8a\x30\xa0\x10\x76\xc6\x82\x74\xd0\x15\xdd\xfc\xed\xc6\x3f\x2a\xca\x9e\xd3\x04\xa5\x6c\x4f\x58\x55\x2a\x43\xc0\x2c\xac\xd4\xbe\x2a\xea\x09\x8e\x92\x8b\x92\x0f\xc1\xb8\x7b\xc8\x57\xca\x08\x84\xe2\x32\x4d\xb7\xb7\xce\x98\x1e\x10\x5b\x90\x49\x37\x24\x35\x0d\x39\x7c\x74\x44\x24\x89\x86\x32\xb2\x31\x51\xbb\x98\x6d\xa3\x6e\x6f\xef\x5f\x37\x77\xa7\x59\xc2\x1c\x67\xcd\x55\x0e\x85\x43\x13\xca\x41\x19\xc4\x67\x9e\x61\x74\x09\x65\xb4\x12\xc1\x1b\xa6\xb9\xc1\x67\xae\xc0\x47\x07\x18\xdc\x1a\x50\x47\x51\x06\x55\xf3\x5e\xe8\x94\xc7\x44\x5e\x4b\xb1\x66\x69\x4f\x2c\xf1\xc7\xe0\x62\x14\x3d\x91\x18\x5f\xb3\xa6\xf7\x9b\xc3\x99\x28\x56\x8d\x10\x54\x8e\xfa\xa8\x9d\xf6\x8e\x79\x0e\x6b\x7e\x96\x12\x42\x5b\x71\xd7\x31\x86\x3e\x73\x10\x82\x94\xe9\x47\x80\x2d\x9d\xf4\x04\xa6\x0e\x29\x2f\x22\x3a\xc5\x36\x1a\xc1\xfd\xdd\xad\x3b\x2f\xa1\xd8\x64\xcd\x55\x7d\xc2\x64\x33\x5e\xa9\x6c\x46\xcf\xe5\xf3\x75\x71\x99\xfe\x37\x49\x96\xcb\xf2\x66\x8f\xf0\x6f\x60\xa2\x83\x7a\xb3\xf7\xa4\x81\x42\x08\x34\x6b\xd3\xa5\x4e\xd6\x46\x29\x7a\x4f\x37\xc9\xfd\xc7\x27\x9b\xf9\x4b\xa3\xfb\x5b\x7b\xa3\x48\xe0\xfa\xb0\x77\xdc\x98\x90\x6e\x99\xd0\xed\x07\x80\x49\x05\xe1\x88\x39\x4d\xac\x18\xf9\xa7\xbf\x4a\x89\x4b\xba\x15\x1b\x86\x78\x22\x99\xe7\x9e\x17\x4c\x53\x40\x98\x3b\x8f\x9a\x86\x03\x60\x9c\xed\xd9\x0f\xa3\x4c\x2e\x96\x88\x9d\xd5\xdb\x19\x1c\xf9\x31\xf4\x24\x02\xbe\x0d\xc8\xd7\x64\x03\xe2\x37\x5f\x69\x12\xc2\xd1\x42\x7c\xdb\xf6\x83\x6f\xf9\xea\xd0\x49\x6a\xf1\x63\x55\x1a\x00\x8f\xbb\xaf\x5d\x1c\x0e\xd1\xa6\x41\x63\x13\x70\x71\x68\x74\xd9\x53\x89\x48\xa5\x2b\x2d\x80\x2e\x3a\xab\xe8\xa7\x6c\x84\x4d\x41\xa3\x59\xd9\xe7\x79\xdf\xb2\x7e\xa1\x29\x8d\xe0\x0b\x9b\x4e\xd8\x9d\x56\xe1\xed\xef\xd1\x95\x55\x52\x0b\x7a\xff\x57\xd3\x4c\xca\x5c\xfa\x31\x09\xa1\x05\x06\x9d\x1a\x0a\x2a\x07\xe4\xd0\x8e\xfd\x30\x84\xb8\xc7\x91\xe7\x1f\xfa\x22\x87\x12\xc5\x37\x02\xe5\xda\xb8\x0c\x3c\x5e\x49\xdb\x53\x36\xb7\xf6\xc5\xf1\x8a\xe7\xcd\x74\x37\x05\x69\xe0\x3d\x4f\xb9\x55\x1a\x8d\x1e\x4f\x72\x93\x31\xba\xe5\xb3\x00\x4b\x1f\xfa\xf7\xdd\xc3\x29\x2d\x08\xf1\x81\x81\x93\xd5\xb5\x77\xbb\x3a\x66\x87\x5c\xa9\xfd\x6f\x64\xe4\x2a\x37\x81\xfd\x32\x29\x70\x2c\x7c\x67\x6f\x78\x59\x46\x0f\x8b\xf0\x73\xeb\xa3\x94\xf4\x81\xb6\x53\x05\xc1\x4a\x3b\x97\x0f\x59\x22\xc4\xc9\x4a\x9a\x9d\x63\x30\x5e\xb8\x28\x8a\xe8\xf5\xed\xa7\x32\x63\xe4\x87\xb4\xff\x78\xb3\x94\x3b\x58\xfc\xaa\x84\x20\xa9\x43\xd8\x77\x67\xe7\x36\x67\x9a\x7d\x6c\x40\x3f\x01\xcd\xf1\x63\x44\xaa\x08\xaf\xb4\x01\x39\xba\x19\x7d\xfb\x72\xab\xaa\x6a\xf3\x01\x09\x04\x50\xe3\x3f\x63\x21\xe6\xa6\x87\x14\x74\xdb\xb8\x03\x79\x69\xac\xb5\x1e\xca\x9a\x90\x8b\x30\x27\x48\x0f\x33\xb3\x53\x28\x22\xe1\x89\x0f\xcf\x46\xb0\x8c\x84\xca\xb4\x3b\xcf\x0f\x7a\xb8\x58\x8c\xf5\xb4\xe0\xb0\xfc\xb5\x03\x9d\x4c\xc3\x32\x0a\xea\x34\xaf\x08\x48\x03\x78\x57\x5f\x68\x43\x3d\xb0\xb9\xfc\x2b\x19\x12\x1f\xaa\x7c\x98\x26\x5e\x25\x8a\xa4\xcc\x26\x47\xd9\x11\x48\x3a\x9b\x9a\x35\xfe\x57\x8d\x7a\xf8\x73\x7a\x4b\xb7\x3c\xb8\x6a\xa4\x9d\x0e\x6e\xd7\xb0\x09\xed\xdf\x07\x6b\x51\xe3\x13\x8e\x2b\x95\xf1\xb7\x7d\xbb\x45\x3a\xeb\xd0\x80\xf9\xf4\xef\xbd\x3c\x43\xd3\x4a\x7d\x5b\x1e\x9e\x64\x67\x54\xfb\x7e\x3c\xcc\x7d\x98\xc2\x21\x85\xbe\x39\x8e\x44\x54\xf5\x16\x83\x60\x0a\xf7\x82\x7b\xec\x88\x0e\xb5\x64\x83\x61\x89\x15\xfc\xa4\x7c\xf4\x34\x59\x66\xe8\xb6\x61\x1d\x97\xfa\xc1\xad\xce\xe4\x59\xc7\xec\x7a\x2e\xbc\x40\xa2\xaf\x9d\xfa\x0b\x47\x5c\xff\xde\x18\x1f\x65\xe3\xa6\xee\x24\xdd\xf7\x34\x7c\x6a\xca\xb2\xa7\x55\x24\x28\x39\xcc\xbd\x50\xc5\xc4\x3d\x2f\xdc\x6c\x2f\x7b\xaa\x14\xe6\x1d\x85\x32\x95\xea\xd6\xcf\xaf\x2b\x04\x6a\xef\xb7\xc8\xe9\xdb\xc1\xce\xd5\x00\x87\x06\xd3\x19\x98\x95\x72\xaf\x2c\x5d\xdc\x91\xae\x54\xf9\xfd\x77\x96\xfe\x80\x6d\xde\x23\x5a\xd2\x23\x8d\xff\x51\x84\x6b\x05\x8a\x0c\x3c\xff\xf9\xc6\x32\x10\xff\x26\xf1\x75\xdb\xc7\x2e\xf4\xe6\x23\x0b\x2d\xd6\x6b\x1b\xcb\x2b\x58\xe4\x8b\x97\x4e\x2f\x01\xe9\x9f\xd6\x33\x42\x9c\x97\xb0\x31\x08\xc5\xa7\xff\x61\x1f\x5a\x6d\xf8\x2a\xdc\xf1\x15\x9b\x46\xfe\xe3\x09\x73\xce\x1f\x7f\xfb\x68\x95\x26\xce\x23\x3d\xa0\x31\x2c\xaf\x12\x85\x91\x0c\x9d\x9e\xd4\xa4\xdc\x2d\x2e\x8c\x8a\x56\x45\xf7\xec\xd9\x33\xac\xcb\xf0\x82\xc7\x8b\x3b\x62\x6f\x9e\xb2\x0a\xc7\xbf\xfe\x87\xe9\xb1\x97\xc6\x75\x53\x37\x1a\xa9\xa8\xa5\x09\x8b\x57\x64\x45\xbc\x58\x56\xc5\xf9\xf6\x02\x91\xcf\x1a\x5e\x67\x4d\x91\x99\xe4\x61\x7d\xa2\x7f\x35\xca\xa8\x68\x52\x9c\x69\x8a\x2a\x39\x9b\xc0\x9c\x15\x8a\xfb\x20\xdd\xc2\xf5\x1b\x7e\xfb\x19\x6e\xff\xac\xab\xba\x61\x98\xdc\xd6\xed\xb7\xf1\xe1\x94\xf2\xe4\xd0\xef\x76\x8f\xe7\xf5\x4e\x57\x5c\xfd\x52\x28\x16\x04\x65\xe1\x1d\xd8\xc1\x66\xeb\x96\x92\x86\xc3\x33\xd6\x10\x5f\x38\x8c\x9e\xc2\x4d\x7b\xb2\x04\xb0\x49\x43\x80\x49\xfa\xff\xce\xb3\xa7\xfb\xe4\x8f\x31\x4a\x07\xd3\x1f\x7e\xd6\xe1\x37\xe2\xce\xb1\x9f\x7f\xcf\xa8\xf5\x21\x49\x54\x73\xc1\xc8\xf0\xee\xe0\x4b\x99\xe0\xec\x80\x15\x3c\xdf\x83\x91\xcb\x5d\xf4\xab\x2c\xc0\x76\xef\x9e\x19\x6b\x18\xb8\x98\x19\x7b\x42\xab\x31\xdd\xe2\x08\x8d\xbe\xcc\xe6\x27\x27\xad\x04\x1c\x68\x71\x35\x4e\x1c\x38\xcf\x34\x12\xc2\xc0\x97\x0a\x42\x02\x0c\xa3\x38\x53\x77\x6e\x96\x22\x2d\x5e\xa7\x4b\xcd\x82\x4f\x00\x16\x7e\xdd\xd7\x0f\xbe\x7c\x81\xe9\xa2\xc5\x17\xad\x34\x09\x9c\xff\xde\x08\x49\x11\x3b\xce\xa0\xdc\x73\x3b\x57\x18\x49\x21\xb3\x2f\x30\xed\x0e\xbe\x08\x50\x08\x72\x14\xeb\xd1\x0f\x03\x94\x6a\x5f\x4c\x51\x70\xeb\xfe\x94\xb1\xc2\xb8\x29\xd3\x9b\x6d\x18\x8d\x8e\xe9\xa9\x39\x2f\x50\x3f\x5f\x36\xff\xdc\x23\x13\xf1\x3a\x2c\x1c\x30\xfe\xce\xf0\x10\x98\x94\x41\xc5\x2d\x87\xb9\xc6\x0e\x11\x3c\x73\xb6\x1b\x8f\xbb\x55\x03\xd0\xbb\x70\x73\x2f\x66\x60\x21\xa9\x62\x3f\x41\x32\xb7\x79\x94\xf5\xe3\x90\x81\xdb\x1f\xf5\xdc\xf9\x0b\x2b\x93\x8f\x69\xa0\x0d\x98\xae\x22\xfe\x96\x98\x08\xd9\x4f\xe1\xdc\xd3\xd4\xbf\x69\xe9\x59\xdd\xfc\x91\x1c\x6a\x7d\xce\x09\x99\x24\x9d\xb4\x3f\x9c\x2e\x15\x3d\x73\x07\x5d\xea\x69\xcf\xec\xb3\xe9\x42\xdc\x62\xbe\xc1\xd0\xd0\x26\x62\xc2\x75\x05\x49\x54\x43\x2e\xf1\x46\x38\x2f\x3b\xc8\x38\xb6\xdf\xa1\x9a\x82\x33\xdd\x68\x41\x9f\x71\xa7\x17\xd6\xc2\x5f\xd6\xe6\xb5\xdc\x55\xcc\x5b\x9c\xac\x78\xbf\x9b\x15\x09\x67\xb9\x27\xe0\x64\x63\xd6\xc1\xfc\xe0\xe1\x72\x98\x4a\x7e\x7c\xca\x80\x2c\x29\x8d\xac\xc7\xf2\xf5\xbc\xbc\xa3\x8f\xba\xbc\xe4\x3a\x32\x0b\xa4\xc3\x00\x0f\x33\xb7\x3a\x50\xbd\x35\x15\x98\x0c\x06\xca\x8a\x7f\x51\x21\xe2\x44\x34\x7f\x34\x9f\x56\x52\x22\x7d\x26\x51\x6c\x09\x48\xe7\x6b\x92\x8d\x32\x1f\x8b\x49\x59\x16\xec\x92\x71\xa8\x19\x91\xc1\x43\x4c\xdb\xf9\x0c\x76\x70\x1a\x3d\x05\xd2\xb7\xc7\x57\x17\x20\xcc\xcb\x3b\x41\x67\xf6\xc9\x37\xf1\xac\x4b\x72\x1a\x3a\x82\x0c\xaf\xe6\x56\x7d\xa5\x97\x26\xa6\x16\x96\xf8\xf8\xcd\x91\x1a\xd0\xb0\x9b\x68\x7e\xfb\x18\x85\x78\x6d\x9d\x88\x43\x18\xc4\x31\x7c\xe3\x66\x77\xd8\x8a\xa9\x0b\x4c\x45\x50\xaa\xea\x8d\xde\x35\x20\xfe\x6e\x09\xc5\xd4\xb0\xc4\xd1\xa1\x63\x8d\x5f\x50\x6e\xfd\x31\x4f\x19\xa9\xb3\x04\x50\x52\x44\x44\x33\x60\x22\x62\xd9\x0b\x4d\x23\xf8\xe8\x18\x98\x44\xda\x14\xfa\xca\x9e\xfd\x0f\x3d\x91\x70\xb8\x6c\xab\x05\x79\xfd\x6b\xe8\xe8\x47\xde\x98\x87\x1b\x23\xbc\x91\x40\xbf\x49\x7a\x64\x1a\x7d\x7f\xa9\x0e\x80\xe1\x44\xb3\xd5\x69\xcf\x0e\x5f\x7f\x72\xa6\x94\xaa\xb0\xb8\x11\x34\xaa\x02\xd5\xeb\x55\x10\xc0\xdc\xa6\x40\x7c\x93\x38\xaa\x4f\xb9\xae\xb6\xed\x48\x0e\x17\xf8\x74\x84\x05\x4f\x60\x7a\x8f\xd8\x81\xad\xcc\x7a\x43\x74\xd2\xe5\x82\x6a\x40\x92\x53\x8e\x51\x58\xaa\x74\xb2\x24\x8e\x38\xd9\xeb\x01\xda\xaa\x16\xdd\xcc\xbc\xf5\x5c\xae\xe6\x6f\xcf\xee\x6b\x84\x8b\x97\x89\x7a\xb2\xc3\x15\x6c\x46\x11\x96\x55\xca\xd5\xc7\x4c\x96\xd4\x02\xdf\x1f\x69\xcb\x46\xb4\x76\xa2\x82\xe0\x9f\x64\x55\x6a\xd8\x57\xcb\xe9\xe8\x99\xbe\xb3\x17\x63\x05\x63\x94\x10\xe9\xe7\x74\x00\x61\x37\xcc\xba\x12\xde\x19\x7a\x15\x32\xd6\x7b\xc7\x41\x36\x4f\x17\x8b\x4c\x7a\xb2\x6f\x8b\x4a\x02\xab\xfa\xb6\xb0\x46\x36\xf4\x4c\x92\x16\x7d\xcb\xb6\x39\xb0\x70\xd6\x6e\xbf\xdc\x51\x88\x60\x1c\x4d\x95\xb4\x6a\x22\x28\xf5\x04\x0a\x8b\x6c\x78\xd1\x30\x01\x4c\xaf\xe6\x01\xb1\x6a\x7f\xd9\x1f\xb8\x3b\x2b\x87\x00\x17\xd5\x06', 1)

================================================
FILE: environment/render/render_pic2.py
================================================
import traceback
import pygame
import traceback
import os
import copy
from render.render_pic3 import Render as Render3

class Render:
    def __init__(self, size_x, size_y):#, o_detector_num, o_fighter_num, e_detector_num, e_fighter_num):
        self.render3 = Render3(size_x, size_y)
        return
        pygame.init()
        self.screen = pygame.display.set_mode((size_x, size_y))
        image_path = os.getcwd() + '/environment/render/resource/'
        self.detector_red  = pygame.image.load(image_path + 'detector-red-20.png')
        self.detector_blue = pygame.image.load(image_path + 'detector-blue-20.png')
        self.fighter_red   = pygame.image.load(image_path + 'fighter-red-20.png')
        self.fighter_bue   = pygame.image.load(image_path + 'fighter-blue-20.png')
        self.detector_red_rect = self.detector_red.get_rect()
        self.detector_blue_rect = self.detector_blue.get_rect()
        self.fighter_red_rect = self.fighter_red.get_rect()
        self.fighter_blue_rect = self.fighter_blue.get_rect() 
        self.side1_detector = []
        self.side1_fighter  = []
        self.side2_detector = []
        self.side2_fighter  = []

        for index in range(o_detector_num):
            detector = {}
            detector['detector'] = copy.deepcopy(self.detector_red)
            detector['rect'] = copy.deepcopy(self.detector_red_rect)
            self.side1_detector.append(detector.copy())

        for index in range(o_fighter_num):
            fighter = {}
            fighter['fighter'] = copy.deepcopy(self.fighter_red)
            fighter['rect'] = copy.deepcopy(self.fighter_red_rect)
            self.side1_fighter.append(fighter.copy())

        for index in range(e_detector_num):
            detector = {}
            detector['detector'] = copy.deepcopy(self.detector_blue)
            detector['rect'] = copy.deepcopy(self.detector_blue_rect)
            self.side2_detector.append(detector.copy())

        for index in range(e_fighter_num):
            fighter = {}
            fighter['fighter'] = copy.deepcopy(self.fighter_blue)
            fighter['rect'] = copy.deepcopy(self.fighter_blue_rect)
            self.side2_fighter.append(fighter.copy())


        self.state_time = pygame.time.Clock()

        

    def dis_update(self, done, step, o_detector_data_obs_list, o_fighter_data_obs_list, e_detector_data_obs_list, e_fighter_data_obs_list, o_detector_data_reward_list, o_fighter_data_reward_list, e_detector_data_reward_list, e_fighter_data_reward_list, o_all_reward, e_all_reward):
        print('update')
        print((o_detector_data_obs_list))
        print((o_fighter_data_obs_list))
        print((o_detector_data_reward_list))
        print((o_fighter_data_reward_list))
        print((o_all_reward))
        # b=a
        return self.render3.dis_update(done, step, o_detector_data_obs_list, o_fighter_data_obs_list, e_detector_data_obs_list, e_fighter_data_obs_list, o_detector_data_reward_list, o_fighter_data_reward_list, e_detector_data_reward_list, e_fighter_data_reward_list, o_all_reward, e_all_reward)
        
        color = 255, 255, 255
        speed = [5, 5]

        self.detector_red_rect = self.detector_red_rect.move(speed)
        self.detector_blue_rect = self.detector_blue_rect.move(speed)
        self.screen.fill(color)
        self.screen.blit(self.detector_red, self.detector_red_rect)
        self.screen.blit(self.detector_blue, self.detector_blue_rect)
        pygame.display.update()
        self.state_time.tick(30)

        return
    def dis_update_done_font(self):
        print('update done font')
        return self.render3.dis_update_done_font()
    def dis_update_font(self, step, red_reward, blue_reward, red_detector_num, blue_detector_num, red_fighter_num, blue_fighter_num, red_missile_num, blue_missile_num):
        print('dis_update_font')
        return self.render3.dis_update_font(step, red_reward, blue_reward, red_detector_num, blue_detector_num, red_fighter_num, blue_fighter_num, red_missile_num, blue_missile_num)
    def dis_update_pos(self, o_detector_pos_list, o_fighter_pos_list, e_detector_pos_list, e_fighter_pos_list):
        print('dis_update_pos')
        return self.render3.dis_update_pos(o_detector_pos_list, o_fighter_pos_list, e_detector_pos_list, e_fighter_pos_list)
    def draw_course(self, center_point_x, center_point_y, course, course_r):
        print('draw_course')
        return self.render3.draw_course(center_point_x, center_point_y, course, course_r)
    def draw_fight_rela(self, center_point_x, center_point_y, striking_list, detector_list, fighter_list, line_colour):
        print('draw_fight_rela')
        return self.render3.draw_fight_rela(center_point_x, center_point_y, striking_list, detector_list, fighter_list, line_colour)


================================================
FILE: environment/world/__init__.py
================================================
__pyarmor__(__name__, __file__, b'\xec\x50\x8c\x64\x26\x42\xd6\x01\x10\x54\xca\x9c\xb6\x36\x84\x05\x6a\x0b\xf3\xc4\x16\x01\xb0\x49\xdd\x1c\xf4\xf8\x5a\xe1\xe0\xc4\xbe\x1b\x41\x5d\x2c\x21\x77\xb1\x53\x58\xd9\xeb\x22\xb3\x4c\x09\x12\xdb\x19\xce\x41\x3b\xeb\xb0\x0d\x17\x26\x12\xf9\x51\x94\x9e\xf1\xf5\x85\x77\xd0\x70\xdf\xce\x84\x05\x76\x90\x38\xf1\x10\xd7\x44\x53\x87\x32\x78\xa3\x65\xcd\x08\xcf\x45\x20\x53\x90\x31\x2c\x73\xa3\x04\x11\xfb\x6f\xf4\x36\xd1\x62\xd3\x8e\xcd\x57\x1f\xfa\x46\xe3\x9e\x0a\x32\xc9\x4d\x7d\xa1\x37\xba\xe0\xe3\x84\x87\xb1\x25\x00\x11\x98\x1a\x78\xdf\x6f\x4c\xd6\x38\x0a\x58\xb0\x25\xee\xf1\x9f\x45\x5f\x65\x92\xe1\x38\x5d\xe3\x1d', 1)

================================================
FILE: environment/world/config.py
================================================

class GlobalVar:
	api_raw = 0
	api_spatial = 1
	band_L = 0
	band_S = 1
	band_X = 2
	band_fp_num = [20, 20, 10]
	detection_hit_probability = [0.2, 0.3, 0.9, 0.6]
	hit_detection_source_detector_L = 0
	hit_detection_source_detector_S = 1
	hit_detection_source_fighter = 2
	hit_detection_source_passive = 3
	img_obs_reduce_ratio = 10
	j_coverage_angle = [45, 30, 10]
	j_max_range = [400, 400, 300]
	l_missile_dis = 120
	l_missile_hit_probability = 0.8
	l_missile_op_dec_ratio = 0.05
	l_missile_op_req = 10
	l_missile_type = 1
	l_missile_num = 2
	passive_loc_continuous_detection_req = 5
	passive_loc_fighter_num_req = 4
	r_coverage_angle_X = 120
	# major lobe
	r_jammed_angle_mlob = [10, 10, 4]
	r_jammed_range_mlobe = [120, 150, 30]
	# side lobe
	r_jammed_range_slobe_aim = [220, 260, 80]
	r_jammed_range_slobe_block = [300, 320, 120]
	r_max_range = [400, 400, 180]
	s_missile_dis = 50
	s_missile_hit_probability = 0.9
	s_missile_op_dec_ratio = 0.05
	s_missile_op_req = 4
	s_missile_type = 2
	s_missile_num = 4

def get_api_raw():
	return GlobalVar.api_raw
    
def get_api_spatial():
	return GlobalVar.api_spatial
    
def get_band_L():
	return GlobalVar.band_L
    
def get_band_S():
	return GlobalVar.band_S
    
def get_band_X():
	return GlobalVar.band_X
    
def get_band_fp_num(band):
	return GlobalVar.band_fp_num[band]
    
def get_detection_hit_probability(typ):
	return GlobalVar.detection_hit_probability[typ]
    
def get_hit_detection_source_detector_L():
	return GlobalVar.hit_detection_source_detector_L
    
def get_hit_detection_source_detector_S():
	return GlobalVar.hit_detection_source_detector_S
    
def get_hit_detection_source_fighter():
	return GlobalVar.hit_detection_source_fighter
    
def get_hit_detection_source_passive():
	return GlobalVar.hit_detection_source_passive
    
def get_img_obs_redu_ratio():
	return GlobalVar.img_obs_reduce_ratio
    
def get_j_coverage_angle(band):
	return GlobalVar.j_coverage_angle[band]
    
def get_j_max_range(band):
	return GlobalVar.j_max_range[band]
    
def get_l_missile_dis():
	return GlobalVar.l_missile_dis
    
def get_l_missile_hit_probability():
	return GlobalVar.l_missile_hit_probability
    
def get_l_missile_op_dec_ratio():
	return GlobalVar.l_missile_op_dec_ratio
    
def get_l_missile_op_req():
	return GlobalVar.l_missile_op_req
    
def get_l_missile_type():
	return GlobalVar.l_missile_type

def get_l_missile_num():
	return GlobalVar.l_missile_num
    
def get_passive_loc_continuous_detection_req():
	return GlobalVar.passive_loc_continuous_detection_req
    
def get_passive_loc_fighter_num_req():
	return GlobalVar.passive_loc_fighter_num_req
    
def get_r_coverage_angle_X():
	return GlobalVar.r_coverage_angle_X
    
def get_r_jammed_angle_mlob(band):
	return GlobalVar.r_jammed_angle_mlob[band]
    
def get_r_jammed_range_mlobe(band):
	return GlobalVar.r_jammed_range_mlobe[band]
    
def get_r_jammed_range_slobe_aim(band):
	return GlobalVar.r_jammed_range_slobe_aim[band]
    
def get_r_jammed_range_slobe_block(band):
	return GlobalVar.r_jammed_range_slobe_block[band]
    
def get_r_max_range(band):
	return GlobalVar.r_max_range[band]
    
def get_s_missile_dis():
	return GlobalVar.s_missile_dis
    
def get_s_missile_hit_probability():
	return GlobalVar.s_missile_hit_probability
    
def get_s_missile_op_dec_ratio():
	return GlobalVar.s_missile_op_dec_ratio
    
def get_s_missile_op_req():
	return GlobalVar.s_missile_op_req
    
def get_s_missile_type():
	return GlobalVar.s_missile_type

def get_s_missile_num():
	return GlobalVar.s_missile_num


================================================
FILE: environment/world/detection_calc.py
================================================
import copy
import world.config as config
import world.position_calc as position_calc


def passive_detection_calc(self_context, enemy_fighter_context_list):
    '''
    根据敌方战机干扰机接收情况,更新自身上下文中无源侦测计数器,根据可侦测标准对自身上下文中可侦测指示赋值
    需确定的问题:干扰机被动侦测雷达信号,能够全向接收雷达信号还是指向性接收?目前认为干扰机接收信号与干扰信号发射的指向性相同
    :param self_context: :自身上下文
    :param enemy_fighter_context_list: 敌方战机上下文列表
    :return:
    '''

    for index, enemy in enumerate(enemy_fighter_context_list):
        exist = False
        for j_receive in enemy['j_receive_list']:
            if self_context['id'] == j_receive['id']:
                exist = True
        if exist:
            self_context['detection_count_list'][index] += 1
        else:
            self_context['detection_count_list'][index] = 0

def radar_visible_calc(self_context, enemy_detector_context_list, enemy_fighter_context_list):
    '''
    计算自身雷达的可见敌方目标,将自身上下文中雷达可见目标列表更新
    规则:
    1. 当一个雷达收到n个干扰机干扰时,在干扰机方向±5°范围内收到主瓣干扰,在其他方向收到副瓣干扰
    2. 若有n个干扰机对一个雷达进行干扰,只要有瞄准式干扰存在,则雷达整体受到瞄准式副瓣干扰影响,若无瞄准式干扰存在,则雷达受到阻塞式干扰影响
    3. 预警机雷达为全向探测,战机雷达为扇形方向探测
    :param self_context:自身上下文
    :param enemy_detector_context_list:敌方预警机上下文列表
    :param enemy_fighter_context_list:敌方战机上下文列表
    :return: 新发现detector数量和fighter数量
    '''

    radar_list = []
    r_band = self_context['r_band']
    o_pos_x = self_context['pos_x']
    o
Download .txt
gitextract_qb55n16v/

├── .gitignore
├── README.md
├── agent/
│   ├── airc_homo_rule/
│   │   └── agent.py
│   ├── base_agent.py
│   ├── fix_rule/
│   │   ├── agent.py
│   │   ├── agent_core.py
│   │   ├── license.lic
│   │   ├── product.key
│   │   ├── pyshield.key
│   │   ├── pyshield.lic
│   │   └── pytransform.py
│   ├── fix_rule_no_att/
│   │   ├── agent.py
│   │   ├── agent_core.py
│   │   ├── license.lic
│   │   ├── product.key
│   │   ├── pyshield.key
│   │   ├── pyshield.lic
│   │   └── pytransform.py
│   └── simple/
│       ├── agent.py
│       └── dqn.py
├── common/
│   └── agent_process.py
├── configuration/
│   ├── reward.py
│   └── system.py
├── doc/
│   └── tutorial.md
├── environment/
│   ├── error_log.py
│   ├── interface.py
│   ├── license.lic
│   ├── product.key
│   ├── pyshield.key
│   ├── pyshield.lic
│   ├── pytransform.py
│   ├── render/
│   │   ├── __init__.py
│   │   ├── render_pic.py
│   │   └── render_pic2.py
│   └── world/
│       ├── __init__.py
│       ├── config.py
│       ├── detection_calc.py
│       ├── em_battle.py
│       ├── load_map.py
│       ├── log.py
│       ├── position_calc.py
│       ├── replay.py
│       └── strike_calc.py
├── fight.py
├── fight_mp.py
├── log/
│   └── readme
├── model/
│   └── README
├── obs_construct/
│   ├── airc_homo_rule/
│   │   └── construct.py
│   └── simple/
│       └── construct.py
├── replay.py
├── tournament/
│   ├── config.ini
│   ├── config_gen.py
│   └── tournament_mp.py
├── train/
│   └── simple/
│       ├── dqn.py
│       └── main.py
└── utility.py
Download .txt
SYMBOL INDEX (264 symbols across 25 files)

FILE: agent/airc_homo_rule/agent.py
  class Agent (line 29) | class Agent(BaseAgent):
    method __init__ (line 30) | def __init__(self):
    method set_map_info (line 50) | def set_map_info(self, size_x, size_y, detector_num, fighter_num):
    method __reset (line 71) | def __reset(self):
    method get_action (line 74) | def get_action(self, obs_dict, step_cnt):
    method engage_enemy (line 131) | def engage_enemy(self, tmp_action, obs_dict, index):
    method choose_action_random (line 157) | def choose_action_random(self, index, step_cnt):
    method choose_action_random_attack (line 162) | def choose_action_random_attack(self, obs_dict, index, step_cnt):
    method choose_action_explore (line 166) | def choose_action_explore(self, obs_dict, index):
    method choose_action_attack (line 210) | def choose_action_attack(self, obs_dict, index):
    method choose_action_still (line 214) | def choose_action_still(step_cnt):

FILE: agent/base_agent.py
  class BaseAgent (line 13) | class BaseAgent:
    method __init__ (line 14) | def __init__(self):
    method get_obs_ind (line 24) | def get_obs_ind(self):

FILE: agent/fix_rule/agent.py
  class Agent (line 17) | class Agent:
    method __init__ (line 18) | def __init__(self):
    method set_map_info (line 24) | def set_map_info(self, size_x, size_y, detector_num, fighter_num):
    method get_action (line 28) | def get_action(self, obs_dict, step_cnt):
    method get_obs_ind (line 39) | def get_obs_ind(self):

FILE: agent/fix_rule/pytransform.py
  class PytransformError (line 42) | class PytransformError(Exception):
    method __init__ (line 43) | def __init__(self, *args, **kwargs):
    method _print_stack (line 49) | def _print_stack(self):
  function dllmethod (line 58) | def dllmethod(func):
  function init_pytransform (line 77) | def init_pytransform():
  function init_runtime (line 86) | def init_runtime(systrace=0, sysprofile=1, threadtrace=0, threadprofile=1):
  function import_module (line 93) | def import_module(modname, filename):
  function exec_file (line 102) | def exec_file(filename):
  function encrypt_project_files (line 111) | def encrypt_project_files(proname, filelist, mode=0):
  function encrypt_files (line 117) | def encrypt_files(key, filelist, mode=0):
  function generate_project_capsule (line 123) | def generate_project_capsule(licfile):
  function _generate_project_capsule (line 129) | def _generate_project_capsule():
  function _encode_capsule_key_file (line 135) | def _encode_capsule_key_file(licfile):
  function generate_module_key (line 141) | def generate_module_key(pubname, key):
  function generate_license_file (line 148) | def generate_license_file(filename, priname, rcode, start=-1, count=1):
  function get_registration_code (line 154) | def get_registration_code():
  function get_expired_days (line 160) | def get_expired_days():
  function get_trial_days (line 166) | def get_trial_days():
  function version_info (line 172) | def version_info():
  function get_hd_sn (line 177) | def get_hd_sn():
  function show_hd_info (line 185) | def show_hd_info():
  function get_license_info (line 188) | def get_license_info():
  function _load_library (line 224) | def _load_library(path=None):
  function pyarmor_init (line 264) | def pyarmor_init(path=None):
  function pyarmor_runtime (line 273) | def pyarmor_runtime(path=None):

FILE: agent/fix_rule_no_att/agent.py
  class Agent (line 31) | class Agent:
    method __init__ (line 32) | def __init__(self):
    method set_map_info (line 38) | def set_map_info(self, size_x, size_y, detector_num, fighter_num):
    method get_action (line 42) | def get_action(self, obs_dict, step_cnt):
    method get_obs_ind (line 53) | def get_obs_ind(self):

FILE: agent/fix_rule_no_att/pytransform.py
  class PytransformError (line 42) | class PytransformError(Exception):
    method __init__ (line 43) | def __init__(self, *args, **kwargs):
    method _print_stack (line 49) | def _print_stack(self):
  function dllmethod (line 58) | def dllmethod(func):
  function init_pytransform (line 77) | def init_pytransform():
  function init_runtime (line 86) | def init_runtime(systrace=0, sysprofile=1, threadtrace=0, threadprofile=1):
  function import_module (line 93) | def import_module(modname, filename):
  function exec_file (line 102) | def exec_file(filename):
  function encrypt_project_files (line 111) | def encrypt_project_files(proname, filelist, mode=0):
  function encrypt_files (line 117) | def encrypt_files(key, filelist, mode=0):
  function generate_project_capsule (line 123) | def generate_project_capsule(licfile):
  function _generate_project_capsule (line 129) | def _generate_project_capsule():
  function _encode_capsule_key_file (line 135) | def _encode_capsule_key_file(licfile):
  function generate_module_key (line 141) | def generate_module_key(pubname, key):
  function generate_license_file (line 148) | def generate_license_file(filename, priname, rcode, start=-1, count=1):
  function get_registration_code (line 154) | def get_registration_code():
  function get_expired_days (line 160) | def get_expired_days():
  function get_trial_days (line 166) | def get_trial_days():
  function version_info (line 172) | def version_info():
  function get_hd_sn (line 177) | def get_hd_sn():
  function show_hd_info (line 185) | def show_hd_info():
  function get_license_info (line 188) | def get_license_info():
  function _load_library (line 224) | def _load_library(path=None):
  function pyarmor_init (line 264) | def pyarmor_init(path=None):
  function pyarmor_runtime (line 273) | def pyarmor_runtime(path=None):

FILE: agent/simple/agent.py
  class Agent (line 28) | class Agent(BaseAgent):
    method __init__ (line 29) | def __init__(self):
    method set_map_info (line 44) | def set_map_info(self, size_x, size_y, detector_num, fighter_num):
    method __reset (line 50) | def __reset(self):
    method get_action (line 53) | def get_action(self, obs_dict, step_cnt):

FILE: agent/simple/dqn.py
  class NetFighter (line 16) | class NetFighter(nn.Module):
    method __init__ (line 17) | def __init__(self, n_actions):
    method forward (line 45) | def forward(self, img, info):
  class RLFighter (line 56) | class RLFighter:
    method __init__ (line 57) | def __init__(
    method choose_action (line 72) | def choose_action(self, img_obs, info_obs):
  class NetDetector (line 85) | class NetDetector(nn.Module):
    method __init__ (line 86) | def __init__(self, n_actions):
    method forward (line 114) | def forward(self, img, info):

FILE: common/agent_process.py
  class AgentProc (line 19) | class AgentProc(Process):
    method __init__ (line 23) | def __init__(self, agent_name, size_x, size_y, detector_num, fighter_n...
    method run (line 36) | def run(self):
    method __decision_proc (line 50) | def __decision_proc(self):
  class AgentCtrl (line 64) | class AgentCtrl:
    method __init__ (line 68) | def __init__(self, agent_name, size_x, size_y, detector_num, fighter_n...
    method agent_init (line 78) | def agent_init(self):
    method terminate (line 92) | def terminate(self):
    method get_action (line 104) | def get_action(self, obs_raw_dict, step_cnt):
    method __agent_restart (line 127) | def __agent_restart(self):

FILE: configuration/reward.py
  class GlobalVar (line 13) | class GlobalVar:
  function get_reward_radar_detector_detector (line 58) | def get_reward_radar_detector_detector():
  function get_reward_radar_detector_fighter (line 62) | def get_reward_radar_detector_fighter():
  function get_reward_radar_fighter_detector (line 66) | def get_reward_radar_fighter_detector():
  function get_reward_radar_fighter_fighter (line 70) | def get_reward_radar_fighter_fighter():
  function get_reward_strike_detector_success (line 74) | def get_reward_strike_detector_success():
  function get_reward_strike_detector_fail (line 78) | def get_reward_strike_detector_fail():
  function get_reward_strike_fighter_success (line 82) | def get_reward_strike_fighter_success():
  function get_reward_strike_fighter_fail (line 86) | def get_reward_strike_fighter_fail():
  function get_reward_detector_destroyed (line 90) | def get_reward_detector_destroyed():
  function get_reward_fighter_destroyed (line 94) | def get_reward_fighter_destroyed():
  function get_reward_strike_act_valid (line 98) | def get_reward_strike_act_valid():
  function get_reward_strike_act_invalid (line 102) | def get_reward_strike_act_invalid():
  function get_reward_keep_alive_step (line 106) | def get_reward_keep_alive_step():
  function get_reward_win (line 110) | def get_reward_win():
  function get_reward_lose (line 114) | def get_reward_lose():
  function get_reward_totally_win (line 118) | def get_reward_totally_win():
  function get_reward_totally_lose (line 122) | def get_reward_totally_lose():
  function get_reward_draw (line 126) | def get_reward_draw():

FILE: configuration/system.py
  class GlobalVar (line 13) | class GlobalVar:
  function get_attack_effect_delay (line 20) | def get_attack_effect_delay():
  function get_hit_prob_enable (line 24) | def get_hit_prob_enable():

FILE: environment/interface.py
  class Environment (line 21) | class Environment:
    method __init__ (line 25) | def __init__(self, map_path, side1_obs_ind, side2_obs_ind, max_step=50...
    method get_done (line 78) | def get_done(self):
    method get_obs (line 86) | def get_obs(self):
    method get_obs_raw (line 105) | def get_obs_raw(self):
    method get_alive_status (line 128) | def get_alive_status(self,side1_detector_obs_raw_list,side1_fighter_ob...
    method get_reward (line 131) | def get_reward(self):
    method reset (line 138) | def reset(self):
    method step (line 144) | def step(self, side1_detector_action, side1_fighter_action, side2_dete...
    method get_map_size (line 155) | def get_map_size(self):
    method get_unit_num (line 163) | def get_unit_num(self):
    method get_unit_property_list (line 173) | def get_unit_property_list(self):
    method set_surrender (line 183) | def set_surrender(self, side):
  class PlayBack (line 192) | class PlayBack:
    method __init__ (line 196) | def __init__(self, log_name, display_delay_time=0):
    method start (line 204) | def start(self):
  function get_distance (line 211) | def get_distance(a_x, a_y, b_x, b_y):
  function angle_cal (line 223) | def angle_cal(o_x, o_y, e_x, e_y):

FILE: environment/pytransform.py
  class PytransformError (line 42) | class PytransformError(Exception):
    method __init__ (line 43) | def __init__(self, *args, **kwargs):
    method _print_stack (line 49) | def _print_stack(self):
  function dllmethod (line 58) | def dllmethod(func):
  function init_pytransform (line 77) | def init_pytransform():
  function init_runtime (line 86) | def init_runtime(systrace=0, sysprofile=1, threadtrace=0, threadprofile=1):
  function import_module (line 93) | def import_module(modname, filename):
  function exec_file (line 102) | def exec_file(filename):
  function encrypt_project_files (line 111) | def encrypt_project_files(proname, filelist, mode=0):
  function encrypt_files (line 117) | def encrypt_files(key, filelist, mode=0):
  function generate_project_capsule (line 123) | def generate_project_capsule(licfile):
  function _generate_project_capsule (line 129) | def _generate_project_capsule():
  function _encode_capsule_key_file (line 135) | def _encode_capsule_key_file(licfile):
  function generate_module_key (line 141) | def generate_module_key(pubname, key):
  function generate_license_file (line 148) | def generate_license_file(filename, priname, rcode, start=-1, count=1):
  function get_registration_code (line 154) | def get_registration_code():
  function get_expired_days (line 160) | def get_expired_days():
  function get_trial_days (line 166) | def get_trial_days():
  function version_info (line 172) | def version_info():
  function get_hd_sn (line 177) | def get_hd_sn():
  function show_hd_info (line 185) | def show_hd_info():
  function get_license_info (line 188) | def get_license_info():
  function _load_library (line 224) | def _load_library(path=None):
  function pyarmor_init (line 264) | def pyarmor_init(path=None):
  function pyarmor_runtime (line 273) | def pyarmor_runtime(path=None):

FILE: environment/render/render_pic2.py
  class Render (line 8) | class Render:
    method __init__ (line 9) | def __init__(self, size_x, size_y):#, o_detector_num, o_fighter_num, e...
    method dis_update (line 57) | def dis_update(self, done, step, o_detector_data_obs_list, o_fighter_d...
    method dis_update_done_font (line 79) | def dis_update_done_font(self):
    method dis_update_font (line 82) | def dis_update_font(self, step, red_reward, blue_reward, red_detector_...
    method dis_update_pos (line 85) | def dis_update_pos(self, o_detector_pos_list, o_fighter_pos_list, e_de...
    method draw_course (line 88) | def draw_course(self, center_point_x, center_point_y, course, course_r):
    method draw_fight_rela (line 91) | def draw_fight_rela(self, center_point_x, center_point_y, striking_lis...

FILE: environment/world/config.py
  class GlobalVar (line 2) | class GlobalVar:
  function get_api_raw (line 40) | def get_api_raw():
  function get_api_spatial (line 43) | def get_api_spatial():
  function get_band_L (line 46) | def get_band_L():
  function get_band_S (line 49) | def get_band_S():
  function get_band_X (line 52) | def get_band_X():
  function get_band_fp_num (line 55) | def get_band_fp_num(band):
  function get_detection_hit_probability (line 58) | def get_detection_hit_probability(typ):
  function get_hit_detection_source_detector_L (line 61) | def get_hit_detection_source_detector_L():
  function get_hit_detection_source_detector_S (line 64) | def get_hit_detection_source_detector_S():
  function get_hit_detection_source_fighter (line 67) | def get_hit_detection_source_fighter():
  function get_hit_detection_source_passive (line 70) | def get_hit_detection_source_passive():
  function get_img_obs_redu_ratio (line 73) | def get_img_obs_redu_ratio():
  function get_j_coverage_angle (line 76) | def get_j_coverage_angle(band):
  function get_j_max_range (line 79) | def get_j_max_range(band):
  function get_l_missile_dis (line 82) | def get_l_missile_dis():
  function get_l_missile_hit_probability (line 85) | def get_l_missile_hit_probability():
  function get_l_missile_op_dec_ratio (line 88) | def get_l_missile_op_dec_ratio():
  function get_l_missile_op_req (line 91) | def get_l_missile_op_req():
  function get_l_missile_type (line 94) | def get_l_missile_type():
  function get_l_missile_num (line 97) | def get_l_missile_num():
  function get_passive_loc_continuous_detection_req (line 100) | def get_passive_loc_continuous_detection_req():
  function get_passive_loc_fighter_num_req (line 103) | def get_passive_loc_fighter_num_req():
  function get_r_coverage_angle_X (line 106) | def get_r_coverage_angle_X():
  function get_r_jammed_angle_mlob (line 109) | def get_r_jammed_angle_mlob(band):
  function get_r_jammed_range_mlobe (line 112) | def get_r_jammed_range_mlobe(band):
  function get_r_jammed_range_slobe_aim (line 115) | def get_r_jammed_range_slobe_aim(band):
  function get_r_jammed_range_slobe_block (line 118) | def get_r_jammed_range_slobe_block(band):
  function get_r_max_range (line 121) | def get_r_max_range(band):
  function get_s_missile_dis (line 124) | def get_s_missile_dis():
  function get_s_missile_hit_probability (line 127) | def get_s_missile_hit_probability():
  function get_s_missile_op_dec_ratio (line 130) | def get_s_missile_op_dec_ratio():
  function get_s_missile_op_req (line 133) | def get_s_missile_op_req():
  function get_s_missile_type (line 136) | def get_s_missile_type():
  function get_s_missile_num (line 139) | def get_s_missile_num():

FILE: environment/world/detection_calc.py
  function passive_detection_calc (line 6) | def passive_detection_calc(self_context, enemy_fighter_context_list):
  function radar_visible_calc (line 25) | def radar_visible_calc(self_context, enemy_detector_context_list, enemy_...
  function under_jam_check (line 110) | def under_jam_check(rader_x, radar_y, radar_band, jammer_x, jammer_y, ja...

FILE: environment/world/em_battle.py
  class BattleField (line 12) | class BattleField:
    method __init__ (line 13) | def __init__(self, size_x, size_y, o_detector_list, o_fighter_list, e_...
    method get_alive_status (line 153) | def get_alive_status(self, o_detector_status_list, o_fighter_status_li...
    method get_done (line 185) | def get_done(self):
    method get_obs_raw (line 192) | def get_obs_raw(self):
    method get_reward (line 284) | def get_reward(self):
    method get_reward_list (line 288) | def get_reward_list(self):
    method reset (line 297) | def reset(self):
    method set_surrender (line 400) | def set_surrender(self, side):
    method show (line 417) | def show(self):
    method step (line 421) | def step(self, side1_detector_action, side1_fighter_action, side2_dete...

FILE: environment/world/load_map.py
  class Map (line 3) | class Map:
    method __init__ (line 4) | def __init__(self, map_path):
    method get_map_size (line 8) | def get_map_size(self):
    method get_unit_num (line 11) | def get_unit_num(self):
    method get_unit_property_list (line 14) | def get_unit_property_list(self):

FILE: environment/world/position_calc.py
  function get_distance (line 4) | def get_distance(a_x, a_y, b_x, b_y):
  function angle_cal (line 8) | def angle_cal(x1, y1, x2, y2):
  function pos_generate (line 21) | def pos_generate(side1_d_num, side1_f_num, side2_d_num, side2_f_num, siz...
  function pos_update (line 45) | def pos_update(pos_x, pos_y, course, step, size_x, size_y):

FILE: environment/world/strike_calc.py
  function get_strike_result_by_ratio (line 9) | def get_strike_result_by_ratio(strike_ratio, random_obj):
  function strike_act_validation_and_initiation (line 16) | def strike_act_validation_and_initiation(missile_type, fighter_context, ...
  function strike_judge (line 85) | def strike_judge(strike_context, fighter_radar_visible_list, random_obj):
  function strike_judge_no_delay (line 142) | def strike_judge_no_delay(strike_context, random_obj):

FILE: obs_construct/airc_homo_rule/construct.py
  class ObsConstruct (line 6) | class ObsConstruct:
    method __init__ (line 7) | def __init__(self, size_x, size_y, detector_num, fighter_num):
    method obs_construct (line 15) | def obs_construct(self, obs_raw_dict):
    method distance_key (line 50) | def distance_key(ele):
    method obs_construct_old (line 53) | def obs_construct_old(self, obs_raw_dict):
    method __get_alive_status (line 84) | def __get_alive_status(self, detector_data_obs_list, fighter_data_obs_...
    method __get_img_obs (line 94) | def __get_img_obs(self, detector_data_obs_list, fighter_data_obs_list,...
    method __set_value_in_img (line 220) | def __set_value_in_img(self, img, pos_x, pos_y, value):
    method __get_data_obs (line 259) | def __get_data_obs(self, detector_data_obs_list, fighter_data_obs_list...

FILE: obs_construct/simple/construct.py
  class ObsConstruct (line 4) | class ObsConstruct:
    method __init__ (line 5) | def __init__(self, size_x, size_y, detector_num, fighter_num):
    method obs_construct (line 12) | def obs_construct(self, obs_raw_dict):
    method __get_alive_status (line 42) | def __get_alive_status(self,detector_data_obs_list,fighter_data_obs_li...
    method __get_img_obs (line 53) | def __get_img_obs(self, detector_data_obs_list, fighter_data_obs_list,...
    method __set_value_in_img (line 172) | def __set_value_in_img(self, img, pos_x, pos_y, value):
    method __get_data_obs (line 212) | def __get_data_obs(self, detector_data_obs_list, fighter_data_obs_list...

FILE: tournament/tournament_mp.py
  function run (line 26) | def run(agent1_name, agent2_name, map_name, round_num, max_step, random_...

FILE: train/simple/dqn.py
  class NetFighter (line 16) | class NetFighter(nn.Module):
    method __init__ (line 17) | def __init__(self, n_actions):
    method forward (line 45) | def forward(self, img, info):
  class RLFighter (line 56) | class RLFighter:
    method __init__ (line 57) | def __init__(
    method store_transition (line 102) | def store_transition(self, s, a, r, s_):
    method __clear_memory (line 111) | def __clear_memory(self):
    method choose_action (line 120) | def choose_action(self, img_obs, info_obs):
    method learn (line 137) | def learn(self):
  class NetDetector (line 180) | class NetDetector(nn.Module):
    method __init__ (line 181) | def __init__(self, n_actions):
    method forward (line 209) | def forward(self, img, info):

FILE: utility.py
  function distance (line 5) | def distance(x1, y1, x2, y2):
  function angle (line 9) | def angle(x1, y1, x2, y2):
Condensed preview — 56 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (452K chars).
[
  {
    "path": ".gitignore",
    "chars": 1635,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
  },
  {
    "path": "README.md",
    "chars": 2003,
    "preview": "# MaCA\n![](https://img.shields.io/badge/language-python-green.svg)\n![](https://img.shields.io/badge/platform-windows-gre"
  },
  {
    "path": "agent/airc_homo_rule/agent.py",
    "chars": 10096,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Xunyun Liu\n@contact: xunyunliu@gmail.com\n@software: PyCharm\n"
  },
  {
    "path": "agent/base_agent.py",
    "chars": 554,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "agent/fix_rule/agent.py",
    "chars": 943,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom pytransform import pyarmor_runtime\npyarmor_runtime()\n\"\"\"\n@author: Ga"
  },
  {
    "path": "agent/fix_rule/agent_core.py",
    "chars": 28387,
    "preview": "__pyarmor__(__name__, __file__, b'\\xe7\\x50\\x8c\\x64\\x26\\x42\\xd6\\x01\\xb9\\x4e\\x3f\\xdf\\x40\\x99\\x74\\xef\\xb8\\xc9\\x91\\x76\\x3b\\x"
  },
  {
    "path": "agent/fix_rule/license.lic",
    "chars": 212,
    "preview": "HSpGTEFHUzoBKkNPREU6UHlhcm1vci1Qcm9qZWN0OHD4jbg3oaZPjPlTyiQyadr7bY7WVZJHSrbRS3HjpzdMKMC4qTYbE97ZIZZ8XWDTHSJrrOVqGCnWjuZ7"
  },
  {
    "path": "agent/fix_rule/product.key",
    "chars": 74,
    "preview": "Bې?CA\u0016k8a\u0011\u00136W\fH0vY\ry\n\u001e\r}\u001f\u0005q\u0001#fRq+JBwzʱnƐS*T\u0011E`wN(\u0005RGy0t\u001dD\u001c&y\u001d\nP:C\u001fq\\8SBV]"
  },
  {
    "path": "agent/fix_rule/pytransform.py",
    "chars": 8607,
    "preview": "# Because ctypes is new from Python 2.5, so pytransform doesn't work\n# before Python 2.5\n#\nfrom ctypes import cdll, c_ch"
  },
  {
    "path": "agent/fix_rule_no_att/agent.py",
    "chars": 1620,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom pytransform import pyarmor_runtime\npyarmor_runtime()\n\"\"\"\n   Copyrigh"
  },
  {
    "path": "agent/fix_rule_no_att/agent_core.py",
    "chars": 21435,
    "preview": "__pyarmor__(__name__, __file__, b'\\xe7\\x50\\x8c\\x64\\x26\\x42\\xd6\\x01\\xb9\\x4e\\x3f\\xdf\\x40\\x99\\x74\\xef\\xb8\\xc9\\x91\\x76\\x3b\\x"
  },
  {
    "path": "agent/fix_rule_no_att/license.lic",
    "chars": 212,
    "preview": "HSpGTEFHUzoBKkNPREU6UHlhcm1vci1Qcm9qZWN0egMhJ6NNlQdmKa/iVehg0LovCYkZYgMtBOQo6jHlP0slLc0iYjbS9NAnZQslmFBVRWO6JERZBMANwGUl"
  },
  {
    "path": "agent/fix_rule_no_att/product.key",
    "chars": 74,
    "preview": "Bې?CA\u0016k8a\u0011\u00136W\fH0vY\ry\n\u001e\r}\u001f\u0005q\u0001#fRq+JBwzʱnƐS*T\u0011E`wN(\u0005RGy0t\u001dD\u001c&y\u001d\nP:C\u001fq\\8SBV]"
  },
  {
    "path": "agent/fix_rule_no_att/pytransform.py",
    "chars": 8607,
    "preview": "# Because ctypes is new from Python 2.5, so pytransform doesn't work\n# before Python 2.5\n#\nfrom ctypes import cdll, c_ch"
  },
  {
    "path": "agent/simple/agent.py",
    "chars": 2530,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "agent/simple/dqn.py",
    "chars": 3976,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "common/agent_process.py",
    "chars": 4449,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "configuration/reward.py",
    "chars": 2849,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "configuration/system.py",
    "chars": 461,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "doc/tutorial.md",
    "chars": 14292,
    "preview": "# 多智能体对抗仿真环境MaCA完全入门指南\n[TOC]\n## 1 前言\n中国电子科技集团公司认知与智能技术重点实验室发布的MaCA(Multi-agent Combat Arena)环境,是国内首个可模拟军事作战的轻量级多智能体对抗与训练"
  },
  {
    "path": "environment/error_log.py",
    "chars": 7289,
    "preview": "{'speed': 3, 'r_band': 2, 'j_band': 2, 'l_missile_num': 2, 's_missile_num': 4, 'id': 3, 'alive': True, 'pos_x': 576, 'po"
  },
  {
    "path": "environment/interface.py",
    "chars": 9814,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom pytransform import pyarmor_runtime\npyarmor_runtime()\n\"\"\"\n@author: Ga"
  },
  {
    "path": "environment/license.lic",
    "chars": 200,
    "preview": "FCpGTEFHUzoBKkNPREU6cHJvLTAyZ5BCrprWffXaRJeFaCw1aihFNyaQ/BLeHa7NWyCHrDf43ud9WKhQVbrO3PWhLjHKZEZE9FkBbDV440VAFJ+knAcuTEk5"
  },
  {
    "path": "environment/product.key",
    "chars": 74,
    "preview": "Bې?CA\u0016k8a\u0011\u00136W\fH0vY\ry\n\u001e\r}\u001f\u0005q\u0001#fRq+JBwzʱnƐS*T\u0011E`wN(\u0005RGy0t\u001dD\u001c&y\u001d\nP:C\u001fq\\8SBV]"
  },
  {
    "path": "environment/pytransform.py",
    "chars": 8607,
    "preview": "# Because ctypes is new from Python 2.5, so pytransform doesn't work\n# before Python 2.5\n#\nfrom ctypes import cdll, c_ch"
  },
  {
    "path": "environment/render/__init__.py",
    "chars": 663,
    "preview": "__pyarmor__(__name__, __file__, b'\\xec\\x50\\x8c\\x64\\x26\\x42\\xd6\\x01\\x10\\x54\\xca\\x9c\\xb6\\x36\\x84\\x05\\x6a\\x0b\\xf3\\xc4\\x16\\x"
  },
  {
    "path": "environment/render/render_pic.py",
    "chars": 45879,
    "preview": "__pyarmor__(__name__, __file__, b'\\xe7\\x50\\x8c\\x64\\x26\\x42\\xd6\\x01\\xb9\\x4e\\x3f\\xdf\\x40\\x9b\\x76\\xef\\x72\\x6c\\x30\\x53\\x5b\\x"
  },
  {
    "path": "environment/render/render_pic2.py",
    "chars": 4793,
    "preview": "import traceback\nimport pygame\nimport traceback\nimport os\nimport copy\nfrom render.render_pic3 import Render as Render3\n\n"
  },
  {
    "path": "environment/world/__init__.py",
    "chars": 659,
    "preview": "__pyarmor__(__name__, __file__, b'\\xec\\x50\\x8c\\x64\\x26\\x42\\xd6\\x01\\x10\\x54\\xca\\x9c\\xb6\\x36\\x84\\x05\\x6a\\x0b\\xf3\\xc4\\x16\\x"
  },
  {
    "path": "environment/world/config.py",
    "chars": 3555,
    "preview": "\nclass GlobalVar:\n\tapi_raw = 0\n\tapi_spatial = 1\n\tband_L = 0\n\tband_S = 1\n\tband_X = 2\n\tband_fp_num = [20, 20, 10]\n\tdetecti"
  },
  {
    "path": "environment/world/detection_calc.py",
    "chars": 4536,
    "preview": "import copy\nimport world.config as config\nimport world.position_calc as position_calc\n\n\ndef passive_detection_calc(self_"
  },
  {
    "path": "environment/world/em_battle.py",
    "chars": 40583,
    "preview": "import copy\nimport random\nimport numpy as np\nimport world.config as config\nfrom render.render_pic import Render\nimport c"
  },
  {
    "path": "environment/world/load_map.py",
    "chars": 578,
    "preview": "import json\n\nclass Map:\n\tdef __init__(self, map_path):\n\t\twith open(map_path, 'r') as f:\n\t\t\tself.map_info = json.load(f)\n"
  },
  {
    "path": "environment/world/log.py",
    "chars": 52971,
    "preview": "__pyarmor__(__name__, __file__, b'\\x84\\x50\\x8c\\x64\\x26\\x42\\xd6\\x01\\x9b\\xd2\\x9b\\x61\\xa4\\xcf\\x1b\\xb9\\x58\\x14\\x4e\\xf4\\xc9\\x"
  },
  {
    "path": "environment/world/position_calc.py",
    "chars": 1916,
    "preview": "import math\n\n\ndef get_distance(a_x, a_y, b_x, b_y):\n    return math.sqrt((a_x - b_x) ** 2 + (a_y - b_y) ** 2)\n\n\ndef angl"
  },
  {
    "path": "environment/world/replay.py",
    "chars": 13511,
    "preview": "__pyarmor__(__name__, __file__, b'\\xe7\\x50\\x8c\\x64\\x26\\x42\\xd6\\x01\\xb9\\x4e\\x3f\\xdf\\x40\\x9b\\x76\\xef\\x72\\x6c\\x30\\x53\\x5b\\x"
  },
  {
    "path": "environment/world/strike_calc.py",
    "chars": 5598,
    "preview": "import random\nimport copy\nimport world.position_calc\nimport configuration.system as system_config\nimport world.position_"
  },
  {
    "path": "fight.py",
    "chars": 10604,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "fight_mp.py",
    "chars": 9509,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "log/readme",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "model/README",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "obs_construct/airc_homo_rule/construct.py",
    "chars": 16000,
    "preview": "import numpy as np\nimport copy\nimport utility as ut\n\n\nclass ObsConstruct:\n    def __init__(self, size_x, size_y, detecto"
  },
  {
    "path": "obs_construct/simple/construct.py",
    "chars": 13697,
    "preview": "import numpy as np\nimport copy\n\nclass ObsConstruct:\n    def __init__(self, size_x, size_y, detector_num, fighter_num):\n "
  },
  {
    "path": "replay.py",
    "chars": 514,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "tournament/config.ini",
    "chars": 129,
    "preview": "{\"map_name\": \"1000_1000_fighter10v10\", \"round_num\": 2, \"max_step\": 1500, \"agent_list\": [\"simple\", \"fix_rule\", \"fix_rule_"
  },
  {
    "path": "tournament/config_gen.py",
    "chars": 666,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "tournament/tournament_mp.py",
    "chars": 12333,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "train/simple/dqn.py",
    "chars": 7760,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "train/simple/main.py",
    "chars": 4432,
    "preview": "#! /usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n@author: Gao Fang\n@contact: gaofang@cetc.com.cn\n@software: PyCharm\n@f"
  },
  {
    "path": "utility.py",
    "chars": 256,
    "preview": "# utility.py\nimport math\n\n\ndef distance(x1, y1, x2, y2):\n    return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)\n\n\ndef ang"
  }
]

// ... and 6 more files (download for full content)

About this extraction

This page contains the full source code of the SJTUwbl/MaCA GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 56 files (381.0 KB), approximately 152.0k tokens, and a symbol index with 264 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!