#%%
import os
import sys
import json
import re
import time
import difflib
from datetime import datetime,timedelta
import requests
from dotenv import load_dotenv  # Handling Passwords and Secret Keys using Environment Variables
from pathlib import Path         #You may explicitly provide a path to your .env file.

env_path=Path('.') / '.env'
load_dotenv(dotenv_path=env_path)

from logging import log
from logging import Logger

#%%

# ====================================================
# defining global variables
# ====================================================

webhook_url=os.environ['WEBHOOK_URL']
slack_bot_user_oauth_token= os.environ['SLACK_BOT_USER_OAUTH_TOKEN']
slack_username= os.environ['SLACK_USERNAME']
slack_channelname= os.environ['SLACK_CHANNELNAME']
github_token= os.environ['GITHUBTOKEN']
schema_file_url= os.environ['SCHEMA_FILE_URL']

now=datetime.now()
current_date_and_time=now.strftime("%D %H:%M:%S")
current_date= now.strftime("%y_%m_%d")

yesterday= now-timedelta(days=1)
yesterday=yesterday.strftime("%y_%m_%d")

# define file names to be compared
file_name_1=f'schema_{yesterday}.rb'
file_name_2=f'schema_{current_date}.rb'

# create log files
change_log_filename = f'change_log_{current_date}.txt'
project_name_and_date= ' Database Schema Change: ' + current_date_and_time + '\n\n'
change_log= open(change_log_filename,'w')
change_log.write(project_name_and_date)

#%%

# ====================================================
# defining functions
# ====================================================

#log process

def _get_logger(name) -> Logger:
    from logging import Formatter,Logger,basicConfig,getLogger,StreamHandler,DEBUG,INFO

    date_format = '%m,%d,%Y %I:%M:%S %p'
    log_format= '%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
    basicConfig(filename= 'etl.log',format=log_format,datefmt=date_format)

    log: Logger = getLogger('Logging')
    log.setLevel(INFO)
    ch=StreamHandler()
    ch.setLevel(DEBUG)
    formatter= Formatter(log_format)
    ch.setFormatter(formatter)
    log.addHandler(ch)

    return log

log: Logger = _get_logger('Logging:')

# =========

def github_download(token,url):

    """
    Call     : github_download(token,url)
    Returns   : file_content
    """

    file_url= url + token

    try:
        # log.info("started download")
        response= requests.get(file_url)

        if response==200:
            file_content=response.text
            #log.info("Downloaded file")
            return file_content

    except:

        status=requests.get(file_url).status_code
        print('Error: ',status)
        return False

#%%
# =========

def write_file(data,file_name):

    """
    Call     :  write_file(data,file_name)
    Returns   : True if able to write the data as a file,otherwise False
    """

    try:
        file= open(file_name,'w')
        file.write(data)
        return True

    except:
        print(f'Error: Could not write {file_name}')
        return False

#%%
# =========

#parse table names from the schema file

def parse_tables(schema_rb):
    """
    Call     :  parse_tables(schema_rb)
    Returns   : A dictionary of table names as key and column definitions from the DDL
    """

    tables={}
    for i in schema_rb:

        try:
            if "create_table" in i:
                table_name= re.search('".*"',i).group().replace('"','') #parse table name

                #each table name will be a key in the table_names dictionary
                tables.update({table_name:[]})

            #following rows will be its value
            elif "end" not in i:
                tables[table_name].append(i.replace('\n',''))

        except:
            continue

    return tables

#%%
#======================

def get_file_content(file_name):
    content= ''

    with open(file_name,'r') as f:
        content=f.read()
    return content

def post_file_to_slack( text, file_name, channelname, file_bytes, file_type= None, title=None):
    return requests.post(
        'https://slack.com/api/files.upload',
        {
            'token': slack_bot_user_oauth_token,
            'filename': file_name,
            'channels': channelname,
            'filetype': 'text',
            'initial_comment': None,
            'title': None

        },
    files= {'file':file_bytes}).json()

# %%
# ==================================
# 1. Download new schema file
# ==================================

try:
    data= github_download(github_token, schema_file_url)
     # write_file(data, file_name_2)

except:

    log.info('Error: Could not download schema.rb')

# %%
# ==================================
# 2. Read files
# ==================================

with open(file_name_1,'r') as file_1:
  file_1_text=file_1.readlines()

with open(file_name_2,'r') as file_2:
  file_2_text=file_2.readlines()

# %%
# ==================================
# 3.  Test 1:  Compare if there are any changes
# ==================================

try:
    assert(file_1_text==file_2_text)
    change_log.write('Test 0: PASS  -  No Schema Change Detected\n')
    log.info('Test 0: PASS  -  No Schema Change Detected\n')

except:
    change_log.write('Test 0: FAIL  - Schema Change Detected\n')
    log.info('Test 0: FAIL  - Schema Change Detected\n')

# ==================================
# 3.  Test 2:  Compare if tables changed
# ==================================

#table_names in table_1 or old file
previous_schema= parse_tables(file_1_text)
new_schema= parse_tables(file_2_text)

previous_schema_tables= set(previous_schema.keys())

#table_names in table_1 or old file
new_schema_tables= set(new_schema.keys())

    # compare files now;

try:
    assert(previous_schema_tables==new_schema_tables)
    change_log.write('Test 1: PASS  -  No changes made to the table names\n')
    log.info('Test 1: PASS  -  No changes made to the table names\n')

except:
    change_log.write('Test 1: FAIL  - Table Name Change Detected\n')
    log.info('Test 0: FAIL  - Table Name Change Detected\n')

    if len(previous_schema_tables.difference(new_schema_tables))>0:
        change_log.write(
            f"""
        Deleted Tables:
                {previous_schema_tables.difference(new_schema_tables)}\n
            """
        )

    if len(new_schema_tables.difference(previous_schema_tables))>0:
        change_log.write(
            f"""
        New Tables:
                {new_schema_tables.difference(previous_schema_tables)}\n
            """
        )

# ==================================
# 3.  Test 3:  Compare column definitions
# ==================================

table_counter=0
for table_name in previous_schema_tables:
    try:
        if table_name not in new_schema_tables:
            continue
        else:
            rows_1=set(previous_schema[table_name])
            rows_2=set(new_schema[table_name])
            assert(rows_1==rows_2)
            #change_log.write('Test 2: PASS  - No column changes were detected ')
            continue

    except:
        if table_name not in new_schema_tables:
            continue
        else:
            rows_1=set(previous_schema[table_name])
            rows_2=set(new_schema[table_name])

            #isolate the error
            if table_counter==0:
                #change_log.write('\n Test 2: FAIL - Column changes detected \n')
                table_counter+=1
            change_log.write(f"""
        Table Name: {table_name} """ )

            if len(rows_1.difference(rows_2))>0:
                #Possible Deletions
                change_log.write(f"""
        Column Differences - Previous Schema:
                {rows_1.difference(rows_2)}
                """
                )

            if len(rows_2.difference(rows_1))>0:
                #Possible Additiona
                change_log.write(f"""
        Column Differences - New Schema:
                {str(rows_2.difference(rows_1))}
                """
                )
change_log.close()

#%%
# ==================================
# 4.  Post Log to Slack
# ==================================

post_file_to_slack(
    text=None,
    file_name=change_log_filename,
    channelname=slack_channelname,
    file_bytes=get_file_content(change_log_filename)
)


#!/usr/bin/env python3
"""Directory handling assistant

Classes
-------
DHandler()
    A collection of methods that can facilitate directory handling
"""

__version__ = '1.0.0'
__author__ = 'Jaewoong Jang'

import os
import sys
import re
import argparse
from distutils.dir_util import copy_tree

