import random as rnd
import timeit
from math import sqrt, log

from chess import PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING
from .bot import ChessBot

class ChessBotVictor(ChessBot):
    def __init__(self, name, opt_dict = None):
        super().__init__(name, opt_dict)
        self.depth = opt_dict['depth']
        self.is_white = True

        self.random_table = [[rnd.randint(0, 2**64) for _ in range(12)] for _ in range(64)]
        self.transposition = dict()

        self.pawns_eval_white = [
            0,  0,  0,  0,  0,  0,  0,  0,
            50, 50, 50, 50, 50, 50, 50, 50,
            10, 10, 20, 30, 30, 20, 10, 10,
            5,  5, 10, 25, 25, 10,  5,  5,
            0,  0,  0, 20, 20,  0,  0,  0,
            5, -5,-10,  0,  0,-10, -5,  5,
            5, 10, 10,-20,-20, 10, 10,  5,
            0,  0,  0,  0,  0,  0,  0,  0
        ]

        self.pawns_eval_black = [i for i in reversed(self.pawns_eval_white)]

        self.knights_eval_white = [
            -50,-40,-30,-30,-30,-30,-40,-50,
            -40,-20,  0,  0,  0,  0,-20,-40,
            -30,  0, 10, 15, 15, 10,  0,-30,
            -30,  5, 15, 20, 20, 15,  5,-30,
            -30,  0, 15, 20, 20, 15,  0,-30,
            -30,  5, 10, 15, 15, 10,  5,-30,
            -40,-20,  0,  5,  5,  0,-20,-40,
            -50,-40,-30,-30,-30,-30,-40,-50
        ]

        self.knights_eval_black = [i for i in reversed(self.knights_eval_white)]

        self.bishops_eval_white = [
            -20,-10,-10,-10,-10,-10,-10,-20,
            -10,  0,  0,  0,  0,  0,  0,-10,
            -10,  0,  5, 10, 10,  5,  0,-10,
            -10,  5,  5, 10, 10,  5,  5,-10,
            -10,  0, 10, 10, 10, 10,  0,-10,
            -10, 10, 10, 10, 10, 10, 10,-10,
            -10,  5,  0,  0,  0,  0,  5,-10,
            -20,-10,-10,-10,-10,-10,-10,-20
        ]

        self.bishops_eval_black = [i for i in reversed(self.bishops_eval_white)]

        self.rooks_eval_white = [
             0,  0,  0,  0,  0,  0,  0,  0,
             5, 10, 10, 10, 10, 10, 10,  5,
            -5,  0,  0,  0,  0,  0,  0, -5,
            -5,  0,  0,  0,  0,  0,  0, -5,
            -5,  0,  0,  0,  0,  0,  0, -5,
            -5,  0,  0,  0,  0,  0,  0, -5,
            -5,  0,  0,  0,  0,  0,  0, -5,
             0,  0,  0,  5,  5,  0,  0,  0
        ]

        self.rooks_eval_black = [i for i in reversed(self.rooks_eval_white)]

        self.queen_eval_white = [
            -20,-10,-10, -5, -5,-10,-10,-20,
            -10,  0,  0,  0,  0,  0,  0,-10,
            -10,  0,  5,  5,  5,  5,  0,-10,
             -5,  0,  5,  5,  5,  5,  0, -5,
              0,  0,  5,  5,  5,  5,  0, -5,
            -10,  5,  5,  5,  5,  5,  0,-10,
            -10,  0,  5,  0,  0,  0,  0,-10,
            -20,-10,-10, -5, -5,-10,-10,-20
        ]

        self.queen_eval_black = [i for i in reversed(self.queen_eval_white)]

        self.king_eval_white = [
            -30,-40,-40,-50,-50,-40,-40,-30,
            -30,-40,-40,-50,-50,-40,-40,-30,
            -30,-40,-40,-50,-50,-40,-40,-30,
            -30,-40,-40,-50,-50,-40,-40,-30,
            -20,-30,-30,-40,-40,-30,-30,-20,
            -10,-20,-20,-20,-20,-20,-20,-10,
             20, 20,  0,  0,  0,  0, 20, 20,
             20, 30, 10,  0,  0, 10, 30, 20
        ]

        self.king_eval_black = [i for i in reversed(self.king_eval_white)]

        self.king_end_game_eval_white = [
            -50,-40,-30,-20,-20,-30,-40,-50,
            -30,-20,-10,  0,  0,-10,-20,-30,
            -30,-10, 20, 30, 30, 20,-10,-30,
            -30,-10, 30, 40, 40, 30,-10,-30,
            -30,-10, 30, 40, 40, 30,-10,-30,
            -30,-10, 20, 30, 30, 20,-10,-30,
            -30,-30,  0,  0,  0,  0,-30,-30,
            -50,-30,-30,-30,-30,-30,-30,-50
        ]

        self.king_end_game_eval_black = [i for i in reversed(self.king_end_game_eval_white)]

    def is_end_game(self, board):
        n_pawns = len(board.pieces(PAWN, True)) + len(board.pieces(PAWN, False))
        n_knights = len(board.pieces(KNIGHT, True)) + len(board.pieces(KNIGHT, False))
        n_bishops = len(board.pieces(BISHOP, True)) + len(board.pieces(BISHOP, False))
        n_rooks = len(board.pieces(ROOK, True)) + len(board.pieces(ROOK, False))
        n_queens = len(board.pieces(QUEEN, True)) + len(board.pieces(QUEEN, False))
        n_kings = len(board.pieces(KING, True)) + len(board.pieces(KING, False))

        if n_pawns + n_knights + n_bishops + n_rooks + n_queens + n_kings <= 22:
            return True
        else:
            return False

    def calc_heuristic_score(self, board):
        if board.is_game_over():
            result = board.result()
            if (self.is_white and result == '1-0') or ((not self.is_white) and result == '0-1'):
                return 10**5
            elif (self.is_white and result == '0-1') or ((not self.is_white) and result == '1-0'):
                return -10**5
            else:
                return 0

        res = 0
        scores = {PAWN:100, KNIGHT:300, BISHOP:300, ROOK:500, QUEEN: 900, KING:9000}
        color_factors = {self.is_white: 1, (not self.is_white): -1}

        for square in range(64):
            piece = board.piece_at(square)
            if piece:
                res += scores[piece.piece_type] * color_factors[piece.color]

                if piece.color == self.is_white:
                    if piece.piece_type == PAWN:
                        if self.is_white:
                            res += self.pawns_eval_white[square]
                        else:
                            res += self.pawns_eval_black[square]

                    elif piece.piece_type == KNIGHT:
                        if self.is_white:
                            res += self.knights_eval_white[square]
                        else:
                            res += self.knights_eval_black[square]

                    elif piece.piece_type == BISHOP:
                        if self.is_white:
                            res += self.bishops_eval_white[square]
                        else:
                            res += self.bishops_eval_black[square]

                    elif piece.piece_type == ROOK:
                        if self.is_white:
                            res += self.rooks_eval_white[square]
                        else:
                            res += self.rooks_eval_black[square]

                    elif piece.piece_type == QUEEN:
                        if self.is_white:
                            res += self.queen_eval_white[square]
                        else:
                            res += self.queen_eval_black[square]

                    elif piece.piece_type == KING and self.is_end_game(board):
                        if self.is_white:
                            res += self.king_end_game_eval_white[square]
                        else:
                            res += self.king_end_game_eval_black[square]

                    else:
                        if self.is_white:
                            res += self.king_eval_white[square]
                        else:
                            res += self.king_eval_black[square]

        self.transposition[self.zobrist_hash(board)] = res
        return res

    def get_moves_to_explore(self, board):
        moves_to_explore = []
        moves = self.possible_moves(board)

        if False:
            scores = []
            for move in moves:
                board_copy = board.copy()
                board_copy.push(move)

                scores.append(self.calc_heuristic_score(board_copy))

            moves_dict = dict(list(zip(scores, moves)))
            scores.sort(reverse=True)

            for i in range(4):
                key = scores[i]
                moves_to_explore.append(moves_dict[key])

            for i in range(2):
                moves_to_explore.append(rnd.choice(moves))

            for i in range(4):
                key = scores[len(scores)-1-i]
                moves_to_explore.append(moves_dict[key])

            return moves_to_explore

        else:
            return moves

    def zobrist_hash(self, board):
        _hash = 0
        for i in range(64):
            piece = board.piece_at(i)
            if piece:
                j = piece.piece_type
                if not piece.color:
                    j += 6
                _hash ^= self.random_table[i][j-1]

        return _hash

    def minimax(self, board, depth, alpha, beta):
        if self.zobrist_hash(board) in self.transposition.keys():
            return self.transposition[self.zobrist_hash(board)]

        if depth == 1 or board.is_game_over():
            return self.calc_heuristic_score(board)

        elif board.turn == self.is_white:
            v = -10**6

            for a in self.get_moves_to_explore(board):
                board_copy = board.copy()
                board_copy.push(a)

                v = max(v, self.minimax(board_copy, depth-1, alpha, beta))
                alpha = max(alpha, v)

                if alpha >= beta:
                    break

            return v

        else:
            v = 10**6

            for a in self.get_moves_to_explore(board):
                board_copy = board.copy()
                board_copy.push(a)

                v = min(v, self.minimax(board_copy, depth-1, alpha, beta))
                beta = min(beta, v)

                if alpha >= beta:
                    break

            return v

    def move(self, board):
        self.is_white = board.turn
        best_score = -10**6
        current_score = 0
        best_move = None

        for move in self.get_moves_to_explore(board):
            board_copy = board.copy()
            board_copy.push(move)
            current_score = self.minimax(board_copy, self.depth, -10**6, 10**6)

            if current_score > best_score:
                best_score = current_score
                best_move = move

        return best_move

