"""
views for application geokret
"""

import re
from datetime import datetime
from lxml import etree

from django.http import HttpResponse
from django.shortcuts import render
from django.template.loader import render_to_string
from django.db.models import Max
from django.utils.translation import ugettext_lazy as _

from gpsfun.main.db_utils import get_object_or_none
from gpsfun.main.ajax import accept_ajax
from gpsfun.main.db_utils import sql2table
from gpsfun.main.GeoKrety.models import GeoKret
from gpsfun.main.GeoName.models import GeoCountry
from gpsfun.main.models import LogUpdate, log_api
from gpsfun.main.utils import points_rectangle
from gpsfun.main.utils import MAX_POINTS

GEOKRETY_ONMAP_STATES = [0, 3]
SEARCH_TOOLTIP = _("Geokret or waypoint")

class KretyWaypoint:
    """ Kret waypoint """
    waypoint = None
    latitude = None
    longitude = None
    count = 0
    distance = 0

def geokrety_map(request):
    """ get map with geokrety """
    krety = []

    default_mapbounds = {
        'bottom': 49.5,
        'top': 50.5,
        'left': 36.2,
        'right': 36.6,
    }

    def rectagle_center(rectangle):
        """ get center of the rectangle """
        return {
            'lat': (rectangle['bottom'] + rectangle['top']) / 2.0,
            'lng': (rectangle['left'] + rectangle['right']) / 2.0
        }

    map_zoom = request.session.get('geokrety_zoom') or 14

    user_waypoint = request.session.get('geokrety_map_waypoint', '')
    geokret_waypoint = request.session.get('geokret_waypoint')
    mapbounds = request.session.get('geokrety_mapbounds') or default_mapbounds
    map_center = request.session.get(
        'geokrety_center') or rectagle_center(default_mapbounds)
    krety = waypoints_rectangle(mapbounds)

    update_date = LogUpdate.objects.filter(update_type='kret')\
        .aggregate(last_date=Max('update_date'))

    return render(
        request,
        'Map/geokrety_map.html',
        {
            'geokrety': krety,
            'geokrety_count': len(krety),
            'map_rect': points_rectangle(krety),
            'update_date': update_date.get("last_date"),
            'tooltip_text': SEARCH_TOOLTIP,
            'user_waypoint': user_waypoint,
            'max_points': MAX_POINTS,
            'map_center': map_center,
            'map_zoom': map_zoom,
            'geokret_waypoint': geokret_waypoint,
        })

@accept_ajax
def map_geokret_info(request):
    """ get map information """
    result = {'status': 'ERR'}
    waypoint = request.GET.get('waypoint')
    krety = GeoKret.objects.filter(
        waypoint=waypoint,
        state__in=GEOKRETY_ONMAP_STATES)
    krety = krety.order_by('name')
    waypoint_url = url_by_waypoint(waypoint)
    result['content'] = render(
        request,
        'Map/geokret_info.html',
        {
            'geokrety': krety,
            'waypoint': {
                'code': waypoint,
                'url_to': waypoint_url}
        })
    result['status'] = 'OK'

    return result

@accept_ajax
def geokrety_map_get_geokrety(request):
    """ get list of geokrety """
    result = {'status': 'ERR'}

    mapbounds = {
        'top': float(request.GET.get('top') or 0),
        'left': float(request.GET.get('left') or 0),
        'bottom': float(request.GET.get('bottom') or 0),
        'right': float(request.GET.get('right') or 0),
    }

    request.session['geokrety_mapbounds'] = mapbounds
    request.session['geokrety_zoom'] = request.GET.get('zoom') or 14
    request.session['geokrety_center'] = {
        'lat': request.GET.get('center_lat'),
        'lng': request.GET.get('center_lng'), }
    # user_waypoint = request.session.get('geokrety_map_waypoint', '')
    krety = waypoints_rectangle(mapbounds)

    result['krety'] = get_kret_list(krety)
    result['rect'] = points_rectangle(krety)
    result['count'] = len(krety)
    result['status'] = 'OK'

    return result

@accept_ajax
def geokrety_map_change_country(request):
    """ change country """
    result = {'status': 'ERR'}
    country_code = request.GET.get('country')
    request.session['geokrety_map_country'] = country_code

    if not country_code:
        return result

    if country_code != 'SEARCH':
        request.session['geokrety_map_waypoint'] = None

    country = get_object_or_none(GeoCountry, iso=country_code)

    address = 'Ukraine, Kharkov'
    if country:
        address = f'{country.name},{country.capital}'

    krety = waypoints_with_geokrety(country_code)

    result['krety'] = get_kret_list(krety)
    result['rect'] = points_rectangle(krety)
    result['address'] = address
    result['status'] = 'OK'

    return result

@accept_ajax
def geokrety_map_search_waypoint(request):
    """ search waypoint """
    result = {'status': 'ERR'}

    waypoint = request.GET.get('waypoint')
    request.session['geokrety_map_waypoint'] = waypoint

    if waypoint is None:
        return result

    found_kret = None
    krety = []

    if waypoint:
        krety = waypoints_by_mask(waypoint)[:1]
        if krety:
            found_kret = {
                'lat': krety[0].latitude,
                'lng': krety[0].longitude}
            request.session['geokret_waypoint'] = found_kret

            # krety_list = get_kret_list(krety)
            rect = points_rectangle(krety)

            mapbounds = {
                'top': rect['lat_max'],
                'left': rect['lng_min'],
                'bottom': rect['lat_min'],
                'right': rect['lng_max'],
            }
            krety = waypoints_rectangle(mapbounds)
    if not krety:
        mapbounds = request.session.get('geokrety_mapbounds')
        krety = waypoints_with_geokrety_rectangle(mapbounds)

    result['krety'] = get_kret_list(krety)
    result['rect'] = points_rectangle(krety)
    result['kret_waypoint'] = found_kret
    result['status'] = 'OK'

    return result

def waypoints_with_geokrety(user_country):
    """ get list of waypoints """
    sql = None
    if user_country == 'SEARCH':
        return []
    if user_country and len(user_country) == 2:
        sql = get_country_sql(user_country)
    if user_country and user_country == 'ALL':
        sql = get_all_countries_sql()
    if user_country and user_country == 'NONE':
        sql = get_no_country_sql()

    return get_krety_list(sql)

def waypoints_with_geokrety_rectangle(mapbounds):
    """ get list of waypoints for the rectangle """
    sql = get_rectangle_sql(mapbounds)
    return get_krety_list(sql)

def url_by_waypoint(waypoint):
    """ get url for waypoint """
    wpoint = ''
    su_t = re.compile(r'TR|MS\d+')
    if waypoint and len(waypoint) > 3:
        wpoint = waypoint.upper()
        treg = re.compile(r'\w{1,2}[\dA-F]+')
        if not treg.match(wpoint):
            wpoint = ''
    if wpoint and wpoint.startswith('OB'):
        return f'http://www.opencaching.nl/viewcache.php?wp={wpoint}'

    if su_t.match(wpoint):
        wpoint = f'{wpoint[:2]}/{wpoint[2:]}'

    return f'http://geokrety.org/go2geo/{wpoint}'

def geokrety_api_who_in_cache(request, cache_code):
    """ get geokrety in cache """
    root_tree = etree.Element('waypoint')
    root_tree.attrib['code'] = cache_code
    desc_tree = etree.SubElement(root_tree, 'description')
    desc_tree.text = 'Krety in Cache Listing Generated from gps-fun.info'
    url_tree = etree.SubElement(root_tree, 'url')
    url_tree.text = f'http://geokrety.org/szukaj.php?wpt={cache_code}'
    time_tree = etree.SubElement(root_tree, 'time')
    time_tree.text = datetime.now().isoformat()
    geokrety_tree = etree.SubElement(root_tree, 'geokrety')
    geokrety = GeoKret.objects.filter(
        state__in=GEOKRETY_ONMAP_STATES,
        waypoint=cache_code)
    for geokret in geokrety:
        geokret_tree = etree.SubElement(geokrety_tree, 'geokret')
        id_tree = etree.SubElement(geokret_tree, 'id')
        id_tree.text = str(geokret.gkid)
        refnum_tree = etree.SubElement(geokret_tree, 'refnum')
        refnum_tree.text = geokret.reference_number
        name_tree = etree.SubElement(geokret_tree, 'name')
        name_tree.text = geokret.name
        distance_tree = etree.SubElement(geokret_tree, 'distance')
        distance_tree.text = str(geokret.distance)
        kret_url_tree = etree.SubElement(geokret_tree, 'kret_url')
        kret_url_tree.text = geokret.url

    response_text = f'<?xml version="1.0" encoding="utf-8"?>{etree.tostring(root_tree).decode("utf-8")}'
    response = HttpResponse(response_text)
    response['Content-Type'] = 'text/xml'
    response['Content-Length'] = str(len(response_text))

    try:
        log_api('whoincache', request.META.get('REMOTE_ADDR', ''))
    except:
        pass

    return response

def waypoints_rectangle(mapbounds):
    """ get list of waypoints for map bounds """
    sql = all_krety_sql()
    if len(mapbounds.keys()):
        sql += f"""
        HAVING l.ns_degree > {mapbounds['bottom']}
            and l.ns_degree < {mapbounds['top']}
            and l.ew_degree > {mapbounds['left']}
            and l.ew_degree < {mapbounds['right']}
        """

    sql += f" LIMIT {MAX_POINTS + 1}"

    krety = get_krety_list(sql)

    return krety

