# -*- coding: utf-8 -*
import difflib
import sys
import argparse
import os
import re
from method_mark import *
from htmltool import *
#from redistool import *

#result_report=result_folder+'/report/report.txt'
#ratio_file=result_folder+'/report/ratio.txt'
#diff_lines_file=result_folder+'/report/difflines.txt'
#diff_method_file=result_folder+'/report/diffmethods.txt'

#防止递归深度超过最大1000
sys.setrecursionlimit(100000)

LINE_SHIFT='~'# 换行符
SHIFT='\n'
TAB='\t'

global_removed_methods={}#相对于旧的版本移除的方法(旧的类中有的方法，新的类中没有), k=文件路径，value:[]
global_added_methods={}  #新的类中有的方法旧的类中没有
global_added_class=[] # 旧版本中缺少的文件,新增文件
global_removed_class=[]#旧版本中有的文件，新版本中删除

global_diff_class_num = 0
global_diff_method_num = 0

total_method_number=0
total_class_number=0   #总共的类

LEFT_BRACE='{'

RIGHT_BRACE='}'

# 缺陷列表: 方法体中存在接口实现类的方法，需要去掉

#(120,127), [(110,138),(120,127) ...] 很显然，(120,127) 处于 (110,138) 内部，是接口实现类的方法，需要找出来

def pickOverlapList(tplList):

    overlapList=[]

    for t in tplList:

        if pickOverlap(tplList,t):

           overlapList.append(t)

    return  overlapList

def  pickOverlap(tplList, tpl):

    found=False
    for t in tplList:

        if tpl[0] > t[0] and tpl[1] < t[1]:

            found=True
            return found

    return found

#方法体中，重复包含接口实现:/Users/source_code/dian-web/src/test/java/com/hanniu/online/test/InitDataTestCase.java
#/dian-web/src/test/java/com/hanniu/online/test/InitDataTestCase.java
#132行开始测试
# 找到和第一个{匹配的}停止读取
#返回一个Tuple (start,end)
#由方法的开始行定位方法的结束行

def getMethodRowRange(code_dic,start):

       braces=[]
       end=readLineByLine(code_dic,start,braces)

       #print('==>开始行:{},结束行:{}'.format(start,end))

       return (start,end)

#测试用
def  testFileMethodRowRange(file,start):

       braces=[] #存储{ } 位置信息，存放Tuple (char,row,flag)

       lines = read_file(file) #文件所有的行
       code_dic=getCodeDic(lines)#key:行号,value:行内容字典

       getMethodRowRange(code_dic,start)

#递归,花刮号配对算法主程
def readLineByLine(code_dic,start,braces):
    #print('==code_dic[start]:{}'.format(code_dic[start]))
    last=False

    if start > len(code_dic) :

        #print('==> 达到最大<===')

        return  start
    else:
       line=code_dic[start].strip()

       #if line.strip() == '' or line.strip().startswith('/') or line.strip().startswith('*'): #注释、为空行直接读取下一行

       #    start+=1
       #    return readLineByLine(code_dic,start,braces)
       #else:

           #print('next:{}'.format(start))

       #开始处理行
       for char in line: #一个字符一个字符地去读取

                if char == LEFT_BRACE or char == RIGHT_BRACE  : #仅当符号为{ 或者 } 时执行花刮号配对算法

                   braces=matchBrace(braces,char,start)
                   if len(braces) == 0 : # 发现花刮号的行，处理后出现集合清空的情况，说明已找到方法的最后一行

                      #print('==>找到最后一行:{}'.format(start))
                      return start

       if last:

               return start
       else :

              start+=1
              return readLineByLine(code_dic,start,braces)

# 花刮号配对算法主程
# 当前刮号如果是},判断集合中的未尾Tuple是否是{,若是，称为“配对成功",同时从集合中移除集合中的未尾Tuple元素;
# 当前刮号如果是{,创建一个新的Tuple对象，加到集合中。

def  matchBrace(braces,char,row):

     size = len(braces)
     if size == 0: #第一个{

         braces.append((char,row,0)) #生成一个Tuple，加入集合中
         return braces

     tailTuple = braces[size-1]

     if char == RIGHT_BRACE: #当前元素右刮号

        if tailTuple[0] == LEFT_BRACE: # 与未尾元素配对成功

           braces.pop(size-1) #移除未尾元素Tuple

        else: #未尾元素tailTuple[0] 为 } ,与char未配对

           braces.append((char,row,0))
     else:#当前元素左刮号

           braces.append((char,row,0))

     return braces

# 读取文件所有的行,去掉所有的注释干扰

def read_file(file_name):
    fopen = open(file_name, 'r')
    text = fopen.read()
    text=removeComments(text)
    fopen.close()
    #start测试用
    #fo = open("/Users/zhangxiao/agilean/valuekanban/python-anti-compile/scripts/test.java", "w")
    #fo.write(text)
    #fo.close()
    #end测试用
    return text.splitlines()

#不去注释读取
def read_file_with_comments(file_name):
    try:
        file_desc = open(file_name, 'r')
        # 读取后按行分割
        text = file_desc.read().splitlines()
        file_desc.close()
        return text
    except IOError as error:
        print(error)
        sys.exit()

 # 比较两个文件并把结果生成一份html文本、相似度、差异行位置

def compare_file(file1, file2,result_folder,diff_html_file):
    global global_diff_class_num
    #print ("正在比较文件{0} 和 {1}".format(file1, file2))
    ratios = {}
    differences={}
    if file1 == "" or file2 == "":
        print('文件路径不能为空：第一个文件的路径：{0}, 第二个文件的路径：{1} .'.format(file1, file2))
        sys.exit()

    fileName=getFileName(file1)
    #print("fileName:{0}".format(fileName))
    text1_lines = read_file(file1)
    text2_lines = read_file(file2)
    diff = difflib.HtmlDiff()    # 创建HtmlDiff 对象
    content = diff.make_file(text1_lines, text2_lines)  # 通过make_file 方法输出 html 格式的对比结果
    # 将结果写入到result文件中
    result=result_folder+'/'+fileName+'.html'
    try:
        with open(result, 'w') as result_file:
            result_file.write(content)
            #print("==========> Successfully Finished\n")
    except IOError as error:
        print ('写入html文件错误：{0}'.format(error))

    #相似度
    '''
    with open(ratio_file,'a') as rtfile:

        s = difflib.SequenceMatcher(None, text1_lines, text2_lines)
        radio=s.ratio()

        #rtfile.write('文件:{}与文件{}相似度:{}\n'.format(file1,file2,radio))

        ratios[file1]=str(radio)
    '''
    #比较差异行的位置

    diffs = findDiffLines(text1_lines, text2_lines)

    #html结果文件
    with open(diff_html_file,'a') as diffFile:

      if len(diffs) == 0:

        #diffFile.write('文件:{}与文件{}没有差异行号\n'.format(file1,file2))
        print('文件:{}与文件{}没有差异行号\n'.format(file1,file2))

      else:

        global_diff_class_num += 1
        count=0
        size=len(diffs)
        diff_str=''
        for df in  diffs:
            count+=1
            if count == size:
               diff_str+=str(df)
            else:
               diff_str+=str(df)+','

        differences[file1]=diff_str

      #开始写入html报告
      write_table_td(diffFile,differences)

      '''
      ths=['类名','相似度']
      write_table_th(diffFile,'类文件比较相似度',ths)
      write_table_td(diffFile,ratios)
      write_table_tail(diffFile)
      '''

def compare_methods(file1,file2,diff_html_file):

   global total_method_number
   global global_diff_method_num
   dic_class_body_1 = findClassBody(file1) # 文件file1方法体,key=file, value=class body

   dic_class_body_2 = findClassBody(file2)

   if dic_class_body_1 is None or dic_class_body_2 is None:
      print('文件:{},没有方法体\n\t'.format(file1))
      return

   dic_file_methods_1={}

   dic_file_methods_2={}

   #dic_file_methods_1:高可用的文件标记字典,key:文件路径,value: MethodMarker[]
   '''#老逻辑
   #file1
   dic_file_methods_1=findMethods(dic_class_body_1[file1],file1)

   dic_file_methods_1=injectMethodLineNumbers(file1,dic_file_methods_1)

   #file2
   dic_file_methods_2=findMethods(dic_class_body_2[file2],file2)

   dic_file_methods_2=injectMethodLineNumbers(file2,dic_file_methods_2)

   #老逻辑
   '''
   dic_file_methods_1[file1]=extremelyFindMethod(file1)
   dic_file_methods_2[file2]=extremelyFindMethod(file2)

   dic_class_body_1={} #清空对象
   dic_class_body_2={}

   #代码行字典,可以拿到任意两个整数之间的所有行，即函数体内容
   lines1 = read_file(file1) #文件所有的行
   code_dic1=getCodeDic(lines1) #文件所有的行字典，key:行号,value:行内容

   lines2 = read_file(file2)
   code_dic2=getCodeDic(lines2) #文件所有的行字典，key:行号,value:行内容

   markers1=dic_file_methods_1[file1]
   total_method_number+=len(markers1)
   markers2=dic_file_methods_2[file2]

   diff_funcs={} #函数差异字典

   with open(diff_html_file,'a') as diff_file:

       for marker1 in markers1:#旧版本
          found = False
          for marker2 in markers2:#新版本
             if marker1.method == marker2.method:
                found = True
                #不再使用start,end来比较
                content1=marker1.body
                content2=marker2.body
                if not compare_method_content(content1,content2) :
                   #print('==>difference,method=>{}, body1:{}, body2:{}'.format(marker1.method,content1,content2))
                   #diff_file.write('文件:{},方法:{}有差异\n\t'.format(file1,marker1.method))
                   diff_funcs[file1]=marker1.method
                break
          if not found:
             #print('文件:{},方法:{}在比较的文件中没有找到\n\t'.format(file1,marker1.method))
             global_removed_methods[file1]=marker1.method

       #找出新增的方法

       for marker2 in markers2:#新版本
          found = False
          for marker1 in markers1:#旧版本
             if marker1.method == marker2.method:
                found = True
                break
          if not found:

             global_added_methods[file2]=marker2.method

       #写入差异内容
       write_table_td(diff_file,diff_funcs)

       global_diff_method_num+=len(diff_funcs)#累加变更的函数

def compare_method_content(content1, content2 ):

    if content1.strip() == content2.strip() :
       return True
    else:
        #print('---Diff method content1:{}'.format(content1))
        #print('---Diff method content2:{}'.format(content2))

        return False

#直接行与行比较,需要正反比较
def findDiffLines(lines1,lines2):

    rows = 0 #行号

    diffs = [] #统计不同行的集合

    #print('===>正向比较<===')

    for line1 in lines1:

      rows+=1

      matched=False

      for line2 in lines2:

        if line1 == line2 :

          matched=True
          break
      if matched is False :

        #print('===>Foud difference<==={},{}',line1,line2)
        diffs.append(rows)

    rows = 0

    #print('==> 反向比较 lines1,lines2,{},{}'.format(len(lines1),len(lines2)))

    for line2 in lines2:

      rows+=1

      #print('rows:{}'.format(rows))

      matched=False

      for line1 in lines1:

         if line2 == line1 :
            matched = True
            break

      if matched is False:

        #print('===>Foud difference<==={},{}',line1,line2)

        diffs.append(rows)

    return removeRepeat(diffs)

def removeRepeat(collection):

    if collection is None or len(collection) ==0 :

        return collection
    else:

        return list(set(collection))

def getFileName(file_path):

    (filepath, tempfilename) = os.path.split(file_path)

    #print("==>filepath:{0}".format(filepath))
    (filename, extension) = os.path.splitext(tempfilename)

    return filename

def getFullFileName(file_path):

    (filepath, tempfilename) = os.path.split(file_path)

    #print("==>filepath:{0}".format(filepath))
    (filename, extension) = os.path.splitext(tempfilename)

    return filename+extension;

'''
 dic, 字典,key:文件名，value:文件路径,递归找出文夹下所有的 java文件
'''
def iteratorFolder(filepath,dic):

    fileNames = os.listdir(filepath)  # 获取当前路径下的文件名，返回List
    for file in fileNames:
        newDir = filepath + '/' + file

        # if os.path.isdir(newDir): # 如果是文件夹
        if os.path.isfile(newDir):  # 如果是文件
            #print(newDir)
            #print(os.path.splitext(newDir)[1])
            if os.path.splitext(newDir)[1] == ".java":  # 判断是否是.java
               dic[getFullFileName(newDir)]=newDir
        else:
            iteratorFolder(newDir,dic)                #如果不是.java文件，递归
    return dic;

'''
比较两个folder,生成差异报告
'''

