bl_info = {
	"name": "Pie Rotate_90",
	"description": "Rotate 90",
	"author": "Vaughan Ling",
	"version": (0, 1, 0),
	"blender": (2, 80, 0),
	"location": "",
	"warning": "",
	"wiki_url": "",
	"category": "Pie Menu"
	}

import bpy, bmesh
from bpy.types import (
		Menu,
		Operator,
		)
import os
class HP_MT_pie_rotate90(Menu):
	bl_label = "Rotate_90"

	def draw(self, context):
		layout = self.layout
		pie = layout.menu_pie()
		# left
		pie.operator('view3d.rotate_90_and_flatten', text = 'Side', icon="CENTER_ONLY").direction = 'FX'
		# right
		pie.operator('view3d.rotate_90_and_flatten', text = 'Side', icon="FILE_REFRESH").direction = 'RX'

		pie.split()
		pie.split()

		pie.operator('view3d.rotate_90_and_flatten', text = 'Front', icon="CENTER_ONLY").direction = 'FY'

		pie.operator('view3d.rotate_90_and_flatten', text = 'Front', icon="FILE_REFRESH").direction = 'RY'

		# bottomleft
		pie.operator('view3d.rotate_90_and_flatten', text = 'Top', icon="CENTER_ONLY").direction = 'FZ'
		# bottomright
		pie.operator('view3d.rotate_90_and_flatten', text = 'Top', icon="FILE_REFRESH").direction = 'RZ'

class HP_OT_rotate_90_and_flatten(bpy.types.Operator):
	bl_idname = "view3d.rotate_90_and_flatten"
	bl_label = ""
	bl_options = {'REGISTER', 'UNDO'}
	direction: bpy.props.StringProperty(name="Direction")

	def execute(self, context):
		vertmode = False
		if context.object.type == 'MESH' and context.object.mode == 'EDIT':
			obj = bpy.context.object.data
			mesh = bpy.context.object.data
			totface = mesh.total_face_sel
			totedge = mesh.total_edge_sel
			totvert = mesh.total_vert_sel

			bm = bmesh.from_edit_mesh(obj)
			if tuple(bpy.context.scene.tool_settings.mesh_select_mode) == (True, False, False):
				if totvert == 1:
					vertmode = True
					print('single vert selected')
					scenepivot = bpy.context.scene.tool_settings.transform_pivot_point
					bpy.ops.view3d.snap_cursor_to_selected()
					bpy.context.scene.tool_settings.transform_pivot_point = 'CURSOR'
					bpy.ops.object.vertex_group_add()
					bpy.ops.object.vertex_group_assign()
					bpy.ops.mesh.select_linked(delimit=set())
			if totvert == 0:
				try:
					bpy.ops.mesh.select_all(action='SELECT')
				except:
					print('Object Mode')
#Rotate 90
		if self.direction == 'RZ':
			bpy.ops.transform.rotate(value=1.5708, orient_axis='Z', orient_type='GLOBAL', orient_matrix_type='GLOBAL', constraint_axis=(False, False, True))
		if self.direction == 'RY':
			bpy.ops.transform.rotate(value=1.5708, orient_axis='Y', orient_type='GLOBAL', orient_matrix_type='GLOBAL', constraint_axis=(False, True, False))
		if self.direction == 'RX':
			bpy.ops.transform.rotate(value=1.5708, orient_axis='X', orient_type='GLOBAL', orient_matrix_type='GLOBAL', constraint_axis=(True, False, False))

#bpy.ops.transform.rotate(value=1.5708, orient_axis='Z',  orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(False, False, True))

#Flattens
		if self.direction == 'FX':
			bpy.ops.transform.resize(value=(0, 1, 1), constraint_axis=(True, False, False), orient_matrix_type='GLOBAL')
		if self.direction == 'FY':
			bpy.ops.transform.resize(value=(1, 0, 1), constraint_axis=(False, True, False), orient_matrix_type='GLOBAL')
		if self.direction == 'FZ':
			bpy.ops.transform.resize(value=(1, 1, 0), constraint_axis=(False, False, True), orient_matrix_type='GLOBAL')
		if vertmode == True:
			bpy.ops.mesh.select_all(action='DESELECT')
			bpy.ops.object.vertex_group_select()
			bpy.ops.object.vertex_group_remove(all=False, all_unlocked=False)
			bpy.context.scene.tool_settings.transform_pivot_point = scenepivot
		return {'FINISHED'}
classes = (
	HP_MT_pie_rotate90,
	HP_OT_rotate_90_and_flatten
)
register, unregister = bpy.utils.register_classes_factory(classes)

if __name__ == "__main__":
	register()


from utils import TweetsMongoDB

from collections import Counter
from utils import User
from utils import Timeline
import json
from tqdm import tqdm
import time

from collections import Counter

def add_unique_id_count():
    cascades = records_cascade.find()
    for cascade in cascades:
        _id = cascade['_id']
        user_id_sequence = cascade['user_id_sequence']
        id_count = len(Counter(user_id_sequence))
        records_cascade.update_one(
            {'_id': _id},
            {'$set': {'meta.unique_id_count': id_count}})

def create_user_vector_to_list(query):
    results = []
    cascades = records_cascade.find(query)
    for cascade in cascades:
        _id = cascade['_id']
        user_vector_sequence = cascade['user_vector_sequence']
        length_5_timeline_max = cascade['length_5_timeline_max']
        rating = cascade['ground_truth']
        user_id = cascade['user_id_sequence'][0]

        engaged_users_vector = []

        # Get first 5 vectors
        # for i in range(5):
        #     engaged_users_vector.append(User(user_vector_sequence[i]).vector.tolist() + Timeline(length_5_timeline_max[i]).vector.tolist())

        for i in range(5):
            engaged_users_vector.append(Timeline(length_5_timeline_max[i]).vector.tolist())

        # engaged_users_vector = [User(user).vector.tolist() for user in user_vector_sequence[:5]]
        # length_5_timeline_max_vector = [Timeline(timeline).vector.tolist() for timeline in length_5_timeline_max[:5]]
        # print(engaged_users_vector)

    # end get 5 vectors

        if rating:
            rating = 1
        else:
            rating = 0

        if engaged_users_vector:
            results.append((engaged_users_vector, rating, user_id))

        # print(results)

    return results

def main():
    cascades_true = records_cascade.count_documents(
        {'ground_truth': True, 'meta.unique_id_count': {'$gte': 1}, 'user_vector_sequence': {'$nin': [0]},
         'user_vector_sequence': {'$size': 10}})
    cascades_false = records_cascade.count_documents(
        {'ground_truth': False, 'meta.unique_id_count': {'$gte': 1}, 'user_vector_sequence': {'$nin': [0]},
         'user_vector_sequence': {'$size': 10}})
    print('True: ', cascades_true)
    print('False: ', cascades_false)

    cascades_true = records_cascade.find(
        {'ground_truth': True, 'meta.unique_id_count': {'$gte': 1}, 'user_vector_sequence': {'$nin': [0]},
         'user_vector_sequence': {'$size': 10}})
    cascades_false = records_cascade.find(
        {'ground_truth': False, 'meta.unique_id_count': {'$gte': 1}, 'user_vector_sequence': {'$nin': [0]},
         'user_vector_sequence': {'$size': 10}})
    print('True: ', dict(Counter([cascade['root']['user_id'] for cascade in cascades_true])))
    print('False: ', dict(Counter([cascade['root']['user_id'] for cascade in cascades_false])))

def create_json(query):
    results = create_user_vector_to_list(query)
    for result in tqdm(results):
        with open('dataset.json', "at", encoding="utf-8") as output:
            output.write(json.dumps(result) + "\n")

if __name__ == '__main__':
    records_cascade = TweetsMongoDB('tweets2').db['fixed_length_cascade']
    # create_json({'user_vector_sequence': {'$nin': [0]}, 'user_vector_sequence.9': {'$exists': True},
    #              '_id_fixed_length_sequence': '1379138530841034752340040091934004009193400400919340040091934004009193400400919138685154556471296113868515455647129611386851545564712961'})
    # create_json(
    #     {'user_vector_sequence': {'$nin': [0]}, 'length_5_timeline_max.4': {'$exists': True}, 'length_5_unique': True})

    # for i in range(2):
    #     create_json(
    #         {'user_vector_sequence': {'$nin': [0]}, 'length_5_timeline_max.4': {'$exists': True}, 'ground_truth': True,
    #          'length_5_unique': True})
    main()


# HeatMiser implementation by Kerim Celik and Julia Connelly
import random
import numpy
from tabulate import tabulate

# helper class for displaying data
class Table:

    def __init__(self):
        self.bigTable = []
        self.tables = [[]]
        self.curTable = 0

    def nextTable(self):
        self.bigTable.append(self.tables[self.curTable])
        self.tables.append([])
        self.curTable += 1

    def addToTable(self, *arg):
        for i in arg:
            self.tables[self.curTable].append(i)

def getListAverage(ls):
    return sum(ls) / len(ls)

def getListStdDev(ls):
    return numpy.std(ls)

def inRange(num, opt):
    return opt <= num < opt + 1

