import sys
from unipath import Path

BASE_DIR = Path(__file__).absolute().ancestor(2)  # django project dir (src)
ROOT_DIR = BASE_DIR.parent                        # repository root dir
LOG_DIR = ROOT_DIR.child('var', 'log')            # log dir
TMP_DIR = ROOT_DIR.child('var', 'tmp')            # tmp dir

sys.path.append(ROOT_DIR.child('conf'))
try:
    import local_settings
    ls = local_settings.__dict__
except ImportError:
    raise RuntimeError('Please, provide your local configuration for this project.\n'
                       'You need to create conf/local_settings.py with your local settings.')
finally:
    sys.path.pop()


# coding=utf-8

class StepItem(object):
    def __init__(self, ori_glass, tar_glass):
        self.original_glass = ori_glass
        self.target_glass = tar_glass

    def can_pour_in_out(self):
        if self.original_glass.can_pour_out():
            out_color = self.original_glass.get_color_by_index()
            if self.target_glass.can_pour_in(out_color.id) and self.target_glass.empty_count >= out_color.count:
                if self.original_glass.is_single_color() and self.target_glass.is_empty():
                    return False
                else:
                    return True
        return False

    def __repr__(self):
        return '{0} into {1}'.format(self.original_glass.id, self.target_glass.id)

    def evaluate(self, grass_list):
        score = 0
        colors = self.original_glass.get_colors()
        for idx, c in enumerate(colors.get_all()):
            for g in grass_list:
                if self.original_glass.id == g.id:
                    continue
                #  当前颜色所处层 的分数
                color_index = self.original_glass.max_count - 1 - idx
                score += (pow(2, color_index) * c.count * color_index)

                #  目标颜色所处层 的分数
                target_index = g.get_index_by_color_id(c.id)
                score += pow(2, g.max_count - 1 - target_index)

                score += idx

        target_color = self.target_glass.get_color_by_index()
        out_color = self.original_glass.get_color_by_index()

        target_count = target_color.count if target_color else 0
        out_count = out_color.count if out_color else 0
        if target_count + out_count == self.target_glass.max_count:
            score += 10

        return score

def get_steps_rank(grass_list):
    from main import SHOW_DETAIL_LOG

    steps = list()
    for g1 in grass_list:
        is_empty = False
        for g2 in grass_list:
            if g1.id == g2.id or g1.is_complete() or g2.is_complete():
                continue
            if is_empty and g2.is_empty():
                continue
            if g2.is_empty():
                is_empty = True

            step = StepItem(g1, g2)
            if step.can_pour_in_out():
                steps.append(step)

    ordered_steps = dict()
    for s in steps:
        score = s.evaluate(grass_list)
        ordered_steps[s] = score
    #     if SHOW_DETAIL_LOG:
    #         print '{0} into {1}, score:{2}'.format(s.original_glass.id, s.target_glass.id, score)
    # if SHOW_DETAIL_LOG:
    #     print '-'*30

    step_rank = sorted(ordered_steps.items(), key=lambda item: -item[1])
    from Utils import Stack
    step_stack = Stack()
    for s in step_rank:
        step_stack.push(s[0])

    return step_stack


class Solution:
    def removeDuplicates(self, nums) -> int:
        i = 0
        idx = []
        while i<len(nums):

            if nums[i] in idx:
                del(nums[i])
            else:
                idx.append( nums[i])
                i += 1
        return len(nums)
if __name__ == "__main__":
    solution = Solution()
    nums =  [0,0,1,1,1,2,2,3,3,4]
    print(solution.removeDuplicates(nums))
    print(nums)

'''
 解法-双指针

首先注意数组是有序的，那么重复的元素一定会相邻。

要求删除重复元素，实际上就是将不重复的元素移到数组的左侧。

考虑用 2 个指针，一个在前记作 p，一个在后记作 q，算法流程如下：

1.比较p 和 q 位置的元素是否相等。

如果相等，q 后移 1 位
如果不相等，将 q 位置的元素复制到 p+1 位置上，p 后移一位，q 后移 1 位
重复上述过程，直到 q 等于数组长度。

返回 p + 1，即为新数组长度。

'''


from flask import Flask, render_template

from forms import http_req_forms,href_finder
from http_requests import http_requests
from href_find import findhref

global version,error

error = False
version = ("0.01")

app=Flask(__name__)

#needs to be configured ...in the near future :)
app.config.update(dict(
    SECRET_KEY= "powerful secretkey",
    WTF_CSRF_SECRET_KEY= "a csrf secret key"))

#index page
@app.route("/", methods=['GET', 'POST'])
def index():
    return render_template("index.html",version=version)

#/http_requester
@app.route('/http_requester' ,methods = ['POST','GET'])
def http_requester():
    #gets input from forms (forms.py)/http_requester.html
    form = http_req_forms()
    #When Execute button is pressed :
    if form.validate_on_submit():
        but = True
        c_s = form.c_s.data
        request_type = form.req.data
        url = form.url.data
        cua = form.c_ua.data
        inua = form.in_ua.data
        global error , request_headers , request_reply , request_text,request_encoding  , r
        #http_requests.py
        r,request_headers,request_reply,request_text,request_encoding,error= http_requests(c_s,request_type,url,cua,inua)
        if (error == True):
            return render_template('http_requester.html',form=form,r=r)
        elif(error == False):
            return render_template('http_requester.html',r=r,form=form, headers = request_headers,encoding=request_encoding,text = request_text, reply = request_reply, url=url, req=request_type,but=but)
    return render_template('http_requester.html',form=form,r=error)

#/href_finder
@app.route("/href_finder" ,methods = ['POST','GET'])
def hreffinder():
    form = href_finder()
    global href,url,buthref
    buthref = False
    url = ""
    href = []
    #When Execute button is pressed :
    if form.validate_on_submit():
        buthref = True
        url = form.url.data
        data = findhref(url).splitlines()
        href.extend(data)
    return render_template("href_finder.html",form = form,href=href , url = url,but=buthref)

#/cms detection
@app.route("/cms_detection" ,methods = ['POST','GET'])
def cms_detection():
    form = href_finder()
    global href,url,buthref
    buthref = False
    url = ""
    href = []
    #When Execute button is pressed :
    if form.validate_on_submit():
        print("")
    return render_template("cms_detection.html",form = form,href=href , url = url,but=buthref)

#/history
@app.route("/history" ,methods = ['POST','GET'])
def history():
    return render_template("history.html")

#/options
@app.route("/options" ,methods = ['POST','GET'])
def options():
    return render_template("options.html")

#error page
@app.errorhandler(404)
def page_not_found(e):
    return render_template('error.html'),404

#error page
@app.errorhandler(500)
def internal_server_error(e):
    return render_template('internal_error.html'),500

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


"""
Author : Dimitri Watel
Year : 2020

Model of the flask application, contains all the functions manipulating the database.

The database managed with TinyDB and stored in a file named **db.json**.
"""

from tinydb import TinyDB, Query, where
import networkx as nx
from networkx.algorithms import isomorphism as isoalg

# Build the database
db = TinyDB('db.json')

def add_iso(g_id):
    """
    Add the graph with id **g_id** in I by storing it in the database with the type 'iso'
    :param g_id: id of a graph
    :return: True
    """
    db.insert({'type': 'iso', 'g_id': g_id})
    return True

def remove_iso(g_id):
    """
    Remove the graph with id **g_id** in I by removing that id stored with the type 'iso' from the database
    :param g_id: id of a graph
    :return: True
    """
    q = Query()
    db.remove((q.type == 'iso') & (q.g_id == g_id))
    return True

def add_node(g_id, u_id, x, y):
    """
    Add a node with id **u_id** to the graph with id **g_id** at coordinates **x** and **y** by storing all those information in the
    database with the type 'node'. If such a node is already associated to the graph in the database, nothing is done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :param x: x coordinate of the node
    :param y: y coordinate of the node
    :return: True if the node is added to the graph and False otherwise
    """
    q = Query()
    i = db.search((q.type == 'node') & (q.g_id == g_id) & (q.u_id == u_id))  # Prevent dupplicates
    if len(i) == 0:
        db.insert({'type': 'node', 'g_id': g_id, 'u_id': u_id, 'x': x, 'y': y})
        return True
    else:
        return False

def add_edge(g_id, u_id, v_id):
    """
    Add an edge linking the nodes with ids **u_id** and **v_id** to the graph with id **g_id** by storing all those information in
    the database with the type 'edge'. If such an edge is already associated to the graph in the database, if **u_id** equals **v_id**
    or if **u_id** or **v_id** do not belong to the graph in the database, nothing is done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :param v_id: id of a node
    :return: True if the edge is added to the graph and False otherwise
    """
    if u_id == v_id:
        return False
    if v_id < u_id:
        u_id, v_id = v_id, u_id

    q = Query()
    i = db.search((q.type == 'node') & (q.g_id == g_id) & ((q.u_id == u_id) | (q.u_id == v_id)))
    if len(i) != 2:
        return False
    i = db.search((q.type == 'edge') & (q.g_id == g_id) & (q.u_id == u_id) & (q.v_id == v_id))  # Prevent dupplicates
    if len(i) == 0:
        db.insert({'type': 'edge', 'g_id': g_id, 'u_id': u_id, 'v_id': v_id})
        return True
    return False

