import matplotlib.pyplot as plt
import netCDF4 as nc
import numpy as np

#%matplotlib inline

x = np.arange(0, 3 * np.pi, 0.01)

y = np.sin(x)

# name of the data file
fN = '/home/ssilje/PYTHON_course/pyvis/data/co2.nc'

ncf = nc.Dataset(fN)

year = ncf.variables['year'][:]
co2 = ncf.variables['co2_annual'][:]

print(year[:3])
print(co2[:3])

#f, ax = plt.subplots()
#plt.plot(x, y)
#plt.show()
# adjusting the resolution
#f.savefig('figure_300.png', dpi=300)

f, ax = plt.subplots()
plt.plot(year, co2)
#plt.show()
# adjusting the resolution
f.savefig('figure_co2.png', dpi=300)

f, ax = plt.subplots()

ax.plot(x, y + 0, color='green')            # specify color by name
ax.plot(x, y + 1, color='b')                # color code (rgbcmyk)
ax.plot(x, y + 2, color='0.75')             # Greyscale between 0 and 1
ax.plot(x, y + 3, color='#1c9099')          # Hex code (RRGGBB from 00 to FF)
ax.plot(x, y + 4, color=(1.0,0.2,0.3))      # RGB tuple, values 0 to 1
ax.plot(x, y + 5, color=(1.0,0.2,0.3, 0.5)) # RGB tuple including alpha channel (transparency)
ax.plot(x, y + 6, color='chartreuse');      # all HTML color names supported

ax.plot(x, y + 7, color='none');            # 'none' stands for no color

f, ax = plt.subplots()

ax.plot(year, co2 + 0, color='green')            # specify color by name
ax.plot(year, co2 + 2, color='b')                # color code (rgbcmyk)
ax.plot(year, co2 + 4, color='0.75')             # Greyscale between 0 and 1
ax.plot(year, co2 + 6, color='#1c9099')          # Hex code (RRGGBB from 00 to FF)
ax.plot(year, co2 + 8, color=(1.0, 0.2, 0.3))    # RGB tuple, values 0 to 1

f, ax = plt.subplots()

ax.plot(x, x + 0, linestyle='solid')
ax.plot(x, x + 1, linestyle='dotted')
# using ls also works
ax.plot(x, x + 2, ls='dashdot')

ax.plot(x, x + 5, linestyle='-') # solid
ax.plot(x, x + 6, linestyle=':') # dotted
# using ls also works
ax.plot(x, x + 7, ls='-.') # dashdot

f, ax = plt.subplots()

ax.plot(x, np.sin(x), label='sin(x)')
ax.plot(x, np.cos(x), label='cos(x)')

# no label keyword -> no legend entry
ax.plot(x, x / 10)

ax.set_ylim(-1.1, 1.1)

ax.legend()

f, ax = plt.subplots(1, 1)

ax.plot(year, co2, color='0.1',linestyle='dotted',label='CO$_2$ concentration')
ax.set_xlabel('time [year]')
ax.set_ylabel('CO$_2$ [ppm]')
# add legend
ax.legend()
ax.set_title('Mauna Loa Weekly Atmospheric CO2 Data', fontsize=15);

ax.set_xlim(year[0], year[len(year)-1])
ax.set_ylim(min(co2), max(co2))

xtick=np.arange(year[0],year[len(year)-1],20)

#for element in ac:
#    print(element)

xticklabels = [xtick[0], xtick[1], xtick[2]]
ax.set_xticks(xtick);
ax.set_xticklabels(xticklabels);

ytick=np.arange(320,380,20)
yticklabels = [ytick[0], ytick[1], ytick[2]]
ax.set_yticks(ytick);
ax.set_yticklabels(yticklabels);

plt.show()


import time
from parlai.core.agents import create_agent_from_model_file

BS = 8
agent = create_agent_from_model_file(
        "zoo:blender/blender_1Bdistill/model", {'model_parallel': False, 'skip_generation': False}
            )

clones = [agent.clone() for _ in range(BS)]
acts = []
text = 'Hi, I am Alan.'

for i in range(100):
    start = time.time()
    acts = []
    for index in range(BS):
        acts.append(clones[index].observe({'text':text, 'episode_done': False}))
    responses = agent.batch_act(acts)

    #for i in range(BS):
    #    print(responses[i]['text'])
    print(time.time() - start)


import os, glob, pickle
import networkx as nx
import csv

DEBUG=0

def extract_with_pdb_number(G, list_nodes, list_nodes_clean, cutting_edges):
    """
    Input : - G, the graph from which we extract the pattern graph.
            - list_nodes, the list of the nodes that we want to extract using pdb format
            - list_nodes_clean, the list of the nodes that we want to extract but still as exctrated in the FR3D UNIT format, useful for labelling.
            - cutting_edges, the place where the backbone B53 is broken in the pattern that we want to extract expressed as a list of couples in [|1, n|]**2.
    Output : Twos graphs, the Gnew graph serves directly as pattern and the Gnewnx graph serves as target for research of pattern inside other patterns.
    """
    Gnew=nx.DiGraph() #Initiate the new GT graph with label from 1 to n to serve as pattern.
    Gnewnx=nx.DiGraph() #Initiate the new GT graph with label similar to the one in the RNA to serve as target.
    list_nodes_pdb = {}
    for ((i, j), t) in G.nodes.data():
        if (i, t['pdb_position']) in list_nodes: #Important to use the pdb_position here to check and not j
            list_nodes_pdb[(i, j)] = (i, t['pdb_position']) #We keep track of which pdb position correspond to which j
            index = list_nodes.index((i, t['pdb_position']))
            Gnew.add_node(index + 1, pdb_position = t['pdb_position'], atoms = t['atoms'], nt = t['nt'])
            Gnewnx.add_node(list_nodes_clean[index], pdb_position = t['pdb_position'], atoms = t['atoms'], nt = t['nt'])
    for (i,j,t) in G.edges.data():
        if i in list_nodes_pdb.keys() and j in list_nodes_pdb.keys() :
            indexi = list_nodes.index(list_nodes_pdb[i])
            indexj = list_nodes.index(list_nodes_pdb[j])
            Gnew.add_edge(indexi + 1, indexj + 1, label=t['label'], near=t['near'])
            Gnewnx.add_edge(list_nodes_clean[indexi], list_nodes_clean[indexj], label=t['label'], near=t['near'])
    for i in range(len(list_nodes) - 1):
        if (i + 1, i + 2) not in Gnew.edges() and (list_nodes[i], list_nodes[i + 1]) not in cutting_edges:
            Gnew.add_edge(i + 1, i + 2, label='B53', near=False)
            Gnewnx.add_edge(list_nodes_clean[i], list_nodes_clean[i + 1], label='B53', near=False)
    return Gnew, Gnewnx

def extract_with_pdb_number_and_gaps(G, list_nodes, list_nodes_clean, cutting_edges):
    """
    Input : - G, the graph from which we extract the pattern graph.
            - list_nodes, the list of the nodes that we want to extract using pdb format
            - list_nodes_clean, the list of the nodes that we want to extract but still as exctrated in the FR3D UNIT format, useful for labelling.
            - cutting_edges, the place where the backbone B53 is broken in the pattern that we want to extract expressed as a list of couples in [|1, n|]**2.
    Output : Twos graphs, the Gnew graph serves directly as pattern and the Gnewnx graph serves as target for research of pattern inside other patterns.
    """
    Gnew=nx.DiGraph()
    node_list = [-1]
    index = 1
    for (i, j) in list_nodes:
        k, t = [(kk,tt) for ((ii, kk), tt) in G.nodes.data() if tt['pdb_position'] == j and i == ii][0]
        Gnew.add_node(index, pdb_position = t['pdb_position'], atoms = t['atoms'], nt = t['nt'], chain = i)
        node_list.append((i, k))
        if (i, j) == list_nodes[-1]:
            iter_node = None
        elif ((i,j),list_nodes[list_nodes.index((i, j)) + 1]) in cutting_edges:
            iter_node = None
        else:
            B53_neighbors=[n for n in G.successors((i, k)) if G[(i, k)][n]['label'] == 'B53']
            if len(B53_neighbors) > 1: #It means that two backbones start from iter_node, which is not biologically admissible.
                print("THE WORLD BLOWS UP1")
            if len(B53_neighbors) == 0:
                print("THE WORLD BLOWS UP2")
            iter_node = B53_neighbors[0]
            succ1, succ2 = list_nodes[list_nodes.index((i,j)) + 1]
            succ = (succ1, int(succ2))
        index +=1
        while iter_node:
            c1, blub = iter_node
            t = [tt for (ii, tt) in G.nodes.data() if ii == iter_node][0]
            if (c1, int(t['pdb_position'])) == succ:
                iter_node = None
            else:
                Gnew.add_node(index, pdb_position = t['pdb_position'], atoms = t['atoms'], nt = t['nt'], chain = c1)
                node_list.append(iter_node)
                index +=1
                B53_neighbors=[n for n in G.successors(iter_node) if G[iter_node][n]['label'] == 'B53']
                if len(B53_neighbors) > 1: #It means that two backbones start from iter_node, which is not biologically admissible.
                    print("THE WORLD BLOWS UP3")
                if len(B53_neighbors) == 0:
                    print("THE WORLD BLOWS UP4")
                iter_node = B53_neighbors[0]
    for i in node_list:
        for j in node_list:
            potential_edge = [(ii,jj,tt) for (ii,jj,tt) in G.edges.data() if i==ii and j==jj]
            if len(potential_edge) ==  1:
                (i,j,t) = [(ii,jj,tt) for (ii,jj,tt) in G.edges.data() if i==ii and j==jj][0]
                indexi = node_list.index(i)
                indexj = node_list.index(j)
                Gnew.add_edge(indexi, indexj, label=t['label'], near=t['near'])
            elif len(potential_edge) > 1:
                print("THE WORLD BLOWS UP")
    return Gnew, Gnew

def extractor(Gpath, Gnewname, list_nodes, cutting_edges, pattern_place="kinkturnpattern/", target_place ="kinkturntarget/", list_nodes_clean = [], withgaps = 0):
    """
    Input : - Gpath, the graph path from which we extract the pattern graph.
            - Gnewname, the name for the pattern and target graphs that we are extracted
            - list_nodes, the list of the nodes that we want to extract using pdb format
            - list_nodes_clean, the list of the nodes that we want to extract but still as exctrated in the FR3D UNIT format, useful for labelling.
            - cutting_edges, the place where the backbone B53 is broken in the pattern that we want to extract expressed as a list of couples in [|1, n|]**2.
            - pattern_place and target_place, the places where respectively put the extracted pattern and target graphs.
    Output : Dump twos graphs in a pickle and nx pickle format, the Gnew graph serves directly as pattern and the Gnewnx graph serves as target for research of pattern inside other patterns.
    """
    with open(Gpath,'rb') as fG:
        G = pickle.load(fG)
        if DEBUG:
            print("Gpath", Gpath)
    if withgaps:
        Gnew, Gnewnx = extract_with_pdb_number_and_gaps(G, list_nodes, list_nodes_clean, cutting_edges)
    else:
        Gnew, Gnewnx = extract_with_pdb_number(G, list_nodes, list_nodes_clean, cutting_edges)
    if DEBUG:
        print([(i) for (i,t) in Gnew.nodes.data()])
        print([(i,j, t['label']) for (i,j,t) in Gnew.edges.data() if t['label'] != 'B53'])
        print([(i,j, t['label']) for (i,j,t) in Gnew.edges.data() if t['label'] == 'B53'])

    with open(pattern_place +Gnewname + ".pickle", 'wb') as ff:
        pickle.dump(Gnew, ff)
    with open(target_place + Gnewname + ".nxpickle", 'wb') as ff2:
        pickle.dump(Gnewnx, ff2)