def run():
    # set up rooms
    optTemp = 72
    optHumid = 47
    optTempDev = 1.5
    optHumidDev = 1.75
    temps = []
    humids = []
    for i in range(0, 12):
        temps.append(random.randint(65, 75))
        humids.append(random.randint(45, 55))

    # initialize variables
    index = 0
    count = 0
    avgTemp = getListAverage(temps)
    avgHumid = getListAverage(humids)
    stdDevTemp = getListStdDev(temps)
    stdDevHumid = getListStdDev(humids)
    avgTempGood = inRange(avgTemp, optTemp)
    avgHumidGood = inRange(avgHumid, optHumid)
    stdDevTempGood = stdDevTemp < optTempDev + 0.1
    stdDevHumidGood = stdDevHumid < optHumidDev + 0.01

    # initialize information display
    rooms = []
    for i in range(1, 13):
        rooms.append("Room " + str(i))
    rowIDs = ["Room Number", "Temp", "Humidity"]
    print("INITIAL STATE OF ROOMS")
    print(tabulate([rooms, temps, humids], showindex=rowIDs, tablefmt="grid"))
    print("\n")
    table = Table()

    # HeatMiser does the problem
    while not (avgTempGood and avgHumidGood and stdDevTempGood and stdDevHumidGood):
        # display information
        table.addToTable(index + 1, temps[index], humids[index])
        actionDescription = ""

        # if the temperature measures are not correct, change this room
        if not (avgTempGood and stdDevTempGood):
            # if the std dev is in range, adjust room base on current avg
            if stdDevTempGood:
                if avgTemp < optTemp:
                    temps[index] += 1
                    actionDescription = "Temperature Increase"
                elif avgTemp >= optTemp + 1:
                    temps[index] -= 1
                    actionDescription = "Temperature Decrease"
            # otherwise move temperature closer to desired average
            else:
                if temps[index] < optTemp:
                    temps[index] += 1
                    actionDescription = "Temperature Increase"
                elif temps[index] >= optTemp + 1:
                    temps[index] -= 1
                    actionDescription = "Temperature Decrease"
            avgTemp = getListAverage(temps)
            stdDevTemp = getListStdDev(temps)
        # otherwise, change the humidity
        else:
            # if the std dev is in range, adjust room base on current avg
            if stdDevHumidGood:
                if avgHumid < optHumid:
                    humids[index] += 1
                    actionDescription = "Humidity Increase"
                elif avgHumid >= optHumid + 1:
                    humids[index] -= 1
                    actionDescription = "Humidity Decrease"
            # otherwise move humidity closer to desired average
            else:
                if humids[index] < optHumid:
                    humids[index] += 1
                    actionDescription = "Humidity Increase"
                elif humids[index] >= optHumid + 1:
                    humids[index] -= 1
                    actionDescription = "Humidity Decrease"
            avgHumid = getListAverage(humids)
            stdDevHumid = getListStdDev(humids)

        # recalculate and reset values
        count += 1
        index += 1
        if index == 12:
            index = 0
        avgTempGood = inRange(avgTemp, optTemp)
        avgHumidGood = inRange(avgHumid, optHumid)
        stdDevTempGood = stdDevTemp < optTempDev + 0.1
        stdDevHumidGood = stdDevHumid < optHumidDev + 0.01

        # display information
        if actionDescription == "":
            actionDescription = "No Action"
        table.addToTable(actionDescription, avgTemp, stdDevTemp, avgHumid, stdDevHumid)
        table.nextTable()

    # print stuff
    print(tabulate(table.bigTable, headers=["Room #", "Temperature", "Humidity", "HeatMiser's Decision", "Average Temp", "Temp StdDev", "Average Humidity", "Humidity StdDev"], tablefmt="grid"))
    print("Total number of rooms visited by HeatMiser: " + str(count))
    print("\n")
    print("FINAL STATE OF ROOMS")
    print(tabulate([rooms, temps, humids], showindex=rowIDs, tablefmt="grid"))
    print("FINAL AVERAGE TEMPERATURE: " + str(avgTemp))
    print("FINAL TEMPERATURE STD DEV: " + str(stdDevTemp))
    print("FINAL AVERAGE HUMIDITY: " + str(avgHumid))
    print("FINAL HUMIDITY STD DEV: " + str(stdDevHumid))
    print("TOTAL NUMBER OF VISITS: " + str(count))
    print("\n")
    return count

def main():
    numVisits = []
    for i in range(1,101):
        print("Run " + str(i))
        numVisits.append(run())
    print("Average Number of Rooms Visited by HeatMiser over 100 Simulations: " + str(getListAverage(numVisits)))
    print("Standard Deviation over 100 Simulations: " + str(getListStdDev(numVisits)))

if __name__ == "__main__":
    main()


# Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements.
#
# For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].
#
# Note:
# You must do this in-place without making a copy of the array.
# Minimize the total number of operations.
class Solution(object):
    def moveZeroes(self, nums):

        if len(nums) == 0 or len(nums) == 1:
            return nums

        howmanyZero = 0

        loc = 0
        while loc < len(nums):
            if(nums[loc] == 0 and loc != len(nums) - 1):
                self.moveZeroToLast(loc, nums)
                howmanyZero = howmanyZero + 1
                loc = loc - 1

            if(howmanyZero == len(nums) - loc):
                break;

            loc = loc + 1

        return nums

    def moveZeroToLast(self, loc, nums):
        for i in range(loc, len(nums)-1):
            nums[i], nums[i+1] = nums[i+1], nums[i]

s = Solution()
print(s.moveZeroes([1,3,0,5,0,2]))


# Warmup questions for assignment 1

# Question 1:
 # 13 in base 5 would be 23
 # 13 in base 2 would be 1101
 # 11010010 in base 10 would be 210

# Question 2:
# 1. That expression will be evaluated to false by short
# circuit evaluation
# 2. This will always be evaluated to True because b will
# always have to false for the starter, but then the last
# part will not be evaluated to false, which will make the
# entire expression impossible to be false.

# Question 3
def even_and_positive():
    number = input('Please enter a number:')
    print(number, 'is an even number', int(number)%2 == 0)
    print(number, 'is an even number', int(number) > 0)
    print(number, 'is an even number', int(number)%2 == 0 and int(number) > 0 )

# Question 4
def hello_bye():
    number = input('Choose a number:')
    if number == '0':   # if two types are different then automatically false 0 == '0'
        print("Bye Bye!")
    elif number == '1':
        print("Hello everyone !")
    else:
        print("Bye Bye!")

# Question 7
def compare_x_y_z(x, y, z):
    return z == 3 or z == x+y

# Question 8
def calculation(x, y, op):
    if op == '+':
        return x+y
    elif op == '*':
        return x*y
    else:
        return 0


def caesarCipher(s, k):
    alpha = 'abcdefghijklmnopqrstuvwxyz'
    if k > len(alpha):
        k = k % len(alpha)
    s1 = ''
    for i in s:
        if i.isupper():
            ind = alpha.index(i.lower())
            if ind + k >= len(alpha):
                ind -= len(alpha)
            s1 += alpha[(ind + k)].upper()
        elif i.islower():
            ind = alpha.index(i)
            if ind + k >= len(alpha):
                ind -= len(alpha)
            s1 += alpha[(ind + k)]
        else:
            s1 += str(i)

    return s1

print(caesarCipher('www.abc.xy', 87))


import tempfile
from pathlib import Path
import logging

# import os
from os import linesep
from typing import List
from html import escape
from string import punctuation
from .config.syntax import (
    MARKDOWN_HEADER as HEADER,
    HTML_SPACE,
    MARKDOWN_HORIZONTAL_RULE as HORIZONTAL_RULE,
    MARKDOWN_SINGLE_LINE_BLOCKQUOTE as SINGLE_LINE_BLOCKQUOTE,
    MARKDOWN_MULTILINE_BLOCKQUOTE as MULTILINE_BLOCKQUOTE,
    MARKDOWN_CODE_BLOCK as CODE_BLOCK,
    MARKDOWN_INLINE_CODE_HL as INLINE_CODE_HIGHLIGHT,
    FOOTNOTE_IDENTIFIER,
)
from .config.conf import (
    DEFAULT_FILE_LOCATION,
    MAX_HEADER_LEVEL,
    MIN_HEADER_LEVEL,
    TABLE_OF_CONTENT_LINE_POSITION,
)

# from standardizer.markdown.config.log import logger