def remove_node(g_id, u_id):
    """
    Remove the node with id **u_id** from the graph with id **g_id** by removing all those information stored in the
    database with the type 'node'. Remove also every edge incident to that node from the graph by removing every
    document from the database containing the type 'edge' and where the id of one of the two extremities is **u_id**
     If no such node exists in the graph in the database, nothing is done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :return: True if the node is removed from the graph and False otherwise
    """
    q = Query()
    r = db.remove((q.type == 'node') & (q.g_id == g_id) & (q.u_id == u_id))
    if len(r) > 0:
        db.remove((q.type == 'edge') & (q.g_id == g_id) & ((q.u_id == u_id) | (q.v_id == u_id)))
        return True
    return False

def remove_edge(g_id, u_id, v_id):
    """
    Remove the edge linking the nodes with id **u_id** and **v_id** from the graph with id **g_id** by removing all those
    information stored in the database with the type 'edge'. If no such edge exists in the graph in the database, nothing is
    done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :param v_id: id of a node
    :return: True if the edge is removed from the graph and False otherwise
    """
    if u_id == v_id:
        return False
    if v_id < u_id:
        u_id, v_id = v_id, u_id
    q = Query()
    r = db.remove((q.type == 'edge') & (q.g_id == g_id) & (q.u_id == u_id) & (q.v_id == v_id))
    return len(r) > 0

def move_node(g_id, u_id, x, y):
    """
    Update the coordinates of the node with id **u_id** in the graph with id **g_id** to **x** and **y** by updating
    the 'x' and 'y' fields of the document containing those ids with the type 'node'. If no such node is associated
    to the graph in the database, nothing is done.
    :param g_id: id of a graph
    :param u_id: id of a node
    :param x: x coordinate of the node
    :param y: y coordinate of the node
    :return: True if the node is moved and False otherwise
    """
    q = Query()
    r = db.update({'x': x, 'y': y}, (q.type == 'node') & (q.g_id == g_id) & (q.u_id == u_id))
    return len(r) > 0

def save_main_name(name):
    """
    Update the name of the graph with id 0 in the database to **name** by updating the field 'name' of the document containing that
    id with the type 'properties'
    :param name: new name of the graph with id 0
    :return: True if the name is not None and False otherwise
    """
    if name is None:
        return False
    q = Query()
    db.upsert({'type': 'properties', 'g_id': 0, 'name': name}, (q.type == 'properties') & (q.g_id == 0))
    return True

def remove_graph(g_id):
    """
    Remove every occurrence of the graph with id **g_id** from the database
    :param g_id: id of a graph
    :return: True
    """
    db.remove(where('g_id') == g_id)
    return True

def erase_graph(g1_id, g2_id, name=None):
    """
    Erase the graph with id **g2_id** with a copy of the graph with id **g1_id**. To do so, every document where
    the field 'g_id' equals **g2_id** is removed and every document where the type is not 'iso' and where
    the field 'g_id' equals **g1_id** is copied, modified so that the field is replaced by **g2_id** and reinserted
    in the database. If the parameter **name** is not None, the name of the copied graph is set to **name** by the
    field 'name' of the document
    containing that id with the type 'properties'.

    g1_id should not equal g2_id otherwise nothing is done.
    :param g1_id: id of a graph
    :param g2_id: id of a graph
    :param name: new name of the copied graph
    :return: False is g1_id equals g2_id and g2_id otherwise.
    """
    if g1_id == g2_id:
        return False
    if g2_id is None:
        g2_id = max(x['g_id'] for x in db.search(where('type') == 'node')) + 1
    remove_graph(g2_id)
    q = Query()
    for x in db.search((q.g_id == g1_id) & (q.type != 'iso')):
        y = dict(x)
        y['g_id'] = g2_id
        db.insert(y)
    if name is not None:
        db.upsert({'type': 'properties', 'g_id': g2_id, 'name': name}, (q.type == 'properties') & (q.g_id == g2_id))
    return g2_id

def _get_graph(g_id):
    """
    A networkx graph object corresponding to the graph with id **g_id**. If no such graph exists an empty graph is
    returned
    :param g_id: id of a graph
    :return: a networkx graph object corresponding to the graph with id **g_id**
    """
    q = Query()
    nodes = (res['u_id'] for res in db.search((q.g_id == g_id) & (q.type == 'node')))
    edges = ((res['u_id'], res['v_id']) for res in db.search((q.g_id == g_id) & (q.type == 'edge')))

    g = nx.Graph()
    g.add_nodes_from(nodes)
    g.add_edges_from(edges)
    return g

def get_graph_dict(g_id):
    """
    Return a dict containing all the information of the graph with id **g_id** stored in the database. The dict has the
    following format :
    {
    'nodes' : list of ids of the nodes of the graph,
    'edges' : list of edges of the graph, each edge is described by the ids of the two extremities of the edge
    'name': the name of the graph stored in the document with type 'properties',
    'iso': True if the graph id is stored with the type 'iso' and False otherwise
    }

    :param g_id: id of a graph
    :return: A dict containing all the information of the graph with id **g_id** stored in the database
    """
    q = Query()
    nodes = [(res['u_id'], res['x'], res['y']) for res in db.search((q.g_id == g_id) & (q.type == 'node'))]
    edges = [(res['u_id'], res['v_id']) for res in db.search((q.g_id == g_id) & (q.type == 'edge'))]
    try:
        name = db.search((q.type == 'properties') & (q.g_id == g_id))[0]['name']
    except IndexError:
        name = ''
    iso = len(db.search((q.type == 'iso') & (q.g_id == g_id))) != 0
    return {'nodes': nodes, 'edges': edges, 'name': name, 'iso': iso}

def get_graph_infos():
    """
    Return a list of dicts containing some information of all the graphs stored in the database. Each dict has the
    following format :
    {
        'graph_id': the id of the graph,
        'name': the name of the graph,
        'iso': True if the graph id is stored with the type 'iso' and False otherwise
    }
    :return: A list of dicts containing some information of all the graphs stored in the database.
    """
    q = Query()
    isos = [res['g_id'] for res in db.search(q.type == 'iso')]
    names = [{'graph_id': res['g_id'], 'name': res['name'], 'iso': res['g_id'] in isos}
             for res in db.search((q.type == 'properties'))]
    names.sort(key=lambda x: x['name'])
    return names

def get_induced_subgraphs():
    """
    Return a list of dicts describing all the subgraphs of the graph with id 0 that are isomorphic to at least one graph for
    which the id is stored in the database with the type 'iso'.
    The list has the following format:
    [
    For each subgraph
        {
            'subgraph_id': the id of the graph stored with the type 'iso' isommorphic to the subgraph
            'nodes': the list of nodes of the subgraph
            'edges': the list of edges of the subgraph, each edge is described by the ids of the two extremities of
            the edge
        }
    ]
    :return: a list of dicts describing all the subgraphs of the graph with id 0 that are isomorphic to at least one graph for
    which the id is stored in the database with the type 'iso'.
    """
    q = Query()
    g = _get_graph(0)
    isos = [res['g_id'] for res in db.search(q.type == 'iso')]
    subgraphs = ((id, _get_graph(id)) for id in isos)

    inds = set()
    induced_subgraphs = []

    for id, subgraph in subgraphs:
        gm = isoalg.GraphMatcher(g, subgraph)
        for gm in gm.subgraph_isomorphisms_iter():
            k = frozenset(gm.keys())
            if k not in inds:
                inds.add(k)
                induced_subgraphs.append({'subgraph_id': id, 'nodes': list(k), 'edges': list(nx.Graph.subgraph(g, k).edges())})

    return induced_subgraphs


import io
import sys

class CoNLLWriter:
    def __init__(self, file):
        self.file_path = file

    def write_file(self, documents):
        try:
            writer_object = io.open(self.file_path, 'w+')
            for idx in documents.keys():
                document = documents[idx]
                writer_object.write("# newdoc id = " + document.doc_id + "\n")
                for sentence in document.sentences:
                    for token in sentence.tokens:
                        writer_object.write(
                            token.token_id + "\t" + token.token_text + "\t_\t_\t_\t_\t_\t_\t_\t" + str(token.label))
                        writer_object.write("\n")
                    writer_object.write("\n")
            writer_object.close()
        except IOError:
            sys.exit("Cannot open file at location: " + self.file_path)


import sys
from io import StringIO
import unittest

class TestClass(unittest.TestCase):
    def assertIO(self, input, output):
        stdout, stdin = sys.stdout, sys.stdin
        sys.stdout, sys.stdin = StringIO(), StringIO(input)
        resolve()
        sys.stdout.seek(0)
        out = sys.stdout.read()[:-1]
        sys.stdout, sys.stdin = stdout, stdin
        self.assertEqual(out, output)
    def test_Sample_Input_1(self):
        input = """ABC"""
        output = """ARC"""
        self.assertIO(input, output)

from math import gcd
from functools import reduce
from itertools import product

