import tensorflow as tf
import tensorflow.contrib.slim as slim
import tensorflow.contrib.layers as tflayers
import numpy as np
from utils import forward

class ConvLayer():
    def __init__(self, num_filters=32, kernel_size=4, stride=2,
                 padding="SAME", normalizer=None, activation=None, weights_init=tf.truncated_normal_initializer):

        self.num_filters = num_filters
        self.padding = padding
        self.kernel_size=kernel_size
        self.stride = stride
        self.normalizer = normalizer
        self.activation = activation
        self.weights_init = weights_init

    def __call__(self,x):
        layer = slim.conv2d(x,self.num_filters,[self.kernel_size,self.kernel_size],[self.stride,self.stride],padding=self.padding ,weights_initializer=self.weights_init,
                                  activation_fn=self.activation)

        return layer

class ResBlock():
    def __init__(self, num_filters=32, kernel_size=4, stride=2,
                 padding_size=1,padding_type="REFLECT", normalizer=None, activation=None, weights_init=tf.truncated_normal_initializer):

        self.num_filters = num_filters
        self.padding_size = padding_size
        self.padding_type = padding_type
        self.kernel_size=kernel_size
        self.stride = stride
        self.normalizer = normalizer
        self.activation = activation
        self.weights_init = weights_init

    def __call__(self,x):
        layers = [
            PaddingLayer(self.padding_size,self.padding_type),
            ConvLayer(num_filters=self.num_filters,kernel_size=self.kernel_size,stride=self.stride,padding="VALID",
                      weights_init=self.weights_init,normalizer=self.normalizer,activation=self.activation),
            PaddingLayer(self.padding_size,self.padding_type),
            ConvLayer(num_filters=self.num_filters,kernel_size=self.kernel_size,stride=self.stride,padding="VALID",
                      weights_init=self.weights_init,normalizer=self.normalizer,activation=None)
        ]
        res = forward(layers)(x) + x
        return res

class PaddingLayer():
    def __init__(self, padding_size, padding_type):

        self.padding_size = padding_size
        self.padding_type = padding_type

    def __call__(self,x):
        p = int(self.padding_size)
        layer = tf.pad(x,[[0, 0], [p, p], [p, p], [0, 0]],self.padding_type)

        return layer

class ConvTransposeLayer():
    def __init__(self, num_outputs=32, kernel_size=3, stride=2,
                 padding="SAME", normalizer=None, activation=None):
        self.num_outputs = num_outputs
        self.padding = padding
        self.kernel_size=kernel_size
        self.stride = stride
        self.normalizer = normalizer
        self.activation = activation

    def __call__(self,x):

        return slim.conv2d_transpose(x,self.num_outputs,self.kernel_size,self.stride,padding=self.padding,
                                  normalizer_fn=self.normalizer,activation_fn=self.activation)

class FCLayer():
    def __init__(self, scope="fc_layer", size=None, dropout=None,
                 nonlinearity=None,reuse=True, normalizer=None):
        assert size, "Must specify layer size (num nodes)"
        self.scope = scope
        self.size = size
        self.dropout = dropout
        self.nonlinearity = nonlinearity
        self.reuse = reuse
        self.normalizer = normalizer

    def __call__(self,x):

        with tf.name_scope(self.scope):
            fc = slim.fully_connected(slim.flatten(x),self.size,activation_fn=self.nonlinearity,reuse=self.reuse,scope=self.scope)

            if self.dropout is not None:
                fc = tf.layers.dropout(inputs=fc,rate = self.dropout)
            if self.normalizer is not None:
                fc = self.normalizer(fc,scope=self.scope)

            return fc

##            if not (hasattr(self, 'w') and hasattr(self, 'b')):
##                std = tf.cast( (2 / x.get_shape()[1].value)**0.5, tf.float32)
##                w = tf.random_normal([x.get_shape()[1].value, self.size],stddev=std)
##                b = tf.zeros([self.size])
##
##                self.w = tf.Variable(w, trainable=True, name="weights")
##                self.b = tf.Variable(b, trainable=True, name="bias")
##
##            if self.dropout is not None:
##                self.w = tf.nn.dropout(self.w,self.dropout)
##
##            if self.nonlinearity is None:
##                return tf.matmul(x,self.w) + self.b
##
##            return self.nonlinearity(tf.matmul(x,self.w) + self.b)


import os
import time
from typing import Dict, List, Union

import spacy
from tree_sitter import Language, Parser
from watchdog.observers import Observer

from services.logger import log

nlp = spacy.load("en_core_web_sm")

class DataParser:
    def __init__(self) -> None:
        self.observer = Observer()
        self.file_map: Dict[str, Union[TextParser, CodeParser]] = {}

    def add_path(self, path: str) -> None:
        log.info(f"Observing path: {path}")
        # self.observer.schedule(EventHandler(self), path=path, recursive=True)
        self._process_path(path)

    def _process_path(self, path: str) -> None:
        for root, dirs, files in os.walk(path):
            for file in files:
                file_path = os.path.join(root, file)
                process_file(file_path)

def process_file(file_path: str) -> None:
    if os.path.isdir(file_path):
        return

    _, extension = os.path.splitext(file_path)

    text_extensions = [".txt", ".md"]
    code_extensions = [
        ".py",
        ".js",
        ".ts",
        ".html",
        ".css",
        ".toml",
        ".json",
        ".yml",
    ]

    with open(file_path, "r", encoding="utf-8", errors="ignore") as file:
        content = file.read()

    if extension in text_extensions:
        text_data = TextParser(content)
        text_data.tokenize()

    elif extension in code_extensions:
        code_data = CodeParser(content)
        code_data.tokenize()
        code_data.extract_comments()

    else:
        return

def run(self) -> None:
    self.observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        self.observer.stop()
    self.observer.join()
    log.info("Observer stopped")

class TextParser:
    def __init__(self, content: str):
        self.content = content
        self.doc = nlp(content)
        self.tokens: List[str] = self.tokenize()
        self.lemmas: List[str] = self.lemmatize()
        self.entities: List[str] = self.extract_entities()

    def tokenize(self) -> List[str]:
        return [token.text for token in self.doc]

    def lemmatize(self) -> List[str]:
        return [token.lemma_ for token in self.doc]

    def extract_entities(self) -> List[str]:
        return [ent.text for ent in self.doc.ents]

def read_markdown_files_from_folder(directory_path):
    documents = []

    for subdir, _, files in os.walk(directory_path):
        for file in files:
            if file.endswith(".md") or file.endswith(".markdown"):
                file_path = os.path.join(subdir, file)
                with open(file_path, "r", encoding="utf-8") as f:
                    documents.append(f.read())

    return documents

PARSER_PYTHON = Language("data/parsers/python.so", "python")

class CodeParser:
    def __init__(self, content: str, language: Language = PARSER_PYTHON):
        self.content = content
        self.language = language
        self.parser = Parser()
        self.parser.set_language(self.language)
        self.tree = self.parser.parse(bytes(content, "utf8"))
        self.comments: List[str] = []
        self.tokens: List[str] = []
        self.comments = self.extract_comments()
        self.tokens = self.tokenize()

    def tokenize(self) -> List[str]:
        tokens = []

        def traverse_tree(node):
            if len(node.children) == 0:  # Leaf node
                tokens.append(node.type)
            else:
                for child in node.children:
                    traverse_tree(child)

        traverse_tree(self.tree.root_node)

        return tokens

    def extract_comments(self):
        query = self.language.query("""(comment) @spell""")
        captures = query.captures(self.tree.root_node)
        comments = [self.content[cap.start_byte : cap.end_byte] for cap, _ in captures]

        return comments


'''
-Hard-
*Priority Queue*

You are given two integers, m and k, and a stream of integers. You are tasked to implement a data structure that calculates the MKAverage for the stream.

The MKAverage can be calculated using these steps:

If the number of the elements in the stream is less than m you should consider the MKAverage to be -1. Otherwise, copy the last m elements of the stream to a separate container.
Remove the smallest k elements and the largest k elements from the container.
Calculate the average value for the rest of the elements rounded down to the nearest integer.
Implement the MKAverage class:

MKAverage(int m, int k) Initializes the MKAverage object with an empty stream and the two integers m and k.
void addElement(int num) Inserts a new element num into the stream.
int calculateMKAverage() Calculates and returns the MKAverage for the current stream rounded down to the nearest integer.

Example 1:

Input
["MKAverage", "addElement", "addElement", "calculateMKAverage", "addElement", "calculateMKAverage", "addElement", "addElement", "addElement", "calculateMKAverage"]
[[3, 1], [3], [1], [], [10], [], [5], [5], [5], []]
Output
[null, null, null, -1, null, 3, null, null, null, 5]

Explanation
MKAverage obj = new MKAverage(3, 1);
obj.addElement(3);        // current elements are [3]
obj.addElement(1);        // current elements are [3,1]
obj.calculateMKAverage(); // return -1, because m = 3 and only 2 elements exist.
obj.addElement(10);       // current elements are [3,1,10]
obj.calculateMKAverage(); // The last 3 elements are [3,1,10].
                          // After removing smallest and largest 1 element the container will be [3].
                          // The average of [3] equals 3/1 = 3, return 3
obj.addElement(5);        // current elements are [3,1,10,5]
obj.addElement(5);        // current elements are [3,1,10,5,5]
obj.addElement(5);        // current elements are [3,1,10,5,5,5]
obj.calculateMKAverage(); // The last 3 elements are [5,5,5].
                          // After removing smallest and largest 1 element the container will be [5].
                          // The average of [5] equals 5/1 = 5, return 5

Constraints:

3 <= m <= 105
1 <= k*2 < m
1 <= num <= 105
At most 105 calls will be made to addElement and calculateMKAverage.

'''

import heapq
from heapq import heappop, heappush
import math

from sortedcontainers import SortedList
import collections