class MarkdownGenerator:
    """Class for generating GitLab or GitHub flavored Markdown."""

    """
    Instance of this class or any subclass is excepted to initialize
    by using 'with' statement in most cases.

    This opens file where content should be written.
    Default filename is default_file.md
    """

    def __init__(
        self,
        _self=None,
        document=None,
        filename=None,
        description=None,
        syntax=None,
        root_object=True,
        tmp_dir=None,
        pending_footnote_references=None,
        footnote_index=None,
        header_data_array=None,
        header_index=None,
        document_data_array=None,
        enable_write=True,
        enable_TOC=True,
        logger=None,
    ):
        """
        Constructor method for MarkdownGenerator

        GitLab allows following HTML tags as well:
        https://www.rubydoc.info/gems/html-pipeline/1.11.0/HTML/Pipeline/SanitizationFilter#WHITELIST-constant

        :param document: existing opened document file, defaults to None
        :param filename: File to be opened, defaults to None
        :param description: Description of generated document, defaults to None
        :param syntax: Markdown syntax flavor (GitHub vs GitLab)
        :param root_object: Whether the instance of this class is root object, defaults to None
        :param tmp_dir: Path of temporal directory. NOTE: not in user, defaults to None
        :param pending_footnote_references, defaults to None
        :param footnote_index
        """
        self.logger = logger if logger else logging.getLogger()
        self.logger.name = __name__
        self.logger.debug("Filename in constructor is {}".format(filename))

        # Attribute for determining if object is first instance of Markdowngenerator
        # It has has file open, which should be noted on exit.
        self.root_object = root_object

        self.description = "Class for generating GitLab flavored Markdown."

        self.document = document
        """
        Attribute for storing everything what is written into the file.
        Makes the manipulation of data in the middle of documenting easier,
        without re-reading and rewriting the document again if defined that
        data will be written only in the end of execution.

        NOTE: This variable should be shared and passed into every child node
        in constructor, that document structure keeps in correct.

        One index in array is one line in file.
        """
        self.document_data_array = document_data_array if document_data_array else []
        self.enable_write = enable_write
        self.enable_TOC = enable_TOC
        ###########
        if not filename:
            self.logger.info(
                "No file location given. Using default '{}'."
                " Overwriting existing file.".format(DEFAULT_FILE_LOCATION)
            )
            self.filename = Path(DEFAULT_FILE_LOCATION).resolve()
            self.default_filename_on_use = True
        elif isinstance(filename, Path):
            self.filename = filename
            self.default_filename_on_use = False
        else:
            self.filename = Path(filename).resolve()
            self.default_filename_on_use = False
        self.syntax = syntax if syntax else "gitlab"

        # Index for amount of footnotes and list of actual notes
        # to be written into the end of file
        # We are using dict, so we can pass it by reference among objects
        self.footnote_index = footnote_index if footnote_index else {"value": 0}
        self.pending_footnote_references = (
            pending_footnote_references if pending_footnote_references else []
        )

        # Trailing details, details section open but not ended if count > 0.
        self.unfinished_details_summary_count = {"value": 0}

        # Header information for table of contents
        self.header_info = header_data_array if header_data_array else []
        self.header_index = header_index if header_index else 0

        # Directory for tmp files, currently not in use.
        self.tmp_dir = tmp_dir

    def __enter__(self):
        """
        Override default enter method to enable
        usage of 'with' while using class instance
        to safely open and close file.

        """

        if self.filename.is_dir():
            self.filename.mkdir(exist_ok=True)
            self.logger.debug(
                "Given path is directory without filename, using default filename."
            )
            self.filename.joinpath(DEFAULT_FILE_LOCATION, ".md")
            self.default_filename_on_use = True
        if not self.document:
            self.document = open(f"{self.filename}", "w+")
            current_tmp_dir = tempfile.gettempdir()
            self.tmp_dir = tempfile.TemporaryDirectory(dir=current_tmp_dir)

        # self.filename = os.path.basename(self.filename)
        return self

    def __exit__(self, *args, **kwargs):
        """
        Close file on exit.

        If there are some footnotes to be written, write them first.
        If Table of Contents should be written, it will be.

        If we have just generated the content of file into the memory,
        now write all at once into the file.

        """
        self.genFootNotes()
        if self.enable_TOC:
            if not self.enable_write:
                self.genTableOfContent()
            else:
                self.logger.warning("Warning: ToC is not enabled when the file is dynamically written.")
        # Everything will be written at once into the file
        if not self.enable_write:
            self.document.writelines(self.document_data_array)
        self.document.close()

    def genFootNotes(self, genHeader=False):
        """
        Method for adding footnotes into the end of file.
        """
        if self.pending_footnote_references:
            # if genHeader:
            self.addHeader(3, "Footnotes")
            for footnote in self.pending_footnote_references:
                self.writeTextLine(footnote)

        if self.unfinished_details_summary_count.get("value") > 0:
            self.logger.warning("Some of the detail blocks is not properly closed!!!")

    def genTableOfContent(self, linenumber=TABLE_OF_CONTENT_LINE_POSITION, max_depth=3):
        """
        Method for creating table of contents.
        """
        tableofcontents = []  # test_logger.debug(f"Expected: '{expected_output}'")
        # test_logger.debug(f"Generated '{generated_output}'")
        tableofcontents.append(f"## Table of Contents  {linesep}")
        prevLevel = 0
        padding = "  "
        footnote = None
        footnoteLevel = 2
        for header in self.header_info:
            name = header.get("headerName")
            level = header.get("headerLevel")
            href = header.get("headerHref")
            if name and level and href:
                if name == "Footnotes":
                    footnote = header
                    continue
                # Too big indent change from high level to low level
                # does not work in unordered list. Amount reduced
                # Line collapses to previous lane otherwise
                if level <= max_depth:
                    if prevLevel != 0 and prevLevel - level < -2:
                        level = prevLevel + 2

                    tableofcontents.append(
                        f"{level * padding}* {self.generateHrefNotation(name, href)}{linesep}"
                    )
                prevLevel = level
        # Footnote should be last one.
        if footnote:
            tableofcontents.append(
                f'{footnoteLevel * padding}* {self.generateHrefNotation(footnote.get("headerName"), footnote.get("headerHref"))}{linesep}'
            )
        tableofcontents.append(f"  {linesep}")
        self.document_data_array = (
            self.document_data_array[: linenumber - 1]
            + tableofcontents
            + self.document_data_array[linenumber - 1 :]
        )

    def writeText(self, text, html_escape: bool = True):
        """
        Method for writing arbitrary text into the document file,
        or just adding data into document data structure for easier manipulation.

        Text input has been escaped by default from HTML characters which could mess up the document..

        :param text: Input text string
        :param html_escape: bool,  Whether the input should be escaped or not
        """
        if html_escape:
            self.document_data_array.append(escape(str(text)))
            if self.enable_write:
                self.document.write(escape(str(text)))
            return
        self.document_data_array.append(str(text))
        if self.enable_write:
            self.document.write(str(text))

    def writeTextLine(self, text=None, html_escape: bool = True):
        """
        Write arbitrary text into the document file and add new line,
        or just adding data with new line into document data structure for easier manipulation.

        Writing is defined in attribute 'self.enable_write' whether it is true or false

        Note double spaces after text.

        Text input has been escaped by default from HTML characters which could mess up the document..

        :param text: Input text string
        :param html_escape: bool, Whether the input should be escaped or not
        """
        if text is None:
            # Just forcing new line, in Markdown there should be 2 or more spaces as well
            self.document_data_array.append(str("  ") + linesep)
            if self.enable_write:
                self.document.write(str("  ") + linesep)

            return
        if html_escape:
            self.document_data_array.append(escape(str(text)) + "  " + linesep)
            if self.enable_write:
                self.document.write(escape(str(text)) + "  " + linesep)
            return
        self.document_data_array.append(str(text) + "  " + linesep)
        if self.enable_write:
            self.document.write(str(text) + "  " + linesep)

    def writeAttributeValuePairLine(self, key_value_pair: tuple, total_padding=30):

        if len(key_value_pair) == 2:
            required_padding = total_padding - len(key_value_pair[0])
            self.logger.debug(
                f"Line {key_value_pair[0]} Lenght of padding is {required_padding}"
            )
            self.writeTextLine(
                f"{self.addBoldedAndItalicizedText(key_value_pair[0])}{HTML_SPACE*required_padding}{key_value_pair[1]}"
            )
        else:
            self.logger.error("Not valid key value pair, when writing padded line.")
            return

    def addHeader(self, level: int, text):
        """
        Standard Markdown

        Method for adding named headers for the document.
        See: https://docs.gitlab.com/ee/user/markdown.html#headers

        :param level: The level of header, from 1 to 6
        :param text: The text for header
        """
        # NOTE Currently non-unique header names are not handled

        # Text for lowercase, remove punctuation, replace whitespace with dashesh
        anchor = "#" + text.lower().translate(
            str.maketrans("", "", punctuation.replace("-", ""))
        ).replace(" ", "-")

        self.header_index += 1
        header = {
            "headerName": escape(text),
            "headerLevel": level,
            "headerHref": anchor,
            "headerID": self.header_index,
        }

        if level <= MAX_HEADER_LEVEL and level >= MIN_HEADER_LEVEL:
            # Add empty line before header unless it's level is 1 (default MIN) and it's first header
            if level != MIN_HEADER_LEVEL or self.header_index != 1:
                self.writeTextLine()
            self.writeTextLine(f"{level * HEADER} {text}")
        elif level < MIN_HEADER_LEVEL:
            self.logger.warning(
                "Header level below minimum value, using minimum value."
            )
            header["headerLevel"] = MIN_HEADER_LEVEL
            self.writeTextLine(f"{MIN_HEADER_LEVEL * HEADER} {text}")
        else:
            self.logger.warning("Header level out of scope, using max value.")
            header["headerLevel"] = MAX_HEADER_LEVEL
            # Add empty line before header unless it's level is 1 (default MIN)
            self.writeTextLine()
            self.writeTextLine(f"{MAX_HEADER_LEVEL * HEADER} {text}")

        self.header_info.append(header)
        # self.logger.debug(f"Adding header {header}")

    """
    Emphasis, aka italics, bold or strikethrough.
    """

    def addBoldedText(self, text: str, write_as_line: bool = False) -> str:
        """
        Standard Markdown

        Method for bolding text
        See: https://docs.gitlab.com/ee/user/markdown.html#emphasis
        Removes leading and trailing whitespaces.

        :param text: Input text to be bolded.
        :param write_as_line: bool, Whether the text should be written to document/buffer directly
        :return: str, Bolded text
        :rtype: string
        """
        bolded = f"**{text.strip()}**"
        if write_as_line:
            self.writeTextLine(bolded)
        return bolded

    def addItalicizedText(self, text, write_as_line: bool = False) -> str:
        """
        Standard Markdown

        Method for italicizing text
        See: https://docs.gitlab.com/ee/user/markdown.html#emphasis
        Removes leading and trailing whitespaces.

        :param text: Input text to be italicized
        :param write_as_line: bool, Whether the text should be written to document/buffer directly
        :return: Italicized text
        :rtype: string
        """
        italicized = f"*{text.strip()}*"
        if write_as_line:
            self.writeTextLine(italicized)
        return italicized

    def addBoldedAndItalicizedText(self, text, write_as_line: bool = False) -> str:
        """
        Standard Markdown

        Method for bolding and italicing text
        See: https://docs.gitlab.com/ee/user/markdown.html#emphasis
        Removes leading and trailing whitespaces.

        :param text: Input text to be italicized and boldgin.
        :param write_as_line: bool, Whether the text should be written to document/buffer directly
        :return: Bolded text
        :rtype: string
        """
        bolded_italicized = f"***{text.strip()}***"
        if write_as_line:
            self.writeTextLine(bolded_italicized)
        return bolded_italicized

    def addStrikethroughText(self, text, write_as_line: bool = False) -> str:
        """
        NOTE: Non-standard Markdown

        Method for getting text strikethroughed
        See: https://docs.gitlab.com/ee/user/markdown.html#emphasis
        Removes leading and trailing whitespaces.

        :param text: Text to be converted
        :param write_as_line: bool, Whether the text should be written to document/buffer directly
        :return: Strikethourghed text
        :rtype: string
        """
        if self.syntax not in ["gitlab", "github"]:
            raise AttributeError("GitLab and GitHub Markdown syntax only.")

        strikethrough = f"~~{text.strip()}~~"
        if write_as_line:
            self.writeTextLine(strikethrough)
        return strikethrough

    def generateHrefNotation(self, text, url, title=None) -> str:
        """
        Standard Markdown

        Method for generating link into markdown document.
        See: https://docs.gitlab.com/ee/user/markdown.html#links

        :param text: Visible text
        :param text: URL of the wanted destination
        :param title: Title for URL. Tooltip on hover
        :return: formated markdown reprenstation text
        :rtype: string
        """
        if title:
            return f'[{text}]({url} "{title}")'
        return f"[{text}]({url})"

    def generateImageHrefNotation(self, image_uri: str, alt_text, title=None) -> str:
        """
        Standard Markdown

        Method for showing image in Markdown.

        GitLab supports videos and audio as well, and is able to play video, if extension is valid as
        described in here: https://docs.gitlab.com/ee/user/markdown.html#videos

        :param image_path: Path or URL into the image
        :param alt_text: Text which appears if image not loaded
        :param title: Title for the image
        :return: Formatted presentation of image in Markdown
        :rtype: string
        """

        if title:
            return f'![{alt_text}]({image_uri} "{title}")'
        return f"![{alt_text}]({image_uri})"

    def addHorizontalRule(self):
        """
        Standard Markdown

        Method for appending Horizontal Rule:
        See: https://docs.gitlab.com/ee/user/markdown.html#horizontal-rule
        """
        self.writeTextLine(f"{linesep}{HORIZONTAL_RULE}{linesep}")

    def addCodeBlock(self, text, syntax: str = None, escape_html: bool = False):
        """
        Standard Markdown

        Method for inserting highlighted code block into the Markdown file
        See: https://docs.gitlab.com/ee/user/markdown.html#code-and-syntax-highlighting

        :param text: Actual content/code into code block
        :param syntax: string, Syntax highlight type for code block
        :param escape_html: bool, Wheather the input is html escaped or not
        """

        # Escape backtics/grave accents in attempt to deny codeblock escape
        grave_accent_escape = "\`"

        text = text.replace("`", grave_accent_escape)

        if escape_html:
            self.writeTextLine(
                f"{CODE_BLOCK}{syntax}{linesep}{text}{linesep}{CODE_BLOCK}"
            )
        else:
            self.writeTextLine(
                f"{CODE_BLOCK}{syntax}{linesep}{text}{linesep}{CODE_BLOCK}",
                html_escape=False,
            )

    def addInlineCodeBlock(self, text, escape_html: bool = False, write: bool = False):
        """
        Standard Markdown

        Method for adding highlighted code in inline style in Markdown.
        By default in Markdown, it is done by using single backticks: `

        :param text: Actual content/code into code block
        :param escape_html: Wheather the input is html escaped or not. Default is True
        :param write: Wheather the output is written immediately or returned.
        :return: If write is false, generated InlineCodeBlock is returned
        :rtype: string
        By default constructed output is returned only.
        """

        inline_hl = f"{INLINE_CODE_HIGHLIGHT}{text}{INLINE_CODE_HIGHLIGHT}"
        if write:
            if escape_html:
                self.writeText(inline_hl)
            else:
                self.writeText(inline_hl, html_escape=False)
        else:
            return inline_hl

    def addSinglelineBlockQuote(self, text):
        """
        Standard Markdown

        Method for adding single line blockquote.
        Removes leading or trailing whitespaces from input.

        Escape input already here to enable ">" default blockquote character.

        :param text: Input to be written as single line blockquote
        """
        self.writeTextLine(
            f"{SINGLE_LINE_BLOCKQUOTE}{escape(text.strip())}", html_escape=False
        )

    def addMultiLineBlockQuote(self, text):
        """
        NOTE: GitLab Markdown Only

        Method for adding multiline blockquote.
        See: https://docs.gitlab.com/ee/user/markdown.html#multiline-blockquote
        Removes leading or trailing whitespaces from input.

        Escape input already here to enable ">" default blockquote character.

        :param text: Input text for inside blockquote
        """
        self.writeTextLine(
            f"{MULTILINE_BLOCKQUOTE}{linesep}{escape(text.strip())}{linesep}{MULTILINE_BLOCKQUOTE}",
            html_escape=False,
        )

    def addUnorderedList(self, iterableStringList):
        """
        Standard Markdown

        Method from constructing unordered list. Takes list of
        strings as argument. Each item from list going for own line.

        :param iterableStringList: List of strings. Each string
        as item in Markdown list
        """
        for item in iterableStringList:
            self.writeText(f"  * {item}{linesep}")
        self.writeTextLine()

    def addTable(
        self,
        header_names: List[str] = None,
        row_elements=None,
        alignment="center",
        dictionary_list=None,
        html_escape=True,
        capitalize_headers=False,
    ):
        """
        Standard Markdown

        Method for generating Markdown table with centered cells.

        If both row_elements and dictionary_list is provided, dictionary_list is used by default.

        If only dictionary_list paramater is provided, function expects that it has list of same type dictionaries.
        Key names of dictionary will be used as header names for table.

        :param header_names: List of header names, defines width of table
        :param row_elements: List of lists. (List of rows, each row contains list of row's elements)
        :param dictionary_list: List of dictionary. Expecting only attributes inside dictionary, no nested objects.
        :param alignment: Alignment of all columns in table
        """
        useDictionaryList = False
        useProvidedHeadernames = False

        if row_elements is None:
            if dictionary_list is None:
                self.logger.warning("Invalid paramaters for generating new table.")
                raise TypeError(
                    f"Invalid paramaters for generating new table. Use either dictionary list or row_elements."
                )
            else:
                useDictionaryList = True

        if row_elements and dictionary_list:
            self.logger.debug(
                "Both row elements and dictionary list provided, using dictionary list as default."
            )

        if header_names:
            self.logger.debug("Header names provided. Using them.")
            useProvidedHeadernames = True
        else:
            self.logger.debug(
                "No header names provided. Using dictionary attribute names as default. Using none, if row_elements used."
            )

        # Headers
        self.writeTextLine()
        if not useProvidedHeadernames and dictionary_list:
            try:
                header_names = dictionary_list[0].keys()
                self.logger.debug(f"Header names are: {header_names}")
            except AttributeError as e:
                self.logger.error(
                    f"Dictionary list for addTable function was not list of objects. Table not generated. : {e}"
                )
                return
        try:
            for header in header_names:
                # Capitalize header names
                if capitalize_headers:
                    self.writeText(f"| {header.capitalize()} ")
                else:
                    self.writeText(f"| {header} ")
        except TypeError as e:
            self.logger.error(f"Invalid header names for table. Not generated: {e}")
            return
        # Write ending vertical bar
        self.writeTextLine(f"|")
        # Write dashes to separate headers
        if alignment == "left":
            self.writeTextLine("".join(["|", ":---|" * len(header_names)]))

        elif alignment == "center":
            self.writeTextLine("".join(["|", ":---:|" * len(header_names)]))

        elif alignment == "right":
            self.writeTextLine("".join(["|", "---:|" * len(header_names)]))
        else:
            self.logger.warning("Invalid alignment value in addTable. Using default.")
            self.writeTextLine("".join(["|", ":---:|" * len(header_names)]))

        # Write each row into the table

        if not useDictionaryList:

            for row in row_elements:
                if len(row) > len(header_names):
                    self.logger.error(
                        f"The are more row elements than header names (Row: {len(row)} - Header: {len(header_names)} "
                    )
                    continue
                for element in row:
                    # Check if element is list
                    # If it is, add it as by line by line into single cell
                    if isinstance(element, list):
                        self.writeText("| ")
                        for list_str in element:
                            self.writeText(list_str)
                            self.writeText("<br> ", html_escape=False)
                    else:
                        self.writeText(f"| {element} ", html_escape)

                self.writeTextLine(f"|")

        else:
            # Iterate over list of dictionaries
            # One row contains attributes of dictionary
            for row in dictionary_list:
                for key in row.keys():
                    if isinstance(row.get(key), list):
                        self.writeText("| ")
                        for list_str in row.get(key):
                            self.writeText(list_str)
                            self.writeText("<br> ", html_escape=False)
                    else:
                        self.writeText(f"| {row.get(key)} ", html_escape)
                self.writeTextLine(f"|")
        self.writeTextLine()

    def insertDetailsAndSummary(
        self, summary_name="Click me to collapse/fold.", escape_html=True
    ):
        """
        Method for initializing Details and Summary block.
        See: https://docs.gitlab.com/ee/user/markdown.html#details-and-summary

        """
        self.writeTextLine("<details>", html_escape=False)

        # Whether the summary name is html escaped or not
        if escape_html:
            self.writeTextLine(
                f"<summary>{escape(summary_name)}</summary>", html_escape=False
            )
        else:
            # Makes bolding possible for summary name with HTML
            self.writeTextLine(f"<summary>{summary_name}</summary>", html_escape=False)
        self.writeTextLine()
        self.unfinished_details_summary_count["value"] += 1

    def endDetailsAndSummary(self):
        """
        Ends details and summary block.
        """
        self.writeTextLine()
        self.writeTextLine("</details>", html_escape=False)
        self.unfinished_details_summary_count["value"] -= 1

    def addFootNote(self, text, footnote, write=True):
        """
        Standard Markdown

        Placement of footnote reference id should be placed
        with brackets by default, as: [footnote_id], whereas the footnote_id is string
        footnote_id. Actual ID will be generated automatically.

        NOTE: Text is written by default. To get generated footnote block as return value,
    set 'write=False'.

        Method for inserting footnote into the document.

        :param text: Text to be written on document and wherethe footnote id is inserted.
        :param write: Defines if footnote should be written immmedially into the document.
        Same as to use 'writeTextLine' for return value when set False.

        :return: returns formatted text input
        """

        # Prevent duplicate footnotes
        # This might happen for examle if footnote is somehow in collection of
        # dictionaries, in part of value names
        # And this list is used to generated table
        already_in_list = False
        for footnote_d in self.pending_footnote_references:
            if footnote in footnote_d:
                already_in_list = True
        if not already_in_list:
            # Append footnote into the list, which will be written in the end.
            self.footnote_index["value"] += 1
            self.pending_footnote_references.append(
                f"[^{self.footnote_index.get('value')}]: {footnote}{linesep}"
            )
        else:
            self.logger.debug(
                f"Trying to add duplicate footnote '{footnote}'. Skipping."
            )

        # FOOTNOTE IDENTIFIER is string which is replaced with actual reference
        # See source of import (syntax.py)
        # Default should be '[footnote_id]'
        text = text.replace(
            f"{FOOTNOTE_IDENTIFIER}", f"[^{self.footnote_index.get('value')}]"
        )
        if write:
            self.writeTextLine(text)
        self.logger.debug(
            f'Added footnote "{footnote}" with identifier {self.footnote_index}.'
        )
        if not write:
            return text


