'''
File name: ctc_chroma/features.py
Author: Frank Zalkow
Date: 2020
License: MIT

This file is part of the following repository:
  https://github.com/fzalkow/ctc_chroma

If you use code of this reposiory, please cite:
  Frank Zalkow and Meinard Müller:
  Using Weakly Aligned Score–Audio Pairs to Train Deep Chroma Models for Cross-Modal Music Retrieval.
  In Proceedings of the International Society for Music Information Retrieval Conference, Montréal, Canada, 2020.
'''

import os
import argparse
import glob
import multiprocessing as mp

import librosa
from tqdm import tqdm
import numpy as np

def get_hcqt_params():
    """Hack to always use the same parameters :)
    Function from https://github.com/rabitt/ismir2017-deepsalience"""
    bins_per_octave = 36
    n_octaves = 6
    harmonics = [0.5, 1, 2, 3, 4, 5]
    sr = 22050
    fmin = 32.7
    hop_length = 256
    return bins_per_octave, n_octaves, harmonics, sr, fmin, hop_length

def compute_hcqt(audio_fpath):
    """Compute the harmonic CQT from a given audio file
    Function from https://github.com/rabitt/ismir2017-deepsalience"""
    (bins_per_octave, n_octaves, harmonics,
     sr, f_min, hop_length) = get_hcqt_params()
    y, fs = librosa.load(audio_fpath, sr=sr)

    cqt_list = []
    shapes = []
    for h in harmonics:
        cqt = librosa.cqt(y, sr=fs, hop_length=hop_length, fmin=f_min*float(h), n_bins=bins_per_octave*n_octaves,
                          bins_per_octave=bins_per_octave)
        cqt_list.append(cqt)
        shapes.append(cqt.shape)

    shapes_equal = [s == shapes[0] for s in shapes]
    if not all(shapes_equal):
        min_time = np.min([s[1] for s in shapes])
        new_cqt_list = []
        for i in range(len(cqt_list)):
            new_cqt_list.append(cqt_list[i][:, :min_time])
        cqt_list = new_cqt_list

    log_hcqt = ((1.0 / 80.0) * librosa.core.amplitude_to_db(np.abs(np.array(cqt_list)), ref=np.max)) + 1.0

    return log_hcqt

def get_time_grid(n_time_frames):
    """Get the hcqt time grid
    Function from https://github.com/rabitt/ismir2017-deepsalience"""
    (_, _, _, sr, _, hop_length) = get_hcqt_params()
    time_grid = librosa.core.frames_to_time(range(n_time_frames), sr=sr, hop_length=hop_length)
    return time_grid

def get_freq_grid():
    """Get the hcqt frequency grid
    Function from https://github.com/rabitt/ismir2017-deepsalience"""
    (bins_per_octave, n_octaves, _, _, f_min, _) = get_hcqt_params()
    freq_grid = librosa.cqt_frequencies(bins_per_octave*n_octaves, f_min, bins_per_octave=bins_per_octave)
    return freq_grid

def compute_and_save_hcqt(fn_wav, fn_out, feature_rate):
    hcqt, times, freqs = compute_hcqt_median(fn_wav, feature_rate)

    # interpolate times
    eps = np.finfo(float).eps
    new_times = np.arange(times[0], times[-1] + eps, 1.0/feature_rate)  # add eps to include last time point

    hcqt_interpolated = median_bin_salience(hcqt, times, new_times, axis=-1)

    np.savez_compressed(fn_out, f_pitch=hcqt_interpolated, f_pitch_ax_time=new_times, f_pitch_ax_freq=freqs)

def compute_hcqt_median(fn_wav, feature_rate):
    hcqt = compute_hcqt(fn_wav)
    times = get_time_grid(len(hcqt[0][0]))
    freqs = get_freq_grid()

    # interpolate times
    eps = np.finfo(float).eps
    new_times = np.arange(times[0], times[-1] + eps, 1.0/feature_rate)  # add eps to include last time point

    return median_bin_salience(hcqt, times, new_times, axis=-1), new_times, freqs

def median_bin_salience(salience, old_times, new_times, axis=1):

    idx = []
    for i in range(len(new_times)):
        start_time = new_times[i]
        idx.append(np.searchsorted(old_times, start_time))
    idx.append(len(old_times))

    new_X = librosa.util.sync(salience, idx, aggregate=np.median, pad=False, axis=axis)

    return new_X

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-i', '--indir')
    parser.add_argument('-o', '--outdir')
    parser.add_argument('--rate', help='Frame Rate', type=int, default=25)
    parser.add_argument('--mode', help='DEVELOP or PRODUCTION', default='PRODUCTION')
    args = parser.parse_args()

    # python 00_extract_features_bittner/extract_features_input.py -i
    # /home/fzalkow/mountpoints/groupmm/Projects/BM/Subsets/barlow-morgenstern/03_BM-medium/data_WAV_WCM
    # -o data/BM_hcqt25 --time-binning median --rate 25

    indir = args.indir
    feature_rate = args.rate
    outdir = args.outdir
    assert os.path.exists(indir)
    assert args.mode in ['DEVELOP', 'PRODUCTION']
    os.makedirs(outdir, exist_ok=True)

    fn_audios = sorted(glob.glob(os.path.join(indir, '*.wav')))

    if args.mode == 'DEVELOP':
        base = os.path.splitext(os.path.basename(fn_audios[0]))[0]
        fn_new = os.path.join(outdir, base + '.npz')
        compute_and_save_hcqt(fn_audios[0], fn_new, feature_rate)

    if args.mode == 'PRODUCTION':
        n_workers = 16  # mp.cpu_count()
        pool = mp.Pool(n_workers)
        amount_of_jobs = len(fn_audios)
        i = 0

        with tqdm(total=amount_of_jobs, desc='Execute jobs', dynamic_ncols=True) as pbar:

            for fn_audio in fn_audios:

                base = os.path.splitext(os.path.basename(fn_audio))[0]
                fn_new = os.path.join(outdir, base + '.npz')
                if not os.path.exists(fn_new):
                    pool.apply_async(compute_and_save_hcqt, args=(fn_audio, fn_new, feature_rate),
                                     callback=lambda _: pbar.update(),
                                     error_callback=lambda x: tqdm.write(str(x)))
                else:
                    pbar.update()
            pool.close()  # no more jobs will be added
            pool.join()


from typing import Optional
import re
import sys

import tuwien.tiss
import tuwien.colab
import tuwien.rdb

NAME_REPLACE = re.compile(r'[^A-Za-z0-9äüößÄÜÖẞ]')

class Room:
    name: str
    suffix: Optional[str]
    name_short: Optional[str]
    alt_name: Optional[str]
    room_codes: [str]
    tiss_code: Optional[str]
    type: Optional[str]
    parent_name: Optional[str]
    area: Optional[int]
    capacity: Optional[int]
    comment: Optional[str]

    def __init__(self, name: str, room_code: str, tiss_code: str = None, room_type: str = None,
                 area: int = None, capacity: int = None, comment: str = None):
        self.name = re.sub(r' *- +[A-Z-]*$', '', name.split(' - Achtung!')[0]).split(' - mündl.')[0].replace(',', '')
        self.name = self.name.replace('HS', 'Hörsaal')
        self.name = self.name\
            .replace('Sem.R.', 'Seminarraum')\
            .replace('Sem. R.', 'Seminarraum')\
            .replace('Sem.', 'Seminarraum')\
            .replace('Sem ', 'Seminarraum ')
        self.name = self.name.replace('AI', 'Atominstitut')
        self.suffix = None
        self.name_short = None
        self.alt_name = None
        self.room_codes = [room_code.replace(' ', '')]
        self.tiss_code = tiss_code
        self.type = room_type
        if self.type is None:
            if 'hörsaal' in self.name.lower() or 'Audi. Max.' in self.name or 'Atrium' in self.name:
                self.type = 'lecture_hall'
            elif 'seminarraum' in self.name.lower():
                self.type = 'seminar_room'
            elif 'projektraum' in self.name.lower():
                self.type = 'project_room'
            elif 'lab' in self.name.lower():
                self.type = 'lab'
            elif 'zeichensaal' in self.name.lower():
                self.type = 'drawing_room'
            elif 'büro' in self.name.lower():
                self.type = 'office'
            elif self.name.startswith('PC') or self.name.startswith('EDV') or self.name.startswith('CAD'):
                self.type = 'lab'
        self.parent_name = None
        self.area = area
        self.capacity = capacity
        self.comment = comment

if __name__ == '__main__':
    print('Fetching coLAB rooms...', file=sys.stderr)
    colab_rooms = [
        Room(room.name, room.id, comment='colab')
        for room in tuwien.colab.get_rooms()
    ]
    print('Successfully fetched coLAB rooms', file=sys.stderr)

    print('Fetching TISS rooms...', file=sys.stderr)
    s = tuwien.tiss.Session()
    tiss_rooms = [
        Room(room.name, room.global_id, tiss_code=room.id, capacity=room.capacity, comment='tiss')
        for room in s.rooms.values()
    ]
    print('Successfully fetched TISS rooms', file=sys.stderr)

    print('Fetching RDB rooms...', file=sys.stderr)
    rdb_rooms = [
        Room(room.name, room.id, room_type=room.type, area=room.area, comment='rdb')
        for room in tuwien.rdb.get_rooms()
    ]
    print('Successfully fetched RDB rooms', file=sys.stderr)

    print('Processing rooms...', file=sys.stderr)
    rooms: [Room] = colab_rooms + tiss_rooms + rdb_rooms
    rooms.sort(key=lambda room: (room.room_codes[0][0] + NAME_REPLACE.sub('', room.name)).lower())

    proc = [rooms[0]]
    for room in rooms[1:]:
        last = proc[-1]
        ln = NAME_REPLACE.sub('', last.name.split('|')[0].lower())
        rn = NAME_REPLACE.sub('', room.name.lower())
        if last.room_codes[0] == room.room_codes[0] and (room.tiss_code is None or last.tiss_code is None) and \
                (ln.startswith(rn) or rn.startswith(ln)):
            last.area = last.area or room.area
            last.capacity = last.capacity or room.capacity
            last.tiss_code = last.tiss_code or room.tiss_code
            last.comment = last.comment + ' ' + room.comment
            if last.name != room.name:
                last.name = last.name + ' | ' + room.name
            last.type = last.type or room.type
            if last.type != room.type and (last.type is not None and room.type is not None):
                if room.name == 'Aufbaulabor':
                    last.type = 'drawing_room'
        else:
            proc.append(room)
    proc.sort(
        key=lambda room:
        ((room.type or "other")[:3] +
         room.room_codes[0][0] +
         re.sub(r'[0-9]+', lambda m: ('0000' + m.group(0))[-4:], NAME_REPLACE.sub('', room.name))
         ).lower()
    )
    print('Finished processing rooms', file=sys.stderr)

    print('name,suffix,name_short,alt_name,room_codes,tiss_code,type,parent_name,area,capacity,comment')
    for room in proc:
        print(f'{room.name},{room.suffix or ""},{room.name_short or ""},{room.alt_name or ""},'
              f'{" ".join(room.room_codes)},{room.tiss_code or ""},{room.type or "other"},{room.parent_name or ""},'
              f'{room.area or ""},{room.capacity or ""},{room.comment or ""}')