def resolve():
  contest = input()

  print("ARC" if contest == "ABC" else "ABC")

if __name__ == "__main__":
    resolve()

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


import os
import numpy as np
from glob import glob
from PIL import Image
from tqdm import tqdm

import torch
from torchvision import transforms

PIX2PIX_DATASETS = [
    'facades', 'cityscapes', 'maps', 'edges2shoes', 'edges2handbags']

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

def pix2pix_split_images(root):
    paths = glob(os.path.join(root, "train/*"))

    a_path = os.path.join(root, "A")
    b_path = os.path.join(root, "B")

    makedirs(a_path)
    makedirs(b_path)

    for path in tqdm(paths, desc="pix2pix processing"):
        filename = os.path.basename(path)

        a_image_path = os.path.join(a_path, filename)
        b_image_path = os.path.join(b_path, filename)

        if os.path.exists(a_image_path) and os.path.exists(b_image_path):
            continue

        image = Image.open(os.path.join(path)).convert('RGB')
        data = np.array(image)

        height, width, channel = data.shape

        a_image = Image.fromarray(data[:,:width/2].astype(np.uint8))
        b_image = Image.fromarray(data[:,width/2:].astype(np.uint8))

        a_image.save(a_image_path)
        b_image.save(b_image_path)

class Dataset(torch.utils.data.Dataset):
    def __init__(self, root, scale_size, data_type, skip_pix2pix_processing=False):
        self.root = root
        if not os.path.exists(self.root):
            raise Exception("[!] {} not exists.".format(root))

        self.name = os.path.basename(root)
        if self.name in PIX2PIX_DATASETS and not skip_pix2pix_processing:
            pix2pix_split_images(self.root)

        self.paths = glob(os.path.join(self.root, '{}/*'.format(data_type)))
        if len(self.paths) == 0:
            raise Exception("No images are found in {}".format(self.root))
        self.shape = list(Image.open(self.paths[0]).size) + [3]

        self.transform = transforms.Compose([
            transforms.Scale(scale_size),
            transforms.ToTensor(),
            transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
        ])

    def __getitem__(self, index):
        image = Image.open(self.paths[index]).convert('RGB')
        return self.transform(image)

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

def get_loader(root, batch_size, scale_size, num_workers=2,
               skip_pix2pix_processing=False, shuffle=True):
    a_data_set, b_data_set = \
        Dataset(root, scale_size, "A", skip_pix2pix_processing), \
        Dataset(root, scale_size, "B", skip_pix2pix_processing)
    a_data_loader = torch.utils.data.DataLoader(dataset=a_data_set,
                                                batch_size=batch_size,
                                                shuffle=True,
                                                num_workers=num_workers)
    b_data_loader = torch.utils.data.DataLoader(dataset=b_data_set,
                                                batch_size=batch_size,
                                                shuffle=True,
                                                num_workers=num_workers)
    a_data_loader.shape = a_data_set.shape
    b_data_loader.shape = b_data_set.shape

    return a_data_loader, b_data_loader


import json
from functools import cmp_to_key
from typing import List, Tuple

from more_itertools import flatten

from adventofcode.utils import load_input

def get_packet_pairs() -> List[Tuple[List, List]]:
    raw_pairs = load_input().split("\n\n")
    pairs = []

    for pair in raw_pairs:
        first, second = pair.split("\n")
        pairs.append((json.loads(first), json.loads(second)))

    return pairs

def compare_packets(first: List, second: List) -> int:
    index = 0
    while index < len(first) and index < len(second):
        # Both values are integers
        if isinstance(first[index], int) and isinstance(second[index], int):
            first_value = int(first[index])
            second_value = int(second[index])

            if first_value == second_value:
                index += 1
                continue

            return first_value - second_value

        # If both values aren't ints, we'll need to compare lists

        # Wrap the first if necessary
        first_value = first[index]
        if not isinstance(first[index], list):
            first_value = [first_value]

        # Wrap the second if necessary
        second_value = second[index]
        if not isinstance(second[index], list):
            second_value = [second_value]

        result = compare_packets(first_value, second_value)

        if result == 0:
            index += 1
            continue

        return result

    # If we got here, one or both of the lists ran out of items
    if len(first) < len(second):
        return -1

    if len(first) > len(second):
        return 1

    return 0

def part_1() -> int:
    return sum(
        index + 1
        for index, pair in enumerate(get_packet_pairs())
        if compare_packets(*pair) < 0
    )

print(part_1())

def part_2() -> int:
    first_divider_packet = [[2]]
    second_divider_packet = [[6]]

    in_order = sorted(
        [first_divider_packet, second_divider_packet, *flatten(get_packet_pairs())],
        key=cmp_to_key(compare_packets),
    )

    return (in_order.index(first_divider_packet) + 1) * (
        in_order.index(second_divider_packet) + 1
    )

print(part_2())


# Node = [val, next]
# List: size, tail

class Empty (Exception):
    pass

class Queue_Circular_LinkedList:
    """implements queue using circular linked list"""
    class _Node:
        """class to represent node of the list"""
        def __init__(self, val=0, next_node=None):
            self._val = val
            self._next = next_node

    def __init__(self):
        self._len = 0
        self._tail = None

    def enque(self, val):
        """enques an element at the tail of the queue"""
        node = self._Node(val, None)
        if self.is_empty():
            node._next = node
        else:
            node._next = self._tail._next
            self._tail._next = node
        self._tail = node
        self._len += 1

    def deque(self) -> int:
        if self.is_empty():
            raise Empty('underflow')
        val = self._tail._next._val
        if len(self) == 1:
            self._tail = None
        else:
            self._tail._next = self._tail._next._next
        self._len -= 1
        return val

    def front(self) -> int:
        if self.is_empty():
            raise self.Empty('undeflow')
        return self._tail._next._val

    def rotate(self, times: int=1):
        if len(self):
            for n in range(times):
                self._tail = self._tail._next

    def __len__(self):
        return self._len

    def is_empty(self):
        return len(self) == 0

def basic_test_queue():
    q = Queue_Circular_LinkedList()
    for num in range(10, 21):
        q.enque(num)

    while q.is_empty()==False:
        print(q.front())
        q.deque()

def rotate_test_circular_queue():
    q = Queue_Circular_LinkedList()
    for num in range(10, 20):
        q.enque(num)

    print(f'q size before rotation: {len(q)}')

    for itr in range(len(q)):
        print(q.front())
        q.rotate()
    print(f'q size AFTER rotation: {len(q)}')

if __name__=='__main__':
    #basic_test_queue()
    rotate_test_circular_queue()


import sys, argparse
from argparse import RawTextHelpFormatter

__author__ = "Ryan Smith (ryanpsmith@wustl.edu)"
__version__ = "$Revision: 0.1.0 $"
__date__ = "$Date: 2015-3-9 $"

def get_args():
    parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description="\
fix_segs\n\
author: " + __author__ + "\n\
version: " + __version__ + "\n\
description: DESCRIPTION")
    parser.add_argument('-i', '--input', type=argparse.FileType('r'), required=False, default=None, help="Input file [stdin]")
    parser.add_argument('-o', '--output', type=argparse.FileType('w'), required=False, default=sys.stdout, help="Output file [stdout]")
    # parse the arguments
    args = parser.parse_args()

    # if no input, check if part of pipe and if so, read stdin.
    if args.input == None:
        if sys.stdin.isatty():
            parser.print_help()
            exit(1)
        else:
            args.input = sys.stdin
    # send back the user input
    return args

'''WARNING: THIS RUNS ONLY ON BEDTOOLS INTERSECT WITH FILTERED COLUMNS
Essentially a one-time use script.
Command used:
<(bedtools intersect -wa -wb -a <(bedtools slop -b 50 -g hg19.genome \
    -i <(vawk '{$3 = $2+1; print$0}' CEPH_MERGED_CIs_sparse.vcf | cut -f 1,2,3,5,10-12)) \
    -b <(vawk '{$3 = $2+1; print$0}' merged_1kg_CEPH_MEs.vcf | cut -f 1,2,3,5,10-12) | \
    grep -v "^X" | cut -f4-7,11-14 | sed 's/LINE1/L1/g')
'''