def csv_parse(family_name, break_list_entry, RNAstorage = "bigRNAstorage/", csvlocation = "RNAcsv/", pattern_place="ALLkinkturnpattern/", target_place ="ALLkinkturntarget/", withgaps = 0):
    """
    Input : - family_name, the name of the family of RNA from which we extract the graphs
            - Gnewname, the name for the pattern and target graphs that we are extracted
            - break_list, a precursor for cutting_edges with a more natural numerotation
            - csvlocation, place where csv are stored.
            - pattern_place and target_place, the places where respectively put the extracted pattern and target graphs.
    Output : Extract the pattern graphs from the csv and return also the list of all mapping that we are waiting for for this family.
    """
    #break_list is the couples of nucleotides between which there is a break.
    # We consider that nucleotides are numeroted from 1 to n
    if break_list_entry == -1:
        annotated = 1
    else:
        annotated = 0
    with open(csvlocation + family_name + '.csv', newline='', encoding='utf-8') as f:
        reader = csv.reader(f)
        resu = []
        for k,prerow in enumerate(reader):
            if annotated:
                for i, e in enumerate(prerow):
                    if e != '':
                        prebreak = e.split('|')
                        stoper = i
                break_list = [int(elem) for elem in prebreak]
                row = prerow[:stoper]
            else:
                break_list = [i for (i, j) in break_list_entry]
                row = prerow
            symmetry = 0
            RNAtarget = row[0].split('|')[0]
            Gpath = RNAstorage + RNAtarget + ".nxpickle"
            list_nodes = []
            list_nodes_clean = []
            cutting_edges = []
            perfect_mapping = []
            for kk, nucleo in enumerate(row):
                explore_list = nucleo.split('|')
                if len(explore_list) > 8:
                    symmetry = 1
                if len(explore_list) > 7:
                    pdb_string = explore_list[4] + explore_list[7]
                else:
                    pdb_string = explore_list[4]
                list_nodes_clean.append((explore_list[2], int(explore_list[4])))
                list_nodes.append((explore_list[2], pdb_string))
                perfect_mapping.append((kk + 1, (explore_list[2], pdb_string)))
            if DEBUG:
                print(perfect_mapping)
            for i in break_list:
                cutting_edges.append((list_nodes[i - 1], list_nodes[i]))
            if symmetry == 0:
                extractor(Gpath, str(k) + family_name + 'into' + RNAtarget, list_nodes, cutting_edges, pattern_place=pattern_place, target_place =target_place, list_nodes_clean = list_nodes_clean, withgaps = withgaps)
                resu.append((RNAtarget, perfect_mapping))
            else:
                if DEBUG:
                    print("SKIPPED DUE TO SYMMETRY")
        return resu


import tkinter as tk
from tkinter import filedialog
import cv2
import os

# Function to perform face detection
def detect_faces(image_path):
    # Load the image
    image = cv2.imread(image_path)

    # Create a cascade classifier for face detection
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

    # Convert the image to grayscale for face detection
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Detect faces in the image
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

    # Draw rectangles around the detected faces
    for (x, y, w, h) in faces:
        cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

    # Display the image with detected faces
    cv2.imshow("Face Detection", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# Function to open a file dialog and select an image
def open_image():
    file_path = filedialog.askopenfilename(filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp")])
    if file_path:
        detect_faces(file_path)

# Create the main window
root = tk.Tk()
root.title("Face Detection")

# Create a button to open an image for face detection
open_button = tk.Button(root, text="Open Image", command=open_image)
open_button.pack(pady=10)

# Start the Tkinter event loop
root.mainloop()


from django.db import models

# Create your models here.

class Article(models.Model):
    name = models.CharField('name', max_length=200)
    text01 = models.TextField('Text', blank=True)
    is_published = models.BooleanField(name = 'is_published', default=False)
    # is_pub123 = models.NullBooleanField(name = 'Опубликовано ли')
    timestamp = models.DateTimeField(null=True)

    def __str__(self):
         return '%s' % (self.name)
         return self.text01


# app.py

"""Main application and routing logic for Vaccine R&D Dash API."""
from flask import Flask, json, jsonify, request
from flask_cors import CORS
from werkzeug.exceptions import HTTPException
from decouple import config
import os

from api.routes.image_route import fetch_images
from flask import send_file

# Logging
import logging

def create_app(test_config=None):
    """
    Creates app
    """
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        # Make sure to change debug to False in production env
        DEBUG=config('DEBUG', default=False),
        SECRET_KEY=config('SECRET_KEY', default='dev'),  # CHANGE THIS!!!!
        LOGFILE=config('LOGFILE', os.path.join(
            app.instance_path, 'logs/debug.log')),
        CACHE_TYPE=config('CACHE_TYPE', 'simple'),  # Configure caching
        # Long cache times probably ok for ML api
        CACHE_DEFAULT_TIMEOUT=config('CACHE_DEFAULT_TIMEOUT', 300),
        TESTING=config('TESTING', default='TRUE'),
    )

    # Enable CORS header support
    CORS(app)

    ##############
    ### Routes ###
    ##############
    @app.route('/', methods=['GET'])
    def home():
        return "This is an example app"

    @app.route('/image/<sid>', methods=['GET'])
    def get_image(sid: str = None, num_img: int = 1):
        if sid is None:
            raise HTTPException(400, 'Bad Request.  Must submit valid SID')
        return send_file(
            fetch_images(sid, num_img),
            mimetype='image/png')

    #############
    ###Logging###
    #############
    # Change logging.INFO to logging.DEBUG to get full logs.  Will be a crapload of information.
    # May significantly impair performance if writing logfile to disk (or network drive).
    # To enable different services, see README.md
    gunicorn_logger = logging.getLogger('gunicorn.error')
    app.logger.handlers.extend(gunicorn_logger.handlers)
    app.logger.setLevel(gunicorn_logger.level)
    app.logger.info('Application logging Set')

    # File logging. Remove in PROD
    if app.config['TESTING'] == 'TRUE':
        app.logger.info('Using TESTING log config.')
        logging.basicConfig(
            filename=app.config['LOGFILE'],
            level=logging.INFO,
            format='[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S %z')

    logging.getLogger('flask_cors').level = logging.INFO

    # Register database functions.  Will allow db.close() to run on teardown
    from db import db
    db.init_db()
    app.logger.info('Database functionality initialized.  Click commands available.')

    return app


import os
import sys
import constants
from langchain.document_loaders import DirectoryLoader, TextLoader
from langchain.indexes import VectorstoreIndexCreator
from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
from langchain.retrievers import SVMRetriever
import logging

from langchain.chat_models import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever

print(r'''
╔═╗ ╔═╗╦ ╦╔═╗╔╦╗       ╔═╗ ┬ ┬┌─┐┌─┐┌┬┐┬┌─┐┌┐┌   ┬   ╔═╗┌┐┌┌─┐┬ ┬┌─┐┬─┐
║═╬╗╠═╣╚╦╝╠═╝ ║║  ───  ║═╬╗│ │├┤ └─┐ │ ││ ││││  ┌┼─  ╠═╣│││└─┐│││├┤ ├┬┘
╚═╝╚╩ ╩ ╩ ╩  ═╩╝       ╚═╝╚└─┘└─┘└─┘ ┴ ┴└─┘┘└┘  └┘   ╩ ╩┘└┘└─┘└┴┘└─┘┴└─
╦ ╦┌─┐┬ ┬┬─┐  ╔═╗┌─┐┬─┐┌─┐┌─┐┌┐┌┌─┐┬    ╔╦╗┌─┐┌─┐┬ ┬┌┬┐┌─┐┌┐┌┌┬┐┌─┐
╚╦╝│ ││ │├┬┘  ╠═╝├┤ ├┬┘└─┐│ ││││├─┤│     ║║│ ││  │ ││││├┤ │││ │ └─┐
 ╩ └─┘└─┘┴└─  ╩  └─┘┴└─└─┘└─┘┘└┘┴ ┴┴─┘  ═╩╝└─┘└─┘└─┘┴ ┴└─┘┘└┘ ┴ └─┘

- QAYPD => Question-Answer Your Personal Documents''')

os.environ["OPENAI_API_KEY"] = constants.APIKEY

question = None
if len(sys.argv) > 1:
  question = sys.argv[1]

#Step 1. Load data
loader = DirectoryLoader('data/')
data = loader.load()

#Step 2. Split data
text_splitter = RecursiveCharacterTextSplitter(chunk_size = 500, chunk_overlap = 0)
all_splits = text_splitter.split_documents(data)

#Step 3. Store data
vectorstore = Chroma.from_documents(documents=all_splits, embedding=OpenAIEmbeddings())

#Step 4. Retrieve and Gnereate data
#Use only the tools provided to look for context to answer the the question at the end.
#If you don't find the answers in the context or don't know the answers to the user questions, truthfully say you don't know.
#Don't attempt to make up answers or hallucinate.
template = """Use the following pieces of context to answer the question at the end.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
Never give answer to the the question from out of context. Keep the answer as verbose as possible.
Keep the answer as formal as possible.
Always say "Hope you found what you were looking for!" at the end of the answer and in the next line.
{context}
Question: {question}
Helpful Answer:"""

QA_CHAIN_PROMPT = PromptTemplate.from_template(template)

# llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)
llm = ChatOpenAI(model_name="gpt-4", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
    llm,
    retriever=vectorstore.as_retriever(),
    chain_type_kwargs={"prompt": QA_CHAIN_PROMPT}
)

#querying
while True:
  if not question:
    question = input("\n-------------------------------------------------------------\n\nPROMPT: ")
  if question in ['quit', 'q', 'exit']:
    print('exited.')
    sys.exit()

  result = qa_chain({"query": question})
  print("\nGAIN: "+result["result"])

  question = None


"""
Card Atomic Species

"""
class AtomicSpecies:
    """
    Card: ATOMIC_SPECIES

    Atomic Species defines the atoms to be used in the dft calculation.
    For each line the symbol, mass, and pseudo potential to be used for the
    atom is supplied.
    """
    def __init__(self):
        self.name = "ATOMIC_SPECIES"
        self.atoms = []

    def num_atoms(self):
        """
        returns the numbers of atom types defined
        """
        return len(self.atoms)

    def add_atom_type(self, symbol, mass, pseudopot):
        """
        Add atom:
        symbol    (1-2) characters
        mass      double
        pseudopot path to pseudo potential file
        """
        atom_type = [symbol, mass, pseudopot]

        self.validate_atom_type(atom_type)
        self.atoms.append(atom_type)

    def validate_atom_type(self, atom_type):
        symbol, mass, pseudopot = atom_type

        if len(symbol) > 2:
            error_str = "Chemical Symbol 1-2 Characters [{0}]"
            raise Exception(error_str.format(symbol))

        if not isinstance(mass, float):
            error_str = "Mass {0} not of correct type double"
            raise Exception(error_str.format(mass))

        if not isinstance(pseudopot, str):
            error_str = "PsuedoPot filename {0} must be string"
            raise Exception(error_str.format(pseudopot))

    def validate(self):
        """
        Validate atoms
        """
        for atom in self.atoms:
            self.validate_atom_type(atom)

    def __str__(self):
        import pyqe.config as config

        atoms_str = "{0}\n".format(self.name)
        for atom in self.atoms:
            atoms_str += config.card_space + "{0} {1} {2}\n".format(atom[0], atom[1], atom[2])
        return atoms_str


import os

import unittest

import numpy as np

from bevodevo.tests.policies.test_mlps import TestMLPPolicy

from bevodevo.policies.cnns import ImpalaCNNPolicy

class TestImpalaCNNPolicy(unittest.TestCase):

    def setUp(self):
        self.policy = ImpalaCNNPolicy(params=None)

    def test_set_params(self):

        my_params = self.policy.get_params()

        new_params = np.random.randn(*my_params.shape)

        self.policy.set_params(new_params)
        recovered_params = self.policy.get_params()

        # some precision is lost going back and forth
        # between numpy and torch here, therefore 1e-6

        self.assertGreater(1e-6, np.abs(new_params - recovered_params).max())

        self.policy.set_params(my_params)
        recovered_params = self.policy.get_params()

        self.assertNotIn(False, my_params == recovered_params)

if __name__ == "__main__": #pragma: no cover
    unittest.main(verbosity=2)


import datetime

from django.core.mail import EmailMultiAlternatives
from django.template.loader import get_template

def get_month_name_from_number(month_number):
    """Returns the month name given a month number.
    Args:
        month_number: An integer.
    Returns:
        A string with the month name.
    """
    month = datetime.date(1900, month_number, 1).strftime("%B")
    return month

def send_account_summary_email(context):
    """Send an email with the account summary information."""
    plaintext = get_template("email.txt")
    htmly = get_template("email.html")

    subject, from_email, to = (
        "Account summary",
        "no-reply@stori.com",
        "customer@email.com",
    )
    text_content = plaintext.render(context)
    html_content = htmly.render(context)
    msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
    msg.attach_alternative(html_content, "text/html")
    msg.send()


#! /usr/bin/env python3
import anatomy
import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description='mp2rage_recon-all (requires freesurfer v7.1, CAT12 and optionally gradient_unwarp.py)')
    parser.add_argument('inv2', type=str,
                        help='path to nifti file containing MP2RAGE INV2 data')
    parser.add_argument('uni', type=str,
                        help='path to nifti file containing MP2RAGE UNI data')
    parser.add_argument('--fs_dir', type=str,
                        help='path to output fs dir')
    parser.add_argument('--spm_dir', type=str,
                        help='path to spm installation')
    parser.add_argument('--gdc_coeff_file',
                        help='run gradient disortion correction using specified coefficient file')
    args = parser.parse_args()

    if args.spm_dir is not None:
        anatomy.set_spm_path(args.spm_dir)

    anatomy.mp2rage_recon_all(args.inv2, args.uni,
                              output_fs_dir=args.fs_dir,
                              gdc_coeff_file=args.gdc_coeff_file)


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

