import re
from copy import deepcopy as cp

import numpy as np
import torch
import torch.nn.functional as F
from transformers import BartTokenizer

from .generation_tricks import get_n_gram

Tokenizer = BartTokenizer.from_pretrained("facebook/bart-large")
translator = re.compile('[%s]' % re.escape('!#$%&()*+,./:;<=>?@[]^_{|}~'))
stop_words = ['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're", "you've", "you'll", "you'd",
              'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 'himself', 'she', "she's", 'her', 'hers',
              'herself', 'it', "it's", 'its', 'itself', 'they', 'them', 'their', 'theirs', 'themselves', 'what',
              'which', 'who', 'whom', 'this', 'that', "that'll", 'these', 'those', 'am', 'is', 'are', 'was', 'were',
              'be', 'been', 'being', 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing', 'a', 'an', 'the',
              'and', 'but', 'if', 'or', 'because', 'as', 'until', 'while', 'of', 'at', 'by', 'for', 'with', 'about',
              'against', 'between', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from',
              'up', 'down', 'in', 'out', 'on', 'off', 'over', 'under', 'again', 'further', 'then', 'once', 'here',
              'there', 'when', 'where', 'why', 'how', 'all', 'any', 'both', 'each', 'few', 'more', 'most', 'other',
              'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', 's', 't', 'can',
              'will', 'just', 'don', "don't", 'should', "should've", 'now', 'd', 'll', 'm', 'o', 're', 've', 'y', 'ain',
              'aren', "aren't", 'couldn', "couldn't", 'didn', "didn't", 'doesn', "doesn't", 'hadn', "hadn't", 'hasn',
              "hasn't", 'haven', "haven't", 'isn', "isn't", 'ma', 'mightn', "mightn't", 'mustn', "mustn't", 'needn',
              "needn't", 'shan', "shan't", 'shouldn', "shouldn't", 'wasn', "wasn't", 'weren', "weren't", 'won', "won't",
              'wouldn', "wouldn't"]
stop_bigrams = set([(a, b) for a in stop_words for b in stop_words])

def splitter(x):
    return (translator.sub(' ', x)).split()

def adding_cls_sep_2d(inputs, cls, sep):
    new_inputs = []
    for seq in inputs:
        new_seq = [cls] + seq + [sep]
        new_inputs.append(new_seq)
    return new_inputs

def adding_cls_sep_3d(inputs, cls, sep):
    new_inputs = []
    for inst in inputs:
        new_inst = adding_cls_sep_2d(inst, cls, sep)
        new_inputs.append(new_inst)
    return new_inputs

def pad_2d_inputs(inputs, pad, t=torch.LongTensor):
    lengths = [len(it) for it in inputs]
    max_len = max(lengths)
    padded_inputs = []
    for seq in inputs:
        new_seq = t(seq)
        padded_seq = F.pad(new_seq, (0, max_len - len(seq)), "constant", pad)
        padded_inputs.append(padded_seq)
    padded_inputs = torch.stack(padded_inputs)
    return padded_inputs

def pad_3d_inputs(inputs, pad):
    """
    :param inputs: Batch, Number, Length
    :param pad: int
    :return: padded_torch_tensor
    """
    numbers = [len(i) for i in inputs]
    lengths = [len(j) for i in inputs for j in i]
    max_num = max(numbers)
    max_len = max(lengths)

    padded_inputs = []
    for inst in inputs:
        padded_inst = []
        for seq in inst:
            seq_j = torch.LongTensor(seq)
            padded_seq = F.pad(seq_j, (0, max_len - len(seq)), "constant", pad)
            padded_inst.append(padded_seq)
        padded_inst = torch.stack(padded_inst)
        padded_inst = F.pad(padded_inst, (0, 0, 0, max_num - len(inst)), "constant", pad)
        padded_inputs.append(padded_inst)
    padded_inputs = torch.stack(padded_inputs)
    return padded_inputs

def pad_4d_inputs(inputs, pad):
    """
    :param inputs: Batch, D1, D2, Length
    :param pad: int
    :return: padded_torch_tensor
    """
    d_3 = [len(i) for i in inputs]
    d_2 = [len(j) for i in inputs for j in i]
    d_1 = [len(k) for i in inputs for j in i for k in j]

    max_d1 = max(d_1)
    max_d2 = max(d_2)
    max_d3 = max(d_3)

    padded_inputs = []
    for t3 in inputs:
        padded_i = []
        for t2 in t3:
            padded_j = []
            for t1 in t2:
                t1 = torch.LongTensor(t1)
                padded_k = F.pad(t1, (0, max_d1 - len(t1)), "constant", pad)
                padded_j.append(padded_k)
            padded_j = torch.stack(padded_j)
            padded_j = F.pad(padded_j, (0, 0, 0, max_d2 - len(t2)), "constant", pad)
            padded_i.append(padded_j)
        padded_i = torch.stack(padded_i)
        padded_i = F.pad(padded_i, (0, 0, 0, 0, 0, max_d3 - len(t3)), "constant", pad)
        padded_inputs.append(padded_i)
    padded_inputs = torch.stack(padded_inputs)
    return padded_inputs

def merge2d(data_1, data_2):
    new_data = []
    for inst_1, inst_2 in zip(data_1, data_2):
        new_data.append(cp(inst_1) + cp(inst_2))
    return new_data

def cross_merge2d(data_1, data_2):
    ret = []
    for inst_1 in data_1:
        ret_i = []
        for inst_2 in data_2:
            ret_i.append(cp(inst_2) + cp(inst_1))
        ret.append(ret_i)
    return ret

def cross_merge3d(data_1, data_2):
    ret = []
    for inst_1, inst_2 in zip(data_1, data_2):
        ret.append(cross_merge2d(inst_1, inst_2))
    return ret

def plain_text(inputs, head=None):
    if head is None:
        return [token for sent in inputs for token in sent]
    else:
        return [token for sent in inputs for token in [head] + sent]

def create_chunks_for_instance_token(doc_inputs, kernel_size, stride, output=False):
    plain_doc_inputs = plain_text(doc_inputs)
    n = len(doc_inputs)
    len_sent = [len(it) for it in doc_inputs]
    c = np.asarray([0] + len_sent).cumsum()
    l = c[-1]
    st = list(range(0, l, stride))
    ed = [min(it + kernel_size, l) for it in st]
    new_st = []
    total_sents = 0
    i = 0
    for it in st:
        while c[i] < it:
            i += 1
        new_st.append(c[i])
        total_sents -= i
    new_ed = []
    j = 0
    for it in ed:
        while (j < n) and c[j + 1] <= it:
            j += 1
        new_ed.append(c[j])
        total_sents += j
    chunks = []
    for start, end in zip(new_st, new_ed):
        new_chunk = cp(plain_doc_inputs[start:end])
        chunks.append(new_chunk)
    if output:
        return chunks, total_sents
    return chunks

def create_chunks_for_instance_sent(doc_inputs, kernel_size, stride, output=False):
    n = len(doc_inputs)
    st = list(range(0, n, stride))
    ed = [min(it + kernel_size, n) for it in st]
    chunks = []
    total_sents = 0
    for start, end in zip(st, ed):
        chunk = cp(plain_text(doc_inputs[start: end]))
        k = end
        while len(chunk) > 510:
            k -= 1
            chunk = cp(plain_text(doc_inputs[start: k]))
        chunks.append(chunk)
        total_sents += k - start
    if output:
        return chunks, total_sents
    return chunks

def create_chunks_for_batch(batch_docs, config):
    batch_chunks = []
    for doc_inputs in batch_docs:
        if config.window_type == "token":
            batch_chunks.append(create_chunks_for_instance_token(doc_inputs, config.kernel_size, config.stride))
        elif config.window_type == "sent":
            batch_chunks.append(create_chunks_for_instance_sent(doc_inputs, config.kernel_size, config.stride))
    return batch_chunks

def create_chunks_4_batch_w_total_sents(batch_docs, config):
    batch_chunks = []
    total_sents = 0
    for doc_inputs in batch_docs:
        if config.window_type == "token":
            chunks, n_sents = create_chunks_for_instance_token(doc_inputs, config.kernel_size, config.stride, True)
            batch_chunks.append(chunks)
            total_sents += n_sents
        elif config.window_type == "sent":
            chunks, n_sents = create_chunks_for_instance_sent(doc_inputs, config.kernel_size, config.stride, True)
            batch_chunks.append(chunks)
            total_sents += n_sents
    return batch_chunks, total_sents

def overlap_score(hyp, ref, c=0.8, k=512, flag=True):
    r = c / k
    ref_2gram = get_n_gram(ref, 2)
    total = len(ref_2gram)
    if total == 0:
        return 0.0
    score = 0
    for i, bi_gram in enumerate(zip(hyp, hyp[1:])):
        w = 1 - i * r
        if bi_gram in ref_2gram:
            score += w
            if flag:
                ref_2gram.remove(bi_gram)
    return score / total

def n_gram_overlap_ratio(hyp, ref, n=2):
    hyp = splitter(Tokenizer.decode(hyp).lower())
    ref = splitter(Tokenizer.decode(ref).lower())

    ref_n_gram = set(get_n_gram(ref, n))
    if len(ref_n_gram) == 0:
        return 0
    inter = (ref_n_gram & set(get_n_gram(hyp, n))) - stop_bigrams
    return len(inter) / len(ref_n_gram)

def n_gram_overlap_count(hyp, ref, n=2):
    hyp = splitter(Tokenizer.decode(hyp).lower())
    ref = splitter(Tokenizer.decode(ref).lower())

    return len((set(get_n_gram(ref, n)) & set(get_n_gram(hyp, n))) - stop_bigrams)

def calculate_overlap_score_full(batch_chunks, batch_refs, flag):
    s = []
    for chunks, refs in zip(batch_chunks, batch_refs):
        n = len(chunks)
        score = []
        for i in range(n):
            score.append(overlap_score(chunks[i], plain_text(refs), flag=flag))
        s.append(score)
    return s

def calculate_overlap_score_sent(batch_chunks, batch_refs, flag):
    s = []
    for chunks, refs in zip(batch_chunks, batch_refs):
        n = len(chunks)
        m = len(refs)
        scores = []
        for i in range(m):
            scores_i = []
            for j in range(n):
                scores_i.append(overlap_score(chunks[j], refs[i], flag=flag))
            scores.append(scores_i)
        s.append(scores)
    return s

def calculate_n_gram_overlap_sent(batch_chunks, batch_refs):
    s = []
    for chunks, refs in zip(batch_chunks, batch_refs):
        n = len(chunks)
        m = len(refs)
        scores = []
        for i in range(m):
            scores_i = []
            for j in range(n):
                scores_i.append(n_gram_overlap_count(chunks[j], refs[i]))
            scores.append(cp(scores_i))
        s.append(scores)
    return s

def pick_golden_chunks(batch_chunks, batch_refs, require_batch_qualify=False):
    batch_n_gram_overlap = calculate_n_gram_overlap_sent(batch_chunks, batch_refs)

    ret = []
    if require_batch_qualify:
        ret_qualify = []

    for inst_n_gram_overlap in batch_n_gram_overlap:
        picked_ids_ = list(np.argmax(np.asarray(inst_n_gram_overlap), axis=-1))
        qualify = [(max(it) >= 4) for it in inst_n_gram_overlap]
        cur = 0
        picked_ids = []
        for qual, pick in zip(qualify, picked_ids_):
            if qual:
                cur = pick
            picked_ids.append(cur)
        ret.append(cp(picked_ids))
        if require_batch_qualify:
            ret_qualify.append(cp(qualify))
    if require_batch_qualify:
        return ret, ret_qualify
    return ret

def apply_filter(inputs, outputs, config):
    batch_chunks = create_chunks_for_batch([inputs], config)
    ref_chunk_ids = pick_golden_chunks(batch_chunks, [outputs])

    ref_chunk_ids = ref_chunk_ids[0]

    hyp = []

    for chunk_id in sorted(list(set(ref_chunk_ids))):
        if chunk_id >= 0:
            hyp += batch_chunks[0][chunk_id]

    ref = plain_text(outputs)

    n_overlap = n_gram_overlap_count(hyp, ref)
    return n_overlap < config.n_overlap_constrain

def pick_first_chunk(batch_scores):
    ret = []
    for inst_scores in batch_scores:
        picked_id = int(np.argmax(np.asarray(inst_scores)))
        ret.append(picked_id)
    return ret

