"""
Common DBus utilities.
"""

from __future__ import absolute_import

from gi.repository import Gio
from gi.repository import GLib

__all__ = ['DBusProperties',
           'DBusProxy',
           'DBusObject',
           'DBusBus',
           'DBusService',
           'DBusException']

DBusException = GLib.GError

class DBusProperties(object):

    """
    Dbus property map abstraction.

    Wraps properties of a DBus interface on a DBus object as attributes.

    :ivar Gio.DBusProxy __proxy: proxy for the DBus.Properties interface
    :ivar str __interface: inspected interface name
    """

    def __init__(self, object, name):
        """
        Initialize a proxy object with standard DBus property interface.

        :param Gio.DBusObject object: accessed object
        :param str name: interface name
        """
        self.__proxy = object._get_interface(
            'org.freedesktop.DBus.Properties')
        self.__interface = name

    def __getattr__(self, key):
        """
        Retrieve the property via the DBus proxy.

        :param str key: name of the dbus property
        :returns: the property value
        """
        return self.__proxy.Get('(ss)', self.__interface, key)

class DBusProxy(object):

    """
    DBus proxy object for a specific interface.

    Provides attribute accessors to properties and methods of a DBus
    interface on a DBus object.

    :ivar str object_path: object path of the DBus object
    :ivar DBusProperties property: attribute access to DBus properties
    :ivar Gio.DBusProxy method: attribute access to DBus methods
    :ivar Gio.DBusProxy _proxy: underlying proxy object
    """

    Exception = DBusException

    def __init__(self, proxy):
        """
        Initialize property and method attribute accessors for the interface.

        :param Gio.DBusProxy proxy: accessed object
        :param str interface: accessed interface
        """
        self._proxy = proxy
        self.object_path = proxy.get_object_path()
        self.property = DBusProperties(self.object,
                                       proxy.get_interface_name())
        self.method = proxy

    @property
    def object(self):
        """
        Get a proxy for the underlying object.

        :rtype: DBusObject
        """
        proxy = self._proxy
        return DBusObject(proxy.get_connection(),
                          proxy.get_name(),
                          proxy.get_object_path())

    def connect(self, event, handler):
        """
        Connect to a DBus signal.

        :param str event: event name
        :param handler: callback
        :returns: subscription id
        :rtype: int
        """
        interface = self._proxy.get_interface_name()
        return self.object.connect(interface, event, handler)

class DBusObject(object):

    """
    Simple proxy class for a DBus object.

    :param Gio.DBusConnection connection:
    :param str bus_name:
    :param str object_path:
    """

    def __init__(self, connection, bus_name, object_path):
        """
        Initialize member variables.

        :ivar Gio.DBusConnection connection:
        :ivar str bus_name:
        :ivar str object_path:

        This performs IO at all.
        """
        self.connection = connection
        self.bus_name = bus_name
        self.object_path = object_path

    def _get_interface(self, name):
        """
        Get a Gio native interface proxy for this Dbus object.

        :param str name: interface name
        :returns: a proxy object for the other interface
        :rtype: Gio.DBusProxy
        """
        return Gio.DBusProxy.new_sync(
            self.connection,
            Gio.DBusProxyFlags.NONE,
            info=None,
            name=self.bus_name,
            object_path=self.object_path,
            interface_name=name,
            cancellable=None,
        )

    def get_interface(self, name):
        """
        Get an interface proxy for this Dbus object.

        :param str name: interface name
        :returns: a proxy object for the other interface
        :rtype: DBusProxy
        """
        return DBusProxy(self._get_interface(name))

    @property
    def bus(self):
        """
        Get a proxy object for the underlying bus.

        :rtype: DBusBus
        """
        return DBusBus(self.connection, self.bus_name)

    def connect(self, interface, event, handler):
        """
        Connect to a DBus signal.

        :param str interface: interface name
        :param str event: event name
        :param handler: callback
        :returns: subscription id
        :rtype: int
        """
        object_path = self.object_path
        return self.bus.connect(interface, event, object_path, handler)

class DBusCallback(object):

    def __init__(self, handler):
        """Store reference to handler."""
        self._handler = handler

    def __call__(self,
                 connection,
                 sender_name,
                 object_path,
                 interface_name,
                 signal_name,
                 parameters,
                 *user_data):
        """Call handler unpacked signal parameters."""
        return self._handler(*parameters.unpack())

class DBusCallbackWithObjectPath(object):

    def __init__(self, handler):
        """Store reference to handler."""
        self._handler = handler

    def __call__(self,
                 connection,
                 sender_name,
                 object_path,
                 interface_name,
                 signal_name,
                 parameters,
                 *user_data):
        """Call handler with object_path and unpacked signal parameters."""
        return self._handler(object_path, *parameters.unpack())

class DBusBus(object):

    """
    Simple proxy class for a connected bus.

    :ivar Gio.DBusConnection connection:
    :ivar str bus_name:
    """

    def __init__(self, connection, bus_name):
        """
        Initialize member variables.

        :param Gio.DBusConnection connection:
        :param str bus_name:

        This performs IO at all.
        """
        self.connection = connection
        self.bus_name = bus_name

    def get_object(self, object_path):
        """
        Get a object representing the specified object.

        :param str object_path: object path
        :returns: a simple representative for the object
        :rtype: DBusObject
        """
        return DBusObject(self.connection, self.bus_name, object_path)

    def connect(self, interface, event, object_path, handler):
        """
        Connect to a DBus signal.

        :param str interface: interface name
        :param str event: event name
        :param str object_path: object path or ``None``
        :param handler: callback
        """
        if object_path:
            callback = DBusCallback(handler)
        else:
            callback = DBusCallbackWithObjectPath(handler)
        return self.connection.signal_subscribe(
            self.bus_name,
            interface,
            event,
            object_path,
            None,
            Gio.DBusSignalFlags.NONE,
            callback,
            None,
        )

    def disconnect(self, subscription_id):
        """
        Disconnect a DBus signal subscription.
        """
        self.connection.signal_unsubscribe(subscription_id)

class DBusService(object):

    """
    Abstract base class for UDisksX service wrapper classes.
    """

    @classmethod
    def connect_service(cls):
        """
        Connect to the service object on DBus.

        :returns: new proxy object for the service
        :rtype: DBusProxy
        :raises BusException: if unable to connect to service.
        """
        return DBusProxy(Gio.DBusProxy.new_for_bus_sync(
            Gio.BusType.SYSTEM,
            Gio.DBusProxyFlags.NONE,
            info=None,
            name=cls.BusName,
            object_path=cls.ObjectPath,
            interface_name=cls.Interface,
            cancellable=None,
        ))


import os
from os import path, listdir
from subprocess import Popen, PIPE
import sys
from datetime import datetime
import yaml
import re
from timeout import timeout

stream = open("data.yaml", "r")
doc = yaml.load(stream)
directory = doc["directory_of_homework"] + sys.argv[1] + "/" + sys.argv[2] + "/" + sys.argv[3]

if sys.argv[4] == "all":
	stream = open("scenarios_" + sys.argv[3] + ".yaml", "r")
	scenarios = yaml.load(stream)
	tasks = scenarios["tasks"]
else:
	tasks = ["task{0}.c".format(sys.argv[4])]
	number_of_task = re.findall(r'\d', sys.argv[4])[0]
	scenarios = {"task{0}".format(sys.argv[4]): { "number_of_tests": 1, "input{0}".format(number_of_task): sys.argv[5], "output{0}".format(number_of_task): sys.argv[6] } }

summary = {}

@timeout(3)
def check_homework(tasks, scenarios):
	num_of_hw = 0
	print("Evaluating homework {0} on student {1} from {2} class\n".format(sys.argv[3], sys.argv[2], sys.argv[1]))

	files = []
	result = {}
	for root, dirs, files in os.walk(directory, topdown=False):
		files = [f for f in listdir(root) if (path.isfile(path.join(root, f))
				 and f in tasks)]
		if not files:
			continue

		for current_file in files:
			print("\nEvalutaing {0}".format(current_file))
			abs_path = path.abspath(path.join(directory, current_file))
			exec_path = path.abspath(path.join(directory, "a.out"))

			gpp_invoke = "gcc -Wall -std=c11 {0} -o {1} 2> homeworks_result.txt".format(abs_path, exec_path)

			result = os.system(gpp_invoke)

			f = open('homeworks_result.txt', 'r')
			result_of_compilation = f.read()

			successful = True
			scenario = current_file.split('.')[0]

			if result is not 0:
				print("\tFiles can't compile (gcc err code:{0})".format(result))
				summary[scenario] = "0/{0} - error".format(scenarios[scenario]["number_of_tests"])
				continue

			if result_of_compilation != "":
				print("\tWarning:\n \t\t{0}".format(result_of_compilation))
				summary[scenario] = "0/{0} - warning".format(scenarios[scenario]["number_of_tests"])
				continue

			if scenario in scenarios.keys():

				actual_successful_test = 0

				for i in range(scenarios[scenario]["number_of_tests"]):
					p = Popen([exec_path], stdout=PIPE, stderr=PIPE, stdin=PIPE)
					input_data = scenarios[scenario]["input{0}".format(i+1)]
					std_out_data, _ = p.communicate(input_data.encode())

					output = std_out_data.decode('latin-1').rstrip('\n').replace('\0', '').strip()
					output = output.replace('\n', ' ')
					sys.stdout.write("\t")

					if output == scenarios[scenario]["output{0}".format(i+1)]:
						sys.stdout.write(" ".join("Test {0} passed".format(i+1)
						   .split()))
						actual_successful_test += 1
					else:
						sys.stdout.write("Test {0} failed:\n".format(i+1))
						sys.stdout.write("\t\tExpected:\n\t\t\t{0}\n".format(scenarios[scenario]["output{0}".format(i+1)]))
						sys.stdout.write("\t\tGot: \n \t\t\t{0}\n".format(output))
						successful = False
					sys.stdout.write("\n")

					summary[scenario] = "{0}/{1}".format(actual_successful_test, scenarios[scenario]["number_of_tests"])
				if successful:
					num_of_hw += 1

	print("\nSummary\n")
	if summary.keys():
		for task in summary.keys():
			print("\t{0} - {1}".format(task, summary[task]))
	else:
		print("\tMissing homework\n")
	return num_of_hw