def exo01():
	i=0
	while i <= 500:
		print("Je dois faire des sauvegardes régulières de mes fichiers.")
		i = i + 1

def exo02():
	for i in range(0,1000):
		if i % 2 != 0:
			print(i)

def exo03():
	i=0
	while i <= 10:
		print(i*13)
		i=i+1

def exo04():
	word = input("Merci de saisir un mot : ")
	print(len(word))

def exo05():
	number = int(input("Merci de saisir un nombre entier : "))
	if number % 2 != 0:
		print("Votre nombre est impair.")
	else:
		print("Votre nombre est pair.")

def exo06():
	number = int(input("Entrez un nombre entre 10 et 20 :"))
	if number < 10:
		print("Plus grand!!")
		exo06()
	if number > 20:
		print("Plus petit!!")
		exo06()
	print("ok")

def exo07():
	user_input = int(input("Entrez un nombre entier: "))
	print(range(int(user_input)+1, int(user_input)+11))

def exo08():
	nb = int(input("Entrez un nombre entier :"))
	for i in range(1,11):
		print(i , "*", nb , "=", i*nb)

def exo09():
	nombre=int(input("entrer votre nombre"))
	liste=[]
	for i in range(0,nombre+1,1):
		liste.append(i)
	print(sum(liste))

def exo10():
	nombre=int(input("entrer votre nombre : "))
	if nombre >= 6 and nombre <= 7:
		print("Vous etes poussin !")
	elif nombre >= 8 and nombre <= 9:
		print("Vous etes pupille !")
	elif nombre >= 10 and nombre <= 11:
		print("Vous etes minime !")
	elif nombre > 12:
		print("Vous etes Cadet !")

def exo11():
	i=0
	nbrArticle = int(input("Combien avez-vous d'articles ? "))
	listPriceHt = []
	while i != nbrArticle:
		i += 1
		prixHT=float(input("Combien coûte l'article ? "))
		listPriceHt.append(prixHT)

	ttc = 1.20
	total= sum(listPriceHt)

	print("Nombre d'articles : ", nbrArticle)
	print(listPriceHt)
	print("Prix HT : ", total)
	print("Prix TTC : ", ttc*total)

def exo12():
	number = int(input("entrer votre nombre : "))
	count = number
	while number > 1:
		number = number - 1
		count = count * number
	print(count)

def exo13():
	number = int(input("entrer votre nombre : "))
	binaire = []
	while number >= 1:
		modulo = int(number % 2)
		binaire.append(str(modulo))
		number = int(number / 2)
	binaire.reverse()
	print(''.join(binaire))

def exo14():
	a = 3
	somme_a = 0
	b = 5
	somme_b = 0
	while a < 1000:
		a = a + 3
		somme_a = a + somme_a
	while b < 1000:
		b = b + 5
		somme_b = b + somme_b
	print(somme_a)
	print(somme_b)

def exo15():
	a = 0
	fib = 1
	start = 0
	while a < 1500:
		a = a + 1
		n = fib + start
		start = fib
		fib = n
	print(fib)

def exo16(a = 1):
	i = 1
	while i < 5:
		if not (a/i).is_integer():
			exo16(a + 1)
		i = i + 1
	print(a)

def bubule():
	list = [4, 8, 415, 1, 25, 75, 6]
	last = True
	limit = len(list)
	while last:
		for i in range(0, limit-1):
			last = False
			if (list[i] > list[i+1]):
				list[i+1], list[i] = list[i], list[i+1]
				last = True
		limit = limit - 1
	print(list)

def insertion():
	list = [4, 8, 415, 1, 25, 75, 6]
	for i in range(1, len(list)):
		current = list[i]
		j = i
		while j > 0 and list[j - 1] > current:
			list[j] = list[j - 1]
			j = j - 1
		list[j] = current
	print(list)

def search(arr, x):
	for i in range(len(arr)):

		if arr[i] == x:
			return i

	return -1


"""
1. Отсортируйте по убыванию методом "пузырька" одномерный целочисленный массив,
заданный случайными числами на промежутке [-100; 100). Выведите на экран
исходный и отсортированный массивы.

Сортировка должна быть реализована в виде функции.

Обязательно доработайте алгоритм (сделайте его умнее).

Идея доработки: если за проход по списку не совершается ни одной сортировки,
то завершение. Обязательно сделайте замеры времени обеих реализаций
и обосновать дала ли оптимизация эффективность

Подсказка: обратите внимание, сортируем не по возрастанию, как в примере,
а по убыванию.

Сделайте выводы!!!
Опишите в чем была ваша доработка и помогла ли вам доработка??
"""

from random import randint
from timeit import timeit

lst_worst = [n for n in range(1001)]
lst_best = [n for n in reversed(range(1001))]
lst_half = [n for n in range(501)] + [n for n in reversed(range(501))]
lst_random = [randint(-100, 100) for n in range(1001)]

def rev_bubble_sort_stupid(list_to_order):
    lst = list_to_order[:]

    for i in range(len(lst)):
        for j in reversed(range(i, len(lst) - 1)):
            if lst[j + 1] > lst[j]:
                lst[j + 1], lst[j] = lst[j], lst[j + 1]
    return lst

def rev_bubble_sort_smart(list_to_order):
    lst = list_to_order[:]
    is_sorted = False

    while not is_sorted:
        for i in range(len(lst)):
            is_sorted = True
            for j in reversed(range(i, len(lst) - 1)):
                if lst[j + 1] > lst[j]:
                    lst[j + 1], lst[j] = lst[j], lst[j + 1]
                    is_sorted = False
            if is_sorted:
                break
    return lst

ncalls = 100

print('worst case:')
print('stupid: ', timeit('rev_bubble_sort_stupid(lst_worst)', globals=globals(), number=ncalls))
print('smart: ', timeit('rev_bubble_sort_smart(lst_worst)', globals=globals(), number=ncalls))

print('best case:')
print('stupid: ', timeit('rev_bubble_sort_stupid(lst_best)', globals=globals(), number=ncalls))
print('smart: ', timeit('rev_bubble_sort_smart(lst_best)', globals=globals(), number=ncalls))

print('half case:')
print('stupid: ', timeit('rev_bubble_sort_stupid(lst_half)', globals=globals(), number=ncalls))
print('smart: ', timeit('rev_bubble_sort_smart(lst_half)', globals=globals(), number=ncalls))

print('random case:')
print('stupid: ', timeit('rev_bubble_sort_stupid(lst_random)', globals=globals(), number=ncalls))
print('smart: ', timeit('rev_bubble_sort_smart(lst_random)', globals=globals(), number=ncalls))

"""
worst case:
stupid:  13.685563499999999
smart:  14.213042699999999
в худшем для пузырька случае(когда все отсортированы в обратном порядке) - что умный, что неумный пузырек одинаков

best case:
stupid:  5.3751599999999975
smart:  0.009192499999997494
в лучшем для пузырька случае(когда все уже отсортировано как надо) - умный намного быстрей (завершается после первой же итерации)

half case:
stupid:  9.615029499999999
smart:  9.8979517
в половинном случае(когда половина упорядочена в лучшую сторону, а половина в худшую сторону) - что умный, что неумный пузырек одинаков

random case:
stupid:  11.031780400000002
smart:  11.890406199999994
в случайном случае))картина как в половинном
"""

little_bad_from_left = [n for n in range(11)] + [n for n in reversed(range(991))]
little_bad_from_right = [n for n in reversed(range(991))] + [n for n in range(11)]

print('little bad from left:')
print('stupid: ', timeit('rev_bubble_sort_stupid(little_bad_from_left)', globals=globals(), number=ncalls))
print('smart: ', timeit('rev_bubble_sort_smart(little_bad_from_left)', globals=globals(), number=ncalls))

print('little bad from right:')
print('stupid: ', timeit('rev_bubble_sort_stupid(little_bad_from_right)', globals=globals(), number=ncalls))
print('smart: ', timeit('rev_bubble_sort_smart(little_bad_from_right)', globals=globals(), number=ncalls))