def waypoint_mask_sql(waypoint):
    """ get sql query to get waypoints by the mask """
    if not waypoint:
        return all_krety_sql()

    sql = None
    wpoint = waypoint.strip().upper()
    pwp = re.compile(
        r'(OP|TR|MS|GC|OC|OX|GR|GL|OK|GA|OZ|TR|RH|OU|TC|OS|ON|OL|OJ|N|GE|WM|SH|TP|TB|OB)[\d,A-F]*')  # OB GL
    pgk = re.compile(r'GK([\d,A-F]+)')
    if pwp.match(wpoint) and len(wpoint) < 9:
        return waypont_sql(wpoint)

    if pgk.match(wpoint):
        hexcode = pgk.findall(wpoint)
        if hexcode and len(hexcode):
            hexcode = hexcode[0]
            try:
                kret_id = int(hexcode, 16)
            except:
                kret_id = 0
            return geokret_sql(kret_id)

    if not waypoint:
        return all_krety_sql()
    sql = kret_name_sql(waypoint)
    return sql

def waypoints_by_mask(waypoint):
    """ get list of waypoints by the mask """
    sql = waypoint_mask_sql(waypoint)
    return get_krety_list(sql)

def get_kret(kret_point):
    """ get geokret """
    krety = GeoKret.objects.filter(
        waypoint=kret_point.waypoint, state__in=(0, 3)).exclude(
            location__isnull=True)
    waypoint_url = krety[0].waypoint_url if krety.count() else ''

    return {
        'waypoint': kret_point.waypoint,
        'name': kret_point.waypoint,
        'distance': kret_point.distance or 0,
        'content': render_to_string(
            'Map/geokret_info.html',
            {
                'kret_point': kret_point,
                'krety': krety,
                'waypoint_url': waypoint_url}),
        'latitude': kret_point.latitude,
        'longitude': kret_point.longitude}

def get_kret_list(krety):
    """ get list of geokrety """
    return [get_kret(kret) for kret in krety]

def get_rectangle_sql(mapbounds):
    """ get sql query to get geokrety for map bounds """
    return f"""
        select
           kret.waypoint,
           l.ns_degree as latitude,
           l.ew_degree as longitude,
           COUNT(kret.id) as cnt,
           MAX(kret.distance) as distance
        from geokret kret
        left join location l on kret.location_id=l.id
        where kret.state in (0,3) and kret.waypoint is not null
            and length(kret.waypoint) > 0 and l.id is not null
            and l.ns_degree > {mapbounds['bottom']}
            and l.ns_degree < {mapbounds['top']}
            and l.ew_degree > {mapbounds['left']}
            and l.ew_degree < {mapbounds['right']}
        group by kret.waypoint, l.ns_degree, l.ew_degree
        """

def all_krety_sql():
    """ sql query to get all geokrety """
    return """
        select
           kret.waypoint,
           l.ns_degree,
           l.ew_degree,
           COUNT(kret.id) as cnt,
           MAX(kret.distance) as distance
        from geokret kret
        left join location l on kret.location_id=l.id
        where kret.state in (0,3) and kret.waypoint is not null
            and length(kret.waypoint) > 0 and l.id is not null
        group by kret.waypoint, l.ns_degree, l.ew_degree
        """

def get_country_sql(user_country):
    """ sql query to get geokrety for the country """
    return f"""
        select
           kret.waypoint,
           l.ns_degree,
           l.ew_degree,
           COUNT(kret.id) as cnt,
           MAX(kret.distance) as distance
        from geokret kret
        left join location l on kret.location_id=l.id
        where kret.country_code='{user_country}' and
            kret.state in (0,3) and kret.waypoint is not null
            and length(kret.waypoint) > 0 and l.id is not null
        group by kret.waypoint, l.ns_degree, l.ew_degree
        """

def get_all_countries_sql():
    """ get sql query to get geokrety for all countries """
    return """
        select
            kret.waypoint,
            l.ns_degree,
            l.ew_degree,
            COUNT(kret.id) as cnt,
            MAX(kret.distance) as distance
        from geokret kret
        left join location l on kret.location_id=l.id
        where
            kret.state in (0,3) and kret.waypoint is not null
            and length(kret.waypoint) > 0 and l.id is not null
        group by kret.waypoint, l.ns_degree, l.ew_degree
        """

def get_no_country_sql():
    """ get geokrety that is not linked to any country """
    return """
        select
            kret.waypoint,
            l.ns_degree,
            l.ew_degree,
            COUNT(kret.id) as cnt,
            MAX(kret.distance) as distance
        from geokret kret
        left join location l on kret.location_id=l.id
        where kret.country_code IS NULL and
            kret.state in (0,3) and kret.waypoint is not null
            and length(kret.waypoint) > 0 and l.id is not null
        group by kret.waypoint, l.ns_degree, l.ew_degree
        """

def waypont_sql(waypoint):
    """ get geokrety for the waypoint by mask """
    return f"""
        select
            kret.waypoint,
            l.ns_degree,
            l.ew_degree,
            COUNT(kret.id) as cnt,
            MAX(kret.distance) as distance
        from geokret kret
        left join location l on kret.location_id=l.id
        where kret.waypoint is not null and length(kret.waypoint) > 0
            and kret.waypoint RLIKE '^{waypoint}.*' and
            kret.state in (0,3)
            and l.id is not null
        group by kret.waypoint, l.ns_degree, l.ew_degree
        """

def geokret_sql(kret_id):
    """ query to get geokret by id """
    return f"""
            select
                kret.waypoint,
                l.ns_degree,
                l.ew_degree,
                COUNT(kret.id) as cnt,
                MAX(kret.distance) as distance
            from geokret kret
            left join location l on kret.location_id=l.id
            where kret.waypoint is not null and length(kret.waypoint) > 0
                and kret.gkid = {kret_id} and
                kret.state in (0,3)
                and l.id is not null
            group by kret.waypoint, l.ns_degree, l.ew_degree
            """

def kret_name_sql(name):
    """ query to get geokret by name """
    name = name.replace(' ', '%')
    return f"""
            select
                kret.waypoint,
                l.ns_degree,
                l.ew_degree,
                COUNT(kret.id) as cnt,
                MAX(kret.distance) as distance
            from geokret kret
            left join location l on kret.location_id=l.id
            where kret.waypoint is not null and length(kret.waypoint) > 0
                and kret.name LIKE '%{name}%' and
                kret.state in (0,3)
                and l.id is not null
            group by kret.waypoint, l.ns_degree, l.ew_degree
            """

def get_krety_list(sql):
    """ get krety using sql query """
    krety = []
    if not sql:
        return krety
    for row in sql2table(sql):
        kret = KretyWaypoint()
        kret.waypoint = row[0]
        kret.count = row[3]
        kret.latitude = row[1]
        kret.longitude = row[2]
        kret.distance = row[4]
        krety.append(kret)
    return krety


import glob
import os
import pickle
import re
from typing import Dict

import matplotlib.pyplot as plt
import pandas as pd

def load_lasso_data(data_dir):
    if not data_dir.endswith("/"):
        data_dir += "/"
    input_files = glob.glob(data_dir + "log2*pkl")
    Abs = [os.path.split(i)[-1].split("_mic")[0] + "_mic" for i in input_files]
    data_dict = {}
    for i in range(len(Abs)):
        with open(input_files[i], "rb") as a:
            data_dict[Abs[i]] = pickle.load(a)
    return data_dict

def convert_to_dataframe_lasso(CV_results):
    """
    For formatting the output of the lasso model
    """

    df_dictionary = {
        "left_out_clade": [],
        "training_accuracy": [],
        "testing_accuracy": [],
        "validation_accuracy": [],
    }  # will be converted to df
    for left_out_clade, d in CV_results.items():
        d_val = {i: d[i]["validation_accuracy"] for i in d.keys()}
        k = max(d_val, key=d_val.get)  # key with max validation data accuracy
        df_dictionary["left_out_clade"].append(left_out_clade)
        df_dictionary["training_accuracy"].append(d[k]["training_accuracy"])
        df_dictionary["testing_accuracy"].append(d[k]["testing_accuracy"])
        df_dictionary["validation_accuracy"].append(d[k]["validation_accuracy"])

    return pd.DataFrame(df_dictionary)

def convert_to_dataframe(CV_results, SVR_data=False):
    df_dictionary = {
        "left_out_clade": [],
        "training_accuracy": [],
        "testing_accuracy": [],
        "validation_accuracy": [],
    }  # will be converted to df
    for left_out_clade, d in CV_results.items():
        df_dictionary["left_out_clade"].append(left_out_clade)
        if isinstance(d, Dict):
            if SVR_data:
                df_dictionary["training_accuracy"].append(
                    d["accuracies"]["training_accuracy"]
                )
                df_dictionary["testing_accuracy"].append(
                    d["accuracies"]["testing_accuracy"]
                )
                df_dictionary["validation_accuracy"].append(
                    d["accuracies"]["validation_accuracy"]
                )
            else:
                df_dictionary["training_accuracy"].append(
                    d["accuracies"][0]["training_accuracy"]
                )
                df_dictionary["testing_accuracy"].append(
                    d["accuracies"][0]["testing_accuracy"]
                )
                df_dictionary["validation_accuracy"].append(
                    d["accuracies"][0]["validation_accuracy"]
                )
        else:
            df_dictionary["training_accuracy"].append(d.training_accuracy)
            df_dictionary["testing_accuracy"].append(d.testing_accuracy)
            df_dictionary["validation_accuracy"].append(d.validation_accuracy)

    return pd.DataFrame(df_dictionary)

