import bisect, collections, functools, heapq, itertools, math, operator, string
from typing import List, Optional, Tuple
import sortedcontainers

# 1700 - Number of Students Unable to Eat Lunch - EASY
class Solution:
    def countStudents(self, students: List[int], sandwiches: List[int]) -> int:
        cnt = collections.Counter(students)
        st = collections.deque(students)
        ans = len(students)
        for v in sandwiches:
            if cnt[v] == 0:
                break
            while st and st[0] != v:
                st.append(st.popleft())
            st.popleft()
            cnt[v] -= 1
            ans -= 1
        return ans

    def countStudents(self, students: List[int], sandwiches: List[int]) -> int:
        s1 = sum(students)
        s0 = len(students) - s1
        for v in sandwiches:
            if v == 0 and s0:
                s0 -= 1
            elif v == 1 and s1:
                s1 -= 1
            else:
                break
        return s0 + s1

# 1701 - Average Waiting Time - MEDIUM
class Solution:
    def averageWaitingTime(self, customers: List[List[int]]) -> float:
        finish = wait = 0
        for a, t in customers:
            wait += max(0, finish - a) + t
            finish = max(finish, a) + t
        return wait / len(customers)

    def averageWaitingTime(self, customers: List[List[int]]) -> float:
        wait = cur = 0
        for a, t in customers:
            cur = max(cur, a) + t
            wait += cur - a
        return wait / len(customers)

# 1702 - Maximum Binary String After Change - MEDIUM
class Solution:
    # 1. 开头的 1 不动, 找到第一个开头为 0 的子串
    # 2. 子串含至少两个 0 时, 可以把子串的 1 都挪到右边, 用左边的 0 生成 1, 直到耗尽 00
    # O(n) / O(1)
    def maximumBinaryString(self, binary: str) -> str:
        i = 0
        while i < len(binary) and binary[i] == "1":
            i += 1

        # 68 ms
        zero = binary[i:].count("0")
        one = len(binary) - i - zero

        # 352 ms
        # one = sum(map(int, binary[i:]))
        # zero = len(binary) - i - one

        # 660 ms
        # zero = sum(1 - int(binary[j]) for j in range(i, len(binary)))
        # one = len(binary) - i - zero

        if zero < 2:
            return binary
        return binary[:i] + "1" * (zero - 1) + "0" + "1" * one