import socket
import json
import struct
import time
from datetime import datetime
import sys	#for exit

def readblob(the_socket,timeout=2):
    #make socket non blocking
    the_socket.setblocking(0)

    #total data partwise in an array
    total_data=[]
    data=''

    #beginning time
    begin=time.time()
    while 1:
        #if you got some data, then break after timeout
        if total_data and time.time()-begin > timeout:
            break

        #if you got no data at all, wait a little longer, twice the timeout
        elif time.time()-begin > timeout*2:
            break

        #recv something
        try:
            data = the_socket.recv(8192)
            if data:
                total_data.append(data)
                #change the beginning time for measurement
                begin=time.time()
            else:
                #sleep for sometime to indicate a gap
                time.sleep(0.1)
        except:
            pass

    #join all parts to make final string
    return total_data

HOST = '127.0.0.1'  # Standard loopback interface address (localhost)
PORT = 8009        # Port to listen on (non-privileged ports are > 1023)
BUFFER_SIZE = 4096

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT)) #Bind system socket
    s.listen(3) #Listen for up to 3 connections
    print("Listening on %s:%s..." % (HOST, str(PORT)))

    while True:

        conn, addr = s.accept()
        with conn:
            print('Connected by', addr)
            data = readblob(conn)
            jdata = ''
            for i in data:
                jdata += i.decode('utf-8')

            # datetime object containing current date and time
            now = datetime.now()
            # dd-mm-YY_at_H-M-S
            dt_string = now.strftime("%d-%m-%Y_at_%H-%M-%S")
            jFile = open(dt_string+".json","w")
            jFile.write(jdata)
            jFile.close()

            print("Connection received from %s..." % str(addr))
            conn.sendall('OK'.encode("ascii"))
            conn.close()


import sys
import heapq
input = sys.stdin.readline

def djikstra():
    q = []
    heapq.heappush(q, [0, 0, 0])
    while q:
        sumV, r, c = heapq.heappop(q)
        if visited[r][c] < sumV:
            continue
        for d in range(4):
            nr = r + dr[d]
            nc = c + dc[d]
            if 0 <= nr < n and 0 <= nc < n:
                if room[nr][nc] == 1 and visited[nr][nc] > visited[r][c]: # 방문할 곳이 흰방일 경우
                    visited[nr][nc] = visited[r][c]
                    heapq.heappush(q, [visited[nr][nc], nr, nc])
                # 방문하고자 하는 장소가 검은 방일 경우
                elif room[nr][nc] == 0 and visited[nr][nc] > visited[r][c] + 1:
                    visited[nr][nc] = visited[r][c] + 1
                    heapq.heappush(q, [visited[nr][nc], nr, nc])

if __name__=="__main__":
    n = int(input())
    room = [list(map(int, input().rstrip())) for _ in range(n)]
    visited = [[102] * n for _ in range(n)]
    visited[0][0] = 0
    dr = [0, 1, 0, -1]
    dc = [1, 0, -1, 0]
    djikstra()
    # for i in visited:
    #     print(i)
    print(visited[n - 1][n - 1])