def _get_NN_results(data_dir, file_suffix=".tsv"):
    """
    Returns data from NN fitting metrics in form to be plotted with plot_results
    """
    if not data_dir.endswith("/"):
        data_dir += "/"

    input_files = glob.glob(data_dir + f"*{file_suffix}")
    Abs = [os.path.split(i)[-1].split("_mic")[0] + "_mic" for i in input_files]

    data_dict = {}
    for Ab in set(Abs):
        Ab_files = [i for i in input_files if i.startswith(data_dir + Ab)]
        Ab_accuracies = [None] * len(Ab_files)
        i = 0
        for f in Ab_files:
            left_out_clade = re.search(r"clade_(.*?)_left", f).group(1)
            last_line = pd.read_csv(Ab_files[0], sep="\t").iloc[-1]
            accuracies = last_line[
                [
                    "training_data_acc",
                    "testing_data_acc",
                    "validation_data_acc",
                ]
            ]
            accuracies["left_out_clade"] = int(left_out_clade)
            Ab_accuracies[i] = accuracies
            i += 1
        df = pd.concat(Ab_accuracies, axis=1).transpose()
        df.set_index("left_out_clade", inplace=True)
        df.columns = [
            "training_accuracy",
            "testing_accuracy",
            "validation_accuracy",
        ]
        data_dict[Ab] = df

    return data_dict

def get_SVR_results(dir_pattern):
    Abs = ["log2_azm_mic", "log2_cip_mic", "log2_cro_mic", "log2_cfx_mic"]

    input_files = [os.path.join(dir_pattern[0], Ab, dir_pattern[1]) for Ab in Abs]

    data_dict = {}
    for i in range(len(Abs)):
        with open(input_files[i], "rb") as a:
            data_dict[Abs[i]] = pickle.load(a)
    return data_dict

def density_plot(preds, labels, axs=None, axs_0=None, axs_1=None):
    df = pd.DataFrame({"Predictions": preds, "Truth": labels})
    if axs is not None:
        df.plot(kind="kde", ax=axs[axs_0, axs_1], legend=False)
        return axs
    else:
        df.plot(kind="kde")

def plot_train_preds_and_labels(data, Ab):
    fig, axs = plt.subplots(4, 3, sharex=True, sharey=True)
    n = 0
    m = 0
    for left_out_clade, d in data[Ab].items():
        axs = density_plot(
            d["model_outputs"]["training_predictions"],
            d["model_outputs"]["training_labels"],
            axs=axs,
            axs_0=n,
            axs_1=m,
        )

        # axs = density_plot(d['model_outputs']['testing_predictions'],
        #                     d['model_outputs']['testing_labels'],
        #                     axs = axs,
        #                     axs_0 = n,
        #                     axs_1 = 1)

        # axs = density_plot(d['model_outputs']['validation_predictions'],
        #                     d['model_outputs']['validation_labels'],
        #                     axs = axs,
        #                     axs_0 = n,
        #                     axs_1 = 2)

        if n > 0 and n % 3 == 0:
            n = 0
            m += 1
        else:
            n += 1
    fig.tight_layout()

def bar_plot_of_results(data, filename):
    fig, axs = plt.subplots(1, 4, sharey=True)
    width = 0.2
    n = 0
    for Ab in data.keys():
        df = data[Ab]
        axs[n].bar(
            df.index - width,
            df.training_accuracy,
            width,
            label="Training Data",
        )
        axs[n].bar(df.index, df.testing_accuracy, width, label="Testing Data")
        axs[n].bar(
            df.index + width,
            df.validation_accuracy,
            width,
            label="Validation Data",
        )
        axs[n].set_xticks(df.index)
        axs[n].set_title(Ab.upper().split("_")[1])
        n += 1

    axs[n - 1].legend(loc="lower right")
    fig.text(0.5, 0.04, "Left Out Clade", ha="center")
    fig.text(0.04, 0.5, "Prediction Accuracy (%)", va="center", rotation="vertical")

    fig.savefig(filename)

def rename_test_and_validate(df: pd.DataFrame) -> pd.DataFrame:
    return df.rename(
        columns={
            "validation_accuracy": "testing_accuracy",
            "testing_accuracy": "validation_accuracy",
        }
    )

def box_plot_of_results(data, filename):
    fig, axs = plt.subplots(1, 4, sharey=True)
    n = 0
    for Ab in data.keys():
        df = data[Ab]
        df.rename(
            columns={
                "training_accuracy": "Train",
                "testing_accuracy": "Test",
                "validation_accuracy": "Validate",
            },
            inplace=True,
        )
        df = df[["Train", "Validate", "Test"]]
        axs[n].boxplot(df, notch=False, labels=df.columns)
        axs[n].set_title(Ab.upper().split("_")[1])
        axs[n].set(ylim=(0, 100))
        axs[n].tick_params(labelrotation=90)
        n += 1

    fig.text(0, 0.5, "Mean Accuracy per MIC Bin", va="center", rotation="vertical")
    fig.tight_layout()

    fig.savefig(filename)

if __name__ == "__main__":
    data_dir = "lasso_model/results/linear_model_results/cross_validation_results/"  # noqa: E501
    data = load_lasso_data(data_dir)

    # svr results are stored within subdir with name of Ab,
    # unlike rest of results which are all stored in one dir
    # dir_pattern = (
    #     "kernel_learning",
    #     "cluster_wise_cross_validation/SVR_results/SVR_CV_results_mean_acc_per_bin.pkl",
    # )
    # data_dir = "."
    # data = get_SVR_results(dir_pattern)

    Abs = list(data.keys())
    Abs.sort()  # to maintain order
    accuracy_data = {Ab: convert_to_dataframe(data[Ab]) for Ab in Abs}
    accuracy_data = {
        Ab: df.set_index("left_out_clade") for Ab, df in accuracy_data.items()
    }
    accuracy_data = {k: rename_test_and_validate(v) for k, v in accuracy_data.items()}

    box_plot_of_results(accuracy_data, os.path.join(data_dir, "CV_accuracy.png"))


# std
import multiprocessing as mp

# local
from recipes.logging import LoggingMixin

class ConservativePool(mp.pool.Pool):
    """
    Subclass of Pool which avoid making a potentially huge list when mapping over a function
    and is therefor more memory efficient
    """

    def _map_async(self, func, iterable, mapper, chunksize, callback=None,
                   error_callback=None):
        """
        Helper function to implement map, starmap and their async counterparts.
        """
        if self._state != 0:
            raise ValueError("Pool not running")
            #

        if chunksize is None:
            raise ValueError('Need chunksize')

        task_batches = self.__class__._get_tasks(func, iterable, chunksize)
        result = mp.pool.MapResult(self._cache, chunksize, N, callback,
                                   error_callback=error_callback)
        self._taskqueue.put((((result._job, i, mapper, (x,), {})
                              for i, x in enumerate(task_batches)), None))
        return result

