from collections import namedtuple
import os
# from unittest.mock import patch
import datetime
import random

import pytest
import hug
from bson.objectid import ObjectId
from pymongo import MongoClient
from pymongo.uri_parser import parse_uri

from helpers import clean_url, clean_email, hash_password
from db import DB
from middlewares import HostEnvMiddleware, MongoMiddleware

"""
API endpoints test
"""

TEST_MONGO_URL = os.environ.get('MONGODB_URI_TEST')

USERS = (
    {'email': 'testuser1@email.com', 'api_key': 'apikey1'},
    {'email': 'testuser2@email.com', 'api_key': 'apikey2'},
)

def create_fixtures():
    """
    Creating user fixtures for tests
    """
    remove_fixtures()
    with MongoClient(TEST_MONGO_URL) as conn:
        parsed = parse_uri(TEST_MONGO_URL)
        db = conn[parsed['database']]
        # adding user and one url for each user
        for i, user in enumerate(USERS):
            user_id = db.users.insert(user)
            db.urls.insert({
                'code': 'user{}'.format(i),
                'short_url': 'http://ef.me/user{}'.format(i),
                'long_url': 'http://user{}.com'.format(i),
                'url_access': [],
                'created_at': datetime.datetime.now(),
                'created_by': user_id
            })

def remove_fixtures():
    """
    Removing fixtures
    """
    with MongoClient(TEST_MONGO_URL) as conn:
        parsed = parse_uri(TEST_MONGO_URL)
        db = conn[parsed['database']]

        emails = [i['email'] for i in USERS]
        emails.append('testuser3@email.com')
        query = {'email': {'$in': emails}}
        user_ids = [i['_id'] for i in list(db.users.find(query, {'_id': 1}))]
        # removing urls
        db.urls.remove({'created_by': {'$in': user_ids}}, {'multi': True})

        # removing users
        db.users.remove({'_id': {'$in': user_ids}}, {'multi': True})

def setup():
    """
    Creating initial fixtures for tests
    """
    os.environ['MONGODB_URI'] = TEST_MONGO_URL
    os.environ['HOST'] = 'http://ef.me'
    create_fixtures()

def teardown():
    """
    Clear fixtures for tests
    """
    os.environ['MONGODB_URI'] = ''
    os.environ['HOST'] = ''
    remove_fixtures()

def test_short_url():
    """
    test /api/short endpoint
    """
    setup()
    import api
    # bad request without long_url query param
    request_url = '/api/short'
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers)
    assert response.data['error'] == 'long_url GET param missing'

    # bad request without authentication header
    response = hug.test.get(api, request_url)
    assert response.status == '401 Unauthorized'

    # bad request with inexistent authentication header
    headers = {'X-Api-Key': 'not-exists'}
    response = hug.test.get(api, request_url, headers=headers)
    assert response.status == '401 Unauthorized'

    # bad request with invalid url
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers,
                            long_url=(1, 2, 3))
    assert response.data['error'] == 'long_url is not a valid URL'

    # bad request with long code
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers,
                            long_url='www.google.com',
                            code='lllllllllllllllongggggggggg')
    assert response.data['error'] == 'Code param must have a max length of 9'

    #  good request with code generating short_url
    request_url = '/api/short'
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers,
                            long_url='www.google.com', code='abcd')
    assert response.data['short_url'] == 'http://ef.me/abcd'

    # good request for same long url will raise a 409 error
    request_url = '/api/short'
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers,
                            long_url='www.google.com', code='abcd')
    assert response.data['error'] == 'long_url already exists'

    #  good request without generating short_url
    request_url = '/api/short'
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers,
                            long_url='www.google.com/123')
    assert 'short_url' in response.data

    teardown()

def test_expand_url():
    """
    /api/expand endpoint tests
    """
    setup()
    import api

    # bad request with missing short_url
    request_url = '/api/expand'
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers)
    assert response.data['error'] == 'short_url GET param missing'

    # bad request with a not valid url
    request_url = '/api/expand'
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers,
                            short_url=(1, 2, 3))
    assert response.data['error'] == 'short_url is not a valid URL'

    # bad request with a inexistent url
    request_url = '/api/expand'
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers,
                            short_url='http://ef.me/noex')
    assert response.data['error'] == 'short_url does not exist'

    # valid request
    request_url = '/api/expand'
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, request_url, headers=headers,
                            short_url='http://ef.me/user0')
    assert response.data['short_url'] == 'http://ef.me/user0'
    assert response.data['long_url'] == 'http://user0.com'

    teardown()

def test_go_to_url():
    """
    testing /s/:code endpoint
    """
    setup()
    import api

    # test not found
    response = hug.test.get(api, '/s/123')
    assert response.status == '404 Not Found'

    # test 301 response
    response = hug.test.get(api, '/s/user1')
    assert response.status == '301 Moved Permanently'

    teardown()

def test_create_user():
    """
    testing /api/user endpoint
    """
    setup()
    import api

    # bad request with no payload
    response = hug.test.post(api, '/api/user')
    assert response.data['error'] == 'Missing email on body request'

    # bad request with bad email payload
    payload = {'email': (1, 2, 3)}
    response = hug.test.post(api, '/api/user', payload)
    assert response.data['error'] == 'Email not valid'

    # bad request with already added user
    payload = {'email': 'testuser1@email.com'}
    response = hug.test.post(api, '/api/user', payload)
    assert response.data['error'] == 'User already exists'

    # good request with valid payload
    payload = {'email': 'testuser3@email.com'}
    response = hug.test.post(api, '/api/user', payload)
    assert response.status == '200 OK'
    assert 'api_key' in response.data

    teardown()

def test_get_user_urls():
    """
    testing /api/urls endpoint
    """
    setup()
    import api

    # bad request without auth
    response = hug.test.get(api, '/api/urls')
    assert response.status == '401 Unauthorized'

    # get all urls from user1
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, '/api/urls', headers=headers).data

    assert len(response) == 1
    assert response[0]['short_url'] == 'http://ef.me/user0'
    assert response[0]['long_url'] == 'http://user0.com'
    assert response[0]['code'] == 'user0'
    assert response[0]['total_accesses'] == 0

    # add one more access to url on user0 and check the results
    hug.test.get(api, '/s/user0')
    response = hug.test.get(api, '/api/urls', headers=headers).data

    assert len(response) == 1
    assert response[0]['total_accesses'] == 1

    # test pagination
    # adding more urls for user0 and retrieve it
    for i in range(10):
        code = random.randint(4, 99999)
        resp = hug.test.get(api, '/api/short', headers=headers,
                            long_url='http://{}.com'.format(code))
        assert resp.status == '201 Created'

    response = hug.test.get(api, '/api/urls', headers=headers).data
    assert len(response) == 5

    # get page 2
    response = hug.test.get(api, '/api/urls', headers=headers, page=2).data
    assert len(response) == 5

    # get page 3. Should have 1 url only
    response = hug.test.get(api, '/api/urls', headers=headers, page=3).data
    assert len(response) == 1

    teardown()

def test_get_user_url():
    """
    test /api/urls/{code} endpoint
    """
    setup()
    import api

    # bad request without auth
    response = hug.test.get(api, '/api/urls/123')
    assert response.status == '401 Unauthorized'

    # good request with user url
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, '/api/urls/user0', headers=headers)
    assert response.data['short_url'] == 'http://ef.me/user0'
    assert response.data['long_url'] == 'http://user0.com'
    assert response.data['total_accesses'] == 0

    # get url from other user returns 404
    headers = {'X-Api-Key': 'apikey1'}
    response = hug.test.get(api, '/api/urls/user1', headers=headers)
    assert response.data['error'] == 'URL does not exist'

    teardown()

"""
Helpers test
"""

def test_clean_url():
    """
    testing clean_url helper
    """
    bad = 123
    bad2 = ''
    good = 'http://google.com'
    without_scheme = 'google.com'
    with_trailing_slash = 'google.com/'

    with pytest.raises(ValueError):
        clean_url(bad)

    with pytest.raises(ValueError):
        clean_url(bad2)

    assert clean_url(good) == good
    assert clean_url(without_scheme) == good
    assert clean_url(with_trailing_slash) == good

def test_clean_email():
    """
    testing clean_email helper
    """
    bad = '123'
    bad2 = 123
    bad3 = '<<@>>'
    good = 'test@email.com'

    with pytest.raises(ValueError):
        clean_email(bad)

    with pytest.raises(ValueError):
        clean_email(bad2)

    with pytest.raises(ValueError):
        clean_email(bad3)

    assert clean_email(good) == good

def test_hash_password():
    expected = 'd0088c5e26b377da76477cda8d7d2f2e5a3723176eb2a1ddf6c4719d567c3bfe7141f1998a1e3a3cbec86c96740d7d25bc954e2970d4974b66193a9ea210a8af'

    assert hash_password('test@email.com', 'salt123') == expected

"""
Middleware test
"""

def test_env_middleware():
    os.environ['HOST'] = 'http://bit.ly'

    fake_request = namedtuple('Request', 'context')
    fake_response = {}
    req = fake_request(context={})

    e = HostEnvMiddleware()
    e.process_request(req, fake_response)
    assert req.context['host'] == 'http://bit.ly'

    os.environ['HOST'] = 'biggggggggggggghosttttttttttttttt.com'
    e = HostEnvMiddleware()
    req = fake_request(context={})
    with pytest.raises(Exception):
        e.process_request(req, fake_response)

    os.environ['HOST'] = ''

def test_mongo_middleware():
    os.environ['MONGODB_URI'] = TEST_MONGO_URL
    parsed = parse_uri(TEST_MONGO_URL)

    fake_request = namedtuple('Request', 'context')
    fake_response = {}
    req = fake_request(context={})

    m = MongoMiddleware()
    m.process_request(req, fake_response)
    assert isinstance(req.context['db'], DB)
    assert req.context['db'].database == parsed['database']

    m.process_response(req, {}, {})
    assert req.context['db'] is None

    os.environ['MONGODB_URI'] = ''

"""
DB test
"""

def test_sanitize_query():
    bad = ''
    good = {}
    good2 = {'_id': '58d0211ea1711d51401aee4c'}
    assert DB.sanitize_query(bad) is False
    assert DB.sanitize_query(good) == {}
    assert DB.sanitize_query(good2) == {'_id': ObjectId('58d0211ea1711d51401aee4c')}


url = 'http://rest.kegg.jp/'
find = 'find' # Searches databases for a given term
list = 'list' # Lists the entries in a database
link = 'link' # Finds related entries in other databases
conv = 'conv' # Converts between KEDD identifiers and outside identifiers
info = 'info' # Gets information about the given database
get = 'get'   # Returns the given database entry and its associated data
delimiter = '\t'
fields = {"NAME", "DESCRIPTION", "CLASS", "MODULE", "DISEASE", "DRUG", \
"DBLINKS", "ORGANISM", "GENE", "COMPOUND", "KO_PATHWAY"}


izbor = int(input("""Zdravo, ovo je spisak za kupovinu odaberi jednu od sledecih opcija:
1. Dodaj stavku na spisak
2. izlaz
"""))
lista = [ ]
n = int(input("Unesi broj stavki koje kupujemo : "))
if n == 0:
    print ('Uneo si 0 stavki u spisak')

if izbor == 1:

    for i in range(0, n):
        element = [input("Unesi stvaku: "), int(input("Unesi kolicinu: "))]
        lista.append(element)

        print ('Vasa lista za kupovinu je',lista)


n = int(input())
txy = [[0, 0, 0]] + [list(map(int, input().split())) for _ in range(n)]

flag = True
for i in range(1, n + 1):
    t = txy[i][0] - txy[i - 1][0]
    x = abs(txy[i][1] - txy[i - 1][1])
    y = abs(txy[i][2] - txy[i - 1][2])

    if not t >= x + y or not t % 2 == (x + y) % 2:
        flag = False
        break

print('Yes') if flag else print('No')


import os
import numpy as np