"""
little bad from left:
stupid:  6.57627380000001
smart:  5.513788399999996
если небольшое количество чисел неудачно отсортировано (то есть в обратном порядке) слева  -
то картина близка к лучшему случаю неумного пузырька как для умного, так и неумного

little bad from right:
stupid:  5.363130699999999
smart:  0.12614820000000293
но! если небольшое количество чисел неудачно отсортировано (то есть в обратном порядке) справа  -
то умная доработка помогает.

вывод:
умная доработка с флагом помогает, но только если нужно отсортировать маленькую часть, расположенную ближе к началу
прохода алгоритма сравнения (в нашем случае сортировка обратная, поэтому алгоритм прохода сравнения начинался справа,
то есть пузырьки тонули), поэтому если справа у нас совсем чутка неотсорировано, а остальное (слева) отсортировано - тогда БУМ!
рост производительности)))

а в среднем случае - что умная, что неумная - все O(n^2)
"""


# using generator

# def fibon(n):
#     a = b = 1
#     for i in range(n):
#         yield a
#         a, b = b, a + b
#
# for x in fibon(100):
#     print(x)

# not using generator

# def fibon(n):
#     a = b = 1
#     result = []
#     for i in range(n):
#         result.append(a)
#         a, b = b, a + b
#     return result
#
# print(fibon(100))

# to see that generator only iterates once

# def generator_function():
#     for i in range(3):
#         yield i
#
# gen = generator_function()
# print(next(gen))
# print(next(gen))
# print(next(gen))
# print(next(gen))

my_string = "Yasoob"
my_iter = iter(my_string)
print(next(my_iter))


from PyQt5 import QtGui

import math
import os
import random
import sys

class camera:
	def __init__(self, x, y, s):
		self.x = x
		self.y = y
		self.s = s

class CGOL_grid:
	def __init__(self, width, height, history):
		# This hard-coded constant gives the number of cgols frames that can be stored in each grid.
		# It can be adjusted and the program benchmarked for speed and memory usage.
		# For memory usage, it should pretty much always be a multiple of 30 because of how Python integers work.
		self.BIT_WIDTH = 30

		self.width = width
		self.height = height

		# If True, the mainloop should step the simulation once.
		self.step_queued = False

		# If true, the mainloop will resize the grid at the next opportunity
		self.resize_queued = None

		# If true, the mainloop will place the currently loaded pattern at the next opportunity.
		self.place_queued = None

		# If true, the user has opened a pattern file and is placing the pattern currently.
		self.is_placing = False

		# If set to true, a new frame has been generated and the GUI should advance one step.
		self.frame_ready = False

		# Stores patterns that are opened for writing to the grid.
		self.pattern = None

		# The history of this grid
		self.history = []
		self.history_cur = 0

		# Holds all of the grids currently in use.
		self.grids = []
		for h in range(history):
			self.grids.append([])

			for x in range(width):
				self.grids[h].append([])

				for y in range(height):
					self.grids[h][x].append(0)

		# Points to the grid that should be used to generate the next step.
		# THIS DOES NOT SIMPLY INDEX THE GRIDS ARRAY.
		# self.latest % len(grids) is the grid that should be used. self.latest // len(grids) is how many times the indexed grid should be rshifted before use.
		self.latest = 0

		# Points to the grid that is currently being rendered. This is used the same way as self.latest.
		self.current = 0

	# Appends an event to the history
	def append_event(self, e):
		if self.history_cur == len(self.history):
			self.history.append(e)
			self.history_cur+=1
		else:
			self.history[self.history_cur] = e
			self.history_cur+=1
			self.history = self.history[:self.history_cur]

	# Get the pixel at these coordinates for the current frame
	def get(self, x, y):
		ind, bit = self.get_current()
		mask = 1 << bit

		return self.grids[ind][x][y] & mask

	# Set the pixel at these coordinates for the current frame
	def set(self, x, y, record=True):
		ind, bit = self.get_current()
		mask = 1 << bit

		if record:
			val = self.get(x, y)
			if not val:
				self.append_event(("PIX", x, y, False, True))

		self.grids[ind][x][y] |= mask

	# Reset the pixel at these coordinates for the current frame
	def reset(self, x, y, record=True):
		ind, bit = self.get_current()
		mask = 1 << bit

		if record:
			val = self.get(x, y)
			if val:
				self.append_event(("PIX", x, y, True, False))

		self.grids[ind][x][y] &= ~mask

	# Flip the pixel at these coordinates for the current frame
	def flip(self, x, y, record=True):
		ind, bit = self.get_current()
		mask = 1 << bit

		if self.grids[ind][x][y] & mask:
			self.grids[ind][x][y] &= ~mask

			if record:
				self.append_event(("PIX", x, y, True, False))
		else:
			self.grids[ind][x][y] |= mask

			if record:
				self.append_event(("PIX", x, y, False, True))

	# Get the latest indexes
	def get_latest(self):
		return self.latest % len(self.grids), self.latest // len(self.grids)

	# Get the currently rendered indexes
	def get_current(self):
		return self.current % len(self.grids), self.current // len(self.grids)

	# Get the indexes of the grid we should render to.
	def get_target(self):
		next = (self.current + 1) % (len(self.grids) * self.BIT_WIDTH)
		return next % len(self.grids), next // len(self.grids)

	# Show the next grid
	def inc_current(self, record=True):
		# If we're already showing the latest frame, step the simulation.
		if (self.current == self.latest):
			self.step_queued = True

		# Otherwise, show the next frame.
		else:
			self.current = (self.current + 1) % (len(self.grids) * self.BIT_WIDTH)
			self.render_queued = True

			if record:
				self.append_event(("ADVANCE",))

	# Show the previous grid.
	def dec_current(self, record=True):
		prev = (self.current - 1) % (len(self.grids) * self.BIT_WIDTH)

		# If showing the previous grid would loop back around to showing the latest grid, don't do anything.
		if (prev == self.latest):
			return False

		self.current = prev
		self.render_queued = True

		if record:
			self.append_event(("REWIND",))

		return True

	# Undo
	def undo(self):
		print("Undo")
		if self.history_cur == 0:
			return

		e = self.history[self.history_cur-1]

		if e[0] == "PIX":
			ind, bit = self.get_current()
			mask = 1 << bit

			if e[3]:
				self.grids[ind][e[1]][e[2]] |= mask
			else:
				self.grids[ind][e[1]][e[2]] &= ~mask

		elif e[0] == "ADVANCE":
			if not self.dec_current(False):
				return

		elif e[0] == "REWIND":
			print("This should never be printed (1)")
			self.inc_current(False)

		elif e[0] == "RESIZE":
			self.resize_queued = (-e[1], -e[2], -e[3], -e[4], False)

		self.render_queued = True
		self.history_cur-=1

	def redo(self):
		print("Redo")
		if self.history_cur == len(self.history):
			self.latest = self.current
			self.inc_current()
			return

		e = self.history[self.history_cur]

		if e[0] == "PIX":
			ind, bit = self.get_current()
			mask = 1 << bit

			if e[4]:
				self.grids[ind][e[1]][e[2]] |= mask
			else:
				self.grids[ind][e[1]][e[2]] &= ~mask

		elif e[0] == "ADVANCE":
			self.inc_current(False)

		elif e[0] == "REWIND":
			print("This should never be printed (2)")
			if not self.dec_current(False):
				return

		elif e[0] == "RESIZE":
			self.resize_queued = (*e[1:], False)

		self.render_queued = True
		self.history_cur+=1

	# Set the grid that follows the currently rendered one as the latest.
	def set_next_to_latest(self):
		self.latest = (self.current + 1) % (len(self.grids) * self.BIT_WIDTH)

	# Add or remove rows and columns to the sides of the grid.
	# Also adjusts the position of the passed camera accordingly.
	def resize(self, left, top, right, bottom, record=True):
		# Error checking
		if self.width + left + right < 4 or self.height + top + bottom < 4:
			print("Aborting resize; resulting grid too small! (The limit is 4x4)")
			return

		if self.width + left + right > 512 or self.height + top + bottom > 512:
			print("Aborting resize; resulting grid too big! (The limit is 512x512)")
			return

		# Modify columns
		if left < 0:
			for g in range(len(self.grids)):
				self.grids[g] = self.grids[g][-left:]

		elif left > 0:
			for g in range(len(self.grids)):
				for i in range(left):
					self.grids[g].insert(0, [])

					for y in range(self.height):
						self.grids[g][0].append(0)

		if right < 0:
			for g in range(len(self.grids)):
				self.grids[g] = self.grids[g][:right+1]

		elif right > 0:
			for g in range(len(self.grids)):
				for i in range(right):
					self.grids[g].append([])

					for y in range(self.height):
						self.grids[g][-1].append(0)

		self.width += left + right

		# Modify rows
		if top < 0:
			for g in range(len(self.grids)):
				for x in range(self.width):
					self.grids[g][x] = self.grids[g][x][-top:]

		elif top > 0:
			for g in range(len(self.grids)):
				for x in range(self.width):
					for i in range(top):
						self.grids[g][x].insert(0, 0)
		if bottom < 0:
			for g in range(len(self.grids)):
				for x in range(self.width):
					self.grids[g][x] = self.grids[g][x][:bottom+1]

		elif bottom > 0:
			for g in range(len(self.grids)):
				for x in range(self.width):
					for i in range(bottom):
						self.grids[g][x].append(0)

		# Modify stored width and height
		self.height += top + bottom

		if record:
			self.append_event(("RESIZE", left, top, right, bottom))

		# Queue render
		self.render_queued = True

	# Fill the next grid with random data.
	def randomize(self):
		ind, bit = self.get_target()
		mask = 1 << bit

		for x in range(self.width):
			for y in range(self.height):
				if random.randint(0, 2) == 0:
					self.grids[ind][x][y] |= mask

		self.set_next_to_latest()
		self.frame_ready = True

#		print("Randomized %d (%d, %d)" % (self.latest, *self.get_latest()))

	# Fill the next grid with dead cells.
	def clear(self):
		ind, bit = self.get_target()
		mask = 1 << bit

		for x in range(len(self.grids[ind])):
			for y in range(len(self.grids[ind][0])):
				self.grids[ind][x][y] &= ~mask

		self.set_next_to_latest()
		self.frame_ready = True

