import functools
import logging
import sys
from logging.handlers import RotatingFileHandler

class LoggerWrapper:
    def __init__(self, stream=None):
        self.logged = set()
        self.logger = logging.Logger(name=__name__, level=logging.DEBUG)

        if not stream:
            stream = sys.stdout

        file_handler = RotatingFileHandler("changetext.log", encoding="utf-8", backupCount=1, maxBytes=1024**2)
        file_handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
        stream_handler = logging.StreamHandler(stream)
        self.logger.addHandler(file_handler)
        self.logger.addHandler(stream_handler)

    def write(self, text):
        if text not in self.logged:
            self.logger.debug(text)
            self.logged.add(text)

@functools.lru_cache
def get_logger(stream=None):
    return LoggerWrapper(stream)

def log_exceptions(stream=None):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(text):
            try:
                return func(text)
            except Exception:
                get_logger(stream).logger.exception(f"An exception occurred. Initial string: {text!r}")

        return wrapper

    return decorator


def upper(x):
    cap=""
    for y in x:
        if ord(y) in range(65,91):
            cap+=y
        elif ord(y) in range(97,123):
            z=ord(y)
            k=z-32
            cap+=chr(k)
        else:
            cap+=y
    return cap

def lower(x):
    cap=""
    for y in x:
        if ord(y) in range(95,123):
            cap+=y
        elif ord(y) in range(65,91):
            z=ord(y)
            k=z+32
            cap+=chr(k)
        else:
            cap+=y
    return cap

def isupper(x):
    x1=False
    for y in x:
        if ord(y) in range(65,91):
            x1=True
    return x1

def islower(x):
    x1=False
    for y in x:
        if ord(y) in range(97,123):
            x1=True
    return x1

def isdigit(x):
    x1=True
    for y in x:
        if ord(y) not in range(48,58):
            x1=False
    return x1

def isalpha(x):
    x1=True
    for y in x:
        if ord(y) not in range(95,123) and ord(y) not in range(65,91):
            x1=False
    return x1
def isalnum(x):
    x1=True
    for y in x:
        if ord(y) not in range(95,123) and ord(y) not in range(65,91) and ord(y) not in range(48,58):
            x1=False
    return x1

def startswith(x2):
    x=input("Enter the string :")
    x1="False"
    for y in x:
        if y[0]==x2:
            x1=True
    return x1

def endswith(x2):
    x=input("Enter the string :")
    x1="False"
    for y in x:
        if y[-1]==x2:
            x1=True
    return x1

def split(x3):
    x=input("Enter the string :")
    begin=0
    list1=[]
    for y in range(len(x)):
        if x[y]==x3:
            list1.append(x[begin:y])
            begin=y+1
        elif y==len(x)-1:
            list1.append(x[begin:])
    return list1

def capitalize(x):
    cap=""
    for i in range(len(x)):
        if i<1:
            if ord(x[i]) in range(97,123):
                c=ord(x[i])
                k=c-32
                cap+=chr(k)
            elif ord(x[i]) in range(97,123) or ord(x[i]) in range(65,91) or ord(x[i]) in range(48,58) or ord(x[i]) in range(32,48) or ord(x[i]) in range(58,65):
                cap+=x[i]
        elif i>=1:
            if ord(x[i]) in range(65,91):
                c=ord(x[i])
                k=c+32
                cap+=chr(k)
            else:
                cap+=x[i]
        else:
            cap+=x[i]
    return cap

def title(a):
    s=""
    i=0
    for y in range(len(a)):
        ch=ord(a[y])
        if ch>64 and ch<91:
            s+=chr(ch+32)
        else:
            s+=chr(ch)
    c=''
    for x in range(len(s)):
        if x==0:
            ch=ord(s[x])
            if ch>96 and ch<123:
                c+=chr(ch-32)
            else:
                c+=chr(ch)
        elif a[x-1]==' ':
            ch=ord(s[x])
            if ch>96 and ch<123:
                c+=chr(ch-32)
            else:
                c+=chr(ch)
        else:
            c+=s[x]
    return c

def swapcase(x):
    cap=""
    for y in x:
        if ord(y) in range(95,123):
            z=ord(y)
            k=z-32
            cap+=chr(k)
        elif ord(y) in range(65,91):
            z=ord(y)
            k=z+32
            cap+=chr(k)
    return cap


from odoo import models, api, fields, _
from odoo.exceptions import ValidationError

class HospitalPatient(models.Model):
    _name = 'hospital.patient'
    _description = 'Patient Record'
    _rec_name = 'patient_name'
    _inherit = ['mail.thread', 'mail.activity.mixin']

    def open_patient_appointment(self):
        return {
            'name': _('Appointments'),
            'domain': [('patient_id', '=', self.id)],
            'res_model': 'hospital.appointment',
            'view_id': False,
            'view_mode': 'tree,form',
            'type': 'ir.actions.act_window',
        }

    def get_appointment_count(self):
        for rec in self:
            rec.count = rec.env['hospital.appointment'].search_count([('patient_id', '=', rec.id)])
            rec.appointments_count = rec.count

    @api.onchange('doctor_id')
    def set_gender_doc(self):
        for rec in self:
            if rec.doctor_id:
                rec.doctor_gender = rec.doctor_id.doc_gender
    # built in function name_get() for customizing name filed according to rec_name
    def name_get(self):
        result = []
        for record in self:
            rec_name = "%s has %s age group" % (record.patient_name, record.age_group)
            result.append((record.id, rec_name))
        return result

    patient_name = fields.Char(string='NAME', required=True, track_visibility='always')
    patient_age = fields.Integer(string='AGE', track_visibility='always', group_operator=False)
    gender = fields.Selection([('male', 'MALE'),
                               ('female', 'FEMALE'), ]
                              , default='male', string="GENDER")
    age_group = fields.Selection([
        ('major', 'MAJOR'),
        ('minor', 'MINOR'),
        ('null', 'NULL'), ],
        string='AGE GROUP', compute='set_age_group')
    notes = fields.Text(string='REGISTRATION NOTES')
    # for patient id
    name_seq = fields.Char(string='Patient ID', required=True, copy=False, readonly=True,
                           index=True, default=lambda self: _('New'))
    appointments_count = fields.Integer(string='Appointments', compute=get_appointment_count)
    # appointments_id = fields.Many2one('hospital.appointment')

    # appointments_id = fields.One2many('hospital.appointment', 'patient_id')

    # function for computing field value by giving depending field vale
    active = fields.Boolean('Active', default=True)
    doctor_id = fields.Many2one('hospital.doctor', string="Consult")
    doctor_gender = fields.Selection([('male', 'MALE'), ('female', 'FEMALE')],
                                     default='male', string='Doc Gender')

    @api.depends('patient_age')
    def set_age_group(self):
        for rec in self:
            if rec.patient_age:
                if rec.patient_age > 18:
                    rec.age_group = 'major'
                else:
                    rec.age_group = 'minor'
            else:
                rec.age_group = 'null'

    # def _age_group_editable(self):
    #     for rec in self:
    #         rec.age_group = rec.age_group.lower() if rec.age_group else False

    # function for adding error message or constrain

    @api.constrains('patient_age')
    def check_age(self):
        for rec in self:
            if rec.patient_age <= 5:
                raise ValidationError(_('AGE MUST BE GREATER THAN 5!'))

    # function for generating sequence number or patient id

    @api.model
    def create(self, vals):
        if vals.get('name_seq', _('New')) == _('New'):
            vals['name_seq'] = self.env['ir.sequence'].next_by_code('hospital.patient.sequence') or _('New')
        result = super(HospitalPatient, self).create(vals)
        return result


# pylint: disable=missing-docstring, unused-import, mixed-indentation

import os
import sys
import collections
import queue
import threading
import time

sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))

from IntComputer import IntComputer

class NIC(IntComputer.IntComputer):
    def __init__(self, program, id, input_queue, output_queue):
        self._program = program
        self._computer = None
        self._id = id
        self.idle = False
        super().__init__( self._program, input_queue, output_queue )

    def _opinput(self, mode):
        # overrideen from base class to return -1
        # if there is no input to process
        try:
            input = self.input_queue.get( block = False)
            self.idle = False
        except queue.Empty:
            input = -1
            self.idle = True

        self._put_num(input, mode)

class Network():
    def __init__(self, count, program):
        self.num_nics = count
        self.nodes = [ ]
        self.input_queues = [ ]
        self.output_queues = [ ]
        self.nat_queue = queue.Queue()
        self.nat_last_y = None

        for i in range( self.num_nics ):
            self.input_queues.append( queue.Queue( ) )
            self.input_queues[-1].put( i )
            self.output_queues.append( queue.Queue( ) )
            self.nodes.append( NIC(program, i, self.input_queues[-1], self.output_queues[-1]) )

    def check_output_queues( self ):
        for q in self.output_queues:
            node = None
            if q.qsize() >= 3:
                node = q.get( )
                x = q.get( )
                y = q.get( )

                if node == 255:
                    # create a new queue which has the effect of remembering the last
                    # x/y pair that was sent.
                    print('{0} sending {1},{2} to {3}'. format(self.output_queues.index(q), x, y, node))
                    self.nat_queue = queue.Queue( )
                    self.nat_queue.put( x )
                    self.nat_queue.put( y )

                elif node is not None and 0 <= node <= self.num_nics:
                    self.input_queues[node].put( x )
                    self.input_queues[node].put( y )

    def check_nat(self):
        idle = all(i.idle == True for i in self.nodes)
        if idle is True and self.nat_queue.empty() is False:
            x = self.nat_queue.get( )
            y = self.nat_queue.get( )

            self.input_queues[0].put( x )
            self.input_queues[0].put( y )

            if self.nat_last_y == y:
                print('twice in a row: {0}, {1}'.format(self.nat_last_y, y))
                sys.exit(0)

            self.nat_last_y = y

    def monitor(self):
        while True:
            # step all of the nics.  GIL kills us in python so we will just
            # run all of the nodes iteratively.  NIC overrides the input function
            # to keep track of idle.
            for nic in self.nodes:
                nic.step( )

            # check output queues to see if we need to forward packs
            # to another nic or the nat
            self.check_output_queues( )

            # see if we have data for the NAT
            self.check_nat( )

if __name__ == '__main__':
    filename = 'input.txt'
    if len(sys.argv) == 2:
        filename = sys.argv[1]
    with open(filename) as f:
        program =  [ int(x) for x in f.read().split(',') ]

    network = Network(50, program)
    network.monitor( )


from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import ParseError
from django.http import Http404
from datetime import date

from .models import Poll, Submission, Answer, Option
from .serializers import (TestSerializer, QuestionSerializer,
                          UserOptionSerializer, SubmissionSerializer)

class Tests(APIView):
    def get(self, request):
        today = date.today()
        pollSet = Poll.objects.filter(startDate__lte=today,
                                      finishDate__gt=today)
        return Response(TestSerializer(pollSet, many=True).data)

class WriteInfoTest(APIView):
    def get(self, request, id):
        try:
            today = date.today()
            poll = Poll.objects.get(id=id)
            if poll.startDate > today or poll.finishDate < today:
                raise Poll.DoesNotExist()

            result = TestSerializer(poll).data
            result['questions'] = []
            for question in poll.question_set.all():
                questionDict = QuestionSerializer(question).data
                questionDict['options'] = UserOptionSerializer(
                            question.option_set.all(), many=True).data
                result['questions'].append(questionDict)

            return Response(result)

        except Poll.DoesNotExist:
            raise Http404()
        except Exception as ex:
            raise ParseError(ex)

    def post(self, request, id):
        try:
            poll = Poll.objects.get(id=id)
            user_id = request.data['user_id']

            def makeAnswer(question):
                answer = Answer(
                    question=question
                    )
                return answer

            answerList = [makeAnswer(question) for question in
                          poll.question_set.all()]
            if len(answerList) != poll.question_set.count():
                raise Exception('Not enough answers')

            submis = Submission(user_id=user_id, poll=poll)
            submis.save()
            for answer in answerList:
                answer.submission = submis
                answer.choice = Option(id=id)
                answer.save()

            return Response('Ответ принят')

        except Poll.DoesNotExist:
            raise Http404()
        except Exception as ex:
            raise ParseError(ex)

