#!/usr/bin/env python

from __future__ import print_function

import csv
import os
import logging
import re
import time
import urllib2
import yaml

import apt
import apt_pkg
import numpy as np

import buildfarm.apt_root
from buildfarm.ros_distro import debianize_package_name,\
    undebianize_package_name
from rospkg.distro import distro_uri

version_rx = re.compile(r'[0-9.-]+[0-9]')

class PackageVersion(object):
    """
    A class to store package versions.
    """
    def __init__(self, name, rosdistro):
        self._name = name
        self.debian_name = debianize_package_name(rosdistro, name)
        self._versions = {}

    def add_version(self, repo, distro_arch, version_string):
        self._versions[(repo, distro_arch)] = version_string

    def get_version(self, repo, distro_arch):
        if (repo, distro_arch) in self._versions:
            return self._versions[(repo, distro_arch)]
        else:
            return None

    def _pp_struct_(self):
        return {'name': self._name,
                'debian_name': self.debian_name,
                'versions': self._versions}

class VersionCache(object):
    def __init__(self, rosdistro):
        self._cache = {}
        self._rosdistro = rosdistro
        self._bootstrap_from_rosdistro(rosdistro)
        self._primary_arch = None  # fill with the first used arch

    def add(self, name, repo, distro_arch, version_string):
        if name not in self._cache:
            self._cache[name] = PackageVersion(name, self._rosdistro)
        self._cache[name].add_version(repo, distro_arch, version_string)

    def get_version(self, name, repo, distro_arch):
        if not name in self._cache:
            return None
        return self._cache[name].get_version(repo, distro_arch)

    def list_debian_names(self):
        return [p.debian_name for p in self._cache.values()]

    def pprint(self):
        import pprint
        pp = pprint.PrettyPrinter()
        for k, v in self._cache.items():
            print("%s:" % (k))
            pp.pprint(v._pp_struct_())

    def _bootstrap_from_rosdistro(self, rosdistro):
        if rosdistro == 'fuerte':
            from buildfarm.ros_distro_fuerte import Rosdistro
        else:
            from buildfarm.ros_distro import Rosdistro
        rd = Rosdistro(rosdistro)
        for name in rd.get_package_list():
            self.add(name, 'rosdistro', 'wet',
                     rd.get_version(name, full_version=True))
        if rosdistro not in ['fuerte', 'groovy', 'hydro', 'indigo']:
            return
        dry_yaml = yaml.load(urllib2.urlopen(distro_uri(rosdistro)))
        for name, d in dry_yaml['stacks'].items():
            if name == '_rules':
                continue
            self.add(name, 'rosdistro', 'dry', d.get('version'))
        for variant in dry_yaml['variants']:
            if len(variant) != 1:
                logging.warn("Not length 1 dict in variant %s: skipping" % \
                                 variant)
                continue
            name = variant.keys()[0]
            self.add(name, 'rosdistro', 'variant', '1.0.0')

    def fill_debian_versions(self, rootdir, repo, distro, arch):
        """
        Call this after populating the rosdistro names, and it will
        try to fill in the debian versions.
        """
        distro_arch = "%s_%s" % (distro, arch)
        if not self._primary_arch:
            self._primary_arch = arch

        logging.debug("building Cache")
        aptcache = get_apt_cache(get_repo_cache_dir_name(rootdir,
                                                         repo,
                                                         distro_arch))
        logging.debug("iterating cache length %d" % len(self._cache))

        for p in self._cache.values():
            # only detect source for one arch
            if self._primary_arch == arch:
                self.add(p._name, repo, distro + "_source",
                         detect_source_version(p.debian_name))

            # look for binaries
            if p.debian_name in aptcache:
                apt_p = aptcache[p.debian_name]
                version_obj = getattr(apt_p, 'candidate', None)
                version = getattr(version_obj, 'version', None)
                self.add(p._name, repo, distro_arch, version)

    def get_distro_versions(self):
        """
        Return the list of rosdistro versions and distro type (dry, wet)
        return np.array( ( name, version, wet == True), ... ])
        """
        output = []
        for p in self._cache.values():
            version = p.get_version('rosdistro', 'wet')
            if version:
                output.append((p._name, version, 'wet'))
            version = p.get_version('rosdistro', 'variant')
            if version:
                output.append((p._name, version, 'variant'))
            version = p.get_version('rosdistro', 'dry')
            if version:
                output.append((p._name, version, 'dry'))
        return np.array(output)

def get_repo_da_caches(rootdir, ros_repo_names, da_strs):
    '''
    Returns [(repo_name, da_str, cache_dir), ...]

    For example, get_repo_da_caches('/tmp/ros_apt_caches', \
                   ['ros', 'shadow-fixed'], ['quantal_i386'])
    '''
    return [(ros_repo_name, da_str,
             get_repo_cache_dir_name(rootdir, ros_repo_name, da_str))
            for ros_repo_name in ros_repo_names
            for da_str in da_strs]

def get_apt_cache(dirname):
    c = apt.Cache(rootdir=dirname)
    c.open()
    return c

def get_ros_repo_names(ros_repos):
    return ros_repos.keys()

def get_da_strs(distro_arches):
    distros = set()
    output = []
    for d, a in distro_arches:
        if d not in distros:
            output.append(d + '_source')
            distros.add(d)
        output.append(get_dist_arch_str(d, a))
    return output

def get_distro_arches(arches, rosdistro):
    if rosdistro == 'fuerte':
        from buildfarm.ros_distro_fuerte import get_target_distros
    else:
        from buildfarm.ros_distro import get_target_distros

    distros = get_target_distros(rosdistro)
    return [(d, a) for d in distros for a in arches]

def make_versions_table(version_cache, ros_pkgs_table, repo_name_da_to_pkgs,
                        da_strs, repo_names, rosdistro):
    '''
    Returns an in-memory table with all the information that will be displayed:
    ros package names and versions followed by debian versions for each
    distro/arch.
    '''
    left_columns = [('name', object), ('version', object), ('wet', object)]
    right_columns = [(da_str, object) for da_str in da_strs]
    columns = left_columns + right_columns

    debian_names = version_cache.list_debian_names()

    non_ros_pkg_names = set([])
    ros_pkg_names = set(debian_names)
    for pkgs in repo_name_da_to_pkgs.values():
        pkg_names = set([pkg.name for pkg in pkgs])
        non_ros_pkg_names |= pkg_names - ros_pkg_names

    table = np.empty(len(ros_pkgs_table) + len(non_ros_pkg_names),
                     dtype=columns)

    for i, (name, version, wet) in enumerate(ros_pkgs_table):
        table['name'][i] = name
        table['version'][i] = version
        table['wet'][i] = wet
        for da_str in da_strs:
            table[da_str][i] = add_version_cell(version_cache,
                                                name,
                                                repo_names,
                                                da_str)

    i = len(ros_pkgs_table)
    for pkg_name in non_ros_pkg_names:
        undebianized_pkg_name = undebianize_package_name(rosdistro, pkg_name)
        table['name'][i] = undebianized_pkg_name
        table['version'][i] = ''
        table['wet'][i] = 'unknown'
        for da_str in da_strs:
            table[da_str][i] = add_version_cell(version_cache,
                                                undebianized_pkg_name,
                                                repo_names, da_str)
        i += 1

    return table

def add_version_cell(version_cache, pkg_name, repo_names, da_str):
    versions = []
    for repo_name in repo_names:
        v = version_cache.get_version(pkg_name, repo_name, da_str)
        v = str(v)
        v = strip_version_suffix(v)
        versions.append(v)
    return '|'.join(versions)

def strip_version_suffix(version):
    """
    Removes trailing junk from the version number.

    >>> strip_version_suffix('')
    ''
    >>> strip_version_suffix('None')
    'None'
    >>> strip_version_suffix('1.9.9-0quantal-20121115-0529-+0000')
    '1.9.9-0'
    >>> strip_version_suffix('1.9.9-foo')
    '1.9.9'
    """
    match = version_rx.search(version)
    return match.group(0) if match else version

def detect_source_version(source_name):
    """
    Detect if the source package is available on the server and return
    the version, else None
    """
    src = apt_pkg.SourceRecords()
    source_lookup = src.lookup(source_name)
    if not source_lookup:
        #print("Missed %s" % source_name)
        return None
    else:
        src_version = strip_version_suffix(src.version)
        #print("Source %s %s" % (source_name, src_version))
        return src_version

def get_dist_arch_str(d, a):
    return "%s_%s" % (d, a)

def get_repo_cache_dir_name(rootdir, ros_repo_name, dist_arch):
    return os.path.join(rootdir, ros_repo_name, dist_arch)

def build_repo_cache(dir_, ros_repo_name, ros_repo_url,
                     distro, arch, update=True):
    logging.debug('Setting up an apt directory at %s', dir_)
    repo_dict = {ros_repo_name: ros_repo_url}
    buildfarm.apt_root.setup_apt_rootdir(dir_, distro, arch,
                                         additional_repos=repo_dict)
    logging.info('Getting a list of packages for %s-%s', distro, arch)
    cache = apt.Cache(rootdir=dir_)
    cache.open()
    if update:
        cache.update()
        # Have to open the cache again after updating.
        cache.open()

def get_pkgs_from_apt_cache(cache_dir, substring):
    cache = apt.Cache(rootdir=cache_dir)
    cache.open()
    return [cache[name] for name in cache.keys() if name.startswith(substring)]

def build_version_cache(rootdir, rosdistro, distro_arches,
                        ros_repos, update=True):
    version_cache = VersionCache(rosdistro)
    for repo in ros_repos:
        for (d, a) in distro_arches:
            da_str = "%s_%s" % (d, a)
            build_repo_cache(get_repo_cache_dir_name(rootdir,
                                                     repo, da_str),
                             repo,
                             ros_repos[repo],
                             d, a, update)
            logging.debug("Filling debian version for %s %s", repo, da_str)
            version_cache.fill_debian_versions(rootdir, repo, d, a)

    return version_cache

def render_csv(version_cache, rootdir, outfile, rosdistro,
               distro_arches, ros_repos):
    distros = {}

    for (d, a) in distro_arches:
        if not d in distros:
            distros[d] = []
        distros[d].append(a)
    das = []
    for d in distros:
        for a in distros[d]:
            das.append((d, a))
    da_strs = get_da_strs(das)
    ros_repo_names = get_ros_repo_names(ros_repos)
    repo_da_caches = get_repo_da_caches(rootdir, ros_repo_names, da_strs)

    ros_pkgs_table = version_cache.get_distro_versions()

    # Get the version of each Debian package in each ROS apt repository.
    repo_name_da_to_pkgs = dict(((repo_name, da_str),
                                 get_pkgs_from_apt_cache(cache, 'ros-%s-' % \
                                                             rosdistro))
                                for repo_name, da_str, cache in repo_da_caches)

    # Make an in-memory table showing the latest deb version for each package.
    t = make_versions_table(version_cache,
                            ros_pkgs_table,
                            repo_name_da_to_pkgs,
                            da_strs,
                            ros_repos.keys(),
                            rosdistro)

    with open(outfile, 'w') as fh:
        # Output CSV from the in-memory table
        w = csv.writer(fh)
        w.writerow(t.dtype.names)
        for row in t:
            w.writerow(row)

def transform_csv_to_html(data_source, metadata_builder,
                          rosdistro, start_time):
    reader = csv.reader(data_source, delimiter=',', quotechar='"')
    rows = [row for row in reader]

    header = rows[0]
    rows = rows[1:]

    html_head = make_html_head(rosdistro, start_time)

    metadata_columns = [None] * 3 + [metadata_builder(c) for c in header[3:]]
    header = [format_header_cell(header[i],
                                 metadata_columns[i]) \
                  for i in range(len(header))]

    # count non-None rows per (sub-)column
    counts = [[]] * 3 + [[0] * 3 for _ in range(3, len(header))]
    for row in rows:
        for i in range(3, len(counts)):
            versions = get_cell_versions(row[i])
            for j in range(0, len(versions)):
                if versions[j] != 'None':
                    counts[i][j] += 1

    rows = [format_row(r, metadata_columns) for r in rows]
    body = make_html_legend()
    body += make_html_table(header, counts, rows)

    return make_html_doc(html_head, body)

def format_header_cell(cell, metadata):
    if metadata and 'column_label' in metadata:
        cell = metadata['column_label']
    else:
        cell = cell[0].upper() + cell[1:]
    return cell

