import pygame, sys
from netwindow import enterwindow

pygame.init()

class Kletka:
    def __init__(self, xpos, ypos, vid='kletka'):
        self.x = xpos
        self.y = ypos
        self.vid = vid

    def setpos(self, pos):
        self.x = pos[0]
        self.y = pos[1]

    def getpos(self):
        return (self.x, self.y)

    def render(self):
        pass

class Hahka(Kletka):
    def __init__(self, xpos, ypos, vid, bitmap, side):
        super().__init__(xpos, ypos, vid)
        self.bitmap = bitmap
        self.bitmap.set_colorkey((255, 255, 255))
        self.side = side
        self.damka = False

    def render(self):
        mainscreen.blit(self.bitmap, (self.x, self.y))

    def updatebitmap(self,newbitmap):
        self.bitmap = newbitmap
        self.bitmap.set_colorkey((255, 255, 255))

class Menu:
    def __init__(self, punkts = (300,300,u'start',(123,235,34),(34,25,66),1)):
        self.i_menu=pygame.image.load('pic\menu.png')
        self.i_rmenu=pygame.image.load('pic\menurightscreen.png')
        self.punkts=punkts
    def render(self, poverhnost, font, num_punkt):
        for e in self.punkts:
            if num_punkt == e[5]:
                poverhnost.blit(font.render(e[2], 1, e[4]), (e[0],e[1]))
            else:
                poverhnost.blit(font.render(e[2], 1, e[3]), (e[0],e[1]))

    def startmenu(self):
        done = True
        font_menu = pygame.font.Font(None, 50)
        punkt = 0
        while done:
            #mainscreen.fill((0,100,200))

            mp = pygame.mouse.get_pos()

            for i in self.punkts:
                if mp[0] > i[0] and mp[0] < (i[0] + 155) and mp[1] > i[1] and mp[1] < (i[1] + 50):
                    punkt = i[5]
            self.render(mainscreen, font_menu, punkt)
            for e in pygame.event.get():
                if e.type == pygame.QUIT:
                    sys.exit()
                if e.type == pygame.KEYDOWN:
                    if e.key == pygame.K_ESCAPE:
                        sys.exit()
                    if e.key == pygame.K_UP:
                        if punkt>0:
                            punkt -= 1
                    if e.key == pygame.K_DOWN:
                        if punkt < (len(self.punkts)-1):
                            punkt += 1
                if e.type == pygame.MOUSEBUTTONDOWN and e.button == 1:
                    if punkt == 0:
                        done= False
                    elif punkt == 1:
                        enterwindow()
                    elif punkt == 2:
                        sys.exit()

            window.blit(mainscreen, (0,0))
            window.blit(rightscreen,(720,0))
            mainscreen.blit(self.i_menu,(0,0))
            rightscreen.blit(self.i_rmenu,(0,0))
            pygame.display.flip()

def hod_with_enemy(polemass, mass, ipos, jpos, i, j):
    """
    еализует ход через врага
    :param polemass: массив данных доски
    :param mass: массив с потенциальными врагами полученный вызовом функции check_enemy
    :param ipos: 1 индекс чем ходить
    :param jpos: 2 индекс чем ходить
    :param i: 1 индекс куда пойдем
    :param j: 2 индекс куда пойдем
    :return: True если ход осуществим иначе False
    """
    for e in mass:
        if polemass[e[0]][e[1]] == polemass[i][j]:
            hod(polemass, ipos, jpos, i, j)
            kletka = Kletka(polemass[e[2]][e[3]].x, polemass[e[2]][e[3]].y, 'kletka')
            polemass[e[2]][e[3]] = kletka
            return True

    return False

def hod(polemass, ipos, jpos, i, j):
    """
    производит простой ход пешки
    :param polemass: массив двнных о доске
    :param ipos: начальная позиция 1
    :param jpos: начальная позиция 2
    :param i: куда ходит 1
    :param j: куда ходит 2
    :return: заполняет массив передеанный массив
    """
    dopnow = polemass[i][j].getpos()
    dopold = polemass[ipos][jpos].getpos()
    polemass[ipos][jpos].setpos(dopnow)
    polemass[i][j] = polemass[ipos][jpos]
    polemass[ipos][jpos] = Kletka(dopold[0], dopold[1])

def checkchess(mp, polemass, i, j):
    """
    производит проверку на принадлежность указателя мыши клетке на доске
    :param mp: данные о указатели мыши
    :param polemass: массив данных л доске
    :param i: 1 индекс в массиве
    :param j: 2 индекс в массиве
    :return: True если мышь находится на i и j  позиции или False в противном
    """
    return (mp[0] > polemass[i][j].x and mp[0] < (polemass[i][j].x + 72) and mp[1] > polemass[i][j].y and mp[1] < (
        polemass[i][j].y + 72))

def check_hod_without_enemy(chess, poss):
    """
    проверяет можно ли сходить на передоваемую клетку по правилам
    :param chess: данные шашки
    :param poss: данные поля куда хочет пойти игрок
    :return: True если на это поле можно сходить или False если нет
    """

    if chess.x != poss.x - 72 and chess.x != poss.x + 72:
        return False

    elif chess.side == 'down':
        if chess.y != poss.y + 72:
            return False
        else:
            return True
    elif chess.side == 'up':
        if chess.y != poss.y - 72:
            return False
        else:
            return True

def check_enemy(polemass, chess, ipos, jpos):
    """
    проверяет наличие вражеской пешки в зоне досягаемости c озможностью её срубить
    :param polemass: массив доски
    :param chess: данные о шашке которой будут ходить
    :param ipos: первый индекс chess в mass
    :param jpos: второй индекс chess в mass
    :return: массив touple со всеми возможными врагами состоящий из/
            (1 индекс в mass поля для сруба, 2 индекс в mass для для сруба, 1 индекс врага, 2 индекс врага,(ipos,jpos))
    """
    enemymass = []
    for i in (1, -1):
        for j in (1, -1):
            if ipos + i <0 or ipos +i>9 or jpos + j<0 or jpos + j > 9:
                continue

            elif polemass[ipos + i][jpos + j].vid != 'kletka':
                if polemass[ipos + i][jpos + j].vid != chess.vid:
                    if ipos + 2*i <0 or ipos +2*i>9 or jpos + 2*j<0 or jpos + 2*j > 9:
                        continue
                    elif polemass[ipos + 2 * i][jpos + 2 * j].vid == 'kletka':
                        enemymass.append((ipos + 2 * i, jpos + 2 * j, ipos + i, jpos + j,(ipos,jpos)))

    return enemymass

def startpos(mass, side='down'):
    """
    Задает массив доски с шашками
    :param mass: массив в который будут заносится данные
    :param side: сторона игрока down или up
    :return: ничего не возвращает тк заполняет преданный массив
    """
    for i in range(10):
        mass.append([])
        for j in range(10):
            mass[i].append([])
    if side == 'down':
        for i in (0, 2):
            for j in range(10)[1::2]:
                mass[i][j] = Hahka(72 * j, 72 * i, 'black', i_hb, 'up')
        for i in (1, 3):
            for j in range(10)[::2]:
                mass[i][j] = Hahka(72 * j, 72 * i, 'black', i_hb, 'up')
        for i in (6, 8):
            for j in range(10)[1::2]:
                mass[i][j] = Hahka(72 * j, 72 * i, 'white', i_hw, 'down')
        for i in (7, 9):
            for j in range(10)[::2]:
                mass[i][j] = Hahka(72 * j, 72 * i, 'white', i_hw, 'down')

    elif side == 'up':
        for i in (0, 2):
            for j in range(10)[1::2]:
                mass[i][j] = Hahka(72 * j, 72 * i, 'white', i_hw, 'up')
        for i in (1, 3):
            for j in range(10)[::2]:
                mass[i][j] = Hahka(72 * j, 72 * i, 'white', i_hw, 'up')
        for i in (6, 8):
            for j in range(10)[1::2]:
                mass[i][j] = Hahka(72 * j, 72 * i, 'black', i_hb, 'down')
        for i in (7, 9):
            for j in range(10)[::2]:
                mass[i][j] = Hahka(72 * j, 72 * i, 'black', i_hb, 'down')

    for i in range(10):
        for j in range(10):
            if type(mass[i][j]) == list:
                mass[i][j] = Kletka(72 * j, 72 * i)

def check_chess_with_enemy(mass, gocolor):
    """
    оставляет массив с возможными клетками которыми можно сходить срубив врага
    :param mass: массив данных доски
    :param gocolor: цвет шашек которыми будут ходить
    :return: массив результатов функции check_enemy()
    """
    arraychess=[]
    for i in range(10):
        for j in range(10):
            if mass[i][j].vid == 'kletka' or mass[i][j].vid != gocolor:
                continue
            else:
                arraychess.append(check_enemy(mass,mass[i][j],i,j))
    return arraychess

def check_correct_chess(datamass, corrrectdatamass, chess):
    """
    проверяет на правельность хода если есть что рубить
    :param datamass: массив с данными доски
    :param corrrectdatamass: массив с данными шашек которые могут ходить полученный из вызова функции check_chess_with_enemy
    :param chess: шашка которой будут ходить
    :return: True если можно сходить иначе False
    """
    fl=True
    for f in corrrectdatamass:
        if len(f) == 0:
            continue
        for e in f:
            fl = False
            if datamass[e[4][0]][e[4][1]] == chess:
                return True
    return fl

def check_correct_damka_hod(chess,poss):
    if chess.x != poss.x - 72 and chess.x != poss.x + 72:
        return False

    elif chess.side == 'down':
        if chess.y != poss.y + 72 and chess.y != poss.y - 72:
            return False
    return True

def set_damka(polemass,i,j):
    if i == 0 or i == 9:
        polemass[i][j].damka = True
        if polemass[i][j].vid == 'black':
            polemass[i][j].updatebitmap(i_db)
        else:
            polemass[i][j].updatebitmap(i_dw)

window = pygame.display.set_mode((920, 720))
pygame.display.set_caption("Hahki")
pygame.display.set_icon(pygame.image.load('pic\DBlack.gif').convert())
mainscreen = pygame.Surface((720, 720))
rightscreen = pygame.Surface((280, 720))

board = pygame.image.load('pic\Board.gif')
i_hb = pygame.image.load('pic\HBlack.gif')
i_hw = pygame.image.load('pic\HWhite.gif')
i_db = pygame.image.load('pic\DBlack.gif')
i_dw = pygame.image.load('pic\DWhite.gif')
i_rightscreen = pygame.image.load('pic\\rightscreen.png')

polemass = []
side = 'down'
startpos(polemass, side)
playerchess = "white"
gochess = 'white'
done = True

mouse_button_down_fl = False
continuehod = False
continuehahka = None

ipos = 0
jpos = 0

punkts = [(400,200,u'Start',(123,15,34),(235,75,156), 0),
          (400,300,u'NetGame', (123,15,34),(235,75,156), 1),
          (400,400,u'Exit',(123,15,34),(235,75,156), 2)]
game = Menu(punkts)
game.startmenu()

