import struct
import socket
from prettytable import PrettyTable
class IPv4(object):
    def __init__(self):
        self.version = None     # 4bit version
        self.headerlen = None      #4bit header length
        self.tos = None         # 8bit type of service
        self.totalLen = None    # 16bit total length
        self.identification = None  # 16bit header identification
        self.fragment = None        # 16bit others and fragment offset
        self.ttl = None             # 8bit time to live
        self.protocol = None        # 8bit type of protocol
        self.checksum = None    # 16bit header checksum
        self.srcIP = None       # 32bit src IP address
        self.dstIP = None       # 32bit dst IP address
    def decodeIP(self,buffer):
        (versionAndLen,self.tos,self.totalLen,self.identification,self.fragment,
         self.ttl,self.protocol,self.checksum,self.srcIP,self.dstIP) = struct.unpack('>cBHHHBBHII',buffer)
        self.version = str(versionAndLen.hex())[0]
        self.headerlen = str(versionAndLen.hex())[1]
        self.dstIP = socket.inet_ntoa(struct.pack('I',socket.ntohl(self.dstIP)))
        self.srcIP = socket.inet_ntoa(struct.pack('I',socket.ntohl(self.srcIP)))
    def info(self):
        row = PrettyTable()
        row.add_row(['version', self.version])
        row.add_row(['header length', self.headerlen])
        row.add_row(['type of service', self.tos])
        row.add_row(['total length', self.totalLen])
        row.add_row(['header identification', self.identification])
        row.add_row(['others and fragment offset', self.fragment])
        row.add_row(['time to live', self.ttl])
        row.add_row(['type of protocol', self.protocol])
        row.add_row(['header checksum', self.checksum])
        row.add_row(['src IP address', self.srcIP])
        row.add_row(['dst IP address', self.dstIP])
        return row
    def data(self):
        data = []
        data.append(self.version)
        data.append(self.headerlen)
        data.append(self.tos)
        data.append(self.totalLen)
        data.append(self.identification)
        data.append(self.fragment)
        data.append(self.ttl)
        data.append(self.protocol)
        data.append(self.checksum)
        data.append(self.srcIP)
        data.append(self.dstIP)
        return data


#!/usr/bin/python3
import os
import tempfile
import argparse

def query_db(row):

    if not row:
        row = 'FirstName'

    sql = f".open /home/jared/chinook.db\nSELECT {row} FROM employees;"
    os.system(f'echo "{sql}" | /usr/bin/sqlite3')

    print("Done!")

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("--row", help="Row to query")
    args = parser.parse_args()

    query_db(args.row)


'''Smoothing/Blurring is done when an img has a lot of noise such as camera sensors,lighting issues,etc'''

import cv2 as cv
import numpy as np

img = cv.imread('Resources/Photos/cats.jpg')
cv.imshow('Original', img)

# 1.) Averaging - Each pixel is replaced by the average value of all pixels in the kernel window i.e. for a 3*3 kernel the centre pixel will be replaced by avg of other 8 surrounding pixels
average = cv.blur(img, (3,3)) #will implement averaging blur with a kernel of3*3. Increasing kernel size will increase blur
cv.imshow('Average Blur', average)

# 2.) GaussianBlur - similar to averaging operation but the surrounding pixels given a weight so weighted avg calculated. It gives less blurring than Averaging Blur but is more natural.
gauss = cv.GaussianBlur(img, (3,3), 0)   #0 is s.d. in x direction
cv.imshow('Gaussian Blurred', gauss)

# 3.) Median Blur - Instead of averaging it replaces pixel with median of its surrounding.
# It provided more blur than above two methods and  is effective to reduce SALT&PEPPER NOISE.
# It is not effective with higher kernel sizes such as 5*5 or 7*7
median = cv.medianBlur(img, 3) # kernel size is just 3 as automaticallly understands 3*3
cv.imshow('Median Blur', median)

# 4.) Bilateral Blurring - most effective blurring
#other blurring methods dont see if they are removing edges or not but Bilateral blurring does blurring but RETAINS edges as well
bilateral = cv.bilateralFilter(img, 10, 20, 20) #10 is diamter of neighborhood, 20 is sigma color (higher value indicates more colors in neighborhood), 20 is sigma space (higher value means pixel farther from centre will influence blurring more)
cv.imshow('Bilateral blurring', bilateral)

cv.waitKey(0)


import requests
import json
import urllib
from requests.exceptions import HTTPError

def getContact(email, apikey):
    contact = {}
    try:
        #print("- Downloading Contact from Hubspot API...")
        url= 'https://api.hubapi.com/contacts/v1/contact/email/' + email + '/profile?hapikey=' + apikey
        response = requests.get(url)
        response.raise_for_status()
        jsonResponse = response.json()
        #print(jsonResponse['properties'])
        if 'phone' in jsonResponse['properties']:
            contact['phone'] = jsonResponse['properties']['phone']['value']
        else:
            contact['phone'] = ""
        if 'firstname' in jsonResponse['properties']:
            contact['name'] = jsonResponse['properties']['firstname']['value']
        else:
            contact['name'] = ""
        if 'lastname' in jsonResponse['properties']:
            contact['lastname'] = jsonResponse['properties']['lastname']['value']
        else:
            contact['lastname'] = ""

    except HTTPError as http_err:
        if response.status_code == 404:
            print("------ ERROR: contact " + email + " might not exist. Maybe it was deleted ------")
        else:
            print(f"--- HTTP error occurred: {response}")
        contact['phone'] = 'error'
        contact['name'] = 'error'
        contact['lastname'] = 'error'
        return contact
    except Exception as err:
        print(f'------- Other error occurred: {err}')
        contact['phone'] = 'error'
        contact['name'] = 'error'
        contact['lastname'] = 'error'

    return contact

def processEvent(e, statusDict):
    #print(e)
    email = e['recipient']
    #print ("Event read for: " + email)

    if email in statusDict.keys():
        #print("- already in statusDict.keys")
        #  IF CURRENT EVENT TYPE IS  FINAL  OR  EQUAL TO CURRENT STATE, DO NOTHING.  ELSE, SAVE IT IF IT'S A MORE RECENT TYPE IN THE WORKFLOW
        if statusDict[email] == 'DROPPED' or statusDict[email] == 'BOUNCE' or statusDict[email] == 'SPAMREPORT' or statusDict[email] == e['type']:
            #print("--- already " + e['type'] + ". Nothing to do.")
            pass
        else:
            if e['type'] == 'CLICK':
                statusDict[email] = e['type']
            elif e['type'] == 'OPEN' and statusDict[email] not in ['CLICK']:
                statusDict[email] = e['type']
            elif e['type'] == 'DELIVERED' and statusDict[email] not in ['CLICK', 'OPEN']:
                statusDict[email] = e['type']
            elif e['type'] == 'PROCESSED' and statusDict[email] not in ['CLICK', 'OPEN', 'DELIVERED']:
                statusDict[email] = e['type']
            elif e['type'] == 'SENT' and statusDict[email] not in ['CLICK', 'OPEN', 'DELIVERED', 'PROCESSED']:
                statusDict[email] = e['type']
            elif e['type'] == 'STATUSCHANGE' or e['type'] == 'DEFERRED':
                statusDict[email] = e['type']
    else:
        #  FIRST TYPE STATE IS THE FIRST RECEIVED
        #print("- NOT in statusDict.keys, adding contact and setting to " + e['type'])
        statusDict[email] = e['type']

def main():

    apikey = input('What\'s is your API Key? ')
    campaignId = input('What\'s the campaignId? ')
    statusDict =	{}

    try:
        print("- Downloading Events from Hubspot API for Campaign " + campaignId + " ...")
        url = 'https://api.hubapi.com/email/public/v1/events?hapikey=' + apikey + '&campaignId=' + campaignId
        #print( ">>> GET: " , url)
        response = requests.get(url)
        response.raise_for_status()
        jsonResponse = response.json()
        for e in jsonResponse['events']:
            processEvent(e, statusDict)

        hasMore = jsonResponse['hasMore']

        while hasMore:
            url = 'https://api.hubapi.com/email/public/v1/events?hapikey=' + apikey + '&campaignId=' + campaignId + '&offset=' + jsonResponse['offset']
            #print( ">>> GET: " , url)
            response = requests.get(url)
            response.raise_for_status()
            jsonResponse = response.json()
            for e in jsonResponse['events']:
                processEvent(e, statusDict)
            #print("<<<< Response: ")
            #print(jsonResponse)
            hasMore = jsonResponse['hasMore']

        print("")
        print("- All events read from API. Saving CSV with each Contact email,status for this campaign")
        print("")
        file_object = open('contactsCampaign.csv', 'w')
        for email in statusDict:
            contact = getContact(email, apikey)
            print (email + "," + contact['phone'] + "," + contact['name'] + "," + contact['lastname'] + "," + statusDict[email])
            file_object.write(email + "," + contact['phone'] + "," + contact['name'] + "," + contact['lastname'] + "," + statusDict[email] + "\n")
        file_object.close()

    except HTTPError as http_err:
        print(f'HTTP error occurred: {http_err}')
    except Exception as err:
        print(f'Other error occurred: {err}')

if __name__ == '__main__':
    main()


from flask import Flask, request
import sqlite3
import pickle
import numpy as np

app = Flask(__name__)
app.config["Debug"] = True

@app.route("/", methods = ["GET"])
def entrada():
    return("¡Bienvenido a la página web de Antonio!")

@app.route("/predict", methods=['GET'])
def prediction():
    tv = request.args.get("tv", None)
    radio = request.args.get("radio", None)
    newspaper = request.args.get("newspaper", None)
    with open("advertising_model", "rb") as f:
        modelo = pickle.load(f)
    prediccion = modelo.predict([[tv, radio, newspaper]])
    return str(prediccion)

@app.route("/ingest_data", methods=['GET'])
def agregar():
    tv = request.args.get("tv", None)
    radio = request.args.get("radio", None)
    newspaper = request.args.get("newspaper", None)
    sales = request.args.get("sales", None)
    connection = sqlite3.connect("Advertising.db")
    cursor = connection.cursor()
    cursor.execute(str("INSERT INTO Advertising(tv, radio, newspaper, sales) VALUES(" + tv + "," + radio + "," + newspaper + "," + sales + ")"))
    num = str(len(cursor.execute("select * from advertising").fetchall()))
    connection.commit()
    connection.close()
    return str("el número de registros de la base de datos ahora es: " + num)