def genReport(folder1, folder2, result_folder,diff_html_file):

    global total_class_number
    #先写入htlm报告的头部信息
    with open(diff_html_file,'w') as diffFile:
         wrtie_header(diffFile)
         #先写入类文件比较行改动结果头部
         ths=['类名','行改动位置']
         write_table_th(diffFile,'类文件比较行改动结果',ths)

    dic1={}

    dic2={}

    dic1=iteratorFolder(folder1,dic1)

    dic2=iteratorFolder(folder2,dic2)

    #开始写入类文件比较行改动结果,旧与新版本比较

    for k1 in dic1:
      total_class_number+=1
      found=False

      for k2 in dic2:

        if k1 == k2 : #同样的文件名进行比较

           found=True

           compare_file(dic1[k1],dic2[k2],result_folder,diff_html_file)

           break

      if found == False:

         #report.write('反编译文件没有找到比较的源码:{0}'.format(k1))
         global_removed_class.append(k1)#从旧版本中移除的类

    #找出新增的文件
    for k2 in dic2:

      found=False

      for k1 in dic1:

        if k1 == k2 : #同样的文件名进行比较

           found=True
           break
      if found == False:

           global_added_class.append(k2)#新增的类

    #比较完毕写入类文件比较行改动 table tail
    with open(diff_html_file,'a') as diffFile:

          write_table_tail(diffFile)
          ths=['类名','发生变更的函数']
          write_table_th(diffFile,'类文件比较函数变更记录',ths)

    #开始写入函数变更记录
    for k1 in dic1:

      for k2 in dic2:

        if k1 == k2 : #同样的文件名进行比较

           compare_methods(dic1[k1],dic2[k2],diff_html_file)

           break

    #比较完毕，生成函数体变更数据 table tail
    with open(diff_html_file,'a') as diffFile:

          write_table_tail(diffFile)

    with open(diff_html_file,'a') as diffFile:

          #生成新增的函数
          ths=['类名','新增的函数']
          write_table_th(diffFile,'新版本新增函数',ths)
          write_table_td(diffFile,global_added_methods)
          write_table_tail(diffFile)
          #生成移除方法
          ths=['类名','删除的函数']
          write_table_th(diffFile,'新版本删除的函数',ths)
          write_table_td(diffFile,global_removed_methods)
          write_table_tail(diffFile)

          #生成新增的类
          ths=['新版本新增的类文件']
          write_table_th(diffFile,'新版本新增的类文件',ths)
          write_table_td(diffFile,global_added_class)
          write_table_tail(diffFile)

          #生成删除的类
          ths=['新版本删除的类文件']
          write_table_th(diffFile,'新版本删除的类文件',ths)
          write_table_td(diffFile,global_removed_class)
          write_table_tail(diffFile)

          #总共的类，更新的类，总共的方法，更新的方法

          ths=['类的总数','更新的类的总数','总共的函数','更新函数']
          write_table_th(diffFile,'类和函数更新情况',ths)
          write_table_td_ele(diffFile,total_class_number,global_diff_class_num,total_method_number,global_diff_method_num)
          write_table_tail(diffFile)

    #比较完毕，生成html报告的尾部信息 html tail
    with open(diff_html_file,'a') as diffFile:

         write_tail(diffFile)

#去掉文本内容的所有注释、\t、空行部分
def removeComments(text):

    #fopen = open(file, 'r')

    #fileread = fopen.read()

    result=re.findall(r'\/\*[\s\S]*?\*\/',text,re.M)

    if result is None :

        return text

    for comment in result:

      #print('==>注释部分:{}'.format(comment))

      text=text.replace(comment,'')

    result=re.findall(r'(\/\/.*)',text,re.M)

    if result is None :

        return text
    for comment in result:
       #print('==>注释部分:{}'.format(comment))
       text=text.replace(comment,'')
    #去掉所有的空行

    body=''

    for str in text.splitlines():

        if str.strip() != '':
            body=body+str+'\n'
    #去掉\t标识
    body=body.replace('\t','')
    return body

#测试移除注释部分
def testRemoveComments(file):

    fopen = open(file, 'r')

    text = fopen.read()

    text=removeComments(text)

    print('==>移除所有注释后，文件内容：{}'.format(text))

#类的内容采用“花括号”算法
#第一个{和最后一个}之间的部分
#提高性能，返回一个Tuple (lines, dic) ,lines: 行数， dic: key，文件, value: 类{}之间的内容
def findClassBody(file):

    dic={}

    lines = read_file(file) #文件所有的行,去掉注释后的行

    code_dic=getCodeDic(lines)#key:行号,value:行内容字典
    firstLeftBrace=0

    for line in lines:
       firstLeftBrace+=1
       if line.strip() == '' or  line.strip().startswith('/') or line.strip().startswith('*'): #注释不处理

           continue

       if line.find(LEFT_BRACE) != -1:
          #print('==>第一个左括号行号:{},line:{}'.format(firstLeftBrace,line))
          break

    tple=getMethodRowRange(code_dic,firstLeftBrace)

    start=tple[0]
    end=tple[1]

    dic[file]=getCodeByRowNumbers(code_dic,start, end)

    return (lines,dic)

#需要考虑:implements,extends情况,获取类的内容{}中间的部分
#新增，提取文件类的内容之前先去掉注释,[\s\S]* <==> .* 不含回车换行
def findClassBody_2(file):

    dic={}

    fopen = open(file, 'r')

    fileread = fopen.read()

    #替换注释部分
    fileread=removeComments(fileread)
    pattern=re.compile(r'\s+public\s+class\s+[A-Za-z0-9_]+\s+(?:implements|extends)*\s[\s\S]*?\{([\s\S.*]*)|\s+public\s+class\s+[A-Za-z0-9_]+\s*\{([\s\S]*)|\s+public\s+abstract\s+class\s+[A-Za-z0-9_]+\s*\{([\s\S]*)')

    #print(fileread)
    #pattern=re.compile(r'(?:public)*\s*(?:abstract\s+class|class|interface)+[\s\S]+\{([\s\S]+)')
    #pattern=re.compile(r'\s*public\s+(?:class|interface){1}\s+[A-Za-z0-9_<>,]+\s+(?:implements|extends)*\s+[A-Za-z0-9<>,]+\s*\{([\s\S]*)|\s*public\s+class\s+[A-Za-z0-9_]+\s+\{([\s\S]*)|\s*public\s+abstract\s+class\s+[A-Za-z0-9_]+\s*\{([\s\S]*)')
    #pattern=re.compile(r'\s*public\s+interface\s+[A-Za-z0-9_<>,]+\s*[\s\S<>,]*\{([\s\S<>,]*)|\s*public\s+class\s+[A-Za-z0-9_]+\s*(?:implements|extends)*\s*[\s\S]*\{([\s\S]*)|\s*public\s+class\s+[A-Za-z0-9_]+\s+\{([\s\S]*)|\s*public\s+abstract\s+class\s+[A-Za-z0-9_]+\s*\{([\s\S]*)')

    result=pattern.findall(fileread,re.MULTILINE)

    #print('result={}'.format(result))

    for tpls in result:

        for tpl in tpls:

            #print('==>tuple:{}'.format(tpl))

            if tpl != '':

               dic[file]=tpl

               return dic

    #print(result)

    fopen.close()

#返回一个类的所有的方法,放在字典中

'''
@ dic_class_body: 存储类的字典,key:文件路径，value: 类的内容

@ 返回：字典，key:文件路径，value:方法内容
@ dic: 高可用的字典,key:文件路径,value: MethodMarker[]
'''
def findMethods(dic_class_body,file) :

    #print('==>解析文件:{}'.format(file))

    #使用非贪婪模式匹配 protected,public,private
    #result=re.findall(r'(p[a-z]{5,8}\s[\s\S\]*?\{[\s\S]*)',dic_class_body.replace('\n',LINE_SHIFT).replace('\t',LINE_SHIFT),re.M)
    result=re.findall(r'(p[a-z]{5,8}\s[\s\S\<>\,@\t\n]*\{)',dic_class_body,re.M)
    print('==>所有的 method {}'.format(result))

    dic={} #文件的方法字典,key:文件路径,value: MethodMarker

    method_markers=[] #MethodMarker集合

    for method_str in result:

        pattern='(?P<method>[a-zA-Z_.]{1,})\(.*\)'

        res=re.search(pattern,method_str)

        if res is None:

           continue

        else:
           method=res.group('method')
           method_str_rows=len(method_str.split(LINE_SHIFT))
           #print('==>len:{},lastone:{}'.format(method_str_rows,method_str.split(LINE_SHIFT)[method_str_rows-1]))
           #print('====>method_str:{}'.format(method_str))
           #修复构造函数不能识别的BUG,2019/10/13
           lines = method_str.split(LINE_SHIFT)

           for line in lines:

               if line.strip().endswith(';'):

                   method_str=method_str.replace(line,'')

           #print('==>result2:{}'.format(method_str))

           if (not method_str.replace(LINE_SHIFT,'').strip().endswith('{')) or method_str.replace(LINE_SHIFT,'').strip().find('==') != -1  or method_str.replace(LINE_SHIFT,'').strip().find('!=') != -1  or method_str.replace(LINE_SHIFT,'').strip().find('>=') != -1 or method_str.replace(LINE_SHIFT,'').strip().find('<=') != -1 or  method_str.replace(LINE_SHIFT,'').strip().find('class') !=-1 or method_str.replace(LINE_SHIFT,'').strip().find(';') !=-1 or  ( method_str.replace(LINE_SHIFT,'').strip().find('(') ==-1 or method_str.replace(LINE_SHIFT,'').strip().find(')') ==-1 ):

                print('=>method:{} not valid,ignore'.format(method))

           else :

               methodMarker=MethodMarker(method,method_str,method_str_rows,0,0,'') #方法标记

               method_markers.append(methodMarker)

    '''
    pattern='(?P<method>[a-zA-Z_]{1,}\(.*\))'
    for methodMarker in method_markers:

       #print('===>methodMarker,method:{}'.format(methodMarker.method))
       print('===>methodMarker,method_str:{}'.format(methodMarker.method_str))
       #仅识别方法名参数
       res=re.search(pattern,methodMarker.method_str)

       if res is None:

          continue
       else:

          methodWithParam=res.group('method')

          print('===> 带参数的方法:{}'.format(methodWithParam))

       #method_str_rows=len(methodMarker.method_str.split(LINE_SHIFT))
       #print('===>methodMarker,method_str size:{}'.format(method_str_rows))
     '''

    dic[file]=method_markers

    return dic #返回字典

def findMethods_2(dic_class_body,file) :

    #print('==>解析文件:{}'.format(file))

    #使用非贪婪模式匹配 protected,public,private
    result=re.findall(r'(p[a-z]{5,8}\s+.*?{)',dic_class_body.replace('\n',LINE_SHIFT).replace('\t',LINE_SHIFT),re.S)

    #print('==>所有的 method {}'.format(result))

    dic={} #文件的方法字典,key:文件路径,value: MethodMarker

    method_markers=[] #MethodMarker集合

    for method_str in result:

        pattern='(?P<method>[a-zA-Z_.]{1,})\(.*\)'

        res=re.search(pattern,method_str)

        if res is None:

           continue

        else:
           method=res.group('method')
           method_str_rows=len(method_str.split(LINE_SHIFT))
           #print('==>len:{},lastone:{}'.format(method_str_rows,method_str.split(LINE_SHIFT)[method_str_rows-1]))
           #print('====>method_str:{}'.format(method_str))
           #修复构造函数不能识别的BUG,2019/10/13
           lines = method_str.split(LINE_SHIFT)

           for line in lines:

               if line.strip().endswith(';'):

                   method_str=method_str.replace(line,'')

           #print('==>result2:{}'.format(method_str))

           if (not method_str.replace(LINE_SHIFT,'').strip().endswith('{')) or method_str.replace(LINE_SHIFT,'').strip().find('==') != -1  or method_str.replace(LINE_SHIFT,'').strip().find('!=') != -1  or method_str.replace(LINE_SHIFT,'').strip().find('>=') != -1 or method_str.replace(LINE_SHIFT,'').strip().find('<=') != -1 or  method_str.replace(LINE_SHIFT,'').strip().find('class') !=-1 or method_str.replace(LINE_SHIFT,'').strip().find(';') !=-1 or  ( method_str.replace(LINE_SHIFT,'').strip().find('(') ==-1 or method_str.replace(LINE_SHIFT,'').strip().find(')') ==-1 ):

                print('=>method:{} not valid,ignore'.format(method))

           else :

               methodMarker=MethodMarker(method,method_str,method_str_rows,0,0,'') #方法标记

               method_markers.append(methodMarker)

    '''
    pattern='(?P<method>[a-zA-Z_]{1,}\(.*\))'
    for methodMarker in method_markers:

       #print('===>methodMarker,method:{}'.format(methodMarker.method))
       print('===>methodMarker,method_str:{}'.format(methodMarker.method_str))
       #仅识别方法名参数
       res=re.search(pattern,methodMarker.method_str)

       if res is None:

          continue
       else:

          methodWithParam=res.group('method')

          print('===> 带参数的方法:{}'.format(methodWithParam))

       #method_str_rows=len(methodMarker.method_str.split(LINE_SHIFT))
       #print('===>methodMarker,method_str size:{}'.format(method_str_rows))
     '''

    dic[file]=method_markers

    return dic #返回字典