from django.shortcuts import render
from rest_framework import viewsets
from .models import Movie, Genre
from .serializers import MovieSerializer, GenreSerializer
from rest_framework.pagination import LimitOffsetPagination

# Create your views here.

class GenreViewSet(viewsets.ModelViewSet):
    queryset = Genre.objects.all().order_by('name')
    serializer_class = GenreSerializer

class MovieViewSet(viewsets.ModelViewSet):
    queryset = Movie.objects.all().order_by('name')
    serializer_class = MovieSerializer
    pagination_class = LimitOffsetPagination

    def get_queryset(self):
        qs = super().get_queryset()
        name = self.request.query_params.get('name', None)
        if name is not None:
            qs = qs.filter(name__icontains=name)

        genre = self.request.query_params.get('genre', None)
        if genre is not None:
            qs = qs.filter(genre__name__icontains=genre)

        director = self.request.query_params.get('director', None)
        if director is not None:
            qs = qs.filter(director__icontains=director)

        return qs


# Importing the important libraries
from decimal import Decimal
from decimal import getcontext
getcontext().prec = 10000 # Specifying the precision

# This is the class that implements the Arithmetic Compression Algorithm
class Arithmetic:

    def __init__(self, prob_table):
        """ Constructor to initialize the important properties
        Args:
            prob_table (Dict): the alphabet and their probabilities
        """
        self.prob_table = prob_table
        self.c_prob_table = self.__get_c_prob_table()                         # Cumulative probability table

    def __get_c_prob_table(self):
        """ Calculates the cumulative probability table
        Returns:
            c_prob_table (dict): the alphabet and their cumulative probabilities
        """
        c_prob_table = dict()
        cur = Decimal('0.0')
        for c in self.prob_table:
            c_prob_table[c] = cur
            cur += Decimal("%.10f" % self.prob_table[c])
        return c_prob_table

    def arithmetic_encode(self, msg):
        """ This the function that encode the message into one decimal value
        Args:
            msg (string): The plain message
        Returns:
            ans (Decimal): The mean value of the message interval(encoded message)
        """
        if not msg: return
        min_lev = Decimal('0.0')
        max_lev = Decimal('1.0')
        r = max_lev - min_lev                                               # Whole number line between 0-1
        for c in msg:                                                       # Looping over the entire message
            min_lev += self.c_prob_table[c] * r                             # Min value of the interval
            r *= Decimal("%.10f" % self.prob_table[c])                       # Current interval length
            max_lev = min_lev + r                                           # Max value of the interval
        ans = (min_lev + max_lev)/Decimal("%.1f" % 2.0)                     # Mean of the last interval
        return ans.normalize()                                              # Trimming the zeros

    def arithmetic_decode(self, msg, n):
        """ This the function that decode the decimal value into the plain message
        Args:
            msg (Decimal): Encoded decimal
            n (int): Length of the plain message
        Returns:
            ans (string): Decoded message
        """
        if not msg: return
        ans = ''
        min_lev = Decimal('0.0')
        max_lev = Decimal('1.0')
        r = max_lev - min_lev                                               # Whole number line between 0-1
        for i in range(n):                                                  # Looping till we get all the characters
            for c in self.prob_table:                                       # Looping on the number line till we find our interval
                cur_interval = Decimal("%.10f" % self.prob_table[c]) * r     # Try all the intervals
                max_lev = min_lev + cur_interval
                if msg < max_lev:                                          # If its within the interval:
                    r = cur_interval                                        # Expand the interval
                    ans += c                                                # Add the char
                    break
                min_lev = max_lev                                           # Move to the next interval
        return ans


def PLL_cbb(x,fs,loop_type,Kv,fn,zeta):
    """
    Baseband Analog PLL Simulation Model

    :param x: input phase deviation in radians
    :param fs: sampling rate in sample per second or Hz
    :param loop_type: 1, first-order loop filter F(s)=K_LF; 2, integrator
                with lead compensation F(s) = (1 + s tau2)/(s tau1),
                i.e., a type II, or 3, lowpass with lead compensation
                F(s) = (1 + s tau2)/(1 + s tau1)
    :param Kv: VCO gain in Hz/v; note presently assume Kp = 1v/rad
                and K_LF = 1; the user can easily change this
    :param fn: Loop natural frequency (loops 2 & 3) or cutoff
                frequency (loop 1)
    :param zeta: Damping factor for loops 2 & 3
    :return: theta_hat = Output phase estimate of the input theta in radians,
             ev = VCO control voltage,
             phi = phase error = theta - theta_hat

    Mark Wickert, April 2007 for ECE 5625/4625
    Modified February 2008 and July 2014 for ECE 5675/4675
    Python version August 2014
    """
    T = 1/float(fs)
    Kv = 2*np.pi*Kv # convert Kv in Hz/v to rad/s/v

    if loop_type == 1:
        # First-order loop parameters
        # Note Bn = K/4 Hz but K has units of rad/s
        #fn = 4*Bn/(2*pi);
        K = 2*np.pi*fn # loop natural frequency in rad/s
    elif loop_type == 2:
        # Second-order loop parameters
        #fn = 1/(2*pi) * 2*Bn/(zeta + 1/(4*zeta));
        K = 4 *np.pi*zeta*fn # loop natural frequency in rad/s
        tau2 = zeta/(np.pi*fn)
    elif loop_type == 3:
        # Second-order loop parameters for one-pole lowpass with
        # phase lead correction.
        #fn = 1/(2*pi) * 2*Bn/(zeta + 1/(4*zeta));
        K = Kv # Essentially the VCO gain sets the single-sided
                # hold-in range in Hz, as it is assumed that Kp = 1
                # and KLF = 1.
        tau1 = K/((2*np.pi*fn)^2);
        tau2 = 2*zeta/(2*np.pi*fn)*(1 - 2*np.pi*fn/K*1/(2*zeta))
    else:
        print('Loop type must be 1, 2, or 3')

    # Initialize integration approximation filters
    filt_in_last = 0; filt_out_last = 0;
    vco_in_last = 0; vco_out = 0; vco_out_last = 0;
    vco_out_cbb = 0

    # Initialize working and final output vectors
    n = np.arange(len(x))
    theta_hat = np.zeros(len(x))
    ev = np.zeros(len(x))
    phi = np.zeros(len(x))

    # Begin the simulation loop
    for k in  range(len(n)):
        #phi[k] = theta[k] - vco_out
        phi[k] = np.imag(x[k] * np.conj(vco_out_cbb))
        pd_out = phi[k]
        # Loop gain
        gain_out = K/Kv*pd_out # apply VCO gain at VCO
        # Loop filter
        if loop_type == 2:
            filt_in = (1/tau2)*gain_out
            filt_out = filt_out_last + T/2*(filt_in + filt_in_last)
            filt_in_last = filt_in
            filt_out_last = filt_out
            filt_out = filt_out + gain_out
        elif loop_type == 3:
            filt_in = (tau2/tau1)*gain_out - (1/tau1)*filt_out_last
            u3 = filt_in + (1/tau2)*filt_out_last
            filt_out = filt_out_last + T/2*(filt_in + filt_in_last)
            filt_in_last = filt_in
            filt_out_last = filt_out
        else:
            filt_out = gain_out;
        # VCO
        vco_in = filt_out
        if loop_type == 3:
            vco_in = u3
        vco_out = vco_out_last + T/2*(vco_in + vco_in_last)
        vco_in_last = vco_in
        vco_out_last = vco_out
        vco_out = Kv*vco_out # apply Kv
        vco_out_cbb = np.exp(1j*vco_out)
        # Measured loop signals
        ev[k] = vco_in
        theta_hat[k] = vco_out
    return theta_hat, ev, phi


import eng_to_ipa as ipa

IPA_VISEME_TABLE = {
    "b": "p", "d": "t", "ʤ": "S", "ð": "T", "f": "f", "g": "k",
    "h": "k", "j": "i", "k": "k", "l": "t", "m": "p", "n": "t",
    "ŋ": "k", "p": "p", "ɹ": "r", "s": "s", "ʃ": "S", "t": "t",
    "t͡ʃ": "S", "θ": "T", "v": "f", "w": "u", "z": "s", "ʒ": "S",
    "ə": "@", "ɚ": "@", "æ": "a", "aɪ": "a", "aʊ": "a", "ɑ": "a",
    "eɪ": "e", "ɝ": "E", "ɛ": "E", "i": "i", "ɪ": "i", "oʊ": "o",
    "ɔ": "O", "ɔɪ": "O", "u": "u", "ʊ": "u", "ʌ": "E", "ˈ": "ˈ",
}

def ipa_to_viseme(word):
    i = 0
    vis = ""
    while i < len(word):
        if (i < len(word) - 1) and ((word[i] + word[i+1]) in IPA_VISEME_TABLE):
            vis += IPA_VISEME_TABLE[word[i] + word[i+1]]
            i += 2
        elif word[i] in IPA_VISEME_TABLE:
            vis += IPA_VISEME_TABLE[word[i]]
            i += 1
        else:
            vis += word[i]
            i += 1
    return vis

def txt_to_viseme(txt):
    words_vis = []
    for word in txt.split(" "):
        word_ipa = ipa.convert(word)
        words_vis.append(ipa_to_viseme(word_ipa))

    return " ".join(words_vis)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Thanks to Kenneth Reitz, I stole the template for this

import os
import sys
from setuptools import find_packages

try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup

PYTHON3 = sys.version_info[0] > 2

required = ['requests>=2.5', 'websocket-client==0.32.0',
        'beautifulsoup4==4.4.1', 'html5lib==0.9999999', 'pyfiglet==0.7.4',
        'slackrtm==0.2.1']
if not PYTHON3:
    required += ['importlib>=1.0.3']

try:
    longdesc = open("README.rs").read()
except:
    longdesc = ''

setup(
    name='limbo',
    version='3.8.2',
    description='Simple and Clean Slack Chatbot',
    long_description=longdesc,
    author='Bill Mill',
    author_email='bill@billmill.org',
    url='https://github.com/llimllib/limbo',
    packages=find_packages(),
    scripts=['bin/limbo'],
    package_data={'': ['LICENSE'], '': ['limbo/plugins/*.py']},
    include_package_data=True,
    install_requires=required,
    license='MIT',
    classifiers=(
        'Development Status :: 4 - Beta',
        'Intended Audience :: Developers',
        'Natural Language :: English',
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python',
        'Programming Language :: Python :: 2.6',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3.4',
    ),
)


import argparse
from readchar import readkey
import random
import string
import time

# Selects Game Mode
def gameMode():

    parser = argparse.ArgumentParser(description = 'Definition of test mode.')
    parser.add_argument('-utm', '--use_time_mode', type=int,
                    help="Max number of secs for time mode or maximum number of inputs for number of inputs mode.\n")
    parser.add_argument('-mv', '--max_value', type=int,
                    help="Max number of secs for time mode or maximum number of inputs for number of inputs mode.")

    # creates the dictionary with {utm : input , mv : input}
    args = vars(parser.parse_args())
    #assigns the values to the values variable
    mv = args["max_value"]
    utm = args["use_time_mode"]

    # when there is no input to max value, the game will run in time mode
    if mv == None:
        print("User Time Mode selected, you have " + str(utm) + " seconds to type!")
        return {"game_time": utm}
    else:
        print("Maximum Value Mode selected, you have" + str(mv) + "chances!")
        return {"max_input": mv}