from django.contrib import admin
from django.conf import settings

from .forms import BaseArticleForm
from .models import Article, Brief, Sidebar
from .models import Destination, Category, Attachment, ArticleImage
from .models import supports_video, supports_polls, supports_galleries

if supports_video:
    from video.admin import VideoInline

class ArticleImagesInline(admin.TabularInline):
    model = ArticleImage
    extra = 3

class SidebarInline(admin.TabularInline):
    model = Sidebar
    extra = 2

class AttachmentInline(admin.TabularInline):
    model = Attachment

class ArticleAdmin(admin.ModelAdmin):
    form = BaseArticleForm

    ordering = ['-created']
    list_display = ('title', 'author', 'destination', 'created',)
    list_filter = ('created', 'last_modified', 'enable_comments', 'publication', 'destination')
    prepopulated_fields = {'slug': ('title',)}
    search_fields = ['body', 'title']
    filter_horizontal = ['sections', 'articles']
    inlines = [
        ArticleImagesInline,
        SidebarInline,
        AttachmentInline
    ]
    related = ('Related', {
        'fields': ['articles'],
        'description': 'Other content directly related to this article'
    })
    if supports_video:
        inlines.append(VideoInline)
    if supports_galleries:
        related[1]['fields'].insert(0, 'galleries')
        filter_horizontal.append('galleries')
    if supports_polls:
        related[1]['fields'].insert(0, 'polls')

    fieldsets = (
        ('Author info', {'fields': (('author', 'guest_author'))}),
        ('Header', {'fields': ('overline', 'title', 'subhead')}),
        ('Content', {'fields': ('summary', 'body', 'pull_quote', 'endnote')}),
        ('Admin fields', {
            'description': 'You should rarely, if ever, need to touch these fields.',
            'fields': ('slug', 'enable_comments', 'sites', 'override_url'),
            'classes': ['collapse']
        }),
        ('Routing', {'fields': ('destination', 'sections')}),
        related,
        ('Meta',     {
            'fields': (('publication'), 'featured'),
            'description': 'Additional information about this story'
        }),
        ('Bulk photo upload', {
            'fields': ('upload',),
            'description': "Upload multiple photos, if you don't want to handle them individually."
        })
    )

    def save_model(self, request, obj, form, change):
        obj.save()
        for img in request.FILES.getlist('upload'):
            ArticleImage(
                image=img,
                article=obj
            ).save()
        obj.bulk_upload = None
        obj.save()

class BriefAdmin(admin.ModelAdmin):
    list_display = ('pub_date', 'text')

    def formfield_for_dbfield(self, db_field, **kwargs):
        if db_field.name == 'text' and 'tango_admin' in settings.INSTALLED_APPS:
            from tango_admin.admin import TextCounterWidget
            kwargs['widget'] = TextCounterWidget()
        return super(BriefAdmin, self).formfield_for_dbfield(db_field, **kwargs)

class DestinationAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('title',)}

admin.site.register(Destination, DestinationAdmin)
admin.site.register(Category)
admin.site.register(Brief, BriefAdmin)
admin.site.register(Article, ArticleAdmin)


import datetime

from flask import Blueprint, jsonify, request

from model.example import Example
from repository.example import ExampleRepository

app_example = Blueprint('example', __name__, url_prefix='/examples')

example_repository = ExampleRepository()

@app_example.route('', methods=['GET'])
def examples():
    # 条件查询
    data = example_repository.query_by(where="")
    if len(data) <= 0:
        jsonify(error="not found any data"), 404

    return jsonify(data)

@app_example.route('/<id>', methods=['GET'])
def example(id):
    # 条件查询
    data = example_repository.query_first_by(where="`id`= %s", params=(id,))
    if data is None:
        jsonify(error="not found any data"), 404

    return jsonify(data)

@app_example.route('', methods=['POST'])
def save():
    data = request.get_json()
    if data is not None and len(data) > 0:
        example = Example()
        example.set_attrs(data)
        example.created_at = datetime.datetime.now()
        example.updated_at = datetime.datetime.now()
        # 保存数据
        example.save()
        return jsonify(example.id)
    else:
        return jsonify(error="not found any data to save"), 400

@app_example.route('/<id>', methods=['DELETE'])
def delete(id):
    result = True
    example = Example()
    example.id = id
    example.deleted_at = datetime.datetime.now()
    # 根据id删除数据
    result = example.delete() > 0
    return jsonify(result)

@app_example.route('/<id>', methods=['PUT'])
def update(id):
    result = True
    data = request.get_json()
    example = Example()
    example.set_attrs(data)
    example.id = id
    example.updated_at = datetime.datetime.now()
    # 根据id更新数据
    result = example.update() > 0
    return jsonify(result)


from django.shortcuts import render,redirect
from address.models import Address

# Create your views here.
def home(requsest):
    return render(requsest, "address/index.html")
def list(request):
    # ----------------------------------------------------
    # select * from address_address
    #select count(*) from address_address
    #sql문을 사용할 수 있지만 보통은 함수로 호출해서 사용하는 것이 일반적
    # - Addressw.objects 레코드 주소
    # - order_by('') : 오름차순
    # - order_by('-') : 내림차순
    # ----------------------------------------------------
    items = Address.objects.order_by('name')

    #group 함수
    address_count = Address.objects.all().count()

    #이제 이 값을 url에 넘겨줘야지.
    return render(request, "address/addressList.html", {'items': items,
                                                        'address_count':address_count})
def write(request):
    return render(request, "address/addressWrite.html")

# form 파라미터 처리
def insert(request):
    # print("name :", request.POST['name'])

    # 데이터 베이스에 입력 처리 (idx 는 Oracle의 순번과 동일)
    addr = Address(name=request.POST['name'],
                   tel=request.POST['tel'],
                   email=request.POST['email'],
                   address=request.POST['address'],
    )
    addr.save()  # 레코드 추가

    # redirect 때는 /로 절대경로 설정해주어야함.
    return redirect("/address/list".Address)
    ##### redirect의 수입을 위해 ctrl+space 하면 자동 수입됨 #####

#상세페이지
def detail(request):
    idv = request.GET['idx']
    #select * from address_address where idx = idv
    addr = Address.objects.get(idx=idv)
    return render(request,'address/detail.html',{'addr':addr})

# 삭제 기능
# csrf_protect는 csrf 방식을 검증한다.
# 앞으로 post 방식일 때는 반드시 사용을 원칙으로 한다.
def delete(request):
    idv = request.POST['idx']
    print("idx:", idv)
    # delete * from address_address where idx = idv
    # 선택한 데이터의 레코드가 삭제됨
    addr = Address.objects.get(idx=idv).delete()
    return redirect('/address/list')

# 수정 기능
def update(request):
    id = request.POST['idx']
    name = request.POST['name']
    tel = request.POST['tel']
    email = request.POST['email']
    address = request.POST['address']

    print("idx:", id)
    print("name:", name)
    print("tel:", tel)
    print("email:", email)
    print("address:", address)
# 수정 데이터 베이스 처리(idx=id -> 값을 넣으면 수정, 없으면 auto로 생성되므로 없어도됨)
    addr = Address(idx=id, name=name, tel=tel, email=email, address=address)

    # 데이터 레코드가 수정됨
    addr.save()

    return redirect('/address/list')


import torch
from torch.distributions import Categorical

class Agent(object):
    def __init__(self, env):
        self.env = env
        #self.reset()

    """
    def reset(self):
        self.state = self.env.reset()
        self.total_reward = 0.0

    def play_step(self, net):
        done_reward = None

        state = torch.from_numpy(self.state).float().unsqueeze(0)
        probs = net(state)
        m = Categorical(probs)
        actions = m.sample()
        net.saved_log_probs.append(m.log_prob(actions))
        action = actions.item()

        new_state, reward, done, _ = self.env.step(action)

        self.total_reward += reward
        net.rewards.append(reward)

        self.state = new_state

        if done:
            done_reward = self.total_reward
            self.reset()

        return done_reward
    """

    def select_action(self, net, state):
        state = torch.from_numpy(state).float().unsqueeze(0)
        probs = net(state)
        m = Categorical(probs)
        action = m.sample()
        net.saved_log_probs.append(m.log_prob(action))
        return action.item()


import pandas as pd
import glob
import json
import os

from tqdm import tqdm