check_homework(tasks, scenarios)


#import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns; sns.set(style="ticks", color_codes=True)

#GRÁFICA
data = pd.read_csv('datos.csv', header = 0)
data

plt.scatter(data['distancia'], data['tiempo_real'], c='r', label = 'Tiempo Real')
plt.scatter(data['distancia'], data['tiempo_medido'], c='b', label = 'Tiempo Medido')

plt.xlabel('distancia [m]')
plt.ylabel('tiempo [s]')
plt.title('Caida Libre')
plt.legend()
plt.grid(True)
plt.show()

#TABLAS DE ERRORES
media = data.tiempo_real.mean()
media

data['error_absoluto'] = abs(data.tiempo_real - data.tiempo_medido)
data.head()

data['error_relativo'] = data['error_absoluto'] / data.tiempo_real * 100
data.head()

#Gráficas
sns.pairplot(data, hue="distancia")


"""Hook data lookup."""
# pylint: disable=arguments-differ,unused-argument
from runway.lookups.handlers.base import LookupHandler

TYPE_NAME = "hook_data"

class HookDataLookup(LookupHandler):
    """Hook data lookup."""

    @classmethod
    def handle(cls, value, context=None, provider=None, **kwargs):
        """Return the value of a key for a given hook in hook_data.

        Args:
            value (str): Parameter(s) given to this lookup.
            context (:class:`runway.cfngin.context.Context`): Context instance.
            provider (:class:`runway.cfngin.providers.base.BaseProvider`):
                Provider instance.

        Format of value:

            <hook_name>::<key>

        """
        try:
            hook_name, key = value.split("::")
        except ValueError:
            raise ValueError("Invalid value for hook_data: %s. Must be in "
                             "<hook_name>::<key> format." % value)

        return context.hook_data[hook_name][key]


"""
Problem 35

The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime.

There are thirteen such primes below 100: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, and 97.

How many circular primes are there below one million?

"""

from __future__ import print_function
from __future__ import division

from itertools import count, imap
from sympy import isprime
from math import log10

found = {}

def primes():
    for i in count(2):
        if isprime(i):
            yield(i)