@app.route("/retrain", methods=['GET'])
def reentrenar():
    connection = sqlite3.connect("Advertising.db")
    cursor = connection.cursor()
    with open("advertising_model", "rb") as f:
        modelo = pickle.load(f)
    x = np.array(cursor.execute("select * from advertising").fetchall())[:, :-1]
    y = np.array(cursor.execute("select * from advertising").fetchall())[:, 3]
    modelo.fit(x,y)
    connection.close()
    return "El modelo ha sido reentrenado con los valores añadidos"


"""Contains example scripts presenting various activation functions characteristics."""
import os

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import numpy as np

import inspect
from typing import Dict, Type

import NaiveNeurals.MLP.activation_functions as functions_module

def plot_characteristics():
    """Plots various activation functions characteristics"""
    functions: Dict[str, Type[functions_module.ActivationFunction]] = {}
    for _, obj in inspect.getmembers(functions_module):
        if obj == functions_module.ActivationFunction:
            continue
        if inspect.isclass(obj) and issubclass(obj, functions_module.ActivationFunction):
            functions[obj.label] = obj

    plot_marks = ['m-', 'k-', 'r--', 'b-', 'c-']
    colors = ['magenta', 'black', 'red', 'blue', 'cyan']
    f1 = plt.figure()
    ax1 = f1.add_subplot(111)
    legend_handlers = []
    for fn_label, fn in functions.items():
        if fn_label == 'lin':
            x_vals = np.linspace(-1, 1, 21)
        elif fn_label == 'softplus':
            x_vals = np.linspace(-2, 2, 21)
        else:
            x_vals = np.linspace(-4, 4, 101)
        plot_label = mpatches.Patch(color=colors.pop(), label=fn_label)
        legend_handlers.append(plot_label)
        ax1.plot(x_vals, fn.function(x_vals), plot_marks.pop())

    plt.legend(handles=legend_handlers)
    plt.savefig(os.path.abspath(os.path.dirname(__file__)) + '/../docs/graphs/activation_functions.png')
    plt.show()

if __name__ == '__main__':
    plot_characteristics()


import datetime
from flask import Flask, render_template, request, json

application = Flask("News")

def getNews():
    resultStr = ''
    with open("news.json", "r", encoding="UTF-8") as file:
        newsList = file.read()
        newsList = json.loads(newsList)
        for news in newsList:
            resultStr += '
'
            resultStr += f'
{news["title"]}
'
            resultStr += f'
{news["date"]}
'
            resultStr += f'
{news["text"]}
'
            resultStr += '
'
        file.close()
    return resultStr

def addNews(title: str, text: str):
    currentDate = datetime.datetime.today()
    with open("news.json", "r", encoding="UTF-8") as file:
        newsList = json.loads(file.read())
        newsData = {"title": title, "date": currentDate, "text": text}
        newsList.append(newsData)
        with open("news.json", "w", encoding="UTF-8") as file2:
            file2.write(json.dumps(newsList, indent=2))
            file2.close()
        file.close()

@application.route("/")
def start():
    content = getNews()
    return render_template("index.html", content=content)

@application.route("/editor")
def editor():
    if request.method == "GET":
        title = request.args.get("title")
        text = request.args.get("text")
        if title != None and text != None:
            addNews(title, text)
    return render_template("editor.html")

application.run(host="0.0.0.0", port=8081)


from __future__ import annotations

from datetime import datetime
from typing import Any
from gym_utilities import in_week, create_offering_dict

# The additional pay per hour that instructors receive for each certificate they
# hold.
BONUS_RATE = 1.50

class WorkoutClass:
    """A workout class that can be offered at a gym.

    === Public Attributes ===
    name: The name of the workout class.

    === Private Attributes ===
    _required_certificates: The certificates that an instructor must hold to
        teach this WorkoutClass.
    """
    name: str
    _required_certificates: list[str]

    def __init__(self, name: str, required_certificates: list[str]) -> None:
        """Initialize a new WorkoutClass called <name> and with the
        <required_certificates>.

        >>> workout_class = WorkoutClass('Kickboxing', ['Strength Training'])
        >>> workout_class.name
        'Kickboxing'
        """
        self.name = name
        self._required_certificates = required_certificates[:]

    def get_required_certificates(self) -> list[str]:
        """Return all the certificates required to teach this WorkoutClass.

        >>> workout_class = WorkoutClass('Kickboxing', ['Strength Training'])
        >>> needed = workout_class.get_required_certificates()
        >>> needed
        ['Strength Training']
        >>> needed.append('haha')
        >>> try_again = workout_class.get_required_certificates()
        >>> try_again
        ['Strength Training']
        """
        # Make a copy of the list to avoid aliasing
        return self._required_certificates[:]

    def __eq__(self, other: Any) -> bool:
        """Return True iff this WorkoutClass is equal to <other>.

        Two WorkoutClasses are considered equal if they have the same name and
        the same required certificates.

        >>> workout_class = WorkoutClass('Kickboxing', ['Strength Training'])
        >>> workout_class2 = WorkoutClass('Kickboxing', ['Strength Training'])
        >>> workout_class == workout_class2
        True
        >>> d = {1: 17}
        >>> workout_class == d
        False
        """
        if not isinstance(other, WorkoutClass):
            return False
        return (self.name == other.name
                and self._required_certificates == other._required_certificates)

class Instructor:
    """
    An instructor at a Gym.

    === Public Attributes ===
    name: The name of this instructor.

    === Private Attributes ===
    _id: The id representing this instructor.
    _qualifications: A list of qualifications this instructor holds.
    """

    name: str
    _id: int
    _qualifications: list[str]

    def __init__(self, _id: int, name: str) -> None:
        """
        Initialize an Instructor with <name>, <id>,
        and qualifications if the instructor
        has any qualifications.
        """
        self._id = _id
        self.name = name
        self._qualifications = []

    def add_certificate(self, q: str) -> bool:
        """
        Appends certificate <q> to self._qualifications.
        """
        if q not in self._qualifications:
            self._qualifications.append(q)
            return True
        return False

    def get_id(self) -> int:
        """
        Returns the Instructor's id.
        """
        temp = self._id
        return temp

    def get_certificates(self) -> list[str]:
        """
        Returns a copy of the Instructor's _qualifications.
        """
        return self._qualifications[:]

