#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Commands to carry out all the actions for uBitTool control.

This module internal functions can read any memory location from the micro:bit
via PyOCD, which uses the CMSIS interface provided by DAPLink.

The exposed function for the command line and GUI interfaces can safely read
areas of Flash (full flash, MicroPython, Python code) and UICR (to read the
customer data), and format the output into Intel Hex, a nicely decoded string
format, or human readable text (for the Python code).
"""
import os
import sys
import tempfile
import webbrowser
from io import StringIO
from threading import Timer
from difflib import HtmlDiff
from traceback import format_exc

from intelhex import IntelHex
from uflash import extract_script

from ubittool import programmer

#
# Data format conversions
#
def _bytes_to_intel_hex(data, offset=0x0000):
    """Take a list of bytes and return a string in the Intel Hex format.

    :param data: List of integers, each representing a single byte.
    :param offset: Start address offset.
    :return: A string with the Intel Hex encoded data.
    """
    i_hex = IntelHex()
    i_hex.frombytes(data, offset)

    fake_file = StringIO()
    try:
        i_hex.tofile(fake_file, format="hex")
    except IOError as e:
        sys.stderr.write("ERROR: File write: {}\n{}".format(fake_file, str(e)))
        return

    intel_hex_str = fake_file.getvalue()
    fake_file.close()
    return intel_hex_str

def _bytes_to_pretty_hex(data, offset=0x0000):
    """Convert a list of bytes to a nicely formatted ASCII decoded hex string.

    :param data: List of integers, each representing a single byte.
    :param offset: Start address offset.
    :return: A string with the formatted hex data.
    """
    i_hex = IntelHex()
    i_hex.frombytes(data, offset)

    fake_file = StringIO()
    try:
        i_hex.dump(tofile=fake_file, width=16, withpadding=False)
    except IOError as e:
        sys.stderr.write("ERROR: File write: {}\n{}".format(fake_file, str(e)))
        return

    pretty_hex_str = fake_file.getvalue()
    fake_file.close()
    return pretty_hex_str

#
# Reading data commands
#
def read_flash_hex(decode_hex=False, **kwargs):
    """Read data from the flash memory and return as a hex string.

    Read as a number of bytes of the micro:bit flash from the given address.
    Can return it in Intel Hex format or a pretty formatted and decoded hex
    string.

    :param address: Integer indicating the start address to read.
    :param count: Integer indicating hoy many bytes to read.
    :param decode_hex: True selects nice decoded format, False selects Intel
            Hex format.
    :return: String with the hex formatted as indicated.
    """
    flash_data = programmer.read_flash(**kwargs)
    if decode_hex:
        return _bytes_to_pretty_hex(
            flash_data, offset=programmer.MICROBIT_FLASH_START
        )
    else:
        return _bytes_to_intel_hex(
            flash_data, offset=programmer.MICROBIT_FLASH_START
        )

def read_uicr_customer_hex(decode_hex=False):
    """Read the UICR Customer data.

    :return: String with the nicely decoded UIR Customer area data.
    """
    uicr_data = programmer.read_uicr(
        address=programmer.UICR_CUSTOMER_START,
        count=programmer.UICR_CUSTOMER_SIZE_BYTES,
    )
    if decode_hex:
        return _bytes_to_pretty_hex(
            uicr_data, offset=programmer.UICR_CUSTOMER_START
        )
    else:
        return _bytes_to_intel_hex(
            uicr_data, offset=programmer.UICR_CUSTOMER_START
        )

def read_micropython():
    """Read the MicroPython runtime from the micro:bit flash.

    :return: String with Intel Hex format for the MicroPython runtime.
    """
    flash_data = programmer.read_flash(
        address=programmer.MICROPYTHON_START,
        count=programmer.MICROPYTHON_END - programmer.MICROPYTHON_START,
        decode_hex=False,
    )
    return _bytes_to_intel_hex(flash_data, offset=programmer.MICROPYTHON_START)

def read_python_code():
    """Read the MicroPython user code from the micro:bit flash.

    :return: String with the MicroPython code.
    """
    flash_data = programmer.read_flash(
        address=programmer.PYTHON_CODE_START,
        count=(programmer.PYTHON_CODE_END - programmer.PYTHON_CODE_START),
    )
    py_code_hex = _bytes_to_intel_hex(
        flash_data, offset=programmer.PYTHON_CODE_START
    )
    try:
        python_code = extract_script(py_code_hex)
    except Exception:
        sys.stderr.write(format_exc())
        raise Exception("Could not decode the MicroPython code from flash")
    return python_code

#
# Hex comparison commands
#
def _open_temp_html(html_str):
    """Create a temporary html file, open it in a browser and delete it.

    :param html_str: String to write to the temporary file.
    """
    fd, path = tempfile.mkstemp(suffix=".html")
    try:
        with os.fdopen(fd, "w") as tmp:
            # do stuff with temp file
            tmp.write(html_str)
        webbrowser.open("file://{}".format(os.path.realpath(path)))
    finally:
        # It can take a bit of time for the browser to open the file,
        # so wait some time before deleting it
        t = Timer(30.0, lambda del_f: os.remove(del_f), args=[path])
        t.start()

def _gen_diff_html(from_title, from_lines, to_title, to_lines):
    """Compare two strings and string of HTML code with the output.

    :param from_title: Title of the left content to compare.
    :param from_lines: List of lines to compare.
    :param to_title: Title of the right content to compare.
    :param to_lines: List of lines to compare.
    :return: String of HTML code with the comparison output.
    """
    html_template = """<!DOCTYPE html>

        <meta charset="UTF-8">
        <title>Diff {from_title} vs. {to_title}</title>

Colors

Added

Changed

Deleted

Links

(f)irst change

(n)ext change

(t)op

Files

Left: {from_title}

Right: {to_title}

        {diff_table}

    """
    differ = HtmlDiff()
    filled_template = html_template.format(
        from_title=from_title,
        to_title=to_title,
        diff_table=differ.make_table(from_lines, to_lines),
    )
    return filled_template

def compare_full_flash_hex(hex_file_path):
    """Compare the micro:bit flash contents with a hex file.

    Opens the default browser to display an HTML page with the comparison
    output.

    :param hex_file_path: File path to the hex file to compare against.
    """
    with open(hex_file_path, encoding="utf-8") as f:
        file_hex_str = f.readlines()
    flash_hex_str = read_flash_hex(decode_hex=False)

    html_code = _gen_diff_html(
        "micro:bit", flash_hex_str.splitlines(), "Hex file", file_hex_str
    )
    _open_temp_html(html_code)

def compare_uicr_customer(hex_file_path):
    """Compare the micro:bit User UICR contents with a hex file.

    Opens the default browser to display an HTML page with the comparison
    output.

    :param hex_file_path: File path to the hex file to compare against.
    """
    with open(hex_file_path, encoding="utf-8") as f:
        file_hex_str = f.readlines()
    flash_hex_str = read_uicr_customer_hex(decode_hex=False)

    html_code = _gen_diff_html(
        "micro:bit", flash_hex_str.splitlines(), "Hex file", file_hex_str
    )
    _open_temp_html(html_code)


# -*- coding: utf-8 -*-
#    Copyright (C) 2018 by
#    Marta Grobelna <marta.grobelna@rwth-aachen.de>
#    Petre Petrov <petrepp4@gmail.com>
#    Rudi Floren <rudi.floren@gmail.com>
#    Tobias Winkler <tobias.winkler1@rwth-aachen.de>
#    All rights reserved.
#    BSD license.
#
# Authors:  Marta Grobelna <marta.grobelna@rwth-aachen.de>
#           Petre Petrov <petrepp4@gmail.com>
#           Rudi Floren <rudi.floren@gmail.com>
#           Tobias Winkler <tobias.winkler1@rwth-aachen.de>

import random

import networkx as nx

from framework.generic_classes import CombinatorialClass

from planar_graph_sampler.grammar.grammar_utils import Counter
from planar_graph_sampler.combinatorial_classes.halfedge import HalfEdge

class HalfEdgeGraph(CombinatorialClass):
    """
    Base class for all different flavours of graphs that show up in the decomposition:
    Bicolored binary trees, bicolored dissections, 3-connected maps, networks, 2-connected maps, 1-connected maps.

    Combinatorically, this simply represents the class of undirected graphs with labelled vertices and unlabelled edges,
    i.e. the l-size is the number of vertices and the u-size is the number of edges.

    Parameters
    ----------
    half_edge: HalfEdge
        A half-edge in the graph.
    """

    __slots__ = 'half_edge'

    def __init__(self, half_edge):
        self.half_edge = half_edge

    # @property
    # def half_edge(self):
    #     """Returns the underlying half-edge for direct manipulation."""
    #     return self._half_edge

    @property
    def number_of_nodes(self):
        """Number of nodes in the graph."""
        return self.half_edge.get_number_of_nodes()

    @property
    def number_of_edges(self):
        """Number of edges in the graph."""
        return self.half_edge.get_number_of_edges()

    @property
    def number_of_half_edges(self):
        """Number of half-edges in the graph."""
        return len(self.half_edge.get_all_half_edges(include_unpaired=True, include_opp=True))

    def random_node_half_edge(self):
        """Returns a half-edge incident to a node chosen uniformly at random.

        This is not the same as choosing a random half-edge!
        """
        nodes = self.half_edge.node_dict()
        random_node = random.choice(list(nodes.keys()))
        return nodes[random_node][0]

    @property
    def is_consistent(self):
        """Checks invariants (for debugging)."""
        return self._check_node_nr() #and self._check_no_double_edges()
        # TODO make more checks here

    def _check_node_nr(self, visited=None):
        """Checks node_nr consistency."""
        if visited is None:
            visited = set()
        curr = self.half_edge
        visited.add(curr)
        incident = curr.incident_half_edges()
        if len(set([he.node_nr for he in incident])) > 1:
            return False
        for he in incident:
            if he.opposite is not None and he.opposite not in visited:
                if not HalfEdgeGraph(he.opposite)._check_node_nr(visited):
                    return False
        return True

    def _check_no_double_edges(self):
        # TODO
        return True

    # CombinatorialClass interface.

    @property
    def u_size(self):
        return self.number_of_edges

    @property
    def l_size(self):
        return self.number_of_nodes

    def u_atoms(self):
        raise NotImplementedError

    def l_atoms(self):
        raise NotImplementedError

    def replace_u_atoms(self, sampler, x, y, exceptions=None):
        """Maybe it's not so stupid to actually implement this here ... (same for l_subs)"""
        raise NotImplementedError

    def replace_l_atoms(self, sampler, x, y, exceptions=None):
        raise NotImplementedError

    def __str__(self):
        return "HalfEdgeGraph (Nodes: {}, Edges: {})".format(self.number_of_nodes, self.number_of_edges)

    # Networkx related functionality.

    @property
    def is_tree(self):
        return nx.is_tree(self.to_networkx_graph())

    @property
    def is_planar(self):
        return nx.check_planarity(self.to_networkx_graph())

    def is_connected(self, k=1):
        """
        Checks if the graph is k-connected.

        Parameters
        ----------
        k: int, optional (default=1)
            Check for k-connectivity.

        Returns
        -------
        bool
            True iff the graph is k-connected.
        """
        # TODO Check if this works the way intended.
        connectivity_dict = nx.k_components(self.to_networkx_graph())
        return len(connectivity_dict[k][0]) == self.number_of_nodes

    def to_planar_embedding(self):
        """Converts to nx.PlanarEmbedding.

        Returns
        -------
        PlanarEmbedding
        """
        nodes = self.half_edge.node_dict()
        embedding = nx.PlanarEmbedding()
        # Loop over all nodes in the graph (node_nr).
        for node in nodes:
            embedding.add_node(node)
            # Loop over all half-edges incident the the current node, in ccw order around the node.
            reference_neighbour = None
            for he in nodes[node]:
                if he.opposite is None:
                    continue
                embedding.add_half_edge_ccw(node, he.opposite.node_nr, reference_neighbour)
                reference_neighbour = he.opposite.node_nr
        return embedding

    def to_networkx_graph(self, include_unpaired=False):
        """Transforms the graph into a networkx graph.

        Parameters
        ----------
        include_unpaired: bool, optional (default=False)
            Includes half-edges that do not have an opposite.
            In this case, a new node is created and connected to the unpaired half-edge.
        """
        # Get the counter in case we have to create nodes for unpaired half-edges.
        counter = Counter()
        # If this graph consists of only unpaired half-edge which share the same node we interpret this as the one-node graph.
        if self.half_edge.get_number_of_nodes() == 1:
            G = nx.Graph()
            if self.half_edge.node_nr is None:
                self.half_edge.node_nr = next(counter)
            G.add_node(self.half_edge.node_nr)
            return G
        # Get all edges (one half-edge per edge).
        half_edges = self.half_edge.get_all_half_edges(include_opp=False, include_unpaired=include_unpaired)
        G = nx.Graph()
        while len(half_edges) > 0:
            half_edge = half_edges.pop()
            if half_edge.opposite is not None:
                G.add_edge(half_edge.node_nr, half_edge.opposite.node_nr)
            else:
                G.add_edge(half_edge.node_nr, next(counter))
        # G = nx.relabel.convert_node_labels_to_integers(G)
        return G

    def plot(self, **kwargs):
        """Plots the graph.

        Parameters
        ----------
        G: networkx.Graph

        """
        G = None
        with_labels = False
        use_planar_drawer = False
        node_size = 100
        if 'G' in kwargs:
            G = kwargs['G']
        if 'with_labels' in kwargs:
            with_labels = kwargs['with_labels']
        if 'use_planar_drawer' in kwargs:
            use_planar_drawer = kwargs['use_planar_drawer']
        if 'node_size' in kwargs:
            node_size = kwargs['node_size']

        if G is None:
            G = self.to_networkx_graph()
        # Generate planar embedding or use default algorithm.
        pos = None
        if use_planar_drawer:
            emb = self.to_planar_embedding()
            pos = nx.combinatorial_embedding_to_pos(emb, fully_triangulate=False)
        # Take color attributes on the nodes into account.
        colors = nx.get_node_attributes(G, 'color').values()
        if len(colors) == G.number_of_nodes():
            nx.draw(G, pos=pos, with_labels=with_labels, node_color=list(colors), node_size=node_size)
        else:
            nx.draw(G, pos=pos, with_labels=with_labels, node_size=node_size)

