"""
    To use the code, users should to config detpath, annopath and imagesetfile
    detpath is the path for 15 result files, for the format, you can refer to "http://captain.whu.edu.cn/DOTAweb/tasks.html"
    search for PATH_TO_BE_CONFIGURED to config the paths
    Note, the evaluation is on the large scale images
"""
import os
import numpy as np
import dota_utils as util
import re
import time
import pdb
import tqdm
import torch
import torchgeometry as tgm
from detectron2.layers import nms_rotated
## the thresh for nms when merge image
nms_thresh = 0.3

# singlenet with round sample
# threshold = {'roundabout': 0.3, 'tennis-court': 0.2, 'swimming-pool': 0.05, 'storage-tank': 0.3,
#                'soccer-ball-field': 0.3, 'small-vehicle': 0.2, 'ship': 0.2, 'plane': 0.3,
#                'large-vehicle': 0.3, 'helicopter': 0.1, 'harbor': 0.4, 'ground-track-field': 0.4,
#                'bridge': 0.2, 'basketball-court': 0.1, 'baseball-diamond': 0.5}

# singlenet with ellipse sample
threshold = {'roundabout': 0.3, 'tennis-court': 0.2, 'swimming-pool': 0.05, 'storage-tank': 0.3,
               'soccer-ball-field': 0.3, 'small-vehicle': 0.2, 'ship': 0.2, 'plane': 0.3,
               'large-vehicle': 0.2, 'helicopter': 0.1, 'harbor': 0.1, 'ground-track-field': 0.3,
               'bridge': 0.1, 'basketball-court': 0.1, 'baseball-diamond': 0.5,
            'container-crane': nms_thresh, 'airport': nms_thresh, 'helipad': nms_thresh}

# threshold = {'roundabout': nms_thresh, 'tennis-court': nms_thresh, 'swimming-pool': nms_thresh, 'storage-tank': nms_thresh,
#             'soccer-ball-field': nms_thresh, 'small-vehicle': nms_thresh, 'ship': nms_thresh, 'plane': nms_thresh,
#             'large-vehicle': nms_thresh, 'helicopter': nms_thresh, 'harbor': nms_thresh, 'ground-track-field': nms_thresh,
#             'bridge': nms_thresh, 'basketball-court': nms_thresh, 'baseball-diamond': nms_thresh}

# threshold = {'roundabout': nms_thresh, 'tennis-court': nms_thresh, 'swimming-pool': nms_thresh, 'storage-tank': nms_thresh,
#                 'soccer-ball-field': nms_thresh, 'small-vehicle': nms_thresh, 'ship': nms_thresh, 'plane': nms_thresh,
#                 'large-vehicle': nms_thresh, 'helicopter': nms_thresh, 'harbor': nms_thresh, 'ground-track-field': nms_thresh,
#                 'bridge': nms_thresh, 'basketball-court': nms_thresh, 'baseball-diamond': nms_thresh,
#                 'container-crane': nms_thresh, 'airport': nms_thresh, 'helipad': nms_thresh}

def batch_polygonToRotRectangle(bbox):
    """
    :param bbox: The polygon stored in format [x1, y1, x2, y2, x3, y3, x4, y4]
    :return: Rotated Rectangle in format [cx, cy, w, h, theta]
    """
    bbox = torch.stack([bbox[:, 0::2], bbox[:, 1::2]], dim=1)
    angle = torch.atan2(-(bbox[:, 0,1]-bbox[:, 0,0]),
                        bbox[:, 1,1]-bbox[:, 1,0])

    center = torch.zeros(bbox.size(0), 2, 1, dtype=bbox.dtype, device=bbox.device)

    for i in range(4):
        center[:, 0, 0] += bbox[:, 0,i]
        center[:, 1, 0] += bbox[:, 1,i]

    center = center / 4.0
    R = torch.stack([torch.cos(angle), -torch.sin(angle),
                     torch.sin(angle), torch.cos(angle)], dim=1)
    R = R.reshape(-1, 2, 2)

    normalized = torch.matmul(R.transpose(2,1), bbox - center)

    if bbox.size(0) == 0:
        return torch.empty((0, 5), dtype=bbox.dtype, device=bbox.device)

    xmin = torch.min(normalized[:, 0,:], dim=1)[0]
    xmax = torch.max(normalized[:, 0,:], dim=1)[0]
    ymin = torch.min(normalized[:, 1,:], dim=1)[0]
    ymax = torch.max(normalized[:, 1,:], dim=1)[0]

    w = xmax - xmin
    h = ymax - ymin

    center = center.squeeze(-1)
    center_x = center[:, 0]
    center_y = center[:, 1]
    new_box = torch.stack([center_x, center_y, w, h, -tgm.rad2deg(angle)], dim=1)
    return new_box

def py_cpu_nms_poly(dets, thresh):
    scores = dets[:, 8]
    polys = []
    areas = []
    for i in range(len(dets)):
        tm_polygon = polyiou.VectorDouble([dets[i][0], dets[i][1],
                                            dets[i][2], dets[i][3],
                                            dets[i][4], dets[i][5],
                                            dets[i][6], dets[i][7]])
        polys.append(tm_polygon)
    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        ovr = []
        i = order[0]
        keep.append(i)
        for j in range(order.size - 1):
            iou = polyiou.iou_poly(polys[i], polys[order[j + 1]])
            ovr.append(iou)
        ovr = np.array(ovr)
        inds = np.where(ovr <= thresh)[0]
        order = order[inds + 1]
    return keep

def detectron2_rota_nms(dets, cls_name):

    keep = None
    # try:
    scores = dets[:, 8]
    thresh = float(threshold[cls_name])
    rbox = batch_polygonToRotRectangle(torch.from_numpy(dets[:, 0:8])).to(torch.device('cuda'))
    keep = nms_rotated(rbox, torch.from_numpy(scores).to(torch.device('cuda')), thresh)
    keep = keep.to(torch.device('cpu')).numpy()

    return keep

def py_cpu_nms(dets, thresh):
    """Pure Python NMS baseline."""
    #print('dets:', dets)
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]

    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    ## index for dets
    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)
        xx1 = np.maximum(x1[i], x1[order[1:]])
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.minimum(y2[i], y2[order[1:]])

        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        ovr = inter / (areas[i] + areas[order[1:]] - inter)

        inds = np.where(ovr <= thresh)[0]
        order = order[inds + 1]

    return keep

def nmsbynamedict(nameboxdict, nms, cat_name):
    nameboxnmsdict = {x: [] for x in nameboxdict}
    for imgname in tqdm.tqdm(nameboxdict):
        #print('imgname:', imgname)
        #keep = py_cpu_nms(np.array(nameboxdict[imgname]), thresh)
        #print('type nameboxdict:', type(nameboxnmsdict))
        #print('type imgname:', type(imgname))
        #print('type nms:', type(nms))
        keep = nms(np.array(nameboxdict[imgname]), cat_name)
        #print('keep:', keep)
        outdets = []
        #print('nameboxdict[imgname]: ', nameboxnmsdict[imgname])
        for index in keep:
            # print('index:', index)
            outdets.append(nameboxdict[imgname][index])
        nameboxnmsdict[imgname] = outdets
    return nameboxnmsdict
def poly2origpoly(poly, x, y, rate):
    origpoly = []
    for i in range(int(len(poly)/2)):
        tmp_x = float(poly[i * 2] + x) / float(rate)
        tmp_y = float(poly[i * 2 + 1] + y) / float(rate)
        origpoly.append(tmp_x)
        origpoly.append(tmp_y)
    return origpoly

def mergebase(srcpath, dstpath, nms, dota=1):
    filelist = util.GetFileFromThisRootDir(srcpath)
    for fullname in filelist:
        name = util.custombasename(fullname)
        # print('name:', name)
        dstname = os.path.join(dstpath, name + '.txt')
        with open(fullname, 'r') as f_in:
            nameboxdict = {}
            lines = f_in.readlines()
            splitlines = [x.strip().split(' ') for x in lines]
            print("Runninng file merge: {}, numbers: {}".format(name, len(splitlines)))
            for splitline in splitlines:
                subname = splitline[0]
                splitname = subname.split('__')
                oriname = splitname[0]
                pattern1 = re.compile(r'__\d+___\d+')
                #print('subname:', subname)
                x_y = re.findall(pattern1, subname)
                x_y_2 = re.findall(r'\d+', x_y[0])
                x, y = int(x_y_2[0]), int(x_y_2[1])

                pattern2 = re.compile(r'__([\d+\.]+)__\d+___')

                rate = re.findall(pattern2, subname)[0]

                confidence = splitline[1]
                poly = list(map(float, splitline[2:]))
                origpoly = poly2origpoly(poly, x, y, rate)
                det = origpoly
                det.append(confidence)
                det = list(map(float, det))
                if (oriname not in nameboxdict):
                    nameboxdict[oriname] = []
                nameboxdict[oriname].append(det)
                cat_name = name.split('_')[-1]
            nameboxnmsdict = nmsbynamedict(nameboxdict, nms, cat_name)
            with open(dstname, 'w') as f_out:
                for imgname in nameboxnmsdict:
                    for det in nameboxnmsdict[imgname]:
                        #print('det:', det)
                        confidence = det[-1]
                        bbox = det[0:-1]
                        x1, y1, x2, y2, x3, y3, x4, y4 = bbox
                        if dota == 1:
                            line = f"{x1:.1f} {y1:.1f} {x2:.1f} {y2:.1f} {x3:.1f} {y3:.1f} {x4:.1f} {y4:.1f}"
                        if dota == 2:
                            line = f"{x1:.0f} {y1:.0f} {x2:.0f} {y2:.0f} {x3:.0f} {y3:.0f} {x4:.0f} {y4:.0f}"
                        outline = imgname + ' ' + str(confidence) + ' ' + line
                        #print('outline:', outline)
                        f_out.write(outline + '\n')
def mergebyrec(srcpath, dstpath):
    """
    srcpath: result files before merge and nms
    dstpath: result files after merge and nms
    """
    # srcpath = r'E:\bod-dataset\results\bod-v3_rfcn_2000000'
    # dstpath = r'E:\bod-dataset\results\bod-v3_rfcn_2000000_nms'

    mergebase(srcpath,
              dstpath,
              py_cpu_nms)
def mergebypoly(srcpath, dstpath, dota=1):
    """
    srcpath: result files before merge and nms
    dstpath: result files after merge and nms
    """
    # srcpath = r'/home/dingjian/evaluation_task1/result/faster-rcnn-59/comp4_test_results'
    # dstpath = r'/home/dingjian/evaluation_task1/result/faster-rcnn-59/testtime'

    mergebase(srcpath,
              dstpath,
              detectron2_rota_nms, dota)
if __name__ == '__main__':
    # see demo for example
    mergebypoly(r'path_to_configure', r'path_to_configure')
    # mergebyrec()


import asyncio
from contextlib import asynccontextmanager
from typing import AsyncGenerator

from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncConnection

from realtime.message import Message, parse

async def subscribe(
    con: AsyncConnection,
    slot_name: str = "realtime_py",
    poll_delay: float = 0.1,
    drop_on_close: bool = True,
) -> AsyncGenerator[Message, None]:
    """Subscribe to a PostgreSQL +9.4 database for changes"""

    GET_UPDATES = text(
        "SELECT lsn, xid, data from pg_logical_slot_get_changes(:slot_name, NULL, NULL)"
    )

    async with replication_slot(
        slot_name=slot_name, con=con, drop_on_close=drop_on_close
    ):

        while True:
            cursor = await con.execute(GET_UPDATES, {"slot_name": slot_name})

            for _, _, data in cursor:
                yield parse(data)

            # Sleep for 0.25 seconds before polling again
            await asyncio.sleep(poll_delay)

