from discord.ext import commands
from discord import app_commands
import discord

from typing import TypedDict

import aiohttp

from os import getenv

def make_embed(message: str):
    return discord.Embed(
        title="Llama",
        description=message
    )

async def talk(promps: str) -> str:
    promps += " assistant: "
    async with aiohttp.ClientSession() as session:
        async with session.post(
            "https://llama-api.tuna2134.jp/", json={"promps": promps}) as res:
            return (await res.json())["content"]

class MessageType(TypedDict):
    role: str
    content: str

def make_promps(messages: list[MessageType]) -> str:
    return " ".join(f"{msg['role']}: {msg['content']}" for msg in messages)

class LlamaView(discord.ui.View):
    def __init__(self, messages: list[MessageType], author_id):
        super().__init__()
        self.messages = messages
        self.author_id = author_id

    @discord.ui.button(label="返信")
    async def reply(self, interaction: discord.Interaction, button: discord.ui.Button) -> None:
        if interaction.user.id != self.author_id:
            return await interaction.response.send_message("うーん、君私の主人じゃないでしょ！")
        if len(self.messages) > 5:
            return await interaction.response.send_message("すいません、制限がかかっているためお答えすることができません")
        await interaction.response.send_modal(LlamaModal(self.messages))

class LlamaModal(discord.ui.Modal, title="メッセージの内容"):
    content = discord.ui.TextInput(
        label="コンテンツ",
        placeholder='llamaに聞きたいことをここに書いてください。'
    )
    def __init__(self, messages: list[MessageType]):
        super().__init__()
        self.messages = messages

    async def on_submit(self, interaction: discord.Interaction):
        await interaction.response.defer()
        self.messages.append({
            "role": "user",
            "content": self.content.value
        })
        message = await talk(make_promps(self.messages))
        self.messages.append({
            "role": "assistant",
            "content": message
        })
        await interaction.followup.send(
            embed=make_embed(message),
            view=ChatgptView(self.messages)
        )

class Llama(commands.Cog):
    def __init__(self, bot: commands.Bot):
        self.bot = bot

    @app_commands.command(description="chatgptと話します")
    @app_commands.describe(content="メッセージ内容")
    async def llama(self, interaction: discord.Interaction, content: str) -> None:
        await interaction.response.defer()
        messages = [
            {
                "role": "user",
                "content": content
            }
        ]
        message = await talk(make_promps(messages))
        messages.append({
            "role": "assistant",
            "content": message
        })
        await interaction.followup.send(
            embed=make_embed(message),
            view=LlamaView(messages, interaction.user.id)
        )

async def setup(bot: commands.Bot) -> None:
    await bot.add_cog(Llama(bot))


'''
原文url
http://mp.weixin.qq.com/s?__biz=MzA4MjEyNTA5Mw==&mid=2652565477&idx=1&sn=c61a8957fd08ad5a1e043c2bfdc45c5d&chksm=8464c7afb3134eb95d9de6bdb8aeaa20d17fe10bb10f70b27df8e229758f74a4d07165b54e45&mpshare=1&scene=23&srcid=0702A5ZduuSEm74R6gSRSu2Y#rd
原文是python2的，我这边python3，代码稍有改动
'''

'''现在，很多人想开发高效的算法以及参加机器学习的竞赛。所以他们过来问我：”该如何开始？”。一段时间以前，我在一个俄罗斯联邦政府的下属机构中领导了媒体和社交网络大数据分析工具的开发。我仍然有一些我团队使用过的文档，我乐意与你们分享。前提是读者已经有很好的数学和机器学习方面的知识（我的团队主要由MIPT（莫斯科物理与技术大学）和数据分析学院的毕业生构成）。

这篇文章是对数据科学的简介，这门学科最近太火了。机器学习的竞赛也越来越多（如，Kaggle, TudedIT），而且他们的资金通常很可观。

R和Python是提供给数据科学家的最常用的两种工具。每一个工具都有其优缺点，但Python最近在各个方面都有所胜出（仅为鄙人愚见，虽然我两者都用）。这一切的发生是因为Scikit-Learn库的腾空出世，它包含有完善的文档和丰富的机器学习算法。

请注意，我们将主要在这篇文章中探讨机器学习算法。通常用Pandas包去进行主数据分析会比较好，而且这很容易你自己完成。所以，让我们集中精力在实现上。为了确定性，我们假设有一个特征-对象矩阵作为输入，被存在一个*.csv文件中。

数据加载

首先，数据要被加载到内存中，才能对其操作。Scikit-Learn库在它的实现用使用了NumPy数组，所以我们将用NumPy来加载*.csv文件。让我们从UCI Machine Learning Repository下载其中一个数据集。
'''
import numpy as np
from urllib import request
from sklearn import preprocessing
from sklearn import metrics
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression, Ridge
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from scipy.stats import uniform as sp_rand
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
def printbr(n):
    print('{}---------------------------------------------------------------------------------------'.format(n))
# url with dataset
url = "http://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
# download the file
raw_data = request.urlopen(url)
# load the CSV file as a numpy matrix
dataset = np.loadtxt(raw_data, delimiter=",")
# separate the data from the target attributes
X = dataset[:,0:7]
y = dataset[:,8]

'''数据标准化

我们都知道大多数的梯度方法（几乎所有的机器学习算法都基于此）对于数据的缩放很敏感。因此，在运行算法之前，我们应该进行标准化，或所谓的规格化。标准化包括替换所有特征的名义值，让它们每一个的值在0和1之间。而对于规格化，它包括数据的预处理，使得每个特征的值有0和1的离差。Scikit-Learn库已经为其提供了相应的函数。
'''

# normalize the data attributes
normalized_X = preprocessing.normalize(X)
# standardize the data attributes
standardized_X = preprocessing.scale(X)

'''特征的选取

毫无疑问，解决一个问题最重要的是是恰当选取特征、甚至创造特征的能力。这叫做特征选取和特征工程。虽然特征工程是一个相当有创造性的过程，有时候更多的是靠直觉和专业的知识，但对于特征的选取，已经有很多的算法可供直接使用。如树算法就可以计算特征的信息量。
'''
printbr(0)
model = ExtraTreesClassifier()
model.fit(X, y)
# display the relative importance of each attribute
print(model.feature_importances_)

#其他所有的方法都是基于对特征子集的高效搜索，从而找到最好的子集，意味着演化了的模型在这个子集上有最好的质量。递归特征消除算法（RFE）是这些搜索算法的其中之一，Scikit-Learn库同样也有提供。

model = LogisticRegression()
# create the RFE model and select 3 attributes
rfe = RFE(model, 3)
rfe = rfe.fit(X, y)
# summarize the selection of the attributes
print(rfe.support_)
print(rfe.ranking_)

'''
算法的开发

正像我说的，Scikit-Learn库已经实现了所有基本机器学习的算法。让我来瞧一瞧它们中的一些。

逻辑回归

大多数情况下被用来解决分类问题（二元分类），但多类的分类（所谓的一对多方法）也适用。这个算法的优点是对于每一个输出的对象都有一个对应类别的概率。
'''
printbr(1)
model = LogisticRegression()
model.fit(X, y)
print(model)
# make predictions
expected = y
predicted = model.predict(X)
# summarize the fit of the model
print(expected.shape, predicted.shape)
print(metrics.classification_report(expected, predicted))
print(metrics.confusion_matrix(expected, predicted))

printbr(2)
'''
朴素贝叶斯

它也是最有名的机器学习的算法之一，它的主要任务是恢复训练样本的数据分布密度。这个方法通常在多类的分类问题上表现的很好。
'''

model = GaussianNB()
model.fit(X, y)
print(model)
# make predictions
expected = y
predicted = model.predict(X)
# summarize the fit of the model
print(metrics.classification_report(expected, predicted))
print(metrics.confusion_matrix(expected, predicted))

printbr(3)
'''
k-最近邻

kNN（k-最近邻）方法通常用于一个更复杂分类算法的一部分。例如，我们可以用它的估计值做为一个对象的特征。有时候，一个简单的kNN算法在良好选择的特征上会有很出色的表现。当参数（主要是metrics）被设置得当，这个算法在回归问题中通常表现出最好的质量。
'''

# fit a k-nearest neighbor model to the data
model = KNeighborsClassifier()
model.fit(X, y)
print(model)
# make predictions
expected = y
predicted = model.predict(X)
# summarize the fit of the model
print(metrics.classification_report(expected, predicted))
print(metrics.confusion_matrix(expected, predicted))
#print(expected.ndim, expected.shape)
printbr(4)
'''
决策树

分类和回归树（CART）经常被用于这么一类问题，在这类问题中对象有可分类的特征且被用于回归和分类问题。决策树很适用于多类分类。
'''

# fit a CART model to the data
model = DecisionTreeClassifier()
model.fit(X, y)
print(model)
# make predictions
expected = y
predicted = model.predict(X)
# summarize the fit of the model
print(metrics.classification_report(expected, predicted))
print(metrics.confusion_matrix(expected, predicted))
printbr(5)
'''
支持向量机

SVM（支持向量机）是最流行的机器学习算法之一，它主要用于分类问题。同样也用于逻辑回归，SVM在一对多方法的帮助下可以实现多类分类。
'''

# fit a SVM model to the data
model = SVC()
model.fit(X, y)
print(model)
# make predictions
expected = y
predicted = model.predict(X)
# summarize the fit of the model
print(metrics.classification_report(expected, predicted))
print(metrics.confusion_matrix(expected, predicted))

'''
除了分类和回归问题，Scikit-Learn还有海量的更复杂的算法，包括了聚类， 以及建立混合算法的实现技术，如Bagging和Boosting。

如何优化算法的参数

在编写高效的算法的过程中最难的步骤之一就是正确参数的选择。一般来说如果有经验的话会容易些，但无论如何，我们都得寻找。幸运的是Scikit-Learn提供了很多函数来帮助解决这个问题。

作为一个例子，我们来看一下规则化参数的选择，在其中不少数值被相继搜索了：
'''
printbr(6)
# prepare a range of alpha values to test
alphas = np.array([1,0.1,0.01,0.001,0.0001,0])
# create and fit a ridge regression model, testing each alpha
model = Ridge()
grid = GridSearchCV(estimator=model, param_grid=dict(alpha=alphas))
grid.fit(X, y)
print(grid)
# summarize the results of the grid search
print(grid.best_score_)
print(grid.best_estimator_.alpha)

#有时候随机地从既定的范围内选取一个参数更为高效，估计在这个参数下算法的质量，然后选出最好的。

printbr(7)
# prepare a uniform distribution to sample for the alpha parameter
param_grid = {'alpha': sp_rand()}
# create and fit a ridge regression model, testing random alpha values
model = Ridge()
rsearch = RandomizedSearchCV(estimator=model, param_distributions=param_grid, n_iter=100)
rsearch.fit(X, y)
print(rsearch)
# summarize the results of the random parameter search
print(rsearch.best_score_)
print(rsearch.best_estimator_.alpha)

#至此我们已经看了整个使用Scikit-Learn库的过程，除了将结果再输出到一个文件中。这个就作为你的一个练习吧，和R相比Python的一大优点就是它有很棒的文档说明。

#在下一篇文章中，我们将深入探讨其他问题。我们尤其是要触及一个很重要的东西——特征的建造。我真心地希望这份材料可以帮助新手数据科学家尽快开始解决实践中的机器学习问题。最后，我祝愿那些刚刚开始参加机器学习竞赛的朋友拥有耐心以及马到成功！


from django.urls import path

from .views import about_us, about_developers

app_name = 'about'

urlpatterns = [
    path('us/', about_us, name='about_us'),
    path('developers/', about_developers, name='about_developers'),

]


# 爬取中国天气网最高气温的前10个城市

import requests

from bs4 import BeautifulSoup
from pyecharts import Bar

ALL_DATA = []  # 存放全国城市最高气温