# # # # # # # # # # # # # # # # # # # # # #
# Chess Bot using Monte Carlo Tree Search #
# # # # # # # # # # # # # # # # # # # # # #

class ChessBotMonteCarlo(ChessBot):
    def __init__(self, name, opt_dict = None):
        super().__init__(name, opt_dict)
        self.n_simulations = opt_dict['n_simulations']
        self.n_interations = opt_dict['n_iterations']
        self.is_white = True

    class Node:
        def __init__(self, n_wins, n_simulations, board, parent, children):
            self.n_wins = n_wins
            self.n_simulations = n_simulations
            self.board = board
            self.parent = parent
            self.children = children

        def add_child(self, node):
            node.parent = self
            self.children.append(node)

    def get_uct(self, node, c=2):
        return (node.n_wins / node.n_simulations) + sqrt(c*log(node.parent.n_simulations)/node.n_simulations)

    def pick_best_child(self, root):
        best_uct = -10**6
        current_uct = 0
        best_child = None

        for child in root.children:
            current_uct = self.get_uct(child)
            if current_uct > best_uct:
                best_uct = current_uct
                best_child = child

        return best_child

    def simulate(self, node):
        n_wins = 0

        for _ in range(self.n_simulations):
            board_copy = node.board.copy()

            # print('Random Playout start...')
            while board_copy.result() == '*':
                moves = self.possible_moves(board_copy)
                board_copy.push(moves[rnd.randint(0, len(moves)-1)])
            # print('Random Playout ended.')

            if (board_copy.result() == '1-0' and self.is_white) or (board_copy.result() == '0-1' and not self.is_white):
                n_wins += 1
            else:
                pass

        return self.Node(n_wins, self.n_simulations, node.board.copy(), None, [])

    def backpropagate(self, node):
        for child in node.children:
            node.n_wins += child.n_wins
            node.n_simulations += child.n_simulations

        while node.parent != None:
            node.parent.n_wins += node.n_wins
            node.parent.n_simulations += node.n_simulations

            node = node.parent

        return node

    def monte_carlo_tree_search(self, root):
        for _ in range(self.n_interations):
            # print('Wins: ' + str(root.n_wins))
            # print('Simulations: ' + str(root.n_simulations))

            # Selection
            node = root
            while len(node.children) > 0:
                node = self.pick_best_child(node)

            if len(self.possible_moves(node.board)) == 0:
                break

            # Expansion
            expanded_nodes = []
            moves = self.possible_moves(node.board)
            for _ in range(len(moves)//2):
                board_copy = node.board.copy()
                board_copy.push(moves[rnd.randint(0, len(moves)-1)])
                expanded_nodes.append(self.Node(0, 0, board_copy, None, []))

            # Simulation
            for expanded_node in expanded_nodes:
                node.add_child(self.simulate(expanded_node))

            # Backpropagation
            root = self.backpropagate(node)

        return root

    def move(self, board):
        self.is_white = board.turn
        root = self.monte_carlo_tree_search(self.Node(0, 0, board, None, []))

        best_stat = -10^6
        current_state = 0
        best_node = None

        for node in root.children:
            current_state = node.n_wins / node.n_simulations
            if current_state > best_stat:
                best_stat = current_state
                best_node = node

        return best_node.board.pop()


'''
#Python 22 抓網站上資料
#抓系上網站的各種老師信箱
'''
import requests, re
email = re.compile('[a-zA-Z0-9_]+@[a-zA-Z0-9\._]+')
url = 'https://dct.ntcu.edu.tw/intro.php#director'
save_email = []
html = requests.get(url)
html.encoding = 'utf-8'
#print(type(html.text))
#print(html.text)
all_email = email.findall(html.text)
for i in range(len(all_email)):
    save_email = all_email[i].replace('','')
    print(save_email)


# Copyright (c) 2014 Hitachi Data Systems, Inc.
# All Rights Reserved.
#
#    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.
#

"""
iSCSI Cinder Volume driver for Hitachi Unified Storage (HUS-HNAS) platform.
"""

from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_log import log as logging
import six

from cinder import exception
from cinder.i18n import _, _LE, _LI
from cinder import interface

from cinder import utils as cinder_utils
from cinder.volume import driver
from cinder.volume.drivers.hitachi import hnas_backend
from cinder.volume.drivers.hitachi import hnas_utils
from cinder.volume import utils

HNAS_ISCSI_VERSION = '5.0.0'

LOG = logging.getLogger(__name__)

iSCSI_OPTS = [
    cfg.StrOpt('hds_hnas_iscsi_config_file',
               default='/opt/hds/hnas/cinder_iscsi_conf.xml',
               help='Legacy configuration file for HNAS iSCSI Cinder '
                    'plugin. This is not needed if you fill all '
                    'configuration on cinder.conf',
               deprecated_for_removal=True),
    cfg.BoolOpt('hnas_chap_enabled',
                default=True,
                help='Whether the chap authentication is enabled in the '
                     'iSCSI target or not.'),
    cfg.IPOpt('hnas_svc0_iscsi_ip',
              help='Service 0 iSCSI IP'),
    cfg.IPOpt('hnas_svc1_iscsi_ip',
              help='Service 1 iSCSI IP'),
    cfg.IPOpt('hnas_svc2_iscsi_ip',
              help='Service 2 iSCSI IP'),
    cfg.IPOpt('hnas_svc3_iscsi_ip',
              help='Service 3 iSCSI IP')
]

CONF = cfg.CONF
CONF.register_opts(iSCSI_OPTS)

HNAS_DEFAULT_CONFIG = {'ssc_cmd': 'ssc',
                       'chap_enabled': True,
                       'ssh_port': 22}
MAX_HNAS_ISCSI_TARGETS = 32
MAX_HNAS_LUS_PER_TARGET = 32

@interface.volumedriver
class HNASISCSIDriver(driver.ISCSIDriver):
    """HNAS iSCSI volume driver.

    Version history:

        code-block:: none

        Version 1.0.0: Initial driver version
        Version 2.2.0: Added support to SSH authentication
        Version 3.2.0: Added pool aware scheduling
                       Fixed concurrency errors
        Version 3.3.0: Fixed iSCSI target limitation error
        Version 4.0.0: Added manage/unmanage features
        Version 4.1.0: Fixed XML parser checks on blank options
        Version 4.2.0: Fixed SSH and cluster_admin_ip0 verification
        Version 4.3.0: Fixed attachment with os-brick 1.0.0
        Version 5.0.0: Code cleaning up
                       New communication interface between the driver and HNAS
                       Removed the option to use local SSC (ssh_enabled=False)
                       Updated to use versioned objects
                       Changed the class name to HNASISCSIDriver
                       Deprecated XML config file
                       Fixed driver stats reporting
"""

    # ThirdPartySystems wiki page
    CI_WIKI_NAME = "Hitachi_HNAS_CI"
    VERSION = HNAS_ISCSI_VERSION

    def __init__(self, *args, **kwargs):
        """Initializes and reads different config parameters."""
        super(HNASISCSIDriver, self).__init__(*args, **kwargs)
        self.configuration = kwargs.get('configuration', None)
        self.context = {}
        self.config = {}

        service_parameters = ['volume_type', 'hdp', 'iscsi_ip']
        optional_parameters = ['ssc_cmd', 'cluster_admin_ip0',
                               'chap_enabled']

        if self.configuration:
            self.configuration.append_config_values(
                hnas_utils.drivers_common_opts)
            self.configuration.append_config_values(iSCSI_OPTS)

            # Trying to get HNAS configuration from cinder.conf
            self.config = hnas_utils.read_cinder_conf(
                self.configuration, 'iscsi')

            # If HNAS configuration are not set on cinder.conf, tries to use
            # the deprecated XML configuration file
            if not self.config:
                self.config = hnas_utils.read_xml_config(
                    self.configuration.hds_hnas_iscsi_config_file,
                    service_parameters,
                    optional_parameters)

            self.reserved_percentage = (
                self.configuration.safe_get('reserved_percentage'))
            self.max_osr = (
                self.configuration.safe_get('max_over_subscription_ratio'))

        self.backend = hnas_backend.HNASSSHBackend(self.config)

    def _get_service(self, volume):
        """Gets the available service parameters.

        Get the available service parameters for a given volume using its
        type.

        :param volume: dictionary volume reference
        :returns: HDP (file system) related to the service or error if no
        configuration is found.
        :raises: ParameterNotFound
        """
        LOG.debug("Available services: %(svc)s.",
                  {'svc': self.config['services'].keys()})
        label = utils.extract_host(volume.host, level='pool')

        if label in self.config['services'].keys():
            svc = self.config['services'][label]
            LOG.info(_LI("Using service label: %(lbl)s."), {'lbl': label})
            return svc['hdp']
        else:
            LOG.error(_LE("No configuration found for service: %(lbl)s."),
                      {'lbl': label})
            raise exception.ParameterNotFound(param=label)

    def _get_service_target(self, volume):
        """Gets the available service parameters

        Gets the available service parameters for a given volume using its
        type.
        :param volume: dictionary volume reference
        :returns: service target information or raises error
        :raises: NoMoreTargets
        """
        fs_label = self._get_service(volume)
        evs_id = self.backend.get_evs(fs_label)

        svc_label = utils.extract_host(volume.host, level='pool')
        svc = self.config['services'][svc_label]

        lu_info = self.backend.check_lu(volume.name, fs_label)

        # The volume is already mapped to a LU, so no need to create any
        # targets
        if lu_info['mapped']:
            service = (
                svc['iscsi_ip'], svc['iscsi_port'], svc['evs'], svc['port'],
                fs_label, lu_info['tgt']['alias'], lu_info['tgt']['secret'])
            LOG.info(_LI("Volume %(vol_name)s already mapped on target "
                         "%(tgt)s to LUN %(lunid)s."),
                     {'vol_name': volume.name, 'tgt': lu_info['tgt']['alias'],
                      'lunid': lu_info['id']})
            return service

        # Each EVS can have up to 32 targets. Each target can have up to 32
        # LUs attached and have the name format 'evs<id>-tgt<0-N>'. We run
        # from the first 'evs1-tgt0' until we find a target that is not already
        # created in the BE or is created but have slots to place new LUs.
        tgt_alias = ''
        for i in range(0, MAX_HNAS_ISCSI_TARGETS):
            tgt_alias = 'evs' + evs_id + '-tgt' + six.text_type(i)
            tgt = self.backend.check_target(fs_label, tgt_alias)

            if (tgt['found'] and
                    len(tgt['tgt']['lus']) < MAX_HNAS_LUS_PER_TARGET or
                    not tgt['found']):
                # Target exists and has free space or, target does not exist
                # yet. Proceed and use the target or create a target using this
                # name.
                break
        else:
            # If we've got here, we run out of targets, raise and go away.
            LOG.error(_LE("No more targets available."))
            raise exception.NoMoreTargets(param=tgt_alias)

        LOG.info(_LI("Using target label: %(tgt)s."), {'tgt': tgt_alias})

        # Check if we have a secret stored for this target so we don't have to
        # go to BE on every query
        if 'targets' not in self.config.keys():
            self.config['targets'] = {}

        if tgt_alias not in self.config['targets'].keys():
            self.config['targets'][tgt_alias] = {}

        tgt_info = self.config['targets'][tgt_alias]

        # HNAS - one time lookup
        # see if the client supports CHAP authentication and if
        # iscsi_secret has already been set, retrieve the secret if
        # available, otherwise generate and store
        if self.config['chap_enabled']:
            # CHAP support is enabled. Tries to get the target secret.
            if 'iscsi_secret' not in tgt_info.keys():
                LOG.info(_LI("Retrieving secret for service: %(tgt)s."),
                         {'tgt': tgt_alias})
                out = self.backend.get_target_secret(tgt_alias, fs_label)
                tgt_info['iscsi_secret'] = out

                # CHAP supported and the target has no secret yet. So, the
                # secret is created for the target
                if tgt_info['iscsi_secret'] == "":
                    random_secret = utils.generate_password()[0:15]
                    tgt_info['iscsi_secret'] = random_secret

                    LOG.info(_LI("Set tgt CHAP secret for service: %(tgt)s."),
                             {'tgt': tgt_alias})
        else:
            # We set blank password when the client does not
            # support CHAP. Later on, if the client tries to create a new
            # target that does not exist in the backend, we check for this
            # value and use a temporary dummy password.
            if 'iscsi_secret' not in tgt_info.keys():
                # Warns in the first time
                LOG.info(_LI("CHAP authentication disabled."))

            tgt_info['iscsi_secret'] = "''"

        # If the target does not exist, it should be created
        if not tgt['found']:
            self.backend.create_target(tgt_alias, fs_label,
                                       tgt_info['iscsi_secret'])
        elif (tgt['tgt']['secret'] == "" and
                self.config['chap_enabled']):
            # The target exists, has no secret and chap is enabled
            self.backend.set_target_secret(tgt_alias, fs_label,
                                           tgt_info['iscsi_secret'])

        if 'tgt_iqn' not in tgt_info:
            LOG.info(_LI("Retrieving IQN for service: %(tgt)s."),
                     {'tgt': tgt_alias})

            out = self.backend.get_target_iqn(tgt_alias, fs_label)
            tgt_info['tgt_iqn'] = out

        self.config['targets'][tgt_alias] = tgt_info

        service = (svc['iscsi_ip'], svc['iscsi_port'], svc['evs'], svc['port'],
                   fs_label, tgt_alias, tgt_info['iscsi_secret'])

        return service

    def _get_stats(self):
        """Get FS stats from HNAS.

        :returns: dictionary with the stats from HNAS
        _stats['pools'] = {
            'total_capacity_gb': total size of the pool,
            'free_capacity_gb': the available size,
            'QoS_support': bool to indicate if QoS is supported,
            'reserved_percentage': percentage of size reserved,
            'max_over_subscription_ratio': oversubscription rate,
            'thin_provisioning_support': thin support (True),
            'reserved_percentage': reserved percentage
            }
        """
        hnas_stat = {}
        be_name = self.configuration.safe_get('volume_backend_name')
        hnas_stat["volume_backend_name"] = be_name or 'HNASISCSIDriver'
        hnas_stat["vendor_name"] = 'Hitachi'
        hnas_stat["driver_version"] = HNAS_ISCSI_VERSION
        hnas_stat["storage_protocol"] = 'iSCSI'

        for pool in self.pools:
            fs_info = self.backend.get_fs_info(pool['fs'])
            pool['provisioned_capacity_gb'] = fs_info['provisioned_capacity']
            pool['total_capacity_gb'] = (float(fs_info['total_size']))
            pool['free_capacity_gb'] = (
                float(fs_info['total_size']) - float(fs_info['used_size']))
            pool['QoS_support'] = 'False'
            pool['reserved_percentage'] = self.reserved_percentage
            pool['max_over_subscription_ratio'] = self.max_osr
            pool['thin_provisioning_support'] = True

        hnas_stat['pools'] = self.pools

        LOG.debug("stats: %(stat)s.", {'stat': hnas_stat})
        return hnas_stat

    def _check_fs_list(self):
        """Verifies the FSs list in HNAS.

        Verify that all FSs specified in the configuration files actually
        exists on the storage.
        """
        fs_list = self.config['fs'].keys()

        for fs in fs_list:
            if not self.backend.get_fs_info(fs):
                msg = (_("File system not found or not mounted: %(fs)s") %
                       {'fs': fs})
                LOG.error(msg)
                raise exception.ParameterNotFound(param=msg)

    def _check_pool_and_fs(self, volume, fs_label):
        """Validates pool and file system of a volume being managed.

        Checks if the file system for the volume-type chosen matches the
        one passed in the volume reference. Also, checks if the pool
        for the volume type matches the pool for the host passed.

        :param volume: Reference to the volume.
        :param fs_label: Label of the file system.
        :raises: ManageExistingVolumeTypeMismatch
        """
        pool_from_vol_type = hnas_utils.get_pool(self.config, volume)

        pool_from_host = utils.extract_host(volume.host, level='pool')
        pool = self.config['services'][pool_from_vol_type]['hdp']
        if pool != fs_label:
            msg = (_("Failed to manage existing volume because the "
                     "pool %(pool)s of the volume type chosen does not "
                     "match the file system %(fs_label)s passed in the "
                     "volume reference.")
                   % {'pool': pool, 'fs_label': fs_label})
            LOG.error(msg)
            raise exception.ManageExistingVolumeTypeMismatch(reason=msg)

        if pool_from_host != pool_from_vol_type:
            msg = (_("Failed to manage existing volume because the pool "
                     "%(pool)s of the volume type chosen does not match the "
                     "pool %(pool_host)s of the host.") %
                   {'pool': pool_from_vol_type, 'pool_host': pool_from_host})
            LOG.error(msg)
            raise exception.ManageExistingVolumeTypeMismatch(reason=msg)

    def _get_info_from_vol_ref(self, vol_ref):
        """Gets information from the volume reference.

        Returns the information (File system and volume name) taken from
        the volume reference.

        :param vol_ref: existing volume to take under management
        :returns: the file system label and the volume name or raises error
        :raises: ManageExistingInvalidReference
        """
        vol_info = vol_ref.strip().split('/')

        if len(vol_info) == 2 and '' not in vol_info:
            fs_label = vol_info[0]
            vol_name = vol_info[1]

            return fs_label, vol_name
        else:
            msg = _("The reference to the volume in the backend should have "
                    "the format file_system/volume_name (volume_name cannot "
                    "contain '/')")
            LOG.error(msg)
            raise exception.ManageExistingInvalidReference(
                existing_ref=vol_ref, reason=msg)

    def check_for_setup_error(self):
        pass

    def do_setup(self, context):
        """Sets up and verify Hitachi HNAS storage connection."""
        self.context = context
        self._check_fs_list()

        version_info = self.backend.get_version()
        LOG.info(_LI("HNAS iSCSI driver."))
        LOG.info(_LI("HNAS model: %(mdl)s"), {'mdl': version_info['model']})
        LOG.info(_LI("HNAS version: %(version)s"),
                 {'version': version_info['version']})
        LOG.info(_LI("HNAS hardware: %(hw)s"),
                 {'hw': version_info['hardware']})
        LOG.info(_LI("HNAS S/N: %(sn)s"), {'sn': version_info['serial']})
        service_list = self.config['services'].keys()
        for svc in service_list:
            svc = self.config['services'][svc]
            pool = {}
            pool['pool_name'] = svc['volume_type']
            pool['service_label'] = svc['volume_type']
            pool['fs'] = svc['hdp']

            self.pools.append(pool)

        LOG.debug("Configured pools: %(pool)s", {'pool': self.pools})

        evs_info = self.backend.get_evs_info()
        LOG.info(_LI("Configured EVSs: %(evs)s"), {'evs': evs_info})

        for svc in self.config['services'].keys():
            svc_ip = self.config['services'][svc]['iscsi_ip']
            if svc_ip in evs_info.keys():
                LOG.info(_LI("iSCSI portal found for service: %(svc_ip)s"),
                         {'svc_ip': svc_ip})
                self.config['services'][svc]['evs'] = (
                    evs_info[svc_ip]['evs_number'])
                self.config['services'][svc]['iscsi_port'] = '3260'
                self.config['services'][svc]['port'] = '0'
            else:
                LOG.error(_LE("iSCSI portal not found "
                              "for service: %(svc)s"), {'svc': svc_ip})
                raise exception.InvalidParameterValue(err=svc_ip)
        LOG.info(_LI("HNAS iSCSI Driver loaded successfully."))

    def ensure_export(self, context, volume):
        pass

    def create_export(self, context, volume, connector):
        pass

    def remove_export(self, context, volume):
        pass

    @cinder_utils.trace
    def create_volume(self, volume):
        """Creates a LU on HNAS.

        :param volume: dictionary volume reference
        :returns: the volume provider location
        """
        fs = self._get_service(volume)
        size = six.text_type(volume.size)

        self.backend.create_lu(fs, size, volume.name)

        return {'provider_location': self._get_provider_location(volume)}

    @cinder_utils.trace
    def create_cloned_volume(self, dst, src):
        """Creates a clone of a volume.

        :param dst: dictionary destination volume reference
        :param src: dictionary source volume reference
        :returns: the provider location of the extended volume
        """
        fs_label = self._get_service(dst)

        self.backend.create_cloned_lu(src.name, fs_label, dst.name)

        if src.size < dst.size:
            LOG.debug("Increasing dest size from %(old_size)s to "
                      "%(new_size)s",
                      {'old_size': src.size, 'new_size': dst.size})
            self.extend_volume(dst, dst.size)

        return {'provider_location': self._get_provider_location(dst)}

    @cinder_utils.trace
    def extend_volume(self, volume, new_size):
        """Extends an existing volume.

       :param volume: dictionary volume reference
       :param new_size: int size in GB to extend
       """
        fs = self._get_service(volume)
        self.backend.extend_lu(fs, new_size, volume.name)

    @cinder_utils.trace
    def delete_volume(self, volume):
        """Deletes the volume on HNAS.

        :param volume: dictionary volume reference
        """
        fs = self._get_service(volume)
        self.backend.delete_lu(fs, volume.name)

    @cinder_utils.synchronized('volume_mapping')
    @cinder_utils.trace
    def initialize_connection(self, volume, connector):
        """Maps the created volume to connector['initiator'].

        :param volume: dictionary volume reference
        :param connector: dictionary connector reference
        :returns: The connection information
        :raises: ISCSITargetAttachFailed
        """
        service_info = self._get_service_target(volume)
        (ip, ipp, evs, port, _fs, tgtalias, secret) = service_info

        try:
            conn = self.backend.add_iscsi_conn(volume.name, _fs, port,
                                               tgtalias,
                                               connector['initiator'])

        except processutils.ProcessExecutionError:
            msg = (_("Error attaching volume %(vol)s. "
                     "Target limit might be reached!") % {'vol': volume.id})
            LOG.error(msg)
            raise exception.ISCSITargetAttachFailed(volume_id=volume.id)

        hnas_portal = ip + ':' + ipp
        lu_id = six.text_type(conn['lu_id'])
        fulliqn = conn['iqn']
        tgt = (hnas_portal + ',' + tgtalias + ',' +
               volume.provider_location + ',' + evs + ',' +
               port + ',' + lu_id)

        LOG.info(_LI("initiate: connection %(tgt)s"), {'tgt': tgt})

        properties = {}
        properties['provider_location'] = tgt
        properties['target_discovered'] = False
        properties['target_portal'] = hnas_portal
        properties['target_iqn'] = fulliqn
        properties['target_lu'] = int(lu_id)
        properties['volume_id'] = volume.id
        properties['auth_username'] = connector['initiator']

        if self.config['chap_enabled']:
            properties['auth_method'] = 'CHAP'
            properties['auth_password'] = secret

        conn_info = {'driver_volume_type': 'iscsi', 'data': properties}

        return conn_info

    @cinder_utils.synchronized('volume_mapping')
    @cinder_utils.trace
    def terminate_connection(self, volume, connector, **kwargs):
        """Terminate a connection to a volume.

        :param volume: dictionary volume reference
        :param connector: dictionary connector reference
        """
        service_info = self._get_service_target(volume)
        (ip, ipp, evs, port, fs, tgtalias, secret) = service_info
        lu_info = self.backend.check_lu(volume.name, fs)

        self.backend.del_iscsi_conn(evs, tgtalias, lu_info['id'])

    @cinder_utils.trace
    def create_volume_from_snapshot(self, volume, snapshot):
        """Creates a volume from a snapshot.

        :param volume: dictionary volume reference
        :param snapshot: dictionary snapshot reference
        :returns: the provider location of the snapshot
        """
        fs = self._get_service(volume)

        self.backend.create_cloned_lu(snapshot.name, fs, volume.name)

        return {'provider_location': self._get_provider_location(snapshot)}

    @cinder_utils.trace
    def create_snapshot(self, snapshot):
        """Creates a snapshot.

        :param snapshot: dictionary snapshot reference
        :returns: the provider location of the snapshot
        """
        fs = self._get_service(snapshot.volume)

        self.backend.create_cloned_lu(snapshot.volume_name, fs, snapshot.name)

        return {'provider_location': self._get_provider_location(snapshot)}

    @cinder_utils.trace
    def delete_snapshot(self, snapshot):
        """Deletes a snapshot.

       :param snapshot: dictionary snapshot reference
       """
        fs = self._get_service(snapshot.volume)
        self.backend.delete_lu(fs, snapshot.name)

    def get_volume_stats(self, refresh=False):
        """Gets the volume driver stats.

        :param refresh: if refresh is True, the driver_stats is updated
        :returns: the driver stats
        """
        if refresh:
            self.driver_stats = self._get_stats()

        return self.driver_stats

    @cinder_utils.trace
    def manage_existing_get_size(self, volume, existing_vol_ref):
        """Gets the size to manage_existing.

        Returns the size of volume to be managed by manage_existing.

        :param volume: cinder volume to manage
        :param existing_vol_ref: existing volume to take under management
        :returns: the size of the volume to be managed or raises error
        :raises: ManageExistingInvalidReference
        """
        # Check if the reference is valid.
        if 'source-name' not in existing_vol_ref:
            reason = _('Reference must contain source-name element.')
            raise exception.ManageExistingInvalidReference(
                existing_ref=existing_vol_ref, reason=reason)

        fs_label, vol_name = (
            self._get_info_from_vol_ref(existing_vol_ref['source-name']))

        LOG.debug("File System: %(fs_label)s "
                  "Volume name: %(vol_name)s.",
                  {'fs_label': fs_label, 'vol_name': vol_name})

        if utils.check_already_managed_volume(vol_name):
            raise exception.ManageExistingAlreadyManaged(volume_ref=vol_name)

        lu_info = self.backend.get_existing_lu_info(vol_name, fs_label)

        if lu_info != {}:
            return lu_info['size']
        else:
            raise exception.ManageExistingInvalidReference(
                existing_ref=existing_vol_ref,
                reason=_('Volume not found on configured storage backend. '
                         'If your volume name contains "/", please rename it '
                         'and try to manage again.'))

    @cinder_utils.trace
    def manage_existing(self, volume, existing_vol_ref):
        """Manages an existing volume.

        The specified Cinder volume is to be taken into Cinder management.
        The driver will verify its existence and then rename it to the
        new Cinder volume name. It is expected that the existing volume
        reference is a File System and some volume_name;
        e.g., openstack/vol_to_manage

        :param volume:           cinder volume to manage
        :param existing_vol_ref: driver specific information used to identify a
                                 volume
        :returns: the provider location of the volume managed
        """
        LOG.info(_LI("Asked to manage ISCSI volume %(vol)s, with vol "
                     "ref %(ref)s."), {'vol': volume.id,
                                       'ref': existing_vol_ref['source-name']})

        fs_label, vol_name = (
            self._get_info_from_vol_ref(existing_vol_ref['source-name']))

        if volume.volume_type is not None:
            self._check_pool_and_fs(volume, fs_label)

        self.backend.rename_existing_lu(fs_label, vol_name, volume.name)

        LOG.info(_LI("Set newly managed Cinder volume name to %(name)s."),
                 {'name': volume.name})

        return {'provider_location': self._get_provider_location(volume)}

    @cinder_utils.trace
    def unmanage(self, volume):
        """Unmanages a volume from cinder.

        Removes the specified volume from Cinder management.
        Does not delete the underlying backend storage object. A log entry
        will be made to notify the admin that the volume is no longer being
        managed.

        :param volume: cinder volume to unmanage
        """
        fslabel = self._get_service(volume)
        new_name = 'unmanage-' + volume.name
        vol_path = fslabel + '/' + volume.name

        self.backend.rename_existing_lu(fslabel, volume.name, new_name)

        LOG.info(_LI("The volume with path %(old)s is no longer being managed "
                     "by Cinder. However, it was not deleted and can be found "
                     "with the new name %(cr)s on backend."),
                 {'old': vol_path, 'cr': new_name})

    def _get_provider_location(self, volume):
        """Gets the provider location of a given volume

        :param volume: dictionary volume reference
        :returns: the provider_location related to the volume
        """
        return self.backend.get_version()['mac'] + '.' + volume.name


#-*- coding: utf-8 -*-
#Created by Hans on 16-9-5

import os
import signal
from tornado.options import options,define,parse_config_file,parse_command_line
from sched.agent import Listener

define('hosts',default='127.0.0.1:2181',type=str,help='zookeeper hosts')
define('root',default='/scheduler',type=str,help='zookeeper root node')

define('agent_path',default='/data/schedule-agent',type=str,help='agent root workspace')
define('log_server',default='127.0.0.1:9090',type=str,help='log server address')

def SigHandle(signum, frame):
    raise KeyboardInterrupt()

signal.signal(signal.SIGTERM, SigHandle)
signal.signal(signal.SIGHUP, SigHandle)
signal.signal(signal.SIGINT, SigHandle)

if __name__ == '__main__':
    if os.path.exists('/etc/scheduler/agent.conf'):
        parse_config_file('/etc/scheduler/agent.conf')
    if os.path.exists('./agent.conf'):
        parse_config_file('./agent.conf')

    parse_command_line()
    agent = Listener(options.hosts,options.root)

    try:
        agent.start()
        agent.join()
    except (KeyboardInterrupt,SystemExit):
        print('******************')
        agent.shutdown()


import argparse
import os
import time
import logging
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.backends.cudnn as cudnn
import torch.optim
import torch.utils.data
import models
import torch.distributed as dist
from data import DataRegime
from utils.log import setup_logging, ResultsLog, save_checkpoint
from utils.optim import OptimRegime
from utils.cross_entropy import CrossEntropyLoss
from utils.misc import torch_dtypes
from utils.param_filter import FilterModules, is_bn
from datetime import datetime
from ast import literal_eval
from trainer import Trainer

model_names = sorted(name for name in models.__dict__
                     if name.islower() and not name.startswith("__")
                     and callable(models.__dict__[name]))

def main(
        results_dir='./results',
        save='',
        datasets_dir='~/Datasets',
        dataset='imagenet',
        model='alexnet',
        input_size=None,
        model_config='',
        dtype='float',
        device='cuda',
        device_ids=(0),
        world_size=-1,
        local_rank=-1,
        dist_init='env://',
        dist_backend='nccl',
        workers=8,
        epochs=90,
        start_epoch=-1,
        batch_size=256,
        eval_batch_size=-1,
        optimizer='SGD',
        label_smoothing=0,
        mixup=None,
        duplicates=1,
        chunk_batch=1,
        cutout=False,
        autoaugment=False,
        grad_clip=-1,
        loss_scale=1,
        lr=0.1,
        momentum=0.9,
        weight_decay=1e-4,
        print_freq=10,
        adapt_grad_norm=None,
        resume='',
        evaluate='',
        seed=123,
        subsplit_str='',
        augval=False,
    ):

    best_prec1 = 0
    dtype_str = dtype
    dtype = torch_dtypes.get(dtype_str)
    torch.manual_seed(seed)
    time_stamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
    if evaluate:
        results_dir = '/tmp'
    if save is '':
        save = time_stamp
    save_path = os.path.join(results_dir, save)

    distributed = local_rank >= 0 or world_size > 1

    if distributed:
        dist.init_process_group(backend=dist_backend, init_method=dist_init,
                                world_size=world_size, rank=local_rank)
        local_rank = dist.get_rank()
        world_size = dist.get_world_size()
        if dist_backend == 'mpi':
            # If using MPI, select all visible devices
            device_ids = list(range(torch.cuda.device_count()))
        else:
            device_ids = [local_rank]

    if not os.path.exists(save_path) and not (distributed and local_rank > 0):
        os.makedirs(save_path)

    setup_logging(os.path.join(save_path, 'log.txt'),
                  resume=resume is not '',
                  dummy=distributed and local_rank > 0)

    results_path = os.path.join(save_path, 'results')
    results = ResultsLog(
        results_path, title='Training Results - %s' % save)

    logging.info("saving to %s", save_path)
    # logging.debug("run arguments: %s", args)
    logging.info("creating model %s", model)

    if 'cuda' in device and torch.cuda.is_available():
        torch.cuda.manual_seed_all(seed)
        torch.cuda.set_device(device_ids[0])
        cudnn.benchmark = True
        cudnn.deterministic = True
    else:
        device_ids = None

    # create model
    model = models.__dict__[model]
    model_config_arg = model_config
    model_config = {'dataset': dataset}

    if model_config_arg == '':
        model_config_d = {}
    elif isinstance(model_config_arg, str):
        model_config_d = literal_eval(model_config_arg)
    model_config = dict(model_config, **model_config_d)

    model = model(**model_config)
    logging.info("created model with configuration: %s", model_config)
    num_parameters = sum([l.nelement() for l in model.parameters()])
    logging.info("number of parameters: %d", num_parameters)

    # optionally resume from a checkpoint
    if evaluate:
        if not os.path.isfile(evaluate):
            parser.error('invalid checkpoint: {}'.format(evaluate))
        checkpoint = torch.load(evaluate)
        model.load_state_dict(checkpoint['state_dict'])
        logging.info("loaded checkpoint '%s' (epoch %s)",
                     evaluate, checkpoint['epoch'])
    elif resume:
        checkpoint_file = resume
        if os.path.isdir(checkpoint_file):
            results.load(os.path.join(checkpoint_file, 'results.csv'))
            checkpoint_file = os.path.join(
                checkpoint_file, 'model_best.pth.tar')
        if os.path.isfile(checkpoint_file):
            logging.info("loading checkpoint '%s'", resume)
            checkpoint = torch.load(checkpoint_file)
            if start_epoch < 0:  # not explicitly set
                start_epoch = checkpoint['epoch'] - 1
            best_prec1 = checkpoint['best_prec1']
            model.load_state_dict(checkpoint['state_dict'])
            logging.info("loaded checkpoint '%s' (epoch %s)",
                         checkpoint_file, checkpoint['epoch'])
        else:
            logging.error("no checkpoint found at '%s'", resume)

    # define loss function (criterion) and optimizer
    loss_params = {}
    if label_smoothing > 0:
        loss_params['smooth_eps'] = label_smoothing
    criterion = getattr(model, 'criterion', CrossEntropyLoss)(**loss_params)
    criterion.to(device, dtype)
    model.to(device, dtype)

    # Batch-norm should always be done in float
    if 'half' in dtype_str:
        FilterModules(model, module=is_bn).to(dtype=torch.float)

    # optimizer configuration
    optim_regime = getattr(model, 'regime', [{'epoch': 0,
                                              'optimizer': optimizer,
                                              'lr': lr,
                                              'momentum': momentum,
                                              'weight_decay': weight_decay}])

    optimizer = optim_regime if isinstance(optim_regime, OptimRegime) \
        else OptimRegime(model, optim_regime, use_float_copy='half' in dtype_str)

    trainer = Trainer(model, criterion, optimizer,
                      device_ids=device_ids, device=device, dtype=dtype,
                      distributed=distributed, local_rank=local_rank, mixup=mixup, loss_scale=loss_scale,
                      grad_clip=grad_clip, print_freq=print_freq, adapt_grad_norm=adapt_grad_norm)

    if not subsplit_str:
        train_split_str = 'train'
        val_split_str = 'val'
    else:
        train_split_str = 'train_' + subsplit_str
        ploc = subsplit_str.index('l')
        val_split_str = 'train_' + subsplit_str[:ploc] + 'r' + subsplit_str[(ploc+1):]

    # Evaluation Data loading code
    eval_batch_size = eval_batch_size if eval_batch_size > 0 else batch_size
    val_data = DataRegime(getattr(model, 'data_eval_regime', None),
                          defaults={'datasets_path': datasets_dir, 'name': dataset, 'split': val_split_str, 'augment': False,
                                    'input_size': input_size, 'batch_size': eval_batch_size, 'shuffle': False,
                                    'num_workers': workers, 'pin_memory': True, 'drop_last': False})

    if evaluate:
        results = trainer.validate(val_data.get_loader())
        logging.info(results)
        return

    # Evaluation Data loading code
    if augval:
        augval_data = DataRegime(
            getattr(model, 'data_eval_regime', None),
            defaults={
                'datasets_path': datasets_dir, 'name': dataset, 'split': val_split_str, 'augment': True,
                'input_size': input_size, 'batch_size': eval_batch_size, 'shuffle': False,
                'num_workers': workers, 'pin_memory': True, 'drop_last': False,
                'autoaugment': autoaugment,
                'cutout': {'holes': 1, 'length': 16} if cutout else None,
            },
        )

    # Training Data loading code
    train_data = DataRegime(getattr(model, 'data_regime', None),
                            defaults={'datasets_path': datasets_dir, 'name': dataset, 'split': train_split_str, 'augment': True,
                                      'input_size': input_size,  'batch_size': batch_size, 'shuffle': True,
                                      'num_workers': workers, 'pin_memory': True, 'drop_last': True,
                                      'distributed': distributed, 'duplicates': duplicates, 'autoaugment': autoaugment,
                                      'cutout': {'holes': 1, 'length': 16} if cutout else None})

    logging.info('optimization regime: %s', optim_regime)
    start_epoch = max(start_epoch, 0)
    trainer.training_steps = start_epoch * len(train_data)
    for epoch in range(start_epoch, epochs):
        trainer.epoch = epoch
        train_data.set_epoch(epoch)
        val_data.set_epoch(epoch)
        if augval:
            augval_data.set_epoch(epoch)
        logging.info('\nStarting Epoch: {0}\n'.format(epoch + 1))

        # train for one epoch
        train_results = trainer.train(train_data.get_loader(),
                                      duplicates=train_data.get('duplicates'),
                                      chunk_batch=chunk_batch)

        if distributed and local_rank > 0:
            continue

        # evaluate on validation set
        val_results = trainer.validate(val_data.get_loader())
        if augval:
            augval_results = trainer.validate(augval_data.get_loader())

        # remember best prec@1 and save checkpoint
        is_best = val_results['prec1'] > best_prec1
        best_prec1 = max(val_results['prec1'], best_prec1)
        save_checkpoint({
            'epoch': epoch + 1,
            'model': model,
            'config': model_config,
            'state_dict': model.state_dict(),
            'best_prec1': best_prec1
        }, is_best, path=save_path)

        logging_format = (
            '\nResults - Epoch: {0:3d}/{1:3d}\n'
            '  Training Loss   {train[loss]:.4f}   '
            'Training Prec@1   {train[prec1]:.3f}   '
            'Training Prec@5   {train[prec5]:.3f}\n'
        )
        if augval:
            logging_format += (
                '  AugVal Loss     {augval_results[loss]:.4f}   '
                'AugVal Prec@1     {augval_results[prec1]:.3f}   '
                'AugVal Prec@5     {augval_results[prec5]:.3f}\n'
            )
        logging_format += (
            '  Validation Loss {val[loss]:.4f}   '
            'Validation Prec@1 {val[prec1]:.3f}   '
            'Validation Prec@5 {val[prec5]:.3f}\n'
        )
        logging.info(
            logging_format
            .format(
                epoch + 1, epochs,
                train=train_results, val=val_results,
                augval_results=augval_results if augval else None,
            )
        )

        values = dict(epoch=epoch + 1, steps=trainer.training_steps)
        values.update({'lr': trainer.optimizer.optimizer.param_groups[0]['lr']})
        plot_partitions = ['training', 'validation']
        values.update({'training ' + k: v for k, v in train_results.items()})
        values.update({'validation ' + k: v for k, v in val_results.items()})
        if augval:
            plot_partitions.append('aug val')
            values.update({'aug val ' + k: v for k, v in augval_results.items()})
        results.add(**values)

        results.plot(x='epoch', y=[k + ' loss' for k in plot_partitions],
                     legend=plot_partitions,
                     title='Loss', ylabel='loss')
        results.plot(x='epoch', y=[k + ' error1' for k in plot_partitions],
                     legend=plot_partitions,
                     title='Error@1', ylabel='error %')
        results.plot(x='epoch', y=[k + ' error5' for k in plot_partitions],
                     legend=plot_partitions,
                     title='Error@5', ylabel='error %')
        results.plot(x='epoch', y=['lr'],
                     legend=['lr'],
                     title='Learning Rate', ylabel='Learning rate (end of epoch)')
        if 'grad' in train_results.keys():
            results.plot(x='epoch', y=['training grad'],
                         legend=['gradient L2 norm'],
                         title='Gradient Norm', ylabel='value')
        results.save()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='PyTorch ConvNet Training')

    parser.add_argument('--results-dir', metavar='RESULTS_DIR', default='./results',
                        help='results dir')
    parser.add_argument('--save', metavar='SAVE', default='',
                        help='saved folder')
    parser.add_argument('--datasets-dir', metavar='DATASETS_DIR', default='~/Datasets',
                        help='datasets dir')
    parser.add_argument('--dataset', metavar='DATASET', default='imagenet',
                        help='dataset name or folder')
    parser.add_argument('--model', '-a', metavar='MODEL', default='alexnet',
                        choices=model_names,
                        help='model architecture: ' +
                        ' | '.join(model_names) +
                        ' (default: alexnet)')
    parser.add_argument('--input-size', type=int, default=None,
                        help='image input size')
    parser.add_argument('--model-config', default='',
                        help='additional architecture configuration')
    parser.add_argument('--dtype', default='float',
                        help='type of tensor: ' +
                        ' | '.join(torch_dtypes.keys()) +
                        ' (default: float)')
    parser.add_argument('--device', default='cuda',
                        help='device assignment ("cpu" or "cuda")')
    parser.add_argument('--device-ids', default=[0], type=int, nargs='+',
                        help='device ids assignment (e.g 0 1 2 3')
    parser.add_argument('--world-size', default=-1, type=int,
                        help='number of distributed processes')
    parser.add_argument('--local_rank', default=-1, type=int,
                        help='rank of distributed processes')
    parser.add_argument('--dist-init', default='env://', type=str,
                        help='init used to set up distributed training')
    parser.add_argument('--dist-backend', default='nccl', type=str,
                        help='distributed backend')
    parser.add_argument('-j', '--workers', default=8, type=int, metavar='N',
                        help='number of data loading workers (default: 8)')
    parser.add_argument('--epochs', default=90, type=int, metavar='N',
                        help='number of total epochs to run')
    parser.add_argument('--start-epoch', default=-1, type=int, metavar='N',
                        help='manual epoch number (useful on restarts). -1 for unset (will start at 0)')
    parser.add_argument('-b', '--batch-size', default=256, type=int,
                        metavar='N', help='mini-batch size (default: 256)')
    parser.add_argument('--eval-batch-size', default=-1, type=int,
                        help='mini-batch size (default: same as training)')
    parser.add_argument('--optimizer', default='SGD', type=str, metavar='OPT',
                        help='optimizer function used')
    parser.add_argument('--label-smoothing', default=0, type=float,
                        help='label smoothing coefficient - default 0')
    parser.add_argument('--mixup', default=None, type=float,
                        help='mixup alpha coefficient - default None')
    parser.add_argument('--duplicates', default=1, type=int,
                        help='number of augmentations over singel example')
    parser.add_argument('--chunk-batch', default=1, type=int,
                        help='chunk batch size for multiple passes (training)')
    parser.add_argument('--cutout', action='store_true', default=False,
                        help='cutout augmentations')
    parser.add_argument('--autoaugment', action='store_true', default=False,
                        help='use autoaugment policies')
    parser.add_argument('--grad-clip', default=-1, type=float,
                        help='maximum grad norm value, -1 for none')
    parser.add_argument('--loss-scale', default=1, type=float,
                        help='loss scale for mixed precision training.')
    parser.add_argument('--lr', '--learning-rate', default=0.1, type=float,
                        metavar='LR', help='initial learning rate')
    parser.add_argument('--momentum', default=0.9, type=float, metavar='M',
                        help='momentum')
    parser.add_argument('--weight-decay', '--wd', default=1e-4, type=float,
                        metavar='W', help='weight decay (default: 1e-4)')
    parser.add_argument('--print-freq', '-p', default=10, type=int,
                        metavar='N', help='print frequency (default: 10)')
    parser.add_argument('--adapt-grad-norm', default=None, type=int,
                        help='adapt gradient scale frequency (default: None)')
    parser.add_argument('--resume', default='', type=str, metavar='PATH',
                        help='path to latest checkpoint (default: none)')
    parser.add_argument('-e', '--evaluate', type=str, metavar='FILE',
                        help='evaluate model FILE on validation set')
    parser.add_argument('--seed', default=123, type=int,
                        help='random seed (default: 123)')
    parser.add_argument('--subsplit-str', default='', type=str,
                        help=
                            'subsplitting string (default: none).'
                            'If given, train and val partitions are subsets of the training set.')
    parser.add_argument('--augval', action='store_true',
                        help='also show validation with augmentations')

    main(**vars(parser.parse_args()))


