from __future__ import annotations

from typing import SupportsFloat, cast

from coredis.response._callbacks import ResponseCallback
from coredis.response.types import ScoredMember, ScoredMembers
from coredis.typing import (
    AnyStr,
    Generic,
    List,
    Optional,
    ResponsePrimitive,
    ResponseType,
    Tuple,
    Union,
    ValueT,
)

class ZRankCallback(
    ResponseCallback[
        Optional[Union[int, List[ResponsePrimitive]]],
        Optional[Union[int, List[ResponsePrimitive]]],
        Optional[Union[int, Tuple[int, float]]],
    ],
):
    def transform(
        self,
        response: Optional[Union[int, List[ResponsePrimitive]]],
        **options: Optional[ValueT],
    ) -> Optional[Union[int, Tuple[int, float]]]:
        if options.get("withscore"):
            return (response[0], float(response[1])) if response else None
        else:
            return cast(Optional[int], response)

    def transform_3(
        self,
        response: Optional[Union[int, List[ResponsePrimitive]]],
        **options: Optional[ValueT],
    ) -> Optional[Union[int, Tuple[int, float]]]:
        if options.get("withscore"):
            return (response[0], response[1]) if response else None
        else:
            return cast(Optional[int], response)

class ZMembersOrScoredMembers(
    ResponseCallback[
        List[Union[AnyStr, List[ResponsePrimitive]]],
        List[Union[AnyStr, List[ResponsePrimitive]]],
        Tuple[Union[AnyStr, ScoredMember], ...],
    ],
):
    def transform(
        self,
        response: List[Union[AnyStr, List[ResponsePrimitive]]],
        **options: Optional[ValueT],
    ) -> Tuple[Union[AnyStr, ScoredMember], ...]:
        if not response:
            return ()
        elif options.get("withscores"):
            it = iter(cast(List[AnyStr], response))
            return tuple(ScoredMember(*v) for v in zip(it, map(float, it)))
        else:
            return cast(Tuple[AnyStr, ...], tuple(response))

    def transform_3(
        self,
        response: List[Union[AnyStr, List[ResponsePrimitive]]],
        **options: Optional[ValueT],
    ) -> Tuple[Union[AnyStr, ScoredMember], ...]:
        if options.get("withscores"):
            return tuple(
                ScoredMember(*v) for v in cast(List[Tuple[AnyStr, float]], response)
            )
        else:
            return cast(Tuple[AnyStr, ...], tuple(response))

class ZSetScorePairCallback(
    ResponseCallback[
        Optional[List[ResponsePrimitive]],
        Optional[List[Union[ResponsePrimitive, List[ResponsePrimitive]]]],
        Optional[Union[ScoredMember, ScoredMembers]],
    ],
    Generic[AnyStr],
):
    def transform(
        self, response: Optional[List[ResponsePrimitive]], **options: Optional[ValueT]
    ) -> Optional[Union[ScoredMember, ScoredMembers]]:
        if not response:
            return None

        if not (options.get("withscores") or options.get("count")):
            return ScoredMember(
                cast(AnyStr, response[0]), float(cast(SupportsFloat, response[1]))
            )

        it = iter(response)
        return tuple(ScoredMember(*v) for v in zip(it, map(float, it)))

    def transform_3(
        self,
        response: Optional[List[Union[ResponsePrimitive, List[ResponsePrimitive]]]],
        **options: Optional[ValueT],
    ) -> Optional[Union[ScoredMember, ScoredMembers]]:
        if not response:
            return None

        if not (options.get("withscores") or options.get("count")):
            return ScoredMember(*cast(Tuple[AnyStr, float], response))

        return tuple(
            ScoredMember(*v) for v in cast(List[Tuple[AnyStr, float]], response)
        )

class ZMPopCallback(
    ResponseCallback[
        Optional[List[ResponseType]],
        Optional[List[ResponseType]],
        Optional[Tuple[AnyStr, ScoredMembers]],
    ],
    Generic[AnyStr],
):
    def transform(
        self, response: Optional[List[ResponseType]], **options: Optional[ValueT]
    ) -> Optional[Tuple[AnyStr, ScoredMembers]]:
        r = cast(Tuple[AnyStr, List[Tuple[AnyStr, int]]], response)
        if r:
            return r[0], tuple(ScoredMember(v[0], float(v[1])) for v in r[1])

        return None

class ZMScoreCallback(
    ResponseCallback[
        List[ResponsePrimitive], List[ResponsePrimitive], Tuple[Optional[float], ...]
    ]
):
    def transform(
        self, response: List[ResponsePrimitive], **options: Optional[ValueT]
    ) -> Tuple[Optional[float], ...]:
        return tuple(score if score is None else float(score) for score in response)

class ZScanCallback(
    ResponseCallback[List[ResponseType], List[ResponseType], Tuple[int, ScoredMembers]],
    Generic[AnyStr],
):
    def transform(
        self, response: List[ResponseType], **options: Optional[ValueT]
    ) -> Tuple[int, ScoredMembers]:
        cursor, r = cast(Tuple[int, List[AnyStr]], response)
        it = iter(r)
        return int(cursor), tuple(
            ScoredMember(*cast(Tuple[AnyStr, float], v))
            for v in zip(it, map(float, it))
        )

class ZRandMemberCallback(
    ResponseCallback[
        Optional[Union[AnyStr, List[ResponsePrimitive]]],
        Optional[Union[AnyStr, List[ResponsePrimitive]]],
        Optional[Union[AnyStr, ScoredMembers]],
    ]
):
    def transform(
        self,
        response: Optional[Union[AnyStr, List[ResponsePrimitive]]],
        **options: Optional[ValueT],
    ) -> Optional[Union[AnyStr, ScoredMembers]]:
        if not (response and options.get("withscores")):
            return response

        it = iter(response)
        return tuple(ScoredMember(*v) for v in zip(it, map(float, it)))

    def transform_3(
        self,
        response: Optional[Union[AnyStr, List[ResponsePrimitive]]],
        **options: Optional[ValueT],
    ) -> Optional[Union[AnyStr, ScoredMembers]]:
        if not (response and options.get("withscores")):
            return response

        return tuple(ScoredMember(*v) for v in response)

class BZPopCallback(
    ResponseCallback[
        Optional[List[ResponsePrimitive]],
        Optional[List[ResponsePrimitive]],
        Optional[Tuple[AnyStr, AnyStr, float]],
    ]
):
    def transform(
        self, response: Optional[List[ResponsePrimitive]], **options: Optional[ValueT]
    ) -> Optional[Tuple[AnyStr, AnyStr, float]]:
        if response:
            return response[0], response[1], float(response[2])
        return None

class ZAddCallback(
    ResponseCallback[ResponsePrimitive, Union[int, float], Union[int, float]]
):
    def transform(
        self, response: ResponsePrimitive, **options: Optional[ValueT]
    ) -> Union[int, float]:
        if options.get("condition"):
            return float(response)
        return int(response)

    def transform_3(
        self, response: Union[int, float], **options: Optional[ValueT]
    ) -> Union[int, float]:
        return response


from collections import deque
import heapq

n, k = map(int, input().split())
arr = [[0]*(n+1) for _ in range(n+1)]
q = []
for i in range(1, n+1):
    data = list(map(int, input().split()))
    for j in range(1, n+1):
        arr[i][j] = data[j-1]
        if data[j-1] != 0:
            # virus
            heapq.heappush(q, (data[j-1], i, j))

# viruses.sort()
s, a, b = map(int, input().split())
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]

if s == 0:
    print(arr[a][b])
    exit(0)

time = 0
next_viruses = []
while len(q) > 0:
    t, x, y = heapq.heappop(q)
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if nx <= 0 or ny <= 0 or nx > n or ny > n or arr[nx][ny] != 0:
            continue
        arr[nx][ny] = t
        next_viruses.append((t, nx, ny))

    if len(q) == 0:
        time += 1
        if time == s:
            print(arr[a][b])
            exit(0)
        for virus in next_viruses:
            heapq.heappush(q, virus)
        next_viruses = []

print(arr[a][b])
exit(0)


def is_null_or_empty(item):
    if item is None or item.strip() == '':
        return True

    return False

def is_estimated(item):
    if item == 'E':
        return True

    return False

def is_missing_or_unavailable(item):
    if item == 'M' or item == 'NA':
        return True

    return False

ENVIRONMENT = (
    'unknown',
    'clear',
    'rain',
    'snow',
    'freezing rain',
    'drifting snow',
    'strong wind',
    'fog, mist, smoke, dust',
    'other'
)

VISIBILITY = (
    'unknown',
    'daylight',
    'daylight, artificial',
    'dawn',
    'dawn, artificial',
    'dusk',
    'dusk, artificial',
    'dark',
    'dark, artificial',
    'other'
)

ROAD_SURFACE = (
    'unknown',
    'dry',
    'ice',
    'loose snow',
    'packed snow',
    'slush',
    'wet',
    'mud',
    'loose sand or gravel',
    'spilled liquid',
    'other'
)

TRAFFIC_CONTROL = (
    'traffic signal',
    'stop sign',
    'yield sign',
    'pedestrian crossover',
    'school bus',
    'traffic gate',
    'traffic controller',
    'no control',
    'roundabout',
    'other'
)

COLLISION_CLASSIFICATION = (
    'fatal',
    'non-fatal injury',
    'p.d. only'
)

IMPACT_TYPE = (
    'approaching',
    'angle',
    'cyclist collisions',
    'pedestrian collisions',
    'rear end',
    'sideswipe',
    'turning movement',
    'smv unattended vehicle',
    'smv other',
    'other'
)


from django.conf.urls import url
from . import views
app_name='music'
urlpatterns = [
           #/music/
           url(r'^$', views.index, name='index'),
           url(r'^register/$', views.UserFormView.as_view(), name='register'),
           url(r'^login/$', views.login_user, name='login'),
           url(r'^logout/$', views.logout_user, name='logout'),
          # /music/<album_id>/
           url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),

           url(r'^music_list/$',views.SongsView, name='music_list'),

            url(r'^(?P<album_id>[0-9]+)/song-add/$', views.create_song, name='song-add'),
           # /music/album/add
	   url(r'album/add/$',views.AlbumCreate.as_view(),name='album-add'),

           # /music/album/2/
           url(r'album/(?P<pk>[0-9]+)/$',views.AlbumUpdate.as_view(),name='album-update'),
          # /music/album/2/delete
           url(r'album/(?P<pk>[0-9]+)/delete/$',views.AlbumDelete.as_view(),name='album-delete'),
          # /music/music_list/(?P<pk>[0-9]+)/delete/
          url(r'music_list/(?P<pk>[0-9]+)/song-delete/$', views.SongDelete.as_view(),name='song-delete'),

]


estado_inicial = True

def setup():
    size(400, 400)

def draw():
    global estado_inicial

    if estado_inicial:
        background(200)
    else:
        background(10)

    resultado1 = botao(100, 125, 200, 50, "clique aqui")
    resultado2 = botao(100, 225, 200, 50, "de novo!")
    if resultado1 or resultado2:
            print('clique')
            estado_inicial = not estado_inicial

def botao(x, y, w, h, _text):
    global estado_botoes
    try:
        estado_botoes
    except NameError:
        estado_botoes = dict()

    mouse_over = (x < mouseX < x + w and
                  y < mouseY < y + h)
    if mouse_over:
        fill(140)
    else:
        fill(240)
    rect(x, y, w, h, 5)
    fill(0)
    textAlign(CENTER, CENTER)
    text(_text, x + w / 2, y + h / 2)
    if mouse_over:
        if mousePressed:
            estado_botoes[(x, y)] = True
            return False
        elif estado_botoes.get((x, y)):
            estado_botoes[(x, y)] = False
            return True
    estado_botoes[(x, y)] = False
    return False


import re
import time

from .check_lex import lexer
from .utils import load_json, write_json_file

CONFIG = None  # _config.json
CONFIG_DEP = None  # _config_dep.json
CONFIG_VALUE = {}  # .config文件
HAVE_CHECK = {}
LAST_CONFIG = []  # (name, value)
ERROR_CONFIG_FLAG = []
ERROR_JSON = {}

def reset_GLOAL():
    global CONFIG, CONFIG_DEP, CONFIG_VALUE, HAVE_CHECK, LAST_CONFIG, ERROR_CONFIG_FLAG, ERROR_JSON
    CONFIG = None
    CONFIG_DEP = None
    CONFIG_VALUE = {}
    HAVE_CHECK = {}
    LAST_CONFIG = []
    ERROR_CONFIG_FLAG = []
    ERROR_JSON = {}

