# 第三版用来接鼠标控制器来实现自动点击.并且结合游戏运行

import shutil

#================
# bug 汇总:
#   1.  看到主要是cv的问题没有做完美, flood迷宫算法没问题
#       cv问题是, 第一个maze 的右下角坐标有时候识别不出来. 考虑调节参数
#                 第二个是切割完小图之后,比较不出来两个相同图片,跟之前担心的一样,差一个像素位置偏差时候很麻烦.
#  2.有兴趣的哥们可以试着优化一下这2点. 先分享版本到这.有时间继续优化.
#
#  3. 洗牌之后的算法需要重新修改. 需要判断黑块.
#
#
#
#
#
#
#
#
import win32con
import win32gui
#=============预处理:
#

if 1:#'初始化窗口:'
    # coding=utf-8
    import win32con
    import win32api
    import win32gui
    import win32ui
    from ctypes import *
    from ctypes import wintypes

    GetForegroundWindow = windll.user32.GetForegroundWindow
    GetWindowRect = windll.user32.GetWindowRect
    SetForegroundWindow = windll.user32.SetForegroundWindow
    GetWindowText = windll.user32.GetWindowTextA
    MoveWindow = windll.user32.MoveWindow
    EnumWindows = windll.user32.EnumWindows

    class RECT(Structure):
        _fields_ = [
            ('left', c_long),
            ('top', c_long),
            ('right', c_long),
            ('bottom', c_long)
        ]

    class POINT(Structure):
        _fields_ = [
            ('x', c_long),
            ('y', c_long),
        ]

    class FormControl(object):
        def __init__(self):
            self.win_hd = None
            self.win_title = ''

        def bindActiveWindow(self):
            """
            函数功能：获取当前焦点所在窗口
            """
            self.win_hd = GetForegroundWindow()

        def bindWindowByName(self, win_name):
            """
            函数功能：根据窗体名获取窗体句柄
            """
            self.win_title = win_name
            pro_fun_type = CFUNCTYPE(c_bool, c_int, c_long)
            pro_fun_p = pro_fun_type(self.EnumWindowsProc)
            EnumWindows(pro_fun_p, None)

        def getWinRect(self):
            """
            函数功能：获取窗体的位置和大小
            """
            if self.win_hd is None:
                return None
            rect = RECT()
            GetWindowRect(self.win_hd, byref(rect))
            return rect

        def toScreenPos(self, x, y):
            """
            函数功能：将窗体内部坐标转换为相对于显示屏的绝对坐标
            """
            # 未指定窗口，则结束函数
            if self.win_hd is None:
                return None
            rect = self.getWinRect()
            # 指定的坐标不在窗体内，则结束函数
            if x < 0 or y < 0 or x > rect.right or y > rect.bottom:
                return None
            pos = POINT()
            pos.x = x + rect.left
            pos.y = y + rect.top
            return pos

        def toWindowPos(self, x, y):
            """
            函数功能：将绝对坐标转换成相对于窗体内部坐标
            """
            if self.win_hd is None:
                return None
            rect = self.getWinRect()
            pos = POINT()
            pos.x = x - rect.left
            pos.y = y - rect.top
            # 指定的坐标不在窗体内，则结束函数
            if pos.x < 0 or pos.y < 0 or pos.x > rect.right or pos.y > rect.bottom:
                return None
            return pos

        def WindowActive(self):
            """
            函数功能：将窗体置前
            """
            if self.win_hd is None:
                return None
            SetForegroundWindow(self.win_hd)

        def getHWND(self):
            return self.win_hd

        def getWinTitle(self):
            """
            函数功能：获取窗体的标题
            """
            if self.win_hd is None:
                return None
            buffer = create_string_buffer(255, '\0')
            GetWindowText(self.win_hd, buffer, 255)
            value = buffer.value.decode('gbk')
            return value

        def MoveTo(self, x, y):
            """
            函数功能：移动窗体到指定坐标位置
            """
            if self.win_hd is None:
                return None
            rect = self.getWinRect()
            MoveWindow(self.win_hd, x, y, rect.right - rect.left, rect.bottom - rect.top, True)

        def WinCapture(self, path, x, y, w, h):
            """
            函数功能：抓取窗体截图，并保存到文件
            参    数：path 保存路径
                     x 截取起始x坐标（窗体内相对坐标）
                     y 截取起始y坐标（窗体内相对坐标）
                     w 截取宽度,为0则取窗体宽度
                     h 截取长度,为0则取窗体高度
            """
            if self.win_hd is None:
                return None
            rect = self.getWinRect()
            if w == 0:
                w = rect.right - rect.left
            if h == 0:
                h = rect.bottom - rect.top
            if x < 0 or y < 0 or (x + w) > rect.right or (y + h) > rect.bottom:
                return None
            self.Capture(self.win_hd, path, x, y, w, h, 0)

        def WinCapture_Mem(self, x, y, w, h):
            """
            函数功能：抓取窗体截图，并返回图像内存数据
            参    数：
                     x 截取起始x坐标（窗体内相对坐标）
                     y 截取起始y坐标（窗体内相对坐标）
                     w 截取宽度,为0则取窗体宽度
                     h 截取长度,为0则取窗体高度
            """
            if self.win_hd is None:
                return None
            rect = self.getWinRect()
            if w == 0:
                w = rect.right - rect.left
            if h == 0:
                h = rect.bottom - rect.top
            if x < 0 or y < 0 or (x + w) > rect.right or (y + h) > rect.bottom:
                return None
            return self.Capture(self.win_hd, '', x, y, w, h, 1)

        def Capture(self, hd, path, x, y, w, h, mode):
            """
            函数功能：截图
            参    数：hd 截取的窗口句柄
                    path 保存路径
                     x 截取起始x坐标（窗体内相对坐标）
                     y 截取起始y坐标（窗体内相对坐标）
                     w 截取宽度,为0则取窗体宽度
                     h 截取长度,为0则取窗体高度
                     mode 保存模式 0：保存为图片，1：返回图像字节数据
            """
            # 根据窗口句柄获取窗口的设备上下文
            hwndDC = win32gui.GetWindowDC(self.win_hd)
            # 根据窗口的DC获取memDC
            srcdc = win32ui.CreateDCFromHandle(hwndDC)
            # memDC创建可兼容的DC
            saveDC = srcdc.CreateCompatibleDC()
            # 创建bigmap准备保存图片
            saveBitMap = win32ui.CreateBitmap()
            # 为bitmap开辟空间
            saveBitMap.CreateCompatibleBitmap(srcdc, w, h)
            # 高度saveDC，将截图保存到saveBitmap中
            saveDC.SelectObject(saveBitMap)
            # 截取从左上角（0，0）长宽为（w，h）的图片
            saveDC.BitBlt((0, 0), (w, h), srcdc, (x, y), win32con.SRCCOPY)
            if mode == 0:
                saveBitMap.SaveBitmapFile(saveDC, path)
            else:
                signedIntsArray = saveBitMap.GetBitmapBits(True)
                return signedIntsArray
            # 释放内存
            srcdc.DeleteDC()
            saveDC.DeleteDC()
            win32gui.ReleaseDC(self.win_hd, hwndDC)
            win32gui.DeleteObject(saveBitMap.GetHandle())

        def EnumWindowsProc(self, hwnd, lParam):
            buffer = create_string_buffer(255, '\0')
            GetWindowText(hwnd, buffer, 255)
            value = buffer.value.decode('gbk')
            if value == self.win_title:
                self.win_hd = hwnd
                print(self.win_hd)
                return False
            return True

    hwnd = win32gui.FindWindow("#32770", u"连连看 v4.1")
    a = FormControl()
    a.win_hd = hwnd
    print(a.getWinRect())
    ttt=a.getWinRect()
    a.MoveTo(0, 0)
    a.WindowActive()
    print(1)
    rect = win32gui.GetWindowRect(hwnd)
    aaaa= (rect[2] - rect[0], rect[3] - rect[1])

    print(aaaa,3333333333333333333333)
    import win32gui as gui
    handle = gui.FindWindow(None, "连连看 v4.1")
    gui.SetForegroundWindow(handle)
    x0, y0, x1, y1 = gui.GetWindowRect(handle);
    print(x0,y0,x1,y1,9999999999999999999999)

print('置顶窗口完毕')
if 0:
    print('打印全部的窗口')#得到窗口的全部信息.
    import win32gui

    windows_list = []
    win32gui.EnumWindows(lambda hWnd, param: param.append(hWnd), windows_list)
    for window in windows_list:
        classname = win32gui.GetClassName(window)
        title = win32gui.GetWindowText(window)
        print(f'classname:{classname} title:{title}')

# classname:#32770 title:连连看 v4.1

#=======
test=0 # 切换用自己图片测试模式还是游戏模式

import cv2
import time
# time.sleep(3) # 启动代码3秒内切到连连看界面
littlepic=57,66  # 点击的方块大小. 单位像素.用画图软件可以自己量.
# 游戏在小游戏/llkwqb里面.
# 首先我们把练练看放到屏幕左上角位置.
print(littlepic)

import numpy as np
from PIL import ImageGrab
import cv2

# BOX = (0, 40, 880, 640)

# 左上角坐标和右下角坐标
# 调整box的值即可改变截取区域

if 0:
    screen = np.array(ImageGrab.grab())[:1200,:1300]  # 1200足够放连连看了.

#=========经过测试imageGrab的像素很低.质量太差了! 改为用下面这个方法来解平.
#==============截取屏幕.
# 下面是截取屏幕的算法.