class ProcessPool(LoggingMixin):
    '''A trimmed down version of mp.pool.Pool'''

    def __init__(self, inq, outq=None, processes=None, **kws):

        self.inq = inq
        self.outq = outq
        self.maintain = kws.get('maintain')
        self._kws = kws

        #self._state = RUN

        if processes is None:
            processes = os.cpu_count() or 1

        self._processes = processes
        self._pool = []
        self._repopulate_pool()

        self._worker_handler = threading.Thread(
            target=ProcessPool._handle_workers, args=(self,))
        self._worker_handler.daemon = True
        self._worker_handler._state = RUN
        self._worker_handler.start()

        # self._worker_monitor = threading.Thread(target=ProcessPool._monitor_workers,
        # args=(self,))
        #self._worker_monitor._state = RUN
        # self._worker_monitor.start()

    def _maintain_pool(self):
        """Clean up any exited workers and start replacements for them.
        """
        if self._join_exited_workers():
            if self.maintain.is_set():
                self._repopulate_pool()
                time.sleep(0.1)

    def _join_exited_workers(self):
        """Cleanup after any worker processes which have exited due to reaching
        their specified lifetime.  Returns True if any workers were cleaned up.
        """
        cleaned = False
        for i in reversed(range(len(self._pool))):
            worker = self._pool[i]
            if worker.exitcode is not None:
                # worker exited
                self.logger.info('cleaning up worker %d' % i)
                worker.join()
                self.logger.info('joined {:s}', worker)
                cleaned = True
                del self._pool[i]

        #alive = sum([p.is_alive() for p in self._pool])
        #worked = [p._completed.value() for p in self._pool]
        #names = [p.name for p in self._pool]
        # self.logger.info('Done cleaning. workers: {:d}; active: {:d};\n{:s}\n{:s}'
                # '' % (len(self._pool), alive, str(names), str(worked)))
        return cleaned

    def _repopulate_pool(self):
        """Bring the number of pool processes up to the specified number,
        for use after reaping workers which have exited.
        """
        for i in range(self._processes - len(self._pool)):
            w = self.Process(self.inq, self.outq, **self._kws)
            self._pool.append(w)
            #w.name = w.name.replace('Process', 'PoolWorker')
            w.daemon = False
            w.start()
            self.logger.info('Added worker')

        #alive = sum([p.is_alive() for p in self._pool])
        self.logger.info('Repopulated: workers: {:d};', len(self._pool))

    @staticmethod
    def _handle_workers(pool):
        thread = threading.current_thread()

        # Keep maintaining workers maintain condition is set
        i = 0
        while thread._state == RUN:
            i += 1
            if not (i % 5):
                worked = [p._completed.value() for p in pool._pool]
                pool.logger.debug('Tasks completed: {:s}' % str(worked))
            pool._maintain_pool()
            time.sleep(0.1)

        pool.logger.debug('worker handler exiting')

    # @staticmethod
    # def _monitor_workers(pool):
        #thread = threading.current_thread()

        # while pool.maintain.is_set():#thread._state == RUN:
        ##alive = sum([p.is_alive() for p in pool._pool])
        # pool.logger.info('# workers: {:d}' % (len(pool._pool),))
        # time.sleep(0.1)

        ##alive = sum([p.is_alive() for p in pool._pool])
        #worked = [p._completed.value() for p in pool._pool]
        #names = [p.name for p in pool._pool]
        # pool.logger.info('workers: {:d};\n{:s}\n{:s}'
        # '' % (len(pool._pool), str(names), str(worked)))

        #pool.logger.debug('_monitor_workers exiting')

    #
    # def kill_switch(self, sentinel=None):
        #self.logger.info('%s adding %i sentinels' %(self, len(self._pool)))
        # for w in self._pool:
        # self.inq.put(sentinel)

    # def close(self):
        #self.logger.info('closing pool')

        # if self._state == RUN:
        #self._state = CLOSE
        #self._worker_handler._state = CLOSE

        #self.logger.info('Adding {:d} sentinels' %len(self._pool))
        # for w in self._pool:
        # self.inq.put(None)
        #self.logger.debug('sentinel added')

    def join(self):

        self.logger.debug('joining pool: {:s}', self)
        self.logger.info('# workers: {:d}; ', len(self._pool))

        # Add a poison pill for each process in the pool
        for _ in range(len(self._pool)):
            self.inq.put(SENTINEL)

        # NOTE:
        # We expect that the pool will join all the exited processes.  However,
        # sometimes we are stuck with processes that never read anything from the
        # queue at all during their lifetime (only the dark lord knows why this
        # happens). Here we circumvent the deadlock with a timeout and termination #HACK
        # FIXME: Figure out why these processes sometimes get stuck like this to
        # avoid all this cruft!
        TIMEOUT = 5
        kill_switch = False
        start = time.time()
        while time.time() - start <= TIMEOUT:
            if any(p.is_alive() for p in self._pool):
                time.sleep(.1)  # Just to avoid hogging the CPU
            else:
                self.logger.info('All processes successfully joined')
                break
        else:
            self.logger.warning('TIMEOUT!')
            kill_switch = True

        # stop worker handler that has been trying to join the exited processes
        self._worker_handler._state = CLOSE
        self._worker_handler.join()
        self.logger.debug('_worker_handler joined')

        # We only enter this if we didn't 'break' above.
        if kill_switch:
            self.logger.warning(
                'These processes did not join before %.1f timeout: (%s). '
                'Killing them now.' % (TIMEOUT, ', '.join(map(str, self._pool)))
            )
            for p in self._pool:
                p.terminate()
                p.join()

            self.logger.info('Killing spree complete')

        # the queue may not be empty because of passive workers
        # (or some other reason!!??)
        while True:
            leftover = []
            try:
                leftover.append(self.inq.get_nowait())
                self.inq.task_done()
            except Empty:
                logging.debug('Queue is empty!')
                break
        if len(leftover):
            self.logger.warning('The following was left in the queue: %s'
                                % str(leftover))

        # All the processes in the pool are now stopped
        self.inq.join()
        self.logger.info('Queue joined: %s' % self)


from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #设置中文
plt.rcParams['font.family'] = 'sans-serif'
colorlist = ['r', 'b', 'g', 'y']

def mat_zhu(size_list, name_list):

    #调节图形宽、高
    plt.figure(figsize = (6,6))

    #横向柱状图
    #plt.barh(name_list,size_list,height=0.5,color=colorlist)

    #竖向柱状图
    plt.bar(name_list, size_list, width=0.5, color=colorlist)

    #添加主题和注释
    plt.title('协议与带宽分布') #主题
    plt.xlabel('带宽(M/S)') #X轴注释
    plt.ylabel('协议') #Y轴注释

    #保存成图片
    plt.savefig('result1.png')

    #绘制图形
    plt.show()
def mat_zhu_mark(size_list, name_list, x_label, y_label, title):
    #调节图形大小、宽、高
    fig = plt.figure(figsize = (6,6))
    ax = fig.add_subplot(111)

    fig.autofmt_xdate() #当x轴太拥挤的时候可以让他自适应

    ax.bar(name_list, size_list, width=0.5)

    plt.rcParams['font.sans-serif']=['SimHei']
    plt.title(title) #主题
    plt.xlabel(x_label)  #x轴注释
    plt.ylabel(y_label)  #y轴注释
    #保存图片
    plt.savefig('result.png')
    #绘制图形
    plt.show()

if __name__ == '__main__':
    counters = [30, 53, 12, 45]   #y轴数据
    protocols = ['http协议', 'ftp协议', 'rdp协议','qq协议']  #x轴数据
    mat_zhu(counters, protocols)


from urllib.error import URLError

from django.conf import settings
from django.core.mail import send_mail

from apps import celery_app
from apps.proxy.models import ProxyNode, UserTrafficLog
from apps.sspanel import models as m
from apps.utils import get_current_datetime

@celery_app.task
def debug_task():
    u = m.User.objects.first()
    print("i am in debug", u)

@celery_app.task
def sync_user_traffic_task(node_id, data):
    """
    这个接口操作比较重，所以为了避免发信号
    所有写操作都需要用BULK的方式
    1 更新节点流量
    2 更新用户流量
    3 记录节点在线IP
    4 关闭超出流量的节点
    """
    node: ProxyNode = ProxyNode.get_or_none(node_id)
    if not node:
        return
    node_total_traffic = 0
    log_time = get_current_datetime()
    user_model_list = []
    trafficlog_model_list = []
    traffic_data = data.get("data", [])

    # load user in batch
    user_ids = []
    for user_data in traffic_data:
        user_id = user_data["user_id"]
        user_ids.append(user_data["user_id"])
    user_map = {}
    for u in m.User.objects.filter(id__in=user_ids):
        user_map[u.id] = u

    for user_data in traffic_data:
        user_id = int(user_data["user_id"])
        u = int(int(user_data["upload_traffic"]) * node.enlarge_scale)
        d = int(int(user_data["download_traffic"]) * node.enlarge_scale)
        # 个人流量增量
        user = user_map[user_id]
        user.download_traffic += d
        user.upload_traffic += u
        user.last_use_time = log_time
        user_model_list.append(user)
        # 个人流量记录
        trafficlog_model_list.append(
            UserTrafficLog(
                proxy_node=node,
                user=user,
                download_traffic=u,
                upload_traffic=d,
                ip_list=user_data.get("ip_list", []),
            )
        )
        # 节点流量增量
        node_total_traffic += u + d

    if not traffic_data:
        # NOTE add blank log to show node is online
        trafficlog_model_list.append(UserTrafficLog(proxy_node=node))
    # 节点流量记录
    node.used_traffic += node_total_traffic
    if node.overflow:
        node.enable = False
    node.current_used_download_bandwidth_bytes = int(data.get("download_bandwidth", 0))
    node.current_used_upload_bandwidth_bytes = int(data.get("upload_bandwidth", 0))
    node.save(
        update_fields=[
            "used_traffic",
            "enable",
            "current_used_download_bandwidth_bytes",
            "current_used_upload_bandwidth_bytes",
        ]
    )
    # 用户流量
    m.User.objects.bulk_update(
        user_model_list,
        [
            "download_traffic",
            "upload_traffic",
            "last_use_time",
        ],
    )
    # 流量记录
    UserTrafficLog.objects.bulk_create(trafficlog_model_list)

@celery_app.task
def check_user_state_task():
    """检测用户状态，将所有账号到期的用户状态重置"""
    m.User.check_and_disable_expired_users()
    m.User.check_and_disable_out_of_traffic_user()

@celery_app.task
def auto_reset_free_user_traffic_task():
    """重置所有免费用户流量"""
    for user in m.User.objects.filter(level=0):
        user.reset_traffic(settings.DEFAULT_TRAFFIC)

@celery_app.task
def reset_node_traffic_task():
    """重置节点使用流量"""
    for node in ProxyNode.objects.all():
        node.used_traffic = 0
        node.save()

@celery_app.task
def make_up_lost_order_task():
    """定时补单"""
    try:
        m.UserOrder.make_up_lost_orders()
    except URLError:
        # Note请求支付宝挂了，等下次retry就好
        pass

@celery_app.task
def clean_traffic_log_task():
    """清空七天前的所有流量记录"""
    dt = get_current_datetime().subtract(days=7)
    query = UserTrafficLog.objects.filter(created_at__lt=dt)
    count = query._raw_delete(query.db)
    print(f"UserTrafficLog  removed count:{count}")