class ResultTest(APIView):
    def get(self, request, id):
        try:
            result = []
            for submission in Submission.objects.filter(
                                        user_id=id).order_by('submitTime'):
                submissionDict = SubmissionSerializer(submission).data
                submissionDict['poll_id'] = submission.poll_id
                submissionDict['answers'] = []
                for answer in submission.answer_set.all():
                    submissionDict['answers'].append({
                        'question': {
                            'id': answer.question_id,
                            'text': answer.question.text,
                        },
                        'answer': answer.choice.text,
                        'points': answer.choice.points
                    })

                result.append(submissionDict)
            return Response(result)

        except Exception as ex:
            raise ParseError(ex)


import pygame

import FireBall
from Setting import *
from Kunai import *
from IceSpell import IceSpell
class Player(pygame.sprite.Sprite):
    def __init__(self,x,y,tileGroup,kunaiGroup=pygame.sprite.Group(),bordergroup=pygame.sprite.Group(),\
                 enemyGroup=pygame.sprite.Group(),coinGroup=pygame.sprite.Group(),fightBorder=pygame.sprite.Group(),\
                 checkpoints=pygame.sprite.Group(),heartGroup=pygame.sprite.Group,iceGroup=pygame.sprite.Group):
        super().__init__()
        self.image=PlayerImage
        self.rect=self.image.get_rect(topleft=(x,y))
        self.direction=pygame.math.Vector2()
        self.tileGroup=tileGroup
        self.kunaiGroup=kunaiGroup
        self.borderGroup=bordergroup
        self.enemyGroup=enemyGroup
        self.coinGroup=coinGroup
        self.fightBorder=fightBorder
        self.checkpoints=checkpoints
        self.heartGroup=heartGroup
        self.iceGroup=iceGroup
        self.jumpSpeed=PlayerJumpSpeed
        self.speed=PlayerSpeed
        self.gravity=Gravity
        self.state="idle"
        self.throw=False
        self.currentimageNum=0
        self.kunaiNumber=StartKunai
        self.iceSpellNumber=StartIceSpell
        self.kunaiTimer=KunaiTimer
        self.left=False
        self.onGround=False
        self.attackAdeadOffset=True
        self.freeRun=self.checkFreeRun()
        self.animationSpeed=PlayerAnimationSpeed
        self.health=100
        self.score=0
        self.dead=False
        self.reduceHelathCollistion=0
        self.reduceEnemyHelathCollistion=0
        self.fightBorderWork=False
        self.rect.height -= 3
        self.attackStamina=100
        self.addStaminaTimer=300
        self.combatMode=1
        self.doubleJumpTimer=0
        self.canDoubleJump=False
    def setDirection(self):
        keys=pygame.key.get_pressed()
        if keys[pygame.K_1] and not self.freeRun:
            self.combatMode=1
        elif keys[pygame.K_2] and not self.freeRun:
            self.combatMode = 2
        elif keys[pygame.K_3] and not self.freeRun:
            self.combatMode = 3

        if keys[pygame.K_f] and self.kunaiNumber>0 and self.kunaiTimer==KunaiTimer:
            if self.combatMode==1:
                self.kunaiGroup.add(Kunai(self.rect.centerx,self.rect.centery,self,self.enemyGroup,KunaiSpeed))
            elif self.combatMode==2 and self.kunaiNumber>=3:
                self.kunaiGroup.add(FireBall.FireBall(self.rect.centerx,self.rect.centery,self,self.enemyGroup,KunaiSpeed,BlueFireImagesLeft,BlueFireImages,1))
                self.kunaiNumber-=2 # decreasing 3 , 2 here 1 in a few lines belower
            elif self.combatMode==3 and self.kunaiNumber>=2:
                self.kunaiGroup.add(FireBall.FireBall(self.rect.centerx,self.rect.centery,self,self.enemyGroup,KunaiSpeed,BlueFireImagesLeft,BlueFireImages))
                self.kunaiNumber-=1 # decreacing 2 ,....
            self.kunaiNumber-=1
            self.kunaiTimer=0
            self.state="throw"
            self.throw=True
            self.speed=0
            self.direction.x=0
            self.currentimageNum=0
        elif keys[pygame.K_e] and self.iceSpellNumber>0 and self.kunaiTimer==KunaiTimer and self.combatMode==3:
            self.kunaiGroup.add(IceSpell(self.rect.centerx,self.rect.centery,self,self.enemyGroup,KunaiSpeed,iceGroup=self.iceGroup))
            self.iceSpellNumber-=1
            self.kunaiTimer=0
            self.state="throw"
            self.throw=True
            self.speed=0
            self.direction.x=0
            self.currentimageNum=0

        else :

            if keys[pygame.K_LEFT] and self.state!="throw":
                self.direction.x=-1
                self.state="run"
                self.left=True
            elif keys[pygame.K_RIGHT] and self.state!="throw":
                self.direction.x=1
                self.state="run"
                self.left = False
            elif self.state=="throw":
                if self.currentimageNum==0:
                    self.direction.x=0
                    self.state="idle"
            else :
                self.direction.x = 0
                self.state = "idle"

            if keys[pygame.K_SPACE] and (self.onGround or (self.doubleJumpTimer>15 and self.doubleJumpTimer<20 and self.canDoubleJump) ) :
                self.jump()
                self.state="jump"
                self.doubleJumpTimer=0
                if self.onGround==False:
                    self.canDoubleJump=False
            if keys[pygame.K_g] and self.attackStamina>0:
                self.attackStamina-=1
                self.state="attack"
                self.speed=0
                self.direction.x=0
    def checkDoubleJump(self):
        if self.doubleJumpTimer<20 and not self.onGround:
            self.doubleJumpTimer+=1

    def addStamina(self):
        self.addStaminaTimer-=1
        if self.addStaminaTimer==0:
            self.attackStamina=100
            self.addStaminaTimer=300
    def update(self,tiles):
        self.tileGroup=tiles
        self.addStamina()
        self.checkDoubleJump()
        if not self.dead:
            self.setDirection()
        self.onGround=False
        self.horizontalMovement()
        self.horizontalCollision()
        self.gravityFun()
        self.verticalCollision()
        self.coinCollision()
        self.heartCollision()
        self.checkJump()
        if self.freeRun and self.dead==False:
            if self.state!="jump":
                self.state="run"
            self.direction.x=1
        self.animate()
        self.kunaiTiming()
        self.deadLeftOffset()
        self.attackLeftoffset()
    def horizontalMovement(self):
        if self.state!="throw": # for not moving during throw
            self.rect.x += self.direction.x * self.speed

    def horizontalCollision(self):
        for sprite in self.tileGroup.sprites():
            if sprite.rect.colliderect(self.rect):
                if self.freeRun:
                    self.health-=20
                    if self.health<=0:
                        self.die()
                    self.rect.y-=120
                if self.direction.x>0:
                    self.rect.right=sprite.rect.left
                if self.direction.x<0:
                    self.rect.left=sprite.rect.right
        for sprite in self.borderGroup.sprites():
            if sprite.rect.colliderect(self.rect):
                if self.direction.x>0:
                    self.rect.right=sprite.rect.left
                if self.direction.x<0:
                    self.rect.left=sprite.rect.right
        if self.fightBorderWork:
            for sprite in self.fightBorder.sprites():
                if sprite.rect.colliderect(self.rect):
                    if self.direction.x>0:
                        self.rect.right=sprite.rect.left
                    if self.direction.x<0:
                        self.rect.left=sprite.rect.right
        for sprite in self.enemyGroup.sprites():
            if sprite.dead == False and self.dead==False:
                if sprite.rect.colliderect(self.rect):
                    if self.state!="attack":

                        if self.reduceHelathCollistion == 0:
                            if self.health >=5:
                                self.health -= 5
                                self.die()
                                self.reduceHelathCollistion = 120
                            else:
                                self.die()
                        elif self.reduceHelathCollistion > 0:
                            self.reduceHelathCollistion -= 1

                        # if self.direction.x > 0:
                        #     self.rect.right = sprite.rect.left
                        # if self.direction.x < 0:
                        #     self.rect.left = sprite.rect.right
                    else:
                        if self.reduceEnemyHelathCollistion == 0:
                            if sprite.health >20:
                                sprite.health -= 20
                                self.reduceEnemyHelathCollistion = 20
                            else:
                                pass
                                sprite.dead = True
                                sprite.currentImageNum = 0
                        elif self.reduceEnemyHelathCollistion > 0:
                            self.reduceEnemyHelathCollistion -= 1

    def verticalCollision(self):
        for sprite in self.tileGroup.sprites():
            if sprite.rect.colliderect(self.rect):
                if self.direction.y > 0:
                    self.rect.bottom = sprite.rect.top
                    self.direction.y = 0
                    self.onGround=True
                    self.canDoubleJump=True
                elif self.direction.y < 0:
                    self.rect.top = sprite.rect.bottom
                    self.direction.y = 0
        for sprite in self.borderGroup.sprites():
            if sprite.rect.colliderect(self.rect):
                if self.direction.y > 0:
                    self.rect.bottom = sprite.rect.top
                    self.direction.y = 0
                    self.onGround=True
                elif self.direction.y < 0:
                    self.rect.top = sprite.rect.bottom
                    self.direction.y = 0
        if self.fightBorderWork:
            for sprite in self.fightBorder.sprites():
                if sprite.rect.colliderect(self.rect):
                    if self.direction.y > 0:
                        self.rect.bottom = sprite.rect.top
                        self.direction.y = 0
                        self.onGround=True
                        self.canDoubleJump=True
                    elif self.direction.y < 0:
                        self.rect.top = sprite.rect.bottom
                        self.direction.y = 0
                        self.canDoubleJump = False
        for sprite in self.enemyGroup.sprites():
            if sprite.dead==False and self.dead==False:
                if sprite.rect.colliderect(self.rect):
                    if self.reduceEnemyHelathCollistion==0:
                        if sprite.health>10:
                            sprite.health-=0
                            self.die()
                            self.reduceEnemyHelathCollistion=40
                        else:
                            pass
                            sprite.dead=True
                            sprite.currentImageNum=0
                    elif self.reduceEnemyHelathCollistion>0:
                        self.reduceEnemyHelathCollistion-=1

                    # if self.direction.y > 0:
                    #     self.rect.bottom = sprite.rect.top
                    #     self.direction.y = 0
                    #     self.onGround=True
                    # elif self.direction.y < 0:
                    #     self.rect.top = sprite.rect.bottom
                    #     self.direction.y = 0

    def coinCollision(self):
        if not self.dead:
            pygame.sprite.spritecollide(self,self.coinGroup,True)
    def heartCollision(self):
        if not self.dead:
            pygame.sprite.spritecollide(self,self.heartGroup,True)

    def jump(self):
        self.direction.y=-self.jumpSpeed
    def gravityFun(self):
        self.direction.y += self.gravity
        self.rect.centery += self.direction.y
    def checkJump(self):
        if self.direction.y <0:
            self.state="jump"
    def animate(self):
        if self.state=="idle":
            if not self.left:
                self.image=PlayerIdleImages[int(self.currentimageNum)]
            elif self.left:
                self.image = PlayerIdleImagesLeft[int(self.currentimageNum)]
            self.currentimageNum += self.animationSpeed
            if self.currentimageNum>=10:
                self.currentimageNum=0
        if self.state=="run":
            if self.direction.x > 0:
                self.left=False
                self.image=PlayerRunImages[int(self.currentimageNum)]
            if self.direction.x < 0:
                self.left = True
                self.image=PlayerRunImagesLeft[int(self.currentimageNum)]
            self.currentimageNum += self.animationSpeed
            if self.currentimageNum>=10:
                self.currentimageNum=0
        if self.state=="jump":
            if not self.left:
                self.image=PlayerJumpImages[int(self.currentimageNum)]
                self.currentimageNum+=self.animationSpeed
            else:
                self.image=PlayerJumpImagesLeft[int(self.currentimageNum)]
                self.currentimageNum += self.animationSpeed
            if self.currentimageNum>=10:
                self.currentimageNum=0
        if self.state=="attack":

            if self.left:

               self.image=PlayerAttackImagesLeft[int(self.currentimageNum)]

               self.currentimageNum+=self.animationSpeed
            else:
                self.image=PlayerAttackImages[int(self.currentimageNum)]
                self.currentimageNum+=self.animationSpeed
            if self.currentimageNum>=10:
                self.currentimageNum=0
        if self.state=="throw":
            if self.left:
               self.image=PlayerThrowImagesLeft[int(self.currentimageNum)]
               self.currentimageNum+=self.animationSpeed
            else:
                self.image=PlayerThrowImages[int(self.currentimageNum)]
                self.currentimageNum+=self.animationSpeed
            if self.currentimageNum>=10:
                self.throw=False
                self.currentimageNum=0
        if self.state=="dead":
            self.direction.x=0
            if self.dead and self.currentimageNum>=9:
                self.currentimageNum=9
            else:

                if self.left:
                   self.image=PlayerDeadImagesLeft[int(self.currentimageNum)]
                   self.currentimageNum+=self.animationSpeed
                else:
                    self.image=PlayerDeadImages[int(self.currentimageNum)]
                    self.currentimageNum+=self.animationSpeed

        if self.combatMode==1:
            pass
        elif self.combatMode==2:
            self.changeColor(0)
        elif self.combatMode==3:
            self.changeColor(220)
    def changeColor(self,hue):
        self.tempImage = self.image.copy()
        colorImage = pygame.Surface(self.image.get_size()).convert_alpha()
        color = pygame.Color(0)
        color.hsla = (hue, 100, 60, 100)
        colorImage.fill(color)
        self.tempImage.blit(colorImage, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
        self.image = self.tempImage

    def kunaiTiming(self):
        if self.kunaiTimer<KunaiTimer:
            self.kunaiTimer+=1

    def attackLeftoffset(self):
        if self.state == "attack" and self.left and self.attackAdeadOffset:

            self.rect.left -= 40
            self.attackAdeadOffset = False
        elif self.left and not self.attackAdeadOffset and self.state != "attack":
            self.attackAdeadOffset = True
            self.rect.left += 40
    def deadLeftOffset(self):
        if self.state == "dead" and self.left and self.attackAdeadOffset:

            self.rect.left -= 40
            self.attackAdeadOffset = False
        elif self.left and not self.attackAdeadOffset and self.state != "dead":
            self.attackAdeadOffset = True
            self.rect.left += 40
    def checkFreeRun(self):
        if len(self.borderGroup.sprites())==0:
            self.gravity-=0.3
            return True
        return False

    def die(self):
        if self.health<=0 and not self.dead:
            self.state="dead"
            self.dead=True
            self.currentimageNum=0


from pygame import mixer  # Load the popular external library
from time import sleep
import random
from threading import *
class music(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.numPeople = 0

    def getNumPeople(self):
        return self.numPeople

    def setNumPeople(self,numPeople):
        self.numPeople = numPeople

    def testMusic(self,NumPeopleFunction):
        mixer.init()
        level1 = ["./mp3/le-festin.mp3", "./mp3/viatecture.mp3", "./mp3/saveALife.mp3"]
        level2 = ["./mp3/WayYouAre.mp3", "./mp3/BELONGwME.mp3", "./mp3/rich-girl.mp3", "./mp3/partyUSA.mp3"]
        level3 = ["./mp3/Down.mp3", "./mp3/MOBAMBA.mp3", "./mp3/CRANKdat.mp3"]

        while True:
            numPeople = NumPeopleFunction()
            print("in the MUSIC CODE" , numPeople)
            if numPeople != self.getNumPeople():
                self.numPeople = numPeople
                if numPeople == 1:
                    mixer.music.load(random.choice(level1))
                    mixer.music.play(0)
                    sleep(15)

                if numPeople == 2:
                    mixer.music.load(random.choice(level2))
                    mixer.music.play(0)
                    sleep(15)

                if numPeople >= 3:
                    mixer.music.load(random.choice(level3))
                    mixer.music.play(0)
                    sleep(15)

                else:
                    mixer.music.stop()
                    print("should pause")
            else:
                if numPeople != 0:
                    continue
                else:
                    mixer.music.stop()


import argparse
import datetime
import json
import os
import re
from collections import defaultdict

parser = argparse.ArgumentParser(description="Script to parce access.log file(s)")
parser.add_argument("-p", "--path", dest="path", action="store", help="Provide path to log file or to folder with logs")
args = parser.parse_args()

def read_file(file):
    request_count = 0
    requests_by_method = {
        "POST": 0,
        "GET": 0,
        "PUT": 0,
        "DELETE": 0,
        "HEAD": 0,
        "CONNECT": 0,
        "OPTIONS": 0,
        "TRACE": 0
    }
    requests_other = 0
    requests_by_ip = defaultdict(int)
    requests_by_time = dict()

    with open(file) as file:
        for line in file:
            request = re.search(r"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s\S\s\S.*HTTP.*\"\s(.*)", line)
            if request:
                ip = request.group(1)
                requests_by_ip[ip] += 1
                if len(requests_by_time) < 3:
                    requests_by_time[line] = int(request.group(2))
                else:
                    min_time_key = min(requests_by_time, key=requests_by_time.get)
                    if int(request.group(2)) >= requests_by_time[min_time_key]:
                        del requests_by_time[min_time_key]
                        requests_by_time[line] = int(request.group(2))

                method = re.search(r"] \"(POST|GET|PUT|DELETE|HEAD|CONNECT|OPTIONS|TRACE)", line)
                if method:
                    requests_by_method[method.group(1)] += 1
                else:
                    requests_other += 1
                request_count += 1

    return requests_other, request_count, requests_by_time, requests_by_method, requests_by_ip

# get info for longest requests and try to use regex more
def get_data_from_longest_request(requests_by_time):
    longest_requests = dict()
    idx = 1
    data_sorted = {k: v for k, v in sorted(requests_by_time.items(), key=lambda x: x[1])}
    for i in data_sorted:
        ip_duration = re.search(r"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s\S\s\S.*HTTP.*\"\s(.*)", i)
        ip = ip_duration.group(1)
        duration = ip_duration.group(2)
        method = re.search(r"] \"(POST|GET|PUT|DELETE|HEAD|CONNECT|OPTIONS|TRACE)", i).group(1)
        url = re.search(rf"] \"{method}\s(\S+)", i).group(1)
        date_time = re.search(r"\S\s\S\s\S(\S+)", i).group(1).replace(":", " ", 1)
        longest_requests[f"ID {idx}"] = {"Method": method, "URL": url, "ip": ip, "Duration": duration,
                                         "Date and Time": date_time}
        idx += 1

    return longest_requests

def main(file):
    other_requests, count, r_by_time, r_by_method, r_by_ip = read_file(file)
    longest = get_data_from_longest_request(r_by_time)
    sorted_ips = {k: v for k, v in sorted(r_by_ip.items(), key=lambda x: x[1], reverse=True)[:3]}

    all_together = {
        "Log file": file,
        "Total requests": count,
        "By methods": r_by_method,
        "Other requests": other_requests,
        "Top 3 IP": sorted_ips,
        "Longest": longest
    }

    data_json = json.dumps(all_together, indent=4)

    print(data_json)

    with open(f"{datetime.datetime.now()}.json", mode="w", encoding="UTF8") as f:
        f.write(data_json)

if os.path.isdir(args.path):
    if not args.path.endswith("/"):
        args.path += "/"
    for file in os.listdir(args.path):
        if file.endswith(".log"):
            f = 5
            main(f"{args.path}{file}")
else:
    main(args.path)


from lab4.commands import *
from sys import stderr

bank = Bank()

commands = {
    "addacc": AddAccountCommand(bank),
    "addcl": AddClientCommand(bank),
    "cash": CountTotalCashCommand(bank),
    "cashacc": ShowCashCommand(bank),
    "client": ClientCommand(bank),
    "course": CourseCommand(bank),
    "history": ShowTransactionHistoryCommand(bank),
    "listacc": BankListAccountsCommand(bank),
    "listcl": BankListClientsCommand(bank),
    "send": SendMoneyCommand(bank)
}

while True:
    parts = input().split()
    if len(parts):
        command, *args = parts
        if command not in commands:
            if command == "help":
                for key in sorted(commands.keys()):
                    print(key, commands[key].help())
            elif command == "exit":
                break
            else:
                print("%s: command not exists" % command)
        else:
            try:
                print(commands[command](*args))
            except CommandError as e:
                print("ERROR:", str(e), file=stderr)


"""
.. _ref_wrapping_numpy_capabilities:

Create a basic operator plugin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This example shows how to create a basic operator plugin, which is for
a single custom operator. This custom operator, ``easy_statistics``,
computes simple statistics quantities on a scalar field with the help of
the ``numpy`` package.

The objective of this simple example is to show how routines for DPF can
be wrapped in Python plugins.

.. note::
    This example requires DPF 4.0 (Ansys 2022R2) or above.
    For more information, see :ref:`ref_compatibility`.

"""

###############################################################################
# Create the operator
# -------------------
# Creating a basic operator plugin consists of writing a single Python script.
# An operator implementation derives from the
# :class:`ansys.dpf.core.custom_operator.CustomOperatorBase` class
# and a call to the :py:func:`ansys.dpf.core.custom_operator.record_operator`
# method.
#
# The ``easy_statistics`` operator takes a field as an input and returns
# the first quartile, the median, the third quartile, and the variance.
# The Python operator and its recording are available in the
# ``easy_statistics.py`` file.
#
# Download and display the Python script.

from ansys.dpf.core import examples
from ansys.dpf import core as dpf

GITHUB_SOURCE_URL = (
    "https://github.com/ansys/pydpf-core/" "raw/examples/first_python_plugins/python_plugins"
)
EXAMPLE_FILE = GITHUB_SOURCE_URL + "/easy_statistics.py"
operator_file_path = examples.downloads._retrieve_file(
    EXAMPLE_FILE, "easy_statistics.py", "python_plugins"
)

with open(operator_file_path, "r") as f:
    for line in f.readlines():
        print("\t\t\t" + line)

###############################################################################
# Load the plugin
# ---------------
# You use the :py:func:`ansys.dpf.core.core.load_library` method to load the
# plugin.

# - The first argument is the path to the directory where the plugin
#   is located.
# - The second argument is ``py_`` plus the name of the Python script.
# - The third argument is the name of the function used to record operators.
#

import os
from ansys.dpf import core as dpf
from ansys.dpf.core import examples

# Python plugins are not supported in process.
dpf.start_local_server(config=dpf.AvailableServerConfigs.GrpcServer)

operator_server_file_path = dpf.upload_file_in_tmp_folder(operator_file_path)
dpf.load_library(os.path.dirname(operator_server_file_path), "py_easy_statistics", "load_operators")

###############################################################################
# Instantiate the operator.

new_operator = dpf.Operator("easy_statistics")

###############################################################################
# Connect a workflow
# ------------------
# Connect a workflow that computes the norm of the displacement to the
# ``easy_statistics`` operator. Methods of the ``easy_statistics`` class
# are dynamically added because specifications for the operator are
# defined in the plugin.

# %%
# .. graphviz::
#
#    digraph foo {
#       graph [pad="0.5", nodesep="0.3", ranksep="0.3"]
#       node [shape=box, style=filled, fillcolor="#ffcc00", margin="0"];
#       rankdir=LR;
#       splines=line;
#       ds [label="ds", shape=box, style=filled, fillcolor=cadetblue2];
#       ds -> displacement [style=dashed];
#       displacement -> norm;
#       norm -> easy_statistics;
#    }

###############################################################################
# Use the operator
# ----------------

ds = dpf.DataSources(dpf.upload_file_in_tmp_folder(examples.find_static_rst()))
displacement = dpf.operators.result.displacement(data_sources=ds)
norm = dpf.operators.math.norm(displacement)
new_operator.inputs.connect(norm)

print("first quartile is", new_operator.outputs.first_quartile())
print("median is", new_operator.outputs.median())
print("third quartile is", new_operator.outputs.third_quartile())
print("variance is", new_operator.outputs.variance())


# Escaner de puertos con sockets

# Importamos modulo socket
from socket import *

# Preguntamos por la IP
ip = input("Introduce IP : ")

# Preguntamos por el puertos
puerto_inicio = input("Introduce puerto de inicio : ")
puerto_fin = input("Introduce puerto de fin : ")

print ("Escaneando IP {} : ".format(ip))

#recorrer cada uno de los puertos
for port in range(int(puerto_inicio),int(puerto_fin) + 1):
    print ("Probando puerto {} ...".format(port))
    # Crea el objeto socket
    s = socket(AF_INET, SOCK_STREAM)
    s.settimeout(5)

    # Comprobar conexion e imprimimos si el puerto está abierto
    if(s.connect_ex((ip,port))==0):
        print("El puerto " , port, "está abierto")

    # Cierra el socket
    s.close()

print("Escaneo finalizado!")


from django.db import migrations, models

class Migration(migrations.Migration):
    dependencies = [
        ("projects", "0004_add_project_container_image"),
    ]

    operations = [
        migrations.AlterField(
            model_name="project",
            name="documentation_type",
            field=models.CharField(
                default=b"sphinx",
                help_text='Type of documentation you are building. More info.',
                max_length=20,
                verbose_name="Documentation type",
                choices=[
                    (b"auto", "Automatically Choose"),
                    (b"sphinx", "Sphinx Html"),
                    (b"mkdocs", "Mkdocs (Markdown)"),
                    (b"sphinx_htmldir", "Sphinx HtmlDir"),
                    (b"sphinx_singlehtml", "Sphinx Single Page HTML"),
                ],
            ),
        ),
        migrations.AlterField(
            model_name="project",
            name="single_version",
            field=models.BooleanField(
                default=False,
                help_text='A single version site has no translations and only your "latest" version, served at the root of the domain. Use this with caution, only turn it on if you will neverhave multiple versions of your docs.',
                verbose_name="Single version",
            ),
        ),
        migrations.AlterField(
            model_name="project",
            name="use_virtualenv",
            field=models.BooleanField(
                default=False,
                help_text="Install your project inside a virtualenv using setup.py install",
                verbose_name="Install Project",
            ),
        ),
    ]


'''
creating data structure
'''
import pandas as pd

# creating a series
s = pd.Series(['banana',42])
print()
print(s)

# manually assign index value
s = pd.Series(
    data = [['banana','apple'],['pork','chicken']],
    index = ['fruit','protein'],
)
print()
print(s)

s = pd.Series({'key':'get ready'})
print()
print(s)

# creating DataFrame
scientist = pd.DataFrame(
{
    "Name": ["Rosaline Franklin", "William Gosset"],
    "Occupation": ["Chemist", "Statistician"],
    "Born": ["1920-07-25", "1876-06-13"],
    "Died": ["1958-04-16", "1937-10-16"],
    "Age": [37, 61],
},
# index = ["Rosaline Franklin", "William Gosset"],
columns=['Name','Age','Born','Died','Occupation']
)
print()
print(scientist)


import argparse
import h5py
import numpy as np
import hydra

from manimo.environments.single_arm_env import SingleArmEnv

HZ = 20

parser = argparse.ArgumentParser()
parser.add_argument("--replay_file", type=str, required=True)
args = parser.parse_args()
replay_file = args.replay_file

# read the test.h5 file
f = h5py.File(replay_file, "r")

# get position action
ee_pos_desired = f["eef_pos"][:]
ee_quat_desired = f["eef_rot"][:]
ee_joints = f["q_pos"][:]

# get start position
demo_start_pos = ee_joints[0]
print(f'num_obs: {ee_pos_desired.shape[0]}')
print(f'start_pos: {demo_start_pos}')

# initialize agent
hydra.initialize(
        config_path="../conf", job_name="collect_demos_test"
    )

actuators_cfg = hydra.compose(config_name="actuators")
sensors_cfg = hydra.compose(config_name="sensors")

env = SingleArmEnv(sensors_cfg, actuators_cfg, hz=HZ)
hydra.core.global_hydra.GlobalHydra.instance().clear()

print(f'Setting home to demo start pos: {demo_start_pos}')
env.set_home(demo_start_pos)
env.reset()

assert ee_pos_desired.shape[0] == ee_quat_desired.shape[0]
num_actions = ee_pos_desired.shape[0]

print("starting replay")

for i in range(num_actions):
    action = [np.append(ee_pos_desired[i], ee_quat_desired[i])]
    env.step(action)

env.reset()


import pytest

from ddtrace.appsec._iast import oce
from ddtrace.appsec._iast._ast.ast_patching import astpatch_module

def _iast_patched_module(module_name):
    module = __import__(module_name, fromlist=[None])
    module_path, patched_source = astpatch_module(module)

    compiled_code = compile(patched_source, module_path, "exec")
    exec(compiled_code, module.__dict__)
    return module

@pytest.fixture(autouse=True, scope="module")
def _enable_oce():
    oce._enabled = True
    yield
    oce._enabled = False


from datetime import datetime
import csv
import pdb

from race import Race
from horse import Horse
import utilities

MAX = 18

date = '20150429'
track = 'CD'
utilities.set_verbosity('HIGH')
# client = MongoClient()
# db = client.PONIES
# rdb = db.RACES
# hdb = db.HORSES

filename = 'results/singleHorse_{}.csv'.format(datetime.now().strftime('%Y-%m-%d'))
with open(filename,'w') as f:
  races = Race.findRaces()

  first_row = 'race_number,purse,distance,class_rating,num_in_field,h_odds,h_age,h_weight,h_gate_position,h_claim_value,h_odds_index,finish_wps\n'
  f.write(first_row)
  for race in races:
    if int(race.class_rating) <0: continue
    ordered_horses = race.sortedHorseOdds()
    for i,horse in enumerate(ordered_horses):
      race_text = '{},{},{},{},{},'.format(race.race_number, race.purse, race.distance, race.class_rating, len(ordered_horses))
      row = race_text + '{},{},{},{},{},{},'.format(horse.odds, horse.age, horse.weight, horse.gate_position, horse.claim_value, i)
      if horse.finish_position['position'] in ['1','2','3']:
        finish_wps = '1'
      else:
        finish_wps = '0'
      horse_count = 0

      row += finish_wps+'\n'
      f.write(row)


class Solution:
  def maximumBags(self, capacity: List[int], rocks: List[int], additionalRocks: int) -> int:
    diff = sorted([capacity[i]-rocks[i] for i in range(len(capacity))])
    ans = 0
    for i in range(len(diff)):
      if additionalRocks >= diff[i]:
        additionalRocks -= diff[i]
        ans += 1
      else:
        break

    return ans


from __future__ import absolute_import, division, print_function
import argparse
import base64
import os.path as op
import random, time, json
import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader, RandomSampler, SequentialSampler
from tqdm import tqdm

from oscar.utils.logger import setup_logger
from oscar.utils.tsv_file import TSVFile
from oscar.utils.tsv_file_ops import tsv_writer
from oscar.utils.misc import (mkdir, set_seed,
        load_from_yaml_file, find_file_path_in_yaml)
from oscar.utils.caption_evaluate import (evaluate_on_coco_caption, evaluate_on_reddit_caption,
        evaluate_on_nocaps, ScstRewardCriterion)
from oscar.utils.cbs import ConstraintFilter, ConstraintBoxesReader
from oscar.utils.cbs import FiniteStateMachineBuilder
from oscar.modeling.modeling_bert import BertForMultiModalDialog
from transformers.pytorch_transformers import BertTokenizer, BertConfig
from transformers.pytorch_transformers import AdamW, WarmupLinearSchedule, WarmupConstantSchedule
import torch.nn as nn
import sys
sys.setrecursionlimit(1000000)

total_num_boxes = 36

class CaptionTSVDataset(Dataset):
    def __init__(self, yaml_file, tokenizer=None, add_od_labels=True,
            max_img_seq_length=50, max_seq_length=70, max_seq_a_length=40, max_seq_c_length=40,
            is_train=True, mask_prob=0.15,mask_response_prob=0.7, max_masked_tokens=3, **kwargs):
        """Constructor.
        Args:
            yaml file with all required data (image feature, caption, labels, etc)
            tokenizer: tokenizer for text processing.
            add_od_labels: whether to add labels from yaml file to BERT.
            max_img_seq_length: max image sequence length.
            max_seq_length: max text sequence length.
            max_seq_a_length: max caption sequence length.
            is_train: train or test mode.
            mask_prob: probability to mask a input token.
            max_masked_tokens: maximum number of tokens to be masked in one sentence.
            kwargs: other arguments.
        """
        self.yaml_file = yaml_file
        self.cfg = load_from_yaml_file(yaml_file)
        self.root = op.dirname(yaml_file)
        self.tag_and_feat_file = find_file_path_in_yaml(self.cfg['feature'], self.root)
        # self.feat_file = find_file_path_in_yaml(self.cfg['feature'], self.root)
        self.dialog_file = find_file_path_in_yaml(self.cfg.get('dialog'), self.root)
        self.dialog2img_file = find_file_path_in_yaml(self.cfg.get('dialog2img'), self.root)

        assert op.isfile(self.tag_and_feat_file)
        # if add_od_labels: assert op.isfile(self.label_file)
        if is_train: assert op.isfile(self.dialog_file) and tokenizer is not None

        # self.label_tsv = None if not self.label_file else TSVFile(self.label_file)
        self.tag_and_feat_tsv = TSVFile(self.tag_and_feat_file, gen_lineidx=True)
        if self.dialog_file and op.isfile(self.dialog_file):
            self.dialogs = [line.decode().rstrip('\n').split('\t') for line in open(self.dialog_file,'rb')] # [[sent1,sent2,....sentn],...[sent1,sent2,....sentn]]
        if self.dialog2img_file and op.isfile(self.dialog2img_file):
            self.dialog2img = [line.decode().rstrip('\n').split('\t') for line in open(self.dialog2img_file,'rb')] # [[top1,top2,....topn],...[top1,top2,....topn]]

        # print('len of dialogs', len(self.dialogs))

        self.tokenizer = tokenizer
        self.tensorizer = CaptionTensorizer(self.tokenizer, max_img_seq_length,
                max_seq_length, max_seq_a_length, max_seq_c_length, mask_prob, mask_response_prob, max_masked_tokens,
                is_train=is_train)
        self.add_od_labels = add_od_labels
        self.is_train = is_train
        self.kwargs = kwargs
        # self.image_keys = self.prepare_image_keys()
        self.key2index = self.prepare_image_key_to_index()
        # self.key2captions = self.prepare_image_key_to_captions()

    def get_valid_tsv(self):
        return self.tag_and_feat_tsv

    # def prepare_image_keys(self):
    #     tsv = self.get_valid_tsv()
    #     return [tsv.seek(i)[0] for i in range(tsv.num_rows())]

    def get_dialog_file(self):
        return self.dialog_file

    def prepare_image_key_to_index(self):
        tsv = self.get_valid_tsv()
        # print(tsv.seek(0)[0])
        # print(type(tsv.seek(0)[0]))
        # print(tsv.seek(0)[1])
        return {tsv.seek(i)[0] : i for i in range(tsv.num_rows())}

    def get_image_features(self, img_idx):
        # feat_info = json.loads(self.tag_and_feat_tsv.seek(img_idx)[1])
        feat_info = eval(self.tag_and_feat_tsv.seek(img_idx)[1]) #transfer to dict
        features = np.frombuffer(base64.b64decode(feat_info['features']), np.float32
                ).reshape((total_num_boxes, -1))

        fea = torch.Tensor(features)

        return fea

    def get_od_labels(self, img_idx):
        od_labels = None
        if self.add_od_labels:
            label_info = eval(self.tag_and_feat_tsv.seek(img_idx)[1])
            # If filter the repeat token
            # od_labels = " ".join(list(set(label_info['objects_class'])))
            od_labels = " ".join(label_info['objects_class'])
        return od_labels

    def __getitem__(self, idx):

        dialogs = self.dialogs[idx]
        context = '[SEP]'.join(dialogs[:-1])
        # if add tag bias
        context += '[TAG]'
        #else when decoding
        # context += '[SEP]'
        response = dialogs[-1]

        img_key = op.splitext(self.dialog2img[idx][0])[0] # get the img idx from img path: get the xxx from xxx.jpg
        img_idx = self.key2index[img_key]

        features = self.get_image_features(img_idx)

        od_labels = self.get_od_labels(img_idx)

        text_b = context + od_labels

        example = self.tensorizer.tensorize_example(response, features, text_b=text_b)

        return example

    def __len__(self):
        return len(self.dialogs)

class CaptionTensorizer(object):
    def __init__(self, tokenizer, max_img_seq_length=50, max_seq_length=70,
            max_seq_a_length=40, max_seq_c_length=40, mask_prob=0.15, mask_response_prob=0.7, max_masked_tokens=3,
            is_train=True):
        """Constructor.
        Args:
            tokenizer: tokenizer for text processing.
            max_img_seq_length: max image sequence length.
            max_seq_length: max text sequence length.
            max_seq_a_length: max caption sequence length.
            is_train: train or test mode.
            mask_prob: probability to mask a input token.
            max_masked_tokens: maximum number of tokens to be masked in one sentence.
        """
        self.tokenizer = tokenizer
        self.is_train = is_train
        self.max_img_seq_len = max_img_seq_length
        self.max_seq_len = max_seq_length
        self.max_seq_a_len = max_seq_a_length
        self.max_seq_c_len = max_seq_c_length
        self.mask_prob = mask_prob
        self.mask_response_prob = mask_response_prob
        self.max_masked_tokens = max_masked_tokens
        self._triangle_mask = torch.tril(torch.ones((self.max_seq_len,
            self.max_seq_len), dtype=torch.long))

    def tensorize_example(self, text_a, img_feat, text_b=None,
            cls_token_segment_id=0, pad_token_segment_id=0,
            sequence_a_segment_id=0, sequence_b_segment_id=1, sequence_tag_segment_id=2):
        if self.is_train:
            tokens_a = self.tokenizer.tokenize(text_a)
            if len(tokens_a) > self.max_seq_a_len - 2:
                tokens_a = tokens_a[:(self.max_seq_a_len - 2)]
        else:
            # fake tokens to generate masks
            tokens_a = [self.tokenizer.mask_token] * (self.max_seq_a_len - 2)

            gth_tokens_a = self.tokenizer.tokenize(text_a)
            if len(tokens_a) > self.max_seq_a_len - 2:
                tokens_a = tokens_a[:(self.max_seq_a_len - 2)]

            if len(gth_tokens_a) > self.max_seq_a_len:
                gth_tokens_a = gth_tokens_a[:(self.max_seq_a_len)]

            padding_gth_len = self.max_seq_a_len - len(gth_tokens_a)
            gth_tokens_a += [self.tokenizer.pad_token] * padding_gth_len
            gth_ids = self.tokenizer.convert_tokens_to_ids(gth_tokens_a)
            gth_ids = torch.tensor(gth_ids, dtype=torch.long)

        tokens = [self.tokenizer.cls_token] + tokens_a + [self.tokenizer.sep_token]
        segment_ids = [cls_token_segment_id] + [sequence_a_segment_id] * (len(tokens) - 1)
        seq_a_len = len(tokens)
        if text_b:
            # pad text_a to keep it in fixed length for better inference.
            padding_a_len = self.max_seq_a_len - seq_a_len
            tokens += [self.tokenizer.pad_token] * padding_a_len
            segment_ids += ([pad_token_segment_id] * padding_a_len)

            tokens_b = self.tokenizer.tokenize(text_b)
            if len(tokens_b) > self.max_seq_len - len(tokens) - 1:
                tokens_b = tokens_b[: (self.max_seq_len - len(tokens) - 1)]
            tokens += tokens_b + [self.tokenizer.sep_token]

            # tag_start = [i for i,x in enumerate(tokens) if x=="[SEP]"][-2]
            tmp_idx = [i for i,x in enumerate(tokens) if x=="[TAG]"]
            if len(tmp_idx) is not 0:
                tag_start = tmp_idx[-1]
                tokens[tag_start] = "[SEP]"
                tag_end = (tag_start + total_num_boxes) if (tag_start + total_num_boxes) < (self.max_seq_len-1) else (self.max_seq_len-1)
            else: # hacked
                # tag_start = (self.max_seq_len -1 ) -1
                tag_start = (len(tokens) -1 ) -5
                tag_end = tag_start + 1

            segment_ids += [sequence_b_segment_id] * (len(tokens_b) - total_num_boxes)
            segment_ids += [sequence_tag_segment_id] * (total_num_boxes + 1)

        seq_len = len(tokens)
        if self.is_train:

            masked_pos = torch.zeros(self.max_seq_len, dtype=torch.int)
            masked_tag_pos = torch.zeros(self.max_seq_len, dtype=torch.int)

        #-----------------------------mask response part-----------------------------

            # randomly mask words for prediction, ignore [CLS]
            candidate_masked_idx = list(range(1, seq_a_len)) # only mask text_a
            random.shuffle(candidate_masked_idx)
            num_masked = min(max(round(self.mask_response_prob * seq_a_len), 1), self.max_masked_tokens)
            num_masked = int(num_masked)
            masked_idx = candidate_masked_idx[:num_masked]
            masked_idx = sorted(masked_idx)
            masked_token = [tokens[i] for i in masked_idx]
            for pos in masked_idx:
                if random.random() <= 0.8:
                    # 80% chance to be a ['MASK'] token
                    tokens[pos] = self.tokenizer.mask_token
                elif random.random() <= 0.5:
                    # 10% chance to be a random word ((1-0.8)*0.5)
                    from random import randint
                    i = randint(0, len(self.tokenizer.vocab))
                    self.tokenizer._convert_id_to_token(i)
                    tokens[pos] = self.tokenizer._convert_id_to_token(i)
                else:
                    # 10% chance to remain the same (1-0.8-0.1)
                    pass

            masked_pos[masked_idx] = 1
            # # pad masked tokens to the same length
            # if num_masked < self.max_masked_tokens:
            #     masked_token = masked_token + ([self.tokenizer.pad_token] *
            #             (self.max_masked_tokens - num_masked))
            # masked_ids = self.tokenizer.convert_tokens_to_ids(masked_token)

        #-----------------------------mask context part-----------------------------
        # else:
            candidate_masked_idx_text_b = list(range(self.max_seq_a_len, tag_start )) #   mask context
            random.shuffle(candidate_masked_idx_text_b)
            num_masked_tb = min(max(round(self.mask_prob * (tag_start - self.max_seq_a_len)), 1), self.max_masked_tokens)
            num_masked_tb = int(num_masked_tb)
            masked_idx_tb = candidate_masked_idx_text_b[:num_masked_tb]
            masked_idx_tb = sorted(masked_idx_tb)
            masked_token_tb = [tokens[i] for i in masked_idx_tb]
            for pos in masked_idx_tb:
                if random.random() <= 0.8:
                    # 80% chance to be a ['MASK'] token
                    tokens[pos] = self.tokenizer.mask_token
                elif random.random() <= 0.5:
                    # 10% chance to be a random word ((1-0.8)*0.5)
                    from random import randint
                    i = randint(0, len(self.tokenizer.vocab))
                    self.tokenizer._convert_id_to_token(i)
                    tokens[pos] = self.tokenizer._convert_id_to_token(i)
                else:
                    # 10% chance to remain the same (1-0.8-0.1)
                    pass

            #  MRM with MLM in the same time
            masked_pos[masked_idx_tb] = 1
            # pad masked tokens to the same length
            total_num_masked = (num_masked  + num_masked_tb)
            if total_num_masked < self.max_masked_tokens:
                masked_token = masked_token  + masked_token_tb + ([self.tokenizer.pad_token] *
                        (self.max_masked_tokens - total_num_masked))
            masked_ids = self.tokenizer.convert_tokens_to_ids(masked_token)

            #-----------------------------mask object tag  part-----------------------------
        # else:
            candidate_masked_idx_tag = list(range(tag_start, tag_end )) #   mask text_b
            candidate_masked_idx_tag = [ min(i,len(tokens)-1) for i in candidate_masked_idx_tag]
            random.shuffle(candidate_masked_idx_tag)
            num_masked_tag = min(max(round(self.mask_prob * (tag_end - tag_start)), 1), self.max_masked_tokens)
            num_masked_tag = int(num_masked_tag)
            masked_idx_tag = candidate_masked_idx_tag[:num_masked_tag]
            masked_idx_tag = sorted(masked_idx_tag)
            masked_token_tag = [tokens[i] for i in masked_idx_tag]
            for pos in masked_idx_tag:
                if random.random() <= 0.8:
                    # 80% chance to be a ['MASK'] token
                    tokens[pos] = self.tokenizer.mask_token
                elif random.random() <= 0.5:
                    # 10% chance to be a random word ((1-0.8)*0.5)
                    from random import randint
                    i = randint(0, len(self.tokenizer.vocab))
                    self.tokenizer._convert_id_to_token(i)
                    tokens[pos] = self.tokenizer._convert_id_to_token(i)
                else:
                    # 10% chance to remain the same (1-0.8-0.1)
                    pass

            # way1: if conditioned Masked LM
            masked_tag_pos[masked_idx_tag] = 1
            # pad masked tokens to the same length
            if num_masked_tag < self.max_masked_tokens:
                masked_tag_token = masked_token_tag + ([self.tokenizer.pad_token] *
                        (self.max_masked_tokens - num_masked_tag))
            masked_tag_ids = self.tokenizer.convert_tokens_to_ids(masked_tag_token)

        else:
            masked_pos = torch.ones(self.max_seq_len, dtype=torch.int)

        # pad on the right for image captioning
        padding_len = self.max_seq_len - seq_len
        tokens = tokens + ([self.tokenizer.pad_token] * padding_len)
        segment_ids += ([pad_token_segment_id] * padding_len)
        input_ids = self.tokenizer.convert_tokens_to_ids(tokens)

        # image features
        img_len = img_feat.shape[0]
        if img_len > self.max_img_seq_len:
            img_feat = img_feat[0 : self.max_img_seq_len, ]
            img_len = img_feat.shape[0]
        else:
            padding_matrix = torch.zeros((self.max_img_seq_len - img_len,
                                          img_feat.shape[1]))
            img_feat = torch.cat((img_feat, padding_matrix), 0)

        # prepare attention mask:
        # note that there is no attention from caption to image
        # because otherwise it will violate the triangle attention
        # for caption as caption will have full attention on image.
        max_len = self.max_seq_len + self.max_img_seq_len
        attention_mask = torch.zeros((max_len, max_len), dtype=torch.long)
        # C: caption, L: label, R: image region
        c_start, c_end = 0, seq_a_len
        l_start, l_end = self.max_seq_a_len, seq_len
        r_start, r_end = self.max_seq_len, self.max_seq_len + img_len
        # triangle mask for caption to caption C-C
        attention_mask[c_start : c_end, c_start : c_end].copy_(self._triangle_mask[0 : seq_a_len, 0 : seq_a_len])
        # full attention for L-L, R-R
        attention_mask[l_start : l_end, l_start : l_end] = 1
        attention_mask[r_start : r_end, r_start : r_end] = 1
        # full attention for C-L, C-R
        attention_mask[c_start : c_end, l_start : l_end] = 1
        attention_mask[c_start : c_end, r_start : r_end] = 1
        # full attention for L-R, R-L:
        attention_mask[l_start : l_end, r_start : r_end] = 1
        attention_mask[r_start : r_end, l_start : l_end] = 1
        # no attention for R-C, L-C

        input_ids = torch.tensor(input_ids, dtype=torch.long)
        segment_ids = torch.tensor(segment_ids, dtype=torch.long)

        # used for get tag position
        tag_pos = torch.zeros(self.max_seq_len, dtype=torch.int)
        tag_idx = list(range( tag_start,  tag_end))
        tag_pos[tag_idx] = 1

        if self.is_train:
            masked_ids = torch.tensor(masked_ids, dtype=torch.long)
            masked_tag_ids = torch.tensor(masked_tag_ids, dtype=torch.long)
            return (input_ids, attention_mask, segment_ids, img_feat, masked_pos, masked_ids, tag_pos, masked_tag_pos, masked_tag_ids)
        return (input_ids, attention_mask, segment_ids, img_feat, masked_pos, gth_ids)

def build_dataset(yaml_file, tokenizer, args, is_train=True):
    if not op.isfile(yaml_file):
        yaml_file = op.join(args.data_dir, yaml_file)
        assert op.isfile(yaml_file)

    if is_train:
        return CaptionTSVDataset(yaml_file, tokenizer=tokenizer,
            add_od_labels=args.add_od_labels, max_img_seq_length=args.max_img_seq_length,
            max_seq_length=args.max_seq_length, max_seq_a_length=args.max_seq_a_length,max_seq_c_length=args.max_seq_c_length,
            is_train=True, mask_prob=args.mask_prob, mask_response_prob=args.mask_response_prob, max_masked_tokens=args.max_masked_tokens)
    if args.use_cbs:
        dataset_class = CaptionTSVDatasetWithConstraints
    else:
        dataset_class = CaptionTSVDataset
    return dataset_class(yaml_file, tokenizer=tokenizer,
            add_od_labels=args.add_od_labels, max_img_seq_length=args.max_img_seq_length,
            max_seq_length=args.max_seq_length, max_seq_a_length=args.max_gen_length,
            is_train=False)

def save_checkpoint(model, tokenizer, args, epoch, global_step):
    checkpoint_dir = op.join(args.output_dir, 'checkpoint-{}-{}'.format(
        epoch, global_step))
    mkdir(checkpoint_dir)
    model_to_save = model.module if hasattr(model, 'module') else model
    save_num = 0
    while (save_num < 10):
        try:
            model_to_save.save_pretrained(checkpoint_dir)
            torch.save(args, op.join(checkpoint_dir, 'training_args.bin'))
            tokenizer.save_pretrained(checkpoint_dir)
            logger.info("Save checkpoint to {}".format(checkpoint_dir))
            break
        except:
            save_num += 1
    if save_num == 10:
        logger.info("Failed to save checkpoint after 10 trails.")
    return checkpoint_dir

def compute_score_with_logits(logits, labels):
    logits = torch.max(logits, -1)[1].data # argmax
    scores = logits == labels
    return scores

def train(args, train_dataset, val_dataset, test_dataset, model, tokenizer):
    args.train_batch_size = args.per_gpu_train_batch_size * max(1, args.n_gpu)
    train_sampler = RandomSampler(train_dataset)
    train_dataloader = DataLoader(train_dataset, sampler=train_sampler,
            batch_size=args.train_batch_size, num_workers=args.num_workers)

    if args.max_steps > 0:
        t_total = args.max_steps
        args.num_train_epochs = args.max_steps // (len(train_dataloader) // \
                args.gradient_accumulation_steps) + 1
    else:
        t_total = len(train_dataloader) // args.gradient_accumulation_steps \
                * args.num_train_epochs

    # Prepare optimizer and scheduler
    no_decay = ['bias', 'LayerNorm.weight']
    grouped_parameters = [
        {'params': [p for n, p in model.named_parameters() if not \
            any(nd in n for nd in no_decay)], 'weight_decay': args.weight_decay},
        {'params': [p for n, p in model.named_parameters() if \
            any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
    ]
    optimizer = AdamW(grouped_parameters, lr=args.learning_rate, eps=args.adam_epsilon)
    if args.scheduler == "constant":
        scheduler = WarmupConstantSchedule(
                optimizer, warmup_steps=args.warmup_steps)
    elif args.scheduler == "linear":
        scheduler = WarmupLinearSchedule(
                optimizer, warmup_steps=args.warmup_steps, t_total=t_total)
    else:
        raise ValueError("Unknown scheduler type: {}".format(args.scheduler))

    if args.n_gpu > 1:
        model = torch.nn.DataParallel(model)

    logger.info("***** Running training *****")
    logger.info("  Num examples = %d", len(train_dataset))
    logger.info("  Num Epochs = %d", args.num_train_epochs)
    logger.info("  Batch size per GPU = %d", args.per_gpu_train_batch_size)
    logger.info("  Total train batch size (w. parallel, & accumulation) = %d",
                   args.train_batch_size * args.gradient_accumulation_steps)
    logger.info("  Gradient Accumulation steps = %d", args.gradient_accumulation_steps)
    logger.info("  Total optimization steps = %d", t_total)

    if args.scst:
        scst_criterion = ScstRewardCriterion()
        logger.info("  SCST training...")

    global_step, global_loss, global_acc =0,  0.0, 0.0
    global_tag_loss, global_tag_acc = 0.0, 0.0
    masked_global_loss, masked_global_acc =  0.0, 0.0
    # lm_global_loss, lm_global_acc =  0.0, 0.0
    model.zero_grad()
    eval_log = []
    eval_testset_log = []
    best_Bleu_1 = 0
    best_Bleu_2 = 0
    best_Bleu_3 = 0
    best_Bleu_4 = 0
    best_ROUGE_L = 0
    best_METEOR = 0
    best_SPICE = 0

    for epoch in range(int(args.num_train_epochs)):
        # for step, (img_keys, batch) in enumerate(train_dataloader):
        for step, ( batch) in enumerate(train_dataloader):
            batch = tuple(t.to(args.device) for t in batch)

            if not args.scst:
                model.train()
                inputs = {'input_ids': batch[0], 'attention_mask': batch[1],
                    'token_type_ids': batch[2], 'img_feats': batch[3],
                    'masked_pos': batch[4], 'masked_ids': batch[5], 'tag_pos': batch[6],'masked_tag_pos': batch[7], 'masked_tag_ids': batch[8]
                    # 'masked_pos': batch[4], 'masked_ids': batch[5] , 'response_pos': batch[6], 'response_ids': batch[7]
                }

                outputs = model(**inputs)
                masked_loss, masked_logits, MTP_loss, tag_logits, tag_ids = outputs[:5]
                loss = masked_loss + MTP_loss
                masked_ids = inputs['masked_ids']
                masked_ids = masked_ids[masked_ids != 0]
                batch_score = compute_score_with_logits(masked_logits, masked_ids)
                batch_acc = torch.sum(batch_score.float()) / torch.sum(inputs['masked_pos'])
                batch_tag_score = compute_score_with_logits(tag_logits, tag_ids)
                batch_tag_acc = torch.sum(batch_tag_score.float()) / torch.sum(inputs['masked_tag_pos'])

            if args.n_gpu > 1:
                loss = loss.mean() # mean() to average on multi-gpu parallel training
                masked_loss = masked_loss.mean() # mean() to average on multi-gpu parallel training
                MTP_loss = MTP_loss.mean() # mean() to average on multi-gpu parallel training
            if args.gradient_accumulation_steps > 1:
                loss = loss / args.gradient_accumulation_steps
            loss.backward()
            torch.nn.utils.clip_grad_norm_(model.parameters(), args.max_grad_norm)
            global_loss += loss.item()
            global_acc += batch_acc
            global_tag_loss += MTP_loss.item()
            global_tag_acc += batch_tag_acc
            masked_global_loss += masked_loss.item()
            masked_global_acc += batch_acc
            if (step + 1) % args.gradient_accumulation_steps == 0:
                global_step += 1
                scheduler.step()
                optimizer.step()
                model.zero_grad()
                if global_step % args.logging_steps == 0:
                    logger.info("Epoch: {}, global_step: {}, lr: {:.6f}, loss: {:.4f} ({:.4f}), MTM loss: {:.4f} ({:.4f}), MLM(MRM+MCM) loss: {:.4f} ({:.4f}), " \
                        "MLM(MRM+MCM) score: {:.4f} ({:.4f}), MTM score: {:.4f} ({:.4f})".format(epoch, global_step,
                        optimizer.param_groups[0]["lr"], loss, global_loss / global_step, MTP_loss, global_tag_loss / global_step, masked_loss, masked_global_loss / global_step,
                        batch_acc, global_acc / global_step, batch_tag_acc, global_tag_acc / global_step)
                    )

                if (args.save_steps > 0 and global_step % args.save_steps == 0) or \
                        global_step == t_total:
                    checkpoint_dir = save_checkpoint(model, tokenizer, args, epoch, global_step)
                    # evaluation
                    if args.evaluate_during_training:
                        logger.info("Perform evaluation at step: %d" % (global_step))
                        evaluate_file = evaluate(args, val_dataset, model, tokenizer,
                                checkpoint_dir)
                        with open(evaluate_file, 'r') as f:
                            res = json.load(f)
                        best_Bleu_1 = max(best_Bleu_1, res['Bleu_1'])
                        best_Bleu_2 = max(best_Bleu_2, res['Bleu_2'])
                        best_Bleu_3 = max(best_Bleu_3, res['Bleu_3'])
                        best_Bleu_4 = max(best_Bleu_4, res['Bleu_4'])
                        best_ROUGE_L = max(best_ROUGE_L, res['ROUGE_L'])
                        best_METEOR = max(best_METEOR, res['METEOR'])
                        best_SPICE = max(best_SPICE, res['SPICE'])
                        res['epoch'] = epoch
                        res['global_step'] = step
                        res['best_Bleu_1'] = best_Bleu_1
                        res['best_Bleu_2'] = best_Bleu_2
                        res['best_Bleu_3'] = best_Bleu_3
                        res['best_Bleu_4'] = best_Bleu_4
                        res['best_ROUGE_L'] = best_ROUGE_L
                        res['best_METEOR'] = best_METEOR
                        res['best_SPICE'] = best_SPICE
                        eval_log.append(res)
                        with open(args.output_dir + '/eval_logs.json', 'w') as f:
                            json.dump(eval_log, f)
                    if args.evaluate_testset_during_training:
                        logger.info("Perform evaluation testset at step: %d" % (global_step))
                        evaluate_file = evaluate(args, test_dataset, model, tokenizer,
                                checkpoint_dir)
                        with open(evaluate_file, 'r') as f:
                            res = json.load(f)
                        best_Bleu_1 = max(best_Bleu_1, res['Bleu_1'])
                        best_Bleu_2 = max(best_Bleu_2, res['Bleu_2'])
                        best_Bleu_3 = max(best_Bleu_3, res['Bleu_3'])
                        best_Bleu_4 = max(best_Bleu_4, res['Bleu_4'])
                        best_ROUGE_L = max(best_ROUGE_L, res['ROUGE_L'])
                        best_METEOR = max(best_METEOR, res['METEOR'])
                        best_SPICE = max(best_SPICE, res['SPICE'])
                        res['epoch'] = epoch
                        res['global_step'] = step
                        res['best_Bleu_1'] = best_Bleu_1
                        res['best_Bleu_2'] = best_Bleu_2
                        res['best_Bleu_3'] = best_Bleu_3
                        res['best_Bleu_4'] = best_Bleu_4
                        res['best_ROUGE_L'] = best_ROUGE_L
                        res['best_METEOR'] = best_METEOR
                        res['best_SPICE'] = best_SPICE

                        eval_testset_log.append(res)
                        with open(args.output_dir + '/eval_testset_logs.json', 'w') as f:
                            json.dump(eval_testset_log, f)
    return global_step, global_loss / global_step

def scst_train_iter(args, train_dataset, model, scst_criterion, img_keys, batch, tokenizer):
    cls_token_id, sep_token_id, pad_token_id, mask_token_id = tokenizer.convert_tokens_to_ids(
            [tokenizer.cls_token, tokenizer.sep_token, tokenizer.pad_token,
                tokenizer.mask_token]
            )
    inputs = {'is_decode': True,
        'input_ids': batch[0], 'attention_mask': batch[1],
        'token_type_ids': batch[2], 'img_feats': batch[3],
        'masked_pos': batch[4],
        'do_sample': False,
        'bos_token_id': cls_token_id,
        'pad_token_id': pad_token_id,
        'eos_token_ids': [sep_token_id, pad_token_id],
        'mask_token_id': mask_token_id,
        # for adding od labels
        'add_od_labels': args.add_od_labels, 'od_labels_start_posid': args.max_seq_a_length,

        # hyperparameters of beam search
        'max_length': args.max_seq_a_length,
        'num_beams': 1,
        "temperature": args.temperature,
        "top_k": args.top_k,
        "top_p": args.top_p,
        "repetition_penalty": args.repetition_penalty,
        "length_penalty": args.length_penalty,
        "num_return_sequences": 1,
        "num_keep_best": 1,
    }

    model.eval()
    with torch.no_grad():
        greedy_res_raw, _ = model(**inputs)
        greedy_res_raw.squeeze_(1)  # batch_size * max_len

    model.train()
    inputs['do_sample'] = True
    sample_res_raw, sample_logprobs = model(**inputs)
    sample_res_raw.squeeze_(1)
    sample_logprobs.squeeze_(1)
    assert sample_logprobs.requires_grad == True
    assert sample_res_raw.requires_grad == False

    def _ids_to_captions(all_ids):
        captions = []
        for ids in all_ids:
            c = tokenizer.decode(ids.tolist(), skip_special_tokens=True)
            captions.append(c)
        return captions

    greedy_res = _ids_to_captions(greedy_res_raw)
    sample_res = _ids_to_captions(sample_res_raw)
    gt_res = [train_dataset.get_captions_by_key(k) for k in img_keys]

    loss = scst_criterion(gt_res, greedy_res, sample_res, sample_logprobs)
    return loss

def get_predict_file(output_dir, yaml_file, args):
    cc = ['pred']
    # make sure it works with/without / in end of the path.
    data = op.basename(op.join(args.data_dir, '')[:-1])
    split = op.basename(yaml_file)
    assert split.endswith('.yaml')
    split = split[:-5]
    cc.append(data)
    cc.append(split)
    cc.append('beam{}'.format(args.num_beams))
    cc.append('sample{}'.format(args.do_sample))
    cc.append('top_p{}'.format(args.top_p))
    cc.append('top_k{}'.format(args.top_k))
    cc.append('temperature{}'.format(args.temperature))
    cc.append('repetition_penalty{}'.format(args.repetition_penalty))
    cc.append('max{}'.format(args.max_gen_length))
    if args.add_od_labels:
        cc.append('odlabels')
    if args.num_keep_best != 1:
        cc.append('best{}'.format(args.num_keep_best))
    if args.use_cbs:
        cc.append('cbs{}'.format(args.min_constraints_to_satisfy))
    if args.output_hidden_states:
        cc.append('hidden')
    return op.join(output_dir, '{}.tsv'.format('.'.join(cc)))

def get_evaluate_file(predict_file):
    assert predict_file.endswith('.tsv')
    fpath = op.splitext(predict_file)[0]
    return fpath + '.eval.json'

def get_evaluate_method(predict_file):
    if 'nocaps' in op.basename(predict_file):
        return 'nocaps'
    else:
        return 'coco'

def evaluate(args, val_dataset, model, tokenizer, output_dir):
    assert op.isdir(output_dir)
    predict_file = get_predict_file(output_dir, val_dataset.yaml_file, args)
    if op.isfile(predict_file):
        logger.info('Skip predict. {} already exists'.format(predict_file))
    else:
        test(args, val_dataset, model, tokenizer, predict_file)

    evaluate_file = get_evaluate_file(predict_file)
    if op.isfile(evaluate_file):
        logger.info('Skip evaluation. {} already exists'.format(evaluate_file))
        return evaluate_file

    eval_method = get_evaluate_method(predict_file)
    if eval_method == 'coco':
        # gt_file = val_dataset.get_caption_file_in_coco_format()
        # result = evaluate_on_coco_caption(predict_file, gt_file, outfile=evaluate_file)

        gt_file = val_dataset.get_dialog_file()
        result = evaluate_on_reddit_caption(predict_file, gt_file, outfile=evaluate_file)
        #for evaluating the DialoGPT result
        # result = evaluate_on_reddit_caption(predict_file+'.txt', gt_file, outfile=evaluate_file)
    else:
        split = 'val' if 'val' in op.basename(val_dataset.yaml_file) else 'test'
        result = evaluate_on_nocaps(split, predict_file,
                    data_dir=args.data_dir, evaluate_file=evaluate_file)
    logger.info("evaluation result: {}".format(str(result)))
    return evaluate_file

def test(args, test_dataset, model, tokenizer, predict_file):
    args.test_batch_size = args.per_gpu_eval_batch_size * max(1, args.n_gpu)
    test_sampler = SequentialSampler(test_dataset)
    cache_file = predict_file

    test_dataloader = DataLoader(test_dataset, sampler=test_sampler,
            batch_size=args.test_batch_size, num_workers=args.num_workers)

    cls_token_id, sep_token_id, pad_token_id, mask_token_id, period_token_id = \
        tokenizer.convert_tokens_to_ids( [tokenizer.cls_token,
            tokenizer.sep_token, tokenizer.pad_token, tokenizer.mask_token, '.']
        )
    model.eval()

    def gen_rows():
        time_meter = 0

        with torch.no_grad():

            for step, batch in tqdm(enumerate(test_dataloader), ncols=100,desc="Testing Forward: ", total=len(test_dataloader)):

                batch = tuple(t.to(args.device) for t in batch)
                inputs = {'is_decode': True,
                    'input_ids': batch[0], 'attention_mask': batch[1],
                    'token_type_ids': batch[2], 'img_feats': batch[3],
                    'masked_pos': batch[4],
                    'gth_ids': batch[5],
                    'do_sample': args.do_sample,
                    'bos_token_id': cls_token_id,
                    'pad_token_id': pad_token_id,
                    # 'eos_token_ids': [sep_token_id, pad_token_id, period_token_id],
                    'eos_token_ids': [sep_token_id, pad_token_id],
                    'mask_token_id': mask_token_id,
                    # for adding od labels
                    'add_od_labels': args.add_od_labels, 'od_labels_start_posid': args.max_seq_a_length,

                    # hyperparameters of beam search
                    'max_length': args.max_gen_length,
                    'num_beams': args.num_beams,
                    "temperature": args.temperature,
                    "top_k": args.top_k,
                    "top_p": args.top_p,
                    "repetition_penalty": args.repetition_penalty,
                    "length_penalty": args.length_penalty,
                    "num_return_sequences": args.num_return_sequences,
                    "num_keep_best": args.num_keep_best,
                }
                if args.use_cbs:
                    inputs.update({'use_cbs': True,
                        'fsm': batch[5],
                        'num_constraints': batch[6],
                        'min_constraints_to_satisfy': args.min_constraints_to_satisfy,
                    })
                tic = time.time()
                # captions, logprobs
                outputs = model(**inputs)
                time_meter += time.time() - tic
                all_caps = outputs[0]  # [batch_size, num_keep_best, max_len]
                all_confs = torch.exp(outputs[1])

                for  caps, confs in zip( all_caps, all_confs):
                    res = []
                    for cap, conf in zip(caps, confs):
                        cap = tokenizer.decode(cap.tolist(), skip_special_tokens=True)

                        cap = cap.split('.')[0]
                        res.append({'response': cap, 'conf': conf.item()})

                    # yield json.dumps(res)
                    yield res
                    # return res

        logger.info("Inference model computing time: {} seconds per batch".format(time_meter / (step+1)))

    tsv_writer(gen_rows(), cache_file)

    return predict_file

def restore_training_settings(args):
    assert not args.do_train
    assert args.do_test or args.do_eval
    # restore training settings, check hasattr for backward compatibility
    train_args = torch.load(op.join(args.eval_model_dir, 'training_args.bin'))
    if hasattr(train_args, 'max_seq_a_length'):
        max_od_labels_len = train_args.max_seq_length - train_args.max_seq_a_length
        max_seq_length = args.max_gen_length + max_od_labels_len
        args.max_seq_length = max_seq_length
        logger.warning('Override max_seq_length to {} = max_gen_length:{} + od_labels_len:{}'.format(
                max_seq_length, args.max_gen_length, max_od_labels_len))

    override_params = ['max_seq_a_length', 'do_lower_case', 'add_od_labels',
            'max_img_seq_length', 'img_feature_dim',
            'img_feature_type']
    for param in override_params:
        if hasattr(train_args, param):
            train_v = getattr(train_args, param)
            test_v = getattr(args, param)
            if train_v != test_v:
                logger.warning('Override {} with train args: {} -> {}'.format(param,
                    test_v, train_v))
                setattr(args, param, train_v)
    return args

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--data_dir", default='/data/data_for_oscar/reddit_oi', type=str, required=False,
                        help="The input data dir with all required files.")
    parser.add_argument("--tag_vocab_file", default='/data/data_for_oscar/reddit_oi/objects_vocab.txt', type=str, required=False,
                        help="The files for saving the tag vocabulary.")
    parser.add_argument("--train_yaml", default='train.yaml', type=str, required=False,
                        help="yaml file for training.")
    parser.add_argument("--test_yaml", default='test.yaml', type=str, required=False,
                        help="yaml file for testing.")
    parser.add_argument("--val_yaml", default='val.yaml', type=str, required=False,
                        help="yaml file used for validation during training.")
    parser.add_argument("--model_name_or_path", default=None, type=str, required=False,
                        help="Path to pre-trained model or model type.")
    parser.add_argument("--output_dir", default='output/', type=str, required=False,
                        help="The output directory to save checkpoint and test results.")
    parser.add_argument("--loss_type", default='sfmx', type=str,
                        help="Loss function types: support kl, x2, sfmx")
    parser.add_argument("--config_name", default="", type=str,
                        help="Pretrained config name or path if not the same as model_name.")
    parser.add_argument("--tokenizer_name", default="", type=str,
                        help="Pretrained tokenizer name or path if not the same as model_name.")
    parser.add_argument("--max_seq_length", default=120, type=int,
                        help="The maximum total input sequence length after tokenization. "
                             "Sequences longer than this will be truncated, "
                             "sequences shorter will be padded.")
    parser.add_argument("--max_seq_a_length", default=40, type=int,
                        help="The maximum sequence length for caption.")
    parser.add_argument("--max_seq_c_length", default=80, type=int, #dump, useless args now
                        help="The maximum sequence length for dialog context.")
    parser.add_argument("--do_train", action='store_true', help="Whether to run training.")
    parser.add_argument("--do_sample", action='store_true', help="Whether to do sampling.")
    parser.add_argument("--do_test", action='store_true', help="Whether to run inference.")
    parser.add_argument("--do_eval", action='store_true', help="Whether to run evaluation.")
    parser.add_argument("--do_lower_case", action='store_true',
                        help="Set this flag if you are using an uncased model.")
    parser.add_argument("--mask_prob", default=0.15, type=float,
                        help= "Probability to mask input sentence during training.")
    parser.add_argument("--mask_response_prob", default=0.7, type=float,
                        help= "Probability to mask input sentence during training.")
    parser.add_argument("--max_masked_tokens", type=int, default=300,
                        help="The max number of masked tokens per sentence.")
    parser.add_argument("--add_od_labels", default=False, action='store_true',
                        help="Whether to add object detection labels or not")
    parser.add_argument("--drop_out", default=0.1, type=float, help="Drop out in BERT.")
    parser.add_argument("--max_img_seq_length", default=50, type=int,
                        help="The maximum total input image sequence length.")
    parser.add_argument("--img_feature_dim", default=2048, type=int,
                        help="The Image Feature Dimension.")
    parser.add_argument("--type_vocab_size", default=3, type=int,
                        help="segment embedding vocabulary size.")
    parser.add_argument("--img_feature_type", default='frcnn', type=str,
                        help="Image feature type.")
    parser.add_argument("--per_gpu_train_batch_size", default=64, type=int,
                        help="Batch size per GPU/CPU for training.")
    parser.add_argument("--per_gpu_eval_batch_size", default=6, type=int,
                        help="Batch size per GPU/CPU for evaluation.")
    parser.add_argument("--output_mode", default='classification', type=str,
                        help="output mode, support classification or regression.")
    parser.add_argument("--num_labels", default=2, type=int,
                        help="num_labels is 2 for classification and 1 for regression.")
    parser.add_argument('--gradient_accumulation_steps', type=int, default=1,
                        help="Number of updates steps to accumulate before backward.")
    parser.add_argument("--learning_rate", default=3e-5, type=float, help="The initial lr.")
    parser.add_argument("--weight_decay", default=0.05, type=float, help="Weight deay.")
    parser.add_argument("--adam_epsilon", default=1e-8, type=float, help="Epsilon for Adam.")
    parser.add_argument("--max_grad_norm", default=1.0, type=float, help="Max gradient norm.")
    parser.add_argument("--warmup_steps", default=0, type=int, help="Linear warmup.")
    parser.add_argument("--scheduler", default='linear', type=str, help="constant or linear or")
    parser.add_argument("--num_workers", default=4, type=int, help="Workers in dataloader.")
    parser.add_argument("--num_train_epochs", default=40, type=int,
                        help="Total number of training epochs to perform.")
    parser.add_argument("--max_steps", default=-1, type=int,
                        help="Total number of training steps. Override num_train_epochs.")
    parser.add_argument('--logging_steps', type=int, default=10, help="Log every X steps.")
    parser.add_argument('--save_steps', type=int, default=-1,
                        help="Save checkpoint every X steps. Will also perform evaluatin.")
    parser.add_argument("--evaluate_during_training", action='store_true',
                        help="Run evaluation during training at each save_steps.")
    parser.add_argument("--evaluate_testset_during_training", action='store_true',
                        help="Run evaluation testset during training at each save_steps.")
    parser.add_argument("--no_cuda", action='store_true', help="Avoid using CUDA.")
    parser.add_argument('--seed', type=int, default=88, help="random seed for initialization.")
    parser.add_argument('--scst', action='store_true', help='Self-critical sequence training')
    # for generation
    parser.add_argument("--eval_model_dir", type=str, default='',
                        help="Model directory for evaluation.")
    parser.add_argument('--max_gen_length', type=int, default=40,
                        help="max length of generated sentences")
    parser.add_argument('--output_hidden_states', action='store_true',
                        help="Turn on for fast decoding")
    parser.add_argument('--num_return_sequences', type=int, default=1,
                        help="repeating times per image")
    parser.add_argument('--num_beams', type=int, default=5, help="beam search width")
    parser.add_argument('--num_keep_best', type=int, default=1,
                        help="number of hypotheses to keep in beam search")
    parser.add_argument('--temperature', type=float, default=1,
                        help="temperature in softmax for sampling")
    parser.add_argument('--top_k', type=int, default=0,
                        help="filter distribution for sampling")
    parser.add_argument('--top_p', type=float, default=1,
                        help="filter distribution for sampling")
    parser.add_argument('--repetition_penalty', type=int, default=3,
                        help="repetition penalty from CTRL paper (https://arxiv.org/abs/1909.05858)")
    parser.add_argument('--length_penalty', type=float, default=0.3,#1,
                        help="beam search length penalty")
    # for Constrained Beam Search
    parser.add_argument('--use_cbs', action='store_true',
                        help='Use constrained beam search for decoding')
    parser.add_argument('--min_constraints_to_satisfy', type=int, default=2,
                        help="minimum number of constraints to satisfy")
    args = parser.parse_args()

    global logger

    args.device = torch.device("cuda" if torch.cuda.is_available() and not args.no_cuda else "cpu")
    args.n_gpu = torch.cuda.device_count()

    output_dir = args.output_dir
    mkdir(output_dir)

    logger = setup_logger("vlpretrain", output_dir, 0)
    logger.warning("Device: %s, n_gpu: %s", args.device, args.n_gpu)
    set_seed(args.seed, args.n_gpu)

    # Load pretrained model and tokenizer
    config_class, model_class, tokenizer_class = BertConfig, BertForMultiModalDialog, BertTokenizer
    if args.do_train:
        assert args.model_name_or_path is not None
        config = config_class.from_pretrained(args.config_name if args.config_name else \
                args.model_name_or_path, num_labels=args.num_labels, finetuning_task='image_captioning')
        if args.scst:
            # avoid using too much memory
            config.output_hidden_states = True
        tokenizer = tokenizer_class.from_pretrained(args.tokenizer_name if args.tokenizer_name \
                else args.model_name_or_path, do_lower_case=args.do_lower_case)
        #---------------add by Jokie for add object tags to the vocab ------------------------
        config.img_feature_dim = args.img_feature_dim
        config.img_feature_type = args.img_feature_type
        config.hidden_dropout_prob = args.drop_out
        config.loss_type = args.loss_type
        config.type_vocab_size = args.type_vocab_size
        model = model_class.from_pretrained(args.model_name_or_path,
                from_tf=bool('.ckpt' in args.model_name_or_path), config=config)
        print(args.train_yaml)

        TAGS_TOKENS_LIST = [line.decode().rstrip('\n').split(',')[0] for line in open(args.tag_vocab_file,'rb')]
        print('len(TAGS_TOKENS_LIST):', len(TAGS_TOKENS_LIST))
        num_add_tokens = tokenizer.add_tokens(TAGS_TOKENS_LIST)
        SPECIAL_TOKENS = ['[TAG]']
        SPECIAL_TOKENS_DICT = {'additional_special_tokens':'[TAG]'}
        num_add_sep_tokens = tokenizer.add_special_tokens(SPECIAL_TOKENS_DICT)
        print('num_add_tokens:', num_add_tokens)
        print('num_add_sep_tokens:', num_add_sep_tokens)
        print('num_tokens:', len(tokenizer))
        model.resize_token_embeddings(len(tokenizer))
        model.bert._resize_token_embeddings(len(tokenizer))
        bert_embedding_weight = model.bert.embeddings.word_embeddings.weight
        print('after resized decoder_shape: ', bert_embedding_weight.size(1))
        print('after resized decoder_shape1: ', bert_embedding_weight.size(0))
        model.decoder = nn.Linear(bert_embedding_weight.size(1),
                            bert_embedding_weight.size(0), bias=False)
        model.vocab_size = bert_embedding_weight.size(0)

    else:
        checkpoint = args.eval_model_dir
        assert op.isdir(checkpoint)
        config = config_class.from_pretrained(checkpoint)
        config.output_hidden_states = args.output_hidden_states
        tokenizer = tokenizer_class.from_pretrained(checkpoint)
        logger.info("Evaluate the following checkpoint: %s", checkpoint)
        model = model_class.from_pretrained(checkpoint, config=config)
        print('num_tokens for decoding when testing:', len(tokenizer))

    model.to(args.device)
    logger.info("Training/evaluation parameters %s", args)
    if args.do_train:
        train_dataset = build_dataset(op.join(args.data_dir, args.train_yaml), tokenizer, args)
        val_dataset = build_dataset(op.join(args.data_dir, args.val_yaml),
                tokenizer, args, is_train=False)
        test_dataset = build_dataset(op.join(args.data_dir, args.test_yaml),
                tokenizer, args, is_train=False)
        global_step, avg_loss = train(args, train_dataset, val_dataset, test_dataset, model, tokenizer)
        logger.info("Training done: total_step = %s, avg loss = %s", global_step, avg_loss)

    # inference and evaluation
    if args.do_test or args.do_eval:
        args = restore_training_settings(args)
        test_dataset = build_dataset(op.join(args.data_dir, args.test_yaml),
                tokenizer, args, is_train=False)
        if args.n_gpu > 1:
            model = torch.nn.DataParallel(model)

        if not args.do_eval:
            predict_file = get_predict_file(checkpoint, test_dataset.yaml_file, args)
            test(args, test_dataset, model, tokenizer, predict_file)
            logger.info("Prediction results saved to: {}".format(predict_file))
        else:
            evaluate_file = evaluate(args, test_dataset, model, tokenizer,
                    checkpoint)
            logger.info("Evaluation results saved to: {}".format(evaluate_file))

if __name__ == "__main__":
    main()