#标记方法体的起、始行号，方法体内容更可靠

#file: 文件的绝对路径, dic:(key:文件路径,value:MethodMarker[])
#函数抽取重要组件
def injectMethodLineNumbers(file,dic):

    methodMarkers=dic[file] #得到一个MethodMarker集合
    lines = read_file(file) #文件所有的行
    numbers=[]
    numberOfMethodMarker=len(methodMarkers)
    #print('==>总共{}个方法'.format(numberOfMethodMarker))
    count_method_marker = 0
    for marker in methodMarkers:#迭代方法标记,找到各个方法的开始行数

       count_method_marker+=1
       #print('==>开始比较第{}个methodMarker method:{},method_str:{}'.format(count_method_marker,marker.method,marker.method_str))

       matched_rows=0;
       for str in marker.method_str.split(LINE_SHIFT):
         row = 0
         for line in lines:
             #print('==>line={},******str={}'.format(line,str))
             row+=1
             if line == '' or line.strip() =='{' or line.strip() == LINE_SHIFT or line.strip().find(';') !=-1 : #空行和单独的{不比较
                continue
             else: #匹配方法的第一行需要考虑全面，容易出错
                if (line.strip().find(str.strip()) !=-1 or str.strip().find(line.strip()) !=-1) and (line.strip().find(marker.method) != -1):
                    #print('==> line.strip():{},str.strip():{}'.format(line.strip(),str.strip()))
                    #print('==>matched at row: {}, str:{}'.format(row,line))
                    marker.start=row
                    numbers.append(row)
                    break #只取命中的第一个子串匹配位置

                    if count_method_marker == numberOfMethodMarker :
                      marker.end=len(lines)

    #print('===>完成方法的起始行定位<=====')
    #print('===>Total rows:{}'.format(len(lines)))
    numbers.append(len(lines))

    #代码行字典,可以拿到任意两个整数之间的所有行，即函数体内容

    code_dic=getCodeDic(lines)

    removeNeiborElements(numbers)

    #print('===>移除相差1的元素，保留最少的数作为特征行的行号后元素<=====')
    print('==>方法行：{}'.format(numbers))

    if (len(numbers)-1) < numberOfMethodMarker: #不正确

        numberOfMethodMarker=len(numbers)-1

    for index in range(0,numberOfMethodMarker):

      #print('===>index={}'.format(index))
      if (index+1) <= numberOfMethodMarker:
         methodMarkers[index].start=numbers[index]

         methodMarkers[index].end=numbers[index+1]-1

    if (len(numbers)-1) == numberOfMethodMarker:
        cleanMethodMarkers(methodMarkers,code_dic)

    #print('====>重置起始行并清洗最后一行后，方法标记对象值<====')

    #处理完后，清除不合法的方法标记

    methodMarkers=removeInvalidFunc (methodMarkers,code_dic)

    '''
    for marker in methodMarkers:

      #print('==>start:{},end:{}'.format(marker.start,marker.end))

      #str=getCodeByRowNumbers(code_dic,marker.start,marker.end)

      print('==>方法 {}, 函数体:{}'.format(marker.method,marker.body))
    '''
    dic[file]=methodMarkers # 更新字典，将新的方法标记对象List作为value

    return dic

def checkInvalidMethod(method,method_str):

    print('==>method:{},method_str:{}'.format(method,method_str))
    if method.strip().find('==') != -1    or  method.strip().find('RequestMapping') != -1 :
       return  True
    if (not method_str.strip().endswith("{") ) or method_str.strip().endswith(";") :
       return True
    return False

#从方法标记中清除不合法的对象,如：private 开头的行
#返回新的方法标记对象，填充 body,重组method, body
def removeInvalidFunc (methodMarkers,code_dic):

    new_method_markers=[]
    removedElements=[]
    size=len(methodMarkers)

    if size == 0 :

       return removedElements

    for methodMarker in methodMarkers:

        body=getCodeByRowNumbers(code_dic,methodMarker.start,methodMarker.end)

        lines=body.splitlines()

        length=len(lines)

        invalid=False

        for row in range(0,length):

            if row >0 :

                temline=lines[row]

                if temline.strip().startswith('private'):
                    #print('==>不合法的方法体:line:{},body:{}'.format(temline.strip(),body))
                    invalid=True
                    break

        #method_str

        if invalid == False:
               result = re.findall(r'if\s*\(',methodMarker.method_str.strip())

               #print('===>method_str:{},result:{}'.format(methodMarker.method_str.strip(),result))

               if len(result) > 0:
                   invalid=True

        if invalid:

            print('===>方法标记：{}不合法，移除'.format(methodMarker.method))
            removedElements.append(methodMarker)

    for ele in removedElements:

        #print(ele)

        methodMarkers.remove(ele)

    #获取方法有可能出错
    for methodMarker in methodMarkers:

         body=getCodeByRowNumbers(code_dic,methodMarker.start,methodMarker.end)
         #mm=MethodMarker(methodMarker.method, methodMarker.method_str, methodMarker.method_str_rows, methodMarker.start, methodMarker.end,body)

         #method start
         pattern='(?P<method>\s+[\s\S]+\(.*\))'

          #仅识别方法名参数

         res=re.search(pattern,methodMarker.method_str,re.M)

         if res is None:

             continue
         else:

            methodWithParam=res.group('method')
            #需要将 LINE_SHIFT去掉
            methodWithParam=methodWithParam.replace(LINE_SHIFT,'')
            mm=MethodMarker(methodWithParam, methodMarker.method_str, methodMarker.method_str_rows, methodMarker.start, methodMarker.end,body)
            new_method_markers.append(mm)
         #method end

    methodMarkers=[]

    return new_method_markers

def cleanHeaderMethod(methodMarker):

     method = methodMarker.method

     return methodMarker

#函数体最后一行清洗
def  cleanMethodMarkers(methodMarkers,code_dic):

    size=len(methodMarkers)
    for index in range(0,size):
        skipLastRow(index,methodMarkers,code_dic)

# 函数体最后一行的处理
def skipLastRow(index,methodMarkers,code_dic):
    try:

      if methodMarkers[index].end <= methodMarkers[index].start:
         return 'pause'
      lastRow=code_dic[methodMarkers[index].end]#最后一行
      if lastRow == '' or (not lastRow.strip().endswith("}") ):

        methodMarkers[index].end=methodMarkers[index].end-1
        skipLastRow(index,methodMarkers,code_dic)#递归
      else:

       return 'ok'
    except KeyError:

       print('Not in Dict--')
       return 'fail'

# 移除相差1或者相等的元素，保留最少的数作为特征行的行号
# 核心算法

def removeNeiborElements(numbers) :

    numbers.sort()#asc排序
    removedElements=[]
    size=len(numbers)
    for i in range(0,size):
       j=i+1
       if j <=size-1:
         diff = numbers[j]-numbers[i]
         if diff == 1 or  diff == 0:
            removedElements.append(numbers[j])
       else:
         break
    #print('===>输出移除元素<=====')
    for ele in removedElements:

        #print(ele)

        numbers.remove(ele)

#返回临时字典，key: 代码行数 , value: 代码行
#lines: 文件所有的代码行
def  getCodeDic(lines):

     dic={}
     count=0
     for line in lines:
        count+=1
        dic[count]=line

     return dic

#dic: 存储代码行的字典
#返回[start,end]区间的所有行
def getCodeByRowNumbers(dic,start, end):

    str=''
    while start<=end:

      try:
        str=str+dic[start]+'\n'
        start+=1
      except KeyError:
        return str
    return str

def checkInvalidMethod(method_str):

    if method_str.strip() == '':

       return True
    for str in method_str:

        if str.strip() == '':

          continue
        if str.strip().endswith(';') or str.strip().find('||') !=-1 or str.strip().find('&&') !=-1 :

           return True

def  extremelyFindMethod(file):

    method_markers=[] #方法标记集合
    #file='/Users/source_code/dian-web/src/main/java/com/hanniu/dian/controller/adm/StaffAdminController.java'
    #file='/Users/source_code/dian-web/src/main/java/com/hanniu/dian/websocket/interceptors/MyHandshakeHandler.java'
    #file='/Users/source_code/dian-web/src/test/java/com/hanniu/online/test/InitDataTestCase.java'
    #file='/Users/source_code/dian-web/src/main/java/com/hanniu/dian/controller/adm/AdminController.java'

    #file='/Users/source_code/dian-web/src/main/java/com/hanniu/dian/controller/adm/MerchandiseController.java'
    #file='/Users/zhangxiao/agilean/valuekanban/agilean-rbac-server/src/main/java/cn/agilean/valuekanban/KafkaConsumerConfig.java'
    tpl=findClassBody(file)#返回一个Tuple(lines,dic)

    lines=tpl[0] #避免多次读文件
    dic_class_body=tpl[1]
    body=dic_class_body[file]

    code_dic=getCodeDic(lines) #key:行号,value:行内容,字典

    #方法的正则
    #body=body.replace('\t',LINE_SHIFT).replace('\n',LINE_SHIFT)
    #body=removeComments(body)

    #body='private void encapsureSortMersMap(List<Merchandise> mers,Map<Long,Sort> sort_map,Map<SortKeyBean,List<Merchandise>> listMap) {'
    #函数括号中的双引号2019/10/24

    if body.strip() == '' :

       return  method_markers
    #2019/10/25 无修饰符的函数: (?:void|[a-zA-Z<>,0-9_.\s]+){1}\s+[a-zA-Z0-9<>,_.@]+\s*\([\s\d\w,<>@\"\(\)=]*\)
    #修复正则：方法返回类型中空格试别不到
    '''
    ConcurrentKafkaListenerContainerFactory<String, KafkaContext> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, KafkaContext> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(kafkaConsumerFactory());
        return factory;
    }
    '''
    #result=re.findall(r'( (?:void|[a-zA-Z0-9<>,_.\s]+){1}\s+[a-zA-Z0-9<>,_.@]+\s*\([\s\d\w,<>@\"\(\)=]*\)\s*[\s\S^;]*?\{|(?:public|private|protected|final){1,2}\s+(?:static|synchronized)?\s*[a-zA-Z<>0-9,.@]*\s*(?:void|[a-zA-Z<>,0-9_.]+){1}\s+[a-zA-Z0-9<>,_.@\s]+\s*\([\s\d\w,<>@\"\(\)=]*\)[\s\S^;]*?\{)',body,re.M)

    #2019/10/24 github
    #/Users/source_code/dian-web/src/main/java/com/hanniu/dian/controller/adm/StaffAdminController.java result=re.findall(r'((?:public|private|protected|final){1,2}\s+(?:static|synchronized)?\s*[a-zA-Z<>0-9,.@]*\s*(?:void|[a-zA-Z<>,0-9_.]+){1}\s+[a-zA-Z0-9<>,_.@]+\s*\([\s\d\w,<>@\"\(\)=]*\)[\s\S^;]*?\{)',body,re.M)
    result=re.findall(r'((?:public|private|protected|final){1,2}\s+(?:static|synchronized)?\s*[a-zA-Z<>0-9,.@]*\s*(?:void|[a-zA-Z<>,0-9_.]+){1}\s+[a-zA-Z0-9<>,_.@]+\s*\([\s\d\w,<>@\"\(\)=]*\)[\s\S^;]*?\{)',body,re.M)
    #today
    #result=re.findall(r'((?:public|private|protected|final){1,2}\s+(?:static|synchronized)?\s*[a-zA-Z<>0-9,.@]*\s*(?:void|[a-zA-Z<>,0-9_.]+){1}\s+[a-zA-Z0-9<>,_.@\s]+\s*\([\s\d\w,<>@\"\(\)=]*\)[\s\S^;]*?\{)',body,re.M)

    #print('==>所有的 method {}'.format(result))

    dic={} #文件的方法字典,key:文件路径,value: MethodMarker

    method_markers=[] #MethodMarker集合

    method_str_list=[]
    method_list=[]
    for method_str in result:

        res = re.findall(r'if\s*\(|catch\s*\(|for\s*\(|new\s+',method_str.strip())
        #print('**************method_str:{}'.format(method_str))
        #print('===>method_str:{},res:{}'.format(method_str,res))

        if len(res) > 0:

           continue

        #if checkInvalidMethod(method_str):
        #    continue
        #print('==>valid method_str:{}'.format(method_str))
        method_str_list.append(method_str)
        #方法正则
        #2019/10/23 正确版本
        #res=re.findall(r'([a-zA-Z0-9_.]+\s*\([\s\d\w,<>@\(\)=]*?\))',method_str.strip(),re.M)
        #2019/10/24 正确版本,让方法method正则与完整方法method_str对应
        res=re.findall(r'([a-zA-Z0-9<>,_.@\s]+\s*\([\s\d\w,<>@\"\(\)=]*\))',method_str.strip(),re.M)

        #
        if res is not None:

           for method in res:

               #print('==>method:{}'.format(m))

               method_list.append(method)

    #处理一个文件的所有的方法
    size1=len(method_str_list)
    size2=len(method_list)
    #print('******** method size:{}, method_str size:{}*******'.format(size1,size2))
    '''
    for mstr in method_str_list:

        print('==>method_str:{}'.format(mstr))

    for md in method_list:

        print('==>method:{}'.format(md))
    '''
    if size1 == 0:

        return  method_markers

    if size1 == size2: #正常

        tplList=[]

        for index in range(0,size1): #遍历方法集合

           #print('==>method_str:{},size: {}'.format( method_str_list[index],len(method_str_list[index].splitlines())))
           #method_markers.append(MethodMarker(method_list[index], method_str_list[index], len(method_str_list[index].splitlines()), 0, 0,'') )
           #找到文件的起始行
           match_rows = []

           #找到方法的整个区间
           #match_rows=findStartBrace(lines, method_str_list[index],match_rows,code_dic,0)

           #match_rows=findMatchRows(method_str_list[index].splitlines(),0,lines,0,match_rows)

           match_rows=deepVisit(lines,0,0,method_str_list[index].splitlines(), match_rows)

           #print('==>****match_rows:{},method_str size:{}'.format(match_rows,len(method_str_list[index].splitlines())))

           if len(match_rows) > 0:

               start_row=match_rows[0]
               #根据方法的第一行“花括号”配对方法找最后一行的行号位置
               row_range=getMethodRowRange(code_dic,start_row) #由方法的第一行得到一个Tuple起始行

               tplList.append(row_range)

               method_body=getCodeByRowNumbers(code_dic,row_range[0], row_range[1])

               method_markers.append(MethodMarker(method_list[index], method_str_list[index], len(method_str_list[index].splitlines()), row_range[0], row_range[1],method_body) )

               #print('method :{} \n body:{}'.format( method_list[index],  method_body))

           else :

               print('>>>Warning:file:{} 匹配行集合为0, method_str:{}'.format(file,method_str_list[index]))

        # Tuple坐标去除方法内部嵌套的函数

        ########## 开始片理重叠区域  #######
        overlapList=pickOverlapList(tplList)

        mmk_size=len(method_markers)
        overLapMakers=[]

        for point in range(0,mmk_size):

            maker= method_markers[point]

            for overlap in overlapList:

                if overlap[0] == maker.start and overlap[1] == maker.end:

                    overLapMakers.append(maker)

                    break

        if len(overLapMakers) > 0:

           for olpMK in overLapMakers:

                print('==>删除重叠区域函数：{} '.format(olpMK.method))

                method_markers.remove(olpMK)

        print('==>重叠区域函数处理完毕<=====')

         ##########结束片理重叠区域  ################

        '''
        for mmk in method_markers:

            print('method_str :{} \n body:{},start:{},end:{}'.format( mmk.method_str,  mmk.body,mmk.start,mmk.end))

        '''
        return  method_markers

    else: #异常

        print('>>>file:{} 完全方法个数为:{},参数方法个数为:{}'.format(file,size1,size2))

        return  method_markers