class DHandler():
    """A collection of methods that can facilitate directory handling

    This class provides methods that can automate some mundane,
    repetitive directory handling tasks, such as copying a directory
    and its contents to another path.

    Attributes
    ----------
    cwd : str
        The working directory at the time of class instantiation
    border_len : int
        The number of symbols of a border line
    borders : dict
        Storage for border lines of different symbols
    funcs : dict
        Storage for the objects of directory handling methods

    Methods
    -------
    read_argv()
        Read in sys.argv using the argparse module.
    disp_func_run(msg, dfrom='', dto='', border_symb='-')
        Display a message that a function will be run.
    yn_prompt(msg='Continue? (y/n)> ')
        Invoke a y/n prompt.
    exam_exists(d, dflag='dfrom', action='exit', border_symb='*')
        Examine if the designated files exist.
    lst_subdirs(dfrom, ignore=None)
        Return the list of existing subdirectory names.
    deploy_dir(dfrom='', dto='')
        Deploy a directory, including its contents, to another path.
    deploy_empty_subdirs(dfrom='', dto='')
        Deploy empty subdirectories to another path.

    Notes
    -----
    When a directory handling method is newly defined, add the name and
    object of the method as a key-value pair to the funcs attribute;
    a user selects which directory handling method to use via the
    command line argument --func, which will then be used as a key of
    the funcs attribute.
    """

    def __init__(self):
        """Bind the objects of directory handling methods to a dict."""
        self.cwd = os.getcwd()
        self.border_len = 60
        self.borders = {s: s * self.border_len for s in ['-', '=', '+', '*']}
        self.funcs = {
            'deploy_dir': self.deploy_dir,
            'deploy_empty_subdirs': self.deploy_empty_subdirs,
            # ... Add new directory handling functions here.
        }

    def read_argv(self):
        """Read in sys.argv using the argparse module.

        Returns
        -------
        argparse.Namespace
            An object of argparse.Namespace
        """
        parser = argparse.ArgumentParser(
            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
        parser.add_argument('--func',
                            default='deploy_dir',
                            choices=self.funcs.keys(),
                            help='directory handling function')
        parser.add_argument('--dfrom',
                            required=True,
                            help=('the directory from which'
                                  + ' information will be retrieved'))
        parser.add_argument('--dto',
                            required=True,
                            help=('the directory to which the retrieved'
                                  + ' information will be applied'))
        parser.add_argument('--nopause',
                            action='store_true',
                            help=('do not pause the shell'
                                  + ' at the end of the program'))
        return parser.parse_args()

    def disp_func_run(self, msg,
                      dfrom='', dto='', border_symb='-'):
        """Display a message that a function will be run.

        Arguments
        ---------
        msg : str
            The message to be displayed
        dfrom : str
            The original directory (default '')
        dto : str
            The target directory (default '')
        border_symb : str
            A key of the borders attribute (default '-')
        """
        print(self.borders[border_symb])
        print(msg)
        print('From: [{}]'.format(dfrom))
        print('To:   [{}]'.format(dto))
        print(self.borders[border_symb])

    def yn_prompt(self,
                  msg='Continue? (y/n)> '):
        """Invoke a y/n prompt.

        Arguments
        ---------
        msg : str
            The prompt message (default 'Continue? (y/n)> ')

        Returns
        -------
        bool
            True for y or Y, False for n or Y
        """
        while True:
            yn = input(msg)
            if re.match(r'\b[yY]\b', yn):
                return True
            if re.match(r'\b[nN]\b', yn):
                return False

    def exam_exists(self, d,
                    dflag='dfrom', action='exit', border_symb='*'):
        """Examine if the designated files exist.

        Arguments
        ---------
        d : str
            The directory to be examined whether exists
        dflag : str
            A flag differentiating between dfrom and dto
        action : str
            Actions for nonexisting files (default 'exit')
        border_symb : str
            A key of the borders attribute (default '*')

        Returns
        -------
        existing_files : list
            Files found to exist out of the designated files
        """
        if not os.path.exists(d):
            print(self.borders[border_symb])
            print(f'{dflag} [{d}] not found.', end='')
            if action == 'exit':
                print(' Terminating.')
                print(self.borders[border_symb])
                sys.exit()
            print('')  # For action != 'exit'
            print(self.borders[border_symb])
            if action == 'makedirs':
                y = self.yn_prompt(msg='Create? (y/n)> ')
                if y:
                    os.makedirs(d)
                else:
                    return

    def lst_subdirs(self, dfrom,
                    ignore=None):
        """Return the list of existing subdirectory names.

        Arguments
        ---------
        dfrom : str
            The original directory
        ignore : str or list
            Subdirectories to be ignored (default None)

        Returns
        -------
        subdirs : list
            The list of subdirectories found to exist
        """
        subdirs = []
        os.chdir(dfrom)
        for f in os.listdir(dfrom):
            if os.path.isdir(f) and f not in ignore:
                subdirs.append(f)
        os.chdir(self.cwd)
        return subdirs

    def deploy_dir(self,
                   dfrom='', dto=''):
        """Deploy a directory, including its contents, to another path.

        Arguments
        ---------
        dfrom : str
            The original directory (default '')
        dto : str
            The target directory (default '')
        """
        self.disp_func_run('deploy_dir():'
                           + ' Deploying dfrom to dto...',
                           dfrom=dfrom, dto=dto)
        copy_tree(dfrom, dto)
        print('Deployment completed.')

    def deploy_empty_subdirs(self,
                             dfrom='', dto=''):
        """Deploy empty subdirectories to another path.

        Arguments
        ---------
        dfrom : str
            The original directory (default '')
        dto : str
            The target directory (default '')
        """
        self.disp_func_run('deploy_empty_subdirs():'
                           + ' Deploying empty subdirectories...',
                           dfrom=dfrom, dto=dto)
        subdirs = self.lst_subdirs(dfrom, ignore=['__pycache__', '.git'])
        # In dfrom: Exit if dfrom has no subdirectory.
        if not subdirs:
            print('dfrom has no subdirectories. Terminating.')
            return
        # Deploy the subdirectories of dfrom to dto.
        os.chdir(dto)  # CWD --> dto
        for subdir in subdirs:
            if not os.path.isdir(subdir):
                os.mkdir(subdir)
                print('[{}] created.'.format(subdir))
        os.chdir(self.cwd)  # dto --> CWD

if __name__ == '__main__':
    dh = DHandler()

    # I/O
    argv = dh.read_argv()

    # Preprocessing
    dh.exam_exists(argv.dfrom,
                   dflag='dfrom', action='exit')
    dh.exam_exists(argv.dto,
                   dflag='dto', action='makedirs')
    dh.exam_exists(argv.dto,
                   dflag='dto', action='exit')
    argv.dfrom = os.path.abspath(argv.dfrom)
    argv.dto = os.path.abspath(argv.dto)

    # Run the user-requested directory handling method.
    dh.funcs[argv.func](dfrom=argv.dfrom,
                        dto=argv.dto)
    if not argv.nopause:
        input('Press enter to exit...')


from flask import Flask, request

app = Flask(__name__)

stores = [
    {
        "name": "My Store",
        "items": [
            {
                "name": "Chair",
                "price": 15.99
            }
        ]
    },
    {
        "name": "PMGV Store",
        "items": [
            {
                "name": "PC",
                "price": 2515.99
            }
        ]
    }
]

@app.route("/store") # http://127.0.0.1:5000/store
def get_stores():
    return {"stores": stores}

@app.route("/store", methods=['POST'])
def create_store():
    new_store = { "name": "My Store from Home", "items":[] }
    stores.append( new_store )
    return new_store, 201


import torch
import torchvision.utils as vutils

from core.abstract.abcvalidator import ABCValidator

class Validator(ABCValidator):
    def __init__(self, config, model, writer):
        super().__init__(config, model, writer)

        self.gen = model

        # Create batch of latent vectors that we will use to visualize the progression of the generator
        self.fixed_noise = torch.randn(self.config.num_visual_img, self.gen.num_latent_z, 1, 1,
                                       device=self.config.device)

    def step(self, epoch, step):
        results = {
            'ssid': 0,
            'ppim': 0,
        }

        self.gen.eval()

        with torch.no_grad():
            fake_img = self.gen(self.fixed_noise).detach()
            norm_fake_imgs = vutils.make_grid(fake_img, padding=2, normalize=True)

        self.writer.add_image('valid/fake_img', norm_fake_imgs, step)

        return results, 0


"""
Serializers for carts models
"""
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers

from carts.models import Cart, CartItem

class CartSerializer(serializers.ModelSerializer):
    """
    Cart model serializer
    """

    class Meta:
        """
        Tells the fields to include in parsed/json object
        """

        # pylint: disable=protected-access, no-member
        model = Cart
        fields = "__all__"

class CartItemSerializer(serializers.ModelSerializer):
    """
    CartItem model serializer
    """

    def create(self, validated_data):
        """
        Creates a CartItem
        Args:
            validated_data(dict): Value containing verified data
        Returns:
            (CartItem): Value containing created CartItem instance
        """
        # pylint: disable=no-member
        cart = validated_data["cart"]
        filter_item = cart.cart_items.filter(product=validated_data["product"])
        if filter_item.exists():
            cart_item = filter_item.get()
            cart_item.quantity += validated_data["quantity"]
            if cart_item.quantity > cart_item.product.stock_quantity:
                raise serializers.ValidationError(
                    _("Product cannot be added because it's out of stock")
                )
        else:
            cart_item = CartItem.objects.create(**validated_data)
        cart_item.save()
        validated_data["cart"].update_bill()
        return cart_item

    def validate(self, attrs):
        if attrs["product"].stock_quantity < attrs["quantity"]:
            raise serializers.ValidationError(
                _("Product cannot be added because it's out of stock")
            )
        return attrs

    class Meta:
        """
        Tells model and fields to include in parsed/json object
        """

        model = CartItem
        fields = "__all__"


from dsa.errors import UserError, MappingError
from io import BytesIO
import zlib

# Most of these errors should never be seen by a user attempting to supply
# valid PNGs in good faith.
class BAD_PNG_HEADER(UserError):
    """Not a valid PNG file (PNG signature not detected)"""

class PNG_EOF(UserError):
    """Unexpected end of PNG file"""

class PNG_CHECKSUM(UserError):
    """PNG file contained invalid checksum for `{chunk}` chunk"""

class BAD_PLTE(UserError):
    """PNG file has invalid palette (not a multiple of 3 bytes)"""

class BAD_IEND(UserError):
    """PNG file corrupt at end (bad IEND chunk)"""

class UNSUPPORTED_PNG(UserError):
    """PNG file not supported (must be 8bpp palettized, non-interlaced)"""

class BAD_FILTER(MappingError):
    """PNG file had invalid image data (filter method = `{key}`)"""

class DUPLICATE_CHUNK(UserError):
    """PNG file contains disallowed duplicate `{chunk}` chunk"""

class MISSING_CHUNK(MappingError):
    """PNG file missing `{key}` chunk"""

class BAD_PALETTE_DATA(UserError):
    """Palette data must be a multiple of 32 bytes long"""

class TOO_MANY_PALETTES(UserError):
    """Too many palettes (max 16)"""

class BAD_BITMAP_DATA(UserError):
    """Bitmap data must be a multiple of 64 bytes long"""

def _num(quad):
    return int.from_bytes(quad, 'big')

def _quad(value):
    return value.to_bytes(4, 'big')

def _chunk(name, data):
    chunk = name + data
    return _quad(len(data)) + chunk + _quad(zlib.crc32(chunk))

def _compress(rows):
    # No filters are applied by the compressor.
    # We need to prepend a 0 filter-type byte to the beginning of each row.
    return zlib.compress(b'\x00' + b'\x00'.join(rows))

_PNG_SIGNATURE = b'\x89PNG\r\n\x1a\n'

def _to_png(rows, plte):
    # rows = 8bpp raw bitmap data, as a list of bytes objects
    # palette = 48-byte chunk specifying 16 palette indices
    result = bytearray(_PNG_SIGNATURE)
    result.extend(_chunk(
        b'IHDR',
        len(rows[0]).to_bytes(4, 'big') + # width
        len(rows).to_bytes(4, 'big') + # height
        bytes([8, 3, 0, 0, 0]) # bit depth, palettized, not interlaced
    ))
    result.extend(_chunk(b'PLTE', plte))
    result.extend(_chunk(b'IDAT', _compress(rows)))
    result.extend(_chunk(b'IEND', b''))
    return bytes(result)

def _png_chunk_gen(data):
    read = BytesIO(data).read
    header = read(8)
    BAD_PNG_HEADER.require(header == _PNG_SIGNATURE)
    while True:
        size = read(4)
        if not size:
            break
        size = int.from_bytes(size, 'big')
        name = read(4)
        data = read(size)
        checksum = read(4)
        PNG_EOF.require(len(checksum) == 4)
        PNG_CHECKSUM.require(
            _quad(zlib.crc32(name + data)) == checksum, chunk=name
        )
        yield (name, data)

def _validate(plte, iend):
    BAD_PLTE.require(len(plte) % 3 == 0)
    BAD_IEND.require(iend == b'')

def _parse_header(ihdr):
    width, height = _num(ihdr[:4]), _num(ihdr[4:8])
    UNSUPPORTED_PNG.require(ihdr[8:] == b'\x08\x03\x00\x00\x00')
    return width, height

def _process_scanline(method, prev_line, this_line):
    left = 0
    result = bytearray()
    for up, this, diag in zip(prev_line, this_line, bytes(1) + prev_line[:-1]):
        average = (left + up) // 2
        reference = left + up - diag
        paeth = min((left, up, diag), key = lambda x: abs(reference - x))
        prediction = BAD_FILTER.get({
            0: 0, 1: left, 2: up, 3: average, 4: paeth
        }, method)
        # PNG spec says we do unsigned math throughout here.
        left = (this + prediction) & 0xff
        result.append(left)
    return bytes(result)

def _scanlines(width, height, idat):
    data = zlib.decompress(idat)
    bytes_per_line = width + 1
    prev_line = b'\x00' * width
    for line_start in range(0, height*bytes_per_line, bytes_per_line):
        method = data[line_start]
        this_line = data[line_start+1:line_start+bytes_per_line]
        this_line = _process_scanline(method, prev_line, this_line)
        yield this_line
        prev_line = this_line

def _png_data(raw):
    result = {}
    for name, data in _png_chunk_gen(raw):
        if name not in result:
            result[name] = data
            continue
        # concatenate IDAT chunks, refuse duplicates of anything else.
        DUPLICATE_CHUNK.require(name == b'IDAT', chunk=name)
        result[name] += data
    plte = MISSING_CHUNK.get(result, b'PLTE')
    iend = MISSING_CHUNK.get(result, b'IEND')
    _validate(plte, iend)
    width, height = _parse_header(MISSING_CHUNK.get(result, b'IHDR'))
    idat = MISSING_CHUNK.get(result, b'IDAT')
    return plte, idat, width, height

def rgb_to_xy(r, g, b):
    value = ((r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10))
    return value.to_bytes(2, 'little')

def xy_to_rgb(x, y):
    return bytes([
        (x & 0x1f) << 3,
        ((x >> 5) << 3) | ((y & 3) << 6),
        (y << 1) & 0xf8
    ])

def _compact_palette(plte):
    return b''.join(rgb_to_xy(r, g, b) for r, g, b in zip(*([iter(plte)] * 3)))

def _expand_palette(tile):
    return b''.join(xy_to_rgb(x, y) for x, y in zip(*([iter(tile)] * 2)))

def _dummy_rows(count):
    return [
        b''.join(bytes([x]) * 16 for x in range(base, base+16))
        for base in range(0, 16*count, 16)
        for block_row in range(16)
    ]

_DUMMY_PLTE = b''.join(bytes([x]) * 3 for x in range(0, 0x11 * 16, 0x11))

def _unpack_palette(data):
    count, remainder = divmod(len(data), 32)
    BAD_PALETTE_DATA.require(remainder == 0)
    # Interpret as palette data.
    TOO_MANY_PALETTES.require(count <= 16)
    return _to_png(_dummy_rows(count), _expand_palette(data))

def _unpack_bitmap(data, width):
    size = len(data)
    # Data should already be expanded to 8bpp, with 8x8 tiles arranged.
    BAD_BITMAP_DATA.require(size % 64 == 0)
    stride = 8 * width
    rows = [data[i:i+stride] for i in range(0, size, stride)]
    return _to_png(rows, _DUMMY_PLTE)

# Filter interface.
pack_args = ('palette flag', {None: False, 'true': True, 'false': False})
# width is omitted when unpacking a palette.
unpack_args = ('width of image in tiles', 'integer?')

def pack(codec_lookup, data, use_palette):
    plte, idat, width, height = _png_data(data)
    return _compact_palette(plte) if use_palette else b''.join(
        _scanlines(width, height, idat)
    )

class View:
    def __init__(self, codec_lookup, data, width):
        self._raw_size, self._is_palette = len(data), width is None
        self._data = (
            _unpack_palette(data)
            if self._is_palette
            else _unpack_bitmap(data, width)
        )

    @property
    def data(self):
        return self._data

    def pack_params(self, unpacked):
        return self._raw_size, [[str(self._is_palette).lower()]]


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Feb 28 16:39:18 2018

@author: rkoch

Here we extract all 220 bp promoter sequences for all genes. Part 2 does the same only for genes in corems

"""
import os
from Bio import SeqIO
import pickle
os.chdir('/Users/rkoch/Documents/Data_and_Scripts')

with open("MTB_genome_data_12/83332.12.fna") as f:
    record = SeqIO.parse(f, "fasta")
    genome = list(record)[0]

gene_dic = pickle.load(open('Dictionaries/gene_dic.p', 'br'))

"""
#without positions in name
gene_prom_seqs = []

for gene, positions in gene_dic.items():
    sequence = genome[positions[0]:positions[1]+1]
    sequence.id = gene
    sequence.name = ''
    sequence.description = ''
    gene_prom_seqs.append(sequence)

gene_prom_seqs.sort(key = lambda x: x.id)
SeqIO.write(gene_prom_seqs, open('MTB_genome_data_12/gene_promotors.fna', 'w'), "fasta")
"""

#with positions in name
gene_prom_seqs = []

for gene, positions in gene_dic.items():
    start = positions[0]
    end = positions[1]+1
    sequence = genome[start:end]
    sequence.id = '%s:%s-%s'%(gene, start, end)
    sequence.name = ''
    sequence.description = ''
    gene_prom_seqs.append(sequence)

gene_prom_seqs.sort(key = lambda x: x.id)
SeqIO.write(gene_prom_seqs, open('MTB_genome_data_12/gene_promotors.fna', 'w'), "fasta")

###---------------------------------------Part-2-------------------------------------------------###

#a dictionary containing for every corem all genes in the corem
corem_genes = pickle.load(open('./Dictionaries/corems_genes.p', 'rb'))
#flatten und uniquify the list of genes
vs = list(corem_genes.values())
vs = list(set([gene for l in vs for gene in l]))
corem_gene_prom_seqs = []
for gene in vs:
    positions = gene_dic[gene]
    start = positions[0]
    end = positions[1]+1
    sequence = genome[start:end]
    sequence.id = '%s:%s-%s'%(gene, start, end)
    sequence.name = ''
    sequence.description = ''
    corem_gene_prom_seqs.append(sequence)
corem_gene_prom_seqs.sort(key = lambda x: x.id)
SeqIO.write(corem_gene_prom_seqs, open('MTB_genome_data_12/corem_gene_promotors.fna', 'w'), "fasta")


from dsa import *

def build(mat):
    g = {}
    for v, u in mat:
        if v not in g:
            g[v] = set()
        if u not in g:
            g[u] = set()
        g[v].add(u)
    return g

def findSmallestSetOfVertices(n: int, edges: List[List[int]]) -> List[int]:
    adj = build(edges)
    nodes = set(adj.keys())
    print(adj)
    visited = set()

    def dfs(n, isStart=False):
        if n in visited:
            return

        if not isStart:
            visited.add(n)

        for neighbors in adj[n]:
            dfs(neighbors)

    for n in nodes:
        dfs(n, True)

    return list(nodes - visited)

    # find all of the reachable nodes from each edge

res = findSmallestSetOfVertices(6, [[0, 1], [0, 2], [2, 5], [3, 4], [4, 2]])
print(res)

    # def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]:
    #     starts, ends = set(), set()

    #     for x, y in edges:
    #         starts.add(x)
    #         ends.add(y)

    #     return starts - ends


# -*- coding: utf-8 -*-
from datetime import datetime
from dbWrapper import dbWrapper
import pandas as pd
from pyecharts import Bar
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl

db = dbWrapper('postgres-a1mzuj9c.sql.tencentcdb.com')
data = db.getDataByTradingday('20181022')
symbol1 = 'FG901'
symbol2 = 'FG905'
data_1 = data[data.symbol == symbol1]
data_2 = data[data.symbol == symbol2]
data_1 = data_1[['symbol','company','quatity']]
data_2 = data_2[['symbol','company','quatity']]
df = pd.merge(data_1,data_2,on='company',how='inner')
df['director'] = df['quatity_x']*df['quatity_y']
multi_data = pd.DataFrame()
x = []
y = []
for i in range(0,len(df)):
    if df.loc[i,'quatity_x'] > 0 and df.loc[i,'quatity_y'] < 0:
        qty = min(abs(df.loc[i,'quatity_x']),abs(df.loc[i,'quatity_y']))
        str = 'buy '+symbol1+' sell '+symbol2
        a = [df.loc[i,'company'],qty,str]
        x.append(a)
    elif df.loc[i,'quatity_x'] < 0 and df.loc[i,'quatity_y'] > 0:
        qty = min(abs(df.loc[i,'quatity_x']),abs(df.loc[i,'quatity_y']))
        str = 'sell '+symbol1+' buy '+symbol2
        a = [df.loc[i,'company'],qty,str]
        y.append(a)
rst_long = pd.DataFrame(x)
rst_short = pd.DataFrame(y)
if len(rst_long) > 0:
    rst_long.columns = ['company','qty','title']
    rst_long = rst_long.sort_values(by='qty',ascending=True)
if len(rst_short) > 0:
    rst_short.columns = ['company','qty','title']
    rst_short[['qty']] = -rst_short[['qty']]
    rst_short = rst_short.sort_values(by='qty',ascending=False)

# df = pd.DataFrame()
# df.append(rst_long)
# df.append(rst_short)
# print(df)
df = pd.DataFrame()
df = df.append(rst_short)
df = df.append(rst_long)
print(df)
print(df['qty'].values.tolist())
title = 'sp:{}/{}'.format(symbol1,symbol2)
bar = Bar(title)
if len(df) > 0:
    bar.add("持仓量", df['company'].values.tolist(), df['qty'].values.tolist(),is_convert=True)
else:
    bar.add("持仓量",[], [], is_convert=True)
bar.render('./html/spread.html')

app = QApplication([])
view = QWebEngineView()
url_string = "file:///./html/spread.html"
view.load(QUrl(url_string))
view.show()
app.exec_()


import pandas as pd

#example_df = bcr.load_dataset('covid19_tutorial')
df = pd.read_csv('../data/melted_global_covid_data.csv')
df = df[['date', 'Country/Region', 'value', 'Province/State']]
df = df.rename(columns={'Country/Region' : 'country', 'value' : 'n_infected', 'Province/State' : 'Province'})
df['date'] = pd.to_datetime(df['date'], infer_datetime_format=True)

#df = df.drop(columns=["Unnamed: 0"])
#print(df.Country.unique())
#print(len(df.Country.unique()))

#df = df[df.Province.isna()]
df = df.groupby(['date', 'country']).sum().reset_index()
#df.index.name = "index"
df = df.set_index("date")

df.to_csv("cleaned_global_covid_data.csv")

print(df)


import json
from typing import List, Tuple

from django.core.exceptions import BadRequest
from django.http import HttpResponse, HttpRequest, HttpResponseNotFound, HttpResponseNotAllowed, HttpResponseForbidden
from django.views.decorators.csrf import csrf_exempt
from pikapals.models import Port, ServiceProvider, Voyage, Seat

def index(_):
    return HttpResponse("Hello, world")

@csrf_exempt
def port_endpoint(request: HttpRequest):
    response: HttpResponse = HttpResponse("")
    if request.method == "GET":
        response: HttpResponse = _port_get(request)
    elif request.method == "POST":
        response: HttpResponse = _port_post(request)
    elif request.method == "DELETE":
        response: HttpResponse = _port_delete(request)

    return response

def _port_post(request: HttpRequest) -> HttpResponse:
    post_data = request.POST
    if "name" not in post_data.keys():
        raise BadRequest("name is required")

    new_port = Port(name=post_data["name"])
    new_port.save()

    data = {"is_success": True, "data": new_port.to_data()}
    return HttpResponse(json.dumps(data))

def _port_get(request: HttpRequest) -> HttpResponse:
    get_data = request.GET
    if "id" not in get_data.keys():
        # return all ports
        ports = Port.objects.all()
        data = {"is_success": True, "data": [port.to_data() for port in ports]}
        return HttpResponse(json.dumps(data))

    try:
        port = Port.objects.get(id=get_data["id"])
    except Port.DoesNotExist:
        return HttpResponseNotFound()

    data = {"is_success": True, "data": port.to_data()}
    return HttpResponse(json.dumps(data))

def _port_delete(request: HttpRequest) -> HttpResponse:
    delete_data = request.POST
    if "id" not in delete_data.keys():
        raise BadRequest("id is required")

    port = Port.objects.get(id=delete_data["id"])
    port.delete()

    data = {"is_success": True}
    return HttpResponse(json.dumps(data))

@csrf_exempt
def service_provider_endpoint(request: HttpRequest):
    response: HttpResponse = HttpResponse("")
    if request.method == "GET":
        response: HttpResponse = _service_provider_get(request)
    elif request.method == "POST":
        response: HttpResponse = _service_provider_post(request)
    elif request.method == "DELETE":
        response: HttpResponse = _service_provider_delete(request)

    return response

def _service_provider_post(request: HttpRequest) -> HttpResponse:
    post_data = request.POST
    if "name" not in post_data.keys():
        raise BadRequest("name is required")

    new_service_provider = ServiceProvider(name=post_data["name"])
    new_service_provider.save()

    data = {"is_success": True, "data": new_service_provider.to_data()}
    return HttpResponse(json.dumps(data))

def _service_provider_get(request: HttpRequest) -> HttpResponse:
    get_data = request.GET
    if "id" not in get_data.keys():
        # return all service_providers
        service_providers = ServiceProvider.objects.all()
        data = {"is_success": True, "data": [service_provider.to_data() for service_provider in service_providers]}
        return HttpResponse(json.dumps(data))

    try:
        service_provider = ServiceProvider.objects.get(id=get_data["id"])
    except ServiceProvider.DoesNotExist:
        return HttpResponseNotFound()

    data = {"is_success": True, "data": service_provider.to_data()}
    return HttpResponse(json.dumps(data))

def _service_provider_delete(request: HttpRequest) -> HttpResponse:
    delete_data = request.POST
    if "id" not in delete_data.keys():
        raise BadRequest("id is required")

    service_provider = ServiceProvider.objects.get(id=delete_data["id"])
    service_provider.delete()

    data = {"is_success": True}
    return HttpResponse(json.dumps(data))

@csrf_exempt
def voyage_endpoint(request: HttpRequest) -> HttpResponse:
    response: HttpResponse = HttpResponse("")
    if request.method == "GET":
        response: HttpResponse = _voyage_get(request)
    elif request.method == "POST":
        response: HttpResponse = _voyage_create(request)
    return response

def _voyage_get(request: HttpRequest):
    get_data = request.GET
    if "voyage_no" not in get_data.keys():
        voyages = Voyage.objects.all()
        data = {"is_success": True, "data": [voyage.toData() for voyage in voyages]}
        return HttpResponse(json.dumps(data))
    voyage_no = get_data["voyage_no"]
    try:
        voyage = Voyage.objects.get(voyage_no=voyage_no)
    except Voyage.DoesNotExist:
        return HttpResponseNotFound()
    return HttpResponse(json.dumps({"is_success": True, "data": voyage.toData()}))

def _voyage_create(request: HttpRequest):
    try:
        post_data = request.POST
        if "voyage_no" not in post_data.keys():
            raise BadRequest("voyage_no is required")
        if "service_provider_id" not in post_data.keys():
            raise BadRequest("service_provider_id is required")
        if "start_port_id" not in post_data.keys():
            raise BadRequest("start_port_id is required")
        if "destination_port_id" not in post_data.keys():
            raise BadRequest("destination_port_id is required")

        voyage_no = post_data["voyage_no"]
        service_provider = ServiceProvider.objects.get(id=post_data["service_provider_id"])
        start_port = Port.objects.get(id=post_data["start_port_id"])
        destination_port = Port.objects.get(id=post_data["destination_port_id"])
        new_voyage = Voyage(voyage_no=voyage_no, service_provider=service_provider, start_port=start_port,
                            destination_port=destination_port)
        new_voyage.save()

        # add seats
        if "seats" in post_data.keys() and type(post_data["seats"]) is List[Tuple['SeatClass', int, int]]:
            new_voyage.create_seats(post_data["seats"])

        data = {"is_success": True, "data": new_voyage.to_data()}
        return HttpResponse(json.dumps(data))

    except ServiceProvider.DoesNotExist or Port.DoesNotExist:
        return HttpResponseNotFound()

@csrf_exempt
def book_seat_endpoint(request: HttpRequest) -> HttpResponse:
    if request.method != "POST":
        return HttpResponseNotAllowed(["POST"])

    if not request.user.is_authenticated:
        return HttpResponseForbidden()

    if "voyage_no" not in request.POST.keys():
        raise BadRequest("voyage_no is required")
    if "seat_id" not in request.POST.keys():
        raise BadRequest("seat_id is required")

    voyage_no = request.POST["voyage_no"]
    seat_id = request.POST["seat_id"]

    try:
        voyage = Voyage.objects.get(voyage_no=voyage_no)
        seat = Seat.objects.get(id=seat_id)

        if seat.voyage != voyage:
            data = {"is_success": False, "error": "Seat does not belong to voyage"}
            return HttpResponse(json.dumps(data))
        if not seat.available:
            data = {"is_success": False, "error": "Seat is not available"}
            return HttpResponse(json.dumps(data))
        seat.available = False
        seat.booked_by = request.user
        seat.save()
        data = {"is_success": True}
        return HttpResponse(json.dumps(data))
    except Voyage.DoesNotExist or Seat.DoesNotExist:
        return HttpResponseNotFound()


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

n = int(input())+1

e = [0 for _ in range(n)]
e[0] = 1

for i in range (1, n+1):
    sln = silnia(i)
    reszta=1
    for d in range(n):
        e[d] += reszta//sln
        # reszta -=((reszta//sln)*sln)
        # reszta*=10
        reszta = (reszta%sln)*10
    print(e)

for i in range(n-1, 0, -1):
    if e[i] > 9:
        e[i-1] += (e[i] //10)
        e[i] %= 10

print(e[0], end=".")
for i in range(1, n):
    print(e[i], end="")


import os
import re

from avocado import Test
from avocado.utils import process, build, archive, genio, distro
from avocado.utils.software_manager.manager import SoftwareManager

class Blktests(Test):
    '''
    Blktests blktests is a test framework for the Linux kernel block layer
    and storage stack. It is inspired by the xfstests filesystem testing framework.

    :avocado: tags=fs
    '''

    def setUp(self):
        '''
        Setup Blktests
        '''
        self.disk = self.params.get('disk', default='')
        self.dev_type = self.params.get('type', default='')
        smm = SoftwareManager()
        dist = distro.detect()
        if dist.name in ['Ubuntu', 'debian']:
            packages = ['gcc', 'make', 'util-linux',
                        'fio', 'libdevmapper-dev', 'g++']
        else:
            packages = ['gcc', 'make', 'util-linux',
                        'fio', 'device-mapper', 'gcc-c++']

        for package in packages:
            if not smm.check_installed(package) and not smm.install(package):
                self.cancel(package + ' is needed for the test to be run')

        locations = ["https://github.com/osandov/blktests/archive/"
                     "master.zip"]
        tarball = self.fetch_asset("blktests.zip", locations=locations,
                                   expire='7d')
        archive.extract(tarball, self.workdir)
        self.sourcedir = os.path.join(self.workdir, 'blktests-master')

        build.make(self.sourcedir)

    def test(self):

        self.clear_dmesg()
        os.chdir(self.sourcedir)

        genio.write_one_line("/proc/sys/kernel/hung_task_timeout_secs", "0")
        if self.disk:
            os.environ['TEST_DEVS'] = self.disk
        cmd = './check %s' % self.dev_type
        result = process.run(cmd, ignore_status=True, verbose=True)
        if result.exit_status != 0:
            self.fail("test failed")
        dmesg = process.system_output('dmesg')
        match = re.search(br'Call Trace:', dmesg, re.M | re.I)
        if match:
            self.fail("some call traces seen please check")

    def clear_dmesg(self):
        process.run("dmesg -c ", sudo=True)


#!/bin/python

# Complete the function below.
import math

def oct2bin(n):
    return bin(n)[2:] #bin() returns '0bxxxxx',remove first 2 chars

"""
maxXor is O(n) where n is bit length of R
"""
def  maxXor( l,  r):
    L = oct2bin(l)
    R = oct2bin(r)
    lenL = len(L)
    lenR = len(R)

    if lenR > lenL:
        """
        if lenR > lenL, then the biggest bit is 1 for R and 0 for L.
        in this case, maxXor of L <= A <= B <= R is 2^lenR - 1.
        you can think about this case:
        L 01111
        R 10000
        """
        return int(math.pow(2,lenR)) -1
    else:
        """
        else find out on which bit, R is 1 and L is 0.
        we recurse to that case and starts on that bit.
        anything else is same as above case.
        """
        for i in range(1, lenR):
            if L[i] == R[i]:
                continue
            else:
                return int(math.pow(2,lenR-i)) - 1

_l = int(raw_input());
_r = int(raw_input());

res = maxXor(_l, _r);
print(res)


import csv
import pandas as pd
import statistics
import plotly.figure_factory as ff

df=pd.read_csv("HeightWeight.csv")
height=df["Height(Inches)"].to_list()
weight=df["Weight(Pounds)"].to_list()

#height data
mean= statistics.mean(height)
median=statistics.median(height)
stdDev=statistics.stdev(height)
mode=statistics.mode(height)

print("mean, meadian, mode, standard deviation of height is {},{},{},{}".format(mean,median,mode,stdDev))

FirstStart,FirstEnd= mean-stdDev,mean+stdDev
SecondStart,SecondEnd= mean-(2*stdDev),mean+(2*stdDev)
ThirdStart,ThirdEnd= mean-(3*stdDev),mean+(3*stdDev)
listOf1stStdDev=[result for result in height if result>FirstStart and result<FirstEnd]
listOf2ndStdDev=[result for result in height if result>SecondStart and result<SecondEnd]
listOf3rdStdDev=[result for result in height if result>ThirdStart and result<ThirdEnd]

print("{}% of data lies within 1 standard deviation".format(len(listOf1stStdDev)*100.0/len(height)))
print("{}% of data lies within 2 standard deviation".format(len(listOf2ndStdDev)*100.0/len(height)))
print("{}% of data lies within 3 standard deviation".format(len(listOf3rdStdDev)*100.0/len(height)))


#!/usr/bin/python3
# -*- coding: utf-8 -*-

import sys
import json
import os
import logging
import traceback
import uuid
import requests
import queue
import time

sys.path.append('./lib')
sys.path.append('./res')
sys.path.append('./ui')

import res.resources
from ui.mainUI import Ui_stackedUI
from logging import handlers
from PyQt5 import QtCore, QtGui, QtWidgets
from lib.outlook_assistant import poll_availability, make_a_reservation, clear_reservations
from lib.access_tokens import uaid

class QtWidgetLogger(logging.Handler):
    """Custom Logging handler that is able to output stdout to a given QWidget for ex. QTextView"""
    def __init__(self):
        logging.Handler.__init__(self)
        self.outputWidget = None

    def emit(self, record):
        record = self.format(record)
        if record and self.outputWidget is not None:
            if len(record) == 1 and ord(str(record)) == 10:
                return
            else:
                cursor = self.outputWidget.textCursor()
                cursor.movePosition(QtGui.QTextCursor.End)
                cursor.insertText(record + "\r\n")
                self.outputWidget.setTextCursor(cursor)
                self.outputWidget.ensureCursorVisible()

# change workdir to scripts location
os.chdir(os.path.dirname(r'{0}'.format(sys.path[0])))

if not os.path.exists(sys.path[0] + "/logs/"):
    os.makedirs(sys.path[0] + "/logs/")

# setup logging
logger = logging.getLogger('Naurunappula')
logger.setLevel(logging.DEBUG)

fh = handlers.TimedRotatingFileHandler(sys.path[0] + '/logs/debug.log', when="d", interval=1, backupCount=7)
fh.setLevel(logging.DEBUG)

ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

qh = QtWidgetLogger()
qh.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)

logger.addHandler(fh)
logger.addHandler(ch)
logger.addHandler(qh)

data_container = queue.Queue() # used by GAThread

# Subclass QThread to send analytics data to Google Analytics
class GAThread(QtCore.QThread):
    def __init__(self, uaid, parent = None):
        QtCore.QThread.__init__(self, parent)
        self.uaid = uaid
        self.endpoint = 'https://www.google-analytics.com/collect'

    def run(self):
        """Send events to Google Analytics platform"""
        while True:
            try:
                data = data_container.get_nowait()
                if data is not None:
                    payload = {'v':'1',
                               'tid': self.uaid,         # tracking ID
                               'cid': data["uuid"],      # device uuid
                               't': 'event',             # hit type
                               'ec': data["category"],   # event category
                               'ea': data["action"],     # event action
                               'el': data["label"],      # event label
                               'ev': data["value"]       # event value
                        }
                    try:
                        logger.debug("Sending data to Google Analytics: {0}".format(data))
                        requests.post(url = self.endpoint, data = payload, headers = {'User-Agent': 'My User Agent 1.0'})
                    except:
                        logger.error("Failed to send data to Google Analytics. Trying again later.")
                data_container.task_done()
            except queue.Empty:
                pass
            finally:
                time.sleep(1)

# Subclass QThread to poll calendar availability
class CalendarPollerThread(QtCore.QThread):
    statusupdate = QtCore.pyqtSignal(dict)

    def __init__(self, preferences, interval, parent = None):
        QtCore.QThread.__init__(self, parent)
        self.preferences = preferences
        self.interval = interval
        self.working = False
        self.paused = False

    def run(self):
        while True:
            if not self.paused:
                logger.info("Polling meetingroom status")
                self.check_status()
            else:
                logger.info("Calendar polling currently paused")
            time.sleep(self.interval)

    def refresh_status(self):
        self.check_status()

    def check_status(self):
        """Polling method that checks what is the current status of the meetingroom. Reoccurs every 30 seconds"""
        if self.working:
            return

        self.working = True

        result = json.loads(poll_availability(self.preferences))
        self.statusupdate.emit(result)

        self.working = False

    def pause(self):
        self.paused = True

    def unpause(self):
        self.paused = False

    def ispaused(self):
        return self.paused

def sendToGoogleAnalytics(uuid, category, action, label, value = 0):
    payload = {}
    payload["uuid"] = uuid
    payload["category"] = category
    payload["action"] = action
    payload["label"] = label
    payload["value"] = value
    data_container.put(payload)

class Naurunappula(QtWidgets.QMainWindow, Ui_stackedUI):
    """Main class definition that implements Ui_stackedUI and all related events related to widgets defined in it"""
    def __init__(self, workdir="", parent=None):
        QtWidgets.QMainWindow.__init__(self, parent)

        self.uuid = ""

        self.setupUi(self)
        self.setup_uuid()

        self.working = False

        qh.outputWidget = self.txtLogOutput # assign a widget to receive log output. Can be accessed from settings

        # connect QT signals to handler methods
        self.green_btnPage1.clicked.connect(self.start_page2)
        self.red_btnPage1.clicked.connect(self.start_page2)
        self.red_btnPage2.clicked.connect(self.start_page1)
        self.red_btnCancel.clicked.connect(self.clear_reservation)
        self.green_btnDecline.clicked.connect(self.decline_reservation)
        self.green_btnAccept.clicked.connect(self.make_reservation)
        self.green_dialPage2.valueChanged.connect(self.dial_value_changed)

        # connect signals for settings1controls
        self.btnSettings1_Next.clicked.connect(self.start_page2)
        self.btnSettings2_Previous.clicked.connect(self.start_page1)
        self.btnExit.clicked.connect(self.close)
        self.buttonBox.accepted.connect(self.settings_acccepted)
        self.buttonBox.rejected.connect(self.settings_rejected)

        # create an invisible settings button that is always present in the top left corner of the screen
        self.btnSettings = QtWidgets.QPushButton('', self)
        self.btnSettings.setMinimumSize(QtCore.QSize(240, 80))
        self.btnSettings.setMaximumSize(QtCore.QSize(240, 80))
        self.btnSettings.setObjectName("btnSettings")
        self.btnSettings.clicked.connect(self.start_settings_page)

        style = "QPushButton#btnSettings { \
            border-image: url(:/images/blank.png); \
        }"

        self.btnSettings.setStyleSheet(style)
        self.btnSettings.move(40,0) # set absolute position for the button so it stays visible always for the user

        self.settingsPageClicked = 1
        self.settingsPageThreshold = 5 # how many times to push the hidden button to access settings
        self.settingsOpened = False # variable that indicates if user is manipulating settings at the moment

        # preferences dictionary
        self.preferences = {}
        self.preferences["name"] = ""
        self.preferences["email"] = ""
        self.preferences["server"] = ""
        self.preferences["username"] = ""
        self.preferences["password"] = ""

        self.settingsLoaded = False
        self.settingsLoaded = self.load_settings() # load settings from file. If this fails, just assume its a new installation and use default values.

        self.amountofErrors = 0 # amount of network errors happened thusfar in a row
        self.errorThreshold = 2 # how many errors in a row can happen before we show an error screen to the user

        # enable dropshadows
        self.enable_drop_shadow()

        self.initialCheckOk = False

        # thread that updates Google Analytics
        self.AnalyticsThread = GAThread(uaid)
        self.AnalyticsThread.start()

        # thread that updates calendar status
        self.green_lblState_Page2.setText("Varaa Tila
" + str(self.green_dialPage2.value() * 5) + " min")
        self.red_lblState_Page2.setText("{0}\nVaraustiedot".format(self.preferences["name"]))
        self.CalendarPollerThread = CalendarPollerThread(self.preferences, 30)
        self.CalendarPollerThread.statusupdate.connect(self.update_ui)
        self.CalendarPollerThread.start()

        # timer that controls how long we spend time in various of places.
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.start_page1)

    def __del__(self):
        """When exiting, reroute stdout back to sys.__stdout__"""
        sys.stdout = sys.__stdout__

    def setup_uuid(self):
        """Setup UUID for the device. If uuid is already defined, read it from a file"""
        logger.info("Attempting to read device ID")
        file = sys.path[0] + "/uuid"
        if os.path.isfile(file):
            try:
                with open(file) as fileInput:
                    self.uuid = str(fileInput.readline())
                assert uuid.UUID(self.uuid).version == 4
                logger.info("Device ID found {0}".format(self.uuid))
            except Exception:
                logger.error("Failed to read device ID! Check file permissions {0}".format(e))
                sys.exit()
        else:
            logger.info("No device ID detected. Creating a new one")
            try:
                self.uuid = uuid.uuid4()
                with open(file, "w") as fileOutput:
                    fileOutput.write(str(self.uuid))
                logger.info("Device ID {0} assigned to this device.".format(self.uuid))
            except Exception as e:
                logger.error("Failed to save device ID! Check file permissions: {0}".format(e))
                sys.exit()

    """
     QT signal handlers
    """
    def close(self):
        self.close()

    def dial_value_changed(self, value):
        value = value * 5
        self.green_lblState_Page2.setText("Varaa Tila
" + str(value) + " min")
        # reset timer that controls idle timeout
        logger.info("Idle timeout restarted")
        self.timer.start(30000)

    def settings_acccepted(self):
        self.preferences["name"] = self.txtMeetingroom.text()
        self.preferences["email"] = self.txtMeetingroomEmail.text()
        self.preferences["server"] = self.txtServer.text()
        self.preferences["username"] = self.lineUsername.text()
        self.preferences["password"] = self.linePassword.text()
        self.settingsOpened = False
        self.save_settings()
        logger.info("Settings saved!")
        sendToGoogleAnalytics(self.uuid, "Interaction", "Settings", "Settings Accepted", 0)
        self.CalendarPollerThread.refresh_status()
        self.CalendarPollerThread.unpause()

    def settings_rejected(self):
        logger.info("Settings discarded!")
        self.settingsOpened = False
        sendToGoogleAnalytics(self.uuid, "Interaction", "Settings", "Settings Rejected", 0)
        self.CalendarPollerThread.refresh_status()
        self.CalendarPollerThread.unpause()
    """
     Load and save methods for device preferences
    """
    def load_settings(self):
        """Load settings from a predefined file called settings.dat"""
        content = []
        temp_pw = ""
        file = sys.path[0] + "/settings.dat"
        logger.info("Loading settings from file: {0}".format(file))

        try:
            with open(file) as fileInput:
                for line in fileInput:
                    content.append(line)
        except FileNotFoundError:
            logger.error("Failed to load configuration file: {0}".format(traceback.print_exc()))
            return False

        content[4] = content[4].strip()

        # decode password
        for c in content[4]:
            temp_pw += chr(ord(c) - 5)

        self.preferences["name"] = content[0].rstrip('\r\n')
        self.preferences["email"] = content[1].rstrip('\r\n')
        self.preferences["server"] = content[2].rstrip('\r\n')
        self.preferences["username"] = content[3].rstrip('\r\n')
        self.preferences["password"] = temp_pw
        return True

    def save_settings(self):
        """Save settings to file for ex. server address and credentials to access a given resource calendar"""
        content = []
        temp_pw = ""

        # encode password
        for c in self.preferences["password"]:
            temp_pw += chr(ord(c) + 5)

        content.append(self.preferences["name"].strip())
        content.append(self.preferences["email"].strip())
        content.append(self.preferences["server"].strip())
        content.append(self.preferences["username"].strip())
        content.append(temp_pw)

        file = sys.path[0] + "/settings.dat"
        logger.info("Saving settings to file: {0}".format(file))
        with open(file, "w") as fileOutput:
            for row in content:
                fileOutput.write(row + "\n")

    """
     Methods used for creating, cancelling and checking reservations
    """
    def clear_reservation(self):
        """Attempt to clear the current reservation"""
        logger.info("Cancel requested!")
        if clear_reservations(self.preferences):
            sendToGoogleAnalytics(self.uuid, "Interaction", "Cancellation", "OK", 1)
        else:
            sendToGoogleAnalytics(self.uuid, "Interaction", "Cancellation", "NOK", 0)

        self.CalendarPollerThread.refresh_status()

    def make_reservation(self):
        """Attempt to make a reservation"""
        logger.info("Reservation requested!")
        duration = int(self.green_dialPage2.value() * 5)

        if make_a_reservation(self.preferences, duration):
            logger.info("Reservation successful!")
            sendToGoogleAnalytics(self.uuid, "Interaction", "Reservation", "{0} min".format(duration), duration)
        else:
            logger.info("Reservation unsuccessful!")
            sendToGoogleAnalytics(self.uuid, "Interaction", "Reservation", "Failed Reservation", 0)

        self.CalendarPollerThread.refresh_status()

    def decline_reservation(self):
        """User clicked back button to cancel the reservation"""
        logger.info("Reservation cancelled!")
        sendToGoogleAnalytics(self.uuid, "Interaction", "Reservation", "Cancelled Reservation", 0)
        self.start_page1()

    def update_ui(self, result):
        """Handler method that receives input from CalendarPoller thread"""
        if not self.settingsLoaded: # if the device is not configured -> return
            self.green_lblState_Page1.setText("Laite\nKonfiguroimatta")
            self.red_lblState_Page1.setText("Laite\nKonfiguroimatta")
            return

        if result["available"] == "True":
            if result["subject"] == "":
                self.green_lblState_Page1.setText("{0}\nVapaa".format(self.preferences["name"]))
                self.green_lblSubject_Page1.setText("Tila")
            else:
                self.green_lblState_Page1.setText("{0}\nVapaa {1} min".format(self.preferences["name"], int(result["duration"])))
                self.green_lblSubject_Page1.setText(result["subject"])

            self.green_lblNext_Page1.setText("Seuraava varaus")

            if result["start"] == "":
                self.green_lblDuration_Page1.setText("Vapaana")
            else:
                self.green_lblDuration_Page1.setText("{0} - {1}".format(result["start"], result["end"]))

            if int(result["duration"]) == 0 or int(result["duration"]) > 120:
                self.green_dialPage2.setRange(1, 24)
                self.green_dialPage2.setValue(6)
            else:
                numofTicks = self.round_down((int(result["duration"])), 5) / 5
                self.green_dialPage2.setRange(1, numofTicks)
                if numofTicks == 1: # special case: 5 minutes until next meeting
                    self.green_dialPage2.setValue(1)
                elif numofTicks == 2: # special case: 10 minutes until next meeting
                    self.green_dialPage2.setValue(2)
                else:
                    self.green_dialPage2.setValue(3)

            if self.centralstack.currentIndex() != 0:
                self.remove_graphics_effects() # remove fadein effects
                self.centralstack.setCurrentIndex(0) # green background
                self.centralstack.currentWidget().setCurrentIndex(0)
                self.enable_drop_shadow() # and enable dropshadows
                self.CalendarPollerThread.unpause()

            self.initialCheckOk = True
        else:
            if result["subject"] == "Error":
                sendToGoogleAnalytics(self.uuid, "Network", "Status", "Communication Failure", 0)
                self.amountofErrors += 1
                if self.amountofErrors >= self.errorThreshold or self.initialCheckOk is False: # two failures has happened with a communication error.
                    self.red_lblState_Page1.setText("Virhetilanne")
                    self.red_lblSubject_Page1.setText("Virhe")
                    self.red_lblDuration_Page1.setText("Tiedonsiirrossa")
            else:
                self.amountofErrors = 0 # reset error count
                self.red_lblState_Page1.setText("{0}\nVarattu {1} min".format(self.preferences["name"], int(result["duration"])))
                self.red_lblSubject_Page1.setText(result["subject"])
                self.red_lblDuration_Page1.setText("{0} - {1}".format(result["start"], result["end"]))

            if self.centralstack.currentIndex() != 1:
                self.remove_graphics_effects() # remove fadein effects
                self.centralstack.setCurrentIndex(1) # red background
                self.centralstack.currentWidget().setCurrentIndex(0)
                self.enable_drop_shadow() # and enable dropshadows
                self.CalendarPollerThread.unpause()
    """
     Methods used for changing layouts and transitioning from one page to another
    """
    def start_page1(self):
        """UI is based on QStackedWidget. This method changes the "page" to Page 1 of the stack"""
        self.remove_graphics_effects()
        currentLayout = self.centralstack.currentWidget().currentWidget()
        currentStack = self.centralstack.currentWidget()
        self.fade_out(currentLayout).finished.connect(lambda: self.change_layout_anim(currentStack, currentLayout, layout=0))
        self.CalendarPollerThread.unpause()
        logger.info("Idle timeout stopped")
        self.timer.stop()

    def start_page2(self):
        """UI is based on QStackedWidget. This method changes the "page" to Page 2 of the stack"""
        self.remove_graphics_effects()
        currentLayout = self.centralstack.currentWidget().currentWidget()
        currentStack = self.centralstack.currentWidget()
        self.fade_out(currentLayout).finished.connect(lambda: self.change_layout_anim(currentStack, currentLayout, layout=1))
        self.CalendarPollerThread.pause()
        logger.info("Idle timeout started")
        self.timer.start(30000)

    def start_settings_page(self):
        """Change the UI to Settings page"""
        if self.centralstack.currentIndex() == 2: # if settings page is already open, return
            return
        if self.settingsPageClicked <= self.settingsPageThreshold:
            logger.info("Settings page requested! {0}/{1}".format(self.settingsPageClicked, self.settingsPageThreshold))
            self.settingsPageClicked += 1
            return
        else:
            logger.info("Settings page accessible!")
            sendToGoogleAnalytics(self.uuid, "Interaction", "Settings", "Settings Entered", 1)
            self.txtMeetingroom.setText(self.preferences["name"])
            self.txtMeetingroomEmail.setText(self.preferences["email"])
            self.txtServer.setText(self.preferences["server"])
            self.lineUsername.setText(self.preferences["username"])
            self.linePassword.setText(self.preferences["password"])
            self.remove_graphics_effects() # remove fadein effects
            self.centralstack.setCurrentIndex(2) # change to settings page
            self.centralstack.currentWidget().setCurrentIndex(0)
            self.settingsPageClicked = 0
            self.settingsOpened = True
            self.CalendarPollerThread.pause()

    """
     Utility methods used when changing layouts
    """
    def change_layout_anim(self, stack = None, prevlayout = None, layout = 0):
        """When changing the laytout, or page, utilize nice GraphicsEffects to make the transition smoother"""
        if stack == None:
            stack = self.centralstack.currentWidget()
        if prevlayout == None:
            prevLayout = self.centralstack.currentWidget().currentWidget()

        stack.setCurrentIndex(layout)

        self.fade_in(stack.currentWidget()).finished.connect(lambda: self.fade_in(prevlayout).finished.connect(lambda: self.finalize_layout_change(prevlayout)))

    def finalize_layout_change(self, layout):
        self.remove_graphics_effects() # remove fadein effects
        if not self.settingsOpened: # we don't need graphics effect in settings.
            self.enable_drop_shadow() # and enable dropshadows

    """
     Graphics effect utility functions used for fading in / out widgets
     and adding dropshadows to widgets.
    """
    def fade_in(self, widget):
        """Adds a Fade In effect to a given widget"""
        eff = QtWidgets.QGraphicsOpacityEffect()
        widget.setGraphicsEffect(eff)
        self.anim = QtCore.QPropertyAnimation(eff, b"opacity")
        self.anim.setDuration(150)
        self.anim.setStartValue(0)
        self.anim.setEndValue(1)
        self.anim.setEasingCurve(QtCore.QEasingCurve.InOutSine)
        self.anim.start()
        return self.anim

    def fade_out(self, widget):
        """Adds a Fade Out effect to a given widget"""
        eff = QtWidgets.QGraphicsOpacityEffect()
        widget.setGraphicsEffect(eff)
        self.anim = QtCore.QPropertyAnimation(eff, b"opacity")
        self.anim.setDuration(150)
        self.anim.setStartValue(1)
        self.anim.setEndValue(0)
        self.anim.setEasingCurve(QtCore.QEasingCurve.InOutSine)
        self.anim.start()
        return self.anim

    def enable_drop_shadow(self):
        """Enables dropshadows to every suitable QWidget"""
        for widget in self.centralwidget.findChildren(QtWidgets.QWidget):
            effect = QtWidgets.QGraphicsDropShadowEffect();
            effect.setBlurRadius(0);
            effect.setColor(QtGui.QColor(0, 0, 0, 64))
            effect.setOffset(1.5,1.5);
            widget.setGraphicsEffect(effect);

    def remove_graphics_effects(self):
        """Before changing layouts it is necessary to remove any GraphicsEffect that maybe in effect"""
        for widget in self.centralwidget.findChildren(QtWidgets.QWidget):
            widget.setGraphicsEffect(None)

    """
     Other utility methods
    """
    def round_down(self, num, divisor):
        """Utility method used when making reservations. Rounds down a given number to the nearest divisor"""
        return num - (num % divisor)

    def round_up(self, num, divisor):
        """Utility method used when making reservations. Rounds up a given number to the nearest divisor"""
        return num + (divisor % (num % divisor))

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    QtGui.QFontDatabase.addApplicationFont(":fonts/BebasNeue Bold.ttf")
    QtGui.QFontDatabase.addApplicationFont(":fonts/BebasNeue Regular.ttf")
    myWindow = Naurunappula(None, None)

    try:
        if os.uname()[4][:3] == 'arm':
            myWindow.showFullScreen() #if we are running on rpi, run the program fullscreen
    except AttributeError: #attribute error is raised if we try to do this in windows
        pass

    myWindow.show()
    app.exec_()


# -*- coding: utf-8 -*-
"""The app module, containing the app factory function."""
import logging
import sys

from flask import Flask, render_template, globals, request

from flask_uber_clone import commands, public, rider, driver
from flask_uber_clone.extensions import (
    bcrypt,
    cache,
    csrf_protect,
    db,
    debug_toolbar,
    flask_static_digest,
    login_manager,
    migrate,
    flask_seeder,
    flask_breadcrumbs
)

@login_manager.user_loader
def load_user(user_id):
    """
    This will be used many times like on using current_user
    :param user_id: username
    :return: user or none
    """
    # http://librelist.com/browser/flask/2012/4/7/current-blueprint/#44814417e8289f5f5bb9683d416ee1ee
    if not request.endpoint:
        return None

    blueprint = globals.current_app.blueprints[request.blueprint]

    if hasattr(blueprint, "load_user"):
        return blueprint.load_user(user_id)

    # https://flask-login.readthedocs.org/en/latest/#how-it-works
    return None

def create_app(config_object="flask_uber_clone.settings"):
    """Create application factory, as explained here: http://flask.pocoo.org/docs/patterns/appfactories/.

    :param config_object: The configuration object to use.
    """
    app = Flask(__name__.split(".")[0])
    app.config.from_object(config_object)
    register_extensions(app)
    register_blueprints(app)
    register_errorhandlers(app)
    register_shellcontext(app)
    register_commands(app)
    configure_logger(app)
    return app

def register_extensions(app):
    """Register Flask extensions."""
    bcrypt.init_app(app)
    cache.init_app(app)
    db.init_app(app)
    csrf_protect.init_app(app)
    login_manager.init_app(app)
    debug_toolbar.init_app(app)
    migrate.init_app(app, db)
    flask_static_digest.init_app(app)
    flask_seeder.init_app(app, db)
    flask_breadcrumbs.init_app(app, init_menu=False)
    return None

def register_blueprints(app):
    """Register Flask blueprints."""
    app.register_blueprint(public.views.blueprint)
    app.register_blueprint(rider.views.blueprint, url_prefix="/ride")
    app.register_blueprint(driver.views.blueprint, url_prefix="/drive")
    return None

def register_errorhandlers(app):
    """Register error handlers."""

    def render_error(error):
        """Render error template."""
        # If a HTTPException, pull the `code` attribute; default to 500
        error_code = getattr(error, "code", 500)
        return render_template(f"{error_code}.html"), error_code

    for errcode in [401, 404, 500]:
        app.errorhandler(errcode)(render_error)
    return None

def register_shellcontext(app):
    """Register shell context objects."""

    def shell_context():
        """Shell context objects."""
        return {"db": db}

    app.shell_context_processor(shell_context)

def register_commands(app):
    """Register Click commands."""
    app.cli.add_command(commands.test)
    app.cli.add_command(commands.lint)

def configure_logger(app):
    """Configure loggers."""
    handler = logging.StreamHandler(sys.stdout)
    if not app.logger.handlers:
        app.logger.addHandler(handler)


import pandas as pd
import sys
import os
import glob

input_file = pd.read_csv(sys.argv[1])

clean_input_file = input_file[['First Name', 'Last Name', 'CKI District',
 'What CKI Position Do You Have?', 'Email Address','Phone Number',
 'Year in School', 'Favorite Means of Communication',
 'What are some of your hobbies?',
 'What are your favorite movies and/or TV shows?',
 'Why are you applying? What do you hope to get out of this? (Your response will be shared with your partner)',
 'How many holes does a straw have',
 'How often would you like to communicate with your buddy? ']]

df = input_file[['First Name','Last Name',
 'Please answer the following questions: [When you go somewhere for the day, you would prefer to plan what you will do and when.]',
 'Please answer the following questions: [If you were a teacher, you would prefer to teach courses involving opinion/theory over a facts based course.]',
 'Please answer the following questions: [In a group setting you usually are rather quiet and reserved.]',
 'Please answer the following questions: [When making decisions you let your heart rule over your head.]',
 'Please answer the following questions: [You are better at dealing with the unexpected and seeing quickly what should be done compared to following a detailed plan.]',
 'Please answer the following questions: [You consider yourself an out-of-the-box-thinking person.]',
 'Please answer the following questions: [You talk easily to almost anyone for as long as you have to.]',
 'Please answer the following questions: [It’s better to be a person of real feeling compared to being consistently reasonable.]',
 'Please answer the following questions: [Following a set schedule does not appeal to you.]',
 'Please answer the following questions: [You prefer to have friends that are grounded compared to those that are constantly coming up with new ideas.]',
 'Please answer the following questions: [In a large group of people you introduce other people.]',
 'Please answer the following questions: [You usually value emotion more than logic.]',
 'Please answer the following questions: [You plan on attending CKIx 2021.]']]

df.columns = ['First Name', 'Last Name','a','b','c','d','e','f','g','h','i','j','k','l','CKIx']
# + values == J , N, I, F
# - values == P , S, E, T
df.loc[(df.a == 'Strongly Agree'), 'a'] = 3
df.loc[(df.a == 'Moderately Agree'), 'a'] = 2
df.loc[(df.a == 'Slightly Agree'), 'a'] = 1
df.loc[(df.a == 'Strongly Disagree'), 'a'] = -3
df.loc[(df.a == 'Moderately Disagree'), 'a'] = -2
df.loc[(df.a == 'Slightly Disagree'), 'a'] = -1

df.loc[(df.b == 'Strongly Agree'), 'b'] = 3
df.loc[(df.b == 'Moderately Agree'), 'b'] = 2
df.loc[(df.b == 'Slightly Agree'), 'b'] = 1
df.loc[(df.b == 'Strongly Disagree'), 'b'] = -3
df.loc[(df.b == 'Moderately Disagree'), 'b'] = -2
df.loc[(df.b == 'Slightly Disagree'), 'b'] = -1

df.loc[(df.c == 'Strongly Agree'), 'c'] = 3
df.loc[(df.c == 'Moderately Agree'), 'c'] = 2
df.loc[(df.c == 'Slightly Agree'), 'c'] = 1
df.loc[(df.c == 'Strongly Disagree'), 'c'] = -3
df.loc[(df.c == 'Moderately Disagree'), 'c'] = -2
df.loc[(df.c == 'Slightly Disagree'), 'c'] = -1

df.loc[(df.d == 'Strongly Agree'), 'd'] = 3
df.loc[(df.d == 'Moderately Agree'), 'd'] = 2
df.loc[(df.d == 'Slightly Agree'), 'd'] = 1
df.loc[(df.d == 'Strongly Disagree'), 'd'] = -3
df.loc[(df.d == 'Moderately Disagree'), 'd'] = -2
df.loc[(df.d == 'Slightly Disagree'), 'd'] = -1
#invert
df.loc[(df.e == 'Strongly Agree'), 'e'] = -3
df.loc[(df.e == 'Moderately Agree'), 'e'] = -2
df.loc[(df.e == 'Slightly Agree'), 'e'] = -1
df.loc[(df.e == 'Strongly Disagree'), 'e'] = 3
df.loc[(df.e == 'Moderately Disagree'), 'e'] = 2
df.loc[(df.e == 'Slightly Disagree'), 'e'] = 1

df.loc[(df.f == 'Strongly Agree'), 'f'] = 3
df.loc[(df.f == 'Moderately Agree'), 'f'] = 2
df.loc[(df.f == 'Slightly Agree'), 'f'] = 1
df.loc[(df.f == 'Strongly Disagree'), 'f'] = -3
df.loc[(df.f == 'Moderately Disagree'), 'f'] = -2
df.loc[(df.f == 'Slightly Disagree'), 'f'] = -1
#invert
df.loc[(df.g == 'Strongly Agree'), 'g'] = -3
df.loc[(df.g == 'Moderately Agree'), 'g'] = -2
df.loc[(df.g == 'Slightly Agree'), 'g'] = -1
df.loc[(df.g == 'Strongly Disagree'), 'g'] = 3
df.loc[(df.g == 'Moderately Disagree'), 'g'] = 2
df.loc[(df.g == 'Slightly Disagree'), 'g'] = 1

df.loc[(df.h == 'Strongly Agree'), 'h'] = 3
df.loc[(df.h == 'Moderately Agree'), 'h'] = 2
df.loc[(df.h == 'Slightly Agree'), 'h'] = 1
df.loc[(df.h == 'Strongly Disagree'), 'h'] = -3
df.loc[(df.h == 'Moderately Disagree'), 'h'] = -2
df.loc[(df.h == 'Slightly Disagree'), 'h'] = -1

#invert
df.loc[(df.i == 'Strongly Agree'), 'i'] = -3
df.loc[(df.i == 'Moderately Agree'), 'i'] = -2
df.loc[(df.i == 'Slightly Agree'), 'i'] = -1
df.loc[(df.i == 'Strongly Disagree'), 'i'] = 3
df.loc[(df.i == 'Moderately Disagree'), 'i'] = 2
df.loc[(df.i == 'Slightly Disagree'), 'i'] = 1

#invert
df.loc[(df.j == 'Strongly Agree'), 'j'] = -3
df.loc[(df.j == 'Moderately Agree'), 'j'] = -2
df.loc[(df.j == 'Slightly Agree'), 'j'] = -1
df.loc[(df.j == 'Strongly Disagree'), 'j'] = 3
df.loc[(df.j == 'Moderately Disagree'), 'j'] = 2
df.loc[(df.j == 'Slightly Disagree'), 'j'] = 1

#invert
df.loc[(df.k == 'Strongly Agree'), 'k'] = -3
df.loc[(df.k == 'Moderately Agree'), 'k'] = -2
df.loc[(df.k == 'Slightly Agree'), 'k'] = -1
df.loc[(df.k == 'Strongly Disagree'), 'k'] = 3
df.loc[(df.k == 'Moderately Disagree'), 'k'] = 2
df.loc[(df.k == 'Slightly Disagree'), 'k'] = 1

df.loc[(df.l == 'Strongly Agree'), 'l'] = 3
df.loc[(df.l == 'Moderately Agree'), 'l'] = 2
df.loc[(df.l == 'Slightly Agree'), 'l'] = 1
df.loc[(df.l == 'Strongly Disagree'), 'l'] = -3
df.loc[(df.l == 'Moderately Disagree'), 'l'] = -2
df.loc[(df.l == 'Slightly Disagree'), 'l'] = -1

df.loc[(df.CKIx == 'Strongly Agree'), 'CKIx'] = 3
df.loc[(df.CKIx == 'Moderately Agree'), 'CKIx'] = 2
df.loc[(df.CKIx == 'Slightly Agree'), 'CKIx'] = 1
df.loc[(df.CKIx == 'Strongly Disagree'), 'CKIx'] = -3
df.loc[(df.CKIx == 'Moderately Disagree'), 'CKIx'] = -2
df.loc[(df.CKIx == 'Slightly Disagree'), 'CKIx'] = -1

# Scores to Letters
df["IE"] = df['c']+df['g']+df['k']
df['IE'] = df['IE'].apply(lambda x: 'I' if x >=0 else 'E')

df["NS"] = df['b']+df['f']+df['j']
df['NS'] = df['NS'].apply(lambda x: 'N' if x >=0 else 'S')

df["FT"] = df['d']+df['h']+df['l']
df['FT'] = df['FT'].apply(lambda x: 'T' if x >=0 else 'F')

df["JP"] = df['a']+df['e']+df['i']
df['JP'] = df['JP'].apply(lambda x: 'J' if x >0 else 'P')

#x == they are going to CKIx
df['x'] = df['CKIx'].apply(lambda x: 'x' if x >0 else ' ')
df['Type'] = df[df.columns[15:20]].apply(
    lambda x: ''.join(x.dropna().astype(str)),
    axis=1
)

merge_type = df[['First Name', 'Type']]
result = pd.merge(clean_input_file, merge_type, on = "First Name", how = 'outer')
print(result)
dif = result.groupby('Type')

Position_options = (
#'ISTJ',
#'ISTP',
#'ISFJ',
#'ISFP',
#'INFJ',
#'INFP',
#'INTJ',
#'INTP',
#'ESTP',
#'ESTJ',
#'ESFP',
#'ESFJ',
#'ENFP',
#'ENFJ',
#'ENTP',
#'ENTJ'
#'ISTJx',
#'ISTPx',
#'ISFJx',
#'ISFPx',
#'INFJx',
#'INFPx',
'INTJx',
#'INTPx',
#'ESTPx',
#'ESTJx',
#'ESFPx',
#'ESFJx',
#'ENFPx',
#'ENFJx',
#'ENTPx',
#'ENTJx'
)
for x in Position_options:
    hello = dif.get_group( x )
    hello = hello.sample(frac=1).reset_index(drop=True)
    hello.to_csv(x+"_pairing.csv")

all_files = glob.glob( "./*_pairing.csv")

empty = []
empty_2 = []
for x in all_files:
    df = pd.read_csv(x, index_col=None, header=0)
    print(df)
    df = df.rename(columns={'Unnamed: 0':'Partner Number'})
    for x,y in df.iterrows():
        if x == 0:
            df.at[x, 'Unnamed: 0']= 1
            continue
        elif x % 2 == 0:
            y = x+1
            df.at[x, 'Unnamed: 0']= y
            continue
        elif x % 2 != 0:
            df.at[x, 'Unnamed: 0']= x
            continue
    df_2=df.copy()
    df = df.drop_duplicates(subset='Unnamed: 0', keep="first")
    df_2 = df_2.drop_duplicates(subset='Unnamed: 0', keep="last")
    empty.append(df)
    empty_2.append(df_2)

for x in Position_options:
    os.remove(x+"_pairing.csv")

final_2 = pd.concat(empty_2, axis=0, ignore_index=False, sort=False)

final = pd.concat(empty, axis=0, ignore_index=False, sort=False)

final = final.rename(columns={
'First Name':'First Name_1',
'Last Name':'Last Name_1',
'CKI District': 'CKI District_1',
'What CKI Position Do You Have?': 'What CKI Position Do You Have?_1',
'Email Address': 'Email Address_1',
'Phone Number': 'Phone Number_1',
'Year in School': 'Year in School_1',
'Favorite Means of Communication':'Favorite Means of Communication_1',
'What are some of your hobbies?':'What are some of your hobbies?_1',
'What are your favorite movies and/or TV shows?':'What are your favorite movies and/or TV shows?_1',
'Why are you applying? What do you hope to get out of this? (Your response will be shared with your partner)':'Why are you applying? What do you hope to get out of this? (Your response will be shared with your partner)_1',
'How many holes does a straw have':'How many holes does a straw have_1',
'How often would you like to communicate with your buddy? ': 'How often would you like to communicate with your buddy?_1',
'Type':'Type'})

final_2 = final_2.rename(columns={
'First Name':'First Name_2',
'Last Name':'Last Name_2',
'CKI District': 'CKI District_2',
'What CKI Position Do You Have?': 'What CKI Position Do You Have?_2',
'Email Address': 'Email Address_2',
'Phone Number': 'Phone Number_2',
'Year in School': 'Year in School_2',
'Favorite Means of Communication':'Favorite Means of Communication_2',
'What are some of your hobbies?':'What are some of your hobbies?_2',
'What are your favorite movies and/or TV shows?':'What are your favorite movies and/or TV shows?_2',
'Why are you applying? What do you hope to get out of this? (Your response will be shared with your partner)':'Why are you applying? What do you hope to get out of this? (Your response will be shared with your partner)_2',
'How many holes does a straw have':'How many holes does a straw have_2',
'How often would you like to communicate with your buddy? ': 'How often would you like to communicate with your buddy?_2',
'Type':'Type'})

final['Unnamed: 0']=final['Unnamed: 0'].astype(object)
final_2['Unnamed: 0']=final_2['Unnamed: 0'].astype(object)

final_final= pd.merge(left=final, right=final_2, on=['Unnamed: 0','Type'])

final_final.to_csv('Output_pairings_2.csv')

#Copyright 2020, Austin Underwood, All rights reserved.


import datetime
import sys

import numpy as np
import pandas as pd
import plotly.graph_objects as go
import dash
import dash.dcc as dcc
from dash import html
from dash.dependencies import Input, Output

import update_data

##### Define constants #####
PER_POPULATION = 100
COVID_DATA_FILE = "data/COVID-19_aantallen_gemeente_cumulatief.csv"

##### Utility functions #####
def round_significant_digits(x, n=2):
    if type(x) in [int, float]:
        if x == 0:
            return 0
        if x > 1:
            return round(x, n)

    power = 10 ** np.ceil(np.log10(abs(x)))
    return round(x / power, n) * power

## Metrics to display ##
METRICS = ['Total_reported', 'Hospital_admission', 'Deceased']

COVID_DATA = pd.read_csv(
    COVID_DATA_FILE,
    sep=";"
)
COVID_DATA["Date_of_report"] = pd.to_datetime(COVID_DATA["Date_of_report"])

date_now = datetime.datetime.now().date()
date_max_df = COVID_DATA["Date_of_report"].max().date()
print(f"Date now: {date_now} Date in df: {date_max_df}")
if date_now - date_max_df > datetime.timedelta(days=1):
    print("Data is older than 1 day, fetching from URL")
    try:
        update_data.update()
        COVID_DATA = pd.read_csv(
            COVID_DATA_FILE,
            sep=";"
        )
        COVID_DATA["Date_of_report"] = pd.to_datetime(
            COVID_DATA["Date_of_report"])
    except:
        print("Cannot read url reverting to local, reading locally.")

# Remove all data points which don't have a municipality name
COVID_DATA = COVID_DATA[COVID_DATA["Municipality_name"] != ""]
COVID_DATA = COVID_DATA[(COVID_DATA["Municipality_name"].notna())]

## Replace faulty data ##
COVID_DATA["Province"] = COVID_DATA["Province"].replace({
    "FryslÃ¢n": "Friesland",
    "Fryslân": "Friesland",
})
# Disambiguate Mun name by Mun code
COVID_DATA["Municipality_name"] = COVID_DATA.groupby(
    "Municipality_code")["Municipality_name"].transform(lambda x: sorted(x)[0])

##  Read population data ##
mun_population_data = pd.read_csv("data/NL_Population_Latest.csv")
mun_population_data = mun_population_data.rename(columns={
    "PopulationOn31December_20": "Population"
})

## Merge the population data ##
COVID_DATA = COVID_DATA.merge(
    mun_population_data,
    left_on="Municipality_code",
    right_on="Regions",
    how="inner"
)

## Compute daily values ##
COVID_DATA = COVID_DATA.sort_values(
    by=["Municipality_code", "Municipality_name", "Date_of_report"]
)
for metric in METRICS:
    COVID_DATA[f"Daily_{metric}"] = COVID_DATA.groupby("Municipality_name")[metric].transform(
        lambda x: x.diff().fillna(0)
    )

## Aggregate data per province ##
PROVINCE_COLS = [
    f"Daily_{metric}" for metric in METRICS] + METRICS + ["Population"]
PROVINCIAL_COVID_DATA = COVID_DATA.groupby(["Province", "Date_of_report"]).agg(
    {col: np.sum for col in PROVINCE_COLS}
).reset_index()

## Calculate unique municipalities which have both population and covid data ##
UNIQUE_MUNICIPALITIES = np.unique(COVID_DATA["Municipality_name"])
UNIQUE_PROVINCES = np.unique(COVID_DATA["Province"])

## Setup the dash app ##
app = dash.Dash(
    __name__,
    assets_folder='assets',
    url_base_pathname='/',
    show_undo_redo=True,
)
app.title = "COVID-19 Dashboard - The Netherlands"
server = app.server

app.layout = html.Div([
    html.Div([
        html.H6("Select municipalities:"),
        dcc.Dropdown(
            id='selected_municipalities',
            options=[
                {'label': i, 'value': i}
                for i in sorted(UNIQUE_MUNICIPALITIES)
            ],
            value=sorted(["'s-Gravenhage", 'Utrecht', 'Eindhoven', 'Heerlen']),
            style={
                'textAlign': 'center',
                'align': 'center',
                'border-radius': '25px',
                'margin-left': '5%',
                'width': '90%'
            },
            multi=True,
        ),
        html.Br(),
    ], style={
        'width': '40%',
        'display': 'inline-block',
        'vertical-align': 'top',
        'textAlign': 'center',
        'border': '2px black solid',
        'border-radius': '25px',
        'margin': '5px',
        'height': '100%',
    }),
    html.Div([
        html.H6("Metric:"),
        dcc.Dropdown(
            id='covid_metric',
            options=[{'label': i.replace("_", " "), 'value': i}
                     for i in METRICS],
            value=METRICS[0],
            style={
                'textAlign': 'left',
                'align': 'center',
                'border-radius': '25px',
                'margin-left': '5%',
                'width': '90%'
            },
        ),
        html.Br(),
    ], style={
        'width': '15%',
        'display': 'inline-block',
        'vertical-align': 'top',
        'textAlign': 'center',
        'border': '2px black solid',
        'border-radius': '25px',
        'margin': '5px',
        'height': '100%',
    }),
    html.Div([
        html.H6("Moving avg. (days)"),
        dcc.Input(
            id="moving_avg",
            type="number",
            placeholder="Rolling Window",
            min=1,
            max=100,
            step=1,
            value=5,
            debounce=False,
            style={
                'align': 'center',
                'vertical-align': 'top',
                'textAlign': 'left',
                'border-radius': '25px',
                'margin-left': '30%',
                'margin-right': '30%',
                'width': '40%',
            }
        ),
        html.Br(),
        html.Br()
    ], style={
        'width': '15%',
        'display': 'inline-block',
        'vertical-align': 'top',
        'textAlign': 'center',
        'border': '2px black solid',
        'border-radius': '25px',
        'margin': '5px',
        'height': '100%',
    }),
    html.Div([
        html.H6("Data type:"),
        dcc.RadioItems(
            id='data_type',
            options=[
                {'label': i, 'value': i}
                for i in ["Absolute", "Population Adjusted"]
            ],
            value="Population Adjusted",
            style={
                'textAlign': 'left',
                'align': 'center',
                'border-radius': '25px',
                'margin-left': '5%',
                'width': '90%'
            },
        ),
        html.Br(),
    ], style={
        'width': '12%',
        'display': 'inline-block',
        'vertical-align': 'top',
        'textAlign': 'center',
        'border': '2px black solid',
        'border-radius': '25px',
        'margin': '5px',
        'height': '100%',
    }),
    html.Br(),
    html.Div([
        dcc.Graph(
            id='daily_figure',
        )
    ], style={
        'width': '49%',
        'display': 'inline-block',
        'padding': '0 20'
    }),
    html.Div([
        dcc.Graph(
            id='total_figure',
        )
    ], style={
        'width': '49%',
        'display': 'inline-block',
        'padding': '0 20'
    }),
    html.Hr(),
    html.Br(),
    html.Div([
        html.H6("Select provinces:"),
        dcc.Dropdown(
            id='selected_provinces',
            options=[{'label': i, 'value': i} for i in UNIQUE_PROVINCES],
            value=sorted(
                ['Zuid-Holland', 'Noord-Brabant', 'Utrecht', 'Limburg']),
            style={
                'textAlign': 'center',
                'align': 'center',
                'border-radius': '25px',
                'margin-left': '5%',
                'width': '90%'
            },
            multi=True,
        ),
        html.Br(),
    ], style={
        'width': '40%',
        'display': 'inline-block',
        'vertical-align': 'top',
        'textAlign': 'center',
        'border': '2px black solid',
        'border-radius': '25px',
        'margin': '5px'
    }),
    html.Br(),
    html.Div([
        dcc.Graph(
            id='daily_province_figure',
        )
    ], style={
        'width': '49%',
        'display': 'inline-block',
        'padding': '0 20'
    }),
    html.Div([
        dcc.Graph(
            id='total_province_figure',
        )
    ], style={
        'width': '49%',
        'display': 'inline-block',
        'padding': '0 20'
    }),
])

@app.callback(
    [
        Output('daily_figure', 'figure'),
        Output('total_figure', 'figure'),
    ],
    [
        Input('selected_municipalities', 'value'),
        Input('covid_metric', 'value'),
        Input('moving_avg', 'value'),
        Input('data_type', 'value'),
    ]
)
def process_and_render_muns(selected_municipalities, covid_metric, moving_avg, data_type):
    selected_municipalities = sorted(selected_municipalities)

    if len(selected_municipalities) > 0:
        mun_data = COVID_DATA[COVID_DATA["Municipality_name"].isin(
            selected_municipalities)].copy()
    else:
        return go.Figure(), go.Figure()

    if moving_avg not in [None, 0, 1]:
        mun_data[f"Daily_{covid_metric}"] =\
            mun_data.groupby("Municipality_name")[f"Daily_{covid_metric}"].transform(
                lambda x: x[::-1].rolling(
                    window=int(moving_avg),
                    min_periods=1,
                    center=False
                )
                .mean()[::-1]
        )

    if data_type == "Population Adjusted":
        mun_data[f"Daily_{covid_metric}"] = (
            mun_data[f"Daily_{covid_metric}"] / mun_data["Population"] * 100
        )
        mun_data[covid_metric] = (
            mun_data[covid_metric] / mun_data["Population"] * 100
        )

    ## Round the data to 3 significant digits ##
    mun_data[f"Daily_{covid_metric}"] = mun_data[f"Daily_{covid_metric}"].apply(
        lambda x: round_significant_digits(x, 3))
    mun_data[covid_metric] = mun_data[covid_metric].apply(
        lambda x: round_significant_digits(x, 3))

    ## Add figure for daily numbers ##
    daily_mun_figure = go.Figure()
    for grp, df in mun_data.groupby("Municipality_name"):
        daily_mun_figure.add_trace(
            go.Scatter(
                x=df["Date_of_report"],
                y=df[f"Daily_{covid_metric}"],
                name=grp,
                mode="markers+lines",
                line_shape="spline",
                marker={"size": 2},
                hovertemplate="%{x}
%{y}",
            )
        )
    daily_mun_figure.update_layout(
        title=f"Daily {covid_metric} ({data_type})"
        .title()
        .replace("_", " ")
        .replace("Population Adjusted", f"per {PER_POPULATION} people"),
        title_x=0.5,
    )
    daily_mun_figure.update_xaxes(title="Date of report")

    ## Add figure for total numbers ##
    total_mun_figure = go.Figure()
    for grp, df in mun_data.groupby("Municipality_name"):
        total_mun_figure.add_trace(
            go.Scatter(
                x=df["Date_of_report"],
                y=df[covid_metric],
                name=grp,
                mode="markers+lines",
                line_shape="spline",
                marker={"size": 2},
                hovertemplate="%{x}
%{y}",
            )
        )
    total_mun_figure.update_yaxes(title_text="")
    total_mun_figure.update_xaxes(title_text="Date of report")
    total_mun_figure.update_layout(
        title=f"{covid_metric} ({data_type})"
        .title()
        .replace("_", " ")
        .replace("Population Adjusted", f"per {PER_POPULATION} people"),
        title_x=0.5,
    )

    return (daily_mun_figure, total_mun_figure)

@app.callback(
    [
        Output('daily_province_figure', 'figure'),
        Output('total_province_figure', 'figure'),
    ],
    [
        Input('selected_provinces', 'value'),
        Input('covid_metric', 'value'),
        Input('moving_avg', 'value'),
        Input('data_type', 'value'),
    ]
)
def process_and_render_provinces(selected_provinces, covid_metric, moving_avg, data_type):
    if len(selected_provinces) > 0:
        province_data_selected = PROVINCIAL_COVID_DATA[PROVINCIAL_COVID_DATA["Province"].isin(
            selected_provinces)].copy()
    else:
        province_data_selected = PROVINCIAL_COVID_DATA.copy()

    if data_type == "Population Adjusted":
        province_data_selected[f"Daily_{covid_metric}"] = (
            province_data_selected[f"Daily_{covid_metric}"] /
            province_data_selected["Population"] * 100
        )
        province_data_selected[covid_metric] = (
            province_data_selected[covid_metric] /
            province_data_selected["Population"] * 100
        )

    if moving_avg not in [None, 0, 1]:
        province_data_selected[f"Daily_{covid_metric}"] =\
            province_data_selected.groupby("Province")[f"Daily_{covid_metric}"].transform(
            lambda x: x[::-1].rolling(
                window=int(moving_avg),
                min_periods=1,
                center=False
            )
            .mean()[::-1]
        )

    province_data_selected[f"Daily_{covid_metric}"] = province_data_selected[f"Daily_{covid_metric}"].apply(
        round_significant_digits)
    province_data_selected[covid_metric] = province_data_selected[covid_metric].apply(
        round_significant_digits)

    daily_province_figure = go.Figure()
    for grp, df in province_data_selected.groupby("Province"):
        daily_province_figure.add_trace(
            go.Scatter(
                x=df["Date_of_report"],
                y=df[f"Daily_{covid_metric}"],
                name=grp,
                mode="markers+lines",
                line_shape="spline",
                marker={"size": 2},
                hovertemplate="%{x}
%{y}",
            )
        )
    daily_province_figure.update_xaxes(title_text="Date of report")
    daily_province_figure.update_yaxes(title_text="")
    daily_province_figure.update_layout(
        title=f"Daily {covid_metric} ({data_type})"
        .title()
        .replace("_", " ")
        .replace("Population Adjusted", f"per {PER_POPULATION} people"),
        title_x=0.5,
    )

    total_province_figure = go.Figure()
    for grp, df in province_data_selected.groupby("Province"):
        total_province_figure.add_trace(
            go.Scatter(
                x=df["Date_of_report"],
                y=df[covid_metric],
                name=grp,
                mode="markers+lines",
                line_shape="spline",
                marker={"size": 2},
                hovertemplate="%{x}
%{y}",
            )
        )
    total_province_figure.update_xaxes(title_text="Date of report")
    total_province_figure.update_yaxes(title_text="")
    total_province_figure.update_layout(
        title=f"{covid_metric} ({data_type})"
        .title()
        .replace("_", " ")
        .replace("Population Adjusted", f"per {PER_POPULATION} people"),
        title_x=0.5,
    )

    return (daily_province_figure, total_province_figure)

def main():
    APP_PORT = 5005
    time_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(
        f"Starting dashboard for COVID-19 data in The Netherlands at {time_now}")
    app.run_server(
        debug=True,
        host="0.0.0.0",
        port=APP_PORT
    )

if __name__ == "__main__":
    sys.exit(main())