def compare(infile):
    entries = [line.rstrip().split('\t') for line in infile]
    #0 == Mobster MEI type
    #1-3 ==  Mobster GTs
    #4 == 1kg MEI type
    #5-7 == 1kg GTs
    callset = []
    for entry in entries:
        gt = GT(entry)
        #only append interescted MEIs of the same type.
        if gt.type_match:
            callset.append(GT(entry))

    #here's some bad hardcoded stuff. gets 'er done though
    #if i ever need to do this on more samples, this will be a pain to change.

    #lets initialize a shitload of lists to hardcoded 0s. this is probably the worst code i've ever written.
    #should use a single counter object or dict/hash but fuck it. cowboy coding day
    #count list format: [NA12878, NA12889, NA12890]

    sample_index = ["NA12878", "NA12889", "NA12890"]

    #total counts
    het_count = [0,0,0]
    hom_alt_count = [0,0,0]
    hom_ref_count = [0,0,0]

    #match counts
    het_match = [0,0,0]
    hom_alt_match = [0,0,0]
    hom_ref_match = [0,0,0]

    #all possible mismatch types to be counted.
    #this way I can tell how MobTyper is biased relative to the 1kg phase3 callset.
    het_VS_hom_alt = [0,0,0]
    het_VS_hom_ref = [0,0,0]

    hom_alt_VS_het = [0,0,0]
    hom_alt_VS_hom_ref = [0,0,0]

    hom_ref_VS_het = [0,0,0]
    hom_ref_VS_hom_alt = [0,0,0]

    #yay more terrible code. so many redundant comparisons. <33% efficient but hey, it'll work.
    for call in callset:
        for i in range(len(sample_index)):
            #increment total counts for each GT type
            if call.mob_gts[i] == "0/1":
                het_count[i] += 1
            if call.mob_gts[i] == "1/1":
                hom_alt_count[i] += 1
            if call.mob_gts[i] == "0/0":
                hom_ref_count[i] += 1
            #get match counts for each GT type
            if call.mob_gts[i] == call.kg_gts[i]:
                if call.mob_gts[i] == "0/1":
                    het_match[i] += 1
                elif call.mob_gts[i] == "1/1":
                    hom_alt_match[i] += 1
                elif call.mob_gts[i] == "0/0":
                    hom_ref_match[i] += 1

            #if mismatch, determine the type of mismatch
            else:
                if call.mob_gts[i] == "0/1":
                    if call.kg_gts[i] == "0/0":
                        het_VS_hom_ref[i]+=1
                    elif call.kg_gts[i] == "1/1":
                        het_VS_hom_alt[i]+=1

                elif call.mob_gts[i] == "1/1":
                    if call.kg_gts[i] == "0/0":
                        hom_alt_VS_hom_ref[i]+=1
                    elif call.kg_gts[i] == "0/1":
                        hom_alt_VS_het[i]+=1

                elif call.mob_gts[i] == "0/0":
                    if call.kg_gts[i] == "1/1":
                        hom_ref_VS_hom_alt[i]+=1
                    elif call.kg_gts[i] == "0/1":
                        hom_ref_VS_het[i]+=1

    #now we've calculated all the fine-grain counts.
    #need to calculate percentages and present results in
    # a format that will facilitate downstream R plotting.

    #probably:  SAMPLE_NAME<\t>INFO_TYPE<\t>PERCENTAGE
    for i,sample in enumerate(sample_index):

        het_match_percent = (het_match[i]/float(het_count[i]))*100
        hom_alt_match_percent = (hom_alt_match[i]/float(hom_alt_count[i]))*100
        hom_ref_match_percent = (hom_ref_match[i]/float(hom_ref_count[i]))*100

        #make sure these complement (100-percentA == percentB)
        het_V_homA_percent = (het_VS_hom_alt[i]/float(het_VS_hom_alt[i]+het_VS_hom_ref[i]))*100
        het_V_homR_percent = (het_VS_hom_ref[i]/float(het_VS_hom_alt[i]+het_VS_hom_ref[i]))*100

        homA_V_het_percent = (hom_alt_VS_het[i]/float(hom_alt_VS_het[i]+hom_alt_VS_hom_ref[i]))*100
        homA_V_homR_percent = (hom_alt_VS_hom_ref[i]/float(hom_alt_VS_het[i]+hom_alt_VS_hom_ref[i]))*100

        homR_V_het_percent = (hom_ref_VS_het[i]/float(hom_ref_VS_hom_alt[i]+hom_ref_VS_het[i]))*100
        homR_B_homA_percent = (hom_ref_VS_hom_alt[i]/float(hom_ref_VS_hom_alt[i]+hom_ref_VS_het[i]))*100

        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "het_match", het_match_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "hom_alt_match", hom_alt_match_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "hom_ref_match", hom_ref_match_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "het_V_homA", het_V_homA_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "het_V_homR", het_V_homR_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "homA_V_het", homA_V_het_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "homA_V_homR", homA_V_homR_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "homR_V_het", homR_V_het_percent))
        sys.stderr.write("{0}\t{1}\t{2:.2f}\n".format(sample, "homR_V_homA", homR_B_homA_percent))

class GT(object):
    def __init__(self, entry):
        self.type_match = False
        self.mob_type = entry[0]
        self.kg_type = entry[4]
        self.mob_gts = entry[1:4]
        self.count = len(self.mob_gts)

        #these are the 1KG GTs, which are phased and need to be converted to normal GT calls
        for i in range(5,8):
            if entry[i] == "0|0":
                entry[i] = "0/0"
            elif entry[i] == "1|1":
                entry[i] = "1/1"
            elif entry[i] == "1|0" or entry[i] == "0|1":
                entry[i] = "0/1"

        self.kg_gts = entry[5:8]

        if self.mob_type ==  self.kg_type:
            self.type_match = True

def main():
    args = get_args()
    compare(args.input)

if __name__ == '__main__':
    main()


from typing import Optional

import numpy as np

import tnnpy.simpleNNlib as snn
from tnnpy.symdyn import NonlinearDynamicalAutomaton