def get_batch_chunks_by_ids(batch_chunks, batch_golden_chunk_ids):
    batch_golden_chunks = []
    for chunks, ids in zip(batch_chunks, batch_golden_chunk_ids):
        golden_chunks = []
        if type(ids) == list:
            for id in ids:
                golden_chunks.append(cp(chunks[id]))
        else:
            golden_chunks.append(cp(chunks[ids]))
        batch_golden_chunks.append(golden_chunks)
    return batch_golden_chunks

def prepare_offline_data(batch_data, config):
    batch_docs, batch_refs, batch_indices = batch_data
    batch_chunks = create_chunks_for_batch(batch_docs, config)
    batch_lengths = [len(it) + 2 for it in batch_chunks]
    batch_scores = calculate_overlap_score_full(batch_chunks, batch_refs, True)

    batch_chunks = adding_cls_sep_3d(batch_chunks, config.cls, config.sep)
    padded_batch_chunks = pad_3d_inputs(batch_chunks, config.pad)

    return padded_batch_chunks, batch_indices, batch_lengths, batch_scores

def prepare_ext_data(batch_data, config, h=None):
    """
        doc_inputs: bsz, n, length
        ref_inputs: bsz, m, length
    """
    batch_docs, batch_refs, batch_indices = batch_data
    batch_chunks = create_chunks_for_batch(batch_docs, config)
    batch_scores = calculate_overlap_score_full(batch_chunks, batch_refs, True)

    batch_chunks = adding_cls_sep_3d(batch_chunks, config.cls, config.sep)
    padded_batch_chunks = pad_3d_inputs(batch_chunks, config.pad)

    batch_scores = pad_2d_inputs(batch_scores, -1, t=torch.FloatTensor)
    if h is None:
        return padded_batch_chunks, batch_scores, batch_indices

    batch_chunk_hidden = []
    for id in batch_indices:
        batch_chunk_hidden.append(h[id])
    bsz = len(batch_indices)
    max_l = max([h.shape[0] for h in batch_chunk_hidden])
    padded_batch_chunk_hidden = torch.zeros((bsz, max_l, config.doc_encoder.d_model))
    padded_batch_chunk_attention_mask = torch.zeros((bsz, max_l, max_l))
    for i, chunk_hidden in enumerate(batch_chunk_hidden):
        l = chunk_hidden.shape[0]
        padded_batch_chunk_hidden[i, :l] = torch.from_numpy(chunk_hidden)
        padded_batch_chunk_attention_mask[i, :l, :l] = torch.ones(l, l)
    return padded_batch_chunk_hidden, batch_scores, padded_batch_chunk_attention_mask

def prepare_cross_attention_masks(batch_golden_chunks, batch_refs, config):
    """
        in each instance golden_chunks[0] is the first chunk (C1*)

        # [cls] Sent1 Sent2 [sep]
        #   C1*   C1*    C2    NA
    """
    bsz = len(batch_refs)
    max_num = max([len(golden_chunks) for golden_chunks in batch_golden_chunks])
    max_src_len = max([len(ck) for gck in batch_golden_chunks for ck in gck])
    max_tgt_len = max([sum([len(ref) for ref in refs]) + 1 for refs in batch_refs])
    batch_att_masks = torch.zeros((bsz, max_tgt_len, max_src_len * max_num))
    for i, (golden_chunks, refs) in enumerate(zip(batch_golden_chunks, batch_refs)):
        num = len(golden_chunks)
        tgt_len = sum([len(ref) for ref in refs]) + 1
        src_len = max_src_len * len(golden_chunks)
        att_mask = torch.zeros(tgt_len, src_len)

        p_tgt = 0
        for j, (chunk, ref) in enumerate(zip(golden_chunks, refs)):
            l_src = len(chunk)
            l_tgt = len(ref)
            att_mask[p_tgt:p_tgt + l_tgt, j * max_src_len: j * max_src_len + l_src] = torch.ones(l_tgt, l_src)
            p_tgt += l_tgt

        # last step:
        pt = (num - 1) * max_src_len
        att_mask[-1:, pt: pt + len(golden_chunks[-1])] = torch.ones(1, len(golden_chunks[-1]))

        batch_att_masks[i, :tgt_len, :src_len] = att_mask
    return batch_att_masks

def prepare_cross_attention_masks_test(batch_golden_chunks, batch_refs, config):
    """
        in each instance golden_chunks[0] is the first chunk (C1*)

        # [cls] Sent1 Sent2 [sep]
        #   C1*   C1*    C2    NA
    """
    bsz = len(batch_refs)
    max_num = max([len(golden_chunks) for golden_chunks in batch_golden_chunks])
    max_src_len = max([len(ck) for gck in batch_golden_chunks for ck in gck])
    max_tgt_len = max([sum([len(ref) for ref in refs]) for refs in batch_refs])
    batch_att_masks = torch.zeros((bsz, max_tgt_len, max_src_len * max_num))

    for i, (golden_chunks, refs) in enumerate(zip(batch_golden_chunks, batch_refs)):
        tgt_len = sum([len(ref) for ref in refs])
        src_len = max_src_len * len(golden_chunks)
        att_mask = torch.zeros(tgt_len, src_len)

        p_tgt = 0
        for j, (chunk, ref) in enumerate(zip(golden_chunks, refs)):
            l_src = len(chunk)
            l_tgt = len(ref)
            att_mask[p_tgt:p_tgt + l_tgt, j * max_src_len: j * max_src_len + l_src] = torch.ones(l_tgt, l_src)
            p_tgt += l_tgt

        batch_att_masks[i, :tgt_len, :src_len] = att_mask
    return batch_att_masks

def prepare_switch_label(batch_refs, config):
    bsz = len(batch_refs)
    max_tgt_len = max([sum([len(ref) for ref in refs]) + 1 for refs in batch_refs])

    switch_labels = torch.zeros(bsz, max_tgt_len)
    for i, refs in enumerate(batch_refs):
        labels = []
        for ref in refs:
            labels += [0] * (len(ref) - 1) + [1]
        labels += [0]
        switch_labels[i, : len(labels)] = torch.FloatTensor(labels)
    return switch_labels

def extend1d(inputs):
    return [[it] for it in inputs]

def prepare_abs_data(batch_data, config):
    batch_docs, batch_refs, __ = batch_data
    batch_chunks = create_chunks_for_batch(batch_docs, config)

    batch_golden_chunk_ids = pick_golden_chunks(batch_chunks, batch_refs)

    batch_golden_chunk_ids = [[0] + golden_chunk_ids[1:] for golden_chunk_ids in batch_golden_chunk_ids]

    batch_golden_chunks = get_batch_chunks_by_ids(batch_chunks, batch_golden_chunk_ids)
    batch_golden_chunks = adding_cls_sep_3d(batch_golden_chunks, config.cls, config.sep)

    # batch_cross_attention_mask: bsz, tgt_len, src_len
    batch_cross_attention_mask = prepare_cross_attention_masks(batch_golden_chunks, batch_refs, config)

    batch_plain_refs = [plain_text(refs) for refs in batch_refs]
    batch_plain_refs = adding_cls_sep_2d(batch_plain_refs, config.cls, config.sep)

    batch_golden_chunks = pad_3d_inputs(batch_golden_chunks, config.pad)
    batch_plain_refs = pad_2d_inputs(batch_plain_refs, config.pad)

    batch_decoder_inputs = batch_plain_refs[:, :-1]
    batch_labels = batch_plain_refs[:, 1:]

    return batch_golden_chunks, batch_decoder_inputs, batch_cross_attention_mask.unsqueeze(1), batch_labels

def prepare_ret_labels(batch_golden_chunk_ids, batch_refs, config):
    retrieval_labels = []
    for golden_ids, refs in zip(batch_golden_chunk_ids, batch_refs):
        labels = []
        for id, ref in zip(golden_ids, refs):
            labels += [id] * len(ref)
        labels += [golden_ids[-1]]
        retrieval_labels.append(labels)
    return retrieval_labels

def prepare_regularizer(batch_chunks, batch_refs, config):
    if config.ret_loss_per_token:
        tgt_lens = [sum([len(ref) for ref in refs]) + 1 for refs in batch_refs]
        batch_indices = [list(range(tgt_len)) for tgt_len in tgt_lens]
        batch_indices_mask = [[[1] * (tgt_len - 1)] for tgt_len in tgt_lens]
    else:
        batch_indices = []
        batch_indices_mask = []
        for refs in batch_refs:
            p = 0
            indices = []
            for ref in refs:
                p += len(ref)
                indices.append(p)
            if len(indices) > 0:
                indices = indices[:-1]
            batch_indices.append(indices)
            if len(indices) > 1:
                batch_indices_mask.append([1] * (len(indices) - 1))
            else:
                batch_indices_mask.append([])

    batch_indices = pad_2d_inputs(batch_indices, 0, torch.LongTensor)
    batch_indices_mask = pad_2d_inputs(batch_indices_mask, 0, torch.FloatTensor)
    batch_norm = torch.relu(torch.sum(batch_indices_mask, dim=-1) - 1)
    return batch_indices, batch_indices_mask, batch_norm

def prepare_ret_data(batch_data, config, h=None):
    batch_docs, batch_refs, batch_indices = batch_data
    batch_chunks = create_chunks_for_batch(batch_docs, config)
    batch_src_mask = [[1] * len(chunks) for chunks in batch_chunks]
    batch_src_mask = pad_2d_inputs(batch_src_mask, 0, torch.FloatTensor)

    # need length for the regulizer
    batch_tgt_indices, batch_tgt_indices_mask, batch_regular_norm = \
        prepare_regularizer(batch_chunks, batch_refs, config)

    batch_golden_chunk_ids = pick_golden_chunks(batch_chunks, batch_refs)

    batch_golden_chunk_ids = [[0] + golden_chunk_ids[1:] for golden_chunk_ids in batch_golden_chunk_ids]

    batch_golden_chunks = get_batch_chunks_by_ids(batch_chunks, batch_golden_chunk_ids)
    batch_golden_chunks = adding_cls_sep_3d(batch_golden_chunks, config.cls, config.sep)

    # batch_cross_attention_mask: bsz, tgt_len, src_len
    batch_cross_attention_mask = prepare_cross_attention_masks(batch_golden_chunks, batch_refs, config)

    # batch_switch_labels
    batch_switch_labels = prepare_switch_label(batch_refs, config)
    retrieval_labels = prepare_ret_labels(batch_golden_chunk_ids, batch_refs, config)
    retrieval_labels = pad_2d_inputs(retrieval_labels, config.ignore_index, torch.LongTensor)

    batch_plain_refs = [plain_text(refs) for refs in batch_refs]
    batch_plain_refs = adding_cls_sep_2d(batch_plain_refs, config.cls, config.sep)

    batch_golden_chunks = pad_3d_inputs(batch_golden_chunks, config.pad)
    batch_plain_refs = pad_2d_inputs(batch_plain_refs, config.pad, torch.LongTensor)

    batch_decoder_inputs = batch_plain_refs[:, :-1]
    batch_labels = batch_plain_refs[:, 1:]

    batch_chunk_hidden = []
    for id in batch_indices:
        batch_chunk_hidden.append(h[id])
    bsz = len(batch_indices)
    max_l = max([h.shape[0] for h in batch_chunk_hidden])
    padded_batch_chunk_hidden = torch.zeros((bsz, max_l, config.doc_encoder.d_model))
    padded_batch_chunk_attention_mask = torch.zeros((bsz, max_l, max_l))
    for i, chunk_hidden in enumerate(batch_chunk_hidden):
        l = chunk_hidden.shape[0]
        padded_batch_chunk_hidden[i, :l] = torch.from_numpy(chunk_hidden)
        padded_batch_chunk_attention_mask[i, :l, :l] = torch.ones(l, l)

    return padded_batch_chunk_hidden, padded_batch_chunk_attention_mask, \
           batch_golden_chunks, batch_decoder_inputs, batch_cross_attention_mask.unsqueeze(1), batch_labels, \
           batch_switch_labels, retrieval_labels, \
           batch_tgt_indices, batch_tgt_indices_mask, batch_src_mask, batch_regular_norm, \
           batch_golden_chunk_ids