class Gym:
    """A gym that hosts workout classes taught by instructors.

    All offerings of workout classes start on the hour and are 1 hour long.
    If a class starts at 7:00 pm, for example, we say that the class is "at"
    the timepoint 7:00, or just at 7:00.

    === Public Attributes ===
    name: The name of the gym.

    === Private Attributes ===
    _instructors: The instructors who work at this Gym.
        Each key is an instructor's ID and its value is the Instructor object
        representing them.
    _workouts: The workout classes that are taught at this Gym.
        Each key is the name of a workout class and its value is the
        WorkoutClass object representing it.
    _room_capacities: The rooms and capacities in this Gym.
        Each key is the name of a room and its value is the room's capacity,
        that is, the number of people who can register for a class in the room.
    _schedule: The schedule of classes offered at this gym.
        Each key is a date and time and its value is a nested dictionary
        describing all offerings that start then. In the nested dictionary,
        each key is the name of a room that has an offering scheduled then,
        and its value is a tuple describing the offering. The tuple elements
        record, in order:
            - the instructor teaching the class,
            - the workout class itself, and
            - a list of registered clients. Each client is represented in the
              list by a unique string.

    === Representation Invariants ===
    - All instructors in _schedule are in _instructors (the reverse is not
      necessarily true).
    - All workout classes in _schedule are in _workouts (the reverse is not
      necessarily true).
    - All rooms recorded in _schedule are also recorded in _room_capacities (the
      reverse is not necessarily true).
    - Two workout classes cannot be scheduled at the same time in the same room.
    - No instructor is scheduled to teach two workout classes at the same time.
      I.e., there does not exist timepoint t, and rooms r1 and r2 such that
          _schedule[t][r1][0] == _schedule[t][r2][0]
    - No client can take two workout classes at the same time.
      I.e., there does not exist timepoint t, and rooms r1 and r2 such that
          c in _schedule[t][r1][2] and c in _schedule[t][r2][2]
    - If an instructor is scheduled to teach a workout class, they have the
      necessary qualifications.
    - If there are no offerings scheduled at date and time <d>, then <d>
      does not occur as a key in _schedule.
    - If there are no offerings scheduled at date and time <d> in room <r> then
      <r> does not occur as a key in _schedule[d]
    - Each list of registered clients for an offering is ordered with the most
      recently registered client at the end of the list.
    """
    name: str
    _instructors: dict[int, Instructor]
    _workouts: dict[str, WorkoutClass]
    _room_capacities: dict[str, int]
    _schedule: dict[datetime,
                    dict[str, tuple[Instructor, WorkoutClass, list[str]]]]

    def __init__(self, gym_name: str) -> None:
        """Initialize a new Gym with <name>. Initially, this gym has no
        instructors, workout classes, rooms, or offerings.

        >>> ac = Gym('Athletic Centre')
        >>> ac.name
        'Athletic Centre'
        """
        self.name = gym_name
        self._instructors = {}
        self._workouts = {}
        self._room_capacities = {}
        self._schedule = {}

    def add_instructor(self, instructor: Instructor) -> bool:
        """Add a new <instructor> to this Gym's roster iff the <instructor> does
        not have the same id as another instructor at this Gym.

        Return True iff the id has not already been added to this Gym's roster.

        >>> ac = Gym('Athletic Centre')
        >>> diane = Instructor(1, 'Diane')
        >>> ac.add_instructor(diane)
        True
        """
        for _id in self._instructors:
            if instructor.get_id() == _id:
                return False

        self._instructors[instructor.get_id()] = instructor
        return True

    def add_workout_class(self, workout_class: WorkoutClass) -> bool:
        """Add a <workout_class> to this Gym iff the <workout_class> does not
        have the same name as another WorkoutClass at this Gym.

        Return True iff the workout class has not already been added this Gym.

        >>> ac = Gym('Athletic Centre')
        >>> kickboxing = WorkoutClass('Kickboxing', ['Strength Training'])
        >>> ac.add_workout_class(kickboxing)
        True
        """
        for workout_name in self._workouts:
            if workout_class.name == workout_name:
                return False

        self._workouts[workout_class.name] = workout_class
        return True

    def add_room(self, name: str, capacity: int) -> bool:
        """Add a room with <name> and <capacity> to this Gym iff there is not
         already a room with <name> at this Gym.

        Return True iff the room has not already been added to this Gym.

        >>> ac = Gym('Athletic Centre')
        >>> ac.add_room('Dance Studio', 50)
        True
        """
        for room_name in self._room_capacities:
            if name == room_name:
                return False

        self._room_capacities[name] = capacity
        return True

    def schedule_workout_class(self, time_point: datetime, room_name: str,
                               workout_name: str, instr_id: int) -> bool:
        """Add an offering to this Gym at <time_point> iff: the room with
        <room_name> is available, the instructor with <instr_id> is qualified
        to teach the workout class with <workout_name>, and the instructor is
        not teaching another workout class at the same <time_point>.

        A room is available iff it does not already have another workout class
        scheduled at that day and time.

        The added offering starts with no registered clients.

        Return True iff the offering was added.

        Preconditions:
            - The room has already been added to this Gym.
            - The Instructor has already been added to this Gym.
            - The WorkoutClass has already been added to this Gym.

        >>> ac = Gym('Athletic Centre')
        >>> jacqueline = Instructor(1, 'Jacqueline Smith')
        >>> ac.add_instructor(jacqueline)
        True
        >>> jacqueline.add_certificate('Cardio 1')
        True
        >>> diane = Instructor(2, 'Diane Horton')
        >>> ac.add_instructor(diane)
        True
        >>> ac.add_room('Dance Studio', 18)
        True
        >>> ac.add_room('lower gym', 50)
        True
        >>> boot_camp = WorkoutClass('Boot Camp', ['Cardio 1'])
        >>> ac.add_workout_class(boot_camp)
        True
        >>> tap = WorkoutClass('Intro Tap', [])
        >>> ac.add_workout_class(tap)
        True
        >>> sep_9_2022_12_00 = datetime(2022, 9, 9, 12, 0)
        >>> ac.schedule_workout_class(sep_9_2022_12_00, 'lower gym',\
        boot_camp.name, jacqueline.get_id())
        True
        >>> ac.schedule_workout_class(sep_9_2022_12_00, 'Dance Studio',\
        tap.name, diane.get_id())
        True
        """

        if time_point in self._schedule:
            for _class in self._schedule[time_point]:
                if self._schedule[time_point][_class][0].get_id() == instr_id:
                    return False

        for q in self._workouts[workout_name].get_required_certificates():
            if q not in self._instructors[instr_id].get_certificates():
                return False

        if time_point in self._schedule:
            for room in self._schedule[time_point]:
                if room_name == room:
                    return False

        if self._schedule.get(time_point) is None:
            self._schedule[time_point] \
                = {room_name: (self._instructors[instr_id],
                               self._workouts[workout_name],
                               [])}
            return True
        self._schedule[time_point][room_name] \
            = (self._instructors[instr_id], self._workouts[workout_name], [])
        return True

    def register(self, time_point: datetime, client: str, workout_name: str) \
            -> bool:
        """Add <client> to the WorkoutClass with <workout_name> that is being
        offered at <time_point> iff the client has not already been registered
        in any course (including <workout_name>) at <time_point>, and the room
        is not full.

        If the WorkoutClass is being offered in more than one room at
        <time_point>, then add the client to the room that has the most clients
        already registered but still has available space. In the case of a tie,
        register <client> in any of the tied classes.

        Return True iff the client was added.

        Precondition: the WorkoutClass with <workout_name> is being offered in
            at least one room at <time_point>.

        >>> ac = Gym('Athletic Centre')
        >>> diane = Instructor(1, 'Diane')
        >>> diane.add_certificate('Cardio 1')
        True
        >>> ac.add_instructor(diane)
        True
        >>> ac.add_room('Dance Studio', 50)
        True
        >>> boot_camp = WorkoutClass('Boot Camp', ['Cardio 1'])
        >>> ac.add_workout_class(boot_camp)
        True
        >>> sep_9_2022_12_00 = datetime(2022, 9, 9, 12, 0)
        >>> ac.schedule_workout_class(sep_9_2022_12_00, 'Dance Studio',\
        boot_camp.name, diane.get_id())
        True
        >>> ac.register(sep_9_2022_12_00, 'Philip', 'Boot Camp')
        True
        >>> ac.register(sep_9_2022_12_00, 'Philip', 'Boot Camp')
        False
        """
        if time_point not in self._schedule:
            return False

        for _class in self._schedule[time_point]:
            if client in self._schedule[time_point][_class][2]:
                return False

        listy = []

        for room_name in self._schedule[time_point]:
            if self._schedule[time_point][room_name][1].name == workout_name:
                listy.append((self._room_capacities[room_name]
                              - len(self._schedule[time_point][room_name][2]),
                              room_name))

        listy.sort()
        listy.reverse()

        for item in listy:
            if item[0] != 0:
                self._schedule[time_point][item[1]][2].append(client)
                return True

        return False

    def instructor_hours(self, time1: datetime, time2: datetime) -> \
            dict[int, int]:
        """Return a dictionary reporting the hours worked by instructors
        teaching classes that start at any time between <time1> and <time2>,
        inclusive.

        Each key is an instructor ID and its value is the total number of hours
        worked by that instructor between <time1> and <time2>. Both <time1> and
        <time2> specify the start time for an hour when an instructor may have
        taught.

        Precondition: time1 <= time2

        >>> ac = Gym('Athletic Centre')
        >>> diane = Instructor(1, 'Diane')
        >>> david = Instructor(2, 'David')
        >>> diane.add_certificate('Cardio 1')
        True
        >>> ac.add_instructor(diane)
        True
        >>> ac.add_instructor(david)
        True
        >>> ac.add_room('Dance Studio', 50)
        True
        >>> boot_camp = WorkoutClass('Boot Camp', ['Cardio 1'])
        >>> ac.add_workout_class(boot_camp)
        True
        >>> t1 = datetime(2019, 9, 9, 12, 0)
        >>> ac.schedule_workout_class(t1, 'Dance Studio', boot_camp.name, 1)
        True
        >>> t2 = datetime(2019, 9, 10, 12, 0)
        >>> ac.instructor_hours(t1, t2) == {1: 1, 2: 0}
        True
        >>> ac.schedule_workout_class(t2, 'Dance Studio', boot_camp.name, 1)
        True
        >>> ac.instructor_hours(t1, t2) == {1: 2, 2: 0}
        True
        """
        hours_dict = {}
        for _id in self._instructors:
            hours_dict[self._instructors[_id].get_id()] = 0

        if not self._schedule:
            return hours_dict

        for time in self._schedule:
            if time1 <= time <= time2:
                for room_name in self._schedule[time]:
                    ins_id = self._schedule[time][room_name][0].get_id()
                    hours_dict[ins_id] += 1

        return hours_dict

    def payroll(self, time1: datetime, time2: datetime, base_rate: float) \
            -> list[tuple[int, str, int, float]]:
        """Return a sorted list of tuples reporting pay earned by each
        instructor teaching classes that start any time between <time1> and
        <time2>, inclusive. The list should be sorted in ascending order of
        instructor ids.

        Each tuple contains 4 elements, in this order:
        - an instructor's ID,
        - the instructor's name,
        - the number of hours worked by the instructor between <time1> and
          <time2>, and
        - the instructor's total wages earned between <time1> and <time2>.
        The returned list is sorted by instructor ID.

        Both <time1> and <time2> specify the start time for an hour when an
        instructor may have taught.

        Each instructor earns a <base_rate> per hour plus an additional
        BONUS_RATE per hour for each certificate they hold.

        Precondition: time1 <= time2

        >>> ac = Gym('Athletic Centre')
        >>> diane = Instructor(1, 'Diane')
        >>> david = Instructor(2, 'David')
        >>> diane.add_certificate('Cardio 1')
        True
        >>> ac.add_instructor(david)
        True
        >>> ac.add_instructor(diane)
        True
        >>> ac.add_room('Dance Studio', 50)
        True
        >>> boot_camp = WorkoutClass('Boot Camp', ['Cardio 1'])
        >>> ac.add_workout_class(boot_camp)
        True
        >>> t1 = datetime(2019, 9, 9, 12, 0)
        >>> ac.schedule_workout_class(t1, 'Dance Studio', boot_camp.name,
        ... 1)
        True
        >>> t2 = datetime(2019, 9, 10, 12, 0)
        >>> ac.payroll(t1, t2, 25.0)
        [(1, 'Diane', 1, 26.5), (2, 'David', 0, 0.0)]
        """
        payroll_list = []

        if not self._schedule:
            return payroll_list

        for time in self._schedule:
            if time1 <= time <= time2:
                for room_name in self._schedule[time]:
                    ins_id = self._schedule[time][room_name][0].get_id()
                    hrs = self.instructor_hours(time1, time2)[ins_id]
                    ins_name = self._schedule[time][room_name][0].name
                    ins = self._instructors[ins_id]
                    payroll_list.append((ins_id,
                                         ins_name,
                                         hrs,
                                         (base_rate + len(
                                             ins.get_certificates())
                                          * BONUS_RATE)
                                         * hrs
                                         ))

        for _id in self._instructors:
            temp = True
            for item in payroll_list:
                if item[0] == _id:
                    temp = False
            if temp:
                payroll_list.append((_id, self._instructors[_id].name, 0, 0.0))

        payroll_list.sort()

        return payroll_list

    def _is_instructor_name_unique(self, instructor: Instructor) -> bool:
        """Return True iff the name of <instructor> is used by <= 1 instructor
        in the Gym.

        >>> ac = Gym('Athletic Centre')
        >>> first_hire = Instructor(1, 'Diane')
        >>> ac.add_instructor(first_hire)
        True
        >>> ac._is_instructor_name_unique(first_hire)
        True
        >>> second_hire = Instructor(2, 'Diane')
        >>> ac.add_instructor(second_hire)
        True
        >>> ac._is_instructor_name_unique(first_hire)
        False
        >>> ac._is_instructor_name_unique(second_hire)
        False
        >>> third_hire = Instructor(3, 'Tom')
        >>> ac._is_instructor_name_unique(third_hire)
        True
        """
        count = 0
        for _id in self._instructors:
            if self._instructors[_id].name == instructor.name:
                count += 1

        if count <= 1:
            return True

        return False

    def offerings_at(self, time_point: datetime) -> list[dict[str, str | int]]:
        """Return a list of dictionaries, each representing a workout offered
        at this Gym at <time_point>.

        The offerings should be sorted by room name, in alphabetical ascending
        order.

        Each dictionary must have the following keys and values:
            'Date': the weekday and date of the class as a string, in the format
                'Weekday, year-month-day' (e.g., 'Monday, 2022-11-07')
            'Time': the time of the class, in the format 'HH:MM' where
                HH uses 24-hour time (e.g., '15:00')
            'Class': the name of the class
            'Room': the name of the room
            'Registered': the number of people already registered for the class
            'Available': the number of spots still available in the class
            'Instructor': the name of the instructor
                If there are multiple instructors with the same name, the name
                should be followed by the instructor ID in parentheses
                e.g., "Diane (1)"

        If there are no offerings at <time_point>, return an empty list.

        NOTE:
        - You MUST use the helper function create_offering_dict from
          gym_utilities to create the dictionaries, in order to make sure you
          match the format specified above.
        - You MUST use the helper method _is_instructor_name_unique when
          deciding how to format the instructor name.

        >>> ac = Gym('Athletic Centre')
        >>> diane1 = Instructor(1, 'Diane')
        >>> diane1.add_certificate('Cardio 1')
        True
        >>> diane2 = Instructor(2, 'Diane')
        >>> david = Instructor(3, 'David')
        >>> david.add_certificate('Strength Training')
        True
        >>> ac.add_instructor(diane1)
        True
        >>> ac.add_instructor(diane2)
        True
        >>> ac.add_instructor(david)
        True
        >>> ac.add_room('Dance Studio', 50)
        True
        >>> ac.add_room('Room A', 20)
        True
        >>> boot_camp = WorkoutClass('Boot Camp', ['Cardio 1'])
        >>> ac.add_workout_class(boot_camp)
        True
        >>> kickboxing = WorkoutClass('KickBoxing', ['Strength Training'])
        >>> ac.add_workout_class(kickboxing)
        True
        >>> t1 = datetime(2022, 9, 9, 12, 0)
        >>> ac.schedule_workout_class(t1, 'Dance Studio', boot_camp.name, 1)
        True
        >>> ac.schedule_workout_class(t1, 'Room A', kickboxing.name, 3)
        True
        >>> ac.offerings_at(t1) == [
        ... { 'Date': 'Friday, 2022-09-09', 'Time': '12:00',
        ... 'Class': 'Boot Camp', 'Room': 'Dance Studio', 'Registered': 0,
        ... 'Available': 50, 'Instructor': 'Diane (1)' },
        ... { 'Date': 'Friday, 2022-09-09', 'Time': '12:00',
        ... 'Class': 'KickBoxing', 'Room': 'Room A', 'Registered': 0,
        ... 'Available': 20, 'Instructor': 'David' }
        ... ]
        True
        """
        listy = []

        if not self._schedule[time_point]:
            return []

        for room_name in self._schedule[time_point]:
            temp = self._schedule[time_point][room_name][0]
            if self._is_instructor_name_unique(temp):
                ins_name = self._schedule[time_point][room_name][0].name
            else:
                ins_name = self._schedule[time_point][room_name][0].name + \
                    f" ({self._schedule[time_point][room_name][0].get_id()})"

            listy.append(
                create_offering_dict(
                    time_point.strftime('%A, %Y-%m-%d'),
                    time_point.strftime('%H:%M'),
                    self._schedule[time_point][room_name][1].name,
                    room_name,
                    len(self._schedule[time_point][room_name][2]),
                    self._room_capacities[room_name]
                    - len(self._schedule[time_point][room_name][2]),
                    ins_name
                )
            )

        listy.sort(key=lambda x: x['Room'])
        return listy

    def to_schedule_list(self, week: datetime = None) \
            -> list[dict[str, str | int]]:
        """Return a list of dictionaries for the Gym's entire schedule, with
        each dictionary representing a workout offered (in the format specified
        by the docstring for offerings_at).

        The dictionaries should be in the list in ascending order by their date
        and time (not the string representation of the date and time).
        Offerings occurring at exactly the same date and time should
        be in alphabetical order based on their room names.

        If <week> is specified, only return the events that occur between the
        date interval (between a Monday 0:00 and Sunday 23:59) that contains
        <week>.

        Hint: The helper function <in_week> can be used to determine if one
        datetime object is in the same week as another.

        >>> ac = Gym('Athletic Centre')
        >>> diane1 = Instructor(1, 'Diane')
        >>> diane1.add_certificate('Cardio 1')
        True
        >>> diane2 = Instructor(2, 'Diane')
        >>> david = Instructor(3, 'David')
        >>> david.add_certificate('Strength Training')
        True
        >>> ac.add_instructor(diane1)
        True
        >>> ac.add_instructor(diane2)
        True
        >>> ac.add_instructor(david)
        True
        >>> ac.add_room('Studio 1', 20)
        True
        >>> boot_camp = WorkoutClass('Boot Camp', ['Cardio 1'])
        >>> ac.add_workout_class(boot_camp)
        True
        >>> kickboxing = WorkoutClass('KickBoxing', ['Strength Training'])
        >>> ac.add_workout_class(kickboxing)
        True
        >>> t1 = datetime(2022, 9, 9, 12, 0)
        >>> ac.schedule_workout_class(t1, 'Studio 1', boot_camp.name, 1)
        True
        >>> t2 = datetime(2022, 9, 8, 13, 0)
        >>> ac.schedule_workout_class(t2, 'Studio 1', kickboxing.name, 3)
        True
        >>> ac.to_schedule_list() == [
        ... { 'Date': 'Thursday, 2022-09-08', 'Time': '13:00',
        ... 'Class': 'KickBoxing', 'Room': 'Studio 1', 'Registered': 0,
        ... 'Available': 20, 'Instructor': 'David' },
        ... { 'Date': 'Friday, 2022-09-09', 'Time': '12:00',
        ... 'Class': 'Boot Camp', 'Room': 'Studio 1', 'Registered': 0,
        ... 'Available': 20, 'Instructor': 'Diane (1)' },
        ... ]
        True
        """
        listy = []
        if not self._schedule:
            return listy

        schedule_keys = list(self._schedule.keys())
        schedule_keys.sort(reverse=False)

        if week:
            for time in schedule_keys:
                if in_week(time, week):
                    listy = self.__add_o(listy, time)

        else:
            for time in schedule_keys:
                listy = self.__add_o(listy, time)

        return listy

    def __add_o(self, listy: list[dict[str, str | int]], t: datetime) \
            -> list[dict[str, str | int]]:
        """
        Helper function for to_schedule_list, appends all offerings at
        <time> to <listy>.
        """
        if len(self.offerings_at(t)) == 1:
            listy.append(self.offerings_at(t)[0])
            return listy

        for item in self.offerings_at(t):
            listy.append(item)
            return listy

    def __eq__(self, other: Gym) -> bool:
        """Return True iff this Gym is equal to <other>.

        Two gyms are considered equal if they have the same name,
        instructors, workouts, room capacities, and schedule.

        >>> ac = Gym('Athletic Centre')
        >>> ac2 = Gym('Athletic Centre')
        >>> ac == ac2
        True
        """
        return self.name == other.name \
            and self._instructors == other._instructors \
            and self._workouts == other._workouts \
            and self._room_capacities == other._room_capacities \
            and self._schedule == other._schedule

    def to_webpage(self) -> None:
        """
        Deleted this method because I was having an error with pandas on
        my computer. It said I had no module _bz2, I tried to install
        using the command line and pip, and also tried to build
        python again, but it didn't work, so I removed the method entirely,
        along with any other methods that called pandas. The method header
        is still here because there is a test on MarkUs that checks if it is.
        """