zuoshangjiao, youxiajiao=None,None
debug_screen=[]
def getmaze():
    global zuoshangjiao
    global youxiajiao
    mouse.move(1,1)
    import pyautogui
    import cv2

    img = pyautogui.screenshot()  # x,y,w,h
    # img.save('screenshot.png')
    img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)

    # screen=img[:aaaa[0],:aaaa[1]]
    screen=img
    # print(999999999999999999999999999,aaaa[0],aaaa[1])
    # screen=img[:ttt.bottom,:ttt.right]

    global debug_screen

    if 0: # 使用保存好的图片调试用
        screen=cv2.imread('3.png')[:ttt.right,:ttt.bottom]
        debug_screen = screen
    cv2.imwrite('tmp.png',screen) # 图像切割.
    # print(screen)
    #===========找到游戏操作的图版的左上和右下. 图版的含义是你一堆littlepic拼起来的区域.
    # littlepic是 那些小图片. 目标就是小图片一样的都点一下.

    # 找到第一个像素点他的 左边50全是黑.
    flag=0
    width,height,channel=screen.shape
    for i in range(width-littlepic[1]):
        if flag==1:
            break
        for j in range(50,height//2):
            tmp=screen[i,j-50:j]
            if np.all(tmp==0)  and tmp.shape[0]==50 and np.all(screen[i:i+7,j:j+7]!=0):
                print(i,j)
                flag=1
                cv2.imwrite('tmp2.png', screen[:i+10,:j+10])  # 图像切割.
                break

    zuoshangjiao=[i,j]
    print(1111111111)

    #==========同理找到右下角.

    # 找到第一个像素点他的 左边50全是黑.
    flag=0
    width,height,channel=screen.shape
    for i in range(width-littlepic[1],0,-1):
        if flag==1:
            break
        for j in range(height-littlepic[0],50,-1):
            tmp=screen[i,j:j+35]
            if np.all(tmp==0)  and tmp.shape[0]==35 and np.all(screen[i-7:i,j-7:j]!=0):
                print(i,j)
                flag=1
                cv2.imwrite('tmp3.png', screen[:i-10,:j-10])  # 图像切割.
                break

    youxiajiao=[i,j]
    print('zuojiao',zuoshangjiao,'youxiajiao',youxiajiao)
    print('左上角有下叫',zuoshangjiao,youxiajiao)

    tmp4=screen[zuoshangjiao[0]:youxiajiao[0],zuoshangjiao[1]:youxiajiao[1]]

    cv2.imwrite('tmp4.png',screen[zuoshangjiao[0]:youxiajiao[0],zuoshangjiao[1]:youxiajiao[1]])
    tmp4 = cv2.cvtColor(tmp4, cv2.COLOR_BGR2GRAY)
    #cv2.THRESH_OTSU 可以优化阈值的选择.
    ret,thresh1 = cv2.threshold(tmp4,127,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

    cv2.imwrite('tmp5.png',thresh1)  # 图像切割.
    tmppic=thresh1
    #======找到所有的水平数值的切割.
    #============找到水平的横线. 都是0的一行

    hang=[]
    for i in range(thresh1.shape[0]):
        if np.all(thresh1[i,:]==0):
          hang.append(i)

    #=========进行像素合并. 找间断的,然后取中值

    hang_after_fix=[]

    savelist=[]

    for i,j in enumerate(hang):
        if i==0:
            savelist.append(j)
            continue
        if j-hang[i-1]==1:
            savelist.append(j)
        else:
            hang_after_fix.append(sum(savelist)/len(savelist))
            savelist=[]
            savelist.append(j)
        #======最后一行别忘了
        if i==len(hang)-1:
            hang_after_fix.append(sum(savelist) / len(savelist))
            savelist = []
    print(hang_after_fix)

    lie=[]
    for i in range(thresh1.shape[1]):
        if np.all(thresh1[:,i]==0):
          lie.append(i)

    #=========进行像素合并. 找间断的,然后取中值

    lie_after_fix=[]

    savelist=[]

    for i,j in enumerate(lie):
        if i==0:
            savelist.append(j)
            continue
        if j-lie[i-1]==1:
            savelist.append(j)
        else:
            lie_after_fix.append(sum(savelist)/len(savelist))
            savelist=[]
            savelist.append(j)
        #======最后一行别忘了
        if i==len(lie)-1:
            lie_after_fix.append(sum(savelist) / len(savelist))
            savelist = []
    print(lie_after_fix)

    #索引int化.
    hang_after_fix=[int(i) for i in hang_after_fix]
    lie_after_fix=[int(i) for i in lie_after_fix]

    #==============下面进行切割小图, 然后存下来,debug用

    dic_all_pic={}
    qipansize=len(hang_after_fix)-1,len(lie_after_fix)-1
    # tmppic 是 棋盘
    for i in range(len(hang_after_fix)-1):
        for j in range(len(lie_after_fix)-1):
            tmp=tmppic[hang_after_fix[i]:hang_after_fix[i+1],lie_after_fix[j]:lie_after_fix[j+1]]
            # cv2.imwrite(f'fordebug/{i}_{j}.png',tmp)
            dic_all_pic[f'{i}_{j}']=tmp

    #=======下面对切割完的进行比较和编码

    print(1)
    #========每个相同的小图之间可能差一些黑色框.所以把矩阵周围一圈黑色都去除.
    for i,j in dic_all_pic.items():
        hang_del,lie_del=[],[]
        for i1 in range(j.shape[0]):
            if np.all(j[i1,:]==0):
                hang_del.append(i1)
        for i1 in range(j.shape[1]):
            if np.all(j[:,i1]==0):
                lie_del.append(i1)
        j=np.delete(j,hang_del,0)
        j=np.delete(j,lie_del,1)
        dic_all_pic[i]=j

    #==========编码
    all_pic=list(dic_all_pic.values())

    # ==========修剪小图片的shape .有时候会差像素.可能因为二值化.都按照最小的切割试试
    xmin = min([i.shape[0] for i in all_pic])
    ymin = min([i.shape[1] for i in all_pic])

    all_pic=[i[1:xmin-1,1:ymin-1] for i in all_pic]

    #========save little pic for debug
    shutil.rmtree('fordebug')
    import os
    os.mkdir('fordebug')
    for i in dic_all_pic:
        cv2.imwrite(f'fordebug/{i}.png',dic_all_pic[i])

    all_pic_del_dup=[] # 记录的是索引
#================================这个地方需要优化比较算法!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    for i in range(len(all_pic)):
        print(f'当前计算的索引是第{i//qipansize[1]}行图片,{i%qipansize[1]}列的图片',)
        dex=[i//qipansize[1],i%qipansize[1]]
        for j in ((all_pic_del_dup)):

            #  有时候切分会差几个像素!
            if np.sum(all_pic[i]!=all_pic[j])<5:#两个图片相同

                all_pic_del_dup.append(j)
                break
        else: # 如果不走break时候才走else. for-else结构非常实用.
          all_pic_del_dup.append(i)

    all_pic_del_dup=np.array(all_pic_del_dup)
    all_pic_del_dup.resize(qipansize)
    print(1)

    print(1)

    #==================下面解这个矩阵.

    # 首先最外一圈补 -1 ,对角线不用补. 不允许走斜线.但是矩阵缺位置更难描述.所以还是都补上

    #=========使用图片的maze
    maze=all_pic_del_dup+1

    # print(1)
    maze2=np.ones([maze.shape[0]+2,maze.shape[1]+2])*0
    maze2[1:-1,1:-1]=maze
    # print(1)
    maze=maze2
    maze=[list(i) for i in maze]
    print("下面打印图片给的maze",maze)          #========以上就是获取maze的代码
    with open('maze.txt','w') as f:
        for i in maze:
            f.write(str(i)+'\n')

    return maze, zuoshangjiao, youxiajiao,hang_after_fix,lie_after_fix

def getmaze2(a,b): # 非第一次的getmaze就不要再算zuoshangjiao,youxiajiao, 仍然使用第一次的zuoshangjia youxiajia

    global zuoshangjiao
    global youxiajiao
    print('getmaze2里面的',zuoshangjiao,youxiajiao)
    mouse.move(1,1)
    print()
    import pyautogui
    import cv2

    img = pyautogui.screenshot()  # x,y,w,h
    # img.save('screenshot.png')
    img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)

    screen=img[:1200,:1300]
    global debug_screen

    # if test: # 使用保存好的图片调试用
    #     screen=cv2.imread('3.png')[:1200,:1300]
    #     debug_screen = screen
    cv2.imwrite('tmp.png',screen) # 图像切割.
    # print(screen)
    #===========找到游戏操作的图版的左上和右下. 图版的含义是你一堆littlepic拼起来的区域.
    # littlepic是 那些小图片. 目标就是小图片一样的都点一下.

    # # 找到第一个像素点他的 左边50全是黑.
    # flag=0
    # width,height,channel=screen.shape
    # for i in range(width-littlepic[1]):
    #     if flag==1:
    #         break
    #     for j in range(50,height//2):
    #         tmp=screen[i,j-50:j]
    #         if np.all(tmp==0)  and tmp.shape[0]==50 and np.all(screen[i:i+7,j:j+7]!=0):
    #             print(i,j)
    #             flag=1
    #             cv2.imwrite('tmp2.png', screen[:i+10,:j+10])  # 图像切割.
    #             break
    #
    #
    # print(1111111111)
    #
    # #==========同理找到右下角.
    #
    # # 找到第一个像素点他的 左边50全是黑.
    # flag=0
    # width,height,channel=screen.shape
    # for i in range(width-littlepic[1],0,-1):
    #     if flag==1:
    #         break
    #     for j in range(height-littlepic[0],50,-1):
    #         tmp=screen[i,j:j+35]
    #         if np.all(tmp==0)  and tmp.shape[0]==35 and np.all(screen[i-7:i,j-7:j]!=0):
    #             print(i,j)
    #             flag=1
    #             cv2.imwrite('tmp3.png', screen[:i-10,:j-10])  # 图像切割.
    #             break

    print('zuojiao',zuoshangjiao,'youxiajiao',youxiajiao)

    tmp4=screen[zuoshangjiao[0]:youxiajiao[0],zuoshangjiao[1]:youxiajiao[1]]

    cv2.imwrite('tmp4.png',screen[zuoshangjiao[0]:youxiajiao[0],zuoshangjiao[1]:youxiajiao[1]])
    tmp4 = cv2.cvtColor(tmp4, cv2.COLOR_BGR2GRAY)
    #cv2.THRESH_OTSU 可以优化阈值的选择.
    ret,thresh1 = cv2.threshold(tmp4,127,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

    cv2.imwrite('tmp5.png',thresh1)  # 图像切割.
    tmppic=thresh1
    #======找到所有的水平数值的切割.
    #============找到水平的横线. 都是0的一行

    hang=[]
    for i in range(thresh1.shape[0]):
        if np.all(thresh1[i,:]==0):
          hang.append(i)

    #=========进行像素合并. 找间断的,然后取中值

    # hang_after_fix=[]

    # savelist=[]
    #
    # for i,j in enumerate(hang):
    #     if i==0:
    #         savelist.append(j)
    #         continue
    #     if j-hang[i-1]==1:
    #         savelist.append(j)
    #     else:
    #         hang_after_fix.append(sum(savelist)/len(savelist))
    #         savelist=[]
    #         savelist.append(j)
    #     #======最后一行别忘了
    #     if i==len(hang)-1:
    #         hang_after_fix.append(sum(savelist) / len(savelist))
    #         savelist = []
    # print(hang_after_fix)

    lie=[]
    for i in range(thresh1.shape[1]):
        if np.all(thresh1[:,i]==0):
          lie.append(i)

    #=========进行像素合并. 找间断的,然后取中值

    # lie_after_fix=[]

    # savelist=[]
    #
    # for i,j in enumerate(lie):
    #     if i==0:
    #         savelist.append(j)
    #         continue
    #     if j-lie[i-1]==1:
    #         savelist.append(j)
    #     else:
    #         lie_after_fix.append(sum(savelist)/len(savelist))
    #         savelist=[]
    #         savelist.append(j)
    #     #======最后一行别忘了
    #     if i==len(lie)-1:
    #         lie_after_fix.append(sum(savelist) / len(savelist))
    #         savelist = []
    # print(lie_after_fix)

    #索引int化.
    hang_after_fix=[int(i) for i in a]
    lie_after_fix=[int(i) for i in b]

    #==============下面进行切割小图, 然后存下来,debug用

    dic_all_pic={}
    qipansize=len(hang_after_fix)-1,len(lie_after_fix)-1
    # tmppic 是 棋盘
    for i in range(len(hang_after_fix)-1):
        for j in range(len(lie_after_fix)-1):
            tmp=tmppic[hang_after_fix[i]:hang_after_fix[i+1],lie_after_fix[j]:lie_after_fix[j+1]]
            # cv2.imwrite(f'fordebug/{i}_{j}.png',tmp)
            dic_all_pic[f'{i}_{j}']=tmp

    #=======下面对切割完的进行比较和编码

    print(1)
    # #========每个相同的小图之间可能差一些黑色框.所以把矩阵周围一圈黑色都去除.
    # for i,j in dic_all_pic.items():
    #     hang_del,lie_del=[],[]
    #     for i1 in range(j.shape[0]):
    #         if np.all(j[i1,:]==0):
    #             hang_del.append(i1)
    #     for i1 in range(j.shape[1]):
    #         if np.all(j[:,i1]==0):
    #             lie_del.append(i1)
    #     j=np.delete(j,hang_del,0)
    #     j=np.delete(j,lie_del,1)
    #     dic_all_pic[i]=j

    #==========编码
    all_pic=list(dic_all_pic.values())

    # ==========修剪小图片的shape .有时候会差像素.可能因为二值化.都按照最小的切割试试
    xmin = min([i.shape[0] for i in all_pic])
    ymin = min([i.shape[1] for i in all_pic])
#---------再减一个像素.
    all_pic=[i[1:xmin-1,1:ymin-1] for i in all_pic]

    #========save little pic for debug
    shutil.rmtree('fordebug')
    import os
    os.mkdir('fordebug',)
    # print(99999999,dic_all_pic)
    for i in dic_all_pic:
        cv2.imwrite(f'fordebug/{i}.png',dic_all_pic[i])
    print('保存好第二次小图片')

    all_pic_del_dup=[] # 记录的是索引============这个就把重复图片给笑出了,之后记录索引.
    all_pic_del_dup2=[] # 记录的是索引============这个就把重复图片给笑出了,之后记录索引.
#================================这个地方需要优化比较算法!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    for i in range(len(all_pic)):
        print(f'当前计算的索引是第{i//qipansize[1]}行图片,{i%qipansize[1]}列的图片',)
        dex=[i//qipansize[1],i%qipansize[1]]
        if np.sum(all_pic[i]==np.zeros_like(all_pic[i]))>np.size(all_pic[i])*0.8:# 如果基本都黑色,那么就是崆不用管.
            all_pic_del_dup.append(-1.0) # 用-1表示.
            continue
        for j in ((all_pic_del_dup2)):

            #  有时候切分会差几个像素!
            if np.sum(all_pic[i]!=all_pic[j])<5:#两个图片相同==============判断图片!!!!!!!!!!!!!

                all_pic_del_dup2.append(j)
                all_pic_del_dup.append(j)
                break
        else: # 如果不走break时候才走else. for-else结构非常实用.
            all_pic_del_dup2.append(i)
            all_pic_del_dup.append(i)

    all_pic_del_dup=np.array(all_pic_del_dup)
    all_pic_del_dup.resize(qipansize)
    print(1)

    print(1)

    #==================下面解这个矩阵.

    # 首先最外一圈补 -1 ,对角线不用补. 不允许走斜线.但是矩阵缺位置更难描述.所以还是都补上

    #=========使用图片的maze
    maze=all_pic_del_dup+1

    # print(1)
    maze2=np.ones([maze.shape[0]+2,maze.shape[1]+2])*0
    maze2[1:-1,1:-1]=maze
    # print(1)
    maze=maze2
    maze=[list(i) for i in maze]
    print("下面打印图片给的maze",maze)          #========以上就是获取maze的代码
    with open('maze.txt','w') as f:
        for i in maze:
            f.write(str(i)+'\n')

    return maze

#========下面走 迷宫问题. 给定初始点和结束点. 给出所有的走法.

# print(1)

step=[(-1,0),(1,0),(0,-1),(0,1)]  # 上, 下, 左, 右 的顺序访问.

# ===========使用flood 算法. 先填充走一个方向的所有结果,再填充走第二个方向的所有结果.然后看是否有相同的即可.

def compare(a,b):  # a  一个numpy数组, b是numpy矩阵
    for i in a:
        if (i==b).all():
            return True
    return False

import copy
def search(maze, index1,index2):
    # 输入一个maze 和 位置(index1, index2) . 然后返回他flood算法走3个方向之后的所有覆盖点.
# 走3个折线.
    # 并且起点和终点之间只允许经过0 或者什么都不经过
    #

    dex=[index1,index2] # 起始索引
    result=[]  # 换了一个新项目环境, 之前的太坑了,乱跑代码.

    #=========经过0个0就可以到的点
    #走一步,如果到达的位置是0, 那么就可以继续按照这个方向走. 否则就只能停止直接写入result

    #使用bfs来处理=======使用queue,比list curd速度要快.

    a=[]
    a.append(dex)
    tmpway=[] # tmpway  是走一个直线的时候经过的位置.
    #==============走一个直线
    #向上走: 对a里面每一个点都一直向上走.
    result=[]
    result.append(dex)
    for k in range(3):
        for i in (a): # python for 循环数组时候不要在循环里面改变数组, 会无限循环下去. # a是上一轮走完4个方向经过的位置
            for j in step: # 4个方向.
                tmp = i
                while 1: # 一直向一个方向走.
                    tmp=[tmp[0]+j[0],tmp[1]+j[1]]
                    if tmp[0]>=0 and tmp[0]<= len(maze)-1 and tmp[1]>=0 and tmp[1]<=len(maze[0])-1: #判断不会走出maze
                        if maze[tmp[0]][tmp[1]]==0: # 如果遇到0了,就可以继续走,仍如a里面
                            if tmp not in tmpway: # tmp不在a中存在

                                 tmpway.append(tmp)
                            if tmp not in result:
                                 result.append(tmp)
                        else:
                            if tmp not in result:
                                result.append(tmp) # 碰到墙了不用走了.并且不允许继续走这个方向了.
                            break
                    else: # 超界了不用走了
                        break
        # a=copy.deepcopy(tmpway)
        a=tmpway.copy() #把可以继续拓展的位置交给下一轮拓展# 这个地方要用copy, 因为数组是传引用的!!!!!!!! 浅拷贝就足够了. 最高层级拷贝就足够用.
        # print('tmpway',tmpway)
        # print("debug",k,result)
                # print(result,999999)
    return result

#测试maze
# maze=np.array([[1,2,3],[1,1,3]])
# #补0
# maze2=np.ones([maze.shape[0]+2,maze.shape[1]+2])*0
# maze2[1:-1,1:-1]=maze
# # print(1)
# maze=maze2
# maze=[list(i) for i in maze]
# print(maze)

# numpy 好像debug有问题. 还是用list来算吧.
# a=search(maze,1,1)  # a就是3个连线后能到达的位置.

#=========然后我们只抽取里面结果位置符合要求的
def find(maze,a,b):
    # 返回值跟:索引a,b 能匹配上答案一样的图片的索引位置的列表
    candidate=search(maze,a,b)
    result=[]
    for i in candidate:
        if i[0]>0 and i[0]<len(maze)-1 and i[1]>0:
            if i[1] < len(maze[0])-1 and maze[i[0]][i[1]] == maze[a][b] :
                if i[0]==a and i[1]==b:#去除自己本身
                    continue
                else:
                  result.append(i)
    return result

# #=================find算法的输出:
# if 0:
#     print('find算法的输出:')
#     print(find(maze,1,10))

#==============下面进行playdemo.
#算法逻辑是玩这个矩阵. maze看做一维数组,优先消除索引小的块.

def play_one_step():
    for i in range(1,len(maze)-1):
        for j in range(1, len(maze[0]) - 1):
            if maze[i][j]!=0:
                a=find(maze,i,j)
                if a!=[]:
                    #=======进行消除运算.
                    maze[i][j]=0 #补0表示空白了.
                    maze[a[0][0]][a[0][1]]=0
                    print(f"消除了索引{i}_{j}和{a[0][0]}_{a[0][1]}")
                    print('打印消除后的maze用来debug',np.array(maze))
                    return True
    return False
#========玩10步:
# if 0:
#     for i in range(10):
#         play_one_step()

#========计算每个砖块的像素位置:

# print('zuoshangjiao',zuoshangjiao,'youxiajiao',youxiajiao)
dic_pix={}  # 把砖块索引和对应的像素坐标放到这个地方.
def computePix(): # 输入的a,b的索引是以1开始计数的.因为maze一周已经补0了.
    hang=len(maze)-2
    lie=len(maze[0])-2
    print('hang',hang,'lie',lie)
    # 算坐标.
    gaodu=(youxiajiao[0]-zuoshangjiao[0])/hang
    kuandu=(youxiajiao[1]-zuoshangjiao[1])/lie
    print('gaodu',gaodu,'kuandu',kuandu)

    for i in range(1,hang+1):
        for j in range(1,lie+1):
            dic_pix[f'{i}_{j}']=[zuoshangjiao[0]+(i-1+0.5)*gaodu,zuoshangjiao[1]+(j-1+0.5)*kuandu]
    #==========注意这个结果key是坐标, value是高和宽!!!!!!!!
# computePix()

#
if 0:#========下面代码画图6,用于debug看是否点击准确.
    print(dic_pix)

    point_size = 1
    point_color = (0, 0, 255) # BGR
    thickness = 4 # 可以为 0 、4、8
    kk=dic_pix.values()

    qq=[]
    for ii in kk:
        qq.append([int(i) for i in ii])

    qq=[i[::-1] for i in qq]
    kk=qq
    kk=[tuple(i) for i in kk]

    print('kk',kk)

    cv2.circle(debug_screen, (10,100), point_size, point_color, thickness)
    for point  in kk[:]:
        cv2.circle(debug_screen, point, point_size, point_color, thickness)

    cv2.imwrite('tmp6.png',debug_screen)

# print(a)

#==============下面书写游戏主逻辑

#================ 首先sleep 5秒. 在这个时间内,需要启动游戏并且选择一个难度开始游戏

time.sleep(3)
import mouse

#===========然后游戏获取maze地图.和点击像素的计算. 这些统一叫做预处理.

maze, zuoshangjiao, youxiajiao,hangafterfix,lieafterfix=getmaze()
computePix()

def play_one_step_trully(): # 在真是环境下玩一步
    for i in range(1,len(maze)-1):
        for j in range(1, len(maze[0]) - 1):
            if maze[i][j]!=0:
                a=find(maze,i,j)
                if a!=[]:
                    #=======进行消除运算.
                    maze[i][j]=0
                    maze[a[0][0]][a[0][1]]=0

                    #========这里进行鼠标点击.
                    mouse.move(dic_pix[f'{i}_{j}'][1],dic_pix[f'{i}_{j}'][0])
                    mouse.click()
                    mouse.move(dic_pix[f'{a[0][0]}_{a[0][1]}'][1],dic_pix[f'{a[0][0]}_{a[0][1]}'][0])
                    mouse.click()

                    print(f"消除了索引{i}_{j}和{a[0][0]}_{a[0][1]}")
                    print('打印消除后的maze用来debug',maze)
                    return True
    return False
play=not test

sleeptime=0.8
while play:
    a=play_one_step_trully()
    if a:
        time.sleep(sleeptime)
    else:#无解了
        time.sleep(2)
        #重新cv一遍即可.
        maze = getmaze2(hangafterfix,lieafterfix)
        computePix()


class Queue:
    def __init__(self):
        self.queue = []

    # adds an item to the end of the list using
    def enqueue(self, item):
        self.queue.append(item)

    #  removes and returns the first item from the list using
    def dequeue(self):
        if not self.isEmpty():
            return self.queue.pop(0)
        else:
            raise IndexError("Queue is empty. Cannot dequeue from an empty queue.")

    # check is empty
    def isEmpty(self):
        return len(self.queue) == 0

my_queue = Queue()
my_queue.enqueue(55)
my_queue.enqueue(60)
my_queue.enqueue(70)

# calling
print(my_queue.dequeue())  #output 55
print(my_queue.dequeue())  #output 60
print(my_queue.isEmpty())  #output False
print(my_queue.dequeue())  #output 70
print(my_queue.isEmpty())  #output True


# Download translations from Weblate Follow these instructions to create your configuration file:
# https://docs.weblate.org/en/latest/wlc.html#files Before executing this script install Python 3 and execute this
# command to install wlc (Weblate Client): pip install wlc

print('Loading modules...')
import ntpath
import os
try:
    import wlc.config
except ImportError:
    print('ERROR! You need to install the Weblate client: pip install wlc')
    exit()
print("Loading Weblate config...")
config = wlc.config.WeblateConfig('weblate')
try:
    config.load('.weblate')
except FileNotFoundError:
    print('ERROR! You need to create your configuration file for Weblate. See these instructions: '
          'https://docs.weblate.org/en/latest/wlc.html#files')
    exit()

w = wlc.Weblate(config=config)
print('Getting available translations...')
component = w.get_component(config.get('weblate', 'project') + '/' + config.get('weblate', 'component'))
for language in component.list():
    if language.language.code == config.get('weblate', 'source_language'):
        continue
    print('Downloading translation for language', language.language.code, '...')
    po = language.download()
    filename = ntpath.basename(language.filename)
    os.makedirs(language.filename.replace(filename, ''), exist_ok=True)
    print('Saving translation for language', language.language.code, '...')
    f = open(language.filename, 'w')
    f.write(po.decode('UTF-8'))
    f.close()
    print('Translation file for', language.language.code, 'saved!')


# -*- coding: utf-8 -*-
"""
Created on Mon Aug 15 22:07:31 2016

@author: Filipe Damasceno
"""
import math

class Distri:
    r2 = 0.70710678118654752440
    aa_beta,bb_beta = 0,0

    @staticmethod
    def comb(n,k):
        if n<0 or k<0 or n<k:
            print("Erro de parâmetros na comb")
            return
        c=1
        ka = n-k if n-k < k else k
        if ka == 0:
            return c
        for i in range(1,ka+1):
            c*=(n-i+1)/i
        return c

    @staticmethod
    def fatorial(n):
        if n<=1:
            return 1
        f = 1
        for i in range(2,n+1):
            f*=i
        return f

    @staticmethod
    def binomCDF(n,p,k1,k2):

        if n < 0 or k1 < 0 or k2 < 0 or n < k1 or n < k2 or k1 > k2:
            print("Erro de parâmetros na binomCDF")
            return
        s,q= 0,1-p
        for k in range(k1,k2+1):
            s+= Distri.comb(n,k)*(p**k)*(q**(n-k))
        return s

    @staticmethod
    def binomPDF(n,p,k):
        return Distri.binomCDF(n,p,k,k)

    @staticmethod
    def hipergeomPDF(k,m,N,n):

        if n<0 or k<0 or n<k or m<k or N<k or n>N or N<2:
            print("Erro de parâmetros na hipergeomPDF")
            return
        return Distri.comb(m,k)*Distri.comb(N-m,n-k)/Distri.comb(N,n)

    @staticmethod
    def hipergeomCDF(k1,k2,m,N,n):

        if k2<k1:
            print("Erro na hipergeomCDF: k1 deve ser menor ou igual que k2")
            return
        s=0
        for k in range(k1,k2+1):
            s+= Distri.hipergeomCDF(k,m,N,n)
        return s

    @staticmethod
    def funcaoErro(x):
        p,a1,a2,a3,a4,a5=0.3275911,0.254829592,-0.284496736,1.421413741,-1.453152027,1.061405429

        xx= x if x>0 else -x
        t=1/(1+p*xx)
        tt=((((a5*t+a4)*t+a3)*t+a2)*t+a1)*t
        ef=1-(-xx**xx)*tt
        return -ef if x<0 else ef
    @staticmethod
    def invErro(r):
        if abs(r)>1:
            print("Erro na invErro: r deve ser menor que 1.")
            return
        return Distri.r2*Distri.invnormal((r+1)/2)
    @staticmethod
    def normalPDF(z):
        return math.exp(-z*z/2)/math.sqrt(2*math.pi)

    @staticmethod
    def normalCDF(z,z1=None,d1=None,d2=None):
        if z1 == None:
            if z < 0:
                return 1-Distri.normalCDF(-z)

            b1,b2,b3,b4,b5,t=0.319381530, -0.356563782, 1.781477937, -1.821255978, 1.330274429, 1/(1+0.2316419*z)

            return 1-Distri.normalPDF(z)*(((((b5*t+b4)*t+b3)*t+b2)*t+b1)*t)
        elif z1 != None == d1 == d2:
            if z > z1:
                print("Erro na normalCDF: z1 deve ser menor que z2.")
                return
            return Distri.normalCDF(z)-Distri.normalCDF(z1)
        elif not None in [z,z1,d1,d2]:
            if z > z1 or d2 <=0:
                print("Erro na normalCDF: x1 deve ser menor que x2.")
                return
            v1,v2 = (z-d1)/d2,(z1-d1)/d2
            return Distri.normalCDF(v1,v2)
        else:
            if d1<=0:
                print("Erro na normalCDF: o desvio deve ser positivo.")
                return
            return Distri.normalCDF((z-z1)/d1)

    @staticmethod
    def invnormal(p):
        if p<0 or p>1:
            print("Erro na invnormal: p deve estar no intervalo [0,1] ")
            return
        if p > 0.999968:
            return 4
        if p < 0.000032:
            return -4
        if p > 0.5:
            return -Distri.invnormal(1-p)
        t = math.sqrt(math.log(1/(p**2)))
        c0,c1,c2 = 2.515517,0.802853,0.010328
        d1,d2,d3 = 1.432788,0.189269,0.001308

        pn,pd = c0+t*(c1+c2*t), ((d3*t+d2)*t+d1)*t+1
        x = pn/pd - t
        for i in range(1,3+1):
            x-=(Distri.normalCDF(x)-p)/Distri.normalPDF(x)
        return x

    @staticmethod
    def exponencialCDF(x,d1,d2=None):
        if d2 == None:
            return 1 - math.exp(-x/d1)

        if d1 < x  or d2 <=0:
            print("Erro na exponencialCDF: x2 deve ser maior que x1")
            return
        return Distri.exponencialCDF(d1,d2)-Distri.exponencialCDF(x,d2)

    @staticmethod
    def possionCDF(lam,k1,k2):
        p,el = 0,math.exp(-lam)

        for k in range(k1,k2+1):
            p+=math.pow(lam,k)/Distri.fatorial(k)
        return p*el

    @staticmethod
    def possionPDF(lam, k):
        return Distri.possionCDF(lam,k,k)

    @staticmethod
    def rayleighCDF(x,sig):
        sig2 = 2*sig**2
        return 1-math.exp(-x**2/sig2)

    @staticmethod
    def rayleighPDF(x,sig):
        sig2 = 2*sig**2
        return x/sig2*math.exp(-x**2/sig2)

    @staticmethod
    def gamma(x):
        if math.abs(x) < 1e-4:
            print("erro!!")
            return
        s = 1.000000000190015
        p = [76.18009172947146,-86.50532032941677,
             24.01409824083091,-1.231739572450155,
             1.208650973866179E-3,-5.395239384953E-6]
        r2pi = 2.5066282746310005
        for n,i in enumerate(p,1):
            s+=i/(x+n)
        s*=r2pi/x
        return s*math.pow(x+5.5,x+0.5)*math.exp(-x-5.5)

    @staticmethod
    def betaPDF(a,b,x):
        return math.pow(x,a-1)*math.pow(1-x,b-1)/Distri.beta(a,b)

    @staticmethod
    def betaCDF(a,b,x):
        Distri.aa_beta,Distri.bb_beta = a,b
        return Distri.integral(0,x)

    @staticmethod
    def beta(x,y):
        return (Distri.gamma(x)*Distri.gamma(y))/Distri.gamma(x+y)

    @staticmethod
    def integral(a,b,tol=None):
        return Distri.adap(a,b,1e-15 if tol else tol)

    @staticmethod
    def adap(a,b,tol):
        cont,c = 0,(a+b)/2
        sab,sac,scb=Distri.simp(a,b),Distri.simp(a,c),Distri.simp(c,b)
        if math.abs(sab-sac-scb) < tol or cont>=300:
            ad = sac+scb
        else:
            ad = Distri.adap(a,c,tol/2)+Distri.adap(c,c,tol/2)
        cont+=1
        return ad

    @staticmethod
    def simp(a,b):
        return (b-a)/6*(Distri.FunPDF(a)+4*Distri.FunPDF(a+b/2)+Distri.FunPDF(b))

    @staticmethod
    def FunPDF(x):
        return Distri.betaPDF(Distri.aa_beta,Distri.bb_beta,x)


def f(nums):
    nums.sort()
    day=1
    idx=0
    while True:
        if nums[idx]>=day:
            day+=1
            idx+=1
        else:
            idx+=1
        if idx==len(nums): break
    return day-1
input()
nums=[int(x) for x in input().split()]
print(f(nums))


import math

def create_statement_data(invoice, plays):
    def play_for(a_performance):
        return plays[a_performance["playID"]]

    def amount_for(a_performance):
        result = 0
        if a_performance["play"]["type"] == "tragedy":
            result = 40000
            if a_performance["audience"] > 30:
                result += 1000 * (a_performance["audience"] - 30)
        elif a_performance["play"]["type"] == "comedy":
            result = 30000
            if a_performance["audience"] > 20:
                result += 1000 + 500 * (a_performance["audience"] - 20)
            result += 300 * a_performance["audience"]
        else:
            raise ValueError("unknown type: {}".format(a_performance["play"]["type"]))

        return result

    def volume_credits_for(perf):
        result = 0
        result += max(perf["audience"] - 30, 0)
        # add extra credit for every ten comedy attendees
        if "comedy" == perf["play"]["type"]:
            result += math.floor(perf["audience"] / 5)
        return result

    def enrich_performance(a_performance):
        result = a_performance.copy()
        result["play"] = play_for(result)
        result["amount"] = amount_for(result)
        result["volume_credits"] = volume_credits_for(result)
        return result

    def total_amount(data):
        result = 0
        for perf in data["performances"]:
            result += perf['amount']
        return result

    def total_volume_credits(data):
        result = 0
        for perf in data["performances"]:
            result += perf["volume_credits"]
        return result

    result = {}
    result['customer'] = invoice['customer']
    result['performances'] = list(map(enrich_performance, invoice['performances']))
    result["total_amount"] = total_amount(result)
    result["total_volume_credits"] = total_volume_credits(result)
    return result


import random

def isTriangle(piece1, piece2, piece3):
# REFERENCE: https://www.mathwarehouse.com/geometry/triangles/triangle-inequality-theorem-rule-explained.php
    # a + b > c and a + c > b and b + c > a
    if(((piece1 + piece2) > piece3) and ((piece1 + piece3) > piece2) and ((piece2 + piece3) > piece1)): #check if the 3 pieces/sides form a valid triangle using the Triangle Inequality Theorem
        return 1
    return 0

def monteCarlo():
    runs = 10000
    count = 0
    numValid = 0

    while(count < runs): #run 10,000 times
       #creating the sides of the triangle
        a = 0
        b = 0

        #creating the 2 random break points
        for i in range(2):
            a = random.random()
            b = random.random()
            # print(a, " ", b)

        breakA = min(a, b)
        breakB = max(a, b)

        #break stick into 3 pieces for the 3 sides
        piece1 = breakA
        piece2 = breakB - breakA
        piece3 = 1 - breakB

        if(isTriangle(piece1, piece2, piece3)): #check if the 3 sides can make a triangle
            numValid +=1
        count+=1

    probability = round((numValid / runs), 3) #make sure we have 3 sig figs

    print("The probablity that a 1 meter stick can be arranged into a triangle is:", probability)

if __name__ == '__main__':
    monteCarlo()


import matplotlib.pyplot as plt
from sympy import *
def WBE(Z,N):
    "Returns a sympy version of Emperical Mass Formula"
   # Z=symbols('Z')
   # N=symbols('N')
    A=N+Z
    a1=15.49
    a2=17.23
    a3=.697
    a4=22.6
    equation=(a1*A-a2*A**(2.0/3.0)-a4*(N-Z)**2/A-a3*Z**2/A**(1/3.0))

    return equation

#def GetNeutronDrip(A,Z):
    #N=A-Z
Z=Symbol('Z')
N=Symbol('N')
Zs=list(range(1,120))
NeutronDrips=[]
for z in Zs:
    try:
        NeutronDrips.append(mpmath.findroot(lambda N: WBE(z,N),z*5))
    except:
        NeutronDrips.append(mpmath.findroot(lambda N: WBE(z,N),z*8))
    print(z)
NeutronMax=[]

Nn=list(range(100))
plt.plot(Zs,NeutronDrips)
plt.title("Neutron Drip Line")
plt.xlabel("Z Value")
plt.ylabel("N Value at Z Value")
WBs=[]
for i in Nn:
    WBs.append(WBE(8,i))
#plt.plot(Nn,WBs)
plt.show()
#print(WBE(Z,N))
#print(solve(WBE(Z,N),Z))
#print(mpmath.findroot(lambda N: WBE(8,N),8))
#mpmath.plot(lambda N: WBE(8,N),[0,20])
#mpmath.plot(lambda x: mpmath.exp(x)*mpmath.li(x), [1, 4])


import logging

#Setup for logging
logging.basicConfig(filename='app.log',
    format='%(asctime)s:%(levelname)s:%(message)s'
)

class PhoneEntry:
    '''
    Each contact is saved as a PhoneEntry in the PhoneBook where
    an entry has a name and a number
    '''
    def __init__(self, name, number):
        self.name = name
        self.number = number

    def display(self):
        print('{}={}'.format(self.name, self.number))

    @staticmethod
    def validateNumber(number):
        ans = False
        if(len(number) != 8):
            errorMsg = 'Number length should be equal to 8: ' + number
            logging.error(errorMsg)
        elif any(char not in '0123456789' for char in number):
            errorMsg = 'Numbers should only contain digits 0-9: ' + number
            logging.error(errorMsg)
        else:
            ans = True
        return ans

    @staticmethod
    def validateName(name):
        lowerCaseName = name.lower()
        ans = False
        if any(c not in 'abcdefghijklmnopqrstuvwxyz' for c in lowerCaseName):
            errorMsg = 'Name should only containg English alphabet: ' + lowerCaseName
            logging.error(errorMsg)
        else:
            ans = True
        return ans


'''
Source: https://leetcode.com/problems/reverse-string/
Author: Vishal Prabhachandar
Date: 2021-June-02

Time complexity: O(n)
Space complexity: O(1)
'''

class Solution:
    def reverseString(self, s: List[str]) -> None:
        '''
        reverse string 's' in-place

        :param s: List of strings
        :return None
        '''
        strLength = len(s)
        for index in range(0, strLength//2):
            s[index],s[strLength-index-1]=s[strLength-index-1],s[index]

        # alternate solution using slice notation
        # s[:] = s[::-1]
        # alternate solution using inbuilt function
        # s.reverse()


## 배열

# 상하좌우 4방향탐색
'''dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
cx = 2
cy = 3
for i in range(0, 4):
    nx = cx + dx[i]
    ny = cy + dy[i]
    print('nx : ', nx, 'ny : ', ny)'''

### 검색

# 순차검색
'''data = [3,2,4,6,7,9,10,5,1]
key = 8
flag = False
cnt = 0
for i in data:
    cnt+=1
    if i == key:
        flag = True

if flag:
    print('Y')
else:
    print('N')
print('cnt : ', cnt)'''

# 이진검색
def selectSort(n):
    for i in range(n):
        maxIdx = 0
        for j in range(1, n-i):
            if data[maxIdx] < data[j]:
                maxIdx = j
        data[n-1-i], data[maxIdx] = data[maxIdx], data[n-1-i]

'''def mergeSort(start, end): # 오류 해결 필요
    if start < end:
        mid = int((start+end)/2)
        mergeSort(start, mid)
        mergeSort(mid+1, end)

        p = start
        q = mid+1
        idx = start
        while p<=mid or q<=end:
            if q > end or (p<=mid and data[p] < data[q]):
                temp[idx] = data[p]
                idx+=1
                p+=1
            else:
                temp[idx] = data[q]
                idx += 1
                p += 1
        for i in range(start, end+1):
            data[i] = temp[i]'''
def mergeSort(s, e):
    if s<e:
        m = int((s+e)/2)
        mergeSort(s, m)
        mergeSort(m+1, e)

        p = s
        q = m+1
        idx = s
        while p<=m or q<=e:
            if q>e or (p<=m and data[p] < data[q]):
                temp[idx] = data[p]
                idx+=1
                p+=1
            else:
                temp[idx] = data[q]
                idx += 1
                q += 1

        for i in range(s, e+1):
            data[i] = temp[i]

searchCnt = 0
# log2 N
def binarySearch(s, e, key):
    global searchCnt
    while s <= e:
        searchCnt+=1
        m = int((s+e)/2)
        if data[m] < key:
            s = m+1
        elif data[m] > key:
            e = m - 1
        else:
            return m
    return -1

def binarySearch2(s, e, key): # lis 알고리즘 구글링 필요
    while s <= e:
        m = int((s+e)/2)
        if data[m] < key:
            s = m+1
        elif data[m] > key:
            e = m - 1
        else:
            return m
    if data[s] < key:
        return s+1
    else:
        return s

n = 10
data = [1, 2, 11, 4, 3, 6, 5, 8, 7, 9, 10]
temp = [0]*len(data)
print('정렬 전 ', data)
# selectSort(n)
# mergeSort(0, n-1)
print('정렬 후 ', data)
'''
idx = binarySearch(0, n-1, 11)
print(idx)
print(searchCnt)
'''
key = 4
idx = binarySearch2(0, n-1, key)
print(idx)


import socket

# Connecting to a local server
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("localhost", 8000))
# msg = b"Hi Server"
# print ("Client:", msg)
# s.send(msg)
message_from_server = client_socket.recv(1024)
print("Server:", message_from_server)

end_of_the_game = False
while end_of_the_game != True: #repeat it until the end of the game equals to True
    user_input = input("Let's try: ")
    client_socket.send(str.encode(user_input))
    print("Client:", user_input)
    response = client_socket.recv(1024) #receive response
    print(response.decode('utf-8')) #print receiving message from server
    if len(response.decode('utf-8')) > 10:
        end_of_the_game = False
    else:
        end_of_the_game = True
client_socket.close()


matrix = [[1, 2, 3],
          [4, 5, 6],
          [7, 8, 9]]

max_product = float('-inf')  # инициализируем начальное максимальное произведение как отрицательную бесконечность
max_product_row = []  # переменная для хранения строк с максимальными произведениями

for j in range(0, len(matrix[0]), 2):
    column = [matrix[i][j] for i in range(len(matrix))]  # извлекаем нечетный столбец

    # Сортируем столбец по возрастанию
    sorted_column = sorted(column)

    # Находим два наибольших элемента
    top1, top2 = sorted_column[-2:]

    # Находим произведение этих элементов
    current_product = top1 * top2

    # Сравниваем с текущим максимальным произведением
    if current_product > max_product:
        max_product = current_product
        max_product_row = [matrix[i] for i in range(len(matrix))]  # Сохраняем строки с максимальными произведениями

print(f"Максимальное произведение двух элементов среди нечетных столбцов матрицы: {max_product}")
print(f"Строки с максимальными произведениями двух элементов:\n{max_product_row}")


# Neste problema, deve-se ler o código de uma peça 1, o número de peças 1, o valor unitário de cada peça 1, o código de uma peça 2, o número de peças 2 e o valor unitário de cada peça 2. Após, calcule e mostre o valor a ser pago.

cod1 = int(input('Códido da peça: '))
num1 = int(input('Número de peças: '))
val1 = float(input('Valor de cada peça: '))
print('Peça 2.')
cod2 = int(input('Códido da peça: '))
num2 = int(input('Número de peças: '))
val2 = float(input('Valor de cada peça: '))

sub1 = num1 * val1
sub2 = num2 * val2
tot = sub1 + sub2

print('VALOR A PAGAR: ', tot)


# Scrapy settings for BlogRipper project
#
# For simplicity, this file contains only the most important settings by
# default. All the other settings are documented here:
#
#     http://doc.scrapy.org/en/latest/topics/settings.html
#

BOT_NAME = 'BlogRipper'

LOG_LEVEL = 'INFO'

SPIDER_MODULES = ['BlogRipper.spiders']
NEWSPIDER_MODULE = 'BlogRipper.spiders'

FEED_EXPORTERS = {
    'md': 'BlogRipper.exporters.MarkdownItemExporter',
}


import matplotlib.pyplot as plt
import numpy as np
import numpy.random as rng

ny, nx = 5, 6

y = np.arange(0, ny)
x = np.arange(0, nx)

# x-component of covariance
Cx = np.zeros((nx, nx))
for i in range(nx):
    for j in range(nx):
        Cx[i, j] = np.exp(-0.5*((x[i] - x[j])/1.0)**2)
    Cx[i, i] += 1E-6

# y-component of covariance
Cy = np.zeros((ny, ny))
for i in range(ny):
    for j in range(ny):
        Cy[i, j] = np.exp(-0.5*((y[i] - y[j])/1.0)**2)
    Cy[i, i] += 1E-6

# Eigen decompositions
Ex, Vx = np.linalg.eig(Cx)
Ey, Vy = np.linalg.eig(Cy)

# Explicit full covariance matrix
n = nx*ny
C = np.zeros((n, n))
for i in range(n):
    for j in range(n):
        dx = x[i % nx] - x[j % nx]
        dy = y[i // nx] - y[j // nx]
        rsq = dx**2 + dy**2
        C[i, j] = np.exp(-0.5*rsq/1.0**2)
    C[i, i] += 1E-6
# C would equal np.kron(Cy, Cx) if it weren't for the extra diagonal bit.

# Some data
L = np.linalg.cholesky(C)
ns = rng.randn(n)
ys = C @ ns
img = ys.reshape((ny, nx))
plt.imshow(img)
plt.show()

# Explicit solve
logl0 = -n*0.5*np.log(2*np.pi) - 0.5*np.log(np.linalg.det(C)) \
                - 0.5*np.dot(ys, np.linalg.solve(C, ys))

# Cholesky solve
logl1 = -n*0.5*np.log(2*np.pi) - np.sum(np.log(np.diag(L))) \
                - 0.5*np.dot(ys, ns)

# Kronecker solve
E = np.kron(Ey, Ex) # All eigenvalues of C

# Dot product of the data against eigenvectors of C
# = the data represented in that basis
coeffs = np.zeros(n)
k = 0
for i in range(ny):
    for j in range(nx):
        V = np.kron(Vy[:,i], Vx[:,j])
        coeffs[k] = np.dot(ys, V)
        k += 1

logl2 = -n*0.5*np.log(2*np.pi) - 0.5*np.sum(np.log(E)) \
                - 0.5*np.dot(coeffs, coeffs/E)

# Eigendecomposition: C = V @ diag(E) @ V.T since C is symmetric V.T = Vinv

# First two should be equal, third should be close.
print(logl0, logl1, logl2)
plt.plot(coeffs)
plt.show()


# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %%
import zmq
import numpy as np
import math
from IPython.display import clear_output, display
from inputs import get_gamepad
import msgpack
import time
import threading

context = zmq.Context()

#  Socket to talk to server
print("Connecting to hello world server…")
socket = context.socket(zmq.PUB)
socket.bind("tcp://0.0.0.0:5555")
# socket.connect("tcp://192.168.50.234:5555")

#  Do 10 requests, waiting each time for a response
# for request in range(10):
#     print("Sending request %s …" % request)
#     socket.send(b"Hello")

#     #  Get the reply.
#     message = socket.recv()
#     print("Received reply %s [ %s ]" % (request, message))

# %%
def joystickToDiff(x, y, minSpeed, maxSpeed, minJoystick=-1.0, maxJoystick=1.0):    # If x and y are 0, then there is not much to calculate...
    if x == 0.0 and y == 0.0:
        return (0.0, 0.0)

    direction = np.arctan2(y, x)
    xmax = np.minimum(1.0, np.abs(np.cos(direction)))
    ymax = np.minimum(1.0, np.abs(np.sin(direction)))
    speed = np.hypot(x,y) / np.hypot(xmax,ymax)
    display("d {}  s {} ".format(direction, speed))

    straight_treshold = np.pi / 8
    if np.abs(direction - np.pi/2.0) < straight_treshold:
        return (speed, speed)
    elif np.abs(direction + np.pi/2.0) < straight_treshold:
        return (-speed, -speed)
    # elif y > 0:

    # First Compute the angle in deg
    # First hypotenuse
    z = math.sqrt(x * x + y * y)

    # angle in radians
    rad = math.acos(math.fabs(x) / z)

    # and in degrees
    angle = rad * 180 / math.pi

    # Now angle indicates the measure of turn
    # Along a straight line, with an angle o, the turn co-efficient is same
    # this applies for angles between 0-90, with angle 0 the coeff is -1
    # with angle 45, the co-efficient is 0 and with angle 90, it is 1

    tcoeff = -1 + (angle / 90) * 2
    turn = tcoeff * math.fabs(math.fabs(y) - math.fabs(x))
    turn = round(turn * 100, 0) / 100

    # And max of y or x is the movement
    mov = max(math.fabs(y), math.fabs(x))

    # First and third quadrant
    if (x >= 0 and y >= 0) or (x < 0 and y < 0):
        rawLeft = mov
        rawRight = turn
    else:
        rawRight = mov
        rawLeft = turn

    # Reverse polarity
    if y < 0:
        rawLeft = 0 - rawLeft
        rawRight = 0 - rawRight

    # minJoystick, maxJoystick, minSpeed, maxSpeed
    # Map the values onto the defined rang
    rightOut = limit(rawRight, minJoystick, maxJoystick, minSpeed, maxSpeed)
    leftOut = limit(rawLeft, minJoystick, maxJoystick, minSpeed, maxSpeed)

    return (rightOut, leftOut)

def limit(v, in_min, in_max, out_min, out_max):
    # Check that the value is at least in_min
    if v < in_min:
        v = in_min
    # Check that the value is at most in_max
    if v > in_max:
        v = in_max
    return (v - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

print(1,1,joystickToDiff(1,1,-100,100))
print(0,0,joystickToDiff(0,0,-100,100))
print(-1,-1,joystickToDiff(-1,-1,-100,100))

# %%
class Messages:
    def control(lr):
        return msgpack.packb({
            "type": "control-wheels",
            "left": lr[0],
            "right": lr[1]
        })

class Control():
    MODE_TRIGGER = "trigger"
    MODE_STICK = "stick"
    mode = 'trigger'

    rx = 0
    ry = 0
    trigger = [0.0, 0.0]
    bumper = [False, False]

    th_read_joy = None
    th_send_control = None

    @staticmethod
    def norm(value):
        low, high = 129.0, 32768.0
        return (np.maximum(0.0,np.abs(value)-low) / (high - low)) * np.sign(value)

    @classmethod
    def start(cls):
        cls.th_read_joy = threading.Thread(target=cls.read_joy)
        cls.th_read_joy.start()
        cls.th_send_control = threading.Thread(target=cls.send_control)
        cls.th_send_control.start()

    @classmethod
    def read_joy(cls):
        while True:
            events = get_gamepad()
            if len(events) == 0:
                print('sleep')
                time.sleep(0.1)
            else:
                for event in events:
                    # print(event.ev_type, event.code, event.state)
                    if event.ev_type == "Absolute":
                        if event.code == "ABS_RX":
                            cls.rx = cls.norm(event.state)
                        elif event.code == "ABS_RY":
                            cls.ry = -cls.norm(event.state)
                        elif event.code == "ABS_Z":
                            cls.trigger[0] = event.state / 255.0
                        elif event.code == "ABS_RZ":
                            cls.trigger[1] = event.state / 255.0
                    if event.ev_type == "Key":
                        if event.code == "BTN_TL":
                            cls.bumper[0] = event.state == 1
                        if event.code == "BTN_TR":
                            cls.bumper[1] = event.state == 1
    @classmethod
    def send_control(cls):
        while True:
            if cls.mode == cls.MODE_STICK:
                left, right = joystickToDiff(cls.rx, cls.ry, -1.0, 1.0)

            elif cls.mode == cls.MODE_TRIGGER:
                left = cls.trigger[0]
                if cls.bumper[0]:
                    left *= -1
                right = cls.trigger[1]
                if cls.bumper[1]:
                    right *= -1

            # display((cls.rx, cls.ry))
            print(cls.mode, left, right)
            socket.send(Messages.control((left, right)))
            # socket.recv()
            time.sleep(0.1)

Control.start()
Control.th_read_joy.join()
# while True:
#     clear_output(wait=True)
#     c.read_joy()
#     c.send_controll()
#     time.sleep(0.01)


from boto3 import Session
from botocore.exceptions import BotoCoreError, ClientError
from rgbmatrix import RGBMatrix, RGBMatrixOptions
from PIL import Image
from pydub import AudioSegment
from pydub.playback import play
import openai
import json
import time
import threading
import io
import pyaudio
import numpy as np
import wave
import os

openai.api_key = os.environ["OPENAI_API_KEY"]
messages = [
        {"role": "system", "content": "Your name is Kevin, and you are a conversational chatbot that a companion for a lonely person. If innaprporiate language is used, do not mention it. Respond accordingly and briefly as if you were in a casual dinner seting. Don't say numbered lists and avoid making responses longer than 3-4 sentences."}
]

face1 = 'faces/face1.jpg'
face2 = 'faces/face2.jpg'
face3 = 'faces/face3.jpg'
face4 = 'faces/face4.jpg'
face5 = 'faces/face5.jpg'
face6 = 'faces/face6.jpg'

mappings = {
        'k': face1,
        'E': face1,
        'i': face2,
        '@': face2,
        'a': face2,
        'e': face2,
        'O': face2,
        't': face3,
        's': face3,
        'S': face3,
        'T': face3,
        'f': face4,
        'sil': face5,
        'p': face5,
        'r': face6,
        'u': face6,
        'o': face6,
}

options = RGBMatrixOptions()
options.rows = 32
options.chain_length = 1
options.parallel = 1
options.hardware_mapping = 'adafruit-hat'

matrix = RGBMatrix(options = options)

session = Session(profile_name="default")
polly = session.client("polly")

FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
CHUNK = 1024
THRESHOLD = 100
SILENCE_TIMEOUT = 2

def gpt_response(prompt):
        messages.append({"role": "user", "content": prompt})
        response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=messages
        )
        content = response['choices'][0]['message']['content']
        messages.append({"role": "assistant", "content": content})
        return content

def tts_lipsync(text):
        audio_response = polly.synthesize_speech(
                Engine="neural",
                Text=text,
                OutputFormat="mp3",
                VoiceId="Stephen")

        visemes_response = polly.synthesize_speech(
                Engine="neural",
                Text=text,
                OutputFormat="json",
                SpeechMarkTypes=["viseme"],
                VoiceId="Stephen")

        audio = audio_response["AudioStream"].read()
        visemes = [json.loads(v) for v in visemes_response["AudioStream"].read().decode().split() if v]

        audio_thread = threading.Thread(target=lambda: play(AudioSegment.from_mp3(io.BytesIO(audio))))
        audio_thread.start()

        time.sleep(1)
        start_time = time.time() * 1000

        for viseme in visemes:
                while time.time() * 1000 - start_time < viseme["time"]:
                        time.sleep(1/1000)
                matrix.SetImage(Image.open(mappings.get(viseme["value"])).rotate(-90))

        matrix.SetImage(Image.open(face5).rotate(-90))
        time.sleep(1)

def main():
        response = gpt_response("Address the user as Ryan. Make an upbeat conversation starter question.")
        print(response)
        tts_lipsync(response)

        audio = pyaudio.PyAudio()
        stream = audio.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK)

        recording = False
        recording_data = []

        silence_timer = None

        print("Listening...")

        while True:
                data = stream.read(CHUNK)
                audio_signal = np.frombuffer(data, dtype=np.int16)

                if max(audio_signal) > THRESHOLD and not recording:
                        recording = True
                        silence_timer = None
                        print("Recording...")

                if recording:
                        recording_data.append(data)

                        if max(audio_signal) <= THRESHOLD:
                                if silence_timer is None:
                                        silence_timer = time.time()
                                elif time.time() - silence_timer >= SILENCE_TIMEOUT:
                                        print("Silence detected, stopping recording")

                                        stream.stop_stream()
                                        stream.close()

                                        with wave.open('recording.wav', "wb") as wf:
                                                wf.setnchannels(CHANNELS)
                                                wf.setsampwidth(audio.get_sample_size(FORMAT))
                                                wf.setframerate(RATE)
                                                wf.writeframes(b"".join(recording_data))

                                        transcript = openai.Audio.transcribe("whisper-1", open('recording.wav', 'rb'))["text"]
                                        print("Transcription:", transcript)
                                        os.remove('recording.wav')

                                        tts_lipsync(gpt_response(transcript))

                                        stream = audio.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK)
                                        recording = False
                                        recording_data = []
                                        print("Listening...")
                        else:
                                silence_timer = None

if __name__ == '__main__':
        main()


"""
Class definition for the handling of the main data collector
"""

import time
import pandas as pd
import numpy as np
import os.path
import copy
from integrator.util import ObtainDataError

class DataCollector:
    """
    Main class for data collection, this class will handle all the others.

    @param database_file_handler (function that yields data blocks; string with csv dataset location; or pandas dataframe): the source data
    @param sources: the difference data sources used
    @param reference_sources (list of DBMapping classes): these are the classes that map different reference variables
    @param reference_engines (list of sqlalchemy engines): the engines to be used by the respective list of reference sources
    @param verbose: output some verbose information
    @param chunksize (default 4*4096): the size of the chunk if the input database is a file or a dataframe
    @param stop_after_chunk (default None): if it should stop collecting after a chunk
    @param skip_missing: if the references are incomplete the row is going to be skipped: THIS MIGHT LEAD TO ADVERSE BEHAVIOURS: SUCH AS EMPTY QUERY/RETURN
    """
    def __init__(self, database_handler, sources=None, reference_sources=None, reference_engines=None, verbose=True, chunksize=4*4096, stop_after_chunk=None, skip_missing=False):
        if type(database_handler) is str: # str input
            if not os.path.isfile(database_handler):
                raise ObtainDataError("Input file does not exist: '{}'! Or we don't have permission to read.".format(database_handler))
            def _db_get():
                for chunk in pd.read_csv(database_handler, chunksize=chunksize):
                    yield chunk
            database_file_handler = _db_get
        elif isinstance(database_handler, pd.DataFrame): # pandas.DataFrame input
            def _db_get():
                for i, j in database_handler.groupby(np.arange(len(database_handler))//chunksize):
                    yield j
            database_file_handler = _db_get
        else: # function that yields chunks
            database_file_handler = database_handler
        self.database_file_handler = database_file_handler
        if type(sources) is not list: #we are avoiding issues here
            sources = [sources]
        self.sources = copy.copy(sources)
        self.checked = False
        self.verbose = verbose
        if reference_sources and reference_engines: #if we possibly doing mapping we need the same number of reference mappers and engine to use with them
            if len(reference_sources) != len(reference_engines):
                raise ObtainDataError('The references sources and engines have different length.')
            self._reference_engines = {i: j for i, j in zip(reference_sources, reference_engines)}
        else:
            self._reference_engines = None
        self._build_reference_graph(reference_sources)
        self.stop_after_chunk = stop_after_chunk
        self.skip_missing = skip_missing

    def _build_reference_graph(self, reference_sources):
        """
        This method builds a graph for future matching of columns.

        @param reference_sources: the references used for dependency resolution
        """
        # print('- Building reference graph.')
        graph = dict()
        if not reference_sources:
            self.reference_graph = None
            return
        for i in reference_sources:
            for a in i.AVAILABLE:
                if a not in graph:
                    graph[a] = {'neighbours': dict()}
                for b in i.AVAILABLE:
                    # if it is the same variable skip
                    if a == b:
                        continue
                    # check if the variable is valid
                    try:
                        # print('|- {} -> {}'.format(a,b), end=' ')
                        i.check_variables_interaction(from_variable=a, to_variables=b)
                    except Exception as e:
                        # print('fail - ', e)
                        continue
                    # print('ok')
                    # add to the neighbours
                    if b not in graph[a]['neighbours']:
                        graph[a]['neighbours'][b] = list()
                    graph[a]['neighbours'][b].append(i) #format: graph [source] "neighbours" [target] = [methods]
        self.reference_graph = graph

    def _minimum_mapping(self, from_variables, to_variables):
        """
        This creates reference variables mapping using the minimum number of jumps possible.

        @param from_variables: the source variables
        @param to_variables: the variables we need
        """
        graph = self.reference_graph
        cur_elements = [(i, []) for i in from_variables]
        target_paths = dict() #this will map target-paths
        if graph:
            while len(cur_elements) > 0:
                ce, cpath = cur_elements.pop(0)
                if ce not in graph or 'visited' in graph[ce]:
                    continue
                else:
                    graph[ce]['visited'] = True
                for i in graph[ce]['neighbours'].keys():
                    if i in to_variables:
                        if i not in target_paths:
                            target_paths[i] = list()
                        for m in graph[ce]['neighbours'][i]:
                            target_paths[i].append((i, [(ce, m)] + cpath))
                    else:
                        for m in graph[ce]['neighbours'][i]:
                            cur_elements.append((i, [(ce, m)] + cpath))
        we_got = set([i for i in target_paths.keys()]).intersection(set(to_variables))
        if len(we_got) < len(to_variables):
            raise ObtainDataError('Not possible to map all the variables. We got "{}". We need "{}".'.format('", "'.join(we_got), '", "'.join(to_variables)))
        # TODO: the next step can be made more efficient by obtaining the minimum cut, in here we are using the shortest path instead
        currently_available = set()
        target_summarized = dict() #format from_variables, to_variables, method
        for target, options in target_paths.items():
            op_len = sorted([(len(i[1]), i) for i in options])
            target_path = op_len[0][1] # let's use the smallest one
            cur_source = target_path[1][0][0]
            cur_method = target_path[1][0][1]
            for i in range(0, len(target_path[1]) - 1):
                cur_source = target_path[1][i+1][0]
                cur_method = target_path[1][i+1][1]
                cur_target = target_path[1][i][0]
                target_summarized[len(target_summarized)] = {'source_variables': [cur_source], 'target_variables': [cur_target], 'method': cur_method}
                cur_method = target_path[1][i][1]
                cur_source = target_path[1][i][0]
            cur_target = target
            target_summarized[len(target_summarized)] = {'source_variables': [cur_source], 'target_variables': [cur_target], 'method': cur_method}
        # the values are compiled to reduce the number of queries
        index = list()
        compiled_targets = dict()
        for i in target_summarized.values():
            query = (i['source_variables'][0], i['method'])
            if query in compiled_targets:
                compiled_targets[query] += i['target_variables']
            else:
                compiled_targets[query] = i['target_variables']
                index.append(query)
        return [(i, compiled_targets[i]) for i in index]

    def reference_check(self, columns):
        """
        Checks if the needed references can be found.

        @param columns: the columns we have currently
        """
        def _flatten(ll):
            ret = list()
            for i in ll:
                if type(i) is list:
                    ret += i
                else:
                    ret.append(i)
            return ret
        missing_references = list(set(_flatten([i.reference for i in self.sources])) - set(columns))
        if len(missing_references) > 0: #if there are some reference columns which we dont have
            compiled_targets = self._minimum_mapping(columns, missing_references)
            index_ref = 0
            for source, target_cols in compiled_targets:
                source_cols, source_method = source
                if self.verbose:
                    print("|- Dependency: {} -> '{}' ({})".format(source_cols, "', '".join(target_cols), source_method))
                self.sources.insert(index_ref, source_method(source_cols, target_cols, self._reference_engines[source_method]))
                index_ref += 1

    def collect(self):
        """
        Collects the data each by chunk.

        For each chunk:
        1. add new columns from the dependency checks
        2. add new columns requested
        """
        start = time.time()
        chunk_id = 0
        for i in self._collect():
            yield i
            chunk_id += 1
            if self.stop_after_chunk is not None and chunk_id >= self.stop_after_chunk:
                return
        if self.verbose:
            print('- Extraction took {:.2f}s'.format(time.time() - start))

    def collect_all(self, filtering_function=None):
        """
        Collect all the data, does the filtering function and returns the complete data frame.

        @param filtering_function (default None): function that will be called with the dataframe (it must return the dataframe)
        """
        all_df = list()
        for i in self.collect():
            if filtering_function:
                i = filtering_function(i)
            all_df.append(i)
        return pd.concat(all_df, sort=False)

    def collect_to_file(self, output_file, filtering_function=None, ignore_file_exists=False, sep=',', index=False, return_dataset=True):
        """
        Collects all the data, does the filtering function on the data and saves it to file. After saving the dataframe may be returned with parameter 'return_dataset'.

        @param output_file: output file
        @param filtering_function (default None): function that will be called with the dataframe (it must return the dataframe)
        @param sep: separator for the output file
        @param return_dataset (default True): if the dataset is going to be returned after this function
        """
        if not os.path.exists(os.path.dirname(os.path.abspath(output_file))):
            raise ObtainDataError('Output file folder does not exists: "{}".'.format(os.path.dirname(os.path.abspath(output_file))))
        if os.path.isfile(output_file) and not ignore_file_exists:
            raise ObtainDataError('Output file already exists: "{}".'.format(output_file))
        start = time.time()
        if return_dataset:
            all_df = self.collect_all(filtering_function)
            if self.verbose:
                print('|- Saving file...', end='')
            all_df.to_csv(output_file, sep=sep, index=index)
        else:
            first_save = True
            for i in self.collect():
                if filtering_function:
                    i = filtering_function(i)
                if first_save:
                    i.to_csv(output_file, sep=sep, index=index)
                    first_save = False
                else:
                    i.to_csv(output_file, sep=sep, index=index, mode='a', header=False)
            print('Dataset', end='')
        if self.verbose:
            print(' saved! Dataframe processing took {:.2f}s'.format(time.time() - start))
        if return_dataset:
            return all_df

    def _collect(self):
        """
        Internal handling of the chunk collection.
        """
        for chunk in self.database_file_handler():
            start_chunk = time.time()
            # if it is a first run we need a column dependency check
            if not self.checked:
                dependency_check = time.time()
                self.reference_check(chunk.columns.values)
                self.checked = True
                if self.verbose:
                    print('|- Dependency resolution in {:.2f}s'.format(time.time() - dependency_check))
            # for each source of data (this will include dependencies)
            for d in self.sources:
                start_time = time.time()
                if self.verbose:
                    print("|- Collecting '{}'".format(d), end='\r')
                # check for missing reference values
                # # reference list
                refs = d.reference
                if type(refs) is not list:
                    refs = [refs]
                reference_missing = {}
                for rc in refs:
                    _n = np.sum(chunk[rc].isna().values)
                    if _n > 0:
                        reference_missing[rc] = _n
                if len(reference_missing) > 0:
                    err = 'Missing reference values for: {}'.format(';'.join(['"{}" ({})'.format(i,j) for i, j in reference_missing.items()])) + '.'
                    if self.skip_missing and self.verbose:
                        print('|* ' + err, end='\n\n')
                    elif self.skip_missing is False:
                        raise ObtainDataError(err + ' Please remove missing values.')
                # if we should skip the missing:
                chunk_search_data = chunk[d.reference]
                if self.skip_missing:
                    chunk_search_data = chunk_search_data.dropna()
                # obtain the data
                if len(chunk_search_data) == 0:
                    print('|- Chunk with no data! Skipping!')
                    ndf = pd.DataFrame(columns=d.reference)
                else:
                    ndf = d.obtain_data(chunk_search_data)
                internal_time = time.time()
                # print(chunk.columns.values)
                # print(chunk.head())
                # print(ndf.columns.values)
                # print(ndf.head())
                try:
                    chunk = chunk.merge(ndf, on=d.reference, how='left', copy=False, validate='many_to_one') #merge the data using the reference variables
                except pd.errors.MergeError as e:
                    if isinstance(ndf[d.reference], pd.Series):
                        raise ObtainDataError("Data extractor '{}' failed. There are duplicate elements. Please disable it. Duplicated elements are '{}'.".format(d, "', '".join([str(i) for i in ndf[d.reference][ndf[d.reference].duplicated(keep=False)].drop_duplicates(keep='first')]))) from pd.errors.MergeError()
                    else: # isinstance(ndf[d.reference], pd.DataFrame)
                        raise ObtainDataError("Data extractor '{}' failed. There are duplicate elements. Please disable it. Duplicated elements are '{}'.".format(d, "', '".join(['<' + ', '.join([str(j) for j in i[1]]) + '>' for i in ndf[d.reference][ndf[d.reference].duplicated(keep=False)].drop_duplicates(keep='first').iterrows()]))) from pd.errors.MergeError()
                if self.verbose:
                    print("|- Source '{}' took {:.2f}s (internal processing {:.2f}s)".format(d, time.time() - start_time, time.time() - internal_time))
            if self.verbose:
                print("- Chunk took {:.2f}s".format(time.time() - start_chunk))
            yield chunk


import torch
import torch.nn as nn

class RNN(nn.Module):
    def __init__(self, input_dim=500, hidden_dim=300, output_dim=100):
        super().__init__()
        self.hidden_layer_size = hidden_dim
        self.rnn = nn.RNN(input_dim, hidden_dim, num_layers=2)
        self.linear = nn.Linear(hidden_dim, output_dim)

    def forward(self, input_seq):
        rnn_out, _ = self.rnn(input_seq.view(len(input_seq), 1, -1))
        predictions = self.linear(rnn_out.view(len(input_seq), -1))
        return predictions


# -*- coding: utf-8 -*-
"""
Created on Tue Nov  7 13:36:36 2017

@author: sraghunath

Linear Regression using Gradient Descent

"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

class LinearRegressionGD(object) :

    def __init__(self,no_iters=20,learning_rate=0.001) :

        self.learning_rate = learning_rate
        self.no_iters = no_iters

    def fit(self,X,y) :

        self.w_ = np.zeros(X.shape[1] + 1)

        self.cost_ = []

        for i in range(self.no_iters) :

            errors = (y - self.get_output(X))

            self.w_[0] = self.learning_rate * errors.sum()

            self.w_[1:] = self.learning_rate * np.dot(X.T,errors)

            self.cost_.append(0.5 * (errors**2).sum())

        return self

    def get_output(self,X) :

        return self.w_[0] + np.dot(self.w_[1:],X.T)

    def predict(self,X_test) :

        return self.get_output(X_test)

df = pd.read_csv('https://raw.githubusercontent.com/rasbt/'
                 'python-machine-learning-book-2nd-edition'
                 '/master/code/ch10/housing.data.txt',
                 header=None,
                 sep='\s+')

df.columns = ['CRIM', 'ZN', 'INDUS', 'CHAS',
              'NOX', 'RM', 'AGE', 'DIS', 'RAD',
              'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']

X = df[['RM']].values

y = df['MEDV'].values

from sklearn.preprocessing import StandardScaler

sc = StandardScaler()

X_std = sc.fit_transform(X)

y_std = sc.fit_transform(y[:,np.newaxis]).flatten()

lmodel = LinearRegressionGD()

lmodel.fit(X_std,y_std)

plt.plot(range(1,lmodel.no_iters+1),lmodel.cost_)

plt.xlabel("Number of epochs")
plt.ylabel("SSE Cost Function")
plt.show()

def linear_plot(X,y,model) :

    plt.scatter(X,y,c="steelblue")
    plt.plot(X,model.predict(X),color="black")


import os
import sys

os.environ['hadoop_home']="C:/hadoop"

print (os.environ.get('hadoop_home'))

from pyspark import SparkConf,SparkContext

def main(sc):
    file= sc.parallelize("a b c c",1)
    rdd=file.flatMap(lambda x:x.split(" "))
    rdd1=rdd.map(lambda w:(w,1))
    rdd2=rdd1.reduceByKey(lambda a,b:a+b)
    print (rdd2.collect())

if __name__ =="__main__":

    conf = SparkConf().setAppName("wordcount")\
        .setMaster("local")
    sc = SparkContext(conf=conf)
    main(sc)


import os, shutil
import matplotlib.pyplot as plt

def set_details(path_raw='', path_proc='', sub='', trial='', signal=''):
    """
    Initialise dictionary of testing details.

	Example:
        path_raw = '/home/joanna/Dropbox/Projects/thisProject/data/raw/'
		path_proc = '/home/joanna/Dropbox/Projects/thisProject/data/proc/'
		sub = 'sub01'
		trial = 'NV_UL'
		signal = 'force'
		type = 'filt' # OR 'raw' OR 'powerspec'

    :param path_raw: file path to raw data
    :type path_raw: str
    :param path_proc: file path to processed data
    :type path_proc: str
    :param sub: subject ID
    :type sub: str
    :param trial: trial
    :type trial: str
	:param signal: signal
    :type signal: str
    :return: file paths to raw and processed data, subject ID, trial, condition type
    :rtype: dict
    """
    try:
        if not os.path.exists(path_proc + sub):
            os.mkdir(path_proc + sub)
    except FileNotFoundError:
        print('Error: Not enough information to create directory for processed data')
    details = {'path_raw': path_raw, 'path_proc': path_proc, 'sub': sub, 'trial': trial, 'signal': signal}
    return details

def save_plot(details=None, cond_type=''):
    """
    If testing details are passed, save plot in directory for processed data.
    Otherwise save plot in local directory.

    :param details: file paths to raw and processed data, subject ID, trial, signal
    :type details: dict
	:param cond_type: condition type (eg. raw, filt, powerspec)
    :type cond_type: str
    :return:
    :rtype:
    """
    if details and cond_type:
        # save figure to processed data directory
        plt.savefig(details['trial'] + '_' + details['signal'] + '_' + cond_type + '.png')
        plt.close()
        shutil.move(details['path_raw'] + details['sub'] + '/' + details['trial'] + '_'  + details['signal'] + '_'  + cond_type + '.png',
                    details['path_proc'] + details['sub'] + '/' + details['trial'] + '_'  + details['signal'] + '_'  + cond_type + '.png')
    else:
        # save figure to local directory
        plt.savefig('figure.png')
        plt.close()

def plot_raw(data, details=None, cond_type='raw'):
    """
    Plot raw data.
    If testing details are passed, plot is saved in directory for processed data.
    Otherwise plot is saved in local directory.

    :param data: data
    :type data: ndarray
    :param details: file paths to raw and processed data, subject ID, trial, signal
    :type details: dict
	:param cond_type: condition type
    :type cond_type: str
    :return:
    :rtype:
    """
    plt.clf()
    plt.close()
    fig = plt.figure()
    plt.plot(data)
    plt.xlabel('Sample')
    plt.ylabel('EMG (a.u.)')
    plt.tight_layout()
    save_plot(details, cond_type)

def plot_filt(data, data_filt, freq, details=None, cond_type='filt'):
    """
    Plot filtered data: short section and full trial.
    If testing details are passed, plot is saved in directory for processed data.
    Otherwise plot is saved in local directory.

    :param data: data
    :type data: ndarray
    :param data_filt: filtered data
    :type data_filt: ndarray
    :param freq: sampling rate (Hz)
    :type freq: int
    :param details: file paths to raw and processed data, subject ID, trial, condition type
    :type details: dict
	:param cond_type: condition type
    :type cond_type: str
    :return:
    :rtype:
    """
    plt.clf()
    fig = plt.figure()
    axes1 = fig.add_subplot(2, 1, 1)
    axes1.set_ylabel('EMG (a.u.), 1 sec')
    axes1.plot(data[0 : 1 * freq], label='raw')
    axes1.plot(data_filt[0 : 1 * freq], label='filtered')
    plt.locator_params(axis='x', nbins=5)
    plt.locator_params(axis='y', nbins=5)
    plt.axis('tight')
    plt.legend(loc='best')
    axes2 = fig.add_subplot(2, 1, 2)
    axes2.set_ylabel('EMG (a.u.), full')
    axes2.set_xlabel('Sample')
    axes2.plot(data)
    axes2.plot(data_filt)
    plt.locator_params(axis='x', nbins=5)
    plt.locator_params(axis='y', nbins=5)
    plt.axis('tight')
    plt.tight_layout()
    save_plot(details, cond_type)
    plt.close()

def plot_powerspec(f, Pxx_den, lowpass, details=None, cond_type='powerspec'):
    """
    Plot power spectrum of data.
    This function requires a power spectral density analysis is first performed on the recorded signal.
    If testing details are passed, plot is saved in directory for processed data.
    Otherwise plot is saved in local directory.

    Example:
        import numpy as np
        import matplotlib.pyplot as plt
        from scipy import signal

        x = np.random.uniform(-1, 1, size=1000)
        x = filter_lowpass(x, 1000, 40)
        f, Pxx_den = signal.welch(x, 1000, nperseg=250)
        plot_powerspec(f, Pxx_den, lowpass=500, details=None, cond_type='powerspec')

    :param f: sample frequencies
    :type f: ndarray
    :param Pxx_den: power spectrum of data
    :type Pxx_den: ndarray
    :param lowpass: lowpass cut-off (Hz)
    :type lowpass: int
    :param details: file paths to raw and processed data, subject ID, trial, condition type
    :type details: dict
	:param cond_type: condition type
    :type cond_type: str
    :return:
    :rtype:
    """
    plt.clf()
    fig = plt.figure(figsize=(11, 7))
    plt.plot(f, Pxx_den, 'k-o')
    plt.xlabel('Frequency [Hz]')
    plt.ylabel('PSD [V**2/Hz]')
    plt.xlim((1, lowpass / 2))
    plt.ylim(0, Pxx_den.max())  # print(Pxx_den.max())
    plt.locator_params(axis='x', nbins=5)
    plt.locator_params(axis='y', nbins=5)
    plt.tight_layout()
    save_plot(details, cond_type)
    plt.close()

def plot_spectrogram(f, t, Sxx, ylim_ul, xmargin, toffset=0, details=None, cond_type='specgram'):
    """
    Plot spectrogram of data.
    This function requires a spectrogram analysis is first performed on the recorded signal.
    If testing details are passed, plot is saved in directory for processed data.
    Otherwise plot is saved in local directory.

    Example:
        import numpy as np
        import matplotlib.pyplot as plt
        from scipy import signal

        x = np.random.uniform(-1, 1, size=1000)
        x = filter_lowpass(x, 1000, 40)
        f, t, Sxx = signal.spectrogram(x, fs=1000, window='hamming', nperseg=256)
        plot_spectrogram(f, t, Sxx, ylim_ul=50, xmargin=2, toffset=2, details=None, cond_type='specgram')

    :param f: sample frequencies
    :type f: ndarray
    :param t: segment times
    :type t: ndarray
    :param Sxx: spectrogram of x. By default, the last axis of Sxx corresponds to the segment times.
    :type Sxx: ndarray
    :param ylim_ul: frequencies upper limit
    :type ylim_ul: int
    :param xmargin: time margin between event and upper or lower limit
    :type xmargin: int
    :param toffset: time offset from event
    :type toffset: int
    :param details: file paths to raw and processed data, subject ID, trial, condition type
    :type details: dict
    :param cond_type: condition type
    :type cond_type: str
    :return:
    :rtype:
    """
    plt.clf()
    fig, ax = plt.subplots(1, figsize=(11,7))
    t = t - toffset
    p = ax.pcolormesh(t, f, Sxx, cmap='RdBu', shading='gouraud')
    fig.colorbar(p)
    plt.ylim((0, ylim_ul))
    plt.xlim((t - xmargin, t + xmargin))
    plt.ylabel('Frequency [Hz]')
    plt.xlabel('Time [sec]')
    plt.locator_params(axis='x', nbins=5)
    plt.locator_params(axis='y', nbins=5)
    plt.tight_layout()
    save_plot(details, cond_type)
    plt.close()