while done:
    mp = pygame.mouse.get_pos()

    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            done = False
        if e.type == pygame.MOUSEBUTTONDOWN and e.button == 1:
            for i in range(10):
                for j in range(10):
                    if checkchess(mp, polemass, i, j):
                        if continuehod == True and polemass[i][j] == continuehahka:
                            print('in False')
                            mouse_button_down_fl = True
                            continuehod=False
                            ipos = i
                            jpos = j
                        elif continuehod == True and polemass[i][j] != continuehahka:
                            break
                        #блок выбора шашки
                        elif (mouse_button_down_fl == False or polemass[i][j].vid == gochess) and polemass[i][j].vid != 'kletka' and polemass[i][j].vid == gochess:
                            if len(check_chess_with_enemy(polemass,gochess)) != 0:
                                if check_correct_chess(polemass,check_chess_with_enemy(polemass,gochess), polemass[i][j]):

                                    print('in False')
                                    mouse_button_down_fl = True
                                    ipos = i
                                    jpos = j
                                    break
                                else:
                                    break
                            else:
                                print('in False')
                                mouse_button_down_fl = True

                                ipos = i
                                jpos = j
                                break
                        #блок хода
                        elif mouse_button_down_fl == True and gochess != polemass[i][j].vid:
                            mass = check_enemy(polemass, polemass[ipos][jpos], ipos, jpos)
                            if len(mass) != 0:
                                if hod_with_enemy(polemass, mass, ipos, jpos, i, j):

                                    mouse_button_down_fl = False
                                    set_damka(polemass,i,j)

                                    if len(check_enemy(polemass, polemass[i][j], i, j)) == 0:
                                        set_damka(polemass,i,j)
                                        if gochess == 'white':
                                            gochess = 'black'
                                        else:
                                            gochess = 'white'
                                    else:
                                        set_damka(polemass,i,j)
                                        continuehod=True
                                        continuehahka = polemass[i][j]
                                    break

                            elif (check_hod_without_enemy(polemass[ipos][jpos], polemass[i][j]) or (polemass[ipos][jpos].damka and check_correct_damka_hod(polemass[ipos][jpos],polemass[i][j]))) and polemass[i][j].vid == 'kletka':
                                print('in True')
                                mouse_button_down_fl = False
                                hod(polemass, ipos, jpos, i, j)
                                set_damka(polemass,i,j)
                                if gochess == 'white':
                                    gochess = 'black'
                                else:
                                    gochess = 'white'
                                break

    window.blit(mainscreen, (0, 0))
    window.blit(rightscreen,(720,0))
    rightscreen.blit(i_rightscreen,(0,0))
    mainscreen.blit(board, (0, 0))

    for i in range(10):
        for j in range(10):
            try:
                polemass[i][j].render()
            except(AttributeError):
                print("AttributeError check render")

    pygame.display.flip()


#!/usr/bin/env python

# Copyright 2017 Johns Hopkins University (Shinji Watanabe)
#  Apache 2.0  (http://www.apache.org/licenses/LICENSE-2.0)

import copy
import json
import logging
import math
import os
import sys
import time
import random
import itertools
from tqdm import tqdm

import numpy as np
import torch

from espnet.asr.asr_utils import add_results_to_json
from espnet.asr.asr_utils import get_model_conf
from espnet.asr.asr_utils import plot_spectrogram
from espnet.asr.asr_utils import _restore_snapshot
from espnet.asr.asr_utils import torch_load
from espnet.asr.asr_utils import torch_save
from espnet.asr.asr_utils import torch_resume
from espnet.asr.asr_utils import torch_snapshot_raw
import espnet.lm.pytorch_backend.extlm as extlm_pytorch
from espnet.nets.asr_interface import ASRInterface
from espnet.nets.mt_interface import MTInterface
from espnet.nets.pytorch_backend.e2e_asr import pad_list
import espnet.nets.pytorch_backend.lm.default as lm_pytorch
from espnet.nets.pytorch_backend.streaming.segment import SegmentStreamingE2E
from espnet.nets.pytorch_backend.streaming.window import WindowStreamingE2E
from espnet.transform.spectrogram import IStft
from espnet.transform.transformation import Transformation
from espnet.utils.cli_writers import file_writer_helper
from espnet.utils.deterministic_utils import set_deterministic_pytorch
from espnet.utils.dynamic_import import dynamic_import
from espnet.utils.io_utils import LoadInputsAndTargets
from espnet.utils.training.batchfy import make_batchset

from torch.utils.data import Dataset
import torch.distributed as dist
import torch.multiprocessing as mp

import matplotlib
matplotlib.use('Agg')

if sys.version_info[0] == 2:
    from itertools import izip_longest as zip_longest
else:
    from itertools import zip_longest as zip_longest

def group_by_ark(jsons):
    # return list of jsons belong to every ark file
    ret = {}
    for k in jsons:
        ark_file = jsons[k]['input'][0]['feat'].split(':')[0]
        if ark_file not in ret:
            ret[ark_file] = {}
        ret[ark_file][k] = jsons[k]
    return [ret[k] for k in ret]

class CustomDataset(Dataset):
    """
    Custom Dataset for Pytorch
        :param jsons: batch json dataset
        :param load_fn: load function
        :param converter: convert data for training
    """

    def __init__(self, jsons, scps, load_fn, converter):
        self.jsons = jsons
        self.scps = scps
        self.load_fn = load_fn
        self.converter = converter

    def __getitem__(self, idx):
        # st = time.time()
        i, j = idx
        batch = self.jsons[i][j]
        data = self.load_fn(batch)
        # print('read kaldi time: ', time.time() - st)
        # st = time.time()
        data = self.converter(data)
        # print('convert time: ', time.time() - st)
        return data

    def __len__(self):
        return sum([len(x) for x in self.jsons])

class CustomConverter(object):
    """Custom batch converter for Pytorch

    :param int subsampling_factor : The subsampling factor
    """

    def __init__(self, subsampling_factor=1):
        self.subsampling_factor = subsampling_factor
        self.ignore_id = -1

    def __call__(self, batch):
        """Transforms a batch

        :param tuple batch: The batch to transform
        :return: a tuple xs_pad, ilens, ys_pad
        :rtype (torch.Tensor, torch.Tensor, torch.Tensor)
        """
        xs, ys = batch

        # perform subsampling
        if self.subsampling_factor > 1:
            xs = [x[::self.subsampling_factor, :] for x in xs]

        # get batch of lengths of input sequences
        ilens = np.array([x.shape[0] for x in xs])

        # perform padding and convert to tensor
        # currently only support real number
        if xs[0].dtype.kind == 'c':
            xs_pad_real = pad_list(
                [torch.from_numpy(x.real).float() for x in xs], 0)
            xs_pad_imag = pad_list(
                [torch.from_numpy(x.imag).float() for x in xs], 0)
            # Note(kamo):
            # {'real': ..., 'imag': ...} will be changed to ComplexTensor in E2E.
            # Don't create ComplexTensor and give it E2E here
            # because torch.nn.DataParellel can't handle it.
            xs_pad = {'real': xs_pad_real, 'imag': xs_pad_imag}
        else:
            # xs_pad = pad_list([torch.from_numpy(x).float() for x in xs], 0).to(device)
            xs_pad = torch.from_numpy(pad_list(xs, 0)).float()

        ilens = torch.from_numpy(ilens)
        # NOTE: this is for multi-task learning (e.g., speech translation)
        # ys_pad = pad_list([torch.from_numpy(np.array(y[0]) if isinstance(y, tuple) else y).long()
        #                    for y in ys], self.ignore_id).to(device)
        ys_pad = torch.from_numpy(pad_list([np.array(y[0]) if isinstance(y, tuple) else y for y in ys], self.ignore_id)).long()

        return xs_pad, ilens, ys_pad

class CustomDistributedSampler(torch.utils.data.Sampler):
    """Sampler that restricts data loading to a subset of the dataset.

        It is especially useful in conjunction with
        :class:`torch.nn.parallel.DistributedDataParallel`. In such case, each
        process can pass a DistributedSampler instance as a DataLoader sampler,
        and load a subset of the original dataset that is exclusive to it.

        .. note::
        Dataset is assumed to be of constant size.

        Arguments:
            dataset: Dataset used for sampling.
            ngpu: whether multi-gpu
            shuffle (optional): If true (default), sampler will shuffle the indices
        """

    def __init__(self, dataset, ngpu, group_shuffle=True, group_in_shuffle=False, valid=False, savedir=None):
        if ngpu > 1:
            if not dist.is_available():
                raise RuntimeError("Requires distributed package to be available")
            num_replicas = dist.get_world_size()
            rank = dist.get_rank()
        else:
            num_replicas = 1
            rank = 0
        self.dataset = dataset
        self.num_replicas = num_replicas
        self.rank = rank
        self.epoch = 0
        if not valid:
            self.num_samples = int(math.ceil(len(self.dataset) * 1.0 / self.num_replicas))
            self.total_size = self.num_samples * self.num_replicas
        else:
            self.num_samples = len(self.dataset)
            self.total_size = self.num_samples
        self.group_shuffle = group_shuffle
        self.group_in_shuffle = group_in_shuffle
        self.valid = valid
        self.savedir = savedir

    def __iter__(self):
        # deterministically shuffle based on epoch
        g = torch.Generator()
        g.manual_seed(self.epoch)

        if self.group_shuffle and self.group_in_shuffle:
            indices = list(itertools.chain(*[[(i, j) for j in torch.randperm(len(self.dataset.jsons[i]), generator=g).tolist()]
                                             for i in torch.randperm(len(self.dataset.jsons), generator=g).tolist()]))
        elif self.group_shuffle and not self.group_in_shuffle:
            indices = list(itertools.chain(*[[(i, j) for j in range(len(self.dataset.jsons[i]))]
                                             for i in torch.randperm(len(self.dataset.jsons), generator=g).tolist()]))
        elif not self.group_shuffle and self.group_in_shuffle:
            indices = list(itertools.chain(*[[(i, j) for j in torch.randperm(len(self.dataset.jsons[i]), generator=g).tolist()]
                                             for i in range(len(self.dataset.jsons))]))
        else:
            indices = list(itertools.chain(*[[(i, j) for j in range(len(self.dataset.jsons[i]))]
                                             for i in range(len(self.dataset.jsons))]))

        # add extra samples to make it evenly divisible
        indices += indices[:(self.total_size - len(indices))]
        assert len(indices) == self.total_size

        # subsample
        if not self.valid:
            indices = indices[self.rank:self.total_size:self.num_replicas]
        else:
            indices = indices[0:self.total_size:1]
        assert len(indices) == self.num_samples

        # write scp file
        self.write_scp(indices)

        return iter(indices)

    def __len__(self):
        return self.num_samples

    def set_epoch(self, epoch):
        self.epoch = epoch

    def write_scp(self, indices):
        if self.savedir is not None:
            scps = list(itertools.chain(*[self.dataset.scps[i][j] for i, j in indices]))
            os.system('mkdir -p {}'.format(self.savedir))
            with open(os.path.join(self.savedir, 'data.{}.scp'.format(self.rank+1)), 'w') as out:
                for scp in scps:
                    out.write(' '.join(scp) + '\n')

class CustomEvaluator:
    """Custom Evaluator for Pytorch

    :param torch.nn.Module model : The model to evaluate
    :param dataset Iterator : The valid iterator
    """

    def __init__(self, model, iterator, reporter, gpu):
        self.model = model
        self.iterator = iterator
        self.reporter = reporter
        self.gpu = gpu

    # The core part of the evaluate routine can be customized by overriding
    def evaluate(self, epoch, total_epochs):
        self.model.eval()
        self.reporter.reset()
        torch.cuda.synchronize()
        with torch.no_grad():
            #for batch in tqdm(self.iterator):
            for batch in self.iterator:
                batch = [x[0].cuda(self.gpu) for x in batch]
                self.model(*batch)
                # if (ii + 1) % 1000 == 0:
                #     print('sentences: ', ii + 1)
                #     print('ctc loss: ', sum(self.reporter.loss_ctc) / len(self.reporter.loss_ctc))
                #     print('ctc cer: ', 1 - float(sum([x[0] for x in self.reporter.cer_ctc])) / float(sum([x[1] for x in self.reporter.cer_ctc])))
                    # self.reporter.print(epoch, total_epochs, valid=True)
        torch.cuda.synchronize()
        self.model.train()
        self.reporter.print(epoch, total_epochs, valid=True)
        return self.reporter.valid_acc