def prepare_swh_data(batch_data, config):
    batch_docs, batch_refs, __ = batch_data
    batch_chunks = create_chunks_for_batch(batch_docs, config)

    batch_golden_chunk_ids = pick_golden_chunks(batch_chunks, batch_refs)

    batch_golden_chunk_ids = [[0] + golden_chunk_ids[1:] for golden_chunk_ids in batch_golden_chunk_ids]

    batch_golden_chunks = get_batch_chunks_by_ids(batch_chunks, batch_golden_chunk_ids)
    batch_golden_chunks = adding_cls_sep_3d(batch_golden_chunks, config.cls, config.sep)

    # batch_cross_attention_mask: bsz, tgt_len, src_len
    batch_cross_attention_mask = prepare_cross_attention_masks(batch_golden_chunks, batch_refs, config)

    # batch_switch_labels
    batch_switch_labels = prepare_switch_label(batch_refs, config)

    batch_plain_refs = [plain_text(refs) for refs in batch_refs]
    batch_plain_refs = adding_cls_sep_2d(batch_plain_refs, config.cls, config.sep)

    batch_golden_chunks = pad_3d_inputs(batch_golden_chunks, config.pad)
    batch_plain_refs = pad_2d_inputs(batch_plain_refs, config.pad)

    batch_decoder_inputs = batch_plain_refs[:, :-1]
    batch_labels = batch_plain_refs[:, 1:]

    return batch_golden_chunks, batch_decoder_inputs, batch_cross_attention_mask.unsqueeze(1), \
           batch_labels, batch_switch_labels

def prepare_data(batch_data, config, h=None):
    if config.mode == "ext":
        return prepare_ext_data(batch_data, config, h)
    elif config.mode == "abs":
        return prepare_abs_data(batch_data, config)
    elif config.mode == "swh":
        return prepare_swh_data(batch_data, config)
    elif config.mode == "ret":
        return prepare_ret_data(batch_data, config, h)

def prepare_data_cuda(batch_data, config, h=None):
    ret = prepare_data(batch_data, config, h)
    cuda_ret = ()
    for it in list(ret):
        if type(it) != list:
            cuda_ret += (it.cuda(config.device),)
        else:
            cuda_ret += (it,)
    return cuda_ret

def prepare_test(batch_data, config):
    batch_docs, _, batch_indices = batch_data
    batch_chunks = create_chunks_for_batch(batch_docs, config)
    return batch_chunks, batch_indices

def prepare_ext_test(batch_indices, config, h):
    batch_chunk_hidden = []
    for id in batch_indices:
        batch_chunk_hidden.append(h[id])
    bsz = len(batch_indices)
    max_l = max([h.shape[0] for h in batch_chunk_hidden])
    padded_batch_chunk_hidden = torch.zeros((bsz, max_l, config.doc_encoder.d_model))
    padded_batch_chunk_attention_mask = torch.zeros((bsz, max_l, max_l))
    for i, chunk_hidden in enumerate(batch_chunk_hidden):
        l = chunk_hidden.shape[0]
        padded_batch_chunk_hidden[i, :l] = torch.from_numpy(chunk_hidden)
        padded_batch_chunk_attention_mask[i, :l, :l] = torch.ones(l, l)
    return padded_batch_chunk_hidden, padded_batch_chunk_attention_mask

def prepare_abs_test(batch_chunks, golden_chunk_ids, summary_sents, config):
    batch_golden_chunks = get_batch_chunks_by_ids(batch_chunks, [golden_chunk_ids])
    batch_golden_chunks = adding_cls_sep_3d(batch_golden_chunks, config.cls, config.sep)

    batch_cross_attention_mask = prepare_cross_attention_masks_test(batch_golden_chunks, [summary_sents], config)
    batch_golden_chunks = pad_3d_inputs(batch_golden_chunks, config.pad)

    batch_plain_sum = [plain_text(summary_sents)]

    batch_decoder_inputs = pad_2d_inputs(batch_plain_sum, config.pad)

    return batch_golden_chunks, batch_decoder_inputs, batch_cross_attention_mask.unsqueeze(1)

def prepare_abs_emb_test(summary_sents, next_token, config):
    shift_token = [plain_text(summary_sents) + [next_token]]
    shift_token = pad_2d_inputs(shift_token, config.pad)
    return shift_token[:, 1:]

def convert_cuda(ret, config):
    if type(ret) == tuple:
        cuda_ret = ()
        for it in list(ret):
            if type(it) != list:
                cuda_ret += (it.cuda(config.device),)
            else:
                cuda_ret += (it,)
        return cuda_ret
    elif type(ret) == list:
        return ret
    else:
        return ret.cuda(config.device)


import os

def renameFiles():
    #1 get file names from folder
    fileList = os.listdir(r"C:\path\path")
    #2 print(fileList)
    saved_path = os.getcwd()
    print("Current working directory is "+saved_path)
    os.chdir(r"C:\path\path")
    #for each file, rename file
    for file_name in fileList:
        os.rename(file_name, file_name.translate(None, " _-1234567890"))
    os.chdir(saved_path)

renameFiles()


import simpy

from settings import *
from simulation import *
from sprites import *
from window import Window

from in_progress import Airline

# create a simulation environment
environ = simpy.Environment(initial_time=0)

# create an arrival area in this environment
arrival_area = arrival(environ)

# create the window and link both ways for convenience
# a priori, only one to one GUI to sim so it's alright
win = Window(arrival_area, CONFIG)
arrival_area.link_GUI(win)

counter_table = (
    [4 for i in range(5)]
    + [0 for i in range(5)]
    + [4 for i in range(10)]
    + [20 for i in range(2000)]
)
counter_table2 = (
    [2 for i in range(10)]
    + [4 for i in range(10)]
    + [60 for i in range(20)]
    + [20 for i in range(2000)]
)

airline_codes = ["AF", "VN"]

airline = Airline(
    win,
    airline_codes[0],
    vec(0, 0),
    counter_table,
)

airline = Airline(
    win,
    airline_codes[1],
    vec(0, 15),
    counter_table2,
)

process_list = [
    "{}_checkin_desk".format(airline_codes[0]),
    "{}_checkin_desk".format(airline_codes[1]),
]
arrival_area.env.process(Pax_generator(arrival_area, 5, 600 / 60, process_list))

# run!
win.run(steps_per_update=STEPS_PER_UPDATE)


#Random kütüphanemizi ekliyoruz.
import random
#Kullanýcýdan deðer alýyoruz.
d = int(input("Sifrenizin uzunlugunu giriniz."))
#Alfaponetik alfabeyi listeliyoruz.
ap =['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
#Alfanumerik alfabeyi listeliyoruz.
an=['1','2','3','4','5','6','7','8','9','0']
#Boþ listeye yukarýdaki alfaponetik ve alfanumerik iki listeden rastgele deðer alýp yazdýracaðýz.
lst=[]
#For bloðu ile (d) deðiþkeni kadar döngüyü çalýþtýrýyoruz.
for i in range(d):
    #Random kütüphanesini kullanarak alfaponetik (ap) ve alfanumerik (an) listelerinden rastgele aldýðýmýz,
    #deðerleri boþ listemize yazdýrýyoruz.
    lst.append(random.choice(ap))
    lst.append(random.choice(an))
# str manipülasyon yöntemi ile çýktýdaki parantez ve týrnaklarý siliyoruz.
print("Sifreniz : " + "".join(lst))


import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
from tensorflow.examples.tutorials.mnist import input_data

'''initial steps'''
#tensorflow loading mnist data
#loading data as one hot vector
'''one hot vector-it means data labels (classes) is converted into columns representing binary representation of labels.same number
of rows but but number of columns is equal to number of classes.(0 or 1 representation)'''

data=input_data.read_data_sets("data/MNIST/", one_hot=True)

print("size od data loaded:")
print("Training set size:\t {}".format(len(data.train.labels)))
print("Test set size:\t {}".format(len(data.test.labels)))
print("Validation set size:\t {}".format(len(data.validation.labels)))
#index in one hot vector represents actual class whether its number 1,2,...8,9.
data.test.cls=np.array([label.argmax() for label in data.test.labels])

#default mnist image size is 28 by 28:
img_size=28

#storing images in one dimensional array like a onr dimensional vector represntation.length of one dim array[28*28]
img_flat=img_size*img_size

#shape of image with heigth,width
img_shape=(img_size,img_size)

#number of classses
no_of_classes=10

def plot_images(images, cls_true, cls_pred=None):
    assert len(images) == len(cls_true) == 9

    # Create figure with 3x3 sub-plots.
    fig, axes = plt.subplots(3, 3)
    fig.subplots_adjust(hspace=0.3, wspace=0.3)

    for i, ax in enumerate(axes.flat):
        # Plot image.
        ax.imshow(images[i].reshape(img_shape), cmap='binary')

        # Show true and predicted classes.
        if cls_pred is None:
            xlabel = "True: {0}".format(cls_true[i])
        else:
            xlabel = "True: {0}, Pred: {1}".format(cls_true[i], cls_pred[i])

        ax.set_xlabel(xlabel)

        # Remove ticks from the plot.
        ax.set_xticks([])
        ax.set_yticks([])
    plt.show()

# Get the first images from the test-set.
images = data.test.images[0:9]

# Get the true classes for those images.
cls_true = data.test.cls[0:9]

# Plot the images and labels using our helper-function above.
plot_images(images=images, cls_true=cls_true)

#none means it will accept any number of input images with each vector representing size of 28 by 28.
x=tf.placeholder(tf.float32,[None,img_flat])

y_true=tf.placeholder(tf.int64,[None,no_of_classes])

y_true_cls = tf.placeholder(tf.int64, [None])

#2-D tensor representing weights
weights=tf.Variable(tf.zeros([img_flat,no_of_classes]))

#1-D tensor representing biases
biases=tf.Variable(tf.zeros([no_of_classes]))

#now trying to build a  model
#the element of the ith row and jth column is an estimate of how likely the ith input image is to be of the jth class.
logits = tf.matmul(x, weights) + biases

y_pred = tf.nn.softmax(logits)

#predicting the label
y_pred_cls = tf.argmax(y_pred, dimension=1)

#cost function calculation.i.e. comparing true labels with predicted labels.
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=logits,labels=y_true)

#in earlier step cross_entropy was calculated for each image.Now use all cross_entropy values and calculate its means to know
#how our model well our model is evaluating.
cost = tf.reduce_mean(cross_entropy)

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.5).minimize(cost)

correct_prediction = tf.equal(y_pred_cls, y_true_cls)
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

#########################################################################################

'''Here tensorflow graph generation code ends '''

'''Actual working starts from below'''
#########################################################################################
session = tf.Session()
#this below line intializes the tensorflow weights and biases.You need to initialize them otherwise error would be caused.
session.run(tf.global_variables_initializer())
batch_size=1000

#actual working of code of above graph created starts from here
def optimize(number_of_iterations):
	for i in range(number_of_iterations):
		x_batch, y_true_batch = data.train.next_batch(batch_size)
		feed_dict_train = {x: x_batch,y_true: y_true_batch}
		session.run(optimizer, feed_dict=feed_dict_train)

feed_dict_test = {x: data.test.images,y_true: data.test.labels,y_true_cls: data.test.cls}

def print_accuracy():
    # Use TensorFlow to compute the accuracy.
	acc = session.run(accuracy, feed_dict=feed_dict_test)

    # Print the accuracy.
	print("Accuracy on test-set: {0:.1%}".format(acc))

def plot_example_errors():
	# Use TensorFlow to get a list of boolean values
	# whether each test-image has been correctly classified,
	# and a list for the predicted class of each image.
	correct, cls_pred = session.run([correct_prediction, y_pred_cls],
									feed_dict=feed_dict_test)

	# Negate the boolean array.
	incorrect = (correct == False)

	# Get the images from the test-set that have been
	# incorrectly classified.
	images = data.test.images[incorrect]

	# Get the predicted classes for those images.
	cls_pred = cls_pred[incorrect]

	# Get the true classes for those images.
	cls_true = data.test.cls[incorrect]

	# Plot the first 9 images.
	plot_images(images=images[0:9],cls_true=cls_true[0:9],cls_pred=cls_pred[0:9])