# 解析页面信息
def parse_page(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 '
                      '(KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36'
    }
    # 请求网页数据
    response = requests.get(url, headers=headers)
    html = response.content.decode('utf-8', 'ignore')

    # 解析网页数据
    soup = BeautifulSoup(html, 'html5lib')
    conMidtab = soup.find('div', class_='conMidtab')  # 华北地区所有的城市
    tables = conMidtab.find_all('table')  # 每一个城市
    for table in tables:
        trs = table.find_all('tr')[2:]  # 每一个地区
        for index,tr in enumerate(trs):
            tds = tr.find_all('td')
            city_td = tds[0]  # 城市td标签
            if index == 0:  # 省份的td标签放在了第一个城市的td标签的元素0上
                city_td = tds[1]
            city = list(city_td.stripped_strings)[0]  # 城市名
            temp_td = tds[-5]  # 温度td标签
            max_temp = list(temp_td.stripped_strings)[0]  # 最高温度

            ALL_DATA.append({'city': city, 'max_temp': int(max_temp)})  # 存储下来
            # print({'city': city, 'max_temp': max_temp})

def main():
    urls = [
        'http://www.weather.com.cn/textFC/hb.shtml',
        'http://www.weather.com.cn/textFC/db.shtml',
        'http://www.weather.com.cn/textFC/hd.shtml',
        'http://www.weather.com.cn/textFC/hz.shtml',
        'http://www.weather.com.cn/textFC/hn.shtml',
        'http://www.weather.com.cn/textFC/xb.shtml',
        'http://www.weather.com.cn/textFC/xn.shtml',
        'http://www.weather.com.cn/textFC/gat.shtml'
    ]  # 全国的url
    for url in urls:
        parse_page(url)

    # 分析数据,根据最高气温排序
    ALL_DATA.sort(key=lambda data: data['max_temp'], reverse=True)
    data = ALL_DATA[0:10]  # 取气温最高的前10个

    cities = list(map(lambda x: x['city'], data))  # 城市名
    temps = list(map(lambda x: x['max_temp'], data))  # 温度

    # 数据可视化,pyecharts库
    chart = Bar('中国天气最高气温排行榜')  # Bar柱状图
    chart.add('', cities, temps)  # '': 名字，citite：x轴， temps：y轴
    chart.render('temperature.html')

if __name__ == '__main__':
    main()


# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from taskgraph.task import Task
from taskgraph.util.schema import Schema
from voluptuous import Required

from gecko_taskgraph.util.copy_task import copy_task

from ..util.attributes import sorted_unique_list

schema = Schema(
    {
        Required("primary-dependency", "primary dependency task"): Task,
        Required(
            "dependent-tasks",
            "dictionary of dependent tasks, keyed by kind",
        ): {str: Task},
    }
)

# Define a collection of group_by functions
GROUP_BY_MAP = {}

def group_by(name):
    def wrapper(func):
        GROUP_BY_MAP[name] = func
        return func

    return wrapper

def loader(kind, path, config, params, loaded_tasks):
    """
    Load tasks based on the jobs dependant kinds, designed for use as
    multiple-dependent needs.

    Required ``group-by-fn`` is used to define how we coalesce the
    multiple deps together to pass to transforms, e.g. all kinds specified get
    collapsed by platform with `platform`

    Optional ``primary-dependency`` (ordered list or string) is used to determine
    which upstream kind to inherit attrs from. See ``get_primary_dep``.

    The `only-for-build-platforms` kind configuration, if specified, will limit
    the build platforms for which a job will be created. Alternatively there is
    'not-for-build-platforms' kind configuration which will be consulted only after
    'only-for-build-platforms' is checked (if present), and omit any jobs where the
    build platform matches.

    Optional ``job-template`` kind configuration value, if specified, will be used to
    pass configuration down to the specified transforms used.
    """
    job_template = config.get("job-template")

    for dep_tasks in group_tasks(config, loaded_tasks):
        job = {"dependent-tasks": dep_tasks}
        job["primary-dependency"] = get_primary_dep(config, dep_tasks)
        if job_template:
            job.update(copy_task(job_template))
        # copy shipping_product from upstream
        product = job["primary-dependency"].attributes.get(
            "shipping_product", job["primary-dependency"].task.get("shipping-product")
        )
        if product:
            job.setdefault("shipping-product", product)
        job.setdefault("attributes", {})["required_signoffs"] = sorted_unique_list(
            *(
                task.attributes.get("required_signoffs", [])
                for task in dep_tasks.values()
            )
        )

        yield job

def skip_only_or_not(config, task):
    """Return True if we should skip this task based on `only_` or `not_` config."""
    only_platforms = config.get("only-for-build-platforms")
    not_platforms = config.get("not-for-build-platforms")
    only_attributes = config.get("only-for-attributes")
    not_attributes = config.get("not-for-attributes")
    task_attrs = task.attributes
    if only_platforms or not_platforms:
        platform = task_attrs.get("build_platform")
        build_type = task_attrs.get("build_type")
        if not platform or not build_type:
            return True
        combined_platform = f"{platform}/{build_type}"
        if only_platforms and combined_platform not in only_platforms:
            return True
        if not_platforms and combined_platform in not_platforms:
            return True
    if only_attributes:
        if not set(only_attributes) & set(task_attrs):
            # make sure any attribute exists
            return True
    if not_attributes:
        if set(not_attributes) & set(task_attrs):
            return True
    return False

def group_tasks(config, tasks):
    group_by_fn = GROUP_BY_MAP[config["group-by"]]

    groups = group_by_fn(config, tasks)

    for combinations in groups.values():
        kinds = [f.kind for f in combinations]
        assert_unique_members(
            kinds,
            error_msg=("Multi_dep.py should have filtered down to one task per kind"),
        )
        dependencies = {t.kind: copy_task(t) for t in combinations}
        yield dependencies

@group_by("platform")
def platform_grouping(config, tasks):
    groups = {}
    for task in tasks:
        if task.kind not in config.get("kind-dependencies", []):
            continue
        if skip_only_or_not(config, task):
            continue
        platform = task.attributes.get("build_platform")
        build_type = task.attributes.get("build_type")
        product = task.attributes.get(
            "shipping_product", task.task.get("shipping-product")
        )

        groups.setdefault((platform, build_type, product), []).append(task)
    return groups

@group_by("single-locale")
def single_locale_grouping(config, tasks):
    """Split by a single locale (but also by platform, build-type, product)

    The locale can be `None` (en-US build/signing/repackage), a single locale,
    or multiple locales per task, e.g. for l10n chunking. In the case of a task
    with, say, five locales, the task will show up in all five locale groupings.

    This grouping is written for non-partner-repack beetmover, but might also
    be useful elsewhere.

    """
    groups = {}

    for task in tasks:
        if task.kind not in config.get("kind-dependencies", []):
            continue
        if skip_only_or_not(config, task):
            continue
        platform = task.attributes.get("build_platform")
        build_type = task.attributes.get("build_type")
        product = task.attributes.get(
            "shipping_product", task.task.get("shipping-product")
        )
        task_locale = task.attributes.get("locale")
        chunk_locales = task.attributes.get("chunk_locales")
        locales = chunk_locales or [task_locale]

        for locale in locales:
            locale_key = (platform, build_type, product, locale)
            groups.setdefault(locale_key, [])
            if task not in groups[locale_key]:
                groups[locale_key].append(task)

    return groups

@group_by("chunk-locales")
def chunk_locale_grouping(config, tasks):
    """Split by a chunk_locale (but also by platform, build-type, product)

    This grouping is written for mac signing with notarization, but might also
    be useful elsewhere.

    """
    groups = {}

    for task in tasks:
        if task.kind not in config.get("kind-dependencies", []):
            continue
        if skip_only_or_not(config, task):
            continue
        platform = task.attributes.get("build_platform")
        build_type = task.attributes.get("build_type")
        product = task.attributes.get(
            "shipping_product", task.task.get("shipping-product")
        )
        chunk_locales = tuple(sorted(task.attributes.get("chunk_locales", [])))

        chunk_locale_key = (platform, build_type, product, chunk_locales)
        groups.setdefault(chunk_locale_key, [])
        if task not in groups[chunk_locale_key]:
            groups[chunk_locale_key].append(task)

    return groups

@group_by("partner-repack-ids")
def partner_repack_ids_grouping(config, tasks):
    """Split by partner_repack_ids (but also by platform, build-type, product)

    This grouping is written for release-{eme-free,partner}-repack-signing.

    """
    groups = {}

    for task in tasks:
        if task.kind not in config.get("kind-dependencies", []):
            continue
        if skip_only_or_not(config, task):
            continue
        platform = task.attributes.get("build_platform")
        build_type = task.attributes.get("build_type")
        product = task.attributes.get(
            "shipping_product", task.task.get("shipping-product")
        )
        partner_repack_ids = tuple(
            sorted(task.task.get("extra", {}).get("repack_ids", []))
        )

        partner_repack_ids_key = (platform, build_type, product, partner_repack_ids)
        groups.setdefault(partner_repack_ids_key, [])
        if task not in groups[partner_repack_ids_key]:
            groups[partner_repack_ids_key].append(task)

    return groups

def assert_unique_members(kinds, error_msg=None):
    if len(kinds) != len(set(kinds)):
        raise Exception(error_msg)

def get_primary_dep(config, dep_tasks):
    """Find the dependent task to inherit attributes from.

    If ``primary-dependency`` is defined in ``kind.yml`` and is a string,
    then find the first dep with that task kind and return it. If it is
    defined and is a list, the first kind in that list with a matching dep
    is the primary dependency. If it's undefined, return the first dep.

    """
    primary_dependencies = config.get("primary-dependency")
    if isinstance(primary_dependencies, str):
        primary_dependencies = [primary_dependencies]
    if not primary_dependencies:
        assert len(dep_tasks) == 1, "Must define a primary-dependency!"
        return list(dep_tasks.values())[0]
    primary_dep = None
    for primary_kind in primary_dependencies:
        for dep_kind in dep_tasks:
            if dep_kind == primary_kind:
                assert (
                    primary_dep is None
                ), "Too many primary dependent tasks in dep_tasks: {}!".format(
                    [t.label for t in dep_tasks]
                )
                primary_dep = dep_tasks[dep_kind]
    if primary_dep is None:
        raise Exception(
            "Can't find dependency of {}: {}".format(
                config["primary-dependency"], config
            )
        )
    return primary_dep


import argparse
import copy
import json
import shutil
import sys
import zipfile
from datetime import datetime
import os
from functools import partial
from time import perf_counter

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import pandas as pd

import warnings
warnings.simplefilter(action='ignore', category=pd.errors.PerformanceWarning)

import numpy as np
import itertools
from collections import defaultdict
import networkx as nx
from networkx.utils import UnionFind

from relic.distance.nppo import join_detector, groupby_detector, pivot_detector
from relic.distance.ppo import compute_all_ppo_labels, compute_baseline, compute_baseline_labels
from relic.distance.tiebreakers import tiebreak_hash_edge, tiebreak_from_computed_scores, tiebreak_hash_edge_join, \
    tiebreak_join_from_inferred_graph, tiebreak_join_computed_scores, tiebreak_join_src_containment, \
    tiebreak_groupby_replay, tiebreak_hash_edge_join_pqe, tiebreak_hash_edge_pqe
from relic.graphs.clustering import exact_schema_cluster, reverse_schema_dict, write_clusters_to_file
from relic.utils.pqedge import PQEdges, get_intra_cluster_edges_only
from relic.utils.serialize import build_df_dict_dir, write_graph, get_job_status_phases, update_phase, str2bool, \
    load_distances_from_raw_files, load_distances_from_pandas_file, update_timing_df, store_distances_to_file, \
    store_all_distances
from relic.algorithm import compute_tuplewise_similarity
from relic.approx.sampling import generate_sample_index, build_sample_df_dict_dir

from relic.utils.matching import perturb_schema_dataset

import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)s %(levelname)s:%(message)s')
logger = logging.getLogger(__name__)