def color_scale(hex_str, factor):
    """Scales a hex string by ``factor``. Returns scaled hex string."""
    hex_str = hex_str.strip('#')
    if factor < 0 or len(hex_str) != 6:
        return hex_str
    r, g, b = int(hex_str[:2], 16), int(hex_str[2:4], 16), int(hex_str[4:], 16)

    def clamp(val, min=0, max=255):
        if val < min:
            return min
        if val > max:
            return max
        return int(val)

    r = clamp(r * factor)
    g = clamp(g * factor)
    b = clamp(b * factor)

    return "#%02x%02x%02x" % (r, g, b)


"""add color to case statuses

Revision ID: a0a6f383a912
Revises: a44e24fa6b99
Create Date: 2020-11-24 19:17:50.275334

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = 'a0a6f383a912'
down_revision = 'a44e24fa6b99'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('case_statuses', sa.Column('color', sa.String(length=16), nullable=True))
    op.add_column('case_statuses', sa.Column('is_final', sa.Boolean(), nullable=True))
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('case_statuses', 'is_final')
    op.drop_column('case_statuses', 'color')
    # ### end Alembic commands ###


#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import wsgiref.handlers
from xml.dom import minidom
from google.appengine.ext.webapp import template
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.api import urlfetch

BASE_URL = "http://twiliotourist.appspot.com"

class TriviaPage(webapp.RequestHandler):
	"""
	Accepts value from the caller, fetches the factoid.
	"""

	def get(self):
		self.post()

	def _error(self, msg, redirecturl=None):
		# NEED TO ADDRESS
		# ERROR HANDLING
		template_values = {
			'msg': msg,
			'redirecturl': redirecturl
		}
		xml_response(self, 'error.xml', templatevalues)

	def post(self):
		factoid_num = self.request.get('Digits')
		# this just handles errors for no factoid, what if there is a wrong num?
		if not factoid_num:
			self._error("Wrong number factoid.", BASE_URL)
			return

		factoid_num = factoid_num.replace('#', '').replace('*', '')[:1]

		if not int(factoid_num) == 1 and not int(factoid_num) == 2:
			if int(factoid_num) % 2 == 0:
				factoid_num = '2'
			else:
				factoid_num = '1'

		factoid = '/scenes/scene' + factoid_num + '.wav'
		template_values = {'factoid' : factoid}

		try:
			xml_response(self, 'factoid.xml', template_values)
		except:
			self._error('Error parsing digits. Goodbye.')
		#@end snippet

def xml_response(handler, page, templatevalues=None):
	"""
	Renders an XML response using a provided template page and values
	"""
	path = os.path.join(os.path.dirname(__file__), page)
	handler.response.headers["Content-Type"] = "text/xml"
	handler.response.out.write(template.render(path, templatevalues))

class GatherPage(webapp.RequestHandler):
	"""
	Initial user greeting.  Plays the welcome audio file then reads the
	"enter zip code" message.  The Play and Say are wrapped in a Gather
	verb to collect the 5 digit zip code from the caller.  The Gather
	will post the results to /weather
	"""
	def get(self):
		self.post()

	def post(self):
		templatevalues = {
			'postprefix': BASE_URL,
		}
		xml_response(self, 'gather.xml', templatevalues)
# @end snippet

def main():
    application = webapp.WSGIApplication([('/', GatherPage),
							('/fact', TriviaPage)],
                                         debug=True)
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
    main()


import configparser
import csv
import tensorflow as tf
import glob
from tensorflow.io import decode_png
import tensorflow.keras.backend as K
import numpy as np

config = configparser.RawConfigParser()
config.read('configuration.txt')

PATCH_SIZE = (
    int(config.get('data attributes', 'patch_height')),
    int(config.get('data attributes', 'patch_width'))
)

def load_testset(filepath, batch_size):
    # This works with arrays as well
    dataset = tf.data.TFRecordDataset(glob.glob(filepath))

    # Maps the parser on every filepath in the array. You can set the number of parallel loaders here
    return dataset.map(_parse_function, num_parallel_calls=8) \
        .map(normalize, num_parallel_calls=8) \
        .batch(batch_size, drop_remainder=True) \
        .repeat()

def load_trainset(filepath, batch_size, N_imgs):
    dataset = tf.data.TFRecordDataset(glob.glob(filepath))

    # Set the number of datapoints you want to load and shuffle
    # do not reshuffle each iteration
    print('total samples:')
    print(N_imgs)
    dataset = dataset.shuffle(250000)

    # Maps the parser on every filepath in the array. You can set the number of parallel loaders here
    dataset = dataset.map(_parse_function, num_parallel_calls=8) \
        .map(normalize, num_parallel_calls=8)

    #split in testing and training
    test_data = dataset.take(int(N_imgs / 10)) \
        .batch(batch_size, drop_remainder=True) \
        .repeat()

    train_data = dataset.skip(int(N_imgs / 10)) \
        .batch(batch_size, drop_remainder=True) \
        .repeat()

    return test_data, train_data

def load_images_labels(filepath, batch_size, N_imgs):
    _, train_data = load_trainset(filepath, batch_size, N_imgs)

    # Create an iterator
    iterator = train_data.make_one_shot_iterator()

    # Create your tf representation of the iterator
    image, label = iterator.get_next()

    return image, label

# ================================ HELPER =======================================
def normalize(image, label):
    # image = (image - MEAN) / STD
    image = tf.cast(image, tf.float32) / 255. * 6. - 3.    # normalize to [-3, 3]
    label = tf.cast(label, tf.float32) / 255.         # label from 0 - 1

    foreground = tf.cast(label > 0.2, tf.float32)
    bkgrnd = 1 - foreground
    label = tf.concat([bkgrnd, foreground], 0)

    assert_max_label = tf.Assert(tf.less_equal(tf.reduce_max(label), 1.), [label])
    assert_max_image = tf.Assert(tf.less_equal(tf.reduce_max(image), 3.), [image])
    assert_min_label = tf.Assert(tf.greater_equal(tf.reduce_min(label), 0.), [label])
    assert_min_image = tf.Assert(tf.greater_equal(tf.reduce_min(image), -3.), [image])
    with tf.control_dependencies([
        assert_max_label,
        assert_max_image,
        assert_min_label,
        assert_min_image
    ]):
        return image, label

def _parse_function(proto):
    global PATCH_SIZE
    # define your tfrecord again. Remember that you saved your image as a string.
    keys_to_features = {'image': tf.FixedLenFeature([], tf.string),
                        'label': tf.FixedLenFeature([], tf.string)}

    # Load one example
    parsed_features = tf.parse_single_example(proto, keys_to_features)

    # Turn your saved image string into an array
    image = decode_png(parsed_features['image'])
    label = decode_png(parsed_features['label'])

    # Bring your picture back in shape
    image = tf.reshape(image, [1, PATCH_SIZE[0], PATCH_SIZE[1]])
    label = tf.reshape(label, [1, PATCH_SIZE[0], PATCH_SIZE[1]])

    return image, label


import os

import pytest
from selenium import webdriver

from testcontainers.compose import DockerCompose
from testcontainers.core.exceptions import NoSuchPortExposed

def test_can_spawn_service_via_compose():
    compose = DockerCompose(os.path.dirname(__file__))

    try:
        compose.start()
        host = compose.get_service_host("hub", 4444)
        port = compose.get_service_port("hub", 4444)
        assert host == "0.0.0.0"
        assert port == "4444"
    finally:
        compose.stop()

def test_can_throw_exception_if_no_port_exposed():
    compose = DockerCompose(os.path.dirname(__file__))

    compose.start()
    with pytest.raises(NoSuchPortExposed):
        compose.get_service_host("hub", 5555)

    compose.stop()

def test_compose_wait_for_container_ready():
    compose = DockerCompose(os.path.dirname(__file__))
    with compose:
        compose.wait_for("http://localhost:4444/wd/hub")


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

import sys
sys.path.append('../')

import os
import scipy.io as sio
import numpy as np
from HSMMIm3.HSMM import CHSMMModel

def getHSMM(path, num_th, flag):
    if flag == 3:
        HSMM = getHSMMIm3(path, num_th)

    return HSMM

def getHSMMIm3(path, num_th):

    filename = os.path.join(path, 'HSMM_a%d.mat' % num_th)
    a = sio.loadmat(filename)['a']

    filename = os.path.join(path, 'HSMM_b%d.mat' % num_th)
    b = sio.loadmat(filename)['b']

    filename = os.path.join(path, 'HSMM_BerlliB%d.mat' % num_th)
    B = sio.loadmat(filename)['B']

    filename = os.path.join(path, 'HSMM_BerlliC%d.mat' % num_th)
    C = sio.loadmat(filename)['C']

    filename = os.path.join(path, 'HSMM_Init%d.mat' % num_th)
    Init = sio.loadmat(filename)['Init']

    filename = os.path.join(path, 'HSMM_Trans%d.mat' % num_th)
    Trans = sio.loadmat(filename)['Trans']

    filename = os.path.join(path, 'HSMM_Theta%d.mat' % num_th)
    Theta = sio.loadmat(filename)['Theta']

    filename = os.path.join(path, 'HSMM_DurationProbs%d.mat' % num_th)
    DurationProbs = sio.loadmat(filename)['DurationProbs']

    hidden_num = Init.shape[0]
    item_num = Theta.shape[1]
    DurationMax = DurationProbs.shape[1]

    HSMM = CHSMMModel(hidden_num, item_num, DurationMax)
    HSMM.a = a
    HSMM.b = b
    HSMM.B = B
    HSMM.C = C
    HSMM.InitProbs = Init[:, 0]
    HSMM.TransProbs = Trans
    HSMM.Theta = Theta
    HSMM.DurationProbs = DurationProbs
    return HSMM


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

"""
Update HTPC Manager from Github. Either through git command or tarball.