def plot_weights():
	# Get the values for the weights from the TensorFlow variable.
	w = session.run(weights)

	# Get the lowest and highest values for the weights.
	# This is used to correct the colour intensity across
	# the images so they can be compared with each other.
	w_min = np.min(w)
	w_max = np.max(w)

	# Create figure with 3x4 sub-plots,
	# where the last 2 sub-plots are unused.
	fig, axes = plt.subplots(3, 4)
	fig.subplots_adjust(hspace=0.3, wspace=0.3)

	for i, ax in enumerate(axes.flat):
		# Only use the weights for the first 10 sub-plots.
		if i<10:
			# Get the weights for the i'th digit and reshape it.
			# Note that w.shape == (img_size_flat, 10)
			image = w[:, i].reshape(img_shape)

			# Set the label for the sub-plot.
			ax.set_xlabel("Weights: {0}".format(i))

			# Plot the image.
			ax.imshow(image, vmin=w_min, vmax=w_max, cmap='seismic')

		# Remove ticks from each sub-plot.
		ax.set_xticks([])
		ax.set_yticks([])
	plt.show()

optimize(30)
print_accuracy()

plot_example_errors()


import mlflow
from models.models import *
from preprocessing.data_preprocessing import *
from utils.utils import *

if __name__ == "__main__":
    #mlflow.set_tracking_uri("http://127.0.0.1:5000")
    mlflow.set_experiment("Zindi_experiment")
    train = pd.read_csv('../umojahack-africa-2022-beginner-challenge/train.csv', parse_dates=['Datetime'])
    inference = pd.read_csv('../umojahack-africa-2022-beginner-challenge/test.csv', parse_dates=['Datetime'])
    train = date_processing(train)
    X = train.drop('Offset_fault', axis='columns')
    y = train.iloc[:,5]
    X_train, X_test, y_train, y_test = train_test_split(X,y, random_state=42, test_size=0.2, stratify=y)
    X_train = outlier_processing(X_train)
    X_train = missing_values_processing(X_train)
    X_train = X_train.iloc[:,1:]
    X_test = X_test.iloc[:,1:]
    X_test['output'] = y_test
    X_test.dropna(inplace= True)
    y_test = X_test['output']
    X_test = X_test.iloc[:,:-1]
    with mlflow.start_run():
        classifier, train_accuracy, test_accuracy = svm_classifier(X_train, X_test, y_train, y_test)
        y_pred = classifier.predict(y_test)
        f1, auc = calculate_metrics(classifier, X_test, y_test, y_pred)
        params = {"kernel":'rbf', "random_state": 42}
        metrics = {"train_accuracy": train_accuracy, "test_accuracy": test_accuracy,
                "f1": f1, "auc": auc}
        roc = plot_auc_roc(y_test, y_pred)
        conf_matrix = confusion_matrix(classifier, X_test, y_test)
        mlflow.log_params(params)
        mlflow.log_metrics(metrics)
        mlflow.log_figure(roc, "svm_roc.png")
        mlflow.log_figure(conf_matrix, "svm_confusion_matrix.png")
        mlflow.sklearn.log_model(classifier, artifact_path="models")
        mlflow.register_model(classifier, "SVC")

    with mlflow.start_run():
        clf, train_accuracy, test_accuracy = lr_classifier(X_train, X_test, y_train, y_test)
        y_pred = clf.predict(y_test)
        f1, auc = calculate_metrics(clf, X_test, y_test, y_pred)
        params = {"random_state": 42, "C": 1e5}
        metrics = {"train_accuracy": train_accuracy, "test_accuracy": test_accuracy,
                "f1": f1, "auc": auc}
        roc = plot_auc_roc(y_test, y_pred)
        conf_matrix = confusion_matrix(clf, X_test, y_test)
        mlflow.log_params(params)
        mlflow.log_metrics(metrics)
        mlflow.log_figure(roc, "lr_roc.png")
        mlflow.log_figure(conf_matrix, "lr_confusion_matrix.png")
        mlflow.sklearn.log_model(clf, artifact_path="models")
        mlflow.register_model(clf, "LogisticRegression")

    with mlflow.start_run():
        tree_clf, train_accuracy, test_accuracy = tree_classifier(X_train, X_test, y_train, y_test)
        y_pred = tree_clf.predict(y_test)
        f1, auc = calculate_metrics(tree_clf, X_test, y_test, y_pred)
        params = {"max_depth": 10}
        metrics = {"train_accuracy": train_accuracy, "test_accuracy": test_accuracy,
                "f1": f1, "auc": auc}
        roc = plot_auc_roc(y_test, y_pred)
        conf_matrix = confusion_matrix(tree_clf, X_test, y_test)
        mlflow.log_params(params)
        mlflow.log_metrics(metrics)
        mlflow.log_figure(roc, "tree_roc.png")
        mlflow.log_figure(conf_matrix, "tree_confusion_matrix.png")
        mlflow.sklearn.log_model(tree_clf, artifact_path="models")
        mlflow.register_model(tree_clf, "decision_trees")

    with mlflow.start_run():
        for_clf, train_accuracy, test_accuracy = forest_classifier(X_train, X_test, y_train, y_test)
        y_pred = for_clf.predict(y_test)
        f1, auc = calculate_metrics(for_clf, X_test, y_test, y_pred)
        metrics = {"train_accuracy": train_accuracy, "test_accuracy": test_accuracy,
                "f1": f1, "auc": auc}
        roc = plot_auc_roc(y_test, y_pred)
        conf_matrix = confusion_matrix(for_clf, X_test, y_test)
        mlflow.log_metrics(metrics)
        mlflow.log_figure(roc, "random_forest_roc.png")
        mlflow.log_figure(conf_matrix, "random_forest_confusion_matrix.png")
        mlflow.sklearn.log_model(for_clf, artifact_path="models")
        mlflow.register_model(for_clf, "random_forest")

    with mlflow.start_run():
        sgd_clf, train_accuracy, test_accuracy = sgd_classifier(X_train, X_test, y_train, y_test)
        y_pred = sgd_clf.predict(y_test)
        f1, auc = calculate_metrics(sgd_clf, X_test, y_test, y_pred)
        params = {"max_iter": 1000, "tol": 1e-3}
        metrics = {"train_accuracy": train_accuracy, "test_accuracy": test_accuracy,
                "f1": f1, "auc": auc}
        roc = plot_auc_roc(y_test, y_pred)
        conf_matrix = confusion_matrix(sgd_clf, X_test, y_test)
        mlflow.log_params(params)
        mlflow.log_metrics(metrics)
        mlflow.log_figure(roc, "sgd_roc.png")
        mlflow.log_figure(conf_matrix, "sgd_confusion_matrix.png")
        mlflow.sklearn.log_model(sgd_clf, artifact_path="models")
        mlflow.register_model(sgd_clf, "sgd")


from xml.etree.ElementTree import Element, SubElement, ElementTree

#首先创建根节点
root = Element('lab')

#添加子节点SubElement(父节点Element对象， Tag字符串格式， Attribute字典格式)
person1 = SubElement(root, 'person', {'name':'Blue'})

#添加子节点
age1 = SubElement(person1, 'age')
#添加text，即22，字符串格式
age1.text = '22'
gender1 = SubElement(person1, 'gender')
gender1.text = 'male'

person2 = SubElement(root, 'person', {'name':'Yellow'})
age2 = SubElement(person2, 'age')
age2.text = '20'
gender2 = SubElement(person2, 'gender')
gender2.text = 'female'

#将根目录转化为xml树状结构(即ElementTree对象)
tree = ElementTree(root)
#写入xml文件
tree.write('sample.xml', encoding="utf-8", xml_declaration=True)


# Extract Unsubscribe Links
# By Vanesa Hercules, 2022

import gspread
from bs4 import BeautifulSoup
import re
import pandas as pd

# Assign Service Account Key
gc = gspread.service_account(filename='client_secret.json')

# Open Google Sheet
sh = gc.open("Unsubscribe Gmail Messages")

# Get All Values From Body Column
values_list = sh.sheet1.col_values(4)

# Create List of Output Cells Per Length of value_ list
cell_list = []
for cell in range(1, len(values_list)+1):
    cell_str = str(cell)
    cell_list.append('E'+ cell_str)

# Zip cell_list with values_list into a DataFrame
df = pd.DataFrame(list(zip(cell_list, values_list)), columns =['cell', 'body'])

# Search for unsubscribe links and write them back to Google Sheet
def search_for_unsublink (body):
    """ Searches for 'unsubscribe' text among all a tags and returns href if found or none"""
    soup = BeautifulSoup(body, features='lxml')
    a_list = list(soup.find_all('a'))
    for a in a_list:
        if re.search('nsubscribe', str(a)):
            unsubscribe_a = a
            unsubscribe_link = unsubscribe_a.get('href')
            return unsubscribe_link

def write_link_to_cell(cell, link):
    """ Write links to Google Sheet"""
    sh.sheet1.update(cell, link)