def octopuses(lines:list, step_count:int=100):

    def step(arr):
        res = []
        for i in range(len(arr)):
            for k in range(len(arr[0])):
                if arr[i,k]<9:
                    arr[i,k] = arr[i,k] + 1
                else:
                    arr[i,k] = 0
                    res.append((i,k))
        return res

    def bright(arr, i, k):
        if 0 != arr[i,k]:
            arr[i,k] = arr[i,k] + 1
            if arr[i,k]>9:
                arr[i,k] = 0
                return True
        return False

    def process(arr, i, k):
        res = []
        if i-1>=0:
            if bright(arr, i-1, k): res.append((i-1,k))
            if k-1>=0:
                if bright(arr, i-1, k-1): res.append((i-1,k-1))
            if k+1<len(arr[0]):
                if bright(arr, i-1, k+1): res.append((i-1,k+1))
        if i+1<len(arr):
            if bright(arr, i+1, k): res.append((i+1,k))
            if k+1<len(arr[0]):
                if bright(arr, i+1, k+1): res.append((i+1,k+1))
            if k-1>=0:
                if bright(arr, i+1, k-1): res.append((i+1,k-1))
        if k-1>=0:
            if bright(arr, i, k-1): res.append((i,k-1))
        if k+1<len(arr[0]):
            if bright(arr, i, k+1): res.append((i,k+1))

        return res

    data = [[int(i) for i in list(line.strip())] for line in lines]
    arr = np.array(data, dtype='int32')

    flashes = 0
    s = 0
    while s<step_count or step_count==-1:
        s += 1
        res = step(arr)
        flashes += len(res)
        while res:
            (i,k) = res.pop()
            news = process(arr, i, k)
            flashes += len(news)
            res += news

        if step_count == -1:
            if np.max(arr) == 0:
                return s

    return flashes

test_lines = [
    '5483143223',
    '2745854711',
    '5264556173',
    '6141336146',
    '6357385478',
    '4167524645',
    '2176841721',
    '6882881134',
    '4846848554',
    '5283751526',
]

lines = [
    '6636827465',
    '6774248431',
    '4227386366',
    '7447452613',
    '6223122545',
    '2814388766',
    '6615551144',
    '4836235836',
    '5334783256',
    '4128344843',
]

assert octopuses(test_lines, 100) == 1656, "Function is wrong"
print("Part A:", octopuses(lines, 100))
assert octopuses(test_lines, -1) == 195, "Function is wrong"
print("Part B:", octopuses(lines, -1))


import sys
from cravat import BaseAnnotator
from cravat import InvalidData
import sqlite3
import os

class CravatAnnotator(BaseAnnotator):
    def annotate(self, input_data, secondary_data=None):
        q = 'select brs_penetrance, lqt_penetrance, brs_structure, lqt_structure, function, lqt, brs, unaff, other, var, hugo from arrvars where chrom = "{chrom}" and pos = {pos} and ref = "{ref}" and alt = "{alt}"'.format(
            chrom = input_data["chrom"], pos=int(input_data["pos"]), ref = input_data["ref_base"], alt = input_data["alt_base"])
        self.cursor.execute(q)
        row = self.cursor.fetchone()
        if row:
            var = row[9]
            if var == None:
                var = ''
            hugo = row[10]
            link = 'https://oates.app.vumc.org/vancart/'+ hugo + '/variant.php?q=' + var
            if link.endswith("="):
                link = ''
            return {'brs_penetrance': row[0], 'lqt_penetrance': row[1], 'brs_structure': row[2], 'lqt_structure': row[3], 'function': row[4], 'lqt' : row[5], 'brs': row[6], 'unaff': row[7], 'other': row[8], 'link': link }

    def cleanup(self):
        pass

if __name__ == '__main__':
    annotator = CravatAnnotator(sys.argv)
    annotator.run()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Aug 23 17:32:15 2020