class PodcastClaims:

	# transcript claims
	def __init__(self, show_uri, episode_uri, transcript_claims):
		self.show_uri = show_uri
		self.episode_uri = episode_uri
		self.transcript_claims = transcript_claims

	def divide_claims(self, surrounding_context=2):
		divided_claims = []

		# pad claims, prepend and extend empty strings to array
		temp_claims = self.transcript_claims.copy()
		temp_claims[:0] = ['SEP'] * surrounding_context
		temp_claims[len(temp_claims):] = ['SEP'] * surrounding_context

		for idx in range(len(self.transcript_claims)):

			# print((idx, 2 * surrounding_context + 1))
			# print(temp_claims[idx:2 * surrounding_context + 1])

			divided_claims.append(temp_claims[idx: idx + 2 * surrounding_context + 1])

		return divided_claims

def main(podcast_dir="../podcasts-no-audio-13GB/spotify-podcasts-2020", surrounding_context=2):

	# Find all podcasts (.json files) in subdirectory
	podcast_filepaths = glob.glob(podcast_dir + "/**/*.json", recursive=True)

	# Read each podcast, concatenate all the transcript claims, then save claims
	## NOTE: A transcript claim is a sentence > 5 words within the podcast

	for podcast_fp in tqdm(podcast_filepaths):
		podcast = read_transcript(podcast_fp)
		save_transcript(podcast, surrounding_context=surrounding_context)
		break

# saves transcript claims in a tsv (tab separated file)
# line format is show_uri, episode_uri, context_claims
def save_transcript(podcast, surrounding_context=2):

	save_dir = f"./outputs"

	if not os.path.isdir(save_dir):
		os.mkdir(save_dir)

	save_fp = f"{save_dir}/podcast_claims_context_{surrounding_context}.tsv"

	divided_claims = podcast.divide_claims(surrounding_context=surrounding_context)

	with open(save_fp, 'a') as f:
		for dc in divided_claims:
			save_str = f"{podcast.show_uri}\t{podcast.episode_uri}\t"
			save_str += "\t".join(dc) + "\n"
			f.write(save_str)

def read_transcript(podcast_fp):
	claims = []
	data = []

	# define episode and show uri
	path, episode_uri = os.path.split(podcast_fp)
	episode_uri = os.path.splitext(episode_uri)[0]
	_, show_uri = os.path.split(path)

	with open(podcast_fp, 'r') as f:
		data = json.load(f)

	for results in data['results']:
		if 'transcript' in results['alternatives'][0]:
			claims.extend(clean_and_filter_claims(results['alternatives'][0]['transcript'].split('.')))

	return PodcastClaims(show_uri=show_uri, episode_uri=episode_uri, transcript_claims=claims)

# claims is an array of strings (each claim is a sentence within the podcast transcript)
def clean_and_filter_claims(claims):
	temp_claims = []

	for claim in claims:

		# replace tabs with spaces
		temp_claim = claim.replace('\t', ' ')

		# filter claims based on amount of words
		if len(temp_claim.split(" ")) < 5:
			continue

		temp_claims.append(temp_claim)

	return temp_claims

if __name__ == "__main__":
	main(podcast_dir="../podcasts-no-audio-13GB/spotify-podcasts-2020", surrounding_context=2)


# -*- coding: utf-8 -*-
"""
Created on Thu Feb  2 16:41:09 2023

@author: ugo.pelissier
"""

from matplotlib.image import imread
from tabulate import tabulate
from tabulate import tabulate
import matplotlib.pyplot as plt
import numpy as np
import os
import time
from scipy.linalg import interpolative, rq

#-----------------------------------------------------------------------------#
# RANDOMIZED SVD
#-----------------------------------------------------------------------------#
def rSVD(A,r,q,p):
    """

    Parameters
    ----------
    A : numpy array
        Target matrix.
    r : int
        Target rank.
    q : int
        Power iterarions.
    p : int
        Oversampling factor.

    Returns
    -------
    Low-rank SVD approximation for A.

    """
    start = time.time()

    # Step 1 : Sample column space of A with random matrix
    m, n = A.shape
    l=r+p
    Omega = np.random.randn(n,l)
    Y = A @ Omega
    for k in range(q):
        Y = A @ (A.T @ Y)
    Q, R = np.linalg.qr(Y,mode='reduced')

    # Step 2: Compute SVD on projected Y = Q.T @ A
    Z = Q.T @ A
    UY, S, VT = np.linalg.svd(Z,full_matrices=0)
    U = Q @ UY

    end = time.time()

    return U, S, VT, (end-start)

def adaptative_randomized_range_finder(A, r, eps, max_iter):
    """

    Parameters
    ----------
    A : numpy array
        Target matrix.
    r : int
        Size of the standard gaussian vector used for error approximation.
    eps : float
        Tolerance for error approximation.
    max_iter : int
        Max number of iterations.

    Returns
    -------
    Q : numpy array
        Orthonormal matrix whose range approximates the range of X.
    approx_error_list : array of floats
        DESCRIPTION.
    true_error_list : array of floats
        DESCRIPTION.
    j : int
        Number of iterations.

    """
    m, n = A.shape
    omega = np.random.randn(n,r) # Gaussian vectors
    y = A @ omega

    # Stoping criteria
    threshold = eps/(10*np.sqrt(2/np.pi))
    approx_error = np.linalg.norm(y[:,-r:],axis=0).max()

    # Initialization
    Q = np.empty([m, 0])
    I = np.eye(m)
    approx_error_list = []
    true_error_list = []

    for j in range(max_iter):
        if (approx_error<threshold):
            # print("\nAdaptative randomized range finder converged in {} iterations.".format(j))
            return Q, np.array(approx_error_list), np.array(true_error_list), j

        else:

            # Project y onto Q
            y[:,j] = (I - Q @ Q.T) @ y[:, j]

            # Normalize and append
            q = y[:,j] / np.linalg.norm(y[:,j])
            Q = np.concatenate((Q, q.reshape(len(q),1)), axis=1)

            # New gaussian vector
            omega = np.random.randn(n,1)

            # Get its approximation error
            y_new = (I - Q @ Q.T) @ (A @ omega)

            # Append to y
            y = np.concatenate((y, y_new), axis=1)

            # Update previous y(i)
            for k in range(j+1,j+r):
                y[:,k] -= q*np.dot(q, y[:,k])

            # Compute new approx error
            approx_error = np.linalg.norm(y[:,-r:],axis=0).max()
            approx_error_list.append(approx_error)

            # True error (normally not computed)
            true_error = np.linalg.norm(((I - Q @ Q.T) @ A),ord=2)
            true_error_list.append(true_error)

    print("Maximum iteration reached. Consider increase max_iter.")

    return Q, np.array(approx_error_list), np.array(true_error_list), j

def adaptative_range_finder_rSVD(A, r, eps, max_iter, q, p):
    """

    Parameters
    ----------
    A : numpy array
        Target matrix.
    r : int
        Size of the standard gaussian vector used for error approximation.
    eps : float
        Tolerance for error approximation.
    max_iter : int
        Max number of iterations.
    q : int
        Power iterarions.
    p : int
        Oversampling factor.

    Returns
    -------
    Low-rank SVD approximation for X.

    """
    start = time.time()

    # Step 1 : Sample column space of X with random P matrix
    Q, _, _, _ = adaptative_randomized_range_finder(A, r, eps, max_iter)

    # Step 2: Compute SVD on projected Y = Q.T @ A
    Y = Q.T @ A
    UY, S, VT = np.linalg.svd(Y,full_matrices=0)
    U = Q @ UY

    end = time.time()

    return U, S, VT, (end-start)

def randomized_subspace_iteration(A,r,q,p):
    """

    Parameters
    ----------
    A : numpy array
        Target matrix.
    r : int
        Target rank.
    q : int
        Power iterarions.
    p : int
        Oversampling factor.

    Returns
    -------

    """
    l=r+p
    m, n = A.shape
    omega = np.random.randn(n,l) # Gaussian vectors

    Y = A @ omega
    Q, R = np.linalg.qr(Y,mode='reduced')

    for j in range(1,q+1):
        Y_tilde = A.T @ Q
        Q_tilde, R_tilde = np.linalg.qr(Y_tilde,mode='reduced')

        Y = A @ Q_tilde
        Q, R = np.linalg.qr(Y,mode='reduced')

    return Q

def randomized_subspace_iteration_rSVD(A,r,q,p):
    """

    Parameters
    ----------
    A : numpy array
        Target matrix.
    r : int
        Target rank.
    q : int
        Power iterarions.
    p : int
        Oversampling factor.

    Returns
    -------

    """
    start = time.time()

    # Step 1 : Sample column space of A with random P matrix
    Q = randomized_subspace_iteration(A,r,q,p)

    # Step 2: Compute SVD on projected Y = Q.T @ A
    Y = Q.T @ A
    UY, S, VT = np.linalg.svd(Y,full_matrices=0)
    U = Q @ UY

    end = time.time()

    return U, S, VT, (end-start)

def row_extraction_svd(A,r,q,p):
    """

    Parameters
    ----------
    A : numpy array
        Target matrix.
    r : int
        Target rank.
    q : int
        Power iterarions.
    p : int
        Oversampling factor.

    Returns
    -------
    Low-rank SVD approximation for A.

    """
    start = time.time()

    # Step 1 : Sample column space of A with random matrix
    m, n = A.shape
    l=r+p
    Omega = np.random.randn(n,l)
    Y = A @ Omega
    for k in range(q):
        Y = A @ (A.T @ Y)

    Q, R = np.linalg.qr(Y,mode='reduced')
    J, proj = interpolative.interp_decomp(Q.T, l, rand=True)

    X = np.zeros((Q.T).shape)
    X[:,J[:l]] = np.eye(l)
    X[:,J[l:]] = proj

    # R, W = rq(A[J[:l],:], mode='economic')
    # Z = X.T @ R
    # U, S, VT_tilde = np.linalg.svd(Z,full_matrices=0)
    # V = W.T @ VT_tilde.T

    # end = time.time()

    # return U, S, V.T, (end-start)
    UY, S, VT = np.linalg.svd(A[J[:l],:],full_matrices=0)
    U = X.T @ UY

    end = time.time()
    return U, S, VT, (end-start)