if __name__ == '__main__':
    pass


import torch
import torch.nn as nn
import torch.optim as optim
import os

from omegaconf import OmegaConf, DictConfig

def save_model(model, path=None):
    if path:
        new_path = os.path.join(model.save_path,path)
        model_file_path = os.path.join(
                new_path,
                model.name)
    else:
        new_path = model.save_path
        model_file_path = os.path.join(model.save_path, model.name)

    if not os.path.exists(new_path):
        os.makedirs(new_path)
    torch.save(model.get_weights(), model_file_path)

def load_model(model, save_path, checkpoint):
    model_file_path = os.path.join(save_path,checkpoint, model.name)
    model.load_state_dict(torch.load(model_file_path))

class Actor(nn.Module):
    '''
    Actor network for DDPG
    '''
    def __init__(self, config: DictConfig, target=False, worker=False):
        super().__init__()
        self.config = config
        self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
        if self.config.running_on == 'M1':
            self.device = 'mps' if torch.backends.mps.is_available() else 'cpu'
        if worker:
            self.device = 'cpu'

        self.name = 'actor'
        if target:
            self.name = 'target_actor'
        self.save_path = config.agent.save_path
        self.learning_rate = config.agent.actor_lr
        self.state_dimension = config.env.state_dimension
        self.action_dimension = config.env.action_dimension

        self.linear_block = nn.Sequential(
                nn.Linear(self.state_dimension, 400),
                #nn.BatchNorm1d(400),
                nn.LayerNorm(400),
                nn.ReLU(),
                nn.Linear(400, 300),
                #nn.BatchNorm1d(300),
                nn.LayerNorm(300),
                nn.ReLU(),
                nn.Linear(300, self.action_dimension),
                nn.Tanh()
                )
        self.optimizer = optim.Adam(
                self.parameters(), lr=self.learning_rate
                )
        self.to(self.device)

    def forward(self, x):
        x = self.linear_block(x)
        return x

    def get_weights(self):
        return {k: v.cpu() for k,v in self.state_dict().items()}

    def set_weights(self, weights):
        self.load_state_dict(weights)

    def save_model(self, path=None):
        save_model(self, path)

    def load_model(self, path, checkpoint):
        load_model(self, path, checkpoint)