#找出完整方法(存在多行，需要splitlines()按行比较
#lines: 同一个文件的去掉注释和空白行的所有行,method_str:带修饰符、参数、左{ 的完整方法
# match_rows=[] # 找到相等的行集合
#递归查找,方法定位连续行号算法主程
#row:从多少行开始查找,row=0

def findStartBrace(lines, method_str,match_rows,code_dic,row):

    method_str_lines=method_str.splitlines()

    size1=len(method_str_lines)

    size2=len(lines)

    #print('==>size:{}'.format(size))

    for x in range(0,size1): #方法分成几行

      for y in range(row,size2):# 文件行从0到未尾

        row+=1
        #测试用

        if  size1 == 1: #只有一行的方法，找到直接返回
           if lines[y].strip() == method_str_lines[x].strip():
              print('1 Found match at:{},一行方法:{} '.format(row,method_str_lines[x]))
              match_rows.append(row)
              return match_rows
        else:#多行需要递归查找

            if lines[y].strip() == method_str_lines[x].strip(): #找到相等行

              #print('2 Found match at:{},一行方法:{} '.format(row,method_str_lines[x]))
              if len(match_rows) >= 1: #如果不是第一行匹配
                 if row-match_rows[len(match_rows)-1] == 1:#还需要判断是否与前一行行号相差1，需要连续相等

                     match_rows.append(row)
                 else: #不连续相等,说明定位不正确,需要从 match_rows[0] 行重新查找
                     last=match_rows[len(match_rows)-1]
                     match_rows=[] #清空已匹配的行,重置lines从match_rows[len(match_rows)-1]行开始重新查找
                     body=getCodeByRowNumbers(code_dic,last, len(lines))
                     lines=body.splitlines()
                     row=last+1
                     return findStartBrace(lines, method_str,match_rows,code_dic,row)

              else:#第一行匹配，直接加入集合

                    match_rows.append(row)

                    return findStartBrace(lines, method_str,match_rows,code_dic,row)

              break; #查找下一行

    return match_rows

#method_str_list: 一个方法的几段字符串 (\n换行)
#lines: 文件的总行数
#返回的行号集合，一个方法在哪连续的几行
#str_star, line_start 首次从0开始
def findMatchRows(method_str_list, str_start,  lines, line_start,rows):

         size1=len(method_str_list)

         size2=len(lines)

         #比较第x个方法
         if str_start == size1-1 or line_start == size2-1:

             return rows

         curr_method_str=method_str_list[str_start]

         row_number=0
         for y in range(line_start,size2):

         #比较第x个方法
           row_number = y+1
           if lines[y].strip() == curr_method_str.strip(): #找到相等行

                if size1 <= 1: # 方法只有一行，直接返回
                   rows.append(row_number)
                   return rows
                else: #方法2行以上

                    if len(rows) == 0: # 还没有找到匹配的行号
                       rows.append(row_number) # 加入集合
                       #继续查找

                       curr_method_str=method_str_list[str_start+1]
                       y=0

                    else:#已有匹配的行,方法2个以上

                        #如果当前是行号与rows中未尾的行号不相差1，则清除rows, 从str_start+1位置
                        diff=line_start-rows[len(rows)-1]
                        if diff == 1: #相差1,正常，查找下一个方法遍历
                            rows.append(row_number)
                            str_start+=1#方法下一个
                            line_start+=1#内循环的下一个位置查找
                            #return findMatchRows(method_str_list, str_start,lines, line_start,rows)
                        else:#相差不为1:

                           rows = []#清空，重新查找
                           str_start=0#重新开始从第一个方法开始查找

                           return findMatchRows(method_str_list, str_start,lines, line_start,rows)

         #行数循环结束

         return rows

#递归查找起始行主程
def deepVisit(lines,line_start,method_start,method_str_list,rows):

    method_size=len(method_str_list)

    line_end=len(lines)
    if method_start == method_size or line_start == line_end:
       #print('达到最大')
       return rows

    curr_method_str=method_str_list[method_start]

    #y:lines行数
    linenumber=0
    for y in range(line_start,line_end):
           linenumber=y+1
           if lines[y].strip() == curr_method_str.strip(): #找到相等行

                if method_size == 1: # 方法只有一行，直接返回

                   #print('==>just one row<==');
                   rows.append(linenumber)
                   return rows
                else: #方法2行以上

                    if len(rows) == 0: # 集合第一行号
                       #print('===>集合第一行号:y:{},linenumber:{}'.format(y,linenumber))
                       rows.append(linenumber) # 加入集合
                       #继续查找第二个方法位置
                       method_start+=1#下一个方法
                       line_start=y
                       return deepVisit(lines,line_start,method_start,method_str_list,rows)

                    else:#已有匹配的行,方法2个以上

                        #如果当前是行号与rows中未尾的行号不相差1，则清除rows, 从str_start+1位置
                        #diff=line_start-rows[len(rows)-1]
                        diff=linenumber-rows[len(rows)-1]
                        #==line_start:613,rows:[614]
                        #print('==line_start:{},rows:{}'.format(line_start,rows))
                        #print('==linenumber:{},rows:{}'.format(linenumber,rows))
                        if diff == 1: #相差1,正常，查找下一个方法遍历
                            rows.append(linenumber)
                            method_start+=1#方法下一个
                            line_start=y
                            return deepVisit(lines,line_start,method_start,method_str_list,rows)

                        else:#相差不为1:

                           method_start=0#重新开始从第一个方法开始查找
                           line_start=rows[len(rows)-1]

                           rows = []#清空，重新查找
                           return deepVisit(lines,line_start,method_start,method_str_list,rows)

    #循环结束

    return rows

'''
旧的和新的比较,有以下结果：
1) 旧的类中的方法在新的类中找不到：删除

2) 旧的类中的方法在新的类中可以找到，但内容不相同： 修改了

3) 新的类中有的方法在旧的类中没有：新增

'''
if __name__ == "__main__":
    #file='/Users/zhangxiao/agilean/valuekanban/git-adapter-server/src/main/java/cn/agilean/gitadapter/service/GitMultiAdapterService.java'
    #file='/Users/zhangxiao/agilean/valuekanban/agilean-rbac-server/src/main/java/cn/agilean/valuekanban/TokenInterceptor.java'
    #file='/Users/source_code/dian-web/src/main/java/com/hanniu/dian/controller/consumer/ConsumerController.java'
    #file='/Users/zhangxiao/agilean/valuekanban/agilean-rbac-server/src/main/java/cn/agilean/valuekanban/KafkaConsumerConfig.java'
    #testFileMethodRowRange(file,18)

    #测试移除所有注释函数
    file='/Users/source_code/dian-web/src/main/java/com/hanniu/dian/controller/adm/StaffAdminController.java'
    extremelyFindMethod(file)
    #testRemoveComments(file)

    #result_folder='/Users/zhangxiao/agilean/valuekanban/python-anti-compile/dest/result'
    #diff_html_file=result_folder+'/report/report.html'

    #folder1='/Users/zhangxiao/agilean/valuekanban/python-anti-compile/dest.back'#反编译

    #folder2='/Users/zhangxiao/agilean/valuekanban/python-anti-compile/dest2.back'
    #folder = '/Users/zhangxiao/agilean/valuekanban/python-anti-compile/dest2.back/cn/agilean/valuekanban/repository'
    #redis = getRedis('127.0.0.1',6379,'redis2017',0)
    #extractFunc(folder,redis)
    #print('====>爬虫己完成函数抽取并存入缓存<====')
    #系统参数传入
    '''
    result_folder=sys.argv[1]

    diff_html_file=result_folder+'/report/report.html'

    folder1=sys.argv[2]

    folder2=sys.argv[3]
    '''
    #生成报告
    #genReport(folder1,folder2,result_folder,diff_html_file)

    #print('<===报告Done==>')

    #file1='/Users/zhangxiao/agilean/valuekanban/agilean-rbac-server/src/main/java/cn/agilean/valuekanban/rbac/controller/UserController.java'
    #file1='/Users/zhangxiao/agilean/valuekanban/server/src/main/java/cn/agilean/valuekanban/security/ApplicationSecurity.java'

    #file2='/Users/zhangxiao/git/python-anti-compile/dest2/cn/agilean/valuekanban/cache/consumer/ContainerCacheConsumer.java'

    #lines1 = read_file(file1)
    #lines2 = read_file(file2)

    #print('lines1:{},lines2:{}',len(lines1),len(lines2))

    #findDiffLines(lines1,lines2)

    #方法体内容
    '''
    dic=findClassBody(file1)

    print('---类的内容{}'.format(dic[file1]))

    file_methods_dic=findMethods(dic[file1],file1)

    injectMethodLineNumbers(file1,file_methods_dic)
    '''


import itertools

s1 = input().rstrip()
s2 = input().rstrip()
s3 = input().rstrip()
ds = {c:i for i, c in enumerate(list(set(s1 + s2 + s3)))}
nd = len(ds)
if nd > 10:
    print('UNSOLVABLE')
    exit()