# -*- coding: utf-8 -*-

def string_hash(v, hashbits=128):
    if v == "":
        return 0
    else:
        x = ord(v[0])<<7
        m = 1000003
        mask = 2**hashbits-1
        for c in v:
            x = ((x*m)^ord(c)) & mask
        x ^= len(v)
        if x == -1:
            x = -2
        return x

def simhash(tokens, hashbits=128):
    v = [0] * hashbits

    for t in [string_hash(x, hashbits) for x in tokens]:
        bitmask = 0
        for i in range(hashbits):
            bitmask = 1 << i
            if t & bitmask:
                v[i] += 1
            else:
                v[i] += -1

    return ''.join(['1' if v[i] >= 0 else '0' for i in range(hashbits)])


#!/usr/bin/env python26

#    by Charlie Armijo, Ken Johns, Bill Hart, Sarah Jones, James Wymer, Kade Gigliotti
#    Experimental Elementary Particle Physics Laboratory
#    Physics Department
#    University of Arizona
#    armijo at physics.arizona.edu
#    johns at physics.arizona.edu
#
#    This is version 7 of the MMFE8 GUI

import pygtk
pygtk.require('2.0')
import gtk
from array import *
#### On PCROD0 use from Numpy import *
import numpy as np
#from Numeric import *
from struct import *
import gobject
from subprocess import call
from time import sleep
import sys
import os
import string
import random
import binstr
import socket
import time
import math