class CustomUpdater:
    """Custom Updater for Pytorch

    :param torch.nn.Module model : The model to update
    :param int grad_clip_threshold : The gradient clipping value to use
    :param torch.optim.optimizer optimizer: The training optimizer
    """

    def __init__(self, model, grad_clip_threshold, gpu,
                 optimizer, grad_noise=False, accum_grad=1):
        self.model = model
        self.grad_clip_threshold = grad_clip_threshold
        self.gpu = gpu
        self.optimizer = optimizer
        self.grad_noise = grad_noise
        self.accum_grad = accum_grad
        self.forward_count = 0
        self.iteration = 0

        # The core part of the update routine can be customized by overriding.

    def update_core(self, batch):
        # to device
        batch = [x[0].cuda(self.gpu) for x in batch]
        self.iteration += 1

        # Compute the loss at this time step and accumulate it
        #st = time.time()
        loss = self.model(*batch) / self.accum_grad
        #torch.cuda.synchronize()
        #print(self.iteration, 'forward time: ', st, time.time() - st)
        #st = time.time()
        loss.backward()  # Backprop
        #torch.cuda.synchronize()
        #print(self.iteration, 'backward time: ', st, time.time() - st)

        # gradient noise injection
        if self.grad_noise:
            from espnet.asr.asr_utils import add_gradient_noise
            add_gradient_noise(self.model, self.iteration, duration=100, eta=1.0, scale_factor=0.55)
        loss.detach()  # Truncate the graph

        # update parameters
        self.forward_count += 1
        if self.forward_count != self.accum_grad:
            return
        self.forward_count = 0
        # compute the gradient norm to check if it is normal or not
        grad_norm = torch.nn.utils.clip_grad_norm_(
            self.model.parameters(), self.grad_clip_threshold)
        logging.info('grad norm={}'.format(grad_norm))
        if math.isnan(grad_norm):
            logging.warning('grad norm is nan. Do not update model.')
        else:
            #st = time.time()
            self.optimizer.step()
            #torch.cuda.synchronize()
            #print(self.iteration, 'optimizer time: ', st, time.time() - st)
        self.optimizer.zero_grad()

def load_trained_model(model_path):
    """Load the trained model.

    Args:
        model_path(str): Path to model.***.best

    """
    # read training config
    idim, odim, train_args = get_model_conf(
        model_path, os.path.join(os.path.dirname(model_path), 'model.json'))

    # load trained model parameters
    logging.info('reading model parameters from ' + model_path)
    # To be compatible with v.0.3.0 models
    if hasattr(train_args, "model_module"):
        model_module = train_args.model_module
    else:
        model_module = "espnet.nets.pytorch_backend.e2e_asr:E2E"
    model_class = dynamic_import(model_module)
    model = model_class(idim, odim, train_args)
    torch_load(model_path, model)

    return model, train_args

def train(args):
    """Train with the given args.

    Args:
        args (namespace): The program arguments.
    """
    set_deterministic_pytorch(args)

    # check cuda availability
    if not torch.cuda.is_available():
        logging.warning('cuda is not available')

    # read json data
    with open(args.train_json, 'rb') as f:
        train_json = json.load(f)['utts']
    with open(args.valid_json, 'rb') as f:
        valid_json = json.load(f)['utts']

    # get idim and odim
    utts = list(valid_json.keys())
    idim = int(valid_json[utts[0]]['input'][0]['shape'][-1])
    odim = int(valid_json[utts[0]]['output'][0]['shape'][-1])
    logging.info('#input dims : ' + str(idim))
    logging.info('#output dims: ' + str(odim))

    args.use_sortagrad = args.sortagrad == -1 or args.sortagrad > 0
    if args.accum_grad >= args.ngpu:
        args.accum_grad = args.accum_grad // args.ngpu
    else:
        args.accum_grad = 1

    # make minibatch list (variable length)
    train_json = group_by_ark(train_json) if args.group_by_ark else [train_json]
    valid_json = group_by_ark(valid_json) if args.group_by_ark else [valid_json]

    if args.ngpu > 1:
        manager = mp.Manager()
        train = manager.list()
        valid = manager.list()
    else:
        train = []
        valid = []

    train_scp = [] if args.cmvn else None
    valid_scp = [] if args.cmvn else None

    for x in train_json:
        batches = make_batchset(x, args.batch_size,
                       args.maxlen_in, args.maxlen_out, args.minibatches,
                       shortest_first=args.use_sortagrad,
                       count=args.batch_count,
                       batch_bins=args.batch_bins,
                       batch_frames_in=args.batch_frames_in,
                       batch_frames_out=args.batch_frames_out,
                       batch_frames_inout=args.batch_frames_inout)
        if args.cmvn:
            train_scp.append([[(bb[0], bb[1]['input'][0]['feat']) for bb in b] for b in batches])
        train.append(batches)

    for x in valid_json:
        # batches = [[xx] for xx in list(x.items())]
        batches = make_batchset(x, args.batch_size,
                       args.maxlen_in, args.maxlen_out, args.minibatches,
                       shortest_first=args.use_sortagrad,
                       count=args.batch_count,
                       batch_bins=args.batch_bins,
                       batch_frames_in=args.batch_frames_in,
                       batch_frames_out=args.batch_frames_out,
                       batch_frames_inout=args.batch_frames_inout)
        if args.cmvn:
            valid_scp.append([[(bb[0], bb[1]['input'][0]['feat']) for bb in b] for b in batches])
        valid.append(batches)

    scp = (train_scp, valid_scp)

    # specify attention, CTC, hybrid mode
    if args.mtlalpha == 1.0:
        mtl_mode = 'ctc'
        logging.info('Pure CTC mode')
    elif args.mtlalpha == 0.0:
        mtl_mode = 'att'
        logging.info('Pure attention mode')
    else:
        mtl_mode = 'mtl'
        logging.info('Multitask learning mode')

    # specify model architecture
    model_class = dynamic_import(args.model_module)
    # TODO(hirofumi0810) better to simplify the E2E model interface by only allowing idim, odim, and args
    # the pre-trained ASR and MT model arguments should be removed here and we should implement an additional method
    # to attach these models
    model = model_class(idim, odim, args)
    # print([(name, x.shape) for name, x in model.named_parameters()])
    assert isinstance(model, ASRInterface)

    if args.rnnlm is not None:
        rnnlm_args = get_model_conf(args.rnnlm, args.rnnlm_conf)
        rnnlm = lm_pytorch.ClassifierWithState(
            lm_pytorch.RNNLM(
                len(args.char_list), rnnlm_args.layer, rnnlm_args.unit))
        torch.load(args.rnnlm, rnnlm)
        model.rnnlm = rnnlm

    # Pretrained model
    if args.pretrained_encoder:
        torch_load(args.pretrained_encoder, model.encoder)
        for p in model.encoder.parameters():
            p.requires_grad = False
    if args.pretrained_ctc:
        torch_load(args.pretrained_ctc, model.ctc)
        for p in model.ctc.parameters():
            p.requires_grad = False

    # write model config
    if not os.path.exists(args.outdir):
        os.makedirs(args.outdir)
    model_conf = args.outdir + '/model.json'
    with open(model_conf, 'wb') as f:
        logging.info('writing a model config file to ' + model_conf)
        f.write(json.dumps((idim, odim, vars(args)),
                           indent=4, ensure_ascii=False, sort_keys=True).encode('utf_8'))
    for key in sorted(vars(args).keys()):
        logging.info('ARGS: ' + key + ': ' + str(vars(args)[key]))

    # training start
    if args.ngpu > 1:
        mp.spawn(train_worker, nprocs=args.ngpu, args=(train, valid, scp, model, args))
    else:
        train_worker(0, train, valid, scp, model, args)

def train_worker(gpu, train, valid, scp, model, args):
    subsampling_factor = model.subsample[0]
    reporter = model.reporter

    # set torch device
    torch.cuda.set_device(gpu)
    model.cuda(gpu)
    if args.ngpu > 1:
        dist.init_process_group(backend='nccl', init_method='tcp://127.0.0.1:{}'.format(args.port),
                                world_size=args.ngpu, rank=gpu)
        model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[gpu])

    # Setup an optimizer
    if args.opt == 'adadelta':
        optimizer = torch.optim.Adadelta(
            model.parameters(), rho=0.95, eps=args.eps,
            weight_decay=args.weight_decay)
    elif args.opt == 'sgd':
        optimizer = torch.optim.SGD(
            model.parameters(),
            lr=args.lr, momentum=0.9
        )
    elif args.opt == 'adam':
        optimizer = torch.optim.Adam(model.parameters(),
                                     weight_decay=args.weight_decay)
    elif args.opt == 'noam':
        from espnet.nets.pytorch_backend.transformer.optimizer import get_std_opt
        optimizer = get_std_opt(model, torch.optim.Adam, args.adim, args.warmup_steps, args.lr)
    elif args.opt == 'radam':
        from espnet.nets.pytorch_backend.transformer.optimizer import get_std_opt
        from espnet.nets.pytorch_backend.transformer.optimizer import RAdam
        optimizer = get_std_opt(model, RAdam, args.adim, args.warmup_steps, args.lr)
    elif args.opt == 'lrsadam':
        from espnet.nets.pytorch_backend.transformer.optimizer import get_lrschedular_opt
        optimizer = get_lrschedular_opt(model, torch.optim.Adam, args.warmup_steps, args.max_lr, args.min_lr, args.decay_factor)
    else:
        raise NotImplementedError("unknown optimizer: " + args.opt)

    # Resume from a snapshot
    if args.resume:
        if os.path.isfile(args.resume):
            logging.info('resumed from %s' % args.resume)
            torch_resume(args.resume, model, optimizer)
        else:
            logging.info("no checkpoint found at '{}'".format(args.resume))

    # Data loading
    load_tr = LoadInputsAndTargets(
        mode='asr', load_output=True, preprocess_conf=args.preprocess_conf,
        preprocess_args={'train': True},  # Switch the mode of preprocessing
        scp_file=os.path.join(args.outdir, '../train/data.{}.scp'.format(gpu+1)) if args.cmvn else None)
    load_cv = LoadInputsAndTargets(
        mode='asr', load_output=True, preprocess_conf=args.preprocess_conf,
        preprocess_args={'train': False},  # Switch the mode of preprocessing
        scp_file=os.path.join(args.outdir, '../valid/data.{}.scp'.format(gpu+1)) if args.cmvn else None)

    # Setup a converter
    converter = CustomConverter(subsampling_factor=subsampling_factor)

    # Construct dataset
    train_scp, valid_scp = scp
    train_dataset = CustomDataset(train, train_scp, load_tr, converter)
    valid_dataset = CustomDataset(valid, valid_scp, load_cv, converter)
    if gpu == 0:
        print('Train samples: ', len(train_dataset))
        print('Valid samples: ', len(valid_dataset))
    train_sampler = CustomDistributedSampler(train_dataset, args.ngpu, group_shuffle=True, group_in_shuffle=True, valid=False, savedir=os.path.join(args.outdir, '../train') if args.cmvn else None)
    valid_sampler = CustomDistributedSampler(valid_dataset, args.ngpu, group_shuffle=False, group_in_shuffle=False, valid=True, savedir=os.path.join(args.outdir, '../valid') if args.cmvn else None)
    num_samples = len(train_sampler)

    train_iter = torch.utils.data.DataLoader(
        train_dataset, batch_size=1, shuffle=(train_sampler is None and not args.use_sortagrad),
        num_workers=args.n_iter_processes, pin_memory=True, sampler=train_sampler
    )
    valid_iter = torch.utils.data.DataLoader(
        valid_dataset, batch_size=1, shuffle=False,
        num_workers=args.n_iter_processes, pin_memory=True, sampler=valid_sampler
    )

    # Set up a trainer
    updater = CustomUpdater(
        model, args.grad_clip, gpu, optimizer, args.grad_noise, args.accum_grad)
    evaluater = CustomEvaluator(model, valid_iter, reporter, gpu)

    evaluater.evaluate(0, args.epochs)
    # import sys; sys.exit(0)

    best_acc = -10000000000
    #st = time.time()
    for epoch in range(args.start_epoch, args.epochs + 1):
        if args.ngpu > 1:
            train_sampler.set_epoch(epoch)
        # train for one epoch
        st = time.time()
        start_time = time.time()
        for batch in train_iter:
            #print('read data time: ', time.time() - start_time)
            #start_time = time.time()
            updater.update_core(batch)
            #torch.cuda.synchronize()
            #print('update_core time: ', time.time() - start_time)
            if (not args.ngpu > 1 or (args.ngpu > 1 and gpu == 0)) and updater.iteration % args.report_interval_iters == 0:
                reporter.print(epoch, args.epochs, (args.start_epoch - 1) * num_samples + updater.iteration, num_samples)
                # remain time
                #torch.cuda.synchronize()
                iter_per_sec = args.report_interval_iters / (time.time() - st)
                remain_time = (1 / iter_per_sec *
                               ((args.epochs - args.start_epoch + 1) * num_samples - updater.iteration)) / 3600
                # learning rate
                lr = optimizer.param_groups[0]['lr'] if args.opt != 'adadelta' else optimizer.param_groups[0]['eps']
                print('{:.2f} iter/sec, Estimated time to finish: {:.2f} hour, Current learning rate: {:.2e}'.format(iter_per_sec, remain_time, lr), flush=True)
                st = time.time()
            start_time = time.time()

        # evaluate on validation set
        current_acc = evaluater.evaluate(epoch, args.epochs)
        is_best = current_acc > best_acc
        diff_acc = current_acc - best_acc
        best_acc = max(best_acc, current_acc)

        # save checkpoint
        if not args.ngpu > 1 or (args.ngpu > 1 and gpu == 0):
            torch_snapshot_raw(model, optimizer, epoch, args.outdir)
            if is_best:
                torch_save(args.outdir + '/model.acc.best', model)

        # update lr
        if args.opt == 'adadelta' and not is_best:
            _restore_snapshot(model, args.outdir + '/model.acc.best', load_fn=torch_load)
            for p in optimizer.param_groups:
                p["eps"] *= args.eps_decay
                logging.info('adadelta eps decayed to ' + str(p["eps"]))

        if args.opt == 'lrsadam':
            if diff_acc < 0:
                _restore_snapshot(model, args.outdir + '/model.acc.best', load_fn=torch_load)
                optimizer.decay = True
            elif diff_acc < 5e-3:
                optimizer.decay = True