digits = tuple(map(int, tuple('0123456789')))
for x in itertools.permutations(digits, nd):
    n1 = 0
    n2 = 0
    n3 = 0
    f = False
    for i in range(len(s1)):
        n1 = n1 * 10 + x[ds[s1[i]]]
        if i == 0 and n1 == 0:
            f = True
            break
    if f:
        continue
    for i in range(len(s2)):
        n2 = n2 * 10 + x[ds[s2[i]]]
        if i == 0 and n2 == 0:
            f = True
            break
    if f:
        continue
    for i in range(len(s3)):
        n3 = n3 * 10 + x[ds[s3[i]]]
        if i == 0 and n3 == 0:
            f = True
            break
    if f:
        continue
    if n1 + n2 == n3:
        print(n1)
        print(n2)
        print(n3)
        exit()

print('UNSOLVABLE')


import torch
import torch.nn.functional as F
from fairseq import utils

class SequenceScorer(object):
    """Scores the target for a given source sentence."""

    def __init__(self, models, tgt_dict):
        self.models = models
        self.pad = tgt_dict.pad()

    def cuda(self):
        for model in self.models:
            model.cuda()
        return self

    def score_batched_itr(self, data_itr, cuda=False, timer=None):
        """Iterate over a batched dataset and yield scored translations."""
        for sample in data_itr:
            s = utils.move_to_cuda(sample) if cuda else sample
            if timer is not None:
                timer.start()
            pos_scores, attn = self.score(s)
            for i, id in enumerate(s['id'].data):
                # remove padding from ref
                src = utils.strip_pad(s['net_input']['src_tokens'].data[i, :], self.pad)
                ref = utils.strip_pad(s['target'].data[i, :], self.pad) if s['target'] is not None else None
                tgt_len = ref.numel()
                pos_scores_i = pos_scores[i][:tgt_len]
                score_i = pos_scores_i.sum() / tgt_len
                if attn is not None:
                    attn_i = attn[i]
                    _, alignment = attn_i.max(dim=0)
                else:
                    attn_i = alignment = None
                hypos = [{
                    'tokens': ref,
                    'score': score_i,
                    'attention': attn_i,
                    'alignment': alignment,
                    'positional_scores': pos_scores_i,
                }]
                if timer is not None:
                    timer.stop(s['ntokens'])
                # return results in the same format as SequenceGenerator
                yield id, src, ref, hypos

    def score(self, sample):
        """Score a batch of translations."""
        net_input = sample['net_input']

        # compute scores for each model in the ensemble
        avg_probs = None
        avg_attn = None
        for model in self.models:
            with torch.no_grad():
                model.eval()
                decoder_out = model.forward(**net_input)
                attn = decoder_out[1]

            probs = model.get_normalized_probs(decoder_out, log_probs=False, sample=sample).data
            print(probs.shape)
            if avg_probs is None:
                avg_probs = probs
            else:
                avg_probs.add_(probs)
            if attn is not None and torch.is_tensor(attn):
                attn = attn.data
                if avg_attn is None:
                    avg_attn = attn
                else:
                    avg_attn.add_(attn)
        avg_probs.div_(len(self.models))

        # ours:
        ens_selected_probs_per_step = torch.tensor(avg_probs.gather(
            dim=2,
            index=sample['target'].data.unsqueeze(-1),
        )).squeeze()
        # end ours

        avg_probs.log_()

        # ours:
        flattend_ens_log_probs = avg_probs.squeeze()
        ens_ents_per_step = self.entropy(flattend_ens_log_probs)
        # end ours

        if avg_attn is not None:
            avg_attn.div_(len(self.models))
        avg_probs = avg_probs.gather(
            dim=2,
            index=sample['target'].data.unsqueeze(-1),
        )

        # ours:
        # per step
        # get ens_globally_selected_prob (mean) - done
        # ens std
        #  top_k_ens_, entropy
        # print(avg_probs.shape) # [1,seq_len,1]
        print("probs: ", ens_selected_probs_per_step)
        print("ents: ", ens_ents_per_step)

        # path = "/home/nlp/aharonr6/git/nmt-uncertainty/models/en_he_trans_base_seg_ens/force_decode_features.txt"
        path = "/home/nlp/aharonr6/git/nmt-uncertainty/data/QE/WMT17 Quality Estimation Shared Task Training and Development Data/sentence_level/preprocessed/train_force_decode_features.txt"
        with open(path, "a") as file:
            ens_probs_floats = [str(float(x.item())) for x in ens_selected_probs_per_step]
            ent_ents_floats = [str(float(x.item())) for x in ens_ents_per_step]
            file.write(" ".join(ens_probs_floats) + "\t" + " ".join(ent_ents_floats) + "\n")
        # end ours

        return avg_probs.squeeze(2), avg_attn

    def entropy(self, x):
        b = F.softmax(x, dim=1) * F.log_softmax(x, dim=1)
        b = -1.0 * b.mean(dim=1)
        return b


import os
import json

import torch
import torch.utils.data as data
import numpy as np

class yolo_phoc_dataset(data.Dataset):
    def __init__(self, gt_root, tensors_root, json_labels_path):
        self.gt_root = gt_root
        self.tensors_root = tensors_root
        self.labels_path = json_labels_path

        with open(json_labels_path) as f:
            self.filenames = json.load(f)
        self.keys = list(self.filenames.keys())

    def __getitem__(self, index):
        tensors_fname, masks_fname = self.filenames[self.keys[index]]

        tensors_path = os.path.join(self.tensors_root, tensors_fname)
        masks_path = os.path.join(self.tensors_root, masks_fname)
        gt_path = os.path.join(self.gt_root, self.keys[index])

        tensors = torch.from_numpy(np.load(tensors_path)).type(torch.FloatTensor)
        tensors = tensors.permute(0, 3, 1, 2)
        masks = np.load(masks_path).squeeze()
        masks = torch.from_numpy(masks.reshape(masks.shape[0], -1)).type(torch.FloatTensor)
        gt = torch.from_numpy(np.load(gt_path)).type(torch.FloatTensor)

        return tensors, masks, gt

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

def get_data_loader(gt_root, tensors_root, json_labels_path,
                    batch_size, shuffle=True, num_workers=8,):

    dataset = yolo_phoc_dataset(gt_root, tensors_root, json_labels_path)

    data_loader = data.DataLoader(dataset=dataset, batch_size=batch_size,
                                  shuffle=shuffle, num_workers=num_workers)

    return data_loader


from django.urls import path, include
from Auctions import views

urlpatterns = [

    path('', views.index, name='index'),
    path('dashboard/', views.dashboard, name = 'dashboard'),
    path('create-auction/', views.create_auction, name = 'create-auction'),
    path('auctions/<str:category>',views.display_auction , name='display-auction'),
    path('auctions/<str:category>/<int:itemset_id>',views.display_items, name='display-items'),
    path('tdashboard/',views.tdashboard),
    path('search/', views.search_by_keywords,name='search'),
    path('join/<int:auction_id>',views.join_auction,name='join'),
    path('dashboard/created-auctions/', views.view_created, name = 'view-created'),
    path('dashboard/participated-auctions/', views.view_participating, name= 'view-joined'),
    path('about/', views.about, name='about'),
    path('policies/', views.policy, name='policy'),

]


import os.path
import os
from appsclone_server.utils.helper import *
from appsclone_server.rinexHeader  import *
from appsclone_server.utils.logs   import *
from appsclone_server.constants    import *
from gdgps_apps.exceptions         import *
from gdgps_apps.apps               import APPS
from gdgps_apps                    import defines