class Critic(nn.Module):
    '''
    Critic network for DDPG
    '''
    def __init__(self, config: DictConfig, target=False, worker=False):
        super().__init__()
        self.config = config
        self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
        if self.config.running_on == 'M1':
            self.device = 'mps' if torch.backends.mps.is_available() else 'cpu'
        if worker:
            self.device = 'cpu'

        self.name = 'critic'
        if target:
            self.name = 'target_critic'
        self.save_path = config.agent.save_path
        self.learning_rate = config.agent.critic_lr
        self.state_dimension = config.env.state_dimension
        self.action_dimension = config.env.action_dimension

        self.batch_size = self.config.memory.batch_size

        self.linear_block = nn.Sequential(
                nn.Linear(self.state_dimension + self.action_dimension, 400),
                #nn.BatchNorm1d(400),
                nn.LayerNorm(400),
                nn.ReLU(),
                nn.Linear(400, 300),
                #nn.BatchNorm1d(300),
                nn.LayerNorm(300),
                nn.ReLU(),
                nn.Linear(300, 1),
                )
        self.optimizer = optim.Adam(
                self.parameters(), lr=self.learning_rate
                )
        self.to(self.device)

    def forward(self, x,y):
        if not(len(x.shape) == 1):
            q = self.linear_block(torch.cat([x,y],1))
            return q
        else:
            q = self.linear_block(torch.cat([x,y],0))
            return q

    def get_weights(self):
        return {k: v.cpu() for k,v in self.state_dict().items()}

    def set_weights(self, weights):
        self.load_state_dict(weights)

    def save_model(self,path=None):
        save_model(self, path)

    def load_model(self, path, checkpoint):
        load_model(self, path, checkpoint)

# Adapted from:
# https://github.com/PacktPublishing/Deep-Reinforcement-Learning-Hands-On-Second-Edition/blob/master/Chapter17/lib/model.py
class D4PGCritic(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.obs_size = self.config.env.state_dimension
        self.act_size = self.config.env.action_dimension
        self.n_atoms = self.config.agent.n_atoms
        self.v_min = self.config.agent.v_min
        self.v_max = self.config.agent.v_max

        self.obs_net = nn.Sequential(
            nn.Linear(self.obs_size, 400),
            nn.ReLU(),
        )

        self.out_net = nn.Sequential(
            nn.Linear(400 + self.act_size, 300),
            nn.ReLU(),
            nn.Linear(300, self.n_atoms)
        )

        delta = (self.v_max - self.v_min) / (self.n_atoms - 1)
        self.register_buffer("supports", torch.arange(
            self.v_min, self.v_max + self.delta, self.delta))

    def forward(self, x, a):
        obs = self.obs_net(x)
        return self.out_net(torch.cat([obs, a], dim=1))

    def distr_to_q(self, distr):
        weights = F.softmax(distr, dim=1) * self.supports
        res = weights.sum(dim=1)
        return res.unsqueeze(dim=-1)


import cv2
import numpy as np
from PIL import Image
import os

path = 'dataset'

recogniser = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")

def getImagesAndLabels(path):

    imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
    #it should be for f in ... maybe
    #it joins one or more path components intelligently. So basically an array of paths is created.
    #Each path is of type "path/f" where path is defined above and f is in os.listdir(path)
    #it returns a string which represents the concatenated path components.
    #os.listdir() method in python is used to get the list of all files and directories in the
    #specified directory.
    #Basically this code stores the paths of all files in the dataset folder in the imagePaths variable
    facesamples = []
    ids = []

    for imagePath in imagePaths:
        PIL_img = Image.open(imagePath).convert('L')
        #Returns a converted copy of this image
        # Syntax: Image.convert(mode=None, matrix=None, dither=None, palette=0, colors=256)
        # for grayscale the mode is 'L'
        img_numpy = np.array(PIL_img, 'uint8')#converting the image into a numpy array

        id = int(os.path.split(imagePath)[-1].split(".")[1])
        #os.path.split splits the path into head and tail and returns a list containing these.
        #the tail is basically the filename in the path and is the last object in the returned list
        #-1 is used to access this last string. now this string is split into multiple strings by
        #a delimmiter '.' and then the first element of this list is accessed.

        faces = detector.detectMultiScale(img_numpy)
        #default scalefactor and minneighbours for this are 1.1 and 3.

        for (x, y, w, h) in faces:
            facesamples.append(img_numpy[y:y+h, x:x+w])
            ids.append(id)

        return facesamples, ids

print("\n [INFO] Training faces.....")

faces, ids = getImagesAndLabels(path)
recogniser.train(faces, np.array(ids))

recogniser.write('trainer/trainer.yml')

print("\n [INFO] {0} faces trained.".format(len(np.unique(ids))))


#!/usr/bin/env python
# coding: utf-8
import cv2
import numpy as np
import glob
import os

rows = 6
cols = 9

objp = np.zeros((rows * cols, 3), np.float32)
objp[:, :2] = np.mgrid[0:rows, 0:cols].T.reshape(-1, 2)

# define the path
path = os.getcwd() + '/images/task_1/'
output_path = os.getcwd() + '/output/task_1/'
# 3d point in real world space
obj_left = []
# 2d points in image plane.
img_l = []

images = glob.glob(os.path.join(path, "left_*.png"))
for img_name in images:
    img_color = cv2.imread(img_name)
    img = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(img, (rows, cols), None)
    obj_left.append(objp)
    img_l.append(corners)
    if ret == True:
        corners2 = cv2.cornerSubPix(img, corners, (11,11), (-1,-1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.01))
        cv2.drawChessboardCorners(img_color, (rows, cols), corners2, ret)
        cv2.imshow('img', img_color)
        cv2.imwrite(output_path + '/corners.png', img_color)

#Calibration
ret, mtx_left, dist, emp, emp = cv2.calibrateCamera(obj_left, img_l, img.shape[::-1], None, None)

# Undistortion for left_2 png
img = cv2.imread(path  + "left_2.png")

h, w = img.shape[:2]
new_mtx_left_matrix, roi = cv2.getOptimalNewCameraMatrix(mtx_left, dist, (w,h), 0)

mapx, mapy = cv2.initUndistortRectifyMap(mtx_left, dist, None, new_mtx_left_matrix, (w,h), 5)
dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)
x, y, w, h = roi
dst = dst[y:y+h, x:x+w]

if dst[0].size > 0:
    cv2.imwrite(output_path + '/left_2_undistorted.png', dst)
    undistorted_image = cv2.imread(os.path.join(output_path + '/left_2_undistorted.png'))
    cv2.imshow('undistorted image', undistorted_image)

param_path = os.getcwd() + '/parameters'

s = cv2.FileStorage('{0}/left_camera_intrinsics.xml'.format(param_path), cv2.FileStorage_WRITE)
s.write('mtx_left', mtx_left)
s.write('distCoeffs_left', dist)
s.release()

# RIght image

rows = 9
cols = 6

objp = np.zeros((rows * cols, 3), np.float32)
objp[:, :2] = np.mgrid[0:rows, 0:cols].T.reshape(-1, 2)

obj_right = [] # 3d point in real world space
img_r = [] # 2d points in image plane.

images = glob.glob(os.path.join(path, "right_*.png"))

for img_name in images:
    img_color = cv2.imread(img_name)
    img = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)

    ret, corners = cv2.findChessboardCorners(img, (rows, cols), None)
    obj_right.append(objp)
    img_r.append(corners)
    if ret == True:
        corners2 = cv2.cornerSubPix(img, corners, (5,5), (-1,-1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.01))
        cv2.drawChessboardCorners(img_color, (rows, cols), corners2, ret)
        cv2.imshow('img', img_color)

#Calibration

ret, mtx_right, dist_right, emp, emp = cv2.calibrateCamera(obj_right, img_r, img.shape[::-1], None, None)

img = cv2.imread(path + "right_2.png")

h, w = img.shape[:2]

new_mtx_right_matrix, roi = cv2.getOptimalNewCameraMatrix(mtx_right, dist_right, (w,h), 0)

mapx, mapy = cv2.initUndistortRectifyMap(mtx_right, dist, None, new_mtx_right_matrix, (w,h), 5)
dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)
x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
if dst[0].size > 0:
    cv2.imwrite(output_path + '/right_2_undistorted.png', dst)
    undistorted_image = cv2.imread(output_path + '/right_2_undistorted.png')
    cv2.imshow('undistorted image', undistorted_image)

s = cv2.FileStorage('{0}/right_camera_intrinsics.xml'.format(param_path), cv2.FileStorage_WRITE)
s.write('mtx_right', mtx_right)
s.write('distCoeffs_right', dist_right)
s.release()


__author__ = 'xuxiaoye'
from django.conf.urls import url
from . import views

urlpatterns = [
    # Json APIs
    url(r'^jsonResult$', views.jsonResult, name='jsonResult'),
    url(r'^api\/login$', views.apiLogin, name='apiLogin'),
    url(r'^rs$', views.rs, name='rs'),
    # End of Json APIs
    # Wechat backend
    url(r'^weixin$', views.weixin, name='weixin'),
    # End of Wechat backend
    # Common process
    url(r'^back$', views.back, name='back'),
    url(r'^logoff$', views.logoff, name='logoff'),
    # End of Common process
    # Application pages
    url(r'^app1\_1$', views.app1_1, name='app1_1'),
    url(r'^app1\_2$', views.app1_2, name='app1_2'),
    url(r'^app2\_1$', views.app2_1, name='app2_1'),
    # End of Application pages
    # Ajax
    url(r'^ajax$', views.ajax, name='ajax'),
    # End of Ajax
    # Default home page
    url(r'^.*$', views.index, name='index'),
    # End of Default home page
]


import pygame
import Classes_objects
import Developer_help
import Load_image
import Sound_effects
import Check_reasults
import Deck_module
import Speical_moves

#-------------------------------------------------------- load data -----------------------------
#----------------------------------------------------players --------------------------------
player1 = Classes_objects.get_player('PLAYER1')
dealer = Classes_objects.get_player('DEALER')
table = Classes_objects.get_player('TABLE')
#--------------------------------------------------images----------------------
card_back = Load_image.get_game_img('CARD_BACK')
white_chip =Load_image.get_game_img('WHITE_CHIP')
red_chip =Load_image.get_game_img('RED_CHIP')
blue_chip =Load_image.get_game_img('BLUE_CHIP')
green_chip =Load_image.get_game_img('GREEN_CHIP')
black_chip =Load_image.get_game_img('BLACK_CHIP')