############################################################################
############################################################################
##########################                     #############################
##########################     CHANNEL CLASS   #############################
##########################                     #############################
############################################################################
############################################################################

class channel:

    def get_chan_val(self):
        return self.chan_val

    #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    #
    #                CHANNEL FUNCTIONS
    #
    #  Here we take the check box and combo box data for
    #  each channel and add it to the appropriate channel
    #  array
    #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    ##### input charge polarity #####
    def SP_callback(self, widget, data=None):
        SP = self.chan_val[0]
        if widget.get_active():
            ### toggle button is down ###
            if SP == 0:
                self.chan_val[0] = 1
                widget.set_label("p")
        else:
            ### toggle button is up ###
            if SP > 0:
                self.chan_val[0] = 0
                widget.set_label("n")

    ##### large sensor capacitance mode #####
    def SC_callback(self, widget, data=None):
        SC = self.chan_val[1]
        if widget.get_active():
        ### button is checked ###
            if SC == 0:
                self.chan_val[1] = 1
        else:
        ### button is not checked ###
            if SC > 0:
                self.chan_val[1] = 0

    ##### leakage current disable #####
    def SL_callback(self, widget, data=None):
        SL = self.chan_val[2]
        if widget.get_active():
        ### button is checked ###
            if SL == 0:
                self.chan_val[2] = 1
        else:
        ### button is not checked ###
            if SL > 0:
                self.chan_val[2] = 0

    ##### test capacitor enable #####
    def ST_callback(self, widget, data=None):
        ST = self.chan_val[3]
        if widget.get_active():
        ### button is checked ###
            if ST == 0:
                #self.msg[data-1] = self.msg[data-1] + np.uint32(0x0008)
                self.chan_val[3] = 1
        else:
        ### button is not checked ###
            if ST > 0:
                #self.msg[data-1] = self.msg[data-1] - np.uint32(0x0008)
                self.chan_val[3] = 0

    ##### mask enable #####
    def SM_callback(self, widget, data=None):
        SM = self.chan_val[4]
        if widget.get_active():
        ### button is checked ###
            if SM == 0:
                #self.msg[data-1] = self.msg[data-1] + np.uint32(0x0010)
                self.chan_val[4] = 1
        else:
        ### button is not checked ###
            if SM > 0:
                #self.msg[data-1] = self.msg[data-1] - np.uint32(0x0010)
                self.chan_val[4] = 0

    ##### threshold DAC #####
    def get_SD_value(self, widget, data=None):
        active = widget.get_active()
        if active < 0:
            return None
        else:
            SD_value = active
            #self.msg[data-1] = np.uint32(0xFE1F) & self.msg[data-1] #??????????

            ### convert value to list of binary digits ###
            SD_value = '{0:04b}'.format(SD_value)
            SD_list = list(SD_value)
            SD_list = map(int, SD_value)

            ### add new value to channel_settings ###
            #self.msg[data-1] = np.uint32(SD_value) ^ self.msg[data-1] #??????????
            for i in range(3,-1,-1):
                self.chan_val[i+5] = SD_list[i]

    ##### channel monitor mode #####
    def SMX_callback(self, widget, data=None):
        SMX = self.chan_val[9]
        if widget.get_active():
        ### button is checked ###
            if SMX == 0:
                self.chan_val[9] = 1
        else:
        ### button is not checked ###
            if SMX > 0:
                self.chan_val[9] = 0

    ##### 10-bit ADC #####
    def get_SZ10b_value(self, widget, data=None):
        active = widget.get_active()
        if active < 0:
            return None
        else:
            SZ10b = active

            ### convert value to list of binary digits ###
            SZ10b = '{0:05b}'.format(SZ10b)
            SZ10b_list = list(SZ10b)
            SZ10b_list = map(int, SZ10b)

            ### add new value to channel_settings ###
            for i in range(4,-1,-1):
                self.chan_val[i+10] = SZ10b_list[i]

    ##### 8-bit ADC #####
    def get_SZ8b_value(self, widget, data=None):
        active = widget.get_active()
        if active < 0:
            return None
        else:
            SZ8b = active

            ### convert value to list of binary digits ###
            SZ8b = '{0:04b}'.format(SZ8b)
            SZ8b_list = list(SZ8b)
            SZ8b_list = map(int, SZ8b)

            ### add new value to channel_settings ###
            for i in range(3,-1,-1):
                self.chan_val[i+15] = SZ8b_list[i]

    ##### 6-bit ADC #####
    def get_SZ6b_value(self, widget, data=None):
        active = widget.get_active()
        if active < 0:
            return None
        else:
            SZ6b = active

            ### convert value to list of binary digits ###
            SZ6b = '{0:03b}'.format(SZ6b)
            SZ6b_list = list(SZ6b)
            SZ6b_list = map(int, SZ6b)

            ### add new value to channel_settings ###
            for i in range(2,-1,-1):
                self.chan_val[i+19] = SZ6b_list[i]

    #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    #             __init__  and  CHANNEL WIDGETS
    #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    def __init__(self, ch_num):
        self.chan_val = np.zeros((24), dtype=int)
        self.channel_box = gtk.HBox(homogeneous=False,spacing=0)
        if ch_num < 9:
            self.glabel = gtk.Label( "  " + str(ch_num + 1) )
        else:
            self.glabel = gtk.Label( str(ch_num + 1) )
        self.button_SP = gtk.ToggleButton( label="n" )
        self.button_SC = gtk.CheckButton()
        self.button_SL = gtk.CheckButton()
        self.button_ST = gtk.CheckButton()
        self.button_SM = gtk.CheckButton()
        self.combo_SD = gtk.combo_box_new_text()
        self.button_SMX = gtk.CheckButton()
        self.combo_SZ10b = gtk.combo_box_new_text()
        self.combo_SZ8b = gtk.combo_box_new_text()
        self.combo_SZ6b = gtk.combo_box_new_text()
        for i in range(16):
            self.combo_SD.append_text(str(i) + " mv")
        self.combo_SD.set_active(0)
        for i in range(32):
            self.combo_SZ10b.append_text(str(i) + " ns")
        self.combo_SZ10b.set_active(0)
        for i in range(16):
            self.combo_SZ8b.append_text(str(i) + " ns")
        self.combo_SZ8b.set_active(0)
        for i in range(8):
            self.combo_SZ6b.append_text(str(i) + " ns")
        self.combo_SZ6b.set_active(0)

        self.button_SP.connect("toggled",self.SP_callback,ch_num)
        self.button_SC.connect("toggled",self.SC_callback,ch_num)
        self.button_SL.connect("toggled",self.SL_callback,ch_num)
        self.button_ST.connect("toggled",self.ST_callback,ch_num)
        self.button_SM.connect("toggled",self.SM_callback,ch_num)
        if ch_num < 64:
            self.button_SM.set_active(True)
        self.combo_SD.connect("changed",self.get_SD_value,ch_num)
        self.button_SMX.connect("toggled",self.SMX_callback,ch_num)
        self.combo_SZ10b.connect("changed",self.get_SZ10b_value,ch_num)
        self.combo_SZ8b.connect("changed",self.get_SZ8b_value,ch_num)
        self.combo_SZ6b.connect("changed",self.get_SZ6b_value,ch_num)

        self.channel_box.pack_start(self.glabel,expand=False)
        self.channel_box.pack_start(self.button_SP,expand=False)
        self.channel_box.pack_start(self.button_SC,expand=False)
        self.channel_box.pack_start(self.button_SL,expand=False)
        self.channel_box.pack_start(self.button_ST,expand=False)
        self.channel_box.pack_start(self.button_SM,expand=False)
        self.channel_box.pack_start(self.combo_SD,expand=False)
        self.channel_box.pack_start(self.button_SMX,expand=False)
        self.channel_box.pack_start(self.combo_SZ10b,expand=False)
        self.channel_box.pack_start(self.combo_SZ8b,expand=False)
        self.channel_box.pack_start(self.combo_SZ6b,expand=False)