# 1704 - Determine if String Halves Are Alike - EASY
class Solution:
    def halvesAreAlike(self, s: str, p: str = "aeiouAEIOU") -> bool:
        return sum(c in p for c in s[: len(s) // 2]) == sum(
            c in p for c in s[len(s) // 2 :]
        )

p = set("aeiouAEIOU")

class Solution:
    def halvesAreAlike(self, s: str) -> bool:
        return sum(c in p for c in s[: len(s) // 2]) == sum(
            c in p for c in s[len(s) // 2 :]
        )

# 1705 - Maximum Number of Eaten Apples - MEDIUM
class Solution:
    def eatenApples(self, apples: List[int], days: List[int]) -> int:
        pq, i, ans = [], 0, 0
        while i < len(apples) or pq:
            while pq and pq[0][0] <= i:
                heapq.heappop(pq)
            if i < len(apples) and apples[i]:
                heapq.heappush(pq, [i + days[i], apples[i]])
            if pq:
                pq[0][1] -= 1
                ans += 1
                if not pq[0][1]:
                    heapq.heappop(pq)
            i += 1
        return ans

    def eatenApples(self, apples: List[int], days: List[int]) -> int:
        pq, i, ans = [], 0, 0
        while i < len(apples):
            while pq and pq[0][0] <= i:
                heapq.heappop(pq)
            if apples[i]:
                heapq.heappush(pq, [i + days[i], apples[i]])
            if pq:
                pq[0][1] -= 1
                if not pq[0][1]:
                    heapq.heappop(pq)
                ans += 1
            i += 1
        while pq:
            cur = heapq.heappop(pq)
            d = min(cur[0] - i, cur[1])
            i += d
            ans += d
            while pq and pq[0][0] <= i:
                heapq.heappop(pq)
        return ans

# 1706 - Where Will the Ball Fall - MEDIUM
class Solution:
    def findBall(self, grid: List[List[int]]) -> List[int]:
        ans = []
        m, n = len(grid), len(grid[0])
        for b in range(n):
            i = 0
            j = b
            succ = True
            while i < m:
                if grid[i][j] == 1 and j + 1 < n and grid[i][j + 1] == 1:
                    j += 1
                    i += 1
                elif grid[i][j] == -1 and j - 1 >= 0 and grid[i][j - 1] == -1:
                    j -= 1
                    i += 1
                else:
                    succ = False
                    break
            if succ:
                ans.append(j)
            else:
                ans.append(-1)
        return ans

    # for-else
    def findBall(self, grid: List[List[int]]) -> List[int]:
        n = len(grid[0])
        ans = [-1] * n
        for j in range(n):
            col = j
            for row in grid:
                dir = row[col]
                col += dir
                if col < 0 or col == n or row[col] != dir:
                    break
            else:
                ans[j] = col
        return ans

# 1710 - Maximum Units on a Truck - EASY
class Solution:
    def maximumUnits(self, boxTypes: List[List[int]], truckSize: int) -> int:
        ans = 0
        for t, v in sorted(boxTypes, key=lambda x: x[1], reverse=True):
            if t > truckSize:
                ans += truckSize * v
                break
            truckSize -= t
            ans += t * v
        return ans

# 1711 - Count Good Meals - MEDIUM
class Solution:
    global arr
    arr = [2**i for i in range(22)]

    # O(nlogC) / O(n), 21n
    def countPairs(self, deliciousness: List[int]) -> int:
        mod = 10**9 + 7
        cnt = collections.defaultdict(int)
        ans = 0
        for v in deliciousness:
            for t in arr:
                ans += cnt[t - v]
            ans %= mod
            cnt[v] += 1
        return ans

    def countPairs(self, deliciousness: List[int]) -> int:
        mod = 10**9 + 7
        ans = 0
        cnt = collections.Counter(deliciousness)
        p = 1
        for k in sorted(cnt):
            if k == 0:
                continue
            while p < k:
                p *= 2
            ans += cnt[k] * cnt[p - k]
            if k == p:  # 自身是一个 2 的幂次
                ans += cnt[k] * (cnt[k] - 1) // 2
            ans %= mod
        return ans

    def countPairs(self, deliciousness: List[int]) -> int:
        # TODO
        def nextPower(x: int):
            x -= 1
            x |= x >> 1
            x |= x >> 2
            x |= x >> 4
            x |= x >> 8
            x |= x >> 16
            return x + 1

        mod = 10**9 + 7
        cnt = collections.Counter(deliciousness)
        ans = 0
        # 由于每个数只遍历了最接近自己的 2 的次幂的组合, 所以不可能重复
        # 比如说 1 + 3 = 4，只在 3 的时候计算, 3 + 5 = 8 只在 5 的时候计算
        for k in cnt:
            if k == 0:
                continue
            # k 的下一个 2 的幂次
            p = nextPower(k)
            # 自身是一个 2 的幂次
            if k == p:
                ans += cnt[k] * (cnt[k] - 1) // 2
            ans += cnt[k] * cnt[p - k]
        return ans % mod

# 1716 - Calculate Money in Leetcode Bank - EASY
class Solution:
    def totalMoney(self, n: int) -> int:
        div, mod = divmod(n, 7)
        ans = 0
        for i in range(mod):
            ans += i + 1 + div
        while div:
            ans += 28 + (div - 1) * 7
            div -= 1
        return ans

    def totalMoney(self, n: int) -> int:
        div, mod = divmod(n, 7)
        ans = 0
        for i in range(mod):
            ans += i + 1 + div
        ans += div * 28 + (div - 1) * div * 7 // 2 if div else 0
        return ans

# 1725 - Number Of Rectangles That Can Form The Largest Square - EASY
class Solution:
    def countGoodRectangles(self, rectangles: List[List[int]]) -> int:
        count = pre = 0
        for l, w in rectangles:
            sq = min(l, w)
            if sq > pre:
                count = 1
                pre = sq
            elif sq == pre:
                count += 1
        return count

# 1732 - Find the Highest Altitude - EASY
class Solution:
    # O(n) / O(n)
    def largestAltitude(self, gain: List[int]) -> int:
        h = [0]
        for v in gain:
            h.append(h[-1] + v)
        return max(h)

    # O(n) / O(1)
    def largestAltitude(self, gain: List[int]) -> int:
        ans = h = 0
        for v in gain:
            h += v
            ans = max(ans, h)
        return ans

    # O(n) / O(1)
    def largestAltitude(self, gain: List[int]) -> int:
        return max(itertools.accumulate(gain, initial=0))

# 1736 - Latest Time by Replacing Hidden Digits - EASY
class Solution:
    def maximumTime(self, time: str) -> str:
        ans = list(time)
        if time[0] == "?":
            ans[0] = "2" if time[1] == "?" or int(time[1]) < 4 else "1"
        if time[1] == "?":
            ans[1] = "3" if ans[0] == "2" else "9"
        if time[3] == "?":
            ans[3] = "5"
        if time[4] == "?":
            ans[4] = "9"
        return "".join(ans)

# 1739 - Building Boxes - HARD
class Solution:
    def minimumBoxes(self, n: int) -> int:
        s = 0
        k = 1
        # 放满, 1, 1 + 2, 1 + 2 + 3, 1 + 2 + ... + k
        while s + k * (k + 1) // 2 <= n:
            s += k * (k + 1) // 2
            k += 1
        # 还有剩余, 从最低一层继续摆放, 假设摆放 m 个, 那么累计可摆放的盒子个数为 1 + 2 + 3 + ... + i >= m
        ans = k * (k - 1) // 2
        k = 1
        while s < n:
            ans += 1
            s += k
            k += 1
        return ans

# 1742 - Maximum Number of Balls in a Box - EASY
class Solution:
    def countBalls(self, lowLimit: int, highLimit: int) -> int:
        d = collections.defaultdict(int)
        for i in range(lowLimit, highLimit + 1):
            x = 0
            while i:
                x += i % 10
                i //= 10
            d[x] += 1
        return max(d.values())

# 1748 - Sum of Unique Elements - EASY
class Solution:
    def sumOfUnique(self, nums: List[int]) -> int:
        freq = [0] * 100
        for n in nums:
            freq[n - 1] += 1
        ans = 0
        for i in range(len(freq)):
            ans += i + 1 if freq[i] == 1 else 0
        return ans

    def sumOfUnique(self, nums: List[int]) -> int:
        return sum(k for k, v in collections.Counter(nums).items() if v == 1)

# 1749 - Maximum Absolute Sum of Any Subarray - MEDIUM
class Solution:
    def maxAbsoluteSum(self, nums: List[int]) -> int:
        ans = p = n = 0
        for v in nums:
            if v >= 0:
                p += v
                ans = max(ans, p)
                n = min(0, n + v)
            if v <= 0:
                n += v
                ans = max(ans, -n)
                p = max(0, p + v)
        return ans

    def maxAbsoluteSum(self, nums: List[int]) -> int:
        ans = p = n = 0
        for v in nums:
            p = max(0, p + v)
            n = min(0, n + v)
            ans = max(ans, p, -n)
        return ans

    def maxAbsoluteSum(self, nums: List[int]) -> int:
        ans = p = n = 0
        for v in nums:
            p = p + v if p > 0 else v
            n = n + v if n < 0 else v
            ans = max(ans, abs(p), abs(n))
        return ans

    # 子数组和最大 -> 某两个位置(i, j)的前缀和的差值 最大 (i <= j)
    # 子数组和最小 -> 某两个位置(i, j)的前缀和的差值 最小 (i <= j)
    # 子数组和的 abs 最大 -> 某两个位置(i, j)的前缀和的差距 最大, i 和 j 相对位置随意
    def maxAbsoluteSum(self, nums: List[int]) -> int:
        summ = mx = mn = 0
        for v in nums:
            summ += v
            if summ > mx:
                mx = summ
            if summ < mn:
                mn = summ
        return mx - mn

# 1750 - Minimum Length of String After Deleting Similar Ends - MEDIUM
class Solution:
    def minimumLength(self, s: str) -> int:
        dq = collections.deque()
        for c, g in itertools.groupby(s):
            dq.append((c, len(tuple(g))))
        while dq:
            if dq[0][0] == dq[-1][0]:
                if len(dq) == 1:
                    return 1 if dq.pop()[1] == 1 else 0
                else:
                    dq.pop()
                    dq.popleft()
            else:
                break
        return sum(v[1] for v in dq)

    def minimumLength(self, s: str) -> int:
        l = 0
        r = len(s) - 1
        while l < r and s[l] == s[r]:
            while l + 1 < r and s[l] == s[l + 1]:
                l += 1
            while l < r - 1 and s[r - 1] == s[r]:
                r -= 1
            l += 1
            r -= 1
        return max(0, r - l + 1)

    def minimumLength(self, s: str) -> int:
        l = 0
        r = len(s) - 1
        while l < r and s[l] == s[r]:
            c = s[l]
            while l <= r and s[l] == c:
                l += 1
            while l <= r and s[r] == c:
                r -= 1
        return r - l + 1

# 1752 - Check if Array Is Sorted and Rotated - EASY
class Solution:
    # O(n^2) / O(n)
    def check(self, nums: List[int]) -> bool:
        n = len(nums)
        a = sorted(nums)
        return any(all(nums[i] == a[(i + x) % n] for i in range(n)) for x in range(n))

    # O(n) / O(1)
    def check(self, nums: List[int]) -> bool:
        cnt = 0
        n = len(nums)
        for i in range(n):
            if nums[i] > nums[(i + 1) % n]:
                cnt += 1
            if cnt > 1:
                return False
        return True

# 1753 - Maximum Score From Removing Stones - MEDIUM
class Solution:
    # O(nlogn) / O(1)
    def maximumScore(self, a: int, b: int, c: int) -> int:
        h = sorted([-a, -b, -c])
        ans = 0
        while len(h) > 1:
            x = -heapq.heappop(h) - 1
            y = -heapq.heappop(h) - 1
            ans += 1
            if x:
                heapq.heappush(h, -x)
            if y:
                heapq.heappush(h, -y)
        return ans

    # O(1) / O(1)
    def maximumScore(self, a: int, b: int, c: int) -> int:
        arr = sorted([a, b, c])
        if arr[0] + arr[1] <= arr[2]:
            return arr[0] + arr[1]
        return sum(arr) // 2

# 1754 - Largest Merge Of Two Strings - MEDIUM
class Solution:
    # O(m^2 + n^2) / O(m^2 + n^2)
    def largestMerge(self, word1: str, word2: str) -> str:
        if word1 >= word2 and word2 > "":
            return word1[0] + self.largestMerge(word1[1:], word2)
        if word2 >= word1 and word1 > "":
            return word2[0] + self.largestMerge(word1, word2[1:])
        return word1 + word2

    # O(m^2 + n^2) / O(1)
    def largestMerge(self, word1: str, word2: str) -> str:
        ans = ""
        i = j = 0
        m = len(word1)
        n = len(word2)
        while i < m and j < n:
            # k = 0
            # while i + k < m and j + k < n and word1[i + k] == word2[j + k]:
            #     k += 1
            # if j + k == n or i + k < m and word1[i + k] > word2[j + k]:
            #     ans += word1[i]
            #     i += 1
            # else:
            #     ans += word2[j]
            #     j += 1

            if word1[i:] > word2[j:]:
                ans += word1[i]
                i += 1
            else:
                ans += word2[j]
                j += 1

        while i < m:
            ans += word1[i]
            i += 1
        while j < n:
            ans += word2[j]
            j += 1
        return ans

# 1758 - Minimum Changes To Make Alternating Binary String - EASY
class Solution:
    # O(n) / O(n)
    def minOperations(self, s: str) -> int:
        n = len(s)
        a = "01" * ((n + 1) // 2)
        b = "10" * ((n + 1) // 2)
        ans = 1e4
        ans = min(ans, sum(x != y for x, y in zip(a, s)))
        ans = min(ans, sum(x != y for x, y in zip(b, s)))
        return ans

    def minOperations(self, s: str) -> int:
        x = y = 0  # x: 1010... y: 0101...
        for i, c in enumerate(s):
            if c != str(i % 2):
                x += 1
            else:
                y += 1
        return min(x, y)

    # 变成 01010... 的步骤数是 x,
    # 变成 10101... 的步骤数是 y,
    # 一定有 x + y = n
    # 任意计算其中一种, 返回 min(x, n-x) 就行
    def minOperations(self, s: str) -> int:
        x = 0
        for i, c in enumerate(s):
            if c != str(i % 2):
                x += 1
        return min(x, len(s) - x)

# 1759 - Count Number of Homogenous Substrings - MEDIUM
class Solution:
    def countHomogenous(self, s: str) -> int:
        ans = 0
        for _, g in itertools.groupby(s):
            l = len(list(g))
            ans += (l + 1) * l // 2
        return ans % (10**9 + 7)

    def countHomogenous(self, s: str) -> int:
        ans = t = 1
        for i in range(1, len(s)):
            if s[i - 1] == s[i]:
                t += 1
            else:
                t = 1
            ans += t
        return ans % (10**9 + 7)

# 1760 - Minimum Limit of Balls in a Bag - MEDIUM
class Solution:
    def minimumSize(self, nums: List[int], maxOperations: int) -> int:
        def check(x: int) -> int:
            t = 0
            for v in nums:
                t += (v - 1) // x
            return t <= maxOperations

        l = 1
        r = max(nums)
        while l < r:
            m = (l + r) // 2
            if check(m):
                r = m
            else:
                l = m + 1
        return l

    def minimumSize(self, nums: List[int], maxOperations: int) -> int:
        return (
            bisect.bisect_left(
                range(1, max(nums) + 1),
                x=True,
                key=lambda m: sum((v - 1) // m for v in nums) <= maxOperations,
            )
            + 1
        )

# 1761 - Minimum Degree of a Connected Trio in a Graph - HARD
class Solution:
    def minTrioDegree(self, n: int, edges: List[List[int]]) -> int:
        d = [0] * (n + 1)
        g = [[False] * (n + 1) for _ in range(n + 1)]
        for x, y in edges:
            d[x] += 1
            d[y] += 1
            g[x][y] = g[y][x] = True
        return min(
            (
                d[x] + d[y] + d[z] - 6
                for x in range(1, n + 1)
                for y in range(x + 1, n + 1)
                if g[x][y]
                for z in range(y + 1)
                if g[x][z] and g[y][z]
            ),
            default=-1,
        )

        # return min(
        #     (
        #         d[x] + d[y] + d[z] - 6
        #         for x in range(1, n - 1)
        #         for y in range(x + 1, n)
        #         for z in range(y + 1, n + 1)
        #         if g[x][y] and g[y][z] and g[z][x]
        #     ),
        #     default=-1,
        # )

    def minTrioDegree(self, n: int, edges: List[List[int]]) -> int:
        d = collections.defaultdict(list)
        for x, y in edges:
            d[x].append(y)
            d[y].append(x)
        ans = math.inf
        for i in range(1, n + 1):
            if len(d[i]) < 2:
                continue
            # 对相邻节点的度数进行排序, 这样可以保证先遍历的元组组合的度数更小
            conn = sorted(d[i], key=lambda x: len(d[x]))
            q = [(0, 1)]
            vis = set(q)
            found = False
            for l, r in q:
                if found:
                    # 找到一个有效三元组了, 其度数组合一定是包含节点i的三元组中最小的, 不再继续遍历其他的
                    break
                j, k = conn[l], conn[r]
                if j in d[k]:
                    found = True
                    ans = min(ans, len(d[i]) + len(d[j]) + len(d[k]) - 6)
                else:
                    # 否则两个方向继续找下一个元组组合
                    for nl, nr in ((l + 1, r), (l, r + 1)):
                        if (
                            0 <= nl < len(conn)
                            and 0 <= nr < len(conn)
                            and nl != nr
                            and (nl, nr) not in vis
                        ):
                            vis.add((nl, nr))
                            q.append((nl, nr))
        return -1 if ans == math.inf else ans

# 1762 - Buildings With an Ocean View - MEDIUM
class Solution:
    def findBuildings(self, heights: List[int]) -> List[int]:
        ans, maxH = [], 0
        for i in range(len(heights) - 1, -1, -1):
            if heights[i] > maxH:
                ans.append(i)
                maxH = heights[i]
        ans.reverse()
        return ans

# 1763 - Longest Nice Substring - EASY
class Solution:
    def longestNiceSubstring(self, s: str) -> str:
        if not s:
            return ""
        ss = set(s)
        for i, c in enumerate(s):
            if c.swapcase() not in ss:
                s0 = self.longestNiceSubstring(s[:i])
                s1 = self.longestNiceSubstring(s[i + 1 :])
                return max(s0, s1, key=len)
        return s

# 1764 - Form Array by Concatenating Subarrays of Another Array - MEDIUM
class Solution:
    # O(nm) / O(1)
    def canChoose(self, groups: List[List[int]], nums: List[int]) -> bool:
        i = j = 0
        while i < len(groups) and j < len(nums):
            g = groups[i]
            if g == nums[j : j + len(g)]:
                i += 1
                j += len(g)
            else:
                j += 1
        return i == len(groups)

# 1765 - Map of Highest Peak - MEDIUM
class Solution:
    def highestPeak(self, isWater: List[List[int]]) -> List[List[int]]:
        dq = collections.deque([])
        m, n = len(isWater), len(isWater[0])
        for i in range(m):
            for j in range(n):
                if isWater[i][j] == 1:
                    dq.append((i, j))
                isWater[i][j] -= 1
        while dq:
            x, y = dq.popleft()
            for nx, ny in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]:
                if 0 <= nx < m and 0 <= ny < n and isWater[nx][ny] == -1:
                    dq.append((nx, ny))
                    isWater[nx][ny] = isWater[x][y] + 1
        return isWater

# 1768 - Merge Strings Alternately - EASY
class Solution:
    def mergeAlternately(self, word1: str, word2: str) -> str:
        return "".join(
            a + b for a, b in itertools.zip_longest(word1, word2, fillvalue="")
        )

# 1769 - Minimum Number of Operations to Move All Balls to Each Box - MEDIUM
class Solution:
    # O(n) / O(n)
    def minOperations(self, boxes: str) -> List[int]:
        n = len(boxes)
        l = [0] * n
        step = 0
        for i in range(1, len(boxes)):
            if boxes[i - 1] == "1":
                step += 1
            l[i] += l[i - 1] + step
        r = [0] * n
        step = 0
        for i in range(len(boxes) - 2, -1, -1):
            if boxes[i + 1] == "1":
                step += 1
            r[i] += r[i + 1] + step
        return [a + b for a, b in zip(l, r)]

    # O(n) / O(1)
    def minOperations(self, boxes: str) -> List[int]:
        l = int(boxes[0])
        r = operations = 0
        for i in range(1, len(boxes)):
            if boxes[i] == "1":
                r += 1
                operations += i
        ans = [operations]
        for i in range(1, len(boxes)):
            operations += l - r
            if boxes[i] == "1":
                l += 1
                r -= 1
            ans.append(operations)
        return ans

    def minOperations(self, boxes: str) -> List[int]:
        n = len(boxes)
        l = r = cost = 0
        for i, v in enumerate(map(int, boxes)):
            r += v
            cost += v * (i + 1)
        ans = [-1] * n
        for i, v in enumerate(map(int, boxes)):
            cost += l - r
            l += v
            r -= v
            ans[i] = cost
        return ans

# 1770 - Maximum Score from Performing Multiplication Operations - MEDIUM
class Solution:
    def maximumScore(self, nums: List[int], multipliers: List[int]) -> int:
        n = len(nums)
        m = len(multipliers)
        f = [[0] * (m + 1) for _ in range(m + 1)]
        for i in range(1, m + 1):
            f[i][0] = f[i - 1][0] + nums[i - 1] * multipliers[i - 1]
        for j in range(1, m + 1):
            f[0][j] = f[0][j - 1] + nums[n - j] * multipliers[j - 1]
        ans = f[0][m] if f[0][m] > f[m][0] else f[m][0]
        # i: 左边拿走数量, j: 右边拿走数量
        for i in range(1, m + 1):
            for j in range(1, m - i + 1):
                left = f[i - 1][j] + nums[i - 1] * multipliers[i + j - 1]
                right = f[i][j - 1] + nums[n - j] * multipliers[i + j - 1]
                f[i][j] = max(left, right)
            ans = max(ans, f[i][m - i])
        return ans

    def maximumScore(self, nums: List[int], multipliers: List[int]) -> int:
        n = len(nums)
        m = len(multipliers)
        # l, r 是左右下标, i 是 mul 里的下标
        f = [[0] * (m + 1) for _ in range(m + 1)]
        for l in range(m - 1, -1, -1):
            for i in range(m - 1, -1, -1):
                r = n - (i - l) - 1
                if r < 0 or r >= n:
                    break
                a = f[l + 1][i + 1] + nums[l] * multipliers[i]
                b = f[l][i + 1] + nums[r] * multipliers[i]
                f[l][i] = max(a, b)
        return f[0][0]

    # cache maxsize is set to None will TLE
    def maximumScore(self, nums: List[int], multipliers: List[int]) -> int:
        @functools.lru_cache(len(multipliers))
        def dfs(l: int, r: int, k: int) -> int:
            if k == len(multipliers):
                return 0
            a = nums[l] * multipliers[k] + dfs(l + 1, r, k + 1)
            b = nums[r] * multipliers[k] + dfs(l, r - 1, k + 1)
            return max(a, b)
            dfs.cache_clear()

        return dfs(0, len(nums) - 1, 0)

# 1773 - Count Items Matching a Rule - EASY
class Solution:
    def countMatches(self, items: List[List[str]], ruleKey: str, ruleValue: str) -> int:
        if ruleKey == "type":
            return sum(x == ruleValue for x, _, _ in items)
        if ruleKey == "color":
            return sum(x == ruleValue for _, x, _ in items)
        if ruleKey == "name":
            return sum(x == ruleValue for _, _, x in items)

    def countMatches(self, items: List[List[str]], ruleKey: str, ruleValue: str) -> int:
        idx = {"type": 0, "color": 1, "name": 2}[ruleKey]
        return sum(v[idx] == ruleValue for v in items)

# 1774 - Closest Dessert Cost - MEDIUM
class Solution:
    # O(n * 3**m) / O(m)
    def closestCost(
        self, baseCosts: List[int], toppingCosts: List[int], target: int
    ) -> int:
        def dfs(i: int, cur: int) -> None:
            nonlocal ans
            if i == len(toppingCosts):
                # 放外面也可以, 表示后面的都不选
                if abs(ans - target) > abs(cur - target):
                    ans = cur
                elif abs(ans - target) == abs(cur - target):
                    ans = min(ans, cur)
                return
            dfs(i + 1, cur)
            if cur <= target:
                dfs(i + 1, cur + toppingCosts[i])
                dfs(i + 1, cur + 2 * toppingCosts[i])
            return

        ans = math.inf
        for v in baseCosts:
            dfs(0, v)
        return ans

    def closestCost(
        self, baseCosts: List[int], toppingCosts: List[int], target: int
    ) -> int:
        def dfs(i: int, cur: int) -> None:
            nonlocal ans
            a = abs(ans - target)
            b = abs(cur - target)
            if cur > target and a < b:
                return
            if a > b:
                ans = cur
            if a == b:
                ans = min(ans, cur)
            if i == len(toppingCosts):
                return
            dfs(i + 1, cur + toppingCosts[i] * 2)
            dfs(i + 1, cur + toppingCosts[i])
            dfs(i + 1, cur)
            return

        ans = math.inf
        for v in baseCosts:
            dfs(0, v)
        return ans

# 1775 - Equal Sum Arrays With Minimum Number of Operations - MEDIUM
class Solution:
    def minOperations(self, nums1: List[int], nums2: List[int]) -> int:
        s1 = sum(nums1)
        s2 = sum(nums2)
        if s1 == s2:
            return 0
        if s1 < s2:
            return self.minOperations(nums2, nums1)
        diff = s1 - s2
        cnt = collections.Counter(v - 1 for v in nums1) + collections.Counter(
            6 - v for v in nums2
        )
        ans = 0
        for k in range(5, 0, -1):
            if diff >= cnt[k] * k:
                diff -= cnt[k] * k
                ans += cnt[k]
            else:
                ans += (diff + k - 1) // k
                diff = 0
                break

        # for i in range(5, 0, -1):
        #     if diff <= 0:
        #         break
        #     for _ in range(cnt[i]):
        #         if diff <= 0:
        #             break
        #         ans += 1
        #         diff -= i

        return ans if diff == 0 else -1

# 1779 - Find Nearest Point That Has the Same X or Y Coordinate - EASY
class Solution:
    def nearestValidPoint(self, x: int, y: int, points: List[List[int]]) -> int:
        ans = -1
        mi = math.inf
        for i, (a, b) in enumerate(points):
            if a == x or b == y:
                d = abs(a - x) + abs(b - y)
                if d < mi:
                    mi = d
                    ans = i
        return ans

# 1780 - Check if Number is a Sum of Powers of Three - MEDIUM
class Solution:
    def checkPowersOfThree(self, n: int) -> bool:
        p3 = [3**i for i in reversed(range(15))]
        for p in p3:
            if n >= 2 * p:
                return False
            elif n >= p:
                n -= p
        return True

    def checkPowersOfThree(self, n: int) -> bool:
        while n > 0:
            if n % 3 == 2:
                return False
            n //= 3
        return True

# 1781 - Sum of Beauty of All Substrings - MEDIUM
class Solution:
    # O(n * n * C) / O(C)
    def beautySum(self, s: str) -> int:
        ans = 0
        for i in range(len(s)):
            d = collections.defaultdict(int)
            for j in range(i, len(s)):
                d[s[j]] += 1
                ans += max(d.values()) - min(d.values())
        return ans

# 1782 - Count Pairs Of Nodes - HARD
class Solution:
    def countPairs(
        self, n: int, edges: List[List[int]], queries: List[int]
    ) -> List[int]:
        d = [0] * (n + 1)
        for x, y in edges:
            d[x] += 1
            d[y] += 1
        cnt = collections.Counter(tuple(sorted(e)) for e in edges)
        # cnt = collections.Counter(x * (n + 1) + y if x < y else y * (n + 1) + x for x, y in edges)
        ans = [0] * len(queries)
        sd = sorted(d)
        for i, q in enumerate(queries):
            l = 1
            r = n
            while l < r:
                if sd[l] + sd[r] <= q:
                    l += 1
                else:
                    ans[i] += r - l
                    r -= 1
            for (x, y), v in cnt.items():
                # if q < d[k // (n + 1)] + d[k % (n + 1)] <= q + v:
                if q < d[x] + d[y] <= q + v:
                    ans[i] -= 1
        return ans

# 1784 - Check if Binary String Has at Most One Segment of Ones - EASY
class Solution:
    def checkOnesSegment(self, s: str) -> bool:
        return len(list(v for v in s.split("0") if v != "")) <= 1
        return "01" not in s

# 1785 - Minimum Elements to Add to Form a Given Sum - MEDIUM
class Solution:
    def minElements(self, nums: List[int], limit: int, goal: int) -> int:
        return math.ceil(abs(goal - sum(nums)) / limit)
        return (abs(goal - sum(nums)) - 1) // limit + 1

# 1790 - Check if One String Swap Can Make Strings Equal - EASY
class Solution:
    def areAlmostEqual(self, s1: str, s2: str) -> bool:
        cnt1 = collections.Counter(s1)
        cnt2 = collections.Counter(s2)
        if cnt1 != cnt2:
            return False
        diff = 0
        for x, y in zip(s1, s2):
            if x != y:
                diff += 1
        if diff == 0 or diff == 2:
            return True
        return False

    def areAlmostEqual(self, s1: str, s2: str) -> bool:
        px = py = ""
        for x, y in zip(s1, s2):
            if x != y:
                if px == "used":
                    return False
                if px == "":
                    px = x
                    py = y
                elif px != y or py != x:
                    return False
                else:
                    px = "used"
        return True if px in "used" else False

    def areAlmostEqual(self, s1: str, s2: str) -> bool:
        px = py = ""
        for x, y in zip(s1, s2):
            if x != y:
                if px == y and py == x:
                    px = "used"
                elif px == "":
                    px = x
                    py = y
                else:
                    return False
        return True if px in "used" else False

    def areAlmostEqual(self, s1: str, s2: str) -> bool:
        i = j = -1
        for idx, (x, y) in enumerate(zip(s1, s2)):
            if x != y:
                if i < 0:
                    i = idx
                elif j < 0:
                    j = idx
                else:
                    return False
        return i < 0 or j >= 0 and s1[i] == s2[j] and s1[j] == s2[i]

    def areAlmostEqual(self, s1: str, s2: str) -> bool:
        arr = []
        for x, y in zip(s1, s2):
            if x != y:
                arr.append(x)
                arr.append(y)
        return len(arr) <= 4 and arr == arr[::-1]

# 1791 - Find Center of Star Graph - EASY
class Solution:
    def findCenter(self, edges: List[List[int]]) -> int:
        n = len(edges)
        d = [0] * (n + 1)
        for o, i in edges:
            d[o - 1] += 1
            d[i - 1] += 1
        for i in range(len(d)):
            if d[i] == n:
                return i + 1
        return -1

    def findCenter(self, edges: List[List[int]]) -> int:
        if edges[0][0] in edges[1]:
            return edges[0][0]
        else:
            return edges[0][1]

# 1792 - Maximum Average Pass Ratio - MEDIUM
class Solution:
    # O((n + e) * logn) / O(n)
    def maxAverageRatio(self, classes: List[List[int]], extraStudents: int) -> float:
        h = list((p / t - (p + 1) / (t + 1), p, t) for p, t in classes)
        heapq.heapify(h)
        for _ in range(extraStudents):
            _, p, t = heapq.heappop(h)
            p += 1
            t += 1
            heapq.heappush(h, (p / t - (p + 1) / (t + 1), p, t))
        return sum(p / t for _, p, t in h) / len(classes)

# 1796 - Second Largest Digit in a String - EASY
class Solution:
    def secondHighest(self, s: str) -> int:
        a = b = -1
        for c in s:
            if c.isdigit():
                if int(c) > a:
                    a, b = int(c), a
                elif a > int(c) > b:
                    b = int(c)
        return b

# 1797 - Design Authentication Manager - MEDIUM
class AuthenticationManager:
    def __init__(self, timeToLive: int):
        self.t = timeToLive
        self.d = {}

    # O(1)
    def generate(self, tokenId: str, currentTime: int) -> None:
        self.d[tokenId] = currentTime + self.t
        return

    # O(1)
    def renew(self, tokenId: str, currentTime: int) -> None:
        if self.d.get(tokenId, 0) > currentTime:
            self.d[tokenId] = currentTime + self.t
        return

    # O(n)
    def countUnexpiredTokens(self, currentTime: int) -> int:
        return sum(v > currentTime for v in self.d.values())

class AuthenticationManager:
    def __init__(self, timeToLive: int):
        self.t = timeToLive
        self.d = collections.OrderedDict()

    # O(1)
    def generate(self, tokenId: str, currentTime: int) -> None:
        self.d[tokenId] = currentTime + self.t
        return

    # O(1)
    def renew(self, tokenId: str, currentTime: int) -> None:
        while self.d and next(iter(self.d.values())) <= currentTime:
            self.d.popitem(last=False)
        if tokenId in self.d:
            self.d[tokenId] = currentTime + self.t
            self.d.move_to_end(tokenId)
        return

    # O(1), Average-case time complexity
    def countUnexpiredTokens(self, currentTime: int) -> int:
        while self.d and next(iter(self.d.values())) <= currentTime:
            self.d.popitem(last=False)
        return len(self.d)

class AuthenticationManager:
    def __init__(self, timeToLive: int):
        """
        lazy update (extra element in heap and deleted in counting)
        is possible because the currentTime is strictly increasing
        which implies that if the renewal before counting is conducted,
        the old record will be automatically deleted before counting.
        """
        self.t = timeToLive
        self.d = {}
        self.q = []

    def generate(self, tokenId: str, currentTime: int) -> None:
        heapq.heappush(self.q, (currentTime + self.t, tokenId))
        self.d[tokenId] = currentTime + self.t
        return

    def renew(self, tokenId: str, currentTime: int) -> None:
        if tokenId in self.d and self.d[tokenId] > currentTime:
            self.d[tokenId] = currentTime + self.t  # add another record (new_time, id)
            heapq.heappush(self.q, (currentTime + self.t, tokenId))
        return

    def countUnexpiredTokens(self, currentTime: int) -> int:
        while self.q and self.q[0][0] <= currentTime:
            # decide whether this record is the most up-to-date one for the given token
            # only one record in dict()
            if self.q[0][0] == self.d[self.q[0][1]]:
                self.d.pop(self.q[0][1])
            heapq.heappop(self.q)
        return len(self.d)

# 1798 - Maximum Number of Consecutive Values You Can Make - MEDIUM
class Solution:
    def getMaximumConsecutive(self, coins: List[int]) -> int:
        coins.sort()
        ans = 0
        for c in coins:
            if c > ans + 1:
                break
            ans += c
        return ans + 1

# 1799 - Maximize Score After N Operations - HARD
class Solution:
    # 2400 ms
    def maxScore(self, nums: List[int]) -> int:
        def gcd(x: int, y: int) -> int:
            while y:
                x, y = y, x % y
            return x

        # 1600 ms
        # d = collections.defaultdict(dict)
        # for i in range(len(nums)):
        #     for j in range(i + 1, len(nums)):
        #         g = gcd(nums[i], nums[j])
        #         d[nums[i]][nums[j]] = g
        #         d[nums[j]][nums[i]] = g

        @functools.lru_cache(None)
        def dfs(t: tuple) -> int:
            m = 0
            l = list(t)
            for i in range(len(l)):
                for j in range(i + 1, len(l)):
                    new = l[:]
                    new.pop(j)
                    new.pop(i)
                    m = max(m, len(l) // 2 * gcd(l[i], l[j]) + dfs(tuple(new)))
                    # m = max(m, len(l) // 2 * d[l[i]][l[j]] + dfs(tuple(new)))
            return m

        return dfs(tuple(nums))

    # O(2**n * n^2 + logU * n^2) / O(2**n + n^2), 1500 ms, U = max(nums)
    def maxScore(self, nums: List[int]) -> int:
        def gcd(x: int, y: int) -> int:
            while y:
                x, y = y, x % y
            return x

        n = len(nums)
        g = [[0] * n for _ in range(n)]
        for i in range(n):
            for j in range(i + 1, n):
                g[i][j] = gcd(nums[i], nums[j])
        f = [0] * (1 << n)
        for k in range(1 << n):
            cnt = bin(k).count("1")
            if cnt % 2 == 0:
                for i in range(n):
                    if (k >> i) & 1:
                        for j in range(i + 1, n):
                            if (k >> j) & 1:
                                f[k] = max(
                                    f[k],
                                    f[k ^ (1 << i) ^ (1 << j)] + cnt // 2 * g[i][j],
                                )
        return f[(1 << n) - 1]

    def maxScore(self, nums: List[int]) -> int:
        def gcd(x: int, y: int) -> int:
            while y:
                x, y = y, x % y
            return x

        @functools.lru_cache(None)
        def dfs(mask: int, k: int) -> int:
            if k == len(nums) // 2 + 1:
                return 0
            r = 0
            for i in range(len(nums)):
                if mask & 1 << i:
                    continue
                for j in range(i + 1, len(nums)):
                    if mask & 1 << j:
                        continue
                    r = max(
                        r,
                        k * gcd(nums[i], nums[j]) + dfs(mask | 1 << i | 1 << j, k + 1),
                    )
            return r

        return dfs(0, 1)

    def maxScore(self, nums: List[int]) -> int:
        def gcd(x: int, y: int) -> int:
            while y:
                x, y = y, x % y
            return x

        @functools.lru_cache(None)
        def dfs(mask: int, k: int) -> int:
            if k == len(nums) // 2 + 1:
                return 0
            r = 0
            for i in range(len(nums)):
                if mask & 1 << i:
                    continue
                for j in range(i + 1, len(nums)):
                    if mask & 1 << j:
                        continue
                    r = max(
                        r,
                        k * gcd(nums[i], nums[j]) + dfs(mask ^ 1 << i ^ 1 << j, k + 1),
                    )
            return r

        return dfs(0, 1)


# Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.

# Note: The input string may contain letters other than the parentheses ( and ).

# Examples:
# "()())()" -> ["()()()", "(())()"]
# "(a)())()" -> ["(a)()()", "(a())()"]
# ")(" -> [""]

from collections import deque

class BFSSolution:
    def removeInvalidParentheses(self, s):
        """
        BFS solution:
        0 level, the original string
        1 level, remove one '(' or ')' from the original string, which gives several substring
        2 level, remove one '(' or ')' from one of the above substring, which gives several substring
        ...
        On each level, pick a string from the set, and check whether it is valid or not.
        If on a certain level, we found a valid case, there is no need to go to furher level!!!

        To avoid duplicate answers, when generate the substrings, we only pick unqiues

        :type s: str
        :rtype: List[str]
        """
        results = []

        if not s:
            return [s]

        visited = {s} # create a set. sets are bags of unique values
        queue = deque([s])
        str_is_valid = False

        # DON'T reset str_is_valid.
        # Because the question requires you to `Remove the minimum number of invalid parentheses`
        # which means, if you found a str is valid, then there is no need to go to next level, i.e.
        # remove more chars from the str to get a valid case.
        while queue:
            str_to_check = queue.popleft()

            if self.is_valid(str_to_check):
                results.append(str_to_check)
                str_is_valid = True

            if str_is_valid:
                continue

            for index, ch in enumerate(str_to_check):
                if ch not in ['(', ')']:
                    continue

                substr = str_to_check[:index] + str_to_check[index + 1:]
                if substr not in visited:
                    queue.append(substr)
                    visited.add(substr)

        return results

    def is_valid(self, input_str):
        count = 0

        for ch in input_str:
            if ch == '(':
                count += 1

            if ch == ')':
                count -= 1

            if count < 0:
                return False

        return count == 0

if __name__ == '__main__':
    sol = BFSSolution()
    test = "(a)())()"
    answer = sol.removeInvalidParenthesesBFS(test)
    print(answer)


from mmdet.apis import inference_detector
from mmdet.models import build_detector
from mmcv.runner import load_state_dict
from collections import OrderedDict
import scipy
import mmcv
import os
import torch
import numpy as np
import cv2
import time
from mmdet.models.utils.efficientdet_utils import plot_one_box, get_index_label, STANDARD_COLORS, standard_to_bgr
from mmdet.models.utils.tracker.multitracker import JDETracker
from mmdet.models.utils.detect_post_process import simple_nms
from mmdet.models.utils.efficientdet_utils import _topk, tranpose_and_gather_feat, nms_torch, plot_one_box

DEVICE = 'cuda'

config_file = '/home/boden/Dev/ws/ws/BDNet_tracking/configs/bdnet/bdnet_tracking.py'
checkpoint_file = '/home/boden/Dev/ws/ws/BDNet_tracking/work_dirs/20210611/epoch_56.pth'

threshold = 0.4
iou_threshold = 0.2
obj_list = ['Sedan', 'Van', 'STruck', 'MTruck', 'LTruck', 'Bus','Traffic_Cone','Traffic_Bar','Traffic_Barrier']

color_list = standard_to_bgr(STANDARD_COLORS)
scale = torch.tensor([896/1418,384/640,896/1418,384/640],dtype=torch.float32).cuda()
config = mmcv.Config.fromfile(config_file)
height = config.height
width = config.width
# load config information
img_mean = config.img_norm_cfg['mean']
img_std = config.img_norm_cfg['std']
num_classes = len(config.classes)

# build the model from a config file and a checkpoint file
model = build_detector(config.model, test_cfg=config.test_cfg)
checkpoint = torch.load(checkpoint_file, map_location=torch.device('cuda'))

model.CLASSES = checkpoint['meta']['CLASSES']
state_dict = checkpoint['state_dict']
# strip prefix of state_dict
if list(state_dict.keys())[0].startswith('module.'):
    state_dict = {k[7:]: v for k, v in checkpoint['state_dict'].items()}
# load state_dict
if hasattr(model, 'module'):
    load_state_dict(model.module, state_dict, False, None)
else:
    load_state_dict(model, state_dict, False, None)

model.cfg = config  # save the config in the model for convenience
model.cuda()
model.eval()

def anchor_free_bbox_post_process(pred_heatmap, pred_wh, pred_off2d, scale):
    scale = torch.from_numpy(scale).cuda()
    down_ratio = 8
    batch, cat, height, width = pred_heatmap.size()
    pred_heatmap = pred_heatmap.detach().sigmoid_()
    wh = pred_wh.detach()
    off2d = pred_off2d.detach()

    # perform nms on heatmaps
    # heat = simple_nms(pred_heatmap)  # used maxpool to filter the max score
    heat = pred_heatmap
    topk = 100
    # (batch, topk)
    scores, inds, clses, ys, xs = _topk(heat, topk=topk)

    if pred_off2d is not None:
        off2d = tranpose_and_gather_feat(off2d, inds)
        off2d = off2d.view(batch, topk, 2)
        xs = (xs.view(batch, topk, 1) + off2d[:, :, 0:1]) * down_ratio
        ys = (ys.view(batch, topk, 1) + off2d[:, :, 1:2]) * down_ratio
    else:
        xs = xs.view(batch, topk, 1) * down_ratio
        ys = ys.view(batch, topk, 1) * down_ratio

    wh = tranpose_and_gather_feat(wh, inds)

    wh = wh.view(batch, topk, 2)
    wh = wh * down_ratio
    clses = clses.view(batch, topk, 1).float()
    scores = scores.view(batch, topk, 1)

    bboxes2d = torch.cat([xs - wh[..., [0]] / 2, ys - wh[..., [1]] / 2,
                          xs + wh[..., [0]] / 2, ys + wh[..., [1]] / 2], dim=2)

    result_list = []
    score_thr = 0.3
    for batch_i in range(bboxes2d.shape[0]):
        scores_per_img = scores[batch_i].squeeze()
        bboxes2d_per_img = bboxes2d[batch_i]
        labels_per_img = clses[batch_i]

        nms_idx = nms_torch(bboxes2d_per_img, scores_per_img, iou_threshold=0.5)

        bboxes2d_per_img = bboxes2d_per_img[nms_idx] / scale

        labels_per_img = labels_per_img[nms_idx]
        scores_per_img = scores_per_img[nms_idx]

        scores_keep = (scores_per_img > score_thr)

        scores_per_img = scores_per_img[scores_keep].unsqueeze(1)
        bboxes2d_per_img = bboxes2d_per_img[scores_keep]

        labels_per_img = labels_per_img[scores_keep]

        bboxes_per_img = torch.cat([bboxes2d_per_img.float(), scores_per_img.float(), labels_per_img.float()], dim=1)
        result_list.append(bboxes_per_img)
    result_list = torch.stack(result_list, dim=0)
    result_list = result_list.squeeze(0)
    result_list = result_list.cpu().numpy()
    return result_list

def anchor_based_bbox_post_process(det_list, scale):
    result_list = []
    center_list = []
    score_thr = 0.5
    for det in det_list:
        bbox, label, score = det['bbox'], det['label'], det['score']
        if score > score_thr:
            x1, y1, x2, y2 = bbox
            center_list.append(np.array([(x1+x2)/2, (y1+y2)/2]))
            x1 /= scale[0]
            y1 /= scale[1]
            x2 /= scale[0]
            y2 /= scale[1]
            result_list.append(np.array([x1, y1, x2, y2, score, label]))

    return np.array(result_list), np.array(center_list)

def anchor_base_feature_post_process(feature_heatmap, center_list):
    embedding_list = []
    if len(center_list) > 0:
        feature_heatmap = feature_heatmap.squeeze().permute(1,2,0).contiguous().cpu().numpy()
        center_list = center_list.astype(np.int)

        ct_int_x = center_list[:, 0]//8
        ct_int_y = center_list[:, 1]//8
        ct_res_x = center_list[:, 0]/8 - ct_int_x
        ct_res_y = center_list[:, 1]/8 - ct_int_y

        for x, y, res_x, res_y in zip(ct_int_x, ct_int_y, ct_res_x, ct_res_y):
            embedding = (1-res_x)*(1-res_y)*feature_heatmap[y, x] + (1-res_x)*(res_y)*feature_heatmap[y+1, x] \
                + (res_x)*(1-res_y)*feature_heatmap[y, x+1] + (res_x)*(res_y)*feature_heatmap[y+1, x+1]

            embedding_list.append(embedding)

    embedding_list = np.array(embedding_list)

    return embedding_list

def display(bbox, img, idx, imshow=False, imwrite=False,color=(0,0,0)):

    if bbox.shape[0] == 0:
        return img

    img = img.copy()

    for j in range(len(bbox)):
        x1, y1, x2, y2 = bbox[j,:4].astype(np.int)
        obj = obj_list[int(bbox[j,5])]
        score = float(bbox[j,4])
        plot_one_box(img, [x1, y1, x2, y2], label=obj,score=score,color=color)

    if imshow:
        cv2.imshow('img', img)
        cv2.waitKey(0)

    if imwrite:
        # cv2.imwrite(f'test/img_inferred_d{0}_this_repo_{i}.jpg', imgs[i])
        cv2.imwrite('/home/boden/Dev/ws/whz/BDPilot-merge/data/val/test_%d.jpg'%idx,img)

    return img

def get_color(idx):
    idx = idx * 3
    color = ((37 * idx) % 255, (17 * idx) % 255, (29 * idx) % 255)

    return color

def plot_tracking(image, tlwhs, obj_ids, scores=None, frame_id=0, fps=0., ids2=None):
    im = np.ascontiguousarray(np.copy(image))
    im_h, im_w = im.shape[:2]

    top_view = np.zeros([im_w, im_w, 3], dtype=np.uint8) + 255

    text_scale = max(1, image.shape[1] / 3200.)
    text_thickness = 1 if text_scale > 1.1 else 1
    line_thickness = max(1, int(image.shape[1] / 500.))

    radius = max(5, int(im_w/140.))
    cv2.putText(im, 'frame: %d fps: %.2f num: %d' % (frame_id, fps, len(tlwhs)),
                (0, int(15 * text_scale)), cv2.FONT_HERSHEY_PLAIN, text_scale, (0, 0, 255), thickness=2)

    for i, tlwh in enumerate(tlwhs):
        x1, y1, w, h = tlwh
        intbox = tuple(map(int, (x1, y1, x1 + w, y1 + h)))
        obj_id = int(obj_ids[i])
        id_text = '{}'.format(int(obj_id))
        if ids2 is not None:
            id_text = id_text + ', {}'.format(int(ids2[i]))
        _line_thickness = 1 if obj_id <= 0 else line_thickness
        color = get_color(abs(obj_id))
        cv2.rectangle(im, intbox[0:2], intbox[2:4], color=color, thickness=line_thickness)
        cv2.putText(im, id_text, (intbox[0], intbox[1]), cv2.FONT_HERSHEY_PLAIN, text_scale, (0, 0, 255),
                    thickness=2)
    return im

def display_bbox(bbox, img, start_index, color=(0,0,0)):
    if bbox.shape[0] == 0:
        return img

    for j in range(len(bbox)):
        x1, y1, x2, y2 = bbox[j,:4].astype(np.int)
        score = float(bbox[j,4])
        obj = obj_list[start_index + int(bbox[j,5])]
        plot_one_box(img, [x1, y1, x2, y2], label=obj,score=score,color=color)

    return img

# DEMO_DIR = '/home/boden/Dev/ws/whz/BDPilot-merge/data/validation_crop'
# DEMO_DIR = '/home/boden/Dev/ws/BDPilotDataset/Depth/save_00_calib_480'
# DEMO_DIR = '/home/boden/Dev/ws/BDPilotDataset/BDMerge/val_lane/scene_1'
DEMO_DIR = '/home/boden/Dev/ws/BDPilotDataset/BDMerge/val_lane/scene_2'
OUTPUT_PATH = '/home/boden/Dev/ws/ws/BDNet_tracking/data/output_0612_3'

IMG_LIST = os.listdir(DEMO_DIR)
IMG_LIST.sort()

tracker = JDETracker(conf_thres=0.3,mean=img_mean,std=img_std,num_classes=len(model.CLASSES))
scale = np.array([768/1418,384/640,768/1418,384/640])

for frame_id,DEMO_IMG in enumerate(IMG_LIST):
    img_name = DEMO_IMG
    DEMO_IMG = os.path.join(DEMO_DIR,DEMO_IMG)
    img = cv2.imread(DEMO_IMG)
    time1 = time.time()
    outputs = inference_detector(model, DEMO_IMG)
    dynamic_bbox_result, center_bbox_result = anchor_based_bbox_post_process(outputs['detect'], scale)
    static_bbox_result = anchor_free_bbox_post_process(outputs['static_detect']['hm'], outputs['static_detect']['wh'], outputs['static_detect']['off_2d'], scale)
    feature_bbox_result = anchor_base_feature_post_process(outputs['track']['embedding'], center_bbox_result)

    online_targets = tracker.update(dynamic_bbox_result, feature_bbox_result)
    online_tlwhs = []
    online_ids = []
    for t in online_targets:
        tlwh = t.tlwh
        tid = t.track_id
        online_tlwhs.append(tlwh)
        online_ids.append(tid)
    img = plot_tracking(img, online_tlwhs, online_ids, frame_id=frame_id, fps=1/(time.time()-time1))

    img = display_bbox(static_bbox_result, img, 6, color=(18,87,220))

    # for bbox in dynamic_bbox_result:
    #     cv2.rectangle(img, (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])), (255, 0, 0), thickness=2)

    cv2.imwrite(os.path.join(OUTPUT_PATH, img_name), img)


from typing import Tuple, List
from openapi_server.annotator.load_data import AnnotationSet

PERSON_TYPES = {'PATIENT', 'DOCTOR'}

Tokens = List[str]
Label = int
Labels = List[int]
Span = Tuple[int, int]
Spans = List[Span]

def label_token(token: str, span: Span, annotation_set: AnnotationSet) -> Label:
    """Return majority annotation type for a given span
    """
    start, end = span

    # Count annotated characters
    overlap = 0
    for annotation in annotation_set:
        if annotation['TYPE'] in PERSON_TYPES:
            overlap += max(
                min(end, annotation['end']) - max(start, annotation['start']),
                0
            )

    # Return 1 if most of the characters in the range are in a person
    # annotation, else 0.
    span_length = end - start
    if overlap > (span_length / 2) and any(c.isalpha() for c in token):
        return 1
    else:
        return 0

def label_tokens(tokens: Tokens, spans: Spans,
                 annotation_set: AnnotationSet) -> Labels:
    """Take list of spans and iterable of annotations; use those annotations to
    make list of labels parallel to list of spans
    """
    return [label_token(token, span, annotation_set) for token, span in
            zip(tokens, spans)]


#Time : O(N*2^N)
#Space: O(2^N)
# Dynamic Programming
#https://leetcode.com/problems/subsets/
def subsets(nums):
        output = [[]]
        for i in nums:
            output.append([i])
        indexDict = {val:index for index,val in enumerate(nums)}
        i = 1
        while i <= len(output)-len(nums):
            last = output[i][-1]
            for j in nums[indexDict[last]+1:]:
                output.append(output[i]+[j])
            i+=1
        return output
print(subsets([1,2,3,4]))


import json
import os
import time
import shutil
from tqdm import tqdm
from addict import Dict
import logging
import argparse

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class COCOConverter():
    """
    Converts labels from COCO format to YOLO (seg or detection)

    Args:
         coco_annot_path (str): COCO annotation path to be converted
         converted_label_path (str): Label path for converted labels to be saved
         image_path (str): Image directory path where images are located
         conversion_mode (str): Label output mode to decide whether as segmentation or detection
    """

    def __init__(self, coco_annot_path: str, converted_label_path: str, image_path: str, conversion_mode: str):
        super().__init__()
        self.coco_annot_path = coco_annot_path
        self.converted_label_path = converted_label_path
        self.image_path = image_path
        self.conversion_mode = conversion_mode

    def from_coco_to_yolo(self):
        with open(self.coco_annot_path, 'r') as json_file:
            data_dict = json.load(json_file)

        if os.path.exists(self.converted_label_path):
            print(f"Saving to {self.converted_label_path}")

        else:
            print(f"Couldn't find a file to save in given path! Creating one...")
            os.mkdir(self.converted_label_path)

        data = Dict(data_dict)
        image_info = data["images"]
        annotations = data["annotations"]
        class_ids = []

        start_time = time.time()
        for i_info in tqdm(image_info):
            lines = []

            for anno in annotations:
                if i_info['id'] == anno['image_id']:
                    if (anno["category_id"] - 1) in class_ids:
                        class_id = class_ids.index((anno['category_id'] - 1))
                    else:
                        class_ids.append((anno["category_id"] - 1))
                        class_id = len(class_ids) - 1

                    line = str(class_id)
                    line += " "

                    if self.conversion_mode == "detection":

                        try:
                            x, y, w, h = anno['bbox']
                            x_centre = (x + (x + w)) / 2
                            y_centre = (y + (y + h)) / 2
                            line += str(x_centre / i_info['width']) + " " + str(y_centre / i_info['height']) + " " + str(
                                w / i_info['width']) + " " + str(h / i_info['height'])
                        except:
                            continue

                        lines.append(line)

                    elif self.conversion_mode == "segmentation":

                        try:
                            for idx, seg in enumerate(anno["segmentation"][0]):
                                if idx % 2 == 0:
                                    line += str(seg / i_info["width"])
                                else:
                                    line += str(seg / i_info["height"])

                        except:
                            continue

                        lines.append(line)

                    else:
                        print("You have entered an invalid conversion mode! Please choose 'detection' or 'segmentation' instead.")

            label_name = self.converted_label_path + "/" + i_info['file_name'].split('.')[0] + ".txt"
            with open(label_name, 'w') as f:
                for line in lines:
                    f.write(line)
                    f.write('\n')

        end_time = time.time()
        print(f"Process Done! \nSpent time: {end_time - start_time} seconds")

    # def train_test_valid_split(self, label_path: str, train_dest_path: str, test_dest_path: str, valid_dest_path: str):
    def train_test_valid_split(self, image_path = None):

        if image_path is not None:
            self.image_path = image_path

        start_time = time.time()
        train_dest_path = self.converted_label_path + "/" + "train"
        test_dest_path = self.converted_label_path + "/" + "test"
        valid_dest_path = self.converted_label_path + "/" + "valid"

        if os.path.exists(train_dest_path) and os.path.exists(test_dest_path) and os.path.exists(valid_dest_path):
            print('Paths already exist! No need to create them!')

        else:
            print("Couldn't find given paths! Creating...")
            os.mkdir(train_dest_path)
            os.mkdir(test_dest_path)
            os.mkdir(valid_dest_path)
            os.mkdir(train_dest_path + "/" + "images")
            os.mkdir(train_dest_path + "/" + "labels")
            os.mkdir(test_dest_path + "/" + "images")
            os.mkdir(test_dest_path + "/" + "labels")
            os.mkdir(valid_dest_path + "/" + "images")
            os.mkdir(valid_dest_path + "/" + "labels")

        images = [i for i in os.listdir(self.image_path) if i.endswith(".jpeg") or i.endswith(".jpg") or i.endswith(".png")]
        train_images = images[:int(0.80 * len(images))]
        validation_images = images[int(0.80 * len(images)):int(0.90 * len(images))]
        test_images = images[int(0.90 * len(images)):]
        print(
            f"Dataset was seperated Successfully! \nTotal Amount of train images is {len(train_images)} \nTotal Amount of test images is {len(test_images)} \nTotal Amount of validation images is {len(validation_images)}")
        print(f"Saving Seperated Images...")

        for image in tqdm(images):
            if image in train_images:
                shutil.copyfile(self.image_path + "/" + image, train_dest_path + "/images/" + image)
                shutil.copyfile(self.converted_label_path + "/" + image[:-3].split('.')[0] + ".txt",
                                train_dest_path + "/labels/" + image[:-3].split('.')[0] + ".txt")
            elif image in test_images:
                shutil.copyfile(self.image_path + "/" + image, test_dest_path + "/images/" + image)
                shutil.copyfile(self.converted_label_path + "/" + image[:-3].split('.')[0] + ".txt",
                                test_dest_path + "/labels/" + image[:-3].split('.')[0] + ".txt")
            elif image in validation_images:
                shutil.copyfile(self.image_path + "/" + image, valid_dest_path + "/images/" + image)
                shutil.copyfile(self.converted_label_path + "/" + image[:-3].split('.')[0] + ".txt",
                                valid_dest_path + "/labels/" + image[:-3].split('.')[0] + ".txt")

        end_time = time.time()
        print(f"Seperated Images are Saved and the process is Finished! \nSpent Time: {end_time - start_time} seconds")

if __name__ == "__main__":
    # converter = COCOConverter(coco_annot_path = '/home/visio-ai/Desktop/task162/annotations/instances_default.json', image_path = 'task162/images/', converted_label_path = '/home/visio-ai/Desktop/project-workspace/converter_tool/labels2', conversion_mode = "detection")
    # converter.from_coco_to_yolo_detect()
    # converter.train_test_valid_split()
    parser = argparse.ArgumentParser(description = "Converter Tool from COCO to Yolo segmentation or detection.")
    parser.add_argument('--coco-annot-path', '--coco-anno-path', dest = "coco_annot_path", required = True, type = str, help = "Path to COCO annotations")
    parser.add_argument('--image-path', '--img-path', dest = "image_path", required = True, type = str, help = "Path to images")
    parser.add_argument('--converted-label-path', '--label-output-path', dest = "converted_label_path", required = True, type = str, help = "Path to save converted labels.")
    parser.add_argument('--conversion-mode', '--conv-mode', dest = "conversion_mode", required = True, type = str, help = "Mode to choose whether to convert yolo segmentation or yolo detection")
    args = parser.parse_args()

    converter = COCOConverter(
        coco_annot_path = args.coco_annot_path,
        image_path = args.image_path,
        converted_label_path = args.converted_label_path,
        conversion_mode = args.conversion_mode
    )

    converter.from_coco_to_yolo()
    # TODO: Add argument to control splitting as well.


import csv
from django.core.management import BaseCommand
from labor.models import Question, Report, Checklist, Answer
from main.models import Company

class Command(BaseCommand):
    help = 'Load a questions csv file into the database'

    def add_arguments(self, parser):
        parser.add_argument('--path', type=str)

    def handle(self, *args, **kwargs):
        path = kwargs['path']
        with open(path, 'rt') as f:
            reader = csv.reader(f, delimiter=';')

            for row in reader:
                # print(row[1])
                report = Report.objects.get(id = 6)
                Question.objects.create(
                    title='2022 ' + row[1],
                    comment=row[2],
                    report=report
                )


import matplotlib.pyplot as plt
import csv

# steg 1 lese filen
with open("lab11\Akvakulturregisteret.csv", "rt", encoding='iso-8859-1') as f:
    tabell = list(csv.reader(f, delimiter=';'))

# steg 2: lage 2D liste + headers
headers = tabell[1]
colname_to_i = {}
# funksjon som tar inn en string og gir plassen til den stringen i listen
for i in range(len(headers)):
    colname = headers[i]
    colname_to_i[colname] = i
data = tabell[2:]

# steg filtrere tabell slik at vi kun har ferskvann og saltvann

def filter_data(data, must_match_value,col):
    filtered_data = []
    for row in data:
    # hvis row er ferskvann, legg til i fresh_water_data
        water_environment = row[col]
        if water_environment == must_match_value:
            filtered_data.append(row)
    return filtered_data

fresh_water_data = filter_data(data, "FERSKVANN", colname_to_i["VANNMILJØ"])
salt_water_data = filter_data(data, "SALTVANN", colname_to_i["VANNMILJØ"])

# steg 3: finne x'er og y'er for posisjonene
xs_salt = list()
ys_salt = list()
for row in salt_water_data:
    # finn rad med x-koordinat, legg til i xs
    i = colname_to_i["N_GEOWGS84"]
    x = float(row[i])
    xs_salt.append(x)
    # finne kolonnen med y-koordinat, legg til i ys
    i = colname_to_i["Ø_GEOWGS84"]
    y = float(row[i])
    ys_salt.append(y)
plt.scatter(x = ys_salt, y = xs_salt, s=10, alpha=0.2, label="saltvann")

xs_fresh = list()
ys_fresh = list()
for row in fresh_water_data:
    # finn rad med x-koordinat, legg til i xs
    i = colname_to_i["N_GEOWGS84"]
    x = float(row[i])
    xs_fresh.append(x)
    # finne kolonnen med y-koordinat, legg til i ys
    i = colname_to_i["Ø_GEOWGS84"]
    y = float(row[i])
    ys_fresh.append(y)

plt.scatter(x = ys_fresh, y = xs_fresh, alpha=0.2, s=10 ,label="ferskvann")
plt.legend()
plt.show()


from django.conf.urls import url, include
from .views import index, professor_view, grupo_view, projeto_view

projeto_patterns = [
    url(r'^projeto/new$', projeto_view.criar_projeto, name='criar_projeto'),
    url(r'^projeto/(?P<pk_proj>\d+)/', include([
        url(r'^detail/$', projeto_view.mostrar_projeto, name='mostrar_projeto'),
        url(r'^edit/$', projeto_view.atualizar_projeto, name='atualizar_projeto'),
        url(r'^delete/$', projeto_view.excluir_projeto, name='excluir_projeto'),
    ])),

]

grupo_patterns = [
    url(r'^grupo/new$', grupo_view.criar_grupo, name='criar_grupo'),
    url(r'^grupo/(?P<pk_grupo>\d+)/', include([
        url(r'^detail/$', grupo_view.mostrar_grupo, name='mostrar_grupo'),
        url(r'^edit/$', grupo_view.atualizar_grupo, name='atualizar_grupo'),
        url(r'^delete/$', grupo_view.excluir_grupo, name='excluir_grupo'),
        url(r'^add_prof/$', grupo_view.adicionar_professor_ao_grupo, name='adicionar_professor_ao_grupo'),
    ])),
    url(r'^grupo/(?P<pk_grupo>\d+)/', include(projeto_patterns)),

]

urlpatterns = [
    url(r'^$', index.mostrar, name='index'),

    url(r'^professor/', include('django.contrib.auth.urls')),

    # urls from professor_view
    url(r'^professor/detail/$', professor_view.mostrar_professor, name='mostrar_professor'),
    url(r'^professor/(?P<pk_prof>\d+)/', include([
        url(r'^edit/$', professor_view.atualizar_professor, name='atualizar_professor'),
        #url(r'^delete/$', professor_view.excluir_professor, name='excluir_professor'),
    ])),
    url(r'^professor/(?P<pk_prof>\d+)/', include(grupo_patterns)),

    url(r'^professor/list$', professor_view.listar_professor, name='listar_professor'),

    # url do botão buscar da tela inicial
    url(r'^busca/$', index.buscar_oportunidade, name='buscar_oportunidade'),

    url(r'^projeto/(?P<pk_proj>\d+)/', projeto_view.ver_projeto, name='ver_projeto'),

    # urls from grupo_view
    url(r'^grupo/list$', grupo_view.listar_grupo, name='listar_grupo'),

    # urls from projeto_view
    url(r'^projeto/list$', projeto_view.listar_projeto, name='listar_projeto'),
]


#!/usr/bin/python
import platform
import subprocess
from time import sleep
from tkinter import *
from tkinter import messagebox

addresses = {
             '10.252.50.150': (185, 300, 'plc'),
             '10.252.50.151': (185, 218, 'hmi'),
             '10.252.50.152': (320, 300, 'icam'),
             '10.252.50.153': (190, 125, 'serv'),
             '10.252.50.154': (320, 125, 'serv'),
             '10.252.50.155': (388, 125, 'bcam'),
             '10.252.50.156': (545, 125, 'bcam'),
             '10.252.50.157': (455, 125, 'hmi'),
             '10.252.50.158': (185, 555, 'nj'),
             '10.252.50.190': (695, 555, 'pc'),
             '10.252.50.191': (805, 455, 'scam'),
             '10.252.50.192': (635, 455, 'scam'),
             '10.252.50.193': (800, 555, 'lprnt'),
             '10.252.50.194': (630, 555, 'lprnt'),
             '10.252.50.1': (675, 165, 'gway'),
             '10.252.1.34': (785, 130, 'db')
             }
hosts = []
stopped = False

class Host:
    def __init__(self, ip, data):
        self.ip = ip
        self.status = 'down'
        self.image_x = data[0]
        self.image_y = data[1]
        self.type = data[2]
        self.image = 'images/' + str(self.type) + str(self.status) + ".gif"
        self.filename = ''

    def update_image(self):
        self.image = 'images/' + str(self.type) + str(self.status) + ".gif"

    def update_filename(self, filename):
        self.filename = filename

def ping(host):
    # Update host status if not current
    response = ping_it(host.ip)
    if response:
        if host.status == 'down':
            host.status = 'up'
            host.update_image()
    else:
        if host.status == 'up':
            host.status = 'down'
            host.update_image()

def ping_it(host):
    # Determine OS and set ping string parameters
    ping_str = "-n 1" if platform.system().lower() == "windows" else "-c 1"
    # Ping host and return if active
    try:
        if subprocess.check_call("ping " + ping_str + " " + host, stdout=subprocess.PIPE) == 0:
            return True
    except:
        return False

def on_closing():
    # Stop drawing objects and destroy window
    global stopped
    if messagebox.askokcancel("Quit", "Do you want to quit?"):
        stopped = True
        top.destroy()

# Build window, canvas, background and static images
top = Tk()
top.wm_title("Ethernet Device Status")
top.protocol("WM_DELETE_WINDOW", on_closing)
top.resizable(0, 0)
C = Canvas(top, bg="white", height=600, width=900)
C.pack()
b_ground = PhotoImage(file='images/background.gif')
C.create_image(0, 0, anchor=NW, image=b_ground)
monitor = PhotoImage(file='images/terminal.gif')
C.create_image(252, 125, anchor=SW, image=monitor)
switch = PhotoImage(file='images/switchup.gif')
C.create_image(435, 215, anchor=SW, image=switch)
C.create_image(690, 360, anchor=SW, image=switch)
C.create_image(435, 425, anchor=SW, image=switch)
# Spawn Host objects from static dictionary and set all default states to 'down'
for address in addresses:
    address = Host(address, addresses[address])
    hosts.append(address)
for host in hosts:
    host.update_filename(PhotoImage(file=host.image))
    C.create_image(host.image_x, host.image_y, anchor=SW, image=host.filename)

# Ping each host (delay 0.5 between to lighten network load) and update host status and GUI
index = 0
while not stopped:
    sleep(0.5)
    host = hosts[index]
    ping(host)
    host.update_filename(PhotoImage(file=host.image))
    if not stopped:
        C.create_image(host.image_x, host.image_y, anchor=SW, image=host.filename)
    index += 1
    index %= len(hosts)
    top.update_idletasks()
    top.update()


from datetime import datetime
import hashlib
import random
import re
import string

from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse

def validate_phone(phone=''):
	pattern =r'^\+(?:[0-9] ?){6,14}[0-9]$'
	s=re.match(pattern,phone)
	if s is not None:
		return True

def random_text(p=5):
	return ''.join(random.sample(string.ascii_letters+string.digits,p))

def invalid_str(value):
	# This checks if a string contains special chars or not
	for i in string.punctuation:
		if i in value:
			return True
	return False

def username_gen(n):
    # This will generate a text in this format 'user<n random digits>'
    return 'user'+ ''.join(random.sample(string.digits,n))

def get_usable_name(instance, profile, name=None):
	if not name:
		name = username_gen(5)

    # Check if the name exists in the Profile table
	exists=profile.objects.filter(username=name).exists()
	if exists:
		return get_usable_name(instance, profile, username_gen(5))
	return name

def random_otp(p=6):
	return ''.join(random.sample(string.digits,p))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PROCESSED FILE VERSION V1.0 built on multiPlot v1.2

multiPlot version v1.2 cleans up to make Pi and Windows use easier

multiPlot version v1.1 adds sunrise sunset times for location of lat long in first file
requires suntime library https://github.com/SatAgro/suntime

multiPlot version v1.0 plots up to 10 PSWS "rawdata" files and average value
modified from WWV_plt2.py @authors dkazdan jgibbons
expects a homepath directory with processed files in homepath or subdirs
leaves plot in Mplot directory
plots files from multiple subdir to compare node results
plot title from first file

windows version hardcoded homepath directory location
for Pi comment out windows homepath and uncomment Pi  lines

uses WWV_utility2.py
Bob Benedict, KD8CGH, 7/29/2021

create text file "Processfiles.txt" in homepath directory
  keyword ('Doppler' or 'Power')
  keyword ('Average' or 'No Average')
  subdir/filename1
  subdir/filename2
  filename3
  ...

Note - expects all data from the same beacon

if found 'Doppler' will plot Doppler shifts, else will plot Power
if found "Average" will add average plot

loads file names in list
plots first file and create axis and title info
plots rest in loop as curves on first plot
calculates average and plots
leaves plotfile in Mplot directory

uses
WWV_utility2.py
20 February 2020
WWV utility file
Routines and classes used in WWV file management and graphing
David Kazdan, AD8Y
John Gibbons, N8OBJ - mods to plot header 2/3/20

"""

#import os # uncomment for pi
from os import path
import sys
import csv
import math
#import shutil  # uncomment for pi
#from datetime import date, timedelta  # uncomment for pi
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import filtfilt, butter
import datetime
from suntime import Sun
#import subprocess
from WWV_utility2 import time_string_to_decimals
from Beacon import readheader

'''  #uncomment for Pi
# ~ points to users home directory - usually /home/pi/
homepath = os.path.expanduser('~')

# imbed the trailing / in the home path
homepath = homepath + "/PSWS/"

#comment out windows homepath
'''

homepath = "E:\\Documents\\PSWS\\"  # set your windows path, comment out for Pi

names = open(homepath+"Processfiles.txt","r")

PlotTarget = names.readline()
PlotTarget = PlotTarget.strip('\n')
PlotAverage = names.readline()
if PlotAverage[0:7] == 'Average':
    doavg=True
else:
    doavg=False

Filenames=['a' for a in range (10)]
Filedates=['a' for a in range (10)]
#PrFilenames=['a' for a in range (10)]
Nodenum=['a' for a in range (10)]
Beaconname=['a' for a in range (10)]
beaconfreq=np.zeros(10)

nfiles = 0  # holder for number of files to plot

colors=['b','g','r','c','m','y','tab:orange','tab:gray','tab:purple','tab:brown']

while True:
    temp = names.readline()
    if  len(temp) <= 1:
        break
    Filenames[nfiles]=temp.strip("\n")
    fdate = Filenames[nfiles].find("/") # find start of filename after subdirectory
    if fdate==-1 :  # if / not found try \
        fdate = Filenames[nfiles].find("\\")
#    print(" position ",fdate)
    # if neith / nor \ found file is in homepath, fdate=-1, following assignment still works
    Filedates[nfiles]=temp[fdate+1:fdate+11]
    nfiles=nfiles + 1

#print(Filenames[0:9])
#print(Filedates[0:9])
print('number of files',nfiles)
if nfiles > 10 :
    print('10 file limit')
    sys.exit(0)

PROCESSDIR = homepath

#saved plot directrory
PlotDir = homepath + 'Mplot/'

'''
read first file
'''
PrFilenames=(PROCESSDIR + Filenames[0])

if (path.exists(PrFilenames)):
    print('File ' + PrFilenames + ' found!\nProcessing...')
else:
    print('File ' + PrFilenames + ' not available.\nExiting disappointed...')
    sys.exit(0)

with open(PrFilenames, 'r') as dataFile:
    dataReader=csv.reader(dataFile)
    data = list(dataReader)
    Header = data.pop(0)

#    print('return',readheader(0,Header))
    Nodenum[0], Beaconname[0], beaconfreq[0], Lat, Long = readheader(Header)
#    print('\n returned ', Nodenum[0], Beaconname[0], beaconfreq[0], Lat, Long, '\n')

''' ###########################################################################
'''
print('Ready to start processing records')

# Prepare data arrays
hours=[[],[],[],[],[],[],[],[],[],[]]
Doppler=[[],[],[],[],[],[],[],[],[],[]]
#Vpk=[[],[],[],[],[],[],[],[],[],[]]
Power_dB=[[],[],[],[],[],[],[],[],[],[]] # will be second data set, received power 9I20
filtDoppler=[[],[],[],[],[],[],[],[],[],[]]
filtPower=[[],[],[],[],[],[],[],[],[],[]]

LateHour=False # flag for loop going past 23:00 hours

# eliminate all metadata saved at start of file - Look for UTC (CSV headers)
#find first row of data0
FindUTC = 0

for row in data:
    if (FindUTC == 0):
        #print('looking for UTC - row[0] =',row[0])
        if (row[0] == 'UTC'):
            FindUTC = 1
#            print('UTC found =', row[0])
    else:
        #print('Processing record')
        decHours=time_string_to_decimals(row[0])
#        if (NewHdr != 'New'):
#            if (calccnt  < 101):
#                calcnt = calcnt+1
#                freqcalc = freqcalc + (float(row[1])/100)
#        if decHours > 23:
#            LateHour=True # went past 23:00 hours
        if (not LateHour) or (LateHour and (decHours>23)): # Otherwise past 23:59:59.  Omit time past midnight.
            hours[0].append(decHours) # already in float because of conversion to decimal hours.
            Doppler[0].append(float(row[1])-beaconfreq[0]) # frequency offset from col 2
#            Vpk[0].append (float(row[2])) # Get Volts peak from col 3
            Power_dB[0].append (20*math.log10(float(row[2]))) # log power from col 4

#print('nf ',0,'len hours',len(hours[0]))

###############################################################################################
# Find max and min of Power_dB for graph preparation:
min_power=np.amin(Power_dB[0]) # will use for graph axis min
max_power=np.amax(Power_dB[0]) # will use for graph axis max

min_Doppler=np.amin(Doppler[0]) # min Doppler
max_Doppler=np.amax(Doppler[0]) # max Doppler

print('\nDoppler min: ', min_Doppler, '; Doppler max: ', max_Doppler)
print('dB min: ', min_power, '; dB max: ', max_power)

#%% Create an order 3 lowpass butterworth filter.
# This is a digital filter (analog=False)
# Filtering at .01 to .004 times the Nyquist rate seems "about right."
# The filtering argument (Wn, the second argument to butter()) of.01
# represents filtering at .05 Hz, or 20 second weighted averaging.
# That corresponds with the 20 second symmetric averaging window used in the 1 October 2019
# Excel spreadsheet for the Festival of Frequency Measurement data.
#FILTERBREAK=.005 #filter breakpoint in Nyquist rates. N. rate here is 1/sec, so this is in Hz.
FILTERBREAK=0.005 #filter breakpoint in Nyquist rates. N. rate here is 1/sec, so this is in Hz.
FILTERORDER=6
b, a = butter(FILTERORDER, FILTERBREAK, analog=False, btype='low')
#print (b, a)
#%%
# Use the just-created filter coefficients for a noncausal filtering (filtfilt is forward-backward noncausal)

filtDoppler[0] = filtfilt(b, a, Doppler[0])

filtPower[0] = filtfilt(b, a, Power_dB[0])

##################################################################################################
# sunrise sunset times in UTC
sun = Sun(float(Lat), float(Long))

UTC_DT=Filedates[0]
print(UTC_DT)
SDAY=int(UTC_DT[8:10])
SMON=int(UTC_DT[5:7])
SYEAR=int(UTC_DT[0:4])
sdate = datetime.date(SYEAR, SMON, SDAY)
today_sr = sun.get_sunrise_time(sdate)
today_ss = sun.get_sunset_time(sdate)
#print(today_sr)
srh=int(format(today_sr.strftime('%H')))
srm=int(format(today_sr.strftime('%M')))
srx=srh+srm/60
ssh=int(format(today_ss.strftime('%H')))
ssm=int(format(today_ss.strftime('%M')))
ssx=ssh+ssm/60

# set up x-axis with time
fig = plt.figure(figsize=(19,10)) # inches x, y with 72 dots per inch
ax = fig.add_subplot(111)
ax.set_xlabel('UTC Hour')
ax.set_xlim(0,24) # UTC day
ax.set_xticks([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24], minor=False)

# plot first curve
if (PlotTarget == 'Doppler'):
    ax.plot([srx,srx],[-1,1],'y',label='sunrise',linestyle='dashed')
    ax.plot([ssx,ssx],[-1,1],'b',label='sunset',linestyle='dashed')
    ax.plot(hours[0], filtDoppler[0], colors[0],label=Beaconname[0] +' '+Nodenum[0]+' '+Filedates[0]) # color k for black
    ax.set_ylabel('Doppler shift, Hz '+ Filedates[0])
    ax.set_ylim([-1.0, 1.0]) # -1 to 1 Hz for Doppler shift
    plt.axhline(y=0, color="gray", lw=1) # plot a zero freq reference line for 0.000 Hz Doppler shift

else:
    ax.plot([srx,srx],[-90,0],'y',label='sunrise',linestyle='dashed')
    ax.plot([ssx,ssx],[-90,0],'b',label='sunset',linestyle='dashed')
    ax.plot(hours[0], filtPower[0], colors[0],label=Beaconname[0] +' '+ Nodenum[0]+' '+Filedates[0]) # color k for black
    ax.set_ylabel('Power, dB '+ Filedates[0])
    ax.set_ylim(-90, 0)

# add grid lines - RLB
plt.grid(axis='both')

'''
######################################################################
read and plot files loop
'''

for nf in range(1, nfiles):
# splot second curve
# read second file, skip header
    print('process file ',nf, Filenames[nf])
    PrFilenames=(PROCESSDIR + Filenames[nf])
    with open(PrFilenames, 'r') as dataFile: # read second set
        dataReader=csv.reader(dataFile)
        data = list(dataReader)
        Header = data.pop(0)
        Nodenum[nf]= Header[2]
    FindUTC = 0

    Nodenum[nf], Beaconname[nf], beaconfreq[nf], Lat, Long = readheader(Header)
#    print('\n returned ', Nodenum[nf], Beaconname[nf], beaconfreq[nf], Lat, Long, '\n')

    for row in data:
        if (FindUTC == 0):
            #print('looking for UTC - row[0] =',row[0])
            if (row[0] == 'UTC'):
                FindUTC = 1
#            print('UTC found =', row[0])
        else:
            decHours=time_string_to_decimals(row[0])
            hours[nf].append(decHours) # already in float because of conversion to decimal hours.
            Doppler[nf].append(float(row[1])-beaconfreq[nf]) # frequency offset from col 2
#            Vpk[nf].append (float(row[2])) # Get Volts peak from col 3
#            Power_dB[nf].append (float(row[4])) # log power from col 4
            Power_dB[nf].append (20*math.log10(float(row[2]))) # log power
# filter  file data
    filtDoppler[nf] = filtfilt(b, a, Doppler[nf])
    filtPower[nf] = filtfilt(b, a, Power_dB[nf])

    if (PlotTarget == 'Doppler'):
        ax.plot(hours[nf], filtDoppler[nf], colors[nf], label=Beaconname[nf] +' '+ Nodenum[nf]+' '+Filedates[nf]) # color k for black
    else:
        ax.plot(hours[nf], filtPower[nf], colors[nf], label=Beaconname[nf] +' '+ Nodenum[nf]+' '+Filedates[nf]) # color k for black

'''
#############################################################################
end for read and plot loop, start average
'''
# find shortest data set, limit average to that
if doavg :
    al=1000000
    ak=0

    for k in range(nfiles):
        templ=len(hours[k])
        if templ < al:
            al=templ
            ak=k

    avg=[]

    if (PlotTarget == 'Doppler'):
        for i in range(al):
            temp=0.0
            for j in range(nfiles):
                temp=temp+filtDoppler[j][i]
            temp=temp/nfiles
            avg.append(temp)
    else:
        for i in range(al):
            temp=0.0
            for j in range(nfiles):
                temp=temp+filtPower[j][i]
            temp=temp/nfiles
            avg.append(temp)

    #print('avg',len(avg))

    ax.plot(hours[ak], avg, 'k', label='Average') # color k for black

'''
end average
'''
ax.legend(loc="lower right",  frameon=False)

# Create Plot Title
plt.title(' Grape Data Plot')
#plt.title(beaconlabel + ' Grape Data Plot\nNode:  ' + node + '     Gridsquare:  '+ GridSqr + '\nLat= ' + Lat + '    Long= ' + Long + '    Elev= ' + Elev + ' M\n' )
# Create Plot File Nam
#GraphFile = yesterdaystr + '_' + node + '_' + RadioID + '_' + GridSqr + '_' + beacon + '_graph.png'
GraphFile = 'multi'+ PlotTarget + '.png'
PlotGraphFile = PlotDir + GraphFile

# create plot
#plt.savefig(PlotDir + yesterdaystr + '_' + node + '_' +  GridSqr + '_' +  RadioID + '_' +  beacon + '_graph.png', dpi=250, orientation='landscape')
plt.savefig(PlotDir + GraphFile, dpi=250, orientation='landscape')
# =============================================================================

print('Plot File: ' + GraphFile + '\n')  # indicate plot file name for crontab printout

#-------------------------------------------------------------------
print('Exiting python multi plot program gracefully')


# Define a class as 'student'
class student:
    def __init__(self, USN=' ', name=' ', age=0):
        self.USN=USN
        self.name=name
        self.age=age
    def getStudent(self):
        self.name = input("Enter the Name: ")
        self.usn = input("Enter the USN: ")
        self.age = input("Enter the Age: ")
        self.gender = input("Enter the Gender: ")

# Define a class as 'test' and inherit base class 'student'
class Subject(student):
    def __init__(self, sem=0,Var1=0, Var2=0, Var3=0, Var4=0, Var5=0):
        self.Var1=Var1
        self.Var2=Var2
        self.Var3=Var3
        self.Var4=Var4
        self.Var5=Var5
        self.sem = sem
    # Method
    def getMarks(self):
        self.sem = input("Enter the Semester: ")
        print("Enter the marks of the respective subjects")
        self.subject= input("Enter the Subject Name ")
        self.Var1 = int(input("Enter the Marks of %s "%(self.subject)))
        self.subject= input("Enter the Subject Name ")
        self.Var2 = int(input("Enter the Marks of %s "%(self.subject)))
        self.subject= input("Enter the Subject Name ")
        self.Var3 = int(input("Enter the Marks of %s "%(self.subject)))
        self.subject= input("Enter the Subject Name ")
        self.Var4 = int(input("Enter the Marks of %s "%(self.subject)))
        self.subject= input("Enter the Subject Name ")
        self.Var5 = int(input("Enter the Marks of %s "%(self.subject)))

# Define a class as 'marks' and inherit derived class 'test'
class Results(Subject):
    # Method
    def display_Results(self):
        print("\n\nName: ",self.name)
        print("\n\nName: ",self.usn)
        print("Age: ",self.age)
        print("Gender: ",self.gender)
        print("Study in: ",self.sem)
        Total_Marks = self.Var1+self.Var2+self.Var3+self.Var4+self.Var5
        print("Total Marks: ",Total_Marks)
        self.percentage = ((Total_Marks/500)*100)
        print("Percentage of %s in Semester %s is %s Percent  "%(self.name,self.sem,self.percentage))

m1 = Results()
# Call base class method 'getStudent()'
m1.getStudent()
# Call first derived class method 'getMarks()'
m1.getMarks()
# Call second derived class method 'display()'
m1.display_Results()


# importing the modules
import PyPDF2
import pyttsx3

pdf_book = open('name.pdf', 'rb')
reading_pdf = PyPDF2.PdfReader(pdf_book)
pdf_pages =    len(reading_pdf.pages)

pdf_speaker = pyttsx3.init()
choose_page =   reading_pdf.pages[0]
pdf_text = choose_page.extract_text()
pdf_speaker.say(pdf_text)
pdf_speaker.runAndWait()


from cProfile import label
import os
import math
import matplotlib
import matplotlib.pyplot as plt
from numpy import average

def calculate_item(array_ref,array_res,n):
    ref = []
    res = []
    for index,_ in enumerate(array_ref):
        if index <= len(array_ref) - n:
            temp = []
            for i in range(n):
                temp.append(array_ref[index+i])
            ref.append(temp)

    for index,_ in enumerate(array_res):
        if index <= len(array_res) - n:
            temp = []
            for i in range(n):
                temp.append(array_res[index+i])
            res.append(temp)

    find = 0
    for item in res:
        if item in ref:
            find+=1

    result = find/len(res)
    if result == 0:
        return 1/len(res)
    else:
        return result

def calculate_bleu(reference,result,N):
    reference_array = reference.split()
    result_array = result.split()
    if len(result_array) > len(reference_array):
        bp = 1
    else:
        bp = math.exp(1-len(reference_array)/len(result_array))

    ssum = 0
    for i in range(N):
        ssum += math.log(calculate_item(reference_array,result_array,i+1))

    return bp * math.exp(1/N * ssum)

google = []
baidu = []
sougou = []

def main():
    with open('reference.txt','r',encoding='utf8') as f_refer:
        with open('google_rst.txt','r',encoding='utf8') as f_google:
            refer = f_refer.readline()
            google_rst = f_google.readline()
            print(refer)
            while refer:
                google.append(calculate_bleu(refer, google_rst, 4))
                refer = f_refer.readline()
                google_rst = f_google.readline()
        f_refer.close()
        f_google.close()
    with open('reference.txt', 'r', encoding='utf8') as f_refer:
        with open('baidu_rst.txt','r',encoding='utf8') as f_baidu:
            refer = f_refer.readline()
            baidu_rst = f_baidu.readline()
            print(refer)
            while refer:
                baidu.append(calculate_bleu(refer, baidu_rst, 4))
                refer = f_refer.readline()
                baidu_rst = f_baidu.readline()
        f_refer.close()
        f_baidu.close()
    with open('reference.txt', 'r', encoding='utf8') as f_refer:
        with open('sougou_rst.txt', 'r', encoding='utf8') as f_sougou:
            refer = f_refer.readline()
            sougou_rst = f_sougou.readline()
            print(refer)
            while refer:
                sougou.append(calculate_bleu(refer, sougou_rst, 4))
                refer = f_refer.readline()
                sougou_rst = f_sougou.readline()
        f_refer.close()
        f_sougou.close()

    ave_google = average(google)
    ave_baidu = average(baidu)
    ave_sougou = average(sougou)
    print("GOOGLE AVERAGE BLEU:{}".format(ave_google))
    print("BAIDU  AVERAGE BLEU:{}".format(ave_baidu))
    print("SOUGOU AVERAGE BLEU:{}".format(ave_sougou))

    x = []
    for i in range(1,31):
        x.append(i)
    plt.figure()
    plt.plot(google,'r',label='google')
    plt.plot(baidu,'g',label='baidu')
    plt.plot(sougou,'b',label='sougou')
    plt.xlabel("sentence")
    plt.ylabel("BLEU")
    plt.legend()
    plt.show()

if __name__ == '__main__':
    main()


import asyncio
from io import BytesIO

from pyrogram import Client, filters
from pyrogram.types import Message
from . import *
from Azazel import aiosession
from ubotlibs.ubot.helper.PyroHelpers import ReplyCheck

async def make_carbon(code):
    url = "https://carbonara.vercel.app/api/cook"
    async with aiosession.post(url, json={"code": code}) as resp:
        image = BytesIO(await resp.read())
    image.name = "carbon.png"
    return image

@Ubot(["carbon"], "كربون")
async def carbon_func(client: Client, message: Message):
    text = (
        message.text.split(None, 1)[1]
        if len(
            message.command,
        )
        != 1
        else None
    )
    if message.reply_to_message:
        text = message.reply_to_message.text or message.reply_to_message.caption
    if not text:
        return await message.delete()
    ex = await message.reply("`تحضير الكربون . . .`")
    carbon = await make_carbon(text)
    await ex.edit("`يتم الرفع . . .`")
    await asyncio.gather(
        ex.delete(),
        client.send_photo(
            message.chat.id,
            carbon,
            caption=f"**Carbonised by** {client.me.mention}",
            reply_to_message_id=ReplyCheck(message),
        ),
    )
    carbon.close()

add_command_help(
    "كربزن",
    [
        [f"carbon او كربون <بالرد>", ".ينشئ صورة كربونية"],
    ],
)


"""
AutoML using Uber's Ludwig
https://github.com/uber/ludwig
"""
import os
from pprint import pprint
import zipfile

from ludwig.api import LudwigModel
from sklearn.model_selection import train_test_split

from autoautoml.core import AutoMLCore
from autoautoml.utils import (get_experiment_settings, read_dataset, evaluate,
                              write, save_artifact, infer_categoricals, clean_dataset)

import warnings
warnings.simplefilter("ignore")

class AutoML(AutoMLCore):

    name = "ludwig"

    def load(self):
        """
        Loads the original data
        """
        super().load()
        self.feat_type = ['categorical' if x.name == 'object' else 'numerical' for x in self.X.dtypes]
        if "model_definition" not in self.automl_settings:
            categorical_list = infer_categoricals(self.dataset.drop(columns=self.target))
            input_features = [
                {"name": col, "type": "category"}
                for col in categorical_list
            ]
            input_features.extend([
                {"name": col, "type": "numerical"}
                for col in self.feature_columns
                if col not in categorical_list
            ])
            if self.problem == "classification":
                output_features = [
                    {
                        "name": self.target,
                        "type": "category"
                    }
                ]
            else:
                output_features = [
                    {
                        "name": self.target,
                        "type": "numerical"
                    }
                ]
            self.automl_settings["model_definition"] = {"input_features": input_features}

    def build_pipeline(self):
        return LudwigModel(**self.automl_settings)

    def fit(self):
        """
        Performs the search
        """
        super().fit()
        self.train_df, self.test_df = train_test_split(self.dataset, test_size=0.1)
        self.automl_pipeline = self.build_pipeline()
        self.automl_pipeline.train(
          data_train_df=self.train_df,
        )

    def evaluate(self):
        """
        Evaluates and stores performance
        """
        print("EVALUATING ESTIMATOR")
        if self.problem_type == "classification":
            metric = "accuracy"
        else:
            metric = "mean_squared_error"
        train_score = self.automl_pipeline.test(data_df=self.train_df)[1][self.target][metric]
        test_score = self.automl_pipeline.test(data_df=self.test_df)[1][self.target][metric]
        self.metadata = {
            "metrics": {
                "test_score": test_score,
                "train_score": train_score
            },
            "experiment_settings": self.experiment_settings
        }
        pprint(self.metadata)

    def save(self):
        """
        Refits and saves final estimator
        """
        if "metadata" in self.artifact_config:
            print("SAVING METADATA")
            save_artifact(self.metadata, self.artifact_config["metadata_path"])
        if "model_path" in self.artifact_config:
            print("SAVING MODEL")
            tmp_model_path = "/tmp/model"
            # ludwig saves in a folder, so we zip it as a single file for saving
            self.automl_pipeline.save(tmp_model_path)
            zipfolder('ludwig_model.zip', tmp_model_path)
            with open('ludwig_model.zip', "rb") as fname:
                serialized_model = fname.read()
                write(serialized_model, self.artifact_config["model_path"])

def zipfolder(output_fname, target_dir):
    zipobj = zipfile.ZipFile(output_fname, 'w', zipfile.ZIP_DEFLATED)
    rootlen = len(target_dir) + 1
    for base, dirs, files in os.walk(target_dir):
        for file in files:
            fn = os.path.join(base, file)
            zipobj.write(fn, fn[rootlen:])