@asynccontextmanager
async def replication_slot(
    slot_name: str, con: AsyncConnection, drop_on_close: bool
) -> AsyncGenerator[None, None]:

    CREATE_SLOT = text(
        """
    with check_exists as (
        SELECT
            count(1) = 1 as already_exists
        FROM
            pg_replication_slots
        WHERE
            slot_name = :slot_name
    )

    SELECT
        CASE
            WHEN already_exists THEN 0
            ELSE (
                SELECT
                    1
                FROM
                    pg_create_logical_replication_slot(
                        :slot_name,
                        'test_decoding'
                    )
            )
        END as res
    FROM
        check_exists
    """
        ""
    )
    DROP_SLOT = text("SELECT pg_drop_replication_slot(:slot_name);")

    params = dict(slot_name=slot_name)

    await con.execute(CREATE_SLOT, params)
    try:
        yield
    finally:
        if drop_on_close:
            await con.execute(DROP_SLOT, params)


import sys
import logging
import datetime
import time

###################################################
# Unlock script
#================================================

# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
#================================================ Android View Client
from com.dtmilano.android.viewclient import ViewClient

###################################################
# Main
###################################################
#==================================================
def main():
    # config logging
    logging.basicConfig(
            level=logging.DEBUG,
            format='%(asctime)s : %(levelname)s %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S',
            filename='Reservior.log',
            filemode='w')

    logging.info('-------------- Begin --------------')
    # Connects to the current device, returning a MonkeyDevice object
    device = MonkeyRunner.waitForConnection()
    vc = ViewClient(device=device, serialno='0123456789ABCDEF', adb=None)

    sim_SN = sys.argv[1]

    print('sim_SN: ' + sim_SN.encode('utf-8'))

    print('start!!!')
    device.wake()

    print('drag screen lock slide!!!')
    device.drag((160, 440), (320, 440), 0.5, 1)
    time.sleep(1)
    print('unlock pin code')
    id_0 = getViewId(vc, u'0')
    print('id_o = ' + str(id_0))
    for i in range(4):
        touchButton(vc, id_0)
    touchButtonByText(vc, u'OK')

    mpr(vc, device, "GW" + sim_SN)

    print('end!!!')
    logging.info('-------------- End --------------')

#==================================================
###################################################
# Function
###################################################
def mpr(vc, device, simSN):
    print('Go to main menu')
    touchButtonByText(vc, u'Main menu')
    print('Go to Replacement')
    touchButtonByText(vc, u'Replace')
    print('Select Pump base')
    touchButtonByText(vc, u'Pump base')
    print('press Replace button')
    touchButtonByText(vc, u'Replace')
    print('press Yes button of remove pump base info')
    touchButtonByText(vc, u'Yes')
    print('press Done button of sidpose system component info')
    touchButtonByText(vc, u'Done')
    print('press Done button of prepare micropump')
    touchButtonByText(vc, u'Done')
    print('press save button of reservior amount')
    touchButtonByText(vc, u'Save')
    print('press next button of paire pump')
    touchButtonByText(vc, u'Next')
    print('select enter pump keys')
    touchButtonByText(vc, u'Enter pump key')
    print('select pump serial number')
    touchButtonByText(vc, simSN)
    # input pin number
    print('input pin number')
    getViewId(vc, u'Enter pump key')
    touchPosition(device, 200, 100)
    time.sleep(2)
    device.type("00000000")
    touchPosition(device, 200, 150)
    touchPosition(device, 280, 40)
    time.sleep(3)
    print('press Fill button')
    touchButtonByText(vc, u'Fill')
    print('press OK button')
    touchButtonByText(vc, u'OK')
    print('press Next button')
    touchButtonByText(vc, u'Next')
    print('insulin button pressed')
    getViewId(vc, u'Activate basal rate profile')
    device.press('KEYCODE_F10', MonkeyDevice.DOWN_AND_UP)
    time.sleep(5)

def isW85(vc):
    try:
        vc.dump(window=-1)
        vc.findViewWithTextOrRaise(u'W-85')
        return True
    except:
        print('No W-85')
        return False

def getDateInfo(device, cmd):
    value = device.shell(cmd)
    return value.encode('utf-8')

def touchButtonByText(vc, text):
    while True:
        try:
            vc.dump(window=-1)
            b = vc.findViewWithTextOrRaise(text)
            b.touch()
            break
        except:
            print('[touchButtonByText] View is not found by text: ' + text.encode('utf-8'))
            logging.info('[touchButtonByText] View is not found by text: ' + text)
            if isW85(vc) == True:
                # press Ok
                touchButtonByText(vc, u'OK')

def getViewId(vc, text):
    id = 0
    while id == 0:
        try:
            vc.dump(window=-1)
            b = vc.findViewWithTextOrRaise(text)
            id = b.getId()
        except:
            print('[getViewId] View is not found by text: ' + text.encode('utf-8'))
            logging.info('[getViewId] View is not found by text: ' + text)
            id = 0
    return id

def touchButton(vc, id):
    try:
       b = vc.findViewByIdOrRaise(id)
       b.touch()
    except:
        print('[touchButton] View is not found by id: ' + str(id))
        logging.info('[touchButton] View is not found by id: ' + str(id))

def touchPosition(device, x, y, delay=1):
    device.touch(x, y, MonkeyDevice.DOWN_AND_UP)
    time.sleep(delay)

if __name__ == '__main__':
    main()


class DSU:
    def __init__(self):
        self.par = list(range(5001)) # 初始化时父亲结点指向自身
        self.rnk = [0] * 5001

    def find(self, x):
        if self.par[x] != x:
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        if xr == yr:
            return False
        elif self.rnk[xr] < self.rnk[yr]:
            self.par[xr] = yr
        elif self.rnk[xr] > self.rnk[yr]:
            self.par[yr] = xr
        else:
            self.par[yr] = xr
            self.rnk[xr] += 1
        return True

class Solution:
    def validTree(self, n: int, edges: List[List[int]]) -> bool:
        uf = DSU()
        for e in edges:
            # 判断有没有环
            if(uf.union(e[0], e[1]) == False):
                return False

        # 图可能没有连通，例如[[1, 2], [3, 4]]
        # 需要判断是不是所有节点的父亲都一样
        par = uf.find(0)
        for i in range(1, n):
            if par != uf.find(i):
                return False
        return True


import threading
#from threading import Thread
import time

luc = threading.Lock()

def funzione_num(num):
    print(f"Partenza del thread {num}")
    print(f"Elaboro...thread {num}")
    time.sleep(2)
    print(f"Finito lavoro del thread {num}")

def funzione():
    print(f"Partenza del thread {threading.current_thread().name}")
    print(f"Elaboro...thread {threading.current_thread().name}")
    time.sleep(2)
    print(f"Finito lavoro del thread {threading.current_thread().name}")

#il main di default è già un thread "MainThread"
def main():
    t = threading.Thread(target=funzione, name="Primo") #target=funzione_num, args=(1,)
    t.start() #fa partire il thread
    t.join() #fa finire il thread "t" prima di iniziare i successivi, vanno sequenzialmente
    q = threading.Thread(target=funzione, name="Secondo") #target=funzione_num, args=(2,)
    q.start()
    q.join()
    #funzione_num(3)
    funzione()
    print("Fine chiamata main.")

if __name__ == "__main__":
    main()


import requests
from speakers import Speakers

class SpeechKitAdapter(object):
    """Класс SpeechKitAdapter реализует получение аудио от сервиса Yandex SpeechKit

    Основное применение - получение аудио от сервиса YSK

    Атрибуты
    --------
    folder_id
        символьный идентификатор рабочего каталога в сервисах cloud.yandex.ru
    api_key
        символьный идентификатор ключа АПИ для сервисов cloud.yandex.ru
    t2sbot
        объект класса TGText2SpeechBot (из tg_bot.py)

    Методы
    ------
    def synthesize(self, text, userinfo):
        отправляет запрос на синтез речи из переданного текста

    async def getAudio(self, chatid, text, asyncinfo, fileid):
        асинхронное получение аудио
    """

    def __init__(self, folder_id, api_key, t2sbot):
        self.__speakersinfo = Speakers()
        self.__folder_id = folder_id
        self.__api_key = api_key
        self.__t2sbot = t2sbot

    def synthesize(self, text, userinfo):
        """Метод для получения синтезированной речи от сервиса cloud.yandex.ru
        Вход: текст для синтеза, объект UserCfg (из usercfg.py)
        Выход: итерируемый объект
        Задача: синтезироваать речь
        """

        url = "https://tts.api.cloud.yandex.net/speech/v1/tts:synthesize"
        headers = {"Authorization": "Api-Key " + self.__api_key}
        data = {
            "text": text,
            "lang": userinfo.getLang(),
            "folderId": self.__folder_id,
            "speed": userinfo.getSpeed(),
            "voice": self.__speakersinfo.getSpeakerId(userinfo.getLang(), userinfo.getSex()),
        }

        with requests.post(url, headers=headers, data=data, stream=True) as resp:
            if resp.status_code != 200:
                raise RuntimeError("Invalid response received: code: %d, message: %s" % (resp.status_code, resp.text))

            for chunk in resp.iter_content(chunk_size=None):
                yield chunk

    async def getAudio(self, chatid, text, asyncinfo, fileid):
        """Метод для формирования
        Вход: идентификатор чата, текст, набор параметров смещения,
            идентификатор файла
        Выход: пусто
        Задача: сохранить полученное аудио
        """

        asyncid = asyncinfo["asyncid"]
        uniqueid = asyncinfo["uniqueid"]
        offset = asyncinfo["offset"]
        userinfo = self.__t2sbot.getuserinfo(chatid)
        audiofile = "synthesizes/%d_%d_%d.ogg" % (chatid, asyncid, fileid)
        with open(audiofile, "wb") as f:
            try:
                shift = offset + uniqueid
                for audio_content in self.synthesize(text[offset:shift], userinfo):
                    f.write(audio_content)
                f.close()
                userinfo.getAsyncMgr().registerUniqueId(asyncid, uniqueid)
                await self.__t2sbot.onReceivedFile(chatid, asyncid, uniqueid)

            except RuntimeError:
                self.__t2sbot.bot.send_message(chatid, "Похоже что волшебная палочка сломалась :(")


'''
# Time:  O(n)
# Space: O(n)
#
# Given a string containing just the characters '(' and ')',
# find the length of the longest valid (well-formed) parentheses substring.
#
# For "(()", the longest valid parentheses substring is "()", which has length = 2.
#
# Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4.
#

'''
def longestValidParentheses(s):
    longest, last, indices = 0, -1, []
    for i in range(len(s)):
        if s[i] == "(":
            indices.append(i)
        elif not indices:
            last = i
        else:
            indices.pop()
            if not indices:
                longest = max(longest,i - last)
            else:
                longest = max(longest, i - indices[-1])
    return longest

print(longestValidParentheses("(()"))


from random import choice
from time import time

from engines.server import global_vars
from engines.sound import Sound

## ALL DECLARATION

__all__ = (
    'Sprint',
    'SPRINT_START_SOUND',
    'LOW_STAMINA_SOUND',
)

## GLOBALS

SPRINT_START_SOUND = Sound('player/suit_sprint.wav')

LOW_STAMINA_SOUND = Sound('player/suit_denydevice.wav')