def recog(args):
    """Decode with the given args.

    Args:
        args (namespace): The program arguments.
    """
    set_deterministic_pytorch(args)
    model, train_args = load_trained_model(args.model)
    assert isinstance(model, ASRInterface)
    model.recog_args = args

    # read rnnlm
    if args.rnnlm:
        rnnlm_args = get_model_conf(args.rnnlm, args.rnnlm_conf)
        if getattr(rnnlm_args, "model_module", "default") != "default":
            raise ValueError("use '--api v2' option to decode with non-default language model")
        rnnlm = lm_pytorch.ClassifierWithState(
            lm_pytorch.RNNLM(
                len(train_args.char_list), rnnlm_args.layer, rnnlm_args.unit))
        torch_load(args.rnnlm, rnnlm)
        rnnlm.eval()
    else:
        rnnlm = None

    if args.word_rnnlm:
        rnnlm_args = get_model_conf(args.word_rnnlm, args.word_rnnlm_conf)
        word_dict = rnnlm_args.char_list_dict
        char_dict = {x: i for i, x in enumerate(train_args.char_list)}
        word_rnnlm = lm_pytorch.ClassifierWithState(lm_pytorch.RNNLM(
            len(word_dict), rnnlm_args.layer, rnnlm_args.unit))
        torch_load(args.word_rnnlm, word_rnnlm)
        word_rnnlm.eval()

        if rnnlm is not None:
            rnnlm = lm_pytorch.ClassifierWithState(
                extlm_pytorch.MultiLevelLM(word_rnnlm.predictor,
                                           rnnlm.predictor, word_dict, char_dict))
        else:
            rnnlm = lm_pytorch.ClassifierWithState(
                extlm_pytorch.LookAheadWordLM(word_rnnlm.predictor,
                                              word_dict, char_dict))

    # gpu
    if args.ngpu == 1:
        gpu_id = list(range(args.ngpu))
        logging.info('gpu id: ' + str(gpu_id))
        model.cuda()
        if rnnlm:
            rnnlm.cuda()

    # read json data
    with open(args.recog_json, 'rb') as f:
        js = json.load(f)['utts']
        # js = {'6f111c9a15630733368394799d0940': js['6f111c9a15630733368394799d0940']}

    scp_file = None
    if train_args.cmvn:
        scp_file = os.path.join(os.path.dirname(args.result_label),
                                args.result_label.split('/')[-1].replace('json', 'scp'))
        with open(scp_file, 'w') as out:
            for name in js.keys():
                out.write(name + ' ' + js[name]['input'][0]['feat'] + '\n')
    new_js = {}

    load_inputs_and_targets = LoadInputsAndTargets(
        mode='asr', load_output=False, sort_in_input_length=False,
        preprocess_conf=train_args.preprocess_conf
        if args.preprocess_conf is None else args.preprocess_conf,
        preprocess_args={'train': False},
        scp_file=scp_file)

    if args.batchsize == 0:
        with torch.no_grad():
            for idx, name in enumerate(js.keys(), 1):
                logging.info('(%d/%d) decoding ' + name, idx, len(js.keys()))
                batch = [(name, js[name])]
                feat = load_inputs_and_targets(batch)[0][0]
                feat = torch.as_tensor(feat).cuda()
                if args.streaming_mode == 'window':
                    logging.info('Using streaming recognizer with window size %d frames', args.streaming_window)
                    se2e = WindowStreamingE2E(e2e=model, recog_args=args, rnnlm=rnnlm)
                    for i in range(0, feat.shape[0], args.streaming_window):
                        logging.info('Feeding frames %d - %d', i, i + args.streaming_window)
                        se2e.accept_input(feat[i:i + args.streaming_window])
                    logging.info('Running offline attention decoder')
                    se2e.decode_with_attention_offline()
                    logging.info('Offline attention decoder finished')
                    nbest_hyps = se2e.retrieve_recognition()
                elif args.streaming_mode == 'segment':
                    logging.info('Using streaming recognizer with threshold value %d', args.streaming_min_blank_dur)
                    nbest_hyps = []
                    for n in range(args.nbest):
                        nbest_hyps.append({'yseq': [], 'score': 0.0})
                    se2e = SegmentStreamingE2E(e2e=model, recog_args=args, rnnlm=rnnlm)
                    r = np.prod(model.subsample)
                    for i in range(0, feat.shape[0], r):
                        hyps = se2e.accept_input(feat[i:i + r])
                        if hyps is not None:
                            text = ''.join([train_args.char_list[int(x)]
                                            for x in hyps[0]['yseq'][1:-1] if int(x) != -1])
                            text = text.replace('\u2581', ' ').strip()  # for SentencePiece
                            text = text.replace(model.space, ' ')
                            text = text.replace(model.blank, '')
                            logging.info(text)
                            for n in range(args.nbest):
                                nbest_hyps[n]['yseq'].extend(hyps[n]['yseq'])
                                nbest_hyps[n]['score'] += hyps[n]['score']
                else:
                    nbest_hyps = model.recognize(feat, args, train_args.char_list, rnnlm)
                new_js[name] = add_results_to_json(js[name], nbest_hyps, train_args.char_list)

    else:
        def grouper(n, iterable, fillvalue=None):
            kargs = [iter(iterable)] * n
            return zip_longest(*kargs, fillvalue=fillvalue)

        # sort data
        keys = list(js.keys())
        feat_lens = [js[key]['input'][0]['shape'][0] for key in keys]
        sorted_index = sorted(range(len(feat_lens)), key=lambda i: -feat_lens[i])
        keys = [keys[i] for i in sorted_index]

        with torch.no_grad():
            for names in grouper(args.batchsize, keys, None):
                names = [name for name in names if name]
                batch = [(name, js[name]) for name in names]
                feats = load_inputs_and_targets(batch)[0]
                nbest_hyps = model.recognize_batch(feats, args, train_args.char_list, rnnlm=rnnlm)

                for i, nbest_hyp in enumerate(nbest_hyps):
                    name = names[i]
                    new_js[name] = add_results_to_json(js[name], nbest_hyp, train_args.char_list)

    with open(args.result_label, 'wb') as f:
        f.write(json.dumps({'utts': new_js}, indent=4, ensure_ascii=False, sort_keys=True).encode('utf_8'))

def enhance(args):
    """Dumping enhanced speech and mask.

    Args:
        args (namespace): The program arguments.
    """
    set_deterministic_pytorch(args)
    # read training config
    idim, odim, train_args = get_model_conf(args.model, args.model_conf)

    # load trained model parameters
    logging.info('reading model parameters from ' + args.model)
    model_class = dynamic_import(train_args.model_module)
    model = model_class(idim, odim, train_args)
    assert isinstance(model, ASRInterface)
    torch_load(args.model, model)
    model.recog_args = args

    # gpu
    if args.ngpu == 1:
        gpu_id = list(range(args.ngpu))
        logging.info('gpu id: ' + str(gpu_id))
        model.cuda()

    # read json data
    with open(args.recog_json, 'rb') as f:
        js = json.load(f)['utts']

    load_inputs_and_targets = LoadInputsAndTargets(
        mode='asr', load_output=False, sort_in_input_length=False,
        preprocess_conf=None  # Apply pre_process in outer func
    )
    if args.batchsize == 0:
        args.batchsize = 1

    # Creates writers for outputs from the network
    if args.enh_wspecifier is not None:
        enh_writer = file_writer_helper(args.enh_wspecifier,
                                        filetype=args.enh_filetype)
    else:
        enh_writer = None

    # Creates a Transformation instance
    preprocess_conf = (
        train_args.preprocess_conf if args.preprocess_conf is None
        else args.preprocess_conf)
    if preprocess_conf is not None:
        logging.info('Use preprocessing'.format(preprocess_conf))
        transform = Transformation(preprocess_conf)
    else:
        transform = None

    # Creates a IStft instance
    istft = None
    frame_shift = args.istft_n_shift  # Used for plot the spectrogram
    if args.apply_istft:
        if preprocess_conf is not None:
            # Read the conffile and find stft setting
            with open(preprocess_conf) as f:
                # Json format: e.g.
                #    {"process": [{"type": "stft",
                #                  "win_length": 400,
                #                  "n_fft": 512, "n_shift": 160,
                #                  "window": "han"},
                #                 {"type": "foo", ...}, ...]}
                conf = json.load(f)
                assert 'process' in conf, conf
                # Find stft setting
                for p in conf['process']:
                    if p['type'] == 'stft':
                        istft = IStft(win_length=p['win_length'],
                                      n_shift=p['n_shift'],
                                      window=p.get('window', 'hann'))
                        logging.info('stft is found in {}. '
                                     'Setting istft config from it\n{}'
                                     .format(preprocess_conf, istft))
                        frame_shift = p['n_shift']
                        break
        if istft is None:
            # Set from command line arguments
            istft = IStft(win_length=args.istft_win_length,
                          n_shift=args.istft_n_shift,
                          window=args.istft_window)
            logging.info('Setting istft config from the command line args\n{}'
                         .format(istft))

    # sort data
    keys = list(js.keys())
    feat_lens = [js[key]['input'][0]['shape'][0] for key in keys]
    sorted_index = sorted(range(len(feat_lens)), key=lambda i: -feat_lens[i])
    keys = [keys[i] for i in sorted_index]

    def grouper(n, iterable, fillvalue=None):
        kargs = [iter(iterable)] * n
        return zip_longest(*kargs, fillvalue=fillvalue)

    num_images = 0
    if not os.path.exists(args.image_dir):
        os.makedirs(args.image_dir)

    for names in grouper(args.batchsize, keys, None):
        batch = [(name, js[name]) for name in names]

        # May be in time region: (Batch, [Time, Channel])
        org_feats = load_inputs_and_targets(batch)[0]
        if transform is not None:
            # May be in time-freq region: : (Batch, [Time, Channel, Freq])
            feats = transform(org_feats, train=False)
        else:
            feats = org_feats

        with torch.no_grad():
            enhanced, mask, ilens = model.enhance(feats)

        for idx, name in enumerate(names):
            # Assuming mask, feats : [Batch, Time, Channel. Freq]
            #          enhanced    : [Batch, Time, Freq]
            enh = enhanced[idx][:ilens[idx]]
            mas = mask[idx][:ilens[idx]]
            feat = feats[idx]

            # Plot spectrogram
            if args.image_dir is not None and num_images < args.num_images:
                import matplotlib.pyplot as plt
                num_images += 1
                ref_ch = 0

                plt.figure(figsize=(20, 10))
                plt.subplot(4, 1, 1)
                plt.title('Mask [ref={}ch]'.format(ref_ch))
                plot_spectrogram(plt, mas[:, ref_ch].T, fs=args.fs,
                                 mode='linear', frame_shift=frame_shift,
                                 bottom=False, labelbottom=False)

                plt.subplot(4, 1, 2)
                plt.title('Noisy speech [ref={}ch]'.format(ref_ch))
                plot_spectrogram(plt, feat[:, ref_ch].T, fs=args.fs,
                                 mode='db', frame_shift=frame_shift,
                                 bottom=False, labelbottom=False)

                plt.subplot(4, 1, 3)
                plt.title('Masked speech [ref={}ch]'.format(ref_ch))
                plot_spectrogram(
                    plt, (feat[:, ref_ch] * mas[:, ref_ch]).T,
                    frame_shift=frame_shift,
                    fs=args.fs, mode='db', bottom=False, labelbottom=False)

                plt.subplot(4, 1, 4)
                plt.title('Enhanced speech')
                plot_spectrogram(plt, enh.T, fs=args.fs,
                                 mode='db', frame_shift=frame_shift)

                plt.savefig(os.path.join(args.image_dir, name + '.png'))
                plt.clf()

            # Write enhanced wave files
            if enh_writer is not None:
                if istft is not None:
                    enh = istft(enh)
                else:
                    enh = enh

                if args.keep_length:
                    if len(org_feats[idx]) < len(enh):
                        # Truncate the frames added by stft padding
                        enh = enh[:len(org_feats[idx])]
                    elif len(org_feats) > len(enh):
                        padwidth = [(0, (len(org_feats[idx]) - len(enh)))] \
                            + [(0, 0)] * (enh.ndim - 1)
                        enh = np.pad(enh, padwidth, mode='constant')

                if args.enh_filetype in ('sound', 'sound.hdf5'):
                    enh_writer[name] = (args.fs, enh)
                else:
                    # Hint: To dump stft_signal, mask or etc,
                    # enh_filetype='hdf5' might be convenient.
                    enh_writer[name] = enh

            if num_images >= args.num_images and enh_writer is None:
                logging.info('Breaking the process.')
                break