class NeuralTM:

    """Given an NDA, constructs the equivalent neural network described in
    our submitted paper.

    :param nda: a symdyn.NonlinearDynamicalAutomaton object

    """

    def __init__(self, nda: NonlinearDynamicalAutomaton, cylinder_sets: bool = False, label: Optional[str]=None):

        self.cylinder_sets = cylinder_sets
        self.label = "" if label is None else label

        if self.cylinder_sets:
            self.d_factor = 2
        else:
            self.d_factor = 1

        self.x_params = nda.flow_params_x
        self.y_params = nda.flow_params_y

        self.x_leftbounds = nda.x_leftbounds
        self.y_leftbounds = nda.y_leftbounds

        max_linx = np.amax(self.x_params[:, :, 0] + self.x_params[:, :, 1])
        max_liny = np.amax(self.y_params[:, :, 0] + self.y_params[:, :, 1])
        self.h = np.amax((max_linx, max_liny)) * 2  # inhibitory constant

        self.x_nsymbols = self.x_params.shape[1]
        self.y_nsymbols = self.x_params.shape[0]
        self.nbranches = self.x_nsymbols * self.y_nsymbols

        # construct input layer

        self.MCLx = snn.RampLayer(self.d_factor,
                                  initial_values=[0.0] * self.d_factor,
                                  label="%s->MCLx" % self.label)
        self.MCLy = snn.RampLayer(self.d_factor,
                                  initial_values=[0.0] * self.d_factor,
                                  label="%s->MCLy" % self.label)

        # construct cell selection layer

        self.BSLbx = snn.HeavisideLayer(
            self.x_nsymbols, biases=-self.x_leftbounds, inclusive=[1] * self.x_nsymbols
        )
        self.BSLby = snn.HeavisideLayer(
            self.y_nsymbols, biases=-self.y_leftbounds, inclusive=[1] * self.y_nsymbols
        )

        if self.cylinder_sets:
            snn.Connection(
                self.MCLx, self.BSLbx, [[1] * self.x_nsymbols, [0] * self.x_nsymbols]
            )
            snn.Connection(
                self.MCLy, self.BSLby, [[1] * self.y_nsymbols, [0] * self.y_nsymbols]
            )
        else:
            snn.Connection(self.MCLx, self.BSLbx, np.array([[1] * self.x_nsymbols]))
            snn.Connection(self.MCLy, self.BSLby, np.array([[1] * self.y_nsymbols]))

        # construct linear transformation layer

        if self.cylinder_sets:
            self.LTL = snn.RampLayer(self.nbranches * 2 * 2,
                                     biases=self.LTL_biases_from_params()
                                     - self.h,
                                     label="%s->LTL" % self.label)
        else:
            self.LTL = snn.RampLayer(self.nbranches * 2,
                                     biases=self.LTL_biases_from_params()
                                     - self.h,
                                     label="%s->LTL" % self.label)

        BSLbx_LTL_cnmat = self.cn_BSLbx_LTL()
        BSLby_LTL_cnmat = self.cn_BSLby_LTL()
        snn.Connection(self.BSLbx, self.LTL, BSLbx_LTL_cnmat)
        snn.Connection(self.BSLby, self.LTL, BSLby_LTL_cnmat)

        MCLx_LTL_cnmat = self.cn_MCLx_LTL()
        MCLy_LTL_cnmat = self.cn_MCLy_LTL()
        snn.Connection(self.MCLx, self.LTL, MCLx_LTL_cnmat)
        snn.Connection(self.MCLy, self.LTL, MCLy_LTL_cnmat)

        LTL_MCLx_cnmat = self.cn_LTL_MCLx()
        LTL_MCLy_cnmat = self.cn_LTL_MCLy()
        snn.Connection(self.LTL, self.MCLx, LTL_MCLx_cnmat)
        snn.Connection(self.LTL, self.MCLy, LTL_MCLy_cnmat)

        self.layers = {"MCLx": self.MCLx,
                       "MCLy": self.MCLy,
                       "BSLbx": self.BSLbx,
                       "BSLby": self.BSLby,
                       "LTL": self.LTL}

    def cn_BSLbx_LTL(self):
        """Generate the connection matrix between the x cell selection layer
        and the linear transformation layer.  The connection pattern
        is discussed in our submitted paper.

        :return: connection matrix between x cell selection layer and
        linear transformation layer

        :rtype: numpy ndarray

        """

        x_part_mat = []
        # there are x_nsymbols neurons in the x cell selection layer
        for col_j in range(self.x_nsymbols):

            # set all connections to 0 first
            if self.cylinder_sets:
                cell_cn_mat = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            else:
                cell_cn_mat = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))

            # then make the relevant ones equal to h/2
            cell_cn_mat[:, col_j] = self.h / 2
            # and the ones to the right of the current cell equal to -h/2
            if col_j > 0:
                cell_cn_mat[:, col_j - 1] = -self.h / 2
            x_part_mat.append(cell_cn_mat.flatten())
        return np.array(x_part_mat)

    def cn_BSLby_LTL(self):
        """Generates the connection matrix between the y cell selection layer
        and the linear transformation layer.  The connection pattern
        is discussed in our submitted paper.

        :return: connection matrix between y cell selection layer and
        linear transformation layer

        :rtype: numpy ndarray

        """

        y_part_mat = []
        # there are n_beta neurons in the beta cell selection layer
        for row_i in range(self.y_nsymbols):

            # set all connections to 0 first
            if self.cylinder_sets:
                cell_cn_mat = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            else:
                cell_cn_mat = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))

            # then make the relevant ones equal to h/2
            cell_cn_mat[row_i] = self.h / 2
            # and the ones to the right of the current cell equal to -h/2
            if row_i > 0:
                cell_cn_mat[row_i - 1] = -self.h / 2
            y_part_mat.append(cell_cn_mat.flatten())

        return np.array(y_part_mat)

    def cn_MCLx_LTL(self):
        """Generates the connection matrix between the x input neurons and
        the linear transformation layer.  These are the connections
        implementing the linear transformations of the NDA piecewise
        linear system.  The multiplication constants are implemented
        as multiplicative weights in the connection matrix, whereas
        the additive constants are implemented as biases to the linear
        transformation layer, outside this function.

        :return: connection matrix between x input neurons and linear
           transformation layer

        :rtype: numpy ndarray

        """
        if self.cylinder_sets:
            conn_mat_x1 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            conn_mat_x2 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            conn_mat_x1[:, :, 0, 0] = self.x_params[:, :, 0]
            conn_mat_x2[:, :, 0, 1] = self.x_params[:, :, 0]

            conn_mat = np.array([conn_mat_x1.flatten(), conn_mat_x2.flatten()])

        else:
            conn_mat_x = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            conn_mat_x[:, :, 0] = self.x_params[:, :, 0]

            conn_mat = np.array(conn_mat_x.flatten())

        return conn_mat

    def cn_MCLy_LTL(self):
        """Generates the connection matrix between the y input neurons and
        the linear transformation layer.  These are the connections
        implementing the linear transformations of the NDA piecewise
        linear system.  The multiplication constants are implemented
        as multiplicative weights in the connection matrix, whereas
        the additive constants are implemented as biases to the linear
        transformation layer, outside this function.

        :return: connection matrix between y input neurons and linear
        transformation layer

        :rtype: numpy ndarray

        """
        if self.cylinder_sets:
            conn_mat_y1 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            conn_mat_y2 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            conn_mat_y1[:, :, 1, 0] = self.y_params[:, :, 0]
            conn_mat_y2[:, :, 1, 1] = self.y_params[:, :, 0]

            conn_mat = np.array([conn_mat_y1.flatten(), conn_mat_y2.flatten()])

        else:
            conn_mat_y = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            conn_mat_y[:, :, 1] = self.y_params[:, :, 0]

            conn_mat = np.array(conn_mat_y.flatten())
        return conn_mat

    def LTL_biases_from_params(self):
        """Generates the biases for the neurons in the linear transformation
        layer, which implement the additive constants of the linear
        transfomations of the NDA piecewise linear system.

        :return: biases for linear transformation layer neurons
        :rtype: numpy ndarray

        """

        if self.cylinder_sets:
            biases = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            biases[:, :, 0, 0] = self.x_params[:, :, 1]
            biases[:, :, 0, 1] = self.x_params[:, :, 1]
            biases[:, :, 1, 0] = self.y_params[:, :, 1]
            biases[:, :, 1, 1] = self.y_params[:, :, 1]

        else:
            biases = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            biases[:, :, 0] = self.x_params[:, :, 1]
            biases[:, :, 1] = self.y_params[:, :, 1]

        return biases.flat

    def cn_LTL_MCLx(self):
        """:return: connection matrix between linear transformation layer and
        x input neurons.

        :rtype: numpy ndarray

        """

        if self.cylinder_sets:
            to_x_0 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            to_x_0[:, :, 0, 0] = 1
            to_x_1 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            to_x_1[:, :, 0, 1] = 1
            x_out_conn = np.array([to_x_0.flatten(), to_x_1.flatten()]).T

        else:
            to_x = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            to_x[:, :, 0] = 1
            x_out_conn = np.array(to_x.flatten())[:, None]

        return x_out_conn

    def cn_LTL_MCLy(self):
        """
        :return: connection matrix between linear transformation layer and
        x input neurons.

        :rtype: numpy ndarray

        """
        if self.cylinder_sets:
            to_y_0 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            to_y_0[:, :, 1, 0] = 1
            to_y_1 = np.zeros((self.y_nsymbols, self.x_nsymbols, 2, 2))
            to_y_1[:, :, 1, 1] = 1

            y_out_conn = np.array([to_y_0.flatten(), to_y_1.flatten()]).T

        else:
            to_y = np.zeros((self.y_nsymbols, self.x_nsymbols, 2))
            to_y[:, :, 1] = 1

            y_out_conn = np.array(to_y.flatten())[:, None]

        return y_out_conn

    def set_init_cond(self, init_x: np.ndarray, init_y: np.ndarray):
        self.MCLx.activation[:] = np.array(init_x)
        self.MCLy.activation[:] = np.array(init_y)

    def run_net(
            self,
            init_x: Optional[np.ndarray] = None,
            init_y: Optional[np.ndarray] =None, n_iterations=1):
        """Run the network, given the initial values for the x and y input
        neurons and the number of iterations

        :param init_x: initial activation values for left and right x
        input neurons

        :param init_y: initial activation values for left and right y
        input neurons

        :param n_iterations: the desired number of network iterations

        :return: list containing the input activation for each
            iteration. Each tuple item in the list contains two
            arrays, respectively containing the activations for the x
            and the y input neurons.  ``[ (np.array([x_l_act0,
            x_r_act0]), np.array([y_l_act0, y_r_act0])), ... ]``

        :rtype: list

        """

        act_history = []

        if init_x is not None:
            self.MCLx.activation[:] = np.array(init_x)
        if init_y is not None:
            self.MCLy.activation[:] = np.array(init_y)

        if self.cylinder_sets:
            MCL_acts = (self.MCLx.activation, self.MCLy.activation)
        else:
            MCL_acts = (self.MCLx.activation[0], self.MCLy.activation[0])

        act_history.append(MCL_acts)

        for iteration in range(n_iterations):
            self.BSLbx.activate()
            self.BSLby.activate()
            self.LTL.activate()
            self.MCLx.activate()
            self.MCLy.activate()

            if self.cylinder_sets:
                MCL_acts = (self.MCLx.activation, self.MCLy.activation)
            else:
                MCL_acts = (self.MCLx.activation[0], self.MCLy.activation[0])

            act_history.append(MCL_acts)

        return act_history


'''
Created on Mar 22, 2017

@author: Shurick

Alex Rozenblit

I pledge my honor that I have abided by the Stevens Honor System
'''

FullAdder = { ('0','0','0') : ('0','0'),
('0','0','1') : ('1','0'),
('0','1','0') : ('1','0'),
('0','1','1') : ('0','1'),
('1','0','0') : ('1','0'),
('1','0','1') : ('0','1'),
('1','1','0') : ('0','1'),
('1','1','1') : ('1','1') }

def numToBaseB(n,b):
    ''' Turns number n in decimal to the same number in base b '''
    if b > n:
        return n
    elif n == 0:
        return '0'
    else:
        return numToBaseBHelper(n,b)