STEP_SOUNDS = [
    'npc/combine_soldier/gear1.wav',
    'npc/combine_soldier/gear2.wav',
    'npc/combine_soldier/gear3.wav',
    'npc/combine_soldier/gear4.wav',
    'npc/combine_soldier/gear5.wav',
    'npc/combine_soldier/gear6.wav',
]

STEP_SOUND_INTERVAL = 0.3
DEFAULT_PLAYER_SPEED = 1
SPRINTING_PLAYER_SPEED = 1.2
AIRBORNE_PLAYER_SPEED = 1

## CLASS

class Sprint:
    '''
        Allow player to sprint.
        :param BattleRoyalPlayer player:
            A player.
    '''

    def __init__(self, player):
        self.player = player
        self.sprinting = False
        self.key_pressed = False
        self.speed = 0
        self.last_step = 0

        self._step_sounds = []
        for sound_path in STEP_SOUNDS:
            self._step_sounds.append(Sound(sound_path, player.index))

    def ensure_speed(self, speed):
        '''Set player speed.'''
        if self.speed != speed:
            self.speed = speed
            self.player.speed = speed

    def step(self):
        '''Player step sound.'''
        cur_step = time()
        if cur_step - self.last_step >= STEP_SOUND_INTERVAL:
            choice(self._step_sounds).play()
            self.last_step = cur_step

# @OnTick
# def listener_on_tick():
#     for sprinting_player in player_manager.values():
#         if sprinting_player.player.ground_entity == -1:
#             sprinting_player.ensure_speed(AIRBORNE_PLAYER_SPEED)
#         else:
#             if sprinting_player.sprinting:
#                 sprinting_player.ensure_speed(SPRINTING_PLAYER_SPEED)
#             else:
#                 sprinting_player.ensure_speed(DEFAULT_PLAYER_SPEED)

#         if sprinting_player.sprinting:
#             inthandle = sprinting_player.player.active_weapon
#             if inthandle == INVALID_ENTITY_INTHANDLE:
#                 continue

#             entity = Entity(index_from_inthandle(inthandle))
#             entity.next_attack = global_vars.current_time + 1
#             entity.next_secondary_fire_attack = global_vars.current_time + 1


import importlib
import os
import sys
from typing import TYPE_CHECKING

__version__ = "0.19.0.dev0"

# Alphabetical order of definitions is ensured in tests
# WARNING: any comment added in this dictionary definition will be lost when
# re-generating the file !
_SUBMOD_ATTRS = {
    "_commit_scheduler": [
        "CommitScheduler",
    ],
    "_inference_endpoints": [
        "InferenceEndpoint",
        "InferenceEndpointError",
        "InferenceEndpointStatus",
        "InferenceEndpointTimeoutError",
        "InferenceEndpointType",
    ],
    "_login": [
        "interpreter_login",
        "login",
        "logout",
        "notebook_login",
    ],
    "_multi_commits": [
        "MultiCommitException",
        "plan_multi_commits",
    ],
    "_snapshot_download": [
        "snapshot_download",
    ],
    "_space_api": [
        "SpaceHardware",
        "SpaceRuntime",
        "SpaceStage",
        "SpaceStorage",
        "SpaceVariable",
    ],
    "_tensorboard_logger": [
        "HFSummaryWriter",
    ],
    "_webhooks_payload": [
        "WebhookPayload",
        "WebhookPayloadComment",
        "WebhookPayloadDiscussion",
        "WebhookPayloadDiscussionChanges",
        "WebhookPayloadEvent",
        "WebhookPayloadMovedTo",
        "WebhookPayloadRepo",
        "WebhookPayloadUrl",
        "WebhookPayloadWebhook",
    ],
    "_webhooks_server": [
        "WebhooksServer",
        "webhook_endpoint",
    ],
    "community": [
        "Discussion",
        "DiscussionComment",
        "DiscussionCommit",
        "DiscussionEvent",
        "DiscussionStatusChange",
        "DiscussionTitleChange",
        "DiscussionWithDetails",
    ],
    "constants": [
        "CONFIG_NAME",
        "FLAX_WEIGHTS_NAME",
        "HUGGINGFACE_CO_URL_HOME",
        "HUGGINGFACE_CO_URL_TEMPLATE",
        "PYTORCH_WEIGHTS_NAME",
        "REPO_TYPE_DATASET",
        "REPO_TYPE_MODEL",
        "REPO_TYPE_SPACE",
        "TF2_WEIGHTS_NAME",
        "TF_WEIGHTS_NAME",
    ],
    "fastai_utils": [
        "_save_pretrained_fastai",
        "from_pretrained_fastai",
        "push_to_hub_fastai",
    ],
    "file_download": [
        "HfFileMetadata",
        "_CACHED_NO_EXIST",
        "cached_download",
        "get_hf_file_metadata",
        "hf_hub_download",
        "hf_hub_url",
        "try_to_load_from_cache",
    ],
    "hf_api": [
        "Collection",
        "CollectionItem",
        "CommitInfo",
        "CommitOperation",
        "CommitOperationAdd",
        "CommitOperationCopy",
        "CommitOperationDelete",
        "GitCommitInfo",
        "GitRefInfo",
        "GitRefs",
        "HfApi",
        "RepoUrl",
        "User",
        "UserLikes",
        "add_collection_item",
        "add_space_secret",
        "add_space_variable",
        "change_discussion_status",
        "comment_discussion",
        "create_branch",
        "create_collection",
        "create_commit",
        "create_commits_on_pr",
        "create_discussion",
        "create_inference_endpoint",
        "create_pull_request",
        "create_repo",
        "create_tag",
        "dataset_info",
        "delete_branch",
        "delete_collection",
        "delete_collection_item",
        "delete_file",
        "delete_folder",
        "delete_inference_endpoint",
        "delete_repo",
        "delete_space_secret",
        "delete_space_storage",
        "delete_space_variable",
        "delete_tag",
        "duplicate_space",
        "edit_discussion_comment",
        "file_exists",
        "get_collection",
        "get_dataset_tags",
        "get_discussion_details",
        "get_full_repo_name",
        "get_inference_endpoint",
        "get_model_tags",
        "get_repo_discussions",
        "get_space_runtime",
        "get_space_variables",
        "get_token_permission",
        "like",
        "list_datasets",
        "list_files_info",
        "list_inference_endpoints",
        "list_liked_repos",
        "list_metrics",
        "list_models",
        "list_repo_commits",
        "list_repo_files",
        "list_repo_likers",
        "list_repo_refs",
        "list_spaces",
        "merge_pull_request",
        "model_info",
        "move_repo",
        "pause_inference_endpoint",
        "pause_space",
        "preupload_lfs_files",
        "rename_discussion",
        "repo_exists",
        "repo_info",
        "repo_type_and_id_from_hf_id",
        "request_space_hardware",
        "request_space_storage",
        "restart_space",
        "resume_inference_endpoint",
        "run_as_future",
        "scale_to_zero_inference_endpoint",
        "set_space_sleep_time",
        "space_info",
        "super_squash_history",
        "unlike",
        "update_collection_item",
        "update_collection_metadata",
        "update_inference_endpoint",
        "update_repo_visibility",
        "upload_file",
        "upload_folder",
        "whoami",
    ],
    "hf_file_system": [
        "HfFileSystem",
        "HfFileSystemFile",
        "HfFileSystemResolvedPath",
    ],
    "hub_mixin": [
        "ModelHubMixin",
        "PyTorchModelHubMixin",
    ],
    "inference._client": [
        "InferenceClient",
        "InferenceTimeoutError",
    ],
    "inference._generated._async_client": [
        "AsyncInferenceClient",
    ],
    "inference_api": [
        "InferenceApi",
    ],
    "keras_mixin": [
        "KerasModelHubMixin",
        "from_pretrained_keras",
        "push_to_hub_keras",
        "save_pretrained_keras",
    ],
    "repocard": [
        "DatasetCard",
        "ModelCard",
        "RepoCard",
        "SpaceCard",
        "metadata_eval_result",
        "metadata_load",
        "metadata_save",
        "metadata_update",
    ],
    "repocard_data": [
        "CardData",
        "DatasetCardData",
        "EvalResult",
        "ModelCardData",
        "SpaceCardData",
    ],
    "repository": [
        "Repository",
    ],
    "utils": [
        "CacheNotFound",
        "CachedFileInfo",
        "CachedRepoInfo",
        "CachedRevisionInfo",
        "CorruptedCacheException",
        "DeleteCacheStrategy",
        "HFCacheInfo",
        "HfFolder",
        "cached_assets_path",
        "configure_http_backend",
        "dump_environment_info",
        "get_session",
        "logging",
        "scan_cache_dir",
    ],
    "utils.endpoint_helpers": [
        "DatasetFilter",
        "ModelFilter",
    ],
}

def _attach(package_name, submodules=None, submod_attrs=None):
    """Attach lazily loaded submodules, functions, or other attributes.

    Typically, modules import submodules and attributes as follows:

    ```py
    import mysubmodule
    import anothersubmodule

    from .foo import someattr
    ```

    The idea is to replace a package's `__getattr__`, `__dir__`, and
    `__all__`, such that all imports work exactly the way they would
    with normal imports, except that the import occurs upon first use.

    The typical way to call this function, replacing the above imports, is:

    ```python
    __getattr__, __dir__, __all__ = lazy.attach(
        __name__,
        ['mysubmodule', 'anothersubmodule'],
        {'foo': ['someattr']}
    )
    ```
    This functionality requires Python 3.7 or higher.

    Args:
        package_name (`str`):
            Typically use `__name__`.
        submodules (`set`):
            List of submodules to attach.
        submod_attrs (`dict`):
            Dictionary of submodule -> list of attributes / functions.
            These attributes are imported as they are used.

    Returns:
        __getattr__, __dir__, __all__

    """
    if submod_attrs is None:
        submod_attrs = {}

    if submodules is None:
        submodules = set()
    else:
        submodules = set(submodules)

    attr_to_modules = {attr: mod for mod, attrs in submod_attrs.items() for attr in attrs}

    __all__ = list(submodules | attr_to_modules.keys())

    def __getattr__(name):
        if name in submodules:
            return importlib.import_module(f"{package_name}.{name}")
        elif name in attr_to_modules:
            submod_path = f"{package_name}.{attr_to_modules[name]}"
            submod = importlib.import_module(submod_path)
            attr = getattr(submod, name)

            # If the attribute lives in a file (module) with the same
            # name as the attribute, ensure that the attribute and *not*
            # the module is accessible on the package.
            if name == attr_to_modules[name]:
                pkg = sys.modules[package_name]
                pkg.__dict__[name] = attr

            return attr
        else:
            raise AttributeError(f"No {package_name} attribute {name}")

    def __dir__():
        return __all__

    if os.environ.get("EAGER_IMPORT", ""):
        for attr in set(attr_to_modules.keys()) | submodules:
            __getattr__(attr)

    return __getattr__, __dir__, list(__all__)

__getattr__, __dir__, __all__ = _attach(__name__, submodules=[], submod_attrs=_SUBMOD_ATTRS)