class Connection_APPS:
  """A connection to APPS, which contains all functions to interact with its API.

  Attributes
  ----------
  DEFAULT_ARGS : dict
    Default upload arguments of APPS and the possible choices for them
  """
  # == Attributes ==
  DEFAULT_ARGS = {
    "pressure"             : None,
    "attitude"             : None,
    "email"                : (
      defines.Data.EMAIL_NOTIFY_DEFAULT,(
        defines.Data.EMAIL_NOTIFY_DEFAULT,
        True,
        False
      )
    ),
    "access"               : (
      defines.Data.ACCESS_DEFAULT,(
        defines.Data.ACCESS_DEFAULT,
        defines.Data.PRIVATE,
        defines.Data.PUBLIC
      )
    ),
    "processing_mode"      : (
      defines.GIPSYData.PROCESSING_MODE_DEFAULT,(
        defines.GIPSYData.PROCESSING_MODE_DEFAULT,
        defines.GIPSYData.STATIC,
        defines.GIPSYData.KINEMATIC
      )
    ),
    "product"              : (
      defines.GIPSYData.PRODUCT_DEFAULT,(
        defines.GIPSYData.PRODUCT_DEFAULT,
        defines.OrbitClockProduct.REAL_TIME,
        defines.OrbitClockProduct.ULTRA,
        defines.OrbitClockProduct.RAPID,
        defines.OrbitClockProduct.FINAL,
        defines.GIPSYData.BEST
      )
    ),
    "troposphere_model"    : (
      defines.GIPSYData.TROP_GMF,(
        defines.GIPSYData.TROP_OFF,
        defines.GIPSYData.TROP_PROVIDED,
        defines.GIPSYData.TROP_VMF1,
        defines.GIPSYData.TROP_GMF,
        defines.GIPSYData.TROP_GPT2
      )
    ),
    "ocean_loading"        : (
      True,(
        True,
        False
      )
    ),
    "model_tides"          : (
      True,(
        True,
        False
      )
    ),
    "elev_dep_weighting"   : (
      defines.GIPSYData.ROOT_SINE,(
        defines.GIPSYData.FLAT,
        defines.GIPSYData.SINE,
        defines.GIPSYData.ROOT_SINE
      )
    ),
    "elev_angle_cutoff"    : (
      7.5,(
        defines.GIPSYData.ELEV_ANGLE_CUTOFF_MIN,
        defines.GIPSYData.ELEV_ANGLE_CUTOFF_MAX
      )
    ),
    "solution_period"      : (
      300,(
        defines.GIPSYData.SOLUTION_PERIOD_MIN
      )
    ),
    "generate_quaternions" : (
      False,(
        True,
        False
      )
    ),
  }
  # == Methods ==
  def __init__(self,settingsFile,downloadDirectory,logger):
    """Connect to APPS and initalize the logger.

    Parameters
    ----------
    settingsFile      : str
      The APPS settings file to read the user's credentials from
    downloadDirectory : str
      The directory to download the processed results to
    logger            : Logs
      The log object to log to
    """
    self.apps   = APPS(settings_file = settingsFile,download_directory = downloadDirectory)
    self.logger = logger

  def testConnection(self):
    """Test the connection to apps.

    Returns
    ----------
    bool
      True if it was able to connect and False otherwise
    """
    self.logger.writeSubroutineLog(connectionTest,Logs.ROUTINE_STATUS.START)
    connectionStatus = self.apps.ping()[0]
    if connectionStatus:
      self.logger.writeRegularLog(Logs.SEVERITY.INFO,connectionSuccess)
    else:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,connectionFailed)
    self.logger.writeSubroutineLog(connectionTest,Logs.ROUTINE_STATUS.END)
    return connectionStatus

  def getQuotaLeft(self):
    """Check the amount of space left in the user's quota.

    Returns
    ----------
    int
      The amount of space left in the user's quota in mebibytes
    """
    profile = self.apps.profile()
    return Helper.bytesToMB(profile["quota"] - profile["usage"])

  def uploadFile(self,filePath,appsIDQueue,uploadArgs):
    """Upload a file to APPS and add its id to the id queue.

    Parameters
    ----------
    filePath    : str
      The path of the file
    appsIDQueue : str
      The file which contains the ids of the files that were uploaded to APPS
    uploadArgs  : dict
      Pairs of argumentName->argument for the upload
    """
    returnValue = 0
    filename = Helper.getFileFromPath(filePath)
    self.logger.writeSubroutineLog(rinexUpload.format(file = filename),Logs.ROUTINE_STATUS.START)
    isValid  = self.__checkFileValidity(filePath)
    if isValid:
      args               = self.__updateUploadArgs(uploadArgs)
      fileResponseObject = self.apps.upload_gipsyx(
        Helper.compressUncompressGzip(filePath,True),
        pressure             = args[0],
        attitude             = args[1],
        email                = args[2],
        access               = args[3],
        processing_mode      = args[4],
        product              = args[5],
        troposphere_model    = args[6],
        ocean_loading        = args[7],
        model_tides          = args[8],
        elev_dep_weighting   = args[9],
        elev_angle_cutoff    = args[10],
        solution_period      = args[11],
        generate_quaternions = args[12]
      )
      self.logger.writeRegularLog(Logs.SEVERITY.INFO,uploadSuccess.format(file = filename))
      self.__addToIDQueue(fileResponseObject["id"],filePath,appsIDQueue)
      returnValue = fileResponseObject["id"]
    else:
      returnValue = -1
    self.logger.writeSubroutineLog(rinexUpload.format(file = filename),Logs.ROUTINE_STATUS.END)
    return returnValue

  def __checkFileValidity(self,filePath):
    """Check file validity.

    Parameters
    ----------
    filePath : str
      The path of the file

    Returns
    ----------
    bool
      True if the rinex file is valid and False otherwise
    """
    file             = Helper.getUncompressedFile(filePath)
    filename         = Helper.getFileFromPath(file)
    header           = RinexHeader()
    header.readMandatoryHeader(file)
    isValid,validity = header.isValidHeader()
    if isValid:
      self.logger.writeRegularLog(Logs.SEVERITY.INFO,fileValidated.format(file = filename))
    else:
      validityErrorStr = RinexHeader.validityErrorToString(validity[0],validity[1])
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,fileNotValidated.format(file = filename,validity = validityErrorStr))
    return isValid

  def __updateUploadArgs(self,uploadArgs):
    """Update uploading args with the specified ones or with the defaults ones if no args
    are specified or if they're incorrect.

    Parameters
    ----------
    uploadArgs : dict
      Pairs of argumentName->argument for the upload

    Returns
    ----------
    list
      The arguments
    """
    args = []
    for argName in uploadArgs:
      if uploadArgs[argName] != "" and Connection_APPS._isValidArg(argName,uploadArgs[argName]):
        args.append(uploadArgs[argName])
      else:
        defaultValue = None
        if isinstance(Connection_APPS.DEFAULT_ARGS[argName],tuple):
          defaultValue = Connection_APPS.DEFAULT_ARGS[argName][0]
        else:
          defaultValue = Connection_APPS.DEFAULT_ARGS[argName]
        self.logger.writeRegularLog(
          Logs.SEVERITY.WARNING,invalidArg.format(
            arg          = uploadArgs[argName],
            argName      = argName,
            defaultValue = defaultValue
          )
        )
        args.append(defaultValue)
    return args

  @staticmethod
  def _isValidArg(argName,arg):
    """Check if received argument is valid.

    Parameters
    ----------
    argName : str
      The name of the argument
    arg     : str
      The received argument

    Returns
    ----------
    bool
      True if the argument is valid and False otherwise
    """
    if argName   == "pressure" or argName == "attitude":
      return arg == None or os.path.isfile(arg)
    elif argName == "elev_angle_cutoff":
      correctDigitsLength = len([digit for digit in str(arg) if digit.isdigit() or digit == "."])
      if correctDigitsLength != len(str(arg)):
        return False
      else:
        return arg > Connection_APPS.DEFAULT_ARGS[argName][1][0] and arg < Connection_APPS.DEFAULT_ARGS[argName][1][1]
    elif argName == "solution_period":
      correctDigitsLength = len([digit for digit in str(arg) if digit.isdigit()])
      if correctDigitsLength != len(str(arg)):
        return False
      else:
        return arg > Connection_APPS.DEFAULT_ARGS[argName][1]
    else:

      return arg in Connection_APPS.DEFAULT_ARGS[argName][1]

  def __addToIDQueue(self,uuid,filename,appsIDQueue):
    """Add the upload's id to the apps ID queue.

    Parameters
    ----------
    uuid        : str
      The id of the uploaded file
    filename    : str
      The uploaded filename
    appsIDQueue : str
      The file which contains the ids of the files that were uploaded to APPS
    """
    with open(appsIDQueue,"a") as f:
      f.write(f"{uuid}\n")
      self.logger.writeRegularLog(Logs.SEVERITY.INFO,addedToQueueSuccess.format(file = filename))

  def __removeFromIDQueue(self,uuid,filename,appsIDQueue):
    """Remove upload's id from the apps ID queue.

    Parameters
    ----------
    uuid        : str
      The id of the uploaded file
    filename    : str
      The uploaded filename
    appsIDQueue : str
      The file which contains the ids of the files that were uploaded to APPS
    """
    newQueue       = ""
    uuidNotInQueue = True
    with open(appsIDQueue,"r") as f:
      lines = f.readlines()
      for line in lines:
        if not uuid == line.split("\n")[0]:
          newQueue += line
        else:
          uuidNotInQueue = False
    if uuidNotInQueue:
      self.logger.writeRegularLog(Logs.SEVERITY.WARNING,idNotInQueue.format(file = filename))
      return
    with open(appsIDQueue,"w") as f:
      f.write(newQueue)
      self.logger.writeRegularLog(Logs.SEVERITY.INFO,removedFromQueueSuccess.format(file = filename))

  def handleFileState(self,uuid,appsIDQueue,resultsDir):
    """Handle what should be done, given the state of a file.

    Parameters
    ----------
    uuid        : str
      The id of the submission
    appsIDQueue : str
      The file which contains the ids of the files that were uploaded to APPS
    resultsDir  : str
      The directory to which the results should be downloaded to
    """
    self.logger.writeSubroutineLog(checkState,Logs.ROUTINE_STATUS.START)
    fileDetails = self.getFileData(uuid,appsIDQueue)
    if fileDetails != None:
      fileState = fileDetails["state"]
      filename  = fileDetails["name"]
      self.logger.writeRegularLog(Logs.SEVERITY.INFO,checkStateFile.format(file = filename))
      if fileState   == defines.Data.NASCENT:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Nascent"))
      if fileState   == defines.Data.SUBMITTED:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Submitted"))
      elif fileState == defines.Data.VERIFIED:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Verified"))
        self.__approveSubmission(uuid,filename,appsIDQueue)
      elif fileState == defines.Data.APPROVED:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Approved"))
      elif fileState == defines.Data.WAITING:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Waiting"))
      elif fileState == defines.Data.QUEUED:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Queued"))
      elif fileState == defines.Data.PROCESSING:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Processing"))
      elif fileState == defines.Data.DONE:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Done"))
      elif fileState == defines.Data.AVAILABLE:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Available"))
        self.__retrieveData(uuid,filename,appsIDQueue,resultsDir)
        self.__removeData(uuid,filename,appsIDQueue)
      elif fileState == defines.Data.ERROR:
        self.logger.writeRegularLog(Logs.SEVERITY.INFO,state.format(file = filename,state = "Error"))
        self.__handleError(uuid,filename,appsIDQueue)
    else:
      self.logger.writeSubroutineLog(checkState,Logs.ROUTINE_STATUS.END)

  def getFileData(self,uuid,appsIDQueue):
    """Get details from the file in APPS.

    Parameters
    ----------
    uuid        : str
      The id of the submission
    appsIDQueue : str
      The file which contains the ids of the files that were uploaded to APPS

    Returns
    ----------
    dict | None
      Pairs of details from APPS. None is returned in case of error
    """
    fileData = None
    try:
      self.logger.writeSubsubroutineLog(fileDataGathering.format(uuid = uuid),Logs.ROUTINE_STATUS.START)
      fileData = self.apps.detail(uuid)
    except DataNotFound:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,dataNotFound.format(uuid = uuid))
      self.__removeFromIDQueue(uuid,"Unknown",appsIDQueue)
      fileData = None
    except InvalidIdentifier:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,invalidIdentifier.format(uuid = uuid))
      self.__removeFromIDQueue(uuid,"Unknown",appsIDQueue)
      fileData = None
    except:
      self.logger.writeRegularLog(Logs.SEVERITY.CRITICAL,criticalException.format(uuid = uuid))
      fileData = None
    finally:
      self.logger.writeSubsubroutineLog(fileDataGathering.format(uuid = uuid),Logs.ROUTINE_STATUS.END)
      return fileData

  def __approveSubmission(self,uuid,filename,appsIDQueue):
    """Approve the submission after it has been verified.

    Parameters
    ----------
    uuid        : str
      The id of the submission
    filename    : str
      The uploaded filename
    appsIDQueue : str
      The file which contains the ids of the files that were uploaded to APPS
    """
    try:
      self.logger.writeSubsubroutineLog(approveFile.format(file = filename),Logs.ROUTINE_STATUS.START)
      self.apps.approve(uuid)
      self.logger.writeRegularLog(Logs.SEVERITY.INFO,approveSuccessful.format(file = filename))
    except DataNotFound:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,dataNotFound.format(uuid = uuid))
      self.__removeFromIDQueue(uuid,filename,appsIDQueue)
    except InvalidIdentifier:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,invalidIdentifier.format(uuid = uuid))
      self.__removeFromIDQueue(uuid,filename,appsIDQueue)
    except InvalidOperation:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,approveUnsuccessful.format(file = filename))
      self.__removeData(uuid,filename,appsIDQueue)
      self.__removeFromIDQueue(uuid,filename,appsIDQueue)
    except:
      self.logger.writeRegularLog(Logs.SEVERITY.CRITICAL,criticalException.format(uuid = uuid))
    finally:
      self.logger.writeSubsubroutineLog(approveFile.format(file = filename),Logs.ROUTINE_STATUS.END)

  def __removeData(self,uuid,filename,appsIDQueue):
    """Remove both source and result data from APPS and from apps ID queue.

    Parameters
    ----------
    uuid        : str
      The id of the submission
    filename    : str
      The uploaded filename
    appsIDQueue : str
      The file which contains the ids of the files that were uploaded to APPS
    """
    try:
      self.logger.writeSubsubroutineLog(removeData.format(file = filename),Logs.ROUTINE_STATUS.START)
      self.apps.delete_data(uuid)
      self.logger.writeRegularLog(Logs.SEVERITY.INFO,dataDeletedSuccessful.format(file = filename))
    except DataNotFound:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,dataNotFound.format(uuid = uuid))
    except InvalidIdentifier:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,invalidIdentifier.format(uuid = uuid))
    except InvalidOperation:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,dataDeletedUnsuccessful.format(file = filename))
    except:
      self.logger.writeRegularLog(Logs.SEVERITY.CRITICAL,criticalException.format(uuid = uuid))
    finally:
      self.__removeFromIDQueue(uuid,filename,appsIDQueue)
      self.logger.writeSubsubroutineLog(removeData.format(file = filename),Logs.ROUTINE_STATUS.END)

  def __retrieveData(self,uuid,filename,appsIDQueue,resultsDir):
    """Retrieve results from APPS.

    Parameters
    ----------
    uuid        : str
      The id of the submission
    filename    : str
      The uploaded filename
    appsIDQueue : str
      The file which contains the ids of the files that were uploaded to APPS
    resultsDir  : str
      The directory to which the results should be downloaded to
    """
    try:
      self.logger.writeSubsubroutineLog(retrieveData.format(file = filename),Logs.ROUTINE_STATUS.START)
      self.apps.download_result(uuid = uuid,dr = resultsDir)
      self.logger.writeRegularLog(Logs.SEVERITY.INFO,dataDownloadedSuccessful.format(file = filename))
    except DataNotFound:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,dataNotFound.format(uuid = uuid))
      self.__removeFromIDQueue(uuid,filename,appsIDQueue)
    except InvalidIdentifier:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,invalidIdentifier.format(uuid = uuid))
      self.__removeFromIDQueue(uuid,filename,appsIDQueue)
    except InvalidOperation:
      self.logger.writeRegularLog(Logs.SEVERITY.ERROR,dataDownloadedUnsuccessful.format(file = filename))
      self.__removeData(uuid,filename,appsIDQueue)
      self.__removeFromIDQueue(uuid,filename,appsIDQueue)
    except:
      self.logger.writeRegularLog(Logs.SEVERITY.CRITICAL,criticalExceptionLog.format(file = filename))
    finally:
      self.logger.writeSubsubroutineLog(retrieveData.format(file = filename),Logs.ROUTINE_STATUS.END)

  def __handleError(self,uuid,filename,appsIDQueue):
    """Handler error from APPS.

    Parameters
    ----------
    uuid        : str
      The id of the submission
    filename    : str
      The uploaded filename
    appsIDQueue : str
      The file which contains the ids of the files that were uploaded to APPS
    """
    self.logger.writeRegularLog(Logs.SEVERITY.ERROR,errorFromAPPS.format(file = filename))
    self.__removeData(uuid,filename,appsIDQueue)

# ✓    unit tested
# ✓ feature tested


OOPS = 'Index not found!'
print('a')
BADLY_MESSAGE = {
    'name': 'Name incorrect',
    'bloke': 'Bloke incorrect',
}

class Field:  # superclass for all base fields
    """A base class with a simple field."""

    def __init__(self):
        self._value = None
        self.__bloke = None

    def __str__(self):
        return f'{self.value}'

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value: str):
        self._value = new_value

    @property
    def bloke(self):
        return self.__bloke

    @bloke.setter
    def bloke(self, new_bloke: str):
        self.__bloke = new_bloke