def reconstruction(A, r, eps, max_iter, target_rank, q, p):
    """

    Parameters
    ----------
    A : numpy array
        Target matrix.
    r : int
        Size of the standard gaussian vector used for error approximation.
    eps : float
        Tolerance for error approximation.
    max_iter : int
        Max number of iterations.
    target_rank : int
        Target rank for classic randomized SVD.
    q : int
        Power iterarions.
    p : int
        Oversampling factor.

    Returns
    -------
    SVD decomposition, error and computation time for classic SVD, randomized SVD, and adaptative randomized SVD

    """
    start = time.time()
    U, S, VT = np.linalg.svd(A) # Full SVD decomposition
    end = time.time()
    ASVD = U[:,:(target_rank+1)] @ np.diag(S[:(target_rank+1)]) @ VT[:(target_rank+1),:] # SVD approximation
    epsSVD = np.linalg.norm(A-ASVD)/np.linalg.norm(A)

    rU, rS, rVT, rt = rSVD(A, target_rank, q, p)
    ArSVD = rU[:,:(target_rank+1)] @ np.diag(rS[:(target_rank+1)]) @ rVT[:(target_rank+1),:] # SVD approximation
    epsrSVD = np.linalg.norm(A-ArSVD)/np.linalg.norm(A)

    # adaptative_rU, adaptative_rS, adaptative_rVT, adaptative_rt = adaptative_range_finder_rSVD(A, r, eps, max_iter, q, p)
    # adaptative_ArSVD = adaptative_rU[:,:(r+1)] @ np.diag(adaptative_rS[:(r+1)]) @ adaptative_rVT[:(r+1),:] # SVD approximation
    # eps_adaptative_rSVD = np.linalg.norm(A-adaptative_ArSVD)/np.linalg.norm(A)

    # iteration_rU, iteration_rS, iteration_rVT, iteration_rt = randomized_subspace_iteration_rSVD(A, target_rank, q, p)
    # iteration_ArSVD = iteration_rU[:,:(r+1)] @ np.diag(iteration_rS[:(r+1)]) @ iteration_rVT[:(r+1),:] # SVD approximation
    # eps_iteration_rSVD = np.linalg.norm(A-iteration_ArSVD)/np.linalg.norm(A)

    row_extraction_rU, row_extraction_rS, row_extraction_rVT, row_extraction_rt = row_extraction_svd(A, target_rank, q, p)
    row_extraction_ArSVD = row_extraction_rU[:,:(target_rank+1)] @ np.diag(row_extraction_rS[:(target_rank+1)]) @ row_extraction_rVT[:(target_rank+1),:] # SVD approximation
    eps_row_extraction_rSVD = np.linalg.norm(A-row_extraction_ArSVD)/np.linalg.norm(A)

    return ASVD, ArSVD, row_extraction_ArSVD, epsSVD, epsrSVD, eps_row_extraction_rSVD, (end-start), rt, row_extraction_rt

#-----------------------------------------------------------------------------#
# MATRIX GENERATORS
#-----------------------------------------------------------------------------#
def fixed_rank_matrix(m, n, rank):
    """

    Parameters
    ----------
    m : int
        Number of rows.
    n : TYPE
        Number of columns.
    rank : int
        Rank of the matrix.

    Returns
    -------
    A : numpy array
        Matrix of size (m,n) & rank=r.
    S : numpy array
        Singular values.

    """
    A = np.random.rand(m,n)
    U, S, VT = np.linalg.svd(A,full_matrices=0)
    S[rank:]=0
    S = (S/S.max())**3  # quickly decaying spectrum
    A = U @ np.diag(S) @ VT
    return A, S

def linear_decaying_spectrum(m, n):
    """

    Parameters
    ----------
    m : int
        Number of rows.
    n : int
        Number of columns

    Returns
    -------
    A : numpy array
        Matrix of size (m,n).
    S : numpy array
        Singular values.

    """
    A = np.random.rand(m,n)
    U, S, VT = np.linalg.svd(A,full_matrices=0)
    S[:m] = np.arange(1,0,-1/n)
    A = U @ np.diag(S) @ VT
    return A, S

#-----------------------------------------------------------------------------#
# POST-PROCESS
#-----------------------------------------------------------------------------#
def time_compare(A, p, q):
    start = time.time()
    U, S, VT = np.linalg.svd(A) # Full SVD decomposition
    end = time.time()
    t_SVD = end-start

    X = []
    T_rSVD = []
    T_extract_rSVD = []
    for i in range(1,501,10):
        X.append(i)

        rU, rS, rVT, rt = rSVD(A, i, q, p)
        T_rSVD.append(rt)

        row_extraction_rU, row_extraction_rS, row_extraction_rVT, row_extraction_rt = row_extraction_svd(A, i, q, p)
        T_extract_rSVD.append(row_extraction_rt)

    T_SVD = [t_SVD for i in range(len(T_rSVD))]

    plt.semilogy(X,T_SVD,'r',label='SVD')
    plt.semilogy(X,T_rSVD,'k',label='rSVD')
    plt.semilogy(X,T_extract_rSVD,'b',label='row_extract_rSVD')

    plt.xlabel("Target rank")
    plt.ylabel("Time (s)")

    plt.legend()
    plt.savefig('time_compare.png', dpi=600)
    plt.show()

def check_adaptative_randomized_range_finder(X, m, n, rank, r, eps, max_iter):
    A, S = fixed_rank_matrix(m, n, rank)
    Q_approx, approx_error_list, true_error_list, j = adaptative_randomized_range_finder(A, r, eps, max_iter)

    print(f"\nReal rank: {rank} | Computed rank: {Q_approx.shape[1]}")

    fig, ax = plt.subplots(1, 1)
    ax.plot(approx_error_list, 'k', label="estimated error")
    ax.plot(true_error_list, 'r', label="true error")
    ax.set(yscale='log', ylabel="error", xlabel='iter', title=f"Real rank: {rank} | Computed rank: {Q_approx.shape[1]}")
    plt.legend()
    plt.savefig('adaptative_randomized_range_finder.png', dpi=600)
    plt.show()

    Q_approx, approx_error_list, true_error_list, j = adaptative_randomized_range_finder(X, r, eps, max_iter)
    fig, ax = plt.subplots(1, 1)
    ax.plot(approx_error_list, 'k', label="estimated error")
    ax.plot(true_error_list, 'r', label="true error")
    ax.set(yscale='log', ylabel="error", xlabel='iter', title=f"Computed rank: {Q_approx.shape[1]}")
    plt.legend()
    plt.savefig('adaptative_randomized_range_finder.png', dpi=600)
    plt.show()

def accuracy_check(A, q, p):
    step = 50
    start = 1

    m, n = A.shape

    U, S, VT = np.linalg.svd(A,full_matrices=0) #SVD decompisition

    error = []
    for r in range(start,start+step):
        rU, rS, rVT, rt = rSVD(A, r, q=0, p=0)
        ArSVD = rU[:,:(r+1)] @ np.diag(rS[:(r+1)]) @ rVT[:(r+1),:] # SVD approximation
        epsrSVD = np.linalg.norm(A-ArSVD,ord=2)
        error.append(epsrSVD)
    plt.plot(np.log10(error), 'b-x', label="$log_{10}(e_{k})$ - $(q,p)=(0,0)$")

    error = []
    for r in range(start,start+step):
        rU, rS, rVT, rt = rSVD(A, r, q=0, p=5)
        ArSVD = rU[:,:(r+1)] @ np.diag(rS[:(r+1)]) @ rVT[:(r+1),:] # SVD approximation
        epsrSVD = np.linalg.norm(A-ArSVD,ord=2)
        error.append(epsrSVD)
    plt.plot(np.log10(error), 'r-x', label="$log_{10}(e_{k})$ - $(q,p)=(0,5)$")

    error = []
    for r in range(start,start+step):
        rU, rS, rVT, rt = rSVD(A, r, q=2, p=5)
        ArSVD = rU[:,:(r+1)] @ np.diag(rS[:(r+1)]) @ rVT[:(r+1),:] # SVD approximation
        epsrSVD = np.linalg.norm(A-ArSVD,ord=2)
        error.append(epsrSVD)
    plt.plot(np.log10(error), 'g-x', label="$log_{10}(e_{k})$ - $(q,p)=(2,5)$")

    plt.plot(np.log10(S[start+1:start+step+1]), 'k-x', label="$log_{10}(\sigma_{k+1})$")

    plt.xlabel("$k$")
    plt.legend()
    plt.savefig('accuracy.png', dpi=600)
    plt.show()

def plot_singular_values(S):
    plt.semilogy(np.diag(S))
    plt.title('Singular values')
    plt.show()

def plot_images(ASVD, ArSVD, row_extraction_ArSVD, target_rank):
    fig, axs = plt.subplots(1,3)

    plt.set_cmap('gray')

    axs[0].imshow(ASVD)
    axs[0].axis('off')
    axs[0].title.set_text('SVD')
    axs[1].imshow(ArSVD)
    axs[1].axis('off')
    axs[1].title.set_text('rSVD')
    axs[2].imshow(row_extraction_ArSVD)
    axs[2].axis('off')
    axs[2].title.set_text('Row extract rSVD')

    fig.tight_layout()
    fig.subplots_adjust(top=0.88)

    fig.savefig(f"jupiter_svd_compare_r_{target_rank}.png", dpi=600)
    plt.show()

def plot_compare(A, r, eps, max_iter, target_rank, q, p):
    ASVD, ArSVD, row_extraction_ArSVD, epsSVD, epsrSVD, eps_row_extraction_rSVD, t, rt, row_extraction_rt = reconstruction(A, r=10, eps=1e-5, max_iter=A.shape[1], target_rank=target_rank, q=q, p=p)
    plot_images(ASVD, ArSVD, row_extraction_ArSVD, target_rank)