# Starts the game with any key
def gameStart():
    print("Press any key to start the game!")

    start_key = readkey()
    if start_key != None:
        return True

def gameTime(t):
    results = {}
    t_end = time.time() + t
    gameStart()

    while time.time() < t_end:
        random_letter = random.choice(string.ascii_letters).lower()
        print(random_letter)
        inserted_key = readkey()

        if inserted_key == random_letter:
            answer = "Resposta Correta"
        else:
            answer = "Resposta Errada"

        print(inserted_key + ":" + answer)
        if inserted_key == " ":
            break

        results[random_letter] = inserted_key

    #print(results)

    return

def maxInput(m):
    results = {}

    gameStart()

    for i in range(0, m):
        answer = ""

        random_letter = random.choice(string.ascii_letters).lower()
        inserted_key = readkey()

        if inserted_key == random_letter:
            answer = "Resposta Correta"
        else:
            answer = "Resposta Errada"

        print(inserted_key + ":" + answer)

        if inserted_key == " ":
            break
        results[random_letter] = inserted_key

    #print(results)

    return

def main():

    # Defines game type and calls the corresponding mode
    game_type = gameMode()

    # FAZER NA MAIN
    if  list(game_type.keys())[0]== "game_time":
        gameTime(game_type["game_time"])
    else:
        maxInput(game_type["max_input"])

if __name__ == "__main__":
    main()


import sys
import re

class States:PROC_FROM, PROC_TO, PROC_BODY = range(3)

state = States.PROC_FROM

RE_250 = re.compile("^250")
RE_354 = re.compile("^354")

def procStartOfNew(line):
	print(".")
	res = raw_input()
	sys.stderr.write(res + "\n")
	if RE_250.match(res) == None: raise Exception("Expected 250")

	return procFrom(line)

RE_FROM = re.compile("^From: <(.+?)>")
def procFrom(line):
	match = RE_FROM.match(line)
	if match == None: raise Exception("Invalid from")

	print("MAIL FROM: <" + match.group(1) + ">");

	res = raw_input()
	sys.stderr.write(res + "\n")
	if RE_250.match(res) == None: raise Exception("Expected 250")

	return States.PROC_TO

RE_TO = re.compile("^To: <(.+?)>")
def procTo(line):
	# Send to command
	match = RE_TO.match(line)
	if match == None: raise Exception("Invalid to")

	print("RCPT TO: <" + match.group(1) + ">")

	res = raw_input()
	sys.stderr.write(res + "\n")
	if RE_250.match(res) == None: raise Exception("Expected 250")

	# Send data command (assuming only one to)
	print("DATA")

	res = raw_input()
	sys.stderr.write(res + "\n")
	if RE_354.match(res) == None: raise Exception("Expected 354")

	return States.PROC_BODY

mailbox_name = sys.argv[1]
with open(mailbox_name, "r") as mailbox_file:
	line = mailbox_file.readline()
	try:
		while line != "":
			if state == States.PROC_FROM:
				state = procFrom(line)
			elif state == States.PROC_TO:
				state = procTo(line)
			elif state == States.PROC_BODY:
				if line.startswith("From:"):
					state = procStartOfNew(line)
				else:
					print(line)

			line = mailbox_file.readline()
	except Exception as e:
		# print(e)
		print("QUIT")


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# Agrego comando para tener gráficos interactivos en Spyder
# Tener en cuenta que se abre una nueva ventana donde se aprecia el gráfico
# %matplotlib

#Generamos 100 datos al azar con una distribución normal

n = 100
x1 = np.random.normal(-2.5, 1, 10000)
x2 = np.random.gamma(2, 1.5, 10000)
x3 = np.random.exponential(2, 10000)+7
x4 = np.random.uniform(14,20, 10000)

dists = [x1,x2,x3,x4]

def update(frame):
    # check if animation is at the last frame, and if so, stop the animation a
    if frame == n:
        myanimation.event_source.stop()

    bins = 10
    for ax,dist in zip(fig.get_axes(),dists):
        ax.cla()
        ax.hist(dist[:frame], bins=bins)

fig, ((ax1,ax2),(ax3,ax4)) = plt.subplots(2,2, sharex=True, sharey=True)
myanimation = animation.FuncAnimation(fig, update, frames=None, interval=100)

Course 2 - Applied Plotting_Charting_and_Data_ Representation/Module 3/Assignment_optional Practice assignment/assignment_optional.py


# Databricks notebook source
# MAGIC %md
# MAGIC You may find this series of notebooks at https://github.com/databricks-industry-solutions/ship2ship-transfers. For more information about this solution accelerator, visit https://medium.com/@timo.roest/ship-to-ship-transfer-detection-b370dd9d43e8.

# COMMAND ----------

# MAGIC %md ## We First Prep the data and download it

# COMMAND ----------

# MAGIC %pip install databricks_mosaic

# COMMAND ----------

from pyspark.sql.functions import *
import mosaic as mos

spark.conf.set("spark.databricks.labs.mosaic.geometry.api", "ESRI")
spark.conf.set("spark.databricks.labs.mosaic.index.system", "H3")
mos.enable_mosaic(spark, dbutils)

# COMMAND ----------

# MAGIC %md ##AIS Data

# COMMAND ----------

dbutils.fs.mkdirs("/tmp/ship2ship")

# COMMAND ----------

# MAGIC %sh
# MAGIC # see: https://coast.noaa.gov/htdata/CMSP/AISDataHandler/2018/index.html
# MAGIC # we download data to dbfs:// mountpoint (/dbfs)
# MAGIC mkdir /ship2ship/
# MAGIC cd /ship2ship/
# MAGIC wget -np -r -nH -L --cut-dirs=4 https://coast.noaa.gov/htdata/CMSP/AISDataHandler/2018/AIS_2018_01_31.zip > /dev/null 2>&1
# MAGIC unzip AIS_2018_01_31.zip
# MAGIC mv AIS_2018_01_31.csv /dbfs/tmp/ship2ship/

# COMMAND ----------

schema = """
  MMSI int,
  BaseDateTime timestamp,
  LAT double,
  LON double,
  SOG double,
  COG double,
  Heading double,
  VesselName string,
  IMO string,
  CallSign string,
  VesselType int,
  Status int,
  Length int,
  Width int,
  Draft double,
  Cargo int,
  TranscieverClass string
"""

AIS_df = (
    spark.read.csv("/tmp/ship2ship", header=True, schema=schema)
    .filter("VesselType = 70")  # Only select cargos
    .filter("Status IS NOT NULL")
)
display(AIS_df)

# COMMAND ----------

# DBTITLE 1,Initialize the database we use throughout this accelerator
# MAGIC %sql
# MAGIC DROP DATABASE IF EXISTS ship2ship CASCADE;
# MAGIC CREATE DATABASE ship2ship;

# COMMAND ----------

(AIS_df.write.format("delta").mode("overwrite").saveAsTable("ship2ship.AIS"))

# COMMAND ----------

# MAGIC %md ## Harbours
# MAGIC
# MAGIC This data can be obtained from [the US DOT](https://www.transportation.gov/data), and loaded with the code below.
# MAGIC
# MAGIC To avoid detecting overlap close to, or within harbours, in Notebook `03.b Advanced Overlap Detection` we filter out events taking place close to a harbour.
# MAGIC Various approaches are possible, including filtering out events too close to shore, and can be implemented in a similar fashion.
# MAGIC
# MAGIC In this instance we set a buffer of `10 km` around harbours to arbitrarily define an area wherein we do not expect ship-to-ship transfers to take place.
# MAGIC Since our projection is not in metres, we convert from decimal degrees. With `(0.00001 - 0.000001)` as being equal to one metre at the equator
# MAGIC Ref: http://wiki.gis.com/wiki/index.php/Decimal_degrees

# COMMAND ----------

# MAGIC %sh
# MAGIC # download our port data to dbfs:// mountpoint (/dbfs)
# MAGIC wget -O /dbfs/tmp/ship2ship/Principal_Ports.geojson https://raw.githubusercontent.com/databricks-industry-solutions/ship2ship-transfers/main/Data/Principal_Ports.geojson

# COMMAND ----------

one_metre = 0.00001 - 0.000001
buffer = 10 * 1000 * one_metre

major_ports = (
    spark.read.format("json")
    .option("multiline", "true")
    .load("/tmp/ship2ship/Principal_Ports.geojson")
    .select("type", explode(col("features")).alias("feature"))
    .select(
        "type",
        col("feature.properties").alias("properties"),
        to_json(col("feature.geometry")).alias("json_geometry"),
    )
    .withColumn("geom", mos.st_aswkt(mos.st_geomfromgeojson("json_geometry")))
    .select(col("properties.PORT_NAME").alias("name"), "geom")
    .withColumn("geom", mos.st_buffer("geom", lit(buffer)))
)
display(major_ports)

# COMMAND ----------

# MAGIC %%mosaic_kepler
# MAGIC major_ports "geom" "geometry"

# COMMAND ----------

(
    major_ports.select("name", mos.mosaic_explode("geom", lit(9)).alias("mos"))
    .select("name", col("mos.index_id").alias("h3"))
    .write.mode("overwrite")
    .format("delta")
    .saveAsTable("ship2ship.harbours_h3")
)

# COMMAND ----------

harbours_h3 = spark.read.table("ship2ship.harbours_h3")
display(harbours_h3)

# COMMAND ----------

# MAGIC %%mosaic_kepler
# MAGIC "harbours_h3" "h3" "h3" 5_000


import urllib.request
import urllib.parse
from bs4 import BeautifulSoup
from string import punctuation, digits
import csv
import pattern.en
import pattern.it
import pattern.fr
import pattern.de
import pattern.es
from pos_tags import pos_tags
from ngram import NGramDictionary

italian = 'italian-english'
unigram = NGramDictionary(n=1)
# POS, Named Entity Recognition, Conjugation, bab.la context sentences, synonyms, expanding contractions

def pos_treebank_to_babla(tag):
    '''
    Convert Penn Treebank II tag to respective bab.la part-of-speech tag/s.
    '''
    if tag in pos_tags:
        return pos_tags[tag]["babla"]
    else:
        return []

def parse_sentence(sentence, language="english"):
    '''
    Tokenize sentence and tag tokens with part-of-speech labels.
    return [(token, pos_tag)]
    '''
    if language == "english":
        tagged_sentence = pattern.en.tag(sentence)
    elif language == "italian":
        tagged_sentence = pattern.it.tag(sentence)
    elif language == "spanish":
        tagged_sentence = pattern.es.tag(sentence)
    elif language == "german":
        tagged_sentence = pattern.de.tag(sentence)
    elif language == "french":
        tagged_sentence = pattern.fr.tag(sentence)
    elif language == "dutch":
        tagged_sentence = pattern.nl.tag(sentence)
    else:
        tagged_sentence = pattern.en.tag(sentence)

    return tagged_sentence