def numToBaseBHelper(n,b):
    ''' Main code for numToBaseB. Helper function needed because of specific base case problem '''
    if n== 0:
        return ''
    elif n % b == 0:
        return numToBaseBHelper(n/b,b) + '0'
    else:
        return numToBaseBHelper(n//b,b) + '1'

def baseBToNum(s,b):
    ''' Turns s in base b to its equivalent in decimal'''
    def baseBToNumHelper(s,b,counter):
        if s == '':
            return '0'
        elif b == 10:
            return s
        elif int(s[-1]) == 1:
            counter = counter + 1
            return int(baseBToNumHelper(s[:-1],b,counter)) + b**counter
        else:
            counter = counter + 1
            return baseBToNumHelper(s[:-1],b,counter)
    return baseBToNumHelper(s,b,-1)

def baseToBase(b1,b2,sinb1):
    '''Turns sinb1 from base b1 to base b2 '''
    return numToBaseB(int(baseBToNum(sinb1,b1)),b2)

def add(s,t):
    ''' Adds s and t by converting both into base 10 and then converting back to base 2'''
    return numToBaseB(baseBToNum(s,2) + baseBToNum(t,2),2)

def addB(x,y):
    '''Adds binary numbers without having to convert them to decimal'''
    def addBHelper(x,y,carryBit):
        if len(x) != len(y):
            return eqlen(x,y)
        elif len(x) == 0 and carryBit == '1':
            return '1'
        elif len(x) == 0:
            return ''
        else:
            sumBit, carryBit = FullAdder[(x[-1],y[-1],carryBit)]
            return addBHelper(x[:-1],y[:-1],carryBit) + sumBit
    return addBHelper(x,y,'0')

def eqlen(x,y):
    ''' Ensures that addB will work even if the two numbers inputed are'nt the same lengths '''
    if len(x) > len(y):
        return addB(x,(len(x) - len(y)) * '0' + y)
    else:
        return addB((len(x) - len(y)) * '0' + x,y)

print(numToBaseB(4,2))
print(numToBaseB(4, 3))
print(numToBaseB(34, 6))
print(numToBaseB(0, 4))
print(baseBToNum("11", 2))
print(baseBToNum("11", 3))
print(baseBToNum("", 10))
print(baseToBase(2, 10, "11"))
print(baseBToNum('3',10))
print(baseToBase(10, 2, "3"))
print(baseToBase(3, 5, "11"))
print(add("11", "01"))
print(add("011", "100"))
print(add("110", "011"))
print(addB("11", "1"))
print(addB("011", "100"))


import asyncio
import serial
from serial.serialutil import SerialException
import json
import pytz
import time

from .models import RawMessage

from channels.db import database_sync_to_async

from channels.generic.websocket import AsyncWebsocketConsumer

class WSConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

        self.simulation_mode = False  # Set this flag to True for simulation mode

        try:
            self.serial = serial.Serial(
                port='/dev/ttyUSB0',
                baudrate=9600,
                bytesize=serial.EIGHTBITS,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                timeout=1
            )
        except SerialException as e:
            await self.send(f"Error opening serial port: {str(e)}")
            return

        # Start reading data from the serial port
        await self.read_data()

    async def disconnect(self, close_code):
        if hasattr(self, 'serial'):
            self.serial.close()

    @database_sync_to_async
    def save_message_to_db(self, data):
        # Check if the data contains null characters
        if '\x00' in data:
            # Replace null characters with a message
            sanitized_data = data.replace('\x00', 'null character were sent ---> \x00')
        else:
            sanitized_data = data

        message_instance = RawMessage(data=sanitized_data)
        message_instance.save()

# ...
    async def read_data(self):
        tz = pytz.timezone('Europe/London')

        while True:
            try:
                data = self.serial.readline().decode('utf-8')

                if data:
                    # Create and save a Message instance with the received message
                    try:
                        await self.save_message_to_db(data)
                    except Exception as e:
                        print(f"Error while saving the message: {str(e)}")

                    message = {"meta": f"{data}"}
                    print(message)

                    await self.send(text_data=json.dumps(message))
                else:
                    print(f'No incoming data from drystore')

            except SerialException as e:
                await self.send(f"Serial port error: {str(e)}")
            except Exception as e:
                await self.send(f"Error: {str(e)}")

            await asyncio.sleep(1)  # Sleep for 1 second before checking the serial port again


"""MULTI2 cipher.

Source: Cryptanalysis of the ISDB Scrambling Algorithm (MULTI2)
"""
from cascada.bitvector.core import Constant
from cascada.bitvector.operation import RotateLeft, BvOr

from cascada.bitvector.ssa import RoundBasedFunction
from cascada.primitives.blockcipher import Encryption, Cipher

REFERENCE_VERSION = False  # if True, constants are added in the encryption

def pi1(L):
    return L

def pi2(R, k_i):
    if REFERENCE_VERSION:
        x = RotateLeft(R + k_i, 1) + (R + k_i) + (-Constant(1, 32))
    else:
        assert isinstance(k_i, list)
        x = RotateLeft(R + k_i[0], 1) + (R + k_i[1])
    return RotateLeft(x, 4) ^ x

def pi3(L, k_i, k_j):
    if REFERENCE_VERSION:
        y = RotateLeft(L + k_i, 2) + (L + k_i) + Constant(1, 32)
    else:
        assert isinstance(k_i, list)
        y = RotateLeft(L + k_i[0], 2) + (L + k_i[1])

    x = RotateLeft(RotateLeft(y, 8) ^ (y + k_j), 1) - (RotateLeft(y, 8) ^ (y + k_j))

    return RotateLeft(x, 16) ^ (BvOr(x, L))

def pi4(R, k_i):
    if REFERENCE_VERSION:
        x = RotateLeft(R + k_i, 2) + (R + k_i) + Constant(1, 32)
    else:
        assert isinstance(k_i, list)
        x = RotateLeft(R + k_i[0], 2) + (R + k_i[1])
    return x

class MULTI2KeySchedule(RoundBasedFunction):
    """Key schedule function."""

    num_rounds = 32
    input_widths = [32, 32] + [32 for _ in range(8)]
    output_widths = [32 for _ in range(8)]
    _min_num_rounds = 2

    @classmethod
    def get_num_keys(cls):
        num_system_keys = 0
        num_round_keys = 0
        for i in range(min(8, cls.num_rounds)):
            if i == 0:
                # s[1] |
                num_system_keys += 1
            elif i == 1:
                # s[2], s[3] | k[1]
                num_system_keys += 2
                num_round_keys += 1
            elif i == 2:
                # s[4] |  k[2], k[3]
                num_system_keys += 1
                num_round_keys += 2
            elif i == 3:
                # | k[4]
                num_round_keys += 1
            elif i == 4:
                # s[5] |
                num_system_keys += 1
            elif i == 5:
                # s[6], s[7] | k[5]
                num_system_keys += 2
                num_round_keys += 1
            elif i == 6:
                # s[8] | k[6], k[7]
                num_system_keys += 1
                num_round_keys += 2
            elif i == 7:
                # | k[8]
                num_round_keys += 1

        num_expanded_round_keys = num_round_keys
        if not REFERENCE_VERSION:
            for i in range(min(8, cls.num_rounds)):
                if i == 0:
                    pass
                elif i == 1:
                    num_expanded_round_keys += 1
                elif i == 2:
                    num_expanded_round_keys += 1
                elif i == 3:
                    num_expanded_round_keys += 1
                elif i == 4:
                    pass
                elif i == 5:
                    num_expanded_round_keys += 1
                elif i == 6:
                    num_expanded_round_keys += 1
                elif i == 7:
                    num_expanded_round_keys += 1

        return num_system_keys, num_round_keys, num_expanded_round_keys

    @classmethod
    def set_num_rounds(cls, new_num_rounds):
        assert new_num_rounds >= cls._min_num_rounds
        cls.num_rounds = new_num_rounds
        num_system_keys, _, num_expanded_round_keys = cls.get_num_keys()
        cls.input_widths = [32, 32] + [32 for _ in range(num_system_keys)]
        cls.output_widths = [32 for _ in range(num_expanded_round_keys)]

    @classmethod
    def eval(cls, d1, d2, *system_key):
        s = [None] + list(system_key)

        num_system_keys, num_round_keys, num_expanded_round_keys = cls.get_num_keys()

        global REFERENCE_VERSION
        old_ref_v = REFERENCE_VERSION
        REFERENCE_VERSION = True

        k = [None]
        for i in range(num_round_keys):
            if i == 0:
                k.append(d1 ^ pi2(d1 ^ d2, s[1]))
            elif i == 1:
                k.append(d1 ^ d2 ^ pi3(k[1], s[2], s[3]))
            elif i == 2:
                k.append(k[1] ^ pi4(k[2], s[4]))
            elif i == 3:
                k.append(k[2] ^ k[3])
            elif i == 4:
                k.append(k[3] ^ pi2(k[4], s[5]))
            elif i == 5:
                k.append(k[4] ^ pi3(k[5], s[6], s[7]))
            elif i == 6:
                k.append(k[5] ^ pi4(k[6], s[8]))
            elif i == 7:
                k.append(k[6] ^ k[7])

        assert len(k) == num_round_keys + 1

        REFERENCE_VERSION = old_ref_v

        if not REFERENCE_VERSION:
            if len(k) > 8:
                # pi4(R, k[8]) | pi4 : k_i + Constant(1, 32)
                k.append(k[8] + Constant(1, 32))

            if len(k) > 6:
                # pi3(L, k[6], *) | pi3 : k_i + Constant(1, 32)
                k.append(k[6] + Constant(1, 32))

            if len(k) > 5:
                # pi2(R, k[5]) | pi2 : k_i + (-Constant(1, 32))
                k.append(k[5] + (-Constant(1, 32)))

            if len(k) > 4:
                # pi4(R, k[4]) | pi4 : k_i + Constant(1, 32)
                k.append(k[4] + Constant(1, 32))

            if len(k) > 2:
                # pi3(L, k[2], *) | pi3 : k_i + Constant(1, 32)
                k.append(k[2] + Constant(1, 32))

            if len(k) > 1:
                # pi2(R, k[1]) | pi2 : k_i + (-Constant(1, 32))
                k.append(k[1] + (-Constant(1, 32)))

        assert len(k) == num_expanded_round_keys + 1

        return k[1: 1+num_expanded_round_keys]

class MULTI2Encryption(Encryption, RoundBasedFunction):
    """Encryption function."""

    num_rounds = 32
    input_widths = [32, 32]
    output_widths = [32, 32]
    round_keys = None

    @classmethod
    def set_num_rounds(cls, new_num_rounds):
        cls.num_rounds = new_num_rounds

    @classmethod
    def eval(cls, L, R):
        k = [None] + list(cls.round_keys)

        for i in range(cls.num_rounds):
            if REFERENCE_VERSION:
                if i % 8 == 0:
                    R ^= pi1(L)
                elif i % 8 == 1:
                    L ^= pi2(R, k[1])
                elif i % 8 == 2:
                    R ^= pi3(L, k[2], k[3])
                elif i % 8 == 3:
                    L ^= pi4(R, k[4])
                elif i % 8 == 4:
                    R ^= pi1(L)
                elif i % 8 == 5:
                    L ^= pi2(R, k[5])
                elif i % 8 == 6:
                    R ^= pi3(L, k[6], k[7])
                elif i % 8 == 7:
                    L ^= pi4(R, k[8])
            else:
                if i % 8 == 0:
                    R ^= pi1(L)
                elif i % 8 == 1:
                    L ^= pi2(R, [k[1], k[-1]])
                elif i % 8 == 2:
                    R ^= pi3(L, [k[2], k[-2]], k[3])
                elif i % 8 == 3:
                    L ^= pi4(R, [k[4], k[-3]])
                elif i % 8 == 4:
                    R ^= pi1(L)
                elif i % 8 == 5:
                    L ^= pi2(R, [k[5], k[-4]])
                elif i % 8 == 6:
                    R ^= pi3(L, [k[6], k[-5]], k[7])
                elif i % 8 == 7:
                    L ^= pi4(R, [k[8], k[-6]])
            cls.add_round_outputs(L, R)

        return L, R

class MULTI2Cipher(Cipher):
    """MULTI2 cipher."""
    key_schedule = MULTI2KeySchedule
    encryption = MULTI2Encryption
    _min_num_rounds = 2

    @classmethod
    def set_num_rounds(cls, new_num_rounds):
        assert new_num_rounds >= cls._min_num_rounds
        cls.encryption.set_num_rounds(new_num_rounds)
        cls.key_schedule.set_num_rounds(new_num_rounds)

    @classmethod
    def test(cls):
        old_num_rounds = cls.num_rounds

        global REFERENCE_VERSION

        for ref_v in [True, False]:
            REFERENCE_VERSION = ref_v

            cls.set_num_rounds(32)

            plaintext = [0, 0]
            key = [0 for _ in range(len(cls.key_schedule.input_widths))]
            ciphertext = (0x1d9dfa1e, 0x4d64bc67)
            assert cls(plaintext, key) == ciphertext

            plaintext = [0x01, 0x23]
            key = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23]
            ciphertext = (0xd241e7c8, 0x74166979)
            assert cls(plaintext, key) == ciphertext

        cls.set_num_rounds(old_num_rounds)