# WARNING: any content below this statement is generated automatically. Any manual edit
# will be lost when re-generating this file !
#
# To update the static imports, please run the following command and commit the changes.
# ```
# # Use script
# python utils/check_static_imports.py --update-file
#
# # Or run style on codebase
# make style
# ```
if TYPE_CHECKING:  # pragma: no cover
    from ._commit_scheduler import CommitScheduler  # noqa: F401
    from ._inference_endpoints import (
        InferenceEndpoint,  # noqa: F401
        InferenceEndpointError,  # noqa: F401
        InferenceEndpointStatus,  # noqa: F401
        InferenceEndpointTimeoutError,  # noqa: F401
        InferenceEndpointType,  # noqa: F401
    )
    from ._login import (
        interpreter_login,  # noqa: F401
        login,  # noqa: F401
        logout,  # noqa: F401
        notebook_login,  # noqa: F401
    )
    from ._multi_commits import (
        MultiCommitException,  # noqa: F401
        plan_multi_commits,  # noqa: F401
    )
    from ._snapshot_download import snapshot_download  # noqa: F401
    from ._space_api import (
        SpaceHardware,  # noqa: F401
        SpaceRuntime,  # noqa: F401
        SpaceStage,  # noqa: F401
        SpaceStorage,  # noqa: F401
        SpaceVariable,  # noqa: F401
    )
    from ._tensorboard_logger import HFSummaryWriter  # noqa: F401
    from ._webhooks_payload import (
        WebhookPayload,  # noqa: F401
        WebhookPayloadComment,  # noqa: F401
        WebhookPayloadDiscussion,  # noqa: F401
        WebhookPayloadDiscussionChanges,  # noqa: F401
        WebhookPayloadEvent,  # noqa: F401
        WebhookPayloadMovedTo,  # noqa: F401
        WebhookPayloadRepo,  # noqa: F401
        WebhookPayloadUrl,  # noqa: F401
        WebhookPayloadWebhook,  # noqa: F401
    )
    from ._webhooks_server import (
        WebhooksServer,  # noqa: F401
        webhook_endpoint,  # noqa: F401
    )
    from .community import (
        Discussion,  # noqa: F401
        DiscussionComment,  # noqa: F401
        DiscussionCommit,  # noqa: F401
        DiscussionEvent,  # noqa: F401
        DiscussionStatusChange,  # noqa: F401
        DiscussionTitleChange,  # noqa: F401
        DiscussionWithDetails,  # noqa: F401
    )
    from .constants import (
        CONFIG_NAME,  # noqa: F401
        FLAX_WEIGHTS_NAME,  # noqa: F401
        HUGGINGFACE_CO_URL_HOME,  # noqa: F401
        HUGGINGFACE_CO_URL_TEMPLATE,  # noqa: F401
        PYTORCH_WEIGHTS_NAME,  # noqa: F401
        REPO_TYPE_DATASET,  # noqa: F401
        REPO_TYPE_MODEL,  # noqa: F401
        REPO_TYPE_SPACE,  # noqa: F401
        TF2_WEIGHTS_NAME,  # noqa: F401
        TF_WEIGHTS_NAME,  # noqa: F401
    )
    from .fastai_utils import (
        _save_pretrained_fastai,  # noqa: F401
        from_pretrained_fastai,  # noqa: F401
        push_to_hub_fastai,  # noqa: F401
    )
    from .file_download import (
        _CACHED_NO_EXIST,  # noqa: F401
        HfFileMetadata,  # noqa: F401
        cached_download,  # noqa: F401
        get_hf_file_metadata,  # noqa: F401
        hf_hub_download,  # noqa: F401
        hf_hub_url,  # noqa: F401
        try_to_load_from_cache,  # noqa: F401
    )
    from .hf_api import (
        Collection,  # noqa: F401
        CollectionItem,  # noqa: F401
        CommitInfo,  # noqa: F401
        CommitOperation,  # noqa: F401
        CommitOperationAdd,  # noqa: F401
        CommitOperationCopy,  # noqa: F401
        CommitOperationDelete,  # noqa: F401
        GitCommitInfo,  # noqa: F401
        GitRefInfo,  # noqa: F401
        GitRefs,  # noqa: F401
        HfApi,  # noqa: F401
        RepoUrl,  # noqa: F401
        User,  # noqa: F401
        UserLikes,  # noqa: F401
        add_collection_item,  # noqa: F401
        add_space_secret,  # noqa: F401
        add_space_variable,  # noqa: F401
        change_discussion_status,  # noqa: F401
        comment_discussion,  # noqa: F401
        create_branch,  # noqa: F401
        create_collection,  # noqa: F401
        create_commit,  # noqa: F401
        create_commits_on_pr,  # noqa: F401
        create_discussion,  # noqa: F401
        create_inference_endpoint,  # noqa: F401
        create_pull_request,  # noqa: F401
        create_repo,  # noqa: F401
        create_tag,  # noqa: F401
        dataset_info,  # noqa: F401
        delete_branch,  # noqa: F401
        delete_collection,  # noqa: F401
        delete_collection_item,  # noqa: F401
        delete_file,  # noqa: F401
        delete_folder,  # noqa: F401
        delete_inference_endpoint,  # noqa: F401
        delete_repo,  # noqa: F401
        delete_space_secret,  # noqa: F401
        delete_space_storage,  # noqa: F401
        delete_space_variable,  # noqa: F401
        delete_tag,  # noqa: F401
        duplicate_space,  # noqa: F401
        edit_discussion_comment,  # noqa: F401
        file_exists,  # noqa: F401
        get_collection,  # noqa: F401
        get_dataset_tags,  # noqa: F401
        get_discussion_details,  # noqa: F401
        get_full_repo_name,  # noqa: F401
        get_inference_endpoint,  # noqa: F401
        get_model_tags,  # noqa: F401
        get_repo_discussions,  # noqa: F401
        get_space_runtime,  # noqa: F401
        get_space_variables,  # noqa: F401
        get_token_permission,  # noqa: F401
        like,  # noqa: F401
        list_datasets,  # noqa: F401
        list_files_info,  # noqa: F401
        list_inference_endpoints,  # noqa: F401
        list_liked_repos,  # noqa: F401
        list_metrics,  # noqa: F401
        list_models,  # noqa: F401
        list_repo_commits,  # noqa: F401
        list_repo_files,  # noqa: F401
        list_repo_likers,  # noqa: F401
        list_repo_refs,  # noqa: F401
        list_spaces,  # noqa: F401
        merge_pull_request,  # noqa: F401
        model_info,  # noqa: F401
        move_repo,  # noqa: F401
        pause_inference_endpoint,  # noqa: F401
        pause_space,  # noqa: F401
        preupload_lfs_files,  # noqa: F401
        rename_discussion,  # noqa: F401
        repo_exists,  # noqa: F401
        repo_info,  # noqa: F401
        repo_type_and_id_from_hf_id,  # noqa: F401
        request_space_hardware,  # noqa: F401
        request_space_storage,  # noqa: F401
        restart_space,  # noqa: F401
        resume_inference_endpoint,  # noqa: F401
        run_as_future,  # noqa: F401
        scale_to_zero_inference_endpoint,  # noqa: F401
        set_space_sleep_time,  # noqa: F401
        space_info,  # noqa: F401
        super_squash_history,  # noqa: F401
        unlike,  # noqa: F401
        update_collection_item,  # noqa: F401
        update_collection_metadata,  # noqa: F401
        update_inference_endpoint,  # noqa: F401
        update_repo_visibility,  # noqa: F401
        upload_file,  # noqa: F401
        upload_folder,  # noqa: F401
        whoami,  # noqa: F401
    )
    from .hf_file_system import (
        HfFileSystem,  # noqa: F401
        HfFileSystemFile,  # noqa: F401
        HfFileSystemResolvedPath,  # noqa: F401
    )
    from .hub_mixin import (
        ModelHubMixin,  # noqa: F401
        PyTorchModelHubMixin,  # noqa: F401
    )
    from .inference._client import (
        InferenceClient,  # noqa: F401
        InferenceTimeoutError,  # noqa: F401
    )
    from .inference._generated._async_client import AsyncInferenceClient  # noqa: F401
    from .inference_api import InferenceApi  # noqa: F401
    from .keras_mixin import (
        KerasModelHubMixin,  # noqa: F401
        from_pretrained_keras,  # noqa: F401
        push_to_hub_keras,  # noqa: F401
        save_pretrained_keras,  # noqa: F401
    )
    from .repocard import (
        DatasetCard,  # noqa: F401
        ModelCard,  # noqa: F401
        RepoCard,  # noqa: F401
        SpaceCard,  # noqa: F401
        metadata_eval_result,  # noqa: F401
        metadata_load,  # noqa: F401
        metadata_save,  # noqa: F401
        metadata_update,  # noqa: F401
    )
    from .repocard_data import (
        CardData,  # noqa: F401
        DatasetCardData,  # noqa: F401
        EvalResult,  # noqa: F401
        ModelCardData,  # noqa: F401
        SpaceCardData,  # noqa: F401
    )
    from .repository import Repository  # noqa: F401
    from .utils import (
        CachedFileInfo,  # noqa: F401
        CachedRepoInfo,  # noqa: F401
        CachedRevisionInfo,  # noqa: F401
        CacheNotFound,  # noqa: F401
        CorruptedCacheException,  # noqa: F401
        DeleteCacheStrategy,  # noqa: F401
        HFCacheInfo,  # noqa: F401
        HfFolder,  # noqa: F401
        cached_assets_path,  # noqa: F401
        configure_http_backend,  # noqa: F401
        dump_environment_info,  # noqa: F401
        get_session,  # noqa: F401
        logging,  # noqa: F401
        scan_cache_dir,  # noqa: F401
    )
    from .utils.endpoint_helpers import (
        DatasetFilter,  # noqa: F401
        ModelFilter,  # noqa: F401
    )


from importPy import *
import importPy
def eega_str2func(func):
	#Convert a the string name of a function to the function itself
	if('.' in func):
		mod,fun = func.split('.')
		if(mod == "octave"):
			return getattr(octave,fun)
		if(mod == "io"):
			return getattr(io,fun)
		else:
			return mod
	else:
		if(hasattr(importPy,func)):
			return getattr(importPy,func)
		else:
			return globals()[func]


#! /usr/bin/env python3

"""
Path Class

Defines a path and what it is supposed to be (mountain, valley, edge)

"""

import inkex        # Required
import simplestyle  # will be needed here for styles support

# compatibility hack
try:
    from lxml import etree
    inkex.etree = etree
except:
    pass

from math import sin, cos, pi

# compatibility hack for formatStyle
def format_style(style):
    try:
        return str(inkex.Style(style)) # new
    except:
        return simplestyle.formatStyle(style) # old
# def format_style(style):
    # return simplestyle.formatStyle(style)