def get_babla_url(word, source_language="italian", target_language="english"):
    # ASCII encode
    word_encoded = urllib.parse.quote(word)
    url = f"https://en.bab.la/dictionary/{source_language}-{target_language}/{word_encoded}"
    return url

def lookup(word, source_language="italian", target_language="english"):
    '''
    Create a dictionary of translations with POS labels as keys.
    return {'vb': ['to instantiate', 'to try on']}
    '''
    url = get_babla_url(word, source_language, target_language)
    contents = urllib.request.urlopen(url).read()

    soup = BeautifulSoup(contents, 'html.parser')
    all_translations = {}
    # Only retrieve translations source language -> targe language, not <->
    seen_quick_results_header = False
    for quick_result in soup.body.find('div', class_='quick-results') \
                            .find_all('div', class_=['quick-results-header', \
                                                     'quick-result-entry']):
        if 'quick-results-header' in quick_result['class']:
            if not seen_quick_results_header:
                # Skip first results header
                seen_quick_results_header = True
                continue
            else:
                # Don't extract translations after second results header
                return all_translations
        else:
            quick_result_option = quick_result.find('div', class_='quick-result-option')
            quick_result_overview = quick_result.find('div', class_="quick-result-overview")

            if quick_result_option != None and quick_result_overview != None:
                quick_result_option_span = quick_result_option.find('span', class_="suffix")
                quick_result_overview_ul = quick_result_overview.find('ul')

                if quick_result_option_span != None and quick_result_overview_ul != None:
                    # Extract the part of speech tag
                    pos = quick_result_option_span.text.strip("{[]}")
                    translations = quick_result_overview_ul.stripped_strings
                    if pos not in all_translations:
                        all_translations[pos] = [translation for translation in translations]
                    else:
                        all_translations[pos] += [translation for translation in translations]
    return all_translations

def merge_translations_arrays(translations_arrays):
    '''
    Get all translations from array of arrays with translations.
    '''
    return [translation \
                for translations in translations_arrays \
                for translation in translations]

def expand_contracted_determiner(word, source_language="italian", target_language="english"):
    if source_language=="italian" and "'" in word:
        return word.replace("'", "a")
    else:
        return word

def translate(word, pos_tag=None, source_language="italian", target_language="english"):
    '''Return array of translations.'''
    if source_language == "italian":
        dictionary = lookup(expand_contracted_determiner(word), source_language, target_language)
    else:
        dictionary = lookup(word, source_language, target_language)

    translations = []
    if pos_tag == None:
        translations = dictionary.values()
    else:
        babla_tags = pos_treebank_to_babla(pos_tag)
        for babla_tag in babla_tags:
            if babla_tag in dictionary:
                translations.append(dictionary[babla_tag])

    if len(translations) == 0:
        translations = dictionary.values()

    return merge_translations_arrays(translations)

def text_gen(fname):
    '''
    Produce next line from the specified file.
    '''
    with open(fname, errors='ignore') as f:
                for line in f:
                    yield line

def get_sentence_word_translations(sentence, source_language="italian", target_language="english"):
    parsed_sentence = parse_sentence(sentence, source_language)
    translations = []
    for (word, pos_tag) in parsed_sentence:
        if word in punctuation:
            translations.append([word])
        elif pos_tag == "NNP":
            translations.append([word])
        else:
            word_translations = translate(word, pos_tag, source_language, target_language)
            if len(word_translations) != 0:
                translations.append(word_translations)
            else:
                translations.append([word])
    return translations

def get_first_word(phrase):
    words_in_phrase = phrase.split()
    if len(words_in_phrase) > 0:
        return words_in_phrase[0]
    else:
        phrase

def get_last_word(phrase):
    words_in_phrase = phrase.split()
    if len(words_in_phrase) > 0:
        return words_in_phrase[-1]
    else:
        phrase

def get_most_probable_word(words, unigram):
    if unigram.n != 1:
        raise ValueError("A unigram dictionary must be passed as an argument.")
    return max([{"word": word, "count": unigram.get_count(word.lower())} \
          for word in words], key=lambda item: item["count"])["word"]

def get_most_probable_translation_bigram(first_translation, second_translation_options, bigram):
    if bigram.n != 2:
        raise ValueError("A bigram dictionary must be passed as an argument.")
    max_count = 0
    second_translation = second_translation_options[0]
    for second_translation_option in second_translation_options:
        current_option_count = bigram.get_count((get_last_word(first_translation).lower(),
                                                 get_first_word(second_translation_option).lower()))
        if current_option_count > max_count:
            max_count = current_option_count
            second_translation = second_translation_option
    return second_translation

def get_most_probable_translation_trigram(first_translation, second_translation, \
                                  third_translation_options, trigram):
    if trigram.n != 3:
        raise ValueError("A trigram dictionary must be passed as an argument.")
    max_count = 0
    third_translation = third_translation_options[0]
    for third_translation_option in third_translation_options:
        current_option_count = trigram.get_count((get_last_word(first_translation).lower(), \
                                                  second_translation.lower(), \
                                                  get_first_word(third_translation_option).lower()))
        if current_option_count > max_count:
            max_count = current_option_count
            third_translation = third_translation_option
    return third_translation

def get_translated_sentence(translations, ngram_dictionary=None):
    if ngram_dictionary == None:
        # return " ".join([translation[0] for translation in translations])
        return " ".join([get_most_probable_word(translation, unigram) for translation in translations])
    else:
        if ngram_dictionary.n == 2 and len(translations) >= 2:
            sentence_translation = [get_most_probable_word(translations[0], unigram)]
            for next_word_translation_options in translations[1:]:
                next_word_translation = get_most_probable_translation_bigram(sentence_translation[-1], \
                                                                             next_word_translation_options, \
                                                                             ngram_dictionary)
                sentence_translation.append(next_word_translation)

        elif ngram_dictionary.n == 3 and len(translations) >= 3:
            sentence_translation = [get_most_probable_word(translations[0], unigram),
                                    get_most_probable_word(translations[1], unigram)]
            for next_word_translation_options in translations[2:]:
                next_word_translation = get_most_probable_translation_trigram(sentence_translation[-2], \
                                                                             sentence_translation[-1], \
                                                                             next_word_translation_options, \
                                                                             ngram_dictionary)
                sentence_translation.append(next_word_translation)
        else:
            return " ".join([get_most_probable_word(translation, unigram) for translation in translations])

        return " ".join(sentence_translation)

def translate_sentence(sentence, source_language="italian", target_language="english", ngram_dictionary=None):
    individual_word_translations = get_sentence_word_translations(sentence, source_language, target_language)
    translated_sentence = get_translated_sentence(individual_word_translations, ngram_dictionary)
    return translated_sentence

def demo_translation():
    ngram = NGramDictionary()
    for line in text_gen('text_it.txt'):
        print(line)
        translated_sentence = translate_sentence(line, \
                                                 source_language="italian", \
                                                 target_language="english", \
                                                 ngram_dictionary=ngram)
        print(translated_sentence)

# demo_translation()


import posix

import mock

from nova import test
from novadocker.virt.docker import hostinfo

class HostInfoTestCase(test.NoDBTestCase):

    def setUp(self):
        super(HostInfoTestCase, self).setUp()
        self.stubs.Set(hostinfo, 'statvfs', self.statvfs)

    def statvfs(self):
        seq = (4096, 4096, 10047582, 7332259, 6820195,
               2564096, 2271310, 2271310, 1024, 255)
        return posix.statvfs_result(sequence=seq)

    def test_get_disk_usage(self):
        disk_usage = hostinfo.get_disk_usage()
        self.assertEqual(disk_usage['total'], 41154895872)
        self.assertEqual(disk_usage['available'], 27935518720)
        self.assertEqual(disk_usage['used'], 11121963008)

    def test_get_memory_usage(self):
        meminfo_str = """MemTotal:        1018784 kB
MemFree:         220060 kB
Buffers:           21640 kB
Cached:           63364 kB
SwapCached:            0 kB
Active:           13988 kB
Inactive:         50616 kB
"""
        with mock.patch('__builtin__.open',
                        mock.mock_open(read_data=meminfo_str),
                        create=True) as m:

            usage = hostinfo.get_memory_usage()
            m.assert_called_once_with('/proc/meminfo')
            self.assertEqual(usage['total'], 1043234816)
            self.assertEqual(usage['used'], 730849280)

    @mock.patch('novadocker.virt.docker.hostinfo.get_mounts')
    def test_find_cgroup_devices_path_centos(self, mock):
        mock.return_value = [
            'none /sys/fs/cgroup cgroup rw,relatime,perf_event,'
            'blkio,net_cls,freezer,devices,memory,cpuacct,cpu,'
            'cpuset 0 0']
        path = hostinfo.get_cgroup_devices_path()
        self.assertEqual('/sys/fs/cgroup', path)

    @mock.patch('novadocker.virt.docker.hostinfo.get_mounts')
    def test_find_cgroup_devices_path_ubuntu(self, mock):
        mock.return_value = [
            'cgroup /cgroup tmpfs rw,relatime,mode=755 0 0',
            'cgroup /cgroup/devices cgroup rw,relatime,devices,' +
            'clone_children 0 0']
        path = hostinfo.get_cgroup_devices_path()
        self.assertEqual('/cgroup/devices', path)


import cv2
import PIL.Image as PImage
import matplotlib.pyplot as plt
from matplotlib import transforms
import numpy as np
import math
import os
import httpx
import keras_ocr

from image_utils import load_images

# def paragraph_extract_preprocess(image : np.ndarray, min_size=(1080, 1080)):
#     """
#     """
#     image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
#     kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
#     image = cv2.GaussianBlur(image, kernel.shape, 0)
#     image = cv2.medianBlur(image, 5)
#     thres, image = cv2.threshold(image, 0, 204, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

#     plt.imshow(image, cmap='gray')
#     plt.show()
#     return image

# def extract_paragraphs(image : np.ndarray):
#     # Erode để phân tách dòng
#     kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (11,1))
#     image = cv2.erode(image, kernel, iterations=4)
#     contours, hierarchy = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
#     plt.imshow(image, cmap='gray')
#     plt.show()

    # avg_height = 0
    # for contour in contours:
    #     x, y, width, height = cv2.boundingRect(contour)
    #     cv2.rectangle(image, (x, y, width, height), color=(0, 0, 255), thickness=3)
    #     avg_height += height
    # avg_height = int(avg_height /(12 * len(contours))) + 1
    # print(avg_height)

    # kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,avg_height))
    # image = cv2.erode(image, kernel, iterations=4)
    # plt.imshow(image, cmap='gray')
    # plt.show()

    # contours, hierarchy = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # return contours