import random

category_list = [['kopek', 'kedi', 'dinazor', 'balik'], ['elma', 'armut', 'karpuz', 'balkabagi']]
word = None
index = None
hangman = ["|\n"
          "|\n"
          "|", "|---\n"
               "|\n"
               "|\n"
               "|\n", "|---\n"
                    "|  |\n"
                    "|\n"
                    "|\n", "|---\n"
                         "|  |\n"
                         "|  O\n"
                         "| -|-\n"
                         "  / \*\n"]
game_map = []
used_letters = []

def ask_for_category():
    categories = ['Hayvanlar','Meyveler']
    print(categories)
    while True:
        category = input("Which category you want to play: ").capitalize()
        if category in categories:
            index = categories.index(category)
            return choose_a_word(category_list[index])
        else:
            print("You should choose a category from the category list.")

def choose_a_word(list_of_words):
    return random.choice(list_of_words)

def create_game():
    for i in word:
        game_map.append("_")
    print(game_map)

def check_the_answer(letter):
    global count

    index_of_letter = -1
    if letter in word and letter not in used_letters:
        for i in word:
            index_of_letter += 1
            if i == letter:
                game_map[index_of_letter] = i
        used_letters.append(letter)
    elif letter in used_letters:
        print("You already used that letter.")
    else:
        count = count + 1
        print('')
        print(hangman[count])
        used_letters.append(letter)
    print('')
    print(game_map)
    print('')
def check_win():
    if "_" not in game_map:
        print("Congratulations the word was "+ word + ".")
        exit()

word = ask_for_category()

create_game()
count = -1
while count != 3:
    print("Used letters: ",end="")
    print(used_letters)
    move = input("\nChoose a letter: ")
    check_the_answer(move)
    check_win()
print("The word was "+word+". Sorry.")


from pirc522 import RFID
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
import signal
import time

GPIO.setwarnings(False)
LEDverte =40
LEDrouge = 37
rc522 = RFID()
buzz=32
GPIO.setup(buzz,GPIO.OUT)
GPIO.setup(LEDverte,GPIO.OUT)
GPIO.setup(LEDrouge,GPIO.OUT)
GPIO.output(LEDverte,GPIO.LOW)
GPIO.output(LEDrouge,GPIO.LOW)
GPIO.output(buzz,GPIO.LOW)
while True:
     GPIO.output(LEDverte,GPIO.LOW)
     GPIO.output(LEDrouge,GPIO.LOW)
     GPIO.output(buzz,GPIO.LOW)
     i=0
     code=""

     (error, tag_type) = rc522.request()
     if not error:
        (error, uid) = rc522.anticoll()
        if not error:
            for i in range(0, len(uid)):
                code += str(uid[i])
                time.sleep(0.05)

            print(code)
            fichier = open("key.txt","w")
            fichier.write(code)
            fichier.close()
            if(code=="43100103411"):
                 GPIO.output(buzz,GPIO.HIGH)
                 GPIO.output(LEDverte,GPIO.HIGH)
                 time.sleep(1)
                 GPIO.output(buzz,GPIO.LOW)
                 GPIO.output(LEDverte,GPIO.LOW)
            elif(code=="1056436163174"):
                 GPIO.output(buzz,GPIO.HIGH)
                 GPIO.output(LEDverte,GPIO.HIGH)
                 time.sleep(1)
                 GPIO.output(buzz,GPIO.LOW)
                 GPIO.output(LEDverte,GPIO.LOW)

            else:
                 GPIO.output(LEDrouge,GPIO.HIGH)
                 time.sleep(1)
                 GPIO.output(buzz,GPIO.LOW)
                 GPIO.output(LEDrouge,GPIO.LOW)


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

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Cluster:
    def __init__(self, center, points=[]):
        self.center = center
        self.points = points

    def find_new_center(self):
        if len(self.points) <= 0:
            return
        x, y = 0, 0
        for point in self.points:
            x += point.x
            y += point.y
        self.center = Point(x / len(self.points), y / len(self.points))

n = 500
k = 5
colors = []

for _ in range(125):
    color = ["#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)])]
    colors.append(color)

def calculate_dist(a, b):
    return np.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2)

def random_points(n, k):
    temp = []
    ces = centers([Point(0, 0), Point(0, 250)], k)
    for i in range(k):
        radius = int((0.5 + random.random()) * 70)
        for j in range(int(n / k)):
            r = radius * math.sqrt(random.random())
            alpha = 2 * math.pi * random.random()
            temp.append(Point(r * math.cos(alpha) + ces[i].x, r * math.sin(alpha) + ces[i].y))

    return temp

def centers(points, k):
    temp = list()
    x_s, y_s = 0, 0
    for point in points:
        x_s += point.x
        y_s += point.y
    x_s /= len(points)
    y_s /= len(points)
    center = Point(x_s, y_s)
    max_dist = 0
    for point in points:
        max_dist = max(max_dist, calculate_dist(point, center))

    for i in range(k):
        x_f = x_s + max_dist * math.cos(2 * i * np.pi / k)
        y_f = y_s + max_dist * math.sin(2 * i * np.pi / k)
        temp.append(Point(x_f, y_f))

    return temp

def draw(clusters, points, matrix):
    fig = plt.figure(figsize=(10, 10))
    ax = fig.add_subplot(1, 1, 1)
    ax.set_facecolor('grey')
    matrix_per_point = matrix.transpose()

    for p_i, point in enumerate(points):
        cluster_index = max([x for x in enumerate(matrix_per_point[p_i])], key=lambda x: x[1])[0]
        plt.scatter(point.x, point.y, c=colors[cluster_index], alpha=0.3)
    for c_i, cluster in enumerate(clusters):
        plt.scatter(cluster.center.x, cluster.center.y, c=colors[c_i])
    plt.show()