class Path:
    """ Class that defines an svg stroke to be drawn in Inkscape

    Attributes
    ---------
    points: tuple or list of tuples
        Points defining stroke lines.
    style: str
        Single character defining style of stroke. Default values are:
        'm' for mountain creases
        'v' for valley creases
        'e' for edge borders
        Extra possible values:
        'u' for universal creases
        's' for semicreases
        'c' for kirigami cuts
    closed: bool
        Tells if desired path should contain a last stroke from the last point to the first point, closing the path
    radius: float
        If only one point is given, it's assumed to be a circle and radius sets the radius

    Methods
    ---------
    invert(self)
        Inverts path

    Overloaded Operators
    ---------
    __add__(self, offsets)
        Adding a tuple to a Path returns a new path with all points having an offset defined by the tuple

    __mul__(self, transform)
        Define multiplication of a Path to a vector in complex exponential representation

    Static Methods
    ---------
    draw_paths_recursively(path_tree, group, styles_dict)
        Draws strokes defined on "path_tree" to "group". Styles dict maps style of path_tree element to the definition
        of the style. Ex.:
        if path_tree[i].style = 'm', styles_dict must have an element 'm'.

    generate_hgrid(cls, xlims, ylims, nb_of_divisions, style, include_edge=False)
        Generate list of Path instances, in which each Path is a stroke defining a horizontal grid dividing the space
        xlims * ylims nb_of_divisions times.

    generate_vgrid(cls, xlims, ylims, nb_of_divisions, style, include_edge=False)
        Generate list of Path instances, in which each Path is a stroke defining a vertical grid dividing the space
        xlims * ylims nb_of_divisions times.

    generate_separated_paths(cls, points, styles, closed=False)
        Generate list of Path instances, in which each Path is the stroke between each two point tuples, in case each
        stroke must be handled separately

    reflect(cls, path, p1, p2)
        Reflects each point of path on line defined by two points and return new Path instance with new reflected points

    list_reflect(cls, paths, p1, p2)
        Generate list of new Path instances, rotation each path by transform

    list_rotate(cls, paths, theta, translation=(0, 0))
        Generate list of new Path instances, rotation each path by transform

    list_add(cls, paths, offsets)
        Generate list of new Path instances, adding a different tuple for each list

    list_simplify(cls, paths)
        Gets complicated path-tree list and converts it into
        a simple list.

    list_invert(cls, paths)
        Invert list of paths and points of each path.

    debug_points(cls, paths):
        Plots points of path tree in drawing order.
    """

    def __init__(self, points, style, closed=False, invert=False, radius=0.1, separated=False):
        """ Constructor

        Parameters
        ---------
        points: list of 2D tuples
            stroke will connect all points
        style: str
            Single character defining style of stroke. For use with the OrigamiPatterns class (probably the only
            project that will ever use this file) the default values are:
            'm' for mountain creases
            'v' for valley creases
            'e' for edge borders
        closed: bool
            if true, last point will be connected to first point at the end
        invert: bool
            if true, stroke will start at the last point and go all the way to the first one
        """
        if type(points) == list and len(points) != 1:
            self.type = 'linear'
            if invert:
                self.points = points[::-1]
            else:
                self.points = points

        elif (type(points) == list and len(points) == 1):
            self.type = 'circular'
            self.points = points
            self.radius = radius

        elif (type(points) == tuple and len(points) == 2):
            self.type = 'circular'
            self.points = [points]
            self.radius = radius

        else:
            raise TypeError("Points must be tuple of length 2 (for a circle) or a list of tuples of length 2 each")

        self.style = style
        self.closed = closed

    def invert(self):
        """ Inverts path
        """
        self.points = self.points[::-1]

    """
        Draw path recursively
        - Static method
        - Draws strokes defined on "path_tree" to "group"
        - Inputs:
        -- path_tree [nested list] of Path instances
        -- group [inkex.etree.SubElement]
        -- styles_dict [dict] containing all styles for path_tree
        """
    @staticmethod
    def draw_paths_recursively(path_tree, group, styles_dict):
        """ Static method, draw list of Path instances recursively
        """
        for subpath in path_tree:
            if type(subpath) == list:
                if len(subpath) == 1:
                    subgroup = group
                else:
                    subgroup = inkex.etree.SubElement(group, 'g')
                Path.draw_paths_recursively(subpath, subgroup, styles_dict)
            else:
                # ~ if subpath.style != 'n':
                if subpath.style != 'n' and styles_dict[subpath.style]['draw']:
                    if subpath.type == 'linear':

                        points = subpath.points
                        path = 'M{},{} '.format(*points[0])
                        for i in range(1, len(points)):
                            path = path + 'L{},{} '.format(*points[i])
                        if subpath.closed:
                            path = path + 'L{},{} Z'.format(*points[0])

                        attribs = {'style': format_style(styles_dict[subpath.style]), 'd': path}
                        inkex.etree.SubElement(group, inkex.addNS('path', 'svg'), attribs)
                    else:
                        attribs = {'style': format_style(styles_dict[subpath.style]),
                                   'cx': str(subpath.points[0][0]), 'cy': str(subpath.points[0][1]),
                                   'r': str(subpath.radius)}
                        inkex.etree.SubElement(group, inkex.addNS('circle', 'svg'), attribs)

    @classmethod
    def generate_hgrid(cls, xlims, ylims, nb_of_divisions, style, include_edge=False):
        """ Generate list of Path instances, in which each Path is a stroke defining
        a horizontal grid dividing the space xlims * ylims nb_of_divisions times.

        All lines are alternated, to minimize Laser Cutter unnecessary movements

        Parameters
        ---------
        xlims: tuple
            Defines x_min and x_max for space that must be divided.
        ylims: tuple
            Defines y_min and y_max for space that must be divided.
        nb_of_divisions: int
            Defines how many times it should be divided.
        style: str
            Single character defining style of stroke.
        include_edge: bool
            Defines if edge should be drawn or not.

        Returns
        ---------
        paths: list of Path instances
        """
        rect_len = (ylims[1] - ylims[0])/nb_of_divisions
        hgrid = []
        for i in range(1 - include_edge, nb_of_divisions + include_edge):
            hgrid.append(cls([(xlims[0], ylims[0]+i*rect_len),
                              (xlims[1], ylims[0]+i*rect_len)],
                             style=style, invert=i % 2 == 0))
        return hgrid

    @classmethod
    def generate_vgrid(cls, xlims, ylims, nb_of_divisions, style, include_edge=False):
        """ Generate list of Path instances, in which each Path is a stroke defining
        a vertical grid dividing the space xlims * ylims nb_of_divisions times.

        All lines are alternated, to minimize Laser Cutter unnecessary movements

        Parameters
        ---------
        -> refer to generate_hgrid

        Returns
        ---------
        paths: list of Path instances
        """
        rect_len = (xlims[1] - xlims[0])/nb_of_divisions
        vgrid = []
        for i in range(1 - include_edge, nb_of_divisions + include_edge):
            vgrid.append(cls([(xlims[0]+i*rect_len, ylims[0]),
                              (xlims[0]+i*rect_len, ylims[1])],
                             style=style, invert=i % 2 == 0))
        return vgrid

    @classmethod
    def generate_polygon(cls, sides, radius, style, center=(0, 0)):
        points = []
        for i in range(sides):
            points.append((radius * cos((1 + i * 2) * pi / sides),
                           radius * sin((1 + i * 2) * pi / sides)))
        return Path(points, style, closed=True)

    @classmethod
    def generate_separated_paths(cls, points, styles, closed=False):
        """ Generate list of Path instances, in which each Path is the stroke
        between each two point tuples, in case each stroke must be handled separately.

        Returns
        ---------
        paths: list
            list of Path instances
        """
        paths = []
        if type(styles) == str:
            styles = [styles] * (len(points) - 1 + int(closed))
        elif len(styles) != len(points) - 1 + int(closed):
            raise TypeError("Number of paths and styles don't match")
        for i in range(len(points) - 1 + int(closed)):
            j = (i+1)%len(points)
            paths.append(cls([points[i], points[j]],
                             styles[i]))
        return paths

    def __add__(self, offsets):
        """ " + " operator overload.
        Adding a tuple to a Path returns a new path with all points having an offset
        defined by the tuple
        """
        if type(offsets) == list:
            if len(offsets) != 1 or len(offsets) != len(self.points):
                raise TypeError("Paths can only be added by a tuple of a list of N tuples, "
                                "where N is the same number of points")

        elif type(offsets) != tuple:
            raise TypeError("Paths can only be added by tuples")
        else:
            offsets = [offsets] * len(self.points)

        # if type(self.points) == list:
        points_new = []
        for point, offset in zip(self.points, offsets):
            points_new.append((point[0]+offset[0],
                               point[1]+offset[1]))

        if self.type == 'circular':
            radius = self.radius
        else:
            radius = 0.2

         # if self.type == 'circular' else 0.1

        return Path(points_new, self.style, self.closed, radius=radius)

    @classmethod
    def list_add(cls, paths, offsets):
        """ Generate list of new Path instances, adding a different tuple for each list

        Parameters
        ---------
        paths: Path or list
            list of N Path instances
        offsets: tuple or list
            list of N tuples

        Returns
        ---------
        paths_new: list
            list of N Path instances
        """
        if type(paths) == Path and type(offsets) == tuple:
            paths = [paths]
            offsets = [offsets]
        elif type(paths) == list and type(offsets) == tuple:
            offsets = [offsets] * len(paths)
        elif type(paths) == Path and type(offsets) == list:
            paths = [paths] * len(offsets)
        elif type(paths) == list and type(offsets) == list:
            if len(paths) == 1:
                paths = [paths[0]] * len(offsets)
            elif len(offsets) == 1:
                offsets = [offsets[0]] * len(paths)
            elif len(offsets) != len(paths):
                raise TypeError("List of paths and list of tuples must have same length. {} paths and {} offsets "
                                " where given".format(len(paths), len(offsets)))
            else:
                pass

        paths_new = []
        for path, offset in zip(paths, offsets):
            paths_new.append(path+offset)

        return paths_new

    def __mul__(self, transform):
        """ " * " operator overload.
        Define multiplication of a Path to a vector in complex exponential representation

        Parameters
        ---------
        transform: float of tuple of length 2 or 4
            if float, transform represents magnitude
                Example: path * 3
            if tuple length 2, transform[0] represents magnitude and transform[1] represents angle of rotation
                Example: path * (3, pi)
            if tuple length 4, transform[2],transform[3] define a different axis of rotation
                Example: path * (3, pi, 1, 1)
        """
        points_new = []

        # "temporary" (probably permanent) compatibility hack
        try:
            long_ = long
        except:
            long_ = int

        if isinstance(transform, (int, long_, float)):
            for p in self.points:
                points_new.append((transform * p[0],
                                   transform * p[1]))

        elif isinstance(transform, (list, tuple)):
            if len(transform) == 2:
                u = transform[0]*cos(transform[1])
                v = transform[0]*sin(transform[1])
                x_, y_ = 0, 0
            elif len(transform) == 4:
                u = transform[0]*cos(transform[1])
                v = transform[0]*sin(transform[1])
                x_, y_ = transform[2:]
            else:
                raise IndexError('Paths can only be multiplied by a number or a tuple/list of length 2 or 4')

            for p in self.points:
                x, y = p[0]-x_, p[1]-y_
                points_new.append((x_ + x * u - y * v,
                                   y_ + x * v + y * u))
        else:
            raise TypeError('Paths can only be multiplied by a number or a tuple/list of length 2 or 4')

        if self.type == 'circular':
            radius = self.radius
        else:
            radius = 0.2

        return Path(points_new, self.style, self.closed, radius=radius)

    @classmethod
    def list_rotate(cls, paths, theta, translation=(0, 0)):
        """ Generate list of new Path instances, rotation each path by transform

        Parameters
        ---------
        paths: Path or list
            list of N Path instances
        theta: float (radians)
            angle of rotation
        translation: tuple or list 2
            axis of rotation

        Returns
        ---------
        paths_new: list
            list of N Path instances
        """
        if len(translation) != 2:
            TypeError("Translation must have length 2")

        if type(paths) != list:
            paths = [paths]

        paths_new = []
        for path in paths:
            paths_new.append(path*(1, theta, translation[0], translation[1]))

        if len(paths_new) == 1:
            paths_new = paths_new[0]
        return paths_new

    # TODO:
    # Apparently it's not working properly, must be debugged and tested
    @classmethod
    def reflect(cls, path, p1, p2):
        """ Reflects each point of path on line defined by two points and return new Path instance with new reflected points

        Parameters
        ---------
        path: Path
        p1: tuple or list of size 2
        p2: tuple or list of size 2

        Returns
        ---------
        path_reflected: Path
        """

        (x1, y1) = p1
        (x2, y2) = p2

        if x1 == x2 and y1 == y2:
            ValueError("Duplicate points don't define a line")
        elif x1 == x2:
            t_x = [-1, 0, 2*x1, 1]
            t_y = [0, 1, 0, 1]
        else:
            m = (y2 - y1)/(x2 - x1)
            t = y1 - m*x1
            t_x = [1 - m**2, 2*m, -2*m*t, m**2 + 1]
            t_y = [2*m, m**2 - 1, +2*t, m**2 + 1]

        points_new = []
        for p in path.points:
            x_ = (t_x[0]*p[0] + t_x[1]*p[1] + t_x[2]) / t_x[3]
            y_ = (t_y[0]*p[0] + t_y[1]*p[1] + t_y[2]) / t_y[3]
            points_new.append((x_, y_))

        return Path(points_new, path.style, path.closed)

    # TODO:
    # Apparently it's not working properly, must be debugged and tested
    @classmethod
    def list_reflect(cls, paths, p1, p2):
        """ Generate list of new Path instances, rotation each path by transform

        Parameters
        ---------
        paths: Path or list
            list of N Path instances
        p1: tuple or list of size 2
        p2: tuple or list of size 2

        Returns
        ---------
        paths_new: list
            list of N Path instances
        """

        if type(paths) == Path:
            paths = [paths]

        paths_new = []
        for path in paths:
            paths_new.append(Path.reflect(path, p1, p2))

        return paths_new

    @classmethod
    def list_simplify(cls, paths):
        """ Gets complicated path-tree list and converts it into
        a simple list.

        Returns
        ---------
        paths: list
            list of Path instances
        """
        if type(paths) == Path:
            return paths

        simple_list = []
        for i in range(len(paths)):
            if type(paths[i]) == Path:
                simple_list.append(paths[i])
            elif type(paths[i]) == list:
                simple_list = simple_list + Path.list_simplify(paths[i])
        return simple_list

    @classmethod
    def list_invert(cls, paths):
        """ Invert list of paths and points of each path.

        Returns
        ---------
        paths: list
            list of Path instances
        """

        if type(paths) == Path:
            # return Path(paths.points[::-1], paths.style, paths.closed, paths.invert)
            return Path(paths.points, paths.style, paths.closed, True)
        elif type(paths) == list:
            paths_inverted = []
            # n = len(paths)
            # for i in range(n):
            #     # paths_inverted.append(Path.list_invert(paths[n-1-i]))
            #     paths_inverted.append(Path.list_invert(paths[i]))
            for path in paths:
                # paths_inverted.append(Path.list_invert(paths[n-1-i]))
                paths_inverted.append(Path.list_invert(path))
            return paths_inverted[::-1]

    @classmethod
    def debug_points(cls, paths):
        """ Plots points of path tree in drawing order.

        """
        if type(paths) == Path:
            inkex.debug(paths.points)
        elif type(paths) == list:
            for sub_path in paths:
                Path.debug_points(sub_path)