class Name(Field):
    """Class of username."""

    # def __init__(self):
    #     Field.__init__(self)
    #     #  self.__bloke = None

    @Field.value.setter
    def value(self, new_value: str):

        if new_value[0].isalpha():  # not in 'ьъыЫЬЪ\'"[]_0123456789!@$%^&*()-+?<>~`|\\/'
            self._value = new_value

        else:
            print(BADLY_MESSAGE.get('name', OOPS))

    @Field.bloke.setter
    def bloke(self, new_bloke: str):

        if new_bloke[0].isalpha():  # not in 'ьъыЫЬЪ\'"[]_0123456789!@$%^&*()-+?<>~`|\\/'
            # self.__bloke = new_bloke
            # self.bloke = new_bloke
            self._Field__bloke = new_bloke

        else:
            print(BADLY_MESSAGE.get('bloke', OOPS))

a = Name()
print(a)
a.value = 'Alpha'
print(a)
print(a.value)
print(a.bloke)
a.bloke = 'Centauri'
print(a.bloke)


class Singleton:
    __instance = None
    sector = "IT"

    def __init__(self, name):
        self.name = name

    def __new__(cls, *arg , **kargs):
        if cls.__instance is None:
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def greet(self):
        print(f"Salut, {self.name}. Acesta este sectorul {self.sector}")

a = Singleton("Andrei")

# print(a.sector)
# print(a.name)
# print(a)
# print(id(a))
#
m = Singleton("Vasile")
# print(m.sector)
# print(m.name)
# print(m)
# print(id(m))

print("Apelare 'a'")
a.greet()
a.sector = "media"
a.greet()

print("")
print("Apelare 'm'")
m.greet()
a.greet()

""" ID-ul de obiect este acelasi pt ca este aceeasi clasa de obiect"""


from sys import stdout
f = open("res.csv", "r")
matrix = list()
for line in f.readlines():
    matrix.append([float(x) for x in line.split()[1:]])
col = len(matrix[0])
row = len(matrix)
inf = 1e9
for j in xrange(col):
    best = inf
    for i in xrange(row):
        if matrix[i][j] < best:
            best = matrix[i][j]
    for i in xrange(row):
        if matrix[i][j] > inf:
            r = '-'
        else:
            r = str(matrix[i][j] / best)
        stdout.write('{0} '.format(r))
    stdout.write('\n')


"""
naam: Jasper Oosterbroek
studentnummer: 1719848
klas: TI-V2C
docent: Frits Dannenberg
"""

import random

"""
description
    Testing of the birtdayParadox on a group of a given size

Parameters
---------
grpsize : int
    The size of the test group

Return
------
    found: int
        percentage of groups with the same birthdays
"""

def birthdayParadox(grpsize):
    found = 0
    samplelst = []
    for x in range(100):
        templst = []
        for y in range(grpsize):
            templst.append(random.randrange(1, 366))
        samplelst.append(templst)

    for x in samplelst:
        seen = []
        for y in x:
            if y not in seen:
                seen.append(y)
            else:
                found = found + 1
                break
    return found

print(birthdayParadox(23))


# Write a function that takes in an array of integers and returns a boolean
# representing whether the array is monotonic.
# An array is said to be monotonic if its elements, from left to right,
# are entirely non-increasing or non-decreasing.

# O(n) Time where n is the length of the input array
# O(1) Space as we are not creating any new variables that depend on the input

def isMonotonic(array):
	increasing = False
	decreasing = False
	for i in range(1, len(array)):
		if array[i] > array[i - 1]:
			increasing = True
		elif array[i] < array[i - 1]:
			decreasing = True
	if increasing and decreasing:
		return False
	else:
		return True


class AttentionConfiguration(object):
    """Configuration object containing parameters to attention model."""

    def __init__(self,
                 sequence_length,
                 vocabulary_size,
                 prediction_classes,
                 number_of_annotations,
                 annotation_size,
                 hidden_state_dimension):
        """Initialize configuration.

        :param sequence_length:
            Int. Number of characters in sequence corresponding to one training example.
        :param vocabulary_size:
            Int. Size of sequence vocabulary (e.g. 'a', 'c', 'g', 't')
        :param prediction_classes:
            Int. Number of classes for classification problem.
        :param number_of_annotations:
            Int. Number of annotation vectors for each training sequence.
        :param annotation_size:
            Int. Dimension of each annotation vector.
        :param hidden_state_dimension:
            Number of hidden units in LSTM used for attention model.
        """
        self.sequence_length = sequence_length
        self.vocabulary_size = vocabulary_size
        self.prediction_classes = prediction_classes
        self.number_of_annotations = number_of_annotations
        self.annotation_size = annotation_size
        self.hidden_state_dimension = hidden_state_dimension


from transform.spatial_transforms import (Compose, Normalize, Resize, CenterCrop, RandomCrop,
                                CornerCrop, MultiScaleCornerCrop,
                                RandomResizedCrop, RandomHorizontalFlip,
                                ToTensor, ScaleValue, ColorJitter,
                                PickFirstChannels)
from transform.temporal_transforms import (LoopPadding, TemporalRandomCrop,
                                 TemporalCenterCrop, TemporalEvenCrop,
                                 SlidingWindow, TemporalSubsampling)
from transform.temporal_transforms import Compose as TemporalCompose

from datasets.video_dataset_multiclips import VideoDatasetMultiClips
from datasets.av_dataset_multiclips import AudioVideoDatasetMultiClips

from utils import Logger,worker_init_fn,get_lr
import torch
from datasets.loader import  VideoLoaderHDF5
from torch.utils.data.dataloader import default_collate

def collate_fn(batch):

    # video_name,batch_clips, batch_targets = zip(*batch)
    new_batchs = {
        'video_name':[],
        'clip':[],
        'target':[]
    }

    for sample in batch:
        for idx,clip in enumerate(sample['clip']):
            new_batchs['video_name'].append(sample['video_name'])
            new_batchs['clip'].append(sample['clip'][idx])
            new_batchs['target'].append(sample['target'][idx])

    new_batchs['clip'] = default_collate(new_batchs['clip'])
    new_batchs['target'] = default_collate(new_batchs['target'])
    # new_batchs['video_name'] = default_collate(new_batchs['video_name'])
    return new_batchs

def get_normalize_method():
    mean=[0.485, 0.456, 0.406]
    std=[0.229, 0.224, 0.225]

    return Normalize(mean,std)

def get_val_utils(opt):
    normalize = get_normalize_method()

    if opt.train_crop == 'other':
        spatial_transform = [
            Resize((opt.scale_h, opt.scale_w)),
            RandomCrop(opt.sample_size),
            ToTensor()
        ]
    else:
        spatial_transform = [
            Resize(opt.sample_size),
            CenterCrop(opt.sample_size),
            ToTensor()
        ]

    spatial_transform.extend([ScaleValue(opt.value_scale), normalize])
    spatial_transform = Compose(spatial_transform)

    temporal_transform = []
    if opt.sample_t_stride > 1:
        temporal_transform.append(TemporalSubsampling(opt.sample_t_stride))

    temporal_transform.append(
        TemporalEvenCrop(opt.sample_duration, opt.n_val_samples))

    temporal_transform = TemporalCompose(temporal_transform)

    loader = VideoLoaderHDF5()
    val_data =  VideoDatasetMultiClips(opt.video_dir,
                                             opt.annotation_path,
                                             opt.val_subset,
                                             opt.fps,
                                             spatial_transform=spatial_transform,
                                             temporal_transform=temporal_transform,
                                             video_loader=loader)

    val_sampler = None

    g = torch.Generator()
    g.manual_seed(opt.manual_seed)
    val_loader = torch.utils.data.DataLoader(val_data,
                                             batch_size=(opt.batch_size // opt.n_val_samples),
                                             shuffle=False,
                                             num_workers=opt.n_threads,
                                             pin_memory=True,
                                             sampler=val_sampler,
                                             worker_init_fn=worker_init_fn,
                                             collate_fn=collate_fn,
                                             generator=g)

    val_logger = Logger(opt.result_path / 'val.log',
                        ['epoch', 'loss', 'acc', 'acc_num'])
    return val_loader, val_logger

def get_inference_utils(opt,inference_subset):
    assert opt.inference_crop in ['center', 'nocrop']

    normalize = get_normalize_method()

    if opt.train_crop == 'other':
        spatial_transform = [
            Resize((opt.scale_h, opt.scale_w)),
            RandomCrop(opt.sample_size),
            ToTensor()
        ]
    else:
        spatial_transform = [Resize(opt.sample_size)]

    if opt.inference_crop == 'center':
        spatial_transform.append(CenterCrop(opt.sample_size))
    spatial_transform.append(ToTensor())
    spatial_transform.extend([ScaleValue(opt.value_scale), normalize])
    spatial_transform = Compose(spatial_transform)

    temporal_transform = []
    if opt.sample_t_stride > 1:
        temporal_transform.append(TemporalSubsampling(opt.sample_t_stride))
    temporal_transform.append(SlidingWindow(opt.sample_duration, opt.inference_stride))
    temporal_transform = TemporalCompose(temporal_transform)

    loader = VideoLoaderHDF5()

    inference_data =  VideoDatasetMultiClips(opt.video_dir,
                                             opt.annotation_path,
                                             inference_subset,
                                             opt.fps,
                                             spatial_transform=spatial_transform,
                                             temporal_transform=temporal_transform,
                                             video_loader=loader)

    g = torch.Generator()
    g.manual_seed(opt.manual_seed)
    inference_loader = torch.utils.data.DataLoader(inference_data,
                                                   batch_size=opt.inference_batch_size,
                                                   shuffle=False,
                                                   num_workers=opt.n_threads,
                                                   pin_memory=True,
                                                   worker_init_fn=worker_init_fn,
                                                   collate_fn=collate_fn,
                                                   generator=g)

    return inference_loader,inference_data.idx_to_class


from pandas import Series
from matplotlib import pyplot
from statsmodels.tsa.ar_model import AR
from sklearn.metrics import mean_squared_error

FILE_PATH = r'datasets/citations.csv'
PREDICTIONS = 30

def offline_test():
    """
    not learns online!
    :return:
    """
    # load dataset from file
    series = Series.from_csv(FILE_PATH, header=0)

    # split dataset to train and test batches
    all_samples = series.values
    train, test = all_samples[:-PREDICTIONS], all_samples[-PREDICTIONS:]

    # train AutoRegression
    model = AR(train)
    model_fit = model.fit()
    window = model_fit.k_ar
    # print('window=' + str(window))
    model_params = model_fit.params

    # walk forward over time steps in test
    history = list(train[-window:])
    # ? history = [history[i] for i in range(len(history))]
    predictions = list()
    for t in range(len(test)):
        lag = history[-window:]
        y_hat = model_params[0]
        for d in range(window):
            y_hat += model_params[d + 1] * lag[window - d - 1]
        obs = test[t]
        predictions.append(y_hat)
        history.append(obs)
        print('predicted=%f, expected=%f' % (y_hat, obs))
    #
    error = mean_squared_error(test, predictions)
    print('Test MSE = %.3f' % error)

    # return test and predictions
    return test, predictions

def load_csv(csv_file_path):
    # load dataset from file
    series = Series.from_csv(csv_file_path, header=0)
    return series.values

def split_samples(samples):
    return samples[:-PREDICTIONS], samples[-PREDICTIONS:]

def main(csv_file_path):
    # load csv
    all_samples = load_csv(csv_file_path)

    # split to test and train
    train, test = split_samples(all_samples)

    # set history=train (duplicate train)
    history = list(train)

    # for i < number_of_predictions
    prediction_list = list()
    for prediction_index in range(PREDICTIONS):
        # train model on history
        model = AR(history)
        model_fit = model.fit()

        # predict next value and concatenate to prediction list
        predictions = model_fit.predict_using_learned_params(start=len(history), end=len(history), dynamic=False)
        prediction_list.append(predictions[0])

        # concatenate test[i] to history
        history.append(test[prediction_index])
        print('predicted={pred_value}, expected={real_value}'.format(
            pred_value=prediction_list[-1], real_value=test[prediction_index])
        )

        # keep history to same length
        history = history[1:]

    # calculate MSE with test and prediction lists
    error = mean_squared_error(test, prediction_list)
    print('Test MSE = {mse_value}'.format(mse_value=error))

    # return test and predictions
    return test, prediction_list

if __name__ == '__main__':
    # test offline method
    print('-- offline')
    test_values, offline_predictions = offline_test()

    # test online method
    print('-- online')
    _, online_predictions = main(FILE_PATH)

    # plot both
    pyplot.plot(test_values, color='red', marker='d')
    pyplot.plot(offline_predictions, color='blue', marker='s')
    pyplot.plot(online_predictions, color='green', marker='o')
    pyplot.show()


# -*- coding: utf-8 -*-
"""
Created on Sat Aug 18 22:26:35 2018

@author: siddh
https://github.com/PukkaPad/Recognizing-handwritten-digits-KNN/blob/master/MNIST_KNN_python.py
"""

#Importing Libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

#Importing the Dataset
dataset = pd.read_csv('train.csv')
X = dataset.iloc[:, 1:].values
y = dataset.iloc[:, 0].values

#Splitting Train/Test Set
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size = 0.25, random_state = 42)