Updater and SourceUpdater written by styxit
https://github.com/styxit

Git updater written by mbw2001
https://github.com/mbw2001

Used as reference:
- https://github.com/mrkipling/maraschino
- https://github.com/midgetspy/Sick-Beard/
"""
import os
import time
from threading import Thread
import urllib.request, urllib.parse, urllib.error
import subprocess
import re
from json import loads
import cherrypy
import htpc
import logging
import tarfile
import shutil
import platform
from apscheduler.triggers.interval import IntervalTrigger
from htpc.root import do_restart

# configure git repo
gitUser = 'Hellowlol'
gitRepo = 'HTPC-Manager'

class Updater(object):
    """ Main class """
    def __init__(self):
        self.logger = logging.getLogger('htpc.updater')
        self.updateEngineName = 'Unknown'
        # Set update engine. Use git updater or update from source.
        self.updateEngine = self.getEngine()
        htpc.CURRENT_HASH = self.updateEngine.current()
        htpc.BRANCH = self.updateEngine.current_branch_name()
        htpc.UPDATERTYPE = self.updateEngineName
        # Check for updates automatically
        htpc.SCHED.add_job(self.update_needed, trigger=IntervalTrigger(hours=6))

    """ Determine the update method """
    def getEngine(self):
        self.logger.debug("Selecting Update engine.")
        gitDir = os.path.normcase(os.path.join(htpc.RUNDIR, '.git'))
        validGitDir = os.path.isdir(gitDir)

        # If valid Git dir and git command succeeded, use Git updater
        if validGitDir and self.test_git():
            self.logger.info('Using GitUpdater engine')
            self.updateEngineName = 'Git'
            return GitUpdater()
        else:  # Otherwise update from Sourece
            self.logger.info('Using SourceUpdater engine')
            self.updateEngineName = 'Source'
            return SourceUpdater()

    def test_git(self):
        self.logger.debug("Checking if git is installed")
        gp = htpc.settings.get('git_path', 'git')
        alternative_gp = []

        # osx people who start htpc-mamanger from launchd have a broken path, so try a hail-mary attempt for them
        if platform.system().lower() == 'darwin':
            alternative_gp.append('/usr/local/git/bin/git')
        if platform.system().lower() == 'windows':
            if gp != gp.lower():
                alternative_gp.append(gp.lower())
            # Disable this if dev as it would be impossible
            # to teste the source updater
            if not htpc.DEV:
                alternative_gp += ["%USERPROFILE%\AppData\Local\GitHub\PORTAB~1\bin\git.exe", "C:\Program Files (x86)\Git\bin\git.exe"]
        # Returns a empty string if failed
        output = GitUpdater().git_exec(gp, 'version')
        self.logger.debug("Found git path %s" % gp)

        if output:
            # Found a working git path.
            self.logger.debug("Found git path %s" % gp)
            htpc.settings.set('git_path', gp)
            return True

        if alternative_gp and not output:
            self.logger.debug("Checking for alternate git location")
            for current_gp in alternative_gp:
                self.logger.debug("Testing git path %s" % current_gp)
                output = GitUpdater().git_exec(current_gp, 'version')
                if output:
                    self.logger.debug("Found git path %s and it works!" % current_gp)
                    self.logger.debug("Saving git path %s to settings" % current_gp)
                    htpc.settings.set('git_path', current_gp)
                    return True

        return False

    @cherrypy.expose()
    @cherrypy.tools.json_out()
    def index(self, force=False):
        """ Update on POST. Check for new updates on GET. """
        if cherrypy.request.method.upper() == 'POST':
            Thread(target=self.updateEngine.update).start()
            return 1
        if cherrypy.request.method.upper() == 'POST' and force:
            self.check_update()
            Thread(target=self.updateEngine.update).start()
            return 1
        else:
            return self.check_update()

    @cherrypy.expose()
    @cherrypy.tools.json_out()
    def updatenow(self):
        Thread(target=self.updateEngine.update).start()

    @cherrypy.expose()
    @cherrypy.tools.json_out()
    def status(self):
        """ method to determine if HTPC Manager is currently updating """
        return self.updateEngine.UPDATING

    def check_update(self):
        """
        Check for updates

        Returns dict() with the following indexes:

        UpdateNeeded    True if an update is needed, False if an update is not needed OR not possible
        latestVersion   Commit hash of the most recent commit
        currentVersion  Commit hash for the version currently in use
        versionsBehind  How many versions is the current version behind the latest version
        """
        output = {'updateNeeded': True, 'latestVersion': 'Unknown', 'currentVersion': 'Unknown', 'versionsBehind': 'Unknown'}

        self.logger.info("Checking for updates from %s." % self.updateEngineName)

        # Get current and latest version
        # current can return True, False, Unknown, and SHA
        current = self.updateEngine.current()
        htpc.CURRENT_HASH = current
        # Can return True, False
        latest = self.updateEngine.latest()
        htpc.LATEST_HASH = latest
        self.logger.debug("Latest commit is %s" % latest)
        self.logger.debug("Current commit is %s" % current)

        if latest is False:
            self.logger.error("Failed to determine the latest version for HTPC Manager.")
        else:
            output['latestVersion'] = latest

        if current is False:
            self.logger.error("Failed to determine the current version for HTPC Manager.")
        else:
            output['currentVersion'] = current

        # If current or latest failed, updating is not possible
        if current is False or latest is False:
            self.logger.debug("Cancel update.")
            output['updateNeeded'] = False
            return output

        # If HTPC Manager is up to date, updating is not needed
        if current == latest and current != "Unknown":
            self.logger.info("HTPC Manager is Up-To-Date.")
            output['versionsBehind'] = 0
            htpc.COMMITS_BEHIND = 0
            output['updateNeeded'] = False
        else:
            behind = self.behind_by(current, latest)
            htpc.COMMITS_BEHIND = behind
            output['versionsBehind'] = behind

        self.logger.info("Currently " + str(output['versionsBehind']) + " commits behind.")
        return output

    def behind_by(self, current, latest):
        """ Check how many commits between current and latest """
        self.logger.debug('Checking how far behind latest')
        try:
            url = 'https://api.github.com/repos/%s/%s/compare/%s...%s' % (gitUser, gitRepo, current, latest)
            result = loads(urllib.request.urlopen(url).read())
            behind = int(result['total_commits'])
            self.logger.debug('Behind: ' + str(behind))
            return behind
        except Exception as e:
            self.logger.error(str(e))
            self.logger.error('Could not determine how far behind')
            return 'Unknown'

    @cherrypy.expose()
    @cherrypy.tools.json_out()
    def branches(self):
        return self.updateEngine.branches()

    def update_needed(self):
        self.logger.info("Running update_needed")
        update_avail = self.check_update()
        # returns true or false
        if update_avail.get("updateNeeded"):
            if htpc.settings.get('app_check_for_updates', False):
                self.logger.debug("Add update footer")
                # Used for the notification footer
                htpc.UPDATE_AVAIL = True
        else:
            htpc.UPDATE_AVAIL = False
        # Since im stupid, protect me please.. srsly its for myself.
        if htpc.UPDATE_AVAIL and htpc.settings.get("app_auto_update", False) and not htpc.DEV:
            self.logger.debug("Auto updating now!")
            Thread(target=self.updateEngine.update).start()

class GitUpdater(object):
    """ Class to update HTPC Manager using git commands. """

    def __init__(self):
        """ Set GitHub settings on load. """
        self.UPDATING = 0
        self.git = htpc.settings.get('git_path', 'git')
        self.logger = logging.getLogger('htpc.updater')
        #self.update_remote_origin() # Disable this since it a fork for now.

    def update_remote_origin(self):
        self.git_exec(self.git, 'config remote.origin.url https://github.com/Hellowlol/HTPC-Manager.git')

    def current_branch_name(self):
        output = self.git_exec(self.git, 'rev-parse --abbrev-ref HEAD')
        if output:
            return output
        else:
            return htpc.settings.get('branch', 'master2')

    def latest(self):
        """ Get hash of latest commit on github. """
        self.logger.debug('Getting latest version from github.')
        try:
            url = 'https://api.github.com/repos/%s/%s/commits/%s' % (gitUser, gitRepo, self.current_branch_name())
            result = loads(urllib.request.urlopen(url).read())
            latest = result['sha'].strip()
            self.logger.debug('Branch: %s' % self.current_branch_name())
            self.logger.debug('Latest sha: %s' % latest)
            self.latestHash = latest
            return latest
        except Exception as e:
            self.logger.error("Failed to get last commit from github %s" % e)
            return False

    def current(self):
        """ Get hash of current Git commit. """
        self.logger.debug('Getting current version.')
        output = self.git_exec(self.git, 'rev-parse HEAD')
        self.logger.debug('Current version: ' + output)

        if not output:
            self.logger.error('Couldnt determine installed branch.')
            return False

        if re.match('^[a-z0-9]+$', output):
            return output

    def branches(self):
        cbn = self.current_branch_name()

        d = {
            "branch": cbn,
            "branches": []
        }

        if self.current is not False:
            d["verified"] = True
        else:
            # If its false, default to master branch
            d["branch"] = htpc.settings.get('branch', 'master2')

        branches = self.git_exec(self.git, 'ls-remote --heads https://github.com/Hellowlol/HTPC-Manager.git')
        if branches:
            # find all branches except the current branch.
            d["branches"] = [b for b in re.findall('\S+\Wrefs/heads/(.*)', branches) if b != cbn]
            return d
        return [d]

    def update(self):
        """ Do update through git. """

        self.logger.info("Attempting update through Git.")
        self.UPDATING = 1

        if htpc.settings.get('branch', 'master2') == self.current_branch_name():
            output = self.git_exec(self.git, 'pull origin %s' % htpc.settings.get('branch', 'master2'))
        else:
            output = self.git_exec(self.git, 'checkout -f ' + htpc.settings.get('branch', 'master2'))
        if not output:
            self.logger.error("Unable to update through git. Make sure that Git is located in your path and can be accessed by this application.")
        elif 'Aborting.' in output:
            self.logger.error("Update aborted.")
        else:
            if htpc.settings.get('git_cleanup') and not htpc.DEV:
                self.logger.debug("Clean up after git")
                self.git_exec(self.git, 'reset --hard')
                # Note to self: rtfm before you run git commands, just wiped the data dir...
                # This command removes all untracked files and files and the files in .gitignore
                # except from the content of htpc.DATADIR and VERSION.txt
                self.git_exec(self.git, 'clean -d -fx -e %s -e VERSION.txt -e userdata/' % htpc.DATADIR)
            self.logger.warning('Restarting HTPC Manager after update.')
            htpc.settings.set('app_updated_at', str(time.time()))
            # Restart HTPC Manager to make sure all new code is loaded
            do_restart()

        self.UPDATING = 0

    def git_exec(self, gp, args):
        """ Tool for running git program on system. """

        try:
            proc = subprocess.Popen(gp + " " + args, stdout=subprocess.PIPE,
                                    stderr=subprocess.STDOUT, shell=True, cwd=htpc.RUNDIR, universal_newlines=True)
            output, err = proc.communicate()
            exitcode = proc.returncode

            self.logger.debug("Running %s %s" % (gp, args))
        except OSError as e:
            self.logger.warning(str(e))
            return ''

        if exitcode > 0:
            self.logger.warning('%s -  %s' % (output, err))
            return ''

        if err:
            self.logger.warning(output + ' - ' + err)
            return ''

        if any(s in output for s in ['not found', 'not recognized', 'fatal:']):
            self.logger.warning(output)
            return ''
        if output and exitcode == 0:
            return output.strip()

class SourceUpdater(object):
    """ Class to update HTPC Manager using Source code from Github. Requires a full download on every update."""
    def __init__(self):
        self.UPDATING = 0
        self.currentHash = False
        self.verified = False
        self.logger = logging.getLogger('htpc.updater')
        self.versionFile = os.path.join(htpc.RUNDIR, 'VERSION.txt')
        self.updateFile = os.path.join(htpc.DATADIR, 'htpc-manager-update.tar.gz')
        self.updateDir = os.path.join(htpc.DATADIR, 'update-source')

    def current(self):
        """ Get hash of current runnig version """
        self.logger.debug('Getting current version.')

        # Check if version file exists
        if not os.path.isfile(self.versionFile):
            self.logger.warning('Version file does not exists. Creating it now.')
            try:
                versionFileHandler = open(self.versionFile, 'w')
                versionFileHandler.close()
                return 'Unknown'
            except:
                # If version file can not be created updating is also not possible
                self.logger.error('Could not create version file.')
                return False

        """ Get version from version file """
        with open(self.versionFile, 'r') as fp:
            currentVersion = fp.read().strip(' \n\r')

        self.logger.debug('Current version: ' + currentVersion)

        if not currentVersion:
            self.logger.error('No commit hash found in version file.')
            return True

        if re.match('^[a-z0-9]+$', currentVersion):
            self.currentHash = currentVersion
            return currentVersion

    def latest(self):
        """ Get hash of latest commit on github """
        self.logger.debug('Getting latest version from github.')
        try:
            url = 'https://api.github.com/repos/%s/%s/commits/%s' % (gitUser, gitRepo, htpc.settings.get('branch', 'master2'))
            result = loads(urllib.request.urlopen(url).read())
            latest = result['sha'].strip()
            self.logger.debug('Latest version: ' + latest)
            self.latestHash = latest
            return latest
        except:
            return False

    def current_branch_name(self):
        """  Tries to find the current branches by reading version file
             and matching that against all branches on github """

        versionfile = self.current()
        current_branch = htpc.settings.get('branch', 'master2')
        # should return sha on success not True False
        if not isinstance(self.current(), bool):
            try:
                url = "https://api.github.com/repos/%s/%s/branches?per_page=100" % (gitUser, gitRepo)
                branches = loads(urllib.request.urlopen(url).read())
                for branch in branches:
                    if branch["commit"]["sha"] == versionfile:
                        current_branch = branch["name"]
                        self.verified = True
            except:
                self.logger.debug("Couldnt figure out what branch your using, using %s" % htpc.settings.get('branch', 'master2'))
        return current_branch

    def branches(self):
        """ Returns the all the branches to gitUser and current branch """
        cbn = self.current_branch_name()
        d = {
            "branch": cbn,
            "branches": []
        }

        if self.verified:
            d["verified"] = True

        try:
            url = "https://api.github.com/repos/%s/%s/branches?per_page=100" % (gitUser, gitRepo)
            branchlist = []
            branches = loads(urllib.request.urlopen(url).read())
            for branch in branches:
                branchlist.append(branch["name"])
            d["branches"] = [b for b in branchlist if b != cbn]
            return d

        except Exception as e:
            self.logger.error(str(e))
            self.logger.error('Could not find any branches, setting default master2')
            return [d]

    """ Do update from source """
    def update(self):
        self.logger.info("Attempting update from source.")

        self.UPDATING = 1

        tarUrl = 'https://github.com/%s/%s/tarball/%s' % (gitUser, gitRepo, htpc.settings.get('branch', 'master2'))

        # Download tar
        downloaded = self.__downloadTar(tarUrl, self.updateFile)
        if downloaded is False:
            return False

        # Extract to temp folder
        extracted = self.__extractUpdate(self.updateFile, self.updateDir)
        if extracted is False:
            return False

        # Overwite app source with source from extracted file
        overwritten = self.__updateSourcecode()
        if overwritten is False:
            return False

        # Write new version to file
        # Just call it directly in case forced update.
        self.__updateVersionFile(self.latest())

        # Cleanup after yourself
        self.__finishUpdate()

        # Restart HTPC Manager to make sure all new code is loaded
        self.logger.warning('Restarting HTPC Manager after update.')
        htpc.settings.set('app_updated_at', str(time.time()))
        do_restart()

    def __downloadTar(self, url, destination):
        """ Download source """
        self.logger.info('Downloading update from %s' % url)
        try:
            self.logger.debug('Downloading update file to %s' % destination)
            downloadedFile = urllib.request.urlopen(url)
            f = open(destination, 'wb')
            f.write(downloadedFile.read())
            f.close()
            self.logger.info('Downloading update complete')
            return True
        except:
            self.logger.warning('Failed to download update file')
            self.__finishUpdate()
            return False

    def __extractUpdate(self, filePath, destinationFolder):
        """ Extract files from downloaded tar file """
        try:
            self.logger.debug('Extracting tar file: %s' % filePath)
            tarArchive = tarfile.open(filePath)
            tarArchive.extractall(destinationFolder)
            tarArchive.close()
            return True
        except:
            self.logger.error('Failed extracting update file.')
            self.__finishUpdate()
            return False

    """ Overwrite HTPC Manager sourcecode with (new) code from update path """
    def __updateSourcecode(self):
        # Find the extracted dir
        sourceUpdateFolder = [x for x in os.listdir(self.updateDir) if
                              os.path.isdir(os.path.join(self.updateDir, x))]

        if len(sourceUpdateFolder) != 1:
            # There can only be one folder in sourceUpdateFolder
            self.logger.error("Invalid update data, update failed %s" % sourceUpdateFolder)

        # Where to extract the update
        targetFolder = os.path.join(htpc.RUNDIR)
        # Full path to the extracted dir
        contentdir = os.path.join(self.updateDir, sourceUpdateFolder[0])

        self.logger.debug('Overwriting files.')

        # Add all existing files and folders to a list
        # used to clean up old files and folders
        all_files_n_folders = []
        for src_dir, dirs, files in os.walk(htpc.RUNDIR):
            for f in files:
                if f != 'VERSION.txt' and not f.startswith('.'):
                    all_files_n_folders.append(os.path.join(src_dir, f))
            for fd in dirs:
                all_files_n_folders.append(os.path.join(src_dir, fd))

        try:
            # Loop files and folders and place them in the HTPC Manager path
            for src_dir, dirs, files in os.walk(contentdir):
                dst_dir = src_dir.replace(contentdir, targetFolder)

                try:
                    all_files_n_folders.remove(dst_dir)
                except ValueError:
                    pass

                if not os.path.exists(dst_dir):
                    os.mkdir(dst_dir)

                for file_ in files:
                    src_file = os.path.join(src_dir, file_)
                    dst_file = os.path.join(dst_dir, file_)
                    if os.path.exists(dst_file):
                        os.remove(dst_file)
                    shutil.move(src_file, dst_dir)

                    try:
                        #self.logger.debug('Tried to remove %s from all_files_n_folders' % dst_file)
                        all_files_n_folders.remove(dst_file)
                    except ValueError:
                        pass

            # Try to remove all old files
            for existing_file in all_files_n_folders:
                if htpc.DATADIR in existing_file or '.git' in existing_file:
                    continue

                try:
                    os.remove(existing_file)
                    self.logger.debug('Successfully removed %s' % existing_file)
                except Exception as e:
                    pass

        except Exception as e:
            self.logger.warning('Failed to overwrite old files %s' % e)
            self.__finishUpdate()
            return False

        self.logger.info('Updating files successfull')
        return True

    def __updateVersionFile(self, newVersion):
        """
        Write the latest commit hash to the version file.

        Used when checking for update the next time.
        """
        with open(self.versionFile, 'wb') as versionFileHandler:
            versionFileHandler.write(newVersion)

    def __finishUpdate(self):
        """ Remove leftover files after the update """
        self.UPDATING = 0

        if os.path.isfile(self.updateFile):
            self.logger.debug('Removing update archive')
            try:
                os.remove(self.updateFile)
            except OSError as e:
                self.logger.error('Failed to remove %s %s' % (self.updateFile, e))

        if os.path.isdir(self.updateDir):
            self.logger.debug('Removing update code folder')
            try:
                shutil.rmtree(self.updateDir)
            except OSError as e:
                self.logger.error('Failed to remove %s %s' % (self.updateDir, e))


from numpy.testing import assert_equal
from pandas.testing import assert_frame_equal
import pymc3 as pm

from ..utils import trace_to_dataframe, save_trace, load_trace

class TestUtils():

    @classmethod
    def setup_class(cls):
        with pm.Model():
            pm.Normal('a', 0, 1, shape=(2, 2))
            pm.Normal('b', 0, 1)
            cls.trace = pm.sample(1000, chains=2)

    def test_trace_to_dataframe(self):
        df_tc = trace_to_dataframe(self.trace, combined=True)
        df_fc = trace_to_dataframe(self.trace, combined=False)

        assert trace_to_dataframe(self.trace).shape == (2000, 5)
        assert trace_to_dataframe(self.trace, combined=False).shape == (1000, 10)

        for j, k in [(0, 0), (0, 1), (1, 0), (1, 1)]:
            assert_equal(self.trace['a'][:, j, k][:1000],
                         df_fc['a__{}_{}'.format(j, k)].iloc[:, 0].values)
            assert_equal(self.trace['a'][:, j, k][1000:],
                         df_fc['a__{}_{}'.format(j, k)].iloc[:, 1].values)

            assert_equal(self.trace['a'][:, j, k], df_tc['a__{}_{}'.format(j, k)].values)

        assert_equal(self.trace['b'], df_tc['b'])
        assert_equal(self.trace['b'], df_tc['b'])

        assert_equal(self.trace['b'][:1000], df_fc['b'].iloc[:, 0])
        assert_equal(self.trace['b'][1000:], df_fc['b'].iloc[:, 1])

    def test_save_and_load(self, tmpdir_factory):
        filename = str(tmpdir_factory.mktemp('traces').join('trace.gzip'))
        save_trace(self.trace, filename=filename)
        trl0 = load_trace(filename)
        tr = trace_to_dataframe(self.trace, combined=False)
        save_trace(tr, filename=filename)
        trl1 = load_trace(filename)

        assert_frame_equal(tr, trl0)
        assert_frame_equal(tr, trl1)
        assert_frame_equal(trl0, trl1)


import com
import math
import settings
import pages
import matplotlib
import matplotlib.animation as animation
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from matplotlib import style
style.use('ggplot')
matplotlib.use("TkAgg")

comms = com.Com(settings.COMPORT)
time_interval = 0.0
NUM_POINTS = 40

class Data():

    def __init__(self, SIZE):
        self.data = [0.5]*SIZE

    def add(self, val):
        self.data.pop(0)
        self.data.append(val)

    def get_data(self):
        return self.data

atrial = Data(NUM_POINTS)
ventrical = Data(NUM_POINTS)
time = Data(NUM_POINTS)

global r_val

r_val = 0

def animate(i):
    if settings.PD_Flag == True:
        global time_interval
        count = 0
        data = comms.getEgramValues()
        while not len(data) and count < 5:
            data = comms.getEgramValues()
            count += 1
        time_interval += 0.04 + 0.02*count

        a_val = round(data[0], 3)
        v_val = round(data[1], 3)
        r_val = data[2:]  # for testing

        atrial.add(a_val)
        ventrical.add(v_val)
        time.add(time_interval)

        a.clear()

        if settings.PLOT_ATR == True:
            a.plot(time.get_data(), atrial.get_data(), label="atrial")
        if settings.PLOT_VTR == True:
            a.plot(time.get_data(), ventrical.get_data(), label="ventrical")
        a.legend(loc='upper right')

f = Figure(figsize=(5, 5), dpi=100)
a = f.add_subplot(111)
axes = plt.axes()
axes.set_ylim([0, 1])


# @Time    : 2019/6/29 10:06
# @Author  : Xu Huipeng
# @Blog    : https://brycexxx.github.io/

from typing import List
from collections import defaultdict

class Solution:
    def findRepeatedDnaSequences(self, s: str) -> List[str]:
        count = defaultdict(int)
        for i in range(len(s) - 9):
            count[s[i:i + 10]] += 1
        res = []
        for dna, cnt in count.items():
            if cnt > 1:
                res.append(dna)
        return res

    def findRepeatedDnaSequences1(self, s: str) -> List[str]:
        res, visited = set(), set()
        for i in range(len(s) - 9):
            tmp = s[i:i + 10]
            if tmp in visited:
                res.add(tmp)
            else:
                visited.add(tmp)
        return list(res)

    def findRepeatedDnaSequences2(self, s: str) -> List[str]:
        res = []
        count = defaultdict(int)
        for i in range(len(s) - 9):
            tmp = s[i:i + 10]
            count[tmp] += 1
            if count[tmp] == 2:
                res.append(tmp)
        return res


from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from .models import House
from django.http import Http404
from django.views import generic
from carts.models import Cart
from math import ceil
from landlords.models import Landlord
from .choices import number_of_bedrooms,price, district_choices,division_choices,zones_choices
from rest_framework import serializers

class HomeView(generic.ListView):

    template_name = "houses/home.html"
    def get_queryset(self, *args, **kwargs):
        request= self.request

        # print (request.session.get("first_name", "Unknown"))
        return  House.objects.featured()[:3]

    def get_context_data(self, *args, **kwargs):
            context = super(HomeView, self).get_context_data(*args, **kwargs)
            request = self.request
            cart_obj, new_obj = Cart.objects.new_or_get(request)
            context['cart'] = cart_obj
            return context

def home_view(request):
    houses = House.objects.featured()[:3]

    context = {"houses":houses}
    template = "houses/home.html"
    return render(request, template, context)

class  DetailSlugView(generic.DetailView):
        model = House
        queryset = House.objects.all()
        template_name = "houses/detail.html"

        def get_context_data(self, *args, **kwargs):
            context = super(DetailSlugView, self).get_context_data(*args, **kwargs)
            request = self.request
            cart_obj, new_obj = Cart.objects.new_or_get(request)
            context['cart'] = cart_obj
            return context

        def get_object(self, *args, **kwargs):
            request = self.request
            slug    = self.kwargs.get('slug')
            try:
                instance = House.objects.get(slug=slug, active=True)
            except House.DoesNotExist:
                raise Http404("This House either doesnot exsit or it was deleted")
            except House.MultipleObjectsReturned:
                qs = House.Objects.filter(slug=slug, active=True)
                instance = qs.first()
            except:
                raise Http404
            return instance

def about(request):
    landlord = Landlord.objects.order_by('-name')

    # Get MVP
    mvp_landlords = Landlord.objects.all().filter(is_mvp=True)
    context = {'landlord':landlord,
                'mvp_landlords':mvp_landlords
    }
    template = 'houses/about.html'
    return render(request, template, context)

@login_required
def userProfile(request):
    # qs = House.objects.all()
    instance_obj = House.objects.all()
    district_exact_query = request.GET.get('district_exact')
    division_exact_query = request.GET.get('division_exact')
    zone_exact_query     = request.GET.get('zone_exact')
    price_exact_query    =  request.GET.get(' price_exact')
    rooms_exact_query    =   request.GET.get('rooms_exact')

    if district_exact_query != '' and  district_exact_query is not None:
        instance_obj = instance_obj.filter(District__icontains=district_exact_query)

    if division_exact_query != '' and  division_exact_query is not None:
        instance_obj = instance_obj.filter(Division__icontains=division_exact_query)

    if zone_exact_query != '' and  zone_exact_query is not None:
        instance_obj = instance_obj.filter(Zone__icontains= zone_exact_query)

    if price_exact_query != '' and  price_exact_query is not None:
        instance_obj = instance_obj.filter(Price__icontains= price_exact_query)

    if rooms_exact_query != '' and  rooms_exact_query is not None:
        instance_obj = instance_obj.filter(Number_Of_Rooms__icontains= rooms_exact_query)

    user = request.user
    context ={
        'user':user,
        'instance_obj':instance_obj,

        }
    template = 'houses/profile.html'
    return render(request, template, context)

def search(request):
    queryset_list = House.objects.all()

    #   keywords
    if 'district' in request.GET:
        district = request.GET['district']
        if district:
            queryset_list = queryset_list.filter(District__iexact=district)

    # Division
    if 'division' in request.GET:
        division = request.GET['division']
        if division:
            queryset_list = queryset_list.filter(Division__iexact=division)

    # Zone
    if 'zone' in request.GET:
        zone = request.GET['zone']
        if zone:
            queryset_list= queryset_list.filter(Zone__iexact=zone)

    # Price
    if 'price' in request.GET:
        price = request.GET['price']
        if price:
            queryset_list = queryset_list.filter(Price__Ite=price)

    # Bedrooms
    if 'bedrooms' in request.GET:
        bedrooms = request.GET['bedrooms']
        if bedrooms:
            queryset_list = queryset_list.filter(Number_Of_Rooms__Ite=bedrooms)

    context = {
        'number_of_bedrooms':number_of_bedrooms,
        'price':price,
        'district_choices':district_choices,
        'division_choices':division_choices,
        'zones_choices ':zones_choices ,

    }
    return render(request, 'search/views.html', context)


import os
import sys
import json
from datetime import datetime
from os import system, name
from time import sleep
import copy
import threading
import imp

try:
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
except:
    pass

GLOBAL_DATA_STORE = None

class Utility:
    '''
    Utility class to handle things that all of the other classes may need.  File / screen access etc.
    '''

    screen_width = 76
    def __init__(self):
        self.bozo ="bozo"
        self.screen_width = 76
    # define our clear function
    def clear(self):

        # for windows
        if name == 'nt':
            _ = system('cls')

        # for mac and linux(here, os.name is 'posix')
        else:
            _ = system('clear')

    def center_with_stars(self,input_string,screen_width=76):
        '''
        Print stuff out with * characters on either side *
        :param input_string: text to print
        :param screen_width: max console width to use
        :return:
        '''
        buffer = int((screen_width -len(input_string)-2)/2)
        input_string = "*" + " " *buffer+ input_string +" "*buffer+"*"
        if(len(input_string)<screen_width):
            input_string.replace(" *","  *")
        # print(len(input_string))
        return input_string

    def print_header(self):
        '''
        Print a generic header.
        :return:
        '''
        print("*"*self.screen_width)
        print(self.center_with_stars("U.C. Berkeley MIDS Summer 2021 W200 Project 1 -- Don Irwin",self.screen_width))
        print("*"*self.screen_width)
        print(self.center_with_stars("Real Estate Market Info by Zip Code System",self.screen_width))
        print("*"*self.screen_width)

    def get_data_from_file(self,str_file_name):
        '''
        Read an entire file and push the data back.
        :param str_file_name:
        :return:
        '''
        with open(str_file_name, 'r') as file:
            data = file.read()

        return data

    def get_this_dir(self):
        '''
        Return the working directory.
        :return:
        '''
        thisdir = os.getcwd()
        return thisdir

    def display_splash_screen(self):
        '''
        Read text file to display vainglorious splash screen.
        :return:
        '''
        self.clear()
        splash_file = os.path.join(self.get_this_dir(),'splash_text.txt')
        print(self.get_data_from_file(splash_file))
        sleep(2)

    def display_exit_screen(self):
        '''
        Exit file for same vainglorious splash screen.
        :return:
        '''

        self.clear()
        splash_file = os.path.join(self.get_this_dir(),'goodbye.txt')
        print(self.get_data_from_file(splash_file))
        sleep(2)

    def do_dependency_check(self):
        '''
        Check for library dependencies which are non-standard python libraries
        Alert use if some environment update is needed.
        :return:
        '''
        try:
            exists = imp.find_module("matplotlib")
            exists = True
        except:
            exists = False

        if not exists:
            self.clear()
            self.print_header()
            print(self.center_with_stars("DEPENDENCY MISSING:"))
            print("")
            print(self.center_with_stars("This program requires the module 'matplotlib'"))
            print("")
            print(            self.center_with_stars(" Please view the link below on how to install: "))
            print(self.center_with_stars(" https://matplotlib.org/stable/users/installing.html "))
            print("")
            print(self.center_with_stars(" Install the missing module, then run the program again. "))
            print("")
            print("*"*self.screen_width)

            sys.exit()

class AreaInformationByZipcode:
    '''
    Simple Class representation of json, probably unnecssary, but we will see.
    '''

    def __init__(self,**kwargs):
        allowed_keys = {'zipcode', 'search_uri', 'description'}
        self.__dict__.update((k, v) for k, v in kwargs.items() if k in allowed_keys)

    def __init__(self, json_string):
        '''
        Load it up
        :param json_string:
        '''
        self.__dict__ = json.loads(json_string)

    def print_internal_directory(self):
        '''
        print the name value pairs in the simple json file
        :return:
        '''
        for k,v in self.__dict__.items():
            print("{} is \"{}\"".format(k,v))

class AreaDataStore:
    '''
    Primary Data object with different internal structures used by all classes.
    This is loaded from disk once at the beginning then re-used throughout.
    '''

    beginning_day_id = "20210318"
    ending_day_id = "20210606"
    smooth_data_dir = "historical_data"
    rough_data_dir = "historical_data_original_do_not_delete"

    def __init__(self,use_rough_data=False):
        '''
        Initializer which sets up iternal objects.
        loads either rough un-smoothed data, or smoothed data.
        :param use_rough_data:
        '''
        if use_rough_data:
            self.data_directory = AreaDataStore.rough_data_dir
        else:
            self.data_directory = AreaDataStore.smooth_data_dir
        self.area_data_objects_by_zipcode = {}
        self.area_name_by_zipcode = {}
        self.util = Utility()
        self.load_area_data_objects()
        self.beginning_day_id = "20210318"
        self.ending_day_id = "20210606"

    #remove later
    def smooth_data(self):
        '''
        Smooths rugged data by stepping the values from one high to another.
        :return:
        '''
        copy_of_area_objects_by_zipcode = copy.deepcopy(self.area_data_objects_by_zipcode)
        last_median_price = 0
        last_list_count = 0
        last_price_per_square_ft = 0
        for zip_code in self.area_data_objects_by_zipcode.keys():
            next_zipcode = True
            day_ids_in_smoothing_step = []
            for day_id in self.area_data_objects_by_zipcode[zip_code].keys():
                print(zip_code,day_id,self.area_data_objects_by_zipcode[zip_code][day_id].median_list_price)
                try:
                    i_median_price = int(self.area_data_objects_by_zipcode[zip_code][day_id].median_list_price.replace(",",""))
                except:
                    i_median_price = 0
                try:
                    i_list_count = int(self.area_data_objects_by_zipcode[zip_code][day_id].active_listings)
                except:
                    i_list_count = 0
                try:
                    i_price_per_square_ft = int(self.area_data_objects_by_zipcode[zip_code][day_id].median_price_per_sqft)
                except:
                    i_price_per_square_ft = 0
                print("listing count =", i_list_count,zip_code,day_id)
                if last_median_price !=0 and last_median_price != i_median_price:
                    #print(day_ids_in_smoothing_step)
                    #we have a change mark the day_id where the change occured
                    count_in_smoothing_step = len(day_ids_in_smoothing_step)
                    price_delta = (i_median_price-last_median_price)

                    listing_delta = (int(i_list_count)-int(last_list_count))
                    square_feet_delta = (int(i_price_per_square_ft)-int(last_price_per_square_ft))

                    if count_in_smoothing_step ==0:
                        median_price_smoothing_step = price_delta
                        listing_count_smoothing_step = listing_delta
                        price_per_square_ft_smoothing_step = square_feet_delta
                    else:
                        median_price_smoothing_step = int(round(price_delta/count_in_smoothing_step))
                        listing_count_smoothing_step = int(round(listing_delta/count_in_smoothing_step))
                        price_per_square_ft_smoothing_step = int(round(square_feet_delta/count_in_smoothing_step))

                    if i_median_price<last_median_price:
                        median_price_smoothing_step = int(round(median_price_smoothing_step*(-1)))
                    if i_price_per_square_ft<last_price_per_square_ft:
                        price_per_square_ft_smoothing_step = int(round(price_per_square_ft_smoothing_step*(-1)))

                    if i_list_count<last_list_count:
                        listing_count_smoothing_step = int(round(listing_count_smoothing_step*(-1)))

                    #now do the smoothing
                    for day_id_to_smooth in day_ids_in_smoothing_step:
                        my_object = copy_of_area_objects_by_zipcode[zip_code][day_id_to_smooth]
                        print(zip_code,day_id_to_smooth,my_object.median_list_price,median_price_smoothing_step,last_median_price,i_median_price,price_delta,count_in_smoothing_step)
                        original_price = my_object.median_list_price
                        try:
                             my_object.median_list_price = "{:,}".format((int(my_object.median_list_price.replace(",","")) + median_price_smoothing_step))
                        except:
                            my_object.median_list_price = my_object.median_list_price

                        try:
                            my_object.median_price_per_sqft = int(my_object.median_price_per_sqft.replace(",","")) + price_per_square_ft_smoothing_step
                        except:
                            my_object.median_price_per_sqft + my_object.median_price_per_sqft

                        try:
                            my_object.active_listings = int(my_object.active_listings) + listing_count_smoothing_step
                        except:
                            my_object.active_listings = my_object.active_listings

                        copy_of_area_objects_by_zipcode[zip_code][day_id_to_smooth] = my_object

                        print("smoothed price=",copy_of_area_objects_by_zipcode[zip_code][day_id_to_smooth].median_list_price,"original price=",original_price)

                    # #now clear out the day_ids to smooth
                    day_ids_in_smoothing_step.clear()

                else:
                    day_ids_in_smoothing_step.append(self.area_data_objects_by_zipcode[zip_code][day_id].extract_day_id)

                last_median_price = i_median_price
                last_price_per_square_ft = i_price_per_square_ft
                last_list_count = i_list_count

        self.save_smoothed_objects(copy_of_area_objects_by_zipcode)

    def save_smoothed_objects(self,copy_of_area_objects_by_zipcode):
        '''
        Iterate object collection and save to JSON file.
        :param copy_of_area_objects_by_zipcode:
        :return:
        '''
        thisdir = os.getcwd()

        for zipcode in copy_of_area_objects_by_zipcode.keys():
            for day_id in copy_of_area_objects_by_zipcode[zipcode].keys():
                json_object = copy_of_area_objects_by_zipcode[zipcode][day_id]

                fileToSave = os.path.join( thisdir, 'historical_data_smoothed',  json_object.extract_day_id , '{}_extract_{}.json'.format(json_object.zipcode,json_object.extract_day_id))

                daydirectory = thisdir + '\\historical_data_scrubbed\\' + json_object.extract_day_id + '\\'
                daydirectory = os.path.join(thisdir,'historical_data_smoothed',  json_object.extract_day_id )

                if not os.path.exists(daydirectory):
                    os.makedirs(daydirectory)
                print(fileToSave)
                with open(fileToSave,"w") as outfile:
                    json.dump(json_object.__dict__,outfile,indent=4,sort_keys=True)

    #remove later
    def scrub_and_save_file(self,json_object):
        '''
        Used to scrub some data one time.
        :param json_object:
        :return:
        '''
        if(len(json_object.median_list_price)==3):
                json_object.median_list_price = json_object.median_list_price + ",000"
        thisdir = os.getcwd()
        fileToSave = thisdir + '\\historical_data_scrubbed\\' + json_object.extract_day_id + '\\{}_extract_{}.json'.format(json_object.zipcode,json_object.extract_day_id)

        fileToSave = os.path.join( thisdir, 'historical_data_scrubbed',  json_object.extract_day_id , '{}_extract_{}.json'.format(json_object.zipcode,json_object.extract_day_id))

        daydirectory = thisdir + '\\historical_data_scrubbed\\' + json_object.extract_day_id + '\\'
        daydirectory = os.path.join(thisdir,'historical_data_scrubbed',  json_object.extract_day_id )

        if not os.path.exists(daydirectory):
            os.makedirs(daydirectory)

        with open(fileToSave,"w") as outfile:
            json.dump(json_object.__dict__,outfile,indent=4,sort_keys=True)

    def load_area_data_objects(self):
        '''
        Most important method in the class.
        Loads all of the data objects into nested dictionaries for consumption by the other classes.
        :return:
        '''
        this_dir = os.getcwd()
        historical_data_dir = this_dir + '\\historical_data\\'
        historical_data_dir = os.path.join(this_dir, self.data_directory)

        print(this_dir)
        day_id_dirs = [day_id_directory for day_id_directory in os.listdir(historical_data_dir) ]

        l_area_data_by_zipcode = []
        zip_code_set = set()

        for day_id in day_id_dirs:
            try:
                my_day_id = int(day_id)
            except:
                continue
            # print("day_id=",day_id)
            if not (int(day_id)<int(self.beginning_day_id)) and not (int(day_id)>int(self.ending_day_id)):
                day_id_directory = historical_data_dir + day_id
                day_id_directory = os.path.join(historical_data_dir,day_id)
                json_files = [full_directory for full_directory in os.listdir(day_id_directory) ]
                for json_file in json_files:
                    zip_code = json_file.split('_')[0]
                    file_name = day_id_directory + '\\' + json_file
                    file_name = os.path.join(day_id_directory,json_file)
                    file_data = self.util.get_data_from_file(file_name)
                    zip_code_by_day_id_data_object = AreaInformationByZipcode(file_data)
                    # self.scrub_and_save_file(zip_code_by_day_id_data_object)
                    # print("zipcode = ", zip_code_by_day_id_data_object.zipcode, zip_code_by_day_id_data_object.extract_day_id)
                    l_area_data_by_zipcode.append((zip_code_by_day_id_data_object))
                    zip_code_set.add(zip_code)

        for zip_code in zip_code_set:
            dict_day_data_in_zipcode = {}
            for zip_code_area_object in l_area_data_by_zipcode:
                if zip_code_area_object.zipcode ==zip_code:
                    # print(zip_code, zip_code_area_object.zipcode, zip_code_area_object.extract_day_id)
                    dict_day_data_in_zipcode[zip_code_area_object.extract_day_id] = zip_code_area_object
                    self.area_name_by_zipcode[zip_code] = zip_code_area_object.description
            self.area_data_objects_by_zipcode[zip_code] = dict_day_data_in_zipcode

            # print(self.area_data_objects_by_zipcode[zip_code])
        # print(self.area_data_objects_by_zipcode.keys())
        # for key in self.area_data_objects_by_zipcode['90017'].keys():
        #     print(key)
        #     object = self.area_data_objects_by_zipcode['90017'][key]
        #     object.print_internal_directory()

    def get_area_info_by_zipcode(self,zip_code):
        '''
        Returns a list of objects keyed by "day_id" YYYYMMDD for a supplied zipcode.
        :param zip_code:
        :return:
        '''
        l_return = [self.area_data_objects_by_zipcode[zip_code][key] for key in sorted(self.area_data_objects_by_zipcode[zip_code].keys())]
        return l_return

class AreaDataMenu:
    '''
    The opening menu of the program.
    consumes the AreaDataStore()
    '''

    def __init__(self):
        '''
        Initializer which prompts user for what data set to use
        sets that set to global.
        '''
        self.util = Utility()
        # self.display_area_data_menu()
        self.first_time_display=True

        data_store_selection = self.display_data_source_menu()
        if data_store_selection == '1':
            global_data_store = AreaDataStore()
        else:
            use_rough_data = True
            global_data_store = AreaDataStore(use_rough_data)

        global GLOBAL_DATA_STORE
        GLOBAL_DATA_STORE = global_data_store
        self.area_data_store = GLOBAL_DATA_STORE
        self.display_area_data_menu()

    def display_data_source_menu(self):
        '''
        Displays the data source menu.
        :return:
        '''
        self.util.clear()
        self.util.print_header()
        self.util.center_with_stars("DATA SOURCE MENU",76)
        print("*"*self.util.screen_width)
        print(" "*self.util.screen_width)

        self.menu_dict = {}
        self.menu_dict['1']="Smoothed Data (default)"
        self.menu_dict['2']="Original Rough Data"

        for option in self.menu_dict.keys():
            if(int(option)<10):
                to_print = "{}.  : {}".format(option,self.menu_dict[option])
            else:
                to_print = "{}. : {}".format(option,self.menu_dict[option])
            # side_buffer = (len(to_print)-screen_width)/2
            to_print = " "*int(20) + to_print
            print(to_print)

        print(" "*self.util.screen_width)
        print(" "*self.util.screen_width)

        print("*"*self.util.screen_width)
        print(self.util.center_with_stars("Select what data you would like to use.",self.util.screen_width))

        print("*"*self.util.screen_width)
        print(" "*self.util.screen_width)

        data_type_selection = input("Please make your selection:")
        while data_type_selection not in self.menu_dict.keys():
            print("The value you selected {} is not a valid input.".format(data_type_selection))
            data_type_selection = input("Please make your selection:")

        return data_type_selection

    def display_area_data_menu(self):
        '''
        Displays all zipcodes and their names.
        :return:
        '''
        self.util.clear()
        max_key = max(self.area_data_store.area_name_by_zipcode, key=lambda k: len(self.area_data_store.area_name_by_zipcode[k]))
        max_len = len(self.area_data_store.area_name_by_zipcode[max_key])
        screen_width = 76
        self.util.print_header()
        print("*"*screen_width)
        title1 = "*                            HOME MENU                                    *"
        print(title1)

        print("*"*screen_width)
        print(" "*screen_width)

        print(" "*screen_width)

        int_menu = 1
        for zip_code in self.area_data_store.area_name_by_zipcode.keys():
            if(int_menu<10):
                to_print = "{}.  {} : {}".format(int_menu,zip_code,self.area_data_store.area_name_by_zipcode[zip_code])
            else:
                to_print = "{}. {} : {}".format(int_menu, zip_code,
                                                 self.area_data_store.area_name_by_zipcode[zip_code])
            # side_buffer = (len(to_print)-screen_width)/2
            to_print = " "*int(5) + to_print
            print(to_print)
            int_menu+=1
        print(" "*screen_width)

        print("*"*screen_width)
        title1 = "*  Enter a number corresponding to the zipcode you wish to view or 'quit' *"
        print(title1)

        print("*"*screen_width)
        print(" "*screen_width)

    def get_main_menu_input(self):
        '''
        prompts the user to select what area they wish to get info on.
        :return:
        '''

        menu_dict = {str(list(self.area_data_store.area_name_by_zipcode).index(zip_code)+1):zip_code for zip_code in self.area_data_store.area_name_by_zipcode.keys()}
        menu_dict['quit']=""

        good_input=False
        while not good_input:
            my_input = input("Please make your selection:").lower()
            if my_input not in menu_dict.keys():
                self.display_area_data_menu()
                print("The input your provided '{}' is not a valid menu choice.".format(my_input))
                continue
            else:
                if my_input == "quit":
                    # print("Quitting -- goodbye.")
                    self.util.display_exit_screen()
                    sys.exit()
                else:
                    good_input = True
                    return menu_dict[my_input]

class GraphDataObject:
    '''
    Poco object that holds information to be passed to graphing function.
    '''

    def __init__(self):
        self.x_axis_values = None
        self.y_axis_values = None
        self.label = None

class AreaDisplay:
    '''
    Handles options for what a user can view about a zipcode.
    '''

    def __init__(self,input_zip_code):
        '''
        Initializer
        :param input_zip_code: zip code to view.
        '''
        global GLOBAL_DATA_STORE
        self.area_data_store = GLOBAL_DATA_STORE
        # self.area_data_store = AreaDataStore()
        self.zip_code = input_zip_code
        self.util = Utility()

    def display_area_data_menu(self):
        '''
        Display options about a specific zipcode.
        :return:
        '''
        self.util.clear()
        max_key = max(self.area_data_store.area_name_by_zipcode, key=lambda k: len(self.area_data_store.area_name_by_zipcode[k]))
        max_len = len(self.area_data_store.area_name_by_zipcode[max_key])
        screen_width = 76

        self.util.print_header()

        print(self.util.center_with_stars("AREA DETAILS MENU ".format(self.zip_code),screen_width))

        print(self.util.center_with_stars("You have selected zip code {}".format(self.zip_code),screen_width))
        print(self.util.center_with_stars("Area Name: {}".format(self.area_data_store.area_name_by_zipcode[self.zip_code]),screen_width))

        print("*"*screen_width)
        print(" "*screen_width)
        print(" "*screen_width)

        self.menu_dict = {}
        self.menu_dict['1']="Graph Median Home Price"
        self.menu_dict['2']="Graph Listings in Market"
        self.menu_dict['3']="Graph Price Per Squre Foot"
        self.menu_dict['4']="Graph All"

        for option in self.menu_dict.keys():
            if(int(option)<10):
                to_print = "{}.  : {}".format(option,self.menu_dict[option])
            else:
                to_print = "{}. : {}".format(option,self.menu_dict[option])
            # side_buffer = (len(to_print)-screen_width)/2
            to_print = " "*int(20) + to_print
            print(to_print)

        self.menu_dict['return']='return'
        self.menu_dict['quit']='quit'

        print(" "*screen_width)
        print(" "*screen_width)

        print("*"*screen_width)
        print(self.util.center_with_stars("Please enter the number of the graph to view.",screen_width))
        print(self.util.center_with_stars("Enter 'return' to return to the Home Menu, 'quit' to exit.",screen_width))

        print("*"*screen_width)
        print(" "*screen_width)

    def get_area_menu_input(self):
        '''
        Captures the users input of the type of graph the want to see.
        :return:
        '''

        good_input=False
        while not good_input:
            good_input = True
            my_input = input("Please make your selection:").lower()
            if my_input not in self.menu_dict.keys():
                self.display_area_data_menu()
                print("The input your provided '{}' is not a valid menu choice.".format(my_input))
                good_input = False
                continue

        if my_input == 'quit':
            self.util.display_exit_screen()
            sys.exit()

        return my_input, self.menu_dict[my_input]

    def display_graph_based_on_input(self,input_tuple,zip_code):
        '''
        Prepares the x and y axis data then feeds it to the graphing class.
        :param input_tuple:
        :param zip_code:
        :return:
        '''
        graph_option = int(input_tuple[0])
        graph_description = input_tuple[1]
        graph_title = graph_description.replace("Graph","Graph of") + \
                      " For\n" + self.area_data_store.area_name_by_zipcode[zip_code] + \
                      ", Zipcode: {}".format(zip_code)
        # datetime(object.extract_dt.split(",")[0]).date()
        x_axis_values = [datetime.strptime(object.extract_dt.split(",")[0],'%m/%d/%Y').date()  for object in self.area_data_store.get_area_info_by_zipcode(zip_code)]
        y_label = ""
        if graph_option == 1:
            y_axis_values = [int(object.median_list_price.replace(",", "")) if len(object.median_list_price.replace(",", ""))>0 else 0  for object in
                             self.area_data_store.get_area_info_by_zipcode(zip_code)]
            if max(y_axis_values)>1000000:
                y_label = "Median Listing Price in Millions"
            else:
                y_label = "Median Listing Price in Dollars"

        if graph_option == 2:

            y_axis_values = [int(object.active_listings) if len(str(object.active_listings).strip())>0 else 0 for object in
                             self.area_data_store.get_area_info_by_zipcode(zip_code)]
            y_label = "Active Listings in Zipcode"

        if graph_option == 3:
            y_axis_values = [int(object.median_price_per_sqft)  for object in
                             self.area_data_store.get_area_info_by_zipcode(zip_code)]
            y_label = "Median Price Per Sq Ft in Dollars"

        #Simple single lined graphs.
        if graph_option != 4:
            area_graph = AreaGraph()
            area_graph.plot_single_line_graph(x_axis_values, y_axis_values, "Day", y_label, graph_title)

        #Multi_line_graph
        if graph_option == 4:
            lgo = []
            mpgdo = GraphDataObject()
            mpgdo.label = "Median Price"
            mpgdo.x_axis_values = x_axis_values
            mpgdo.y_axis_values = [int(object.median_list_price.replace(",", "")) if len(object.median_list_price.replace(",", ""))>0 else 0  for object in
                             self.area_data_store.get_area_info_by_zipcode(zip_code)]
            lgo.append(mpgdo)
            algdo = GraphDataObject()
            algdo.label = "Active Listings"
            algdo.x_axis_values = x_axis_values
            algdo.y_axis_values = [int(object.active_listings)*200 if len(str(object.active_listings).strip())>0 else 0 for object in
                             self.area_data_store.get_area_info_by_zipcode(zip_code)]
            lgo.append(algdo)
            ppsqftgdo = GraphDataObject()
            ppsqftgdo.label = "Sqft Price"
            ppsqftgdo.x_axis_values = x_axis_values
            ppsqftgdo.y_axis_values = [int(object.median_price_per_sqft)*1000  for object in
                             self.area_data_store.get_area_info_by_zipcode(zip_code)]
            lgo.append(ppsqftgdo)

            area_graph = AreaGraph()
            graph_title = "Multi Line Graph" + \
                          " For\n" + self.area_data_store.area_name_by_zipcode[zip_code] + \
                          ", Zipcode: {}".format(zip_code)

            area_graph.plot_multi_line_graph(lgo,graph_title)

class AreaGraph:
    '''
    Object that renders the graph.
    '''

    def __init__(self):
        global GLOBAL_DATA_STORE
        self.area_data_store = GLOBAL_DATA_STORE
        self.util = Utility()

    def plot_multi_line_graph(self,list_graph_data_objects,title):
        '''
        Plot a multi line graph.
        :param list_graph_data_objects: list of GraphDataObjects
        :param title:
        :return:
        '''
        x_axis_values = None
        for graph_object in list_graph_data_objects:
            plt.plot(graph_object.x_axis_values,graph_object.y_axis_values,label=graph_object.label)
            x_axis_values = graph_object.x_axis_values
        plt.xlabel("Day")
        plt.ylabel("Value")
        plt.title(title)
        # plt.xticks(x_axis_values[::10],rotation=45)
        plt.xticks(rotation=45)
        plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=5))

        plt.gcf().subplots_adjust(bottom=0.20)
        plt.gcf().subplots_adjust(left=0.25)
        plt.gcf().autofmt_xdate()
        plt.legend()
        plt.show()

    def plot_single_line_graph(self, x_axis_values, y_axis_values, x_label, y_label, graph_label):
        '''
        Plot a single line graph.
        :param x_axis_values:  list of x values
        :param y_axis_values: list of y values
        :param x_label:
        :param y_label:
        :param graph_label:
        :return:
        '''

        plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m/%d/%Y'))
        plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=5))

        plt.plot(x_axis_values,y_axis_values)

        plt.xlabel(x_label)
        plt.ylabel(y_label)
        plt.title(graph_label)
        # plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=5))

        plt.xticks(rotation=45)
        plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=5))
        plt.gcf().subplots_adjust(bottom=0.20)
        plt.gcf().subplots_adjust(left=0.25)
        plt.gcf().autofmt_xdate()

        plt.show()

    def plot_the_dealio(self):
        print("in plot the dealio")

        y_axis_values = [int(object.median_price_per_sqft.replace(",","")) for object in self.area_data_store.get_area_info_by_zipcode("90023")]
        x_axis_values = [object.extract_day_id for object in self.area_data_store.get_area_info_by_zipcode("90023")]

        plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m/%d/%Y'))
        plt.gca().xaxis.set_major_locator(mdates.DayLocator())

        plt.plot(x_axis_values,y_axis_values)

        plt.xlabel("Day")
        plt.ylabel("Active Listing Count")
        plt.title("Dealio")
        plt.xticks(x_axis_values[::5],rotation=45)
        plt.gcf().subplots_adjust(bottom=0.25)
        plt.show()


import http.server
from prometheus_client import start_http_server
from prometheus_client import Counter

REQUESTS = Counter('kata1_server_requests_total', 'Total number of requests to this webserver')

class ServerHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        REQUESTS.inc()
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"Hello World!")

if __name__ == "__main__":
    start_http_server(8000)
    server = http.server.HTTPServer(('', 8001), ServerHandler)
    print("Prometheus metrics available on port 8000 /metrics")
    print("HTTP server available on port 8001")
    server.serve_forever()


# -*- coding: utf-8 -*-
"""
Created on Sun Jun 25 17:34:06 2017