geometry based sieving
"""

import os
import pickle

from skimage import measure
import pandas as pd
import numpy as np
import nibabel as nib
from skimage import measure
from sklearn import neighbors

# PROPERTIES = ['area', 'extent', 'filled_area', 'inertia_tensor', 'major_axis_length', 'minor_axis_length'] # 3d compatible
PROPERTIES = ['area', 'eccentricity', 'extent',
              'inertia_tensor', 'major_axis_length', 'minor_axis_length',
              'moments_hu', 'perimeter', 'solidity']
def read_nifti(img_path):
    """
    Wrapper for nibabel to read in NIfTI scans.

    Parameters
    ----------
    img_path : string
        The path to the .nii scan

    Returns
    -------
    A numpy array representing the scan

    """
    raw = nib.load(img_path)
    img = raw.get_fdata()

    return img

def label_2d(im):
    labeled = im.copy()
    vals_seen = []
    adder = 0
    for i in range(labeled.shape[2]):
        sli = im[:,:,i]
        labeled_slice = measure.label(sli)
        labeled_slice = labeled_slice + (adder * (~np.isclose(labeled_slice, 0)))# we are labeling every slice individually, but we don't want to reuse labels between slices
        labeled[:,:,i] = labeled_slice
        the_max = labeled_slice.max()
        if the_max > 0:
            adder = the_max

        vals_seen.extend(np.unique(labeled_slice))
        vals_seen.remove(0)
        '''
        print(f'Vals_seen: {vals_seen}')
        print(f'Adder: {adder}')
        print(f'Unique in this slice: {np.unique(labeled_slice)}')
        print('\n')
        '''
        if len(vals_seen) > len(np.unique(vals_seen)):
            raise Exception(f'Labels are not unique after slice {i}')

    return labeled.astype(int)

def generate_properties(im, props=PROPERTIES):
    """
    Generates geometric properties for shapes in the binary input image

    Parameters
    ----------
    im : TYPE
        DESCRIPTION.
    props : TYPE, optional
        DESCRIPTION

    Returns
    -------
    X_train : TYPE
        DESCRIPTION.

    """
    X_train = pd.DataFrame()

    labeled = label_2d(im)
    for i in range(labeled.shape[2]):
        sli = labeled[:,:,i]
        try:
            X_train = X_train.append(pd.DataFrame(measure.regionprops_table(sli, properties=props)))
        except IndexError:
            pass # happens when the slice has no regions in it

    return X_train

def standardize_data(data, params):

    standard_data = data.copy()

    for col, mean, stddev in zip(data.columns, params[0], params[1]):
        standard_data[col] = (standard_data[col] - mean) / stddev

    return standard_data

def train_and_save(training_data, outloc):
    """
    Trains a LOF algorithm for the purposes of novelty detection and pickles it
    Standardizes the data first (transforms each column by subtracting the mean
    and then dividing by the stddev)

    Parameters
    ----------
    training_data : TYPE
        a pandas DataFrame of the training data.
    out_loc : TYPE
        name of the pickled object to save, which is a tuple with length 2, where
        the first entry is the model. The second is a list of lists, where the first
        list is the list of means used to transform the data and the second is the list
        of the stddevs used to transform the data

    Returns
    -------
     a tuple with length 2, where
        the first entry is the model. The second is a list of lists, where the first
        list is the list of means used to transform the data and the second is the list
        of the stddevs used to transform the data

    """
    standard_data = training_data.copy()

    means = []
    stddevs = []
    for col in training_data.columns:
        mean = training_data[col].mean()
        stddev = training_data[col].std()

        means.append(mean)
        stddevs.append(stddev)

    standard_data = standardize_data(training_data, (means, stddevs))

    lof = neighbors.LocalOutlierFactor(novelty=True)
    lof.fit(standard_data)

    out_obj = (lof, (means, stddevs))
    pickle.dump(out_obj, open(outloc, "wb" ))

    return out_obj

def load_default_model():
    script_folder = os.path.dirname(os.path.realpath(__file__))
    repo_folder = os.path.dirname(script_folder)
    model_loc = os.path.join(repo_folder, 'bin', 'gbs_models', 'gbs_default.pkl')

    lof, params = pickle.load(open(model_loc, 'rb'))

    return lof, params

def sieve_image(im, model_and_params=None, props=None):

    if model_and_params is None:
        model_and_params = load_default_model()
    if props is None:
        props=PROPERTIES

    model = model_and_params[0]
    params = model_and_params[1]

    labeled = label_2d(im)
    #observations = pd.DataFrame(measure.regionprops_table(labeled, properties=props))

    props_with_label = props
    props_with_label.append('label')

    observations = generate_properties(labeled, props=props_with_label)
    labels_only = pd.DataFrame(observations['label'])
    observations_drop = observations.drop(columns='label')

    standard_observations = standardize_data(observations_drop, params)

    predictions = model.predict(standard_observations)
    labels_only['prediction'] = predictions

    to_zero = [row['label'] for i, row in labels_only.iterrows() if row['prediction'] == -1]

    mask = np.isin(labeled, to_zero)

    new_im = im.copy()
    new_im[mask] = 0

    return new_im.astype(int)


import numpy as np
import random
import math
import matplotlib.pyplot as plt

def intersects(s0,s1):
    dx0 = s0[1][0]-s0[0][0]
    dx1 = s1[1][0]-s1[0][0]
    dy0 = s0[1][1]-s0[0][1]
    dy1 = s1[1][1]-s1[0][1]
    p0 = dy1*(s1[1][0]-s0[0][0]) - dx1*(s1[1][1]-s0[0][1])
    p1 = dy1*(s1[1][0]-s0[1][0]) - dx1*(s1[1][1]-s0[1][1])
    p2 = dy0*(s0[1][0]-s1[0][0]) - dx0*(s0[1][1]-s1[0][1])
    p3 = dy0*(s0[1][0]-s1[1][0]) - dx0*(s0[1][1]-s1[1][1])
    return (p0*p1<=0) & (p2*p3<=0)

def randomPath():
    pathList = []
    StartCord = (0,0)
    startDir = 0
    ranStop = random.randint(0, 3)
    hasIntersect = False

    while ranStop > 0:
        ranLength = random.random() * 30 + 20
        newCord = (StartCord[0]+ranLength*(math.cos(math.radians(startDir))),StartCord[1]+ranLength*(math.sin(math.radians(startDir))))
        list2 = [StartCord,newCord]

        for i in pathList:
            list1 = [(pathList[i].startX, pathList[i].startY), (pathList[i].endX, pathList[i].endY)]
            if intersects(list1,list2):
                hasIntersect = True
                break
        if hasIntersect:
            continue

        pathList.append(Line(StartCord,newCord))
        Dir = bool(random.getrandbits(1))

        newAngle = random.random()*135+45
        newcurve = make_curve(newAngle, 10, start_point=[newCord[0],newCord[1]],n_lines=20,left=Dir,start_degree=startDir)
        if Dir:
            startDir = 360 % (startDir+newAngle)
        else:
            startDir = 360 % (startDir-newAngle)
        for i in newcurve:
          pathList.append(newcurve[i])
        StartCord = (newcurve[-1].endX,newcurve[-1].endY)
    return pathList


def even_odd(data, redata):
    if len(data) == 0:
        return redata
    else:
        if data[0] % 2 == 0:
            redata.insert(0, data[0])
            return even_odd(data[1:], redata)
        else:
            redata.append(data[0])
            return even_odd(data[1:], redata)

if __name__ == '__main__':
    print(even_odd([1,2,3,4,5,6,7],[]))
    print(even_odd([1,3,5,7,2,4,6,8],[]))


adjList = {
    'a' : ['b','c','d'],
    'b' : ['a','c'],
    'c' : ['a','b','d','e'],
    'd' : ['a','c','e'],
    'e' : ['c','d','f'],
    'f' : ['e']
    }

'''
visited = {a:1}
# parent = {}
dfsTraversal = []

for node in adjList.keys():
    visited[node] = 0
#     # parent[node] = None

def dfs(source):

    visited[source] = 1
    dfsTraversal.append(source)

    for vertex in adjList[source]: # exploring adjacent vertex of source
        if visited[vertex] == 0:
            # parent[vertex] = source
            dfs(vertex)

dfs('a')
print(dfsTraversal)

'''

visited = set()
dfsTraversal = []

def dfs(source):

    visited.add(source)
    dfsTraversal.append(source)

    for vertex in adjList[source]: # exploring adjacent vertex of source
        if vertex not in visited:
            dfs(vertex)

dfs('a')
print(dfsTraversal)


# https://leetcode.com/problems/n-ary-tree-level-order-traversal/

from typing import List

# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children

class Solution:
    def levelOrder(self, root: 'Node') -> List[List[int]]:
        rst = []
        if not root:
            return rst

        curNodes = [root]
        while curNodes:
            nextNodes = []
            curVals = []
            for node in curNodes:
                curVals.append(node.val)
                if node.children:
                    nextNodes += node.children
            rst.append(curVals)
            curNodes = nextNodes
        return rst


import numpy as np
import time
pi    = np.pi
naxis = np.newaxis
F_2D  = lambda x: np.fft.fft2(x, axes=(0, 1))
IF_2D = lambda x: np.fft.ifft2(x, axes=(0, 1))
F_3D  = lambda x: np.fft.fftn(x, axes=(0, 1, 2))
IF_3D = lambda x: np.fft.ifftn(x, axes=(0, 1, 2))

def pupilGen(fxlin, fylin, wavelength, na, na_in=0.0):
	'''
	pupilGen create a circular pupil function in Fourier space.
	Inputs:
			fxlin     : 1D spatial frequency coordinate in horizontal direction
			fylin     : 1D spatial frequency coordinate in vertical direction
			wavelength: wavelength of incident light
			na        : numerical aperture of the imaging system
			na_in     : put a non-zero number smaller than na to generate an annular function
	Output:
			pupil     : pupil function
	'''
	pupil = np.array(fxlin[naxis, :]**2+fylin[:, naxis]**2 <= (na/wavelength)**2, dtype="float32")
	if na_in != 0.0:
		pupil[fxlin[naxis, :]**2+fylin[:, naxis]**2 < (na_in/wavelength)**2] = 0.0
	return pupil

def _genGrid(size, dx):
	'''
	_genGrid create a 1D coordinate vector.
	Inputs:
			size : length of the coordinate vector
			dx   : step size of the 1D coordinate
	Output:
			grid : 1D coordinate vector
	'''
	xlin = np.arange(size, dtype='complex64')
	return (xlin-size//2)*dx

class Solver3DDPC:
	'''
	Solver3DDPC class provides methods to preprocess 3D DPC measurements and recovers 3D refractive index with Tikhonov or TV regularziation.
	'''
	def __init__(self, dpc_imgs, wavelength, na, na_in, pixel_size, pixel_size_z, rotation, RI_medium):
		'''
		Initialize system parameters and functions for DPC phase microscopy.
		'''
		self.wavelength     = wavelength
		self.na             = na
		self.na_in          = na_in
		self.pixel_size     = pixel_size
		self.pixel_size_z   = pixel_size_z
		self.rotation       = rotation
		self.dpc_num        = len(rotation)
		self.fxlin          = np.fft.ifftshift(_genGrid(dpc_imgs.shape[1], 1.0/dpc_imgs.shape[1]/self.pixel_size))
		self.fylin          = np.fft.ifftshift(_genGrid(dpc_imgs.shape[0], 1.0/dpc_imgs.shape[0]/self.pixel_size))
		self.dpc_imgs       = dpc_imgs.astype('float32')
		self.RI_medium      = RI_medium
		self.window         = np.fft.ifftshift(np.hamming(dpc_imgs.shape[2]))
		self.pupil          = pupilGen(self.fxlin, self.fylin, self.wavelength, self.na)
		self.phase_defocus  = self.pupil*2.0*pi*((1.0/wavelength)**2-self.fxlin[naxis, :]**2-self.fylin[:, naxis]**2)**0.5
		self.oblique_factor = self.pupil/4.0/pi/((RI_medium/wavelength)**2-self.fxlin[naxis, :]**2-self.fylin[:, naxis]**2)**0.5
		self.normalization()
		self.sourceGen()
		self.WOTFGen()

	def normalization(self):
		'''
		Normalize the 3D intensity stacks by their average illumination intensities, and subtract the mean.
		'''
		self.dpc_imgs  /= np.mean(self.dpc_imgs, axis=(0, 1, 2), keepdims=True)
		self.dpc_imgs  -= 1.0

	def sourceGen(self):
		'''
		Generate DPC source patterns based on the rotation angles and numerical aperture of the illuminations.
		'''
		self.source = []
		pupil       = pupilGen(self.fxlin, self.fylin, self.wavelength, self.na, na_in=self.na_in)
		for rot_index in range(self.dpc_num):
			self.source.append(np.zeros((self.dpc_imgs.shape[:2]), dtype='float32'))
			rotdegree = self.rotation[rot_index]
			if rotdegree < 180:
				self.source[-1][self.fylin[:, naxis]*np.cos(np.deg2rad(rotdegree))+1e-15>=
				                self.fxlin[naxis, :]*np.sin(np.deg2rad(rotdegree))] = 1.0
				self.source[-1] *= pupil
			else:
				self.source[-1][self.fylin[:, naxis]*np.cos(np.deg2rad(rotdegree))+1e-15<
				                self.fxlin[naxis, :]*np.sin(np.deg2rad(rotdegree))] = -1.0
				self.source[-1] *= pupil
				self.source[-1] += pupil
		self.source = np.asarray(self.source)

	def sourceFlip(self, source):
		'''
		Flip the sources in vertical and horizontal directions, since the coordinates of the source plane and the pupil plane are opposite.
		'''
		source_flip = np.fft.fftshift(source)
		source_flip = source_flip[::-1, ::-1]
		if np.mod(source_flip.shape[0], 2)==0:
			source_flip = np.roll(source_flip, 1, axis=0)
		if np.mod(source_flip.shape[1], 2)==0:
			source_flip = np.roll(source_flip, 1, axis=1)

		return np.fft.ifftshift(source_flip)

	def WOTFGen(self):
		'''
		Generate the absorption (imaginary part) and phase (real part) weak object transfer functions (WOTFs) using the sources and the pupil.
		'''
		dim_x       = self.dpc_imgs.shape[1]
		dim_y       = self.dpc_imgs.shape[0]
		dfx         = 1.0/dim_x/self.pixel_size
		dfy         = 1.0/dim_y/self.pixel_size
		z_lin       = np.fft.ifftshift(_genGrid(self.dpc_imgs.shape[2], self.pixel_size_z))
		prop_kernel = np.exp(1.0j*z_lin[naxis, naxis, :]*self.phase_defocus[:, :, naxis])
		self.H_real = []
		self.H_imag = []
		for rot_index in range(self.dpc_num):
			source_flip      = self.sourceFlip(self.source[rot_index])
			FSP_cFPG         = F_2D(source_flip[:, :, naxis]*self.pupil[:, :, naxis]*prop_kernel)*\
						       F_2D(self.pupil[:, :, naxis]*prop_kernel*self.oblique_factor[:, :, naxis]).conj()
			self.H_real.append(2.0*IF_2D(1.0j*FSP_cFPG.imag*dfx*dfy))
			self.H_real[-1] *= self.window[naxis, naxis, :]
			self.H_real[-1]  = np.fft.fft(self.H_real[-1], axis=2)*self.pixel_size_z
			self.H_imag.append(2.0*IF_2D(FSP_cFPG.real*dfx*dfy))
			self.H_imag[-1] *= self.window[naxis, naxis, :]
			self.H_imag[-1]  = np.fft.fft(self.H_imag[-1], axis=2)*self.pixel_size_z
			total_source     = np.sum(source_flip*self.pupil*self.pupil.conj())*dfx*dfy
			self.H_real[-1] *= 1.0j/total_source
			self.H_imag[-1] *= 1.0/total_source
			print("3D weak object transfer function {:02d}/{:02d} has been evaluated.".format(rot_index+1, self.dpc_num), end="\r")
		self.H_real = np.array(self.H_real).astype('complex64')
		self.H_imag = np.array(self.H_imag).astype('complex64')

	def _V2RI(self, V_real, V_imag):
		'''
		Convert the complex scattering potential (V) into the refractive index. Imaginary part of the refractive index is dumped.
		'''
		wavenumber  = 2.0*pi/self.wavelength
		B           = -1.0*(self.RI_medium**2-V_real/wavenumber**2)
		C           = -1.0*(-1.0*V_imag/wavenumber**2/2.0)**2
		RI_obj      = ((-1.0*B+(B**2-4.0*C)**0.5)/2.0)**0.5

		return np.array(RI_obj)

	def setRegularizationParameters(self, reg_real=5e-5, reg_imag=5e-5, tau=5e-5, rho = 5e-5):
		'''
		Set regularization parameters for Tikhonov deconvolution and total variation regularization.
		'''
		# Tikhonov regularization parameters
		self.reg_real = reg_real
		self.reg_imag = reg_imag

		# TV regularization parameters
		self.tau      = tau

		# ADMM penalty parameter
		self.rho      = rho

	def _prox_LASSO(self, V1_k, y_DV_k, use_gpu):
		'''
		_prox_LASSO performs the proximal operator and solves the LASSO problem with L1 norm for total variation regularization.
		Inputs:
			V1_k      		: complex scattering potential
			y_DV_k    		: Lagrange multipliers for the gradient vectors of the scattering potential
			use_gpu   		: flag to specify gpu usage
		Output:
			DV_k    		: soft-thresholded gradient vectors of the scattering potential
			DV_k_or_diff    : difference between the thresholded gradient vectors and the original ones
		'''
		if use_gpu:
			shape_3d     = self.dpc_imgs.shape[:3]
			DV_k_or_diff = af.constant(0.0, shape_3d[0], shape_3d[1], shape_3d[2], 6, dtype=af.Dtype.f32)
			DV_k_or_diff[:,:,:,0] = V1_k[:,:,:,0] - af.shift(V1_k[:,:,:,0], 0, -1)
			DV_k_or_diff[:,:,:,1] = V1_k[:,:,:,0] - af.shift(V1_k[:,:,:,0], -1)
			DV_k_or_diff[:,:,:,2] = V1_k[:,:,:,0] - af.shift(V1_k[:,:,:,0], 0, 0, -1)
			DV_k_or_diff[:,:,:,3] = V1_k[:,:,:,1] - af.shift(V1_k[:,:,:,1], 0, -1)
			DV_k_or_diff[:,:,:,4] = V1_k[:,:,:,1] - af.shift(V1_k[:,:,:,1], -1)
			DV_k_or_diff[:,:,:,5] = V1_k[:,:,:,1] - af.shift(V1_k[:,:,:,1], 0, 0, -1)
		else:
			DV_k_or_diff = np.zeros(self.dpc_imgs.shape[:3]+ (6, ), dtype='float32')
			DV_k_or_diff[:,:,:,0] = V1_k[:,:,:,0] - np.roll(V1_k[:,:,:,0], -1, axis=1)
			DV_k_or_diff[:,:,:,1] = V1_k[:,:,:,0] - np.roll(V1_k[:,:,:,0], -1, axis=0)
			DV_k_or_diff[:,:,:,2] = V1_k[:,:,:,0] - np.roll(V1_k[:,:,:,0], -1, axis=2)
			DV_k_or_diff[:,:,:,3] = V1_k[:,:,:,1] - np.roll(V1_k[:,:,:,1], -1, axis=1)
			DV_k_or_diff[:,:,:,4] = V1_k[:,:,:,1] - np.roll(V1_k[:,:,:,1], -1, axis=0)
			DV_k_or_diff[:,:,:,5] = V1_k[:,:,:,1] - np.roll(V1_k[:,:,:,1], -1, axis=2)

		DV_k         = DV_k_or_diff - y_DV_k
		if use_gpu:
			DV_k = af.maxof(DV_k-self.tau/self.rho, 0.0) - af.maxof(-DV_k-self.tau/self.rho, 0.0)
		else:
			DV_k = np.maximum(DV_k-self.tau/self.rho, 0.0) - np.maximum(-DV_k-self.tau/self.rho, 0.0)

		DV_k_or_diff = DV_k - DV_k_or_diff

		return DV_k, DV_k_or_diff

	def _prox_projection(self, V1_k, V2_k, y_V2_k, boundary_constraint):
		'''
		_prox_projection performs Euclidean norm projection to impose positivity or negativity constraints on the scattering potential.
		Inputs:
		   V1_k                : complex scattering potential
		   V2_k                : splitted complex scattering potential
		   y_V2_k              : Lagrange multipliers for the splitted scattering potential
		   boundary_constraint : indicate whether to use positive or negative constraint on the scattering potential
		Output:
		   V2_k                : updated splitted complex scattering potential
		'''
		V2_k   = V1_k + y_V2_k
		V_real = V2_k[:,:,:,1]
		V_imag = V2_k[:,:,:,0]

		if boundary_constraint["real"]=="positive":
			V_real[V_real<0.0] = 0.0
		elif boundary_constraint["real"]=="negative":
			V_real[V_real>0.0] = 0.0

		if boundary_constraint["imag"]=="positive":
			V_imag[V_real<0.0] = 0.0
		elif boundary_constraint["imag"]=="negative":
			V_imag[V_real>0.0] = 0.0

		V2_k[:,:,:,0] = V_imag
		V2_k[:,:,:,1] = V_real

		return V2_k

	def _deconvTikhonov(self, AHA, AHy, determinant, use_gpu):
		'''
		_deconvTikhonov solves a Least-Squares problem with L2 regularization.
		'''
		if use_gpu:
			V_real      = af.real(af.ifft3((AHA[0]*AHy[1]-AHA[2]*AHy[0])/determinant))
			V_imag      = af.real(af.ifft3((AHA[3]*AHy[0]-AHA[1]*AHy[1])/determinant))
		else:
			V_real      = IF_3D((AHA[0]*AHy[1]-AHA[2]*AHy[0])/determinant).real
			V_imag      = IF_3D((AHA[3]*AHy[0]-AHA[1]*AHy[1])/determinant).real

		return V_real, V_imag

	def _deconvTV(self, AHA, determinant, fIntensity, fDx, fDy, fDz, tv_max_iter, boundary_constraint, use_gpu):
		'''
		_deconvTV solves the 3D DPC deconvolution with total variation regularization and boundary value constraints using the ADMM algorithm.
		'''
		AHy         =[(self.H_imag.conj()*fIntensity).sum(axis=0), (self.H_real.conj()*fIntensity).sum(axis=0)]

		if use_gpu:
			shape_3d    = self.dpc_imgs.shape[:3]
			V1_k        = af.constant(0.0, shape_3d[0], shape_3d[1], shape_3d[2], 2, dtype=af.Dtype.f32)
			V2_k        = af.constant(0.0, shape_3d[0], shape_3d[1], shape_3d[2], 2, dtype=af.Dtype.f32)
			DV_k        = af.constant(0.0, shape_3d[0], shape_3d[1], shape_3d[2], 6, dtype=af.Dtype.f32)
			y_DV_k      = af.constant(0.0, shape_3d[0], shape_3d[1], shape_3d[2], 6, dtype=af.Dtype.f32)
			y_V2_k      = af.constant(0.0, shape_3d[0], shape_3d[1], shape_3d[2], 2, dtype=af.Dtype.f32)
			AHy         = [af.to_array(AHy_i) for AHy_i in AHy]
		else:
			V1_k        = np.zeros(self.dpc_imgs.shape[:3]+ (2, ), dtype='float32')
			V2_k        = np.zeros(self.dpc_imgs.shape[:3]+ (2, ), dtype='float32')
			DV_k        = np.zeros(self.dpc_imgs.shape[:3]+ (6, ), dtype='float32')
			y_DV_k      = np.zeros(self.dpc_imgs.shape[:3]+ (6, ), dtype='float32')
			y_V2_k      = np.zeros(self.dpc_imgs.shape[:3]+ (2, ), dtype='float32')

		t_start     = time.time()
		for iteration in range(tv_max_iter):
			# solve Least-Squares
			if use_gpu:
				AHy_k   = [AHy[0]+self.rho*(af.fft3(V2_k[:,:,:,0]-y_V2_k[:,:,:,0])+ af.conjg(fDx)*af.fft3(DV_k[:,:,:,0]+y_DV_k[:,:,:,0])\
														   				          + af.conjg(fDy)*af.fft3(DV_k[:,:,:,1]+y_DV_k[:,:,:,1])\
														   				          + af.conjg(fDz)*af.fft3(DV_k[:,:,:,2]+y_DV_k[:,:,:,2])),\
						   AHy[1]+self.rho*(af.fft3(V2_k[:,:,:,1]-y_V2_k[:,:,:,1])+ af.conjg(fDx)*af.fft3(DV_k[:,:,:,3]+y_DV_k[:,:,:,3])\
														   				          + af.conjg(fDy)*af.fft3(DV_k[:,:,:,4]+y_DV_k[:,:,:,4])\
														   				          + af.conjg(fDz)*af.fft3(DV_k[:,:,:,5]+y_DV_k[:,:,:,5]))]
			else:
				AHy_k   = [AHy[0]+self.rho*(F_3D(V2_k[:,:,:,0]-y_V2_k[:,:,:,0])+ fDx.conj()*F_3D(DV_k[:,:,:,0]+y_DV_k[:,:,:,0])\
														   				       + fDy.conj()*F_3D(DV_k[:,:,:,1]+y_DV_k[:,:,:,1])\
														   				       + fDz.conj()*F_3D(DV_k[:,:,:,2]+y_DV_k[:,:,:,2])),\
						   AHy[1]+self.rho*(F_3D(V2_k[:,:,:,1]-y_V2_k[:,:,:,1])+ fDx.conj()*F_3D(DV_k[:,:,:,3]+y_DV_k[:,:,:,3])\
														   				       + fDy.conj()*F_3D(DV_k[:,:,:,4]+y_DV_k[:,:,:,4])\
														   				       + fDz.conj()*F_3D(DV_k[:,:,:,5]+y_DV_k[:,:,:,5]))]
			V1_k[:,:,:,1],\
			V1_k[:,:,:,0] 	 = self._deconvTikhonov(AHA, AHy_k, determinant, use_gpu)

			# solve LASSO proximal step
			DV_k, DV_k_diff  = self._prox_LASSO(V1_k, y_DV_k, use_gpu)

			# solve Euclidean proximal step
			V2_k             = self._prox_projection(V1_k, V2_k, y_V2_k, boundary_constraint)

			# dual update
			y_DV_k          += DV_k_diff;
			y_V2_k          += V1_k - V2_k;

			print("elapsed time: {:5.2f} seconds, iteration : {:02d}/{:02d}".format(time.time()-t_start, iteration+1, tv_max_iter), end="\r")

		return V1_k[:,:,:,1], V1_k[:,:,:,0]

	def solve(self, method="Tikhonov", tv_max_iter=20, boundary_constraint={"real":"negative", "imag":"negative"}, use_gpu=False):
		'''
		_prox_LASSO performs the proximal operator and solves the LASSO problem with L1 norm for total variation regularization.
		Inputs:
			method   		    : select "Tikhonov" or "TV" deconvolution methods.
			tv_max_iter		    : If "TV" method is used, specify the number of iterations of the ADMM algorithm
			boundary_constraint : indicate whether to use positive or negative constraint on the scattering potential
			use_gpu   		    : flag to specify gpu usage
		Output:
			RI_obj			    : reconstructed 3D refractive index
		'''
		if use_gpu:
			globals()["af"] = __import__("arrayfire")

		AHA         = [(self.H_imag.conj()*self.H_imag).sum(axis=0), (self.H_imag.conj()*self.H_real).sum(axis=0),\
		               (self.H_real.conj()*self.H_imag).sum(axis=0), (self.H_real.conj()*self.H_real).sum(axis=0)]
		fIntensity  = F_3D(self.dpc_imgs).transpose(3, 0, 1, 2).astype('complex64')

		if method == "Tikhonov":
			print("="*10+" Solving 3D DPC with Tikhonov regularization "+"="*10)
			AHA[0]        += self.reg_imag
			AHA[3]        += self.reg_real
			AHy            = [(self.H_imag.conj()*fIntensity).sum(axis=0), (self.H_real.conj()*fIntensity).sum(axis=0)]
			if use_gpu:
				AHA = [af.to_array(AHA_i) for AHA_i in AHA]
				AHy = [af.to_array(AHy_i) for AHy_i in AHy]

			determinant    = AHA[0]*AHA[3]-AHA[1]*AHA[2]
			V_real, V_imag = self._deconvTikhonov(AHA, AHy, determinant, use_gpu)

		elif method == "TV":
			print("="*10+" Solving 3D DPC with total variation regularization and boundary value constraint "+"="*10)
			fDx            = np.zeros(self.dpc_imgs.shape[:3], dtype='complex64')
			fDy            = np.zeros(self.dpc_imgs.shape[:3], dtype='complex64')
			fDz            = np.zeros(self.dpc_imgs.shape[:3], dtype='complex64')
			fDx[0, 0, 0]   = 1.0; fDx[0, -1, 0] = -1.0; fDx = F_3D(fDx).astype('complex64')
			fDy[0, 0, 0]   = 1.0; fDy[-1, 0, 0] = -1.0; fDy = F_3D(fDy).astype('complex64')
			fDz[0, 0, 0]   = 1.0; fDz[0, 0, -1] = -1.0; fDz = F_3D(fDz).astype('complex64')
			AHA[0]        += self.rho*(fDx*fDx.conj() + fDy*fDy.conj() + fDz*fDz.conj() + 1.0)
			AHA[3]        += self.rho*(fDx*fDx.conj() + fDy*fDy.conj() + fDz*fDz.conj() + 1.0)
			if use_gpu:
				AHA = [af.to_array(AHA_i) for AHA_i in AHA]
				fDx = af.to_array(fDx)
				fDy = af.to_array(fDy)
				fDz = af.to_array(fDz)

			determinant    = AHA[0]*AHA[3]-AHA[1]*AHA[2]
			V_real, V_imag = self._deconvTV(AHA, determinant, fIntensity, fDx, fDy, fDz, tv_max_iter, boundary_constraint, use_gpu)
		RI_obj         = self._V2RI(V_real, V_imag)

		return RI_obj


import os
import torch
import pandas as pd
import torchaudio
import cv2
import torchaudio.transforms as T
from torch.utils.data import Dataset
import numpy as np

from .utils_dataset import get_transform

class BatvisionV2Dataset(Dataset):

    def __init__(self, cfg, annotation_file, location_blacklist=None):

        self.cfg = cfg
        self.root_dir = cfg.dataset.dataset_dir
        self.audio_format = cfg.dataset.audio_format

        location_list = os.listdir(self.root_dir)
        if location_blacklist:
            location_list = [location for location in location_list if location not in location_blacklist]
        location_csv_paths = [os.path.join(self.root_dir, location, annotation_file) for location in location_list]

        self.instances = []

        for location_csv in location_csv_paths:
            self.instances.append(pd.read_csv(location_csv))

        self.instances = pd.concat(self.instances)

    def __len__(self):
        return len(self.instances)

    def __getitem__(self, idx):
        # Access instance
        instance = self.instances.iloc[idx]

        # Load path
        depth_path = os.path.join(self.root_dir,instance['depth path'],instance['depth file name'])
        audio_path = os.path.join(self.root_dir,instance['audio path'],instance['audio file name'])

        ## Depth
        # Load depth map
        depth = np.load(depth_path).astype(np.float32)
        depth = depth / 1000 # to go from mm to m
        if self.cfg.dataset.max_depth:
            depth[depth > self.cfg.dataset.max_depth] = self.cfg.dataset.max_depth
        # Transform
        depth_transform = get_transform(self.cfg, convert =  True, depth_norm = self.cfg.dataset.depth_norm)
        gt_depth = depth_transform(depth)

        ## Audio
        # Load audio binaural waveform
        waveform, sr = torchaudio.load(audio_path)
        # STFT parameters for full length audio
        win_length = 200
        n_fft = 400
        hop_length = 100

        # Cut audio to fit max depth
        if self.cfg.dataset.max_depth:
            cut = int((2*self.cfg.dataset.max_depth / 340) * sr)
            waveform = waveform[:,:cut]
            # Update STFT parameters
            win_length = 64
            n_fft = 512
            hop_length=64//4

        # Process sound
        if 'spectrogram' in self.audio_format:
            if 'mel' in self.audio_format:
                spec = self._get_melspectrogram(waveform, n_fft = n_fft, power = 1.0, win_length = win_length)
            else:
                spec = self._get_spectrogram(waveform, n_fft = n_fft, power = 1.0, win_length = win_length, hop_length =  hop_length)
            spec_transform =  get_transform(self.cfg, convert = False) # convert False because already a tensor
            audio2return = spec_transform(spec)
        elif 'waveform' in self.audio_format:
            audio2return = waveform

        return audio2return, gt_depth

    # audio transformation: spectrogram
    def _get_spectrogram(self, waveform, n_fft = 400, power = 1.0, win_length = 400, hop_length=100):

        spectrogram = T.Spectrogram(
          n_fft=n_fft,
          win_length=win_length,
          power=power,
          hop_length=hop_length,
        )
        #db = T.AmplitudeToDB(stype = 'magnitude')
        return spectrogram(waveform)

    # audio transformation: mel spectrogram
    def _get_melspectrogram(self, waveform, n_fft = 400, power = 1.0, win_length = 400, f_min = 20.0, f_max = 20000.0):

        melspectrogram = T.MelSpectrogram(sample_rate = 44100,
          n_fft=n_fft,
          win_length=win_length,
          power=power,
          f_min = f_min,
          f_max = f_max,
          n_mels = 32,
        )
        return melspectrogram(waveform)


import sys
import heapq

n = int(sys.stdin.readline())

heap = []
computers = [0 for _ in range(n)]
count = [0 for _ in range(n)]

su = 0

for _ in range(n):
    p,q = map(int, sys.stdin.readline().split())
    heapq.heappush(heap, [p,q])

while heap:
    temp = heapq.heappop(heap)
    for i in range(len(computers)):
        if computers[i] <= temp[0]:
            if computers[i] == 0:
                su += 1
            computers[i] = temp[1]
            count[i] += 1
            break

print(su)

for i in count:
    if i == 0:
        pass
    else:
        print(i, end= " ")

백준/Gold/12764. 싸지방에 간 준하/싸지방에 간 준하.py

싸지방에 간 준하.py


def minimumSwaps(arr):
    count = 0
    for i in range(len(arr)):
        while arr[i] != i+1:
            temp = arr[i];
            arr[i] = arr[temp-1];
            arr[temp-1] = temp;
            count +=1;
    return count;
n=int(input())
a=list(map(int,input().split()))
print(minimumSwaps(a))


import numpy as np
import itertools
import argparse

cards = ['A', 'K', 'Q', 'J', '10', '9', '8', '7', '6', '5', '4', '3', '2']
suits = ['S', 'H', 'C', 'D']

class Card:
    def __init__(self, val, suit):
        self.val = val
        self.suit = suit

    def __str__(self):
        return f'{self.val} {self.suit}'

class Hand:
    def __init__(self, card1, card2):
        self.card1 = card1
        self.card2 = card2
        self.hand_counts = {
        9 : [0, 'Straight Flush'],
        8 : [0, 'Four of a Kind'],
        7 : [0, 'Full House'],
        6 : [0, 'Flush'],
        5 : [0, 'Straight'],
        4 : [0, 'Three of a Kind'],
        3 : [0, 'Two Pair'],
        2 : [0, 'Pair'],
        1 : [0, 'High Card'],
        }

    def count(self, n):
        self.hand_counts[n][0] += 1

    def __str__(self):
        res = f'{self.card1} {self.card2} makes:\n'
        pct = np.asarray([_[0] for _ in self.hand_counts.values()])
        pct = pct/pct.sum()*100
        for i, hand in enumerate(self.hand_counts.values()):
            res += f'{hand[1]}: {round(pct[i], 4)}%\n'
        return res

value = {c:13-i for i, c in enumerate(cards)}

def high_card(cards):
    return max([value[c.val] for c in cards])

def same_suit(cards):
    return len(set([c.suit for c in cards])) == 1

def is_straight(cards):
    sc = sorted(cards, key=lambda x: value[x.val])
    prev = value[sc[0].val]
    if value[sc[1].val] == 1 and prev == 13:
        prev = 0
    for j in range(1, len(cards)):
        curr = value[sc[j].val]
        if curr != prev+1:
            return False
        prev = curr
    return True

def is_4_of_a_kind(cards):
    _, counts = get_same_cards(cards)
    if len(counts) == 2 and counts.max() == 4:
        return True
    return False

def is_full_house(cards):
    _, counts = get_same_cards(cards)
    if len(counts) == 2 and counts.max() == 3:
        return True
    return False

def is_trio(cards):
    _, counts = get_same_cards(cards)
    if len(counts) == 3 and counts.max() == 3:
        return True
    return False

def is_2_pair(cards):
    _, counts = get_same_cards(cards)
    if len(counts) == 3 and counts.max() == 2:
        return True
    return False

def is_pair(cards):
    _, counts = get_same_cards(cards)
    if len(counts) == 4:
        return True
    return False

def get_same_cards(cards):
    vals = np.asarray([value[c.val] for c in cards])
    return np.unique(vals, return_counts=True)

def get_val(vals, counts, c):
    return sorted(vals[counts == c], key=lambda x:-x)

def hand(cards):
    hc = high_card(cards)
    vals, counts = get_same_cards(cards)
    if same_suit(cards) and is_straight(cards):
        return (9, [hc])
    elif is_4_of_a_kind(cards):
        f = get_val(vals, counts, 4)
        return (8, f)
    elif is_full_house(cards):
        f1 = get_val(vals, counts, 3)
        f2 = get_val(vals, counts, 2)
        return (7, f1 + f2)
    elif same_suit(cards):
        return (6, [hc])
    elif is_straight(cards):
        return (5, [hc])
    elif is_trio(cards):
        f1 = get_val(vals, counts, 3)
        f2 = get_val(vals, counts, 1)
        return (4, f1 + f2)
    elif is_2_pair(cards):
        f1 = get_val(vals, counts, 2)
        f2 = get_val(vals, counts, 1)
        return (3, f1 + f2)
    elif is_pair(cards):
        f1 = get_val(vals, counts, 2)
        f2 = get_val(vals, counts, 1)
        return (2, f1 + f2)
    else:
        return (1, get_val(vals, counts, 1))

def get_best_hand(all_cards):
    all_hands = []
    for cards in itertools.combinations(all_cards, 5):
        all_hands.append(hand(cards))

    return max(all_hands)

def draw_cards(Deck, n):
    cards = []
    for _ in range(n):
        cards.append(Deck.pop(0))
    return cards

def comp_two_hands(hand1, hand2, Deck):
    table = draw_cards(Deck, 5)
    bh1 = get_best_hand(hand1+table)
    bh2 = get_best_hand(hand2+table)
    if bh1 > bh2:
        return -1, bh1, bh2
    elif bh1 < bh2:
        return 1, bh1, bh2
    else:
        return 0, bh1, bh2

parser = argparse.ArgumentParser()
parser.add_argument('--hand1', type=str, required=True)
parser.add_argument('--hand2', type=str)
parser.add_argument('--comp', action='store_true')
parser.add_argument('--overall_equity', action='store_true')

args = parser.parse_args()

def parse_hand(hand):
    return [_.split(' ') for _ in hand.split(' & ')]

def create_deck(remove_cards=[]):
    Deck = []
    for card in cards:
        for suit in suits:
            if (card, suit) in remove_cards:
                continue
            Deck.append(Card(card, suit))
    return Deck

if args.comp:
    hand1 = parse_hand(args.hand1)
    hand2 = parse_hand(args.hand2)
    Deck = create_deck(hand1+hand2)
    f = lambda x: Card(x[0], x[1])
    hand1 = [f(_) for _ in hand1]
    hand2 = [f(_) for _ in hand2]

    hand1_count = 0
    hand2_count = 0
    tie_count = 0
    nseeds = 10
    nsims = 200

    Hand1 = Hand(*hand1)
    Hand2 = Hand(*hand2)

    for seed in range(nseeds):
        np.random.seed(seed)
        for sim in range(nsims):
            deck_shuffled = np.random.permutation(Deck).tolist()
            res, h1, h2 = comp_two_hands(hand1, hand2, deck_shuffled.copy())
            Hand1.count(h1[0])
            Hand2.count(h2[0])
            if res == -1:
                hand1_count += 1
            elif res == 1:
                hand2_count += 1
            else:
                tie_count += 1

    h1_win = hand1_count/nseeds/nsims*100
    h2_win = hand2_count/nseeds/nsims*100
    tie = tie_count/nseeds/nsims*100

    print(f'Hand1: {hand1[0]}, {hand1[1]} wins {h1_win}%')
    print(f'Hand2: {hand2[0]}, {hand2[1]} wins {h2_win}%')
    print(f'Tie happens: {tie}%')
    print(Hand1)
    print(Hand2)
elif args.overall_equity:
    hand1 = parse_hand(args.hand1)
    Deck = create_deck(hand1)
    f = lambda x: Card(x[0], x[1])
    hand1 = [f(_) for _ in hand1]

    nseeds = 10
    nsims = 500
    hand1_count = 0
    hand2_count = 0
    tie_count = 0

    Hand1 = Hand(*hand1)
    for seed in range(nseeds):
        np.random.seed(seed)
        for i in range(nsims):
            rnd_card = np.random.randint(0, len(Deck))
            rnd_card2 = np.random.randint(0, len(Deck))
            while rnd_card2 == rnd_card:
                rnd_card2 = np.random.randint(0, len(Deck))
            hand2 = [Deck[rnd_card], Deck[rnd_card2]]
            Hand2 = Hand(*hand2)
            deck_shuffled = np.random.permutation(Deck).tolist()
            res, h1, h2 = comp_two_hands(hand1, hand2, deck_shuffled.copy())
            Hand1.count(h1[0])
            Hand2.count(h2[0])
            if res == -1:
                hand1_count += 1
            elif res == 1:
                hand2_count += 1
            else:
                tie_count += 1
    h1_win = hand1_count/nseeds/nsims*100
    h2_win = hand2_count/nseeds/nsims*100
    tie = tie_count/nseeds/nsims*100

    print(f'Hand1: {hand1[0]}, {hand1[1]} wins {h1_win}%')
    print(f'Hand2 wins {h2_win}%')
    print(f'Tie happens: {tie}%')
    print(Hand1)
    # print(Hand2)

else:
    hand1 = parse_hand(args.hand1)
    Deck = create_deck(hand1)
    f = lambda x: Card(x[0], x[1])
    hand1 = [f(_) for _ in hand1]

    nseeds = 10
    nsims = 500

    Hand1 = Hand(*hand1)

    for seed in range(nseeds):
        np.random.seed(seed)
        for sim in range(nsims):
            deck_shuffled = np.random.permutation(Deck).tolist()
            table = draw_cards(deck_shuffled, 5)
            h1 = get_best_hand(table+hand1)
            Hand1.count(h1[0])

    print(Hand1)


#!/usr/bin/python

import json
import sys

out_file = sys.argv[1]
document_entities_file = sys.argv[2]
query_file = sys.argv[3]

query_docs = {}
docs = set()
with open(out_file) as f:
	for line in f:
		query, _, document, rank, _, _ = line.split()
		rank = int(rank)
		if rank > 10:
			continue
		if query not in query_docs:
			query_docs[query] = []
		query_docs[query].append(document)
		docs.add(document)

doc_entities = {}
with open(document_entities_file) as f:
	for line in f:
		document, entity, _ = line.split()
		if document not in docs:
			continue
		if document not in doc_entities:
			doc_entities[document] = []
		doc_entities[document].append(entity)

queries = {}
j = json.load(open(query_file))
for q in j['queries']:
	queries[q['title']] = q['text']

for query in query_docs:
	for doc in query_docs[query]:
		i = 0
		if doc in doc_entities:
			for entity in doc_entities[doc]:
				i += 1
				if i <= 5:
					print('\t'.join([query, '"{}"'.format(queries[query]), entity]))


from django.shortcuts import render

#   se importan los modelos
from .models import Author, Genre, Book, BookInstance

# se crea la funcion index

def index (request) :
    #   se optiene el numero de libros
    num_books = Book.objects.all().count()
    #   se optiene el numero de instancias
    num_inctances = BookInstance.objects.all().count()
    #   se optiene el numero de authores
    num_authors = Author.objects.all().count()

    #   para ver los libros disponivles
    #   aca se trabaja con la base de datos
    #   status__exact = "a" es para que los campos sean exactamente igual a la letra "a" y con count te da la cantidad de libros con ese campo
    disponivles = BookInstance.objects.filter (status__exact = "a").count()

#   request hace referencia a el parametro de la funcion
#   despues se hace referensia al archivo de la plantilla html que va a mostrar el contenido luego en context van los datos que resive el archibo html
    return render (
        request,
        "index.html",
        context = {
        "num_books": num_books,
        "num_inctances": num_inctances,
        "num_authors": num_authors,
        "disponivles": disponivles,
        }

    )

Programacion/002 ejemplos/002 - 13 django catalogo/catalog/views.py


import asyncio
import json

from aiogram import Bot, Dispatcher, executor, types
from aiogram.utils.markdown import hbold, hunderline, hcode, hlink
from aiogram.dispatcher.filters import Text
from config import token
from test import morph

from main import check_news_update

bot = Bot(token=token, parse_mode=types.ParseMode.HTML)
dp = Dispatcher(bot)

def get_json(ner, date):
    dict_news = list()

    with open("news_dict.json", "r", encoding="utf-8") as read_file:
        data = json.load(read_file)
        day = None
        month = None
        year = None
        print('gf')
        for new in data.keys():
            ner_tec, _ = morph(str(data[new]['article_full_desc']))
            _, data_tec = morph(str(data[new]['article_data']))
            c = True
            for n in ner:
                if n not in ner_tec:
                    c = False
            if len(date) != 0:
                day = date.day
                month = date.month
                year = date.year
            for d in data_tec:
                if day is not None and day != d.day:
                    c = False
                if month is not None and month != d.day:
                    c = False
                if year is not None and year != d.day:
                    c = False
            if c == True:
                dict_news.append([data[new]['article_data'], data[new]['article_full_desc']])
                print(dict_news)
    return dict_news

@dp.message_handler(content_types=types.ContentTypes.TEXT)
async def process_text_message(message: types.Message):
    text,r=morph(message.text)
    list_news = get_json(text,r)
    print(list_news)
    for news in list_news:
        result = str(news[0]) + "\n" + str(news[1])
        await message.answer(result)
    else:
        await message.answer("Нет таких новостей")

    await message.answer("1")

# @dp.message_handler(Text(equals="Сводка"))
# async def get_news_summary(message: types.Message):
#     with open("news_dict.json",encoding="utf-8") as file:
#         news_dict = json.load(file)
#
#     for k, v in sorted(news_dict.items())[-5:]:
#         text = prediction(message.text)

if __name__ == '__main__':
    executor.start_polling(dp)


#6588

from sys import stdin
array = [True for i in range(1000001)]  # 전체 수 만큼 True의 리스트 생성
for i in range(2, 1001):  # 1001 = int(math.sqrt(1000000)) + 1, 에라토스테네스 체 -> 1000^2 = 1000000: 제곱근까지만 검증해 코드 같다.
    if array[i]:
        for k in range(i + i, 1000001, i):  #range(시작 숫자, 종료숫자, step)
            array[k] = False  # i+i부터 ~ 1000000, i의 배수 index -> False
while True:
    n = int(stdin.readline())
    if n == 0:
        break
    for i in range(3, len(array)):  # 1,2 사용x
        if array[i] and array[n-i]:  # i+(n-i) = n
            print(n, "=", i, "+", n-i)
            break  #b-a가 가장 큰 것을 출력하기 위해 찾으면 break

"""
* 에라토스테네스의 체(소수 판별 알고리즘)
에라토스테네스의 체에서는 1을 제거
--> 지워지지 앟는 수 중에 제일 작은 2를 소수로 선택한다
--> 나머지 2의 배수를 모두 지운다 --> 지워지지 않는 수 중에 제일 작은 3을 소수로 선택한다
--> 나머지 3의 배수를 지운다 ... 5, 7, 11, 13 등으로 반복을 한다.
제곱근까지만 약수의 여부를 검증해도 소수인지 아닌지 알 수 있는 이유는 6과 같은 수의 경우 2*3=3*2로 대칭을 이루기 때문이다.