class MKAverage:

    def __init__(self, m: int, k: int):
        self.m = m
        self.k = k
        self.minh = []
        self.maxh = []
        self.minhd = []
        self.maxhd = []
        self.nums = []
        self.cnt = 0
        self.t = m - 2*k
        self.sums = 0
        self.sminh = 0
        self.smaxh = 0

    def addElement(self, num: int) -> None:
        # print('xxx', num, self.sums, self.sminh, self.smaxh)
        self.sums += num
        self.nums.append(num)
        i = -1
        if self.cnt >= self.m:
            i = self.cnt - self.m
            while self.minhd and self.minhd[0][1] < i:
                heapq.heappop(self.minhd)
            while self.minhd and self.maxhd[0][1] < i:
                heapq.heappop(self.maxhd)
            mark = 0
            if self.nums[i] > self.minhd[0][0]:
                self.sminh -= self.nums[i]
                self.sums -= self.nums[i]
                mark = 1
            elif self.nums[i] < -self.maxh[0][0]:
                self.smaxh -= self.nums[i]
                self.sums -= self.nums[i]
                mark = -1
            else:
                self.sums -= self.nums[i]
            if mark > 0:
                val, pos = heapq.heappop(self.maxhd)
                heapq.heappush(self.minh, (-val, pos))
            elif mark < 0:
                val, pos = heapq.heappop(self.minhd)
                heapq.heappush(self.maxh, (-val, pos))

        # while self.minh and self.minh[0][1] <= i:
        #     heapq.heappop(self.minh)
        # while self.maxh and self.maxh[0][1] <= i:
        #     heapq.heappop(self.maxh)
        # print('before add', num, self.sums, self.sminh, self.smaxh, self.minh, self.maxh)

        # if not self.minhd:
        #     heapq.heappush(self.minhd, (num, self.cnt))

        # if not self.maxhd:
        #     heapq.heappush(self.maxhd, (-num, self.cnt))

        self.sminh += num
        if len(self.minh) > self.k:
            while self.minh and self.minh[0][1] < i:
                heapq.heappop(self.minh)
            val, pos = heapq.heappop(self.minh)
            # heapq.heappush(self.minhd, (val, pos))
            heapq.heappush(self.maxhd, (-val, pos))
            self.sminh -= val
        self.smaxh += num
        heapq.heappush(self.maxh, (-num, self.cnt))
        if len(self.maxh) > self.k:
            while self.maxh and self.maxh[0][1] < i:
                heapq.heappop(self.maxh)
            val, pos = heapq.heappop(self.maxh)
            heapq.heappush(self.minhd, (-val, pos))
            # heapq.heappush(self.maxhd, (val, pos))
            self.smaxh -= -val
        self.cnt += 1
        print('afetr add', num, self.sums, self.sminh, self.smaxh, self.minh, self.maxh, self.minhd, self.maxhd)

    def calculateMKAverage(self) -> int:
        if self.cnt < self.m: return -1
        # print(self.minh, self.maxh)
        # print(self.sums,  self.sminh,  self.smaxh, self.t)
        return math.floor((self.sums - self.sminh - self.smaxh) / self.t)

class MKAverage2:

    def __init__(self, m: int, k: int):
        self.m, self.k = m, k
        self.deque = collections.deque()
        self.sl = SortedList()
        self.total = self.first_k = self.last_k = 0

    def addElement(self, num: int) -> None:
        self.total += num
        self.deque.append(num)
        index = self.sl.bisect_left(num)
        if index < self.k:
            self.first_k += num
            if len(self.sl) >= self.k:
                self.first_k -= self.sl[self.k - 1]
        if index >= len(self.sl) + 1 - self.k:
            self.last_k += num
            if len(self.sl) >= self.k:
                self.last_k -= self.sl[-self.k]
        self.sl.add(num)
        if len(self.deque) > self.m:
            num = self.deque.popleft()
            self.total -= num
            index = self.sl.index(num)
            if index < self.k:
                self.first_k -= num
                self.first_k += self.sl[self.k]
            elif index >= len(self.sl) - self.k:
                self.last_k -= num
                self.last_k += self.sl[-self.k - 1]
            self.sl.remove(num)

    def calculateMKAverage(self) -> int:
        if len(self.sl) < self.m:
            return -1
        return (self.total - self.first_k - self.last_k) // (self.m - 2 * self.k)

class MKAverage3:
    def __init__(self, m: int, k: int):
        self.m, self.k = m, k
        self.arr = [0]*m
        self.lh1, self.rh1 = self.heap_init(m, k)
        self.lh2, self.rh2 = self.heap_init(m, m - k)
        self.score = 0

    def heap_init(self, p1, p2):
        h1 = [(0, i) for i in range(p1-p2, p1)]
        h2 = [(0, i) for i in range(p1-p2)]
        heapq.heapify(h1)
        heapq.heapify(h2)
        return (h1, h2)

    def update(self, lh, rh, m, k, num):
        score, T = 0, len(self.arr)
        if num > rh[0][0]:
            heappush(rh, (num, T))
            if self.arr[T - m] <= rh[0][0]:
                if rh[0][1] >= T - m: score += rh[0][0]
                score -= self.arr[T - m]
                heappush(lh, (-rh[0][0], rh[0][1]))
                heappop(rh)
        else:
            heappush(lh, (-num, T))
            score += num
            if self.arr[T - m] >= rh[0][0]:
                heappush(rh, (-lh[0][0], lh[0][1]))
                q = heappop(lh)
                score += q[0]
            else:
                score -= self.arr[T - m]

        while lh and lh[0][1] <= T - m: heappop(lh)  # lazy-deletion
        while rh and rh[0][1] <= T - m: heappop(rh)  # lazy-deletion
        return score

    def addElement(self, num):
        t1 = self.update(self.lh1, self.rh1, self.m, self.k, num)
        t2 = self.update(self.lh2, self.rh2, self.m, self.m - self.k, num)
        self.arr.append(num)
        self.score += (t2 - t1)

    def calculateMKAverage(self):
        if len(self.arr) < 2*self.m: return -1
        return self.score//(self.m - 2*self.k)

def negateX(z):
    return ( -z[0],-z[1] )

class MKAverage4:

    def __init__(self, m: int, k: int):
        # use 4 heaps (2 min, 2 max)
        # lowQ and lowA consist of a pair, complementing each other
        # together they hold all the numbers in the window
        # the key step is to maintain lowQ having k smallest numbers
        # if not, exchange lowQ[0] with lowA[0] until satisfied
        # similarly for highA and highQ

        self.lowQ = []  # max-heap, smallest k numbers in the window
        self.highQ = [] # min-heap, largest k numbers in the window
        self.lowA = []  # min-heap, largest m-k numbers in the window
        self.highA = [] # max-heap, smallest m-k numbers in the window
        self.total = 0
        self.counter = 0
        self.m = m
        self.k = k
        self.divisor = m - k - k
        self.allNums = []

    def addElement(self, num: int) -> None:
        # print("addElement",num)
        self.total += num
        heappush(self.lowA, (num,self.counter) )
        heappush(self.highA, (-num,-self.counter) )

        if self.counter < self.m:
            if self.counter == self.m-1:
                # print(self.lowA)
                # print(self.highA)
                for _ in range(self.k):
                    heappush(self.lowQ, negateX(heappop(self.lowA)))
                    heappush(self.highQ, negateX(heappop(self.highA)))
                self.total -= -sum( n for n,_ in self.lowQ )
                self.total -= sum( n for n,_ in self.highQ )
        else:
            removedIndex = self.counter-self.m
            removed = (self.allNums[self.counter-self.m], removedIndex)
            # print("removedNum",removed)
            if removed <= negateX(self.lowQ[0]):
                # print("removedNum from lowQ")
                low = heappop(self.lowA)
                self.total -= low[0]
                heappush(self.lowQ, negateX(low))
            elif removed >= self.highQ[0]:
                # print("removedNum from highQ")
                high = heappop(self.highA)
                self.total -= -high[0]
                heappush(self.highQ, negateX(high))
            else:
                self.total -= removed[0]

            while -self.lowQ[0][1] <= removedIndex:
                heappop(self.lowQ)
            while self.lowA[0][1] <= removedIndex:
                heappop(self.lowA)
            while self.highQ[0][1] <= removedIndex:
                heappop(self.highQ)
            while -self.highA[0][1] <= removedIndex:
                heappop(self.highA)

            while self.highA[0] < negateX(self.highQ[0]):
                a,q = heappop(self.highA),heappop(self.highQ)
                self.total += a[0]
                self.total += q[0]
                heappush(self.highA, negateX(q))
                heappush(self.highQ, negateX(a))
                # print("swizzle high")
            while self.lowA[0] < negateX(self.lowQ[0]):
                a,q = heappop(self.lowA),heappop(self.lowQ)
                self.total -= a[0]
                self.total -= q[0]
                heappush(self.lowA, negateX(q))
                heappush(self.lowQ, negateX(a))
                # print("swizzle low")

        self.allNums.append(num)
        self.counter += 1
        # print(self.total, self.allNums, "|||", self.lowQ, self.highQ, "|||", self.lowA, self.highA)

    def calculateMKAverage(self) -> int:
        if self.counter < self.m:
            return -1
        return self.total // self.divisor

class BinaryIndexTree:
    def __init__(self, n: int):
        self.leng = n + 1
        """
        i is the number, nodes[i] = sum(nums[i - i & (-i), i - 1]),
        nums is the original array
        e.g.: https://pic.leetcode-cn.com/755dd21358e8cd6ac39c85bdbaa67188dcf67dad7bd8c32d4ad777c1f376ff08-binaryindexedtreeexpandedtreewithinfo.gif
        """
        self.nodes = [0] * self.leng

    def query(self, i: int) -> int:
        """
        i is a number
        return the sum of numbers that is less than or equal to,
        which is equivalent to the sum of logN ranges (等于i代表的logi个区间的总和。)
        """
        ans = 0
        while i:
            ans += self.nodes[i]
            i -= i & -i  # remove the lowbit of i
        return ans

    def update(self, i: int, delta: int) -> None:
        while i < self.leng:
            self.nodes[i] += delta
            # parent(i) = i + i&(-i), i&(-i) is thes lowbit of i,
            # e.g. i = 10, 10 = (1100)2, lowbit(1100_2) = 100_2
            i += i & -i