@author: Michael Zhang
"""

from labjack import ljm
import json
import datetime

#Smart Actuator Libraries
import TE_4030_RAW as acc_raw
import TE_HIGH_RAW as acc_high_raw
import Sensor_Profiles as SP

def get_data_and_log(handle):
    time_current = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    today_date = datetime.datetime.now().date()

    acc_low_x_value,acc_low_y_value,acc_low_z_value = acc_raw.TE_4030_LOW_ACC_RAW(handle,AIN=[0,2,4])
    acc_high_z_val = acc_high_raw.TE_HIGH_ACC_RAW(handle,AIN_names=["AIN6"])

    onboard_5V = ljm.eReadName(handle, "AIN8")
    motor_temp_1 = SP.AD22100K(ljm.eReadName(handle, "AIN1"),onboard_5V)
    motor_temp_2 = SP.AD22100K(ljm.eReadName(handle, "AIN3"),onboard_5V)
    system_hum = SP.HIH_4030(ljm.eReadName(handle, "AIN5"))
    #motor_current_1 = ljm.eReadName(handle, "AIN7")
    #motor_current_2 = ljm.eReadName(handle, "AIN9")
    DAQ_temp = SP.LJT7_onboard(ljm.eReadName(handle, "AIN14"))

    extra_temp = SP.AD22100K(ljm.eReadName(handle, "AIN10"),onboard_5V)
    sensor_data = {
            str(time_current):
                {
                    'Accelerometer X Raw Fs=400Hz': acc_low_x_value,
                    'Accelerometer Y Raw Fs=400Hz': acc_low_y_value,
                    'Accelerometer Z Raw Fs=400Hz': acc_low_z_value,
                    'High Frequency Accelerometer Z Raw Fs=10,000Hz': acc_high_z_val,
                    'Motor Temperature #1': motor_temp_1,
                    'Motor Temperature #2': motor_temp_2,
                    'System Humidity': system_hum,
                    'Motor Current #1': "NaN",
                    'Motor Current #2': "NaN",
                    'DAQ Temperature': DAQ_temp,
                    'Ambient Temperature' : extra_temp
                }
            }
    try:
        file_name='C:\Log Data\data_'+str(today_date)+'.json'
        with open(file_name, 'r+', encoding = 'utf-8') as outfile:
            outfile.seek(0,2)
            position = outfile.tell() -1
            outfile.seek(position)
            outfile.write(json.dumps(sensor_data).replace('{',',',1))
    except FileNotFoundError:
        file_name='C:\Log Data\data_'+str(today_date)+'.json'
        with open(file_name, 'w', encoding = 'utf-8') as outfile:
            json.dump(sensor_data, outfile)

    return motor_temp_1,motor_temp_2,DAQ_temp,system_hum,time_current,extra_temp


from collections import defaultdict
import random

mydeck = [r+s for r in '23456789TJQKA' for s in 'SHDC']

hand_names = {
    0 : "high card",
    1 : "2 of a kind",
    2 : "2-pair",
    3 : "3 of a kind",
    4 : "straight",
    5 : "flush",
    6 : "full house",
    7 : "four of a kind",
    8 : "straight flush",
}

def swap(deck,i,j):
    deck[i], deck[j] = deck[j], deck[i]

def shuffle(deck):
    n = len(deck)
    for i in range(n-1):
        swap(deck,i,random.randint(i,n-1))

def deal(numhands, n=5, deck=mydeck):
    "deal out 'numhands' hands of 'n' cards each after shuffling"
    #run python's shuffle algo
    #random.shuffle(mydeck)

    #run custom shuffling algo
    shuffle(deck)

    #prepare hands of 'n' cards each
    return [deck[n*i:n*(i+1)] for i in range(0,numhands)]

def factorial(n):
    if(n<=0):
        return 1
    else:
        return factorial(n-1) * n

def test_shuffler(shuffler, deck, num_iter):
    "Tests if the shuffler shuffles good"
    counts = defaultdict(int)
    for _ in range(num_iter):
        input = list(deck)
        shuffle(input)
        counts[''.join(input)] += 1

    expected_count = num_iter * (1/factorial(len(deck)))

    isShufflerGood = all( (0.9 <= counts[e]/expected_count <= 1.1) for e in counts )

    name = shuffler.__name__

    print("%s(%s) %s" % (name,deck,"good" if isShufflerGood else "bad"))

    for key,value in counts.items():
        print("%s: attained=>%7.4f%% expected=>%7.4f%%" % (key, (value/num_iter)*100, (expected_count/num_iter)*100))

    return isShufflerGood

def straight(ranks):
    "Return True if the ordered ranks form a 5-card straight."
    assert(ranks)

    return (max(ranks)-min(ranks)==4 and len(set(ranks))==5)

def flush(hand):
    "Return True if all the cards have the same suit."
    assert(hand)

    suits = [s for r,s in hand]
    return (len(set(suits))==1)

def kind(n, ranks):
    """Return the first rank that this hand has exactly n of.
    Return None if there is no n-of-a-kind in the hand."""
    assert(ranks)

    counts = defaultdict(int)
    for e in ranks:
        counts[e] += 1

    for k,v in counts.items():
        if v == n:
            return k

    return None

def two_pair(ranks):
    """If there are two pair, return the two ranks as a
    tuple: (highest, lowest); otherwise return None."""
    assert(ranks)

    temp = set(ranks)
    if len(temp) != 3:
        return None

    h = None
    l = None
    for e in temp:
        if ranks.count(e) == 2:
            if h==None:
                h = e
            else:
                l = e

    if h==None and l==None:
        return None
    else:
        return (h,l)

def card_ranks(cards):
    "Return a list of the ranks, sorted with higher first."

    ranks = ['--23456789TJQKA'.index(r[0]) for r in cards]
    ranks.sort(reverse=True)

    #to handle: ace can rank either above K or below 2
    if(ranks == [14,5,4,3,2]):
        ranks = [5,4,3,2,1]

    return ranks

def hand_rank(hand):
    "Returns the rank of the hand in the form of a tuple"

    ranks = card_ranks(hand)

    if straight(ranks) and flush(hand):            # straight flush
        return (8, max(ranks))
    elif kind(4, ranks):                           # 4 of a kind
        return (7, kind(4, ranks), kind(1, ranks))
    elif kind(3, ranks) and kind(2, ranks):        # full house
        return (6, kind(3,ranks), kind(2,ranks))
    elif flush(hand):                              # flush
        return (5, ranks)
    elif straight(ranks):                          # straight
        return (4, max(ranks))
    elif kind(3, ranks):                           # 3 of a kind
        return (3, kind(3,ranks), ranks)
    elif two_pair(ranks):                          # 2 pair
        return (2, two_pair(ranks), ranks)
    elif kind(2, ranks):                           # kind
        return (1, kind(2,ranks), ranks)
    else:                                          # high card
        return (0,ranks)

def hand_percentages(n=700*1000):
    "Prints a table indicating probablity of each type of hand"
    counts = [0]*9
    for i in range(int(n/10)):
        for hand in deal(10):
            rank = hand_rank(hand)[0]
            counts[rank] += 1

    for i in reversed(range(9)):
        print("%14s : %7.4f%%" % (hand_names[i],100*counts[i]/n))

def allmax(iterable, key=None):
    "Return a list of all items equal to the max of the iterable."

    result, maxval = [],None
    key = key or (lambda x : x)

    for x in iterable:
        xval = key(x)
        if not result or xval > maxval:
            result, maxval = [x], xval
        elif xval == maxval:
            result.append(x)

    return result

def poker(hands):
    "Return the best hand: poker([hand,...]) => hand"
    if not hands:
        return False

    return allmax(hands, key=hand_rank)

def test():
    "Test cases for the functions in poker program"
    sf = "6C 7C 8C 9C TC".split() # Straight Flush
    fk = "9D 9H 9S 9C 7D".split() # Four of a Kind
    fh = "TD TC TH 7C 7D".split() # Full House
    st1 = "AC 2S 3H 4D 5H".split() # Straight
    st2 = "AS 2C 3D 4D 5H".split() # Straight

    assert poker([sf, fk, fh]) == [sf]
    assert poker([fk, fh]) == [fk]
    assert poker([fh, fh]) == [fh,fh]
    assert poker([sf]) == [sf]
    assert poker([sf] + 99*[fh]) == [sf]
    assert poker([st1,st2]) == [st1,st2]

    assert hand_rank(sf) == (8, 10)
    assert hand_rank(fk) == (7, 9, 7)
    assert hand_rank(fh) == (6, 10, 7)

    assert straight([9, 8, 7, 6, 5]) == True
    assert straight([9, 8, 8, 6, 5]) == False

    assert flush(sf) == True
    assert flush(fk) == False

    assert card_ranks(st1) == [5,4,3,2,1]
    assert card_ranks(st2) == [5,4,3,2,1]

    print(deal(4))

    hand_percentages(4000)

    test_shuffler(shuffle,"abcd",10000)

    return 'tests pass'

test()


import whois
from pprint import pprint

domains = '''
aipa.ca
split5.ca

'''

#domains = ''

for d in domains.split('\n'):
	if d:
		print('-'*80)
		print(d)
		w = whois.query(d, ignore_returncode=1)
		if w:
			wd = w.__dict__
			for k, v in wd.items():
				print('%20s\t"%s"' % (k, v))