#		print("Cleared %d (%d, %d)" % (self.latest, *self.get_latest()))

	# Simulates one step into the next grid. Gets a copy of is_periodic so we can change it from another thread without affecting the render.
	def step(self, window, is_periodic):
		s_ind, s_bit = self.get_current()
		d_ind, d_bit = self.get_target()

		s_mask = 1 << s_bit
		d_mask = 1 << d_bit

		d_mask_inv = ~d_mask

		# Separate loops for periodic vs finite grids helps performance
		# This is the only part of the code where performance is a serious concern.
		if is_periodic:
			# For each tile...
			for x in range(self.width):

				# In between columns, check if we should abort
				if window.is_halting:
					print("Halting simulation thread.")
					window.is_halting = False
					return

				for y in range(self.height):
					neighbors = 0

					# For each neighbor of this tile...
					for a in range(x-1, x+2):
						for b in range(y-1, y+2):
							# Don't count this cell as its own neighbor.
							if (a == x and b == y):
								continue

							# Count the neighbors
							if self.grids[s_ind][a % self.width][b % self.height] & s_mask:
								neighbors+=1

								if neighbors > 3:
									break

					# Apply CGoL rules
					if neighbors < 2 or neighbors > 3 or (neighbors == 2 and not self.grids[s_ind][x][y] & s_mask):
						self.grids[d_ind][x][y] &= d_mask_inv

					else:
						self.grids[d_ind][x][y] |= d_mask

		else:
			# For each tile...
			for x in range(self.width):

				# In between columns, check if we should abort
				if not window.is_halting:
					print("Halting simulation thread.")
					window.is_halting = False
					return

				for y in range(self.height):
					neighbors = 0

					# For each neighbor of this tile...
					for a in range(max(x-1, 0), min(x+2, self.width)):
						for b in range(max(y-1, 0), min(y+2, self.height-1)):
							# Don't count this cell as its own neighbor.
							if (a == x and b == y):
								continue

							# Count the neighbors
							if self.grids[s_ind][a % self.width][b % self.height] & s_mask:
								neighbors+=1

								if neighbors > 3:
									break

						if neighbors > 3:
							break

					# Apply CGoL rules
					if neighbors < 2 or neighbors > 3 or (neighbors == 2 and not self.grids[s_ind][x][y] & s_mask):
						self.grids[d_ind][x][y] &= d_mask_inv

					else:
						self.grids[d_ind][x][y] |= d_mask

		# Ready to render next frame
		self.set_next_to_latest()
		self.frame_ready = True

		print("Next ready at %d (%d, %d), generated from %d (%d, %d)" % (self.latest, d_ind, d_bit, self.current, s_ind, s_bit))

	# Renders using the passed camera, to the passed QPixmap
	def render(self, window, cam, elem):
		ind, bit = self.get_current()

		pix = elem.pixmap()

		print("Rendering frame %d... (%d, %d)" % (self.current, ind, bit))

		rect = pix.rect()
		w2 = rect.width() / 2 / cam.s
		h2 = rect.height() / 2 / cam.s

		# Get the range of grid squares that should be rendered
		left = cam.x - w2
		top = cam.y - h2
		right = cam.x + w2 + 1
		bottom = cam.y + h2 + 1

		painter = QtGui.QPainter(pix)

		# Clear the pixmap
		painter.fillRect(0, 0, rect.width(), rect.height(), QtGui.QColor.fromRgb(10, 10, 10))

		# Draw the grid background
		grid_l = int(0 - cam.x * cam.s + rect.width() / 2)
		grid_t = int(0 - cam.y * cam.s + rect.height() / 2)
		painter.fillRect(grid_l, grid_t, int(self.width * cam.s), int(self.height * cam.s), QtGui.QColor.fromRgb(25, 25, 25))

		# Iterate over all the squares in this range
		mask = 1 << bit
		for x in range(max(math.floor(left), 0), min(math.ceil(right), self.width)):
			for y in range(max(math.floor(top), 0), min(math.ceil(bottom), self.height)):
				if self.grids[ind][x][y] & mask:
					painter.fillRect(int((x - left) * cam.s), int((y - top) * cam.s), int(cam.s), int(cam.s), QtGui.QColor.fromRgb(230, 230, 230))

		# Render the preview
		if self.is_placing:
			pat_width = len(self.pattern)
			pat_height = len(self.pattern[0])

			x = max(math.floor(left + window.label.mouse_x / int(cam.s)), 0)
			y = max(math.floor(top + (window.label.mouse_y + 10) / int(cam.s)), 0)
			print(x, y)

			for a in range(max(-x, 0), min(min(pat_width, self.width-x), math.ceil(right)-x)):
				for b in range(max(-y, 0), min(min(pat_height, self.height-y), math.ceil(bottom))):
					if self.pattern[a][b]:
						painter.fillRect(int((x + a - left) * cam.s), int((y + b - top) * cam.s), int(cam.s), int(cam.s), QtGui.QColor.fromRgb(210, 230, 210))

		elem.update()
		painter.end()

#		elem.setPixmap(pix)

	# Copy this frame into the next frame
	def clone(self):
		s_ind, s_bit = self.get_current()
		d_ind, d_bit = self.get_target()

		s_mask = 1 << s_bit
		d_mask = 1 << d_bit

		for x in range(self.width):
			for y in range(self.height):
				if self.get(x, y):
					self.grids[d_ind][x][y] |= d_mask
				else:
					self.grids[d_ind][x][y] &= ~d_mask

	# Crops the pattern currently being displayed and saves it to a file.
	def save(self, fn):
		if os.name == "nt" and fn[0] == "/":
			fn = fn[1:]

		# Find the bounding box of the current pattern
		left = 0
		for x in range(self.width):
			has_bits = False
			for y in range(self.height):
				if self.get(x, y):
					has_bits = True
					left = x
					break

			if has_bits:
				break

		right = 0
		for x in range(self.width-1, -1, -1):
			has_bits = False
			for y in range(self.height):
				if self.get(x, y):
					has_bits = True
					right = x
					break

			if has_bits:
				break

		top = 0
		for y in range(self.height):
			has_bits = False
			for x in range(self.width):
				if self.get(x, y):
					has_bits = True
					top = y
					break

			if has_bits:
				break

		bottom = 0
		for y in range(self.height-1, -1, -1):
			has_bits = False
			for x in range(self.width):
				if self.get(x, y):
					has_bits = True
					bottom = y
					break

			if has_bits:
				break

		print("Saving (%d, %d) - (%d, %d)" % (left, top, right, bottom))

		with open(fn, "w") as fout:
			fout.write(str(right - left + 1) + " ")
			fout.write(str(bottom - top + 1) + " ")

			for y in range(top, bottom+1):
				for x in range(left, right+1):
					fout.write("1" if self.get(x, y) else "0")

	# Opens a file and stores the pattern in this program's
	def open(self, fn):
		if os.name == "nt" and fn[0] == "/":
			fn = fn[1:]

		self.pattern = []

		with open(fn, "r") as fin:
			# Get width and height
			dat = fin.read().split(" ")

			try:
				pat_width = int(dat[0])
				pat_height = int(dat[1])

			except ValueError:
				print("Aborting Open: Invalid File.")

			try:
				for x in range(pat_width):
					self.pattern.append([])

					for y in range(pat_height):
						ind = y*pat_width + x

						self.pattern[x].append(1 if dat[2][ind] == "1"  else 0)

			except IndexError:
				print("Aborting Open: Invalid File.")

		self.is_placing = True

	# Place the opened pattern onto the next grid at the given position.
	# If do_erase, this will overwrite live pixels in the grid with dead pixels in the pattern
	def place(self, x, y, do_erase):
		ind, bit = self.get_target()
		mask = 1 << bit

		pat_width = len(self.pattern)
		pat_height = len(self.pattern[0])

		self.clone()

		for a in range(max(-x, 0), min(pat_width, self.width-x)):
			for b in range(max(-y, 0), min(pat_height, self.height-y)):
				if self.pattern[a][b]:
					self.grids[ind][x+a][y+b] |= mask
				elif do_erase:
					self.grids[ind][x+a][y+b] &= ~mask

		self.set_next_to_latest()
		self.frame_ready = True


import matplotlib.pyplot as plt
import numpy as np
import nbaShotCharts as nba
import argparse

def get_nba_avg(df, basic, area, range):
    '''Returns the NBA average FG percentage for a zone
     on the court, defined by the basic, area, and range
     parameters as per stats.nba.com API. Requires pandas
     data frame with NBA Average data, like the one returned
     by nbaShotCharts.py get_league_avg method in Shots class
     '''
    result = df.loc[(
        df["SHOT_ZONE_BASIC"] == basic) & (
        df["SHOT_ZONE_AREA"] == area) & (
        df["SHOT_ZONE_RANGE"] == range),
        "FG_PCT"
    ].values

    if len(result) == 1:
        return result[0]
    else:
        raise IndexError  # replace with custom error

def two_or_three(basic):
    three_zones = [
        "Backcourt", "Above the Break 3", "Left Corner 3", "Right Corner 3"
    ]
    two_zones = [
        "In The Paint (Non-RA)", "Mid-Range", "Restricted Area"
    ]
    if basic in three_zones:
        return 3.
    elif basic in two_zones:
        return 2.
    else:
        raise IndexError  # replace with custom error

def expected_points_scored(points, avg_fg_pct):
    return points * avg_fg_pct

def expected_points_scored_row(row, avg_df):
    '''Accepts row from pandas dataframe, calls points_scored given
    necessary args from row, and returns integer result of
    expected_points_scored. avg_df is a dataframe of nba averages
    from each shot zone, obtained here from nbaShotCharts.py
    '''
    return expected_points_scored(
        points=two_or_three(row["SHOT_ZONE_BASIC"]),
        avg_fg_pct=get_nba_avg(
            df=avg_df,
            basic=row["SHOT_ZONE_BASIC"],
            area=row["SHOT_ZONE_AREA"],
            range=row["SHOT_ZONE_RANGE"]
        )
    )

def points_scored(basic, made):
    if made is 0:
        return 0.
    else:
        return two_or_three(basic)

def points_scored_row(row):
    '''Accepts row from pandas dataframe, calls points_scored given
    necessary args from row, and returns integer result of points_scored
    '''
    return points_scored(row["SHOT_ZONE_BASIC"], row["SHOT_MADE_FLAG"])

def add_points_scored(df):
    '''Returns a pandas dataframe with a new column - POINTS_SCORED -
    for each shot in the original player shot chart dataframe.
    '''
    df["POINTS_SCORED"] = df.apply(points_scored_row, axis=1)
    return df

def add_expected_points_scored(df, avg_df):
    '''Returns a pandas dataframe with a new column - EXPECTED_POINTS_SCORED -
    for each shot in the original player shot chart dataframe.
    avg_df is a dataframe of nba average from each shot zone,
    obtained here from nbaShotCharts.py
    '''
    df["EXPECTED_POINTS_SCORED"] = df.apply(
        expected_points_scored_row, axis=1, args=(avg_df,)
    )
    return df

def goldsberry(player_name, hex_gridsize=30, cmap=plt.cm.coolwarm, joint=False):
    player = nba.Shots(nba.get_player_id(player_name))
    nba_avg = player.get_league_avg()
    player_sc = add_expected_points_scored(
        add_points_scored(
            player.get_shots()
        ), nba_avg
    )

    plt.figure(figsize=(12, 11))
    nba.draw_court(outer_lines=True)

    if joint:
        pass
    else:
        nba.shot_chart(
            x=player_sc.LOC_X, y=player_sc.LOC_Y, kind="hex",
            C=np.divide(player_sc.POINTS_SCORED, player_sc.EXPECTED_POINTS_SCORED),
            hex_gridsize=hex_gridsize,
            cmap=cmap,
        )

    plt.xlim(-300, 300)
    plt.ylim(-100, 500)
    plt.show()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Create goldsberry-like nba shot charts')
    parser.add_argument(
        '--player', type=str,
        default="James, LeBron",
        help="player name in 'Last, First' format"
    )
    parser.add_argument(
        '--hex_gridsize', type=int,
        default=30,
        help="hex gridsize for matplotlib"
    )

    args = parser.parse_args()
    goldsberry(args.player)