from collections import deque
class MKAverage5:
    def __init__(self, m: int, k: int):
        """
        Constraints:
            3 <= m <= 105
            1 <= k*2 < m
            1 <= num <= 105
            At most 105 calls will be made to addElement and calculateMKAverage.
        """
        self.max_num = 10 ** 5
        self.m = m
        self.k = k
        # self.queue_len_limit = m - 2 * k
        self.queue = deque([])
        """
        self.value_tree.query(num) = the sum of the number which <= num
        self.count_tree.query(num) = the count of the number which <=num
        """
        self.value_tree = BinaryIndexTree(self.max_num)
        self.count_tree = BinaryIndexTree(self.max_num)

        self.remaining_cnt = m - 2 * k
        self.MKAverage = None  # avoid repetitive computing for MKAverage

    def addElement(self, num: int) -> None:
        self.value_tree.update(num, num)
        self.count_tree.update(num, 1)
        self.queue.append(num)
        if len(self.queue) > self.m:
            removed_num = self.queue.popleft()
            self.value_tree.update(removed_num, -removed_num)
            self.count_tree.update(removed_num, -1)

        self.MKAverage = None  # avoid recomputing MKAverage if no new number added

    def search_low_boundary(self, count: int) -> int:
        """
        search the minimum num that makes self.count_tree.query(num) >= count
        即self.queue中小于等于num的数至少有count个
        e.g, input 1,
        self.value_tree.nodes = [0, 1, 3, 3, 10, 5, 11, 7, 36]
        self.count_tree.nodes = [0, 1, 2, 1, 4, 1, 2, 1, 8]
        self.max_num = 8
        i, low_boundary_num, prefix_sum
        3,   0,     0
        2,   0,     0
        1,   2,     2
        0,   2,     2

        low_boundary_num = 2, low_boundary_num + 1 = 3,
        so search_low_boundary(3) = 3 means the minimum num that makes self.count_tree.query(num) >= 3
        """
        # there are prefix_sum numbers that are less than count
        low_boundary_num, prefix_sum = 0, 0
        # self.max_num + 1 是self.count_tree.sums的长度
        for i in range(int(math.log2(self.max_num + 1)), -1, -1):
            low_boundary_num2 = low_boundary_num + (1 << i)
            # print(i, low_boundary_num, prefix_sum, low_boundary_num2)

            if low_boundary_num2 <= self.max_num and prefix_sum + self.count_tree.nodes[low_boundary_num2] < count:
                prefix_sum += self.count_tree.nodes[low_boundary_num2]
                low_boundary_num = low_boundary_num2

        # +1 because 'low_boundary_num' will have position of largest value less than 'count'
        return low_boundary_num + 1

    def calculateMKAverage(self) -> int:
        if len(self.queue) < self.m:
            return -1
        if self.MKAverage is not None:
            return self.MKAverage
        low_num, high_num = self.search_low_boundary(self.k), self.search_low_boundary(self.m - self.k)
        # num_sum = self.value_tree.query(high_num) - self.value_tree.query(low_num)
        high, low = self.value_tree.query(high_num),  self.value_tree.query(low_num)
        num_sum = high - low
        print(self.value_tree.nodes[:6])
        print(self.count_tree.nodes[:6])
        print(low_num, high_num)
        print(low, high, num_sum)
        print(self.count_tree.query(low_num), self.count_tree.query(high_num))
        """
        https://leetcode.com/problems/finding-mk-average/discuss/1152438/Python3-Fenwick-tree/903394
        Because probably there are more than k number that is less than or equal to low_num,
        and there are more than m-k number that is less than or equal to high_num, we have to make some adjustments.
        即有的数多减了, 有的数少减了。需要重新调整
        e.g. m = 6, k = 2, nums = [1,2,2,3,3,4]
        prefix_sum = [0,1,3,5,6] prefix_sum[i] 表示 <= i的数的个数
        k1 = k, k2 = m - k = 4
        -> prefix_sum[lo=2]=3>=k1=2
        -> prefix_sum[hi=3]=5>=k2=4
        -> values_tree.query(hi)-values_tree.query(lo) = sum([1,2,2,3,3]) - sum([1,2,2]) = sum([3,3])
        But the actual solution here is sum([2,3]), we need to remove a 3 and add back a 2.
        """
        num_sum += (self.count_tree.query(low_num) - self.k) * low_num
        num_sum -= (self.count_tree.query(high_num) - (self.m - self.k)) * high_num

        # rounded down to the nearest integer
        self.MKAverage = num_sum // self.remaining_cnt
        return self.MKAverage

if __name__ == "__main__":
    # obj = MKAverage(3, 1)
    # obj.addElement(3)#        // current elements are [3]
    # obj.addElement(1)#        // current elements are [3,1]
    # print(obj.calculateMKAverage())# // return -1, because m = 3 and only 2 elements exist.
    # obj.addElement(10)#       // current elements are [3,1,10]
    # print(obj.calculateMKAverage())# // The last 3 elements are [3,1,10].
    #                         # // After removing smallest and largest 1 element the container will be [3].
    #                         # // The average of [3] equals 3/1 = 3, return 3
    # obj.addElement(5)#        // current elements are [3,1,10,5]
    # obj.addElement(5)#        // current elements are [3,1,10,5,5]
    # obj.addElement(5)#        // current elements are [3,1,10,5,5,5]
    # print(obj.calculateMKAverage())# // The last 3 elements are [5,5,5].
    #                         # // After removing smallest and largest 1 element the container will be [5].
    #                         # // The average of [5] equals 5/1 = 5, return 5

    # obj = MKAverage(6, 1)
    # obj.addElement(3)#        // current elements are [3]
    # obj.addElement(1)#        // current elements are [3,1]

    # obj.addElement(12)#       // current elements are [3,1,10]

    # obj.addElement(5)#        // current elements are [3,1,10,5]
    # obj.addElement(3)#        // current elements are [3,1,10,5,5]
    # obj.addElement(4)#        // current elements are [3,1,10,5,5,5]
    # print(obj.calculateMKAverage())# // The last 3 elements are [5,5,5].
    #                         # // After removing smallest and largest 1 element the container will be [5].
    #                         # // The average of [5] equals 5/1 = 5, return 5

    # obj = MKAverage(3, 1)
    # obj.addElement(17612)#        // current elements are [3]
    # obj.addElement(74607)#        // current elements are [3,1]
    # print(obj.calculateMKAverage())# // return -1, because m = 3 and only 2 elements exist.
    # obj.addElement(8272)#       // current elements are [3,1,10]

    # obj.addElement(33433)#        // current elements are [3,1,10,5]
    # print(obj.calculateMKAverage())# // return -1, because m = 3 and only 2 elements exist.
    # obj.addElement(15456)#        // current elements are [3,1,10,5,5]
    # obj.addElement(64938)#        // current elements are [3,1,10,5,5,5]
    # print(obj.calculateMKAverage())# // The last 3 elements are [5,5,5].
    #                         # // After removing smallest and largest 1 element the container will be [5].
    #                         # // The average of [5] equals 5/1 = 5, return 5
    # obj.addElement(99741)#        // current elements are [3,1,10,5,5,5]

    obj = MKAverage5(6, 2)
    obj.addElement(1)#        // current elements are [3]
    obj.addElement(2)#        // current elements are [3,1]

    obj.addElement(2)#       // current elements are [3,1,10]

    obj.addElement(3)#        // current elements are [3,1,10,5]
    obj.addElement(3)#        // current elements are [3,1,10,5,5]
    obj.addElement(4)#        // current elements are [3,1,10,5,5,5]
    print(obj.calculateMKAverage())# // The last 3 elements are [5,5,5].
    #


from nltk.corpus import stopwords
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras import Sequential, Input
from tensorflow.keras.layers import Dense, Dropout

from string import punctuation
from os import listdir
from collections import Counter
from numpy import array, half

def load_doc(filename):
    f = open(filename, 'r')
    doc  = f.read()
    f.close()
    return doc

def clean_doc(doc):
    tokens = doc.split()
    table = str.maketrans('', '', punctuation)
    tokens = [w.translate(table) for w in tokens]
    tokens = [w for w in tokens if w.isalpha()]
    stop_words = set(stopwords.words('english'))
    tokens = [w for w in tokens if not w in stop_words]
    tokens = [w for w in tokens if len(w) > 1]
    return tokens

def add_doc_to_vocab(filename, vocab):
    doc = load_doc(filename)
    tokens = clean_doc(doc)
    vocab.update(tokens)
    return ''

def process_docs(directory, vocab, callback, is_train=True):
    lines = list()
    for filename in listdir(directory):
        if is_train and filename.startswith('cv9'):
            continue
        if not is_train and not filename.startswith('cv9'):
            continue
        path = directory + '/' + filename
        line = callback(path, vocab)
        lines.append(line)
    return lines

def make_tokens(vocab, min_occur):
    return [token for token, count in vocab.items() if count >= min_occur]

def save_list(lines, filename):
    data = '\n'.join(lines)
    file = open(filename, 'w')
    file.write(data)
    file.close()

def make_doc_to_line(filename, vocab):
    doc = load_doc(filename)
    tokens = clean_doc(doc)
    tokens = [w for w in tokens if w in vocab]
    return ' '.join(tokens)

def make_vocab_file(data_dir, pos, neg, is_train):
    vocab = Counter()
    _ = process_docs(data_dir+pos, vocab, add_doc_to_vocab, is_train)
    _ = process_docs(data_dir+neg, vocab, add_doc_to_vocab, is_train)
    print(f'vocabulary length: {len(vocab)}')
    # print(vocab.most_common(50))

    min_occur = 2
    tokens = make_tokens(vocab, min_occur)
    print(f'token length: {len(tokens)}')

    save_list(tokens, 'vocab.txt')

def load_vocab_file(filename, data_dir, pos, neg, is_train):
    vocab = load_doc(filename)
    vocab = vocab.split()
    vocab = set(vocab)

    pos_lines = process_docs(data_dir+pos, vocab, make_doc_to_line, is_train)
    neg_lines = process_docs(data_dir+neg, vocab, make_doc_to_line, is_train)

    print(f'positive lines length: {len(pos_lines)}')
    print(f'negative lines length: {len(neg_lines)}')

    return neg_lines + pos_lines

def make_vector(tokenizer, docs):
    return tokenizer.texts_to_matrix(docs, mode='freq')

def make_y_vector(size):
    half_size = int(size/2)
    return array([0 for _ in range(half_size)] + [1 for _ in range(half_size)])

def make_dataset(filename, data_dir, pos, neg, train_size, test_size):
    docs_train = load_vocab_file(filename, data_dir, pos, neg, is_train=True)
    docs_test = load_vocab_file(filename,data_dir, pos, neg, is_train=False)

    tokenizer = Tokenizer()
    tokenizer.fit_on_texts(docs_train)

    X_train = make_vector(tokenizer, docs_train)
    y_train = make_y_vector(train_size)

    X_test = make_vector(tokenizer, docs_test)
    y_test = make_y_vector(test_size)

    return (X_train, y_train), (X_test, y_test)

def make_model(n_words):
    model = Sequential()
    model.add(Input(shape=(n_words,)))
    model.add(Dense(50, activation='relu'))
    model.add(Dense(1, activation='sigmoid'))
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model


import torch
from .engine_utils import get_init_pose_train, get_normed_kps, get_init_scale_train
from .engine_utils import aug_3d_bbox, aug_RT
from .batch_test import batch_data_test, batch_updater_test
from lib.vis_utils.image import grid_show, heatmap
from lib.pysixd.misc import transform_pts_batch, transform_normed_pts_batch