import optparse
from celltool import simple_interface
from celltool.utility import path
from . import cli_tools
from . import match_files

usage = "usage: %prog [options] image_or_contour_1 ... image_or_contour_n"

parser = optparse.OptionParser(usage=usage, description=__doc__.strip(),
    formatter=cli_tools.CelltoolFormatter())
parser.set_defaults(
    show_progress=True,
    match_by_name=True,
    image_type='original',
    destination='.'
)
parser.add_option('-q', '--quiet', action='store_false', dest='show_progress',
    help='suppress progress bars and other status updates')
parser.add_option('-l', '--landmark', action='append', dest='intensity_ranges',
    type='int', metavar='INTENSITY',
    help='find pixels with values equal to INTENSITY and treat their centroid as a landmark')
parser.add_option('-i', '--landmark-interval', action='append', dest='intensity_ranges',
    type='int', nargs=2, metavar='LOW HIGH',
    help='find pixels with values in [LOW, HIGH] and treat their centroid as a landmark')
parser.add_option('-w', '--weight', action='append', dest='weights',
    type='float', metavar='WEIGHT',
    help='set the weight shared by all contours to WEIGHT (if specified once), or set the weight of the nth landmark to WEIGHT (if specified multiply)')
parser.add_option('-r', '--order-match', action='store_false', dest='match_by_name',
    help='match contours to images by their order on the command line [default: match by name]')
parser.add_option('-a', '--aligned-images', action='store_const', const='aligned', dest='image_type',
    help='set if images have been aligned with extract_images [default: images are assumed to be oriented as the original contours were]')
parser.add_option('-d', '--destination', metavar='DIRECTORY',
    help='directory in which to write the output contours [default: %default]')

def main(name, arguments):
    parser.prog = name
    options, args = parser.parse_args(arguments)
    args = cli_tools.glob_args(args)
    if len(args) == 0:
        raise ValueError('Some contour and image files must be specified!')
    intensity_ranges = []
    for r in options.intensity_ranges:
        try:
            low, high = r
        except:
            low = high = r
        intensity_ranges.append([low, high])
    if options.weights is None or len(options.weights) == 0:
        options.weights = [0.5]
    elif len(options.weights) != 1 and len(options.weights) != len(intensity_ranges):
        raise optparse.OptionValueError("Either one or %d weights are required; %d sepcified."%(len(intensity_ranges), len(options.weights)))
    elif sum(options.weights) > 1:
        raise optparse.OptionValueError("The sum of the weights must be <= 1.")

    matches = match_files.match_contours_and_images(args, options.match_by_name, options.show_progress)
    contours, image_names, unmatched_contours, unmatched_image_names = matches
    filenames = [path.path(contour._filename) for contour in contours]
    contours = simple_interface.add_image_landmarks_to_contours(contours, image_names,
        intensity_ranges, options.weights, options.image_type, options.show_progress)
    destination = path.path(options.destination)
    destination.makedirs_p()
    # note that with path objects, the '/' operator means 'join path components.'
    names = [destination / filename.name for filename in filenames]
    simple_interface.save_contours(contours, names, options.show_progress)

if __name__ == '__main__':
    import sys
    import os
    main(os.path.basename(sys.argv[0]), sys.argv[1:])


import os
import struct
from collections import namedtuple
import psutil
import numpy as np

__all__ = ['readGadgetSnapshot', 'GadgetHeader']

__GadgetHeader_fmt = '6I6dddii6Iiiddddii6Ii'

GadgetHeader = namedtuple('GadgetHeader', \
        'npart mass time redshift flag_sfr flag_feedback npartTotal flag_cooling num_files BoxSize Omega0 OmegaLambda HubbleParam flag_age flag_metals NallHW flag_entr_ics')
def get_memory():
    process = psutil.Process(os.getpid())
    print(process.memory_info().rss/1e9, "GB is current memory usage")  # in bytes

def readGadgetSnapshot(filename, read_pos=False, read_vel=False, read_id=False,\
        read_mass=False, print_header=False, single_type=-1, lgadget=False):
    """
    This function reads the Gadget-2 snapshot file.

    Parameters
    ----------
    filename : str
        path to the input file
    read_pos : bool, optional
        Whether to read the positions or not. Default is false.
    read_vel : bool, optional
        Whether to read the velocities or not. Default is false.
    read_id : bool, optional
        Whether to read the particle IDs or not. Default is false.
    read_mass : bool, optional
        Whether to read the masses or not. Default is false.
    print_header : bool, optional
        Whether to print out the header or not. Default is false.
    single_type : int, optional
        Set to -1 (default) to read in all particle types.
        Set to 0--5 to read in only the corresponding particle type.
    lgadget : bool, optional
        Set to True if the particle file comes from l-gadget.
        Default is false.

    Returns
    -------
    ret : tuple
        A tuple of the requested data.
        The first item in the returned tuple is always the header.
        The header is in the GadgetHeader namedtuple format.
    """
    blocks_to_read = (read_pos, read_vel, read_id, read_mass)
    ret = []
    with open(filename, 'rb') as f:
        f.seek(4, 1)
        h = list(struct.unpack(__GadgetHeader_fmt, \
                f.read(struct.calcsize(__GadgetHeader_fmt))))
        if lgadget:
            h[30] = 0
            h[31] = h[18]
            h[18] = 0
            single_type = 1
        h = tuple(h)
        header = GadgetHeader._make((h[0:6],) + (h[6:12],) + h[12:16] \
                + (h[16:22],) + h[22:30] + (h[30:36],) + h[36:])
        if print_header:
            print(header)
        if not any(blocks_to_read):
            return header
        ret.append(header)
        f.seek(256 - struct.calcsize(__GadgetHeader_fmt), 1)
        f.seek(4, 1)
        #
        mass_npart = [0 if m else n for m, n in zip(header.mass, header.npart)]
        if single_type not in set(range(6)):
            single_type = -1
        #
        for i, b in enumerate(blocks_to_read):
            fmt = np.dtype(np.float32)
            fmt_64 = np.dtype(np.float64)
            item_per_part = 1
            npart = header.npart
            #
            if i < 2:
                item_per_part = 3
            elif i == 2:
                fmt = np.dtype(np.uint32)
                fmt_64 = np.dtype(np.uint64)
            elif i == 3:
                if sum(mass_npart) == 0:
                    ret.append(np.array([], fmt))
                    break
                npart = mass_npart
            #
            size_check = struct.unpack('I', f.read(4))[0]
            #
            block_item_size = item_per_part*sum(npart)
            if size_check != block_item_size*fmt.itemsize:
                fmt = fmt_64
            if size_check != block_item_size*fmt.itemsize:
                raise ValueError('Invalid block size in file!')
            size_per_part = item_per_part*fmt.itemsize
            #
            if not b:
                f.seek(sum(npart)*size_per_part, 1)
            else:
                if single_type > -1:
                    f.seek(sum(npart[:single_type])*size_per_part, 1)
                    npart_this = npart[single_type]
                else:
                    npart_this = sum(npart)
                data = np.fromstring(f.read(npart_this*size_per_part), fmt)
                if item_per_part > 1:
                    data.shape = (npart_this, item_per_part)
                ret.append(data)
                if not any(blocks_to_read[i+1:]):
                    break
                if single_type > -1:
                    f.seek(sum(npart[single_type+1:])*size_per_part, 1)
            f.seek(4, 1)
    #
    return tuple(ret)

def position_to_index(pos, lbox, nmesh):

    deltax = lbox/nmesh

    idvec = np.floor((pos)/deltax)

    return (idvec%nmesh).astype('int16')

def kroneckerdelta(i, j):
    if i == j:
        return 1
    else:
        return 0


from __future__ import division

import json
import os

import cv2
import numpy as np
import torch
import torch.distributed as dist
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from torch.utils.data.distributed import DistributedSampler
from torch.utils.data.sampler import RandomSampler

from datasets.base_dataset import BaseDataset, BaseTransform, ExemplarTransform
from datasets.transforms import RandomColorJitter