# Print iterations progress
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█', printEnd = "\r"):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
        printEnd    - Optional  : end character (e.g. "\r", "\r\n") (Str)
    """
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
    # Print New Line on Complete
    if iteration == total:
        print()

# Main
l = len(df)
for index, row in df.iterrows():
    result = search_for_unsublink(row['body'])
    write_link_to_cell(row['cell'], result)
    # Update Progress Bar
    printProgressBar(index + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50)


import sys, os
sys.path.append(os.path.relpath('../'))
from exception import Lab5Exception

def add(arg1, arg2):
    r"""
        This function accepts two arguments - arg1 and arg2.
        It returns the result of the operation (arg1 + arg2).

        You are expected to think of corner cases,
        and appropriately raise Exception.
    """
    if not (type(arg1) == float or type(arg1) == int or type(arg1) == complex):
        raise Lab5Exception("Non-numeric arguements provided")
    if not (type(arg2) == float or type(arg2) == int or type(arg2) == complex):
        raise Lab5Exception("Non-numeric arguements provided")
    return arg1 + arg2

def subtract(arg1, arg2):
    r"""
        This function accepts two arguments - arg1 and arg2.
        It returns the result of the operation (arg1 - arg2).

        As the previous function, you are expected to think of corner cases,
        and appropriately raise Exception.
    """
    if not (type(arg1) == float or type(arg1) == int or type(arg1) == complex):
        raise Lab5Exception("Non-numeric arguements provided")
    if not (type(arg2) == float or type(arg2) == int or type(arg2) == complex):
        raise Lab5Exception("Non-numeric arguements provided")
    return arg1 - arg2

def divide(arg1, arg2):
    r"""
        This function accepts two arguments - arg1 and arg2.
        It returns the result of the operation (arg1 / arg2).

        You are expected to think of corner cases, and appropriately raise Exception.
    """
    if not (type(arg1) == float or type(arg1) == int or type(arg1) == complex):
        raise Lab5Exception("Non-numeric arguements provided")
    if not (type(arg2) == float or type(arg2) == int or type(arg2) == complex):
        raise Lab5Exception("Non-numeric arguements provided")
    if arg2 == 0:
        raise Lab5Exception("Division by zero is not possible")
    return arg1/arg2

def str_left_rotate(arg1, arg2):
    r"""
        This function should left rotate a string by the specified amount.
        arg1 signifies the input string and arg2 signifies the amount of rotation.

        Example -
        1. str_left_rotate("hello", 2) should return "llohe"
        2. str_left_rotate("hello", 1) should return "elloh"
        3. str_left_rotate("hello", 4) should return "ohell" and so on

        You are not to use any inbuilt string method, the implementation has to be
        done by you!!

        Again, you are expected to think of corner cases, and appropriately raise Exception.
    """
    # raise exception for negative arg2!!
    # can check for type of args, like str_left_rotate("bencho",7.8)
    # check empty strings
    if type(arg1) != str:
        raise Lab5Exception("String to be rotated is not of str data type")
    if type(arg2) != int:
        raise Lab5Exception("Rotation amount given is not an integer")
    if arg2 < 0:
        raise Lab5Exception("Negative rotation amount provided")
    rotated_str = ""
    for i in range(len(arg1)):
        rotated_str += arg1[(i+arg2)%len(arg1)]
    return rotated_str

def apply(fn, args):
    r"""
        This is the API end-point available to the grader.
        The grader will supply the function pointer to this function,
        along with the arguments and expect the return value.

        Example -
        1. apply(add, (2, 3)) will expect 5 as the answer.
        2. apply(subtract, (2, 3)) will expect -1 as the answer.
    """
    if not (type(args) == tuple or type(args) == list):
        raise Lab5Exception("Arguements provided are not in a tuple/list")
    if len(args) != 2:
        raise Lab5Exception("2 Arguements are not provided")
    return fn(args[0],args[1])


import numpy as np
import itertools
import math
from scipy.special import erfinv
import yaml

class BaseSubProblem:
    """
    The base class for all the sub-problem generators.
    """

    def __init__(self, n_classes=2, n_features=2, random_vertices=True, errors=np.array([0.5,0.5]), random_state=np.random.RandomState(42), n_samples_per_class=np.array([100,100]), **configuration):
        """

        :param n_classes: The number of classes
        :param n_features: The nuber of features describing the samples
        :param errors: The error rate for each class
        :param random_state: A numpy.random.RandomState object
        :param n_samples_per_class: A list conatining the number of samples for each class
        :param configuration: sub-problem specific configuration.
        """
        self.n_classes = n_classes
        self.random_vertices = random_vertices
        self.errors = errors
        self.n_features = n_features
        self.rs = random_state
        self.n_samples_per_class = n_samples_per_class
        self.bayes_error = np.zeros(self.n_classes)
        self.descriptions = np.zeros((self.n_classes, np.max(self.n_samples_per_class)))
        self.config = configuration
        self.view_name = "generated"

    def gen_report(self):
        """
        General method the generate the report on the view.

        :return: A string containing the general report for the view
        """
        view_string = "\n\nThis view is generated with {}, with the following configuration : \n```yaml\n".format(
            self.__class__.__name__)
        view_string += yaml.dump(self.config,
                                 line_break="\n", default_flow_style=False)
        view_string += "n_features: {}\n".format(self.n_features)
        view_string += "```"
        return view_string

class StumpsGenerator(BaseSubProblem):

    def gen_data(self):
        """
        Generates the samples according to gaussian distributions with scales
        computed with the given error and class separation. This sub-problem is
        easily understandable by a decision tree.

        The features are built as :
        relevant_features : the  math.ceil(math.log2(self.n_classes)) first ones,
        uniform noise features : all the remaining ones

        :return: data a np.ndarray of dimension n_classes, n_samples_per_class, \
        n_features containing the samples' descriptions, sorted by class
        """
        self.n_relevant_features = math.ceil(math.log2(self.n_classes))
        self.view_name = "stumps"
        class_sep = self.config["class_sep"]
        vertices = np.array(
            [np.array([coord for coord in coords]) for coords in
             itertools.product(
                 *zip([-1 for _ in range(self.n_relevant_features)],
                      [1 for _ in range(self.n_relevant_features)]))])

        if self.random_vertices == True:
            selected_vertices = self.rs.choice(np.arange(len(vertices)),
                                               self.n_classes,
                                               replace=False)
        else:
            selected_vertices = np.arange(self.n_classes)
        self.selected_vertices = vertices[selected_vertices,
                                 :] * class_sep
        vec = np.zeros((self.n_classes, max(self.n_samples_per_class),
                        self.n_relevant_features))
        for class_ind, center_coord in enumerate(
                self.selected_vertices):
            error = self.errors[class_ind]

            scale = (class_sep / math.sqrt(2)) * (1 / (
                erfinv(2 * (1 - error) ** (
                        1 / self.n_relevant_features) - 1)))
            cov = np.identity(self.n_relevant_features) * scale **2
            vec[class_ind, :,:] = self.rs.multivariate_normal(center_coord, cov,
                                              self.n_samples_per_class[
                                                  class_ind])
            mis_described = np.unique(
                np.where(np.multiply(vec[class_ind], center_coord) < 0)[0])
            well_described = np.array([ind for ind
                                       in range(
                    self.n_samples_per_class[class_ind])
                                       if ind not in mis_described])
            self.bayes_error[class_ind] = mis_described.shape[0]
            self.descriptions[class_ind, mis_described] = -1
            self.descriptions[class_ind, well_described] = 1
        data = self.rs.uniform(low=np.min(vec), high=np.max(vec), size=(self.n_classes, max(self.n_samples_per_class), self.n_features))
        data[:,:,:self.n_relevant_features] = vec
        return data

    def gen_report(self):
        """
        Generates the specific report for StumpsGenerator.
        """
        base_str = BaseSubProblem.gen_report(self)
        base_str += "\n\nThis view has {} features, among which {} are relevant for classification (they are the {} first columns of the view) the other are filled with uniform noise.".format(
            self.n_features, self.n_relevant_features, self.n_relevant_features)
        base_str += "\n\n Its empirical bayesian classifier is a decision stump"
        return base_str

    def get_bayes_classifier(self):
        from sklearn.tree import DecisionTreeClassifier
        return DecisionTreeClassifier(max_depth=math.ceil(math.log2(self.n_classes)))

class TreesGenerator(BaseSubProblem):  # pragma: no cover
    """ Work in progress : Similar generator as StumpsGenerator, but that
    generates several blobs per class """

    def gen_data(self):
        """
        WIP
        """
        self.n_relevant_features = math.ceil(math.log2(self.n_classes))
        self.view_name = "tree_depth_2"
        class_sep = self.config["class_sep"]
        vertices = np.array(
            [np.array([coord for coord in coords]) for coords in
             itertools.product(
                 *zip([-1 for _ in range(self.n_relevant_features)],
                      [1 for _ in range(self.n_relevant_features)]))])

        if self.random_vertices == True:
            selected_vertices = self.rs.choice(np.arange(len(vertices)),
                                               self.n_classes,
                                               replace=False)
        else:
            selected_vertices = np.arange(self.n_classes)
        self.selected_vertices = vertices[selected_vertices,
                                 :] * class_sep
        self.covs = np.zeros((self.n_classes, self.n_relevant_features, self.n_relevant_features))
        vec = np.zeros((self.n_classes, max(self.n_samples_per_class),
                        self.n_relevant_features))
        blob_centers = np.zeros((self.n_classes, self.n_relevant_features+1, self.n_relevant_features))
        for class_ind, center_coord in enumerate(
                self.selected_vertices):
            mis_described = []
            error = self.errors[class_ind]/(self.n_relevant_features+1)
            blob_centers[class_ind, 0, :] = center_coord
            internal_error_percentage = self.n_relevant_features*2/(self.n_relevant_features*2+self.n_relevant_features**2)
            internal_scale = (class_sep / math.sqrt(2)) * (1 / (
                erfinv(2 * (1 - error/internal_error_percentage) ** (
                        1 / (2*self.n_relevant_features)) - 1)))
            cov = np.identity(self.n_relevant_features) * internal_scale**2
            self.covs[class_ind] = cov
            n_samples = self.n_samples_per_class[class_ind] - (int(self.n_samples_per_class[class_ind]/(self.n_relevant_features+1)))*self.n_relevant_features
            vec[class_ind, :n_samples, :] = self.rs.multivariate_normal(center_coord, cov,
                                                                        n_samples)

            # mis_described += list(np.unique(np.where(
            #     np.any(abs(vec[class_ind] - center_coord)>class_sep, axis=1))[0]))
            n_samples_per_blob = int(self.n_samples_per_class[class_ind]/(self.n_relevant_features+1))
            external_error_percentage = self.n_relevant_features / (
                        self.n_relevant_features * 2 + self.n_relevant_features ** 2)
            external_scale = (class_sep / math.sqrt(2)) * (1 / (
                erfinv(2 * (1 - error / external_error_percentage) ** (
                        1 / self.n_relevant_features) - 1)))
            cov = np.identity(
                self.n_relevant_features) * external_scale**2
            for dim_index, update_coord in enumerate(center_coord):
                beg = n_samples+dim_index*n_samples_per_blob
                end = n_samples+(dim_index+1)*n_samples_per_blob
                new_center = center_coord.copy()
                new_center[dim_index] = update_coord-4*update_coord
                blob_centers[class_ind, dim_index+1, :] = new_center

                vec[class_ind, beg:end,:] = self.rs.multivariate_normal(new_center, cov,
                                                                            n_samples_per_blob)
                mis_described += list(np.unique(np.where(
                    np.any(abs(vec[class_ind, beg:end] - new_center)>class_sep, axis=1))[0])+beg)
            # mis_described = np.array(mis_described)
            # well_described = np.array([ind for ind
            #                            in range(
            #         self.n_samples_per_class[class_ind])
            #                            if ind not in mis_described])

            # self.bayes_error[class_ind] = mis_described.shape[0]
            # self.descriptions[class_ind, mis_described] = -1
            # self.descriptions[class_ind, well_described] = 1
        for class_ind in range(self.n_classes):
            for sample_ind in range(self.n_samples_per_class[class_ind]):
                if np.argmin(np.min(np.linalg.norm(vec[class_ind, sample_ind, :] - blob_centers, axis=2), axis=1))!= class_ind:
                    self.bayes_error[class_ind] +=1
                    self.descriptions[class_ind, sample_ind] = -1
                else:
                    self.descriptions[class_ind, sample_ind] = +1
        data = self.rs.uniform(low=-1, high=1, size=(
        self.n_classes, max(self.n_samples_per_class), self.n_features))
        data[:, :, :self.n_relevant_features] = vec
        return data

    def gen_report(self):
        """
        WIP
        """
        base_str = BaseSubProblem.gen_report(self)
        base_str += "\n\nThis view has {} features, among which {} are relevant for classification (they are the {} first columns of the view).".format(self.n_features, self.n_relevant_features, self.n_relevant_features)
        base_str += "\n\n Its empirical bayesian classifier is a decision tree of depth 3"
        return base_str

    def get_bayes_classifier(self):
        from sklearn.tree import DecisionTreeClassifier
        return DecisionTreeClassifier(max_depth=2)

class RingsGenerator(BaseSubProblem):

    def gen_data(self):
        r"""Generates the samples according to gaussian distributions with scales
        computed with the given error and class separation. The generator first
        computes a radius according to the gaussian distribution, then
        generates n_features-1 random angles to build the polar coordinates of
        the samples. The dataset returned is the cartesian version of this
        "polar" dataset.

        :return: data a np.ndarray of dimension n_classes, n_samples_per_class, n_features containing the samples' descriptions, sorted by class
        """
        if self.n_features<2:
            raise ValueError("n_features for view {} must be at least 2, (now: {})".format(1, self.n_features))
        self.view_name = "rings"
        data = np.zeros((self.n_classes, max(self.n_samples_per_class), self.n_features))
        class_sep = self.config["class_sep"]
        vertices = (np.arange(self.n_classes)+1)*class_sep

        if self.random_vertices == True:
            selected_vertices = self.rs.choice(np.arange(len(vertices)),
                                               self.n_classes,
                                               replace=False)
        else:
            selected_vertices = np.arange(self.n_classes)
        self.selected_vertices = vertices[selected_vertices]
        radii = np.zeros((self.n_classes, max(self.n_samples_per_class)))
        for class_ind, center_coord in enumerate(
                self.selected_vertices):
            error = self.errors[class_ind]
            if class_ind==0 or class_ind==self.n_classes-1:
                scale = ((class_sep/2) / math.sqrt(2)) *  (1 /
                    erfinv(1 - 2*error))
            else:
                scale = ((class_sep/2) / math.sqrt(2)) *  (1 /
                    erfinv( 2*(1-error)**(1/2)-1))
            radii[class_ind, :] = self.rs.normal(center_coord, scale,
                                                 self.n_samples_per_class[
                                                     class_ind])
            first_angle = self.rs.uniform(low=0, high=2*math.pi, size=(self.n_samples_per_class[class_ind],1))
            if self.n_features>2:
                other_angles = self.rs.uniform(low=0, high=1, size=(self.n_samples_per_class[class_ind], self.n_features-2))
                other_angles = np.arccos( 1 - 2 * other_angles)
                angles = np.concatenate((other_angles, first_angle), axis=1)
            else:
                angles = first_angle
            cartesian = np.array([to_cartesian(r, angle) for r, angle in zip(radii[class_ind], angles)])
            data[class_ind, :, :] = cartesian
            back_to_radii = np.sqrt(np.sum(np.square(cartesian), axis=1))
            if class_ind>1 and class_ind<self.n_classes-1:
                mis_described = np.unique(
                    np.where(np.logical_or(back_to_radii < vertices[class_ind]-(vertices[class_ind]-vertices[class_ind-1])/2, back_to_radii > vertices[class_ind]+(vertices[class_ind+1]-vertices[class_ind])/2))[0])
            elif class_ind==0:
                mis_described = np.unique(np.where(back_to_radii > vertices[class_ind]+(vertices[class_ind + 1] - vertices[class_ind]) / 2)[0])
            else:
                mis_described = np.unique(np.where(back_to_radii < vertices[class_ind]-(vertices[class_ind] - vertices[class_ind - 1]) / 2)[0])
            well_described = np.array([ind for ind
                                       in range(
                    self.n_samples_per_class[class_ind])
                                       if ind not in mis_described])
            self.bayes_error[class_ind] = mis_described.shape[0]
            self.descriptions[class_ind, mis_described] = -1
            self.descriptions[class_ind, well_described] = 1
        return data

    def gen_report(self):
        """
        Generates the specific report for StumpsGenerator.
        """
        base_str = BaseSubProblem.gen_report(self)
        base_str += "\n\nThis view has {} features, all of them are relevant for classification.".format(
            self.n_features)
        base_str += "\n\n Its empirical bayesian classifier is any algorithm used with an RBF kernel."
        return base_str

    def get_bayes_classifier(self):
        from sklearn.svm import SVC
        return SVC(kernel='rbf', gamma='scale', C=0.1)

def to_cartesian(radius, angles):
    """
    Transforms polar coordinates to cartesian coordinates.
    """
    a = np.concatenate((np.array([2 * np.pi]), angles))
    si = np.sin(a)
    si[0] = 1
    si = np.cumprod(si)
    co = np.cos(a)
    co = np.roll(co, -1)
    return si * co * radius


import hashlib

from django.test import TestCase

from ..models import DimUser, Simulation, SimulationGroup, SimulationInputFile

class SimInputFileTests(TestCase):
    """
    Tests for the data model for simulation input files.
    """

    @classmethod
    def setUpClass(cls):
        cls.user = DimUser.objects.create(username='test-user')
        cls.sim_group = SimulationGroup.objects.create(submitted_by=cls.user)
        cls.simulation = Simulation.objects.create(group=cls.sim_group)

    @classmethod
    def tearDownClass(cls):
        for data_model in Simulation, SimulationGroup, DimUser:
            data_model.objects.all().delete()

    def assertContentsEqual(self, input_file, expected_contents):
        self.assertIsInstance(input_file, SimulationInputFile)
        retrieved_contents = input_file.get_contents()
        self.assertEqual(retrieved_contents, expected_contents)
        expected_hash = hashlib.md5(expected_contents).hexdigest()
        self.assertEqual(input_file.metadata[input_file.MetadataKeys.CHECKSUM], expected_hash)

    def test_one_file(self):
        """
        Test with an input file associated with just one simulation.
        """
        contents = 'Four score and seven years ago, our forefathers ...'
        sim_input_file = SimulationInputFile.objects.create_file(contents, created_by=self.user)
        self.assertContentsEqual(sim_input_file, contents)

        sim_input_file.simulations.add(self.simulation.id)
        self.assertEqual(sim_input_file.simulations.count(), 1)
        self.assertEqual(sim_input_file.simulations.all()[0], self.simulation)

    def test_file_shared_by_many(self):
        """
        Test where an input file is shared by multiple simulations.
        """
        contents = "Roses are red, violets are blue, ..."
        sim_input_file = SimulationInputFile.objects.create_file(contents, created_by=self.user)
        self.assertContentsEqual(sim_input_file, contents)

        simulation2 = Simulation.objects.create(group=self.sim_group)
        simulation3 = Simulation.objects.create(group=self.sim_group)

        sim_input_file.simulations.add(self.simulation, simulation2, simulation3)
        self.assertEqual(sim_input_file.simulations.count(), 3)
        expected_pks = (self.simulation.id, simulation2.id, simulation3.id)
        for simulation in sim_input_file.simulations.all():
            self.assertIn(simulation.id, expected_pks)

    def test_foo(self):
        """
        Test where a simulation has multiple input files.
        """
        empty_contents = ''
        empty_input_file = SimulationInputFile.objects.create_file(empty_contents, created_by=self.user)
        self.assertContentsEqual(empty_input_file, empty_contents)
        empty_input_file.simulations.add(self.simulation)

        json_contents = '''
            {
                "foo_parameter": 42,
                "bar_parameter": "/path/to/data.csv"
            }
        '''
        json_input_file = SimulationInputFile.objects.create_file(json_contents, created_by=self.user)
        self.assertContentsEqual(json_input_file, json_contents)
        json_input_file.simulations.add(self.simulation)

        self.assertEqual(self.simulation.input_files.count(), 2)
        for input_file in (empty_input_file, json_input_file):
            self.assertIsInstance(self.simulation.input_files.get(id=input_file.id), SimulationInputFile)

    def test_open_for_reading(self):
        """
        Test the open_for_reading() method of an input file.
        """
        empty_om_scenario = """
            <?xml version='1.0' encoding='UTF-8' standalone='no'?>
            <om:scenario xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
                         name='name'
                        schemaVersion='32'
                        xsi:schemaLocation='http://openmalaria.org/schema/scenario_32 scenario_32.xsd'
                        xmlns:om='http://openmalaria.org/schema/scenario_32'
                        analysisNo='0'
                        wuID='0'>
            </om:scenario>"
        """
        sim_input_file = SimulationInputFile.objects.create_file(empty_om_scenario, created_by=self.user)
        with sim_input_file.open_for_reading() as f:
            retrieved_contents = f.read()
        self.assertEqual(retrieved_contents, empty_om_scenario)


'''
This file shows example code for path control.
This will be quite helpful for collaboration through github.
SOURCE:
https://docs.python.org/3/library/os.html
'''

# import
import os

# get the filepath
filepath = os.path.abspath(__file__)
print('\nthe filepath is \n{}'.format(filepath))

# get the parent folder of the filepath
HERE = os.path.dirname(os.path.abspath(__file__))
print('\nthe path of the parent folder of this file is \n{}'.format(HERE))

# get cwd (current working directory)
my_cwd = os.getcwd()
print('\nthe current working directory is \n{}'.format(my_cwd))

# get the directory of 'data' in 'py_03_intermediate' folder
parent_folder = 'py_02_intermediate'
foldername = 'data'
DIR = os.path.join(HERE, foldername)
print('\nthe folderpath to "{}" in "{}" is \n{}'.format(foldername, parent_folder, DIR))

# get the directory of 'data' in 'py_01_builtin' folder
parent_folder = 'py_01_builtin'
foldername = 'data'
DIR = os.path.join(my_cwd, parent_folder, foldername)
print('\nthe folderpath to "{}" in "{}" is \n{}'.format(foldername, parent_folder, DIR))


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

import os
from .symlink import create_symlink
from .error import RelativeSymlinkError
from .git_checkout_resolver import GitCheckoutResolver

class GitResolver(object):
    """
    Base Git Resolver functionality. Clones/pulls a git repository.
    """

    DEFAULT_BRANCH = "default"

    def __init__(self, git, ctx, dependency, git_url_rewriter, cwd):
        """Construct a new WurfGitResolver instance.

        :param git: A Git instance
        :param ctx: A Waf Context instance.
        :param dependency: The dependency instance.
        :param git_url_rewriter: A GitUrlRewriter instance
        :param cwd: Current working directory as a string. This is the place
            where we should create new folders etc.
        """
        self.git = git
        self.ctx = ctx
        self.dependency = dependency
        self.git_url_rewriter = git_url_rewriter
        self.cwd = cwd

    def resolve(self):
        """
        Fetches the dependency if necessary.

        :return: The path to the resolved dependency as a string.
        """
        repo_url = self.git_url_rewriter.rewrite_url(self.dependency.source)

        default_repo_path = os.path.join(self.cwd, self.DEFAULT_BRANCH)
        if not os.path.isdir(default_repo_path):
            self.git.clone(
                repository=repo_url,
                directory=default_repo_path,
                cwd=self.cwd,
            )
            self.__create_symlink_to_default_branch(default_repo_path)
        else:
            # We only want to pull if we haven't just cloned. This avoids
            # having to type in the username and password twice when using
            # https as a git protocol.
            try:
                # git pull will fail if the repository is unavailable
                # This is not a problem if we have already downloaded
                # the required version for this dependency
                self.git.pull(cwd=default_repo_path)
            except Exception as e:
                self.ctx.to_log("Exception when executing git pull:")
                self.ctx.to_log(e)

        # If the dependency contains submodules, we also get those
        if self.dependency.pull_submodules:
            self.git.pull_submodules(cwd=default_repo_path)

        return default_repo_path

    def __create_symlink_to_default_branch(self, default_repo_path):
        # Create a symlink to the default branch folder, likely master or main
        default_branch = self.git.default_branch(cwd=default_repo_path)
        link_path = os.path.join(
            self.cwd, GitCheckoutResolver.branch_folder_name(default_branch)
        )
        self.ctx.to_log(
            f"wurf: GitResolver Create symlink {link_path} -> {default_repo_path}"
        )
        try:
            try:
                # We set overwrite True since We need to remove the symlink if it
                # already exists since it may point to an incorrect folder
                create_symlink(
                    from_path=default_repo_path,
                    to_path=link_path,
                    overwrite=True,
                    relative=True,
                )
            except RelativeSymlinkError:
                self.ctx.to_log(
                    "wurf: Using relative symlink failed - fallback to absolute."
                )
                create_symlink(
                    from_path=default_repo_path,
                    to_path=link_path,
                    overwrite=True,
                    relative=False,
                )
        except Exception as ex:
            msg = f"Symlink creation for {self.dependency.name}'s default branch\n"

            # We also want to log the captured output if the command failed
            # with a CalledProcessError, the output would be lost otherwise
            if hasattr(ex, "output"):
                msg += str(ex.output)

            # Using exc_info will attach the current exception information
            # to the log message (including the traceback)
            self.ctx.logger.debug(msg, exc_info=True)

    def __repr__(self):
        """
        :return: Representation of this object as a string
        """
        return "%s(%r)" % (self.__class__.__name__, self.__dict__)


import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="TF3Dscan",
    version="0.0.1",
    author="Nigatu Ayele",
    author_email="naodm2006awet4@gmail.com",
    description="Transcription factor binding site prediction",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/pypa/example-project",
    packages=setuptools.find_packages(),
    classifiers=(
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ),
)


import logging
import traceback

from flask_restplus import Api
import settings

log = logging.getLogger(__name__)

api = Api(version='1.0.1',
          title='Stockkly API',
          description='A free, near real-time, RestAPI for providing price data for stocks (FTSE, NASDAQ), crypto-currencies, funds and Precious metals (GOLD, SILVER).')

@api.errorhandler
def default_error_handler(e):
    message = 'An unhandled exception occurred.'
    log.exception(message)

    if not settings.FLASK_DEBUG:
        return {'message': message}, 500


# from django.shortcuts import render
# # Create your views here.

from rest_framework.decorators import api_view, permission_classes  #ls5
from rest_framework.response import Response
from products.serializers import ProductSerializer, ProductValidateSerializer  #ls4
from products.serializers import BrandSerializer, ReviewSerializer  #ls6
from products.models import Product, Review, Brand  #ls6
from rest_framework import status
from rest_framework.permissions import IsAuthenticated  #ls5
from rest_framework.permissions import AllowAny, IsAdminUser  #ls6
from rest_framework.generics import ListAPIView, ListCreateAPIView, RetrieveUpdateDestroyAPIView  #ls6
from rest_framework.pagination import PageNumberPagination  #ls6
from rest_framework.viewsets import ModelViewSet #ls6

@api_view(['GET'])
def test(request):
    data = {
        'text': 'Hello World!',
        'int': 100,
        'float': 2.99,
        'list': [1, 2, 3, 4],
        'bool': False
    }
    return Response(data=data)

#ls3
@api_view(['POST'])
def test_post(request):
    print(request.data['name'])
    print(request.data.get('name')) #--более предпочтит использовать
    return Response(data={'message': 'OK'})

# @api_view(['GET']) #ls2
# def product_list_view(request):
#     products = Product.objects.all()
#     serializer = ProductSerializer(products, many=True)
#     return Response(data=serializer.data)

@api_view(['GET', 'POST']) #ls3
@permission_classes([IsAuthenticated]) #ls5
def product_list_create_view(request):
    print(request.user) #ls5
    if request.method == 'GET':
        products = Product.objects.all()
        serializer = ProductSerializer(products, many=True)
        return Response(data=serializer.data)
    elif request.method == 'POST':
       serializer = ProductValidateSerializer(data=request.data) #ls4
       if not serializer.is_valid():
           return Response(status=status.HTTP_406_NOT_ACCEPTABLE,
                           data={'errors' : serializer.errors})
       # title = request.data.get('title')
       title = serializer.validated_data.get('title')
       # if title is None: #ls4
       #     title = ''
       # if len(title) < 2: #ls4
       #     return Response(status=status.HTTP_406_NOT_ACCEPTABLE,
       #                     data={'error': 'title length less than 2'})
       weight = request.data.get('weight')
       price = request.data.get('price')
       is_stock = request.data.get('is_stock')
       valid_until = request.data.get('valid_until')
       brand_id = request.data.get('brand_id')
       # product = Product.objects.create(**serializer.validated_data)
       product = Product.objects.create(title = title, weight = weight,
                                        price = price, is_stock= is_stock,
                                        valid_until = valid_until,
                                        brand_id = brand_id)
       for i in serializer.validated_data['reviews']:
           Review.objects.create(product=product, text=i['text'], stars=i['stars'])
       return Response(data=ProductSerializer(product).data)

# @api_view(['GET']) #ls2
# def product_item_view(request, id):
#     try:
#         product = Product.objects.get(id=id)
#     except Product.DoesNotExist:
#         return Response(data={'error': 'Product not Found!!!'},
#                         status=status.HTTP_404_NOT_FOUND)
#                         # status=404)
#     serializer = ProductSerializer(product)
#     return Response(data=serializer.data)

#ls3
@api_view(['GET', 'PUT', 'DELETE'])
def product_item_view(request, id):
    try:
        product = Product.objects.get(id=id)
    except Product.DoesNotExist:
        return Response(data={'error': 'Product not Found!!!'},
                        status=status.HTTP_404_NOT_FOUND)
                        # status=404)
    if request.method == 'GET':
        serializer = ProductSerializer(product)
        return Response(data=serializer.data)
    elif request.method == 'DELETE':
        product.delete()
        return Response(data={'message': 'Product removed'})
    else:
        product.title = request.data.get('title')
        product.weight = request.data.get('weight')
        product.price = request.data.get('price')
        product.is_stock = request.data.get('is_stock')
        product.valid_until = request.data.get('valid_until')
        product.brand_id = request.data.get('brand id')
        product.save()
        return Response(data=ProductSerializer(product).data)

#ls6
# class BrandListAPIView(ListAPIView):
class BrandListAPIView(ListCreateAPIView):
    queryset = Brand.objects.all()
    serializer_class = BrandSerializer
    # permission_classes = IsAuthenticated,
    pagination_class = PageNumberPagination

class BrandItemAPIView(RetrieveUpdateDestroyAPIView):
    queryset = Brand.objects.all()
    serializer_class = BrandSerializer
    # lookup_field = 'id'

class ReviewModelViewSet(ModelViewSet):
    queryset = Review.objects.all()
    serializer_class = ReviewSerializer


from sklearn import *
import sklearn
import numpy as np
import pandas as pd
import re

from multiprocessing import Pool, cpu_count
from nltk.corpus import stopwords
from nltk.stem.snowball import SnowballStemmer
from nltk.tokenize import RegexpTokenizer
#import nltk
#nltk.download()

try:
    cpus = cpu_count()
except NotImplementedError:
    cpus = 2   # arbitrary default

paper_stop_words = [ "fig", "figure", "et", "al", "table",
            "data", "analysis", "analyze", "study",
            "method", "result", "conclusion", "author",
            "find", "found", "show", "perform",
            "demonstrate", "evaluate", "discuss"]

def clean_str(s):
    """Cleaning text """
    # s = re.sub("(\(\d*\))","",s)
    # s = re.sub(r"\/"," ",s)
    # s = re.sub(r">"," ",s)
    # s = re.sub(r"<"," ",s)
    # s = re.sub(r"-"," ",s)
    # s = re.sub(r"–"," ",s)
    # s = re.sub(r"\'s", " 's", s)
    # s = re.sub(r"\'ve", " 've", s)
    # s = re.sub(r"n\'t", " n't", s)
    # s = re.sub(r"\'re", " 're", s)
    # s = re.sub(r"\'d", " 'd", s)
    # s = re.sub(r"\'ll", " 'll", s)
    # s = re.sub(r" a "," ",s)
    # s = re.sub(r" the "," ",s)
    # s = re.sub(r"(\(Fig\..*\))"," ",s)
    # s = re.sub(r"(\(Table\..*\))"," ",s)
    # s = re.sub(r"Fig.\S+ "," ",s)
    # s = re.sub(r"Table "," ",s)
    # s = re.sub(r", "," ",s)
    # s = re.sub(r"[().?\[\]!;:+]", " ", s)
    # s = re.sub(r" '\S+", "", s)
    # s = re.sub(' +',' ',s)
    s = re.sub(r" \d*", " ", s)
    tokenizer = RegexpTokenizer(r'\w+')
    words = tokenizer.tokenize(s.lower())
    stemmer = SnowballStemmer("porter")
    words = [w for w in words if not w in stopwords.words("english")]
    words = [w for w in words if not w in paper_stop_words]
    words = [stemmer.stem(w) for w in words]
    s = " ".join(words)
    return s

def load_data_and_labels(variants_file,text_file):
    """Load text and Classes"""
    var = pd.read_csv(variants_file)
    txt = pd.read_csv(text_file, sep="\|\|", engine='python', header=None, skiprows=1, names=["ID","Text"])
    txt_var = pd.merge(var, txt, how='left', on='ID')

    for index, row in txt_var.iterrows():
        if len(row['Text']) < 10:
            txt_var.drop(index,inplace=True)

    x_text = list(txt_var['Text'])
    print ("Cleaning data ...\n")

    # x_text = [clean_str(sent) for sent in x_text]

    pool = Pool(processes=cpus)
    x_text = pool.map(clean_str, x_text)
    pool.close()
    pool.join()

    # Map the actual classes to one hot labels
    try:
        labels = sorted(list(set(txt_var['Class'].tolist())))
        one_hot = np.zeros((len(labels), len(labels)), int)
        np.fill_diagonal(one_hot, 1)
        label_dict = dict(zip(labels, one_hot))
        y = txt_var['Class'].apply(lambda y: label_dict[y]).tolist()
    except:
        y = None
        labels = None
    return [x_text, y, labels]

class cust_regression_vals(sklearn.base.BaseEstimator, sklearn.base.TransformerMixin):
    def fit(self, x, y=None):
        return self
    def transform(self, x):
        x = x.drop(['Gene', 'Variation','ID','Text'],axis=1).values
        return x

class cust_txt_col(sklearn.base.BaseEstimator, sklearn.base.TransformerMixin):
    def __init__(self, key):
        self.key = key
    def fit(self, x, y=None):
        return self
    def transform(self, x):
        return x[self.key].apply(str)

def gene_related_features(variants_file,text_file):

    var = pd.read_csv(variants_file)
    txt = pd.read_csv(text_file, sep="\|\|", engine='python', header=None, skiprows=1, names=["ID","Text"])

    train = pd.merge(var, txt, how='left', on='ID')

    for index, row in train.iterrows():
        if len(row['Text']) < 10:
            train.drop(index,inplace=True)

    train = train.drop(['Class'], axis=1)
    train['Gene_Share'] = train.apply(lambda r: sum([1 for w in r['Gene'].split(' ') if w in r['Text'].split(' ')]), axis=1)
    train['Variation_Share'] = train.apply(lambda r: sum([1 for w in r['Variation'].split(' ') if w in r['Text'].split(' ')]), axis=1)

    for i in range(56):
        train['Gene_'+str(i)] = train['Gene'].map(lambda x: str(x[i]) if len(x)>i else '')
        train['Variation'+str(i)] = train['Variation'].map(lambda x: str(x[i]) if len(x)>i else '')

    gen_var_lst = sorted(list(train.Gene.unique()) + list(train.Variation.unique()))
    print(len(gen_var_lst))
    gen_var_lst = [x for x in gen_var_lst if len(x.split(' '))==1]
    print(len(gen_var_lst))
    i_ = 0

    for gen_var_lst_itm in gen_var_lst:
       if i_ % 100 == 0: print(i_)
       train['GV_'+str(gen_var_lst_itm)] = train['Text'].map(lambda x: str(x).count(str(gen_var_lst_itm)))
       i_ += 1

    for c in train.columns:
        if train[c].dtype == 'object':
            if c in ['Gene','Variation']:
                lbl = preprocessing.LabelEncoder()
                train[c+'_lbl_enc'] = lbl.fit_transform(train[c].values)
                train[c+'_len'] = train[c].map(lambda x: len(str(x)))
                train[c+'_words'] = train[c].map(lambda x: len(str(x).split(' ')))
            elif c != 'Text':
                lbl = preprocessing.LabelEncoder()
                train[c] = lbl.fit_transform(train[c].values)
            if c=='Text':
                train[c+'_len'] = train[c].map(lambda x: len(str(x)))
                train[c+'_words'] = train[c].map(lambda x: len(str(x).split(' ')))

    # print('Pipeline...')

    # #Defining Transformers:

    # count_Gene  = feature_extraction.text.CountVectorizer(analyzer=u'char', ngram_range=(1, 8))
    # tsvd1 = decomposition.TruncatedSVD(n_components=20, n_iter=25, random_state=12)
    # count_Variation = feature_extraction.text.CountVectorizer(analyzer=u'char', ngram_range=(1, 8))
    # tsvd2 = decomposition.TruncatedSVD(n_components=20, n_iter=25, random_state=12)

    # pi1 = pipeline.Pipeline([('Gene', cust_txt_col('Gene')), ('count_Gene', count_Gene),('tsvd1',tsvd1)])
    # pi2 = pipeline.Pipeline([('Variation', cust_txt_col('Variation')), ('count_Variation',count_Variation), ('tsvd2',tsvd2)])
    # # pi3 = pipeline.Pipeline([('Text', cust_txt_col('Text')), ('tfidf_Text', feature_extraction.text.TfidfVectorizer(ngram_range=(1, 2))), ('tsvd3', decomposition.TruncatedSVD(n_components=50, n_iter=25, random_state=12))])

    # fp = pipeline.Pipeline([
    #     ('union', pipeline.FeatureUnion(
    #         n_jobs = -1,
    #         transformer_list = [
    #             ('standard', cust_regression_vals()),
    #             ('pi1', pi1),
    #             ('pi2', pi2),
    #             #commented for Kaggle Limits
    #             #('pi3', pi3)
    #         ])
    #     )])

    # train = fp.fit_transform(train).astype(int)
    # print(train.shape)

    return train

def batch_iter(data, batch_size, num_epochs, shuffle=True):
    """Iterate the data batch by batch"""

    data = np.array(data)
    data_size = len(data)
    num_batches_per_epoch = int((len(data)-1)/batch_size) + 1
    for epoch in range(num_epochs):
        # Shuffle the data at each epoch
        if shuffle:
            shuffle_indices = np.random.permutation(np.arange(data_size))
            shuffled_data = data[shuffle_indices]
        else:
            shuffled_data = data
        for batch_num in range(num_batches_per_epoch):
            start_index = batch_num * batch_size
            end_index = min((batch_num + 1) * batch_size, data_size)
            yield shuffled_data[start_index:end_index]


"""Module containing the rooms' descriptions and how they are displayed."""