def batch_data(cfg, data, device="cuda", phase="train", dtype=torch.float32):
    if phase == "test":
        return batch_data_test(cfg, data, device=device, dtype=dtype)

    input_cfg = cfg.INPUT
    # batch training data and flatten
    tensor_kwargs = {"dtype": dtype, "device": device}
    to_float_args = {"dtype": dtype, "device": device, "non_blocking": True}
    to_long_args = {"dtype": torch.long, "device": device, "non_blocking": True}

    batch = {}
    num_imgs = len(data)

    # construct by flattening instance data =============================
    batch["pcl"] = torch.cat([d["instances"].pcl for d in data], dim=0).to(**to_float_args)

    batch["obj_cls"] = torch.cat([d["instances"].obj_classes for d in data], dim=0).to(**to_long_args)
    batch["obj_pose"] = torch.cat([d["instances"].obj_poses.tensor for d in data], dim=0).to(**to_float_args)
    batch["obj_scale"] = torch.cat([d["instances"].obj_scales for d in data], dim=0).to(**to_float_args)

    # batch["obj_visib_mask"] = torch.cat([d["instances"].obj_visib_masks.tensor for d in data], dim=0).to(
    #     **to_float_args
    # )
    # batch["obj_trunc_mask"] = torch.cat([d["instances"].obj_trunc_masks.tensor for d in data], dim=0).to(
    #     **to_float_args
    # )

    batch["obj_mean_points"] = torch.cat([d["instances"].obj_mean_points for d in data], dim=0).to(**to_float_args)
    batch["obj_mean_scales"] = torch.cat([d["instances"].obj_mean_scales for d in data], dim=0).to(**to_float_args)

    if "last_frame" in cfg.INPUT.INIT_POSE_TYPE_TRAIN:
        batch["last_frame_poses"] = torch.cat([d["instances"].last_frame_poses for d in data], dim=0).to(
            **to_float_args
        )

    if cfg.INPUT.KPS_TYPE.lower() == "fps":
        batch["obj_fps_points"] = torch.cat([d["instances"].obj_fps_points for d in data], dim=0).to(**to_float_args)

    num_insts_per_im = [len(d["instances"]) for d in data]
    num_insts_all = len(batch["obj_cls"])
    K_list = []
    sym_infos_list = []
    im_ids = []
    inst_ids = []  # the idx in the current img, should be used with im_ids
    for i_im in range(num_imgs):
        sym_infos_list.extend(data[i_im]["instances"].obj_sym_infos)
        for i_inst in range(num_insts_per_im[i_im]):
            im_ids.append(i_im)
            inst_ids.append(i_inst)
            K_list.append(data[i_im]["cam"].clone())

    batch["im_id"] = torch.tensor(im_ids, **tensor_kwargs)
    batch["inst_id"] = torch.tensor(inst_ids, **tensor_kwargs)
    batch["K"] = torch.stack(K_list, dim=0).to(**to_float_args)
    batch["sym_info"] = sym_infos_list

    # keep max_objs ----------------------------
    n_obj = min(cfg.DATALOADER.MAX_OBJS_TRAIN, num_insts_all)
    for _k in batch:
        if len(batch[_k]) == num_insts_all:
            batch[_k] = batch[_k][:n_obj]

    if input_cfg.WITH_IMG:
        batch["img"] = torch.stack([d["image"] for d in data]).to(**to_float_args)

    if input_cfg.WITH_DEPTH:
        batch["depth_obs"] = torch.stack([d["depth"] for d in data], dim=0).to(**to_float_args)

    # do some augmentation here --------------------------------------------
    if torch.rand(1) < input_cfg.BBOX3D_AUG_PROB:
        aug_3d_bbox(batch)

    if torch.rand(1) < input_cfg.RT_AUG_PROB:
        aug_RT(batch)

    return batch

def batch_updater(
    cfg,
    batch,
    cur_iter=1,
    poses_est=None,
    scales_est=None,
    device="cuda",
    dtype=torch.float32,
    phase="train",
):
    if phase == "test":
        return batch_updater_test(
            cfg,
            batch,
            poses_est=poses_est,
            scales_est=scales_est,
            device=device,
            dtype=dtype,
        )
    # batch updater for train =========================================
    tensor_kwargs = {"dtype": dtype, "device": device}
    to_float_args = {"dtype": dtype, "device": device, "non_blocking": True}

    n_obj = batch["obj_pose"].shape[0]
    if poses_est is None:
        # init pose --------------------------------------------------------------------------
        get_init_pose_train(cfg, batch, **tensor_kwargs)  # obj_pose_est
    else:
        batch["obj_pose_est"] = poses_est

    if scales_est is None:
        if cfg.MODEL.REFINE_SCLAE:
            get_init_scale_train(cfg, batch, **tensor_kwargs)  # obj_scale_est
        else:
            batch["obj_scale_est"] = batch["obj_scale"].detach().clone()
    else:
        batch["obj_scale_est"] = scales_est

    if "obj_kps" not in batch:
        get_normed_kps(cfg, batch, **to_float_args)  # obj_kps

    r_est = batch["obj_pose_est"][:, :3, :3]
    t_est = batch["obj_pose_est"][:, :3, 3:4]
    s_est = batch["obj_scale_est"]

    tfd_kps = transform_normed_pts_batch(
        batch["obj_kps"],
        r_est,
        t=None if cfg.INPUT.ZERO_CENTER_INPUT else t_est,
        scale=s_est,
    )

    batch["tfd_kps"] = tfd_kps.permute(0, 2, 1)  # [bs, 3, num_k]

    if cfg.INPUT.ZERO_CENTER_INPUT:
        batch["x"] = batch["pcl"].permute(0, 2, 1) - t_est.view(n_obj, 3, 1)  #  [bs, 3, num_k] - [bs, 3, 1]
    else:
        batch["x"] = batch["pcl"].permute(0, 2, 1)

    # done batch update train------------------------------------------


#!/usr/bin/env python

'''
Commands:
# ON
# OFF
ALL ON
ALL OFF
TEMP
T
PIC
SLEEP START #
SLEEP END #
SLEEP
SET ## (bottom temp)
RANGE # (top-bottom temp)
ON (thermostat mode on)
OFF (thermostat mode off)
STATUS
'''

import sys
import time
import os
import datetime
import matplotlib
matplotlib.use('Agg')
import matplotlib.dates
import matplotlib.pyplot
from twython import Twython
import numpy
from subprocess import Popen, PIPE
import twitter_credentials as tc
import iphone_data as iphone
import remote_commands as rc
import temperature_log_reader as tlr
import postgresql_commands as psql
import camera_commands as cc
import traceback

# your twitter consumer and access information goes here
CONSUMER_KEY = tc.CONSUMER_KEY
CONSUMER_SECRET = tc.CONSUMER_SECRET
ACCESS_TOKEN = tc.ACCESS_TOKEN
ACCESS_SECRET = tc.ACCESS_SECRET
# acceptable username
#ok_user_name = tc.ok_user_name
ok_user_name = tc.ok_user_id

# set iphone info
iPhoneIP = iphone.iPhoneIP
iPhoneMAC = iphone.iPhoneMAC
# set the variables for iPhone check
iPhoneStatusOld = 0  # default to 0 (not here)
iPhoneStatusNew = 0  # default to 0 (not here)

# sign on to twitter
twitter = Twython(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_SECRET)

# set if we are using an ac or heater
isheater = 1

# set the sleep_mode variable
sleep_status = False   # False = sleep mode waiting to start, True = sleep mode has started, waiting to end
sleep_mode = True  # we will want to start and stop sleep mode
# set the sleep end and start times
sleep_start = datetime.datetime.now()
sleep_end = datetime.datetime.now()
sleep_start_hour_default = 0
sleep_start_minute_default = 0
sleep_end_hour_default = 7
sleep_end_minute_default = 30

# set the thermostat mode variable (0 off, 1 on)
thermostat_always_off = False
thermostat_mode = 0
thermostat_temp = 71
thermostat_range = 1
# active_heaters (all, 1, 2, 3, 4)
active_heaters = [True, False, False, False, False]
# activate_heaters (-1 = off, 0 = no action, 1 = on)
activate_heaters = 0

# set the delta times for each process (in sec)
# TweetCheck: check twitter
# IPhoneCheck: check if iphone is connected
# ThermTweetCheck: send a dm tweet if thermostat sends a signal
# CameraCheck: check the camera image
deltaTweetCheck = 60
deltaIPhoneCheck = 120
deltaThermTweetCheck = 600
deltaCameraCheck = 60
deltaPsqlCheck = 5
deltaActivateHeaters = 0
tweetCheckTime = 0
iPhoneCheckTime = 0
thermTweetCheckTime = 0
cameraCheckTime = 0
psqlCheckTime = 0
activateHeatersCheckTime = 0
currentTime = time.time()

commands = {'1 ON': rc.on1,
            '1 OFF': rc.off1,
            '2 ON': rc.on2,
            '2 OFF': rc.off2,
            '3 ON': rc.on3,
            '3 OFF': rc.off3,
            '4 ON': rc.on4,
            '4 OFF': rc.off4,
            'ALL ON': rc.onAll,
            'ALL OFF': rc.offAll,
            'TEMP': tlr.temp,
            'T': tlr.tempLog,
            'PIC': tlr.take_image}

do_midnight_plot = True