@celery_app.task
def send_mail_to_users_task(user_id_list, subject, message):
    users = m.User.objects.filter(id__in=user_id_list)
    address = [user.email for user in users]
    if send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, address):
        logs = [
            m.EmailSendLog(user=user, subject=subject, message=message)
            for user in users
        ]
        m.EmailSendLog.objects.bulk_create(logs)
        print(f"send email success user: address: {address}")
    else:
        raise Exception(f"Could not send mail {address} subject: {subject}")

@celery_app.task
def close_stale_tickets_task():
    m.Ticket.close_stale_tickets()


import MySQLdb as sql
import RPi.GPIO as GPIO
import time
from datetime import datetime

btn = 0
pin_1 = 15
pin_2 = 18
cnt = 1

db = sql.connect("localhost", "pi", "1234", "timeTable")
cur = db.cursor()
query = "INSERT INTO dbTable (num, btn, time) VALUES (%s, %s, %s)"

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin_1, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
GPIO.setup(pin_2, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)

while True and cnt < 11 :
    if btn == 0 and GPIO.input(pin_1) == GPIO.HIGH :
        t = datetime.now()
        dt = (cnt, 'A', (str(t.year) + '-' + str(t.month) + '-' + str(t.day) + ' ' + t.strftime("%H:%M:%S")))
        cur.execute(query, dt)
        db.commit()
        cnt += 1
        btn = 1
    elif btn == 1 and GPIO.input(pin_1) == GPIO.LOW :
        btn = 0

    if btn == 0 and GPIO.input(pin_2) == GPIO.HIGH :
        t = datetime.now()
        dt = (cnt, 'B', (str(t.year) + '-' + str(t.month) + '-' + str(t.day) + ' ' + t.strftime("%H:%M:%S")))
        cur.execute(query, dt)
        db.commit()
        cnt += 1
        btn = 1

    elif btn == 1 and GPIO.input(pin_2) == GPIO.LOW :
        btn = 0

    time.sleep(0.1)

    if cnt >= 11 :
        query = "SELECT * FROM dbTable"
        cur.execute(query)
        desc = cur.description
        print("=======================================")
        print(" 순번 | 버튼 정보 |       발생 시간       |")
        print("=======================================")
        while True:
            result = cur.fetchone()
            if not result: break
            print(' ', result[0], ' |      ', result[1], ' | ', result[2], '|')

cur.close()
db.close()


#!/usr/bin/env python
# encoding=utf-8
# maintainer: rgaudin

import inspect

import reversion
from django.db import models
from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _

from bolibana.models import EntityType, Report, MonthPeriod