from random import randint

import pygame

ENTRY_CAVE_TEXT = (
    "As you awaken in a dimly lit room, confusion sets in. Your surroundings are unfamiliar "
    "and disorienting, leaving you feeling lost and unsure of what to do next. You quickly "
    "realize that you need to find a way out of this place. A faint whisper echoes in your "
    "mind, urging you to 'look at' the walls. Perhaps they hold a clue to your escape. It's "
    "time to start searching and uncovering the secrets of this mysterious room."
)

VALLEY_TEXT = (
    "As you step out of the dark and confining room, you're greeted by "
    "the sight of an expansive green area. The soft blades of grass tickle "
    "your feet as you take in your surroundings. The area is dotted with tall "
    "trees, providing shade and a sense of tranquility. However, you quickly "
    "remember the task at hand - to find a way to survive. You'll need to explore "
    "the area and take advantage of the resources it has to offer. The fresh air "
    "and open space invigorate you, giving you the energy to tackle whatever "
    "challenges lay ahead."
)

class RoomText:
    """Room text object displaying the room's description."""

    def __init__(self, cmd_line):
        """Initialize object."""
        self.cmd_line = cmd_line

        self.room_text_dict = {
            "entry_cave": ENTRY_CAVE_TEXT,
            "valley": VALLEY_TEXT,
        }
        self.room_first_entry = dict.fromkeys(self.room_text_dict.keys(), True)
        self.update_text = True
        self.past_updated_text = 0
        self.update_text_speed = 20
        self.letter_counter = 0
        self.line_counter = 0
        self.prev_value = ""
        self.is_first = True

        self.keyboard_sound = pygame.mixer.Sound("src/audio/mech_keyboard.wav")
        self.enter_sound = pygame.mixer.Sound("src/audio/mech_keyboard_enter.wav")
        self.enter_sound.set_volume(0.1)

    def update_text_cooldowns(self):
        """Update cooldowns to type the next letter."""
        current_time = pygame.time.get_ticks()
        if not self.update_text:
            if current_time - self.past_updated_text >= (
                self.update_text_speed - randint(-20, 20)
            ):
                self.update_text = True

    def update_room_first_entry(self):
        """Check if current room has been already accessed in the past."""
        if self.room_first_entry[self.cmd_line.map_state]:
            self.cmd_line.active_player = False
            self.room_name = self.cmd_line.map_state.upper().replace("_", " ")
            self.room_text = self.room_text_dict[self.cmd_line.map_state]
            self.room_text = self.cmd_line.split_long_user_input(self.room_text)
            self.update_text_cooldowns()
            self.display_animated_text()

    def display_animated_text(self):
        """Display text letter by letter directly into the CL history."""
        # Get the current length of the CL history as starting point
        if self.is_first:
            self.prev_line_counter = self.cmd_line.len_history
            self.is_first = False

        # Write room description as it was typed in a mechanical keyboard
        if self.update_text == True:
            self.play_keyboard_sound()
            self.letter_counter += 1
            text = self.room_text[self.line_counter][: self.letter_counter]
            try:
                self.cmd_line._history[
                    self.prev_line_counter + self.line_counter
                ] = text
            except IndexError:
                self.cmd_line._history.append(text)
            self.past_updated_text = pygame.time.get_ticks()
            if self.letter_counter == len(self.room_text[self.line_counter]) + 2:
                self.line_counter += 1
                self.letter_counter = 0
                if self.line_counter == len(self.room_text):
                    self.update_text = False
                    self.is_first = True
                    self.line_counter = 0
                    self.room_first_entry[self.cmd_line.map_state] = False
                    self.keyboard_sound.stop()
                    self.cmd_line.input.value = ""
                    self.cmd_line.active_player = True
                    self.enter_sound.play()

    def play_keyboard_sound(self):
        """Play the sound of a mechanical keyboard typing."""
        if self.letter_counter == 0:
            self.keyboard_sound.play(loops=-1)

    def display_letter_on_cl(self, prev_value, new_letter):
        """Display room's description."""
        self.cmd_line._input.draw_letter_after_value(
            self.cmd_line.surface, prev_value, new_letter
        )