import sys
if sys.version_info.major == 3:
	from tkinter import *
else:
	from Tkinter import *
from PIL import Image, ImageTk, ImageFilter, ImageEnhance
import os
from pydebugger.debug import debug

class Application(Frame):
	def __init__(self, master=None, image1=None, image2=None, image3=None, title=None):
		Frame.__init__(self, master)
		self.master = master
		if not title:
			title = image1
		if not title:
			title = "No Image"
		if title:
			master.iconbitmap(os.path.join(os.path.dirname(__file__), 'favicon.png'))
		else:
			master.iconbitmap(os.path.join(os.path.dirname(__file__), 'nofavicon.ico'))
		self.image1 = image1
		self.image2 = image2
		self.image3 = image3
		self.size1 = (0, 0)
		self.size2 = (0, 0)
		self.size3 = (0, 0)

		master.wm_title(title)
		self.pack()
		# self.createWidgets(image1)
		master.resizable(0,0)
		if image1:
			if os.path.isfile(image1):
				self.showImage1()
				if image2:
					if os.path.isfile(image2):
						self.showImage2()
					self.showNextButton()
		else:
			self.showNoImage(master)
		# if name:
		# 	self.label0 = Label(self, text=name, relief=SUNKEN, height=10, font='Consolas 10 bold')
		# 	self.label0.grid(row=1, column=0, padx=5, pady=5, rowspan=150)

		self.binder(master)
		# print "self.size1 =", self.size1
		# print "self.size2 =", self.size2
		# print "self.size3 =", self.size3
		# if not image3:
		# else:
		self.first_center()
		self.center()

	def first_center(self, final_width=None, final_height=None):
		all_size_width = [self.size1[0], self.size2[0], self.size3[0]]
		all_size_height = [self.size1[1], self.size2[1], self.size3[1]]
		if not self.image2:
			self.master.geometry("%sx%s+30+30"%(str(max(all_size_width)), str(max(all_size_width))))
		else:
			if not final_width:
				if self.image3:
					final_width = sum(all_size_width) + 70
				else:
					final_width = sum(all_size_width) + 40
			if not final_height:
				if self.image3:
					final_height = max(all_size_height[:-1])
				else:
					final_height = max(all_size_height) + 30
			# else:
			# 	final_width = sum(all_size_width)
			# 	final_height = max(all_size_height)
			self.master.geometry("%sx%s+30+30"%(
				str(final_width),
				str(final_height)
			  )
			)

	def center(self):
		"""
		centers a tkinter window
		:param win: the root or Toplevel window to center
		"""
		self.master.update_idletasks()
		width = self.master.winfo_width()
		frm_width = self.master.winfo_rootx() - self.master.winfo_x()
		win_width = width + 2 * frm_width
		height = self.master.winfo_height()
		titlebar_height = self.master.winfo_rooty() - self.master.winfo_y()
		win_height = height + titlebar_height + frm_width
		x = self.master.winfo_screenwidth() // 2 - win_width // 2
		y = self.master.winfo_screenheight() // 2 - win_height // 2
		self.master.geometry('{}x{}+{}+{}'.format(width, height, x, y))
		self.master.deiconify()

	def quitX(self, event=None):
		self.destroy()
		sys.exit()

	def binder(self, master):
		if self.image2:
			if self.image3:
				if os.path.isfile(self.image3):
					master.bind("n", self.showImage3)
		master.bind("q", self.quitX)

	def showNoImage(self, master):
		master.iconbitmap(os.path.join(os.path.dirname(__file__), 'nofavicon.ico'))
		self.label1 = Label(self, text="No Image", relief=SUNKEN, width=20, height=10, font='Consolas 28 bold')
		self.label1.grid(row=0, column=0, padx=5, pady=5, rowspan=10)

	def showImage1(self, event=None):
		if self.image1:
			self.img = Image.open(self.image1)
			self.size1 = self.img.size
			# print "self.size1 0 =", self.size1
			self.photo1 = ImageTk.PhotoImage(self.img.convert("RGB"))
			self.label1 = Label(self, image=self.photo1)
			self.label1.grid(row=0, column=0, padx=5, pady=5, rowspan=10)

	def showImage2(self, event=None):
		if self.image2:
			img = Image.open(self.image2)
			self.size2 = img.size
			# print "self.size2 0 =", self.size2
			self.photo2 = ImageTk.PhotoImage(img.convert("RGB"))
			self.label2 = Label(self, image=self.photo2)
			self.label2.grid(row=0, column=1, padx=5, pady=5, rowspan=10)

	def showImage3(self, event=None):
		self.label2.grid(rowspan=1)
		if self.image3:
			img = Image.open(self.image3)
			self.size3 = img.size
			# print "self.size3 0 =", self.size3
			all_size_width = [self.size1[0], self.size2[0], self.size3[0]]
			all_size_height = [self.size1[1], self.size2[1], self.size3[1]]
			final_width = sum(all_size_width[:-1]) + 70
			final_height = sum(all_size_height[1:]) + 40
			self.first_center(final_width, final_height)
			self.photo3 = ImageTk.PhotoImage(img.convert("RGB"))
			self.label3 = Label(self, image=self.photo3)
			self.label3.grid(row=1, column=1, padx=5, pady=5, rowspan=10)
		self.center()

	def showNextButton(self):
		if self.image2 and self.image3:
			button5 = Button(self, text="Next", command=self.showImage3)
			button5.grid(row=4, column= 2, sticky = N)

	def sharpen(self):
		img2 = self.img.filter(ImageFilter.SHARPEN)
		self.photo2 = ImageTk.PhotoImage(img2)
		self.label2 = Label(self, image=self.photo2)
		self.label2.grid(row=0, column=1, padx=5, pady=5, rowspan=10)

	def showOther(self, event=None):
		self.label2.grid(rowspan=1)
		img = Image.open(self.image2)
		self.photo3 = ImageTk.PhotoImage(img)
		self.label3 = Label(self, image=self.photo3)
		self.label3.grid(row=1, column=1, padx=5, pady=5, rowspan=10)

def center(toplevel):
	"""
    centers a tkinter window
    :param win: the root or Toplevel window to center
    """
	toplevel.update_idletasks()
	width = toplevel.winfo_width()
	frm_width = toplevel.winfo_rootx() - toplevel.winfo_x()
	win_width = width + 2 * frm_width
	height = toplevel.winfo_height()
	titlebar_height = toplevel.winfo_rooty() - toplevel.winfo_y()
	win_height = height + titlebar_height + frm_width
	x = toplevel.winfo_screenwidth() // 2 - win_width // 2
	y = toplevel.winfo_screenheight() // 2 - win_height // 2
	toplevel.geometry('{}x{}+{}+{}'.format(width, height, x, y))
	toplevel.deiconify()

def showImages(title="", image1=None, image2=None, image3=None):
	debug(image1 = image1)
	debug(image2 = image2)
	debug(image3 = image2)
	#print ("image 1 =", image1)
	#print ("image 2 =", image2)
	#print ("image 3 =", image3)
	root = Tk()
	#root = Toplevel(root1)
	#root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
	center(root)
	c = Application(root, image1, image2, image3, title)
	c.mainloop()

if __name__ == '__main__':
	# import sys
	# root = Tk()
	# root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
	# c = Application(root, sys.argv[1], sys.argv[2], sys.argv[3], "TEST Image V")
	# c.mainloop()
	showImages(*sys.argv[1:])


import tkinter as tk
from tkinter import filedialog
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np
import pandas as pd
import seaborn as sns
import sys

Nrange = 128
rIdx = 1024
Ntime = 300

debug = False
debug2 = False

class Window:
    def __init__(self, ts, f, bw, ws, fn, val):
        self.ts = ts
        self.f = f
        self.bw = bw
        self.ws = ws
        self.fn = fn
        self.val = val

class BlockIndex:
    def __init__(self, tID, rID):

        self.timeID = tID
        self.rangeID = rID
        self.idxArry  = []

    def add_win(self, win, idx):
        if ((win.f >= self.rangeID*Nrange & win.f < (self.rangeID+1)*Nrange) | (win.f <= self.rangeID*Nrange & win.f + win.bw >= self.rangeID*Nrange)) & \
            ((win.fn >= self.timeID * Ntime & win.fn < (self.timeID+1)*Ntime) | (win.fn > (self.timeID+1)*Ntime & win.fn - win.ts <= (self.timeID+1)*Ntime)):

            self.idxArry.append(idx)
        else:
            print('This window should not be here. Block ID: {},{} ({},{}). Window start: {} end: {} at frame: {} ts: {}'.format(self.timeID, self.rangeID, self.timeID*Ntime, self.rangeID*Nrange, win.f, win.f + win.bw, win.fn, win.ts))

    def size(self):
        return len(self.idxArry)

    def entries(self):
        return self.idxArry

class Edge:
    def __init__(self, u, v):
        self.u = u
        self.v = v

    def connect(self):
        temp = [u,v]
        return temp

    def print(self):
        print('{} - {}'.format(u,v))

def main():
    #ws='whitespace'
    #ts='timescale'
    #f='frequency'
    #bw='bandwidth'
    #fn='frame_no'

    matplotlib.style.use('ggplot')

    root = tk.Tk()
    root.withdraw()
    filename = filedialog.askopenfilename() #('Window_dump.csv')

    #graph(filename)
    legacy(filename)

def graph ( file ):

    VertexList = [] #V - list of vertices with the index of the vertex (window) list equal to the index of the window
    EdgeList = [] #E -

    BlockList = [] #B - psuedo 2d array of blocks. ... this actually could work well with a GPU architecture ................

    wins = pd.read_csv(file, header=0) #, chunksize = chnk)
    print(wins.columns)

    ######row[1]     row[2]    row[3]     row[4]     row[5]
    #cols:timescale,frequency,bandwidth,whitespace,frame_no
    cols = wins.columns

    t_thresh = 10
    b_thresh = 66

    candidate = 0
    total = 0
    counter = 0

    blockid = 0

    Nrows = 0
    Ncols = 0

    for row in wins.itertuples():
        total+=1
        winval = (row[1]- t_thresh)/t_thresh * (row[3] / b_thresh)
        if winval > 1 :

            temp = Window(int(row[1]),int(row[2]),int(row[3]),int(row[4]),int(row[5]),winval);

            VertexList.append(temp)

            #generate blocks (if necessary)
            if int(row[5]/Ntime) + 1 > int(blockid/rIdx):
                for x in range(0,rIdx):
                    BlockList.append(BlockIndex(int(blockid/rIdx),blockid%rIdx))
                    blockid += 1
                print('Blockid = {}'.format(blockid))

            #need to generate this list for ALL blocks covered, not just the first fit.
            #BlockList[int(row[5]/Ntime)*rIdx + int(row[2]/Nrange)].add_win(temp,candidate)

            for t in range(int((row[5] - row[1])/Ntime),int(row[5]/Ntime)+1):
                for b in range(int(row[2]/Nrange),int((row[2] + row[3])/Nrange)+1):

                    BlockList[t*rIdx + b].add_win(temp,candidate)

                    if debug: print('added candidate: {},{} to: {},{}'.format(row[5],row[2],t*rIdx,b))
            #generate edges

            edgeGen(VertexList,EdgeList,BlockList,temp,candidate)

            candidate += 1
        if total%1000 == 0:
            print('Row: {}, with {} windows'.format(total,candidate))
            print('Size of V: {}. Size of E: {}'.format(len(VertexList),len(EdgeList)))

    print('Total windows: {} Candiate windows: {}'.format(total,candidate))
    print('Final Size of V: {}. Size of E: {}'.format(len(VertexList),len(EdgeList)))