def get_tokens(data):
    """ check_lex借助ply.lex实现的词法分析器
        对输入的data数据解析, 并返回list
    """
    lexer.input(data)
    result = []
    while True:
        tok = lexer.token()
        if not tok:
            break
        result.append(tok)
    return result

class Error:
    """ 整理错误信息, 打印到*_error.json中

    属性包括:
        * name: 配置项名称
        * path: 配置项存储路径
        * error: 存储具体的错误信息
        * value: 错误配置在配置文件(.config)中的具体取值
        * dep_value: 配置项的属性信息, 以及在配置文件的取值
    """

    def __init__(self, config_name, error, index=-1) -> None:
        self.name = config_name
        self.path = self.get_path(config_name)
        self.error = [error]
        self.type = self.update_type(config_name)
        self.value = CONFIG_VALUE[config_name] if CONFIG_VALUE.get(config_name, None) is not None else None
        self.dep_value = [self.handle_value(index)]

    def update_type(self, config_name):
        if CONFIG.get(config_name, None) is not None:
            result = None
            for item in CONFIG[config_name]:
                result = item['type']
            return result
        else:
            return None

    def get_path(self, config_name):
        if CONFIG.get(config_name, None) is not None:
            path = []
            for item in CONFIG[config_name]:
                # if item['path'] not in path:
                    path.append(item['path'])
            return path
        else:
            return None

    def update_value(self, line):
        words = get_tokens(line)
        result = ''
        for item in words:
            result += ' ' if len(result) > 0 else ''
            if item.type == 'WORD' and not re.fullmatch('-?[0-9]+', item.value) and re.fullmatch('[A-Z0-9_x]+', item.value):
                value = CONFIG_VALUE.get(item.value, 'n')
                result += item.value + ' {= ' + value + '}'
            else:
                result += item.value
        return result

    def handle_value(self, index):
        if index == -1:
            return None
        config_dep = CONFIG_DEP.get(self.name, None)
        result = {
            'rev_select': self.update_value(config_dep[index]['rev_select']),
            'depends': self.update_value(config_dep[index]['dep']),
            'restrict': self.update_value(config_dep[index]['restrict']),
        }
        return result

def add_error(config_name, error_data, index = -1):
    global ERROR_JSON
    target = ERROR_JSON.get(config_name, None)
    if target and error_data not in target.error:
        target.error.append(error_data)
        target.dep_value.append(target.handle_value(index))
    else:
        node = Error(config_name, error_data, index)
        ERROR_JSON[config_name] = node

def load_config(path):
    """ 加载.config配置文件
        对于配置文件中不存在以及is not set的config取值为n
    """
    global CONFIG_VALUE
    with open(path, 'r') as file:
        lines = file.readlines()
        name = ''
        for line in lines:
            if line[0:9] == '# CONFIG_':
                name = line.replace('# CONFIG_','').replace(' is not set\n', '')
                ptr = CONFIG_VALUE.get(name, None)
                if not ptr:
                    CONFIG_VALUE[name] = 'n'
                else:
                    print("error, repeat config => " + name + " in .config")
            elif line[:7] == 'CONFIG_':
                line = line[7:].replace('\n', '')
                (name, value) = line.split('=', 1)
                ptr = CONFIG_VALUE.get(name, None)
                if not ptr:
                    CONFIG_VALUE[name] = value
                else:
                    print("error, repeat config => " + name + " in .config")
    print("{:<40}".format("[Load config end!]") + "got " + str(len(CONFIG_VALUE)) + " config")

def check_MODULES():
    """ 检查非法模块
        当CONFIG_MODULES被关闭时，配置项取值为'm'是错误
    """
    global CONFIG_VALUE
    for item in CONFIG_VALUE:
        if CONFIG_VALUE[item] == 'm':
            if CONFIG_VALUE['MODULES'] != 'y':
                add_error('MODULES', 'the configuration has tristate type, but MODULES is not enable')
            break

def check_type(config_type, value):
    """ 检查配置项取值是否满足类型限制

    Args:
        config_type (str): 类型定义
        value (str): 实际取值

    Returns:
        布尔类型: True 取值正确
                 False 取值错误
    """
    if value == '' or value == 'n':
        return True
    if config_type == 'bool' and (value == 'y' or value == 'n'):
        return True
    elif config_type == 'tristate' and (value == 'y' or value == 'm' or value == 'n'):
        return True
    elif config_type == 'int' and re.fullmatch('-?[0-9]+', value):
        return True
    elif config_type == 'hex' and (re.fullmatch('0', value) or value[:2] == '0x'):
        return True
    elif config_type == 'string':
        return True
    return False

def value2num(value):
    """ 按照Kconfig官方文档要求:
        数字类按原值计算
        对于bool、tristate类型, y = 2,  m = 1,  n = 0
        其余类型全部为 0
    """
    if isinstance(value, int):
        return value
    if re.fullmatch('-?[0-9]+', value):
        return int(value)
    elif value[0:2] == '0x':
        return int(value, 16)
    elif value == 'y':
        return 2
    elif value == 'm':
        return 1
    elif value == 'n':
        return 0
    return 0

def num2value(num):
    if num == 2:
        return 'y'
    elif num == 1:
        return 'm'
    else:
        return 'n'

def get_last_config_name():
    global LAST_CONFIG
    result = []
    for item in LAST_CONFIG:
        result.append(item[0])
    return result

def get_last_config_value():
    global LAST_CONFIG
    result = []
    for item in LAST_CONFIG:
        result.append(item[1])
    return result

def get_config_value(word):
    """ 在配置文件中查找配置项的取值
        若未出现则认为是n
        数字类型也返回string形式
    """
    if isinstance(word, int):
        return str(word)
    if re.fullmatch('-?[0-9]+', word) or word[0:2] == '0x':
        return word
    if re.fullmatch('[A-Z0-9_x]+', word):
        if word in CONFIG_VALUE:
            if word in get_last_config_name():
                return CONFIG_VALUE[word]
            if HAVE_CHECK.get(word, None) is None:
                if CONFIG_DEP.get(word, None) == None:
                    add_error(word, "lack config => " + word)
                    return CONFIG_VALUE[word]
                check_config(CONFIG_DEP[word], word)
            return CONFIG_VALUE[word]
        else:
            return 'n'
    else:
        return word

def check_bracket(tokens, index):
    save = []
    temp = []
    index += 1
    while index < len(tokens):
        if tokens[index].value == '(':
            save.append(temp)
            temp = []
        elif tokens[index].value == ')':
            if len(save) == 0:
                index += 1
                break
            else:
                value = reduce(check_expr(temp))
                temp = save.pop()
                temp += get_tokens(value)
        else:
            temp.append(tokens[index])
        index += 1
    return (reduce(check_expr(temp)), index)

def handle_op(tokens, index, value):
    if index < len(tokens):
        if tokens[index].value in ['=', '!=', '<', '<=', '>', '>=']:
            next = tokens[index + 1].value
            next = get_config_value(next)
            value = get_config_value(value)
            if tokens[index].value == '=':
                value = 'y' if value == next else 'n'
            elif tokens[index].value == '!=':
                value = 'y' if value != next else 'n'
            elif tokens[index].value == '<':
                value = 'y' if value < next else 'n'
            elif tokens[index].value == '<=':
                value = 'y' if value <= next else 'n'
            elif tokens[index].value == '>':
                value = 'y' if value > next else 'n'
            elif tokens[index].value == '>=':
                value = 'y' if value >= next else 'n'
            return (value, index + 2)
    return (value, index)

def get_bracket(tokens, index):
    if index < len(tokens) and tokens[index].value == '[':
        index += 1
        save = []
        while index < len(tokens) and tokens[index].value != ']':
            save.append(tokens[index])
            index += 1
        index += 1
        if value2num(reduce(check_expr(save))):
            return (True, index)
        else:
            return (False, index)
    return (True, index)

def handle_bracket(tokens, index, value, stack):
    if index < len(tokens) and tokens[index].value == '[':
        (result, index) = get_bracket(tokens, index)
        if result:
            stack.append(value)
        else:
            if len(stack) > 0:
                prev = stack.pop()
                if prev == '!' and len(stack) > 0:
                    stack.pop()
            else:
                stack.append('y')
    else:
        stack.append(value)
    return (stack, index)

def op2num(op):
    if op == '!': return 3
    elif op == '&&': return 2
    else: return 1

def infix2suffix(stack):
    result = []
    op = []
    for item in stack:
        if item in ['&&', '||', '!']:
            if len(op) == 0:
                op.append(item)
            else:
                while len(op) and op2num(op[-1]) >= op2num(item):
                    result.append(op.pop())
                op.append(item)
        else:
            result.append(item)
    while len(op):
        result.append(op.pop())
    return result

def reduce(stack):
    if len(stack) == 1:
        return stack[0]
    cal_stack = infix2suffix(stack)
    result = []
    for item in cal_stack:
        if item == '!':
            tmp = result.pop()
            result.append(num2value(2 - value2num(tmp)))
        elif item == '&&':
            right = result.pop()
            left = result.pop()
            result.append(num2value(min(value2num(left), value2num(right))))
        elif item == '||':
            right = result.pop()
            left = result.pop()
            result.append(num2value(max(value2num(left), value2num(right))))
        else:
            result.append(item)
    return result[0]

def check_expr(tokens):
    stack = []  # 存储解析后表达式
    index = 0
    while index < len(tokens):
        if tokens[index].type in ['NOT', 'AND', 'OR']:
            stack.append(tokens[index].value)
            index += 1
        elif tokens[index].type == 'OPEN_PARENT':  # (
            (value, index) = check_bracket(tokens, index)
            stack.append(value)
        elif tokens[index].type == 'WORD':
            value = get_config_value(tokens[index].value)
            # 如果后跟不等式判断, 检查表达式是否成立
            (value, index) = handle_op(tokens, index + 1, value)
            # 如果后跟if表达式, 检查表达式是否成立
            (stack, index) = handle_bracket(tokens, index, value, stack)
        elif tokens[index].type == 'SP_WORD':
            value = 'y'
            # 如果后跟不等式判断, 检查表达式是否成立
            index += 1
            if index < len(tokens) and tokens[index].value in ['=', '!=', '<', '<=', '>', '>=']:
                index += 2
            if len(stack) > 0 and stack[len(stack) - 1] == '!':
                stack.append('n')
            else:
                stack.append('y')
    return stack

def check_select(tokens):
    stack = check_expr(tokens)
    if not len(stack): return 'n'
    return reduce(stack)

def check_dep(tokens):
    stack = check_expr(tokens)
    if not len(stack): return 'y'
    return reduce(stack)

def check_restrict(tokens, config_name, config_value, config_index):
    """ 检查取值限制是否满足
        restrict表达式中, 格式通常为()[XXX], []内部if表达式形式多样, 需要全面考虑
        表达式内部不存在sp_word, 多出现在()或[]内部进行比较
        表达式内部若出现word[expr], 通常为imply语句

    Args:
        tokens : 取值限制表达式
        config_name : 配置项名称
        config_value : 配置项取值
        config_index : 配置项序号

    Returns:
        布尔类型: 检查结果
    """

    stack = []  # 存储解析后表达式
    index = 0
    while index < len(tokens):
        if tokens[index].type in ['OR', 'NOT', 'AND']:
            stack.append(tokens[index].value)
            index += 1
        elif tokens[index].type == 'OPEN_PARENT':
            index += 1
            parent_index = 0
            temp = []
            while index < len(tokens):
                if tokens[index].value == '(':
                    parent_index += 1
                elif tokens[index].value == ')':
                    if parent_index == 0:
                        break
                    parent_index -= 1
                temp.append(tokens[index])
                index += 1
            index += 1
            if len(temp) == 1:
                if temp[0].type == 'WORD':
                    (result, index) = get_bracket(tokens, index)
                    if result:
                        value = get_config_value(temp[0].value)
                        config_value = get_config_value(config_value)
                        if value != config_value:
                            stack.append('n')
                        else:
                            stack.append('y')
                    else:
                        stack.append('y')
                elif temp[0].type == 'SP_WORD':
                    (result, index) = get_bracket(tokens, index)
                    stack.append('y')
                elif temp[0].type == 'QUOTE_WORD':
                    value = temp[0].value
                    if len(value) == 2:
                        value = 'y' if len(config_value) == 0 else 'n'
                    else:
                        value = 'y' if value[1:-1] == config_value else 'n'
                    (stack, index) = handle_bracket(tokens, index, value, stack)
            elif len(temp) == 2:
                if temp[0].type == 'NOT' and (temp[1].type == 'WORD' or temp[1].type == 'SP_WORD'):
                    value = 'y' if config_value == reduce(check_expr(temp)) else 'n'
                    (stack, index) = handle_bracket(tokens, index, value, stack)
                elif temp[0].type == 'WORD' and temp[1].type == 'WORD':
                    (result, index) = get_bracket(tokens, index)
                    if result:
                        left = value2num(get_config_value(temp[0].value))
                        right = value2num(get_config_value(temp[1].value))
                        config_value = value2num(get_config_value(config_value))
                        if left <= config_value and config_value <= right:
                            pass
                        else:
                            add_error(config_name, "range error", config_index)
                    stack.append('y')
            else:
                value = reduce(check_expr(temp))
                (stack, index) = handle_bracket(tokens, index, value, stack)
    if len(stack) == 0:
        return True
    return True if value2num(reduce(stack)) else False