def illustrate_power_iterations():
    A, S = linear_decaying_spectrum(m=1000, n=100)

    color_list = np.array([[0,0,2/3],
                           [0,0,1],
                           [0,1/3,1],
                           [0,2/3,1],
                           [0,1,1],
                           [1/3,1,2/3],
                           [2/3,1,1/3],
                           [1,1,0],
                           [1,2/3,0],
                           [1,1/3,0],
                           [1,0,0],
                           [2/3,0,0]])

    plt.plot(S,color='k',label='SVD')

    Y = A
    for q in range(1,6):
        Y = A.T @ Y
        Y = A @ Y
        Uq, Sq, VTq = np.linalg.svd(Y,full_matrices=0)
        plt.plot(Sq, color=tuple(color_list[2*q+1]),label='rSVD, q='+str(q))

    plt.xlabel("$k$")
    plt.legend()
    plt.savefig('power_iteration.png', dpi=600)
    plt.show()

def printInfo(epsSVD, epsrSVD, eps_row_extraction_rSVD, t, rt, row_extraction_rt):
    data = [["Error",epsSVD, epsrSVD, eps_row_extraction_rSVD],
            ["Time (s)",t, rt, row_extraction_rt]]
    print ("\n",tabulate(data, headers=["","SVD","rSVD", "row_extract_rSVD"]))

A = imread('data/jupiter.png')
A = np.mean(A,axis=2) # Convert RGB to grayscale

# img = plt.imshow(A)
# img.set_cmap('gray')
# plt.axis('off')
# plt.show()

target_rank = 1000
q = 2
p = 5

ASVD, ArSVD, row_extraction_ArSVD, epsSVD, epsrSVD, eps_row_extraction_rSVD, t, rt, row_extraction_rt = reconstruction(A, r=10, eps=1e-5, max_iter=A.shape[1], target_rank=target_rank, q=q, p=p)

# printInfo(epsSVD, epsrSVD, eps_row_extraction_rSVD, t, rt, row_extraction_rt)

# check_adaptative_randomized_range_finder(m=1000, n=1000, rank=50, r=20, eps=1e-5, max_iter=200)

# illustrate_power_iterations()

# accuracy_check(A, q, p)

# check_adaptative_randomized_range_finder(A, m=1000, n=500, rank=50, r=10, eps=1e-5, max_iter=1600)

# time_compare(A, p, q)

plot_compare(A, r=10, eps=1e-5, max_iter=A.shape[1], target_rank=target_rank, q=q, p=p)


"""
    进程池使用演示
    进程池：作用
    大量函数需要频繁销毁，创建，
    先写事件函数，后创建进程池
    父进程结束，进程池销毁
"""
from multiprocessing import Pool
from time import sleep, ctime, time

start = time()
# 进程池事件函数
def worker(msg):
    sleep(2)
    print(ctime(), "--", msg)
    return 200

# 创建进程池，进程池事件，必须写在上面

pool = Pool(4)  # 不写参数，默认使用机器所有内核

# 向进程池中添加事件
for i in range(10):
    msg = "Tedu %d"%i
    r = pool.apply_async(func=worker, args=(msg,))  # args传的是元组

# 关闭进程池
pool.close()

# 回收进程池
pool.join()
# print(r.get())    # 获取进程池的返回值
end = time()
print(end-start)


import time
from collections import namedtuple

from adafruit_pybadger import pybadger

from states import DefaultMenuItemState, MainMenu, State, StateManager
from util import ALL_COLORS, display_bg_and_text, generate_qr_code_display_group

# These are constants, try changing them and saving the file!
NAME = "Pythonista"
NAME_BADGE_COLORS = ALL_COLORS
URL = "https://aka.ms/pycon2020"
LED_BRIGHTNESS = 0.1  # Dim the brightness of the LEDs.
pybadger.pixels.brightness = LED_BRIGHTNESS

class PressStart(State):

    label = "Main Screen"

    def display(self):
        display_bg_and_text(image="images/initial.bmp", text="press start to begin")

    def handle_event(self):
        if pybadger.button.start:
            state_manager.state = MainMenu
        elif pybadger.button.a and pybadger.button.b:
            state_manager.state = EasterEgg

class Credits(DefaultMenuItemState):

    label = "Credits"

    def display(self):
        display_bg_and_text(image="images/credits.bmp")

class NameBadge(DefaultMenuItemState):

    label = "Name Badge"

    led_on = True

    def display(self):
        self.led_color = NAME_BADGE_COLORS[self.current_index % len(NAME_BADGE_COLORS)]
        pybadger.show_badge(
            name_string=NAME,
            background_color=self.led_color,
            hello_scale=2,
            my_name_is_scale=2,
            name_scale=2,
        )

class QrCode(DefaultMenuItemState):

    label = "Learn More"

    def __init__(self):
        self.qr_group = generate_qr_code_display_group(URL)
        super().__init__()

    def display(self):
        pybadger.display.show(self.qr_group)

class SocialBattery(DefaultMenuItemState):

    label = "Social Battery Status"

    led_on = True

    GREEN = (0, 255, 0)
    YELLOW = (255, 255, 0)
    RED = (255, 0, 0)

    SocialState = namedtuple("SocialState", ["color", "image"])
    states = [
        SocialState(color=GREEN, image="images/social_battery/full.bmp"),
        SocialState(color=YELLOW, image="images/social_battery/low.bmp"),
        SocialState(color=RED, image="images/social_battery/empty.bmp"),
    ]

    def display(self):
        social_state = self.states[self.current_index % len(self.states)]
        display_bg_and_text(image=social_state.image)
        self.led_color = social_state.color

class EasterEgg(State):

    label = "Easter Egg"

    def display(self):
        display_bg_and_text(image="images/easter_egg/easter_egg.bmp")
        time.sleep(4.0)  # Wait 4 seconds, then return to main state_manager.
        state_manager.previous_state()

main_menu = MainMenu(NameBadge, SocialBattery, QrCode, Credits, PressStart)

state_manager = StateManager()
state_manager.add(
    main_menu,
    PressStart(),
    Credits(),
    NameBadge(),
    QrCode(),
    SocialBattery(),
    EasterEgg(),
)
state_manager.state = PressStart

while True:
    state_manager.check_for_event()
    time.sleep(0.15)  # Prevent duplicate button presses.


import json
import requests

url = "https://dsci551project-1ff87-default-rtdb.firebaseio.com/"

def ls(inp):
    a = inp.split()
    root = 'root'

    resp = requests.get(url + root + a[1] + '.json').json()
    res = json.dumps(resp , indent = 4)
    return str(res)

if __name__ == '__main__':
    ls()


import re
import rpm
from spacewalk.common import rhn_pkg
from spacewalk.common.rhnException import rhnFault
from spacewalk.server import rhnPackageUpload

CACHE_DIR = '/var/cache/rhn/reposync/'

class ContentPackage:

    def __init__(self):
        # map of checksums
        self.checksum_type = None
        self.checksum = None

        # unique ID that can be used by plugin
        self.unique_id = None

        self.name = None
        self.version = None
        self.release = None
        self.epoch = None
        self.arch = None

        self.path = None

        self.a_pkg = None

    def __cmp__(self, other):
        ret = cmp(self.name, other.name)
        if ret == 0:
            rel_self = str(self.release).split('.')[0]
            rel_other = str(other.release).split('.')[0]
            # pylint: disable=E1101
            ret = rpm.labelCompare((str(self.epoch), str(self.version), rel_self),
                                   (str(other.epoch), str(other.version), rel_other))
        if ret == 0:
            ret = cmp(self.arch, other.arch)
        return ret

    def getNRA(self):
        rel = re.match(".*?\\.(.*)",self.release)
        rel = rel.group(1)
        nra = str(self.name) + str(rel) + str(self.arch)
        return nra

    def setNVREA(self, name, version, release, epoch, arch):
        self.name = name
        self.version = version
        self.release = release
        self.arch = arch
        self.epoch = epoch

    def getNVREA(self):
        if self.epoch:
            return self.name + '-' + self.version + '-' + self.release + '-' + self.epoch + '.' + self.arch
        else:
            return self.name + '-' + self.version + '-' + self.release + '.' + self.arch

    def getNEVRA(self):
        if self.epoch is None:
            self.epoch = '0'
        return self.name + '-' + self.epoch + ':' + self.version + '-' + self.release + '.' + self.arch

    def load_checksum_from_header(self):
        if self.path is None:
            raise rhnFault(50, "Unable to load package", explain=0)
        self.a_pkg = rhn_pkg.package_from_filename(self.path)
        self.a_pkg.read_header()
        self.a_pkg.payload_checksum()
        self.a_pkg.input_stream.close()

    def upload_package(self, org_id, metadata_only=False):
        if not metadata_only:
            rel_package_path = rhnPackageUpload.relative_path_from_header(
                self.a_pkg.header, org_id, self.a_pkg.checksum_type, self.a_pkg.checksum)
        else:
            rel_package_path = None
        _unused = rhnPackageUpload.push_package(self.a_pkg,
                                                force=False,
                                                relative_path=rel_package_path,
                                                org_id=org_id)
        return rel_package_path


#import Classes.Person

from Classes import Person,Meeting,Course,Attendance,Class
import os
import sqlite3
import csv