while True:
    # get the current time
    currentTime = time.time()
    # get the current datetime
    currentDatetime = datetime.datetime.now()
    # see if we want to post the date history
    if do_midnight_plot:
        if currentDatetime.hour == 0:
            # put the last 24 hours on twitter
            tlr.tempPlot(twitter, 24)
            # make sure we do not repeat the mignight plot
            do_midnight_plot = False
    elif currentDatetime.hour > 0:
        # make sure we will do a midnight plot when the time is correct
        do_midnight_plot = True
    # see if we should check the postgresql database
    if psqlCheckTime < currentTime:
        # update the psql check time
        psqlCheckTime = currentTime + deltaPsqlCheck
        # try to read the psql database
        try:
            psqlResult = psql.sendReceiveSQL("SELECT min FROM therm;")
            thermostat_temp = float(psqlResult[0][0])
            psqlResult = psql.sendReceiveSQL("SELECT range FROM therm;")
            thermostat_range = float(psqlResult[0][0])
            #psqlResult = psql.sendReceiveSQL("SELECT * FROM activeHeaters;")
            #active_heaters = list(psqlResult[0])
            psqlResult = psql.sendReceiveSQL("SELECT sleep FROM status")
            sleep_mode = psqlResult[0][0]
            # see if we should change the sleep status
            if sleep_mode:
                psqlResult = psql.sendReceiveSQL("SELECT endHour FROM sleep")
                sleep_end.hour = int(psqlResult[0][0])
                sleep_end.minute = int(psqlResult[0][0]-sleep_end.hour)
                psqlResult = psql.sendReceiveSQL("SELECT startHour FROM sleep")
                sleep_start.hour = int(psqlResult[0][0])
                sleep_start.minute = int(psqlResult[0][0]-sleep_end.hour)
                # see if we should start the sleep status
                if sleep_status and currentDatetime.hour == sleep_start.hour and \
                   currentDatetime.minute == sleep_start.minute:
                    # GOING TO SLEEP!
                    sleep_status = True
                    psql.sendSQL("UPDATE sleep SET active = true;")
                # see if we should end the sleep status
                if sleep_status and currentDatetime.hour == sleep_end.hour and \
                   currentDatetime.minute == sleep_end.minute:
                    # WAKING UP!
                    sleep_status = False
                    psql.sendSQL("UPDATE sleep SET active = false;")
        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            print("Postgresql error!")

        # check the temperatures
        try:
            mainDir = '/sys/bus/w1/devices'
            allDeviceDirs = os.listdir(mainDir)
            # find index that has masater directory
            deviceNames = []
            for i in range(len(allDeviceDirs)):
                if allDeviceDirs[i] == 'w1_bus_master1':
                    masterDirIndex = i
                else:
                    deviceNames.append(allDeviceDirs[i])
            numDevices = len(deviceNames)
            temps = [[] for i in range(numDevices)]
            for i in range(numDevices):
                tfile = open(mainDir + '/' + allDeviceDirs[masterDirIndex] + '/' + deviceNames[i] + '/w1_slave')
                # read the text
                text = tfile.read()
                # close the file
                tfile.close()
                # split the text with new lines and select the second to last line
                secondline = text.split("\n")[-2]
                # split the line into words, referring to the spaces and select the 10th word
                tempWord = secondline.split(" ")[9]
                # The first two characaters are t=, so get rid of them
                temp = float(tempWord[2:])
                # convert to correct temps
                tempC = temp / 1000
                temps[i] = tempC * 9 / 5 + 32
            # end of reading in all the sensor data
            # get the median
            tempF = numpy.median(temps)

            #tempF = tlr.get_temp()
            tempFstr = "%.2f" % tempF
            psql.sendSQL("DELETE FROM temp WHERE now > 0 OR now <= 0;")
            psql.sendSQL("INSERT INTO temp (now) VALUES (" + tempFstr + ");")
            #psql.sendSQL("UPDATE temp SET now = " + tempFstr + ";")
            # activate heaters if neccessary
            if tempF < thermostat_temp and not thermostat_always_off:
                if isheater > 0:
                    # turn on heat
                    rc.onAll(twitter, sendMessage=False)
                else:
                    # turn off ac
                    rc.offAll(twitter, sendMessage=False)
            if tempF > thermostat_temp + thermostat_range and not thermostat_always_off:
                if isheater > 0:
                    # turn off heat
                    rc.offAll(twitter, sendMessage=False)
                else:
                    # turn on ac
                    rc.onAll(twitter, sendMessage=False)
        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            print("Error reading temperatures")

    # see if we should check twitter
    if tweetCheckTime < currentTime:
        # update the tweet check time
        tweetCheckTime = currentTime + deltaTweetCheck
        # read direct messages
        # see if we are in thermostat mode
        if thermostat_mode != 0:
            # see what the temperature is
            # read the temperature of the sensors and tweet it
            try:
                mainDir = '/sys/bus/w1/devices'
                allDeviceDirs = os.listdir(mainDir)
                #deviceNames = allDeviceDirs[0:-1]
                deviceNames = []
                masterDir = ''
                for deviceName in allDeviceDirs:
                    if 'master' not in deviceName:
                        deviceNames.append(deviceName)
                    else:
                        masterDir = deviceName

                numDevices = len(deviceNames)
                temps = [[] for i in range(numDevices)]
                for i in range(numDevices):
                    tfile = open(mainDir + '/' + masterDir + '/' + deviceNames[i] + '/w1_slave')
                    # read the text
                    text = tfile.read()
                    # close the file
                    tfile.close()
                    # split the text with new lines and select the second to last line
                    secondline = text.split("\n")[-2]
                    # split the line into words, referring to the spaces and select the 10th word
                    tempWord = secondline.split(" ")[9]
                    # The first two characaters are t=, so get rid of them
                    temp = float(tempWord[2:])
                    # convert to correct temps
                    tempC = temp / 1000
                    temps[i] = tempC * 9 / 5 + 32
                # end of reading in all the sensor data
                # get the median
                tempF = numpy.median(temps)

                tempFstr = "%.2f" % tempF
                psql.sendSQL("DELETE FROM temp WHERE now > 0 OR now <= 0;")
                psql.sendSQL("INSERT INTO temp (now) VALUES (" + tempFstr + ");")
                #psql.sendSQL("UPDATE temp SET now = " + tempFstr + ";")

                # compare to thermostat threshold and send message if needed
                if thermTweetCheckTime < currentTime:
                    sendTweetUpdate = True
                    thermTweetCheckTime = currentTime + deltaThermTweetCheck
                else:
                    sendTweetUpdate = False

                if tempF < thermostat_temp and not thermostat_always_off:
                    if isheater > 0:
                        # turn on heat
                        rc.onAll(twitter, sendMessage=sendTweetUpdate)
                    else:
                        # turn off ac
                        rc.offAll(twitter, sendMessage=sendTweetUpdate)
                if tempF > thermostat_temp + thermostat_range and not thermostat_always_off:
                    if isheater > 0:
                        # turn off heat
                        rc.offAll(twitter, sendMessage=sendTweetUpdate)
                    else:
                        # turn on ac
                        rc.onAll(twitter, sendMessage=sendTweetUpdate)
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                print(exc_type, fname, exc_tb.tb_lineno)
                twitter.send_direct_message(text='Error reading temperatures', screen_name=tc.ok_user_id)

        # see if we are in sleep mode
        if sleep_mode != 0:
            now = datetime.datetime.now()
            # see if we are at the sleep hour and minute
            if (not sleep_status) and now.hour == sleep_start.hour and now.minute == sleep_start.minute:
                # we are at the sleep start time, so turn off the heat
                rc.offAll(twitter)
                # keep sleep mode on
                sleep_status = True
                psql.sendSQL("UPDATE sleep SET active = true;")
                print('sleep mode start activated')
            if sleep_status and now.hour == sleep_end.hour and now.minute == sleep_end.minute:
                # we are at the sleep end time, so turn on the heat
                rc.onAll(twitter)
                # turn off sleep mode
                sleep_status = 0
                psql.sendSQL("UPDATE sleep SET active = false;")
                twitter.send_direct_message(text='Sleep Mode Off', screen_name=tc.ok_user_id)
                print('sleep mode end activated')

        # read direct messages
        try:
            direct_messages = twitter.get_direct_messages()
            direct_messages = direct_messages['events']
        except:
            print('twitter GET rate limit error')
            direct_messages = []

        num_messages = len(direct_messages)
        # see if there is a new direct message
        # print('found ' + str(num_messages) + ' messages')
        for i in range(num_messages):
            #sender_name = direct_messages[num_messages - i - 1]['sender_screen_name']
            sender_name = direct_messages[num_messages - i -1]['message_create']['sender_id']
            message_id = direct_messages[num_messages - i - 1]['id']
            if sender_name == ok_user_name:
                #message = direct_messages[num_messages - i - 1]['text'].upper()
                message = direct_messages[num_messages - i - 1]['message_create']['message_data']['text'].upper()
                # see what command was sent
                print(message)
                try:
                    commands[message](twitter)
                except:
                    try:
                        message_split = message.split(' ')
                        if message[0] == 'T':
                            try:
                                hoursToPlot = int(message[1:])
                                tlr.tempPlot(twitter, hoursToPlot)
                            except Exception as err:
                                print('could not plot the temp')
                                traceback.print_tb(err.__traceback__)
                        elif message_split[0] == 'SLEEP':
                            # turn on sleep mode
                            sleep_mode = 1
                            try:
                                if message_split[1] == 'START':
                                    sleep_start = datetime.datetime.now()
                                    if sleep_start.hour > int(message_split[2]):
                                        sleep_start += datetime.timedelta(days=1)
                                    sleep_start = sleep_start.replace(hour=int(message_split[2]))
                                    sleep_start = sleep_start.replace(minute=int(message_split[3]))
                                    print('start sleep mode tweet received')
                                    twitter.send_direct_message(
                                        text='Sleep mode will start on ' + sleep_start.strftime('%H:%M'),
                                        screen_name=tc.ok_user_id)

                                elif message_split[1] == 'END':
                                    sleep_end = datetime.datetime.now()
                                    if sleep_end.hour > int(message_split[2]):
                                        sleep_end += datetime.timedelta(days=1)
                                    sleep_end = sleep_end.replace(hour=int(message_split[2]))
                                    sleep_end = sleep_end.replace(minute=int(message_split[3]))
                                    print('end sleep mode tweet received')
                                    twitter.send_direct_message(
                                        text='Sleep mode will end on ' + sleep_end.strftime('%H:%M'),
                                        screen_name=tc.ok_user_id)
                                else:
                                    # use the default sleep settings
                                    sleep_start = datetime.datetime.now()
                                    if sleep_start.hour > sleep_start_hour_default:
                                        sleep_start += datetime.timedelta(days=1)
                                    sleep_start = sleep_start.replace(hour=sleep_start_hour_default)
                                    sleep_start = sleep_start.replace(minute=sleep_start_minute_default)
                                    sleep_end = datetime.datetime.now()
                                    if sleep_end.hour > sleep_end_hour_default:
                                        sleep_end += datetime.timedelta(days=1)
                                    sleep_end = sleep_end.replace(hour=sleep_end_hour_default)
                                    sleep_end = sleep_end.replace(minute=sleep_end_minute_default)
                                    print('default sleep mode')
                                    twitter.send_direct_message(
                                        text='Default Sleep mode enabled. Sleep mode will start on ' + sleep_start.strftime(
                                            '%H:%M'), screen_name=tc.ok_user_id)
                                    twitter.send_direct_message(
                                        text='Sleep mode will end on ' + sleep_end.strftime('%H:%M'),
                                        screen_name=tc.ok_user_id)

                            except:
                                print('issues with sleep mode tweet read')
                        elif message_split[0] == 'SET':
                            # set the new thermostat temp
                            thermostat_temp = int(message_split[1])
                            # put the  the psql database
                            try:
                                psql.sendSQL("DELETE FROM therm WHERE min > 0 OR min <= 0;")
                                psql.sendSQL("INSERT INTO therm VALUES (" + str(thermostat_temp) + ", " +
                                             str(thermostat_range) + ");")
                                #psql.sendSQL("UPDATE therm SET now = " + tempFstr + ";")
                            except Exception as e:
                                exc_type, exc_obj, exc_tb = sys.exc_info()
                                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                                print(exc_type, fname, exc_tb.tb_lineno)
                                print("Postgresql error!")
                            twitter.send_direct_message(text='Thermostat temp set to ' + message_split[1],
                                                        screen_name=tc.ok_user_id)
                        elif message_split[0] == 'RANGE':
                            # set the new thermostat range
                            thermostat_range = int(message_split[1])
                            twitter.send_direct_message(
                                text='Thermostat max temp set to ' + str(int(message_split[1]) + thermostat_temp),
                                screen_name=tc.ok_user_id)
                            try:
                                psql.sendSQL("DELETE FROM therm WHERE min > 0 OR min <= 0;")
                                psql.sendSQL("INSERT INTO therm VALUES (" + str(thermostat_temp) + ", " +
                                             str(thermostat_range) + ");")
                            except Exception as e:
                                exc_type, exc_obj, exc_tb = sys.exc_info()
                                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                                print(exc_type, fname, exc_tb.tb_lineno)
                                print("Postgresql error!")

                        elif message_split[0] == 'ON':
                            # turn on thermostat mode
                            thermostat_mode = 1
                            psql.sendSQL("UPDATE status SET thermostat = true;")
                            twitter.send_direct_message(text='Thermostat mode turned on', screen_name=tc.ok_user_id)
                        elif message_split[0] == 'OFF':
                            # turn off thermostat mode
                            thermostat_mode = 0
                            psql.sendSQL("UPDATE status SET thermostat = false;")
                            twitter.send_direct_message(text='Thermostat mode turned off', screen_name=tc.ok_user_id)
                        elif message_split[0] == 'STATUS':
                            # send the status of the thermostat
                            message_to_send = 'Temp: %1.1f, Thermostat Mode: %d,  T Range: %d-%d,  Home: %d' % \
                                              (tlr.get_temp(), thermostat_mode, thermostat_temp,
                                               thermostat_temp+thermostat_range, iPhoneStatusOld)
                            twitter.send_direct_message(text=message_to_send, screen_name=tc.ok_user_id)
                        else:
                            print('unknown twitter command!')
                            twitter.send_direct_message(text='Did not understand command', screen_name=tc.ok_user_id)
                    except Exception as e:
                        exc_type, exc_obj, exc_tb = sys.exc_info()
                        fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                        print(exc_type, fname, exc_tb.tb_lineno)
                        print('twitter sending error')
            try:
                twitter.destroy_direct_message(id=message_id)
                print('direct message destroyed')
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                print(exc_type, fname, exc_tb.tb_lineno)
                print('error deleting direct message!')
        # end of the tweet check

    # see if we should check if the iphone is here
    if iPhoneCheckTime < currentTime and not thermostat_always_off:
        # update the iPhone check time
        iPhoneCheckTime = currentTime + deltaIPhoneCheck
        # ping the iphone
        try:
            ping_response = Popen(["ping", iPhoneIP, '-c 1'], stdout=PIPE).stdout.read()
            pid = Popen(["arp", "-a", iPhoneIP], stdout=PIPE)
            arp_output = pid.communicate()[0].split()
            # see if iphone is connected
            if iPhoneMAC in arp_output:
                iPhoneStatusNew = 1
                if iPhoneStatusNew != iPhoneStatusOld:
                    thermostat_mode = 1
                    psql.sendSQL("UPDATE status SET thermostat = true;")
                    twitter.send_direct_message(text='You came home! Thermostat mode turned on',
                                                screen_name=tc.ok_user_id)
                iPhoneStatusOld = 1
            else:
                # iphone is disconnected!
                iPhoneStatusNew = 0
                if iPhoneStatusNew != iPhoneStatusOld:
                    # we have a switch (I just left home)
                    # turn off the thermostat mode and all outlets
                    thermostat_mode = 0
                    psql.sendSQL("UPDATE status SET thermostat = false;")
                    twitter.send_direct_message(text='You left the house!  Thermostat mode and all outlets turned off.',
                                                screen_name=tc.ok_user_id)
                    rc.offAll(twitter)
                iPhoneStatusOld = 0
        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            print('Error with iphone pinging')

    # see if we should check if the camera sees something
    if cameraCheckTime < currentTime:
        cameraCheckTime = currentTime+deltaCameraCheck
        # check the camera
        # camera.capture(image_filename)

    # see if we should activate heaters
    if activateHeatersCheckTime < currentTime and not thermostat_always_off:
        # update the activate heaters checktime
        activateHeatersCheckTime = currentTime + deltaActivateHeaters
        if activate_heaters > 0:
            if active_heaters[0]:
                rc.onAll(twitter, sendMessage=False)
            if active_heaters[1]:
                rc.on1(twitter, sendMessage=False)
            if active_heaters[2]:
                rc.on2(twitter, sendMessage=False)
            if active_heaters[3]:
                rc.on3(twitter, sendMessage=False)
            if active_heaters[4]:
                rc.on4(twitter, sendMessage=False)
        elif activate_heaters < 0:
            # turn off heat
            if active_heaters[0]:
                rc.offAll(twitter, sendMessage=False)
            if active_heaters[1]:
                rc.off1(twitter, sendMessage=False)
            if active_heaters[2]:
                rc.off2(twitter, sendMessage=False)
            if active_heaters[3]:
                rc.off3(twitter, sendMessage=False)
            if active_heaters[4]:
                rc.off4(twitter, sendMessage=False)