class RelicAlgorithm:

    def __init__(self, input_dir, output_dir, name='wf_', g_truth_file=None, max_edges=None,
                 sample_frac=1.0, sample_index_flag=False, match_schema=False,
                 alpha=0.0, beta=0.0, gamma=0.0, lsh_graph_file=None,
                 **kwargs):
        logger.info('Starting instance of RelicAlgorithm on %s', name)

        # Directory Setup
        self.nb_name = name
        self.artifact_dir = input_dir
        self.inferred_dir = output_dir
        os.makedirs(self.inferred_dir, exist_ok=True)

        # Load the dataset
        # Load/read on demand infrastructure
        # self.dataset = ArtifactDict(self.artifact_dir)
        logger.info(f'Loading Artifacts from {self.artifact_dir}')
        if sample_frac < 1.0:
            sample_index = None
            if sample_index_flag:
                sample_index = generate_sample_index(self.artifact_dir, self.inferred_dir, frac=sample_frac)
            self.dataset = build_sample_df_dict_dir(self.artifact_dir, frac=sample_frac, sample_index=sample_index)
        else:
            self.dataset = build_df_dict_dir(self.artifact_dir)
        logger.info('Loading Complete')

        # Load the Ground Truth
        # Optional GT annotation or remove entirely
        if g_truth_file:
            if g_truth_file.endswith('.txt'):
                self.g_truth = nx.read_edgelist(g_truth_file)
            if g_truth_file.endswith('.pkl'):
                self.g_truth = nx.read_gpickle(g_truth_file)

        self.match_schema = match_schema

        if alpha > 0.0:
            self.dataset, self.rename_map= perturb_schema_dataset(self.dataset, self.g_truth, alpha=alpha, beta=beta, gamma=gamma)
            self.match_schema = match_schema

        # Create the initial graph
        self.g_inferred = nx.Graph()
        self.create_initial_graph()

        # Create initial components list and clustering
        self.components = UnionFind()
        self.num_components = 0
        self.initial_cluster = {}
        self.cluster_lookup = {}

        # Create the pairwise weights_dict to store multiple weights
        # Priority queue or self-sorting datastructure in association with unionfind
        self.pairwise_weights = defaultdict(PQEdges)
        self.initialize_components()

        # Current Edge being added
        self.edge_no = 0

        # Tie Breaker Info
        self.tied_edges = {}
        self.two_tie_edges = {}

        # Serialization Info
        self.serialize = True
        self.score_records = dict()

        self.lsh_edges = None
        if lsh_graph_file:
            self.lsh_edges = self.load_lsh_edge_pairs(lsh_graph_file)
            self.lsh_triples = self.load_lsh_edge_triples(lsh_graph_file)

        # No. Max edges if present:
        if max_edges:
            self.max_n_edges = max_edges
        else:
            self.max_n_edges = len(self.dataset)

    def load_artifacts(self):
        pass

    def create_initial_graph(self):
        logger.debug('Creating the initial graph of artifact nodes')
        self.g_inferred = nx.Graph()
        for artifact in self.dataset.keys():
            if artifact not in [n for n in self.g_inferred.nodes()]:
                logger.debug('Adding artifact to graph %s', str(artifact))
                self.g_inferred.add_node(artifact)

        return self.g_inferred

    def load_lsh_edge_pairs(self, lsh_graph_file):
        logger.debug('Loading LSH Graph')
        lsh_graph = nx.read_gpickle(lsh_graph_file)
        lsh_graph.remove_edges_from(list(nx.selfloop_edges(lsh_graph)))

        return list(lsh_graph.edges())

    def load_lsh_edge_triples(self, lsh_graph_file):
        logger.debug('Loading LSH Graph for Triples')
        lsh_graph = nx.read_gpickle(lsh_graph_file)
        lsh_graph.remove_edges_from(list(nx.selfloop_edges(lsh_graph)))
        triples = set()

        for node in lsh_graph.nodes():
            node_neighbors = lsh_graph.neighbors(node)
            for n_combo in itertools.combinations(node_neighbors, 2):
                triples.add(frozenset((node, n_combo[0], n_combo[1])))

        return list(triples)

    def set_initial_clusters(self, cluster_type='exact_schema'):
        # Initial Clusters set to individual artifacts:
        if cluster_type == 'exact_schema':
            self.initial_cluster = exact_schema_cluster(self.dataset)
        self.cluster_lookup = reverse_schema_dict(self.initial_cluster)

        return self.initial_cluster

    def initialize_components(self):
        # Initializes the current list of graph components:
        logger.debug('Updating Graph Components')
        components = [n for c in nx.connected_components(self.g_inferred) for n in c]
        self.components = UnionFind(elements=components)
        self.num_components = len(components)
        return self.components

    def add_edge_and_merge_components(self, edge, data):
        logger.debug(f'About to add and merge edge {edge}')

        if type(edge[0]) == tuple:  # two sources, like join
            for e in edge[0]:
                self.g_inferred.add_edge(e, edge[1], **data)
                self.components.union(e, edge[1])
        else:
            self.g_inferred.add_edge(edge[0], edge[1], **data)
            self.components.union(edge[0], edge[1])

        logger.debug([x for x in self.components.to_sets()])
        self.edge_no += 1
        self.num_components = len([x for x in self.components])

    def compute_edges_of_type(self, edge_type='all', similarity_function=compute_all_ppo_labels,
                              n_pairs=2, pairs=None):
        if self.lsh_edges:
            if n_pairs == 2:
                pairs = self.lsh_edges
            elif n_pairs == 3:
                pairs = self.lsh_triples

        edge_scores = compute_tuplewise_similarity(self.dataset, similarity_metric=similarity_function,
                                                   label=edge_type, n_pairs=n_pairs, match_schema=self.match_schema,
                                                   pairs=pairs)
        self.pairwise_weights.update(edge_scores)
        if self.serialize == True:
            for edge_type, score_dict in edge_scores.items():
                self.score_records[edge_type] = copy.deepcopy(score_dict)

    def add_edges_of_type(self, edge_type='jaccard', intra_cluster=False, tiebreak_function=None,
                          final_function=tiebreak_hash_edge,
                          sim_threshold=0.1, max_step=False, tiebreak_pqe=None, tiebreak_kwargs=None):

        if len(self.g_inferred.edges) >= self.max_n_edges:
            logger.warning(f"Reached maximum edges, unable to add {edge_type} to graph")
            return

        # Compute all pairwise edges first
        if edge_type not in self.pairwise_weights:
            raise KeyError('Edge type not computed in pairwise_weight dict')

        if intra_cluster:
            weights_pq = get_intra_cluster_edges_only(self.pairwise_weights[edge_type], self.cluster_lookup)
            logger.debug('Intra Cluster PQEdges')
            logger.debug(self.pairwise_weights[edge_type])
            logger.debug(weights_pq)
        else:
            weights_pq = self.pairwise_weights[edge_type]

        steps = 0
        stop = False
        if not max_step:
            max_step = len(self.dataset)

        while self.num_components > 1 and steps < max_step and not stop:
            # First check if we have already reached max edges in graph:
            if len(self.g_inferred.edges) >= self.max_n_edges:
                logger.warning(f"Reached maximum edges, stopping add_edge_routing")
                stop = True
                break
            #logger.debug(f'PQ Status: {weights_pq}')
            #logger.debug(f'UnionFind Status: {[x for x in self.components.to_sets()]}')
            max_edges = weights_pq.pop_unionfind_max(self.components)
            #logger.debug(f'MaxEdges Found:  {max_edges} edge(s)...')

            add_remaining_tie_break_edges = False

            if not max_edges:
                logger.debug('No compatible edges left in PQ/UnionFind')
                stop = True
                break
            elif max_edges[0][1] < sim_threshold:
                logger.debug(f'{max_edges} edge(s) below threshold {sim_threshold}, stopping')
                stop = True
                break
            elif len(max_edges) > 1:
                logger.info(f"Tiebreaking {len(max_edges)} edges...")
                weight = max_edges[0][1]
                if tiebreak_function:
                    tiebreak_pqe = tiebreak_function(max_edges, pqe=tiebreak_pqe, **tiebreak_kwargs)
                    tie_break_edges = tiebreak_pqe.pop_max()
                else:
                    tie_break_edges = max_edges
                if len(tie_break_edges) > 1:
                    final_pqe = PQEdges()
                    logger.info(f"Applying final tiebreaker for  {len(tie_break_edges)} edges...")
                    final_pqe = final_function(tie_break_edges, pqe=final_pqe)
                    final_edges = final_pqe.pop_max()
                    edge = final_edges[0][0]
                    add_remaining_tie_break_edges = True

                else:
                    edge = tie_break_edges[0]

            else:
                edge = max_edges[0]
                weight = edge[1]

            logger.info(f"Adding edge #{self.edge_no}: {edge[0]}, type {edge_type}, weight: {weight}")
            if tiebreak_kwargs and 'pqe' in tiebreak_kwargs.keys():
                logger.debug(f"PQE status: {tiebreak_kwargs['pqe']}")
            self.add_edge_and_merge_components(list(edge[0]), {'weight': weight, 'type': edge_type, 'num': self.edge_no})
            steps += 1

            # Clean up and add back remaining edges to respective PQEs:
            if len(max_edges) > 1:
                logger.info(f'Adding back {len(max_edges)} edges to pqdict')
                for e in max_edges:
                    if e not in self.pairwise_weights[edge_type] and e != edge:
                        try:
                            if edge_type == 'join':
                                u, v = e[0][0]
                                dst = e[0][1]
                                logger.debug(f"Evaluating Join Edge info: {u},,,{v}-->{dst}")

                                if self.components[u] == self.components[dst] or self.components[v] == self.components[dst]:
                                    logger.debug(f'Skipping adding back redundant edge: {e}')
                                else:
                                    self.pairwise_weights[edge_type].additem(e[0], e[1])
                            else:
                                if self.components[e[0]] != self.components[e[1]]:
                                    self.pairwise_weights[edge_type].additem(e[0], e[1])
                        except KeyError as e:
                            logger.warning(f'Error: Trying to add back {e}, selected {edge}, to {edge_type} dict')

                if add_remaining_tie_break_edges and tiebreak_function:
                    try:
                        for e in tie_break_edges:
                            if self.components[e[0]] != self.components[e[1]]:
                                if e != edge:
                                    if e not in tiebreak_pqe:
                                        tiebreak_pqe.additem(e[0], e[1])
                    except ValueError as err:
                        logger.error(err)
                        logger.error(f"Tiebreak Edges: {tie_break_edges}")
                        logger.error(f"Edge: {e}")
                        raise(e)