def format_row(row, metadata_columns):
    latest_version = row[1]
    public_changing_on_sync = [False] * 3 + \
        [is_public_changing_on_sync(c) for c in row[3:]]
    # Flag if this is dry or a variant so as not to show sourcedebs as red
    no_source = row[2] in ['variant', 'dry']
    # ignore source columns for dry/variant when deciding of columns are homogeneous
    diff_columns = [c for i, c in enumerate(row) if i > 2 and (not no_source or i % 3)]
    has_diff_between_rosdistros = len(set(diff_columns)) > 1

    # urls for each building repository column
    metadata = [None] * 3 + [md for md in metadata_columns[3:]]
    if row[2] == 'dry':
        # disable links for dry source columns
        metadata = [(c if i < 3 or i % 3 else None) for i, c in enumerate(metadata)]
    elif row[2] in ['unknown', 'variant']:
        # disable all links for unknown and variant rows
        metadata = [None for _ in range(len(metadata))]
    job_urls = [md['job_url'].format(pkg=row[0].replace('_', '-')) \
                    if md else None for md in metadata]
    # only pass no_source if this is a sourcedeb entry
    row = row[:3] + [format_versions_cell(row[i],
                                          latest_version,
                                          job_urls[i],
                                          public_changing_on_sync[i],
                                          no_source and i % 3 == 0) \
                         for i in range(3, len(row))]
    if has_diff_between_rosdistros:
        row[0] += ' diff'

    return row

def is_public_changing_on_sync(cell):
    versions = get_cell_versions(cell)
    return versions[1] != versions[2]

def get_cell_versions(cell):
    return cell.split('|')

def format_versions_cell(cell, latest_version, url=None,
                         public_changing_on_sync=False,
                         no_source=False):
    versions = get_cell_versions(cell)
    repos = ['building', 'shadow-fixed', 'ros/public']
    search_suffixes = ['1', '2', '3']
    # set the latest_version to None if no package expected
    if no_source:
        latest_version = None
    cell = ''.join([format_version(v,
                                   latest_version,
                                   r,
                                   s,
                                   versions[-1],
                                   url if r == 'building' else None)\
                        for v, r, s in zip(versions, repos, search_suffixes)])

    if public_changing_on_sync:
        cell += 'sync'

    return cell

def format_version(version, latest, repo, search_suffix,
                   public_version, url=None):
    label = '%s: %s' % (repo, version)
    if latest:
        color = {'None': 'pkgMissing',
                 latest: 'pkgLatest'}.get(version, 'pkgOutdated')
        # use reasonable names (even if invisible) to be searchable
        order_value = {'None': '5 red',
                       latest: '1 green'}.get(version, '3 blue')
    else:
        color = {'None': 'pkgIgnore'}.get(version, 'pkgObsolete')
        # use reasonable names (even if invisible) to be searchable
        order_value = {'None': '2 gray'}.get(version, '4 yellow')
    order_value += search_suffix
    if repo != 'ros/public' and is_regression(version, public_version):
        order_value += ' regression' + search_suffix
    if url:
        order_value = '%s' % (url, order_value)
    return make_square_div(label, color, order_value)

def is_regression(version, public_version):
    # public has a package and specific repo doesn't
    return public_version != 'None' and version == 'None'

def make_square_div(label, color, order_value):
    return '
%s
' % \
        (color, label, order_value)

def make_html_head(rosdistro, start_time):
    rosdistro = rosdistro[0].upper() + rosdistro[1:]
    # Some of the code here is taken from a datatables example.
    return '''
<title>ROS %s - build status page - %s</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>

''' % (rosdistro, time.strftime('%Y-%m-%d %H:%M:%S %Z', start_time))