#Splitting train set into validation set
X_train, X_valid, y_train, y_valid = train_test_split(X_train,y_train, test_size = 0.1, random_state = 84)

print("training data points: {}".format(len(y_train)))
print("validation data points: {}".format(len(y_valid)))
print("testing data points: {}".format(len(y_test)))

from sklearn.neighbors import KNeighborsClassifier

kVals = range(1, 30, 2)
accuracies = []

for k in range(1, 30, 2):
    print("train the classifier with the current value of {}".format(k))
    model = KNeighborsClassifier(n_neighbors=k)
    model.fit(X_train, y_train)

    #evaluate the model and print the accuracies list
    score = model.score(X_valid, y_valid)
    print("k=%d, accuracy=%.2f%%" % (k, score * 100))
    accuracies.append(score)

i = np.argmax(accuracies)
print("k=%d achieved highest accuracy of %.2f%% on validation data" % (kVals[i],
    accuracies[i] * 100))

kVals[i]
model = KNeighborsClassifier(n_neighbors=kVals[i])
model.fit(X_train, y_train)

# Predict labels for the test set
predictions = model.predict(X_test)

# Evaluate performance of model for each of the digits
from sklearn.metrics import classification_report
print("EVALUATION ON TESTING DATA")
print(classification_report(y_test, predictions))

from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, predictions)

sum = 0
for i in range (0,10):
    sum = sum + cm[i][i]

print(sum)

sum/len(y_test)

z = X_test[254]
z = z.reshape(28,28)
z.shape
plt.imshow(z, cmap = 'Greys')

"""from skimage import exposure
import imutils
import cv2
for i in np.random.randint(0, high=len(y_test), size=(5,)):
    # np.random.randint(low, high=None, size=None, dtype='l')
    image = X_test[i]
    prediction = model.predict(image)[0]

    # convert the image for a 64-dim array to an 8 x 8 image compatible with OpenCV,
    # then resize it to 32 x 32 pixels for better visualization
    image = image.reshape((8, 8)).astype("uint8")
    image = exposure.rescale_intensity(image, out_range=(0, 255))
    image = imutils.resize(image, width=32, inter=cv2.INTER_CUBIC)

    # show the prediction
    print("I think that digit is: {}".format(prediction))
    cv2.imshow("Image", image)
    cv2.waitKey(0)"""


from collections import Counter, OrderedDict

__author__ = 'Narendra'

notes = '''
1. Read instructions for each function carefully.
2. Feel free to create new functions if needed. Give good names though :)
3. Try to use builtins and datastructures instead of writing your own.
4. If something about the function spec is not clear, use the corresponding test
   for clarification
'''

from placeholders import *

# Sort the words that are passed in by word length instead of word content.
# e.g ["apple", "dog", "elephant"] should result in ["elephant", "apple", "dog"]
# hint: use list.sort, don't write your own.
# sort the list inplace and return the same list.
def sort_by_length(words):
    if words is None:
        return None
    else:
        words.sort(key=len, reverse=True)
        return words

# return the top n most frequently occurring chars and their respective counts
# e.g aaaaaabbbbcccc, 2 should return [(a 5) (b 4)]
# in case of a tie, return char which comes earlier in alphabet ordering
# e.g. cdbba,2 -> [(b,2) (a,1)]
# use standard types and builtin functions and no control flow statements.
def top_chars(word, n):
    # counts = Counter(word)
    # return counts.most_common(n)
    # counts = Counter(word)
    counts = OrderedDict()
    for char in word:
        counts[char] = counts.get(char, 0) + 1

    sorted_dict = sorted(counts, key=counts.__getitem__, reverse=True)
    for k in sorted_dict[:n]:
        print("{} : {}".format(k, counts[k]))

def test_sort_by_length():
    assert ["apple", "bear", "dog"] == sort_by_length(["dog", "apple", "bear"])
    assert ["apple", "bear", "dog"] == sort_by_length(["apple", "dog",  "bear"])
    assert ["apple", "dog", "cat"] == sort_by_length(["dog", "apple", "cat"])
    assert ["elephant", "apple"] == sort_by_length(["apple", "elephant"])
    assert ["three", "four", "one", "two"] == sort_by_length(["one", "two", "three", "four"])
    assert [] == sort_by_length([])
    assert None == sort_by_length(None)

def test_top_chars():
    # assert [('p', 2)] == top_chars("app",1)
    # assert [('p', 2), ('a',1)] == top_chars("app",2)
    # assert [('p', 2), ('a',1)] == top_chars("app",3)

    # assert [('a', 2)] == top_chars("aabc", 1)
    # assert [('a', 2), ('b', 1)] == top_chars("aabc", 2)
    # assert [('a', 2), ('b', 1), ('c', 1)] == top_chars("aabc", 3)
    #
    # assert [('e', 3)] == top_chars("irreversible", 1)
    # assert [('e', 3), ('r', 3)] == top_chars("irreversible", 2)
    # assert [('e', 3), ('r', 3), ('i',2), ('b', 1)] == top_chars("irreversible", 4)
    pass

three_things_i_learnt = """
-
-
-
"""

time_taken_minutes = ___


from flask import Flask, redirect, request
import os
import jwt

app = Flask(__name__)

@app.route("/sso/clove")
def sso_clove():
    # If the user is not logged in, store the fact that the request came from Clove
    # via a specific hub_domain (in cookie for example). After they are logged in,
    # redirect them to the generated URL.

    jwt_s = jwt.encode(generate_user_payload(), secret(), algorithm="HS256")
    domain = request.args.get('hub_domain')
    verify_domain(domain)

    return redirect(f"https://{domain}/sso/jwt?jwt={jwt_s}")

def verify_domain(domain):
    valid = domain == "preview.cloveapp.io" or domain.endswith(".mycompany.com")

    if not valid:
        raise Exception("Invalid hub_domain")

def generate_user_payload():
    return {
        "user": {
            "id": 1000,
            "given_name": "Adam",
            "family_name": "Admin",
            "name": "Adam Admin",
            "email": "sso+admin@cloveapp.io",
            "custom_data": {
                "sfdc_contact_id": "0034W00002IZh2YQAT"
            },
            "organization": {
                "id": 2000,
                "name": "SSO Demo Org",
                "custom_data": {
                    "sfdc_account_id": "0014W00002Cu9AiQAJ"
                }
            }
        }
    }

def secret():
    return os.getenv('SSO_SECRET')

if secret() == None:
    raise Exception("SSO_SECRET is not set")


#!/usr/bin/python3
'''
Pings a To-Do API for data for all users and writes it to a JSON file
'''
if __name__ == "__main__":
    import json
    import requests
    import sys
    rootURL = 'https://jsonplaceholder.typicode.com/'

    # grab info about all users
    url = rootURL + 'users'
    response = requests.get(url)
    users = json.loads(response.text)

    # grab the info about the users' tasks
    constructor = {}
    for user in users:
        employee_id = user.get('id')
        user_id_key = str(employee_id)
        username = user.get('username')
        constructor[user_id_key] = []
        url = rootURL + 'todos?userId={}'.format(employee_id)

        response = requests.get(url)
        objs = json.loads(response.text)
        for obj in objs:
                json_data = {
                    "username": username,
                    "task": obj.get('title'),
                    "completed": obj.get('completed'),
                }
                constructor[user_id_key].append(json_data)

    # write the data to the file
    json_encoded_data = json.dumps(constructor)
    with open('todo_all_employees.json', 'w') as myFile:
        myFile.write(json_encoded_data)


numberList = []

for i in range(20):
    number = int(input("Enter a number: "))
    numberList.append(number)

total = sum(numberList)
average = total / 20
highest = max(numberList)
lowest = min(numberList)

print(total, average, highest, lowest)

CENG113/Exercises in the class/Exercises in the book/Chapter 7_ Lists and Tuples/04. numberAnalysisProgram.py


from te import tvm
import te.lang.cce
from te.platform.cce_conf import api_check_support
from te.platform.fusion_manager import fusion_manager
from te.utils.op_utils import check_dtype
from topi.cce import util
from impl.util.util_apply_op_schedule import common_apply_op_process
from impl.util.util_apply_op_schedule import ApplyOpConfig

NUM_ZERO = 0.0

# pylint: disable=locally-disabled, too-many-arguments, unused-argument
# pylint: disable=too-many-locals, invalid-name
@fusion_manager.register("apply_adagrad_d")
def apply_adagrad_d_compute(var,
                            accum,
                            lr,
                            grad,
                            var_out,
                            accum_out,
                            update_slots,
                            kernel_name="apply_adagrad_d"):
    """
    Update '*var' according to the Adagrad algorithm.

    accum += grad ** 2
    var -= lr * grad / accum.sqrt()

    Parameters:
    ----------
    var: the dict of var, only support float16, float32

    accum: the dict of accum, only support float16, float32

    lr: the dict of lr, only support float16, float32

    grad: the dict of grad, only support float16, float32

    var_out: the dict of var output, only support float16, float32

    accum_out: the dict of accum output, only support float16, float32

    update_slots: An optional 'bool'. Defaults to 'True',
        If True, the accum tensor will be updated;
        otherwise the option is False, the accum tensor will not be update.

    kernel_name : cce kernel name, default value is "apply_adagrad".

    Returns
    -------
    None
    """

    input_dtype = var.dtype
    if input_dtype == "float16" and api_check_support("te.lang.cce.vadd",
                                                      "float32"):
        var = te.lang.cce.cast_to(var, "float32")
        accum = te.lang.cce.cast_to(accum, "float32")
        lr = te.lang.cce.cast_to(lr, "float32")
        grad = te.lang.cce.cast_to(grad, "float32")

    if update_slots is True:
        grad_square = te.lang.cce.vmul(grad, grad)
        accum = te.lang.cce.vadd(accum, grad_square)
    elif input_dtype == 'float32':
        accum = te.lang.cce.vadds(accum, tvm.const(NUM_ZERO, "float32"))

    lr_grad = tvm.compute(grad.shape,
                          lambda *indices: grad(*indices) * lr[0],
                          tag='elewise_single_VS_mul')
    sqrt_accum = te.lang.cce.vsqrt(accum)

    update = te.lang.cce.vdiv(lr_grad, sqrt_accum)
    var = te.lang.cce.vsub(var, update)

    res1 = te.lang.cce.vadds(var, tvm.const(0.0, dtype="float32"))
    res2 = te.lang.cce.vadds(accum, tvm.const(0.0, dtype="float32"))

    if input_dtype == "float16":
        res1 = te.lang.cce.cast_to(res1, "float16")
        res2 = te.lang.cce.cast_to(res2, "float16")

    # this compute is for muti output
    def _compute(*index):
        return accum(*index), var(*index), res1(*index),\
               res2(*index)

    return tvm.compute(var.shape, _compute, name="outputs")

@util.check_input_type(dict, dict, dict, dict, dict, dict, bool, str)
def apply_adagrad_d(var,
                    accum,
                    lr,
                    grad,
                    var_out,
                    accum_out,
                    update_slots=True,
                    kernel_name="apply_adagrad_d"):
    """
    Update '*var' according to the Adagrad algorithm.

    accum += grad ** 2
    var -= lr * grad / accum.sqrt()

    Parameters:
    ----------
    var: the dict of var, only support float16, float32

    accum: the dict of accum, only support float16, float32

    lr: the dict of lr, only support float16, float32

    grad: the dict of grad, only support float16, float32

    var_out: the dict of var output, only support float16, float32

    accum_out: the dict of accum output, only support float16, float32

    update_slots: An optional 'bool'. Defaults to 'True',
        If True, the accum tensor will be updated;
        otherwise the option is False, the accum tensor will not be update.

    kernel_name : cce kernel name, default value is "apply_adagrad".

    Returns
    -------
    None
    """

    check_list = ('float16', 'float32')
    dtype = var.get('dtype')
    check_dtype(dtype, check_list)
    dtype = dtype.lower()

    input_dict = (var, accum, lr, grad)

    args = ApplyOpConfig.TensorArgs(input_dict, apply_adagrad_d_compute,
                                    [var_out, accum_out],
                                    5 if dtype == 'float32' else 7)
    name = ApplyOpConfig.TensorName(all=('var', 'accum', 'lr', 'grad'),
                                    scalar=('lr', ),
                                    reuse=('accum', 'var'))
    options = ApplyOpConfig.TensorOptions(attrs=update_slots)

    common_apply_op_process(ApplyOpConfig(args, name, options), kernel_name)