# -*- coding: utf-8 -*-
import re
import math
import unicodedata

from collections import Counter

def strip_accents(s):
	return ''.join(c for c in unicodedata.normalize('NFKD', s)
		if unicodedata.category(c) != 'Mn')

# Returns a dial code string for a word.
## Omits special characters
def word_to_number(word):
	number = "";
	mapping_number = {
		".": 1,
		"a": 2,
		"b": 2,
		"c": 2,
		"d": 3,
		"e": 3,
		"f": 3,
		"g": 4,
		"h": 4,
		"i": 4,
		"j": 5,
		"k": 5,
		"l": 5,
		"m": 6,
		"n": 6,
		"ñ": 6,
		"o": 6,
		"p": 7,
		"q": 7,
		"r": 7,
		"s": 7,
		"t": 8,
		"u": 8,
		"v": 8,
		"w": 9,
		"x": 9,
		"y": 9,
		"z": 9};

	word = ''.join(e for e in word if e.isalnum())
	word = re.sub(r'[0-9]', '', word);
	word = word.replace('á', 'a');
	word = word.replace('é', 'e');
	word = word.replace('í', 'i');
	word = word.replace('ó', 'o');
	word = word.replace('ú', 'u');
	word = word.lower();

	for i in range (0, len(word)):
		character = word[i];

		if (character in mapping_number):
			number += str(mapping_number[character]);
		else:
			print('Character ' + character + ' not recognised');

	return number;