#--------------------------------------------------buttons---------------------
back_button = Classes_objects.get_button('BACK')
bet_allin_button = Classes_objects.get_button('ALL_IN')
bet_approve_button = Classes_objects.get_button('APPROVE')
bet_clear_button = Classes_objects.get_button('CLEAR')
split_button = Classes_objects.get_button('SPLIT')
#------------------------------------------------------sound------------------------------------------
button_effect = Sound_effects.get_sound('BUTTON')
chip_effect = Sound_effects.get_sound('CHIP')

def set_bet(win,balance):

	'''
	#------------------------------------------------------------define the bet at the start of a turn------------------------------------
	'''

	win.fill((0,150,0))
	win.blit(card_back,(350,350))
	win.blit(card_back,(450,350))
	reset_balance = balance
	amount = 0
	while True:
		back_button.draw(win,(0,0,0))
		bet_allin_button.draw(win,(0,0,0))
		bet_approve_button.draw(win,(0,0,0))
		bet_clear_button.draw(win,(0,0,0))
		win.blit(white_chip,(40,350))
		win.blit(red_chip,(115,350))
		win.blit(blue_chip,(190,350))
		win.blit(green_chip,(75,425))
		win.blit(black_chip,(150,425))

		pygame.draw.rect(win,(100,150,0),(520,40,300,100),0)#to reset the board
		Developer_help.write(win,'Balance: {}'.format(balance),30,550,50)
		Developer_help.write(win,'bet amount: {}'.format(amount),30,550,100)

		pygame.time.delay(50)
		pygame.display.update()

		for event in pygame.event.get():
			pos = pygame.mouse.get_pos()
			if event.type == pygame.MOUSEMOTION:
				#------------------------------------------------------------chips------------------------------------------------------
				if balance >=1:
				#WHITE
					if pos[0] in range(40,110) and pos[1] in range(350,420):
						#HIGHLIGHT THE CHIPS
						pygame.draw.circle(win,(0,0,0),(75,385),37)
						win.blit(white_chip,(40,350))
					else:
						pygame.draw.circle(win,(0,150,0),(75,385),37)
						win.blit(white_chip,(40,350))
				if balance >=5:
					#RED
					if pos[0] in range(115,185) and pos[1] in range(350,420):
						#HIGHLIGHT THE CHIPS
						pygame.draw.circle(win,(0,0,0),(150,385),37)
						win.blit(red_chip,(115,350))
					else:
						pygame.draw.circle(win,(0,150,0),(150,385),37)
						win.blit(red_chip,(115,350))
				if balance >=10:
						#BLUE
					if pos[0] in range(190,260) and pos[1] in range(350,420):
						#HIGHLIGHT THE CHIPS
						pygame.draw.circle(win,(0,0,0),(225,385),37)
						win.blit(blue_chip,(190,350))
					else:
						pygame.draw.circle(win,(0,150,0),(225,385),37)
						win.blit(blue_chip,(190,350))
				if balance >=25:
					#GREEN
					if pos[0] in range(75,145) and pos[1] in range(425,495):
						#HIGHLIGHT THE CHIPS
						pygame.draw.circle(win,(0,0,0),(110,460),37)
						win.blit(green_chip,(75,425))
					else:
						pygame.draw.circle(win,(0,150,0),(110,460),37)
						win.blit(green_chip,(75,425))
				if balance >= 100:
					#BLACK
					if pos[0] in range(150,220) and pos[1] in range(425,495):
						#HIGHLIGHT THE CHIPS
						pygame.draw.circle(win,(0,0,0),(185,460),37)
						win.blit(black_chip,(150,425))
					else:
						pygame.draw.circle(win,(0,150,0),(185,460),37)
						win.blit(black_chip,(150,425))
				#----------------------------------------------------------------------buttons------------------------------------
				if back_button.is_over(pos):
					back_button.color = (0,0,255)
				else:
					back_button.color = (255,0,0)

				if bet_approve_button.is_over(pos):
					bet_approve_button.color = (0,0,255)
				else:
					bet_approve_button.color = (255,0,0)

				if bet_clear_button.is_over(pos):
					bet_clear_button.color = (0,0,255)
				else:
					bet_clear_button.color = (255,0,0)

				if bet_allin_button.is_over(pos):
					bet_allin_button.color = (0,0,255)
				else:
					bet_allin_button.color = (255,0,0)

			if event.type == pygame.MOUSEBUTTONDOWN:
				if back_button.is_over(pos):
					button_effect.play()
					return 'back'#keyword to signal the outer function game screen
				#Buttons for raising the bet
				#White
				if pos[0] in range(40,110) and pos[1] in range(350,420) and balance >=1:
					chip_effect.play()
					balance-=1
					amount+=1
				#Red
				if pos[0] in range(115,185) and pos[1] in range(350,420) and balance >=5:
					chip_effect.play()
					balance-=5
					amount+=5
				#Blue
				if pos[0] in range(190,260) and pos[1] in range(350,420) and balance >=10:
					chip_effect.play()
					balance-=10
					amount+=10
				#Green
				if pos[0] in range(75,145) and pos[1] in range(425,495) and balance >=25:
					chip_effect.play()
					balance-=25
					amount+=25
				#Black
				if pos[0] in range(150,220) and pos[1] in range(425,495) and balance >= 100:
					chip_effect.play()
					balance-=100
					amount+=100

				if bet_allin_button.is_over(pos):
					button_effect.play()
					amount += balance
					balance = 0
				if bet_clear_button.is_over(pos):#clears bet amount and reset balance
					button_effect.play()
					amount = 0
					balance = reset_balance
				if bet_approve_button.is_over(pos):
					#check bet limit
					if amount <2 or amount > 500:
						Developer_help.write(win,'Limit is between 2 and 500 $',30,175,100)
					else:
						button_effect.play()
						return amount,balance

			if event.type == pygame.QUIT:
				return 'quit'

	#---------------------------------------------------- player1 turn function -------------------------------------------