def check_config(config_list, config_name): # HAVE_CHECK放在for循环, 检查config时自动查看config取值
    """ 检查配置项是否满足Kconfig约束条件
        检查逻辑：
            select检查
            dep检查
            restrict检查

    Args:
        config_list : 配置项约束条件
        config_name : 待检查配置项名称
    """
    global HAVE_CHECK, LAST_CONFIG
    if CONFIG_VALUE.get(config_name, None) == None or CONFIG_VALUE.get(config_name, None) == 'n':
        HAVE_CHECK[config_name] = True
        return 'n'
    config_value = CONFIG_VALUE.get(config_name, 'n')
    LAST_CONFIG.append((config_name, config_value))
    if config_name in CONFIG_VALUE:
        index = -1
        error_save = {
            'type error' : [],
            'unmet dependences' : [],
            'restrict warning' : [],
            'depends error' : []
        }
        for item in config_list:
            index += 1
            if not check_type(item['type'], config_value):
                HAVE_CHECK[config_name] = False
                # add_error(config_name, "type error", index)
                error_save['type error'].append(index)
                continue
            select_tokens = get_tokens(item['rev_select'])
            dep_tokens = get_tokens(item['dep'])
            if len(select_tokens) and value2num(check_select(select_tokens)):
                HAVE_CHECK[config_name] = True
                if len(item['dep']) and not value2num(check_dep(dep_tokens)):
                    # add_error(config_name, "unmet dependences", index)
                    error_save['unmet dependences'].append(index)
                elif len(error_save['unmet dependences']):
                    error_save['unmet dependences'].pop()
                break
            elif len(dep_tokens) == 0 or value2num(check_dep(dep_tokens)):
                restrict_tokens = get_tokens(item['restrict'])
                if len(error_save['depends error']):
                    error_save['depends error'].pop()
                if len(restrict_tokens) == 0 or check_restrict(restrict_tokens, config_name, config_value, index):
                    HAVE_CHECK[config_name] = True
                    if len(error_save['restrict warning']):
                        error_save['restrict warning'].pop()
                else:
                    HAVE_CHECK[config_name] = False
                    # add_error(config_name, "restrict warning", index)
                    error_save['restrict warning'].append(index)
            else:
                HAVE_CHECK[config_name] = False
                # add_error(config_name, "depends error", index)
                error_save['depends error'].append(index)
            if HAVE_CHECK[config_name]:
                break
        # 看error_save有无错误，有则填入
        if len(error_save['depends error']):
            add_error(config_name, "depends error", error_save['depends error'][0])
        if len(error_save['restrict warning']):
            add_error(config_name, "restrict warning", error_save['restrict warning'][0])
        if len(error_save['unmet dependences']):
            add_error(config_name, "unmet dependences", error_save['unmet dependences'][0])
    else:
        # 如果未检查且不在.config文件, 默认是正确的
        HAVE_CHECK[config_name] = True
    LAST_CONFIG.pop()

def Checker(dep_path, config_path, file_path, save_file):
    """ 检查功能入口

    Args:
        dep_path (str): Kconfig解析后生成的_dep.json文件
        config_path (str): Kconfig解析后生成的_config.json文件
        file_path (str): 待检查内核配置文件
        save_file (str): 输出检查结果_error.json文件
    """

    reset_GLOAL()
    global CONFIG, CONFIG_DEP, CONFIG_VALUE, HAVE_CHECK
    begin = time.time()
    load_config(file_path)
    CONFIG_DEP = load_json(dep_path)
    CONFIG = load_json(config_path)
    check_MODULES()
    for name in CONFIG_VALUE:
        if CONFIG_VALUE[name] == 'n':
            HAVE_CHECK[name] = True
            continue
        elif CONFIG_DEP.get(name, None) == None:
            add_error(name, "lack config")
            continue
        check_config(CONFIG_DEP[name], name)
    cost = time.time() - begin
    print("\rCheck time\t\t{}".format(str(cost)))
    global ERROR_JSON
    if len(ERROR_JSON) > 0:
        print("{:<40}".format("[Prepare write check result]") + "file => " + save_file)
        write_json_file(ERROR_JSON, save_file)
    else:
        print("{:<40}".format("[Check end]") + "The configuration is right !")


from django import forms
from .models import NoteBook, Note, Profile
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class NoteBookForm(forms.ModelForm):
	class Meta:
		model = NoteBook
		fields = ['name', 'description', 'color', 'is_public', 'owner']
		widgets = {'owner': forms.HiddenInput()}

class NoteForm(forms.ModelForm):
	class Meta:
		model = Note
		fields = '__all__'
		widgets = {'created_at': forms.HiddenInput(), 'notebook':forms.HiddenInput()}

class NewUserForm(UserCreationForm):
	email = forms.EmailField(required=True)

	class Meta:
		model = User
		fields = ['username', 'email', 'password1', 'password2']

	def save(self, commit=True):
		user = super(NewUserForm, self).save(commit=False)
		user.email = self.cleaned_data['email']
		if commit:
			user.save()
		return user

class EditProfileForm(forms.ModelForm):
	class Meta:
		model = Profile
		fields = ['photo', 'bio']

	def __init__(self, *args, **kwargs):
		super(EditProfileForm, self).__init__(*args, **kwargs)
		self.fields['photo'].required = False


# NIM/Nama  : 16520299/Malik Akbar Hashemi Rafsanjani
# Tanggal   : 29 November 2020
# Deskripsi : Program menerima input N dan M lalu membaca matriks A ukuran NxM dan
#             menuliskan berapa bilangan positif di dalam matriks serta mencetak matriks

# KAMUS
# N, M, Pos : integer
# Mat : Matriks

# Definisi fungsi isiMatrix
def isiMatrix(N, M):
    # Inisialisasi dan pengisian elemen matriks

    # KAMUS LOKAL
    # Mat : matriks
    # i,j : integer

    # ALGORITMA
    Mat = [[0 for i in range(M)] for j in range(N)]
    for i in range(N):
        for j in range(M):
            Mat[i][j] = int(input("Masukkan nilai A[" + str(i+1) + "][" + str(j+1) + "]: "))
    return Mat

# Definisi fungsi cariPositif
def cariPositif(Mat, N, M):
    # Menghitung berapa banyak bilangan positif di dalam matriks

    # KAMUS LOKAL
    # count, i, j : integer

    # ALGORITMA
    count = 0
    for i in range(N):
        for j in range(M):
            if Mat[i][j] > 0:
                count += 1
    return count

# Definisi prosedur cetakMatrix
def cetakMatrix(Mat, N, M):
    # Mencetak matriks ke layar

    # KAMUS LOKAL
    # i, j : integer

    # ALGORITMA
    for i in range(N):
        for j in range(M):
            print(Mat[i][j], end=" ")
        print()

# ALGORITMA PROGRAM UTAMA

# Menerima input N dan M
N = int(input("Masukkan N: "))
M = int(input("Masukkan M: "))

# Inisialisasi dan mengisi matriks
Mat = isiMatrix(N,M)

# Menghitung berapa banyak bilangan positif di dalam matriks
Pos = cariPositif(Mat, N, M)

# Mencetak hasil perhitungan bilangan positif
print("Ada " + str(Pos) + " bilangan positif di matriks.")

# Mencetak matriks ke layar
cetakMatrix(Mat, N, M)


#!/usr/bin/env python3

# Edit line 31 in csv.h from
#
# // sprintf(formstring,"%%%ie",kolombreedte);
#
# into
#
# // sprintf(formstring,"%%%if",kolombreedte);
#
# or this script won't be able to read the scientific notations

from matplotlib import pyplot as plt

with open("dieptedata.csv") as f:
    dieptes = [ float(d) for d in f.read().splitlines() ]

    plt.plot(dieptes, color='blue', marker=None, linestyle='solid')

    plt.xlabel("Datapunt")
    plt.ylabel("Diepte")
    plt.show()


from .search_request import SearchRequest
from .search_result import SearchResult
from .search_result import SearchResultExcerpt
from .search_result_queue import SearchResultQueue
from .web_crawler_queue import WebCrawlerQueue
from .search_utils import SearchUtils
from enum import Enum
import queue
import threading
import time
import httplib2
import logging
import os

class WebCrawlerWorker:
    status = Enum('WebCrawelerWorkerStatus', ['None', 'Processing', 'Waiting', 'Stopping'])
    thread: threading.Thread
    id: int
    search_request: SearchRequest
    search_queue: WebCrawlerQueue
    result_queue: SearchResultQueue

    def __init__(self, id: str, search_request: SearchRequest, search_queue: WebCrawlerQueue, result_queue: SearchResultQueue):
        self.id = id
        self.search_request = search_request
        self.search_queue = search_queue
        self.result_queue = result_queue
        self.status = 'None'

    def set_status(self, status):
        self.status = status
        logging.info(f'WebCrawlerWorker[{self.id}]: set_status: {status}')

    def start_thread(self):
        if self.status == 'None':
            self.thread = threading.Thread(target=self.work_loop)
            self.thread.start()
            self.set_status('Processing')
        else:
            logging.error(f'WebCrawlerWorker[{self.id}]: Worker thread status is {self.status}')

    def stop_thread(self):
        if self.status == 'Processing' or self.status == 'Waiting':
            self.status = 'Stopping'
            self.thread.join() # wait for the thread finish
            self.set_status('None')

    def active(self):
        return self.status == 'Processing' or self.status == 'Stopping'

    def work_loop(self):
        while True:
            if self.status == 'Stopping':
                break # Stop was requsted
            else:
                url = self.search_queue.dequeue()
                if url:

                    self.set_status('Processing')
                    self.process_url(url)
                else:
                    self.set_status('Waiting')
                    time.sleep(1)

    def process_url(self, url):
        logging.info(f'WebCrawlerWorker[{self.id}]: Processing {url}')
        try:

            # Query the URL
            resp, contents = httplib2.Http().request(url)
            str_contents = contents.decode('utf-8')

            if self.search_request.debug_output_enabled:
                self.save_debug_files(url, str_contents)

            # Handle any results
            results = SearchUtils.search_keywords(self.search_request, url, str_contents)
            logging.info(f'WebCrawlerWorker[{self.id}]: Processing {url}, Match={len(results)>0}')
            for result in results:
                self.result_queue.enqueue(result)

            # Handle any links
            links = SearchUtils.search_links(self.search_request, url, str_contents)
            for link in links:

                # Check the domain
                link_lower = link.lower()
                domain_match = 'none'
                for domain in self.search_request.domains:
                    if(domain in link_lower):
                        domain_match = domain
                        self.search_queue.enqueue(link)
                        break

                logging.debug(f'WebCrawlerWorker[{self.id}]: Processing {url}, Link={link}, DomainMatch={domain_match}')

        except Exception as Argument:
            logging.exception(f'WebCrawlerWorker[{self.id}]: Processing {url}, Exception{Argument}')

    def save_debug_files(self, url: str, contents : str):

        urls_dir = f'{self.search_request.debug_output_dir}/urls'
        if not os.path.exists(urls_dir):
            os.makedirs(urls_dir)

        invalid_chars = ["#", "/", "\"", "+", "$", "?", "@" ]
        filename = url
        for c in invalid_chars:
            filename = filename.replace(c, "-")
        filePath = f'{urls_dir}/{filename}.txt'

        file = open(filePath, "w")
        try:
            file.write(contents)
        finally:
            file.close()