def build_custom_exemplar_dataloader(cfg, training, distributed=True):
    rank = dist.get_rank()

    normalize_fn = transforms.Normalize(mean=cfg["pixel_mean"], std=cfg["pixel_std"])

    if training:
        hflip = cfg.get("hflip", False)
        vflip = cfg.get("vflip", False)
        rotate = cfg.get("rotate", False)
        gamma = cfg.get("gamma", False)
        gray = cfg.get("gray", False)
        transform_fn = BaseTransform(
            cfg["input_size"], hflip, vflip, rotate, gamma, gray
        )
    else:
        transform_fn = BaseTransform(cfg["input_size"], False, False, False, False)

    exemplar_fn = ExemplarTransform(cfg["input_size"])

    if training and cfg.get("colorjitter", None):
        colorjitter_fn = RandomColorJitter.from_params(cfg["colorjitter"])
    else:
        colorjitter_fn = None

    if rank == 0:
        print("building CustomDataset from: {}".format(cfg["meta_file"]))

    dataset = CustomDataset(
        cfg["img_dir"],
        cfg["density_dir"],
        cfg["meta_file"],
        cfg["exemplar"],
        transform_fn=transform_fn,
        exemplar_fn=exemplar_fn,
        normalize_fn=normalize_fn,
        colorjitter_fn=colorjitter_fn,
    )

    if distributed:
        sampler = DistributedSampler(dataset)
    else:
        sampler = RandomSampler(dataset)

    data_loader = DataLoader(
        dataset,
        batch_size=cfg["batch_size"],
        num_workers=cfg["workers"],
        pin_memory=True,
        sampler=sampler,
    )

    return data_loader

class CustomDataset(BaseDataset):
    def __init__(
        self,
        img_dir,
        density_dir,
        meta_file,
        cfg_exemplar,
        transform_fn,
        exemplar_fn,
        normalize_fn,
        colorjitter_fn=None,
    ):
        self.img_dir = img_dir
        self.density_dir = density_dir
        self.meta_file = meta_file
        self.cfg_exemplar = cfg_exemplar
        self.transform_fn = transform_fn
        self.exemplar_fn = exemplar_fn
        self.normalize_fn = normalize_fn
        self.colorjitter_fn = colorjitter_fn

        # construct metas
        with open(meta_file, "r+") as f_r:
            self.metas = []
            for line in f_r:
                meta = json.loads(line)
                self.metas.append(meta)

        # construct exemplar_metas
        exemplar_metas = []
        with open(cfg_exemplar["meta_file"], "r+") as f_r:
            for line in f_r:
                meta = json.loads(line)
                exemplar_metas.append(meta)
        if cfg_exemplar["num_exemplar"] > len(exemplar_metas):
            raise ValueError(
                "num_exemplar must smaller than the length of exemplar_metas!"
            )
        else:
            exemplar_metas = exemplar_metas[0 : cfg_exemplar["num_exemplar"]]

        # construct exemplar list
        exemplar_imgs = []
        exemplar_boxes = []
        for meta in exemplar_metas:
            image = cv2.imread(os.path.join(cfg_exemplar["img_dir"], meta["filename"]))
            image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            height, width = image.shape[:2]
            # resize to a fix size
            box = meta["box"]
            if self.exemplar_fn:
                image, box = self.exemplar_fn(image, box, (height, width))
            image = transforms.ToTensor()(image)
            box = torch.tensor(box, dtype=torch.float64)
            if cfg_exemplar["norm"] and self.normalize_fn:
                image = self.normalize_fn(image)
            exemplar_imgs.append(image.unsqueeze(0))
            exemplar_boxes.append(box.unsqueeze(0))
        self.exemplar_imgs = torch.cat(exemplar_imgs, dim=0)  # n x c x h x w
        self.exemplar_boxes = torch.cat(exemplar_boxes, dim=0)  # n x c x h x w

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

    def __getitem__(self, index):
        meta = self.metas[index]
        # read img
        img_name = meta["filename"]
        img_path = os.path.join(self.img_dir, img_name)
        image = cv2.imread(img_path)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        height, width = image.shape[:2]
        # read density
        density_name = meta["density"]
        density_path = os.path.join(self.density_dir, density_name)
        density = np.load(density_path)
        # transform
        if self.transform_fn:
            image, density, _, _ = self.transform_fn(
                image, density, [], [], (height, width)
            )
        if self.colorjitter_fn:
            image = self.colorjitter_fn(image)
        image = transforms.ToTensor()(image)
        density = transforms.ToTensor()(density)
        if self.normalize_fn:
            image = self.normalize_fn(image)
        return {
            "filename": img_name,
            "height": height,
            "width": width,
            "image": image,
            "density": density,
            "exemplar_imgs": self.exemplar_imgs,
            "exemplar_boxes": self.exemplar_boxes,
        }


# -*- coding: utf-8 -*-
# __author__ = 'qingmei'
# last_modify: 2018.08.15

from biocluster.agent import Agent
from biocluster.tool import Tool
from biocluster.core.exceptions import OptionError
import os
from bson.objectid import ObjectId

class RegionAnnoAgent(Agent):
    """
    基因注释接口
    一个controller和一个tool,一个api
    对应脚本cmd: region-gene.pl cmd: eff-enrich.R
    region_path,前三列只要是chrid start end就可以，位置信息有重复也没关系
    """
    def __init__(self, parent):
        super(RegionAnnoAgent, self).__init__(parent)
        options = [
            {"name": "main_id", "type": "string"},  #
            {"name": "task_id", "type": "string"},  #
            {"name": "pop_summary_path", "type": "infile", "format": "dna_evolution.pop_summary"},
            # {"name": "pop_summary_path", "type": "string"},     # 已经是绝对路径，待写成infile核查
            {"name": "region_path", "type": "infile", "format": "dna_evolution.bed"},    # sg_anno_params的region_path
            {"name": "update_info", "type": "string"},
            {"name": "go_summary_path", "type": "infile", "format": "dna_evolution.pop_enrich"},
            {"name": "genome_version_id", "type": "string"},
            {"name": "pathway_path", "type": "string"}  # 对象存储路径
        ]
        self.add_option(options)
        self.step.add_steps("region_anno")
        self.on('start', self.stepstart)
        self.on('end', self.stepfinish)

    def stepstart(self):
        self.step.region_anno.start()
        self.step.update()

    def stepfinish(self):
        self.step.region_anno.finish()
        self.step.update()

    def check_options(self):
        """
        重写参数检测函数
        :return:
        """
        if not self.option('pop_summary_path'):
            raise OptionError('必须输入pop_summary_path')
        if not self.option('region_path'):
            raise OptionError('必须输入region_path')
        if not self.option('main_id'):
            raise OptionError('必须输入main_id')
        if not self.option('task_id'):
            raise OptionError('必须输入task_id')
        if not self.option('genome_version_id'):
            raise OptionError('必须输入genome_version_id')
        if not self.option("pathway_path"):
            raise OptionError("请设置pathway_path")

    def set_resource(self):
        """
        设置所需资源，需在之类中重写此方法 self._cpu ,self._memory
        :return:
        """
        self._cpu = 2
        self._memory = "6G"

class RegionAnnoTool(Tool):
    def __init__(self, config):
        super(RegionAnnoTool, self).__init__(config)
        self._version = "v1.0.1"
        self.perl_path = 'miniconda2/bin/perl '
        self.R_path = 'program/R-3.3.1/bin/Rscript '
        self.region_gene_path = self.config.PACKAGE_DIR + '/dna_evolution/region-gene.pl'
        self.effR_path = self.config.PACKAGE_DIR + '/dna_evolution/eff-enrich.R'
        self.set_environ(LD_LIBRARY_PATH=self.config.SOFTWARE_DIR + '/gcc/5.4.0/lib64')
        self.image_magick = self.config.SOFTWARE_DIR + "/program/ImageMagick/bin/convert"
        self.ko_path = self.config.SOFTWARE_DIR + '/database/KEGG/kegg_2017-05-01/kegg/pathway/ko/'
        self.parafly = "program/parafly-r2013-01-21/src/ParaFly"

    # def get_select_region(self):
    #     """
    #     把传进来的region还原成文件
    #     eg：chr1-123-234;chr2-345-567;
    #     """
    #     region_list = self.option('select_region').split(';')
    #     with open(self.work_dir + '/select.region', 'w') as fw:
    #         fw.write('#chr\tstart\tend\n')
    #         for i in region_list:
    #             line_list = i.split('-')
    #             fw.write('\t'.join(line_list) + '\n')
    #     self.logger.info('~~~~~~select.region文件生成成功')

    def run_region_gene(self):
        """
        输入pop.summary select(三列信息，chrid start end)
        运行eff-enrich.R,计算注释统计
        """
        cmd = "{} {}".format(self.perl_path, self.region_gene_path)
        cmd += " -a {} -i {}".format(self.option('pop_summary_path').prop['path'],
                                     self.option('region_path').prop['path'])
        cmd += " -o {}".format(self.work_dir + "/select_region")
        self.logger.info('开始运行region_gene提取')
        self.run_cmd(cmd, "region_gene")

    def run_eff_detail(self, type_):
        """
        """
        cmd = "{} {}".format(self.R_path, self.effR_path)
        cmd += " --input {}".format(self.work_dir + "/select_region." + type_ + ".stat")
        cmd += " --output {}".format(self.output_dir + "/select_region." + type_ + ".stat")
        if type_ == 'eggnog':
            cmd += " --eggnog"
        else:
            cmd += " --top 1"
        self.logger.info('开始运行effrich.R注释统计:' + type_)
        self.run_cmd(cmd, "eff_detail_" + type_)

    def run_get_picture(self):
        """
        根据ko号找到对应的所有ko的pdf和png文件-- 添加如果存在pathway_dir就将该文件夹删除 add by hongdong 20180301
        :return:
        """
        if os.path.isdir(self.output_dir + '/pathway_dir'):
            os.system('rm -r %s' % os.path.join(self.output_dir, '/pathway_dir'))
        self.num = 0
        cmd_list = []
        os.system("mkdir {}".format(self.output_dir + '/pathway_dir'))
        all_ko = os.listdir(self.ko_path)
        with open(self.work_dir + "/select_region.kegg.stat")as fr:
            for line in fr:
                tmp = line.strip().split('\t')
                ko_png = tmp[0] + '.png'
                if ko_png in all_ko:
                    ko_path = os.path.join(self.ko_path, ko_png)
                    os.link(ko_path, self.output_dir + '/pathway_dir/' + ko_png)
                    pdf_path = os.path.join(self.output_dir + '/pathway_dir', tmp[0] + '.pdf')
                    cmd = self.image_magick + ' -flatten -quality 100 -density 130 -background white ' + ko_path + ' ' + pdf_path
                    cmd_list.append(cmd)
                else:
                    self.set_error("ko{} png文件在本地数据库{}中没有，请核实!".format(tmp[0], self.ko_path))
        with open(self.work_dir + "/cmd.list", "w") as fw:
            for i in range(len(cmd_list)):
                fw.write(cmd_list[i] + "\n")
        cmd = self.parafly + " -c {} -CPU 10".format(self.work_dir + "/cmd.list")
        cmd_obj = self.add_command("cmd_list", cmd).run()
        self.wait(cmd_obj)
        if cmd_obj.return_code == 0:
            self.logger.info("cmd list执行成功")
        else:
            self.set_error("cmd list运行出错!")

    def run_cmd(self, cmd, cmd_name):
        """
        执行cmd
        """
        command = self.add_command(cmd_name, cmd).run()
        self.wait()
        if command.return_code == 0:
            self.logger.info("{}运行完成".format(cmd_name))
        else:
            self.set_error("{}运行失败".format(cmd_name))
            raise Exception("{}运行失败".format(cmd_name))

    def check_exists(self, file_path):
        """
        用于检查文件及文件夹是否存在
        """
        if not os.path.exists(file_path):
            raise Exception("文件或文件夹{}不存在！".format(file_path))

    def run(self):
        """
        运行
        :return:
        """
        super(RegionAnnoTool, self).run()
        # self.get_select_region()
        self.run_region_gene()
        self.run_eff_detail("kegg")
        self.run_eff_detail("go")
        self.run_eff_detail("eggnog")
        if os.path.exists(self.output_dir + "/select_region.kegg.stat.detail"):
            self.logger.info('kegg')
            # 若结果文件产生了，就证明kegg.stat文件不为空且存在。就运行picture
            self.run_get_picture()
        self.set_db()
        # self.end()

    def set_db(self):
        """
        更新主表的chr_list和path:marker.filtered.marker
        self.filtered_marker_path
        """
        region_id = ObjectId(self.option("main_id"))
        genome_version_id = ObjectId(self.option('genome_version_id'))
        self.logger.info("开始region_anno的导表！")
        api = self.api.api("dna_evolution.region_anno")
        task_id = self.option('task_id')
        # api.get_update_chrlist(marker_id, self.target_dir_ + "/pop.filtered.marker",
        #                        self.target_dir_ + "/pop.filtered.detail.info")
        api.add_sg_region_anno_detail(region_id, self.option('pop_summary_path').prop['path'], genome_version_id)
        api.sg_region_anno_go_stat(task_id, region_id, self.output_dir + "/select_region.go.stat.detail",
                                   self.option('go_summary_path').prop['path'])
        api.sg_region_anno_kegg_stat(task_id, region_id, self.output_dir + "/select_region.kegg.stat.detail",
                                     self.output_dir + "/pathway_dir",
                                     os.path.join(self.option("pathway_path"), "region_anno/pathway_dir"))
        api.sg_region_anno_eggnog_stat(task_id, region_id, self.output_dir + "/select_region.eggnog.stat.detail")
        self.logger.info("设置region_anno的导表成功！")
        self.end()