def player1_turn(win,player1_card1,player1_card2,at_table,player1_balance,player1_name,player1_bet):
	'''
	Dictates what a players turn should be like
	takes in (card1,card2,amount at table)
	'''
	#options to bet via function set_bet
	#------------------------------------------------------------ LOAD DATA -----------------------
	#------------------------------------------------------------ buttons -------------------------
	pass_turn_button = Classes_objects.get_button('PASS_TURN')
	hit_button = Classes_objects.get_button('HIT')
	back_button = Classes_objects.get_button('BACK')
	low_ace_button = Classes_objects.get_button('LOW_ACE')
	high_ace_button = Classes_objects.get_button('HIGH_ACE')
	split_button = Classes_objects.get_button('SPLIT')
	double_down_button = Classes_objects.get_button('DOUBLE_DOWN')
	#------------------------------------------------------------- sound --------------------------
	draw_effect = Sound_effects.get_sound('DRAW')
	pass_effect = Sound_effects.get_sound('PASS')
	button_effect = Sound_effects.get_sound('BUTTON')

	is_double_down = False
	is_split = False
	is_ace = False
	is_natural = True
	if player1_card1[0] == 1 or player1_card2[0] == 1 :
		is_ace = True
	card1_image = pygame.image.load(Load_image.get_card_image(player1_card1))
	card2_image = pygame.image.load(Load_image.get_card_image(player1_card2))
	card_x = 400
	card_y = 200
	#in order to view the cards on the screen, get card function imported from load_card_image module allows me to access loaction of image
	#without any trouble
	win.fill((0,150,0))
	draw_effect.play()
	win.blit(card1_image,(card_x,card_y))
	pygame.display.update()
	card_x+=40
	card_y+=40
	#stored coordinations in a variable in order to allow posting of new cards over the board also
	pygame.time.delay(500)
	draw_effect.play()
	win.blit(card2_image,(card_x,card_y))
	pygame.display.update()
	#### check if split ###
	split = False
	if player1_card1[0] == player1_card2[0]:
		card1_value = player1_card1[0]
		card2_value = player1_card2[0]
		is_split = True
	#################################turn j,q,k cards to value 10##################
	player1_card1 = Developer_help.correct_card_value(player1_card1)
	player1_card2 =  Developer_help.correct_card_value(player1_card2)
	cards_sum = Check_reasults.check_cards_sum(win,is_natural,player1_card1[0],player1_card2[0])
	if cards_sum in range(9,12):
		is_double_down = True
	cards_used = [player1_card1,player1_card2]
	while cards_sum < 21:

		pass_turn_button.draw(win,(0,0,0))
		hit_button.draw(win,(0,0,0))
		back_button.draw(win,(0,0,0))
		if split is False:
			low_ace_button.x = 200
			high_ace_button.x = 200

		#----------------------------------Turn-------------------------------#
		pygame.draw.rect(win,(100,150,0),(470,40,350,100),0)#to reset the board
		Developer_help.write(win,"{}'s Balance: {}".format(player1_name,player1_balance),30,500,50)
		Developer_help.write(win,'Overall bet amount: {}'.format(at_table),30,500,100)
		pygame.time.delay(50)
		pygame.display.update()
		for event in pygame.event.get():
			pos = pygame.mouse.get_pos()
			###############################################if mouse moves
			if event.type == pygame.MOUSEMOTION:
				if back_button.is_over(pos):
					back_button.color = (0,0,255)
				else:
					back_button.color = (255,0,0)

				if pass_turn_button.is_over(pos):
					pass_turn_button.color = (0,0,255)
				else:
					pass_turn_button.color = (255,0,0)

				if hit_button.is_over(pos):
					hit_button.color = (0,0,255)
				else:
					hit_button.color = (255,0,0)

				#---------------------------------- Speical buttons --------------------------

				if is_double_down:
					double_down_button.draw(win,(0,0,0))
					if double_down_button.is_over(pos):
						double_down_button.color = (0,0,255)
					else:
						double_down_button.color = (255,0,0)

				if is_split:
					split_button.draw(win,(0,0,0))
					if split_button.is_over(pos):
						split_button.color = (0,0,255)
					else:
						split_button.color = (255,0,0)

				if is_ace:
					#show buttons first
					low_ace_button.draw(win,(0,0,0))
					high_ace_button.draw(win,(0,0,0))

					if low_ace_button.is_over(pos):
						low_ace_button.color = (0,0,255)
					else:
						low_ace_button.color = (255,0,0)
					if high_ace_button.is_over(pos):
						high_ace_button.color = (0,0,255)
					else:
						high_ace_button.color = (255,0,0)

					#####################################################if mouse clicks
			if event.type == pygame.MOUSEBUTTONDOWN:
				if back_button.is_over(pos):
					button_effect.play()
					return 'back'
				if pass_turn_button.is_over(pos):
					if split:
						cards_sum = [hand1,cards_sum]
					pass_effect.play()
					is_split = False
					Developer_help.write(win,'Stand',90,200,100)
					pygame.display.update()
					pygame.time.delay(2000)
					return cards_sum
				if hit_button.is_over(pos):
					draw_effect.play()
					if split:
						pygame.draw.rect(win,(0,150,0),(40,190,120,275),0)#scrap button
					else:
						pygame.draw.rect(win,(0,150,0),(190,190,120,275),0)#scrap button
					is_split = False
					is_natural = False
					new_card = Deck_module.pull_card()#pull card
					cards_used.append(new_card)
					card_x+=40
					card_y+=40
					#post card image changes cordination so new posting could be shown
					new_card_image = pygame.image.load(Load_image.get_card_image(new_card))
					win.blit(new_card_image,(card_x,card_y))
					pygame.display.update()
					pygame.time.delay(1000)
					##################change j,q,k values to 10
					new_card = Developer_help.correct_card_value(new_card)
					if new_card[0] == 1:
						is_ace = True
					else:
						is_ace = False
					cards_sum = Check_reasults.check_cards_sum(win,is_natural,new_card[0],cards_sum)
					last_card = new_card
					if cards_sum is False:
						if split:
							return hand1
						else:
							return False
					elif cards_sum is True:
						return True
					#so the function would stop and wont let the game continue
				if low_ace_button.is_over(pos):
					button_effect.play()
					if is_double_down:
						pygame.draw.rect(win,(0,150,0),(40,190,120,275),0)#scrap button
					is_double_down = False
					is_ace = False
					if split:
						pygame.draw.rect(win,(0,150,0),(40,190,120,275),0)#scrap button
					else:
						pygame.draw.rect(win,(0,150,0),(190,190,120,275),0)#scrap button
				if high_ace_button.is_over(pos):
					button_effect.play()
					is_ace = False
					if is_double_down:
						pygame.draw.rect(win,(0,150,0),(40,190,120,275),0)#scrap button
					is_double_down = False
					if split:
						pygame.draw.rect(win,(0,150,0),(40,190,120,275),0)#scrap button
					else:
						pygame.draw.rect(win,(0,150,0),(190,190,120,275),0)#scrap button
					cards_sum = Check_reasults.check_cards_sum(win,is_natural,10,cards_sum)
					if cards_sum is True:
						return True
					elif cards_sum is False:
						return False
				if is_split is True:
					if split_button.is_over(pos):
						is_split = False
						is_double_down = False
						table.win(player1_bet)
						player1.bet(player1_bet)
						player1_balance = player1.balance
						at_table = table.balance
						pygame.draw.rect(win,(100,150,0),(470,40,300,100),0)#to reset the board
						pygame.draw.rect(win,(0,150,0),(40,190,150,275),0)#scrap button
						Developer_help.write(win,"{}'s Balance: {}".format(player1_name,player1_balance),30,500,50)
						Developer_help.write(win,'Overall bet amount: {}'.format(at_table),30,500,100)
						pygame.display.update()
						pygame.time.delay(50)
						hand1 = Speical_moves.split(win,(card1_value,player1_card1[1]),(card2_value,player1_card2[1]),player1_name)
						if hand1 == 'back':
							return 'back'
						elif hand1 == 'quit':
							return 'quit'
						cards_sum = player1_card1[0]
						#that a split has happened
						split = True
						card_x-=40
						card_y-=40
				if is_double_down and double_down_button.is_over(pos):
					if player1_balance >= player1_bet:
						is_double_down = False
						table.win(player1_bet)
						at_table += player1_bet
						player1.bet(player1_bet)
						player1_balance-= player1_bet
						pygame.draw.rect(win,(0,150,0),(40,190,150,275),0)#scrap button
						pygame.draw.rect(win,(0,150,0),(190,190,120,275),0)#scrap button
					else:
						Developer_help.write(win,'There are not enough chips for that',30,150,100)

			if event.type == pygame.QUIT:
				return 'quit'
	#returns 21 if value is equal to 21!
	return cards_sum


"""
Compile some information from a table
"""

import xlrd
import xlwt
import os

def frequencies_by_place(xls, entities_sheet, entities_id, entities_place,
                                 data_sheet, output, null=None, out_cols_basename=None,
                                 entities_filter=None, cols_exclusion=None):
    """
    Entities table:
    ID_Aluno | codigo_postal
    xxxxxxxx | xxxx-xxx
    xxxxxxxx | xxxx-xxx

    data_sheet:
    ID_Aluno | disciplina_1 | disciplina_2 | disciplina_n
    xxxxxxxx |    nota_1    |    xxxxxxx   |   xxxxxxx
    xxxxxxxx |    nota_2    |    xxxxxxx   |   xxxxxxx
    xxxxxxxx |    nota_3    |    xxxxxxx   |   xxxxxxx

    Output tables (one for each disciplina and other for the total)
                    |  nota_1  |  nota_2  |  nota_3  | Mean | Variance
    total           | NrAlunos | NrAlunos | NrAlunos |  x   |    y
    codigo_postal_1 | NrAlunos | NrAlunos | NrAlunos |  x   |    y
    codigo_postal_n | NrAlunos | NrAlunos | NrAlunos |  x   |    y

    In the entities_sheet and data_sheet, there must be only one referente
    for an entity (duplicated entities are not allowed)

    Filtering entities properties is possible
    """

    import numpy
    from decimal           import Decimal
    from glass.tbl.xls.fld  import get_columns_position
    from glass.tbl.xls.summ import list_unique_values_column
    from glass.tbl.xls.summ import count_values_column
    from glass.tbl.xls.summ import count_values_column_if_entity_exists
    from glass.tbl.xls.summ import count_values_column_by_entity_property

    """
    Aux method to estimate some generic statistics based on a "Dict Histogram"
    (total, mean and standard deviation)
    """
    def map_dict(histogram):
        if 'mean' in histogram.keys():
            del histogram['mean']

        if 'stdesviation' in histogram.keys():
            del histogram['stdesviation']

        if 'total' in histogram.keys():
            del histogram['total']

        # Get the total of entities
        histogram['total'] = sum(histogram.values())
        # Get mean
        numerator = 0
        denominator = 0
        std_sample = []
        for v in histogram:
            if type(v) != str:
                numerator += Decimal(v) * Decimal(histogram[v])
                denominator += histogram[v]
                std_sample += [v for x in range(histogram[v])]

        if numerator and denominator:
            histogram['mean'] = numerator / Decimal(denominator)
            histogram['stdesviation'] = Decimal(numpy.std(std_sample))

        return histogram

    # Open xls file
    __xls_file = xlrd.open_workbook(xls, on_demand=True)

    # Map entities with location
    """
    d = {
        entitie_id : location
    }
    """
    if entities_filter:
        filters = entities_filter.split(';')
        filters_map = {}
        for flt in filters:
            col_filter, val_filter = flt.split('=')
            filters_map[col_filter] = val_filter

        interest_col = [entities_id, entities_place] + filters_map.keys()

    else:
        filters_map = 0
        interest_col = [entities_id, entities_place]

    __entities_sheet = __xls_file.sheet_by_name(entities_sheet)
    id_place_position = get_columns_position(
        __entities_sheet, interest_col
    )

    if entities_id not in id_place_position.keys():
        raise ValueError('Couldn\'t find the given column id')
    elif entities_place not in id_place_position.keys():
        raise ValueError('Couldn\'t find the position of the place id')

    entities_map = {}
    for row in range(1, __entities_sheet.nrows):
        __id = __entities_sheet.cell(
            row, id_place_position[entities_id]).value

        location = __entities_sheet.cell(
            row, id_place_position[entities_place]).value

        if filters_map:
            c = 0
            for col_filter in filters_map:
                __filter = __entities_sheet.cell(
                    row, id_place_position[col_filter]).value

                if __filter != val_filter:
                    c += 1
                    break

            if c:
                continue

        entities_map[__id] = location

    # Count Entities by value in each column
    """
    d = {
        col_1 : {
            total : {
                total   : total_count,
                value_1 : value_1_count,
                value_2 : value_2_count,
                value_n : value_n_count
            },
            location_1: {
                total   : total_count,
                value_1 : value_1_count,
                value_2 : value_2_count,
                value_n : value_n_count
            },
            location_2: {
                total   : total_count,
                value_1 : value_1_count,
                value_2 : value_2_count,
                value_n : value_n_count
            }
        },
        col_2 : {
            total : {
                total   : total_count,
                value_1 : value_1_count,
                value_2 : value_2_count,
                value_n : value_n_count
            },
            location_1: {
                total   : total_count,
                value_1 : value_1_count,
                value_2 : value_2_count,
                value_n : value_n_count
            },
            location_2: {
                total   : total_count,
                value_1 : value_1_count,
                value_2 : value_2_count,
                value_n : value_n_count
            }
        },
        col_n : {
            ...
        }
    }
    """
    data_sheet = __xls_file.sheet_by_name(data_sheet)
    data = {}

    cols_exclusion = cols_exclusion if type(cols_exclusion) == list else \
        [cols_exclusion] if type(cols_exclusion) == str else 0

    for col in range(1, data_sheet.ncols):
        column_name = data_sheet.cell(0, col).value
        if cols_exclusion:
            if column_name in cols_exclusion:
                continue
        # List unique values
        values = list_unique_values_column(data_sheet, col)

        # Del NoData identifier if defined
        if null or null == 0:
            if null in values:
                values.remove(null)

        # Count occourences of a value in that column
        val_count = count_values_column_if_entity_exists(
            data_sheet, col, entities_map.keys(), values
        )

        for v in values:
            if v not in val_count:
                val_count[v] = 0

        data[column_name] = {'total' : map_dict(val_count)}

        # Do the same for each location
        locations = list(set(entities_map.values()))

        for place in locations:
            val_count = count_values_column_by_entity_property(
                data_sheet, col, place, entities_map,
                values
            )

            for v in values:
                if v not in val_count:
                    val_count[v] = 0

            data[column_name].update({place : map_dict(val_count)})

    """
    Update data dict with one combination of all keys/values data
    d.update({
        general : {
            total : {
                total   : total_count,
                value_1 : value_1_count,
                value_2 : value_2_count,
                value_n : value_n_count
            },
            location_1: {
                total   : total_count,
                value_1 : value_1_count,
                value_2 : value_2_count,
                value_n : value_n_count
            },
            location_2: {
                total   : total_count,
                value_1 : value_1_count,
                value_2 : value_2_count,
                value_n : value_n_count
            }
        }
    })
    """
    general = {}
    for col_sheet in data:
        for k in data[col_sheet]:
            if k not in general:
                general[k] = {}
                for _k in data[col_sheet][k]:
                    general[k][_k] = data[col_sheet][k][_k]
            else:
                for _k in data[col_sheet][k]:
                    if _k in general[k]:
                        general[k][_k] += data[col_sheet][k][_k]
                    else:
                        general[k][_k] = data[col_sheet][k][_k]
    data['general'] = general

    for __dict in data['general']:
        with_stats = map_dict(data['general'][__dict])
        data['general'][__dict] = with_stats

    # Write data in a new xls_file
    out_xls = xlwt.Workbook()
    for col_sheet in data:
        new_sheet = out_xls.add_sheet(col_sheet)

        if out_cols_basename:
            cols_basename = ['{b}_{_k}'.format(
                b=out_cols_basename, _k=str(k)
                ) for k in data[col_sheet]['total'].keys()]

        else:
            cols_basename = data[col_sheet]['total'].keys()

        cols_name = data[col_sheet]['total'].keys()

        cols_basename.sort()
        cols_name.sort()

        # Write columns names
        for c in range(len(cols_name)):
            new_sheet.write(0, c+1, cols_basename[c])

        # Write lines
        lnh = 1
        lines_name = data[col_sheet].keys()
        lines_name.sort()
        for line in lines_name:
            # Write line name
            new_sheet.write(lnh, 0, line)

            # Write counting data
            for cln in range(len(cols_name)):
                if cols_name[cln] in data[col_sheet][line].keys():
                    new_sheet.write(
                        lnh, cln + 1, data[col_sheet][line][cols_name[cln]]
                    )

            lnh += 1

    out_xls.save(output)

    __xls_file.release_resources()
    del __xls_file