def sentence_to_numbers(sentence):
	out = ""
	for word in ' '.join(sentence.split()).split():
		out += word_to_number(word) + " "
	return out

def get_cosine(vec1, vec2):
	intersection = set(vec1.keys()) & set(vec2.keys())
	numerator = sum([vec1[x] * vec2[x] for x in intersection])

	sum1 = sum([vec1[x]**2 for x in vec1.keys()])
	sum2 = sum([vec2[x]**2 for x in vec2.keys()])
	denominator = math.sqrt(sum1) * math.sqrt(sum2)

	if not denominator:
		return 0.0
	else:
		return float(numerator) / denominator

def text_to_vector(text):
	word = re.compile(r'\w+')
	words = word.findall(text)
	return Counter(words)

def word_to_vector(word):
	char = re.compile(r'\w')
	chars = char.findall(word)
	return Counter(chars)


def quase_newton(f, x0, x1, tol=1e-6, max_iter=100):
    x_prev = x0
    x = x1
    iteracoes = 0

    while iteracoes < max_iter:
        iteracoes += 1

        aproximacao_derivada = ( f(x + (x_prev - x)) - f(x) ) / (x_prev - x)
        x_next = x - f(x) / aproximacao_derivada

        erro_absoluto = abs(x_next - x)
        erro_relativo = erro_absoluto / abs(x_next)

        print('| {:10} | {:<20} | {:<25} | {:<25} | {:<25} | {:<25}|'.format(iteracoes, x_next, x_prev, f(x), erro_absoluto, erro_relativo))

        if erro_relativo < tol:
            return x_next, iteracoes

        x_prev = x
        x = x_next

    return None, iteracoes

def f(x):
    return x**2 - 5

x0 = 3.0
x1 = 1.0

print("Método de Quase-Newton")
print('| {:10} | {:<20} | {:<25} | {:<25} | {:<25} | {:<25}|'.format("iteracoes", "x_next", "x_prev", "f(x)", "erro_absoluto", "erro_relativo"))

raiz, iteracoes = quase_newton(f, x0, x1)

if raiz is not None:
    print("Convergiu em ", iteracoes, " para ", raiz)
else:
    print("O método não convergiu após", iteracoes, "iterações.")


# coding: utf-8

import re
from lxml import etree

question_pattern = re.compile('
问题(.*?)', re.S)
question_options_pattern = re.compile('
.*?<input class="radio_type1".*?(.*?)</sp', re.S)

def us_gbk(value):
    if value >= '\u4e00' and value[:-1] <= '\u9fa5':
        value = value.encode('gb2312', 'replace')
    return value
result = dict()
n = 0
with open('dati.html', 'r', encoding='utf-8') as f:
    html = f.read()

    # items_questions = question_pattern.findall(html)
    # print(items_questions)
    # items_options_questions = question_options_pattern.findall(html)
    # print([x.strip() for x in items_options_questions])
    # for item in range(len(items_questions)):
    #     result[items_questions[item]] = items_options_questions[n:n+5]
    #     n +=5
    # print(result)
    # datas = dict()
    # x = etree.HTML(html)
    # inps = x.xpath('//div[@class="qustion"]/ul/input')
    # n = 0
    # count = int(len(inps)/5)
    # for i in range(1, 6):
    #     inp = inps[(i-1) * count:i * count-1]
    #     datas.update({
    #         'kbaList['+str(n)+'].derivativecode': us_gbk(inp[0].xpath('@value')[0]),
    #         'kbaList['+str(n)+'].businesstype': us_gbk(inp[1].xpath('@value')[0]),
    #         'kbaList['+str(n)+'].questionno': us_gbk(inp[2].xpath('@value')[0]),
    #         'kbaList['+str(n)+'].kbanum': us_gbk(inp[3].xpath('@value')[0]),
    #         'kbaList['+str(n)+'].question': inp[4].xpath('@value')[0].encode('gb2312', 'replace'),
    #         'kbaList['+str(n)+'].options1': us_gbk(inp[5].xpath('@value')[0]),
    #         'kbaList['+str(n)+'].options2': us_gbk(inp[6].xpath('@value')[0]),
    #         'kbaList['+str(n)+'].options3': us_gbk(inp[7].xpath('@value')[0]),
    #         'kbaList['+str(n)+'].options4': us_gbk(inp[8].xpath('@value')[0]),
    #         'kbaList['+str(n)+'].options5': us_gbk(inp[9].xpath('@value')[0]),
    #         'kbaList['+str(n)+'].answerresult': '',
    #         'kbaList['+str(n)+'].options': '',
    #     })
    #     n +=1
    # print(datas)


# 09String.py

# text = input("Insert Message in English : ")
# print(text.upper(), end = "")
# print(text.lower(), end = "\tAAA")
# print(text.capitalize())

# for c in text:
#     print(c)

# 대문자로 입력된 것은 소문자로, 소문자는 대문자로 출력하기
# Hello World --> hELLO wORLD

text = input("Insert Message in English : ")

for c in text:
    if c.isupper():
        print(c.lower(), end="")
    elif c.islower():
        print(c.upper(), end="")
    else:
        print(c, end="")

print("\n")
'''
for c in text:
    if c.isupper():
        d = c.lower()
        text = text.replace(c,d)
    elif c.islower():
        d = c.upper()
        text = text.replace(c,d)
    else:
        pass
print(text)
'''
rText = str()
for c in text:
    if c.isupper():
        rText += c.lower()
    elif c.islower():
        rText += c.upper()
    else:
        rText += c
print(rText)

print("text = ", text)
print("swap = ", text.swapcase())

print("-" * 80)

# text를 역순으로 출력하시오.
# rText에 역순을 저장한 후, rText를 출력하시오.
# range(10, -1, -1)
# range(1, 10, 1)

rText = str()
for c in range(len(text)-1, -1, -1):
    rText = rText + text[c]
print(rText)
print(text[::-1])


from __future__ import annotations

import numpy as np

from morphoclass.transforms.helper import require_field

class RandomJitter:
    """Randomly jitter all nodes.

    The jittering is applied in the following way. For each coordinate x
    draw two random numbers, d1 in {-d_add, +d_add} and d2 in
    {-d_scale, +d_scale} and transform x as follows:

        x => (x + d1) * (1 + d2)

    Note that d_scale is the scale variation relative to 1.0.

    Parameters
    ----------
    d_add : float
        The maximal additive factor for jittering.
    d_scale : float
        The maximal multiplicative factor for jittering (relative to 1.0).
    shift_to_origin : bool (optional)
        If true then make sure that the root point is at the origin
        before and after the transformation.
    """

    def __init__(self, d_add=0.0, d_scale=0.0, shift_to_origin=True):
        self.d_add = d_add
        self.d_scale = d_scale
        self.shift_to_origin = shift_to_origin

    @require_field("tmd_neurites")
    def __call__(self, data):
        """Apply the morphology transformation.

        Parameters
        ----------
        data
            The input morphology data sample.

        Returns
        -------
        data
            The modified morphology data sample.
        """
        for apical in data.tmd_neurites:
            # Number of nodes
            n = len(apical.p)

            # Generate random shifts and scales
            random_shift = 2 * self.d_add * np.random.rand(3, n) - self.d_add
            random_scale = 2 * self.d_scale * np.random.rand(3, n) - self.d_scale

            # Extract node coordinates
            coords = np.array([apical.x, apical.y, apical.z])

            # Shift to origin
            if self.shift_to_origin:
                if len(np.nonzero(apical.p == -1)[0]) != 1:
                    msg = "Apical must have only one root"
                    raise ValueError(msg)
                coords = coords - coords[:, apical.p == -1]

            # Apply jittering
            coords += random_shift
            coords *= 1.0 + random_scale

            # Shift to origin again
            if self.shift_to_origin:
                coords = coords - coords[:, apical.p == -1]

            # Update apical
            apical.x, apical.y, apical.z = coords

        return data