"""_summary_
"""
import logging
import pika
from pika.exceptions import AMQPError
from src.settings import QUEUE

class QueueRabbitmq():
    """_summary_
    """

    def __init__(self, queue_name: str):
        """_summary_
        """
        self.__connection = None
        self.__channel = None
        self.__queue_name = queue_name

    def __create_connection(self):
        """_summary_
        """
        self.__connection = pika.BlockingConnection(
            pika.ConnectionParameters(
                host=QUEUE["QUEUE_HOST"],
                port=QUEUE["QUEUE_PORT"]
            ))
        self.__channel = self.__connection.channel()
        self.__channel.queue_declare(queue=self.__queue_name)

    def send_message(self, message: str):
        """_summary_
        """
        try:
            self.__create_connection()
            self.__channel.basic_publish(
                exchange='', routing_key=self.__queue_name, body=message)
            self.__connection.close()
        except AMQPError as ex:
            logging.error(ex.args)

    def receive_message(self):
        """_summary_
        """
        self.__create_connection()
        method_frame, header_frame, body = self.__channel.basic_get(
            self.__queue_name
        )

        if method_frame:
            self.__channel.basic_ack(method_frame.delivery_tag)

        self.__connection.close()
        return method_frame, body

    def queue_purge(self):
        """_summary_
        """
        self.__create_connection()
        self.__channel.queue_purge(self.__queue_name)


import os
import sys
from flask import Flask, jsonify, request, abort, send_file
from dotenv import load_dotenv
from linebot import LineBotApi, WebhookParser
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
from fsm import TocMachine
from utils import send_text_message

import configparser

load_dotenv()

machine = TocMachine(
    states=["user", "help",
            "new", "hot", "search", "name",
            "taiwan", "usa", "week",
            "hot_drama", "type_drama", "hot_taiwan",
            "china", "hongkong", "japan", "korea", "america", "england",
            ],
    transitions=[
        {
            "trigger": "advance",
            "source": "user",
            "dest": "help",
            "conditions": "is_going_to_help",
        },
        {
            "trigger": "advance",
            "source": "user",
            "dest": "new",
            "conditions": "is_going_to_new",
        },
        {
            "trigger": "advance",
            "source": "user",
            "dest": "hot",
            "conditions": "is_going_to_hot",
        },
        {
            "trigger": "advance",
            "source": "user",
            "dest": "search",
            "conditions": "is_going_to_search",
        },

        {
            "trigger": "advance",
            "source": "search",
            "dest": "name",
            "conditions": "is_going_to_name",
        },

        {
            "trigger": "advance",
            "source": "user",
            "dest": "taiwan",
            "conditions": "is_going_to_taiwan",
        },
        {
            "trigger": "advance",
            "source": "user",
            "dest": "usa",
            "conditions": "is_going_to_usa",
        },
        {
            "trigger": "advance",
            "source": "user",
            "dest": "week",
            "conditions": "is_going_to_week",
        },

        {
            "trigger": "advance",
            "source": "user",
            "dest": "hot_taiwan",
            "conditions": "is_going_to_hot_taiwan",
        },
        {
            "trigger": "advance",
            "source": "user",
            "dest": "hot_drama",
            "conditions": "is_going_to_hot_drama",
        },
        {
            "trigger": "advance",
            "source": "user",
            "dest": "type_drama",
            "conditions": "is_going_to_type_drama",

        },
        {
            "trigger": "advance",
            "source": "type_drama",
            "dest": "china",
            "conditions": "is_going_to_china",
        },
        {
            "trigger": "advance",
            "source": "type_drama",
            "dest": "hongkong",
            "conditions": "is_going_to_hongkong",
        },
        {
            "trigger": "advance",
            "source": "type_drama",
            "dest": "japan",
            "conditions": "is_going_to_japan",
        },
        {
            "trigger": "advance",
            "source": "type_drama",
            "dest": "korea",
            "conditions": "is_going_to_korea",
        },
        {
            "trigger": "advance",
            "source": "type_drama",
            "dest": "america",
            "conditions": "is_going_to_america",
        },
        {
            "trigger": "advance",
            "source": "type_drama",
            "dest": "england",
            "conditions": "is_going_to_england",
        },

        {
            "trigger": "advance",
            "source": ["china", "hongkong", "japan", "korea", "america", "england"],
            "dest": "type_drama",
            "conditions": "is_going_to_back",
        },

        {
            "trigger": "advance",
            "source": "name",
            "dest": "search",
            "conditions": "is_going_to_back",
        },

        {
            "trigger": "advance",
            "source": ["china", "hongkong", "japan", "korea", "america", "england"
                        , "name"],
            "dest": "help",
            "conditions": "is_going_to_home",
        },

        {
            "trigger": "go_back",
            "source": [ "help",
                        "new", "hot",
                        # "movie", "tv", "search_movie",
                        "taiwan", "usa", "week",
                        "hot_drama", "hot_taiwan",
                        # "china", "hongkong", "japan", "korea", "america", "england"
                        ],
            "dest": "user"
        }
    ],
    initial="user",
    auto_transitions=False,
    show_conditions=True,
)

app = Flask(__name__, static_url_path="")

# read config
config = configparser.ConfigParser()
config.read("config.ini")

# get channel_secret and channel_access_token from your environment variable
# channel_secret = os.getenv("LINE_CHANNEL_SECRET", None)
# channel_access_token = os.getenv("LINE_CHANNEL_ACCESS_TOKEN", None)

# get channel_secret and channel_access_token from your environment variable
channel_access_token = config['line_bot']['Channel_Access_Token']
channel_secret = config['line_bot']['Channel_Secret']

# print(channel_access_token)
# print(channel_secret)

if channel_secret is None:
    print("Specify LINE_CHANNEL_SECRET as environment variable.")
    sys.exit(1)
if channel_access_token is None:
    print("Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.")
    sys.exit(1)

line_bot_api = LineBotApi(channel_access_token)
parser = WebhookParser(channel_secret)

# echo
@app.route("/callback", methods=["POST"])
def callback():
    signature = request.headers["X-Line-Signature"]
    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # parse webhook body
    try:
        events = parser.parse(body, signature)
    except InvalidSignatureError:
        abort(400)

    # if event is MessageEvent and message is TextMessage, then echo text
    for event in events:
        if not isinstance(event, MessageEvent):
            continue
        if not isinstance(event.message, TextMessage):
            continue

        line_bot_api.reply_message(
            event.reply_token, TextSendMessage(text=event.message.text)
        )

    return "OK"

# main function
@app.route("/webhook", methods=["POST"])
def webhook_handler():
    signature = request.headers["X-Line-Signature"]
    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info(f"Request body: {body}")

    # parse webhook body
    try:
        events = parser.parse(body, signature)
    except InvalidSignatureError:
        abort(400)

    # if event is MessageEvent and message is TextMessage, then echo text
    for event in events:
        if not isinstance(event, MessageEvent):
            continue
        if not isinstance(event.message, TextMessage):
            continue
        if not isinstance(event.message.text, str):
            continue
        print(f"\nFSM STATE: {machine.state}")
        print(f"REQUEST BODY: \n{body}")
        response = machine.advance(event)
        if response == False:
            send_text_message(event.reply_token, "Not Entering any State")

    return "OK"

# draw the fsm img
@app.route("/show-fsm", methods=["GET"])
def show_fsm():
    machine.get_graph().draw("fsm.png", prog="dot", format="png")
    return send_file("fsm.png", mimetype="image/png")

if __name__ == "__main__":
    port = os.environ.get("PORT", 5000)
    app.run(host="0.0.0.0", port=port, debug=True)


from __future__ import division
import random
import scipy.stats as ss
import numpy as np
import copy
import seaborn as sns
import matplotlib.pyplot as plt

arr = np.array

class Door(object):
    def __init__(self, prob_open, name, verbose=False):
        self.p = prob_open
        self.name = name
        self.verbose = verbose

    def push(self):
        result = random.random() < self.p
        if self.verbose:
            print("{} (prob_open={}) {}".format(
                self.name, self.p,
                "opened" if result else "didn't open"
            ))
        return result