def rotations(n):
    res = set()
    digit_count = int(log10(n))
    for i in range(1, digit_count+1):
        a, b = 10**i, 10**(digit_count-i+1)
        res.add(n%a * b + n//a)
    return res

c = 0
for i in primes():
    if i > 1000000:
        break
    if all(imap(isprime, rotations(i))):
        c += 1

print(c)


import pycqed as pq
import matplotlib.pyplot as plt
import os
from pycqed.analysis import measurement_analysis as ma
from numpy.testing import assert_almost_equal

class TestSSRODiscriminationAnalysis:

    @classmethod
    def setup_class(cls):
        cls.datadir = os.path.join(pq.__path__[0], 'tests', 'test_data')
        ma.a_tools.datadir = cls.datadir

    def test_butterfly_postselected(self):
        # Test the correct file is loaded
        a = ma.butterfly_analysis(timestamp='20170710_180002',
                                  close_main_fig=False, initialize=True,
                                  threshold=0.5,
                                  digitize=False, case=True)

        assert_almost_equal(a.butterfly_coeffs['F_a_butterfly'], 0.7998,
                            decimal=3)

    def test_butterfly_simple(self):
        # Test the correct file is loaded
        a = ma.butterfly_analysis(timestamp='20170710_182949',
                                  close_main_fig=False, initialize=False,
                                  threshold=0.5,
                                  digitize=False, case=True)

        assert_almost_equal(a.butterfly_coeffs['F_a_butterfly'], 0.819,
                            decimal=3)

    @classmethod
    def teardown_class(cls):
        plt.close('all')


import pymunk as pm
from random import randrange
import math
import constants

class RoadBuilder:
    def __init__(self, space):
        self._space = space

    def build_road(self, vs, radius, color=(0, 0, 0, 0)):
        """
        :param color: color of the road
        :param vs: Vertices that make up the roads
        :param radius: radius of the road Segments
        :return: The road Segment objects
        """
        # create the road Segments using the given vertices
        static_body = pm.Body(body_type=pm.Body.STATIC)
        static_segments = []
        for v in vs:
            seg = pm.Segment(static_body, v[0], v[1], radius)
            seg.elasticity = 0.10
            seg.friction = 0.90
            seg.color = color
            seg.filter = pm.ShapeFilter(categories=3)
            static_segments.append(seg)

        self._space.add(static_body)
        self._space.add(*static_segments)
        return static_body, static_segments

    def random_terrain_vertices_generator(self, vs, length, total_segments):
        """
        Randomly generates a road that builds towards the positive x-direction with
        each segment being a fixed length
        :param total_segments: total number of segments to be made
        :param length: length of the road Segment
        :param vs: Starting vertex
        :return: The vertices of the random terrain
        """
        vertices = [vs]
        # starting from 1 to be able to append new vertices to the vertices list that already contains 1
        for seg_num in range(1, total_segments*2):
            # most steep : 1, very flat: > 2
            steepness = 2
            # x-value has to be the same every other point to make the segments connect
            if seg_num % 2 == 1:
                delta_y = randrange(int(-length/steepness), int(length/steepness))
                delta_x = math.sqrt(length ** 2 - delta_y ** 2)
            else:
                delta_x = 0
                delta_y = 0
            # append a new vertex using the coordinates of the previous vertex
            prev_vertex = vertices[seg_num - 1]
            # make sure the delta_y value never create a point below the screen
            if prev_vertex[1] + int(delta_y) > constants.HEIGHT:
                delta_y = constants.HEIGHT - prev_vertex[1]
            # create the new vertex
            new_vertex = prev_vertex[0] + int(delta_x), prev_vertex[1] + int(delta_y)
            vertices.append(new_vertex)
        # put the vertices into pairs
        vertex_pairs = []
        for i in range(0, total_segments*2, 2):
            vertex_pairs.append((vertices[i], vertices[i+1]))
        return vertex_pairs


from __future__ import print_function
from flask import request, render_template as render
from server import app, splitter_sub as splitter
from notebook import manager as Manager, editor as Editor

from os.path import expanduser

path = expanduser('~') + '/Dropbox/MD_NOTES'

editor  = Editor.editor( path )
manager = Manager.manager

def jsonify( d ):
    return str( d ).replace( "'", '"' )

# Setting up the variables for the layout.html base template so the same
# variables don't have to be passed everytime a page is called
@app.context_processor
def inject_global():
    tree=manager.create_file_tree( path )

    def recurse_dict( file_dict ):
        for key, value in file_dict.iteritems():
            if isinstance(value, dict):
                file_dict[key] = recurse_dict( value )
            else:
                if isinstance(value, str):
                    file_dict[key] = '/edit?file=' + splitter.join(manager.split_path(value))
        return file_dict

    file_list = manager.create_file_list( path )

    return dict( tree=recurse_dict( tree ), fileList=file_list )

@app.route( '/' )
@app.route( '/index' )
@app.route( '/index.html' )
def index():
    return render( 'index.html',  content='Hello', title='index' )

@app.route( '/edit' )
def edit():
    file_path = request.args.get( 'file' )
    if not file_path:
        return index()
    file_data = editor.get_file_data( file_path )
    return render( 'editor.html', file_data=file_data )

@app.route( '/save', methods=['POST'] )
def save():
    data = request.get_json()
    editor.write_file_data( data.get( 'file' ), data.get( 'data' ) )
    return jsonify( { "success" : "true" } )


# -*- coding: utf-8 -*-

class Edge:
    def __init__(self,ID,i,next_ID):
        self.ID = ID
        self.input = i
        self.next_ID = next_ID

class NFA:

    def __init__(self):
        self.graph = []
        self.total = 0

    def read(self,path):
        f = open(path,'r')
        mapping_function=[]
        for line in f.readlines():
                func = line.strip().split(' ')

                mapping_function.append(Edge(int(func[0]), func[1], int(func[2])))
        self.graph = mapping_function
        # print(self.graph)
    def printNFA(self):
        for g in self.graph:
            p = "%d %s %d" % (g.ID,g.input,g.next_ID)
            print(p)
        print("")
char = ['a','b']

class Subset:
    sub_ID = 0
    def __init__(self,nodes):
        self.nodes = nodes
        self.already = 0
        self.id = Subset.sub_ID
        Subset.sub_ID += 1

class DFA:
    def __init__(self, nfa):
        self.nfa = nfa.graph
        self.total = 0
        self.subsets = []
        self.graph = []
        self.accept = []
        self.no = []

    def eclosure(self,nodes):
        if nodes == []:
            return -1
        nodes.sort()
        # print(nodes)
        for node in nodes:
            for n in self.nfa:
                if n.ID == node and n.input == 'ß' and n.next_ID not in nodes:
                    nodes.append(n.next_ID)
        nodes.sort()
        f = 0
        for n in self.subsets:
            if nodes == n.nodes:
                f = 1
                return n
        if f == 0:
            sub = Subset(nodes)
            self.subsets.append(sub)
            if 1 in nodes:
                self.accept.append(sub.id)
            else:
                self.no.append(sub.id)
            return sub

    def move(self,nodes,i):
        aims = []
        for node in nodes:
            for n in self.nfa:
                if n.ID == node and n.input == i:
                    aims.append(n.next_ID)
        return list(set(aims)) # 去重

    def determinate(self):
        self.subsets.append(self.eclosure([0]))
        for i in self.subsets:
            if i.already == 1:
                continue
            i.already = 1
            for c in char:
                if not self.eclosure(self.move(i.nodes,c)) == -1:
                    self.graph.append(Edge(i.id,c,self.eclosure(self.move(i.nodes,c)).id))
                else:
                    continue

    def printDFA(self):
        for g in self.graph:
            p = "%d %s %d" % (g.ID,g.input,g.next_ID)
            print(p)

if __name__ == "__main__":
    nfa = NFA()
    nfa.read('2-3/4.txt')
    nfa.printNFA()
    dfa = DFA(nfa)
    dfa.determinate()
    dfa.printDFA()


import yaml
import os

class AbsoluteConfigFactory(object):
    def __init__(self, *secret_files, keep_secrets=False):
        data = ""
        for file in secret_files:
            with open(file, 'r') as fin:
                    data += fin.read() + '\n'
        self.secrets = data
        loaded = yaml.load(data)
        self.secret_keys = [] if keep_secrets or loaded is None else loaded.keys()

    def get(self, file):
        if not hasattr(self, file):
            with open(file, 'r') as fin:
                data = fin.read()
            decoded_yaml = yaml.load(self.secrets + data)
            for key in self.secret_keys:
                decoded_yaml.pop(key, None)
            setattr(self, file, decoded_yaml)
        return getattr(self, file)

class ConfigFactory(AbsoluteConfigFactory):
    def __init__(self, basedir, *secret_files, keep_secrets=False, secrets_absolute_path=False):
        self.basedir = basedir
        if not secrets_absolute_path:
            secret_files = [self.format_path(file) for file in secret_files]
        super().__init__(*secret_files, keep_secrets=keep_secrets)

    def get(self, file):
        file = self.format_path(file)
        return super().get(file)

    def format_path(self, file):
        return os.path.join(self.basedir, file if os.path.splitext(file)[1] is not '' else os.path.splitext(file)[0] + ".yaml")


"""
给你二叉树的根节点 root ，返回它节点值的 前序 遍历。
"""

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution(object):
    def preorderTraversal_recursion(self, root):
        def dfs(node):
            if not node:
                return
            ans.append(node.val)
            dfs(node.left)
            dfs(node.right)

        ans = []
        dfs(root)
        return ans

    def preorderTraversal_loop(self, root):
        res = list()
        if not root:
            return res

        stack = []
        node = root
        while stack or node:
            while node:
                res.append(node.val)
                stack.append(node)
                node = node.left
            node = stack.pop()
            node = node.right
        return res

if __name__ == '__main__':
    node2 = TreeNode(2)
    node3 = TreeNode(3)
    root = TreeNode(1, node2, node3)

    solution = Solution()
    fun = solution.preorderTraversal(root)
    print(fun)


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

# # Question 1
# Given two linked list of the same size, the task is to create a new linked list using those linked lists. The condition is that the greater node among both linked list will be added to the new linked list.
#

# In[5]:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

def merge_lists(list1, list2):
    # Create a new empty linked list
    newList = None

    # Traverse both linked lists simultaneously
    while list1 is not None and list2 is not None:
        # Compare the values of the nodes
        if list1.data >= list2.data:
            # Add the node from list1 to the new list
            newNode = Node(list1.data)
            newNode.next = newList
            newList = newNode
            list1 = list1.next
        else:
            # Add the node from list2 to the new list
            newNode = Node(list2.data)
            newNode.next = newList
            newList = newNode
            list2 = list2.next

    # Add remaining nodes from list1, if any
    while list1 is not None:
        newNode = Node(list1.data)
        newNode.next = newList
        newList = newNode
        list1 = list1.next

    # Add remaining nodes from list2, if any
    while list2 is not None:
        newNode = Node(list2.data)
        newNode.next = newList
        newList = newNode
        list2 = list2.next

    return newList

# Helper function to print the linked list
def print_list(head):
    while head is not None:
        print(head.data, end="->")
        head = head.next
    print("None")

# Example usage:
# Creating the first linked list: 5->2->3->8
list1 = Node(5)
list1.next = Node(2)
list1.next.next = Node(3)
list1.next.next.next = Node(8)

# Creating the second linked list: 1->7->4->5
list2 = Node(1)
list2.next = Node(7)
list2.next.next = Node(4)
list2.next.next.next = Node(5)

# Merge the two linked lists
newList = merge_lists(list1, list2)

# Print the merged linked list
print_list(newList)

# # Question 2
# Write a function that takes a list sorted in non-decreasing order and deletes any duplicate nodes from the list. The list should only be traversed once.
# For example if the linked list is 11->11->11->21->43->43->60 then removeDuplicates() should convert the list to 11->21->43->60.
#

# In[6]:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

def remove_duplicates(head):
    current = head

    # Traverse the list
    while current is not None and current.next is not None:
        # Compare current node with the next node
        if current.data == current.next.data:
            # Skip the next node by updating current's next pointer
            current.next = current.next.next
        else:
            # Move to the next node
            current = current.next

    return head

# Helper function to print the linked list
def print_list(head):
    while head is not None:
        print(head.data, end="->")
        head = head.next
    print("None")

# Example usage:
# Creating the linked list: 11->11->11->21->43->43->60
head = Node(11)
head.next = Node(11)
head.next.next = Node(11)
head.next.next.next = Node(21)
head.next.next.next.next = Node(43)
head.next.next.next.next.next = Node(43)
head.next.next.next.next.next.next = Node(60)

# Remove duplicates from the linked list
head = remove_duplicates(head)

# Print the modified linked list
print_list(head)

# # Question 3
# Given a linked list of size N. The task is to reverse every k nodes (where k is an input to the function) in the linked list. If the number of nodes is not a multiple of k then left-out nodes, in the end, should be considered as a group and must be reversed (See Example 2 for clarification).
#

# In[7]:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

def reverse_k_nodes(head, k):
    prev = None
    curr = head
    next = None
    count = 0

    # Reverse the group of k nodes
    while curr is not None and count < k:
        next = curr.next
        curr.next = prev
        prev = curr
        curr = next
        count += 1

    # Recursively reverse the next group of k nodes
    if next is not None:
        head.next = reverse_k_nodes(next, k)

    return prev

# Helper function to print the linked list
def print_list(head):
    while head is not None:
        print(head.data, end="->")
        head = head.next
    print("None")

# Example usage:
# Creating the linked list: 1->2->3->4->5->6->7->8->9
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.next.next.next = Node(4)
head.next.next.next.next = Node(5)
head.next.next.next.next.next = Node(6)
head.next.next.next.next.next.next = Node(7)
head.next.next.next.next.next.next.next = Node(8)
head.next.next.next.next.next.next.next.next = Node(9)

k = 3  # Number of nodes to reverse

# Reverse every k nodes in the linked list
head = reverse_k_nodes(head, k)

# Print the modified linked list
print_list(head)

# # Question 4
# Given a linked list, write a function to reverse every alternate k nodes (where k is an input to the function) in an efficient way. Give the complexity of your algorithm.
#
#

# In[8]:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

def reverse_alternate_k_nodes(head, k):
    prev = None
    curr = head
    next = None
    count = 0
    is_alternate = True
    alternate_head = None
    alternate_tail = None
    prev_tail = None

    # Reverse the alternate groups of k nodes
    while curr is not None:
        while curr is not None and count < k:
            next = curr.next
            curr.next = prev
            prev = curr
            curr = next
            count += 1

        if is_alternate:
            if alternate_head is None:
                alternate_head = prev
                alternate_tail = prev
            else:
                alternate_tail.next = prev
                alternate_tail = prev
            is_alternate = False
        else:
            if prev_tail is None:
                head = prev
            else:
                prev_tail.next = prev
            prev_tail = alternate_tail
            alternate_head = None
            is_alternate = True

        if count < k:
            break

        prev = None
        count = 0

    if alternate_head is not None:
        prev_tail.next = alternate_head

    return head

# Helper function to print the linked list
def print_list(head):
    while head is not None:
        print(head.data, end="->")
        head = head.next
    print("None")

# Example usage:
# Creating the linked list: 1->2->3->4->5->6->7->8->9->10
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.next.next.next = Node(4)
head.next.next.next.next = Node(5)
head.next.next.next.next.next = Node(6)
head.next.next.next.next.next.next = Node(7)
head.next.next.next.next.next.next.next = Node(8)
head.next.next.next.next.next.next.next.next = Node(9)
head.next.next.next.next.next.next.next.next.next = Node(10)

k = 3  # Number of nodes to reverse altern

# # Question 5
# Given a linked list and a key to be deleted. Delete last occurrence of key from linked. The list may have duplicates.
#

# In[13]:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

def delete_last_occurrence(head, key):
    prev = None
    curr = None
    key_found = False

    # Traverse the linked list
    temp = head
    while temp is not None:
        if temp.data == key:
            prev = curr
            curr = temp
            key_found = True
        temp = temp.next

    # Check if key was found
    if not key_found:
        return head

    # Perform the deletion
    if curr == head:
        head = curr.next
    else:
        prev.next = curr.next

    return head

# Helper function to print the linked list
def print_list(head):
    while head is not None:
        print(head.data, end="->")
        head = head.next
    print("None")

# Example usage:
# Creating the linked list: 1->2->3->2->4->2->5
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.next.next.next = Node(2)
head.next.next.next.next = Node(4)
head.next.next.next.next.next = Node(2)
head.next.next.next.next.next.next = Node(5)

key = 2  # Key to be deleted

# Delete the last occurrence of the key
head = delete_last_occurrence(head, key)

# Print the modified linked list
print_list(head)

# # Question 6
# Given two sorted linked lists consisting of N and M nodes respectively. The task is to merge both of the lists (in place) and return the head of the merged list.
#
#

# In[14]:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

def merge_sorted_lists(head1, head2):
    dummy = Node(0)
    curr = dummy

    # Traverse both lists simultaneously
    ptr1 = head1
    ptr2 = head2
    while ptr1 is not None and ptr2 is not None:
        if ptr1.data <= ptr2.data:
            curr.next = ptr1
            ptr1 = ptr1.next
        else:
            curr.next = ptr2
            ptr2 = ptr2.next
        curr = curr.next

    # Append any remaining nodes
    if ptr1 is not None:
        curr.next = ptr1
    if ptr2 is not None:
        curr.next = ptr2

    return dummy.next

# Helper function to print the linked list
def print_list(head):
    while head is not None:
        print(head.data, end="->")
        head = head.next
    print("None")

# Example usage:
# Creating the first linked list: 1->3->5->7
head1 = Node(1)
head1.next = Node(3)
head1.next.next = Node(5)
head1.next.next.next = Node(7)

# Creating the second linked list: 2->4->6
head2 = Node(2)
head2.next = Node(4)
head2.next.next = Node(6)

# Merge the two sorted linked lists
merged_head = merge_sorted_lists(head1, head2)

# Print the merged linked list
print_list(merged_head)

# # Question 7
# Given a Doubly Linked List, the task is to reverse the given Doubly Linked List.
#
#

# In[15]:

class Node:
    def __init__(self, data):
        self.data = data
        self.prev = None
        self.next = None

def reverse_doubly_linked_list(head):
    prev = None
    curr = head

    # Reverse the doubly linked list
    while curr is not None:
        next = curr.next
        curr.next = prev
        curr.prev = next
        prev = curr
        curr = next

    # Update the head of the doubly linked list
    head = prev

    return head

# Helper function to print the doubly linked list in both forward and backward directions
def print_list(head):
    # Forward traversal
    while head is not None:
        print(head.data, end="->")
        head = head.next
    print("None")

    # Backward traversal
    while head is not None:
        print(head.data, end="->")
        head = head.prev
    print("None")

# Example usage:
# Creating the doubly linked list: 1<->2<->3<->4<->5
head = Node(1)
head.next = Node(2)
head.next.prev = head
head.next.next = Node(3)
head.next.next.prev = head.next
head.next.next.next = Node(4)
head.next.next.next.prev = head.next.next
head.next.next.next.next = Node(5)
head.next.next.next.next.prev = head.next.next.next

# Reverse the doubly linked list
head = reverse_doubly_linked_list(head)

# Print the modified doubly linked list
print_list(head)

# # Question 8
# Given a doubly linked list and a position. The task is to delete a node from given position in a doubly linked list.
#

# In[16]:

class Node:
    def __init__(self, data):
        self.data = data
        self.prev = None
        self.next = None

def delete_node_at_position(head, position):
    if head is None:
        return

    if position == 0:
        if head.next is not None:
            head.next.prev = None
        head = head.next
        return head

    curr = head
    count = 0
    while curr is not None and count < position:
        curr = curr.next
        count += 1

    if curr is None:
        return

    curr.prev.next = curr.next
    if curr.next is not None:
        curr.next.prev = curr.prev

    del curr

    return head

# Helper function to print the doubly linked list
def print_list(head):
    while head is not None:
        print(head.data, end="->")
        head = head.next
    print("None")

# Example usage:
# Creating the doubly linked list: 1<->2<->3<->4<->5
head = Node(1)
head.next = Node(2)
head.next.prev = head
head.next.next = Node(3)
head.next.next.prev = head.next
head.next.next.next = Node(4)
head.next.next.next.prev = head.next.next
head.next.next.next.next = Node(5)
head.next.next.next.next.prev = head.next.next.next

position = 2  # Position of the node to be deleted

# Delete the node at the given position
head = delete_node_at_position(head, position)

# Print the modified doubly linked list
print_list(head)

# In[ ]:


# -*- coding: utf-8 -*-

from odoo import models, fields, api

class AccountAssetAsset(models.Model):
    _inherit = 'account.asset.asset'

    @api.model
    def _get_invoice(self):
        invoice_ids = []
        invoice_search = self.env['account.invoice'].search([('type', '=', 'in_invoice'),('origin', 'ilike', 'PO'),('state', 'in', ('open','paid'))])
        for inv in  invoice_search:
            purchase_br = self.env['purchase.order'].search([('name', '=', inv.origin)])
            for line in purchase_br.order_line:
                if line.is_capital and line.remaining_asset_qty:
                    invoice_ids.append(inv.id)
                    break
        return [('id', 'in', invoice_ids and invoice_ids or [])]

    invoice_id = fields.Many2one('account.invoice', string="Invoice", domain=_get_invoice)
    is_asset_proceeded = fields.Boolean('Asset Proceeded', default=False)


import requests
import re
import json
import pickle
import gc
import time

src = 'http://www.baidu.com/s?wd='

pattern1 = re.compile('style=\"text-decoration:none;\">(.*?) </a>')
pattern2 = re.compile('<!--STATUS (.*?)-->')

s_t = 60001
e_d = 80000

# with open('../src/test.json', 'r') as f:
with open('../src/train.json', 'r') as f:
    json_line_t = 0
    urls = []
    for line in f:
        text = json.loads(line)

        json_line_t += 1

        if json_line_t < s_t:
            continue
        print(json_line_t)

        search_content = text['title']

        tmp_src = src + "\"" + search_content + "\""

        test_flag = True
        while True:
            try:
                content = requests.get(url=tmp_src).text
            except:
                print('contect error')
                time.sleep(60)
                content = requests.get(url=tmp_src).text
            status_pd = re.findall(pattern2, content)
            if status_pd[0] == 'OK':
                tmp_ans = re.findall(pattern1, content)
                if len(tmp_ans) == 0:
                    if test_flag == True:
                        print('get none')
                        time.sleep(10)
                        test_flag = False
                        continue
                if test_flag == False:
                    print('new get', len(tmp_ans))
                urls.append(tmp_ans)
                break
            else:
                print(json_line_t, 'Failed!')
                time.sleep(60)

        if json_line_t % 10000 == 0:
            with open('../src/train_urls/'+str(int(json_line_t/10000))+'.pkl', 'wb') as fw:
                pickle.dump(urls, fw, -1)
            del urls
            gc.collect()
            urls = []

        if json_line_t == e_d:
            break


import numpy as np
import sklearn.metrics.pairwise

import evm_enabler
import general_model as gm

class EVMOptions():
    """Options class for an EVM classifier

    The options class allows us to set custom options for each classifier
    and still pass these instructions to a General Model.  For more information
    about the EVM visit the following: https://arxiv.org/pdf/1506.06112.pdf,
    https://github.com/EMRResearch/ExtremeValueMachine

    Attributes:
        threshold (double): threshold used to call something novel
        tailsize (int): the number of extreme vectors allowed for the weibull distributions
        cover_threshold (double): probabilistic threshold to designate redundancy between points. Paper sets at 0.5
        for all experiments
        dist_func (string): name of function used to calculate distance (value: 'cosine' or 'euclidean')
        num_to_fuse (int): when picking y* need to find max probability.  Num_to_fuse looks at average max prob for
        top 'num_to_fuse'. Paper found increase of 1-2 percentage points by tuning this.
        margin_scale (double): Default 0.5 where to put margin between points

    """

    def __init__(self, tailsize, cover_threshold, dist_func, num_to_fuse, margin_scale=0.5):
        self.tailsize = tailsize
        self.cover_threshold = cover_threshold
        self.dist_func = dist_func
        self.num_to_fuse = num_to_fuse
        self.margin_scale = margin_scale

class ExtremeValueMachine(gm.General_Model):
    """Class for the flat EVM classifier

    This class implements the General Model Abstract class.
    The result is an EVM classifier that
    has no hierarchy.  It has the options as defined in
    the options object.  The init builds and compiles
    the model.

    Attributes:
        name (string): the name of the classifier
        options (object): options object for the classifier
    """

    def __init__(self, name, options):

        self.name = name
        self.trained = False

        ##
        ## EVM parameters
        ##
        self.tailsize = options.tailsize  ## <- number of extreme vectors allowed
        self.cover_threshold = options.cover_threshold
        self.dist_func = options.dist_func
        self.num_to_fuse = options.num_to_fuse
        self.margin_scale = options.margin_scale

        ##
        ## Items for the model
        ##
        self.points = None
        self.weibulls = None
        self.labels = None

        ##
        ## Have to handle distances somewhere
        ##
        def euclidean_cdist(X, Y):
            return sklearn.metrics.pairwise.pairwise_distances(X, Y, metric="euclidean", n_jobs=1)

        def euclidean_pdist(X):
            return sklearn.metrics.pairwise.pairwise_distances(X, metric="euclidean", n_jobs=1)

        def cosine_cdist(X, Y):
            return sklearn.metrics.pairwise.pairwise_distances(X, Y, metric="cosine", n_jobs=1)

        def cosine_pdist(X):
            return sklearn.metrics.pairwise.pairwise_distances(X, metric="cosine", n_jobs=1)

        dist_func_lookup = {
            "cosine": {"cdist": cosine_cdist,
                       "pdist": cosine_pdist},

            "euclidean": {"cdist": euclidean_cdist,
                          "pdist": euclidean_pdist}
        }

        self.cdist_func = dist_func_lookup[self.dist_func]["cdist"]
        self.pdist_func = dist_func_lookup[self.dist_func]["pdist"]

    def train(self, x, y):

        """Train the the EVM classifier

        This function trains the EVM classifier.

        Args:
            train (list): [x_train, y_train] numpy arrays (y_train NOT one-hot)
            val (list): [x_val, y_val] numpy arrays (y_val NOT one-hot)
            options (object): options object for the classifier

        """
        ##
        ## Separate train and test
        ##

        x_train = x.astype('double')
        y_train = np.argmax(y, axis = 1)

        ##
        ## Fit the model (the model ends up being points, weibulls and labels)
        ## See https://arxiv.org/pdf/1506.06112.pdf for details
        ##
        self.weibulls = evm_enabler.fit(x_train, y_train, self.tailsize, self.pdist_func, self.margin_scale)
        self.points, self.weibulls, self.labels = evm_enabler.reduce_model(x_train, self.weibulls, y_train,
                                                                           self.cover_threshold, self.pdist_func)
        self.trained = True

    def confidence(self, pool):

        """Report confidence of predictions of the pool

        Args:
            pool (numpy.ndarray): instances to predict

        Returns
            results: array of prediction confidences for the pool
        """
        if (self.trained):
            predictions, probs = evm_enabler.predict_evm(pool, self.points, self.weibulls, self.labels, self.cdist_func,
                                                         self.num_to_fuse)  ## Predict the pool

            return np.transpose(probs)
        else:
            print('Not trained! (prediction)')


import baseline as bl
import baseline.tf.embeddings
import baseline.tf.classify
import time
import tensorflow as tf
import numpy as np
import os
import argparse
import logging
log = logging.getLogger('baseline.timing')
NUM_PREFETCH = 2
SHUF_BUF_SZ = 5000

def get_logging_level(ll):
    ll = ll.lower()
    if ll == 'debug':
        return logging.DEBUG
    if ll == 'info':
        return logging.INFO
    return logging.WARNING

def get_tf_logging_level(ll):
    ll = ll.lower()
    if ll == 'debug':
        return tf.logging.DEBUG
    if ll == 'info':
        return logging.INFO
    return tf.logging.WARN

def to_tensors(ts):
    X = []
    y = []
    for sample in ts:
        X.append(sample['word'].squeeze())
        y.append(sample['y'].squeeze())
    return np.stack(X), np.stack(y)

parser = argparse.ArgumentParser(description='Train a Baseline model with TensorFlow Estimator API')
parser.add_argument('--export_dir', help='Directory for TF export (for serving)', default='./models', type=str)
parser.add_argument('--checkpoint_dir', help='Directory for model checkpoints', default='./checkpoints', type=str)
parser.add_argument('--model_type', help='What type of model to build', type=str, default='default')
parser.add_argument('--poolsz', help='How many hidden units for pooling', type=int, default=100)
parser.add_argument('--stacksz', help='How many hidden units for stacking', type=int, nargs='+')
parser.add_argument('--text', help='raw value', type=str)
parser.add_argument('--backend', help='backend', default='tf')
parser.add_argument('--remote', help='(optional) remote endpoint', type=str) # localhost:8500
parser.add_argument('--name', help='(optional) signature name', type=str)
parser.add_argument('--epochs', help='Number of epochs to train', type=int, default=2)
parser.add_argument('--batchsz', help='Batch size', type=int, default=50)
parser.add_argument('--filts', help='Parallel convolution filter widths (if default model)', type=int, default=[3, 4, 5], nargs='+')
parser.add_argument('--mxlen', help='Maximum post length (number of words) during training', type=int, default=100)
parser.add_argument('--train', help='Training file', default='../data/stsa.binary.phrases.train')
parser.add_argument('--valid', help='Validation file', default='../data/stsa.binary.dev')
parser.add_argument('--test', help='Testing file', default='../data/stsa.binary.test')
parser.add_argument('--embeddings', help='Pretrained embeddings file', default='/data/embeddings/GoogleNews-vectors-negative300.bin')
parser.add_argument('--ll', help='Log level', type=str, default='info')
parser.add_argument('--tf_ll', help='TensorFlow Log level', type=str, default='warning')
parser.add_argument('--lr', help='Learning rate', type=float, default=0.001)
parser.add_argument('--optim', help='Optimizer (sgd, adam) (default is adam)', type=str, default='adam')
parser.add_argument('--gpus', help='Number of GPUs to use', default=1, type=int)
args = parser.parse_known_args()[0]

logging.basicConfig(level=get_logging_level(args.ll))
tf.logging.set_verbosity(get_tf_logging_level(args.tf_ll))

pool_field = 'cmotsz' if args.model_type == 'default' else 'rnnsz'

model_params = {
    'model_type': args.model_type,
    'filtsz': args.filts,
    pool_field: args.poolsz
}

if args.stacksz is not None:
    model_params['hsz'] = args.stacksz

feature_desc = {
    'word': {
        'vectorizer': bl.Token1DVectorizer(mxlen=args.mxlen, transform_fn=bl.lowercase),
        'embed': {'file': args.embeddings, 'type': 'default', 'unif': 0.25}
    }
}
# Create a reader that is using our vectorizers to parse a TSV file
# with rows like:
# <label>\t<sentence>\n

vectorizers = {k: v['vectorizer'] for k, v in feature_desc.items()}
reader = bl.TSVSeqLabelReader(vectorizers,
                              clean_fn=bl.TSVSeqLabelReader.do_clean)

train_file = args.train
valid_file = args.valid
test_file = args.test

# This builds a set of counters
vocabs, labels = reader.build_vocab([train_file,
                                     valid_file,
                                     test_file])

# This builds a set of embeddings objects, these are typically not DL-specific
# but if they happen to be addons, they can be
embeddings = dict()
for k, v in feature_desc.items():
    embed_config = v['embed']
    embeddings_for_k = bl.load_embeddings('word',
                                          embed_file=embed_config['file'],
                                          known_vocab=vocabs[k],
                                          embed_type=embed_config.get('type', 'default'),
                                          unif=embed_config.get('unif', 0.),
                                          use_mmap=True)

    embeddings[k] = embeddings_for_k['embeddings']
    # Reset the vocab to the embeddings one
    vocabs[k] = embeddings_for_k['vocab']

X_train, y_train = to_tensors(reader.load(train_file, vocabs=vocabs, batchsz=1))
X_valid, y_valid = to_tensors(reader.load(valid_file, vocabs=vocabs, batchsz=1))
X_test, y_test = to_tensors(reader.load(test_file, vocabs=vocabs, batchsz=1))

def train_input_fn():
    dataset = tf.data.Dataset.from_tensor_slices((X_train, y_train))
    dataset = dataset.shuffle(buffer_size=SHUF_BUF_SZ)
    # https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/distribute/README.md
    # effective_batch_sz = args.batchsz*args.gpus
    dataset = dataset.batch(args.batchsz//args.gpus)
    dataset = dataset.map(lambda x, y: ({'word': x}, y))
    dataset = dataset.repeat(args.epochs)
    dataset = dataset.prefetch(NUM_PREFETCH)
    _ = dataset.make_one_shot_iterator()
    return dataset

def eval_input_fn():
    dataset = tf.data.Dataset.from_tensor_slices((X_valid, y_valid))
    dataset = dataset.batch(args.batchsz)
    dataset = dataset.map(lambda x, y: ({'word': x}, y))
    _ = dataset.make_one_shot_iterator()
    return dataset

def predict_input_fn():
    dataset = tf.data.Dataset.from_tensor_slices((X_test, y_test))
    dataset = dataset.batch(args.batchsz)
    dataset = dataset.map(lambda x, y: ({'word': x}, y))
    _ = dataset.make_one_shot_iterator()
    return dataset

def server_input_fn():
    tensors = {
        'word': tf.placeholder(tf.int64, [None, None])
    }
    features = {
        'word': tensors['word']
    }
    return tf.estimator.export.ServingInputReceiver(receiver_tensors=tensors, features=features)

def one_epoch(X_train):
    """

    effective_batch_sz = args.batchsz = gpu_batchsz*args.gpus

    :param X_train:
    :return:
    """
    return len(X_train)//args.batchsz

def fit(estimator):

    for i in range(args.epochs):
        start_time = time.time()
        estimator.train(input_fn=train_input_fn, steps=one_epoch(X_train))
        elapsed = time.time() - start_time
        log.info('EPOCH {} {}s'.format(i+1, elapsed))
        eval_results = estimator.evaluate(input_fn=eval_input_fn)
        print(eval_results)
    predictions = np.array([p['classes'] for p in estimator.predict(input_fn=predict_input_fn)])

    cm = bl.ConfusionMatrix(labels)
    for truth, guess in zip(y_test, predictions):
        cm.add(truth, guess)

    print(cm.get_all_metrics())

def model_fn(features, labels, mode, params):

    if labels is not None:
        y = tf.one_hot(tf.reshape(labels, [-1, 1]), len(params['labels']))

    if mode == tf.estimator.ModeKeys.PREDICT:
        bl.tf.SET_TRAIN_FLAG(False)
        model = bl.model.create_model(embeddings, labels=params['labels'], word=features['word'], y=None, sess=None, **model_params)
        predictions = {
            'classes': model.best,
            'probabilities': model.probs,
            'logits': model.logits,
        }
        outputs = tf.estimator.export.PredictOutput(predictions['classes'])
        return tf.estimator.EstimatorSpec(mode, predictions=predictions, export_outputs={'classes': outputs})

    elif mode == tf.estimator.ModeKeys.EVAL:
        bl.tf.SET_TRAIN_FLAG(False)
        model = bl.model.create_model(embeddings, labels=params['labels'], word=features['word'], y=y, sess=None, **model_params)
        loss = model.create_loss()
        predictions = {
            'classes': model.best,
            'probabilities': model.probs,
            'logits': model.logits,
        }
        eval_metric_ops = {
            'accuracy': tf.metrics.accuracy(
                labels=labels, predictions=predictions['classes'])}
        return tf.estimator.EstimatorSpec(mode=mode, predictions=model.logits, loss=loss, eval_metric_ops=eval_metric_ops)

    bl.tf.SET_TRAIN_FLAG(True)
    model = bl.model.create_model(embeddings, labels=params['labels'], word=features['word'], y=y, sess=None, **model_params)
    loss = model.create_loss()
    #Optimizer = tf.train.GradientDescentOptimizer if args.optim == 'sgd' else tf.train.AdamOptimizer
    #print(Optimizer)
    #optimizer = Optimizer(learning_rate=args.lr)
    #train_op = optimizer.minimize(loss=loss, global_step=tf.train.get_global_step())
    colocate = True if args.gpus > 1 else False
    global_step, train_op = bl.tf.optz.optimizer(loss, optim=args.optim, eta=args.lr, colocate_gradients_with_ops=colocate)

    return tf.estimator.EstimatorSpec(mode=mode, predictions=model.logits,
                                      loss=loss,
                                      train_op=train_op)
params = {'labels': labels}

checkpoint_dir = '{}-{}'.format(args.checkpoint_dir, os.getpid())
if args.gpus > 1:
    config = tf.estimator.RunConfig(model_dir=checkpoint_dir, train_distribute=tf.contrib.distribute.MirroredStrategy(num_gpus=args.gpus))
else:
    config = tf.estimator.RunConfig(model_dir=checkpoint_dir)

estimator = tf.estimator.Estimator(model_fn=model_fn, config=config, params=params)

fit(estimator)

export_dir = '{}-{}'.format(args.export_dir, os.getpid())
estimator.export_savedmodel(export_dir_base=export_dir, serving_input_receiver_fn=server_input_fn)


import cv2
import numpy as np
from InputProcessing import InputFormatting
# from .InputProcessing import DataToImage
from data_to_letters import ImageNormaliser
from test_calibrare import DataToImage
import os
import re
from keras.models import load_model
import base64

# class DataToImage:
#     def __init__(self, dataPath, imagePath):
#         self._base64 = self.read_from_file(dataPath)
#         self.imageName = imagePath
#         self.base64_to_image()
#         self._image = None
#
#     @property
#     def base64(self):
#         return self._base64
#
#     @base64.setter
#     def base64(self, value):
#         if isinstance(value, str):
#             self._base64 = value
#
#     @staticmethod
#     def partition(strOne):
#         if ',' in strOne:
#             strOne = strOne.partition(",")[2]
#             pad = len(strOne) % 4
#             strOne += "=" * pad
#             return strOne
#         else:
#             return strOne
#
#     def read_from_file(self, dataPath):
#         f = open(dataPath, 'r')
#         strOne = f.read()
#         f.close()
#         # print(">> " +strOne)
#         data = self.partition(strOne)
#         return data
#
#     def base64_to_image(self):
#         base64_str = self.partition(self._base64)
#         binary_str = base64.b64decode(base64_str)
#         # Here comes the naming solution\
#         self.imageName = "tempFiles/newImage.png"
#         with open(self.imageName, "wb") as fh:
#             fh.write(binary_str)
#
#     def get_image(self):
#         img = cv2.imread(self.imageName, cv2.IMREAD_GRAYSCALE)
#         return img
#
#     @property
#     def image(self):
#         self._image = self.get_image()
#         return self._image
#
#     @image.setter
#     def image(self, value):
#         if isinstance(value, str):
#             self._image = value
#

def image_norm(img):
    # we are doing the default threshold in order to accept every color in the image
    # then we are resizing and afterwards we are thresholding with the thresh 200
    # in order to keep most of the greys that appeard during the interpolation in the image.
    img = ImageNormaliser.thresholding(img)
    img = ImageNormaliser.resize_percent(img, 50)
    img = ImageNormaliser.thresholding(img, thresh=200)
    # ImageNormaliser.plotData(img)

    return img

'''
    Element class is a container for image and type of it : line, word or char
'''
class Element:
    def __init__(self, img, type='undef'):
        self.image = img
        self.type = type
        self.width = self.image.shape[1]
        self.height = self.image.shape[0]

        # aici s-ar putea pune predictul
        # (nu stiu daca e o idee prea buna sa incarcam modelul pentru un singur simbol dar disctuam)

'''
    Status Image Analyser

'''
class ImageAnalyser:

    def __init__(self, raw_img):
        self.raw_image = raw_img

    # define lines
    def execute_morpho_on_oy(self):
        img = self.raw_image
        img = cv2.convertScaleAbs(img, alpha=(255.0 / 65535.0))
        im2, contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        cv2.fillPoly(img, contours, color=(255, 255, 255))
        # ImageNormaliser.plotData(img)
        #kernels for morphological operations
        kernel1 = np.ones((2, 30))
        kernel2 = np.ones((3, 3))

        dilation = cv2.dilate(img, kernel2, iterations=1)
        closing = cv2.morphologyEx(dilation, cv2.MORPH_CLOSE, kernel1)
        erosion = cv2.erode(closing, kernel2, iterations=2)

        img = cv2.cvtColor(erosion, cv2.COLOR_RGB2GRAY)
        return img

    # define words
    def execute_morpho_on_ox(self):
        img = self.raw_image
        img = cv2.convertScaleAbs(img, alpha=(255.0 / 65535.0))
        im2, contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        cv2.fillPoly(img, contours, color=(255, 255, 255))

        # kernels for morphological operations
        kernel1 = np.ones((30, 2))
        kernel2 = np.ones((3, 3))

        dilation = cv2.dilate(img, kernel2, iterations=1)
        closing = cv2.morphologyEx(dilation, cv2.MORPH_CLOSE, kernel1)
        erosion = cv2.erode(closing, kernel2, iterations=2)

        img = cv2.cvtColor(erosion, cv2.COLOR_RGB2GRAY)
        return img

    def compute_projection_oy(self, morpho_image):

        oy_values = list()
        for i in range(self.raw_image.shape[0]):
            oy_values.append(0)
            for j in range(self.raw_image.shape[1]):
                if morpho_image[i][j] > 0:
                    oy_values[i] += 1
        return oy_values

    def compute_projection_ox(self, morpho_image):
        oy_values = list()
        # print(morpho_image.shape)
        # print(morpho_image[328][47])
        for i in range(self.raw_image.shape[1]):
            oy_values.append(0)
            for j in range(self.raw_image.shape[0]):
                # print(str(i) + " , " + str(j))
                # if i == 88:
                #     print('hue')
                try:
                    if morpho_image[j][i] > 0:
                        pass
                        oy_values[i] += 1
                except Exception as e:
                    print(">> " + str(i) +" , " +str(j))
                    print(str(e))
        return oy_values

    def get_bounds(self, values):
        index = -1
        bounds = list()

        def trigger(values, pos):
            count = -1

            for i in range(pos, len(values)):
                if values[i] == 0:
                    return count
                count += 1
            return -1

        for i in range(len(values)):
            if index > -1 and i < index:
                continue

            if values[i] > 0:
                count = trigger(values, i)
                if count > 0:
                    index = count + i
                    bounds.append((i, count+i))

        return bounds

    def get_bounds_variable(self, white_values):

        bounds = list()
        index = -1

        def trigger(pos, vec):
            count = 0
            for i in range(pos, len(vec) - 1):
                if abs(vec[i] - vec[i + 1]) > 4:
                    return count
                count += 1

            return -1

        for i in range(len(white_values) - 1):
            if index > -1 and i < index:
                continue

            if (white_values[i] < 8 and white_values[i] > 0) and \
                    (white_values[i + 1] < 8 and white_values[i + 1] > 0):
                if abs(white_values[i] - white_values[i + 1]) < 5:

                    count = trigger(i, white_values)
                    if count != -1:
                        bounds.append(int(count / 2 + i))
                        index = i + count

        return bounds

    @staticmethod
    def compute_partial_projection(morpho_image, axis='ox'):
        positions = [0.25, 0.40, 0.5, 0.60, 0.75]
        values = list()
        if axis == 'ox':
            for pos in positions:
                values.append(0)
                j = int(morpho_image.shape[1] * pos)
                for i in range(morpho_image.shape[0]):
                    if morpho_image[i][j] == 0:
                        values[positions.index(pos)] += 1
                        # morpho_image[i][j] = 100
            # ImageNormaliser.plotData(morpho_image)
        else:
            pass

        sum = 0
        for val in values:
            sum += val
        return int(sum/len(values))

    @staticmethod
    def draw_bounds(image, bounds, axis='ox'):

        img = image.copy()

        if axis == 'ox':
            try:
                img = img.astype(np.uint8)
                img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
                for elem in bounds:
                    for i in range(img.shape[0]):
                        img[i][elem[0]] = (0, 255, 0)
                        img[i][elem[1]] = (0, 255, 0)
            except :
                for elem in bounds:
                    for i in range(img.shape[0]):
                        img[i][elem[0]] = 200
                        img[i][elem[1]] = 200
        else:
            img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
            for elem in bounds:
                for i in range(img.shape[1]):
                    img[elem[0]][i] = (0, 255, 0)
                    img[elem[1]][i] = (0, 255, 0)
        ImageNormaliser.plotData(img)

class LineBuilder(ImageAnalyser):
    def __init__(self, element):
        ImageAnalyser.__init__(self, raw_img=element.image)
        self.raw_image = element.image
        self.bounds = self.__build_bounds()
        self.elements = self.build_elements()

    #private method
    def __build_bounds(self):
        img_morpho = self.execute_morpho_on_oy()
        # ImageNormaliser.plotData(img_morpho)
        oy_values = self.compute_projection_oy(img_morpho)
        bounds = self.get_bounds(oy_values)
        # self.draw_bounds(self.raw_image, bounds, axis='oy')
        return bounds

    def build_elements(self, verbose=0):
        elements = list()
        height_negative_space = 20

        if verbose == 1:
            print(">> Height of added negative space : " + str(height_negative_space))

        for elem in self.bounds:

            new_elem = self.raw_image[elem[0]:elem[1], :]
            if verbose == 1:
                print(">> Current raw elem shape " + str(new_elem.shape))
            new_elem_np = self.__add_negative_space(new_elem, height_negative_space)
            new_elem = Element(img=new_elem_np, type='line')
            elements.append(new_elem)

        return elements

    def __add_negative_space(self, element, height):

        space = np.zeros((height, self.raw_image.shape[1]))
        new_elem = np.vstack((space, element))
        new_elem = np.vstack((new_elem, space))

        return new_elem

class WordBuilder(ImageAnalyser):
    def __init__(self, element):
        ImageAnalyser.__init__(self, raw_img=element.image)
        self.raw_image = element.image
        self.bounds = self.__build_bounds()
        self.elements = self.build_elements()

    def __build_bounds(self):
        img_morpho = self.execute_morpho_on_ox()
        # ImageNormaliser.plotData(img_morpho)
        ox_values = self.compute_projection_ox(img_morpho)
        bounds = self.get_bounds(ox_values)
        # self.draw_bounds(self.raw_image, bounds)

        return bounds

    @staticmethod
    def __merge_bounds(elements, max_distance=10, verbose=0):
        i = 0
        while i < len(elements) - 1:
            e1 = elements[i]
            if i + 1 < len(elements):
                e2 = elements[i + 1]

                if abs(e2[0] - e1[1]) < max_distance:
                    if verbose == 1:
                        print(">> Merging bounds : " + str(e1) + " and " + str(e2))
                    new_elem = (e1[0], e2[1])
                    elements[i] = new_elem
                    elements.pop(i + 1)
                    i -= 1
            i += 1
        return elements

    def build_elements(self, verbose=0):
        elements = list()
        width_negative_space = 20
        max_dist_allowed = 10

        if verbose == 1:
            print(">> Width of added negative space : " + str(width_negative_space))

        if len(self.bounds) > 1:
            self.bounds = self.__merge_bounds(self.bounds, max_dist_allowed, verbose)

        for elem in self.bounds:

            new_elem = self.raw_image[:, elem[0]:elem[1]]
            if verbose == 1:
                print(">> Current raw elem shape " + str(new_elem.shape))
            new_elem_np = self.__add_negative_space(new_elem, width_negative_space)
            new_elem = Element(img=new_elem_np, type='word')
            elements.append(new_elem)

        return elements

    def __add_negative_space(self, element, width):

        space = np.zeros((self.raw_image.shape[0], width))
        new_elem = np.hstack((space, element))
        new_elem = np.hstack((new_elem, space))
        return new_elem

class CharBuilder(ImageAnalyser):

    def __init__(self, element):
        ImageAnalyser.__init__(self, element.image)
        self.raw_image = element.image
        self._mean_height = -1
        self.bounds = self.__build_bounds()
        self.elements = self.build_elements()

    def __build_bounds(self):
        img_morpho_ox = self.execute_morpho_on_ox()
        img_morpho_oy = self.execute_morpho_on_oy()
        ox_values = self.compute_projection_ox(img_morpho_ox)
        self._mean_height = self.compute_partial_projection(morpho_image=img_morpho_oy, axis='ox')
        bounds = self.get_bounds_variable(ox_values)
        bounds = self.__normalise_bounds(bounds)
        self.draw_bounds_hue(bounds)
        print(">>> " + str(bounds))

        # self.draw_bounds(bounds)
        return bounds

    def __normalise_bounds(self, bounds):
        # elinate the bounds that are above the thresh
        i = 0
        while i < len(bounds)-1:
            if self.__check_bound(bounds[i]):
                bounds.remove(bounds[i])
                i -= 1
            i += 1
        #turn the list of values into list of tuples
        bounds = [0] + bounds + [self.raw_image.shape[1]]
        result = list()
        for i in range(len(bounds) -1):
            result.append((bounds[i], bounds[i+1]))
        return result

    def __check_bound(self, bound):
        thresh = int(self._mean_height * 0.6)
        for i in range(self.raw_image.shape[0]):
            if self.raw_image[i][bound] > 0:
                if i > thresh:
                    # print(i)
                    return False
                else:
                    return True

    def draw_bounds_hue(self, bounds):
        print(bounds)
        img = self.raw_image.copy()
        img = img.astype(np.uint8)
        img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        for elem in bounds:
            for i in range(img.shape[0]):
                img[i][elem[0]] = (0,255,0)
                # img[i][elem[1]-1] = (0,255,0)
        val = int(self._mean_height *0.6)
        for i in range(img.shape[1]):
            img[val][i] = (0,0,255)

        ImageNormaliser.plotData(img)

    def build_elements(self, verbose=0):
        elements = list()

        for elem in self.bounds:
            if elem == 0:
                continue
            else:
                new_elem = self.raw_image[:, elem[0]:elem[1]]
                # ImageNormaliser.plotData(new_elem)
                char_synth = CharSynthesizer(new_elem)
                new_elem = char_synth.normalise_char()
                if new_elem is not None:
                    # print(">>" + str(new_elem.shape))
                    # ImageNormaliser.plotData(new_elem)
                    ret, thresh = cv2.threshold(new_elem, 0, 255, cv2.THRESH_BINARY)
                    new_elem = thresh
                    new_elem = Element(img=new_elem, type='char')
                    elements.append(new_elem)

        return elements

class CharSynthesizer:
    def __init__(self, img, resize_dim=64):
        self.__img = img
        self.__resize_dim = resize_dim

    def normalise_char(self):
        img = self.crop_char(self.__img)
        img = ImageNormaliser.resize_specific_dim(img, self.__resize_dim)
        if np.count_nonzero(img > 0):
            # ImageNormaliser.plotData(img)
            return img
        return None

    def crop_char(self, img):
        img = cv2.convertScaleAbs(img, alpha=(255.0 / 65535.0))
        im2, contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        height, width = img.shape[0], img.shape[1]
        #init the oy exterme coordinates for letter
        y_max = -1
        y_min = height + 1
        x_coords = list()
        y_coords = list()
        return_image = None

        for i in contours:
            for j in i:
                for elem in j: #for every point in countour
                    y = elem[1]
                    x_coords.append(elem[0])
                    y_coords.append(elem[1])
                    if y > y_max: #define oy extremities
                        y_max = y
                    elif y < y_min:
                        y_min = y

        if y_max > -1 and y_min < height+1:
            x_coords= np.array(x_coords)
            y_coords = np.array(y_coords)
            x_distrib = x_coords.sum()/len(x_coords) #compute mean of the x coords
            y_distrib = y_coords.sum()/len(y_coords) #compute mean of the y coords
            new_height = y_max - y_min
            image = img[y_min: y_max, :] #the letter touches all bounds of the image

            #square the rectangle
            try:
                if new_height > width:
                    return_image = self.fill_letter_ox(image, x_distrib) #get a square image

                    return_image = self.square_img(return_image)
                elif width > new_height:
                    return_image = self.fill_letter_oy(image, y_distrib, height)
                    # ImageNormaliser.plotData(return_image)
                    return_image = self.square_img(return_image)
                    pass
                else:
                    return_image = self.square_img(image)
                    pass
            except Exception as e:
                print("Exception in filling the letters : " + str(e))
        else:
            print(">> There is no char in this split")

        return return_image

    # methods are returning a square image with centred letter based on info distribution
    @staticmethod
    def fill_letter_ox(image,x_distrib):
        direction = None
        height, width = image.shape[0], image.shape[1]
        im = None
        #establish the direction for fill
        if x_distrib > width/2:
            direction = "right"
        else:
            direction = "left"
        try:
            im = np.array(image)
            val = height - width
            fill = np.zeros((height, val))

            try:
                # fill in by direction
                if direction == "left":
                    im = np.hstack((fill, im))
                else:
                    im = np.hstack((im, fill))
            except Exception as ex:
                print(">> Exception on applying hstack : " + str(ex))

        except Exception as e:
            print(">> Exception in building the fill " + str(e))

        # if im is not None:
        # ImageNormaliser.plotData(im, "hue")
        return im

    @staticmethod
    def fill_letter_oy(image, y_distrib, original_height):
        direction = None
        im = None
        height, width = image.shape[0], image.shape[1]
        # establish the direction for fill
        if y_distrib > original_height / 2:
            direction = "bottom" #trebuie inversate
        else:
            direction = "top"

        im = np.array(image)
        val = width - height

        #treat the case where we need to add more fill lines that the actual image height
        #this way we overcome the isolation of the image
        try:
            if val > height*0.7: #if the difference between width and height is big
                fill_height = int(val/2)
                if val % 2 == 0:
                    fill1 = np.zeros((fill_height, width))
                    fill2 = np.zeros((fill_height, width))
                    # print(">>> : " + str(fill1.shape) + "  " + str(fill2.shape))

                else:
                    fill1 = np.zeros((fill_height+1, width))
                    fill2 = np.zeros((fill_height, width))

                try:
                    im = np.vstack((fill1, im))
                    im = np.vstack((im, fill2))
                except Exception as ex:
                    print(">> Exception in applying vstack : " + str(ex))

            else :
                fill = np.zeros((val, width))
                # fill in by direction
                try:
                    if direction == "top":
                        im = np.vstack((fill, im))
                    else:
                        im = np.vstack((im, fill))
                except Exception as ex:
                    print(">> Exception in applying vstack : " + str(ex))

        except Exception as e:
            print(">> Exception in building fill" + str(e))

        # if im is not None:
        #     print(">> Char shape : " + str(im.shape))
            # ImageNormaliser.plotData(im, "hue")
        return im

    #method is computing information percent in order to eroad or not and adds
    #negative space
    def square_img(self,char):

        # filling the shapes in order to distinguish letters from simple lines
        # lines from the extremities of the word can represent segmentation errors
        img = char.copy()
        temp = char.copy()
        temp = temp * 255
        temp = cv2.convertScaleAbs(temp, alpha=(255.0 / 65535.0))
        temp = temp * 255
        im2, contours, hierarchy = cv2.findContours(temp, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        cv2.fillPoly(temp, contours, color=255)

        #count the distribution of whites vs blacks
        # ImageNormaliser.plotData(temp)
        black = np.count_nonzero(temp == 0)
        white = np.count_nonzero(temp > 0)
        # print(">> Black value " + str(black) + "  White value " + str(white))
        computed_percent = -1
        if black > white:
            computed_percent = int((white * 100)/ (black+white)) #+ white
            print(">>>" + str(img.shape) + "   ->" + str(computed_percent))
        if computed_percent > -1:
            if computed_percent > 35:
                kernel = np.ones((2, 2))
                img = cv2.erode(img, kernel, iterations=1)
                val = int(img.shape[0] / 4)
                img = self.add_negative_space(img, val)
            elif computed_percent > 6 and computed_percent < 35:
                val = int(img.shape[0] / 4) #discutabil
                img = self.add_negative_space(img, val)
            else:
                # #FINDME
                img = np.zeros(img.shape)
                pass

            return img
        else:
            img = np.zeros(img.shape)
            return img

    @staticmethod
    def add_negative_space(img, val):
        side_len = img.shape[0]

        fill1 = np.zeros((val, side_len))  # intended for vstack
        fill2 = np.zeros(((side_len + val*2), val))  # intended for hstack

        img = np.vstack((fill1, img))
        img = np.vstack((img, fill1))
        img = np.hstack((fill2, img))
        img = np.hstack((img, fill2))

        return img

class OutputBuilder:
    def __init__(self, path):
        self.path = path
        self.raw_img = self._get_raw_image()
        # print(self.path)

    def build_images(self):

        img = self.raw_img
        # ImageNormaliser.plotData(img)

        initial_elem = Element(img)
        names_list = list()
        line_builder = LineBuilder(initial_elem)
        lines = line_builder.elements

        line_index = 1

        for line in lines:
            word_builder = WordBuilder(line)
            words = word_builder.elements
            l_name = '_'+str(line_index)
            line_path = self.path+"\\lines\\"+l_name+".png"
            cv2.imwrite(line_path, line.image)
            names_list.append(line_path)
            word_index = 1
            for word in words:
                w_name = l_name+'_' + str(word_index)
                word_path = self.path+"\\words\\"+w_name+".png"
                cv2.imwrite(word_path, word.image)
                names_list.append(word_path)
                char_builder = CharBuilder(word)
                chars = char_builder.elements
                char_index = 1
                for char in chars:
                    c_name = w_name + '_' + str(char_index)
                    char_path = self.path+"\\chars\\"+c_name+'.png'
                    cv2.imwrite(char_path, char.image)
                    names_list.append(char_path)
                    char_index += 1
                word_index += 1
            line_index += 1

        # for name in names_list:
        #     arr = re.split('\\\|\.', name)
        #     print(str(name) + "    " + str(arr[-2]))

    def _get_raw_image(self):
        data_reader = DataToImage(self.path)
        img = data_reader.image
        img = ImageNormaliser.resize_percent(img, 40)
        img = ImageNormaliser.thresholding(img)
        return img

    def build_output_dict(self):
        result = dict()
        count = 0
        dirs = [self.path + "\\" + 'lines',
        self.path + "\\" + 'words',
        self.path + "\\" + 'chars']

        for curr_dir in dirs:
            for img in os.listdir(curr_dir):
                splitedArray = re.split('\\\|\.', img)
                temp = InputFormatting.png_to_base64(curr_dir+"\\"+img)
                result[splitedArray[-2]] = temp
                count += 1
        # result['noElem'] = count
        return result

class CharClassifier:
    def __init__(self, model_path):
        self.model_path = model_path
        self.model = load_model(model_path)

    def predict(self, img):
        labels = {1: 97, 2: 98, 3: 99, 4: 100, 5: 101, 6: 102, 7: 103,
                  8: 104, 9: 105, 10: 106, 11: 108, 12: 109, 13: 110,
                  14: 111, 15: 112, 16: 113, 17: 114, 18: 115, 19: 116,
                  20: 117, 21: 118, 22: 122}

        img = img.reshape(1, 64, 64, 1)
        predictions = self.model.predict(img)
        print(predictions)
        predicted_label = np.argmax(predictions, axis=1)
        letter = labels[int(predicted_label[0])]
        print(">>Litera : " + chr(letter) + "   " + str(predicted_label))

def test(img):
    line_builder = LineBuilder(img)
    lines = line_builder.elements

    word_builder = WordBuilder(lines[0].image)
    words = word_builder.elements

    char_builder = CharBuilder(words[0].image)
    chars = char_builder.bounds

    # print(chars)

def get_elems(img):
    print(">> In get_elems")
    initial_elem = Element(img)
    clf = CharClassifier("tempFiles/keras_pd2_v4.h5")
    line_builder = LineBuilder(initial_elem)
    lines = line_builder.elements

    for line in lines:
        # ImageNormaliser.plotData(line.image)
        word_builder = WordBuilder(line)
        words = word_builder.elements
        # ImageNormaliser.plotData(line.image)
        for word in words:
            # ImageNormaliser.plotData(word.image)

            char_builder = CharBuilder(word)
            # bounds = char_builder.bounds
            # char_builder.draw_bounds(bounds)
            chars = char_builder.elements
            for char in chars:
                clf.predict(char.image)
                ImageNormaliser.plotData(char.image)

def show_projection(im, values):
    img = np.zeros((im.shape[0], im.shape[1]))

    for i in range(len(values)):
        for j in range(values[i]):
            img[i][j] = 255

    ImageNormaliser.plotData(img)

if __name__ == "__main__":
    print(">>Start")
    data_reader = DataToImage("tempFiles/fis.txt", "tempFiles/newImage.png")
    image = data_reader.image
    ImageNormaliser.plotData(image)
    # name = 'vala'
    # path = str(os.getcwd()) + '\\temporary\\' + name
    #
    #
    # ir = OutputBuilder(path)
    # # ir.build_images()
    # res = ir.build_output_dict()
    #
    # for k, v in res.items():
    #     print(str(k) + "   " + str(v))

    image = image_norm(image)
    get_elems(image)
    # test(image)