import torch
from torch import nn

from qnn.layers import RealLock

class QEmbedding(nn.Embedding):

    def __init__(self,
                 num_embeddings,
                 embedding_dim,
                 padding_idx=None,
                 max_norm=None,
                 norm_type=2.0,
                 scale_grad_by_freq=False,
                 sparse=False,
                 _weight=None):
        super(QEmbedding, self).__init__(num_embeddings, 4 * embedding_dim, padding_idx, max_norm, norm_type,
                                         scale_grad_by_freq, sparse, _weight)
        self.true_embedding_dim = embedding_dim

        self.real_lock = None

    def add_real_lock(self):
        self.real_lock = RealLock()

    def forward(self, input):
        embedding = super(QEmbedding, self).forward(input).view(*input.shape, self.true_embedding_dim, 4)
        if self.real_lock:
            embedding = self.real_lock(embedding)
        return embedding

    def dimension(self):
        return self.true_embedding_dim


# https://atcoder.jp/contests/abc157/tasks/abc157_c

n, m = map(int, input().split())
scs = [tuple(map(int, input().split())) for _ in range(m)]

mi = 0
if 2 <= n:
    mi += 10 ** (n - 1)
ma = 10 ** n
ans = -1

for i in range(mi, ma):
    st = str(i)
    tmp = True
    for j in range(m):
        if (int(st[scs[j][0] - 1]) != scs[j][1]):
            tmp = False
    if tmp:
        ans = i
        break