def setup_arguments(args):
    parser = argparse.ArgumentParser()

    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("--artifact_zip",
                        help="ZIP containing artifacts to be analyzed",
                        type=str)

    group.add_argument("--artifact_dir",
                        help="Directory containing artifacts to be analyzed",
                        type=str)

    parser.add_argument("--nb_name",
                        help="Name of the notebook to be analyzed",
                        type=str, default=datetime.now().strftime("%Y%m%d%H%M%S"))

    parser.add_argument("--out",
                        help="Output Directory for Results",
                        type=str, default='inferred/')

    parser.add_argument("--config_json",
                        help="Configuration JSON file for inference Job. Overrides all other job parameters if present",
                        type=str)

    parser.add_argument("--pre_cluster",
                        help="Pre cluster by exact schema",
                        type=str2bool, default=True,
                        nargs='?', const=True)

    parser.add_argument("--celljaccard",
                        help="Look for cell-level jaccard edges",
                        type=str2bool, default=True,
                        nargs='?', const=True)

    parser.add_argument("--cellcontain",
                        help="Look for cell-level containment edges",
                        type=str2bool, default=True,
                        nargs='?', const=True)

    parser.add_argument("--groupby",
                        help="Use Groupby Edge Detection",
                        type=str2bool, default=True,
                        nargs='?', const=True)

    parser.add_argument("--join",
                        help="Use Join Edge Detection",
                        type=str2bool, default=True,
                        nargs='?', const=True)

    parser.add_argument("--transform",
                        help="Use Transform Edge Detection",
                        type=str2bool, default=False,
                        nargs='?', const=False)

    parser.add_argument("--pivot",
                        help="Use Pivot Edge Detection",
                        type=str2bool, default=True,
                        nargs='?', const=True)

    parser.add_argument("--intra_cell",
                        help="Cell-Level Edge Retention Threshold",
                        type=float, default=0.1)

    parser.add_argument("--colt",
                        help="Column-Level Edge Retention Threshold",
                        type=float, default=0.1)

    parser.add_argument("--inter_cell",
                        help="Inter Cluster Cell-Level Edge Retention Threshold",
                        type=float, default=0.1)

    parser.add_argument("--intra_contain",
                        help="Cell-Level Edge Retention Threshold",
                        type=float, default=0.1)

    parser.add_argument("--inter_contain",
                        help="Inter Cluster Cell-Level Edge Retention Threshold",
                        type=float, default=0.1)

    parser.add_argument("--g_truth_file",
                        help="Ground Truth File as a pickled NetworkX graph",
                        type=str)

    parser.add_argument("--pre_compute",
                        help="Use pre-computed distances (in the appropriate distance folder)",
                        type=str2bool, default=False,
                        nargs='?', const=False)

    parser.add_argument("--max_n_edges",
                        help="Number of edges to infer (default nartifacts - 1)",
                        type=int)

    parser.add_argument("--result_prefix",
                        help="Prefix the job result file with some string",
                        type=str, default='')

    parser.add_argument("--baseline",
                        help="Run baseline comparison",
                        type=str2bool, default=False,
                        nargs='?', const=False)

    parser.add_argument("--sample_frac",
                        help="Sampling Fraction to load dataset",
                        type=float, default=1.0)

    parser.add_argument("--sample_index",
                        help="Use consistent sampling when sample_frac less than 1.0",
                        type=str2bool, default=False,
                        nargs='?', const=False)

    parser.add_argument("--store_scores",
                        help="Write computed scores to disk in output dir",
                        type=str2bool, default=True,
                        nargs='?', const=True)

    parser.add_argument("--match_schema",
                        help="Run schema matching algorithm before computing pairwise similarities",
                        type=str2bool, default=False,
                        nargs='?', const=False)

    parser.add_argument("--perturb_alpha",
                        help="Perturb Schema (Alpha) parameter",
                        type=float, default=0.0)

    parser.add_argument("--perturb_beta",
                        help="Perturb Schema (Beta) parameter",
                        type=float, default=0.0)

    parser.add_argument("--perturb_gamma",
                         help="Perturb Schema (Gamma) parameter",
                         type=float, default=0.0)

    parser.add_argument("--lsh_graph_file",
                       help="LSH Graph File after clustering",
                       type=str, default=None)

    options = parser.parse_args(args)

    return options

def run_precluster(relic_instance, options, job_status, status_file):
    if options.pre_cluster:
        update_phase(job_status, 'Clustering', status_file)
        clusters = relic_instance.set_initial_clusters()
        os.makedirs(options.out+'/inferred', exist_ok=True)
        write_clusters_to_file(clusters, options.out+'/clusters.txt')
        logger.info(f'Clustered by Schema: {len(clusters.keys())} individual clusters created.')
        logger.info('Looking for PPO edges within each cluster...')

        if options.celljaccard:
            tiebreak_pqe = PQEdges()
            final_pqe = PQEdges()
            update_phase(job_status, 'Intra-Cluster Jaccard', status_file)
            relic_instance.add_edges_of_type(edge_type='jaccard', intra_cluster=True,
                                             tiebreak_function=tiebreak_from_computed_scores,
                                             final_function=tiebreak_hash_edge_pqe,
                                             sim_threshold=options.intra_cell,
                                             tiebreak_pqe=tiebreak_pqe,
                                             tiebreak_kwargs={'pairwise_weights': relic_instance.pairwise_weights,
                                                              'score_type': 'overlap'}
                                             )

        if options.cellcontain:
            tiebreak_pqe = PQEdges()
            final_pqe = PQEdges()
            update_phase(job_status, 'Intra-Cluster Containment', status_file)
            relic_instance.add_edges_of_type(edge_type='containment', intra_cluster=True,
                                             tiebreak_function=tiebreak_from_computed_scores,
                                             final_function=tiebreak_hash_edge_pqe,
                                             sim_threshold=options.intra_contain,
                                             tiebreak_pqe=tiebreak_pqe,
                                             tiebreak_kwargs={'pairwise_weights': relic_instance.pairwise_weights,
                                                              'score_type': 'overlap'}
                                             )
    return relic_instance

def run_join(relic_instance, options, distance_load_function, job_status, status_file):
    if options.join:
        logger.info('Looking for join edges across clusters...')
        update_phase(job_status, 'Join Detection', status_file)
        if options.pre_compute:
            logger.info(f'Loading Triplewise Join distances from file...')
            distance_file = options.out + '/join.csv'
            # TODO: Fix Hack for missing join.csv in case there are no schema-eligible join candidates
            # Else consolidate all the run_functions into a bigger function that can handle different detector types
            if os.path.exists(distance_file):
                relic_instance.pairwise_weights.update(distance_load_function(distance_file))
            else:
                logger.warning(f'Missing distance file: {distance_file}')
                return relic_instance
            logger.info(f'Loading complete...')
        else:
            relic_instance.compute_edges_of_type(edge_type='join', similarity_function=join_detector, n_pairs=3)

        tiebreak_pqe = PQEdges()
        final_pqe = PQEdges()
        relic_instance.add_edges_of_type(edge_type='join', intra_cluster=False, sim_threshold=1.0,
                                         tiebreak_function=tiebreak_join_computed_scores,
                                         final_function=tiebreak_hash_edge_join_pqe,
                                         tiebreak_pqe=tiebreak_pqe,
                                         tiebreak_kwargs={'pairwise_weights': relic_instance.pairwise_weights,
                                                          'score_type': 'containment'}
                                         )
    return relic_instance

def run_inter_cell(relic_instance, options, job_status, status_file):
    logger.info('Looking for PPO edges across clusters...')
    if options.celljaccard:
        tiebreak_pqe = PQEdges()
        final_pqe = PQEdges()
        update_phase(job_status, 'Inter-Cluster Jaccard', status_file)
        relic_instance.add_edges_of_type(edge_type='jaccard', intra_cluster=False,
                                         tiebreak_function=tiebreak_from_computed_scores,
                                         final_function=tiebreak_hash_edge_pqe,
                                         sim_threshold=options.inter_cell,
                                         tiebreak_pqe=tiebreak_pqe,
                                         tiebreak_kwargs={'pairwise_weights': relic_instance.pairwise_weights,
                                                          'score_type': 'overlap'}
                                         )
    return relic_instance

def run_inter_contain(relic_instance, options, job_status, status_file):
    if options.cellcontain:
        tiebreak_pqe = PQEdges()
        final_pqe = PQEdges()
        update_phase(job_status, 'Inter-Cluster Containment', status_file)
        relic_instance.add_edges_of_type(edge_type='containment', intra_cluster=False,
                                         tiebreak_function=tiebreak_from_computed_scores,
                                         final_function=tiebreak_hash_edge_pqe,
                                         sim_threshold=options.inter_contain,
                                         tiebreak_pqe=tiebreak_pqe,
                                         tiebreak_kwargs={'pairwise_weights': relic_instance.pairwise_weights,
                                                          'score_type': 'overlap'}
                                         )
    return relic_instance

def run_groupby(relic_instance, options, distance_load_function, job_status, status_file):
    if options.groupby:
        logger.info('Looking for Groupby edges across clusters...')
        update_phase(job_status, 'Groupby Detection', status_file)
        if options.pre_compute:
            logger.info(f'Loading Pairwise Groupby distances from file...')
            relic_instance.pairwise_weights.update(distance_load_function(options.out + '/groupby.csv'))
            logger.info(f'Loading complete...')
        else:
            relic_instance.compute_edges_of_type(edge_type='groupby', similarity_function=groupby_detector, n_pairs=2)

        tiebreak_pqe = PQEdges()
        final_pqe = PQEdges()
        relic_instance.add_edges_of_type(edge_type='groupby', intra_cluster=False, sim_threshold=1.0,
                                         tiebreak_function=tiebreak_groupby_replay,
                                         final_function=tiebreak_hash_edge_pqe,
                                         tiebreak_pqe=tiebreak_pqe,
                                         tiebreak_kwargs={'df_dict': relic_instance.dataset}
                                         )
        logger.info(f'GB Tiebreak Dict: {len(tiebreak_pqe.keys())}')
    return relic_instance

def run_pivot(relic_instance, options, distance_load_function, job_status, status_file):
    if options.pivot:
        logger.info('Looking for Pivot edges across clusters...')
        update_phase(job_status, 'Pivot Detection', status_file)
        if options.pre_compute:
            logger.info(f'Loading Pairwise Pivot distances from file...')
            relic_instance.pairwise_weights.update(distance_load_function(options.out + '/pivot.csv'))
            logger.info(f'Loading complete...')
        else:
            relic_instance.compute_edges_of_type(edge_type='pivot', similarity_function=pivot_detector, n_pairs=2)
        tiebreak_pqe = PQEdges()
        final_pqe = PQEdges()
        relic_instance.add_edges_of_type(edge_type='pivot', intra_cluster=False, sim_threshold=1.0,
                                         tiebreak_function=tiebreak_from_computed_scores,
                                         final_function=tiebreak_hash_edge_pqe,
                                         tiebreak_pqe=tiebreak_pqe,
                                         tiebreak_kwargs={'pairwise_weights': relic_instance.pairwise_weights,
                                                          'score_type': 'containment'}
                                         )
    return relic_instance

def run_baseline(relic_instance, options, distance_load_function, job_status, status_file):
    if options.baseline:
        logger.info('Running column baseline')
        update_phase(job_status, 'Baseline Column', status_file)
        if options.pre_compute:
            logger.info(f'Loading Pairwise Baseline distances from file...')
            relic_instance.pairwise_weights.update(distance_load_function(options.out + '/baseline.csv'))
            logger.info(f'Loading complete...')
        else:
            relic_instance.compute_edges_of_type(edge_type='baseline', similarity_function=compute_baseline_labels, n_pairs=2)

        final_pqe = PQEdges()
        relic_instance.add_edges_of_type(edge_type='baseline', intra_cluster=False, sim_threshold=0.0,
                                         tiebreak_function=None,
                                         final_function=tiebreak_hash_edge_pqe,
                                         )
    return relic_instance