def run_freq_by_place_by_sheet(xls, sheets_map, output_fld, null=None,
                               out_cols_basename=None, entities_filter=None,
                               cols_exclusion=None):
    """
    Execute frequencies_by_place for each group of entities and data sheets

    sheets_map should be something like this:
    sheets_map = {
        'entities_sheet_name' : {
            fid   : 'entities_field_id_name',
            place : 'entities_place_field_name',
            data  : 'data_sheet_name'
        },
        ...
    }
    """

    for entity_sheet in sheets_map:
        frequencies_by_place(
            xls, entity_sheet, sheets_map[entity_sheet]['fid'],
            sheets_map[entity_sheet]['place'],
            sheets_map[entity_sheet]['data'],
            output,
            null=null, out_cols_basename=out_cols_basename,
            entities_filter=entities_filter,
            cols_exclusion=cols_exclusion
        )

def frequencies_by_entity_attr(xls, entities_sheet, entities_id, attr_sheet,
                            interest_values, output, entities_filter=None,
                            attr_exclusion=None):
    """
    Count entities with a number of attributes with a set of specific values

    Example:
    specific_values = A, S
    Entities table:
    entity_id | some_data
    xxxxxxxx  | xxxx-xxx
    xxxxxxxx  | xxxx-xxx

    attributes_sheet:
    From tables as:
    entity | attr_1 | attr_2 | ... | attr_n
       0   |    S   |   S    | ... |   S
       1   |    A   |   B    | ... |   S
       2   |    B   |   B    | ... |   A
       3   |    S   |   A    | ... |   S
       4   |    A   |   S    | ... |   B

    We came to the following result:
    values  | entities_count | attribute_count
      S;A   |        2       |        3
      S;A   |        2       |        2
      S;A   |        1       |        1

    Filtering entities properties is possible... Many could be used...
    When many fields are used, the AND operator logic will be applied

    E.g of application:
    Number of students with a number of negatives
    """

    from glass.tbl.xls.fld import get_columns_position

    # Open file
    __xls = xlrd.open_workbook(xls, on_demand=True)

    # Map entities
    if entities_filter:
        filters = entities_filter.split(';')
        filters_map = {}
        for flt in filters:
            col_filter, val_filter = flt.split('=')
            filters_map[col_filter] = val_filter

        interest_col = [entities_id] + filters_map.keys()

    else:
        filters_map = 0
        interest_col = entities_id

    __entities_sheet = __xls.sheet_by_name(entities_sheet)
    cols_position = get_columns_position(__entities_sheet, interest_col)

    if entities_id not in cols_position:
        raise ValueError('Couldn\'t find the given column id')

    entities_map = {}
    for row in range(1, __entities_sheet.nrows):
        __id = __entities_sheet.cell(row, cols_position[entities_id]).value

        if filters_map:
            c = 0
            for col_filter in filters_map:
                __filter = __entities_sheet.cell(
                    row, cols_position[col_filter]).value

                if __filter != filters_map[col_filter]:
                    c += 1
                    break

            if c:
                continue

        entities_map[__id] = 0

    # Count occurences of the specific/interes values by entitie
    data_sheet = __xls.sheet_by_name(attr_sheet)

    interest_values = interest_values if type(interest_values) == list else \
        [interest_values] if type(interest_values) == str else 0

    if not interest_values: raise ValueError(
        'interest_values should be a list or string')

    for col in range(1, data_sheet.ncols):
        column_name = data_sheet.cell(0, col).value
        if attr_exclusion and type(attr_exclusion) == list:
            if column_name in attr_exclusion:
                continue

        for row in range(1, data_sheet.nrows):
            __id = data_sheet.cell(row, 0).value
            value = data_sheet.cell(row, col).value

            if value in interest_values:
                if __id in entities_map:
                    entities_map[__id] += 1

    # Count the number entities with the same number of occurences of the
    # interest/specific values
    occurence_count = entities_map.values()
    occurence_unique = list(set(occurence_count))

    entities_countv = {}
    for countv in occurence_unique:
        entities_count = occurence_count.count(countv)
        entities_countv[entities_count] = countv

    # Write output
    out_xls = xlwt.Workbook()
    new_sheet = out_xls.add_sheet(os.path.splitext(os.path.basename(output))[0])

    # colums
    c = ['values', 'entities_number', 'values_occurences']
    for i in range(len(c)):
        new_sheet.write(0, i, c[i])

    # values
    l = 1
    for i in entities_countv:
        new_sheet.write(l, 0, ';'.join([str(x) for x in interest_values]))
        new_sheet.write(l, 1, i)
        new_sheet.write(l, 2, entities_countv[i])
        l+=1

    out_xls.save(output)

    __xls.release_resources()
    del __xls

def frequencies_table(xls, data_sheet, output,
                           entities_sheet=None, entities_id=None,
                           entities_filter=None, values_filter=None):
    """
    Count values occurences in each attribute column

    input table:
    entity | attr_1 | attr_2 | ... | attr_n
       0   |   a    |   b    | ... |   a
       1   |   b    |   c    | ... |   b
       2   |   b    |   c    | ... |   c
       3   |   a    |   f    | ... |   d
       4   |   c    |   a    | ... |   f

    output table:
           | a | b | c | d | f |
    attr_1 | 2 | 2 | 1 | 0 | 0 |
    attr_2 | 1 | 1 | 2 | 0 | 1 |
    attr_n | 1 | 1 | 1 | 1 | 1 |

    It is possible filter entities and attribute values
    """

    from glass.tbl.xls.fld  import get_columns_position
    from glass.tbl.xls.summ import count_values_column
    from glass.tbl.xls.summ import count_values_column_if_entity_exists

    # Open file
    __xls = xlrd.open_workbook(xls, on_demand=True)

    if entities_sheet and entities_id and entities_filter:
        filters = entities_filter.split(';')
        filters_map = {}
        for flt in filters:
            col_filter, val_filter = flt.split('=')
            filters_map[col_filter] = val_filter

        __entities_sheet = __xls.sheet_by_name(entities_sheet)

        int_col = [entities_id] + filters_map.keys()
        cols_position = get_columns_position(
            __entities_sheet, int_col
        )

        entities_map = []
        for row in range(1, __entities_sheet.nrows):
            __id = __entities_sheet.cell(
                row, cols_position[entities_id]).value

            c = 0
            for col_filter in filters_map:
                __filter = __entities_sheet.cell(
                    row, cols_position[col_filter]).value

                if __filter != filters_map[col_filter]:
                    c += 1
                    break

            if c:
                continue

            entities_map.append(__id)

    else:
        entities_map = None

    attr_sheet = __xls.sheet_by_name(data_sheet)

    data = {}
    registed_values = []
    values_filter = values_filter if type(values_filter) == list else \
        [values_filter] if type(values_filter) == str else None

    for col in range(1, attr_sheet.ncols):
        col_name = attr_sheet.cell(0, col).value

        if not entities_map:
            values_count = count_values_column(attr_sheet, col, values_filter)
        else:
            values_count = count_values_column_if_entity_exists(
                attr_sheet, col, entities_map, values_filter
            )

        registed_values.extend(values_count.keys())

        data[col_name] = values_count

    registed_values = list(set(registed_values))

    # Write output
    out_xls = xlwt.Workbook()
    new_sheet = out_xls.add_sheet(
        os.path.splitext(os.path.basename(output))[0]
    )

    # columns
    for i in range(len(registed_values)):
        new_sheet.write(0, i+1, registed_values[i])

    # Write values
    r=1
    for row in data:
        new_sheet.write(r, 0, row)
        for col in range(len(registed_values)):
            if registed_values[col] in data[row]:
                new_sheet.write(r, col+1, data[row][registed_values[col]])
        r += 1

    out_xls.save(output)

    __xls.release_resources()
    del __xls