import numpy as np
from multiprocessing import cpu_count, Pool, freeze_support
import pandas as pd
cores = cpu_count()  # Number of CPU cores on your system
partitions = cores  # Define as many partitions as you want

def parallelize(data, func,partitions):
    freeze_support()

    data_split = np.array_split(data, partitions)

    pool = Pool(cores)
    data = pd.concat(pool.map(func, data_split))
    pool.close()
    pool.join()
    return data


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# WYWOŁANIE
# train_multiple_networks <KATALOG_Z_DANYMI> <NAZWA_KOLUMNY> <ROZMIAR_WEJŚCIA_SIECI> <ILOŚĆ_EPOK>
# <STOSUNEK TRENING/TEST> <KATALOG_Z_REZULTATAMI> <WSPÓŁCZYNNIK_SKALOWANIA>

import sys
import os
import train_for_gnss as training_script

def main(argv):
    path = argv[1]
    files = []
    names = []
    # r=root, d=directories, f = files
    for r, d, f in os.walk(path):
        for file in f:
            if '.csv' in file:
                files.append(os.path.join(r, file))
                names.append(file.split('.')[0])

    for i in range(len(files)):
        print('{} -> {}'.format(names[i], files[i]))
        training_script.main(['', files[i], argv[2], argv[3], argv[4],
                              argv[5], names[i], argv[6], argv[7]])

if __name__ == '__main__':
    main(sys.argv)


import  requests
url = "http://m.ip138.com/ip.asp?ip="
r = requests.get(url+'202.204.80.112')
print(r.status_code)
print(r.text[-500:])

# ip地址查询得全代码
try:
    r = requests.get(url + '202.204.80.112')
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    print(r.encoding)
    print(r.text[-500:])
except:
    print("爬取失败")

ip归属地得自动查询.py

ip归属地得自动查询.py


"""
    CS5001 Fall 2022
    Final Project: Brain Tumor Segmentation
    -Training and validating a U-Net model
    Hua Wang
"""

from sklearn.model_selection import train_test_split
from unet.model import *
from unet.util import *
import torch

def validation(unet: Unet, validation_img: pd.DataFrame, device,
               batch_size: int = 10):
    """
    Make predictions on the validation/test dataset given a U-Net
    model and file directories to read the dataset

    :param unet: Unet, a pretrained model
    :param validation_img: dataframe, file directories for data set
    :param device: torch.device
    :param batch_size: int
    :return: pred_dice_score, pred_iou_score, tensors
    """

    # load data into device
    validation_content, validation_mask = load_data(
        validation_img, shuffle=True, batch_size=batch_size
    )
    validation_content, validation_mask = adjust_data(
        validation_content, validation_mask
    )
    validation_content_tensor = \
        torch.from_numpy(validation_content).to(device).float()
    validation_mask_tensor = \
        torch.from_numpy(validation_mask).to(device).float()

    unet.eval()  # close BatchNorm2d during validation

    # calculate prediction of validation image with no autograd mechanism
    with torch.no_grad():
        pred_mask_tensor = unet.forward(validation_content_tensor)
        pred_mask_tensor = torch.round(pred_mask_tensor)
        pred_dice_score = dice_score(pred_mask_tensor, validation_mask_tensor)
        pred_iou_score = iou_score(pred_mask_tensor, validation_mask_tensor)

    return pred_dice_score, pred_iou_score

def train(train_img: pd.DataFrame,
          validation_img: pd.DataFrame,
          lr: float = 0.0001,
          use_cel: bool = True,
          epoch: int = 1,
          shuffle: bool = False,
          batch_size: int = 32,
          device_: str = 'cpu'):
    """
    Train the model based on training set, given file directories to load
    the training set and validation set
    :param train_img: dataframe, file directories for training data
    :param validation_img: dataframe, file directories for validation data
    :param lr: float, learning rate
    :param use_cel: bool, whether to use cross entropy loss
    :param epoch: int
    :param shuffle: bool
    :param batch_size: int
    :param device_: string
    :return: none
    """
    # define device
    if device_ != 'cuda' and device_ != 'cpu':
        raise ValueError("invalid device")
    if not torch.cuda.is_available() and device_ == 'cuda':
        device = torch.device('cpu')
    else:
        device = torch.device(device_)
    print("using", device.type)

    # how many iterations do we need to go through all data in an epoch
    iteration = train_img.shape[0] // batch_size

    # execute validation on every 20 iteration
    interval = 20

    # initialize model and model parameters
    print("initialize model")
    unet = Unet(3).to(device)  # 3 RGB channels
    optimizer = torch.optim.Adam(unet.parameters(), lr=lr)
    criterion = nn.CrossEntropyLoss()
    dice_loss = MyLoss(dice_loss_mode=True, smooth=0.01)

    for e in range(epoch):
        for i in range(iteration):
            # get train data_analysis and masks (we drop last few samples)
            train_content, train_mask = load_data(train_img,
                                                  start_idx=i * batch_size,
                                                  shuffle=shuffle,
                                                  batch_size=batch_size)

            # rescaled content data and convert mask data into binary digit
            train_content, train_mask = adjust_data(train_content, train_mask)

            # create tensor matrix for model to train
            train_content_tensor = torch.from_numpy(train_content).to(device)
            train_mask_tensor = torch.from_numpy(train_mask).to(device)

            # Now our data is double(float64 in pytorch),
            # while the weights in conv are float
            # So, convert our data to float32
            train_content_tensor = train_content_tensor.float()
            train_mask_tensor = train_mask_tensor.float()

            # train data
            # set the model in the training mode
            unet.train()
            optimizer.zero_grad()  # clear grad, avoid accumulation
            pred_mask_tensor = \
                unet.forward(train_content_tensor)  # get model prediction
            loss = dice_loss(pred_mask_tensor, train_mask_tensor)
            if use_cel:
                loss += criterion(pred_mask_tensor, train_mask_tensor)
            accuracy = dice_score(pred_mask_tensor, train_mask_tensor)
            loss.backward()  # backpropagation
            optimizer.step()  # update model weight

            # print training log
            print('epoch-%s-iteration-%s: loss %s accuracy %s'
                  % (e + 1, i + 1, loss.item(), accuracy.item()))
            if (i + 1) % interval == 0:
                valid_dice_score, valid_iou_score = \
                    validation(unet, validation_img, device,
                               batch_size=validation_img.shape[0])
                unet.train()  # set the mode back to train after validation
                print('valid iou score: %s valid dice score: %s' %
                      (valid_iou_score.item(), valid_dice_score.item()))
                # save model if valid_iou_score exceed 0.8
                if valid_iou_score.item() > 0.8:
                    torch.save({'model': unet.state_dict()},
                               'unet_epoch%s_iter%s.pth' % (e + 1, i + 1))

def main():
    # get user inputs
    split = int(
        input("Would you like to re-split the data (1 for yes, 0 for no)? "))
    print(
        "If you're using cuda, the recommended batch size would be 32 or 64.\n"
        + "It would take about 30min to train the model using cuda")
    print(
        "If you're using cpu, the recommended batch size would be 16.\n"
        + "It would take >2h to train the model on cpu."
    )
    device = input("Set device (cuda or cpu): ")
    if device == 'cpu':
        print("Recommend: 1 epoch, 16 batch size")
    epoch = int(input("Set epoch: "))
    batch_size = int(input("Set batch size: "))

    if split:
        root_dir = "../kaggle_3m"
        # select all file paths into two dataframes
        masks, contents = extract_paths(root_dir)
        # sort paths and combine dataframes
        dir_df = sort_combine_paths(masks, contents)
        # split training set, validation set and test set,
        # not depend on patient id
        train_dirs, test_dirs = train_test_split(
            dir_df, test_size=0.1, random_state=40
        )
        # we won't save these data frame
        # because we don't want to overwrite previous data sets.
    else:
        # read training data from previous saved csv file
        train_dirs = pd.read_csv("../data/image_dirs/train_data.csv")

    train_dirs, validation_dirs = train_test_split(
        train_dirs, test_size=0.2, random_state=40
    )

    # train
    train(train_img=train_dirs, validation_img=validation_dirs, epoch=epoch,
          batch_size=batch_size, device_=device)

if __name__ == '__main__':
    main()


from typing import TypeVar, Union, Iterable, Tuple
import pathlib
import os

PathT = TypeVar('PathT', bound=pathlib.Path)

def assignment_tuple(text_assignment: str) -> Tuple[int, int]:
    first_last = text_assignment.split('-')
    return (int(first_last[0]), int(first_last[1]))

def elf_assignments_from_file(filepath: Union[PathT, str]) -> Iterable[Tuple[Tuple, Tuple]]:
    p = pathlib.Path(filepath)
    assert p.exists(), f"Elf assignments file not found: {p}"
    with open(p, 'r') as f:
        lines = f.read().splitlines()
    assignment_pairs = (line.split(',') for line in lines)
    return tuple((assignment_tuple(assignment_pair[0]), assignment_tuple(assignment_pair[1])) for assignment_pair in assignment_pairs)

def assignment_contains_fully_wasted_elf(assignment: Tuple[Tuple, Tuple]) -> bool:
    elf_0, elf_1 = assignment
    for elf_leader_sections, elf_helper_sections in ((elf_0, elf_1), (elf_1, elf_0)):
        elf_leader_first_section, elf_leader_last_section = elf_leader_sections
        elf_helper_first_section, elf_helper_last_section = elf_helper_sections
        if elf_helper_first_section >= elf_leader_first_section and elf_helper_last_section <= elf_leader_last_section:
            return True
    return False

def elf_assignments_with_fully_wasted_elf(assignments: Iterable[Tuple[Tuple, Tuple]]) -> Iterable[Tuple[Tuple, Tuple]]:
    return tuple(filter(assignment_contains_fully_wasted_elf, assignments))

def assignment_contains_partially_wasted_elf(assignment: Tuple[Tuple, Tuple]) -> bool:
    elf_0, elf_1 = assignment
    for elf_leader_sections, elf_helper_sections in ((elf_0, elf_1), (elf_1, elf_0)):
        elf_leader_first_section, elf_leader_last_section = elf_leader_sections
        elf_helper_first_section, elf_helper_last_section = elf_helper_sections
        if elf_helper_first_section >= elf_leader_first_section and elf_helper_first_section <= elf_leader_last_section:
            return True
    return False

def elf_assignments_with_partially_wasted_elf(assignments: Iterable[Tuple[Tuple, Tuple]]) -> Iterable[Tuple[Tuple, Tuple]]:
    return tuple(filter(assignment_contains_partially_wasted_elf, assignments))

def count_assignments(assignments: Iterable[Tuple[Tuple, Tuple]]) -> int:
    return len(assignments)

def main():
    elf_assignments = elf_assignments_from_file(os.environ['ELF_ASSIGNMENTS_FILE'])

    # part 1
    fully_wasted_elves = elf_assignments_with_fully_wasted_elf(elf_assignments)
    num_fully_wasted_elves = count_assignments(fully_wasted_elves)
    print(f"{num_fully_wasted_elves} elves available for reassignment")

    # part 2
    partially_wasted_elves = elf_assignments_with_partially_wasted_elf(elf_assignments)
    num_partially_wasted_elves = count_assignments(partially_wasted_elves)
    print(f"{num_partially_wasted_elves} elves could be put to better use")

if __name__ == '__main__':
    main()


import random
import uuid

from common.base import Base
from data_types.human_name import HumanName
from data_types.address import Address
from resources.organization import Organization
from data_types.contact_point import ContactPoint