* 시간초가 코드
import sys
def isPrime(num):
    if num == 1:
        return False
    else:
        for i in range(2, int(num ** 0.5) + 1):
            if num % i == 0:
                return False
        return True
prime = []
for i in range(3,100001):
    if i % 2 == 0:
        continue
    else:
        if isPrime(i):
            prime.append(i)
while True:
    find = 0
    n = int(sys.stdin.readline())
    if n == 0:
        break
    for i in range(len(prime)):
        for j in reversed(range(len(prime))):
            if prime[i] + prime[j] == n:
                find = 1
                break
        if find == 1:
            break
    if find == 1:
        print(n, " = ", prime[i], " + ", prime[j])
    else:
        print("Goldbach's conjecture is wrong.")
"""

알고리즘 기초 1/2-1. 수학 1/6_골드바흐의_추측.py

6_골드바흐의_추측.py


import unittest
import random
from sortedkeycollections import AVLTree, SortedKeyList, SortedArrayList

class TestSortedKeyList(unittest.TestCase):
    def setUp(self):
        self.test_class = SortedKeyList

    def test_insert(self):
        values_integer = [(21, '113'), (71, 'wcwf'), (-6, (121, 32, 'x')), (11, 232), (-6, 'seq'), (21, -50),
                          (-600000, 'adf'), (11, 'wwe')]
        prioritized_values_integer = [(-600000, 'adf'), (-6, (121, 32, 'x')), (-6, 'seq'), (11, 232), (11, 'wwe'),
                                      (21, '113'), (21, -50), (71, 'wcwf')]

        collection_integer = self.test_class()
        for pair in values_integer:
            collection_integer.insert(*pair)

        self.assertEqual(list(iter(collection_integer)), prioritized_values_integer)
        self.assertEqual(len(collection_integer), len(values_integer))

        values_str = [('xYz', '93242sax'), ('xYz', ('x', 823)), ('a97', -23), ('a', 'xx'), ('HH', -23.6), ('a', 132),
                      ('77', 32)]
        prioritized_values_str = [('77', 32), ('HH', -23.6), ('a', 'xx'), ('a', 132), ('a97', -23), ('xYz', '93242sax'),
                                  ('xYz', ('x', 823))]

        collection_str = self.test_class()
        for priority, obj in values_str:
            collection_str.insert(priority, obj)

        self.assertEqual(list(iter(collection_str)), prioritized_values_str)
        self.assertEqual(len(collection_str), len(values_str))

    def test_popleft(self):
        if self.test_class is None:
            return

        values = [((12, 'x'), 78.5), ((-10, 'X'), 'wca'), ((12, '8'), '87'), ((-10, 'X'), 212121)]
        expected_values = [((12, 'x'), 78.5), ((12, '8'), '87'), ((-10, 'X'), 212121), ((-10, 'X'), 'wca')]
        collection = self.test_class()
        for pair in values:
            collection.insert(*pair)

        while len(collection) > 0:
            self.assertEqual(collection.popleft(), expected_values.pop())

    def test_popleft_exception(self):
        collection = self.test_class()
        self.assertRaises(KeyError, lambda: collection.popleft())

class TestSortedArrayList(TestSortedKeyList):
    def setUp(self):
        self.test_class = SortedArrayList

class TestAVLTree(TestSortedKeyList):
    def setUp(self):
        self.test_class = AVLTree

    def test_balance(self):
        tree = AVLTree()
        for _ in range(50):
            tree.insert(random.randint(-100, 100), random.randint(-500, 500))

        for _ in range(40):
            tree.popleft()

        for i in range(20):
            tree.insert(i, random.randint(-900, 900))

        for node in tree.node_iter():
            lh, rh = node.left_tree_height(), node.right_tree_height()
            height = max(lh, rh) + 1
            self.assertEqual(node.height, height)
            self.assertGreater(2, abs(lh - rh))

if __name__ == '__main__':
    unittest.main()


import vtk

def main():
    colors = vtk.vtkNamedColors()

    # Set the background color.
    colors.SetColor("bkg", [0.2, 0.3, 0.4, 1.0])

    # Create a sphere to deform
    sphere = vtk.vtkSphereSource()
    sphere.SetThetaResolution(51)
    sphere.SetPhiResolution(17)
    sphere.Update()
    bounds = sphere.GetOutput().GetBounds()

    # Create a filter to color the sphere
    ele = vtk.vtkElevationFilter()
    ele.SetInputConnection(sphere.GetOutputPort())
    ele.SetLowPoint(0,0,-0.5);
    ele.SetHighPoint(0,0,0.5);
    ele.SetLowPoint((bounds[1] + bounds[0]) / 2.0,
                    (bounds[3] + bounds[2]) / 2.0,
                    -bounds[5]);
    ele.SetHighPoint((bounds[1] + bounds[0]) / 2.0,
                     (bounds[3] + bounds[2]) / 2.0,
                     bounds[5]);
    ele.Update()

    # Create a mesh to deform the sphere
    pts = vtk.vtkPoints()
    pts.SetNumberOfPoints(6)
    pts.SetPoint(0,
                 bounds[0] - 0.1 * (bounds[1] - bounds[0]),
                 (bounds[3] + bounds[2]) / 2.0,
                 (bounds[5] + bounds[4]) / 2.0)
    pts.SetPoint(1,
                 bounds[1] + 0.1 * (bounds[1] - bounds[0]),
                 (bounds[3] + bounds[2]) / 2.0,
                 (bounds[5] + bounds[4]) / 2.0)
    pts.SetPoint(2,
                 (bounds[1] + bounds[0]) / 2.0,
                 bounds[2] - 0.1 * (bounds[3] - bounds[2]),
                 (bounds[5] + bounds[4]) / 2.0)
    pts.SetPoint(3,
                 (bounds[1] + bounds[0]) / 2.0,
                 bounds[3] + 0.1 * (bounds[3] - bounds[2]),
                 (bounds[5] + bounds[4]) / 2.0)
    pts.SetPoint(4,
                 (bounds[1] + bounds[0]) / 2.0,
                 (bounds[3] + bounds[2]) / 2.0,
                 bounds[4] - 0.1 * (bounds[5] - bounds[4]))
    pts.SetPoint(5,
                 (bounds[1] + bounds[0]) / 2.0,
                 (bounds[3] + bounds[2]) / 2.0,
                 bounds[5] + 0.1 * (bounds[5] - bounds[4]))
    tris = vtk.vtkCellArray()

    cells = [[2, 0, 4], [1, 2, 4], [3, 1, 4], [0, 3, 4], [0, 2, 5], [2, 1, 5], [1, 3, 5], [3, 0, 5]]

    for cell in cells:
        tris.InsertNextCell(3)
        for c in cell:
            tris.InsertCellPoint(c)

    pd = vtk.vtkPolyData()
    pd.SetPoints(pts)
    pd.SetPolys(tris)

    meshMapper = vtk.vtkPolyDataMapper()
    meshMapper.SetInputData(pd)
    meshActor = vtk.vtkActor()
    meshActor.SetMapper(meshMapper)
    meshActor.GetProperty().SetRepresentationToWireframe()
    meshActor.GetProperty().SetColor(colors.GetColor3d("Black"))

    deform = vtk.vtkDeformPointSet()
    deform.SetInputData(ele.GetOutput())
    deform.SetControlMeshData(pd)
    deform.Update()

    controlPoint = pts.GetPoint(5)
    pts.SetPoint(5, controlPoint[0],
                 controlPoint[1],
                 bounds[5] + .8 * (bounds[5] - bounds[4]))
    pts.Modified()

    polyMapper = vtk.vtkPolyDataMapper()
    polyMapper.SetInputConnection(deform.GetOutputPort())
    polyActor = vtk.vtkActor()
    polyActor.SetMapper(polyMapper)

    renderer = vtk.vtkRenderer()
    renWin = vtk.vtkRenderWindow()
    renWin.AddRenderer(renderer)
    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)

    renderer.AddActor(polyActor)
    renderer.AddActor(meshActor)

    renderer.GetActiveCamera().SetPosition(1,1,1)
    renderer.ResetCamera()
    renderer.SetBackground(colors.GetColor3d("bkg"))

    renWin.SetSize(300,300)
    renWin.Render()

    iren.Start()

if __name__ == '__main__':
    main()


"""Calcula el precio de la energía diario a partir de los precio horarios"""
import pathlib

from utils import read_format_hourly_prices, resample_hourly_prices

base_path = pathlib.Path.cwd()
cleansed_path = base_path.joinpath("data_lake/cleansed")
business_path = base_path.joinpath("data_lake/business")

def compute_daily_prices(
    source_path=cleansed_path,
    target_path=business_path,
    source_filename="precios-horarios.csv",
    target_namefile="precios-diarios.csv",
):
    """Calcula los precios promedios diarios.

    Usael archivo data_lake/cleansed/precios-horarios.csv, calcula el precio
    promedio diario (sobre las 24 horas del dia) para cada uno de los dias. Las
    columnas del archivo data_lake/business/precios-diarios.csv son:

    * fecha: fecha en formato YYYY-MM-DD
    * precio: precio promedio diario de la electricidad en la bolsa nacional
    """

    df_hourly_prices = read_format_hourly_prices(source_path, filename=source_filename)

    df_daily_prices = resample_hourly_prices(df_hourly_prices, freq="D")

    df_daily_prices.to_csv(target_path.joinpath(target_namefile))

if __name__ == "__main__":
    import doctest

    compute_daily_prices()
    doctest.testmod()


def minigame():
 import pygame
 import sys
 import pictures
 import random

 status = 'alive'
 zombie_size = [50,100,150,200,250,300]
 obstacle_list = []
 bg_pos = 0
 move= 0
 side = 0
 score = 0

 game_screen = pygame.display.set_mode((608,342)) #creates a screen 1024 pixels wide and 576 pixels long
 clock = pygame.time.Clock() # creates clock object, this will be used later to control the fps

 def move_bg():
  game_screen.blit(background,(bg_pos,0))
  game_screen.blit(background,(bg_pos+608,0))

 def new_obstacle():
  z_size = random.choice(zombie_size)
  new_obstacle = obstacle.get_rect(center =(800,z_size))
  return new_obstacle

 def move_obstacle(obstacle):
   for obstacle in obstacle_list:
     obstacle.centerx = obstacle.centerx -1

 def obstacle_screen(obstacle):
  for obstacles in obstacle_list:
    game_screen.blit(obstacle, obstacles)

 def death (obstacle):
  status = 'alive'
  for obstacle in obstacle_list:
    if avatar_bound.colliderect(obstacle):
     status = 'dead'
  return status

 pygame.init() #initialize pygame module

 #uploading all the necessary images
 background = pygame.image.load('pictures/bg.jpg').convert()
 avatar = pygame.image.load('pictures/avatar.png').convert_alpha()
 obstacle = pygame.image.load('pictures/zombie.png').convert_alpha()
 gameover = pygame.image.load('pictures/gameover.jpg').convert()
 gamewin = pygame.image.load('pictures/win.webp').convert()

 #transforming and scaling images
 avatar = pygame.transform.scale(avatar, (58, 62))
 obstacle = pygame.transform.scale(obstacle, (60, 80))
 gameover= pygame.transform.scale(gameover,(608,342))
 gamewin= pygame.transform.scale(gamewin,(608,342))
 avatar_bound = avatar.get_rect(center =(50,150)) # get rectangle around surface this will help us check for collisions

 add_obstacle = pygame.USEREVENT
 pygame.time.set_timer(add_obstacle, 2200) #every 1500 millseconds event

 while True:
  # write code to exit out of module (add score parameters
  for event in pygame.event.get():
    if event.type == pygame.QUIT: #or score reaches 10
     pygame.quit()
     sys.exit()
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_UP or event.key == ord('w'):
            move =0
            move = move - 3
        if event.key == pygame.K_DOWN or event.key == ord('s'):
            move =0
            move = move + 3
        if event.key == pygame.K_LEFT or event.key == ord('a'):
            side = 0
            side = side - 3
        if event.key == pygame.K_RIGHT or event.key == ord('d'):
            side = 0
            side = side + 3
    if event.type == pygame.KEYUP:
       side = 0
       move = 0
    if event.type == add_obstacle :
       obstacle_list.append(new_obstacle())

  bg_pos = bg_pos-1
  game_screen.blit(background,(bg_pos,0)) # block transfer of bg image, upper left corner at (0,0)
  move_bg()
  if bg_pos <= -608:
    bg_pos = 0

  if status == 'alive' and  score<= 20:
   move_obstacle(obstacle_list)
   obstacle_screen(obstacle)
   game_screen.blit(avatar, avatar_bound)
   # controlling movements of avatar
   avatar_bound.centery = avatar_bound.centery + move
   avatar_bound.centerx = avatar_bound.centerx + side
   status = death(obstacle_list)
   score = score + 0.01

  elif status == 'dead':
    game_screen.blit(gameover,(-20,0))

  elif score >= 20:
     game_screen.blit(gamewin,(0,0))

  pygame.display.update() # updating the display screen
  clock.tick(100) #updates 100 times in a second


#!/usr/bin/env python3

import os
import sys
import urllib.request

from flask import (
    Flask,
    flash,
    jsonify,
    make_response,
    redirect,
    render_template,
    request,
)
from werkzeug.utils import secure_filename

from scripts import predict_model
from scripts import mongodb
from scripts import train_model

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

ENVIRONMENT_WINDOWS = True

@app.route("/")
def index():
    return "Application Alive"

@app.route("/api/v1.0/users", methods=["GET"])
def get_users():
    return jsonify({"Users": mongodb.get_list_users()})

@app.route("/api/v1.0/experiments/<user>", methods=["GET"])
def get_experiments(user):
    user = user.lower()

    file_dir_data = os.listdir("data/")
    if user not in file_dir_data:
        return make_response(jsonify({"error": "User Not Found"}), 404)

    else:
        file_dir_user = os.listdir("data/{}".format(user))
        return jsonify({"user": user, "experiments": file_dir_user})

@app.route("/api/v1.0/train/<user>/<experiment_name>", methods=["GET"])
def train_experiment(user, experiment_name):
    user = user.lower()
    experiment_name = experiment_name.lower()

    file_dir_data = os.listdir("data/")
    if user not in file_dir_data:
        return make_response(jsonify({"error": "User Not Found"}), 404)

    file_dir_user = os.listdir("data/{}".format(user))

    if experiment_name not in file_dir_user:
        return make_response(jsonify({"error": "Experiment Not Found"}), 404)

    model_def = "data/{}/{}/model_definition.yaml".format(user, experiment_name)
    data_csv = "data/{}/{}/train_data.csv".format(user, experiment_name)
    log_file = "data/{}/{}/training.log".format(user, experiment_name)

    if ENVIRONMENT_WINDOWS:
        output_dir = "data\{}\{}".format(user, experiment_name)
    else:
        output_dir = "data/{}/{}".format(user, experiment_name)

    res = train_model.train_model(
        model_def, output_dir, data_csv, experiment_name, log_file
    )

    if res != True:
        return jsonify(
            {
                "user": user,
                "response": res,
                "model_definition": model_def,
                "data_csv": data_csv,
                "log_file": log_file,
                "output_dir": output_dir,
            }
        )

    return jsonify({"user": user, "response": "Training in Progress"})

@app.route("/api/v1.0/predict/<user>/<experiment_name>", methods=["POST"])
def predict_experiment(user, experiment_name):
    file = request.files["file"]

    if file.filename != "":
        filename = secure_filename(file.filename)

        if "predict" not in os.listdir("data/{}/{}".format(user, experiment_name)):
            os.mkdir("data/{}/{}/predict/".format(user, experiment_name))

        file.save("data/{}/{}/predict/{}".format(user, experiment_name, filename))

        return jsonify(
            {"result": {"dog": 0.85, "cat": 0.15}, "exp": experiment_name, "user": user}
        )

    return jsonify({"response": "Error"})

@app.route("/api/v1.0/register/<user>", methods=["GET"])
def register_user(user):
    user = user.lower()
    dir_list_users = os.listdir("data/")
    if user in dir_list_users:
        return make_response(jsonify({"error": "User Already Exists"}), 420)
    else:
        os.mkdir("data/{}".format(user))
        return jsonify({"user": user, "response": "User Successfully Created"})

@app.route("/api/v1.0/register/<user>/<experiment_name>", methods=["GET"])
def register_experiment(user, experiment_name):
    user = user.lower()
    experiment_name = experiment_name.lower()

    dir_list_users = os.listdir("data/")
    if user in dir_list_users:
        dir_list_experiments = os.listdir("data/{}/".format(user))
        if experiment_name in dir_list_experiments:
            return make_response(jsonify({"error": "Experiment Already Exists"}), 420)
        else:
            os.mkdir("data/{}/{}".format(user, experiment_name))
            return jsonify(
                {
                    "user": user,
                    "experiment": experiment_name,
                    "response": "Experiment Successfully Created",
                }
            )
    else:
        return make_response(jsonify({"error": "User Does Not Exist"}), 420)

@app.route("/api/v1.0/remove/<user>", methods=["GET"])
def remove_user(user):
    user = user.lower()
    dir_list_users = os.listdir("data/")
    if user not in dir_list_users:
        return make_response(jsonify({"error": "User Does Not Exist"}), 420)
    else:
        dir_list_experiments = os.listdir("data/{}".format(user))
        if len(dir_list_experiments) == 0:
            os.rmdir("data/{}".format(user))
            return jsonify({"user": user, "response": "User Successfully Removed"})
        else:
            return jsonify(
                {
                    "user": user,
                    "response": "User Experiments still exist",
                    "experiments": dir_list_experiments,
                }
            )

@app.route("/api/v1.0/remove/<user>/<experiment_name>", methods=["GET"])
def remove_experiment(user, experiment_name):
    user = user.lower()
    experiment_name = experiment_name.lower()

    dir_list_users = os.listdir("data/")
    if user in dir_list_users:
        dir_list_experiments = os.listdir("data/{}/".format(user))
        if experiment_name in dir_list_experiments:
            os.rmdir("data/{}/{}".format(user, experiment_name))
            return jsonify(
                {
                    "user": user,
                    "experiment": experiment_name,
                    "response": "Experiment Successfully Removed",
                }
            )
        else:
            return make_response(jsonify({"error": "Experiment Does Not Exist"}), 420)
    else:
        return make_response(jsonify({"error": "User Does Not Exist"}), 420)

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({"error": "Request Not Found"}), 404)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port="5000")


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

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

"""linebot.models.actions module."""

from abc import ABCMeta

from future.utils import with_metaclass

from .base import Base

def get_action(action):
    """Get action."""
    action_obj = Base.get_or_new_from_json_dict_with_types(
        action, {
            'postback': PostbackAction,
            'message': MessageAction,
            'uri': URIAction,
            'datetimepicker': DatetimePickerAction,
            'camera': CameraAction,
            'cameraRoll': CameraRollAction,
            'location': LocationAction,
            'richmenuswitch': RichMenuSwitchAction,
        }
    )
    return action_obj

def get_actions(actions):
    """Get actions."""
    new_actions = []
    if actions:
        for action in actions:
            action_obj = get_action(action)
            if action_obj:
                new_actions.append(action_obj)

    return new_actions

class Action(with_metaclass(ABCMeta, Base)):
    """Abstract base class of Action."""

    def __init__(self, **kwargs):
        """__init__ method.

        :param kwargs:
        """
        super(Action, self).__init__(**kwargs)

        self.type = None

class PostbackAction(Action):
    """PostbackAction.

    https://developers.line.me/en/docs/messaging-api/reference/#postback-action

    When a control associated with this action is tapped,
    a postback event is returned via webhook with the specified string in the data property.
    """

    def __init__(
        self,
        label=None,
        data=None,
        display_text=None,
        text=None,
        input_option=None,
        fill_in_text=None,
        **kwargs
    ):
        """__init__ method.

        :param str label: Label for the action.
        :param str data: String returned via webhook
            in the postback.data property of the postback event.
        :param str display_text: Text displayed in the chat as a message sent by
            the user when the action is performed.
        :param str text: Deprecated. Text displayed in the chat as a message sent by
            the user when the action is performed. Returned from the server through a webhook.
        :param kwargs:
        """
        super(PostbackAction, self).__init__(**kwargs)

        self.type = 'postback'
        self.label = label
        self.data = data
        self.display_text = display_text
        self.text = text
        self.input_option = input_option
        self.fill_in_text = fill_in_text

class MessageAction(Action):
    """MessageAction.

    https://developers.line.me/en/docs/messaging-api/reference/#message-action

    When a control associated with this action is tapped,
    the string in the text property is sent as a message from the user.
    """

    def __init__(self, label=None, text=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action.
        :param str text: Text sent when the action is performed.
        :param kwargs:
        """
        super(MessageAction, self).__init__(**kwargs)

        self.type = 'message'
        self.label = label
        self.text = text