def run_relic(options):
    logger.info('Testing RELIC on input:' + str(options.artifact_dir))
    logger.info('Output directory: ' + str(options.out))
    logger.info(f'Options: {options}')
    os.makedirs(options.out, exist_ok=True)

    distance_load_function = load_distances_from_pandas_file

    # Setup Job Log
    # create file handler which logs even debug messages
    fh = logging.FileHandler(str(options.out)+'job.log')
    fh.setLevel(logging.DEBUG)
    logger.addHandler(fh)

    job_status = {
        'status': 'running',
        'job_id': options.nb_name,
        'phaseno': 0,
        'totalphases': get_job_status_phases(options)
    }

    status_file = str(options.out)+'job_status.json'

    if 'artifact_zip' in options and options.artifact_zip:  # Zip file was provided
        zip_out = options.out+'/artifacts/'
        logger.info(f'Extracting ZIP file: {options.artifact_zip} to directory {zip_out}')
        if os.path.exists(zip_out):
            shutil.rmtree(zip_out)
        os.makedirs(zip_out)
        with zipfile.ZipFile(options.artifact_zip, 'r') as zip_ref:
            zip_ref.extractall(zip_out)
        artifact_dir = zip_out
    else:
        artifact_dir = options.artifact_dir

    timing_dicts = []

    start = perf_counter()
    relic_instance = RelicAlgorithm(artifact_dir, options.out, name=options.nb_name, g_truth_file=options.g_truth_file,
                                    max_edges=options.max_n_edges, sample_frac=options.sample_frac,
                                    sample_index_flag=options.sample_index, match_schema=options.match_schema,
                                    alpha=options.perturb_alpha, beta=options.perturb_beta, gamme=options.perturb_gamma,
                                    lsh_graph_file=options.lsh_graph_file)
    end = perf_counter()
    update_timing_df(timing_dicts, options.nb_name, 'loading', end-start)

    relic_instance.create_initial_graph()

    update_phase(job_status, 'Computing Pairwise Distances', status_file)

    if options.baseline:
        run_baseline(relic_instance, options, distance_load_function, job_status, status_file)
    else:
        if options.pre_compute:
            logger.info(f'Loading Pairwise PPO distances from file...')
            relic_instance.pairwise_weights.update(distance_load_function(options.out+'/ppo.csv'))
            logger.info(f'Loading Complete...')
        else:
            start = perf_counter()
            relic_instance.compute_edges_of_type(edge_type='all', similarity_function=compute_all_ppo_labels, n_pairs=2)
            end = perf_counter()
            update_timing_df(timing_dicts, options.nb_name, 'ppo', end-start)

        functions = {
            'pre_cluster': partial(run_precluster, relic_instance, options, job_status, status_file),
            'join': partial(run_join, relic_instance, options, distance_load_function, job_status, status_file),
            'inter_cell': partial(run_inter_cell, relic_instance, options, job_status, status_file),
            'inter_contain': partial(run_inter_contain, relic_instance, options, job_status, status_file),
            'groupby': partial(run_groupby, relic_instance, options, distance_load_function, job_status, status_file),
            'pivot': partial(run_pivot, relic_instance, options, distance_load_function, job_status, status_file)
        }

        order = ['pre_cluster', 'join', 'inter_cell', 'inter_contain', 'groupby', 'pivot']
        if options.lsh_graph_file:
            order = ['inter_cell', 'inter_contain', 'groupby', 'pivot']
        #order = ['join', 'groupby', 'pivot', 'pre_cluster', 'inter_cell', 'inter_contain']

        for func in order:
            start = perf_counter()
            relic_instance = functions[func]()
            end = perf_counter()
            update_timing_df(timing_dicts, options.nb_name, func, end-start)

    write_graph(relic_instance.g_inferred, f"{options.out}/{options.result_prefix}inferred_graph.csv")
    if options.g_truth_file:
        nx.write_edgelist(relic_instance.g_truth, f"{options.out}/true_graph.csv", data=True)

    job_status['status'] = 'complete'
    with open(status_file, 'w') as fp:
        json.dump(job_status, fp)

    pd.DataFrame(timing_dicts).to_csv(f"{options.out}/{options.result_prefix}_run_time.csv")

    if options.store_scores:
        store_all_distances(relic_instance.score_records, options.out)

def main(args=sys.argv[1:]):
    logger.info(f'Arguments: {args}')
    options = setup_arguments(args)
    logger.info(f'Options: {options}')
    run_relic(options)

if __name__ == "__main__":
    main()


from bs4 import BeautifulSoup# 패키지 설치
from urllib import parse, request
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys

from datetime import datetime
from pytz import timezone
from openpyxl import load_workbook
import pandas as pd
import time
import os
import openpyxl

url = 'https://best.aliexpress.com/'
top_url_txt = 'url/top_url.txt'
link_txt = 'url/category_urls/'
screenshot_name = './screenshot/test_'
img_down_route = './image/'
search_day = "%Y/%m/%d"

def excel_create(top_list, category_name):
    '''
    엑셀 파일로 저장하기.
    '''
    KST = datetime.now(timezone('Asia/Seoul'))
    s_time = KST.strftime(search_day)
    alarm = ''
    # pd_tmp = {'ITEM_CODE':[],'TITLE':[] ,'IMG_ROUTE':[], 'URL':[], 'TIME':[]}
    pd_tmp = {'ITEM_CODE':[],'TITLE':[] ,'IMG_ROUTE':[], 'URL':[]}
    for i in range(len(top_list)):
        item_links = []
        img_links = []
        item_names = []
        img_routes = []
        item_names, item_links, img_links = category_item_code(top_list[i], category_name[i])# 카테고리별로 txt파일로 나눠 저장
        if len(item_links) != 11:
            alarm += category_name[i]+' : lenge short\n'
        item_codes = item_code_extraction(item_links)
        img_routes = down_img(img_links, item_codes)

        pd_tmp['ITEM_CODE']+=item_codes
        pd_tmp['TITLE']+=item_names
        pd_tmp['IMG_ROUTE']+=img_routes
        pd_tmp['URL']+=item_links
        # pd_tmp['TIME']+=s_time
    # print(pd_tmp)
    create_ex = pd.DataFrame(pd_tmp)
    # create_ex = ex_tmp.to_frame()
    print(create_ex)
    print(alarm)
    create_ex.to_excel('./excel/output.xlsx')

def down_img(img_urls, img_codes):
    '''
    이미지 다운로드
    '''
    img_r = []
    for i, j in zip(img_urls, img_codes):
        if not os.path.exists(img_down_route+j+'.jpg'):
            request.urlretrieve(i, img_down_route+j+'.jpg')
        img_r.append(img_down_route+j+'.jpg')

    return img_r

def item_code_extraction(tyr_extraction_urls):
    '''
    상품코드 추출
    '''
    slash_num = 0
    ext_i_codes = []
    tmp = ''
    for i in tyr_extraction_urls:
        for j in i:
            if j == '/':
                slash_num += 1
            else:
                if slash_num == 5:
                    if j == '.':
                        ext_i_codes.append(tmp)
                        tmp = ''
                        slash_num = 0
                        break
                    else :
                        tmp += j
    return ext_i_codes

def category_item_code(top_item_urls, c_name):
    '''
    카테고리별 상위 11개 상품 정보 획득
    selenium
    '''
    item_link = []
    img_link = []
    item_name = []
    img_tmp = ''
    try:
        options = Options()
        options.add_argument("--headless")
        options.add_argument("--no-sandbox")
        options.add_argument('--start-fullscreen')
        driver = webdriver.Chrome(options=options)
        driver.get(top_item_urls)
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(3)
        # driver.save_screenshot(screenshot_name+'123'+'.png')
        html = driver.page_source
        driver.quit()

        soup = BeautifulSoup(html, 'html.parser') #URL과 파라메터 합쳐서 전달후 정보 읽어옴
        # soup = soup.find('div',class_ = 'top-ranking')
        # print(soup)rankings-item
        one_pic = soup.findAll('ul',class_='rankings-list')[0]
        one_pic = one_pic.find('li',class_='rankings-item')

        top_ten = soup.findAll('ul',class_='rankings-list')[1]
        soup = top_ten.findAll('li',class_='rankings-item')

        # print(len(soup))
        item_name.append(one_pic.find('div',class_='title').text)
        img_tmp = 'https:'+one_pic.find('img',class_='image').get('src')[:-12]
        if img_tmp[-1] == '_':
            img_link.append(img_tmp[:-1])
        else:
            img_link.append(img_tmp)
        item_link.append('https:'+one_pic.find('a').attrs['href'])

        for i in soup:
            item_name.append(i.find('div',class_='title').text)
            img_tmp = 'https:'+i.find('img',class_='image').get('src')[:-12]
            if img_tmp[-1] == '_':
                img_link.append(img_tmp[:-1])
            else:
                img_link.append(img_tmp)
            item_link.append('https:'+i.find('a').attrs['href'])

        return item_name, item_link, img_link
    except :
        return [], [], []

#div (title, ) img (image,(src)), a(href)

def top_category(top_rank_url):
    '''
    top_9 카테고리 url 획득
    '''
    top_url = []
    top_name = []
    try :
        requ = (top_rank_url)
        response_body = request.urlopen(requ).read()
        soup = (BeautifulSoup(response_body, 'html.parser')) #URL과 파라메터 합쳐서 전달후 정보 읽어옴
        ul_c = soup.find('div', class_='ui-slidebox-wrap') #필요한 부분 자름
        top_div = ul_c.findAll('div', class_='ui-slidebox-item')
        for i in top_div:
            top_str = 'https:'+i.find('a').attrs['href']
            top_name = (i.find('div', class_='product-name').text).split()
            top_url.append([top_str[:28]+'ko/__pc/'+top_str[28:], '_'.join(top_name)]) #url만 가공하여 습득
    except :
        return []

    return top_url#, top_name

def main():
    item_codes = []
    category_names = []
    top_lists = top_category(url)

    for i in range(len(top_lists)) :
        category_names.append(top_lists[i][1])
        top_lists[i] = top_lists[i][0]
        if '&' in category_names[i]:
            for j in range(len(category_names[i])):
                if category_names[i][j] == '&':
                    category_names[i] = category_names[i][:j]+'n'+category_names[i][j+1:]

    excel_create(top_lists, category_names)

main()


# coding=utf-8
import json
from dataclasses import dataclass, asdict
from typing import List, Optional

from src.constants import DEFAULT_LIMIT, DEFAULT_OFFSET
from src.entity.room import Room
from src.exceptions import RoomNotFoundError, RoomNumberMismatchError, MissingRequiredField, \
    IntMustBePositive, StringMustNotBeEmpty
from src.use_case.interface.room_repository import RoomRepository
from src.util.context import log_extra
from src.util.log import LOG
from src.util.validator import is_empty

@dataclass
class MutationRequest:
    room_number: str
    description: str
    phone_number: Optional[str]
    vlan_number: str

    def validate(self):
        if self.room_number is None:
            raise MissingRequiredField('room_number')

        if is_empty(self.room_number):
            raise StringMustNotBeEmpty('room_number')

        if self.description is None:
            raise MissingRequiredField('description')

        if self.vlan_number is None:
            raise MissingRequiredField('vlan_number')

        if is_empty(self.vlan_number):
            raise StringMustNotBeEmpty('vlan_number')

class RoomManager:
    def __init__(self, room_repository: RoomRepository):
        self.room_repository = room_repository

    def delete(self, ctx, room_number) -> None:
        """
        Delete a room from the database.

        User story: As an admin, I can delete a room, so I can remove rooms that do not exist.

        :raise RoomNotFound
        """
        try:
            self.room_repository.delete_room(ctx, room_number=room_number)
            LOG.info('room_delete', extra=log_extra(ctx, room_number=room_number))

        except RoomNotFoundError as e:
            raise RoomNotFoundError(room_number) from e

    def get_by_number(self, ctx, room_number) -> Room:
        """
        Get a room from the database.

        User story: As an admin, I can get a room, so that see the room information.

        :raise RoomNotFound
        """
        result, _ = self.room_repository.search_room_by(ctx, room_number=room_number)
        LOG.info('room_get_by_number', extra=log_extra(ctx, room_number=room_number))
        if not result:
            raise RoomNotFoundError(room_number)

        return result[0]

    def search(self, ctx, limit=DEFAULT_LIMIT, offset=DEFAULT_OFFSET, terms=None) -> (List[Room], int):
        """
        Search a room in the database.

        User story: As an admin, I can search rooms, so that see the room information.

        :raise IntMustBePositiveException
        """
        if limit < 0:
            raise IntMustBePositive('limit')

        if offset < 0:
            raise IntMustBePositive('offset')

        result, count = self.room_repository.search_room_by(ctx, limit=limit, offset=offset, terms=terms)
        LOG.info('room_search', extra=log_extra(
            ctx,
            terms=terms,
        ))
        return result, count

    def update_or_create(self, ctx, room_number, mutation_request: MutationRequest) -> bool:
        """
        Create/Update a room from the database.

        User story: As an admin, I can modify a room, so that I change its description.
        :return: True if the room was created, false otherwise.

        :raise MissingRequiredFieldError
        :raise VlanNotFound
        :raise RoomNumberMismatchError
        """
        # Make sure all the fields set are valid.
        mutation_request.validate()

        room, _ = self.room_repository.search_room_by(ctx, room_number=room_number)
        if room:
            # [UPDATE] Room already exists, perform a whole update.

            # Create a dict with fields to update. If field is not provided in the mutation request, consider that it
            # should be None as it is a full update of the member.
            fields_to_update = asdict(mutation_request)
            fields_to_update = {k: v for k, v in fields_to_update.items()}

            # This call will never throw a RoomNotFound because we checked for the object existence before.
            self.room_repository.update_room(ctx, room_number, **fields_to_update)

            # Log action.
            LOG.info('room_update', extra=log_extra(
                ctx,
                room_number=room_number,
                mutation=json.dumps(fields_to_update, sort_keys=True),
            ))

            return False
        else:
            # [CREATE] Room does not exist, create it.

            # Build a dict that will be transformed into a room. If a field is not set, consider that it should be
            #  None.
            if room_number != mutation_request.room_number:
                raise RoomNumberMismatchError()

            fields = asdict(mutation_request)
            fields = {k: v for k, v in fields.items()}

            self.room_repository.create_room(ctx, **fields)

            # Log action
            LOG.info('room_create', extra=log_extra(
                ctx,
                room_number=room_number,
                mutation=json.dumps(fields, sort_keys=True)
            ))

            return True