class Patient(Base):
    """Patient

    http://www.hl7.org/fhir/patient.html

    Demographics and other administrative information about an individual or animal receiving care or other health-related services.

    Attributes:
      "resourceType"         : "Patient",
      "identifier"           : [{ Identifier }], // An identifier for this patient
      "active"               : <boolean>, // Whether this patient's record is in active use
      "name"                 : [{ HumanName }], // A name associated with the patient
      "birthDate"            : "<date>", // The date of birth for the individual
      "managingOrganization" : { Reference(Organization) }, // Organization that is the custodian of the patient record
      "telecom"              : [{ ContactPoint }], // A contact detail for the individual
    """

    def __init__(self, faker, sex):
        """Init Patient Resource"""
        self.resourceType = "Patient"
        self.identifier = uuid.uuid4().hex
        self.active = bool(random.getrandbits(1))
        self.name = [HumanName(faker, sex).serialize()]
        self.address = [Address(faker).serialize()]
        self.birthDate = faker.date_of_birth(minimum_age=0, maximum_age=110)
        self.managingOrganization = Organization(faker).serialize()
        self.telecom = [ContactPoint(faker).serialize()]

    def attributes(self):
        """Returns attributes"""
        return {
            "resourceType:": "Patient",
            "identifier:": "[{ Identifier }], // An identifier for this patient",
            "active:": "<boolean>, // Whether this patient's record is in active use",
            "name:": "[{ HumanName }], // A name associated with the patient",
            "birthDate:": "'<date>', // The date of birth for the individual",
            "managingOrganization:": "{ Reference(Organization) }, // Organization that is the custodian of the patient record",
            "telecom": "[{ ContactPoint }], // A contact detail for the individual",
        }


"""
Start Date: 12/10/2020
Authors: Daniel Loughran and Aidan Orefice
Script to initialise the hexagonal lattice

Create a simple animation to highlight the basic mechanics of lattice are working.
"""

import numpy as np
import time
import matplotlib.pyplot as plt
from configuration import *
import pandas as pd
from itertools import groupby
from operator import itemgetter
from matplotlib.lines import Line2D
from scipy.spatial.distance import euclidean
from hexalattice.hexalattice import *
import matplotlib as mpl

mpl.rcParams.update({
    'figure.figsize' : [16,9],
    'xtick.labelsize' : 15,
    'ytick.labelsize' : 15,
    'axes.labelsize' : 25,
    'legend.fontsize' : 17,
    'savefig.bbox' : 'tight',
})

def choose_numbers(list1, prob):
    new_list = []
    deleted_list = []
    for i in list1:
        p = np.random.uniform(0,1)
        if p < prob:
            new_list.append(i)
        else:
            deleted_list.append(i)
    return new_list, deleted_list