class URIAction(Action):
    """URIAction.

    https://developers.line.me/en/docs/messaging-api/reference/#uri-action

    When a control associated with this action is tapped,
    the URI specified in the uri property is opened.
    """

    def __init__(self, label=None, uri=None, alt_uri=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
            Max: 20 characters
        :param str uri: URI opened when the action is performed.
        :param alt_uri: URI opened when the desktop app.
        :type alt_uri: T <= :py:class:`linebot.models.actions.AltUri`
        :param kwargs:
        """
        super(URIAction, self).__init__(**kwargs)

        self.type = 'uri'
        self.label = label
        self.uri = uri
        self.alt_uri = self.get_or_new_from_json_dict(alt_uri, AltUri)

class AltUri(with_metaclass(ABCMeta, Base)):
    """AltUri.

    https://github.com/line/line-bot-sdk-python/issues/155

    URI opened when the desktop app.
    """

    def __init__(self, desktop=None, **kwargs):
        """__init__ method.

        :param str desktop: URI opened on LINE for macOS and Windows
            when the action is performed.
            If the altUri.desktop property is set,
            the uri property is ignored on LINE for macOS and Windows.
        :param kwargs:
        """
        super(AltUri, self).__init__(**kwargs)

        self.desktop = desktop

class DatetimePickerAction(Action):
    """DatetimePickerAction.

    https://developers.line.me/en/docs/messaging-api/reference/#datetime-picker-action

    When a control associated with this action is tapped,
    a postback event is returned via webhook with the date and time
    selected by the user from the date and time selection dialog.
    The datetime picker action does not support time zones.
    """

    def __init__(self, label=None, data=None, mode=None,
                 initial=None, max=None, min=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param str data: String returned via webhook
            in the postback.data property of the postback event
        :param str mode: Action mode
            date: Pick date
            time: Pick time
            datetime: Pick date and time
        :param str initial: Initial value of date or time
        :param str max: Largest date or time value that can be selected.
            Must be greater than the min value.
        :param str min: Smallest date or time value that can be selected.
            Must be less than the max value.
        :param kwargs:
        """
        super(DatetimePickerAction, self).__init__(**kwargs)

        self.type = 'datetimepicker'
        self.label = label
        self.data = data
        self.mode = mode
        self.initial = initial
        self.max = max
        self.min = min

class CameraAction(Action):
    """CameraAction.

    https://developers.line.me/en/reference/messaging-api/#camera-action

    This action can be configured only with quick reply buttons.
    When a button associated with this action is tapped,
    the camera screen in the LINE app is opened.
    """

    def __init__(self, label=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param kwargs:
        """
        super(CameraAction, self).__init__(**kwargs)

        self.type = 'camera'
        self.label = label

class CameraRollAction(Action):
    """CameraRollAction.

    https://developers.line.me/en/reference/messaging-api/#camera-roll-action

    This action can be configured only with quick reply buttons.
    When a button associated with this action is tapped,
    the camera roll screen in the LINE app is opened.
    """

    def __init__(self, label=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param kwargs:
        """
        super(CameraRollAction, self).__init__(**kwargs)

        self.type = 'cameraRoll'
        self.label = label

class LocationAction(Action):
    """LocationRollAction.

    https://developers.line.me/en/reference/messaging-api/#location-action

    This action can be configured only with quick reply buttons.
    When a button associated with this action is tapped,
    the location screen in the LINE app is opened.
    """

    def __init__(self, label=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param kwargs:
        """
        super(LocationAction, self).__init__(**kwargs)

        self.type = 'location'
        self.label = label

class RichMenuSwitchAction(Action):
    """RichMenuSwitchAction.

    https://developers.line.biz/en/reference/messaging-api/#richmenu-switch-action

    This action can be configured only with rich menus.
    It can't be used for Flex Messages or quick replies.
    When you tap a rich menu associated with this action,
    you can switch between rich menus,
    and a postback event including the rich menu alias ID selected
     by the user is returned via a webhook.
    """

    def __init__(self, label=None, rich_menu_alias_id=None, data=None, **kwargs):
        """__init__ method.

        :param str label: Label for the action
        :param str rich_menu_alias_id: Rich menu alias ID to switch to.
        :param str data: String returned by the postback.data property
         of the postback event via a webhook
        :param kwargs:
        """
        super(RichMenuSwitchAction, self).__init__(**kwargs)

        self.type = 'richmenuswitch'
        self.label = label
        self.rich_menu_alias_id = rich_menu_alias_id
        self.data = data


import sys
input = sys.stdin.readline

from queue import PriorityQueue
queue = PriorityQueue() # 우선순위 큐

N = int(input())
for i in range(N):
    a = int(input())

    if a == 0:
        if queue.empty():
            print(0)
        else:
            print(-queue.get()) # 가장 큰 값 제거하고 - 붙여서 출력하기 (넣을 때 음수로 넣었으니까)
    else:
        queue.put(-a) # 오름차순으로 제거하기 위해 음수로 넣기


class SLList():
    class node():
        def __init__(self,data):
            self.element=data
            self.next = None #declares and intializes to NONE
        #NODE class is visible to every method in SLLIST class

    def __init__(self):#happens at every obj creation for SLList class
        self.head = self.node(None)#creation of obj for node class
        self.size = 0#declared and intializes to 0

    def isEmpty(self):
        if self.size>0:
            return False
        else:
            return True

    def insertFirst(self,data):
        newNode = self.node(data)
        if self.size == 0:
            #head, newNode -> objs of node class
            self.head.element = newNode.element #self.head.element was NONE, now it's newNode.element=>.element stands for data
        else:
            newNode.next = self.head#contains ref to next node//makes LINK bw newNode and head
            self.head = newNode #assigning the obj to head
        self.size += 1

    def insertLast(self,data):
        newNode=self.node(data)#created a node
        if(self.size==None):
            self.head.element=newNode.element
        else:
            currentNode=self.head #like i=0, first element
            while(currentNode.next!=None):
                currentNode=currentNode.next
            #currentNode that comes out will be the last node
            currentNode.next=newNode#linked the node
        self.size+=1

    def printList(self):
        if (self.isEmpty()):
            print("List is Empty")
        else:
            currentNode = self.head
            while(currentNode != None):
                print(currentNode.element, end =" ")
                currentNode = currentNode.next
            print("")

    def deleteFirst(self):
        if(self.isEmpty()):
            print("List is Empty")
        else:
            if (self.head.next == None):#if there's only one value
                self.head.element = None
            else:
                temp = self.head
                self.head = self.head.next #next obj assigned as new head, first obj del
                del temp
            self.size -=1

    def deleteLast(self):
        currentNode=self.head
        while(currentNode.next.next!=None):
            currentNode=currentNode.next
            #last but one, second last element comes out
        currentNode.next=None#ref for next is none, lost

    def listSize(self):
        return self.size

sll = SLList()
print(sll.isEmpty())
sll.insertFirst(10)
sll.insertFirst(20)
sll.insertFirst(30)
sll.insertLast(40)
sll.insertLast(50)
sll.insertLast(60)
sll.printList()
print(sll.listSize())
sll.deleteFirst()
sll.deleteLast()
sll.printList()
print(sll.listSize())
print(sll.isEmpty())


import collections
import heapq
class Solution:
    def networkDelayTime(self, times: list[list[int]], n: int, k: int) -> int:
        graph = collections.defaultdict(list)
        for u, v, w in times:
            graph[u].append((w, v))
        hq = [(0, k)]
        dist = collections.defaultdict(int)
        while hq:
            weight, node = heapq.heappop(hq)
            if node not in dist:
                dist[node] = weight
                for next_weight, next in graph[node]:
                    total_weight = next_weight + weight
                    heapq.heappush(hq, (total_weight, next))

        if len(dist) == n:
            return max(dist.values())
        return -1
temp = Solution()
print(temp.networkDelayTime([[2,1,1],[2,3,1],[3,4,1]], 4, 2))


from pyspark.sql import SparkSession

spark = SparkSession.builder.appName('test_rdd').getOrCreate()
sc = spark.sparkContext

class TestRDD():
    # Creations
    def test_create_from_dataframe(self):
        df = spark.range(10).toDF('id')
        rdd = df.rdd
        rows = rdd.collect()
        assert len(rows) == 10
        assert rows[9]['id'] == 9

    def test_create_from_collection(self):
        data = [1, 2, 3, 4]
        rdd = sc.parallelize(data, 2)
        list_1 = rdd.collect()
        assert list_1 == [1, 2, 3, 4]
        list_2 = rdd.glom().collect()
        assert list_2 == [[1, 2], [3, 4]]

    def test_create_from_file(self):
        pass

    # Transformations
    def test_map(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        rdd_1 = rdd.map(lambda word: (word, word[0], len(word)))
        list_1 = rdd_1.collect()
        assert list_1[0] == ('The', 'T', 3)

    def test_filter(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        rdd_1 = rdd.map(lambda word: (word, word[0], len(word)))
        rdd_2 = rdd_1.filter(lambda record: record[2] == 5)
        list_2 = rdd_2.collect()
        assert list_2 == [('quick', 'q', 5), ('brown', 'b', 5), ('jumps', 'j', 5)]

    def test_sortBy(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        rdd_1 = rdd.sortBy(lambda word: len(word))
        list_1 = rdd_1.take(5)
        assert list_1 == ['The', 'fox', 'the', 'dog', 'over']

    # Partition Transformations
    def test_mapPartitions(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        rdd_1 = rdd.mapPartitions(lambda part: [word[::-1] for word in part])
        list_1 = rdd_1.collect()
        assert list_1 == ['ehT', 'kciuq', 'nworb', 'xof', 'spmuj', 'revo', 'eht', 'yzal', 'god']

    def test_foreachPartition(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)

        def func(partition):
            for word in partition:
                print(word[::-1])

        rdd.foreachPartition(func)

    # Actions
    def test_count(self):
        data = range(1, 5)
        rdd = sc.parallelize(data)
        cnt = rdd.count()
        assert cnt == 4

    def test_reduce(self):
        data = range(1, 5)
        rdd = sc.parallelize(data)
        product = rdd.reduce(lambda x, y: x * y)
        assert product == 24

    # Pair RDDs
    def test_keyBy_and_mapValues(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        pair_rdd = sc.parallelize(words).keyBy(lambda word: word.lower()[0])
        rdd_1 = pair_rdd.mapValues(lambda word: word.upper())
        list_1 = rdd_1.take(3)
        assert list_1 == [('t', 'THE'), ('q', 'QUICK'), ('b', 'BROWN')]
        list_2 = rdd_1.keys().collect()
        assert list_2 == ['t', 'q', 'b', 'f', 'j', 'o', 't', 'l', 'd']
        list_3 = rdd_1.values().collect()
        assert list_3[0] == 'THE'

    def test_countByKey(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        pair_rdd = sc.parallelize(words).map(lambda word: (word.lower()[0], word.upper()))
        d = pair_rdd.countByKey()
        assert list(d.items()) == [('t', 2), ('q', 1), ('b', 1), ('f', 1), ('j', 1), ('o', 1), ('l', 1), ('d', 1)]

    def test_reduceByKey(self):
        pair_rdd = sc.parallelize([('a', 1), ('b', 2), ('c', 3), ('b', 2), ('a', 1)])
        rdd_1 = pair_rdd.reduceByKey(lambda x, y: x*y)
        list_1 = rdd_1.collect()
        assert list_1 == [('a', 1), ('b', 4), ('c', 3)]

    # Broadcast Variable
    def test_BV(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        bv_data = {'e': 5, 'j': 10, 'o': 15, 't': 20, 'y': 25}
        bv = sc.broadcast(bv_data)
        bv_value = bv.value
        rdd_1 = rdd.map(lambda word: bv_value.get(word.lower()[0], -1))
        list_1 = rdd_1.collect()
        assert list_1 == [20, -1, -1, -1, 10, 15, 20, -1, -1]

    # Accumulator
    def test_accumulator(self):
        words = 'The quick brown fox jumps over the lazy dog'.split(' ')
        rdd = sc.parallelize(words, 2)
        first_acc = sc.accumulator(value=0)

        def func(word):
            if len(word) == 3:
                first_acc.add(1)

        rdd.foreach(func)
        assert first_acc.value == 4

if __name__ == '__main__':
    test = TestRDD()
    # Call a method here
    test.test_accumulator()
    spark.stop()