def calculate_matrix(points, clusters, m):
    matrix = np.zeros(shape=(len(clusters), len(points)))
    p = 2 / (m - 1)
    for p_i, point in enumerate(points):
        sum_t = sum([(1 / calculate_dist(point, temp.center)) ** p for temp in clusters])
        for c_i, cluster in enumerate(clusters):
            matrix[c_i][p_i] = ((1 / calculate_dist(point, cluster.center)) ** p) / sum_t
    return matrix

def centroids(points, clusters, matrix):
    for c_i, cluster in enumerate(clusters):
        sum_t = np.zeros(2)
        for p_i, point in enumerate(points):
            sum_t += np.array([point.x * matrix[c_i][p_i], point.y * matrix[c_i][p_i]])
        cluster.center = Point(sum_t[0] / sum(matrix[c_i]), sum_t[1] / sum(matrix[c_i]))

def check(matrix1, matrix2, e, n, k):
    for i in range(k):
        for j in range(n):
            if abs(matrix1[i][j] - matrix2[i][j]) > e: return True
    return False

def c_means(points, centers, m, e):
    clusters = list()
    for center in centers:
        clusters.append(Cluster(center))
    for point in points:
        cluster_temp = clusters[0]
        for cluster in clusters:
            if calculate_dist(point, cluster.center) < calculate_dist(point, cluster_temp.center):
                cluster_temp = cluster
        cluster_temp.points.append(point)
    matrix = calculate_matrix(points, clusters, m)
    draw(clusters, points, matrix)

    centroids(points, clusters, matrix)
    new_matrix = calculate_matrix(points, clusters, m)

    while check(matrix, new_matrix, e, n, k):
        matrix = new_matrix
        centroids(points, clusters, matrix)
        new_matrix = calculate_matrix(points, clusters, m)
        draw(clusters, points, matrix)

points_list = random_points(n, k)
clusters_t = centers(points_list, k)
c_means(points_list, clusters_t, 2, 0.01)


"""
    Telegram Bot
"""
import logging

# Importing telegram python module
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters

# Importing app modules
from twitter import models
import telegram_handler.utils as utils
import telegram_handler as handler

# Setting up the logger
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)

# Global object to store last tweet data
tweet = models.Tweet(None, "", [])

def bot():
    """Main function to start the bot"""
    # Setting up the updater
    updater = Updater(token=utils.get_secret(), use_context=True)
    # Setting up the dispatcher
    dispatcher = updater.dispatcher

    # Handlers
    start_handler = CommandHandler('start', handler.start)
    message_handle = MessageHandler(Filters.text & ~Filters.command, handler.send_tweet)
    delete_handle = CommandHandler('delete', handler.delete_tweet)
    comment_handle = CommandHandler('comment', handler.comment_tweet, pass_args=True)
    test_handle = CommandHandler('test', handler.test)

    # Adding handlers to the dispatcher
    dispatcher.add_handler(start_handler)
    dispatcher.add_handler(message_handle)
    dispatcher.add_handler(delete_handle)
    dispatcher.add_handler(test_handle)
    dispatcher.add_handler(comment_handle)

    # Starting the bot
    updater.start_polling()


def chk(i, j):
    global b
    global arr_chk
    block = b[i][j]
    if b[i+1][j] == block and b[i][j+1] == block and b[i+1][j+1] == block and block !=0:
        arr_chk[i][j], arr_chk[i+1][j], arr_chk[i][j+1], arr_chk[i+1][j+1] = 1, 1, 1, 1
    return 0

def down_block(h,w):
    global b
    for i in range(w):
        c = []
        for j in range(h-1, -1, -1):
            if b[j][i] != 0:
                c.append(b[j][i])
        for j in range(h-1, -1, -1):
            if len(c) != 0:
                b[j][i] = c.pop(0)
            else:
                b[j][i] = 0

def solution(m, n, board):
    global arr_chk
    global cnt
    global b
    b = []
    for i in range(len(board)):
        b.append(list(board[i]))

    cnt = 0
    arr_chk = [[0 for i in range(n)] for j in range(m)]
    print(m,n)

    #m, n : 세로 가로
    # 왼쪽위 기준으로 자신, 우, 하, 대각아래 체크, 세로 1~m까지 가로 0~n-1까지

    h, w = len(board), len(board[0])

    while True:
        for i in range(0, h-1):
            for j in range(0, w-1):
                chk(i, j)

        val = 0
        for i in range(h):
            for j in range(w):
                val += arr_chk[i][j]

        if val == 0:
            break
    # cnt증가 후 배열 초기화
        for i in range(h):
            for j in range(w):
                if arr_chk[i][j] == 1:
                    b[i][j] = 0
                    cnt += 1

        down_block(h,w)

        arr_chk = [[0 for i in range(n)] for j in range(m)]

    return cnt

#feat(Jeongmu-Jo): [카카오, 2018블라인드] 프렌즈4블럭


from django.contrib import messages
from django.shortcuts import redirect, render
from forum.forms import ThreadForm, ThreadReplyForm
from django.contrib.auth.decorators import login_required
from forum.models import Thread

@login_required
def home(request):
    threads = Thread.objects.all()
    return render(request, 'forum/index.html', { "threads": threads })

@login_required
def thread_detail(request, pk):
    thread = Thread.objects.get(id = pk)
    return render(request, 'forum/thread_detail.html', { "thread": thread })

@login_required
def add_thread(request):
    if request.method == 'POST':
        form = ThreadForm(request.POST)
        if form.is_valid():
            thread = form.save(commit=False)
            thread.user = request.user
            thread.save()
            messages.success(request, 'Thread berhasil dibuat')
            return redirect('forum:home')
        else:
            messages.error(request, form.errors)
    return render(request, 'forum/add_thread.html')

@login_required
def edit_thread(request, pk):
    thread = Thread.objects.get(id = pk)
    if request.user != thread.user:
        messages.error(request,'403: Access Denied')
        return redirect('forum:home')
    if request.method == 'POST':
        form = ThreadForm(request.POST, instance=thread)
        if form.is_valid():
            form.save()
            return redirect('forum:detail_thread', pk=pk)
        else:
            messages.error(request, form.errors)
    return render(request, 'forum/edit_thread.html', { 'thread' : thread })

@login_required
def reply_thread(request, pk):
    if request.method == "POST":
        form = ThreadReplyForm(request.POST)
        if form.is_valid():
            reply = form.save(commit=False)
            reply.user = request.user
            reply.main_thread = Thread.objects.get(id = pk)
            reply.save()
            return redirect('forum:detail_thread', pk=pk)
        else:
            messages.error(request, form.errors)
    thread = Thread.objects.get(id = pk)
    return render(request, 'forum/reply_thread.html', { 'thread' : thread })

@login_required
def delete_thread(request, pk):
    thread = Thread.objects.get(id = pk)
    if request.user != thread.user:
        messages.error(request,'403: Access Denied')
        return redirect('forum:home')
    if request.method == 'POST':
        thread.delete()
        messages.success(request, 'Thread berhasil dihapus')
        return redirect('forum:home')
    return render(request, 'forum/delete_thread.html', { "thread" : thread })


from core.api.decorators.validators import allowed_methods
from twiits.models import Tweet
from .delete_tweet import DeleteTweet
import core.api.responses.error_codes as error_codes

class DeleteTweetV1(DeleteTweet):
    __versions_compatible__ = ('1', '1.0')

    def __init__(self, **kwargs):
        super(DeleteTweetV1, self).__init__(**kwargs)
        self.allowed_methods = ('POST', )

    @allowed_methods
    def get_or_create_data(self):
        ctxt = dict()
        self._data = ctxt

        tweet_id = self.kwargs.get('tweet_id')
        if not tweet_id:
            self.set_bad_req('tweet id not passed', error_code=error_codes.MISSING_PARAMS)
            return self._data

        user = self.get_user()
        try:
            tweet = Tweet.objects.get(id=tweet_id, user=user)
            tweet.delete()
            ctxt['is_deleted'] = True
        except Tweet.DoesNotExist:
            ctxt['is_deleted'] = False

        return self._data


import os, sys
ROOT_PATH = os.path.dirname(os.path.abspath('settings.py'))
sys.path.append(ROOT_PATH)
sys.path.append(os.path.join(ROOT_PATH, '..','..', 'CommunityTools', 'sphenecoll'))

DEBUG=True

AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)

ADMINS = (
          ('Firstyear', 'firstyear@internode.on.net'),
          ('Micolous', 'micolous@gmail.com'),
          ('tWoolie', 'woolford.thomas@gmail.com'),
          )

DATABASES = {'default':
             {
              'ENGINE':'django.db.backends.sqlite3',
              'NAME': 'test.db',
              }
             }

LDAP_AUTH_SETTINGS = (
                      {'url': 'ldap://ldap.example.com',
                       'bindname' : 'someuser',
                       'realm': 'EXAMPLE.COM',
                      },
                     )