import json
import typing

from aiohttp.web_exceptions import (
    HTTPException,
    HTTPUnprocessableEntity,
    HTTPForbidden,
    HTTPUnauthorized,
    HTTPInternalServerError,
    HTTPConflict,
    HTTPNotFound,
    HTTPMethodNotAllowed,
)
from aiohttp.web_middlewares import middleware
from aiohttp_apispec import validation_middleware
from aiohttp_session import get_session

from app.admin.models import Admin
from app.web.utils import error_json_response

if typing.TYPE_CHECKING:
    from app.web.app import Application, Request

@middleware
async def auth_middleware(request: "Request", handler: callable):
    session = await get_session(request)
    print(session)
    if session:
        request.admin = Admin.from_session(session)
    return await handler(request)

HTTP_ERROR_CODES = {
    400: "bad_request",
    401: "unauthorized",
    403: "forbidden",
    404: "not_found",
    405: "not_implemented",
    409: "conflict",
    500: "internal_server_error",
}

@middleware
async def error_handling_middleware(request: "Request", handler):
    try:
        response = await handler(request)
        return response
    except HTTPUnprocessableEntity as e:
        return error_json_response(
            http_status=400,
            status=HTTP_ERROR_CODES[400],
            message=e.reason,
            data=json.loads(e.text),
        )
    except HTTPForbidden as e:
        return error_json_response(
            http_status=403,
            status=HTTP_ERROR_CODES[403],
            message="Provide valid credentials (email/password) for get access",
            data=e.text,
        )
    except HTTPUnauthorized as e:
        return error_json_response(
            http_status=401,
            status=HTTP_ERROR_CODES[401],
            message="You must be authorized for do this action",
            data=e.text,
        )
    except HTTPInternalServerError as e:
        return error_json_response(
            http_status=500,
            status=HTTP_ERROR_CODES[500],
            message=e.text,
        )
    except HTTPConflict as e:
        return error_json_response(
            http_status=409,
            status=HTTP_ERROR_CODES[409],
            message=e.text,
        )
    except HTTPNotFound as e:
        return error_json_response(
            http_status=404,
            status=HTTP_ERROR_CODES[404],
            message=e.text,
        )
    except HTTPMethodNotAllowed as e:
        return error_json_response(
            http_status=405,
            status=HTTP_ERROR_CODES[405],
            message=e.text,
        )

def setup_middlewares(app: "Application"):
    app.middlewares.append(auth_middleware)
    app.middlewares.append(error_handling_middleware)
    app.middlewares.append(validation_middleware)


import os,sys
import time
import openpyxl
import pandas as pd
import random
"""定义变量以及列表初始化"""
coe=[]
rex=[]
re=[]
part=0
count=0

while True:

	os.system('clear')

	print('\033[1;32;40m============================================================================')
	print('这是一个用来调整价格的脚本，首先要将需要调整的全部价格导入到一个Excel 表格中')
	print('然后调用该脚本即可完成操作。第一列列名要改成total！')
	print('============================================================================')
	print('\033[0m')

	path=input('\033[1;33;40m请输入Excel文件路径,输入exit退出: ')
	print('\033[0m')
	path=path.strip()
	if path=='exit':
		sys.exit()

	elif os.path.exists(path)==False:
		print('\033[1;37;31m未找到该文件，请检查文件路径！\033[1;37;31m')
		print('\033[0m')
		time.sleep(1)
		continue

	target=input("请输入目标价格： ")
	#extracting data from excel
	data=pd.DataFrame(pd.read_excel(path))
	for i in data['total']:
		coe.append(i)
	for i in coe:
		count=i+count

	r=float(target)/count
	for i in range(len(coe)-1):
		rex.append(r+random.uniform(-1/(10**(round(len(target)/2)+1)),1/(10**(round(len(target)/2)+1))))

	for i in range(len(coe)-1):
		part=part+coe[i]*rex[i]
	lastrex=(float(target)-part)/coe[-1]
	rex.append(round(lastrex,3))

	#writing to excel
	wb=openpyxl.load_workbook(path)
	ws=wb['Sheet1']

	ws.cell(row=1,column=2).value='系数'
	for i in range(1,len(rex)+1):
		re=rex[i-1]
		ws.cell(row=i+1,column=2).value=re

	ws.cell(row=1,column=3).value='结果'
	for i in range(1,len(rex)+1):
		er=rex[i-1]*coe[i-1]
		ws.cell(row=i+1,column=3).value=er

	save=wb.save(path)
	if save==None:
		print('\033[1;32;40m文件保存成功!\033[1;32;40m')
		print('\033[0m')
		time.sleep(2)
	else:
		print('\033[1;37;31m文件保存失败！\033[1;37;31m')
		print('\033[0m')
		time.sleep(2)


from decouple import config
from deta import Deta
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

DETA_PROJECT_KEY = config('DETA_PROJECT_KEY')
DB_NAME = config('DB_NAME')

app = FastAPI()
deta = Deta(DETA_PROJECT_KEY)
db = deta.Base(DB_NAME)

class Driver(BaseModel):
    key: str
    link: str

@app.get("/wacom-drivers", status_code=200)
def get_drivers():
    response = db.fetch()
    drivers = response.items
    return drivers

@app.get("/wacom-drivers/{key}", status_code=200)
def get_driver(key: str):
    driver = db.get(key)
    if driver is None:
        raise HTTPException(status_code=404, detail="Driver not found")
    return driver


from tqdm import tqdm
from random import randint

def insertion_sort(array):
	for i in tqdm(range(1, len(array))):
		current = array[i]
		j = i - 1
		while j >= 0 and array[j] > current:
			array[j + 1] = array[j]
			j -= 1
		array[j + 1] = current
	return array

nums = [randint(1,20000) for _ in range(20000)]
print(insertion_sort(nums))


from PySide6 import QtGui, QtWidgets, QtCore
from ui.MainWindowUI import Ui_MainWindow
from fpga.Comm import Comm
from fpga.Components import *
import logging
import utils.utils as utils
class MainWindow(QtWidgets.QMainWindow):
    __REG_BASE = 0xC0
    __CAP_BASE = 0x40
    __ANEMO_BASE = 0x20
    __GIRO_BASE = 0x00
    __VERIN_BASE = 0x80
    __VERIN_ANGLE_BASE = 0xA0
    __POLLING_RATE_MS = 100
    def __init__(self):
        super().__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        #self.ui.CapControlMinusButton.clicked.connect(self.ui.BoatWidget.insert)
        #self.ui.CapControlPlusButton.clicked.connect(self.ui.BoatWidget.extract)
        self.__checkPortTimer = QtCore.QTimer(self)
        self.__checkPortTimer.timeout.connect(self.scanPorts)
        #timer = QtCore.QTimer(self)
        #timer.timeout.connect(self.rotate)
        #timer.start(100)
        self.__WindForce = 0
        self.__WindDirection = 0
        self.__CompassDirection = 0
        self.__HydraulicPos = 50
        self.ui.CapControlMinusButton.clicked.connect(lambda : self.__updateHydraulic(self.__HydraulicPos - 10))
        self.ui.CapControlPlusButton.clicked.connect(lambda : self.__updateHydraulic(self.__HydraulicPos + 10))

        self.rot = 0
        self.__Comm = Comm()
        self.cnt = 0
        self.pwmR = 0
        self.pwmG = 0
        self.pwmB = 0
        self.pwmLR = Pwm(self.__Comm, 0x80, 4)
        self.pwmLG = Pwm(self.__Comm, 0x90, 4)
        self.pwmLB = Pwm(self.__Comm, 0xA0, 4)
        self.pwmRR = Pwm(self.__Comm, 0xB0, 4)
        self.pwmRG = Pwm(self.__Comm, 0xC0, 4)
        self.pwmRB = Pwm(self.__Comm, 0xD0, 4)
        self.__CapPwm = Pwm(self.__Comm, MainWindow.__CAP_BASE, 4)
        self.__AnemoPwm = Pwm(self.__Comm, MainWindow.__ANEMO_BASE, 4)
        self.__GiroPwm = Pwm(self.__Comm, MainWindow.__GIRO_BASE, 4)
        self.__VerinPwm = Pwm(self.__Comm, MainWindow.__VERIN_BASE, 4)
        #self.ui.CompassACWButton.clicked.connect(self.minusR)
        #self.ui.CompassACWButton.clicked.connect(self.__decreaseCompassAngle)
        self.ui.CompassACWButton.clicked.connect(lambda: self.__updateCompass((self.__CompassDirection - 10) % 360))
        self.ui.CompassCWButton.clicked.connect(lambda: self.__updateCompass((self.__CompassDirection + 10) % 360))
        #self.ui.CompassCWButton.clicked.connect(self.__increaseCompassAngle)
        #self.ui.CompassCWButton.clicked.connect(((lambda self, x: MainWindow.updateCompass(self, x))(self, self.__CompassDirection + 10)))
        #self.ui.WdACWButton.clicked.connect(self.minusG)
        #self.ui.WdCWButton.clicked.connect(self.plusG)
        #self.ui.WfDecreaseButton.clicked.connect(self.minusB)
        #self.ui.WfIncreaseButton.clicked.connect(self.plusB)
        self.ui.WdACWButton.clicked.connect(lambda: self.__updateWind((self.__WindDirection - 10) % 360, self.__WindForce))
        self.ui.WdCWButton.clicked.connect(lambda: self.__updateWind((self.__WindDirection + 10) % 360, self.__WindForce))
        self.ui.WfDecreaseButton.clicked.connect(lambda: self.__updateWind(self.__WindDirection, self.__WindForce - 10))
        self.ui.WfIncreaseButton.clicked.connect(lambda: self.__updateWind(self.__WindDirection, self.__WindForce + 10))
        self.ui.HydraulicManualControl.toggled.connect(self.__hydraulicManualControlEnableDisable)
        self.portActionGroup = QtGui.QActionGroup(self)
        self.portActionGroup.setExclusive(True)
        self.baudrateActionGroup = QtGui.QActionGroup(self)
        for action in self.ui.menuBaudRate.actions():
            self.baudrateActionGroup.addAction(action)
            action.setCheckable(True)
            if action.text() == "115200":
                action.setChecked(True)
        self.baudrateActionGroup.setExclusive(True)
        self.ui.menuBaudRate.triggered.connect(self.__baudSelected)
        self.ui.menuSerialPort.aboutToShow.connect(self.scanPorts)
        self.ui.menuPort.triggered.connect(self.__portSelected)
        self.ui.menuBaudRate.setEnabled(False)
        self.ui.actionOpen.setEnabled(False)
        self.ui.actionOpen.triggered.connect(self.__openClosePort)
        self.updateTimer = QtCore.QTimer(self)
        self.updateTimer.timeout.connect(self.__update)
        self.__updateCompass(0)
        self.__updateWind(0, 0)
        self.__hydraulicManualControlEnableDisable()
        self.__updateHydraulic(self.__HydraulicPos)
        self.__FpgaFreq = 0
        self.ui.BabordButton.pressed.connect(lambda : self.__sendBtnValue(0x4))
        self.ui.BabordButton.released.connect(lambda : self.__sendBtnValue(0x0))
        self.ui.StandbyButton.pressed.connect(lambda : self.__sendBtnValue(0x2))
        self.ui.StandbyButton.released.connect(lambda : self.__sendBtnValue(0x0))
        self.ui.TribordButton.pressed.connect(lambda : self.__sendBtnValue(0x1))
        self.ui.TribordButton.released.connect(lambda : self.__sendBtnValue(0x0))
        self.__initFPGA()

    def __hydraulicManualControlEnableDisable(self):
        self.ui.CapControlMinusButton.setDisabled(not self.ui.HydraulicManualControl.isChecked())
        self.ui.CapControlPlusButton.setDisabled(not self.ui.HydraulicManualControl.isChecked())
    def __update(self):
        if self.__Comm.isOpen():
            if not self.ui.HydraulicManualControl.isChecked():
                freq = self.__VerinPwm.getFreq()
                duty = 0
                sens = 0
                if freq != 0:
                    duty = self.__VerinPwm.getDuty() / freq
                    freq = self.__FpgaFreq / freq
                    value = utils.map(duty, 0, 1, 0, 5)
                    sens = int.from_bytes(self.__Comm.readAt(MainWindow.__REG_BASE + 4, 1), 'little')
                    if not sens:
                        value = -value
                    self.__updateHydraulic(self.__HydraulicPos + value)