def edgeGen(V,E,B,win,id):
        #Nrows = row[3]/Nrange
        #Ncols = row[1]/Ntime
        #for t in range(row[5]/Ntime - Ncols,row[5]/Ntime):
        #    for b in range(row[2]/Nrange - Nrows,row[2]/Ntime):
        edgeCheck = []

        Nrows = int(win.ts/Ntime)
        Ncols = int(win.bw/Nrange)
        if debug2: print('Active block: {},{} with time {} and range {} - window details: f{}, bw{}, fn{}, ts{}'.format(int(win.fn/Ntime - Nrows),int(win.f/Nrange),Nrows,Ncols,win.f, win.bw, win.fn, win.ts))
        for t in range(int((win.fn - win.ts)/Ntime),int(win.fn/Ntime)+1):
            for b in range(int(win.f/Nrange),int((win.f + win.bw)/Nrange)+1):

                if debug2: print('Checking: {},{}'.format(t,b))
                edgeCheck += B[t*rIdx+b].entries()

        #print(edgeCheck)
        reducedEdge = np.unique(edgeCheck)
        if debug: print('id {}, possible conflict set: {}'.format(id, reducedEdge))

        for e in reducedEdge:
            unique = True
            test = V[e]
            if debug2: print('Current edge check id: {}'.format(e))
            if ((e != id) and ((test.f >= win.f and test.f < win.f+win.bw) or (test.f <= win.f and test.f + test.bw - 1 >= win.f)) and ((
                test.fn >= win.fn - win.ts + 1 and test.fn < win.fn) or (test.fn > win.fn and test.fn - test.ts < win.fn))):

                edge = Edge(id,e)
                E.append(edge)
                edge.print

                if debug: print('window id {}, ({},{} bw {} ts {}) overlapped by: id {}, ({},{} bw {} ts {})'.format(id, V[id].f, V[id].fn, V[id].bw, V[id].ts, e, V[e].f, V[e].fn, V[e].bw, V[e].ts,))

def ts_vs_ws ( file ):

    wins = pd.read_csv(file, header=0) #, chunksize = chnk)
    print(wins.columns)

    #cols:timescale,frequency,bandwidth,whitespace,frame_no
    cols = wins.columns

    ts = max(wins[cols[0]])
    fn = max(wins[cols[4]])

    ts_arr = np.arange(1,ts+1)
    ws_arr = np.zeros_like(ts_arr)

    totalws = 0

    #row:index,timescale,frequency,bandwidth,whitespace,frame_no
    for row in wins.itertuples():
        ws_arr[row[1]-1] += row[4]
        totalws += row[4]

    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)

    ax.semilogy(ts_arr,ws_arr, label='Whitespace vs TS')

    ax.set_yscale('symlog') #super important to plot '0' values
    plt.text(0.2,0.8,"Total ws: " + "{:,}".format(totalws), horizontalalignment='center', verticalalignment='center', transform=ax.transAxes)
    ax.legend()
    plt.show()

def legacy (filename):

    wins = pd.read_csv(filename, header=0) #, chunksize = chnk)
    print(wins.columns)

    #cols:timescale,frequency,bandwidth,whitespace,frame_no
    cols = wins.columns

    #print(wins.head(10))
    #ts = wins.sort_values([cols[0],cols[2]])

    #uniq = pd.unique(wins[cols[0]].values.ravel())#, columns = [cols[0],cols[3]])
    #ts_sort = np.c_[uniq,np.zeros(uniq.size)]
    #ts_sum = np.empty_like(ts_sort)

    ##Row[0] is the index given by the dataframe
    ##Here the unique TS is used as the index, where the unique whitespace value is summed for each TS
    ##TS is already sorted ascending, by nature of the detection
    ## THIS WILL ONLY WORK IF EVERY TS IS OBSERVED !!!BAD!!!
    #for row in wins.itertuples():
    #    ts_sort[row[1]-1,1] += row[4]

    sns.jointplot(wins[cols[2]],wins[cols[0]],kind="hex",color="#4CB391", stat_func=None)
    sns.jointplot(x='bandwidth',y='timescale',data = wins,kind="kde",color="#4CB391", stat_func=None)
    plt.show()

    x = max(wins[cols[2]])
    y = max(wins[cols[0]])
    fn = max(wins[cols[4]])

    nbins = 131072

    print('Max Bandwidth: {}  Max Timescale: {}'.format(x,y))

    mesh = np.zeros((x,y))
    num_frames = np.zeros(fn)

    freqdensity = np.zeros(nbins)

    #print(mesh)

    uniq = pd.unique(wins[cols[2]].values.ravel())
    uniq.sort()

    ws_sort = np.c_[uniq,np.zeros(uniq.size)]
    ws_sum = np.empty_like(ws_sort)

    count = 0
    totalws = 0
    #Row[0] is the index given by the dataframe
    for row in wins.itertuples():
        mesh[row[3]-1,row[1]-1] += row[4]
        #temp = np.where(ws_sort[:,0]==row[3])
        #ws_sort[temp,1] += row[4]
        totalws += row[4]
    ##     mesh[row[1]-1,row[3]-1] += row[4]

        #populate frequency density array
        #for i in range(row[2],row[2]+row[3]-1):
        #    freqdensity[i]+=row[1]

        count += 1
        if (count%100000 == 0): print('Up to: {}'.format(count))

    print('Total Whitespace: ')
    print(totalws)

    fig = plt.figure()
    ##ax1 = fig.add_subplot(1,2,1) #convention (row,col,idx)
    ##ax2 = fig.add_subplot(1,2,2)

    ##pd.DataFrame.hist(wins,column=cols[0],bins=(x+1),log=True,ax=ax1)
    ##ax1.set_xlim([0,50])
    ##ax1.set_title('Timescale Density')
    ##ax1.set_xlabel('Timescale')
    ##ax1.set_ylabel('# Observations')

    ##ax2.plot(num_frames)
    ##ax2.set_ylim([0,100])
    ##ax2.set_title('Whitespace Channels')
    ##ax2.set_xlabel('Frame Number')
    ##ax2.set_ylabel('# Whitespace Channels')
    ##plt.show()

    #print('Mesh populated')
    #print(mesh)

    ax = fig.add_subplot(1,1,1)
    plt.pcolormesh(mesh, norm=LogNorm(vmin=1, vmax=np.amax(mesh)))
    plt.colorbar()
    #ax.set_yscale('log')
    #ax.set_xscale('log')
    ax.set_xlim(1,x)
    ax.set_ylim(1,y)
    ax.set_title('Whitespace Density')
    ax.set_xlabel('Bandwidth in Bins (190Hz/bin)')
    ax.set_ylabel('Timescale (5.3ms/unit)')

    #ax1 = fig.add_subplot(2,1,1)
    #ax1.plot(freqdensity)
    ##ax1.set_xlim([0,50])
    #ax1.set_title('Whitespace Density per Bin')
    #ax1.set_xlabel('Frequency in Bins (190Hz/bin)')
    #ax1.set_ylabel('Whitespace')

    plt.show()

    #ts_sum = ts_sort
    # np.copyto(ts_sum,ts_sort)
    np.copyto(ws_sum,ws_sort)

    #df = pd.DataFrame(data=ts_sort,columns=[cols[0],cols[3]])
    #print(df)

    #for i in range(uniq.size-1, 0, -1):
    #    ts_sum[i-1,1] += ts_sum[i,1]
        #print(ts_sum[i,1])
    for i in range(uniq.size-1, 0, -1):
        ws_sum[i-1,1] += ws_sum[i,1]

    print('\nws_sort:')
    print(ws_sort)
    print('\nws_sum:')
    print(ws_sum)

    sns.jointplot(ws_sort[:,0],ws_sort[:,1],kind="hex",color="#4CB391")
    plt.show()

    #for i in range(len(wins)):
     #       set1 = np.array(wins[wins.columns[0::2]])[i]

    #wins.plot(x=cols[0],y=cols[3],kind='scatter')
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    #ax.plot(ts_sort)
    #ax.set_yscale('log')
    #plt.semilogy(ts_sort[0], ts_sort[1], ts_sum[0], ts_sum[1])
    ax.semilogy(ws_sort[:,0], ws_sort[:,1], label='Unique Whitespace')
    ax.semilogy(ws_sum[:,0], ws_sum[:,1], label='Cumulative Whitespace')

    ax.set_yscale('symlog') #super important to plot '0' values
    ax.legend()
    plt.show()

if __name__ == "__main__":
    sys.exit(int(main() or 0))


from googleapp.models import AndroidVersion,Category,ContentRating,Genre,PayType,App,AppGenre
from rest_framework import response, serializers, status

class AndroidVersionSerializer(serializers.ModelSerializer):

	class Meta:
		model = AndroidVersion
		fields = ('android_version_id', 'android_version')

class CategorySerializer(serializers.ModelSerializer):

	class Meta:
		model = Category
		fields = ('category_id', 'category_name')

class ContentRatingSerializer(serializers.ModelSerializer):

	class Meta:
		model = ContentRating
		fields = ('content_rating_id', 'content_rating')

class GenreSerializer(serializers.ModelSerializer):

	class Meta:
		model = Genre
		fields = ('genre_id', 'genre_name',)

class PayTypeSerializer(serializers.ModelSerializer):

	class Meta:
		model = PayType
		fields = ('pay_type_id', 'pay_type_name',)

class AppGenreSerializer(serializers.ModelSerializer):
	app_id = serializers.ReadOnlyField(source='app.app_id')
	genre_id = serializers.ReadOnlyField(source='genre.genre_id')

	class Meta:
		model = AppGenre
		fields = ('app_id', 'genre_id')