def make_html_legend():
    definitions = [
        ('wet', 'catkin'),
        ('dry', 'rosbuild'),
        ('1 2 3', 'The apt repos (1) building, (2) shadow-fixed, (3) ros/public'),
        (' ', 'same version'.replace(' ', ' ')),
        (' ', 'different version'.replace(' ', ' ')),
        (' ', 'missing'.replace(' ', ' ')),
        (' ', 'obsolete'.replace(' ', ' ')),
        (' ', 'intentionally missing'.replace(' ', ' '))
    ]
    definitions = ['
%s: %s
' % (k, v) for (k, v) in definitions]
    return '''\

    %s

''' % ('\n'.join(definitions))

def make_html_table(columns, counts, rows):
    '''
    Returns a string containing an HTML-formatted table, given a header and some
    rows.

    >>> make_html_table(header=['a'], rows=[[1], [2]])
    '
\\n
a
\\n
1
\\n
2
\\n
\\n'

    '''
    headers = []
    for i in range(len(columns)):
        headers.append('%s
%s' % (columns[i], ''.join(['%d' % (i + 1, v) for i, v in enumerate(counts[i])])))
    header_str = '
' + ''.join('%s	' % c for c in headers) + '
'
    rows_str = '\n'.join('
' + ' '.join('%s	' % c for c in r) + '
' for r in rows)
    footer_str = '
' + ''.join('%s	' % (c if i != 2 else '') for i, c in enumerate(columns)) + '
'
    return '''\

        %s

        %s

        %s

''' % (header_str, footer_str, rows_str)

def make_html_doc(head, body):
    '''
    Returns the contents of an HTML page, given a title and body.
    '''
    return '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

        %(head)s

        %(body)s

''' % locals()


# -*- coding: utf-8 -*-
"""
Created on Mon Dec 19 00:44:45 2022

@author: mossando
"""
from sklearn.cluster import KMeans
import numpy as np

def criterio_f(dedo,lim = 0.45,lim1_2 = 0.08 ,lim2 = 0.05):

 d = [] # Distorsión

 # Cálculo de Distorsión en k = {1,2}
 k=1
 kmeans = KMeans(n_clusters = k)
 kmeans.fit(dedo)
 d.append(kmeans.inertia_)
 k += 1
 kmeans = KMeans(n_clusters = k).fit(dedo)
 d.append(kmeans.inertia_)

 while True:

   if k <= 4:# Criterio indice CVA
     if d[k-1]/d[k-2] < lim:
       k += 1
       kmeans = KMeans(n_clusters = k).fit(dedo)
       d.append(kmeans.inertia_)
       if d[k-1]/d[k-2] > lim + lim1_2:
         break
     else:
       k += 1
       kmeans = KMeans(n_clusters = k).fit(dedo)
       d.append(kmeans.inertia_)

   if k >4:# Criterio indice CPPI
     if np.diff(d)[k-2]/(d[1]-d[0])  < lim2:
       break
     k += 1
     kmeans = KMeans(n_clusters = k).fit(dedo)
     d.append(kmeans.inertia_)
 return(k - 1)


#!/home/fengxiang/anaconda3/envs/wrfout/bin/python
# -*- encoding: utf-8 -*-
'''
Description:
读取wrfout数据中的降水
将wrfout数据中的降水集合成一个文件
# TODO 将wrfout的格点数据插值为站点数据
-----------------------------------------
Time             :2021/09/09 10:53:08
Author           :Forxd
Version          :1.0
'''

# %%
import xarray as xr
import os
import xesmf as xe
import numpy as np
import wrf
import netCDF4 as nc
from baobao.interp import regrid_xesmf
# from baobao.coord_transform import xy_ll
# import wrf

# %%

# %%
def combine_rain(path):
    """
    由于wrfout数据的降水是累计降水，
    这里将它变为逐小时降水,同时进行合并
    又由于wrfout数据的坐标是x,y格点上的，
    通过wrf-python 库将其转为不规则的latlon格点坐标

    Args:
        path ([type]): 包含有wrfout数据的文件夹路径

    Returns:
        rain[DataArray] : 多时次聚合后的降水
    """

    fl_list = os.popen('ls {}/wrfout_d04*'.format(path))  # 打开一个管道
    fl_list = fl_list.read().split()
    dds_list = []
    r = 0
    for fl in fl_list:
        print(fl[-18:])
        ds = xr.open_dataset(fl)
        da = ds['RAINNC']+ds['RAINC']+ds['RAINSH']-r
        r = (ds['RAINNC']+ds['RAINC']+ds['RAINSH']).values.round(1)

        dda = da.squeeze()  # 该是几维的就是几维的
        dc = dda.rename({'XLAT':'lat', 'XLONG':'lon', 'XTIME':'time'})
        dds_list.append(dc)
    da_concate = xr.concat(dds_list, dim='time') # 原始的， 未经坐标变化的降水
    rain = da_concate.round(1)
    return rain

# %%
# path = '/mnt/zfm_18T/fengxiang/HeNan/Data/1912_900m/'
# rain = combine_rain(path)
# rain

# %%
# flnm_obs = '/mnt/zfm_18T/fengxiang/HeNan/Data/OBS/rain_station.nc'
# 特定区域范围内观测的站点数据
# da_obs = xr.open_dataarray(flnm_obs)
# wrf输出后转化的latlon格点数据

## 构建插值区域
# %%
# cc = da_obs.isel(time=0)
# sta = cc.id.values
# wrfin = nc.Dataset('/mnt/zfm_18T/fengxiang/HeNan/Data/1912_900m/wrfout_d04_2021-07-19_12:00:00')
# x, y = wrf.ll_to_xy(wrfin, cc.lat, cc.lon)
# rain_station = rain.sel(south_north=y, west_east=x)
# rain_station

# %%
# rain_station.drop_vars(['latlon_coord'])
# rain_station.to_netcdf('ttt.nc')

# lon = xr.DataArray(cc.lon.values, coords=[sta], dims=['sta'])
# lat = xr.DataArray(cc.lat.values, coords=[sta], dims=['sta'])
# ## 插值
# # rr = da_wrf.interp(lon=lon, lat=lat, method='nearest').round(1)
# rr = da_wrf.interp(lon=lon, lat=lat, method='linear').round(1)
# xr.DataArray.interp

# %%
def grid2station(flnm_obs, flnm_wrf, flnm_wrfout='/mnt/zfm_18T/fengxiang/HeNan/Data/1912_900m/wrfout_d04_2021-07-19_12:00:00'):
    """将格点数据插值为站点数据

    Args:
        flnm_obs ([type]): 多时次聚合的站点数据
        flnm_wrf ([type]): 多时次聚合的wrfout数据, 某个变量的，例如RAINNC
        flnm_wrfout ([type]): 原始的wrfout数据

    Returns:
        da_station: 从wrf数据插值出来的和观测经纬度一致的格点数据
    """

    print("插值数据到站点")
    # 特定区域范围内观测的站点数据
    da_obs = xr.open_dataarray(flnm_obs)
    # wrf输出后聚合到一起的多时间维度数据
    da_wrf = xr.open_dataarray(flnm_wrf)

    cc = da_obs.isel(time=0)
    # sta = cc.id.values
    wrfin = nc.Dataset(flnm_wrfout)
    x, y = wrf.ll_to_xy(wrfin, cc.lat, cc.lon)
    da_station = da_wrf.sel(south_north=y, west_east=x)
    da_station = da_station.drop_vars(['latlon_coord'])
    da_station = da_station.rename({'idx':'sta'})
    # print(da_station)

    return da_station

# %%
def regrid_latlon(flnm_rain, area):
    """
    将combine得到的数据()，
    插值到格距较粗的latlon格点上,
    也包含有投影转换的需求
    插值到latlon格点上
    将二维的latlon坐标水平插值到一维的latlon坐标上
    """
    print("插值数据到网格点")
    ds = xr.open_dataset(flnm_rain)
    ds_out = regrid_xesmf(ds, area, rd=1)
    return ds_out

def save_one(path_main = '/mnt/zfm_18T/fengxiang/HeNan/Data/1900_90m/'):
    """处理一个模式的数据

    Args:
        path_main (str, optional): [description]. Defaults to '/mnt/zfm_18T/fengxiang/HeNan/Data/1900_90m/'.
    """

    path_dic = {
        'path_main':path_main,  # 模式数据文件夹
        'path_wrfout':'/mnt/zfm_18T/fengxiang/HeNan/Data/1900_90m/wrfout_d04_2021-07-19_00:00:00', # 原始的一个wrfout数据，获得投影需要
        'path_rain_wrf_grid':path_main+'rain.nc', # 原始降水数据存储路径+文件名
        'path_rain_wrf_latlon':path_main+'rain_latlon.nc',  # 插值到latlon之后的文件名
        'path_rain_wrf_station':path_main+'rain_station.nc',  # 插值到站点之后的文件名
        'path_rain_obs_station':'/mnt/zfm_18T/fengxiang/HeNan/Data/OBS/rain_station.nc', # 站点降水
    }
    area = {
        'lon1':110.5,
        'lon2':116,
        'lat1':32,
        'lat2':36.5,
        'interval':0.125,
    }

    ## 合并数据
    da = combine_rain(path_main)
    da.to_netcdf(path_dic['path_rain_wrf_grid'])

    ## 降低分辨率和转换投影
    # regrid_rain_model(path_dic, area)
    da1 = regrid_latlon(path_dic['path_rain_wrf_grid'], area)
    da1.to_netcdf(path_dic['path_rain_wrf_latlon'])

    ## 插值到站点
    da2 = grid2station(path_dic['path_rain_obs_station'], path_dic['path_rain_wrf_grid'],path_dic['path_wrfout'])
    da2.to_netcdf(path_dic['path_rain_wrf_station'])
    pass

def dual():
    """处理多个模式的数据
    """
    pass
    model_list = ['1900_90m', '1900_900m','1912_900m', '1912_90m',]
    for model in model_list:
        path_main = '/mnt/zfm_18T/fengxiang/HeNan/Data/'+model+'/'
        save_one(path_main)

if __name__ == '__main__':

    pass
    # main()
    # save_one()
    dual()


#!/usr/bin/env python3

import sys
import xml.etree.ElementTree as ET

if len(sys.argv) != 3:
    print(f"Usage: {sys.argv[0]} <infile> <outfile>")
    exit(1)

infile_path = sys.argv[1]
outfile_path = sys.argv[2]

tree = ET.parse(infile_path)
root = tree.getroot()

for child in root:
    if child.tag == "link":
        found_intertial = False
        found_collision = False
        for link_element in child:
            if link_element.tag == "inertial":
                found_intertial = True
            elif link_element.tag == "collision":
                found_collision = True
        if found_intertial and (not found_collision):
            for link_element in child:
                if link_element.tag == "inertial":
                    child.remove(link_element)
                    print(f"removed inertial element for link: {child.attrib}")

tree.write(outfile_path)


from django.conf import settings
from django.test import TestCase

# Local imports
from .models import Project, Language
from .templatetags.custom_filters import getsubdivisions, getrange, stripmarkup, getlanguages

class CustomTemplateFilterTests(TestCase):
    def test_stripmarkup(self):
        HTML = '
This is my github, go on and follow me.'
        STRIPPED_TEXT = 'This is my github, go on and follow me.'
        self.assertEqual(stripmarkup(HTML), STRIPPED_TEXT)

    def test_getsubdivisions(self):
        self.assertEqual(getsubdivisions(range(1, 8), 3), [[1, 2, 3], [4, 5, 6], [7]])
        self.assertEqual(getsubdivisions(range(1, 8), "random garbage value"), [[1, 2, 3], [4, 5, 6], [7]])
        with self.assertRaises(ValueError):
            getsubdivisions(2134, "bullshit value")

    def test_getrange(self):
        self.assertEqual(getrange(5), range(1, 6))
        with self.assertRaises(ValueError):
            getrange("crap")

    def test_getlanguages(self):
        lang1 = Language.objects.create(name='Java')
        lang2 = Language.objects.create(name='Python')
        lang3 = Language.objects.create(name='PHP')
        p = Project.objects.create(
            name='Coding Portfolio',
            description='Programming portfolio for lazy people like me',
        )
        p.languages.add(lang1, lang2)
        self.assertEqual(getlanguages(""), [lang.name for lang in p.languages.all()])


# coding=utf8
"""
事故应急池计算
"""
import random
import json
import os

from conf.path import json_exam_path

with open(os.path.join(json_exam_path, "rainfalls.json"), "r", encoding="utf-8") as fp:
    rainfalls = json.load(fp)

# ***** V1: 收集系统范围内发生事故的物料量, m^3 ***** #
def setV1():
    # 铁路槽车容量, m3
    railway_tanker_capacity = [50, 60]
    # 汽车罐车, m3
    car_tanker_capacity = [5, 10, 15, 20, 25, 30]
    # 储罐容量, m3
    storage_tanker_capacity = [1, 3, 5, 10, 15, 20, 25, 30, 40, 50, 80, 100, 150]
    # 反应器或中间储罐, m3
    reactor_capacity = [1, 2, 3, 4, 5]
    types = range(0, 4)
    capacities = [railway_tanker_capacity, car_tanker_capacity, storage_tanker_capacity, reactor_capacity]
    type_index = random.choice(types)
    capacity = random.choice(capacities[type_index])
    # V1, m3
    V1 = capacity
    return [V1, type_index]

# ***** V2: 发生事故的储罐、装置或铁路、汽车装卸区的消防水量, m^3 ***** #
def setV2(V1):
    # 给水流量, L/s
    if V1 >= 50:
        flow_range = [200 + i * 10 for i in range(11)]
        area_range = [i * 1000 for i in range(20, 31)]
    elif V1 >= 20:
        flow_range = [100 + i * 10 for i in range(11)]
        area_range = [i * 1000 for i in range(15, 21)]
    else:
        flow_range = [60 + i * 10 for i in range(4)]
        area_range = [i * 1000 for i in range(10, 16)]
    # 厂区面积, m2
    area = random.choice(area_range)
    # 火灾延续时间, h
    duration_range = range(3, 6)
    # 流量, L/s
    flow = random.choice(flow_range)
    # t, h
    duration = random.choice(duration_range)
    # V2, m3
    V2 = flow * duration * 3600 / 1000
    return [round(V2, 2), flow, duration, area]

# ***** V3: 发生事故时可以转输到其他储存或处理设施的物料量, m^3 ***** #
def setV3(V1):
    # 这里只考虑围堰的情况, m3
    cofferdam = random.choice([True, False])
    if cofferdam:
        V3 = V1
    else:
        V3 = 0
    return [V3, cofferdam]

# ***** V4: 发生事故时仍必须进入该收集系统的生产废水量, m^3 ***** #
def setV4():
    # 这里假定发生事故时停止生产, m3
    V4 = 0
    return V4

# ***** V5: 发生事故时仍可能进入该收集系统的降雨量, m^3 ***** #
def setV5(area):
    # 降雨数据
    location = random.choice(rainfalls)
    city = location["location"]
    rainfall_steps = int((location["rainfall"][1] - location["rainfall"][0]) / 10)
    rainfall_range = [location["rainfall"][0] + i * 10 for i in range(rainfall_steps + 1)]
    days_steps = location["days"][1] - location["days"][0]
    days_range = [location["days"][0] + i for i in range(days_steps + 1)]
    # 年降雨量, mm
    rainfall = random.choice(rainfall_range)
    # 天数
    days = random.choice(days_range)
    # V5, m3
    V5 = 10 * (rainfall / days) * area / (10 ** 4)
    return [round(V5, 2), city, rainfall, days]

def setPoolQuestion(seed=None):
    """事故应急池计算"""
    # 设置随机数种子
    if seed:
        random.seed(seed)
    V1, type_index = setV1()
    V2, flow, duration, area = setV2(V1=V1)
    V3, cofferdam = setV3(V1=V1)
    V4 = setV4()
    V5, city, rainfall, days = setV5(area=area)
    V = round(V1 + V2 - V3 + V4 + V5, 2)
    question = f"现有位于{city}的某化工厂，厂房面积${area}m^3$，厂内储存有可燃液体，并运行着相关的生产工艺。\n某天，"
    if type_index == 0:
        question += f"该工厂的卸车区正在进行着装卸工作，一容积为${V1}m^3$的满载的槽车发生可燃液体泄露起火事故。"
    elif type_index == 1:
        question += f"该工厂的卸车区正在进行着装卸工作，一容积为${V1}m^3$的满载的罐车发生可燃液体泄露起火事故。"
    elif type_index == 2:
        question += f"厂内一容积为${V1}m^3$装有可燃液体的满载的储罐发生泄露起火事故。"
    else:
        question += f"该工厂生产车间一容积为${V1}m^3$的满载的可燃液体反应釜发生泄露起火事故。"
    question += f"\n该工厂立即启动应急预案，开展消防工作，并以${flow}L/s$的消防水流量进行灭火以及降温。\n${duration}h$后，火势彻底扑灭，消防给水停止。"
    question += f"\n灭火过程中，发生泄漏的罐体内物料已全部流出，但由于该工厂设有事故应急池，消防废水全部收集于应急池内，"
    if cofferdam:
        question += "并且发生泄漏事故的区域设有符合规范的围堰，泄露物无向外扩散的情况，"
    else:
        question += f"并且泄漏物也全部进入了应急池，"
    question += "该起事故未造成环境污染。"
    question += "\n假设本次事故发生后，该工厂立刻停止了生产工艺，停止产生生产废水。"
    question += "处理事故时，未有其他废水或者其他泄漏物进入事故应急池。"
    question += "事故结束后，事故应急池内废水也未外溢。"
    question += f"\n已知该工厂所在地区年降雨量为${rainfall}mm$，降雨天数为{days}天。"
    question += "\n试计算该工厂的事故应急池的容量最小可能是多少？\n（计算中间数据以及最终结果均保留小数点后两位，单位为$m^3$）"
    calculation_process = "解析：\n"
    calculation_process += f"（1）由于物料满载且全部泄露，则发生事故的物料量即发生泄露的罐体容积：\n$$\nV_1={V1}m^3\n$$\n"
    calculation_process += f"（2）然后确定消防水量：\n$$\nV_2={flow}\\times{duration}\\times3600/1000={V2}m^3\n$$\n"
    if cofferdam:
        calculation_process += f"（3）由于设置有围堰，泄漏物将全部截流于围堰内：\n$$\nV_3={V3}m^3\n$$\n"
    else:
        calculation_process += f"（3）由于泄漏物全部进入了应急池：\n$$\nV_3={V3}m^3\n$$\n"
    calculation_process += f"（4）并且事故发生后，该工厂停止了生产工艺，无生产废水产生：\n$$\nV_4={V4}m^3\n$$\n"
    calculation_process += f"（5）根据厂区面积以及该地区的降雨数据：\n$$\nV_5=(10\\times{rainfall}/{days})\\times{area}/10^4={V5}m^3\n$$\n"
    calculation_process += f"（6）综上，该工厂事故应急池最小容积为：\n$$\nV={V1}+{V2}-{V3}+{V4}+{V5}={V}m^3\n$$"
    return question, calculation_process, V


"""Util for testing OCR engines with filters and cache their results"""
import os
from dataclasses import dataclass
from pickle import dump, load
from typing import List

# ???
# pylint: disable=no-name-in-module
from cv2 import imread, getTickCount, getTickFrequency
from src.filter import Filter
from src.dataset import Dataset
from src.reader import OCRReader

@dataclass
class TestSettings:
    """This class contains all the settings for a test."""

    reader: OCRReader
    filters: List[Filter]  # list of filters to apply to image in order

    def __str__(self) -> str:
        filters_string = ", ".join([str(filter) for filter in self.filters])
        return f"{self.reader}: {filters_string}"

@dataclass
class SingleTestResult(TestSettings):
    """This class contains the result of a single test."""

    time: float
    success: float
    result_text: str
    expected_text: str

@dataclass
class MultiTestResult:
    """This class contains the result of multiple tests."""

    results: List[SingleTestResult]
    test_settings: TestSettings

    total_time: float = 0
    total_success: float = 0

    average_time: float = 0
    average_success: float = 0

    def __post_init__(self):
        # calculate average time and success
        self.total_time = 0
        self.total_success = 0

        for result in self.results:
            self.total_time += result.time
            self.total_success += result.success

        self.average_time = self.total_time / len(self.results)
        self.average_success = self.total_success / len(self.results)

    def __str__(self) -> str:
        return self.test_settings.__str__()

class TestCase:
    """This class contains a single test case."""

    __test__ = False

    def __init__(
        self, test_settings: TestSettings, image_path: str, expected_text: str
    ):
        self.test_settings = test_settings
        self.image_path = image_path
        self.expected_text = expected_text

    def test(self) -> SingleTestResult:
        """This method will test the OCR engine with filters applied."""

        # load image
        image = imread(self.image_path)

        # start measuring time in milliseconds
        time = getTickCount()

        # apply filters
        for current_filter in self.test_settings.filters:
            image = current_filter.filter(image)

        # read text
        text = self.test_settings.reader.read(image)

        # stop measuring time
        time = (getTickCount() - time) / getTickFrequency() * 1000

        # compare text
        success = self.get_success_rate(text, self.expected_text)

        # return result
        return SingleTestResult(
            self.test_settings.reader,
            self.test_settings.filters,
            time,
            success,
            text,
            self.expected_text,
        )

    def get_success_rate(self, text: list, expected: str) -> float:
        """
        Compares result to expected text. Resulting float number is
        a percentage of how many words both strings have in common.
        """

        # make a union of lowercased words and calculate how many of them are in the expected text

        # Dear pylint, I did consider it, but I don't want to use a set comprehension here.
        # pylint: disable=consider-using-set-comprehension
        words = set([word.lower() for line in text for word in line.split()])
        expected_words = set([word.lower() for word in expected.split()])

        return len(words.intersection(expected_words)) / len(expected_words)

    def __str__(self):
        return f"TestCase({self.test_settings}, {self.image_path})"

class TesterUtil:
    """
    Tester utility for OCR engines with filters and cache their results for better performance.
    """

    __test__ = False

    def __init__(self, cache_path: str, dataset: Dataset):
        self.cache_path = cache_path
        self.cache = {}
        self.load_cache()
        self.dataset = dataset

    def load_cache(self):
        """
        Loads the cache from the cache file.
        """

        # check if the cache file exists
        if not os.path.exists(self.cache_path):
            return

        # load the cache
        with open(self.cache_path, "rb") as file:
            try:
                self.cache = load(file)
            except ModuleNotFoundError:
                self.cache = {}

    def save_cache(self):
        """
        This method will save the cache to the cache file.
        """

        # save the cache
        with open(self.cache_path, "wb") as file:
            dump(self.cache, file)

    def test(
        self, test_settings: TestSettings, meme_count=10, ignore_cache=False
    ) -> SingleTestResult:
        """
        This method will test a specific test case and return the result.
        """

        test_settings_id = str(test_settings)

        # check if we already have a cached result
        if not ignore_cache and test_settings_id in self.cache:
            return self.cache[test_settings_id]

        # load first memeCount memes
        meme_dataset = self.dataset.get(meme_count)

        # create a list of test cases
        test_cases = [
            TestCase(test_settings, meme.image_path, meme.expected_text)
            for meme in meme_dataset
        ]

        # run all test cases
        results = [testCase.test() for testCase in test_cases]

        # cache the result
        self.cache[test_settings_id] = MultiTestResult(
            results, test_settings, test_settings.reader, test_settings.filters
        )

        self.save_cache()

        return self.cache[test_settings_id]


from functools import reduce
from collections import Iterable, Callable

class NotCallable(TypeError):
    pass

class absorb(object):
    def __init__(self, func, use_original = False):
        if not isinstance(func, Callable):
            raise NotCallable('absorb got a `{}` object.' \
                .format( type(func).__name__ ))
        self.func = func
        self.use_original = use_original

    def __call__(self, value, *args, **kwargs):
        try:
            return self.func(value, *args, **kwargs)

        except:
            return None \
                if not self.use_original \
                else value

class Composition(object):
    def __init__(self, *functions):
        functions = list(functions)
        for func in functions:
            if not isinstance(func, Callable):
                raise NotCallable( \
                    "Composition is containing a `{}` object." \
                    .format( type(func).__name__ ))

        self.functions = functions

    def __call__(self, value = None):
        if not self.functions:
            return value

        return reduce(lambda value, func: func(value), self.functions, value)


import pygame

pygame.init()

screen= pygame.display.set_mode((800, 800))

cat = pygame.image.load('sprites\png\pear.png').convert()
catX=0
catY=100

clock = pygame.time.Clock()
running = True
while running:
    #fond en blanc
    screen.fill((255, 255, 255))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    #test touches
    pressed = pygame.key.get_pressed()
    pygame.key.get_pressed()
    if pressed[pygame.K_LEFT]:
        catX -= 10
    if pressed[pygame.K_RIGHT]:
        catX += 10
    if pressed[pygame.K_UP]:
        catY -= 10
    if pressed[pygame.K_DOWN]:
        catY += 10
    screen.fill((255, 255, 255))
    screen.blit(cat, (catX, catY))
    pygame.display.update()
    #ralentir image
    clock.tick(50) #en fps

pygame.quit()


from PySide2.QtCore import Qt
import PySide2.QtWidgets as qtw
from PySide2.QtGui import QPixmap, QImage
from functools import partial
from base_area import MainWindow
from my_widgets import MultiQuestion, SingleQuestion

def _exit_on_esc(e):
    if e.key() == Qt.Key_Escape:
        qtw.QApplication.instance().quit()

if __name__ == '__main__':
    # main window (fullscreen)
    app = qtw.QApplication([])

    pic = QImage('dv5_1.png').scaledToHeight(1200, Qt.SmoothTransformation)
    pic_inst = qtw.QLabel()
    # pic_inst.setScaledContents(True)
    pic_inst.setAlignment(Qt.AlignCenter)
    pic_inst.setPixmap(QPixmap.fromImage(pic))
    pic_inst.setStyleSheet('border:2px solid rgb(0, 0, 0);border-radius:20px;')

    pic2 = qtw.QLabel()
    pic2.setPixmap(QPixmap.fromImage(pic))
    pic3 = qtw.QLabel()
    pic3.setPixmap(QPixmap.fromImage(pic))
    xxx = qtw.QWidget()
    #t0 = qtw.QVBoxLayout()
    t0 = qtw.QGridLayout()
    t0.addWidget(pic_inst, 0, 0, 1, 1, Qt.AlignCenter)
    t0.addWidget(pic2, 1, 0, 1, 1, Qt.AlignLeft)
    t0.addWidget(pic3, 2, 0, 1, 1, Qt.AlignCenter)
    xxx.setLayout(t0)
    header = ["1\nCompletely\ninappropriate", "2", "3", "4", "5", "6", "7\nCompletely\nappropriate"]
    questions = ["How likely is it that this person committed a premeditated crime?",
                 "How likely is it that this person committed an impulsive crime?",
                 "How likely is it that this person committed a premeditated crime?",
                 "How likely is it that this person committed an impulsive crime?",
                 """How likely is it that this person committed a premeditated crime? Here's even more text to see how things wrap...

                 Newlines and all.""",
                 "How likely is it that this person committed an impulsive crime?",
                 "How likely is it that <b>this person</b> committed a premeditated crime?",
                 "How likely is it that this person committed an impulsive crime?",
                 "How likely is it that this person committed a premeditated crime?",
                 "How likely is it that this person committed an impulsive crime?",
                 "How likely is it that this person committed a premeditated crime?",
                 "How likely is it that this person committed an impulsive crime?",
                 "How likely is it that this person committed a premeditated crime?",
                 "How likely is it that this person committed an impulsive crime?",
                 "How likely is it that this person committed a premeditated crime?",
                 "How likely is it that this person committed an impulsive crime?"]
    multi_q = MultiQuestion(header, questions)

    q1 = SingleQuestion(header, 'What is your name?')
    q2 = SingleQuestion(header, 'What is your quest?')
    single_q = qtw.QWidget()
    layout = qtw.QVBoxLayout()
    layout.addWidget(q1)
    layout.addWidget(q2)
    single_q.setLayout(layout)
    tmp2 = qtw.QLabel('BAR')
    tmp2.setAlignment(Qt.AlignRight | Qt.AlignBottom)
    stack = [[single_q, multi_q, xxx], pic_inst, tmp2]

    window = MainWindow(stack)

    app.exec_()


from flask import Flask, render_template, request
import functions as funk
import joblib
import numpy as np
from sklearn.ensemble import RandomForestRegressor

model = joblib.load('store_rf_model.joblib')
app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        # Get the data from the form
        input1 = request.form['date']
        input2 = request.form['season']
        input3 = request.form['event']
        input4 = request.form['tourists']
        # Do something with the data, like save it to a database

        day, month,year, day_of_the_week_num = funk.get_date(input1)
        season_autumn,season_spring,season_summer,season_winter = funk.get_season(input2)
        covid = funk.get_covid(year)
        event = funk.get_event(input3)
        tourists = float(input4)
        pred_var = np.array([day,month,covid,event,tourists,day_of_the_week_num,season_autumn,season_spring,season_summer,season_winter])
        pred_var = pred_var.reshape(1,-1)
        #print(pred_var)
        pred = model.predict(pred_var)
        #return day, month,year, day_of_the_week_num
        results = str(pred[0])
        return render_template('results.html',results=results)
        # Render the template with the input fields
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True)


satz = "Unsere Seminare sind anerkannt als Arbeitnehmerweiterbildung (Bildungsurlaub) nach dem AWbG für NRW. Angestellte und Arbeiter/Innen in NRW haben nach dem AWbG Anspruch auf fünf Tage Bildungsurlaub im Jahr."

# Häufigkeit von Buchstaben
d = {}
for zeichen in satz:
    if zeichen in d:
        d[zeichen] += 1
    else:
        d[zeichen] = 1

print(d)

# Sortieren nach Häufigkeit
print(sorted(d.items(), key = lambda tupel: tupel[1], reverse = True))


from sklearn.naive_bayes import GaussianNB
import mldatautil as ml
import sys

if len(sys.argv) != 3:
    print('usage: sript.py feature_flags combine_activities')
    quit()

feature_flags = sys.argv[1]
combine = sys.argv[2]

# get the data into numpy arrays
train_x, train_y, test_x, test_y = ml.gettraintestdata(feature_flags, combine)

model = GaussianNB()
model.fit(train_x, train_y)

predicted = model.predict(test_x)
correct = 0
tot = 0
for idx in range(test_y.shape[0]):
    if test_y[idx] == predicted[idx]:
        correct += 1

    tot += 1

test_acc = correct/tot

predicted = model.predict(train_x)
correct = 0
tot = 0
for idx in range(train_x.shape[0]):
    if train_y[idx] == predicted[idx]:
        correct += 1

    tot += 1

train_acc = correct/tot
ml.printresults("naive bayes", test_acc, train_acc)


from abc import ABCMeta
from pylegend._typing import (
    PyLegendSequence,
    PyLegendDict,
)
from pylegend.core.language.expression import (
    PyLegendExpression,
    PyLegendExpressionBooleanReturn,
    PyLegendExpressionStringReturn,
    PyLegendExpressionNumberReturn,
    PyLegendExpressionIntegerReturn,
    PyLegendExpressionFloatReturn,
    PyLegendExpressionDateReturn,
    PyLegendExpressionDateTimeReturn,
    PyLegendExpressionStrictDateReturn,
)
from pylegend.core.sql.metamodel import (
    Expression,
    QuerySpecification,
    SingleColumn,
)
from pylegend.core.tds.tds_frame import FrameToSqlConfig

__all__: PyLegendSequence[str] = [
    "PyLegendColumnExpression",
    "PyLegendBooleanColumnExpression",
    "PyLegendStringColumnExpression",
    "PyLegendNumberColumnExpression",
    "PyLegendIntegerColumnExpression",
    "PyLegendFloatColumnExpression",
    "PyLegendDateColumnExpression",
    "PyLegendDateTimeColumnExpression",
    "PyLegendStrictDateColumnExpression",
]

class PyLegendColumnExpression(PyLegendExpression, metaclass=ABCMeta):
    __frame_name: str
    __column: str

    def __init__(self, frame_name: str, column: str) -> None:
        self.__frame_name = frame_name
        self.__column = column

    def to_sql_expression(
            self,
            frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
            config: FrameToSqlConfig
    ) -> Expression:
        query = frame_name_to_base_query_map[self.__frame_name]
        db_extension = config.sql_to_string_generator().get_db_extension()
        filtered = [
            s for s in query.select.selectItems
            if (isinstance(s, SingleColumn) and
                s.alias == db_extension.quote_identifier(self.__column))
        ]
        if len(filtered) == 0:
            raise RuntimeError("Cannot find column: " + self.__column)  # pragma: no cover
        return filtered[0].expression

class PyLegendBooleanColumnExpression(PyLegendColumnExpression, PyLegendExpressionBooleanReturn):

    def __init__(self, frame_name: str, column: str) -> None:
        super().__init__(frame_name=frame_name, column=column)

class PyLegendStringColumnExpression(PyLegendColumnExpression, PyLegendExpressionStringReturn):

    def __init__(self, frame_name: str, column: str) -> None:
        super().__init__(frame_name=frame_name, column=column)

class PyLegendNumberColumnExpression(PyLegendColumnExpression, PyLegendExpressionNumberReturn):

    def __init__(self, frame_name: str, column: str) -> None:
        super().__init__(frame_name=frame_name, column=column)

class PyLegendIntegerColumnExpression(PyLegendNumberColumnExpression, PyLegendExpressionIntegerReturn):

    def __init__(self, frame_name: str, column: str) -> None:
        super().__init__(frame_name=frame_name, column=column)

class PyLegendFloatColumnExpression(PyLegendNumberColumnExpression, PyLegendExpressionFloatReturn):

    def __init__(self, frame_name: str, column: str) -> None:
        super().__init__(frame_name=frame_name, column=column)

class PyLegendDateColumnExpression(PyLegendColumnExpression, PyLegendExpressionDateReturn):

    def __init__(self, frame_name: str, column: str) -> None:
        super().__init__(frame_name=frame_name, column=column)

class PyLegendDateTimeColumnExpression(PyLegendDateColumnExpression, PyLegendExpressionDateTimeReturn):

    def __init__(self, frame_name: str, column: str) -> None:
        super().__init__(frame_name=frame_name, column=column)

class PyLegendStrictDateColumnExpression(PyLegendDateColumnExpression, PyLegendExpressionStrictDateReturn):

    def __init__(self, frame_name: str, column: str) -> None:
        super().__init__(frame_name=frame_name, column=column)


#!/usr/bin/env python """
import sys
import tempfile
import os

from datetime import date
today = date.today()

"""Mailroom Part 4"""
""" Updates from Part 3
1. Refactored for testing
"""

# Prompt user to choose from menu of 4 actions:
# Send a Thank You, Create a Report, Send thanks to all donors or quit.

assert_donor_db = {"Cher": [1000.00, 245.00],
            "Drew Barrymore": [25000.00],
            "Charlie Brown": [25.00, 50.01, 100.00],
            "Jack Black": [256.00, 752.50, 10101.00],
            "Sam Smith": [5500.00, 24.00],
            }

donor_db = {"Cher": [1000.00, 245.00],
            "Drew Barrymore": [25000.00],
            "Charlie Brown": [25.00, 50.01, 100.00],
            "Jack Black": [256.00, 752.50, 10101.00],
            "Sam Smith": [5500.00, 24.00],
            }

default_folder = "thank_you_cards"

def get_input(prompt):
    response = input(prompt)
    return response

def sort_key(donors):
    #  sort by total donations
    return sum(donors[1])

def list_donors():
    return list(donor_db)

def add_donor(donator, donation):
    """      Add new donor with donation
    """

    donor_db[donator] = []
    donor_db[donator] = donor_db[donator] + [donation]

def update_donor(donator, donation):
    """      update donor with new donation
    """

    donor_db[donator] = donor_db[donator] + [donation]

def get_letter_text(donation_dict):
    """Get letter text for file content"""

    formatted = 'Dear {name},\
    \n\n\tThank you for your very kind donation of ${donation:,.2f}.\
    \n\n\tIt will be put to very good use.\n\n\t\t\tSincerely,\
    \n\t\t\t   -The Team'.format(**donation_dict)

    return formatted

def create_card(donator, amount, fldr):
    """
    Create thank you note for passed user
    """

    donation_dict = {}
    donation_dict['name'] = donator
    donation_dict['donation'] = float(amount)

    ty_text = get_letter_text(donation_dict)

    file_name = donation_dict['name'].replace(' ', '_') + '.txt'
    file_path = os.path.join(fldr, file_name)

    try:
        with open(file_path, 'w+') as f:
            f.write(ty_text)
            print(ty_text)
    except IOError:
        print(f"IOError: Error writing to file: {write_path}")

    print(f"\n** Thank you note to {donation_dict['name']} for ${donation_dict['donation']:,.2f} written to {write_path}.  **\n")

def get_donor_name():
    donor_prompt = "\n".join(("\nEnter Full name of donor",
                        "  or Enter list to show current donors",
                        "  or 'q' to return to main menu",
                        "  Please enter donor name:"
                        " > "))
    in_name = get_input(donor_prompt)
    return in_name.title()

def send_ty(donors):
    ''' Send thank you to selected donor '''

    donation = []

    while True:
        donor_name = get_donor_name()

        if donor_name.lower() == 'list':
            donor_names = list_donors()
            print('\n')
            for donor_name in donor_names:
                print(f'   * {donor_name}')
            print('\n')
        elif donor_name.lower() == "q":
            break
        elif donor_name == '':
            continue
        else:
            donation = get_donation()
            if donor_exists(donor_name):
                update_donor(donor_name, donation)
                create_card(donor_name, donation, write_path)
                break
            else:
                add_donor(donor_name, donation)
                create_card(donor_name, donation, write_path)
                break

    return

def donor_exists(name):
    if donor_db.get(name):
        return True
    else:
        return False

def get_donation():
    while True:
        prompt = "Please enter a valid amount to donate >"
        donation = get_input(prompt)
        if donation == "q":
            return

        try:
            donation = float(donation)
        except ValueError:
            print('ValueError: Please enter a numeric value')
        else:
            if donation > 0:
                break
            else:
                continue

    return donation

def get_report(data_passed):

    report = []
    sorted_donors = dict(sorted(data_passed.items(), key=sort_key, reverse=True))
    for donor in sorted_donors.items():
        count = len(donor[1])
        total = sum(donor[1])
        avg = total/count
        write_row = ('{:25}  ${:13,.2f}   {:11}  ${:12,.2f}'.format(
            donor[0], total, count, avg))
# belarsonQ:  how to get this format converted to string
#        write_row = ('f'{donor:25}  ${total:13,.2f}   {count:11}  ${avg:12,.2f}')
        report.append(write_row)

    return report

def display_report():
    for row in get_report(donor_db):
        print(row)

def display_report_header():
    header = []
    col1 = 'Donor Name'
    col2 = 'Total Given'
    col3 = 'Num Gifts'
    col4 = 'Average Gift'
    # print(f'{col1:25} | {col2:13} | {col3:11} | {col4:13}')
    # print('-'*70)
    header.append(f'{col1:25} | {col2:13} | {col3:11} | {col4:13}')
    header.append('-'*70)
    return header

def create_report(donors):
    """
    Print formatted report of donors and donations
    Sort report by total donations
    """
    report = []

    report_header = [display_report_header()]
    report_body = [display_report()]
    print(report_header)
    print(report_body)

def ask_for_folder():
    global user_folder

    # as creating folders is platform specific, end if not Windows.
    import platform

    if not platform.system().lower() == 'windows':
        print(f'Sorry, future development requested but not currently enabled for {platform.system()} platform')
        exit_program(0)

    text = "\n".join(("\n\n\nEnter folder Name or hit enter for default",
                      " >"))
    folder_prompt = get_input(text)

    if folder_prompt:
        user_folder = folder_prompt.replace(" ", "_")
    else:
        user_folder = default_folder

    temp_path = tempfile.gettempdir()
    folder_name = user_folder + '_' + today.strftime("%b_%d_%Y")

    folder_path = os.path.join(temp_path, folder_name)

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

    return folder_path

def send_all_ty(donors):
    '''
    Create cards for all donor in dictionary
    Note: revised code to use comprehension in Mailroom Part 3
    '''

    [create_card(donor, donations[-1], write_path) for donor, donations in donor_db.items()]
    '''
    for donor, donations in donor_db.items():
        donation_current = donations[-1]
        create_card(donor, donation_current, write_path)
    '''
    return

def exit_program(donors):
    print('Thank you')
    sys.exit()

def get_selection():

    menu_prompt = "\n".join(("**  Please Select Valid Option Listed:  **",
                        "       1: Send a Thank You",
                        "       2: Create a Report",
                        "       3: Thanks to All Donors",
                        "       4: Quit",
                        f"       (Folder: {user_folder})",
                        "       Please enter your choice:"
                        " > "))

    response = get_input(menu_prompt)

    return response

if __name__ == '__main__':

    try:
        response = ''
        write_path = ask_for_folder()
        print(f'writing to file: {write_path}')

        switch_func_dict = {
            '1': send_ty,
            '2': create_report,
            '3': send_all_ty,
            '4': exit_program
        }

        while True:
            response = get_selection()
            try:
                # if response in switch_func_dict:
                # switch_func_dict.get(response, "nothing")()
                # switch_func_dict.get(response, "nothing")(donor_db)
                switch_func_dict[response](donor_db)
                # else:
                #    print("Please enter valid option")
            except KeyError:
                print('Please select a value 1-4')

    except KeyboardInterrupt:
        print('\n\nKeyboardInterrupt: Interrupted and Exiting')
        sys.exit(0)


from uuid import uuid4

from pyramid.events import NewResponse, NewRequest
from pyramid.events import subscriber

from unicore.google.tasks import pageview
from cms import utils

ONE_YEAR = 31556952

@subscriber(NewRequest)
def new_request(event):
    request = event.request
    registry = request.registry

    profile_id = registry.settings.get('ga.profile_id')
    if not profile_id:
        request.google_analytics = {}
        return

    request.google_analytics = {
        'path': request.path,
        'uip': request.remote_addr,
        'dr': request.referer or '',
        'dh': request.domain,
        'user_agent': request.user_agent,
        'ul': unicode(request.accept_language),
    }

@subscriber(NewResponse)
def new_response(event):
    request = event.request
    registry = request.registry
    response = event.response

    profile_id = registry.settings.get('ga.profile_id')
    excluded_paths = registry.settings.get('ga.excluded_paths', '')
    if profile_id and not utils.excluded_path(request.path, excluded_paths):
        client_id = request.cookies.get('ga_client_id', str(uuid4()))
        response.set_cookie('ga_client_id', value=client_id, max_age=ONE_YEAR)
        pageview.delay(profile_id, client_id, request.google_analytics)


from PyQt4.QtGui import *
from i18n import _

class HistoryWidget(QTreeWidget):

    def __init__(self, parent=None):
        QTreeWidget.__init__(self, parent)
        self.setColumnCount(2)
        self.setHeaderLabels([_("Amount"), _("To / From")])
        self.setIndentation(0)

    def append(self, address, amount):
        item = QTreeWidgetItem([amount, address])
        self.insertTopLevelItem(0, item)


import os
from argparse import ArgumentParser
from os.path import join

import numpy as np
import pytorch_lightning as pl
import torch
import torch.backends.cudnn as cudnn
from pytorch_lightning.callbacks import ModelCheckpoint, TQDMProgressBar, LearningRateMonitor

from StandardStrategies.CtoY import CtoY
from StandardStrategies.XtoCtoY import XtoCtoY
from StandardStrategies.XtoY import XtoY
from StandardStrategies.XtoC import XtoC
from continualStrategies.train import train_and_test_continual
from dataset.dataloader import get_loaders
from dataset.dataloader import load_cub200
from explainers.Explainer import Label_Explainer

ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
CHECKPOINT_PATH = join(ROOT_DIR, "results")

def main():
    # parse parameters
    parser = ArgumentParser(description='experiment', allow_abbrev=False)
    parser.add_argument('--dataset', type=str, default="cub200",
                        help='dataset name.', choices=["cub200"])
    parser.add_argument('--classifier', type=str, default="linear",
                        help='classifier name.', choices=["linear", "cnn", "..."])
    parser.add_argument('--featureExtractor', type=str, default="linear",
                        help='classifier name.', choices=["VAE", "CNN", "linear", "resnet"])
    parser.add_argument('--experiment', type=str, default="XtoCtoY",
                        help='classifier name.', choices=["XtoCtoY", "XtoC", "CtoY", "XtoY"])
    parser.add_argument('--continual', action="store_true", default=False,
                        help='standard or continual experiment', )
    parser.add_argument('--batch_size', default=20,
                        help='batchsize', )
    parser.add_argument('--optimizer_name', default="SGD",
                        choices=["SGD", "ADAM"])
    parser.add_argument('-scheduler_step', type=int, default=20,
                        help='Number of steps before decaying current learning rate by half')
    parser.add_argument('--epochs_per_task', default=5,
                        help='epochs_per_task in continual environment', )

    parser.add_argument('-weight_decay', type=float,
                        default=0.0004, help='weight decay for optimizer')
    parser.add_argument('-lr', type=float, default=0.01, help="learning rate")

    args = parser.parse_known_args()[0]

    # set reproducible results
    seed = 10
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    print('Using device:', device)
    if device.type == 'cuda':
        cudnn.benchmark = True
        torch.cuda.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
        torch.backends.cudnn.deterministic = True
        torch.backends.cudnn.benchmark = False
    else: torch.manual_seed(seed)

    np.random.seed(seed)

    # get datasets
    train, val, test = load_cub200(join(ROOT_DIR, "data"))

    if args.continual:
        train_and_test_continual(
            train, val, test, device, args, CHECKPOINT_PATH)
    else:

        trainloader, valloader, testloader = get_loaders(
            train, val, test, args.batch_size)
        if args.experiment == "CtoY":
            strategy = CtoY(optimizer_name=args.optimizer_name, model_hparams={"num_classes": 200, "act_fn_name": "relu"},
                            optimizer_hparams={"lr": args.lr, "weight_decay": args.weight_decay, "scheduler_step": args.scheduler_step}, continual=False)
        elif args.experiment == "XtoY":
            strategy = XtoY(optimizer_name=args.optimizer_name, model_hparams={"num_classes": 200, "act_fn_name": "relu"},
                            optimizer_hparams={"lr": args.lr, "weight_decay": args.weight_decay, "scheduler_step": args.scheduler_step}, continual=False)
        elif args.experiment == "XtoCtoY":

            strategy = XtoCtoY(optimizer_name=args.optimizer_name, model_hparams={"num_classes": 200, "act_fn_name": "relu"},
                               optimizer_hparams={"lr": args.lr, "weight_decay": args.weight_decay, "scheduler_step": args.scheduler_step},
                               continual=False,device=device.type)
        elif args.experiment == "XtoC":
            strategy = XtoC(optimizer_name=args.optimizer_name, model_hparams={"num_classes": 200, "act_fn_name": "relu"},
                            optimizer_hparams={"lr": args.lr, "weight_decay": args.weight_decay, "scheduler_step": args.scheduler_step}, continual=False,device=device.type)

        else:
            raise "experiment not defined"
        checkpoint = ModelCheckpoint(save_weights_only=True, mode="max")
        trainer = pl.Trainer(default_root_dir=os.path.join(CHECKPOINT_PATH, strategy.name, "standard", args.dataset),
                             # Where to save models
                             # We run on a single GPU (if possible)
                             gpus=1 if str(device) == "cuda" else 0,

                             max_epochs=800,  # How many epochs to train for if no patience is set

                             callbacks=[checkpoint,
                                        # Save the best checkpoint based on the maximum val_acc recorded. Saves only weights and not optimizer
                                        LearningRateMonitor("epoch"),
                                        TQDMProgressBar(1)]  # Log learning rate every epoch
                             )
        #TEST for the metrics

#        print('Before passing to verifier')
#        print(strategy.model.model2.weight.size())
        #explainer=Label_Explainer(strategy, 'data/epoch=188-step=45170.ckpt', testloader) #TODO: fix immediately on cpu
        #explainer.fit(method='GRADCAM')

        trainer.fit(strategy, train_dataloaders=trainloader,
                    val_dataloaders=valloader)

        #explainer=Label_Explainer(strategy, checkpoint.best_model_path, testloader, )
        #explainer.run()

        trainer.test(strategy, dataloaders=testloader)

        #explainer = Label_Explainer(checkpoint.best_model_path, testloader)
        #explainer.run()

if __name__ == '__main__':
    main()


from argparse import ArgumentParser
from queue import Queue
from threading import Thread
from time import sleep, time
from datetime import timedelta
from signal import signal, SIGINT
from os import access, path, R_OK

from tqdm import tqdm

import config as config_file
from detector import ObjectDetector
from threads import loader_thread, detector_thread, tracker_thread
from loader import VideoLoader
from tracker import ObjectTracker

def log(msg: str, bar: tqdm = None, cfg = None):
    if cfg is not None and cfg.SILENT:
        return

    if bar is not None and not bar.disable:
        bar.write(msg)
    else:
        print(msg)

def is_readable_file(parser, arg):
    if not path.isfile(arg) or not access(arg, R_OK):
        parser.error(f"${arg} není validní čitelný soubor!")

    return arg

def kvidet(input_video, config):
    to_detect = Queue()
    to_track = Queue()
    to_summarize = Queue()

    video_loader = VideoLoader(config.FRAME_SKIP)
    object_detector = ObjectDetector()
    object_tracker = ObjectTracker()

    video_loader.load(input_video)

    loader_bar = tqdm(desc="loader progress", total=video_loader.get_video_frame_count() // config.FRAME_SKIP,
                      ascii=True, disable=(not config.PROGRESS))
    detector_bar = tqdm(desc="detection progress", total=video_loader.get_video_frame_count() // config.FRAME_SKIP,
                        ascii=True, disable=(not config.PROGRESS))
    tracker_bar = tqdm(desc="tracker progress", total=video_loader.get_video_frame_count() // config.FRAME_SKIP,
                       ascii=True, disable=(not config.PROGRESS))

    loader = Thread(target=loader_thread, args=(video_loader, to_detect, loader_bar), daemon=True)
    detector = Thread(target=detector_thread, args=(object_detector, to_detect, to_track, detector_bar), daemon=True)
    tracker = Thread(target=tracker_thread, args=(object_tracker, to_track, to_summarize, tracker_bar), daemon=True)

    # stop threads
    def stop_detection(sig, fr):
        video_loader.stop = True
        object_detector.stop = True
        object_tracker.stop = True

    signal(SIGINT, stop_detection)

    loader.start()
    log("loader started", loader_bar, config)

    detector.start()
    log("detector started", detector_bar, config)

    tracker.start()
    log("tracker started", tracker_bar, config)

    loader.join()
    detector.join()
    tracker.join()

    loader_bar.close()
    detector_bar.close()
    tracker_bar.close()

    log("all threads finished", cfg=config)

    summarization_task = to_summarize.get()
    detected_vehicles = summarization_task.payload

    log("sorting vehicles by direction", cfg=config)

    sorted_vehicles_by_direction = {}

    if detected_vehicles is None:
        return sorted_vehicles_by_direction

    for vehicle in detected_vehicles.values():
        for direction, bounding_vectors in config.BOUNDING_VECTORS.items():
            if direction not in sorted_vehicles_by_direction:
                sorted_vehicles_by_direction[direction] = []

            if len(vehicle.position_history) < 2:
                continue

            if vehicle.motion_vector.is_between(bounding_vectors[0], bounding_vectors[1]):
                sorted_vehicles_by_direction[direction].append(vehicle)
    return sorted_vehicles_by_direction

if __name__ == "__main__":
    arg_parser = ArgumentParser(description="Detekce projíždějících aut a jejich směrů")

    arg_parser.add_argument("input_path", help="cesta k videosouboru",
                            type=lambda filename: is_readable_file(arg_parser, filename))
    arg_parser.add_argument("--silent", "-s", help="zda vypisovat na standardní výstup průběh detekce",
                            default=config_file.SILENT, action="store_true")
    arg_parser.add_argument("--debug", "-d", help="zda vypisovat ladící údaje na standardní výstup",
                            default=config_file.DEBUG, action="store_true")
    arg_parser.add_argument("--time", "-t", help="zda vypisovat na standardní výstup dobu strávenou detekcí",
                            default=config_file.TIME, action="store_true")
    arg_parser.add_argument("--progress", "-p", help="zda vypisovat živě průběh detekce na standardní výstup",
                            default=config_file.PROGRESS, action="store_true")
    arg_parser.add_argument("--frame-skip", "-n", help="číst poze každý N-tý snímek",
                            default=config_file.FRAME_SKIP, metavar="N", type=int)

    args = arg_parser.parse_args()

    config = config_file
    config.SILENT = args.silent
    config.DEBUG = args.debug
    config.TIME = args.time
    config.PROGRESS = args.progress
    config.FRAME_SKIP = args.frame_skip

    start_time = time()
    result = kvidet(args.input_path, config)
    end_time = time()

    print("-----------------")
    print("Results:")
    for direction in result:
        print(f"direction: {direction} vehicles: {len(result[direction])}")

    if config.TIME:
        elapsed_time=timedelta(seconds=end_time) - timedelta(seconds=start_time)
        hours, remainder = divmod(int(elapsed_time.total_seconds()), 60 * 60)
        minutes, seconds = divmod(remainder, 60)
        print(f"elapsed time: {hours}h {minutes}m {seconds}s")


#!/usr/bin/env python

import argparse
import ray
import tensorflow as tf
from baselines.logger import configure
from baselines.common import set_global_seeds
from baselines.common.vec_env.vec_normalize import VecNormalize
import baselines.ppo2.policies as policies
import baselines.ppo2.ppo2 as ppo2
from nips.round2_env import CustomEnv, CustomActionWrapper
from nips.remote_vec_env import RemoteVecEnv

def create_env():
    env = CustomEnv(visualization=args.vis, integrator_accuracy=args.accuracy)
    env = CustomActionWrapper(env, action_repeat=args.repeat)
    return env

def train():
    config = tf.ConfigProto(
        allow_soft_placement=True,
        intra_op_parallelism_threads=args.num_cpus,
        inter_op_parallelism_threads=args.num_cpus
    )
    tf.Session(config=config).__enter__()

    env = RemoteVecEnv([create_env] * args.num_cpus)
    env = VecNormalize(env, ret=True, gamma=args.gamma)

    ppo2.learn(
        policy=policies.MlpPolicy, env=env,
        total_timesteps=args.num_timesteps, nminibatches=args.num_minibatches,
        nsteps=args.num_steps, noptepochs=args.num_epochs, lr=args.learning_rate,
        gamma=args.gamma,
        lam=args.lam, ent_coef=args.ent_coef, vf_coef=args.vf_coef, cliprange=args.clip_range,
        log_interval=args.log_interval, save_interval=args.save_interval,
        load_path=args.checkpoint_path,
        num_casks=args.num_casks
    )

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='PPO training for NIPS 2018: AI for Prosthetics Challenge, Round 2')
    parser.add_argument('--num-timesteps', default=1e6, type=int, help='number of timesteps')
    # batch_size = num_steps * num_envs
    parser.add_argument('--num-steps', default=128, type=int, help='number of steps per update')
    # valid number of envs
    parser.add_argument('--num-minibatches', default=1, type=int, help='number of training minibatches per update')
    parser.add_argument('--num-epochs', default=4, type=int, help='number of training epochs per update')
    parser.add_argument('--learning-rate', default=3e-4, type=float, help='learning rate')
    # RL domain
    parser.add_argument('--gamma', default=0.99, type=float, help='discounting factor')
    # PPO specific
    parser.add_argument('--lam', default=0.95, type=float, help='advantage estimation discounting factor')
    parser.add_argument('--ent-coef', default=0.001, type=float, help='policy entropy coefficient')
    parser.add_argument('--vf-coef', default=0.5, type=float, help='value function loss coefficient')
    parser.add_argument('--clip-range', default=0.2, type=float, help='clipping range')
    # env related
    parser.add_argument('--seed', default=6730, type=int, help='random seed')
    parser.add_argument('--accuracy', default=5e-5, type=float, help='simulator integrator accuracy')
    parser.add_argument('--repeat', default=1, type=int, help='number of action repeat')
    parser.add_argument('--vis', default=False, action='store_true', help='visualization option')
    # training settings
    parser.add_argument('--num-cpus', default=1, type=int, help='number of cpus')
    parser.add_argument('--num-casks', default=0, type=int, help='number of casks, for acceleration')
    parser.add_argument('--num-gpus', default=0, type=int, help='number of gpus')
    parser.add_argument('--log-dir', default='./logs', type=str, help='logging events output directory')
    parser.add_argument('--log-interval', default=1, type=int, help='number of timesteps between logging events')
    parser.add_argument('--save-interval', default=1, type=int, help='number of timesteps between saving events')
    parser.add_argument('--checkpoint-path', default=None, type=str, help='path to load the model checkpoint from')
    args = parser.parse_args()
    print(args)

    ray.init(num_cpus=args.num_cpus, num_gpus=args.num_gpus)
    set_global_seeds(args.seed)
    configure(dir=args.log_dir)
    train()


from handlers import Handler
from blog import Blog

class NewPost(Handler):
    def get(self):
        self.render("newpost.html", user_title="", user_content="", error="")

    def post(self):
        user_title = self.request.get('subject')
        user_content = self.request.get('content')
        if not (user_title and user_content):
            self.render("newpost.html",
                        user_title=user_title,
                        user_content=user_content,
                        error="Please enter both a title and content.")
        else:
            post = Blog(title=user_title, entry=user_content)
            key = post.put()
            self.redirect("/blog/%d" % key.id())


import os
from flask_sqlalchemy import SQLAlchemy

DB_PATH = os.environ.get("SQLALCHEMY_DATABASE_URI")
DB_TEST_PATH = os.environ.get("SQLALCHEMY_TEST_DATABASE_URI")

db = SQLAlchemy()

'''
setup_db(app)
    binds a flask application and a SQLAlchemy service
'''
def setup_db(app, test=True):

    if test:
        db_path = DB_TEST_PATH
    else:
        db_path = DB_PATH
    app.config["SQLALCHEMY_DATABASE_URI"] = db_path
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
    db.app = app
    db.init_app(app)
    db.create_all()

class Table:
    """Base class for models in this module
    Defines common operations"""

    def insert(self):
        db.session.add(self)
        db.session.commit()

    def update(self):
        db.session.commit()

    def delete(self):
        db.session.delete(self)
        db.session.commit()

    def rollback(self):
        db.session.rollback()

class User(db.Model, Table):
    __tablename__ = 'user'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String, nullable=False)
    joined_ts = db.Column(db.TIMESTAMP, nullable=False)
    tweet = db.relationship("Tweet", backref="tweet", lazy='dynamic')

    def describe(self):
        return {
            "username": self.username,
            "user id": self.id,
            "joined": self.joined_ts
        }

class Tweet(db.Model, Table):
    __tablename__ = 'tweet'

    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String, nullable=False)
    tweet_ts = db.Column(db.TIMESTAMP, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

    def describe(self):
        return {
            "tweet": self.text,
            "tweet id": self.id,
            "tweet timestamp": self.tweet_ts,
            "posted user": self.user_id
        }


import torch
from torch import nn

torch.manual_seed(0)

class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(28 * 28, 512),
            nn.ReLU(),
            nn.Linear(512, 512),
            nn.ReLU(),
            nn.Linear(512, 10),
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

torch_mlp = NeuralNetwork()
loss_fn = nn.CrossEntropyLoss()

def torch_primal(X: torch.Tensor, y: torch.LongTensor) -> torch.Tensor:
    return loss_fn(torch_mlp(X), y)


class Carro:
    def __init__(self, request):
        self.request=request #ALMACENANDO PETICION PARA ENTRAR AL CARRITO EN REQUEST
        self.session=request.session  #INICIANDO SESION
        carro=self.session.get("carro")
        if  not carro:   #SI NO HAY CARRO EN LA SESION
            carro=self.session["carro"]={} #CREA CARRO CON UN DICCIONARIO VACIO
        else:   #SI HAY CARRO EN LA SESION
            self.carro=carro  #IGUALANDO CARRO AL CARRO QUE YA HABIA EN LA SESION

    def agregar(self, producto): #FUNCION PARA AGREGAR PRODUCTOS AL CARRO
        if(str(producto.id) not in self.carro.keys()):  #SI NO ENCUENTRA EL ID DEL PRODUCTO EN EL CARRO
            self.carro[producto.id]={     #AGREGA PRODUCTO AL CARRO DICCIONARIO CLAVE-VALOR
                "producto_id":producto.id,
                "nombre":producto.nombre,
                "precio":str(producto.precio),
                "cantidad":1,  #CANTIDAD DE PRODUCTOS EN PRINCIPIO 1
                "imagen":producto.imagen.url
            }

        else:
            for key, value in self.carro.items(): #POR CADA CLAVE VALOR EN EL CARRO
                if key==str(producto.id):  #COMPROBANDO SI CLAVE ES IGUAL A ALGUN ID DE UN PRODUCTO EN EL CARRO
                    value["cantidad"]=value["cantidad"]+1 #LE SUMA UN VALOR MAS A LA CANTIDAD DE PRODUTOS
                    break #CERRANDO FOR EN CASO YA ENCUENTRE EL PRODUCTO
        self.guardar_carro()

    def guardar_carro(self):   #FUNCION PARA ACTUALIZAR SESION
        self.session["carro"]=self.carro
        self.session.modified=True

    def eliminar(self, producto):  #FUNCION PARA ELIMINAR UN PRODUCTO DEL CARRO
        producto.id=str(producto.id)   #OBTENIENDO ID DE PRODUCTO
        if producto.id in self.carro:   #COMPROBANDO QUE ESE ID DE PRODUCTO ESTE EN EL CARRO
            del self.carro[producto.id]      #QUITANDO PRODUCTO  DEL CARRO
            self.guardar_carro()  #ACTUALIZANDO CARRO

    def restar_producto(self, producto):  #FUNCION PARA RESTAR UNIDADES AL PRODUCTO AGREGADO AL CARRO
        for key, value in self.carro.items():
                if key==str(producto.id):
                    value["cantidad"]=value["cantidad"]-1
                    if value["cantidad"]<1: #SI LA CANTIDAD DE PRODUCTOS ES MENOR QUE 1
                        self.eliminar(producto) #LLAMA A FUNCION ELIMINAR PARA BORRAR PRODUCTO DEL CARRO
                    break
        self.guardar_carro()#ACTUALIZANDO CARRO

    def limpiar_carro(self):
        self.session["carro"]={}  #CONSTRUTE DICCIONARIO VACIO
        self.session.modified=True


import requests
from flask import Flask, request, Response

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

URL_HOST = "https://gitlab.com/api/v4/issues"
URL_PRIV = "private_token=pLEY6MtfGVF8FCx"

headers = {"private_token" : "pLEY6MtfGVF8FCx"}

@app.route('/webhook', methods=['POST'])
def respond():
    print(request.json);
    print('-------')
    r = requests.get(URL_HOST, headers=headers, params={'iid[]': '1'})
    print(r.json())
    return Response(status=200)


from django.db import models
from wagtail.admin.edit_handlers import (
    FieldPanel,
    MultiFieldPanel,
    PageChooserPanel,
    StreamFieldPanel,
)
from wagtail.core.fields import RichTextField, StreamField
from wagtail.core.models import Page
from wagtail.search import index

from wagtail_dot_org import blocks as wagtail_dot_org_blocks
from wagtail_dot_org.pages import blocks as pages_blocks

class HomePage(Page):
    icon = models.CharField(
        max_length=255,
        choices=[("leaf", "Leaf"), ("arrow", "Arrow"), ("animation", "Animation")],
        verbose_name="Icon",
        blank=True,
        default="",
    )
    cta_text = models.TextField(verbose_name="CTA text", blank=True, default="")
    cta_page = models.ForeignKey(
        to="wagtailcore.Page",
        on_delete=models.SET_NULL,
        related_name="+",
        verbose_name="CTA page",
        blank=True,
        null=True,
    )
    cta_url = models.URLField(verbose_name="CTA URL", blank=True, default="")
    body = StreamField(
        block_types=[
            ("headline", wagtail_dot_org_blocks.HeadlineBlock()),
            ("teaser", wagtail_dot_org_blocks.TeaserBlock()),
            ("standalonecta", wagtail_dot_org_blocks.StandaloneCTABlock()),
            ("highlight", wagtail_dot_org_blocks.HighlightBlock()),
            ("iconbullets", wagtail_dot_org_blocks.IconBulletsBlock()),
            ("quotes", wagtail_dot_org_blocks.QuotesBlock()),
            ("getstartedchooser", wagtail_dot_org_blocks.GetStartedChooserBlock()),
        ],
        default="",
        verbose_name="Body",
        blank=True,
    )
    heading = models.TextField(verbose_name="Heading", max_length=100, default="")
    sub_heading = models.TextField(verbose_name="Sub heading", blank=True, default="")
    intro = RichTextField(
        verbose_name="Intro",
        blank=True,
        features=["bold", "italic", "link"],
        default="",
    )

    hero_panels = [
        FieldPanel("heading"),
        FieldPanel("sub_heading"),
        FieldPanel("intro"),
        FieldPanel("icon"),
        FieldPanel("cta_text"),
        PageChooserPanel("cta_page"),
        FieldPanel("cta_url"),
    ]
    content_panels = Page.content_panels + [
        MultiFieldPanel(heading="Hero", children=hero_panels),
        StreamFieldPanel("body"),
    ]

    search_fields = Page.search_fields + [
        index.FilterField("icon"),
        index.FilterField("cta_text"),
        index.FilterField("cta_page"),
        index.FilterField("cta_url"),
        index.SearchField("body"),
        index.FilterField("body"),
        index.SearchField("heading"),
        index.FilterField("heading"),
        index.FilterField("sub_heading"),
        index.FilterField("intro"),
    ]

    class Meta:
        verbose_name = "Homepage"

class BlogPage(Page):

    parent_page_types = [
        "pages.BlogPage",
        "pages.HomePage",
        "pages.ContentPage",
    ]

    class Meta:
        verbose_name = "Blog page"

class ContentPage(Page):
    heading = models.TextField(verbose_name="Heading", default="")
    icon = models.CharField(
        max_length=255,
        choices=[("leaf", "Leaf")],
        verbose_name="Icon",
        blank=True,
        default="",
    )
    cta_text = models.TextField(verbose_name="CTA text", blank=True, default="")
    cta_page = models.ForeignKey(
        to="wagtailcore.Page",
        on_delete=models.SET_NULL,
        related_name="+",
        verbose_name="CTA page",
        blank=True,
        null=True,
    )
    cta_url = models.URLField(verbose_name="CTA URL", blank=True, default="")
    intro = RichTextField(
        verbose_name="Intro",
        blank=True,
        features=["bold", "italic", "link"],
        default="",
    )
    body = StreamField(
        block_types=[
            ("headline", wagtail_dot_org_blocks.HeadlineBlock()),
            ("teaser", wagtail_dot_org_blocks.TeaserBlock()),
            ("standalonecta", wagtail_dot_org_blocks.StandaloneCTABlock()),
            ("highlight", wagtail_dot_org_blocks.HighlightBlock()),
            ("iconbullets", wagtail_dot_org_blocks.IconBulletsBlock()),
            ("quotes", wagtail_dot_org_blocks.QuotesBlock()),
            ("getstartedchooser", wagtail_dot_org_blocks.GetStartedChooserBlock()),
            ("quote", pages_blocks.QuoteBlock()),
            ("richtext", pages_blocks.RichTextBlock()),
            ("textandmedia", pages_blocks.TextAndMediaBlock()),
            ("signupform", pages_blocks.SignupFormBlock()),
            ("comparisontable", pages_blocks.ComparisonTableBlock()),
            ("cards", pages_blocks.CardsBlock()),
        ],
        default="",
        verbose_name="Body",
        blank=True,
    )
    sub_heading = models.TextField(verbose_name="Sub heading", blank=True, default="")

    hero_panels = [
        FieldPanel("heading"),
        FieldPanel("sub_heading"),
        FieldPanel("icon"),
        FieldPanel("cta_text"),
        PageChooserPanel("cta_page"),
        FieldPanel("cta_url"),
        FieldPanel("intro"),
    ]
    content_panels = Page.content_panels + [
        MultiFieldPanel(heading="Hero", children=hero_panels),
        StreamFieldPanel("body"),
    ]

    parent_page_types = [
        "pages.ContentPage",
        "pages.HomePage",
        "pages.BlogPage",
    ]

    class Meta:
        verbose_name = "Content page"


class Bag:
    def __init__(self, line):
        split1 = line.split(' contain ')
        split2 = split1[0].split(' ')
        self.color = '_'.join(split2[0:2])
        contents = split1[1]
        self.contents = []
        if not contents.startswith('no'):
            for c in contents.split(', '):
                split3 = c.split(' ')
                self.contents.append(InnerBag(split3[0], '_'.join(split3[1:3])))

    def __str__(self):
        return '%s %s' % (self.color, [str(c) for c in self.contents])

class InnerBag:
    def __init__(self, quantity, color):
        self.quantity = int(quantity)
        self.color = color

    def __str__(self):
        return '%s %s' % (self.quantity, self.color)

input = open('input/day07.txt').readlines()
all_bags = {}
outer_bags = {}
for i in input:
    bag = Bag(i)
    all_bags[bag.color] = bag
    for c in bag.contents:
        if c.color in outer_bags:
            outer_bags[c.color].append(bag.color)
        else:
            outer_bags[c.color] = [bag.color]

# https://www.reddit.com/r/adventofcode/comments/k8cbhv/2020_day_7_part_1_incorrect_solution_count_is_too/
bags = set()  # Outer bags
bags_to_scan = {'shiny_gold'}

# Scan for new parent bags.
while bags_to_scan:
	# Keep track of new outer bags so we can scan their parents in the next loop.
    new_bags = set()

    for bag in bags_to_scan:
		# Look at all possible parents that can contain this bag
        if bag in outer_bags:
            for parent in outer_bags[bag]:
                # If this parent hasn't already been found, keep track of it.
                if parent not in bags:
                    new_bags.add(parent)

	# Add the new bags to our main list.
    bags |= new_bags

	# Replace the scan list with the new bags we found
    bags_to_scan = new_bags

print("Part 1:", len(bags))

# https://github.com/voidlessVoid/advent_of_code_2020/blob/main/day_07/michael/solution.py
def count_contents(current_bag):
    if not current_bag.contents:
        return 0
    return sum([count_contents(all_bags[bag.color]) * bag.quantity + bag.quantity \
        for bag in current_bag.contents])

print("Part 2:", count_contents(all_bags["shiny_gold"]))


tcno = input("TC Kimlik No İlk 9 Hanesini Giriniz: ")
a, b, toplamDokuz = 0, 0, 0
for i in range(9):
    toplamDokuz = toplamDokuz+int(tcno[i])
    if i%2 == 0:
        a = a+7*int(tcno[i])
    elif i%2 == 1:
        b = b+int(tcno[i])
    if i == 8:
        haneOn = (a-b)%10
        haneOnBir = (haneOn+toplamDokuz)%10
        print(tcno+str(haneOn)+str(haneOnBir))


input = "2276696"

MAPPING = ('0', '1', 'ABC', 'DEF', 'GHI', 'JKL', 'MNO', 'PQRS', 'TUV', 'WXYZ')

def phone_mnemonic(phone_number):
    def phone_mnemonic_helper(digit):
        if digit == len(phone_number):
            # All digits are processed, so add partial_mnemonic to mnemonic.
            # (We add a copy since subsequent calls modify partial_mnemonic).
            mnemonics.append(''.join(partial_mnemonic))
        else:
            # Try all possible characters for this digit.
            for c in MAPPING[int(phone_number[digit])]:
                partial_mnemonic[digit] = c
                phone_mnemonic_helper(digit + 1)

    mnemonics, partial_mnemonic = [], [0] * len(phone_number)
    phone_mnemonic_helper(0)

    return mnemonics

result = phone_mnemonic(input)

print(result)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jul 28 13:54:18 2021

@author: carter
"""

import subprocess
import pandas as pd
import fz_util as util
import re

### read in arguments
args = util.get_args()
default_args = {'chunks': 1,
                'starts': None,
                'stops': None,
                'partition': 'standard', # standard, long, highmem, gpu
                'walltime': '24:00:00', # '2-00:00:00'
                'cpus': 1,
                'gigs': 8,
                'jobname': args['runcode'],
                'bashfilename': args['runcode'].split('.')[0]}
args = {**default_args, **args}

### adjust partition name
school = util.server_school()
if school == 'chicago' and args['partition'] == 'general':
    args['partition'] = 'standard'
elif school == 'indiana' and args['partition'] == 'standard':
    args['partition'] = 'general'

### assign arguments
runcode = args['runcode']
chunks = args['chunks']
starts = args['starts']
stops = args['stops']
partition = args['partition']
walltime = args['walltime']
cpus = args['cpus']
gigs = args['gigs']
jobname = args['jobname']
bashfilename = args['bashfilename']

### directories
dirs = util.get_dirs()
projdir = dirs['bashdir']
logdir = dirs['logdir']
codedir = dirs['codedir']
pythonpath = dirs['pythonpath']

### number of jobs and basic parameters
N = chunks
exefile = codedir + runcode

### get starts and stops
if starts is None or stops is None:
    runlist = []
elif type(starts) == int:
    runlist = list(range(starts, stops+1))
else:
    starts = [int(x) for x in starts.split(',')]
    stops = [int(x) for x in stops.split(',')]
    runlist = []
    for start, stop in zip(starts, stops):
        runlist += list(range(start, stop+1))

def get_jobN(name):
    matches = re.findall('\d+', name)
    if len(matches) > 0:
        return matches[-1]
    return ''

### get status
def get_queue():
    status = subprocess.run(['squeue',  '--user=cdavis40'], stdout = subprocess.PIPE)
    status = str(status).split('\\n')
    status = status[1:-1]
    colnames = ['jobid', 'partition', 'name', 'user', 'st', 'time', 'nodes', 'reason']
    outdata = []
    if status == []:
        return pd.DataFrame(columns = colnames + ['jobN'])
    for row in status:
        row = row.split(' ')
        row = [x for x in row if x != '']
        outdata.append(dict(zip(colnames, row)))
    outdata = pd.DataFrame(outdata)
    outdata['jobN'] = [get_jobN(name) for name in outdata.name]
    return(outdata)

def cancel_job(idnumb):
    subprocess.run(['scancel', idnumb])

def submit_job(ii):
    subprocess.run(['sbatch', projdir + str(ii) + bashfilename + '.sh'])

### create submit files
for i in range(N):
    if len(runlist) == 0 or (i+1) in runlist:
        print('Writing Job File Number %d' % (i+1))
        args['chunkid'] = i+1
        with open(projdir + str(i+1) + bashfilename + '.sh', 'w') as fptr:
            fptr.write('#!/bin/bash\n')
            if school == 'chicago':
                fptr.write('#SBATCH --account=phd\n')
            fptr.write('#SBATCH --partition=' + partition + '\n')
            if school == 'chicago':
                fptr.write('#SBATCH --cpus-per-task=' + str(cpus) + '\n')
                fptr.write('#SBATCH --mem-per-cpu=' + str(gigs) + 'G\n')
            if school == 'indiana':
                fptr.write('#SBATCH --mem=' + str(gigs) + 'G\n')
            fptr.write('#SBATCH --time=' + walltime + '\n')
            fptr.write('#SBATCH --job-name=' + str(i+1) + jobname + '\n')
            fptr.write('#SBATCH --output="' + logdir + bashfilename + str(i+1) + '-%A.log"\n')
            if school == 'indiana':
                fptr.write('module load python\n')
            fptr.write('export PYTHONPATH="' + pythonpath + ':$PYTHONPATH"\n')
            if school == 'chicago':
                fptr.write('/home/cdavis40/anaconda3/bin/python ' + exefile + util.args_to_string(args) + '\n\n')
            if school == 'indiana':
                fptr.write('python ' + exefile + util.args_to_string(args) + '\n\n')

### submit jobs
for i in range(N):
    if len(runlist) == 0 or (i+1) in runlist:
        print('Submitting Job %d:' % (i+1))
        submit_job(i+1)
        print('\tJob %d Submitted' % (i+1))


#!/bin/python3

from sys import argv
from pathlib import Path
import shutil

selection = []
extensions = []

if __name__ == "__main__":
    out_dir = "protocols"
    ext_dir = "/usr/share/wayland-protocols"
    base_dir = "/usr/share/wayland"

    out_dir = Path(out_dir)
    if not (out_dir.exists() and out_dir.is_dir()):
        print("Output directory does not exist!")
        exit()

    ext_dir = Path(ext_dir)
    if not (ext_dir.exists() and ext_dir.is_dir()):
        print("Could not find protocols directory!")
        exit()

    core = Path(base_dir) / "wayland.xml"
    if not (core.exists() and core.is_file()):
        print("Could not find wayland core protocol!")
        exit()

    shutil.copyfile(core, out_dir / "wayland.xml")

    print("Protocols:")
    fs = ext_dir.rglob("*.xml")
    for i, p in enumerate(fs):
        s = str(p.relative_to(ext_dir))
        print(f"[{i + 1}]: " + s)
        extensions.append(p)
    print()

    if len(extensions) == 0:
        print("No protocols found!")
        exit()

    print("The following selection is a space-seperated list of indexes (e.g. '1 5 3') and both-inclusive ranges (e.g. '5-10').")
    print("No protocols are selected by default.")
    print("The tokens are evaluated in the order they appear.")
    print("'^' inverts the selection, '*' means everything")
    s = input("Select protocols: ")

    if s == "":
        print("No protocols selected!")
        exit()

    for ps in s.split(" "):
        p = None
        inverted = False
        if ps.startswith("^"):
            inverted = True
            ps = ps[1:]

        if ps == "*":
            p = (1, len(extensions))
        elif ps.count("-") == 1:
            (p1, p2) = ps.split("-")
            if not p1.isnumeric():
                print(f"Invalid selection! Could not recognize '{p1}'")
                exit()
            if not p2.isnumeric():
                print(f"Invalid selection! Could not recognize '{p2}'")
                exit()
            p1 = int(p1)
            p2 = int(p2)
            if p1 > p2:
                p = (p2, p1)
            elif p1 == p2:
                p = p1
            else:
                p = (p1, p2)
        elif ps.isnumeric():
            p = int(ps)
        else:
            print(f"Invalid selection! Could not recognize '{ps}'")
            exit()
        if type(p) is int:
            if p < 1 or p > len(extensions):
                print(f"Invalid selection! '{p}' is out of range 1-{len(extensions)}")
                exit()
            if not inverted:
                if not (p - 1) in selection:
                    selection.append(p - 1)
            else:
                if (p - 1) in selection:
                    selection.remove(p - 1)
        elif type(p) == tuple:
            if not inverted:
                for l in range(p[0] - 1, p[1]):
                    if not l in selection:
                        selection.append(l)
            else:
                for l in range(p[0] - 1, p[1]):
                    if l in selection:
                        selection.remove(l)
    print()

    if len(selection) == 0:
        print("No protocols selected!")
        exit()

    print("Selected:")
    for x in selection:
        o = extensions[x]
        c = Path(out_dir, o.name)
        print("[" + str(x + 1) + "] " + str(extensions[x]) + " -> " + str(c))

    i = input("Begin copying? [Y/n] ")
    if not (i.lower() == "" or i.lower() == "y" or i.lower() == "yes"):
        print("No confirmation given. Stopping...")
        exit()

    for x in selection:
        o = extensions[x]
        c = Path(out_dir, o.name)
        if not (o.exists() and o.is_file()):
            print("ERROR! Protocol file doesn't exist anymore!!")
            exit()
        if c.exists():
            if c.is_dir():
                print("ERROR! Output location is already a directory!")
                exit()
        shutil.copyfile(o, c)

    print("done.")


#정렬

##########버블정렬##########
def bubble_sort(array):
     compare=0
     change=0

     for i in range(len(array)-1):
         for j in range(len(array)-1):
             if (array[j]>array[j+1]):
                 change += 1
                 buffer = array[j]
                 array[j] = array[j+1]
                 array[j+1] = buffer
             compare += 1
     print(array)

     return array;
##########선택정렬##########
def selection_sort(array):
     compare=0
     change=0

     for i in range(len(array)-1):
         pivot = i
         for j in range(i, len(array)-1):
             if (array[pivot]>=array[j+1]):
                 pivot += 1
             compare += 1
         change += 1
         buffer = array[i]
         array[i] = array[pivot]
         array[pivot] = buffer
         compare += 1
     print(array)

     return array;

selection_sort([5,3,1,2,4])


# src/hypermodern_python/console.py
import textwrap
import locale
import click
import requests

from . import __version__

API_URL = "https://en.wikipedia.org/api/rest_v1/page/random/summary"

@click.command()
@click.version_option(version=__version__)
def main():
    """The hypermodern Python project."""

    # Get and set locale language
    locale_lang, locale_encoding = locale.getdefaultlocale()
    click.echo(textwrap.fill(locale_lang + " : " + locale_encoding))

    # Language selector
    LANG_SLICE = slice(8,10)

    NEW_URL = list(API_URL)
    NEW_URL[LANG_SLICE] = 'en'
    NEW_URL = ''.join(NEW_URL)

    click.echo(textwrap.fill(NEW_URL))

    with requests.get(NEW_URL) as response:
        try:
            response.raise_for_status()
            data = response.json()

            title = data["title"]
            extract = data["extract"]

            click.secho(title, fg="green")
            click.echo(textwrap.fill(extract))

        except requests.exceptions.HTTPError as err:
            click.secho("HTTP Error", fg="red")
            # click.echo(textwrap.fill(err))
            raise SystemExit(err)