#                    print("value = {0}".format(value))
#                print("sens = {0}".format(sens))
#                print("duty = {0}".format(duty))
#                print("freq = {0}".format(freq))
            leds_status = int.from_bytes(self.__Comm.readAt(MainWindow.__REG_BASE + 5, 1), 'little')
            self.ui.LedBabord.setChecked( leds_status & 0x4)
            self.ui.LedStandby.setChecked(leds_status & 0x2)
            self.ui.LedTribord.setChecked(leds_status & 0x1)
                #self.__updateHydraulic()

#            self.pwmLR.getDuty()
#            self.pwmLG.getDuty()
#            self.pwmLB.getDuty()
#            self.pwmRR.getDuty()
#            self.pwmRG.getDuty()
#            self.pwmRB.getDuty()

    def __portSelected(self, action : QtGui.QAction):
        self.ui.menuBaudRate.setEnabled(True)
        self.ui.actionOpen.setEnabled(True)
        if self.__Comm.getPort() != self.portActionGroup.checkedAction().text() and self.__Comm.isOpen():
            self.__openClosePort()
    def __openClosePort(self):
        if not self.__Comm.isOpen():
            self.__Comm.setConfig(self.portActionGroup.checkedAction().text(), int(self.baudrateActionGroup.checkedAction().text()))
            self.__Comm.open()
            logging.info("Opened {0}, baud = {1}".format(self.portActionGroup.checkedAction().text(), int(self.baudrateActionGroup.checkedAction().text())))
            self.ui.actionOpen.setText("Close")
            self.__FpgaFreq = int.from_bytes(self.__Comm.readAt(MainWindow.__REG_BASE, 4, True), 'little')
            if self.__FpgaFreq == 0:
                logging.info("Can't read Fpga frequency")
                self.__openClosePort()
            else:
                logging.info("Fpga freq = {0}".format(self.__FpgaFreq))
                self.__initFPGA()
                self.__checkPortTimer.start(1000)
                self.updateTimer.start(MainWindow.__POLLING_RATE_MS)
        else:
            self.__Comm.close()
            logging.info("Closed {0}".format(self.__Comm.getPort()))
            self.ui.actionOpen.setText("Open")
            self.__checkPortTimer.stop()
            self.updateTimer.stop()

    def rotate(self) -> None:
        self.ui.CompassWidget.rotate(self.rot)
        self.ui.WindWidget.rotate(self.rot)
        self.rot += 10
    def minusR(self):
        self.pwmR -= 10
        if self.pwmR <= 0:
            self.pwmR = 0
        value = int(self.pwmR / 100 * (2**32 - 1))
        self.pwmLR.setDuty(value)
        self.pwmRR.setDuty(value)
    def minusG(self):
        self.pwmG -= 10
        if self.pwmG <= 0:
            self.pwmG = 0
        value = int(self.pwmG / 100 * (2**32 - 1))
        self.pwmLG.setDuty(value)
        self.pwmRG.setDuty(value)
    def minusB(self):
        self.pwmB -= 10
        if self.pwmB <= 0:
            self.pwmB = 0
        value = int(self.pwmB / 100 * (2**32 - 1))
        self.pwmLB.setDuty(value)
        self.pwmRB.setDuty(value)
    def plusR(self):
        self.pwmR += 10
        if self.pwmR >= 100:
            self.pwmR = 100
        value = int(self.pwmR / 100 * (2**32 - 1))
        self.pwmLR.setDuty(value)
        self.pwmRR.setDuty(value)
    def plusG(self):
        self.pwmG += 10
        if self.pwmG >= 100:
            self.pwmG = 100
        value = int(self.pwmG / 100 * (2**32 - 1))
        self.pwmLG.setDuty(value)
        self.pwmRG.setDuty(value)
    def plusB(self):
        self.pwmB += 10
        if self.pwmB >= 100:
            self.pwmB = 100
        value = int(self.pwmB / 100 * (2**32 - 1))
        self.pwmLB.setDuty(value)
        self.pwmRB.setDuty(value)
    def test(self) -> None:
        dat = [0] * 16
        for i in range(len(dat)):
            temp = (self.cnt + i) % 256
            dat[i] = temp
        if not self.__Comm.writeAt(0x0, 16, dat, True):
            print("Write Ko")
        #else:
        #    print("Write Ok")
        rxDat = self.__Comm.readAt(0, 16, True)
        if rxDat != None:
            print("RxData :")
            print("    ", end='')
            for i in range(16):
                print(" {0:02X}".format(i), end='')
            print()
            for i in range(0, len(rxDat) - 1, 16):
                print("0x{0:02X}".format(i), end='')
                for j in range(16):
                    if i + j >= len(rxDat):
                        break
                    print(" {0:02X}".format(rxDat[i + j]), end='')
                print()
        self.cnt = (self.cnt + 1) % 256

    def scanPorts(self):
        disconnected = True
        if self.portActionGroup.checkedAction() != None:
            currentPort = self.portActionGroup.checkedAction().text()
        else:
            currentPort = ''
        import serial.tools.list_ports
        portList = serial.tools.list_ports.comports()
        self.ui.menuPort.clear()
        if len(portList):
            self.ui.menuPort.setDisabled(False)
            portList.sort()
            for port in portList:
                self.ui.menuPort.addAction(port.name)
                if currentPort == port.name:
                    self.ui.menuPort.actions()[-1].setChecked(True)
                    disconnected = False
        else:
            self.ui.menuPort.setDisabled(True)
        if disconnected:
            self.ui.menuBaudRate.setDisabled(True)
            self.ui.actionOpen.setDisabled(True)
            self.ui.actionOpen.setText("Open")
            if self.__Comm.isOpen():
                self.__openClosePort()
        for action in self.ui.menuPort.actions():
            self.portActionGroup.addAction(action)
            action.setCheckable(True)
    def __baudSelected(self, action : QtGui.QAction):
        baud = int(action.text())
        logging.info("Changed baud to {0}".format(baud))
        self.__Comm.setConfig(baud=baud)

    def __updateCompass(self, directionValue):
        self.__CompassDirection = directionValue
        self.ui.CompassValueLabel.setText("{0}°".format(self.__CompassDirection))
        self.ui.CompassWidget.rotate(self.__CompassDirection)
        if self.__Comm.isOpen():
            compassTon = 1 + self.__CompassDirection / 10
            freq = int(1/((compassTon + 65)*1e-3 * self.__FpgaFreq) * (2**32 - 1))
            duty = int(compassTon/(compassTon + 65) * (2**32 - 1))
            self.__CapPwm.setFreq(freq)
            self.__CapPwm.setDuty(duty)
    def __updateWind(self, directionValue, forceValue):
        self.__WindDirection = directionValue
        if forceValue < 0:
            self.__WindForce = 0
        elif forceValue > 250:
            self.__WindForce = 250
        else:
            self.__WindForce = forceValue
        self.ui.WindValueLabel.setText("{0}Km/h {1}°".format(self.__WindForce, self.__WindDirection))
        self.ui.WindWidget.rotate(self.__WindDirection)
        anemoTon = 1 + self.__WindDirection / 10
        #freq = int(1e3/self.__FpgaFreq * 2**32)
        if self.__Comm.isOpen():
            freq = int(1/((anemoTon + 65)*1e-3 * self.__FpgaFreq) * (2**32 - 1))
            duty = int(anemoTon/(anemoTon + 65) * (2**32 - 1))
            self.__AnemoPwm.setFreq(freq)
            self.__AnemoPwm.setDuty(duty)
            duty = int(0.5*(2**32 - 1))
            freq = int(self.__WindForce / self.__FpgaFreq * (2**32 - 1))
            self.__GiroPwm.setDuty(duty)
            self.__GiroPwm.setFreq(freq)
        #self.__AnemoPwm.setDuty(utils.map(self.__WindDirection, 0, 360, (2**32 - 1)*0.1, 2**32 - 1))
        #self.__GiroPwm.setDuty()
    def __updateHydraulic(self, value):
        if value < 0:
            value = 0
        elif value > 100:
            value = 100
        if value != self.__HydraulicPos:
            self.__HydraulicPos = value
            self.ui.BoatWidget.set_pos(self.__HydraulicPos)
            adcValue = int(utils.map(int(self.ui.BoatWidget.get_turningAngle()), -40, 40, 1300, 3000))
            self.ui.HydraulicAngle.setText("{0}° ({1})".format(int(self.ui.BoatWidget.get_turningAngle()), adcValue))
            if self.__Comm.isOpen():
                self.__Comm.writeAt(MainWindow.__VERIN_ANGLE_BASE, 2, adcValue.to_bytes(2, 'little'), True)
    def __sendBtnValue(self, value : int):
        if self.__Comm.isOpen():
            self.__Comm.writeAt(MainWindow.__REG_BASE, 1, value.to_bytes(1, 'little'))
    def __initFPGA(self):
        self.__updateCompass(self.__CompassDirection)
        self.__updateWind(self.__WindDirection, self.__WindForce)
        self.__updateHydraulic(self.__HydraulicPos)


# -*- coding: utf-8 -*-
"""
Created on Mon Sep 12 15:56:02 2022

@author: arman hossain

!python excel.py
"""

import sys

from PyQt5.QtWidgets import (
    QApplication, QWidget, QHeaderView
)
from PyQt5.uic import loadUi
import pickle
import os