class Teacher(Person.Person):
    def __init__(self,userid="KKumar",name="KrishnaKumar",dob="7-6-1990",ph="33256",email="krishna3@gmail.com",type='T',dept="CSE",cou_tau="OS,SE"):
        super().__init__(userid,name,dob,ph,email,type)
        self.department=dept
        self.courses_taught=cou_tau

    def scheduleMeeting(self,meeting_id,title,conducted_by,course,date,start_time,duration):
        me=Meeting.Meeting(meeting_id,title,conducted_by,course,date,start_time,duration)
        path=os.path.abspath('.')+"/src/DB"
        conn = sqlite3.connect(path+'/person.db')
        cursor = conn.cursor()
        cursor.execute('''INSERT INTO MEETING VALUES (?,?,?,?,?,?,?,"set()")''',(meeting_id,title,conducted_by,course,date,start_time,duration))
        # Display data inserted
        """print("Data Inserted in the table: ")
        data=cursor.execute('''SELECT * FROM PERSON''')
        for row in data:
            print(row)"""
        #Commit your changes in the database
        conn.commit()
        #Closing the connection
        conn.close()
        return me

    def uploadAttendance(meetingid,pth=os.path.abspath('.')+"/src/SampleAttendanceReports/s1.csv"):
        #print(pth)
        eve=[]
        with open(pth,"r",encoding="utf8", errors='ignore') as f:
            reader=csv.reader(x.replace('\0',"") for x in f)
            for ev in reader:
                if ev:
                    #print(ev[0].split('\t')[0])
                    eve.append(ev[0].split('\t')[0])
        pres=set()
        for i in eve[1:]:
            pres.add(i)
        #print(len(pres))
        path=os.path.abspath('.')+"/src/DB"
        conn = sqlite3.connect(path+'/person.db')
        cursor = conn.cursor()
        cursor.execute('''UPDATE MEETING SET ATT_REPORT=? WHERE MEETINGID=?''',[str(pres),meetingid])
        conn.commit()
        for i in pres:
            #print(i)
            t=len(list(cursor.execute('''SELECT * FROM ATTENDANCE''')))
            #at=Attendance.Attendance(t+1,i,meetingid,1,True)
            cursor.execute('''INSERT INTO ATTENDANCE VALUES (?,?,?)''',(t+1,i,meetingid))
        conn.commit()
        #Closing the connection
        conn.close()
        return pres

    def viewScheduleMeetings(self):
        path=os.path.abspath('.')+"/src/DB"
        conn = sqlite3.connect(path+'/person.db')
        cursor = conn.cursor()
        lst=cursor.execute('''SELECT * FROM MEETING WHERE COND_BY=? and ATT_REPORT="set()" ''',[self.userid])
        ret=[list(i) for i in lst]
        conn.commit()
        conn.close()
        return ret

    def viewMeetingAttendance(self,meeting):
        path=os.path.abspath('.')+"/src/DB"
        conn = sqlite3.connect(path+'/person.db')
        cursor = conn.cursor()
        print(meeting)
        lst=cursor.execute('''SELECT ATT_REPORT FROM MEETING WHERE MEETINGID=?''',[meeting])
        ret=[list(i) for i in lst]
        conn.commit()
        conn.close()
        return ret[0]

    def viewOverallAttendance(self,course):
        ret=[]
        path=os.path.abspath('.')+"/src/DB"
        conn = sqlite3.connect(path+'/person.db')
        cursor = conn.cursor()
        CourseId,Title,Prerequisites,ClassEnrolled,FacultyAssigned,LectureAll='0','0','0','0','0','0'
        lst=cursor.execute('''SELECT * FROM COURSE WHERE COURSEID=?''',[course])
        for i in lst:
            CourseId,Title,Prerequisites,ClassEnrolled,FacultyAssigned,LectureAll=i
        lst=cursor.execute('''SELECT * FROM CLASS WHERE CLASSID=?''',[ClassEnrolled])
        for i in lst:
            ClassId,Advisor,Students,CourseEnrolled=i
        conn.close()
        co=Course.Course(CourseId,Title,Prerequisites,ClassEnrolled,FacultyAssigned,LectureAll)
        d=dict()
        for i in Students:
            d[i]=co.getStudentAttendance(i)
        return d.items()

    def viewProfile(self):
        return [self.id,self.usertype,self.name,self.dob,self.ph,self.email,self.department,self.courses_taught]


import os
from requests import get, post, delete

def get_token() -> dict:
    url = 'https://api.moltin.com/oauth/access_token'
    data = {
        'client_id': os.getenv('CLIENT_ID'),
        'client_secret': os.getenv('CLIENT_SECRET'),
        'grant_type': 'client_credentials'
    }
    response = post(url, data=data)
    response.raise_for_status()
    return response.json()

def get_products(access_token: str) -> dict:
    url = 'https://api.moltin.com/pcm/products'
    headers = {'Authorization': f'Bearer {access_token}'}
    response = get(url, headers=headers)
    response.raise_for_status()
    return response.json()

def get_product(access_token: str, product_id: str) -> tuple:
    url = f'https://api.moltin.com/pcm/products/{product_id}'
    headers = {'Authorization': f'Bearer {access_token}'}
    product_response = get(url, headers=headers)
    product_response.raise_for_status()

    url = f'https://api.moltin.com/v2/inventories/{product_id}'
    stock_response = get(url, headers=headers)
    if stock_response.status_code == 404:
        available = 0
    else:
        available = stock_response.json()['data']['available']
    return product_response.json()['data'], available

def get_image_url(access_token: str, file_id: str) -> str:
    url = f'https://api.moltin.com/v2/files/{file_id}'
    headers = {'Authorization': f'Bearer {access_token}'}
    response = get(url, headers=headers)
    response.raise_for_status()
    return response.json()['data']['link']['href']

def add_product_to_cart(
        access_token: str, cart_ref: str, product_id: str, quantity: int
) -> dict:
    url = f'https://api.moltin.com/v2/carts/{cart_ref}/items'
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    payload = {
        "data": {
            "id": product_id,
            "type": "cart_item",
            "quantity": quantity,
        }
    }
    response = post(url, headers=headers, json=payload)
    if response.status_code != 400:  # Insufficient stock returns status 400
        response.raise_for_status()
    return response.json()

def get_cart_items(access_token: str, cart_ref: str) -> dict:
    url = f'https://api.moltin.com/v2/carts/{cart_ref}/items'
    headers = {'Authorization': f'Bearer {access_token}'}
    response = get(url, headers=headers)
    response.raise_for_status()
    return response.json()

def delete_cart_items(access_token: str, cart_id: str) -> None:
    url = f'https://api.moltin.com/v2/carts/{cart_id}/items'
    headers = {'Authorization': f'Bearer {access_token}'}
    response = delete(url, headers=headers)
    response.raise_for_status()

def create_customer(access_token: str, name: str, email: str) -> int:
    url = 'https://api.moltin.com/v2/customers'
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    payload = {
        'data': {
            'type': 'customer',
            'name': str(name),
            'email': email,
        },
    }
    response = post(url, headers=headers, json=payload)
    if response.status_code != 422:  # Failed email validation returns code 422
        response.raise_for_status()
    return response.status_code

def get_customer_by_email(access_token: str, email: str) -> dict:
    url = 'https://api.moltin.com/v2/customers'
    headers = {'Authorization': f'Bearer {access_token}'}
    params = {'filter': f'eq(email,{email})'}
    response = get(url, headers=headers, params=params)
    response.raise_for_status()
    return response.json()

def get_pricebook_id(access_token: str) -> str:
    url = 'https://api.moltin.com/pcm/catalogs'
    headers = {'Authorization': f'Bearer {access_token}'}
    response = get(url, headers=headers)
    response.raise_for_status()
    return response.json()['data'][0]['attributes']['pricebook_id']

def get_all_prices(access_token: str, pricebook_id: str) -> dict:
    url = f'https://api.moltin.com/pcm/pricebooks/{pricebook_id}/prices'
    headers = {'Authorization': f'Bearer {access_token}'}
    response = get(url, headers=headers)
    response.raise_for_status()
    pricelist = {
        position['attributes']['sku']:
            position['attributes']['currencies']['USD']['amount'] / 100
        for position in response.json()['data']
    }
    return pricelist


from common.types import *
from common.utils import *
from model.assets import modelStoreConfig

from YOLOv5n.models.common import DetectMultiBackend
from YOLOv5n.utils.general import non_max_suppression, xyxy2xywh

from .functions import *

import os
import json
import shutil
import subprocess
from datetime import datetime

import base64

import torch
import numpy as np