def segment_image_by_lines(image : np.ndarray, line_boxes) -> list:
    """tách ảnh theo dòng, trả về ảnh crop theo dòng

    image: ảnh gốc
    line_boxes: danh sách vị trí các dòng, trả về ở extract_text_lines()
    """
    # plt.imshow(img, cmap='gray')
    # plt.show()
    # preprocessed_img = paragraph_extract_preprocess(img)
    # # print(pytesseract.image_to_osd(preprocessed_img))
    # # offset = detect_orientation(preprocessed_img)
    # # reoriented_img = orient_image(preprocessed_img, offset)
    # # reoriented_original_img = orient_image(img, offset)

    # line_crops = []
    # y_list = []
    # contours = extract_paragraphs(preprocessed_img)
    # for contour in contours:
    #     x, y, width, height = cv2.boundingRect(contour)
    #     if height < img.shape[1]/100:
    #         continue

    #     # cv2.rectangle(img, (x, y, width, height), color=(0, 0, 255), thickness=3)
    #     line_crops.append(img[y : y+height, x : x+width])
    #     y_list.append(y)

    # line_crops.pop(0) # Contour đầu tiên là toàn bộ ảnh, bỏ ra vì ko cần
    # y_list.pop(0)
    # # Sắp xếp từ trên xuống dưới
    # args_sorted = np.argsort(y_list)
    # line_crops = [line_crops[i] for i in args_sorted]
    # return line_crops

    image = cv2.cvtColor(image, code=cv2.COLOR_RGB2GRAY)
    line_crops = []
    for line_box in line_boxes:
        rect = cv2.boundingRect(line_box)
        x, y, w, h = rect
        crop = image[y : y+h, x : x+w].copy()

        line_box = line_box - line_box.min(axis=0)
        mask = np.zeros((h, w), dtype=np.uint8)
        cv2.drawContours(mask, [line_box], -1, (255, 255, 255), -1, cv2.LINE_AA)
        # print(crop)
        line_image = cv2.bitwise_and(crop, crop, mask=mask)

        background = np.ones_like(crop, dtype=np.uint8)*255
        cv2.bitwise_not(background, background, mask=mask)
        line_image = line_image + background
        line_crops.append(line_image)

    # image = cv2.cvtColor(image, code=cv2.COLOR_RGB2GRAY)
    # line_crops = []
    # for boxes in line_boxes:
    #     points = []
    #     for point in boxes:
    #         points.append(point)

    #     points = np.asarray(points, dtype=np.uint8)
    #     print(points)

    #     rect = cv2.boundingRect(points)
    #     x, y, w, h = rect
    #     crop = image[y : y+h, x : x+w]

    #     mask = np.zeros((h,w), dtype=np.uint8)
    #     for box in line_boxes:
    #         cv2.drawContours(mask, [box], -1, (255,0,0), -1, cv2.LINE_AA)

    #     line_image = cv2.bitwise_and(crop, crop, mask=mask)

    #     background = np.ones_like(crop, dtype=np.uint8)*255
    #     cv2.bitwise_not(background, background, mask=mask)
    #     line_image = line_image + background
    #     line_crops.append(line_image)

    return line_crops

def separate_lines(image : np.ndarray, threshold = 200):
    '''tìm ranh giới các dòng, sắp xếp từ trên xuống dưới. Trả về list các (y1, y2), y1 là cận trên dòng, y2 là cận dưới dòng

    image: ảnh rgb
    '''
    image = cv2.cvtColor(image, code=cv2.COLOR_RGB2GRAY)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
    image = cv2.GaussianBlur(image, kernel.shape, 0)
    image = cv2.medianBlur(image, 5)
    thres, image = cv2.threshold(image, 0, 204, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (11,1))
    image = cv2.dilate(image, kernel, iterations=4)
    histogram = cv2.reduce(image, dim=1, rtype=cv2.REDUCE_AVG)
    histogram = [math.pow(x[0], 2) for x in histogram]
    # plt.imshow(image,cmap='gray')
    plt.plot(histogram)
    plt.savefig("debug_images/histogram.png")

    H,W = image.shape[:2]
    uppers = [y for y in range(H-1) if histogram[y]<=threshold and histogram[y+1]>threshold]
    lowers = [y for y in range(H-1) if histogram[y]>threshold and histogram[y+1]<=threshold]

    debug_image = cv2.cvtColor(image.copy(), cv2.COLOR_GRAY2BGR)
    for y in uppers:
        cv2.line(debug_image, (0,y), (W, y), (255,0,0), 1)

    for y in lowers:
        cv2.line(debug_image, (0,y), (W, y), (0,255,0), 1)

    cv2.imwrite("debug_images/line_sep_res.png", debug_image)

    # plt.imshow(image)
    # plt.show()

    lines = [(y1, y2) for y1, y2 in zip(uppers, lowers)]
    return lines

def keras_recognize(image : np.ndarray):
    """nhận diện vị trí chữ bằng Keras_ocr

    image: ảnh, dạng numpy array
    """
    debug_image = image.copy()
    image, scale_factor = preprocess_osd(image)
    image = cv2.cvtColor(image, code=cv2.COLOR_GRAY2RGB)
    recognizer = keras_ocr.detection.Detector()
    prediction_groups = recognizer.detect([image])

    groups = []
    for prediction in prediction_groups:
        boxes = []
        for box in prediction:
            unscaled_box = [(x / scale_factor, y / scale_factor) for x, y in box]
            unscaled_box = np.array(unscaled_box, dtype=np.int32)
            boxes.append(unscaled_box)
        groups.append(boxes)

    debug_image = keras_ocr.tools.drawBoxes(debug_image, boxes, color=(255,0,0), thickness=1, boxes_format='boxes')
    cv2.imwrite("debug_images/osd_result.png", debug_image)

    return groups

def categorize_by_lines(lines : list, prediction_groups):
    """Phân nhóm các hộp chứa chữ theo dòng

    lines: danh sách dòng, trả về từ separate_lines()
    prediction_groups: danh sách nơi có chữ, trả về từ keras_recognize()
    """
    box_by_lines = [[] for line in lines]
    for prediction in prediction_groups:
        for box in prediction:
            v1, v2, v3, v4 = box
            centroid = (v1[1] + v2[1] + v3[1] + v4[1]) / 4
            line_idx = 0
            for line_y1, line_y2 in lines:
                if line_y1 <= centroid <= line_y2:
                    # print("box: ", box, "IS in line", line_idx, "because", line_y1, line_y2)
                    box_by_lines[line_idx].append(box)
                    break
                else:
                    # print("box: ", box, "NOT in line", line_idx, "because", line_y1, line_y2)
                    line_idx += 1
    return box_by_lines

def preprocess_osd(image : np.ndarray, min_size=(2160,2160)):
    if len(image.shape) == 3:
        image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    total_scale_factor = 1

    min_width, min_height = min_size
    height, width = image.shape[:2]

    if width < min_width:
        scale_factor = min_width / width
        height = int(height * scale_factor)
        width = min_width
        total_scale_factor *= scale_factor
    if height < min_height:
        scale_factor = min_height / height
        width = int(width * scale_factor)
        height = min_height
        total_scale_factor *= scale_factor

    # while width < min_width or height < min_height:
    #     width *= 2
    #     height *= 2
    #     total_scale_factor *= 2

    image = cv2.resize(src=image, dsize=(width, height), interpolation=cv2.INTER_CUBIC)
    return image, total_scale_factor

def preprocess_ocr(image : np.ndarray, min_size=(320,320)):
    """Tiền xử lý ảnh trước khi OCR, trả về ảnh đã xử lý

    image: ảnh gốc, dạng numpy array
    min_size: kích cỡ tối thiểu (chiều cao, chiều dài). Đối với OCR nên để ở khoảng
    """
    if len(image.shape) == 3:
        image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

    image, scale_factor = preprocess_osd(image, min_size=min_size)
    thres, image = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    # kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
    # image = cv2.GaussianBlur(image, kernel.shape, 0)
    # thres, image = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    # image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)
    return image

def send_to_tika(image : np.ndarray):
    is_success, image_buffer = cv2.imencode(".jpeg", image)
    image_bytes = image_buffer.tobytes()
    with httpx.Client() as client:
        headers = {
            "Accept": "text/plain",
            "X-Tika-OCRPageSegMode": "7", #single text line
            "X-Tika-OCRLanguage": "vie"
        }
        return client.put(url="http://10.15.10.123:9998/tika", data=image_bytes, headers=headers, timeout=None).text

def extract_text_lines(image : np.ndarray):
    """tìm dòng, trả về polygon bao quanh mỗi chữ dưới dạng list

    image: ảnh dạng numpy array
    """
    lines = separate_lines(image)
    prediction_groups = keras_recognize(image)
    box_by_lines = categorize_by_lines(lines, prediction_groups)
    line_boxes = []
    for line in box_by_lines:
        line_box = []
        for box in line:
            for point in box:
                line_box.append(point)
        if len(line_box) == 0:
            continue
        box = np.asarray(line_box, dtype=np.int32)
        rectangle = cv2.minAreaRect(box.copy())
        box = cv2.boxPoints(rectangle)
        box = np.array(box, dtype=np.int32)
        line_boxes.append(box)

    debug_image = image.copy()
    debug_image = cv2.polylines(debug_image, line_boxes, isClosed=True, color=(0, 0, 255), thickness=2)
    cv2.imwrite("debug_images/polygon.png", debug_image)

    return line_boxes

def read_image_by_lines(image : np.ndarray):
    """OCR ảnh, sắp xếp theo từng dòng

    image: ảnh, dạng numpy array
    """
    plt.imshow(image)
    plt.savefig("debug_images/source.png")
    results = []
    line_boxes = extract_text_lines(image)
    line_crops = segment_image_by_lines(image, line_boxes)
    for line_crop in line_crops:
        line_crop = preprocess_ocr(line_crop)
        result = send_to_tika(line_crop)
        results.append(result)

    print(results)
    return results

def main():
    img = load_images()
    img = img[3]
    results = []
    line_boxes = read_image_by_lines(img)

    # box = [[910,1969],
    #         [934,1946],
    #         [1000,2016],
    #         [976,2039],
    #         [1086,1958],
    #         [1124,1958],
    #         [1124,1987],
    #         [1086,1987],
    #         [1067,2028],
    #         [1153,1952],
    #         [1177,1978],
    #         [1092,2055],
    #         [1004,2018],
    #         [1080,2018],
    #         [1080,2047],
    #         [1004,2047],
    #         [1149,2038],
    #         [1211,2038],
    #         [1211,2066],
    #         [1149,2066],
    #         [1092,2043],
    #         [1137,2043],
    #         [1137,2066],
    #         [1092,2066]]

    # box = np.asarray(box, dtype=np.int32)
    # rectangle = cv2.minAreaRect(box.copy())
    # print(rectangle)
    # read_image_by_lines(img)

if __name__ == '__main__':
    main()