class AppSerializer(serializers.ModelSerializer):
	app_name = serializers.CharField(
		allow_blank=False,
		max_length=255
	)
	rating = serializers.CharField(
		allow_blank=True,
		max_length=10
	)
	reviews = serializers.IntegerField(
		allow_null=True
	)
	size = serializers.CharField(
		allow_null=True,
		max_length=20
	)

	install = serializers.CharField(
		allow_null=True,
		max_length=20
	)

	price = serializers.CharField(
		allow_null=True,
		max_length=10
	)

	updated_time = serializers.CharField(
		allow_null=True,
		max_length=20
	)

	current_version = serializers.CharField(
		allow_null=True,
		max_length=50
	)

	category = CategorySerializer(
		many=False,
		read_only=True
	)
	category_id = serializers.PrimaryKeyRelatedField(
		allow_null=False,
		many=False,
		write_only=True,
		queryset=Category.objects.all(),
		source='category'
	)

	pay_type = PayTypeSerializer(
		many=False,
		read_only=True
	)
	pay_type_id = serializers.PrimaryKeyRelatedField(
		allow_null=False,
		many=False,
		write_only=True,
		queryset=PayType.objects.all(),
		source='pay_type'
	)

	content_rating = ContentRatingSerializer(
		many=False,
		read_only=True
	)
	content_rating_id = serializers.PrimaryKeyRelatedField(
		allow_null=False,
		many=False,
		write_only=True,
		queryset=ContentRating.objects.all(),
		source='content_rating'
	)

	android_version = AndroidVersionSerializer(
		many=False,
		read_only=True
	)
	android_version_id = serializers.PrimaryKeyRelatedField(
		allow_null=False,
		many=False,
		write_only=True,
		queryset=AndroidVersion.objects.all(),
		source='android_version'
	)

	app_genre = AppGenreSerializer(
		source='app_genre_set', # Note use of _set
		many=True,
		read_only=True
	)
	app_genre_ids = serializers.PrimaryKeyRelatedField(
		many=True,
		write_only=True,
		queryset=Genre.objects.all(),
		source='app_genre'
	)

	class Meta:
		model = App
		fields = ('app_id', 'app_name', 'rating', 'reviews', 'size','install','price','updated_time','current_version','category','category_id','pay_type','pay_type_id','content_rating','android_version','content_rating_id','android_version_id','app_genre','app_genre_ids')

	def create(self, validated_data):

		# print(validated_data)

		genres = validated_data.pop('app_genre')
		app = App.objects.create(**validated_data)

		if genres is not None:
			for genre in genres:
				AppGenre.objects.create(
					app_id=app.app_id,
					genre_id=genre.genre_id
				)
		return app

	def update(self, instance, validated_data):
		app_id = instance.app_id
		new_genres = validated_data.pop('app_genre')

		instance.app_name = validated_data.get(
			'app_name',
			instance.app_name
		)
		instance.rating = validated_data.get(
			'rating',
			instance.rating
		)
		instance.reviews = validated_data.get(
			'reviews',
			instance.reviews
		)
		instance.size = validated_data.get(
			'size',
			instance.size
		)
		instance.install = validated_data.get(
			'install',
			instance.install
		)
		instance.price = validated_data.get(
			'price',
			instance.price
		)
		instance.updated_time = validated_data.get(
			'updated_time',
			instance.updated_time
		)
		instance.category_id = validated_data.get(
			'category_id',
			instance.category_id
		)
		instance.current_version = validated_data.get(
			'current_version',
			instance.current_version
		)
		instance.pay_type_id = validated_data.get(
			'pay_type_id',
			instance.pay_type_id
		)
		instance.content_rating_id = validated_data.get(
			'content_rating_id',
			instance.content_rating_id
		)
		instance.android_version_id = validated_data.get(
			'android_version_id',
			instance.android_version_id
		)
		instance.save()

		# If any existing country/areas are not in updated list, delete them
		new_ids = []
		old_ids = AppGenre.objects \
			.values_list('genre_id', flat=True) \
			.filter(app_id__exact=app_id)

		# TODO Insert may not be required (Just return instance)

		# Insert new unmatched country entries
		for genre in new_genres:
			new_id = genre.genre_id
			new_ids.append(new_id)
			if new_id in old_ids:
				continue
			else:
				AppGenre.objects \
					.create(app_id=app_id,genre_id=new_id)

		# Delete old unmatched country entries
		for old_id in old_ids:
			if old_id in new_ids:
				continue
			else:
				AppGenre.objects \
					.filter(app_id=app_id, genre_id=old_id) \
					.delete()

		return instance


#Import cssutils and webcolors as required
import cssutils as cu
import webcolors as wc

#Found this online, it suppresses the ridiculous level of error logging from cssutils
import logging
cu.log.setLevel(logging.CRITICAL)

#Giving a shorter name to the name-to-hex dictionary
nth = wc.CSS2_NAMES_TO_HEX

#I'll keep the next few lines in for now, shows how I figured out how to only
#convert a color value to hex if there's a hex representation for that value
# blue = 'blue'
# blurb = 'blurb'
# if blue in nth:
#     print(nth[blue])
# if blurb in nth:
#     print(nth[blurb])

#Read from the css file provided
inbound_file = cu.parseFile('main.css')

#For each rule in our file...
for rule in inbound_file.cssRules:
    #If it's a style rule...
    if rule.type == rule.STYLE_RULE:
        #Then check out the properties it has
        for property in rule.style:
            #And if it's either color or background-color and has a name-to-hex value
            if (property.name == 'color' or property.name == 'background-color') and property.value in nth:
                #Then change it's value to the hex value
                property.value = nth[property.value]

#Get a new file ready to write to
outbound_file = open("new_main.css","w")
#Decode the bytestring values of the outbound file and encode as UTF-8
outbound_file.write(inbound_file.cssText.decode("utf-8"))
#Finally, close the file
outbound_file.close()


#This program opens a text file and reads the data.
#It then displays the data in a line graph
import matplotlib.pyplot as plt
def main():
    #open text file and store data in list
    text_file=open("1994_Weekly_Gas_Averages.txt","r")
    data = [float(line[:-1]) for line in text_file]
    text_file.close()
    #customize the plot to have a line graph of the data
    #line graph will have labeled axis and title
    plt.plot(data)
    plt.title("1994 Weekly Gas Averages")
    plt.xlabel("Intervals")
    plt.ylabel("Gas Averages")
    plt.show()

main()


from torch import nn
from torch.nn import functional as f
import torch
import torchvision

class ConvBnRelu(nn.Module):
    def __init__(self, in_channels, out_channels):
        super().__init__()
        self.conv = nn.Sequential(nn.Conv2d(in_channels, out_channels, 3, padding=1),
                                  nn.BatchNorm2d(out_channels),
                                  nn.ReLU(inplace=True)
                                  )

    def forward(self, x):
        return self.conv(x)