class DoorBel(object):
    """"DoorBel is a beta dist."""
    def __init__(self, name, opened=1, closed=1):
        self.name = name
        # uninformed prior
        self.opened = opened
        self.closed = closed

    def __str__(self):
        return "Beta(opened={}, closed={}) --> H={}".format(
            self.opened, self.closed, self.entropy()
        )

    def entropy(self):
        return ss.beta(self.opened, self.closed).entropy()

    def exp_diff_H(self):
        H = self.entropy()
        # prob for outcome "a" and "b"
        P_a = self.mean()
        P_b = 1 - P_a
        # entropy for outcome "a" and "b"
        H_a = ss.beta.entropy(self.opened + 1, self.closed)
        H_b = ss.beta.entropy(self.opened, self.closed + 1)
        # new estimated entropy
        H_est = (P_a * H_a + P_b * H_b)
        # change of H
        exp_diff = H - H_est

        return exp_diff

    def update(self, opened):
        if opened:
            self.opened += 1
        else:
            self.closed += 1

    def mean(self):
        return ss.beta.mean(self.opened, self.closed)

    def likelihood(self, loc):
        return ss.beta.pdf(loc, self.opened, self.closed)

    def logpdf(self, loc):
        return ss.beta.logpdf(loc, self.opened, self.closed)

###############################################################################
def init():
    world = [Door(1, "d0"), Door(.2, "d1")]
    belief = [DoorBel(door.name) for door in world]
    return world, belief

def init_all_openable(num=2):
    world = [Door(1, "d" + str(i)) for i in range(num)]
    belief = [DoorBel(door.name) for door in world]
    return world, belief

def init_all_openable_big():
    return init_all_openable(num=5)

def init_some_openable_big(num=5):
    world = [Door(i % 2, "d" + str(i)) for i in range(num)]
    belief = [DoorBel(door.name) for door in world]
    return world, belief

def init_stochastic_world(num=5):
    world = [Door(1 / (i+1), "d" + str(i)) for i in range(num)]
    belief = [DoorBel(door.name) for door in world]
    return world, belief

###############################################################################
def run_experiment(world, belief, select_strategy, num_interactions,
                   observation_model=None):
    """Run the given `select_strategy` for the given `num_inteactions` and
    return the complete histroy of the belief for further analysis.

    """
    bel_history = []
    for i in range(num_interactions):

        idx = select_strategy(belief)
        opened = world[idx].push()
        if observation_model:
            opened = observation_model(opened)
        belief[idx].update(opened)

        bel_history.append(copy.deepcopy(belief))
    return bel_history

def multi_run(f_init, strategy_name, select_strategy, num_interactions=100,
              runs=50, observation_model=None):
    """Execute multiple runs of the given strategy (with the given parameters).

    """
    print(strategy_name)

    # often used stuff
    world, belief = f_init()
    num_objects = len(world)
    names = [door.name for door in world]

    # Initialze arrays that we need throughout the runs
    entropy_obj = np.empty((runs, num_interactions, num_objects))
    entropy_total = np.zeros((runs, num_interactions))

    expected_diff_H_obj = np.empty_like(entropy_obj)
    expected_diff_H_total = np.ones_like(entropy_total)

    likelihood_obj = np.empty_like(entropy_obj)
    likelihood_total = np.ones_like(entropy_total)

    log_likelihood_obj = np.empty_like(entropy_obj)
    log_likelihood_total = np.ones_like(entropy_total)

    estimated_p_obj = np.empty_like(entropy_obj)
    real_p_obj = [np.full((1, num_interactions), world[i].p)
                  for i in range(num_objects)]

    error_obj = np.empty_like(entropy_obj)
    error_total = np.zeros_like(entropy_total)

    squared_error_obj = np.empty_like(entropy_obj)
    squared_error_total = np.zeros_like(entropy_total)

    summary = {}
    data = {}

    #========================================================================
    # RUN multiple times
    for run in range(runs):
        world, belief = f_init()
        bel = run_experiment(world, belief, select_strategy, num_interactions,
                             observation_model)

        #======================================================================
        # COLLECT AND SUMMARIZE DATA
        for obj in range(num_objects):
            # Entropy over time
            entropy_obj[run, :, obj] = arr([b[obj].entropy() for b in bel])
            entropy_total[run, :] += entropy_obj[run, :, obj]

            # Expected change of entropy over time
            expected_diff_H_obj[run, :, obj] = arr([b[obj].exp_diff_H()
                                                    for b in bel])
            expected_diff_H_total[run, :] += expected_diff_H_obj[run, :, obj]
            # Esimate over time
            estimated_p_obj[run, :, obj] = arr([b[obj].mean() for b in bel])

            # Error over time: abs(p_true, p_estimated)
            error_obj[run, :, obj] = np.abs(real_p_obj[obj] -
                                            estimated_p_obj[run, :, obj])
            error_total[run, :] += error_obj[run, :, obj]

            # Squared error over time
            squared_error_obj[run, :, obj] = error_obj[run, :, obj]**2
            squared_error_total[run, :] += squared_error_obj[run, :, obj]

            # Likelihood over time
            likelihood_obj[run, :, obj] = arr([b[obj].likelihood(world[obj].p)
                                               for b in bel])
            likelihood_total[run, :] *= likelihood_obj[run, :, obj]

            log_likelihood_obj[run, :, obj] = arr([b[obj].logpdf(world[obj].p)
                                                   for b in bel])
            log_likelihood_total[run, :] *= log_likelihood_obj[run, :, obj]

    data["error"] = error_total
    data["MSE"] = squared_error_total
    data["entropy"] = entropy_total
    data["expected_diff_H"] = expected_diff_H_total
    data["likelihood"] = likelihood_total
    data["log_likelihood"] = log_likelihood_total

    summary["error"] = error_total.mean()
    summary["MSE"] = squared_error_total.mean()
    summary["entropy"] = entropy_total.mean()
    summary["expected_diff_H"] = expected_diff_H_total[:, -1].mean()
    summary["likelihood"] = likelihood_total[:, -1].mean()
    summary["log_likelihood"] = log_likelihood_total[:, -1].mean()

    #========================================================================
    # PLOT strategies seperately
    fig, (ax1, ax2, ax3, ax4, ax5, ax6) = plt.subplots(1, 6, figsize=(22, 4))
    plt.suptitle(strategy_name, fontsize=14)
    colors = sns.color_palette()
    c3 = colors[3]

    # estimate over time
    ax = ax1
    sns.tsplot(estimated_p_obj, condition=names, ax=ax)
    for obj in range(num_objects):
        sns.tsplot(real_p_obj[obj], color="grey", label="real p", ax=ax)
    ax.set_ylim((0, 1))
    ax.set_title("Estimate over time")

    # error over time
    # ax = axX
    # sns.tsplot(error_obj, condition=names, ax=ax)
    # sns.tsplot(error_total, condition=["total"], color=c3, ax=ax)
    # ax.set_title("Error over time for " + strategy_name)

    # squared error over time
    ax = ax2
    sns.tsplot(squared_error_obj, condition=names, ax=ax)
    sns.tsplot(squared_error_total, condition=["total"], color=c3, ax=ax)
    ax.set_title("Squared error over time")

    # entropy over time
    ax = ax3
    sns.tsplot(entropy_obj, condition=names, ax=ax)
    sns.tsplot(entropy_total, condition=["toatl"], color=c3, ax=ax)
    ax.set_title("Entropy over time")

    # expected change of entropy
    ax = ax4
    sns.tsplot(expected_diff_H_obj, condition=names, ax=ax)
    ax.set_title("Expected change of Entropy")

    # likelihood over time
    ax = ax5
    sns.tsplot(likelihood_obj, condition=names, ax=ax)
    sns.tsplot(likelihood_total, condition=["total"], color=c3, ax=ax)
    ax.set_title("Likelihood over time")

    # log likelihood over time
    ax = ax6
    sns.tsplot(log_likelihood_obj, condition=names, ax=ax)
    sns.tsplot(log_likelihood_total, condition=["total"], color=c3, ax=ax)
    ax.set_title("Log-likelihood over time")

    return summary, data


from flask import Flask, render_template, url_for, request, jsonify
from flask_sqlalchemy import SQLAlchemy
import config

app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)

class Student(db.Model):
    __tablename__ = 'students'
    id = db.Column(db.Integer, primary_key = True, autoincrement = True)
    phoneNum = db.Column(db.String(11), nullable = False, unique = True)
    userName = db.Column(db.String(16), nullable = False)
    course = db.Column(db.String(10), nullable = False)
    Number = db.Column(db.Integer, nullable = False)

@app.route('/yike')
def index():
    return render_template('index.html')

@app.route('/info', methods = ['POST'])
def addInfo():
    ntfInfo = {'result' : 'error'}
    if request.method == 'POST':
        data = request.get_json()
        phoneNum = data.get('phoneNum')
        userName = data.get('userName')
        course = data.get('course')
        Number = data.get('Number')

        if None != phoneNum and None != userName and None != course and None != Number:
            if Student.query.filter_by(phoneNum = phoneNum).first() == None:
                student = Student(phoneNum = phoneNum, userName = userName, course = course, Number = Number)
                db.session.add(student)
                db.session.commit()
                ntfInfo['result'] = 'success'
            else:
                ntfInfo['result'] = 'already_exist'

        return jsonify(ntfInfo)

if __name__ == '__main__':

    app.debug = True
    app.run()


#!/usr/bin/env python

# encoding: utf-8

# @Time    : 2019/10/28 15:18
# @Author  : yq
# @Site    :
# @File    : FTPManager.py
# @Software: PyCharm
import os
import socket
import configparser
import time
from ftplib import FTP

import codecs