class MyModel(metaclass=Singleton):
    """
    YOLOv5n 사용!
    """
    def __init__(self, maxRecord=10):
        """
        maxRecord : 몇 개의 Log를 메모리에 기억하고, 사용할 것인지!
        """
        self._logs:List[Log] = []
        self.maxRecord = maxRecord
        self._isConnected = False

        # print("\n\n\n\n\n\n\n",modelStoreConfig['data'] )
        self._device = torch.device("cpu")

        self._model = DetectMultiBackend(modelStoreConfig['weights']['best'], device=self._device, \
            dnn=False, data=modelStoreConfig['data'])
        # torch.save(model, '../yolov5_bear-team/our_last_model.pt')
        # self._model = torch.load(modelStoreConfig['weights']['best'],map_location=self._device, )
        self._model.eval()

    @property
    def logs(self):
        return self._logs

    @property
    def logSrc(self):
        if len(self.logs) == 0:
            return ""
        else:
            return self.logs[0].src

    @property
    def isConnected(self):
        return self._isConnected

    async def add_log(self, log:Log)->None:
        """
        Log가 한계까지 쌓이면 디스크에 저장하고, 가장 오래된 로그를 삭제한다.
        Memory 상에 있는 Log는 항상 같은 Src Video이다!!
        """

        if len(self.logs) != 0:
            if self.logs[0].src != log.src:
                await self.save_log(self.logs[0].src, removed=True)
            else:
                await self.save_log(self.logs[0], removed=False)

        if len(self.logs) == self.maxRecord:
            self.logs.pop(0)

        self.logs.append(log)
        return None

    async def start_log(self, title) -> Log:
        log = Log(src=title, id = 0, recorded=datetime.now(), objects=[], risked=[], risk=RiskCategory.LOW)

        if (modelStoreConfig["paths"]['logs'] / title).exists():
            shutil.rmtree(modelStoreConfig['paths']['logs'] / title)
        os.makedirs(modelStoreConfig['paths']['logs'] / title, exist_ok=True)

        await self.add_log(log)

        self._isConnected = True
        return log

    async def end_log(self, src:str, savedSrc:str) -> None:
        """
        메모리에 있는 Log들을 모두 저장하고, 메모리를 비운다.
        이후, log의 src를 savedSrc로 바꾼다.
        """
        await self.save_log(src, removed=True)
        subprocess.run(['mv', modelStoreConfig['paths']['logs'] / src, modelStoreConfig['paths']['logs'] / savedSrc])

        self._isConnected = False
        return None

    async def save_log(self, src:str, removed=False) -> bool:
        """
        메모리에 있는 Log를 모두 저장한다.
        removed=True라면 Memory를 비운다.
        만약 현재 Log의 src가 지정된 src가 아니라면 False를 반환한다.
        """

        for log in self.logs:
            name = await make_log_name(log.src, log.id)
            with open(name, 'w') as fd:
                fd.write(log.json())

        if removed:
            self._logs = []

        if len(self.logs) != 0 and self.logs[0].src != src:
            return False
        else:
            return True

    async def write(self, img:Image)-> Log:
        """
        Model을 돌려 Log를 기록하고 반환하기
        RGBA -> RGB Channel로 변경하여 Model에 넣는다.
        id는 Image의 Id와 동일하다.
        Log를 돌려받으면 호출한 쪽에서 Image에 위험한 Object들을 넣고, Log와 Image를 함께 Client에 준다.
        Image의 Risk를 사용하지 않는다. 어차피 로그랑 중복!
        """

        data = np.frombuffer(base64.b64decode(img.data), dtype=np.uint8).reshape(img.width, img.height, -1)[..., :3]
        objList:List[Object] = await self._run(data)
        # print("\n\n\n\n\n\n\n", objList, "\n\n\n\n\n\n\n")
        log = Log(src=img.src, id=img.id, recorded=img.captured, objects=objList, risked=[], risk=RiskCategory.LOW)

        await self.add_log(log)
        sameObjects: List[List[Object]] = await find_sameObjects(self.logs)

        highest:RiskCategory = RiskCategory.LOW
        for objects in sameObjects:
            """
            마지막 Object가 가장 최신 프레임!
            """
            risk = calculate_risk(objects)
            objects[-1].risk = risk

            if highest < risk:
                highest = risk

        log.risk = highest
        for idx, obj in enumerate(log.objects):
            if obj.risk == log.risk:
                log.risked.append(idx)

        return log

    @torch.no_grad()
    async def _run(self, img:np.ndarray):
        """
        Return [category, props, center_x, center_y, w, h]
        상대좌표!
        Image : [640, 640, 3]
        한장씩 처리한다.
        """

        maxDet = 500
        classes = None
        confThreshold = 0.25
        iouThreshold = 0.5
        agnosticNMS = False

        img = np.transpose(img, [2, 0, 1]) # WHC -> CWH
        img = np.ascontiguousarray(img)
        img = torch.from_numpy(img).to(torch.float32).to(self._device)
        img /= 255.0

        img = img[None] # Bach 차원 추가하기

        pred = self._model(img)
        pred = non_max_suppression(pred, confThreshold, iouThreshold, classes, agnosticNMS, max_det=maxDet)[0]
        # print("\n\n\n\n\n\n\n", pred, "\n\n\n\n\n\n")
        gn = torch.tensor(img.shape)[[1, 0, 1, 0]] # Normalize whwh

        inferences:List[Object] = []
        for *xyxy, prob, predCategory in reversed(pred):
            xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1)  # normalized xywh

            objCategory:ObjectCategory = ObjectCategory.BICYCLE # Default
            for category in ObjectCategory:
                if int(category) == int(predCategory):
                    objCategory = category
                    break

            object = Object(category=objCategory, probability=float(prob), center=xywh[:2], width=xywh[2], height=xywh[3], risk=RiskCategory.LOW)

            inferences.append(object)
        return inferences

    async def get_log(self, src:str, id: int) -> Log:
        """
        1. Memory에 있는 Log인지 확인한다.
        2. Memory에 없다면, 저장된 로그를 불러온다.
           2-1. 불러온 로그를 메모리에 저장하고, src를 검사한다.
        """
        for log in self.logs:
            if log.src == src and log.id == id:
                return log
            else:
                continue

        logPath = await make_log_name(src, id)
        if not logPath.exists():
            raise FileNotFoundError
        else:
            with open(logPath, 'r') as fd:
                log = Log(**json.load(fd))
                await self.add_log(log)
                return log


#!/usr/bin/env python
try:
    # try setuptools, so devs can run bdist_wheel
    from setuptools import setup, Command
except ImportError:
    # but most users really don't require it
    from distutils.core import setup, Command

import versioneer
versioneer.versionfile_source = "ecdsa/_version.py"
versioneer.versionfile_build = versioneer.versionfile_source
versioneer.tag_prefix = "python-ecdsa-"
versioneer.parentdir_prefix = "ecdsa-"
versioneer.VCS = "git"

commands = versioneer.get_cmdclass().copy()

class Test(Command):
    description = "run unit tests"
    user_options = []
    boolean_options = []
    def initialize_options(self):
        pass
    def finalize_options(self):
        pass
    def run(self):
        from ecdsa import numbertheory
        numbertheory.__main__()
        from ecdsa import ellipticcurve
        ellipticcurve.__main__()
        from ecdsa import ecdsa
        ecdsa.__main__()
        from ecdsa import test_pyecdsa
        test_pyecdsa.unittest.main(module=test_pyecdsa, argv=["dummy"])
        # all tests os.exit(1) upon failure
commands["test"] = Test

setup(name="ecdsa",
      version=versioneer.get_version(),
      description="ECDSA cryptographic signature library (pure python)",
      author="Brian Warner",
      author_email="warner-pyecdsa@lothar.com",
      url="http://github.com/warner/python-ecdsa",
      packages=["ecdsa"],
      license="MIT",
      cmdclass=commands,
      classifiers=[
          "Programming Language :: Python",
          "Programming Language :: Python :: 2",
          "Programming Language :: Python :: 2.6",
          "Programming Language :: Python :: 2.7",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.2",
          "Programming Language :: Python :: 3.3",
          "Programming Language :: Python :: 3.4",
      ],
)


#! /usr/bin/env python3
from typing import List, Tuple, Dict
from collections import Counter

# from random import randint
from math import log
from collections import defaultdict
from bisect import bisect_left, bisect_right

"""08/20/2019

Solution1:
I predict, without even writing Solution1, it will time out.
And my prediction is correct. Solution1 is the most naive. Due to a ton of
repetitive computation, it is not surprising that it timed out.

Solution2:
I used segment tree for this solution, with each node being a dict recording
the frequency of each number and a tuple recording the max frequency number and
its corresponding frequency. This segment tree implementation does speed up
the solution, but it still timed out.

Solution3:
I gave up after the unsuccessful attempt with Solution2, even though I did
believe segment tree was a viable solution. After reading the discussion, I
saw that segment tree was indeed one of the standard solution to this problem.
The difference between a successful implementation of segment tree and my
previous segment tree is the merge step both during segment tree initialization
and querying. The key factors are:

1. Only the majority number in a child node has the possibility of becoming
majority in the parent node. So when merging two child nodes, we only need to
examine the majority number in each child. If majority does not exist in a
child node, we don't even have to examine it.

2. Examination can be done in O(log(n)) time. The way I examined majority in
the previous method was via dictionary, and it was O(n) time with probably quite
some overhead with dictionary processes. A very good way of examination is to
use binary search on a list of positions of the target number against a querying
range's start and end. Once proper positions on the list for querying range's
start and end, we can easily read how many of such target number exist within
this range. This takes O(log(n)) time with little overhead.

Once the merge function is optimized via the two factors above, the solution
shall pass OJ. I cannot do it today since I don't have internet at home. I will
run it tomorrow.

Update 08/21/2019
Solution3 clocked in at 1076 ms, 55%

P.S. The random pick method is definitely brilliant. It is similar to the method
in one of the CodeJam problem. Here, since we are looking for the majority
number, it is natural that if such number exists, we shall be able to randomly
pick it out more than 50% of the time. Error happens if none of the number we
pick is the majority while the majority actually exists. The probably of doing
this is less than 1/2 for each pick. Thus, the more picks we do, the less likely
that all of them are non-majority number. The concensus on the discussion was
to pick 20 times, in which the probability all of them are wrong picks is as
small as (1/2)**20, which furthr amounts to 0.01 times of error in 10000 queries.
For each random pick, we do the same binary search method to check whether it
is the real majority or not.
"""

class MajorityChecker1:
    def __init__(self, arr: List[int]):
        self.arr = arr

    def query(self, left: int, right: int, threshold: int) -> int:
        count = Counter(self.arr[left : right + 1])
        for k, v in count.items():
            if v >= threshold:
                return k
        return -1