class Decoder(nn.Module):
    def __init__(self, in_channels, middle_channels, out_channels):
        super(Decoder, self).__init__()
        self.deconv = nn.Sequential(
            ConvBnRelu(in_channels, middle_channels),
            nn.ConvTranspose2d(middle_channels, out_channels, kernel_size=4, stride=2, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
        )

    def forward(self, x):
        return self.deconv(x)

class CSE(nn.Module):
    def __init__(self, in_ch, r):
        super(CSE, self).__init__()

        self.linear_1 = nn.Linear(in_ch, in_ch // r)
        self.linear_2 = nn.Linear(in_ch // r, in_ch)

    def forward(self, x):
        input_x = x

        x = x.view(*(x.shape[:-2]), -1).mean(-1)
        x = f.relu(self.linear_1(x), inplace=True)
        x = self.linear_2(x)
        x = x.unsqueeze(-1).unsqueeze(-1)
        x = torch.sigmoid(x)

        x = input_x * x

        return x

class SSE(nn.Module):
    def __init__(self, in_ch):
        super(SSE, self).__init__()

        self.conv = nn.Conv2d(in_ch, 1, kernel_size=1, stride=1)

    def forward(self, x):
        input_x = x

        x = self.conv(x)
        x = torch.sigmoid(x)

        x = input_x * x

        return x

class SCSE(nn.Module):
    def __init__(self, in_ch, r):
        super(SCSE, self).__init__()

        self.cSE = CSE(in_ch, r)
        self.sSE = SSE(in_ch)

    def forward(self, x):
        c_se = self.cSE(x)
        s_se = self.sSE(x)

        x = c_se + s_se

        return x

class UNetResNet(nn.Module):
    def __init__(self, out_channel, dropout=0.2,
                 pretrained=False):
        super().__init__()
        self.num_classes = out_channel
        self.dropout = dropout

        self.encoder = torchvision.models.resnet34(pretrained=pretrained)
        self.pool = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)

        self.se_e0 = SCSE(64, 4)
        self.conv1 = self.encoder.layer1
        self.se_e1 = SCSE(64, 4)
        self.conv2 = self.encoder.layer2
        self.se_e2 = SCSE(128, 4)
        self.conv3 = self.encoder.layer3
        self.se_e3 = SCSE(256, 4)
        self.conv4 = self.encoder.layer4
        self.se_e4 = SCSE(512, 4)

        self.max_pool = nn.MaxPool2d(2, 2)

        self.center = nn.Sequential(ConvBnRelu(512, 1024))

        self.dec5 = nn.ConvTranspose2d(1024, 512, kernel_size=4, stride=2, padding=1)

        self.dec4 = Decoder(512, 512, 256)
        self.se_d4 = SCSE(256, 4)
        self.dec3 = Decoder(256 + 256, 512, 128)
        self.se_d3 = SCSE(256, 4)
        self.dec2 = Decoder(128 + 128, 256, 64)
        self.se_d2 = SCSE(64, 4)
        self.dec1 = Decoder(64 + 64, 128, 64)
        self.se_d1 = SCSE(128, 4)
        self.final = nn.Conv2d(64, out_channel, kernel_size=1)

    def forward(self, x):
        x = self.encoder.conv1(x)
        x = self.encoder.bn1(x)
        x = self.encoder.relu(x)
        x = self.pool(x)
        x = self.se_e0(x)
        conv1 = self.conv1(x)
        conv1 = self.se_e1(conv1)
        conv2 = self.conv2(conv1)
        conv2 = self.se_e2(conv2)
        conv3 = self.conv3(conv2)
        conv3 = self.se_e3(conv3)
        conv4 = self.conv4(conv3)
        conv4 = self.se_e4(conv4)

        pool = self.max_pool(conv4)
        center = self.center(pool)
        dec5 = self.dec5(center)

        dec4 = self.dec4(torch.cat([dec5, conv4], 1))
        dec4 = self.se_d4(dec4)
        dec3 = self.dec3(torch.cat([dec4, conv3], 1))
        dec3 = self.se_d3(dec3)
        dec2 = self.dec2(torch.cat([dec3, conv2], 1))
        dec2 = self.se_d2(dec2)
        dec1 = f.dropout2d(self.dec1(torch.cat([dec2, conv1], 1)), p=self.dropout)
        dec1 = self.se_d1(dec1)
        return self.final(dec1)


import argparse
import os
import torch
from torch import nn, optim
from torch.utils.data import DataLoader
from torchvision.datasets import SVHN
from torchvision import transforms
from torchvision import datasets
from models import CNN
from trainer import train_source_cnn
from utils import get_logger

def main(args):
    args.logdir = args.logdir+args.mode
    if not os.path.exists(args.logdir):
        os.makedirs(args.logdir)
    logger = get_logger(os.path.join(args.logdir, 'train_source.log'))
    logger.info(args)

    # data
    # source_transform = transforms.Compose([
    #     transforms.ToTensor()]
    # )
    # source_dataset_train = SVHN(
    #     './input', 'train', transform=source_transform, download=True)
    # source_dataset_test = SVHN(
    #     './input', 'test', transform=source_transform, download=True)
    # source_train_loader = DataLoader(
    #     source_dataset_train, args.batch_size, shuffle=True,
    #     drop_last=True,
    #     num_workers=args.n_workers)
    # source_test_loader = DataLoader(
    #     source_dataset_test, args.batch_size, shuffle=False,
    #     num_workers=args.n_workers)
    source_dataset_name = 'MNIST'
    target_dataset_name = 'mnist_m'
    source_image_root = os.path.join('dataset', source_dataset_name)
    target_image_root = os.path.join('dataset', target_dataset_name)
    batch_size = 128
    image_size = 28
    img_transform_source = transforms.Compose([
        transforms.Resize(image_size),
        transforms.ToTensor(),
        transforms.Normalize(mean=(0.1307,), std=(0.3081,))
    ])
    dataset_source_train = datasets.MNIST(
        root='dataset',
        train=True,
        transform=img_transform_source,
        download=True
    )
    source_train_loader = torch.utils.data.DataLoader(
        dataset=dataset_source_train,
        batch_size=batch_size,
        shuffle=True,
        num_workers=8)
    dataset_source_test = datasets.MNIST(
        root='dataset',
        train=False,
        transform=img_transform_source,
    )

    source_test_loader = torch.utils.data.DataLoader(
        dataset=dataset_source_test,
        batch_size=batch_size,
        shuffle=False,
        num_workers=8
    )

    # train source CNN
    source_cnn = CNN(in_channels=args.in_channels).to(args.device)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(
        source_cnn.parameters(),
        lr=args.lr, weight_decay=args.weight_decay)
    source_cnn = train_source_cnn(
        source_cnn, source_train_loader, source_test_loader,
        criterion, optimizer, args=args)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    # NN
    parser.add_argument('--in_channels', type=int, default=3)
    parser.add_argument('--n_classes', type=int, default=10)
    parser.add_argument('--trained', type=str, default='')
    parser.add_argument('--slope', type=float, default=0.2)
    # train
    parser.add_argument('--lr', type=float, default=1e-3)
    parser.add_argument('--weight_decay', type=float, default=2.5e-5)
    parser.add_argument('--epochs', type=int, default=50)
    parser.add_argument('--batch_size', type=int, default=128)
    # misc
    parser.add_argument('--device', type=str, default='cuda:0')
    parser.add_argument('--n_workers', type=int, default=0)
    parser.add_argument('--logdir', type=str, default='outputs/garbage_')
    parser.add_argument('--message', '-m',  type=str, default='')
    parser.add_argument('--mode', type=str, default='s2u',choices=['m2mm','s2u'])
    args, unknown = parser.parse_known_args()
    main(args)


import jwt
from django.http.response import JsonResponse
from rest_framework import status
from config import config
import re
from enum import Enum

def jwt_check_middleware(get_response):
    def middleware(request):

        ignore_check_urls = [
            r'^(\/)$'
            r'^(\/member\/login)$'
            r'^(\/member\/register)$'
        ]

        for pattern in ignore_check_urls:
            if bool(re.search(pattern, request.path)):
                return get_response(request)
        try:
            auth = request.META.get('HTTP_AUTHORIZATION').split()
        except AttributeError:
            return JsonResponse({"message": JWTCheckErrorTypes.NO_AUTHENTICATE_HEADER.value},
                status = status.HTTP_401_UNAUTHORIZED)
        if auth[0].lower() == 'token':
            try:
                payload = jwt.decode(
                    auth[1], config['SECRET_KEY'], algorithms = ['HS256']

                )
                data = payload.get('data')
                request.META['TOKEN_PAYLOAD'] = data
                response = get_response(request)
                return response
            except jwt.ExpiredSignatureError:
                return JsonResponse({"message": JWTCheckErrorTypes.TOKEN_EXPIRED.value},
                status = status.HTTP_401_UNAUTHORIZED)
            except jwt.InvalidTokenError:
                return JsonResponse({"message": JWTCheckErrorTypes.INVALID_TOKEN.value},
                status = status.HTTP_401_UNAUTHORIZED)
        else:
            return JsonResponse({"message": JWTCheckErrorTypes.NOT_SUPPORT_AUTH_TYPE.value},
                status = status.HTTP_401_UNAUTHORIZED)
    return middleware

class JWTCheckErrorTypes(Enum):
    NO_AUTHENTICATE_HEADER = 'No authenticate header'
    NOT_SUPPORT_AUTH_TYPE = 'No support auth type'
    INVALID_TOKEN = 'Invalid token'
    TOKEN_EXPIRED = 'Token expired'


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render
from django.http import JsonResponse
from django.urls import reverse

from .tables import DashboardTable

def dashboard(request):
    context = dict(
        table_coins=DashboardTable(
            id='table_coins',
            url=reverse('api:coin-list', kwargs={'format': 'json'}),
            columns=['code', 'name']
        ),
        table_markets=DashboardTable(
            id='table_markets',
            url=reverse('api:market-list', kwargs={'format': 'json'}),
            columns=['code', 'coin', 'unit']
        ),
        table_tickers=DashboardTable(
            id='table_tickers',
            url=reverse('api:ticker-list', kwargs={'format': 'json'}),
            columns=['market', 'price', 'volumn', 'date', 'sequence']
        )
    )
    return render(request, 'index.html', context)

def check_queries(request):
    context = dict(
        table_check_queries=DashboardTable(
            id='table_check_queries',
            url=reverse('api:querytest-list', kwargs={'format': 'json'}),
            columns=['name', 'params', 'result', 'expect', 'created_at', 'passed']
        )
    )
    return render(request, 'check.html', context)


import sklearn.metrics
import numpy as np
import matplotlib.pyplot as plt
# MCC-F1 Funtion:
def mcc_f1(ground_truths, predicted_values):

    """
    The function mcc_f1 calculates MCC and F1 scores based on varying thresholds identifed by the PRC function
    based on inputs -  ground truth vaules and predicted values.

    Parameters
    ----------
    ground_truths, predicted_values : numpy.ndarray;
                        Input arrays; groundtruth values (True values) and predicted values.

    Returns
    -------
    mcc, f1, thresholds: numpy.ndarray;
                           Output arrays; Unit normalized MCC scores and F1 score values
                           for every threshold.
    """

    mcc = []
    f1 = []

    # Generating thresholds with the PRC function
    precision, recall, thresholds = sklearn.metrics.precision_recall_curve(
                                    ground_truths, predicted_values)

    # For every value of the thresholds (cutoffs), calculate MCC and F1 scores :
    for T in thresholds:
        predicted_values_after_cutoff = predicted_values > T  # Positive classes are determined for every predicted value that exceeds the threshold.

        mcc.append((sklearn.metrics.matthews_corrcoef(
                    ground_truths, predicted_values_after_cutoff)+1)*0.5) # get normalised MCC: change the range of MCC from [-1, 1] to [0, 1]

        f1.append(sklearn.metrics.f1_score(
                    ground_truths, predicted_values_after_cutoff))

    mcc = np.array(mcc)
    f1 = np.array(f1)

    # Resulting values are an array of MCC & F1 scores across different thresholds (cutoffs)
    return mcc,f1, thresholds

# MCC-F1 Metric:
def MCC_F1_Metric(mcc,f1,thresholds, W_num_of_subranges = 100):

    """
    MCC_F1_Metric function computes the MCC-F1 metric i.e. the average distances between the predcition scores to the point of Perfect Performace (1,1)
    and also results in the best threshold value

    Parameters
    ----------

    mcc,f1, thresholds : numpy.ndarray;
                        MCC and F1 scores across varying thresholds

    W_num_of_subranges : int, optional;
        Number of subranges- default = 100;
        larger values of 𝑊 will cause the MCC-𝐹1 metric to capture the performance of a classifier more accurately.

    Returns
    -------
    MCC_F1_Met : float;
                The ratio of the average distance of the MCC-F1 score to the Point of Perfect Performace (1,1)
                A metric to compare classifier performance.

    Best_threshold : int;
                Index of the best prediction score threshold (𝑇),
                Index of the point on the MCC-𝐹1 curve closest to the point of perfect performance (1,1).

    """

    subrange_intervals = np.linspace(np.min(mcc), np.max(mcc),W_num_of_subranges) # breaking into subranges

    # Computing MCC values per subrange

    values_per_subrange = np.zeros_like(subrange_intervals) # 'n' is the number of points per subrange
    for i in range(W_num_of_subranges-1):
        for j in mcc:
            if j >= subrange_intervals[i] and j < subrange_intervals[i+1]:
                values_per_subrange[i] = values_per_subrange[i] + 1

    # Calculating the distances between points in a subrange to the Point of perfect performance (1,1)
    Distance_of_points_within_subrange = np.sqrt(((mcc-1)**2)+((f1-1)**2)) # calculating the Euclidean distance 𝐷𝑖
    sum_of_distance_within_subrange = np.zeros_like(subrange_intervals)
    index = -1
    for value in mcc:
        index += 1
        for i in range(W_num_of_subranges-1):
                 if value >= subrange_intervals[i] and value < subrange_intervals[i+1]:
                        sum_of_distance_within_subrange[i] = sum_of_distance_within_subrange[i] + Distance_of_points_within_subrange[index]

    # Mean Distance across subranges
    mean_Distance_per_subrange = np.array(sum_of_distance_within_subrange/values_per_subrange)
    total_number_of_subranges = 0
    total_sum_of_mean_distances = 0
    for i in mean_Distance_per_subrange:
        if not np.isnan(i):
            total_number_of_subranges += 1
            total_sum_of_mean_distances += i # addition of all the means across subranges that have atleast 1 MCC value.

    grand_mean_distance = total_sum_of_mean_distances/total_number_of_subranges # P = total number of subranges that have atleast 1 MCC value

    """
    Compare the grand average distance to √2 (The distance between the point of worst performance (0,0) and
    the point of perfect performance (1,1) is √2).That is the maximum possible distance between a point on the MCC-𝐹1 curve
    The ratio between the grand avgerage distance and √2 is taken.
    This ratio ranges between 0 and 1 (worst value = 0; best value = 1). To get the MCC-𝐹1 score, we subtract this ratio from 1
    """

    MCC_F1_Met = 1 - (grand_mean_distance /np.sqrt(2))

    # Finding the best threshold 𝑇 the point on the MCC-𝐹1 curve closest to the point of perfect performance (1,1).

    result = np.where(Distance_of_points_within_subrange == Distance_of_points_within_subrange.min())
    Best_threshold = result[0][0]

    print("MCC-F1 metric = {0:.2f}".format(MCC_F1_Met), "Best Threshold = {0:.2f}".format(thresholds[Best_threshold]))

    return MCC_F1_Met,Best_threshold

# Generating a plot (the overall canvas);
axis = None
def axis_plotting(total_plots):
    global axis
    if axis == None:
        fig = plt.figure(figsize=(7,7))
        axis = []
        for i in range(1,total_plots+1):
            ax = fig.add_subplot(total_plots, 1, i)
            axis.append(ax)

def plotting(mcc, f1, thresholds,MCC_F1_Met,Best_threshold,classifer_name = "",total_plots = 1,ax = 0):

        """
        Plotting function - fuction to plot the MCC and F1 scores (across varying Thresholds), and highlight the the MCC_F1 metric with the best threshold
        For multiple plots, 'total_plots' should be > 1 AND 'ax' (< total_plots) starting from  1

        Parameters
        ----------
        mcc,f1 : numpy.ndarray;
            MCC and F1 scores across varying thresholds

        MCC_F1_Met : float;
                The ratio of the average distance of the MCC-F1 score to the Point of Perfect Performace (1,1)
                A metric to compare classifier performance.

        Best_threshold : int;
                Index of the best prediction score threshold (𝑇),
                Index of the point on the MCC-𝐹1 curve closest to the point of perfect performance (1,1).

        classifer_name : str, optional
                    default = ""

        total_plots: int, optional
                    Number of sub-plots to generate; default = 1

        ax : int, optional
            Index of subplot ([1,2,3...]); default = None

        Returns
        -------

        MCC-F1 curve:
            for multiple sublplots, adjust total_plots and ax input value.

        """

        global axis
        if total_plots > 1 and ax < total_plots: # if more than 1 total plot is mentioned;
            axis_plotting(total_plots) #calling function to generate plot;
            if ax == 0:
                subplot = plt.gca() # plot on current axis value,
            else:
                subplot = axis[ax-1] # plotting additional graphs based on index of the axis.
        elif ax > total_plots:
            print("Index inconsistent with total_plots")
        else:
            axis = None
            subplot = plt.gca() # plot on base plot if no additional subplots are needed

        # Labelling the plot;
        subplot.plot(f1,mcc)
        subplot.annotate(classifer_name + "_MCC_Met - {0:.2f}".format(
            MCC_F1_Met),
                 (f1[Best_threshold],mcc[Best_threshold]),
                 textcoords="offset points",
                 xytext=(0,10),
                 ha='left')

        subplot.scatter(f1[Best_threshold],mcc[Best_threshold],color='red')
        subplot.set(xlabel='F1 score',
               ylabel='unit−normalized MCC',title='MCC-F1 curve')

        # Inserting Random line
        subplot.axhline(0.5,linewidth=0.7, color='green',linestyle='--')
        subplot.annotate('Random line',xy =(0,0.5),xytext=(250,-15),
                    color='g', xycoords = subplot.get_yaxis_transform(),
                    textcoords="offset points", va="bottom")

        # Displaying and labelling points of performances.

        subplot.scatter(1,1,color = 'black');subplot.scatter(0,0,color = 'black')
        subplot.annotate('Point of Perfect performance',(1,1),
                    textcoords="offset points",xytext=(-9,-2),ha='right')
        subplot.annotate('Point of Worst performance',(0,0)
                    ,textcoords="offset points",xytext=(9,2),ha='left')

        subplot.set_xticks(np.arange(0, 1.1, 0.25)); subplot.set_yticks(np.arange(0, 1.1, 0.25))
        subplot.set_xlim(-0.05,1.05); subplot.set_ylim(-0.05,1.05)
        subplot.grid(alpha = 0.3)