class HexagonalLattice():
    '''
    Class that controls the physical attributes of the hexagonal lattice.

    Parameters:
    height - vertical length of the hexagonal lattice, in units of # of cells.
    width - horizontal length of the vertical lattice, in units of # of cells.

    Attributes:
    height - vertical length of the hexagonal lattice, in units of # of cells.
    width - horizontal length of the hexagonal lattice, in units of # of cells.
    hexagon - hexagonal lattice unrolled into 1d array - used for charge spread.
    ref - hexagonal lattice unrolled into 1d array - used for keeping track of state of cell.
    neighbours - dictionary of the neighbours of each lattice site.
    '''
    def __init__(self, width, height, runtime, threshold, sigmoid_strength, coupling = 1, refractory_period = 10,
     graph = False, FullStateMethod = False, stats = False, seed = 0, x = 0, multiplier = 7):
        self.height = height
        self.width = width
        self.dt = 1 #Discrete time width of lattice.
        self.threshold = threshold
        self.runtime = runtime #Total time we want to run for.
        self.sig_st = sigmoid_strength
        self.coupling = pow(coupling, 1/2)
        self.ref_per = refractory_period + 2
        self.graph = graph
        self.full_save = FullStateMethod #Options r full (whole run), any number (last x timesteps), transition (150 before AF, 150 after AF), False (Nothign saved)
        self.pacing_period = width * 2
        self.stats = stats
        self.x_graph = x
        self.multiplier = multiplier

        if seed == 0:
            self.seed = np.random.randint(0,int(2**32 - 1))
        else:
            self.seed = seed
        np.random.seed(self.seed)

        self.title = title + str(self.seed)

        #Ensuring lattice is of the correct dimensions - for toroidal geometry lattice must be even int x even int
        if not(self.width % 2 == 0) or not(self.height % 2 == 0):
            raise ValueError('The lattice must be of dimensions (even integer) x (even integer).')

    def CreateLattice(self):
        self.hexagon = np.zeros((self.width * self.height), dtype = np.float16) #Hexagonal Lattice in 1d array.
        self.ref = np.zeros((self.width * self.height), dtype = np.float16) #Identical for recording refractoriness.
        self.Neighbours()

    def CreateLatticeNoNeighbours(self):
        self.hexagon = np.zeros((self.width * self.height), dtype = np.float16) #Hexagonal Lattice in 1d array.
        self.ref = np.zeros((self.width * self.height), dtype = np.float16) #Identical for recording refractoriness.

    def Neighbours(self):
        """
        Method to initially identify the neighbours of each site on the hexagonal lattice.
        Only used during initialisation period of main script.

        Boundary Conditions:
        Currently modelled with a toroidal topology i.e. periodic in x and y plane.
        Next step could be to introduce a clindrical topology - this would mean create a discontinuity at the ends of
        the lattice in x plane. To implement this all j=0 or j =self.width - 1 sites, i.e all sites in the first and
        last columns, should be altered to not connect to sites on opposing side of lattice.

        Returns:
        neighbours - A dictionary with each lattice site (key) having a 1d array of it's lattice neighbours (value).
        """
        self.neighbours = {}
        for i in range(self.height):
            if i == 0: #First row always even
                for j in range(0, self.width):
                    if j == 0: # (0,0) root cell of the hexagonal lattice (bottom left).
                        self.neighbours[0] = np.asarray([self.width * (self.height -1), 1, self.width])
                         #, (self.width * 2) - 1, self.width - 1, self.width * self.height - 1
                    elif j == self.width - 1: #bottom right corner
                        self.neighbours[j] = np.asarray([self.width * self.height - 1, j + self.width, j - 1, j + self.width - 1,
                          self.width * self.height - 2])
                         #, 0
                    else:
                        self.neighbours[j] = np.asarray([self.width * (self.height - 1) + j,  j + 1,  j + self.width,
                         j - 1, j + self.width - 1, self.width * (self.height - 1) + j - 1])
            elif i == self.height - 1: #Last row always odd
                for j in range(0, self.width):
                    index = i * self.width + j
                    if j == 0: #top left corner
                        self.neighbours[index] = np.asarray([index - self.width + 1, index + 1, 1, index - self.width,
                         0])
                         #, self.width * self.height - 1
                    elif j == self.width - 1: #top right corner
                        self.neighbours[index] = np.asarray([ index - self.width,
                         index - 1, self.width - 1])
                         #, index - self.width + 1, 0,index - (self.width * 2) + 1,
                    else:
                        self.neighbours[index] = np.asarray([index - self.width + 1,  index + 1, j + 1, index - self.width,
                         index - 1, j])
            else: #All intermediate rows.
                if_even = i % 2 == 0 #False is odd True is even
                for j in range(0, self.width):
                    index = i * self.width + j
                    if j == 0: #left-most column
                        if if_even:
                            self.neighbours[index] = np.asarray([index - self.width, index + 1,
                             index + self.width])
                             #index - 1, index + self.width - 1,, index + (self.width * 2) - 1
                        else:
                            self.neighbours[index] = np.asarray([ index - self.width + 1, index + 1,
                             index + self.width + 1, index + self.width, index - self.width])
                             # index + self.width - 1,
                    elif j == self.width - 1: #right-most column
                        if if_even:
                            self.neighbours[index] = np.asarray([index - self.width, index + self.width, index - 1,
                             index + self.width - 1,  index - self.width - 1])
                             #index - self.width + 1,
                        else:
                            self.neighbours[index] = np.asarray([index - 1,
                             index + self.width, index - self.width])
                             #, index + 1, index - (self.width * 2) + 1, index - self.width + 1
                    else: #All non-edge sites.
                        if if_even:
                            self.neighbours[index] = np.asarray([index - self.width, index + 1, index + self.width,
                             index + self.width - 1, index - self.width - 1, index - 1])
                        else:
                            self.neighbours[index] = np.asarray([ index - self.width + 1, index + 1,  index + self.width + 1,
                             index - 1, index + self.width, index - self.width])

    def index_to_xy(self, index):
        row = np.floor(index / self.width)
        y = row - row*(1-(np.sqrt(3)/2)) #fix.
        if_even = row % 2 == 0
        if if_even:
            x = index - (row * self.width)
        else:
            x = index - (row * self.width) + 0.5
        return (x,y)

    def number_of_bonds(self):
        bonds = 0
        for i in self.neighbours.keys():
            for j in self.neighbours[i]:
                bonds += 1
        return bonds/2

    def sinusoid2D(self, x, y, A, amp, mean):
        #Amplitude - directly sets the amplitude of the function
        #Mean - directly sets the offset/mean of the function.
        # 0 < (Mean +/- amp) < 1
        #A stretch out the modes.
        #Ay must be an integer value to ensure periodicity.
        amp = float(amp)
        mean = float(mean)
        A = float(A)
        return (amp/2)*(np.sin(A*x*(2*np.pi/self.width))+np.sin(A*y*(2*np.pi/self.index_to_xy(self.height* self.width -1)[1]))) + mean

    def CouplingMethod(self, sinusoid_params = [1,0.1,0.6]):
        keys = self.neighbours.keys()
        copy = self.neighbours.copy()
        #new_dic = {i : [] for i in range(len(keys))}
        deleted_dic = {i : [] for i in range(len(keys))}
        counter = 0
        for i in keys:
            if i % self.width == self.width - 1:
                if np.floor(i/self.width) % 2 == 0:
                    no_neighbours = 2
                else:
                    no_neighbours = 0
            else:
                no_neighbours = 3
            for j in self.neighbours[i][:no_neighbours]:
                counter += 1
                x1, x2 = self.index_to_xy(i), self.index_to_xy(j)# change this x,y
                x,y = 0.5*(x1[0] + x2[0]), 0.5*(x1[1] + x2[1])
                grad_coupling = self.sinusoid2D(x, y, *sinusoid_params)
                p = np.random.uniform(0,1)
                if p < grad_coupling:
                    pass #keep bond
                else:
                    deleted_dic[i].append(j)
                    deleted_dic[j].append(i)

            #If we want to look at the unique counts.
            #unique, counts = np.unique(self.coupling_samp, return_counts=True)
            #print(np.asarray((unique,counts)).T)

        for i in deleted_dic.keys():
            neighbours = deleted_dic[i]
            for j in neighbours:
                index = list(self.neighbours[i]).index(j)
                self.neighbours[i] = np.delete(self.neighbours[i], index)

        self.coupling_samp = np.asarray([len(self.neighbours[i])/len(copy[i]) for i in self.neighbours.keys()])
        self.mean, self.var = np.mean(self.coupling_samp), np.var(self.coupling_samp)

    def Coupling_Sample(self, A, amp, offs):
        fig,(ax1,ax2) = plt.subplots(1,2)

        hex_centers, ax1 = create_hex_grid(nx=self.width,ny=self.height, do_plot=True, align_to_origin = False, h_ax = ax1)
        x = [i[0] for i in hex_centers]
        y = [i[1] for i in hex_centers]

        sin_z = [self.sinusoid2D(x[i], y[i], A, amp, offs) for i in range(len(x))]
        a = ax1.scatter(x,y,marker = 'h', s=15, c = sin_z) #s=17
        plt.colorbar(a, ax = ax1, shrink=0.6)

        ax2.yaxis.set_tick_params(labelsize=0)
        hex_centers, ax2 = create_hex_grid(nx=self.width,ny=self.height, do_plot=True, align_to_origin = False, h_ax = ax2)
        x = [i[0] for i in hex_centers]
        y = [i[1] for i in hex_centers]
        b = ax2.scatter(x,y,marker = 'h', s=15, c = self.coupling_samp, cmap=plt.cm.get_cmap('viridis', 7))
        cbar = plt.colorbar(b,ax = ax2, ticks=np.arange(1/14,17/14,1/7), shrink = 0.6)
        cbar.set_ticklabels(["0", "1/6", "1/3", "1/2", "2/3", "5/6", "1"])
        #plt.clim(0,1)

        #Adding common X and Y axis labels
        '''fig.add_subplot(111, frameon=False)
        plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
        plt.xlabel("X position")
        plt.ylabel("Y position")'''

        plt.tight_layout()

        """label_offs = 'Offset = ' + str(offs)
        label_amp = 'Amplitude = ' + str(amp)
        label_a = r'$A$ = ' + str(A)
        label_mean = 'Mean = ' + str(round(self.mean,3))
        label_variance = 'Variance = ' + str(round(self.var,3))
        label_seed = 'Seed = ' + str(self.seed)

        legend_elements = [Line2D([0], [0], marker='o', color='white', label=label_offs, markerfacecolor='white', markersize=0),
                Line2D([0], [0], marker='o', color='white', label=label_amp, markerfacecolor='white', markersize=0),
                Line2D([0], [0], marker='o', color='white', label=label_a, markerfacecolor='white', markersize=0),
                Line2D([0], [0], marker='o', color='white', label=label_mean, markerfacecolor='white', markersize=0),
                Line2D([0], [0], marker='o', color='white', label=label_variance, markerfacecolor='white', markersize=0),
                Line2D([0], [0], marker='o', color='white', label=label_seed, markerfacecolor='white', markersize=0)]

        fig.set_size_inches(16,9)
        plt.legend(handles = legend_elements, loc='upper center', bbox_to_anchor=(0.5, -0.025), ncol=3, fontsize = 14)
        plt.axis('scaled')
        plt.title(r"Sample of $\frac{Amplitude}{2} \times \left( \sin(A\frac{2\pi x}{length}) + \sin(A\frac{2\pi y}{height}) \right) + Offset$", fontsize = 20)"""
        plt.savefig('SpaceViz_%i,%i,%i,%i.png' %(amp*100,offs*100,A,self.seed))
        plt.close()

    def Initialise(self):
        self.index_int = [i*self.width for i in range(self.height)] #Left hand side
        self.ref[self.index_int] = 1

    def SigmoidDist(self,charges):
        return 1/(1+np.exp(-self.sig_st*(charges-self.threshold)))

    def ActivationCheck(self):
        index_charged = np.where(self.hexagon > 0)[0]
        p = (1 - self.SigmoidDist(self.hexagon[index_charged])) * self.multiplier
        a = np.random.rand(len(index_charged))
        self.index_act = index_charged[a>p]
        self.ref[self.index_act] = 1 #Set sites to activated.
        self.hexagon[index_charged] = 0
        if self.t % self.pacing_period == 0:
            self.index_act = np.concatenate((self.index_act,self.index_int))

    #Uses sites that have been set to activated and spreads their charge. Resets charge to zero of activated sites.
    def ChargeProp(self):
        #index_act = np.where(self.ref == 1)[0] #sites that are activated - need to spread their charge
        for ind in self.index_act:
            neighbours = self.neighbours[ind]
            avail_neighbours = [i for i in neighbours if self.ref[i] == 0]
            if len(avail_neighbours) > 0:
                self.hexagon[avail_neighbours] += 1/len(avail_neighbours)

    #Develops the states of each site.
    def StateDevelop(self):
        self.ref[self.ref >= 1] += 1
        self.ref[self.ref == self.ref_per] = 0

    def Per_check(self, per):
        indi = [(i*self.width) - 1 for i in range(1,self.height + 1)]#Indexs of right hand side
        pre_length = len(indi)
        for i in range(self.width - int(self.width/5), self.pacing_period):
            data = self.RefHistory[(self.t - self.pacing_period + i) * len(self.ref) : (self.t - self.pacing_period + i + 1) * len(self.ref)]
            indi = [j for j in indi if data[j] == 0]
            if len(indi) < pre_length: #Arbitrary fraction, len(indi) is number of edge sites not activated yet
                self.per = True
                return [per[0] + 1, per[1] + 1]
        return [per[0], per[1] + 1]

    def Stats_check(self):
        if self.in_AF == False:
            self.percolating = self.Per_check(self.percolating)
            if self.AF_check():
                self.in_AF = True
                self.AF_bool.append((self.t, self.in_AF))
            else:
                self.AF_bool.append((self.t, self.in_AF))
        else:
            if self.AF_check():
                self.in_AF = True
            else:
                self.in_AF = False
            self.AF_bool.append((self.t, self.in_AF))

    def AF_check(self):
        if sum(self.AF[self.t - self.pacing_period:self.t]) > len(self.AF[self.t - self.pacing_period:self.t]) * self.height * 1.1:
            return True #If sum of activ. sites over pacing period > 1.1 * expected number of activate --> FIBRILLATION.
        width_dif = int((self.pacing_period - self.width) / 4)  #Checking if sites are activated at end of beat - trying to catch special cases
        avg_over_dif = sum(self.AF[self.t - width_dif:self.t]) / width_dif
        avg_over_norm = sum(self.AF[self.t + 1 - self.pacing_period:self.t - width_dif * 2]) / len(self.AF[self.t + 1 - self.pacing_period:self.t - width_dif * 2])
        if avg_over_dif > avg_over_norm / 6: #6 is an arbitrary fraction
            if self.AF[self.t - 1] > 0:
                return True
            else:
                return False
        else:
            return False

    def Search_Meth2(self): #Searches for the 2nd, 3rd and 4th re-excited sites. Returns time of 2nd re-excitation.
        sites = {}
        re_sites = {2:True, 3:True, 4:True}
        for j in range(self.AF_first_beat + 1, self.AF_last_beat):
            time_data = self.RefHistory[j*len(self.ref):(j+1)*len(self.ref)]
            activated_sites = np.where(time_data == 1)[0]
            for i in activated_sites:
                if i in list(sites.keys()):
                    sites[i] += 1
                    if re_sites[2] == True:
                        if sites[i] == 2:
                            re_sites[2] = i
                            self.AF_time = (max(j-100,1), j+100) #Increased the range from 30 to 100
                            #print(self.AF_time)  #Transition time range
                            k = self.ref_per - 1
                            while k < j - self.AF_first_beat:
                                new_time = j - k
                                time_data = self.RefHistory[new_time*len(self.ref):(new_time+1)*len(self.ref)]
                                activated_sites = np.where(time_data == 1)[0]
                                if i in activated_sites:
                                    self.new_time = new_time
                                    self.ham_dis_time, self.x_mean_time = self.Hamming_distance(new_time)
                                    set_time = new_time
                                    k = self.runtime + 1
                                k += 1
                            self.Hamming_distance_arr = []
                            for k in range(set_time - 10, set_time + 6):
                                self.Hamming_distance_arr.append(self.Hamming_distance(k)[0])
                    if re_sites[3] == True:
                        if sites[i] == 3:
                            re_sites[3] = i
                    if re_sites[4] == True:
                        if sites[i] == 4:
                            re_sites[4] = i
                            return re_sites
                else:
                    sites[i] = 1
        return re_sites

    def Hamming_distance(self, AF_time):
        time_data = self.RefHistory[AF_time*len(self.ref):(AF_time+1)*len(self.ref)]
        activated_sites = np.where(time_data == 1)[0]
        activated_sites_x = [self.index_to_xy(i)[0] for i in activated_sites]
        if len(activated_sites) > 0:
            x_mean = np.mean(activated_sites_x)
            Ham_dis = np.sum((activated_sites_x-x_mean)**2)/(len(activated_sites_x))
            return np.sqrt(Ham_dis), x_mean
        else:
            return 0, 0

    def Location_Check(self, site2, site3, site4):
        locs = [self.index_to_xy(site2), self.index_to_xy(site3), self.index_to_xy(site4)]
        verify = True
        err = 5.01
        height_y = self.index_to_xy(self.width*self.height -1)[1]
        for i in range(len(locs)-1):
            for j in range(1,len(locs)-i):
                if euclidean(locs[i],locs[i+j]) > err:
                    verify = False
                if verify == False:
                    val1 = (locs[i][0], locs[i][1] + height_y)
                    val2 = (locs[i+j][0], locs[i+j][1] + height_y)
                    if euclidean(val1,locs[i+j]) < err:
                        verify = True
                    elif euclidean(locs[i],val2) < err:
                        verify = True
        return verify

    def Graph(self):
        f, ax = plt.subplots()
        x = [i for i in range(len(self.AF))]
        ax.plot(x, self.AF, ls = '-', label = 'Number of activated sites')
        ax.set_ylabel("Number of activated cells")
        ax.set_xlabel("Time")
        plt.savefig('Graphed_{}'.format(self.x_graph) + '.png')  #################################
        plt.close()

    def save_choice(self): #Run once at end
        #AF Start time and location
        beat_af = [i[0] // self.pacing_period for i in self.AF_bool if i[1] == True]
        consec_AF_beats = [list(map(itemgetter(1), g)) for tk, g in groupby(enumerate(beat_af), lambda ix : ix[0] - ix[1])]
        consec_AF_beats_3 = [i for i in consec_AF_beats if len(i) > 2]
        #print(consec_AF_beats_3)
        if len(consec_AF_beats_3) > 0:
            self.AF_first_beat = (consec_AF_beats_3[0][0] - 1) * self.pacing_period  #first beat after fib starts
            self.AF_last_beat = consec_AF_beats_3[0][-1] * self.pacing_period  #last beat after fib starts
            #print(self.AF_first_beat, self.AF_last_beat)
            self.re_sites = self.Search_Meth2()  #2nd,3rd,4th activated sites. Uncomment when doing location stuff
            self.kill = True

    def RunIt(self):
        self.t = 0
        self.RefHistory = np.zeros(((self.runtime)  * len(self.ref)), dtype = np.int16)
        self.AF = np.zeros(self.runtime, dtype = np.int16)
        self.done = True
        self.in_AF = False
        self.AF_bool = []
        self.kill = False
        self.percolating = [0,0]
        while self.t < self.runtime:
            if self.t == 0:
                self.Initialise()
                self.ActivationCheck()
                self.AF[0] = len(self.index_act)
                self.ChargeProp()
                if self.full_save != False:
                    self.RefHistory[0:len(self.ref)] = self.ref
                self.StateDevelop()
                self.t += self.dt
            elif self.t % self.pacing_period == 0:
                self.Stats_check()
                self.Initialise()
                self.save_choice()
            elif self.t == self.runtime - 1:
                self.Stats_check()
                self.save_choice()
            self.ActivationCheck()
            self.RefHistory[self.t*len(self.ref):(self.t+self.dt)*len(self.ref)] = self.ref
            self.AF[self.t] = len(self.index_act)
            self.ChargeProp()
            self.StateDevelop()
            self.t += self.dt
            if self.kill:
                self.t = self.runtime + 1 #To kill when AF starts
        if self.graph:
            self.Graph()
        if self.full_save == 'full':
            np.save(self.title + '.npy', self.RefHistory)
        elif self.full_save == 'transition' and self.in_AF:
            np.save(self.title + '.npy', self.RefHistory[self.AF_time[0] * len(self.ref):self.AF_time[1] * len(self.ref)])
        run = list(config.values())
        run.append(self.seed)
        #'location_2', 'location_3', 'location_4', 'AF_time',
        if self.kill:
            #self.Location_Check(self.re_sites[2],self.re_sites[3],self.re_sites[4])
            run.append(self.re_sites[2])
            run.append(self.re_sites[3])
            run.append(self.re_sites[4])
            run.append(self.Location_Check(self.re_sites[2],self.re_sites[3],self.re_sites[4]))
            run.append(self.AF_time)
            run.append([self.Hamming_distance_arr])
            run.append(self.ham_dis_time)
            run.append(self.x_mean_time)
        else:
            run.extend([False]*8)
        run.append(self.percolating[0] / self.percolating[1])
        run.append(self.title)
        return run


'''
RankUp 008
Ваша задача — написать функцию, которая увеличивает строку
для создания новой строки. Если строка уже заканчивается числом,
это число должно быть увеличено на 1.
Если строка не заканчивается числом, то к новой строке следует добавить число 1.
Примеры:
foo -> foo1
foobar23 -> foobar24
foo0042 -> foo0043
foo9 -> foo10
foo099 -> foo100
https://www.codewars.com/kata/54a91a4883a7de5d7800009c/train/python
 '''

def increment_string(s:str)->str:
    llen = len(s)
    num_s = ''; txt_s = ''
    for simb in range(llen-1, 0,-1):
        if s[simb].isdigit():
            num_s = s[simb] + num_s
        else:
            txt_s = s[:simb+1]
            break
    if num_s == '':
        s = s + '1'
    else:
        # print(num_s,' ',txt_s)
        new_s = str(int(num_s)+1)
        s = txt_s + new_s.rjust(len(num_s),'0')
    return s

s = 'foo'
print(1, s,' ', increment_string(s),'\n')
s = 'foo002'
print(1, s,' ', increment_string(s),'\n')
s = 'foobar23'
print(2, s,' ', increment_string(s),'\n')
s= 'foo0042'
print(3, s,' ', increment_string(s),'\n')
s= 'foo9'
print(4, s, increment_string(s),'\n')


# -*- coding: utf-8 -*-
"""
Created on Tue Nov 21 17:35:53 2017

@author: bokorn
"""
import torch
import numpy as np
from quat_math import (quatDiff,
                       quatAngularDiff,
                       quaternion_multiply,
                       quaternion_inverse,
                       quaternion_about_axis)

from functools import partial
from itertools import product

eps = 1e-7

def tensorAngularAllDiffs(label_qs, verts):
    return 2 * torch.acos(torch.abs(torch.transpose(torch.mm(verts,
        torch.transpose(label_qs,0,1)),0,1)).clamp(max=1-eps))

def tensorSignedAngularDiff(q1, q2):
    return 2 * torch.acos(torch.mm(q1,q2.t()).clamp(min=eps-1, max=1-eps))

def tensorAngularDiff(q1, q2):
    return 2 * torch.acos(torch.abs((q1*q2).sum(1)).clamp(max=1-eps))

def getGaussianKernal(v1, v2=None, sigma=np.pi/36):
    if(v2 is None):
        v2 = v1
    kernal = torch.exp(-tensorAngularAllDiffs(v1,v2)**2/sigma)
    kernal = (kernal/kernal.sum(1)).transpose(0,1)
    return kernal

def getSignedGaussianKernal(pts, verts, sigma=np.sqrt(2)*np.pi/4):
    d_pos = tensorSignedAngularDiff(pts, verts)
    d_neg = tensorSignedAngularDiff(pts, -verts)
    d = torch.min(d_pos, d_neg)
    sign = 1-2*(d_neg < d_pos).float()
    kernal = sign * torch.exp(-d**2/sigma**2)
    return kernal

def meanShiftStep(pts, verts, weights, sigma=np.sqrt(2)*np.pi/4):
    K = weights.t() * getSignedGaussianKernal(pts, verts, sigma)
    new_pts = torch.mm(K, verts)
    new_pts /= torch.norm(new_pts,dim=1).unsqueeze(1)
    return new_pts

def meanShift(pts, verts, weights, sigma=np.sqrt(2)*np.pi/4, eps_term = 1e-5, max_iter = 100):
    for _ in range(max_iter):
        new_pts = meanShiftStep(pts, verts, weights, sigma)
        if(torch.max(torch.abs(pts-new_pts)) < eps_term):
            break;
    return new_pts

def pose2Viewpoint(q):
    delta_quat = np.array([-.5,-.5,-.5,.5])
    q_flip = quaternion_multiply(delta_quat, q.copy())
    q_flip[2] *= -1
    return quaternion_inverse(q_flip)

def viewpoint2Pose(q):
    delta_quat = np.array([.5,.5,.5,.5])
    q_flip = quaternion_inverse(q.copy())
    q_flip[2] *= -1
    return quaternion_multiply(delta_quat, q_flip)

def quatDiffBatch(view_quats, base_quats):
    return np.array(list(map(quatDiff, view_quats, base_quats)))

def quatAngularDiffBatch(q1, q2):
    return 2*np.arccos(np.minimum(np.abs(np.sum(q1*q2, axis=1)), 1-eps))
    #return np.array(list(map(quatAngularDiff, view_quats, base_quats)))

def quatAngularDiffProd(view_quats, base_quats):
    #diff = partial(quatAngularDiff, view_quat)
    pairs = product(view_quats, base_quats)
    return np.array(list(map(lambda pair: quatAngularDiff(pair[0], pair[1]), pairs)))

def quatAngularDiffDot(q1, q2):
    return 2*np.arccos(np.minimum(np.abs(q1.dot(q2.T)), 1-eps))

def quaternionMultiplyBatch(q2, q1):
    return np.stack([ q2[:,0]*q1[:,3] + q2[:,1]*q1[:,2] - q2[:,2]*q1[:,1] + q2[:,3]*q1[:,0],
                      -q2[:,0]*q1[:,2] + q2[:,1]*q1[:,3] + q2[:,2]*q1[:,0] + q2[:,3]*q1[:,1],
                      q2[:,0]*q1[:,1] - q2[:,1]*q1[:,0] + q2[:,2]*q1[:,3] + q2[:,3]*q1[:,2],
                      q2[:,0]*q1[:,0] - q2[:,1]*q1[:,1] - q2[:,2]*q1[:,2] + q2[:,3]*q1[:,3]], dim=1)

def quaternioniAngularDifferenceBatch(q2, q1):
    return np.stack([ q2[:,0]*q1[:,3] + q2[:,1]*q1[:,2] - q2[:,2]*q1[:,1] + q2[:,3]*q1[:,0],
                      q2[:,0]*q1[:,2] + q2[:,1]*q1[:,3] + q2[:,2]*q1[:,0] + q2[:,3]*q1[:,1],
                      q2[:,0]*q1[:,1] - q2[:,1]*q1[:,0] + q2[:,2]*q1[:,3] + q2[:,3]*q1[:,2],
                      q2[:,0]*q1[:,0] + q2[:,1]*q1[:,1] + q2[:,2]*q1[:,2] + q2[:,3]*q1[:,3]], dim=1)

def tensorMultiplyBatch(q1,q2):
    return torch.stack([ q1[:,0]*q2[:,3] + q1[:,1]*q2[:,2] - q1[:,2]*q2[:,1] + q1[:,3]*q2[:,0],
                        -q1[:,0]*q2[:,2] + q1[:,1]*q2[:,3] + q1[:,2]*q2[:,0] + q1[:,3]*q2[:,1],
                         q1[:,0]*q2[:,1] - q1[:,1]*q2[:,0] + q1[:,2]*q2[:,3] + q1[:,3]*q2[:,2],
                        -q1[:,0]*q2[:,0] - q1[:,1]*q2[:,1] - q1[:,2]*q2[:,2] + q1[:,3]*q2[:,3]], dim=1)

def continuousSymmetricAngularDistance(q1, q2, axis_sym):
    num_q = q1.shape[0];

    xi_sym = torch.cat((axis_sym, torch.tensor([0.]))).unsqueeze(0)

    q1_inv = q1*torch.tensor([-1.,-1.,-1.,1.])
    xi1 = tensorMultiplyBatch(tensorMultiplyBatch(q1,xi_sym),q1_inv)

    q2_inv = q2*torch.tensor([-1.,-1.,-1.,1.])
    xi2 = tensorMultiplyBatch(tensorMultiplyBatch(q2,xi_sym),q2_inv)

    dot = (xi1 * xi2).sum(dim=1)
    return torch.acos(dot.clamp(min = eps-1, max=1-eps))

def symmetricAngularDistance(q1, q2, axes_of_sym, angles_of_sym):
    if(len(axes_of_sym) == 0):
        return tensorAngularDiff(q1, q2)
    axis = axes_of_sym[0]
    angles = angles_of_sym[0]
    dist = torch.tensor(np.inf)
    for th in angles:
        if(np.isfinite(th)):
            q_sym = torch.tensor(quaternion_about_axis(th, axis)).float().unsqueeze(0)
            q2_rot = tensorMultiplyBatch(q2, q_sym)
            dist = torch.min(dist, symmetricAngularDistance(q1, q2_rot, axes_of_sym[1:], angles_of_sym[1:]))
        else:
            return continuousSymmetricAngularDistance(q1,q2,torch.tensor(axis).float())
    return dist


#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Abstract: Select all rooftops that recieve a minimum average of 3.5 kWh of insolation per day and create a new shapefile. This is an example of the property function
from the core concept 'objects.'

"""

__author__ = "Eric Ahlgren"
__copyright__ = "Copyright 2015"
__credits__ = ["Eric Ahlgren"]
__license__ = ""
__version__ = "0.1"
__maintainer__ = ""
__email__ = ""
__date__ = "March 2015"
__status__ = "Development"

import sys
import os

sys.path = [ '.', '../..' ] + sys.path
from utils import _init_log

# Import arcpy and set path to data
import arcpy
from arcpy import env

env.workspace = os.path.join("..","..","..","data","objects")
env.overwriteOutput = True

# Set local variables
in_features = "rooftops_pv.shp"
out_feature_class = os.path.join("..","..","..","data","objects","tmp","roofs_aboveMinInsol.shp")
where_clause = '"pvrooftop_solar2014.SUM" >= 1277500'

# Execute Select
arcpy.Select_analysis(in_features, out_feature_class, where_clause)


# -------------------------------------------------------------------------------------------------------------------- #
# File Name    : SerialSendWidget.py
# Project Name : PySerialTerm
# Author       : Raim.Delgado
# Organization : SeoulTech
# Description  :
# [Revision History]
# >> 2022.02.19 - First Commit
# -------------------------------------------------------------------------------------------------------------------- #
import os
import sys
from typing import List

FILE_PATH = os.path.dirname(os.path.realpath(__file__))  # %PROJECT_ROOT%/Scripts
ROOT_PATH = os.path.dirname(os.path.dirname(FILE_PATH))
RESOURCES_PATH = os.path.join(ROOT_PATH, "Resources")
SCRIPTS_PATH = os.path.join(ROOT_PATH, "Scripts")
WIDGETS_PATH = os.path.join(SCRIPTS_PATH, "Widgets")
LIBRARY_PATH = os.path.join(ROOT_PATH, "Library")
SERIAL_PATH = os.path.join(LIBRARY_PATH, "Serial")
sys.path.extend([SCRIPTS_PATH, RESOURCES_PATH, WIDGETS_PATH, LIBRARY_PATH, SERIAL_PATH])
sys.path = list(set(sys.path))
del FILE_PATH, ROOT_PATH, SCRIPTS_PATH, RESOURCES_PATH, WIDGETS_PATH, LIBRARY_PATH, SERIAL_PATH

from UiCommon import *
from Commons import *

class NumericDelegate(QtWidgets.QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        editor = super(NumericDelegate, self).createEditor(parent, option, index)
        if isinstance(editor, QtWidgets.QLineEdit):
            reg_ex = QtCore.QRegExp("[0-9A-Fa-f]{1,2}")
            validator = QtGui.QRegExpValidator(reg_ex, editor)
            editor.setValidator(validator)
        return editor

class CharacterDelegate(QtWidgets.QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        editor = super(CharacterDelegate, self).createEditor(parent, option, index)
        if isinstance(editor, QtWidgets.QLineEdit):
            editor.setMaxLength(1)
        return editor

class PacketTable(QtWidgets.QTableWidget):
    listHorHeader: List[str]

    def __init__(self, parent=None):
        super(PacketTable, self).__init__(parent)
        self.listHorHeader = ["No.", "RAW(Hex)", "ASCII(Char)"]
        self.setColumnCount(len(self.listHorHeader))
        self.setHorizontalHeaderLabels(self.listHorHeader)
        self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
        self.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        self.horizontalHeader().setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
        self.horizontalHeader().setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
        self.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
        self.verticalHeader().hide()
        num_delegate = NumericDelegate(self)
        self.setItemDelegateForColumn(1, num_delegate)
        char_delegate = CharacterDelegate(self)
        self.setItemDelegateForColumn(2, char_delegate)
        self.cellChanged.connect(self.on_cell_changed)

    def on_cell_changed(self, row: int, col: int):
        self.blockSignals(True)
        str_item = self.item(row, col).text()
        if col == 1:
            if len(str_item) < 2:
                str_item = "0" + str_item

            self.setItem(row, col, QtTableItem(str_item.upper()))  # align center
            str_ascii = bytes.fromhex(str_item).decode("ISO-8859-1")

            self.setItem(row, 2, QtTableItem(str_ascii))

        elif col == 2:
            self.setItem(row, col, QtTableItem(str_item))
            str_raw = format(ord(str_item), "x")
            self.setItem(row, 1, QtTableItem(str_raw.upper()))

        self.blockSignals(False)

    def clearTable(self):
        self.setRowCount(0)

    def adjustRowNo(self):
        for i in range(self.rowCount()):
            self.setItem(i, 0, QtTableItem(i, True))

    def addRow(self):
        if self.rowCount() != 0:
            indices = self.selectedIndexes()
            indices = [index.row() for index in indices]
            if indices:
                index = max(indices)
                row_no = index + 1
            else:
                row_no = self.rowCount()
        else:
            row_no = self.rowCount()

        self.insertRow(row_no)
        self.setRowHeight(row_no, 1)
        self.setItem(row_no, 1, QtTableItem("00"))
        self.adjustRowNo()
        self.viewport().update()  # refresh table contents

    def delRow(self):
        if self.rowCount() != 0:
            indices = self.selectionModel().selectedRows()
            if not indices:
                self.removeRow(self.rowCount() - 1)
            else:
                for index in reversed(sorted(indices)):
                    self.removeRow(index.row())

            self.adjustRowNo()
            self.viewport().update()  # refresh table contents

    def shiftDown(self):
        self.blockSignals(True)
        curr_row = self.currentRow()

        if curr_row < self.rowCount() - 1:
            for i in range(1, 3):
                itemStore = self.takeItem(curr_row + 1, i)
                self.setItem(curr_row + 1, i, self.takeItem(curr_row, i))
                self.setItem(curr_row, i, itemStore)
            self.setCurrentCell(curr_row + 1, 0)

        self.blockSignals(False)

    def shiftUp(self):
        self.blockSignals(True)
        curr_row = self.currentRow()

        if curr_row > 0:
            for i in range(1, 3):
                itemStore = self.takeItem(curr_row - 1, i)
                self.setItem(curr_row - 1, i, self.takeItem(curr_row, i))
                self.setItem(curr_row, i, itemStore)
            self.setCurrentCell(curr_row - 1, 0)

        self.blockSignals(False)

class CWidgetSerialSend(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(CWidgetSerialSend, self).__init__(parent)
        self.sig_send_serial_packet = PySignal(bytearray)
        self.initUi()
        self.initSlots()

    def initUi(self):
        self.initPacketCtrl()
        self.initStringCtrl()
        self.initPacketStorage()
        MainLayout = QtWidgets.QVBoxLayout(self)

        MainLayout.addWidget(self.widgetPacket, 1)
        MainLayout.addWidget(self.widgetCtrlStr)
        MainLayout.addWidget(self.widgetCtrlStorage)

        MainLayout.setContentsMargins(0, 0, 0, 0)

    def initTableWidget(self):
        self.tablePacket = PacketTable()

    def initSlots(self):
        self.btnClear.clicked.connect(self.on_click_btn_clear)
        self.btnAdd.clicked.connect(self.on_click_btn_add)
        self.btnSub.clicked.connect(self.on_click_btn_del)
        self.btnShiftUp.clicked.connect(self.on_click_btn_shift_up)
        self.btnShiftDwn.clicked.connect(self.on_click_btn_shift_down)
        self.btnSend.clicked.connect(self.on_click_btn_send)
        self.btnSendString.clicked.connect(self.on_click_btn_send_str)
        self.btnStore.clicked.connect(self.on_click_btn_store)
        self.btnSendStorage.clicked.connect(self.on_click_btn_send_storage)
        self.btnClearStorage.clicked.connect(self.on_click_btn_clear_storage)
        self.btnDelStorage.clicked.connect(self.on_click_btn_del_storage)

    def initPacketCtrl(self):
        self.initTableWidget()
        btnHeight = 25
        btnFontSz = 16
        btnFont = QtGui.QFont()
        btnFont.setPointSize(btnFontSz)

        self.widgetCtrlPacket = QtWidgets.QWidget()
        VLayoutCtrl = QtWidgets.QVBoxLayout(self.widgetCtrlPacket)
        self.btnClear = QtWidgets.QPushButton('CLEAR')
        self.btnClear.setFixedHeight(btnHeight)
        HLayoutAddSub = QtWidgets.QHBoxLayout()
        self.btnAdd = QtWidgets.QPushButton('+')
        self.btnAdd.setFixedHeight(btnHeight)
        self.btnAdd.setFont(btnFont)
        self.btnSub = QtWidgets.QPushButton('-')
        self.btnSub.setFixedHeight(btnHeight)
        self.btnSub.setFont(btnFont)
        self.btnShiftUp = QtWidgets.QPushButton('▲')
        self.btnShiftUp.setFixedHeight(btnHeight)
        # self.btnShiftUp.setFont(btnFont)
        self.btnShiftDwn = QtWidgets.QPushButton('▼')
        self.btnShiftDwn.setFixedHeight(btnHeight)
        # self.btnShiftDwn.setFont(btnFont)
        GLayoutPos = QtWidgets.QGridLayout()
        GLayoutPos.addWidget(self.btnAdd, 0, 0)
        GLayoutPos.addWidget(self.btnSub, 0, 1)
        GLayoutPos.addWidget(self.btnShiftUp, 1, 0)
        GLayoutPos.addWidget(self.btnShiftDwn, 1, 1)
        self.btnSend = QtWidgets.QPushButton('SEND')
        self.btnSend.setFixedHeight(btnHeight)

        HLayoutFmt = QtWidgets.QHBoxLayout()
        self.rbtnForward = QtWidgets.QRadioButton('Forward')
        self.rbtnForward.setChecked(True)
        self.rbtnReverse = QtWidgets.QRadioButton('Reverse')
        HLayoutFmt.addWidget(self.rbtnForward)
        HLayoutFmt.addWidget(self.rbtnReverse)
        self.btnStore = QtWidgets.QPushButton('STORE')
        self.btnStore.setFixedHeight(btnHeight)
        VLayoutCtrl.setContentsMargins(5, 0, 5, 0)
        VLayoutCtrl.addWidget(self.btnClear)
        VLayoutCtrl.addLayout(HLayoutAddSub)
        VLayoutCtrl.addLayout(GLayoutPos)
        VLayoutCtrl.addWidget(self.btnSend)
        VLayoutCtrl.addWidget(self.rbtnForward)
        VLayoutCtrl.addWidget(self.rbtnReverse)
        # VLayoutCtrl.addLayout(HLayoutFmt)
        VLayoutCtrl.addWidget(self.btnStore)
        VLayoutCtrl.addStretch(1)

        self.widgetCtrlPacket.setMaximumWidth(80)

        # Send Packet
        self.widgetPacket = QtWidgets.QWidget()
        VLayoutPacket = QtWidgets.QVBoxLayout(self.widgetPacket)
        lblPacket = QtWidgets.QLabel()
        lblPacket.setText('[Send Packet]')
        HLayoutPacketCtrl = QtWidgets.QHBoxLayout()
        HLayoutPacketCtrl.addWidget(self.tablePacket, 1)
        HLayoutPacketCtrl.addWidget(self.widgetCtrlPacket)
        VLayoutPacket.addWidget(lblPacket)
        VLayoutPacket.addLayout(HLayoutPacketCtrl)
        VLayoutPacket.setContentsMargins(0, 0, 0, 0)

    def initStringCtrl(self):
        btnHeight = 25
        self.widgetCtrlStr = QtWidgets.QWidget()
        VLayoutCtrlStr = QtWidgets.QVBoxLayout(self.widgetCtrlStr)
        lblCtrlStr = QtWidgets.QLabel()
        lblCtrlStr.setText('[Send String]')
        HLayoutCtrlStr = QtWidgets.QHBoxLayout()
        self.txtStringInput = QtWidgets.QLineEdit()
        self.txtStringInput.setFixedHeight(btnHeight)
        self.btnSendString = QtWidgets.QPushButton('SEND')
        self.btnSendString.setFixedHeight(btnHeight)
        self.btnSendString.setFixedWidth(70)
        HLayoutCtrlStr.addWidget(self.txtStringInput, 1)
        HLayoutCtrlStr.addWidget(self.btnSendString)
        HLayoutCtrlStr.setContentsMargins(0, 0, 5, 0)
        HLayoutCtrlStr.setSpacing(10)
        VLayoutCtrlStr.addWidget(lblCtrlStr)
        VLayoutCtrlStr.addLayout(HLayoutCtrlStr)
        VLayoutCtrlStr.setContentsMargins(0, 0, 0, 0)

    def initPacketStorage(self):
        btnHeight = 25
        btnWidth = 70
        self.widgetCtrlStorage = QtWidgets.QWidget()
        VLayoutCtrlStorage = QtWidgets.QVBoxLayout(self.widgetCtrlStorage)
        lblCtrlStr = QtWidgets.QLabel()
        lblCtrlStr.setText('[Send Stored Packet]')
        HLayoutCtrlStorage = QtWidgets.QHBoxLayout()
        self.lstPacketHistory = QtWidgets.QListWidget()
        self.lstPacketHistory.setSortingEnabled(True)
        VLayoutBtn = QtWidgets.QVBoxLayout()
        self.btnClearStorage = QtWidgets.QPushButton('CLEAR')
        self.btnClearStorage.setFixedHeight(btnHeight)
        self.btnClearStorage.setFixedWidth(70)
        self.btnDelStorage = QtWidgets.QPushButton('DELETE')
        self.btnDelStorage.setFixedHeight(btnHeight)
        self.btnDelStorage.setFixedWidth(70)
        self.btnSendStorage = QtWidgets.QPushButton('SEND')
        self.btnSendStorage.setFixedHeight(btnHeight)
        self.btnSendStorage.setFixedWidth(70)
        VLayoutBtn.addWidget(self.btnClearStorage)
        VLayoutBtn.addWidget(self.btnDelStorage)
        VLayoutBtn.addWidget(self.btnSendStorage)
        VLayoutBtn.addStretch(1)

        HLayoutCtrlStorage.addWidget(self.lstPacketHistory, 1)
        HLayoutCtrlStorage.addLayout(VLayoutBtn)
        HLayoutCtrlStorage.setContentsMargins(0, 0, 5, 0)
        HLayoutCtrlStorage.setSpacing(10)

        VLayoutCtrlStorage.addWidget(lblCtrlStr)
        VLayoutCtrlStorage.addLayout(HLayoutCtrlStorage)
        VLayoutCtrlStorage.setContentsMargins(0, 0, 0, 0)

    def on_click_btn_store(self):
        bt_temp = bytearray([])
        for i in range(self.tablePacket.rowCount()):
            temp = int(self.tablePacket.item(i, 1).text(), 16)
            bt_temp.append(temp)

        if self.rbtnReverse.isChecked():
            bt_temp.reverse()

        if len(bt_temp) > 0:
            strStore = "(" + str(len(bt_temp)) + ")-" + "0x"
            strStore += ''.join('{:02x}'.format(byte) for byte in bt_temp)
            self.lstPacketHistory.addItem(QtWidgets.QListWidgetItem(strStore))

    def on_click_btn_clear_storage(self):
        self.lstPacketHistory.clear()

    def on_click_btn_del_storage(self):
        self.lstPacketHistory.takeItem(self.lstPacketHistory.row(self.lstPacketHistory.currentItem()))

    def on_click_btn_send_storage(self):
        if self.lstPacketHistory.count() > 0 or self.lstPacketHistory is not None:
            strSelected = self.lstPacketHistory.currentItem().text().split('-0x')[1]
            bta_temp = bytearray.fromhex(strSelected)
            if self.rbtnReverse.isChecked():
                bta_temp.reverse()

            self.sig_send_serial_packet.emit(bta_temp)

    def on_click_btn_clear(self):
        self.tablePacket.clearTable()

    def on_click_btn_add(self):
        self.tablePacket.addRow()

    def on_click_btn_del(self):
        self.tablePacket.delRow()

    def on_click_btn_shift_up(self):
        self.tablePacket.shiftUp()

    def on_click_btn_shift_down(self):
        self.tablePacket.shiftDown()

    def on_click_btn_send_str(self):
        str_item = self.txtStringInput.text()
        bt_temp = bytearray([])
        for c in str_item:
            bt_temp.append(ord(c))

        if self.rbtnReverse.isChecked():
            bt_temp.reverse()

        self.sig_send_serial_packet.emit(bt_temp)

    def on_click_btn_send(self):
        bt_temp = bytearray([])
        for i in range(self.tablePacket.rowCount()):
            temp = int(self.tablePacket.item(i, 1).text(), 16)
            bt_temp.append(temp)

        if self.rbtnReverse.isChecked():
            bt_temp.reverse()

        if len(bt_temp) > 0:
            self.sig_send_serial_packet.emit(bt_temp)

    def release(self):
        self.close()

if __name__ == '__main__':
    app = QtCore.QCoreApplication.instance()
    if app is None:
        app = QtWidgets.QApplication(sys.argv)

    app.setStyle('fusion')
    MainUI = CWidgetSerialSend()
    MainUI.show()

    app.exec_()
    MainUI.release()