class MajorityChecker2:
    def __init__(self, arr: List[int]) -> None:
        self.arr = arr
        # https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/
        size = 2 * (2 ** int(log(len(self.arr), 2) + 1)) - 1
        self.seg_tree: List[Tuple[Dict[int, int], Tuple[int, int]]] = [
            (defaultdict(int), (0, 0)) for _ in range(size)
        ]
        self.init_seg_tree(0, 0, len(self.arr) - 1)

    def query(self, left: int, right: int, threshold: int) -> int:
        count_dict, majority_tuple = self.query_seg_tree(
            left, right, 0, len(self.arr) - 1, 0
        )
        return -1 if majority_tuple[1] < threshold else majority_tuple[0]

    def merge(
        self,
        item1: Tuple[Dict[int, int], Tuple[int, int]],
        item2: Tuple[Dict[int, int], Tuple[int, int]],
    ) -> Tuple[Dict[int, int], Tuple[int, int]]:
        res_dict: Dict[int, int] = defaultdict(int)
        res_majority: Tuple[int, int] = item1[1]
        res_dict.update(item1[0])
        for k, v in item2[0].items():
            res_dict[k] += v
            if res_dict[k] > res_majority[1]:
                res_majority = (k, res_dict[k])

        return res_dict, res_majority

    def init_seg_tree(self, root: int, ss: int, se: int) -> None:
        if ss == se:
            self.seg_tree[root] = ({self.arr[ss]: 1}, (self.arr[ss], 1))
        else:
            mid = ss + (se - ss) // 2
            self.init_seg_tree(2 * root + 1, ss, mid)
            self.init_seg_tree(2 * root + 2, mid + 1, se)
            self.seg_tree[root] = self.merge(
                self.seg_tree[2 * root + 1], self.seg_tree[2 * root + 2]
            )

    def query_seg_tree(
        self, qs: int, qe: int, ss: int, se: int, root: int
    ) -> Tuple[Dict[int, int], Tuple[int, int]]:
        if qs == ss and qe == se:
            return self.seg_tree[root]
        mid = ss + (se - ss) // 2
        if qs > mid:
            return self.query_seg_tree(qs, qe, mid + 1, se, root * 2 + 2)
        elif qe <= mid:
            return self.query_seg_tree(qs, qe, ss, mid, root * 2 + 1)
        else:
            return self.merge(
                self.query_seg_tree(qs, mid, ss, mid, root * 2 + 1),
                self.query_seg_tree(mid + 1, qe, mid + 1, se, root * 2 + 2),
            )

class MajorityChecker3:
    def __init__(self, arr: List[int]) -> None:
        self.arr = arr

        # provision record for all positions of each number
        self.pos_dict: Dict[int, List[int]] = defaultdict(list)
        for i, a in enumerate(self.arr):
            self.pos_dict[a].append(i)

        # https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/
        size = 2 * (2 ** int(log(len(self.arr), 2) + 1)) - 1
        # provision segment tree
        self.seg_tree: List[int] = [-1] * size
        self.init_seg_tree(0, 0, len(self.arr) - 1)

    def query(self, left: int, right: int, threshold: int) -> int:
        maj = self.query_seg_tree(left, right, 0, len(self.arr) - 1, 0)
        return maj if self.frequency(maj, left, right) >= threshold else -1

    def merge(self, maj1: int, maj2: int, start: int, end: int) -> int:
        # NOTE: if a child node has no majority, none of its members can be
        # majority in the parent node. When a child has a majority number, it
        # may or may not be the majority in the parent node. Further examination
        # is needed.
        if (
            maj1 != -1
            and self.frequency(maj1, start, end) * 2 > end - start + 1
        ):
            return maj1
        if (
            maj2 != -1
            and self.frequency(maj2, start, end) * 2 > end - start + 1
        ):
            return maj2
        return (
            -1
        )  # when neither child node has majority, parent node has no majority

    def frequency(self, target: int, start: int, end: int) -> int:
        # use binary search to find how many target number resides within the
        # given range [start, end]
        return bisect_right(self.pos_dict[target], end) - bisect_left(
            self.pos_dict[target], start
        )

    def init_seg_tree(self, root: int, ss: int, se: int) -> None:
        if ss == se:
            self.seg_tree[root] = self.arr[ss]
        else:
            mid = ss + (se - ss) // 2
            self.init_seg_tree(2 * root + 1, ss, mid)
            self.init_seg_tree(2 * root + 2, mid + 1, se)
            self.seg_tree[root] = self.merge(
                self.seg_tree[2 * root + 1],
                self.seg_tree[2 * root + 2],
                ss,
                se,
            )

    def query_seg_tree(
        self, qs: int, qe: int, ss: int, se: int, root: int
    ) -> int:
        if qs == ss and qe == se:
            return self.seg_tree[root]
        mid = ss + (se - ss) // 2
        if qs > mid:
            return self.query_seg_tree(qs, qe, mid + 1, se, root * 2 + 2)
        elif qe <= mid:
            return self.query_seg_tree(qs, qe, ss, mid, root * 2 + 1)
        else:
            return self.merge(
                self.query_seg_tree(qs, mid, ss, mid, root * 2 + 1),
                self.query_seg_tree(mid + 1, qe, mid + 1, se, root * 2 + 2),
                qs,
                qe,
            )

test_case_first: List[int] = [2, 2, 1, 2, 1, 2, 2, 1, 1, 2]
test_case: List[List[int]] = [
    [2, 5, 4],
    [0, 5, 6],
    [0, 1, 2],
    [2, 3, 2],
    [6, 6, 1],
    [0, 3, 3],
    [4, 9, 6],
    [4, 8, 4],
    [5, 9, 5],
    [0, 1, 2],
]
mc = MajorityChecker1(test_case_first)
for t in test_case:
    print(mc.query(t[0], t[1], t[2]))


from setuptools import setup, find_packages, Extension
from glob import glob
from Cython.Build import cythonize
import platform
import os
import versioneer

include_dirs = ['ffld2', 'ffld2/lib']
library_dirs = []
extra_compile_args = []
extra_link_args = []
libraries = []

sources = (['cyffld2/ffld2/HOGPyramid.cpp',
            'cyffld2/ffld2/JPEGImage.cpp',
            'cyffld2/ffld2/LBFGS.cpp',
            'cyffld2/ffld2/Model.cpp',
            'cyffld2/ffld2/Object.cpp',
            'cyffld2/ffld2/Patchwork.cpp',
            'cyffld2/ffld2/Rectangle.cpp',
            'cyffld2/ffld2/Scene.cpp',
            'cyffld2/ffld2/Mixture.cpp',
            'cyffld2/ffld2/lib/ffld2.cpp',
            'cyffld2/_ffld2.pyx'])

_platform = platform.platform().lower()
if 'linux' in _platform:
    extra_compile_args += ['-fopenmp']
    extra_link_args += ['-fopenmp']

    libraries += ['xml2', 'fftw3f', 'jpeg']
elif 'darwin' in _platform:
    libraries += ['xml2', 'fftw3f', 'jpeg']
elif 'windows' in _platform:
    extra_compile_args += ['/openmp']
    extra_link_args += ['/openmp']

    if os.environ.get('CONDA_BUILD', None):
        # There is a bug in visual studio 2008 whereby you can't pass non-aligned
        # values, therefore, we have to turn off alignment enforcement
        # for eigen on Win32. See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=83
        # more more information.
        if int(os.environ.get('ARCH', 32)) == 32:  # Default to 32 for safety
            extra_compile_args += ['/DEIGEN_DONT_ALIGN_STATICALLY=1']

        extra_compile_args += ['/D_USE_MATH_DEFINES=1' , '/EHsc']

        libxml_dir = os.path.join(os.environ['LIBRARY_INC'], 'libxml2')
        include_dirs += [os.environ['LIBRARY_INC'], libxml_dir]

        library_dirs.append(os.environ['LIBRARY_LIB'])
        # This looks a bit strange but it is to match the library names
        # that I have created in other recipes.
        libraries += ['libxml2', 'libfftw3f-3', 'jpeg']

extensions = [Extension('cyffld2._ffld2', sources,
                        include_dirs=include_dirs,
                        library_dirs=library_dirs,
                        extra_compile_args=extra_compile_args,
                        extra_link_args=extra_link_args,
                        libraries=libraries,
                        language='c++')]

setup(name='cyffld2',
      version=versioneer.get_version(),
      cmdclass=versioneer.get_cmdclass(),
      description='A Cython wrapper around the FFLD2 face detection library.',
      author='Patrick Snape',
      author_email='p.snape@imperial.ac.uk',
      url='https://github.com/menpo/cyffld2',
      ext_modules=cythonize(extensions, quiet=True),
      package_data={'cyffld2': [
          'ffld2/models/headhunter_dpm_baseline.txt',
          'ffld2/*.h',
          'ffld2/lib/*.h',
          'ffld2/*.cpp',
          'ffld2/lib/*.cpp',
          '_ffld2.pyx',
          '_ffld2.pxd'
      ]},
      packages=find_packages()
)


import matplotlib.pyplot as plt
import numpy as np

# 100 samples from normal distribution with 0 mean and 1 variance

samples = np.random.normal(0, 1, 100)

# Visualize data with a histogram

plt.hist(samples, bins=50)
plt.show()

# Sort them to increasing order

sorted_samples = np.sort(samples)

# Draw a line plot for x=i:th sample and y is i/100

y = np.arange(0,1,0.01)

plt.plot(sorted_samples, y)
plt.show()


import datetime
from random import choice

class MonteCarlo(object):
    def __init__(self, board, **kwargs):
        # Takes an instance of a Board and, optionally, some keyword arguments.
        # Initialises the list of game states, and the statistics tables.
        self.board = board
        self.states = []
        seconds = kwargs.get('time', 30)
        self.calculation_time = datetime.timedelta(seconds=seconds)
        self.max_moves = kwargs.get('max_moves', 100)
        self.wins = {}
        self.plys = {}

    def update(self, state):
        # Takes a game state, and appends it to the history.
        self.states.append(state)

    def get_play(self):
        # Causes the AI to calculate the best move from the current game state
        # and return it.
        begin = datetime.datetime.utcnow()
        while datetime.datetime.utcnow() - begin < self.calculation_time:
            self.run_simulation()

    def run_simulation(self):
        # Plays out a 'random' game from the current position, then updates the
        # statistics tables with the result.
        visited_states = set()
        states_copy = self.states[:]
        state = states_copy[-1]
        player = self.board.current_player(state)

        expand = True
        for __ in range(self.max_moves):
            legal = self.board.legal_plays(states_copy)

            play = choice(legal)
            state = self.board.next_state(state, play)
            states_copy.append(state)

            # `player` here refers to the player who moved into that state.
            if expand and (player, state) not in self.plays:
                expand = False
                self.plays[(player, state)] = 0
                self.wins[(player, state)] = 0

            player = self.board.current_player(state)
            winner = self.board.winner(states_copy)
            if winner:
                break

            for player, state in visited_states:
                if (player, state) not in self.plays:
                    continue
                self.plays[(player, state)] += 1
                if player == winner:
                    self.wins[(player, state)] += 1