class Excel(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        loadUi("excel.ui", self)
        self.sortChanged(0)
        self.setWindowTitle("List View")
        self.connect()
        self.initui()
        self.total_data_label.setText(str(len(self.tableWidget.data))+"         ")

    def initui(self):
        header = self.tableWidget.horizontalHeader()
        header.setSectionResizeMode(1, QHeaderView.Stretch)
        self.initCombo()

    def initCombo(self):
        if os.path.exists('./data/2002-2022-vendor-year-count.pickle'):
            self.comboBox.addItems(['All']+list(self.read_data("./data/2002-2022-vendor-year-count.pickle").keys()))

    def read_data(self,filename):
        with open(filename, 'rb') as file:
            obj = pickle.load(file)
            return obj

    def connect(self):
        self.previous_btn.clicked.connect(self.previous_pressed)
        self.next_btn.clicked.connect(self.next_pressed)
        self.plus_btn.clicked.connect(self.current_plus_pressed)
        self.minus_btn.clicked.connect(self.current_minus_pressed)
        # self.current_btn.clicked.connect(self.current_btn_pressed)
        self.tableWidget.horizontalHeader().sortIndicatorChanged.connect(self.sortChanged)
        self.comboBox.activated.connect(self.comboindexchanged)

    def comboindexchanged(self,index):
        vendor = self.comboBox.itemText(index)
        self.tableWidget.filter_dataset(vendor)
        self.tableWidget.goto_page(1)
        self.setbuttontext(1)
        self.total_data_label.setText(str(len(self.tableWidget.data))+"         ")

    def sortChanged(self,index):
        self.tableWidget.sortChanged(index)
        self.tableWidget.goto_page(1)
        self.setbuttontext(1)

    def reload_data(self):
        self.tableWidget.reload_data()
        self.comboBox.setCurrentIndex(0)
        self.tableWidget.goto_page(1)
        self.setbuttontext(1)

    def setbuttontext(self,number):
        if number < 1:
            return
        if number == 1:
            self.previous_btn.setEnabled(False)
        else:
            self.previous_btn.setEnabled(True)
        next = number+self.tableWidget.item_per_page
        pre = number-self.tableWidget.item_per_page
        self.current_btn.setText(str(number))
        self.plus_btn.setText(str(next))
        if pre>0:
            self.minus_btn.setEnabled(True)
            self.minus_btn.setText(str(pre))
        else:
            self.minus_btn.setText(str(0))
            self.minus_btn.setEnabled(False)

    def current_plus_pressed(self):
        self.tableWidget.goto_page(int(self.plus_btn.text()))
        self.setbuttontext(int(self.plus_btn.text()))
    def current_minus_pressed(self):
        self.tableWidget.goto_page(int(self.minus_btn.text()))
        self.setbuttontext(int(self.minus_btn.text()))
    def next_pressed(self):
        self.tableWidget.goto_page_next()
        self.setbuttontext(int(self.current_btn.text())+1)
    def previous_pressed(self):
        self.tableWidget.goto_page_pre()
        self.setbuttontext(int(self.current_btn.text())-1)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Excel()
    win.show()
    sys.exit(app.exec())


import copy
from typing import List, Tuple

def print_graph(graph):
    for i in range(len(graph)):
        print(graph[i])

def read_and_parse_input(file_name: str):
    with open(file_name, "r") as input_file:
        contents = input_file.readlines()
    for i, content in enumerate(contents):
        content = content.replace("\n", "")
        contents[i] = [char for char in content]
    return contents

def process_point(i: int, j: int, value: str, graph) -> str:
    count = 0
    adjacent = [(1, 0), (0, 1), (1, 1), (-1, 0), (0, -1), (-1, 1), (1, -1), (-1, -1)]
    if value == "L":
        tmp_cntr = 0
        for neighbour in adjacent:
            x_off, y_off = neighbour
            if 0 <= x_off + i < len(graph) and 0 <= y_off + j < len(graph[i]):
                if graph[x_off + i][y_off + j] != "#":
                    count += 1
            else:
                tmp_cntr += 1
        return count == len(adjacent) - tmp_cntr
    elif value == "#":
        for neighbour in adjacent:
            x_off, y_off = neighbour
            if 0 <= x_off + i < len(graph) and 0 <= y_off + j < len(graph[i]):
                if graph[x_off + i][y_off + j] == "#":
                    count += 1
        return count >= 4

def process_point_2(i: int, j: int, graph):
    directions = [(1, 0), (0, 1), (1, 1), (-1, 0), (0, -1), (-1, 1), (1, -1), (-1, -1)]
    tmp_cntr = 0
    hash_cntr = 0
    reg_cntr = 0
    for direction in directions:
        next_ = find_next_point(i, j, direction, graph)
        if next_ == -1:
            tmp_cntr += 1
        elif next_ == "#":
            hash_cntr += 1
        elif next_ != "#":
            reg_cntr += 1
    if graph[i][j] == "L":
        return reg_cntr == len(directions) - tmp_cntr
    if graph[i][j] == "#":
        return hash_cntr >= 5

def find_next_point(i: int, j: int, direction: Tuple[int, int], graph):
    x_off, y_off = i + direction[0], j + direction[1]
    while 0 <= x_off < len(graph) and 0 <= y_off < len(graph[i]):
        if graph[x_off][y_off] != ".":
            return graph[x_off][y_off]
        x_off += direction[0]
        y_off += direction[1]
    return -1

def fill_seats(graph: List[List[str]]) -> List[List[str]]:
    output = copy.deepcopy(graph)
    for i in range(len(graph)):
        for j in range(len(graph[i])):
            if graph[i][j] == "L":
                count = process_point(i, j, graph[i][j], graph)
                output[i][j] = "#" if count else graph[i][j]
            elif graph[i][j] == "#":
                count = process_point(i, j, graph[i][j], graph)
                output[i][j] = "L" if count else graph[i][j]
            else:
                output[i][j] = graph[i][j]
    return output

def fill_seats_2(graph):
    output = copy.deepcopy(graph)
    for i in range(len(graph)):
        for j in range(len(graph[i])):
            if graph[i][j] == "L":
                count = process_point_2(i, j, graph)
                output[i][j] = "#" if count else graph[i][j]
            elif graph[i][j] == "#":
                count = process_point_2(i, j, graph)
                output[i][j] = "L" if count else graph[i][j]
            else:
                output[i][j] = graph[i][j]
    return output

def same_graph(prev, graph):
    for i in range(len(graph)):
        for j in range(len(graph[i])):
            if graph[i][j] != prev[i][j]:
                return False
    return True

def count_occupied(graph):
    count = 0
    for i in range(len(graph)):
        for j in range(len(graph[i])):
            if graph[i][j] == "#":
                count += 1
    return count

if __name__ == "__main__":
    graph = read_and_parse_input("input.txt")
    prev = graph
    while True:
        graph = fill_seats_2(graph)
        if same_graph(prev, graph):
            print(count_occupied(graph))
            break
        prev = graph


import time
import serial
import serial.tools.list_ports
import threading

def send_servo(digree):
    sendData = f"SERVO={digree}\n"
    my_serial.write( sendData.encode() )

def send_buzzer(freq):
    sendData = f"BUZZER={freq}\n"
    my_serial.write( sendData.encode() )

def send_fnd(data):
    sendData = f"FND={data}\n"
    my_serial.write( sendData.encode() )

def serial_read_thread():
    while True:
        read_data = my_serial.readline()
        print(read_data.decode())

def main():
    try:
        while True:
            send_servo(0)
            send_buzzer(261)
            send_fnd(1234)
            time.sleep(1.0)

            send_servo(90)
            send_buzzer(293)
            send_fnd(5678)
            time.sleep(1.0)

            send_servo(180)
            send_buzzer(329)
            send_fnd(3.14)
            time.sleep(1.0)

            send_servo(90)
            send_buzzer(349)
            send_fnd(12.34)
            time.sleep(1.0)
    except KeyboardInterrupt:
        send_buzzer(0)

if __name__ == '__main__':

    ports = list(serial.tools.list_ports.comports())
    for p in ports:
        if 'Arduino Uno' in p.description:
            print(f"{p} 포트에 연결하였습니다.")
            my_serial = serial.Serial(p.device, baudrate=9600, timeout=1.0)
            time.sleep(2.0)

    t1 = threading.Thread(target=serial_read_thread)
    t1.daemon = True
    t1.start()

    main()

    my_serial.close()

한끝아파52 소스코드/02.파이썬코드/7_2.파이썬으로 아두이노 서보모터,피에조부저,FND 제어하기/main7_2_2.py


# -*- encoding: utf-8 -*-
from django.conf.urls import patterns, url
from rest_framework.routers import DefaultRouter
from .resources import (
    ServiceViewSet, AdvertViewSet, BookingViewSet
)

router = DefaultRouter()

router.register(r'service', ServiceViewSet)
router.register(r'advert', AdvertViewSet)
router.register(r'booking', BookingViewSet)

urlpatterns = patterns('',
)
urlpatterns += router.urls


# coding: utf-8
from __future__ import unicode_literals

import shutil
from tempfile import mktemp
import datetime

import mimetypes
from collections import OrderedDict

import tablib
from django.http import HttpResponse
from django.utils.encoding import smart_str, force_bytes

from django.views.generic.list import MultipleObjectMixin

from admin_view.utils.dt import to_aware
from admin_view.views.base import AdminTemplateView

class ReportFormViewMixin(MultipleObjectMixin):
    filter_class = None
    filename = 'Report.xlsx'

    def get_filter_class(self):
        return self.filter_class

    def get_filter(self, queryset=None):
        return self.get_filter_class()(
            self.request.GET or None,
            queryset=queryset or self.get_queryset(),
            view=self
        )

    def is_filtered(self):
        get = self.request.GET.copy()
        get.pop('_export', None)
        return bool(get)

    def get_queryset(self):
        if not self.is_filtered():
            return self.model.objects.none()
        return super().get_queryset()

    def get_columns(self, filter_form):
        fields = filter_form.get_enabled_fields()
        return fields

    def get_export_format(self):
        return self.request.GET.get('_export')

    def get_context_data(self, **kwargs):
        self.object_list = self.model.objects.none()

        context = super().get_context_data(**kwargs)

        filter_form = self.get_filter()
        filter_form.form.is_valid()
        columns = self.get_columns(filter_form)

        export_format = self.get_export_format()

        qs = filter_form.qs
        page = None

        if not export_format:
            paginator, page, qs, is_paginated = self.paginate_queryset(qs, page_size=100)

        export_data = self.get_export_data(qs, columns)

        context['form'] = filter_form
        context['export_data'] = export_data
        context['export_format'] = self.get_export_format()
        context['page'] = page
        return context

    def get_export_data(self, qs, columns):
        export_data = tablib.Dataset(headers=[label for key, label in columns] + ['_instance'])
        for instance in qs:
            export_data.append(self.get_export_data_row(instance, columns) + [instance])
        return export_data

    def get_export_data_row(self, instance, columns):
        row = [self.extract_field(instance, key) for key, label in columns]
        return row

    def extract_field(self, instance, key):
        func = getattr(self, 'extract_' + key, None)
        if func:
            value = func(instance)
        else:
            if hasattr(instance, 'get_%s_display' % key):
                value = getattr(instance, 'get_%s_display' % key)()
            else:
                value = getattr(instance, key)
        if value is None:
            value = ''
        if isinstance(value, datetime.datetime):
            value = to_aware(value).strftime('%Y-%m-%d %H:%M:%S')
        return value

    def get_xlsx_file(self, request, output_file, **kwargs):
        context = self.get_context_data(**kwargs)
        export_format = context['export_format']
        export_dataset = context['export_data']
        del export_dataset[export_dataset.headers[-1]]

        with open(output_file, 'wb') as f:
            f.write(getattr(export_dataset, export_format))

        return

    def get_filename(self):

        return self.filename

    def get(self, request, *args, **kwargs):
        export_format = self.get_export_format()
        if export_format:
            from multiprocessing import Process
            output_file = mktemp(suffix='.' + export_format)
            try:
                p = Process(target=self.get_xlsx_file,
                            args=(request,),
                            kwargs={'output_file': output_file}
                            )
                p.start()
                p.join()
                filename = self.get_filename()
                content_type = mimetypes.guess_type(filename)[0]
                response = HttpResponse(
                    open(output_file, 'rb').read(),
                    content_type=content_type)
                response['Content-Disposition'] = b'attachment; filename="%s"' % force_bytes(
                    filename)
                return response
            finally:
                shutil.rmtree(output_file, ignore_errors=True)

        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

class ReportFormView(ReportFormViewMixin, AdminTemplateView):
    template_name = "admin/custom_view/report.html"