import time
startTime = time.time()
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
import spacy
# import pyLDAvis.gensim_models
# pyLDAvis.enable_notebook()# Visualise inside a notebook
from gensim.corpora.dictionary import Dictionary
from gensim.models import LdaMulticore
from gensim.models import LdaModel
from gensim.models import CoherenceModel

import sys

try:
    lang = sys.argv[1]
    print("Running topic modelling in " + str(lang) + " language")
except:
    print("Please input a language parameter [en, ru, it] in order to run the script")
    exit()

print("Reading in input data now.")
df_comb = pd.read_excel("./files/input/combined_data.xlsx")

from langdetect import detect, DetectorFactory
DetectorFactory.seed = 0

df_comb["actual_lang"] = df_comb["content"].apply(detect)
print("Filtering data to account for content with language detected as " + str(lang))
df = df_comb[df_comb["actual_lang"] == str(lang)].reset_index(drop=True)

lang_models = {"en": spacy.load("en_core_web_md"), "it": spacy.load("it_core_news_md"), "ru": spacy.load("ru_core_news_md")}

# Our spaCy model:
nlp = lang_models[str(lang)]

print("Loading " + str(lang) + " model")

# Tags I want to remove from the text
print("Tokenizing, lemmatizing and removing stopwords.")
removal= ['ADV','PRON','CCONJ','PUNCT','PART','DET','ADP','SPACE', 'NUM', 'SYM']
tokens = []
for summary in nlp.pipe(df['content']):
    proj_tok = [token.lemma_.lower() for token in summary if token.pos_ not in removal and not token.is_stop and token.is_alpha]
    tokens.append(proj_tok)

df['tokens'] = tokens

print("Creating dictionary and corpus")
dictionary = Dictionary(df['tokens'])

dictionary.filter_extremes(no_below=5, no_above=0.5, keep_n=1000)

corpus = [dictionary.doc2bow(doc) for doc in df['tokens']]

## Code to plot coherence plot for each topic number (present in topic_modelling_full.ipynb file as well)

# topics = []
# score = []
# for i in range(1,10,1):
#     print("Running iteration number " + str(i))
#     lda_model = LdaMulticore(corpus=corpus, id2word=dictionary, iterations=10, num_topics=i, workers = 4, passes=10, random_state=100)
#     cm = CoherenceModel(model=lda_model, texts = df['tokens'], corpus=corpus, dictionary=dictionary, coherence='c_v')
#     topics.append(i)
#     score.append(cm.get_coherence())
# num_topics = topics[score.index(max(score))]

## best parameters for each language model (pre-run)
topic_lang = {"en": 7, "it": 6, "ru": 8}
topic_alpha = {"en": "symmetric", "it": "asymmetric", "ru": "asymmetric"}
topic_beta = {"en": 0.01, "it": 0.91, "ru": 0.01}

num_topics = topic_lang[lang]
print("Number of topics with highest coherence score for " + str(lang) + " model is: " + str(num_topics))

alpha = topic_alpha[lang]
beta = topic_beta[lang]

print("Optimal Parameters for " + str(lang) + " have been obtained. Running model now.")

# lda_model = LdaMulticore(corpus=corpus, id2word=dictionary, iterations=100, num_topics=num_topics, workers = 4, passes=100)
lda_model = LdaModel(corpus=corpus, id2word=dictionary, iterations=100, num_topics=num_topics, passes=100, alpha = alpha, eta = beta, random_state=100)

# lda_display = pyLDAvis.gensim_models.prepare(lda_model, corpus, dictionary, sort_topics=False)
# pyLDAvis.save_html(lda_display, "./files/output/" + str(lang) + "/lda_" + str(lang) + ".html")

def format_topics_sentences(ldamodel=None, corpus=corpus, texts=df['tokens']):
    # Init output
    sent_topics_df = pd.DataFrame()

    # Get main topic in each document
    for i, row_list in enumerate(ldamodel[corpus]):
        row = row_list[0] if ldamodel.per_word_topics else row_list
        # print(row)
        row = sorted(row, key=lambda x: (x[1]), reverse=True)
        # Get the Dominant topic, Perc Contribution and Keywords for each document
        for j, (topic_num, prop_topic) in enumerate(row):
            if j == 0:  # => dominant topic
                wp = ldamodel.show_topic(topic_num)
                topic_keywords = ", ".join([word for word, prop in wp])
                sent_topics_df = sent_topics_df.append(pd.Series([int(topic_num), round(prop_topic,4), topic_keywords]), ignore_index=True)
            else:
                break
    sent_topics_df.columns = ['Dominant_Topic', 'Perc_Contribution', 'Topic_Keywords']
    return(sent_topics_df)

df_topic_sents_keywords = format_topics_sentences(ldamodel=lda_model, corpus=corpus, texts=df['tokens'])

# Format
df_dominant_topic = df_topic_sents_keywords.reset_index(drop=True)
df_dominant_topic.columns = ['Dominant_Topic', 'Topic_Perc_Contrib', 'Keywords']
df_dominant_topic = pd.concat([df,df_dominant_topic], axis=1)
df_dominant_topic = df_dominant_topic.sort_values(by='Topic_Perc_Contrib',ascending=False).reset_index(drop=True)

writer = pd.ExcelWriter('./files/output/' + str(lang) + '/topic_modelling_output_' + str(lang) + '.xlsx' , engine='xlsxwriter')
workbook = writer.book
workbook.formats[0].set_font_size(12)
df_dominant_topic.to_excel(writer, sheet_name = 'Output', index=False)

for idx, col in enumerate(df_dominant_topic):  # loop through all columns
    series = df_dominant_topic[col]
    max_len = 20
    writer.sheets['Output'].set_column(idx, idx, max_len)  # set column width

writer.close()

print("Outputted excel file has been saved in ./files/output/"+str(lang)+" folder")
print("Visualisation data has been saved in ./files/output/"+str(lang)+" folder")
print("Coherence plot has been saved in ./files/output/"+str(lang)+" folder")

executionTime = (time.time() - startTime)
print('Execution time in seconds: ' + str(executionTime))


import math

class Azimuth:
    """
    Estos objetos son ángulos en el sentido de las manecillas del reloj a partir del Norte,
    Es decir, son exclusivamentes azimutes por el momento, pueden ser escritos de la sgte manera.
    Siguiendo la notación de los ángulos en grados, minutos y segundos o de forma numeríca, para
    la separación entre grados minutos o segundos se puede utilizar lso caracteres de ° o ' para
    los grados o los minutos y el caracter de " para los segundos, es obligatorio ponerlo si o sí
    para que el programa identifique si se trata de un ángulo con grados, grados y minutos o grados,
    minutos y segundos.
    1. numero entero
    2. numero decimal
    3. numero decimal + ' o ° cualquiera de los dos
    4. numero entero + ' o ° + numero decimal o entero + ° o '
    5. numero entero + ' o ° + numero entero [entre 0 a 59] + ° o ' + numero decimal o entero entre 0 y 59 + ' o ° o "
    """
    value = None

    def __init__(self, value):
        if type(value)==type([]):
            value[0]=float(value[0])
            self.spin_number = int(value[0] // 360)
            self.spin_number_decimal = round(value[0] / 360, 3)
            value[0] = value[0] - 360*self.spin_number

            if len(value)==1:
                self.degree_decimals = value[0]
                self.degree = int(math.floor(self.degree_decimals))
                self.minutes_decimals = round((self.degree_decimals - self.degree)*60,3)
                self.minutes = int(math.floor(self.minutes_decimals))
                self.seconds = round(float((self.minutes_decimals - self.minutes)*60),3)
                self.decimal = (self.degree+self.minutes/60+self.seconds/3600)
            if len(value)==2:
                self.degree_decimals = value[0]
                self.degree = int(math.floor(self.degree_decimals))
                self.minutes_decimals = round(float(value[1]),3)
                self.minutes = int(math.floor(self.minutes_decimals))
                self.seconds = round(float((self.minutes_decimals - self.minutes)*60),3)
                self.decimal = (self.degree+self.minutes/60+self.seconds/3600)
            if len(value)==3:
                self.degree_decimals = value[0]
                self.degree = int(self.degree_decimals)
                self.minutes_decimals = float(value[1])
                self.minutes = int(self.minutes_decimals)
                self.seconds = round(float(value[2]),3)
                self.decimal = (self.degree+self.minutes/60+self.seconds/3600)

    def print_angle(self):
        """
        Esta función imprime de manera organizada el Azimut en el formato de
        grados, minutos y segundos.
        """
        print(f'''{self.degree}°{self.minutes}'{self.seconds}"''')


"""
This module contains functions that help evaluate trained models.
"""
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split, TimeSeriesSplit

def split(df, label_colname, test_size, seed):
    """
    Splits a dataset into training and testing dataframes.
    """
    X = df.drop(columns=[label_colname]).values
    y = df[label_colname].values
    X_train, X_test, y_train, y_test = \
        train_test_split(X, y, test_size=test_size, random_state=seed)

    df_train = pd.DataFrame(np.column_stack((X_train, y_train)),
                            columns=df.columns)
    df_test = pd.DataFrame(np.column_stack((X_test, y_test)),
                            columns=df.columns)
    return df_train, df_test

def time_split(df, n_splits):
    """
    Splits a dataframe ordered by a datetime. Training sets are supersets of
    earlier sets.

    The data will be partitioned into n_splits + 1 segments. The first split
    uses the first segment as the training set and the second segment as the
    test set. The second split uses the first and second segment as the
    training set and the third segment as the test set etc.
    """
    splitter = TimeSeriesSplit(n_splits)
    splits = splitter.split(df.values)
    return [(df.iloc[train_i], df.iloc[test_i]) for train_i, test_i in splits]