class MalariaReport(Report):

    """ Complies with bolibana.reporting.DataBrowser """

    YES = 'Y'
    NO = 'N'
    YESNO = ((YES, _(u"Yes")), (NO, _(u"No")))

    class Meta:
        app_label = 'pnlp_core'
        verbose_name = _(u"Malaria Report")
        verbose_name_plural = _(u"Malaria Reports")
        unique_together = ('period', 'entity', 'type')

    u5_total_consultation_all_causes = models.PositiveIntegerField( \
                                           _(u"Total Consultation All Causes"))
    u5_total_suspected_malaria_cases = models.PositiveIntegerField( \
                                           _(u"Total Suspected Malaria Cases"))
    u5_total_simple_malaria_cases = models.PositiveIntegerField( \
                                              _(u"Total Simple Malaria Cases"))
    u5_total_severe_malaria_cases = models.PositiveIntegerField( \
                                              _(u"Total Severe Malaria Cases"))
    u5_total_tested_malaria_cases = models.PositiveIntegerField( \
                                              _(u"Total Tested Malaria Cases"))
    u5_total_confirmed_malaria_cases = models.PositiveIntegerField( \
                                           _(u"Total Confirmed Malaria Cases"))
    u5_total_treated_malaria_cases = models.PositiveIntegerField( \
                                             _(u"Total Treated Malaria Cases"))
    u5_total_inpatient_all_causes = models.PositiveIntegerField( \
                                              _(u"Total Inpatient All Causes"))
    u5_total_malaria_inpatient = models.PositiveIntegerField( \
                                                 _(u"Total Malaria Inpatient"))
    u5_total_death_all_causes = models.PositiveIntegerField( \
                                                  _(u"Total Death All Causes"))
    u5_total_malaria_death = models.PositiveIntegerField( \
                                                     _(u"Total Malaria Death"))
    u5_total_distributed_bednets = models.PositiveIntegerField( \
                                               _(u"Total Distributed Bednets"))

    o5_total_consultation_all_causes = models.PositiveIntegerField( \
                                           _(u"Total Consultation All Causes"))
    o5_total_suspected_malaria_cases = models.PositiveIntegerField( \
                                           _(u"Total Suspected Malaria Cases"))
    o5_total_simple_malaria_cases = models.PositiveIntegerField( \
                                              _(u"Total Simple Malaria Cases"))
    o5_total_severe_malaria_cases = models.PositiveIntegerField( \
                                              _(u"Total Severe Malaria Cases"))
    o5_total_tested_malaria_cases = models.PositiveIntegerField( \
                                              _(u"Total Tested Malaria Cases"))
    o5_total_confirmed_malaria_cases = models.PositiveIntegerField( \
                                           _(u"Total Confirmed Malaria Cases"))
    o5_total_treated_malaria_cases = models.PositiveIntegerField( \
                                             _(u"Total Treated Malaria Cases"))
    o5_total_inpatient_all_causes = models.PositiveIntegerField( \
                                              _(u"Total Inpatient All Causes"))
    o5_total_malaria_inpatient = models.PositiveIntegerField( \
                                                 _(u"Total Malaria Inpatient"))
    o5_total_death_all_causes = models.PositiveIntegerField( \
                                                  _(u"Total Death All Causes"))
    o5_total_malaria_death = models.PositiveIntegerField( \
                                                     _(u"Total Malaria Death"))

    pw_total_consultation_all_causes = models.PositiveIntegerField( \
                                           _(u"Total Consultation All Causes"))
    pw_total_suspected_malaria_cases = models.PositiveIntegerField( \
                                           _(u"Total Suspected Malaria Cases"))
    pw_total_severe_malaria_cases = models.PositiveIntegerField( \
                                              _(u"Total Severe Malaria Cases"))
    pw_total_tested_malaria_cases = models.PositiveIntegerField( \
                                              _(u"Total Tested Malaria Cases"))
    pw_total_confirmed_malaria_cases = models.PositiveIntegerField( \
                                           _(u"Total Confirmed Malaria Cases"))
    pw_total_treated_malaria_cases = models.PositiveIntegerField( \
                                             _(u"Total Treated Malaria Cases"))
    pw_total_inpatient_all_causes = models.PositiveIntegerField( \
                                              _(u"Total Inpatient All Causes"))
    pw_total_malaria_inpatient = models.PositiveIntegerField( \
                                                 _(u"Total Malaria Inpatient"))
    pw_total_death_all_causes = models.PositiveIntegerField( \
                                                  _(u"Total Death All Causes"))
    pw_total_malaria_death = models.PositiveIntegerField( \
                                                     _(u"Total Malaria Death"))
    pw_total_distributed_bednets = models.PositiveIntegerField( \
                                               _(u"Total Distributed Bednets"))
    pw_total_anc1 = models.PositiveIntegerField(_(u"Total ANC1 Visits"))
    pw_total_sp1 = models.PositiveIntegerField(_(u"Total SP1 given"))
    pw_total_sp2 = models.PositiveIntegerField(_(u"Total SP2 given"))

    stockout_act_children = models.CharField(_(u"ACT Children"), \
                                             max_length=1, choices=YESNO)
    stockout_act_youth = models.CharField(_(u"ACT Youth"), \
                                          max_length=1, choices=YESNO)
    stockout_act_adult = models.CharField(_(u"ACT Adult"), \
                                          max_length=1, choices=YESNO)
    stockout_artemether = models.CharField(_(u"Artemether"), \
                                           max_length=1, choices=YESNO)
    stockout_quinine = models.CharField(_(u"Quinine"), \
                                        max_length=1, choices=YESNO)
    stockout_serum = models.CharField(_(u"Serum"), max_length=1, choices=YESNO)
    stockout_bednet = models.CharField(_(u"Bednets"), \
                                       max_length=1, choices=YESNO)
    stockout_rdt = models.CharField(_(u"RDTs"), max_length=1, choices=YESNO)
    stockout_sp = models.CharField(_(u"SPs"), max_length=1, choices=YESNO)

    sources = models.ManyToManyField('MalariaReport', \
                                     verbose_name=_(u"Sources"), \
                                     blank=True, null=True)

    @property
    def total_consultation_all_causes(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_suspected_malaria_cases(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_simple_malaria_cases(self):
        # no value for pregnant_women
        return self.u5_total_simple_malaria_cases \
               + self.o5_total_simple_malaria_cases

    @property
    def total_severe_malaria_cases(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_tested_malaria_cases(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_confirmed_malaria_cases(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_treated_malaria_cases(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_inpatient_all_causes(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_malaria_inpatient(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_death_all_causes(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_malaria_death(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_anc1(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_sp1(self):
        return self.total_for_field(inspect.stack()[0][3])

    @property
    def total_sp2(self):
        return self.total_for_field(inspect.stack()[0][3])

    def total_for_field(self, field):
        values = []
        for cat in ('u5', 'o5', 'pw'):
            fname = '%s_%s' % (cat, field)
            if hasattr(self, fname):
                values.append(getattr(self, fname))
        return sum(values)

    @property
    def mperiod(self):
        """ casted period to MonthPeriod """
        mp = self.period
        mp.__class__ = MonthPeriod
        return mp

    @classmethod
    def start(cls, period, entity, author, \
               type=Report.TYPE_SOURCE, *args, **kwargs):
        """ creates a report object with meta data only. Object not saved """
        report = cls(period=period, entity=entity, created_by=author, \
                     modified_by=author, _status=cls.STATUS_CREATED, \
                     type=type)
        for arg, value in kwargs.items():
            try:
                setattr(report, arg, value)
            except AttributeError:
                pass

        return report

    def add_underfive_data(self, total_consultation_all_causes, \
                                 total_suspected_malaria_cases, \
                                 total_simple_malaria_cases, \
                                 total_severe_malaria_cases, \
                                 total_tested_malaria_cases, \
                                 total_confirmed_malaria_cases, \
                                 total_treated_malaria_cases, \
                                 total_inpatient_all_causes, \
                                 total_malaria_inpatient, \
                                 total_death_all_causes, \
                                 total_malaria_death, \
                                 total_distributed_bednets):
        self.u5_total_consultation_all_causes = total_consultation_all_causes
        self.u5_total_suspected_malaria_cases = total_suspected_malaria_cases
        self.u5_total_simple_malaria_cases = total_simple_malaria_cases
        self.u5_total_severe_malaria_cases = total_severe_malaria_cases
        self.u5_total_tested_malaria_cases = total_tested_malaria_cases
        self.u5_total_confirmed_malaria_cases = total_confirmed_malaria_cases
        self.u5_total_treated_malaria_cases = total_treated_malaria_cases
        self.u5_total_inpatient_all_causes = total_inpatient_all_causes
        self.u5_total_malaria_inpatient = total_malaria_inpatient
        self.u5_total_death_all_causes = total_death_all_causes
        self.u5_total_malaria_death = total_malaria_death
        self.u5_total_distributed_bednets = total_distributed_bednets

    def add_overfive_data(self, total_consultation_all_causes, \
                                 total_suspected_malaria_cases, \
                                 total_simple_malaria_cases, \
                                 total_severe_malaria_cases, \
                                 total_tested_malaria_cases, \
                                 total_confirmed_malaria_cases, \
                                 total_treated_malaria_cases, \
                                 total_inpatient_all_causes, \
                                 total_malaria_inpatient, \
                                 total_death_all_causes, \
                                 total_malaria_death):
        self.o5_total_consultation_all_causes = total_consultation_all_causes
        self.o5_total_suspected_malaria_cases = total_suspected_malaria_cases
        self.o5_total_simple_malaria_cases = total_simple_malaria_cases
        self.o5_total_severe_malaria_cases = total_severe_malaria_cases
        self.o5_total_tested_malaria_cases = total_tested_malaria_cases
        self.o5_total_confirmed_malaria_cases = total_confirmed_malaria_cases
        self.o5_total_treated_malaria_cases = total_treated_malaria_cases
        self.o5_total_inpatient_all_causes = total_inpatient_all_causes
        self.o5_total_malaria_inpatient = total_malaria_inpatient
        self.o5_total_death_all_causes = total_death_all_causes
        self.o5_total_malaria_death = total_malaria_death

    def add_pregnantwomen_data(self, total_consultation_all_causes, \
                                 total_suspected_malaria_cases, \
                                 total_severe_malaria_cases, \
                                 total_tested_malaria_cases, \
                                 total_confirmed_malaria_cases, \
                                 total_treated_malaria_cases, \
                                 total_inpatient_all_causes, \
                                 total_malaria_inpatient, \
                                 total_death_all_causes, \
                                 total_malaria_death, \
                                 total_distributed_bednets, \
                                 total_anc1, \
                                 total_sp1, \
                                 total_sp2):
        self.pw_total_consultation_all_causes = total_consultation_all_causes
        self.pw_total_suspected_malaria_cases = total_suspected_malaria_cases
        self.pw_total_severe_malaria_cases = total_severe_malaria_cases
        self.pw_total_tested_malaria_cases = total_tested_malaria_cases
        self.pw_total_confirmed_malaria_cases = total_confirmed_malaria_cases
        self.pw_total_treated_malaria_cases = total_treated_malaria_cases
        self.pw_total_inpatient_all_causes = total_inpatient_all_causes
        self.pw_total_malaria_inpatient = total_malaria_inpatient
        self.pw_total_death_all_causes = total_death_all_causes
        self.pw_total_malaria_death = total_malaria_death
        self.pw_total_distributed_bednets = total_distributed_bednets
        self.pw_total_anc1 = total_anc1
        self.pw_total_sp1 = total_sp1
        self.pw_total_sp2 = total_sp2

    def add_stockout_data(self, stockout_act_children, \
                                stockout_act_youth, \
                                stockout_act_adult, \
                                stockout_artemether, \
                                stockout_quinine, \
                                stockout_serum, \
                                stockout_bednet, \
                                stockout_rdt, \
                                stockout_sp):
        self.stockout_act_children = stockout_act_children
        self.stockout_act_youth = stockout_act_youth
        self.stockout_act_adult = stockout_act_adult
        self.stockout_artemether = stockout_artemether
        self.stockout_quinine = stockout_quinine
        self.stockout_serum = stockout_serum
        self.stockout_bednet = stockout_bednet
        self.stockout_rdt = stockout_rdt
        self.stockout_sp = stockout_sp

    def fill_blank(self):
        self.add_underfive_data(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
        self.add_overfive_data(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
        self.add_pregnantwomen_data(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
        self.add_stockout_data(self.NO, self.NO, self.NO, self.NO, self.NO, \
                               self.NO, self.NO, self.NO, self.NO)

    def to_dict(self):
        d = {}
        for field in self._meta.get_all_field_names():
            try:
                if not field.split('_')[0] in ('u5', 'o5', 'pw', 'stockout'):
                    continue
            except:
                continue
            d[field] = getattr(self, field)
        return d

    @classmethod
    def generate_receipt(cls, instance):
        """ generates a reversable text receipt for a MalariaReport

        FORMAT:
            RR000/sss-111-D
            RR: region code on two letters
            000: internal report ID
            sss: entity slug
            111: sent day in year
            D: sent day of week """

        DOW = ['D', 'L', 'M', 'E', 'J', 'V', 'S']
        region_type = EntityType.objects.get(slug='region')

        def region_id(slug):
            return slug.upper()[0:2]

        region = 'ML'
        for ent in instance.entity.get_ancestors().reverse():
            if ent.type == region_type:
                region = region_id(ent.slug)
                break
        receipt = '%(region)s%(id)d/%(entity)s-%(day)s-%(dow)s' \
                  % {'day': instance.created_on.strftime('%j'), \
                     'dow': DOW[int(instance.created_on.strftime('%w'))], \
                     'entity': instance.entity.slug, \
                     'id': instance.id, \
                     'period': instance.period.id, \
                     'region': region}
        return receipt

    def get(self, slug):
        """ [data browser] returns data for a slug variable """
        return getattr(self, slug)

    def field_name(self, slug):
        """ [data browser] returns name of field for a slug variable """
        return self._meta.get_field(slug).verbose_name

    def validate(self):
        """ runs MalariaReportValidator """
        from pnlp_core.validators import MalariaReportValidator
        validator = MalariaReportValidator(self)
        validator.validate()
        return validator.errors

    @classmethod
    def create_aggregated(cls, period, entity, author, *args, **kwargs):
        agg_report = cls.start(period, entity, author, \
               type=Report.TYPE_AGGREGATED, *args, **kwargs)

        sources = MalariaReport.validated.filter(period=period, \
            entity__in=entity.get_children())

        if sources.count() == 0:
            agg_report.fill_blank()
            agg_report.save()

        for report in sources:
            for key, value in report.to_dict().items():
                pv = getattr(agg_report, key)
                if not pv:
                    nv = value
                elif pv in (cls.YES, cls.NO):
                    if pv == cls.YES:
                        nv = pv
                    else:
                        nv = value
                else:
                    nv = pv + value
                setattr(agg_report, key, nv)
            agg_report.save()

        for report in sources:
            agg_report.sources.add(report)

        with reversion.create_revision():
            agg_report.save()
            reversion.set_user(author.user)

        return agg_report

@receiver(pre_save, sender=MalariaReport)
def pre_save_report(sender, instance, **kwargs):
    """ change _status property of Report on save() at creation """
    if instance._status == instance.STATUS_UNSAVED:
        instance._status = instance.STATUS_CLOSED
    # following will allow us to detect failure in registration
    if not instance.receipt:
        instance.receipt = 'NO_RECEIPT'

@receiver(post_save, sender=MalariaReport)
def post_save_report(sender, instance, **kwargs):
    """ generates the receipt """
    if instance.receipt == 'NO_RECEIPT':
        instance.receipt = sender.generate_receipt(instance)
        instance.save()

reversion.register(MalariaReport)


#!/usr/bin/env python
from __future__ import print_function

from collections import defaultdict, namedtuple
from operator import add
from math import floor

class AutoInc(object):
    # ''' Get a uniquely auto-incremented integer value '''
    __slots__ = ('v',)

    def __init__(self, value=0):
        self.v = int(value)

    def __call__(self):
        self.v += 1
        return self.v

    def add(self, value):
        self.v += int(value)
        return self.v

    def __int__(self):
        return self.v

    def __float__(self):
        return float(self.v)

    def __long__(self):
        return long(self.v)

    def __repr__(self):
        return str(self.v)

    def __str__(self):
        return str(self.v)

class Histogram(defaultdict):

    @staticmethod
    def lexcmp(k0, k1):
        """ Hacky comparator to privilege string length """
        return cmp(len(k1), len(k0)) or cmp(k0, k1)

    @staticmethod
    def autoinc():
        return AutoInc()

    def __init__(self, *args, **kwargs):
        for arg in args:
            argclsname = arg.__class__.__name__
            if argclsname.startswith('FrozenHistogram'):
                # reconstitute FrozenHistogram
                kwargs.update(arg._asdict())
            elif (argclsname.startswith('Histogram') or
                  argclsname.startswith('defaultdict') or
                  argclsname.startswith('dict')):
                # copy-construct
                kwargs.update(dict(arg))
            else:
                # normal arg: column name
                kwargs.update({ str(arg): AutoInc() })
        super(Histogram, self).__init__(AutoInc, *tuple(), **kwargs)

    def prettyprint(self, **kwargs):
        from pprint import pformat
        return "%s(%s,\n%s)" % (
            self.__class__.__name__,
            AutoInc.__name__,
            pformat(dict(self), **kwargs))

    def __repr__(self):
        return self.prettyprint()

    def __str__(self):
        longest_key = sorted(self.iterkeys(),
                             cmp=Histogram.lexcmp,
                             reverse=False)[0]
        return self.prettyprint(depth=10,
                                width=len(longest_key))

    def inc(self, idx):
        return self[str(idx)]()

    def add(self, idx, value):
        return self[str(idx)].add(value)

    def val(self, idx):
        return int(self[idx])

    def keyset_hash(self):
        return hex(abs(hash(self.iterkeys())))

    def frozentype(self, rename=True):
        return namedtuple('FrozenHistogram_%s' % self.keyset_hash(),
            tuple(self.iterkeys()), rename=rename)

    def freeze(self):
        return self.frozentype()(**self)

    def normalize(self):
        ceil = float(sum(int(v) for v in self.itervalues()))
        return self.frozentype()(**dict(
            (ituple[0], float(ituple[1]) / ceil) for ituple in self.iteritems()
        ))

    def max(self):
        """ Maximum value """
        return max(*(int(v) for v in self.values()))

    def min(self):
        """ Minimum value """
        return min(*(int(v) for v in self.values()))

    def sum(self):
        return reduce(add, (int(v) for v in self.itervalues()))

    def average(self):
        """ Histogram mean/average (float) """
        return float(self.sum()) / float(len(self))

    def avg(self):
        """ Histogram mean/average (integer) """
        return int(floor(self.average()))

    def range(self):
        """ Histogram numerical range (integer) """
        return self.max() - self.min()

    def valuelist(self):
        return sorted(int(v) for v in self.itervalues())

    def median(self):
        """ Median histogram value (integer, or int/2) """
        vals = self.valuelist()
        idx = len(vals) / 2
        if len(vals) % 2:
            return vals[idx+1]
        return float(vals[idx] + vals[idx+1]) / 2.0

    def keys_for_value(self, value):
        """ List of keys with the given integer value """
        return map(lambda pair: pair[0],
            filter(lambda pair: int(pair[1]) == int(value),
            self.iteritems()))

    def valueset(self):
        return set(self.valuelist())

if __name__ == '__main__':
    # Hh = Histogram('color', 'phone', 'zip', 'firstname', 'lastname')
    Hh = Histogram('color', 'phone', 'zip', firstname=10, lastname=10)
    Hp = Histogram(firstname=0, lastname=0)

    Hh['color']()
    Hh['color']()
    Hh['color']()
    Hh['color']()
    Hh['color']()
    Hh['color']()

    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()
    Hh['phone']()

    Hh['zip']()
    Hh['zip']()
    Hh['zip']()
    Hh['zip']()

    print(Hh)
    print(Hh.freeze()._asdict())
    print(Hh.normalize())
    print('')

    # print("MAX Hh: %s" % max(*(int(v) for v in Hh.values())))
    print("MIN Hh: %s" % Hh.min())
    print("MAX Hh: %s" % Hh.max())
    print("SUM Hh: %s" % Hh.sum())
    print("AVG Hh: %s" % Hh.avg())
    print("RANGE Hh: %s" % Hh.range())
    print("MEDIAN Hh: %s" % Hh.median())
    print("KEYS IN Hh FOR 19: %s" % Hh.keys_for_value(19))
    print("KEYS IN Hh FOR 777: %s" % Hh.keys_for_value(777))
    print("KEYS IN Hh FOR 0: %s" % Hh.keys_for_value(0))
    print('')

    hh = Histogram(Hh, 'iheard', 'youlike', yo=10, dogg=100)

    print(hh)
    print(hh.freeze()._asdict())
    print(hh.normalize())
    print('')

    print("MIN hh: %s" % hh.min())
    print("MAX hh: %s" % hh.max())
    print("SUM hh: %s" % hh.sum())
    print("AVG hh: %s" % hh.avg())
    print("RANGE hh: %s" % hh.range())
    print("MEDIAN hh: %s" % hh.median())
    print("KEYS IN hh FOR 19: %s" % hh.keys_for_value(19))
    print("KEYS IN hh FOR 777: %s" % hh.keys_for_value(777))
    print("KEYS IN hh FOR 0: %s" % hh.keys_for_value(0))
    print('')

    Hp.inc('color')
    Hp.inc('color')
    Hp.inc('color')
    Hp.inc('color')
    Hp.inc('color')
    Hp.inc('color')

    Hp.inc('zip')
    Hp.inc('zip')

    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')
    Hp.inc('phone')

    print(Hp)

    print(Hp.freeze()._asdict())
    print(Hp.normalize())

    print("MAX Hp: %s" % Hp.max())


import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.preprocessing import PowerTransformer, QuantileTransformer
from sklearn.datasets import make_classification
from sklearn.mixture import GaussianMixture
from sklearn.decomposition import PCA
import plotly.express as px

data = pd.read_csv(r'Programming\tabular-playground-series-jul-2022\data.csv')

print(data.head(10))
print(data.info()) # From here we observe
# that there are 7 discrete and 22 continuous features
print(data.shape)

fig = plt.figure(figsize=(15,14))

for i in range(7):
    plt.subplot(4,2,i+1)
    feature_no = i+7
    sns.countplot(x=data.iloc[:,feature_no])
    plt.title(f'feature_no :- {feature_no}')
    plt.xlim([-1,44])
    plt.ylim([0,11000])
plt.show()

continuous_features = [f'f_0{i}' for i in range(7)]
continuous_features = continuous_features + [f'f_{i}' for i in range(14,29)]
fig = plt.figure(figsize=(15,14))

for i,f in enumerate(continuous_features):
    plt.subplot(6,4,i+1)
    sns.histplot(x=data[f])
    plt.title(f'Feature :- {f}')
plt.show()

sns.heatmap(data.corr().abs(), vmin=0, vmax=1)
# data.corr() is used to find the pairwise correlation
# of all the columns in the dataframe.Correlation of a
# variable with itself is 1.

plt.show()

### Using elbow method we can easily conclude that preferred no of clusters is 7.
inertias = []
for k in range(1,30):
    km = KMeans(n_clusters=k)
    km.fit(data.iloc[:10000])
    inertias.append(km.inertia_)

plt.figure(figsize=(10,10))
plt.plot(range(1,30), inertias, 'bx-')
plt.xlabel('Number of clusters, k')
plt.ylabel('Inertia')
plt.title('ELBOW METHOD')
plt.show()
### Power Transformer is preferred as it converts the data more into gaussian as compared
### to other scaling methods.
pt_scaled_data = pd.DataFrame(PowerTransformer().fit_transform(data))
pt_scaled_data.columns = data.columns
print(data.head(10))
# model_km = KMeans(n_clusters = 7, random_state=0)
# preds_km = model_km.fit_predict(pt_scaled_data)

submission = pd.read_csv(r'Programming\tabular-playground-series-jul-2022\sample_submission.csv')
# submission['Predicted'] = preds_km
# submission.to_csv('submission_kmeans.csv', index=False)

### First let's do PCA and then apply GaussianMixtureModel.
pca = PCA(n_components=3)
components = pca.fit_transform(pt_scaled_data)

model_gm = GaussianMixture(n_components=7, random_state=0)
preds_gm = model_gm.fit_predict(pt_scaled_data)
submission['Predicted'] = preds_gm
submission.to_csv('sub_wqas.csv', index=False)


from django.shortcuts import render
import requests
from lxml import html
from requests.compat import quote_plus

# Create your views here.
def home (request):
    return render(request, 'base.html')
def new_search(request):
    search = request.POST.get('search')
    print(search)
    session = requests.Session()
    r = session.get("https://www.craigslist.org/")
    city = session.cookies.get_dict()['cl_def_hp']
    base_url = 'https://{}.craigslist.org/search/bbb?query='.format(city)
    final_url = base_url+quote_plus(search)
    response = requests.get(final_url)
    element_tree = html.fromstring(response.text)
    information_list = element_tree.xpath("//li[@class='result-row']")
    final_posting = []
    for inf in  information_list:
        anchor_tag = inf.xpath('.//p/a')
        title = anchor_tag[0].text
        url = anchor_tag[0].get('href')
        price = inf.xpath(".//a/span[@class='result-price']")
        if len(price)==0:
            price = 'N/A'
        else:
            price = price[0].text
        '''Logic to find image'''
        a=inf.xpath('.//a')
        image_inf = a[0].get('data-ids')
        if image_inf:
            image_id = image_inf.split(':')[-1]
            image_url = "https://images.craigslist.org/{}_300x300.jpg".format(image_id)
        else:
            image_url = "https://www.carechartsuk.co.uk/wp-content/uploads/2015/09/NO-IMAGE-AVAILABLE-ICON-web1.jpg"
        print(image_url)
        final_posting.append((title, url, price, image_url))
    # print(final_posting)
    search_stuff = {
        'search': search,
        'final_postings': final_posting,
    }
    return  render( request, 'myapp/new_search.html', search_stuff)


import abc
import logging
import os
import socket
import uuid
from copy import deepcopy
from twisted.internet.defer import Deferred
from twisted.python.failure import Failure
from types import MethodType
from typing import Optional

import requests

logger = logging.getLogger(__name__)

class ClientError(Exception):
    pass

class IClient(object):

    @classmethod
    def build_options(cls, **kwargs):
        raise NotImplementedError

    def add(self, files, recursive=False, **kwargs):
        raise NotImplementedError

    def cancel(self, content_hash):
        raise NotImplementedError

    def get(self, content_hash, client_options=None, **kwargs):
        raise NotImplementedError

    def id(self, client_options=None, *args, **kwargs):
        raise NotImplementedError

class ClientConfig(object):
    """
    Initial configuration for classes implementing the IClient interface
    """
    def __init__(self, max_retries=3, timeout=None):

        self.max_retries = max_retries
        self.client = dict(
            timeout=timeout or (12000, 12000)
        )

class ClientOptions(object):
    """
    Runtime parameters for classes implementing the IClient interface
    """
    def __init__(self, client_id, version, options=None):
        assert isinstance(client_id, str), 'Client id must be a string'
        assert isinstance(version, float), 'Version must be a fp number'

        self.client_id = client_id
        self.version = version
        self.options = options or dict()

    def get(self, client_id, version, option):
        if self.client_id != client_id:
            raise ClientError("Invalid client_id '{}' (expected: '{}')"
                              .format(client_id, self.client_id))
        if self.version != version:
            raise ClientError("Invalid client version '{}' (expected: '{}')"
                              .format(version, self.version))
        return self.options.get(option, None)

    def set(self, **options):
        if not self.options:
            self.options = {}
        self.options.update(options)

    def filtered(self, client_id, version, **_kwargs):
        if self.client_id != client_id:
            logger.warning('Resource client: invalid client id: %s',
                           self.client_id)
        elif not isinstance(self.version, float):
            logger.warning('Resource client: invalid version format: %s',
                           self.version)
        else:
            return self.clone()

    @property
    def peers(self) -> list:
        if isinstance(self.options, dict):
            return self.options.get('peers', [])
        return []

    @peers.setter
    def peers(self, value: list) -> None:
        if not isinstance(self.options, dict):
            self.options = dict()
        self.options['peers'] = value

    @property
    def timeout(self) -> Optional[int]:
        if isinstance(self.options, dict):
            return self.options.get('timeout')
        return None

    @timeout.setter
    def timeout(self, value: Optional[int]) -> None:
        if not isinstance(self.options, dict):
            self.options = dict()
        self.options['timeout'] = value

    def clone(self):
        return self.__class__(
            self.client_id,
            self.version,
            options=deepcopy(self.options)
        )

    @staticmethod
    def from_kwargs(kwargs):
        return kwargs.get('client_options', kwargs.get('options', None))

class ClientHandler(metaclass=abc.ABCMeta):

    retry_exceptions = (
        requests.exceptions.Timeout,
        requests.exceptions.RetryError,
        requests.exceptions.ConnectionError,
        socket.timeout,
        socket.error,
        Failure
    )

    def __init__(self, config: Optional[ClientConfig]):
        self.config = config or ClientConfig()

    def _retry(self, method: MethodType,
               *args,
               raise_exc: Optional[bool] = False,
               **kwargs):

        retries = 0
        result = None

        while not result:
            retries += 1
            logger.debug("Executing sync with retry. "
                         "count=%r, method=%r, args=%r, kwargs=%r",
                         retries, method, args, kwargs)

            try:
                result = method(*args, **kwargs)
            except Exception as exc:

                if exc.__class__ not in self.retry_exceptions:
                    logger.error('Error executing, raising. '
                                 'count=%r, method=%r, args=%r, '
                                 'kwargs=%r, exc=%r',
                                 retries, method, args, kwargs, exc)
                    raise exc
                if retries < self.config.max_retries:
                    logger.warning('Error executing, will retry. '
                                   'count=%r, method=%r, args=%r, '
                                   'kwargs=%r, exc=%r',
                                   retries, method, args, kwargs, exc)
                    continue
                if raise_exc:
                    logger.error('Error executing, raising all. '
                                 'count=%r, method=%r, args=%r, '
                                 'kwargs=%r, exc=%r',
                                 retries, method, args, kwargs, exc)
                    raise exc

                return None
            return result

    def _retry_async(self, method: MethodType, *args, **kwargs):
        retries = 0
        result = Deferred()

        def _run():
            nonlocal retries
            retries += 1

            logger.debug("Executing async with retry. "
                         "count=%r, method=%r, args=%r, kwargs=%r",
                         retries, method, args, kwargs)

            deferred = method(*args, **kwargs)
            deferred.addCallbacks(result.callback, _error)
            return deferred

        def _error(exc):
            if isinstance(exc, Failure):
                exc = exc.value

            if exc.__class__ not in self.retry_exceptions:
                logger.debug('Error executing async, raising. '
                             'count=%r, method=%r, args=%r, '
                             'kwargs=%r, exc=%r',
                             retries, method, args, kwargs, exc)
                result.errback(exc)
            elif retries < self.config.max_retries:
                logger.debug('Error executing async, will retry. '
                             'count=%r, method=%r, args=%r, '
                             'kwargs=%r, exc=%r',
                             retries, method, args, kwargs, exc)
                _run()
            else:
                logger.debug('Error executing async, raising all. '
                             'count=%r, method=%r, args=%r, '
                             'kwargs=%r, exc=%r',
                             retries, method, args, kwargs, exc)
                result.errback(exc)

        _run()
        return result

class DummyClient(IClient):

    _resources = dict()
    _paths = dict()
    _id = "test"

    def add(self, files: dict, **_):
        return self._add(files)

    def add_async(self, files: dict, **_):
        deferred = Deferred()
        deferred.callback(self._add(files))
        return deferred

    def _add(self, files: dict):
        from golem.core.fileshelper import common_dir

        resource_hash = str(uuid.uuid4())
        self._resources[resource_hash] = files
        self._paths[resource_hash] = common_dir(files.keys())
        return resource_hash

    def get(self,
            content_hash: str,
            client_options: Optional[ClientOptions] = None,
            filepath: Optional[str] = None,
            **_) -> tuple:

        from golem.core.fileshelper import copy_file_tree

        resource = self._resources[content_hash]
        path = self._paths[content_hash]
        files = [os.path.join(filepath, f) for f in resource.values()]

        if path != filepath:
            copy_file_tree(path, filepath)

        return content_hash, files

    def id(self,
           client_options: Optional[ClientOptions] = None,
           *args, **kwargs) -> str:

        return self._id

    def cancel(self, content_hash: str):
        return content_hash

    @staticmethod
    def cancel_async(content_hash: str):
        deferred = Deferred()
        deferred.callback(content_hash)
        return deferred

    @classmethod
    def build_options(cls, **kwargs):
        return ClientOptions(cls._id, 1)


#!/usr/bin/python
# update 2017-09-07 23:45
from flask import Flask, jsonify, make_response, request
from redis import Redis
import os

r = Redis(host = os.environ['REDIS_HOST'], port = 6379)

app = Flask(__name__)

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

def get_comments_raw (item_id):
    comments = r.get(item_id)
    if comments == None:
        comments = []
    else:
        comments = eval(comments)
    return comments

@app.route('/comment/<string:item_id>', methods=['GET'])
def get_comments(item_id):
    item_comments = get_comments_raw(item_id)
    return jsonify({'comments': item_comments})

@app.route('/comment/<string:item_id>', methods=['PUT'])
def add_comment(item_id):
    new_comment = {'user': request.json['user'], 'comment': request.json['comment']}
    item_comments = get_comments_raw(item_id)
    item_comments.append(new_comment)
    r.set(item_id, item_comments)
    return make_response(jsonify({'error': ''}), 200)

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


from requests_oauthlib import OAuth1Session
# User must create their own secrets.py with the following:
# 1) client_key: Consumer Key(API Key)
# 2) client_secret: Consumer Secret (API Secret)
# 3) access_token
# 4) access_token_secret
import secrets

client_key = secrets.client_key
client_secret = secrets.client_secret

resource_owner_key = secrets.access_token
resource_owner_secret = secrets.access_token_secret

protected_url = 'https://api.twitter.com/1.1/account/settings.json'

oauth = OAuth1Session(client_key,
                          client_secret=client_secret,
                          resource_owner_key=resource_owner_key,
                          resource_owner_secret=resource_owner_secret)

protected_url = 'https://api.twitter.com/1.1/search/tweets.json'
params = {'q':'food'}
r = oauth.get(protected_url, params=params)
print (r.text)