print(ans)


import sys
sys.path.append("..")

from typing import List, Optional
from utils import TreeNode

class Solution:
    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []

        queue = [(0, root)]
        nodes = {}

        while queue:
            level, node = queue.pop()
            nodes[level] = node.val

            if node.left:
                queue.insert(0, (level + 1, node.left))

            if node.right:
                queue.insert(0, (level + 1, node.right))

        return list(nodes.values())

if __name__ == '__main__':
    s = Solution()
    root = TreeNode.from_list([1, 2, 3, None, 5, None, 4])
    print(s.rightSideView(root))


from __future__ import print_function
import os
import capnp

capnp.remove_import_hook()
kcc_capnp = capnp.load('ti-165410142.capnp')

def writeKcc(file):
    kcc = kcc_capnp.Kcc.new_message()
    people = kcc.init('people', 1)

    bilal = people[0]
    bilal.nama = 'Muhammad Bilal Shah'
    bilal.nim = '165410142'
    bilalKomplain = bilal.init('komplain', 1)
    bilalKomplain[0].mataKuliah = "Konsep Cloud Computing"
    bilalKomplain[0].nilaiPantas = 'B'
    bilalKomplain[0].alasan = 'Saya rajin berangkat, presensi saya baik, d atas 80%, selalu mengikuti kuliah dari awal sampai akhir, mendengarkan dengan baik kuliah bapak, dan beberapa teman yang sama seperti saya juga mendapatkan nilai B walau tidak maju presentasi ke depan.'

    kcc.write(file)

def printKcc(file):
    kcc = kcc_capnp.Kcc.read(file)

    for mahasiswa in kcc.people:
        print('Nama = ',mahasiswa.nama)
        print('Nim = ',mahasiswa.nim)
        for komplain in mahasiswa.komplain:
	        print('Mata Kuliah = ',komplain.mataKuliah)
	        print('Nilai yang pantas saya dapatkan = ',komplain.nilaiPantas)
	        print('Alasan = ',komplain.alasan)

if __name__ == '__main__':
    f = open('hasil', 'w')
    writeKcc(f)

    f = open('hasil', 'r')
    printKcc(f)