# config_path = r'E:\projects\pycharm\NearGoos\background\byQY\config\Config.ini'
class FTPManager:
    def __init__(self, config_path, section):
        self.config_path = config_path
        self.ftp = FTP()
        self.section = section

        # 重新设置下编码方式
        self.ftp.encoding = 'UTF-8'

    def ftp_connect(self, host, username, password):
        """
        连接FTP
        :param host: 主机地址
        :param username: 用户名
        :param password: 密码
        :return:
        """
        # socket.setdefaulttimeout(3600)

        self.ftp.connect(host)
        self.ftp.login(username, password)

    def get_file_info_list(self, filepath):
        """
        以文本的方式获得文件信息列表
        :param filepath: 文件目录
        :return:
        """
        self.ftp.cwd(filepath)
        file_list = self.ftp.retrlines('MLSD')
        # file_list = self.ftp.nlst()
        # print(file_list)
        return file_list

    def get_config(self):
        """
        获取配置文件信息
        :return: 配置文件类
        """
        config = configparser.ConfigParser()
        config.read(self.config_path)
        return config

    def close_connect(self):
        """
        关闭FTP链接
        :return:
        """
        self.ftp.close()

    def get_filename(self, file_need, filepath):
        """
        返回指定文件名的文件目录
        :param file_need: 需被匹配的文件名
        :param filepath: 文件目录
        :return: 文件名数组
        """
        self.ftp.cwd(filepath)
        files = [filename for filename in self.ftp.nlst() if file_need in filename]
        return files

    def get_file_size(self, file_need, filepath):
        self.ftp.cwd(filepath)
        files = [filename for filename in self.ftp.nlst() if file_need in filename]
    # # 存储
    # def upload(self, target_path, old_path):
    #     fp = open(old_path, "rb")
    #     buf_size = 1024
    #     self.storbinary("STOR {}".format(target_path), fp, buf_size)
    #     fp.close()
    # def is_exist_file(self, local_file, remote_file):
    #     str_year = self.getCreateTime(self, remote_file)
    #

    def is_same_size(self, local_file, remote_file):
        """
        判断远程文件和本地文件大小是否一致
        :param local_file: 本地文件
        :param remote_file: 远程文件
        :return: 是否一致的布尔值
        """

        try:
            remote_file_size = self.ftp.size(remote_file)
        except Exception as err:
            # self.debug_print("is_same_size() 错误描述为：%s" % err)
            remote_file_size = -1
        try:
            local_file_size = os.path.getsize(local_file)
        except Exception as err:
            # self.debug_print("is_same_size() 错误描述为：%s" % err)
            local_file_size = -1
        # self.debug_print('local_file_size:%d  , remote_file_size:%d' % (local_file_size, remote_file_size))
        if remote_file_size == local_file_size:
            return 1
        else:
            return 0

    # [to-do] 此处可增加为批量下载
    def download_file(self, local_file, remote_file, local_file_dir):
        """
        下载远程文件至本地
        :param local_file:本地文件
        :param remote_file:远程文件
        :return:
        """
        if os.path.exists(local_file):
            # self.debug_print('%s 文件大小相同，无需下载' % local_file)
            print('文件已有无需下载')
            return 0
        else:
            if not os.path.exists(local_file_dir):
                os.makedirs(local_file_dir)
            # self.debug_print('>>>>>>>>>>>>下载文件 %s ... ...' % local_file)
            buf_size = 1024
            file_handler = open(local_file, 'wb')
            self.ftp.retrbinary('RETR %s' % remote_file, file_handler.write, buf_size)
            file_handler.close()
            print('下载数据成功')
            with open(local_file, 'rb+') as fp:
                content = fp.read()
                try:
                    #
                    content.decode("utf8")
                except:
                    content = content.decode("ANSI",'ignore').encode("utf8")
                    fp.seek(0)
                    fp.write(content)
                fp.close()
            print('转码成功')

            return 1

    def upload_file(self, local_file, remote_file):
        """
        从本地上传文件至FTP
        :param local_path:
        :param remote_path:
        :return:
        """
        if not os.path.isfile(local_file):
            # self.debug_print('%s 不存在' % local_file)
            print('不存在')
            return
        if self.is_same_size(local_file, remote_file):
            # self.debug_print('%s 文件大小相同，无需上传' % local_file)
            print('大小相同无需上传')
            return

        buff_size = 1024

        file_handler = open(local_file, 'rb')
        self.ftp.storbinary('STOR %s' % remote_file, file_handler, buff_size)
        file_handler.close()
        # self.debug_print('上传: %s' % local_file + "成功!")
        print('上传成功')

    # 获取年份
    def getCreateTime(self, remote_file):
       L = list(self.ftp.sendcmd('MDTM ' + remote_file))
       str = L[4]+L[5]+L[6]+L[7]
       return str


import sqlite3
import os

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH = os.path.join(BASE_DIR, 'projects.db')
HEADERS = {
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}

def connect_db():
    conn = sqlite3.connect(DB_PATH)
    return conn

def create_table(conn):
    cur = conn.cursor()
    cur.execute('''CREATE TABLE IF NOT EXISTS projects
                   (id INTEGER PRIMARY KEY AUTOINCREMENT,
                    title TEXT NOT NULL,
                    link TEXT NOT NULL,
                    description TEXT)''')
    conn.commit()

def insert_data(conn, data):
    cur = conn.cursor()
    cur.execute('''INSERT INTO projects(title, link, description)
                   VALUES (?, ?, ?)''', (data['title'], data['link'], data['description']))
    conn.commit()


from PIL import Image

weights = Image.open("weights.png")

for i in range(1, 11):
    case = Image.open(f"cases/{i}.png")
    circle = 0
    for x in range(case.height):
        for y in range(case.width):
            casePixel = case.getpixel((x, y))
            weightPixel = weights.getpixel((x, y))

            weightSum = ((weightPixel[3] - 225) / 10) / \
                (case.height * case.width)

            if casePixel == (0, 0, 0, 255) and circle < 1:
                circle += weightSum
            elif circle == 1:
                circle -= weightSum

    print(f"{i}: c") if circle > (1 - circle) else print(f"{i}: r")


import sqlalchemy as sa
import sqlalchemy.orm as orm
from mealie.core import root_logger
from mealie.db.models.model_base import SqlAlchemyBase
from slugify import slugify
from sqlalchemy.orm import validates

logger = root_logger.get_logger()

site_settings2categories = sa.Table(
    "site_settings2categories",
    SqlAlchemyBase.metadata,
    sa.Column("site_settings.id", sa.Integer, sa.ForeignKey("site_settings.id")),
    sa.Column("category_id", sa.Integer, sa.ForeignKey("categories.id")),
)

group2categories = sa.Table(
    "group2categories",
    SqlAlchemyBase.metadata,
    sa.Column("group_id", sa.Integer, sa.ForeignKey("groups.id")),
    sa.Column("category_id", sa.Integer, sa.ForeignKey("categories.id")),
)

recipes2categories = sa.Table(
    "recipes2categories",
    SqlAlchemyBase.metadata,
    sa.Column("recipe_id", sa.Integer, sa.ForeignKey("recipes.id")),
    sa.Column("category_id", sa.Integer, sa.ForeignKey("categories.id")),
)

custom_pages2categories = sa.Table(
    "custom_pages2categories",
    SqlAlchemyBase.metadata,
    sa.Column("custom_page_id", sa.Integer, sa.ForeignKey("custom_pages.id")),
    sa.Column("category_id", sa.Integer, sa.ForeignKey("categories.id")),
)

class Category(SqlAlchemyBase):
    __tablename__ = "categories"
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String, index=True, nullable=False)
    slug = sa.Column(sa.String, index=True, unique=True, nullable=False)
    recipes = orm.relationship("RecipeModel", secondary=recipes2categories, back_populates="recipe_category")

    @validates("name")
    def validate_name(self, key, name):
        assert name != ""
        return name

    def __init__(self, name, session=None) -> None:
        self.name = name.strip()
        self.slug = slugify(name)

    def update(self, name, session=None) -> None:
        self.__init__(name, session)

    @staticmethod
    def get_ref(session, slug: str):
        return session.query(Category).filter(Category.slug == slug).one()

    @staticmethod
    def create_if_not_exist(session, name: str = None):
        test_slug = slugify(name)
        result = session.query(Category).filter(Category.slug == test_slug).one_or_none()
        if result:
            logger.debug("Category exists, associating recipe")
            return result
        else:
            logger.debug("Category doesn't exists, creating tag")
            return Category(name=name)


from __future__ import division
import json
import sys

transi_dic = {'_starting_tag': {'_ending_tag': '_count'}}
#transition diction has the format as transi_dic = [starting_tag][ending_tag]
transi_pro_dic = {}

#construct the transition probability
def transi_occurance_compute(line):
 container = line.split(' ')
 index = 0
 while index < len(container)-1:
  initial_tag = container[index].split('/')
  end_tag = container[index+1].split('/')
  index = index + 1
  if transi_dic.has_key(initial_tag[1]) == False:
    transi_dic[initial_tag[1]] = {}
    #initialize the count to be 1
    transi_dic[initial_tag[1]]['count'] = 1.0
    transi_dic[initial_tag[1]][end_tag[1]] = 1.0
  else:
    transi_dic[initial_tag[1]]['count'] = transi_dic[initial_tag[1]]['count'] + 1
    if transi_dic[initial_tag[1]].has_key(end_tag[1]) == False:
        transi_dic[initial_tag[1]][end_tag[1]] = 1.0
    else:
        transi_dic[initial_tag[1]][end_tag[1]] = transi_dic[initial_tag[1]][end_tag[1]] + 1

def transition_prob_compute():
  for key,value in transi_dic.items():
    count = 1.0
    transi_pro_dic[key] = {}
    if type(value) is dict:
      for k,v in value.items():
        if value.has_key('count'):
          v = v/value['count']
        if k != 'count':
          transi_pro_dic[key][k] = v

#emission diction has the format as transi_dic = [word][tag]
emission_dic = {'_word': {'_tag': '_count'}}
emission_prob_dic = {}

#construct the emission probability
def emission_occurance_compute(line):
  container = line.split(' ')
  emission_index = 0
  while emission_index < len(container)-1:
    word = container[emission_index].split('/')[0]
    tag = container[emission_index].split('/')[1]
    emission_index = emission_index + 1
    if emission_dic.has_key(str(tag)) == False:
      emission_dic[str(tag)] = {}
      #initialize the count to be 1
      emission_dic[str(tag)]['count'] = 1.0
      emission_dic[str(tag)][word] = 1.0
    else:
      emission_dic[str(tag)]['count'] = emission_dic[str(tag)]['count'] + 1
      if emission_dic[str(tag)].has_key(word) == False:
        emission_dic[str(tag)][word] = 1.0
      else:
        emission_dic[str(tag)][word] = emission_dic[str(tag)][word] + 1

def emission_prob_compute():
  for key,value in emission_dic.items():
    count = 1.0
    emission_prob_dic[key] = {}
    if type(value) is dict:
      for k,v in value.items():
        if value.has_key('count'):
          v = v/value['count']
          emission_prob_dic[key][k] = v

#Execute the function defined above
with open(sys.argv[1]) as ft:
    for line in ft:
        transi_occurance_compute(line)
        emission_occurance_compute(line)

#call the computation function once for probability
transition_prob_compute()
emission_prob_compute()

output_json_data = {}
output_json_data['transi_pro_dic'] = transi_pro_dic
output_json_data['emission_prob_dic'] = emission_prob_dic

with open('hmmmodel.txt', 'w') as outfile:
    json.dump(output_json_data,outfile, sort_keys = True, indent = 4,ensure_ascii=False)
outfile.close()


import requests
from bs4 import BeautifulSoup
import shutil
import os

res = requests.get("https://www.imdb.com/list/ls050274118/")
res = requests.get("https://www.imdb.com/list/ls063784435/")

#print(res.text)

soup = BeautifulSoup(res.text,features="html.parser")

matches = soup.findAll("div", {"class":"lister-item-image"})
for m in matches:
    print(m)
    children = m.findChildren("img" , recursive=True)
    for child in children:
        print (child['alt'])
        response = requests.get(child['src'], stream=True)
        os.mkdir('knn_examples/train/'+str(child['alt']))
        with open("knn_examples/train/"+str(child['alt']) + "/" + str(child['alt']) +".png", 'wb') as out_file:
            shutil.copyfileobj(response.raw, out_file)
        del response