def heartrate():
    nCases = int(input())

    for _ in range(nCases):
        inp = input().split()
        b = round(float(inp[0]), 4)
        p = round(float(inp[1]), 4)

        BPM = round(float((60*b) / p), 4)
        ABPM = round(float(60/p), 4)
        minABPM = round(BPM - ABPM, 4)
        maxABPM = round(BPM + ABPM, 4)

        print(minABPM, BPM, maxABPM)

if __name__ == '__main__':
    heartrate()


N, B = map(int, input().split())

graph = [list(map(int, input().split())) for _ in range(N)]

def mul(N, graph_a, graph_b):
    result = [[0] * N for _ in range(N)]
    for i in range(N):
        for j in range(N):
            for k in range(N):
                result[i][j] += graph_a[i][k] * graph_b[k][j]
            result[i][j] %= 1000
    return result

def cal(N, B, graph):
    if B == 1:
        return graph
    elif B == 2:
        return mul(N, graph, graph)
    else:
        sub = cal(N, B // 2, graph)
        # 제곱끼리를 한번 곱해줘야함
        if B % 2 == 0:
            return mul(N, sub, sub)
        # 홀수면 1개가 남기 때문에 곱해주기
        else:
            sub2 = mul(N, sub, sub)
            return mul(N, sub2, graph)

answer = cal(N, B, graph)

for i in answer:
    for j in i:
        print(j % 1000, end=' ')
    print()


#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# ----------------------
"""
Scraper for embedded lyrics
"""

import sys, os, re, chardet
import xml.dom.minidom as xml
from optparse import OptionParser
from common import utilities

__author__      = "Paul Harrison and 'ronin'"
__title__       = "EmbeddedLyrics"
__description__ = "Search tracks tag for embedded lyrics"
__version__     = "0.2"
__priority__    = "100"
__syncronized__ = True

debug = False

def getLyrics3(filename):
    #Get lyrics embed with Lyrics3/Lyrics3V2 format
    #See: http://id3.org/Lyrics3
    #http://id3.org/Lyrics3v2

    utilities.log(debug, "%s: trying %s" % (__title__, "lyrics embed with Lyrics3/Lyrics3V2 format"))

    f = File(filename)
    f.seek(-128-9, os.SEEK_END)
    buf = f.read(9)
    if (buf != "LYRICS200" and buf != "LYRICSEND"):
        f.seek(-9, os.SEEK_END)
        buf = f.read(9)
    if (buf == "LYRICSEND"):
        """ Find Lyrics3v1 """
        f.seek(-5100-9-11, os.SEEK_CUR)
        buf = f.read(5100+11)
        f.close();
        start = buf.find("LYRICSBEGIN")
    elif (buf == "LYRICS200"):
        """ Find Lyrics3v2 """
        f.seek(-9-6, os.SEEK_CUR)
        size = int(f.read(6))
        f.seek(-size-6, os.SEEK_CUR)
        buf = f.read(11)
        if(buf == "LYRICSBEGIN"):
            buf = f.read(size-11)
            tags=[]
            while buf!= '':
                tag = buf[:3]
                length = int(buf[3:8])
                content = buf[8:8+length]
                if (tag == 'LYR'):
                    return content
                buf = buf[8+length:]
    f.close();
    return None

def endOfString(string, utf16=False):
    if (utf16):
        pos = 0
        while True:
            pos += string[pos:].find('\x00\x00') + 1
            if (pos % 2 == 1):
                return pos - 1
    else:
        return string.find('\x00')

def ms2timestamp(ms):
    mins = "0%s" % int(ms/1000/60)
    sec = "0%s" % int((ms/1000)%60)
    msec = "0%s" % int((ms%1000)/10)
    timestamp = "[%s:%s.%s]" % (mins[-2:],sec[-2:],msec[-2:])
    return timestamp

# Uses the high level interface in taglib to find the lyrics
# should work with all the tag formats supported by taglib that can have lyrics
def getLyricsGeneric(filename):
    try:
        import taglib
    except:
        utilities.log(True, "Failed to import taglib. This grabber requires "
                            "pytaglib TagLib bindings for Python. "
                            "https://github.com/supermihi/pytaglib")
        return None

    try:
        utilities.log(debug, "%s: trying to open %s" % (__title__, filename))
        f = taglib.File(filename)

        # see if we can find a lyrics tag
        for tag in f.tags:
            if tag.startswith('LYRICS'):
                return f.tags[tag][0]

        return None
    except:
        return None

# Get USLT/SYLT/TXXX lyrics embed with ID3v2 format
# See: http://id3.org/id3v2.3.0
def getID3Lyrics(filename):
    utilities.log(debug, "%s: trying %s" % (__title__, "lyrics embed with ID3v2 format"))

    # just use the generic taglib method for now
    return getLyricsGeneric(filename)

def getFlacLyrics(filename):
    utilities.log(debug, "%s: trying %s" % (__title__, "lyrics embed with Flac format"))

    # just use the generic taglib method for now
    return getLyricsGeneric(filename)

def getMP4Lyrics(filename):
    utilities.log(debug, "%s: trying %s" % (__title__, "lyrics embed with MP4 format"))

    # just use the generic taglib method for now
    return getLyricsGeneric(filename)

class LyricsFetcher:

    def get_lyrics(self, lyrics):
        utilities.log(debug, "%s: searching lyrics for %s - %s - %s" % (__title__, lyrics.artist, lyrics.album, lyrics.title))

        filename = lyrics.filename

        ext = os.path.splitext(filename)[1].lower()
        lry = None

        try:
            if ext == '.mp3':
                lry = getLyrics3(filename)
        except:
            pass

        if lry:
            enc = chardet.detect(lry)
            lyrics.lyrics = lry.decode(enc['encoding'])
        else:
            if ext == '.mp3':
                lry = getID3Lyrics(filename)
            elif  ext == '.flac':
                lry = getFlacLyrics(filename)
            elif  ext == '.m4a':
                lry = getMP4Lyrics(filename)
            if not lry:
                return False
            lyrics.lyrics = lry

        return True

def performSelfTest():
    try:
        import taglib
    except:
        utilities.log(True, "Failed to import taglib. This grabber requires "
                            "pytaglib ? TagLib bindings for Python. "
                            "https://github.com/supermihi/pytaglib")
        sys.exit(1)

    found = False
    lyrics = utilities.Lyrics()
    lyrics.source = __title__
    lyrics.syncronized = __syncronized__
    lyrics.artist = 'Robb Benson'
    lyrics.album = 'Demo Tracks'
    lyrics.title = 'Lone Rock'
    lyrics.filename = os.path.dirname(os.path.abspath(__file__)) + '/examples/taglyrics.mp3'
    fetcher = LyricsFetcher()
    found = fetcher.get_lyrics(lyrics)

    if found:
        utilities.log(True, "Everything appears in order.")
        buildLyrics(lyrics)
        sys.exit(0)

    utilities.log(True, "The lyrics for the test search failed!")
    sys.exit(1)

def buildLyrics(lyrics):
    from lxml import etree
    xml = etree.XML(u'<lyrics></lyrics>')
    etree.SubElement(xml, "artist").text = lyrics.artist
    etree.SubElement(xml, "album").text = lyrics.album
    etree.SubElement(xml, "title").text = lyrics.title
    etree.SubElement(xml, "syncronized").text = 'True' if __syncronized__ else 'False'
    etree.SubElement(xml, "grabber").text = lyrics.source

    lines = lyrics.lyrics.splitlines()
    for line in lines:
        etree.SubElement(xml, "lyric").text = line

    utilities.log(True,  utilities.convert_etree(etree.tostring(xml, encoding='UTF-8',
                                                 pretty_print=True, xml_declaration=True)))
    sys.exit(0)

def buildVersion():
    from lxml import etree
    version = etree.XML(u'<grabber></grabber>')
    etree.SubElement(version, "name").text = __title__
    etree.SubElement(version, "author").text = __author__
    etree.SubElement(version, "command").text = 'alsong.py'
    etree.SubElement(version, "type").text = 'lyrics'
    etree.SubElement(version, "description").text = __description__
    etree.SubElement(version, "version").text = __version__
    etree.SubElement(version, "priority").text = __priority__
    etree.SubElement(version, "syncronized").text = 'True' if __syncronized__ else 'False'

    utilities.log(True,  utilities.convert_etree(etree.tostring(version, encoding='UTF-8',
                                                 pretty_print=True, xml_declaration=True)))
    sys.exit(0)

def main():
    global debug

    parser = OptionParser()

    parser.add_option('-v', "--version", action="store_true", default=False,
                      dest="version", help="Display version and author")
    parser.add_option('-t', "--test", action="store_true", default=False,
                      dest="test", help="Perform self-test for dependencies.")
    parser.add_option('-s', "--search", action="store_true", default=False,
                      dest="search", help="Search for lyrics.")
    parser.add_option('-a', "--artist", metavar="ARTIST", default=None,
                      dest="artist", help="Artist of track.")
    parser.add_option('-b', "--album", metavar="ALBUM", default=None,
                      dest="album", help="Album of track.")
    parser.add_option('-n', "--title", metavar="TITLE", default=None,
                      dest="title", help="Title of track.")
    parser.add_option('-f', "--filename", metavar="FILENAME", default=None,
                      dest="filename", help="Filename of track.")
    parser.add_option('-d', '--debug', action="store_true", default=False,
                      dest="debug", help=("Show debug messages"))

    opts, args = parser.parse_args()

    lyrics = utilities.Lyrics()
    lyrics.source = __title__
    lyrics.syncronized = __syncronized__

    if opts.debug:
        debug = True

    if opts.version:
        buildVersion()

    if opts.test:
        performSelfTest()

    if opts.artist:
        lyrics.artist = opts.artist
    if opts.album:
        lyrics.album = opts.album
    if opts.title:
        lyrics.title = opts.title
    if opts.filename:
        lyrics.filename = opts.filename

    fetcher = LyricsFetcher()
    if fetcher.get_lyrics(lyrics):
        buildLyrics(lyrics)
        sys.exit(0)
    else:
        utilities.log(True, "No lyrics found for this track")
        sys.exit(1)

if __name__ == '__main__':
    main()


"""Create a mosaic plot from a contingency table.

It allows to visualize multivariate categorical data in a rigorous
and informative way.

see the docstring of the mosaic function for more informations.
"""
# Author: Enrico Giampieri - 21 Jan 2013

from statsmodels.compat.python import lrange, lzip

from itertools import product

import numpy as np
from numpy import array, cumsum, iterable, r_
from pandas import DataFrame

from statsmodels.graphics import utils

__all__ = ["mosaic"]

def _normalize_split(proportion):
    """
    return a list of proportions of the available space given the division
    if only a number is given, it will assume a split in two pieces
    """
    if not iterable(proportion):
        if proportion == 0:
            proportion = array([0.0, 1.0])
        elif proportion >= 1:
            proportion = array([1.0, 0.0])
        elif proportion < 0:
            raise ValueError("proportions should be positive,"
                              "given value: {}".format(proportion))
        else:
            proportion = array([proportion, 1.0 - proportion])
    proportion = np.asarray(proportion, dtype=float)
    if np.any(proportion < 0):
        raise ValueError("proportions should be positive,"
                          "given value: {}".format(proportion))
    if np.allclose(proportion, 0):
        raise ValueError("at least one proportion should be "
                          "greater than zero".format(proportion))
    # ok, data are meaningful, so go on
    if len(proportion) < 2:
        return array([0.0, 1.0])
    left = r_[0, cumsum(proportion)]
    left /= left[-1] * 1.0
    return left

def _split_rect(x, y, width, height, proportion, horizontal=True, gap=0.05):
    """
    Split the given rectangle in n segments whose proportion is specified
    along the given axis if a gap is inserted, they will be separated by a
    certain amount of space, retaining the relative proportion between them
    a gap of 1 correspond to a plot that is half void and the remaining half
    space is proportionally divided among the pieces.
    """
    x, y, w, h = float(x), float(y), float(width), float(height)
    if (w < 0) or (h < 0):
        raise ValueError("dimension of the square less than"
                          "zero w={} h=()".format(w, h))
    proportions = _normalize_split(proportion)

    # extract the starting point and the dimension of each subdivision
    # in respect to the unit square
    starting = proportions[:-1]
    amplitude = proportions[1:] - starting

    # how much each extrema is going to be displaced due to gaps
    starting += gap * np.arange(len(proportions) - 1)

    # how much the squares plus the gaps are extended
    extension = starting[-1] + amplitude[-1] - starting[0]

    # normalize everything for fit again in the original dimension
    starting /= extension
    amplitude /= extension

    # bring everything to the original square
    starting = (x if horizontal else y) + starting * (w if horizontal else h)
    amplitude = amplitude * (w if horizontal else h)

    # create each 4-tuple for each new block
    results = [(s, y, a, h) if horizontal else (x, s, w, a)
                for s, a in zip(starting, amplitude)]
    return results

def _reduce_dict(count_dict, partial_key):
    """
    Make partial sum on a counter dict.
    Given a match for the beginning of the category, it will sum each value.
    """
    L = len(partial_key)
    count = sum(v for k, v in count_dict.items() if k[:L] == partial_key)
    return count

def _key_splitting(rect_dict, keys, values, key_subset, horizontal, gap):
    """
    Given a dictionary where each entry  is a rectangle, a list of key and
    value (count of elements in each category) it split each rect accordingly,
    as long as the key start with the tuple key_subset.  The other keys are
    returned without modification.
    """
    result = {}
    L = len(key_subset)
    for name, (x, y, w, h) in rect_dict.items():
        if key_subset == name[:L]:
            # split base on the values given
            divisions = _split_rect(x, y, w, h, values, horizontal, gap)
            for key, rect in zip(keys, divisions):
                result[name + (key,)] = rect
        else:
            result[name] = (x, y, w, h)
    return result

def _tuplify(obj):
    """convert an object in a tuple of strings (even if it is not iterable,
    like a single integer number, but keep the string healthy)
    """
    if np.iterable(obj) and not isinstance(obj, str):
        res = tuple(str(o) for o in obj)
    else:
        res = (str(obj),)
    return res

def _categories_level(keys):
    """use the Ordered dict to implement a simple ordered set
    return each level of each category
    [[key_1_level_1,key_2_level_1],[key_1_level_2,key_2_level_2]]
    """
    res = []
    for i in zip(*(keys)):
        tuplefied = _tuplify(i)
        res.append(list(dict([(j, None) for j in tuplefied])))
    return res

def _hierarchical_split(count_dict, horizontal=True, gap=0.05):
    """
    Split a square in a hierarchical way given a contingency table.

    Hierarchically split the unit square in alternate directions
    in proportion to the subdivision contained in the contingency table
    count_dict.  This is the function that actually perform the tiling
    for the creation of the mosaic plot.  If the gap array has been specified
    it will insert a corresponding amount of space (proportional to the
    unit length), while retaining the proportionality of the tiles.

    Parameters
    ----------
    count_dict : dict
        Dictionary containing the contingency table.
        Each category should contain a non-negative number
        with a tuple as index.  It expects that all the combination
        of keys to be represents; if that is not true, will
        automatically consider the missing values as 0
    horizontal : bool
        The starting direction of the split (by default along
        the horizontal axis)
    gap : float or array of floats
        The list of gaps to be applied on each subdivision.
        If the length of the given array is less of the number
        of subcategories (or if it's a single number) it will extend
        it with exponentially decreasing gaps

    Returns
    -------
    base_rect : dict
        A dictionary containing the result of the split.
        To each key is associated a 4-tuple of coordinates
        that are required to create the corresponding rectangle:

            0 - x position of the lower left corner
            1 - y position of the lower left corner
            2 - width of the rectangle
            3 - height of the rectangle
    """
    # this is the unit square that we are going to divide
    base_rect = dict([(tuple(), (0, 0, 1, 1))])
    # get the list of each possible value for each level
    categories_levels = _categories_level(list(count_dict.keys()))
    L = len(categories_levels)

    # recreate the gaps vector starting from an int
    if not np.iterable(gap):
        gap = [gap / 1.5 ** idx for idx in range(L)]
    # extend if it's too short
    if len(gap) < L:
        last = gap[-1]
        gap = list(*gap) + [last / 1.5 ** idx for idx in range(L)]
    # trim if it's too long
    gap = gap[:L]
    # put the count dictionay in order for the keys
    # this will allow some code simplification
    count_ordered = dict([(k, count_dict[k])
                        for k in list(product(*categories_levels))])
    for cat_idx, cat_enum in enumerate(categories_levels):
        # get the partial key up to the actual level
        base_keys = list(product(*categories_levels[:cat_idx]))
        for key in base_keys:
            # for each partial and each value calculate how many
            # observation we have in the counting dictionary
            part_count = [_reduce_dict(count_ordered, key + (partial,))
                            for partial in cat_enum]
            # reduce the gap for subsequents levels
            new_gap = gap[cat_idx]
            # split the given subkeys in the rectangle dictionary
            base_rect = _key_splitting(base_rect, cat_enum, part_count, key,
                                       horizontal, new_gap)
        horizontal = not horizontal
    return base_rect

def _single_hsv_to_rgb(hsv):
    """Transform a color from the hsv space to the rgb."""
    from matplotlib.colors import hsv_to_rgb
    return hsv_to_rgb(array(hsv).reshape(1, 1, 3)).reshape(3)

def _create_default_properties(data):
    """"Create the default properties of the mosaic given the data
    first it will varies the color hue (first category) then the color
    saturation (second category) and then the color value
    (third category).  If a fourth category is found, it will put
    decoration on the rectangle.  Does not manage more than four
    level of categories
    """
    categories_levels = _categories_level(list(data.keys()))
    Nlevels = len(categories_levels)
    # first level, the hue
    L = len(categories_levels[0])
    # hue = np.linspace(1.0, 0.0, L+1)[:-1]
    hue = np.linspace(0.0, 1.0, L + 2)[:-2]
    # second level, the saturation
    L = len(categories_levels[1]) if Nlevels > 1 else 1
    saturation = np.linspace(0.5, 1.0, L + 1)[:-1]
    # third level, the value
    L = len(categories_levels[2]) if Nlevels > 2 else 1
    value = np.linspace(0.5, 1.0, L + 1)[:-1]
    # fourth level, the hatch
    L = len(categories_levels[3]) if Nlevels > 3 else 1
    hatch = ['', '/', '-', '|', '+'][:L + 1]
    # convert in list and merge with the levels
    hue = lzip(list(hue), categories_levels[0])
    saturation = lzip(list(saturation),
                     categories_levels[1] if Nlevels > 1 else [''])
    value = lzip(list(value),
                     categories_levels[2] if Nlevels > 2 else [''])
    hatch = lzip(list(hatch),
                     categories_levels[3] if Nlevels > 3 else [''])
    # create the properties dictionary
    properties = {}
    for h, s, v, t in product(hue, saturation, value, hatch):
        hv, hn = h
        sv, sn = s
        vv, vn = v
        tv, tn = t
        level = (hn,) + ((sn,) if sn else tuple())
        level = level + ((vn,) if vn else tuple())
        level = level + ((tn,) if tn else tuple())
        hsv = array([hv, sv, vv])
        prop = {'color': _single_hsv_to_rgb(hsv), 'hatch': tv, 'lw': 0}
        properties[level] = prop
    return properties

def _normalize_data(data, index):
    """normalize the data to a dict with tuples of strings as keys
    right now it works with:

        0 - dictionary (or equivalent mappable)
        1 - pandas.Series with simple or hierarchical indexes
        2 - numpy.ndarrays
        3 - everything that can be converted to a numpy array
        4 - pandas.DataFrame (via the _normalize_dataframe function)
    """
    # if data is a dataframe we need to take a completely new road
    # before coming back here. Use the hasattr to avoid importing
    # pandas explicitly
    if hasattr(data, 'pivot') and hasattr(data, 'groupby'):
        data = _normalize_dataframe(data, index)
        index = None
    # can it be used as a dictionary?
    try:
        items = list(data.items())
    except AttributeError:
        # ok, I cannot use the data as a dictionary
        # Try to convert it to a numpy array, or die trying
        data = np.asarray(data)
        temp = {}
        for idx in np.ndindex(data.shape):
            name = tuple(i for i in idx)
            temp[name] = data[idx]
        data = temp
        items = list(data.items())
    # make all the keys a tuple, even if simple numbers
    data = dict([_tuplify(k), v] for k, v in items)
    categories_levels = _categories_level(list(data.keys()))
    # fill the void in the counting dictionary
    indexes = product(*categories_levels)
    contingency = dict([(k, data.get(k, 0)) for k in indexes])
    data = contingency
    # reorder the keys order according to the one specified by the user
    # or if the index is None convert it into a simple list
    # right now it does not do any check, but can be modified in the future
    index = lrange(len(categories_levels)) if index is None else index
    contingency = {}
    for key, value in data.items():
        new_key = tuple(key[i] for i in index)
        contingency[new_key] = value
    data = contingency
    return data

def _normalize_dataframe(dataframe, index):
    """Take a pandas DataFrame and count the element present in the
    given columns, return a hierarchical index on those columns
    """
    #groupby the given keys, extract the same columns and count the element
    # then collapse them with a mean
    data = dataframe[index].dropna()
    grouped = data.groupby(index, sort=False, observed=False)
    counted = grouped[index].count()
    averaged = counted.mean(axis=1)
    # Fill empty missing with 0, see GH5639
    averaged = averaged.fillna(0.0)
    return averaged

def _statistical_coloring(data):
    """evaluate colors from the indipendence properties of the matrix
    It will encounter problem if one category has all zeros
    """
    data = _normalize_data(data, None)
    categories_levels = _categories_level(list(data.keys()))
    Nlevels = len(categories_levels)
    total = 1.0 * sum(v for v in data.values())
    # count the proportion of observation
    # for each level that has the given name
    # at each level
    levels_count = []
    for level_idx in range(Nlevels):
        proportion = {}
        for level in categories_levels[level_idx]:
            proportion[level] = 0.0
            for key, value in data.items():
                if level == key[level_idx]:
                    proportion[level] += value
            proportion[level] /= total
        levels_count.append(proportion)
    # for each key I obtain the expected value
    # and it's standard deviation from a binomial distribution
    # under the hipothesys of independence
    expected = {}
    for key, value in data.items():
        base = 1.0
        for i, k in enumerate(key):
            base *= levels_count[i][k]
        expected[key] = base * total, np.sqrt(total * base * (1.0 - base))
    # now we have the standard deviation of distance from the
    # expected value for each tile. We create the colors from this
    sigmas = dict((k, (data[k] - m) / s) for k, (m, s) in expected.items())
    props = {}
    for key, dev in sigmas.items():
        red = 0.0 if dev < 0 else (dev / (1 + dev))
        blue = 0.0 if dev > 0 else (dev / (-1 + dev))
        green = (1.0 - red - blue) / 2.0
        hatch = 'x' if dev > 2 else 'o' if dev < -2 else ''
        props[key] = {'color': [red, green, blue], 'hatch': hatch}
    return props

def _get_position(x, w, h, W):
    if W == 0:
        return x
    return (x + w / 2.0) * w * h / W

def _create_labels(rects, horizontal, ax, rotation):
    """find the position of the label for each value of each category

    right now it supports only up to the four categories

    ax: the axis on which the label should be applied
    rotation: the rotation list for each side
    """
    categories = _categories_level(list(rects.keys()))
    if len(categories) > 4:
        msg = ("maximum of 4 level supported for axes labeling... and 4"
               "is already a lot of levels, are you sure you need them all?")
        raise ValueError(msg)
    labels = {}
    #keep it fixed as will be used a lot of times
    items = list(rects.items())
    vertical = not horizontal

    #get the axis ticks and labels locator to put the correct values!
    ax2 = ax.twinx()
    ax3 = ax.twiny()
    #this is the order of execution for horizontal disposition
    ticks_pos = [ax.set_xticks, ax.set_yticks, ax3.set_xticks, ax2.set_yticks]
    ticks_lab = [ax.set_xticklabels, ax.set_yticklabels,
                 ax3.set_xticklabels, ax2.set_yticklabels]
    #for the vertical one, rotate it by one
    if vertical:
        ticks_pos = ticks_pos[1:] + ticks_pos[:1]
        ticks_lab = ticks_lab[1:] + ticks_lab[:1]
    #clean them
    for pos, lab in zip(ticks_pos, ticks_lab):
        pos([])
        lab([])
    #for each level, for each value in the level, take the mean of all
    #the sublevel that correspond to that partial key
    for level_idx, level in enumerate(categories):
        #this dictionary keep the labels only for this level
        level_ticks = dict()
        for value in level:
            #to which level it should refer to get the preceding
            #values of labels? it's rather a tricky question...
            #this is dependent on the side. It's a very crude management
            #but I couldn't think a more general way...
            if horizontal:
                if level_idx == 3:
                    index_select = [-1, -1, -1]
                else:
                    index_select = [+0, -1, -1]
            else:
                if level_idx == 3:
                    index_select = [+0, -1, +0]
                else:
                    index_select = [-1, -1, -1]
            #now I create the base key name and append the current value
            #It will search on all the rects to find the corresponding one
            #and use them to evaluate the mean position
            basekey = tuple(categories[i][index_select[i]]
                            for i in range(level_idx))
            basekey = basekey + (value,)
            subset = dict((k, v) for k, v in items
                          if basekey == k[:level_idx + 1])
            #now I extract the center of all the tiles and make a weighted
            #mean of all these center on the area of the tile
            #this should give me the (more or less) correct position
            #of the center of the category

            vals = list(subset.values())
            W = sum(w * h for (x, y, w, h) in vals)
            x_lab = sum(_get_position(x, w, h, W) for (x, y, w, h) in vals)
            y_lab = sum(_get_position(y, h, w, W) for (x, y, w, h) in vals)
            #now base on the ordering, select which position to keep
            #needs to be written in a more general form of 4 level are enough?
            #should give also the horizontal and vertical alignment
            side = (level_idx + vertical) % 4
            level_ticks[value] = y_lab if side % 2 else x_lab
        #now we add the labels of this level to the correct axis

        ticks_pos[level_idx](list(level_ticks.values()))
        ticks_lab[level_idx](list(level_ticks.keys()),
                             rotation=rotation[level_idx])
    return labels

def mosaic(data, index=None, ax=None, horizontal=True, gap=0.005,
           properties=lambda key: None, labelizer=None,
           title='', statistic=False, axes_label=True,
           label_rotation=0.0):
    """Create a mosaic plot from a contingency table.

    It allows to visualize multivariate categorical data in a rigorous
    and informative way.

    Parameters
    ----------
    data : {dict, Series, ndarray, DataFrame}
        The contingency table that contains the data.
        Each category should contain a non-negative number
        with a tuple as index.  It expects that all the combination
        of keys to be represents; if that is not true, will
        automatically consider the missing values as 0.  The order
        of the keys will be the same as the one of insertion.
        If a dict of a Series (or any other dict like object)
        is used, it will take the keys as labels.  If a
        np.ndarray is provided, it will generate a simple
        numerical labels.
    index : list, optional
        Gives the preferred order for the category ordering. If not specified
        will default to the given order.  It does not support named indexes
        for hierarchical Series.  If a DataFrame is provided, it expects
        a list with the name of the columns.
    ax : Axes, optional
        The graph where display the mosaic. If not given, will
        create a new figure
    horizontal : bool, optional
        The starting direction of the split (by default along
        the horizontal axis)
    gap : {float, sequence[float]}
        The list of gaps to be applied on each subdivision.
        If the length of the given array is less of the number
        of subcategories (or if it's a single number) it will extend
        it with exponentially decreasing gaps
    properties : dict[str, callable], optional
        A function that for each tile in the mosaic take the key
        of the tile and returns the dictionary of properties
        of the generated Rectangle, like color, hatch or similar.
        A default properties set will be provided fot the keys whose
        color has not been defined, and will use color variation to help
        visually separates the various categories. It should return None
        to indicate that it should use the default property for the tile.
        A dictionary of the properties for each key can be passed,
        and it will be internally converted to the correct function
    labelizer : dict[str, callable], optional
        A function that generate the text to display at the center of
        each tile base on the key of that tile
    title : str, optional
        The title of the axis
    statistic : bool, optional
        If true will use a crude statistical model to give colors to the plot.
        If the tile has a constraint that is more than 2 standard deviation
        from the expected value under independence hypothesis, it will
        go from green to red (for positive deviations, blue otherwise) and
        will acquire an hatching when crosses the 3 sigma.
    axes_label : bool, optional
        Show the name of each value of each category
        on the axis (default) or hide them.
    label_rotation : {float, list[float]}
        The rotation of the axis label (if present). If a list is given
        each axis can have a different rotation

    Returns
    -------
    fig : Figure
        The figure containing the plot.
    rects : dict
        A dictionary that has the same keys of the original
        dataset, that holds a reference to the coordinates of the
        tile and the Rectangle that represent it.

    References
    ----------
    A Brief History of the Mosaic Display
        Michael Friendly, York University, Psychology Department
        Journal of Computational and Graphical Statistics, 2001

    Mosaic Displays for Loglinear Models.
        Michael Friendly, York University, Psychology Department
        Proceedings of the Statistical Graphics Section, 1992, 61-68.

    Mosaic displays for multi-way contingency tables.
        Michael Friendly, York University, Psychology Department
        Journal of the american statistical association
        March 1994, Vol. 89, No. 425, Theory and Methods

    Examples
    --------
    >>> import numpy as np
    >>> import pandas as pd
    >>> import matplotlib.pyplot as plt
    >>> from statsmodels.graphics.mosaicplot import mosaic

    The most simple use case is to take a dictionary and plot the result

    >>> data = {'a': 10, 'b': 15, 'c': 16}
    >>> mosaic(data, title='basic dictionary')
    >>> plt.show()

    A more useful example is given by a dictionary with multiple indices.
    In this case we use a wider gap to a better visual separation of the
    resulting plot

    >>> data = {('a', 'b'): 1, ('a', 'c'): 2, ('d', 'b'): 3, ('d', 'c'): 4}
    >>> mosaic(data, gap=0.05, title='complete dictionary')
    >>> plt.show()

    The same data can be given as a simple or hierarchical indexed Series

    >>> rand = np.random.random
    >>> from itertools import product
    >>> tuples = list(product(['bar', 'baz', 'foo', 'qux'], ['one', 'two']))
    >>> index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
    >>> data = pd.Series(rand(8), index=index)
    >>> mosaic(data, title='hierarchical index series')
    >>> plt.show()

    The third accepted data structure is the np array, for which a
    very simple index will be created.

    >>> rand = np.random.random
    >>> data = 1+rand((2,2))
    >>> mosaic(data, title='random non-labeled array')
    >>> plt.show()

    If you need to modify the labeling and the coloring you can give
    a function tocreate the labels and one with the graphical properties
    starting from the key tuple

    >>> data = {'a': 10, 'b': 15, 'c': 16}
    >>> props = lambda key: {'color': 'r' if 'a' in key else 'gray'}
    >>> labelizer = lambda k: {('a',): 'first', ('b',): 'second',
    ...                        ('c',): 'third'}[k]
    >>> mosaic(data, title='colored dictionary', properties=props,
    ...        labelizer=labelizer)
    >>> plt.show()

    Using a DataFrame as source, specifying the name of the columns of interest

    >>> gender = ['male', 'male', 'male', 'female', 'female', 'female']
    >>> pet = ['cat', 'dog', 'dog', 'cat', 'dog', 'cat']
    >>> data = pd.DataFrame({'gender': gender, 'pet': pet})
    >>> mosaic(data, ['pet', 'gender'], title='DataFrame as Source')
    >>> plt.show()

    .. plot :: plots/graphics_mosaicplot_mosaic.py
    """
    if isinstance(data, DataFrame) and index is None:
        raise ValueError("You must pass an index if data is a DataFrame."
                         " See examples.")

    from matplotlib.patches import Rectangle

    #from pylab import Rectangle
    fig, ax = utils.create_mpl_ax(ax)
    # normalize the data to a dict with tuple of strings as keys
    data = _normalize_data(data, index)
    # split the graph into different areas
    rects = _hierarchical_split(data, horizontal=horizontal, gap=gap)
    # if there is no specified way to create the labels
    # create a default one
    if labelizer is None:
        labelizer = lambda k: "\n".join(k)
    if statistic:
        default_props = _statistical_coloring(data)
    else:
        default_props = _create_default_properties(data)
    if isinstance(properties, dict):
        color_dict = properties
        properties = lambda key: color_dict.get(key, None)
    for k, v in rects.items():
        # create each rectangle and put a label on it
        x, y, w, h = v
        conf = properties(k)
        props = conf if conf else default_props[k]
        text = labelizer(k)
        Rect = Rectangle((x, y), w, h, label=text, **props)
        ax.add_patch(Rect)
        ax.text(x + w / 2, y + h / 2, text, ha='center',
                 va='center', size='smaller')
    #creating the labels on the axis
    #o clearing it
    if axes_label:
        if np.iterable(label_rotation):
            rotation = label_rotation
        else:
            rotation = [label_rotation] * 4
        labels = _create_labels(rects, horizontal, ax, rotation)
    else:
        ax.set_xticks([])
        ax.set_xticklabels([])
        ax.set_yticks([])
        ax.set_yticklabels([])
    ax.set_title(title)
    return fig, rects