import json
import os
from concurrent import futures

import luigi
import numpy as np
import nifty.tools as nt
import z5py

from cluster_tools.inference import InferenceLocal
from cluster_tools.inference.inference_embl import InferenceEmbl

OFFSETS = [
    [-1, 0, 0],
    [0, -1, 0],
    [0, 0, -1],
    [-2, 0, 0],
    [0, -3, 0],
    [0, 0, -3],
    [-3, 0, 0],
    [0, -9, 0],
    [0, 0, -9]
]

def update_block_shape(config_dir, block_shape, default_config):
    global_conf = os.path.join(config_dir, 'global.config')
    if os.path.exists(global_conf):
        with open(global_conf) as f:
            config = json.load(f)
    else:
        config = default_config

    if config['block_shape'] != block_shape:
        config['block_shape'] = block_shape

    with open(global_conf, 'w') as f:
        json.dump(config, f)

def predict(input_path, input_key,
            output_path, output_prefix,
            ckpt, gpus, tmp_folder, target,
            gpu_type='2080Ti', predict_affinities=False):
    task = InferenceLocal if target == 'local' else InferenceEmbl

    # halo = [8, 64, 64]
    # block_shape = [32, 256, 256]

    # larger halo
    halo = [12, 96, 96]
    block_shape = [24, 128, 128]

    if predict_affinities:
        output_key = {
            f'{output_prefix}/foreground': [0, 1],
            f'{output_prefix}/affinities': [1, 10]
        }
    else:
        output_key = {
            f'{output_prefix}/foreground': [0, 1],
            f'{output_prefix}/boundaries': [1, 2]
        }

    config_dir = os.path.join(tmp_folder, 'configs')
    os.makedirs(config_dir, exist_ok=True)
    update_block_shape(config_dir, block_shape, task.default_global_config())

    conf = task.default_global_config()
    conf.update({'block_shape': block_shape})
    with open(os.path.join(config_dir, 'global.config'), 'w') as f:
        json.dump(conf, f)

    if target == 'local':
        device_mapping = {ii: gpu for ii, gpu in enumerate(gpus)}
    else:
        device_mapping = None
    n_threads = 6

    conf = task.default_task_config()
    conf.update({
        'dtype': 'uint8',
        'device_mapping': device_mapping,
        'threads_per_job': n_threads,
        'mixed_precision': True,
        'gpu_type': gpu_type,
        'qos': 'high',
        'mem_limit': 24,
        'time_limit': 600
    })
    with open(os.path.join(config_dir, 'inference.config'), 'w') as f:
        json.dump(conf, f)

    t = task(tmp_folder=tmp_folder, config_dir=config_dir, max_jobs=len(gpus),
             input_path=input_path, input_key=input_key,
             output_path=output_path, output_key=output_key,
             checkpoint_path=ckpt, halo=halo,
             framework='pytorch')
    assert luigi.build([t], local_scheduler=True)
    update_block_shape(config_dir, [32, 256, 256], task.default_global_config())

def set_bounding_box(tmp_folder, bounding_box):
    config = InferenceLocal.default_global_config()
    config.update({
        'roi_begin': [bb.start for bb in bounding_box],
        'roi_end': [bb.stop for bb in bounding_box]
    })

    config_folder = os.path.join(tmp_folder, 'configs')
    os.makedirs(config_folder, exist_ok=True)
    config_file = os.path.join(config_folder, 'global.config')

    with open(config_file, 'w') as f:
        json.dump(config, f)

def get_checkpoint(checkpoint, use_best=False, is_affinity_model=False):
    if use_best:
        path = os.path.join(checkpoint, 'best.pt')
    else:
        path = os.path.join(checkpoint, 'latest.pt')

    n_out = 10 if is_affinity_model else 2
    if 'large' in checkpoint:
        model_kwargs = dict(
            scale_factors=[
                [1, 2, 2],
                [1, 2, 2],
                [2, 2, 2],
                [2, 2, 2],
                [2, 2, 2]
            ],
            in_channels=1,
            out_channels=n_out,
            initial_features=128,
            gain=2,
            pad_convs=True,
            final_activation='Sigmoid'
        )
    else:
        model_kwargs = dict(
            scale_factors=[
                [1, 2, 2],
                [1, 2, 2],
                [2, 2, 2],
                [2, 2, 2]
            ],
            in_channels=1,
            out_channels=n_out,
            initial_features=64,
            gain=2,
            pad_convs=True,
            final_activation='Sigmoid'
        )

    ckpt = {
        'class': ('mipnet.models.unet', 'AnisotropicUNet'),
        'kwargs': model_kwargs,
        'checkpoint_path': path,
        'model_state_key': 'model_state'
    }

    return ckpt

def run_multicut(path,
                 checkpoint_name,
                 target,
                 max_jobs,
                 tmp_folder,
                 beta):
    from cluster_tools.workflows import MulticutSegmentationWorkflow
    task = MulticutSegmentationWorkflow

    config_dir = os.path.join(tmp_folder, 'configs')
    configs = task.get_config()

    ws_config = configs['watershed']
    ws_config.update({
        "threshold": 0.25,
        'apply_dt_2d': True,
        'apply_filters_2d': True,
        'apply_ws_2d': False,
        'sigma_seeds': 2.6
    })
    with open(os.path.join(config_dir, 'watershed.config'), 'w') as f:
        json.dump(ws_config, f)

    cost_config = configs['probs_to_costs']
    cost_config.update({
        'beta': beta
    })
    with open(os.path.join(config_dir, 'probs_to_costs.config'), 'w') as f:
        json.dump(cost_config, f)

    bd_key = f'predictions/{checkpoint_name}/boundaries'
    node_labels_key = f'node_labels/{checkpoint_name}/multicut'
    ws_key = f'segmentation/{checkpoint_name}/watershed'
    seg_key = f'segmentation/{checkpoint_name}/multicut'

    t = task(target=target, max_jobs=max_jobs,
             tmp_folder=tmp_folder, config_dir=config_dir,
             input_path=path, input_key=bd_key,
             ws_path=path, ws_key=ws_key,
             problem_path=os.path.join(tmp_folder, 'data.n5'),
             node_labels_key=node_labels_key,
             output_path=path, output_key=seg_key)
    assert luigi.build([t], local_scheduler=True)

def run_mws(data_path, checkpoint_name,
            target, max_jobs, tmp_folder,
            threshold):
    fg_key = f'predictions/{checkpoint_name}/foreground'
    mask_key = f'predictions/{checkpoint_name}/mask'
    aff_key = f'predictions/{checkpoint_name}/affinities'
    seg_key = f'segmentation/{checkpoint_name}/mutex_watershed'

    from cluster_tools.thresholded_components.threshold import ThresholdLocal, ThresholdSlurm
    task = ThresholdLocal if target == 'local' else ThresholdSlurm
    config_dir = os.path.join(tmp_folder, 'configs')
    t = task(tmp_folder=tmp_folder, config_dir=config_dir, max_jobs=max_jobs,
             input_path=data_path, input_key=fg_key,
             output_path=data_path, output_key=mask_key,
             threshold=0.5)
    assert luigi.build([t], local_scheduler=True)

    from cluster_tools.mutex_watershed import MwsWorkflow
    task = MwsWorkflow

    config_dir = os.path.join(tmp_folder, 'configs')

    configs = task.get_config()
    conf = configs['mws_blocks']
    conf.update({
        'strides': [4, 4, 4],
        'randomize_strides': True
    })
    with open(os.path.join(config_dir, 'mws_blocks.config'), 'w') as f:
        json.dump(conf, f)

    conf = configs['block_edge_features']
    conf.update({
        'offsets': OFFSETS
    })
    with open(os.path.join(config_dir, 'block_edge_features.config'), 'w') as f:
        json.dump(conf, f)

    # TODO with halo?
    halo = None
    t = task(tmp_folder=tmp_folder, config_dir=config_dir,
             target=target, max_jobs=max_jobs,
             input_path=data_path, input_key=aff_key,
             output_path=data_path, output_key=seg_key,
             offsets=OFFSETS, halo=halo,
             mask_path=data_path, mask_key=mask_key,
             stitch_via_mc=True)
    assert luigi.build([t], local_scheduler=True)

def postprocess(path, checkpoint_name,
                seg_key, out_key,
                target, max_jobs, tmp_folder,
                size_threshold=250, threshold=None):
    from cluster_tools.postprocess import FilterByThresholdWorkflow
    from cluster_tools.postprocess import SizeFilterWorkflow

    fg_key = f'predictions/{checkpoint_name}/foreground'
    hmap_key = f'predictions/{checkpoint_name}/boundaries'

    config_dir = os.path.join(tmp_folder, 'configs')

    if threshold is not None:
        task = FilterByThresholdWorkflow
        t = task(target=target, max_jobs=max_jobs,
                 tmp_folder=tmp_folder, config_dir=config_dir,
                 input_path=path, input_key=fg_key,
                 seg_in_path=path, seg_in_key=seg_key,
                 seg_out_path=path, seg_out_key=out_key,
                 threshold=threshold)
        assert luigi.build([t], local_scheduler=True)
        seg_key = out_key

    if size_threshold is not None:
        task = SizeFilterWorkflow
        t = task(tmp_folder=tmp_folder, config_dir=config_dir,
                 target=target, max_jobs=max_jobs,
                 input_path=path, input_key=seg_key,
                 output_path=path, output_key=out_key,
                 hmap_path=path, hmap_key=hmap_key,
                 relabel=True, preserve_zeros=True,
                 size_threshold=size_threshold)
        assert luigi.build([t], local_scheduler=True)

# this deserves a cluster tools task
def affinity_to_boundary(data_path, prediction_prefix,
                         tmp_folder, target, max_jobs):
    aff_key = os.path.join(prediction_prefix, 'affinities')
    bd_key = os.path.join(prediction_prefix, 'boundaries')

    with z5py.File(data_path, 'a') as f:
        if bd_key in f:
            return

        ds_affs = f[aff_key]
        shape = ds_affs.shape[1:]
        chunks = ds_affs.chunks[1:]
        ds_bd = f.require_dataset(bd_key, shape=shape, chunks=chunks, compression='gzip',
                                  dtype=ds_affs.dtype)

        blocking = nt.blocking([0, 0, 0], shape, chunks)

        def _block(block_id):
            block = blocking.getBlock(block_id)
            bb = tuple(slice(beg, end) for beg, end in zip(block.begin, block.end))

            bb_affs = (slice(None),) + bb
            affs = ds_affs[bb_affs]

            bd = np.maximum(affs[1], affs[2])
            bd = np.maximum(bd, np.maximum(affs[4], affs[5]))
            ds_bd[bb] = bd.astype(ds_bd.dtype)

        with futures.ThreadPoolExecutor(8) as tp:
            tp.map(_block, range(blocking.numberOfBlocks))

def segment_with_boundaries(sample,
                            checkpoint,
                            target,
                            gpus,
                            max_jobs=32,
                            bounding_box=None,
                            beta=.5,
                            threshold=0.25,
                            only_prediction=False,
                            gpu_type='2080Ti',
                            is_affinity_model=False,
                            size_threshold=250):
    checkpoint_name = os.path.split(checkpoint)[1]

    data_path = os.path.join('./data', f'{sample}.n5')
    raw_key = 'raw'
    prediction_prefix = os.path.join('predictions', checkpoint_name)
    tmp_folder = os.path.join('./tmp_folders', f'tmp_{checkpoint_name}_{sample}')

    if bounding_box is not None:
        set_bounding_box(tmp_folder, bounding_box)

    ckpt = get_checkpoint(checkpoint,
                          is_affinity_model=is_affinity_model)
    predict(data_path, raw_key,
            data_path, prediction_prefix,
            ckpt, gpus, tmp_folder, target,
            gpu_type=gpu_type,
            predict_affinities=is_affinity_model)
    if only_prediction:
        return
    if is_affinity_model:
        affinity_to_boundary(data_path, prediction_prefix,
                             tmp_folder, target, max_jobs)

    run_multicut(data_path, checkpoint_name,
                 target, max_jobs, tmp_folder,
                 beta=beta)

    seg_key = f'segmentation/{checkpoint_name}/multicut'
    out_key = f'segmentation/{checkpoint_name}/multicut_postprocessed'

    postprocess(data_path, checkpoint_name,
                seg_key, out_key,
                target, max_jobs, tmp_folder,
                threshold=threshold,
                size_threshold=size_threshold)

def segment_with_affinities(sample,
                            checkpoint,
                            target,
                            gpus,
                            max_jobs=32,
                            bounding_box=None,
                            threshold=0.5,
                            only_prediction=False,
                            gpu_type='2080Ti',
                            size_threshold=250):
    checkpoint_name = os.path.split(checkpoint)[1]

    data_path = os.path.join('./data', f'{sample}.n5')
    raw_key = 'raw'
    prediction_prefix = os.path.join('predictions', checkpoint_name)
    tmp_folder = os.path.join('./tmp_folders', f'tmp_{checkpoint_name}_{sample}_mws')

    if bounding_box is not None:
        set_bounding_box(tmp_folder, bounding_box)

    ckpt = get_checkpoint(checkpoint,
                          is_affinity_model=True)
    predict(data_path, raw_key,
            data_path, prediction_prefix,
            ckpt, gpus, tmp_folder, target,
            gpu_type=gpu_type,
            predict_affinities=True)
    if only_prediction:
        return
    affinity_to_boundary(data_path, prediction_prefix,
                         tmp_folder, target, max_jobs)

    run_mws(data_path, checkpoint_name,
            target, max_jobs, tmp_folder,
            threshold=threshold)

    seg_key = f'segmentation/{checkpoint_name}/mutex_watershed'
    out_key = f'segmentation/{checkpoint_name}/mutex_watershed_postprocessed'

    postprocess(data_path, checkpoint_name,
                seg_key, out_key,
                target, max_jobs, tmp_folder,
                size_threshold=size_threshold)

if __name__ == '__main__':
    segment_with_affinities(
        'small',
        './checkpoints/affinity_model_default_human_rat',
        'local',
        gpus=[0, 1, 2, 3]
    )


from src.common.database import Database

class Main(object):

    @classmethod
    def start_service(cls):
        card_number = input("Enter card Number: ")

        check_card_number = Database.find_one(query={"card_number": card_number})
        if check_card_number is not None:
            pin = input("Enter Pin: ")
            data = Database.find_one(query={"card_number": card_number, "pin": pin})
            if data is not None:
                print('___________________________________')
                print("Welcome {} ".format(data['name']).upper())
                print('___________________________________')

                Main.present_options(card_number, pin)
            else:
                print("invalid pin")
        else:
            print("Invalid card number")

    @staticmethod
    def present_options(card_number, pin):
        print("1. Deposite cash\n2. Withdraw cash\n3. Account enquiries\n4. Change pin")
        print('___________________________________\n')
        number = int(input(" Enter Option number: "))
        if number == 1:
            amount = int(input("Enter the amount to Deposit: "))
            data = Database.find_one(query={"card_number": card_number, "pin": pin})
            print("You are Depositing GHS {} into your account( {} )".format(amount, data['acc_number']))
            print("Do you wish to continue?\n1. YES\n2. NO")
            confirm_option = int(input(""))
            if confirm_option == 1:
                initial = Database.find_one(query={"card_number": card_number})
                Database.update_balance(card_number=card_number,
                                        pin=pin,
                                        amount=amount)
                updated = Database.find_one(query={"card_number": card_number})
                print("You have succesfully Deposited GHS {} into your account {}\nInitial balance: GHS {}\nNew Balance GHS {}\nLast Transaction date: {}".format(amount,
                                                                                updated['acc_number'],
                                                                                initial['balance'],
                                                                                updated['balance'],
                                                                                updated['last_transaction_date']))

            elif confirm_option == 2:
                print("Transaction cancelled")
                return None
            else:
                print("You have entered invalid response")
                return None

        elif number == 2:
            withdrawal_amount = int(input("Enter the amount to withdraw: "))
            data = Database.find_one(query={"card_number": card_number})
            print("You are withdrawing GHS {} from your account( {} )".format(withdrawal_amount, data['acc_number']))
            print("Do you wish to continue?\n1. YES\n2. NO")
            confirm_option = int(input(""))
            if confirm_option == 1:
                initial = Database.find_one(query={"card_number": card_number})
                if initial['balance']-5 >= withdrawal_amount:
                    Database.update_balance(card_number=card_number,
                                            pin=pin,
                                            amount=-withdrawal_amount)
                    updated = Database.find_one(query={"card_number": card_number})
                    print("You have succesfully withdrawn GHS {} from your account {}\nInitial balance: GHS {}\nNew Balance GHS {}\nLast Transaction date: {}".format(withdrawal_amount,
                                                                                updated['acc_number'],
                                                                                initial['balance'],
                                                                                updated['balance'],
                                                                                updated['last_transaction_date']))
                else:
                    print("Transaction failed! Your balance is insufficient")

            elif confirm_option == 2:
                print("Transaction cancelled")
                return None
            else:
                "You have entered invalid response"
                return None

        elif number == 3:
            data = Database.find_one(query={"card_number": card_number, "pin": pin})
            print("_____________________________")
            print('Name: {}\nAccount Number: {}\nCurrent Balance: {}\nLast transaction Date: {}'.format(data['name'], data['acc_number'], data['balance'], data['last_transaction_date']))
        elif number == 4:
            new_pin = input("Enter new pin: ")
            comfirm_new_pin = input("Enter new pin again: ")
            if new_pin == comfirm_new_pin:
                Database.update_pin(card_number=card_number, new_pin=new_pin)
                print("Pin changed successfully\nExiting app...\nRun app again")
                return None
            else:
                print('Pin does not match\nExiting app...')
        else:
            print("Invalid input")


import uvicorn
from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Welcome to basic math operations api!"}

@app.get("/add")
async def add(a: int, b: int):
    return {"result": a + b}

@app.get("/subtract")
async def subtract(a: int, b: int):
    return {"result": a - b}

@app.get("/multiply")
async def multiply(a: int, b: int):
    return {"result": a * b}

@app.get("/divide")
async def divide(a: int, b: int):
    if b == 0:
        raise HTTPException(
            status_code=404, detail='Division by 0 not allowed!')
    return {"result": a / b}

if __name__ == '__main__':
    uvicorn.run("app:app", host="0.0.0.0", port=5000, reload=True)


from FACE_VERIFICATION.validation import Verify
from utils.encrypt import Encrypt
from utils.calling import caller
import pickle

obj1 = Verify()
obj2 = Encrypt()
obj3 = caller()

class RUN:
    def __init__(self):
        pass
    def controller(self,data):
        mode = data['mode']
        if mode == "verify":
            response = obj1.verify(frame_count=1,WINDOW=data['image_area'])
            print(response)
            return response
        if mode == "train":
            response = obj1.generate_embeds(frame_count=2,WINDOW=data['image_area'])
            print(response)
            return response
        if mode == "predict":
            response = obj1.verify(frame_count=1,WINDOW=data['image_area'])
            print(response)
            return response

    def encrypt_controller(self,unique_id=None,data=None,mode=None,_id=None):

        if mode == 'Add' or mode == 'Update':
            data = obj2.encrypt_data(unique_id,data)
            return obj3.database_controller(unique_id,data,mode=mode,_id =_id)

        elif mode == "View":
            data = obj3.database_controller(unique_id,data,mode=mode,_id =_id)
            new_data = []
            for key in data.keys():
                new_data = data[key]
                new_data = obj2.decrypt_data(unique_id,new_data)
                data[key] = new_data

            return data

        else:
            return obj3.database_controller(unique_id,data,mode=mode,_id =_id)


def call_repeatmasker(fasta, lib, engine = "ncbi", cores = 1, dir = "./"):

    # RepeatMasker -e ncbi -pa 28 -s
    #    -lib dmel_repbase_lib.fasta
    #    -no_is -nolow
    #    -dir .
    #    dmel-all-chromosome-r6.22.fasta
    import subprocess
    from rwt.checkers import check_installation
    if not (check_installation("RepeatMasker")):
        sys.exit()

    return(subprocess.run(["RepeatMasker",
        "-e " + engine,
        str(cores),
        "-s",
        "-lib " + lib,
        "-no_is",
        "-nolow",
        "-dir " + dir,
        fasta]))

def call_repbase_fixer(ifa, ofa):
    import subprocess
    return(subprocess.run(["Rscript","--vanilla","scripts/format_repbase_fa.R",ifa,ofa]))

def call_fa2gtf(ifai, ogtf):
    import subprocess
    return(subprocess.run(["Rscript","--vanilla", "scripts/fa2gtf.R", ifai, ogtf]))


#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Cube centring, detects bad frames, crops and bins

@author: Iain
"""
__author__ = 'Iain Hammond'
__all__ = ['calib_dataset']

from os import makedirs, system
from os.path import isfile, isdir

import numpy as np
from pyprind import ProgBar
import matplotlib
from matplotlib import pyplot as plt
from hciplot import plot_frames

from vip_hci.config import get_available_memory, time_ini, timing
from vip_hci.fits import open_fits, write_fits
from vip_hci.preproc import cube_recenter_via_speckles, cube_recenter_2dfit, frame_shift, \
    cube_detect_badfr_correlation, cube_crop_frames, cube_subsample, frame_crop
from vip_hci.stats import cube_distance
from vip_hci.var import frame_center

matplotlib.use('Agg')

class calib_dataset:  # this class is for pre-processing of the calibrated data
    def __init__(self, inpath, outpath, dataset_dict, recenter_method, recenter_model, coro=True):
        self.inpath = inpath
        self.outpath = outpath
        self.derot_angles_cropped = open_fits(self.inpath+'derot_angles_cropped.fits', verbose=False)
        self.recenter_method = recenter_method
        self.recenter_model = recenter_model
        self.sci_list = []
        # get all the science cubes into a list
        with open(self.inpath+'sci_list.txt', "r") as f:
            tmp = f.readlines()
            for line in tmp:
                self.sci_list.append(line.split('\n')[0])
        self.sci_list.sort()  # make sure they are in order so derotation doesn't make a mess of the frames
        print(len(self.sci_list), 'science cubes', flush=True)
        # read the dimensions of each science cube from calibration, or get from each fits file
        if isfile(self.inpath+'new_ndit_sci_sky_unsat.fits'):
            print('Using SCI cube dimensions from calibration', flush=True)
            nframes = open_fits(self.inpath+'new_ndit_sci_sky_unsat.fits', verbose=False)
            self.real_ndit_sci = [int(nframes[0])] * len(self.sci_list)
        else:
            self.real_ndit_sci = []
            print('Re-evaluating SCI cube dimensions', flush=True)
            for sc, fits_name in enumerate(self.sci_list):  # enumerate over the list of all science cubes
                tmp = open_fits(self.inpath+'4_sky_subtr_'+fits_name, verbose=False)
                self.real_ndit_sci.append(tmp.shape[0])  # gets length of each cube for later use
                del tmp
        self.dataset_dict = dataset_dict
        self.nproc = dataset_dict['nproc']
        if not isdir(self.outpath):
            makedirs(self.outpath)
        system("cp " + self.inpath + 'master_unsat-stellarpsf_fluxes.fits ' + self.outpath)  # for use later
        system("cp " + self.inpath + 'fwhm.fits ' + self.outpath)  # for use later
        system("cp " + self.inpath + 'master_unsat_psf_norm.fits ' + self.outpath)  # for use later

    def recenter(self, sigfactor=4, subi_size=41, crop_sz=251, verbose=True, debug=False, plot=False, coro=True):
        """
        Centers cropped science images by fitting a double Gaussian (negative+positive) to each median combined SCI cube,
        or by fitting a single negative Gaussian to the coronagraph using the speckle pattern of each median combined SCI cube.

        Parameters:
        ----------
        sigfactor: float, default = 4
            If thresholding is performed during 2gauss fitting, set the threshold in terms of gaussian sigma in the
            subimage (will depend on your cropping size)
        subi_size: int, default = 21
            Size of the square subimage sides in pixels.
        crop_sz: int, optional, in units of pixels. 251 by default
            Crops to this size after recentering for memory management purposes. Useful for very large datasets
        verbose: bool
            To provide extra information about the progress and results of the pipeline
        plot: bool
            If True, a plot of the shifts is saved (PDF)
        coro: bool
            For coronagraph data. False otherwise. Recentering requires coronagraphic data

        Writes fits to file:
        ----------
        x_shifts.fits # writes the x shifts to the file
        y_shifts.fits # writes the y shifts to the file
        {source}_master_cube.fits # makes the recentered master cube
        derot_angles.fits # makes a vector of derotation angles
        """

        if not coro:
            if self.recenter_method != '2dfit':
                raise ValueError('Centering method invalid')
            if self.recenter_model == '2gauss':
                raise ValueError('2Gauss requires coronagraphic data')

        ncubes = len(self.sci_list)

        fwhm_all = open_fits(self.inpath+'fwhm.fits', verbose=debug) # changed this to open the file as sometimes we wont run get_stellar_psf() or it may have already run
        fwhm = fwhm_all[0] # fwhm is the first entry in the file
        fwhm = fwhm.item() # changes from numpy.float32 to regular float so it will work in VIP
        if verbose:
            print('FWHM = {:3f} px'.format(fwhm), flush=True)

        if not subi_size % 2:
            subi_size -= 1
            print('WARNING: Sub image size not odd. Adjusted to {} px'.format(subi_size), flush=True)

        # Creates a master science cube with just the median of each cube
        if not isfile(self.outpath+'median_calib_cube.fits'):
            bar = ProgBar(len(self.sci_list), stream=1, title='Creating master science cube (median of each science cube)....')
            for sc, fits_name in enumerate(self.sci_list):  # enumerate over the list of all science cubes
                tmp = open_fits(self.inpath+'4_sky_subtr_'+fits_name, verbose=debug)  # open cube as tmp
                if sc == 0:
                    _, ny, nx = tmp.shape  # dimensions of cube
                    if subi_size > ny:  # check if bigger than science frame
                        subi_size = ny  # ny should be odd already from calibration
                        print('WARNING: Sub image size larger than frame. Adjusted to {} px'.format(subi_size), flush=True)
                    tmp_tmp = np.zeros([ncubes, ny, ny])  # template cube with the median of each SCI cube
                tmp_tmp[sc] = np.median(tmp, axis=0)  # median frame of cube tmp
                get_available_memory()
                bar.update()
            write_fits(self.outpath+'median_calib_cube.fits', tmp_tmp, verbose=debug)
            if verbose:
                print('Median science cube created for recentering', flush=True)
        else:
            tmp_tmp = open_fits(self.outpath+'median_calib_cube.fits', verbose=debug)
            _, ny, nx = tmp_tmp.shape
            if verbose:
                print('Median science cube for recentering has been read from file', flush=True)

        if self.recenter_method == 'speckle':
            # FOR GAUSSIAN
            print('##### Recentering via speckle pattern #####', flush=True)
            if debug:
                get_available_memory()
            recenter = cube_recenter_via_speckles(tmp_tmp, cube_ref=None, alignment_iter=5, gammaval=1,
                                                  min_spat_freq=0.5, max_spat_freq=3, fwhm=fwhm, debug=debug,
                                                  recenter_median=True, negative=coro, fit_type='gaus', crop=True,
                                                  subframesize=subi_size, imlib='opencv', interpolation='lanczos4',
                                                  plot=plot, full_output=True, nproc=self.nproc)
            sy = recenter[4]
            sx = recenter[3]
        elif self.recenter_method == '2dfit':
            # DOUBLE GAUSSIAN
            print('##### Recentering via 2dfit #####', flush=True)
            if debug:
                get_available_memory()
            params_2g = {'fwhm_neg': 0.8*fwhm, 'fwhm_pos': 2*fwhm, 'theta_neg': 48., 'theta_pos':135., 'neg_amp': 0.8}
            recenter = cube_recenter_2dfit(tmp_tmp, xy=None, fwhm=fwhm, subi_size=subi_size,
                                           model=self.recenter_model, nproc=self.nproc, imlib='opencv',
                                           interpolation='lanczos4', offset=None,
                                           negative=False, threshold=True, sigfactor=sigfactor,
                                           fix_neg=False, params_2g=params_2g,
                                           save_shifts=False, full_output=True, verbose=verbose,
                                           debug=debug, plot=plot)
            sy = recenter[1]
            sx = recenter[2]
        elif self.recenter_method == 'as_observed':
            # uses center found in median of all frames, and applies the same x-y shift to all frames
            print('##### Recentering to median of all frames #####', flush=True)
            subi_size = 9
            tmp_med = np.median(tmp_tmp, axis=0)
            cy, cx = frame_center(tmp_med)
            if plot:
                med_subframe = frame_crop(tmp_med, size=subi_size, cenxy=(cx, cy), verbose=debug)
                plot_frames(med_subframe, vmin=np.percentile(med_subframe, 0.5), vmax=np.percentile(med_subframe, 99.5),
                            label='Median frame for centering', cmap='inferno', dpi=300,
                            save=self.outpath + 'frame_center_as_observed.pdf')
            tmp_med = tmp_med[np.newaxis, :, :]  # make 3D to use in cube_recenter_2dfit
            recenter = cube_recenter_2dfit(tmp_med, full_output=True, xy=(cx, cy), subi_size=subi_size, nproc=self.nproc,
                                           fwhm=fwhm, debug=verbose, negative=coro, plot=plot)
            sy = np.repeat(recenter[1], len(self.sci_list))  # make array of shifts equal to number of science cubes
            sx = np.repeat(recenter[2], len(self.sci_list))
        else:
            raise ValueError("Centering method is not recognised. Use either `speckle', `2dfit' or `as_observed'.")

        if plot:  # save the shift plot
            plt.savefig(self.outpath+'shifts-xy_{}.pdf'.format(self.recenter_method), bbox_inches='tight', pad_inches=0.1)
            plt.close('all')
        del recenter

        if debug:
            get_available_memory()

        # LOAD IN REAL_NDIT_SCI
        # Load original cubes, shift them, and create master cube
        if crop_sz is not None:
            crop = True
            if not crop_sz % 2:
                crop_sz -= 1
                print('Crop size not odd, adapted to {}'.format(crop_sz), flush=True)
            print('Cropping to {} pixels'.format(crop_sz), flush=True)
            tmp_tmp = np.zeros([int(np.sum(self.real_ndit_sci)), crop_sz, crop_sz])
        else:
            tmp_tmp = np.zeros([int(np.sum(self.real_ndit_sci)), ny, nx])

        angles_1dvector = np.zeros([int(np.sum(self.real_ndit_sci))])  # empty array for derot angles, length of number of frames
        if verbose:
            print('Shifting frames and creating master science cube', flush=True)
        for sc, fits_name in enumerate(self.sci_list):
            tmp = open_fits(self.inpath+'4_sky_subtr_'+fits_name, verbose=debug)  # opens science cube
            if crop:
                tmp = cube_crop_frames(tmp, crop_sz, force=False, verbose=debug, full_output=False)
            dim = int(self.real_ndit_sci[sc])  # gets the integer dimensions of this science cube
            for dd in range(dim):  # dd goes from 0 to the largest dimension
                tmp_tmp[int(np.sum(self.real_ndit_sci[:sc]))+dd] = frame_shift(tmp[dd], shift_y=sy[sc], shift_x=sx[sc], imlib='vip-fft')  # this line applies the shifts to all the science images in the cube the loop is currently on. it also converts all cubes to a single long cube by adding the first dd frames, then the next dd frames from the next cube and so on
                angles_1dvector[int(np.sum(self.real_ndit_sci[:sc]))+dd] = self.derot_angles_cropped[sc][dd]  # turn 2d rotation file into a vector here same as for the mastercube above
                # sc*ndit+dd i don't think this line works for variable sized cubes
            if debug:
                get_available_memory()
                print('Science cube number: {}'.format(sc+1), flush=True)

        # write all the shifts
        write_fits(self.outpath+'x_shifts.fits', sx, verbose=debug)  # writes the x shifts to the file
        write_fits(self.outpath+'y_shifts.fits', sy, verbose=debug)  # writes the y shifts to the file
        write_fits(self.outpath+'{}_master_cube.fits'.format(self.dataset_dict['source']), tmp_tmp, verbose=debug)  # makes the master cube
        write_fits(self.outpath+'derot_angles.fits', angles_1dvector, verbose=debug)  # writes the 1D array of derotation angles
        if verbose:
            print('Shifts applied, master cube saved', flush=True)
        del tmp_tmp, sx, sy, angles_1dvector

    def bad_frame_removal(self, pxl_shift_thres=0.5, sub_frame_sz=31, verbose=True, debug=False, plot=True):
        """
        For removing outlier frames often caused by AO errors. To be run after recentering is complete. Takes the
        recentered mastercube and removes frames with a shift greater than a user defined pixel threshold in x or y above
        the median shift. It then takes the median of those cubes and correlates them to the median combined mastercube.
        Removes all those frames below the threshold from the mastercube and rotation file, then saves both as new files
        for use in post processing

        Parameters:
        ----------
        pxl_shift_thres : float, in units of pixels. Default is 0.5 pixels.
            Any shifts in the x or y direction greater than this threshold will cause the frame/s
            to be labelled as bad and thus removed. May required a stricter threshold depending on the dataset
        sub_frame_sz : integer, must be odd. Default is 31.
            This sets the cropping during frame correlation to the median
        debug : bool
            Will show open and save messages for FITS files
        plot : bool
            Will write the correlation plot to file if True, False will not
        """

        if verbose:
            print('######### Beginning bad frame removal #########', flush=True)

        if not sub_frame_sz % 2:
            sub_frame_sz -= 1
            print('WARNING: Bad frame sub image size not odd. Adjusted to {} px'.format(sub_frame_sz), flush=True)

        angle_file = open_fits(self.outpath+'derot_angles.fits', verbose=debug)  # opens the rotation file
        recentered_cube = open_fits(self.outpath+'{}_master_cube.fits'.format(self.dataset_dict['source']), verbose=debug)  # loads the master cube

        # open x shifts file for the respective method
        x_shifts = open_fits(self.outpath+"x_shifts.fits", verbose=debug)
        median_sx = np.median(x_shifts)  # median of x shifts

        # opens y shifts file for the respective method
        y_shifts = open_fits(self.outpath+"y_shifts.fits", verbose=debug)
        median_sy = np.median(y_shifts)  # median of y shifts

        # self.ndit came from the z dimension of the first calibrated science cube above in recentering
        # x_shifts_long = np.zeros([len(self.sci_list)*self.ndit]) # list with number of cubes times number of frames in each cube as the length
        # y_shifts_long = np.zeros([len(self.sci_list)*self.ndit])

        # long are shifts to be applied to each frame in each cube
        x_shifts_long = np.zeros([int(np.sum(self.real_ndit_sci))])
        y_shifts_long = np.zeros([int(np.sum(self.real_ndit_sci))])

        for i in range(len(self.sci_list)):  # from 0 to the length of sci_list
            ndit = self.real_ndit_sci[i]  # gets the dimensions of the cube
            x_shifts_long[i*ndit:(i+1)*ndit] = x_shifts[i]  # sets the average shifts of all frames in that cube
            y_shifts_long[i*ndit:(i+1)*ndit] = y_shifts[i]

        write_fits(self.outpath+'x_shifts_long.fits', x_shifts_long, verbose=debug)  # saves shifts to file
        write_fits(self.outpath+'y_shifts_long.fits', y_shifts_long, verbose=debug)
        x_shifts = x_shifts_long
        y_shifts = y_shifts_long

        if verbose:
            print("x shift median:", median_sx)
            print("y shift median:", median_sy, flush=True)

        bad = []
        good = []

        i = 0
        shifts = list(zip(x_shifts, y_shifts))
        bar = ProgBar(len(x_shifts), stream=1, title='Running pixel shift check...')
        for sx, sy in shifts:  # iterate over the shifts to find any greater or less than pxl_shift_thres pixels from median
            if abs(sx) < ((abs(median_sx)) + pxl_shift_thres) and abs(sx) > ((abs(median_sx)) - pxl_shift_thres) and abs(sy) < ((abs(median_sy)) + pxl_shift_thres) and abs(sy) > ((abs(median_sy)) - pxl_shift_thres):
                good.append(i)
            else:
                bad.append(i)
            i += 1
            bar.update()

        # only keeps the files that weren't shifted above the threshold
        frames_pxl_threshold = recentered_cube[good]
        # only keeps the corresponding derotation entry for the frames that were kept
        angle_pxl_threshold = angle_file[good]
        del recentered_cube, angle_file

        if verbose:
            print('Frames within pixel shift threshold:', len(frames_pxl_threshold))
            print('########### Median combining {} frames for correlation check... ###########'.format(
                len(frames_pxl_threshold)), flush=True)

        # makes array of good frames from the recentered mastercube
        subarray = cube_crop_frames(frames_pxl_threshold, size=sub_frame_sz, verbose=verbose)  # crops all the frames to a common size
        frame_ref = np.nanmedian(subarray, axis=0)  # median frame of remaining cropped frames, can be sped up with multi-processing

        if verbose:
            print('Running frame correlation check...', flush=True)

        # calculates correlation threshold using the median of the Pearson correlation of all frames, minus 1 standard deviation

        # frame_ref = frame_crop(tmp_median, size = sub_frame_sz, verbose=verbose) # crops the median of all frames to a common size
        distances = cube_distance(subarray, frame_ref, mode='full', dist='pearson', plot=plot)  # calculates the correlation of each frame to the median and saves as a list
        if plot:  # save a plot of distances compared to the median for each frame if set to 'save'
            plt.savefig(self.outpath+'distances.pdf', format='pdf', bbox_inches='tight', pad_inches=0.1)
            plt.close('all')
        correlation_thres = np.median(distances) - np.std(distances)  # threshold is the median of the distances minus one stddev

        good_frames, bad_frames = cube_detect_badfr_correlation(subarray, frame_ref=frame_ref, dist='pearson',
                                                                threshold=correlation_thres, plot=plot, verbose=verbose)
        if plot:
            plt.savefig(self.outpath+'frame_correlation.pdf', format='pdf', bbox_inches='tight', pad_inches=0.1)
            plt.close('all')

        # only keeps the files that were above the correlation threshold
        frames_threshold = frames_pxl_threshold[good_frames]
        del frames_pxl_threshold
        if verbose:
            print('Frames within correlation threshold:', len(frames_threshold), flush=True)
        # only keeps the derotation entries for the good frames above the correlation threshold
        angle_threshold = angle_pxl_threshold[good_frames]

        # saves the good frames to a new file, and saves the derotation angles to a new file
        write_fits(self.outpath+'{}_master_cube.fits'.format(self.dataset_dict['source']), frames_threshold,
                   verbose=debug)
        write_fits(self.outpath+'derot_angles.fits', angle_threshold, verbose=debug)
        if verbose:
            print('Saved good frames and their respective rotations to file', flush=True)
        del frames_threshold

    def crop_cube(self, arcsecond_diameter=3, verbose=True, debug=False):
        """
        Crops frames in the master cube after recentering and bad frame removal. Recommended for post-processing ie.
        PCA in concentric annuli. If the provided arcsecond diameter happens to be larger than the cropping provided in
        recentering, no cropping will occur.

        Parameters
        ----------
        arcsecond_diameter : float or int
            Size of the frames diameter in arcseconds. Default of 3" for NaCO corresponds to 111x111 (x,y) pixel frames.
            Note this is a diameter, not a radius.
        verbose : bool optional
            If True extra messages of completion are shown.
        debug : bool
            Prints extra information during cropping, and when FITS are opened or saved.

        Writes to FITS file
        -------
        cropped cube : numpy ndarray
            Cube with cropped frames
        """
        if not isfile(self.outpath+'{}_master_cube.fits'.format(self.dataset_dict['source'])):
            raise NameError('Missing master cube from recentering and bad frame removal!')

        master_cube = open_fits(self.outpath+'{}_master_cube.fits'.format(self.dataset_dict['source']),
                                verbose=debug)
        _, ny, _ = master_cube.shape
        crop_size = int(np.ceil(arcsecond_diameter / self.dataset_dict['pixel_scale']))  # rounds up

        if not crop_size % 2:
            crop_size += 1
            print('Crop size not odd, increased to {}'.format(crop_size), flush=True)
        if debug:
            print('Input crop size is {} pixels'.format(crop_size), flush=True)

        if crop_size >= ny:
            print('Crop size is larger than the frame size. Skipping cropping...', flush=True)

        else:
            if verbose:
                print('######### Running frame cropping #########', flush=True)
                start_time = time_ini(verbose=False)
            master_cube = cube_crop_frames(master_cube, crop_size, force=False, verbose=debug, full_output=False)
            if verbose:
                timing(start_time)
                print('Cropping complete', flush=True)
            write_fits(self.outpath + '{}_master_cube.fits'.format(self.dataset_dict['source']), master_cube,
                       verbose=debug)
        del master_cube

    def median_binning(self, binning_factor=10, verbose=True, debug=False):
        """
        Median combines the frames within the master science cube as per the binning factor, and makes the necessary
        changes to the derotation file. Temporal sub-sampling of data is useful to significantly reduce
        post-processing computation time, however we risk using a temporal window that equates to the decorrelation
        rate of the PSF. This is generally noticeable for separations beyond 0.5"

        Parameters:
        ----------
        binning_factor: int, default = 10
            Defines how many frames to median combine
        verbose : bool
            Whether to print completion, timing and binning information
        debug : bool
            Prints when FITS files are opened and saved

        Writes to FITS file:
        ----------
        the binned master cube
        the binned derotation angles
        """

        if not isinstance(binning_factor, int) and not isinstance(binning_factor, list) and \
                not isinstance(binning_factor, tuple):  # if it isn't int, tuple or list then raise an error
            raise TypeError('Invalid binning_factor! Use either int, list or tuple')

        if not isfile(self.outpath+'{}_master_cube.fits'.format(self.dataset_dict['source'])):
            raise NameError('Missing master cube from recentering and bad frame removal!')

        if not isfile(self.outpath+'derot_angles.fits'):
            raise NameError('Missing derotation angles files from recentering and bad frame removal!')

        bin_fac = int(binning_factor)  # ensure integer
        if bin_fac != 1 and bin_fac != 0:
            master_cube = open_fits(self.outpath + '{}_master_cube.fits'.format(self.dataset_dict['source']),
                                    verbose=debug)
            derot_angles = open_fits(self.outpath + 'derot_angles.fits', verbose=debug)
            if verbose:
                start_time = time_ini(verbose=False)
            cube_bin, derot_angles_bin = cube_subsample(master_cube, n=bin_fac, mode="median", parallactic=derot_angles,
                                                        verbose=verbose)
            if verbose:
                timing(start_time)  # prints how long median binning took
            write_fits(self.outpath+'{}_master_cube.fits'.format(self.dataset_dict['source']), cube_bin,
                       verbose=debug)
            write_fits(self.outpath+'derot_angles.fits', derot_angles_bin, verbose=debug)
            del master_cube, derot_angles, cube_bin, derot_angles_bin
        else:
            print('Binning factor is {}, skipping binning...'.format(binning_factor), flush=True)


from selenium import webdriver
import time, re, urllib, requests

from telethon.sync import TelegramClient
from config import api_id, api_hash

client = TelegramClient('name', api_id, api_hash)

client.start()

dlgs = client.get_dialogs()

tegmo = None

for dlg in dlgs:
    if dlg.title == "LTC Click Bot":
        tegmo = dlg

if tegmo == None:
    print("Отсутствует чат с ботом")
    exit()

print(tegmo.title)

# dr_options = webdriver.FirefoxOptions()
# dr_options.set_headless()
# driver = webdriver.Firefox(options=dr_options)

from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--log-level=3')
driver = webdriver.Chrome(chrome_options=chrome_options)

tmp_url = ''
n = 0
nn = 0
links = True
links2 = True
try:
    while True:
        msg = client.get_messages(tegmo, limit=1)[0]

        if re.search(r'\bThere is a new site for you to\b', msg.message):
            client.send_message(  tegmo , "🖥 Visit sites")

        if re.search(r'\bPlease stay on the site for at least 10 seconds\b', msg.message):
            time.sleep(10)
            continue

        if re.search(r'\bSorry\b', msg.message):
            time.sleep(10)
            nn = nn + 1
            print('Закончились ссылки ждем','.'*nn,  end='\r')
            client.send_message(  tegmo , "🖥 Visit sites")
            continue

        if re.search(r'\bPress the "Visit website" button to earn LTC\b', msg.message):
            nn = 0
            url = msg.reply_markup.rows[0].buttons[0].url
            if tmp_url == url:
                nn = nn + 1

                print("ссыдка с задежкой", '.'*nn , end='\r')
                time.sleep(5)

                t_el = driver.find_elements_by_class_name('timer')
                text = ''
                for i in t_el:
                    if (len(i.text) > 0):
                        text = i.text
                        i.click()
                print(text)

                if ''.join(text) == '':
                    client.send_message(  tegmo , "🖥 Visit sites")

                links2 = False
                continue
            links = True
            print("переходим по ссылке", url)
            driver.get(url)

            n = n + 1
            print("проходов ",n)

            tmp_url = url
            time.sleep(2)

except Exception as ex:
    print(ex)
finally:
    driver.close()


from multiprocessing import context
from django.shortcuts import render, redirect
from .models import *

# Create your views here.
def produk_list(request):
    template_name = "produk_list.html"
    group_produk = Circle_produk.objects.all()
    context ={
        "produk" : group_produk,
    }
    return render(request, template_name, context)

def tambah_barang(request):
    template_name = "add_barang.html"
    kategori = Kategori.objects.all()
    if request.method == "POST":
        input_nama = request.POST.get('nama')
        input_jumlah = request.POST.get('jumlah')
        input_deskripsi = request.POST.get('deskripsi')
        input_kategori = request.POST.get('kategori')

        get_kategori = Kategori.objects.get(nama=input_kategori)

        Circle_produk.objects.create(
            nama = input_nama,
            jumlah = input_jumlah,
            deskripsi = input_deskripsi,
            kategori = get_kategori
        )
        return redirect(produk_list)
    context ={
        "kategori": kategori
    }

    return render(request, template_name, context)

def update_barang(request,id):
    template_name = "add_barang.html"
    kategori = Kategori.objects.all()
    get_produk = Circle_produk.objects.get(id=id)
    if request.method == "POST":
        input_nama = request.POST.get('nama')
        input_jumlah = request.POST.get('jumlah')
        input_deskripsi = request.POST.get('deskripsi')
        input_kategori = request.POST.get('kategori')

        get_kategori = Kategori.objects.get(nama=input_kategori)
        get_produk.nama = input_nama
        get_produk.jumlah = input_jumlah
        get_produk.deskripsi = input_deskripsi
        get_produk.kategori = get_kategori
        get_produk.save()
        return redirect(produk_list)

    context ={
        "kategori": kategori,
        "get_produk" : get_produk
    }

    return render(request, template_name, context)

def delete_barang(request, id):
    Circle_produk.objects.get(id=id).delete()
    return redirect(produk_list)


from django.contrib.auth.decorators import user_passes_test, login_required
from django.http import HttpResponse, HttpResponseRedirect
from django.http import JsonResponse
from django.shortcuts import render, redirect
from apps.rfid.models import GeneralAssembly
from hybridjango.utils import group_test

class Ballot:
    nr = 0
    title = 'Avstemning'
    choices = [
        'Blank',
        'Vevkom',
        'Bedkom',
        'Arrkom',
        'Jentekom',
        'Redaksjonen',
    ]
    only_members = True
    empty_votes = True
    is_attending = True
    has_voted = []
    votes = []
    active = True

class Suggestion:
    num = 0
    author = "Ikke vevsjef"
    suggestion_text = "Vevkom burde ta over styret"
    suggestions_enabled = False

empty_vote = 'Tomt'
suggestion_list = []

@user_passes_test(group_test("Tellekorps"))
def overview(request):
    user = request.user
    if request.method == 'POST':
        if 'ballot_form' in request.POST:
            Ballot.title = request.POST.get('title', 'Avstemning')
            Ballot.only_members = True if request.POST.get('membersOnly') else False
            Ballot.empty_votes = True if request.POST.get('empty_votes') else False
            Ballot.is_attending = True if request.POST.get('is_attending') else False
            Ballot.choices = [v for k, v in request.POST.items() if k.startswith('choice-')]
            Ballot.votes = []
            Ballot.has_voted = []
            Ballot.nr += 1
        return HttpResponseRedirect('#')
    elif 'active' in request.GET:
        Ballot.active = not (request.GET['active'] == 'Deaktiver')
    return render(
        request, 'ballot/overview.html', context={
            'active': Ballot.active,
            },
        )

@user_passes_test(group_test("Nestleder"))
def suggestion_overview(request):
    user = request.user
    if request.method == 'POST':
        if 'toggle_suggestions' in request.POST:
            Suggestion.suggestions_enabled = not Suggestion.suggestions_enabled
        elif 'clear_suggestions' in request.POST:
            del suggestion_list[:]
        return HttpResponseRedirect("#")

    return render(request, 'ballot/suggestions.html', context={
            'suggestions_enabled' : Suggestion.suggestions_enabled
    })

@login_required
def post_suggestion(request):
    sugg = Suggestion()
    sugg.num += 1
    sugg.author = request.user
    sugg.suggestion_text = request.POST.get('suggestion_text')
    suggestion_list.append(sugg)

@user_passes_test(group_test("Nestleder"))
def get_suggestions(request):
    json_list = [{
        "author_name" : suggestion.author.full_name,
        "suggestion_text" : suggestion.suggestion_text,
    } for suggestion in suggestion_list]
    return JsonResponse({"suggestion_list" : json_list})

@login_required
def ballot(request):
    return render(request, 'ballot/voteview.html', get_ballot_dict(request.user))

@login_required
def get_choices(request):
    return JsonResponse(get_ballot_dict(request.user))

def get_ballot_dict(user):
    choices = Ballot.choices.copy()
    if Ballot.empty_votes:
        choices.append(empty_vote)
    return {
        'nr': Ballot.nr,
        'title': Ballot.title,
        'choices': choices,
        'has_voted': user.pk in Ballot.has_voted,
        'active': Ballot.active,
        'suggestions_enabled' : Suggestion.suggestions_enabled,
    }

def vote(request):
    if request.method == 'POST':
        user = request.user
        generalassembly = GeneralAssembly.objects.all().last() #fetches the newest made generalassembly object

        if not user.is_authenticated:
            return HttpResponse("Du må være innlogget for å stemme")
        if not Ballot.active:
            return HttpResponse("Avstemningen er ikke aktiv")
        if user.pk < 2:
            return HttpResponse("Linjeforeningen Hybrida kan ikke stemme selv")
        if Ballot.only_members and not user.member:
            return HttpResponse("Kun medlemmer kan stemme")
        if Ballot.is_attending and user not in generalassembly.users.all():
            return HttpResponse("Du må registrere oppmøte for å kunne stemme")
        if user.pk in Ballot.has_voted:
            return HttpResponse("Du har allerede stemt")

        new_vote = request.POST.get("choice", None)
        if new_vote in Ballot.choices or (Ballot.empty_votes and new_vote == empty_vote):
            Ballot.has_voted.append(user.pk)
            Ballot.votes.append(new_vote)
            return HttpResponse("Du stemte på {}.".format(new_vote))

    return HttpResponse("Du avga ingen stemme")

@user_passes_test(group_test("Tellekorps"))
def get_results(request):
    user = request.user
    if not (user.is_authenticated and group_test("Tellekorps")):
        return JsonResponse(
            {"title": "Hvem er best?", "results": [{"name": "vevkom", "votes": 9001}, {"name": "andre", "votes": 0}],
             "total": 9001, "total_nonblank": 9001})
    results = [{'name': choice, 'votes': Ballot.votes.count(choice)} for choice in Ballot.choices]
    total_nonblank = total = len(Ballot.votes)
    if Ballot.empty_votes:
        results.append({'name': empty_vote, 'votes': Ballot.votes.count(empty_vote)})
        total_nonblank -= Ballot.votes.count(empty_vote)
    return JsonResponse({'title': Ballot.title, 'results': results, 'total': total, 'total_nonblank': total_nonblank})


import os

def nystudent():

    funnet=False

    nyregistrering=True
    while nyregistrering==True:

        print()
        print('Du har valgt å registrere ny student.')
        print()

        inndata = input('Skriv inn studentnummer: ')

        #åpne studentfilen
        studentfil=open('student.txt', 'r')
        #Lese første
        studentnummer=studentfil.readline()

        #løkke for å finne studentnr
        while studentnummer!='':
            studentnummer=studentnummer.rstrip('\n')
            fornavn=studentfil.readline().rstrip('\n')
            etternavn=studentfil.readline().rstrip('\n')
            studium=studentfil.readline().rstrip('\n')

            #Hvis student allerede er registrert
            if studentnummer == inndata:
                funnet=True
                print()
                print('Denne studenten er allerede registrert')
                print()

            #Leser neste
            studentnummer=studentfil.readline()

        studentfil.close()

        if not funnet:
            #Begynne registreringsprosessen

            print('Vennligst fyll inn informasjon om studenten')
            fornavn=input('Skriv inn fornavn: ')
            etternavn=input('Skriv inn etternavn: ')
            studie=input('Skriv inn studie: ')

            #åpne fil i append
            studentfil=open('student.txt', 'a')

            #Skriv inn i fil
            studentfil.write(str(inndata) + '\n')
            studentfil.write(fornavn + '\n')
            studentfil.write(etternavn + '\n')
            studentfil.write(studie + '\n')

            studentfil.close()
            print('Studenten er nå registrert.')

        valg=input('Ønsker du å gjøre en ny registrering? ja/nei ')
        if valg=='ja':
            nyregistrering=True
        if valg=='nei':
            nyregistrering=False

def slettstudent():

    funnet=False

    nysletting=True
    while nysletting==True:

        print()
        print('Du har valgt å slette student.')
        print()

        inndata=input('Skriv inn studentnummer: ')
        #Sjekker om studenten er i eksamensfilen

        eksamensfil=open('eksamensresultat.txt', 'r')

        #Leser første linje i eksamensfil

        fagkode=eksamensfil.readline()

        while fagkode!='':
            fagkode=fagkode.rstrip('\n')
            studentnummer=eksamensfil.readline().rstrip('\n')
            karakter=eksamensfil.readline().rstrip('\n')

            if studentnummer == inndata:
                funnet=True

            #Leser neste post

            fagkode=eksamensfil.readline()

        if studentnummer==inndata:
            print()
            print('Kan ikke utføre sletting')
            print('Studenten har én eller flere eksamenskarakterer registrert.')
            print('Dette gjør at studenten ikke kan slettes.')
            print()

            #Betingelse for sletting av student

        eksamensfil.close()

        if not funnet:

            studentfil=open('student.txt' , 'a')
            temp_fil=open('temp_fil.txt', 'w')

            studentnummer=studentfil.readline()

            while studentnummer!='':
                studentnummer=studentnummer.rstrip('\n')
                fornavn=studentfil.readline().rstrip('\n')
                etternavn=studentfil.readline().rstrip('\n')
                studium=studentfil.readline().rstrip('\n')

                if studentnummer!= inndata:
                    temp_fil.write(studentnummer + '\n')
                    temp_fil.write(fornavn + '\n')
                    temp_fil.write(etternavn + '\n')
                    temp_fil.write(studium + '\n')

                if studentnummer == inndata:
                    funnet=True

                studentnummer=studentfil.readline()

            studentfil.close()
            temp_fil.close()

            os.remove('student.txt')
            os.rename('temp_fil.txt','student.txt')

            print('Studenten er slettet')

        valg=input('Ønsker du å gjøre en ny sletting? ja/nei ')
        if valg=='ja':
            nysletting=True
        if valg=='nei':
            nysletting=False

def karakterutskrift():

    funnet=False

    nysletting=True
    while nysletting==True:

            print()
            print('Du har valgt å skrive ut karakterutskrift.')
            print()

            inndata=input('Skriv inn studentnummer: ')

            eksamensfil=open('eksamensresultat.txt', 'r')

            fagkode=eksamensfil.readline()

            while fagkode!='':
                fagkode=fagkode.rstrip('\n')
                studentnummer=eksamensfil.readline().rstrip('\n')
                karakter=eksamensfil.readline().rstrip('\n')

                if studentnummer == inndata:
                    print(studentnummer, fagkode, karakter)
                    funnet=True

                fagkode=eksamensfil.readline()

            eksamensfil.close()

            if not funnet:
                print('Du har skrevet et ugyldig studentnummer')

            if funnet:

                studentfil=open('student.txt' , 'r')

                studentnummer=studentfil.readline()

                while studentnummer!='':
                    studentnummer=studentnummer.rstrip('\n')
                    fornavn=studentfil.readline().rstrip('\n')
                    etternavn=studentfil.readline().rstrip('\n')
                    studium=studentfil.readline().rstrip('\n')

                    if studentnummer == inndata:
                        funnet=True
                        print(fornavn, etternavn, studium)

                    studentnummer=studentfil.readline()

                studentfil.close()

                emnefil=open('emne.txt', 'r')

                emnekode=emnefil.readline()

                while emnekode !='':
                    emnekode=emnekode.rstrip('\n')
                    fag=emnefil.readline().rstrip('\n')

                    if emnekode == fagkode:
                        funnet=True
                        print(fag)

                    emnekode=emnefil.readline()

                emnefil.close()

            valg=input('Ønsker du å gjøre en ny utskrift? ja/nei ')
            if valg=='ja':
                nysletting=True
            if valg=='nei':
                nysletting=False

def main():

    meny=True
    while meny==True:
        print()
        print('HOVEDMENY')
        print('-----------------------------------------------------------')
        print('1 - Legg til ny student')
        print('2 - Slett student')
        print('3 - Skriv ut karakterliste')
        print()
        print('4 - Avslutt prgrammet')
        print('-----------------------------------------------------------')
        print()

        print('Hva ønsker du å gjøre?')
        valg=int(input('Tast 1 , 2 , 3 eller 4 : '))
        if valg==1:
            nystudent()
        elif valg==2:
            slettstudent()
        elif valg==3:
            karakterutskrift()
        elif valg==4:
            meny=False
            print()
            print('Du har valgt å avslutte programmet ')
            print('Programmet avsluttes')

        else:
            print('Du har tastet et ugyldig nummer')
            print()

main()


# First Solution
import sys
input = sys.stdin.readline

def Solution():
    N = int(input().rstrip())
    M = int(input().rstrip())
    S = input().rstrip()

    cnt, ans, i = 0, 0, 0

    while i < M - 2:
        if S[i:(i+3)] == "IOI":
            cnt += 1
            if cnt == N:
                cnt -= 1
                ans += 1
            i += 2   # 한칸씩 볼 필요 X
        else:
            cnt = 0
            i += 1

    print(ans)

Solution()

# -------------------------------
# More advanced solution
# 정규표현식 모듈 이용
import re

n = int(input())
_ = input()
string = input()

ioi = re.findall('I(?:OI)+', string) #I(OI)*반복 이 들어간 문자열들 추출
count = 0

for k in ioi:
	c = len(k) // 2 - n + 1
	if c > 0:
		count += c

print(count)


from PyQt4.QtCore import pyqtSignal
from PyQt4.QtGui import QCursor, QPixmap, QColor
from qgis.core import (QgsPoint, QgsRectangle, QgsTolerance,
                       QgsFeatureRequest, QgsFeature, QgsGeometry,
                       QgsVectorLayer, QGis)
from qgis.gui import QgsMapTool, QgsRubberBand

class InspectionTool(QgsMapTool):
    """
        Inspection tool which copies the feature to a new layer
        and copies selected data from the underlying feature.
    """

    finished = pyqtSignal(QgsVectorLayer, QgsFeature)

    def __init__(self, canvas, layerfrom, layerto, mapping):
        """
            mapping - A dict of field - field mapping with values to
                            copy to the new layer
        """
        QgsMapTool.__init__(self, canvas)
        self.layerfrom = layerfrom
        self.layerto = layerto
        self.fields = mapping
        self.band = QgsRubberBand(canvas, QGis.Polygon )
        self.band.setColor(QColor.fromRgb(255,0,0, 65))
        self.band.setWidth(5)

        self.cursor = QCursor(QPixmap(["16 16 3 1",
            "      c None",
            ".     c #FF0000",
            "+     c #FFFFFF",
            "                ",
            "       +.+      ",
            "      ++.++     ",
            "     +.....+    ",
            "    +.     .+   ",
            "   +.   .   .+  ",
            "  +.    .    .+ ",
            " ++.    .    .++",
            " ... ...+... ...",
            " ++.    .    .++",
            "  +.    .    .+ ",
            "   +.   .   .+  ",
            "   ++.     .+   ",
            "    ++.....+    ",
            "      ++.++     ",
            "       +.+      "]))

    def clearBand(self):
        self.band.reset()

    def canvasReleaseEvent(self, event):
        searchRadius = (QgsTolerance.toleranceInMapUnits( 5, self.layerfrom,
                                                           self.canvas().mapRenderer(), QgsTolerance.Pixels))

        point = self.toMapCoordinates(event.pos())

        rect = QgsRectangle()
        rect.setXMinimum(point.x() - searchRadius)
        rect.setXMaximum(point.x() + searchRadius)
        rect.setYMinimum(point.y() - searchRadius)
        rect.setYMaximum(point.y() + searchRadius)

        rq = QgsFeatureRequest().setFilterRect(rect)

        # Look for an existing feature first. If there is one
        # then we emit that back to qmap.
        try:
            feature = self.layerto.getFeatures(rq).next()
            self.band.setToGeometry(feature.geometry(), self.layerto)
            self.finished.emit(self.layerto, feature)
            return
        except StopIteration:
            pass

        try:
            # Only supports the first feature
            # TODO build picker to select which feature to inspect
            feature = self.layerfrom.getFeatures(rq).next()
            self.band.setToGeometry(feature.geometry(), self.layerfrom)

            fields = self.layerto.pendingFields()
            newfeature = QgsFeature(fields)
            newfeature.setGeometry(QgsGeometry(feature.geometry()))

            #Set the default values
            for indx in xrange(fields.count()):
                newfeature[indx] = self.layerto.dataProvider().defaultValue( indx )

            # Assign the old values to the new feature
            for fieldfrom, fieldto in self.fields.iteritems():
                newfeature[fieldto] = feature[fieldfrom]

            self.finished.emit(self.layerto, newfeature)
        except StopIteration:
            pass

    def activate(self):
        """
        Set the tool as the active tool in the canvas.

        @note: Should be moved out into qmap.py
               and just expose a cursor to be used
        """
        self.canvas().setCursor(self.cursor)

    def deactivate(self):
        """
        Deactive the tool.
        """
        pass

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True


#!/usr/bin/env python3

import argparse
import os
import re
import subprocess
import sys

LOG_FILE_OPTION = 'log_file'
OUTPUT_PATH_OPTION = '--output-path'
ONLY_FAILED_OPTION = '--only-failed'
HUMAN_READABLE_OPTION = '--human-readable'
USE_RUBY_PARSER_OPTION = '--use-ruby'
FIND_COREDUMPS_OPTION = "--find-coredumps"
WRITE_RESULTS_TO_DATABASE_OPTION = "--write-to-database"
HELP_OPTION = '--help'

options = argparse.ArgumentParser(description="CTest parser usage:")
options.add_argument(LOG_FILE_OPTION, help="CTEST LOG FILE PATH")
options.add_argument("-f", ONLY_FAILED_OPTION, action="store_true", help="PARSE ONLY FAILED TESTS")
options.add_argument("-r", HUMAN_READABLE_OPTION, action="store_true", help="HUMAN READABLE OUTPUT")
options.add_argument("-o", OUTPUT_PATH_OPTION, metavar="output_path", help="OUTPUT DIRECTORY PATH")
options.add_argument("-u", USE_RUBY_PARSER_OPTION, action="store_true", help="USE OLD RUBY PARSER")
options.add_argument("-c", FIND_COREDUMPS_OPTION, choices=["url", "files"], help="FIND AND STORE COREDUMPS")
options.add_argument("-w", WRITE_RESULTS_TO_DATABASE_OPTION, action="store_true", help="WRITE TEST RESULTS TO DATABASE")

parserRoot = os.path.dirname(os.path.abspath(__file__))

def parseCtestRuby(opts, path):
    command = [
        "{}/ruby-scripts/parse_ctest_log.rb".format(parserRoot),
        "-l", opts.log_file,
        "-o", "{}/ruby/results".format(path),
        "-j", "{}/ruby/json".format(path),
        "-s", "{}/ruby/ctest_sublogs".format(path)
    ]
    if opts.human_readable:
        command.append("-r")
    if opts.only_failed:
        command.append("-f")
    return subprocess.check_output(command)

def parseCtestPython(opts, path):
    command = [
        "{}/python-scripts/parse_ctest_log.py".format(parserRoot),
        opts.log_file,
        "-o", "{}/python/results".format(path),
        "-j", "{}/python/json".format(path),
        "-s", "{}/python/ctest_sublogs".format(path)
    ]
    if opts.human_readable:
        command.append("-r")
    if opts.only_failed:
        command.append("-f")
    return subprocess.check_output(command)

def storeCoredumpsRuby(opts, buildId, path):
    command = [
        "{}/ruby-scripts/coredump_finder.sh".format(parserRoot),
        buildId,
        opts.find_coredumps
    ]
    coredumps = subprocess.check_output(command)
    writeCoredumpsToFile("{}/ruby/coredump".format(path), coredumps)

def storeCoredumpsPython(opts, buildId, path):
    command = [
        "{}/python-scripts/coredump_finder.py".format(parserRoot),
        buildId,
        opts.find_coredumps
    ]
    coredumps = subprocess.check_output(command)
    writeCoredumpsToFile("{}/python/coredump".format(path), coredumps)

def getLogsDir(output):
    return re.search(b'(Logs dir: |"logs_dir": ")(\w+-\d+)', output).group(2)

def writeCoredumpsToFile(path, coredumps):
    file = open(path, "w")
    file.write("COREDUMPS \\\n")
    file.writelines(coredumps)
    file.close()

def writeToDatabaseRuby(opts, path):
    command = [
        "{}/ruby-scripts/write_build_results.rb".format(parserRoot),
        "-f", "{}/ruby/json".format(path)
    ]
    return subprocess.check_output(command)

def writeToDatabasePython(opts, path):
    command = [
        "{}/python-scripts/write_build_results.py".format(parserRoot),
        "{}/python/json".format(path)
    ]
    return subprocess.check_output(command)

def main(args=None):
    opts = options.parse_args(args=args)
    path = os.path.dirname(os.path.abspath(opts.log_file))
    if opts.output_path:
        path = opts.output_path

    if opts.use_ruby:
        result = parseCtestRuby(opts, path)
        if opts.find_coredumps:
            storeCoredumpsRuby(opts, getLogsDir(result), path)
        if opts.write_to_database:
            writeToDatabaseRuby(opts, path)
    else:
        result = parseCtestPython(opts, path)
        if opts.find_coredumps:
            storeCoredumpsPython(opts, getLogsDir(result), path)
        if opts.write_to_database:
            writeToDatabasePython(opts, path)

if os.path.samefile(__file__, sys.argv[0]):
    main()


# 1. Check if the root is empty, hence if the tree is empty.
# 2. We are going to use queues to solve this problem as the queue FIFO property works well here.
# 3. Initialize a queue to hold the current root node
# 4. level is going to be an empty list/queue which we use to add in all the nodes at the particular level in the tree
# 5. next queue is going to hold the nodes in the NEXT level of the binary tree
# 6. result will store our nested list representation of the level order of the tree
# * The main idea is that starting off with the root, we loop thorugh all the nodes level by level, we add the nodes at each respective level to the level queue and we add their children to the next queue
# * After the end of each loop we transfer the nodes at the respective level into our results queue, we now want to look at the next level in the tree, hence we assign our queue to point to the next_queue variable which holds the next level nodes.
# * We empty the next_queue variable and level queues and repeat this same process until there are no more nodes left to visit.
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
def levelOrder(root):
    #      3
    #     / \
    #    9  20
    #      /  \
    #    15    7
    # q = [3]; level = [3]; next_q = [9, 20]; result =[]
    if not root: return []
    queue = [root]
    level = []
    next_queue = []
    result = []
    while queue:
        for root in queue:
            level.append(root.val)
            if root.left:
                next_queue.append(root.left)
            if root.right:
                next_queue.append(root.right)
        result.append(level)
        queue = next_queue
        next_queue = []
        level = []
    return result


from tianshou.data import Batch, ReplayBuffer, to_numpy, to_torch, to_torch_as
import stable_baselines3.common.logger as L
import functools
import gym
import numpy as np
from torch.nn import functional as F
from einops.layers.torch import Rearrange
from encoder import *
import einops

class RNEncoder(nn.Module):
  def __init__(self, obs_space, act_space, cfg):
    super().__init__()
    self.cfg = cfg
    obs_space = gym.spaces.Box(low=-1, high=1000, shape=cfg.obs_shape)
    self.enc = ImpalaEncoder(obs_space, channels=cfg.filters, flatten=False)
    c, h, w = self.enc.final_shape
    self.pred_z_cat = create_mlp(cfg.filters[-1], cfg.obj_cat_num, [cfg.filters[-1]], return_seq=True)
    self.output_shape = (h, w, c + cfg.obj_cat_num)
  def split_obs(self, o):
    shape = o.shape
    obs_shape = self.cfg.obs_shape
    mask_shape = (8, 8, self.cfg.obj_cat_num)
    obs = o[...,:np.prod(obs_shape)].reshape(*shape[:-1], *obs_shape)
    mask = o[...,np.prod(obs_shape):].reshape(*shape[:-1], *mask_shape)
    return obs, mask.detach()
  def forward(self, x, ret_latent=False):
    if isinstance(x, dict):
      x = x['obs']
    obs, obj_cat = self.split_obs(x)

    out0 = self.enc(obs).permute(0,2,3,1) # (h, w, c)
    out = torch.cat([out0, obj_cat], dim=-1)
    if ret_latent:
      return out, out0
    else:
      return out
  def enc_loss(self, b, latent=None):
    if self.cfg.enc_coeff <= 0:
      pred_loss = torch.Tensor([0]).to(b.obs.device).sum()
    else:
      obs, obj_cat = self.split_obs(b.obs)
      if latent is None:
        latent = self.enc(obs)
      pred_z_cat = self.pred_z_cat(latent)
      pred_z_cat_loss = -(F.log_softmax(pred_z_cat, dim=-1) * obj_cat).sum(-1)
      pred_z_cat_loss = (pred_z_cat_loss).sum([1,2]).mean()
      L.record_mean('encoder/pred_loss', pred_z_cat_loss.item())
      pred_loss = self.cfg.enc_coeff * pred_z_cat_loss
    return pred_loss

class AddSInfo(nn.Module):
  def __init__(self, h, w, c, cout=32, channel_first=False, use_mlp=True):
    super().__init__()
    identity = torch.tensor([[[1.0, 0.0, 1.0], [0.0, 1.0, 1.0]]], dtype=torch.float32)
    grid = F.affine_grid(identity, [1, 1, h, w])
    grid = grid.permute(0, 3, 1, 2).contiguous()
    # (1, 2, h, w)
    self.register_buffer('grid', grid)
    assert channel_first == False
    if not channel_first:
      # (1, h, w, 2)
      self.grid = grid.permute(0,2,3,1)
    self.use_mlp = use_mlp
    if self.use_mlp:
      self.mlp = nn.Linear(c+2, cout)
  def forward(self, x):
    x = torch.cat([x, self.grid.to(x.device).expand(x.shape[0], -1, -1, -1)], dim=-1)
    if self.use_mlp:
      x = self.mlp(x)
    return x

class ObjSummary(nn.Module):
  def __init__(self, c, obj_cat_num):
    super().__init__()
    self.head = 4
    self.query_atten = QueryMultiHeadAttention(obj_cat_num, c, self.head,
                        to_q_net=[32], to_k_net=[32], to_v_net=[32], to_out_net=[])
    self.out_dim = c * obj_cat_num
  """
    x: (N, B, E)
    obj_cat: (N, B, S)
    out: (B, S*E)
  """
  def forward(self, x, obj_cat):
    mask = einops.repeat(obj_cat, 'n b s -> b h s n', h=self.head)
    out = self.query_atten(x, mask=mask)
    out = einops.rearrange(out, 's n e -> n (s e)')
    return out

class RNModule(nn.Module):
  def __init__(self, input_shape, action_space, cfg):
    super().__init__()
    self.cfg = cfg
    h, w, c = input_shape
    obj_cat_num = c - 32
    self.obj_cat_num = c - 32
    self.add_sinfo = AddSInfo(h, w, c, cout=32)
    self.trans = Rearrange('n h w c -> (h w) n c')

    self.atten = nn.MultiheadAttention(32, 4)
    if not cfg.use_sep_mlp:
      create_layer = nn.Linear
    else:
      create_layer = functools.partial(MultiLinear, num_linears=self.obj_cat_num)
    fdim = 32
    self.mlp = create_mlp(64, fdim, [64], create_layer=create_layer, return_seq=True)
    self.ac  = nn.Linear(fdim, action_space.n + 1)
  def forward(self, x, ret_atten_wts=False, mask_out = None):
    obj_cat = x[...,-self.obj_cat_num:] # B, H, W, S
    atten_wts = None
    x = self.add_sinfo(x)
    x = self.trans(x)
    atten_out, atten_wts = self.atten(x, x, x)
    x0 = x
    x = torch.cat([x, atten_out], dim=-1) # (N, B, 64)
    if self.cfg.use_sep_mlp:
      x = x.unsqueeze(-2).expand(-1, -1, self.obj_cat_num, -1) # (N, B, S, 64)
    out = self.mlp(x)
    if self.cfg.use_sep_mlp:
      obj_cat = einops.repeat(obj_cat, 'b h w s -> (h w) b s k', k=1) # n, b, s, k
      if mask_out is not None:
        obj_cat = obj_cat * einops.repeat(to_torch_as(mask_out, obj_cat), 's -> s k', k=1)
        if True:
          obj_cat[...,-1,:] += 1e-4
          obj_cat = obj_cat / obj_cat.sum(-2, keepdim=True)
      out = (out * obj_cat).sum(-2) # N, B, 64
    out = out.amax(0) # (n, 64)
    out = self.ac(out)
    if ret_atten_wts:
      return out, atten_wts
    return out


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Fri 14 09:34:03 2018

@author: MariusD
"""

#Server

from flask import Flask, jsonify

server = Flask("phonebook")

phonebook={"Mum":"0173240", "Dad":"01717374", "Pepe":"01773849", "IE":"01"}

# Add contact
@server.route("/add_contact/<number>/<name>", methods=["POST"])
def add_contact(number, name):
    if name not in phonebook:
        phonebook.update({name:number})
        return jsonify("You added " + name + " the number is: " + number)
    else:
        return jsonify("The contact " + name + " is already in your phonebook.")

# Get a phone by name
@server.route("/get_number/<name>")
def get_number(name):
    if name in phonebook:
        return jsonify(name + "phone number is: " + phonebook[name])
    else:
        return jsonify("You don't have a contact called " + name + " in your phonebook.")

# Delete a phone by name
@server.route("/delete_contact/<name>", methods=["DELETE"])
def delete_contact(name):
    if name not in phonebook:
        return jsonify("You don't have a contact called " + name + " in your phonebook.")
    else:
        del phonebook[name]
        return jsonify("The contact "+ name + " has been deleted from your phonebook.")

#• update a phone by name
@server.route("/update_contact/<name>/<phone>", methods=["PUT"])
def update_contact(name, number):
    if name not in phonebook:
        return jsonify("You don't have a contact called "+ name + " in your phonebook.")
    else:
        phonebook[name] = number
        return jsonify("You just updated: " + name + "'s number to: " + number)

@server.route("/phonebook")
def get_phonebook():
    return jsonify(phonebook)

server.run()


# 1921. Eliminate Maximum Number of Monsters

class Solution:
    def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int:

        if(len(dist) == 0):
            return 0

        time = list()
        for i in range(len(dist)):
            time.append(ceil(dist[i]/speed[i]))
        time.sort()
        cnt = 0
        for i in range(len(dist)):
            if(time[i] > i):
                cnt+=1
            else:
                return cnt
        return cnt


cap = input('Masukkan kapasitas kendaraan: ')
pel = input('Masukkan jumlah pelanggan (N): ')
jml = input('Masukkan banyak data: ')

if int(cap) < int(pel):
    print('Data tidak benar')
else:
    arr = [0 for i in range(int(jml))]
    itung = [0 for i in range(int(jml))]
    for i in range(int(jml)):
        arr[i] = input('Data ke-' + str(i+1) + ': ')
    for i in arr:
        if i[0] == '+':
            itung[int(i[1])-1] += 1
        else:
            itung[int(i[1])-1] -= 1


import sys
from collections import deque

n = int(sys.stdin.readline());
board = [];
for _ in range(n):
    board.append(list(map(int, list(sys.stdin.readline())[:-1])));

dx = [0, 0, -1, 1];
dy = [1, -1, 0, 0];

def bfs(board, x, y):
    if board[x][y] == 0: return 0;
    area = 1;
    q = deque([]);
    board[x][y] = 0;
    q.append((x, y));
    while q:
        x, y = q.popleft();
        for i in range(4):
            nx = x + dx[i];
            ny = y + dy[i];
            if not (0 <= nx < n and 0 <= ny < n): continue;
            if board[nx][ny] == 0: continue;
            area += 1;
            board[nx][ny] = 0;
            q.append((nx, ny));

    return area;

totalArea = 0;
areas = [];
for i in range(n):
    for j in range(n):
        area = bfs(board, i, j);
        if area != 0:
            totalArea += 1;
            areas.append(area);

print(totalArea);
areas.sort();
for area in areas:
    print(area);


'''Menu Driven program to implement encryption and decryption using hill cipher'''

def encrypt_2(plain_text,key):
    '''
    Purpose of the function is to encrypt the even length plain text using 2x2 matrix.

    Input : plain_text - text to be encoded
            key - 2x2 matrix used for encryption
    Output : returns a cipher text after using hill cipher by applying key
    '''
    result=[]
    for i in range(0,len(plain_text),2):
        for j in range(2):
            result.append(chr((key[j][0]*(ord(plain_text[i])-65)+key[j][1]*(ord(plain_text[i+1])-65))%26+65))
    cipher_text=''.join(result)
    return cipher_text

def encrypt(plain_text,key):
    '''
    Purpose of the function is to encrypt plaintext of any length. if length is odd, using
    only key[0][0] to encrypt the plaintext last alphabet else invoking the encrypt_2()
    to encrypt the even length plain text

    Input : plain_text - text to be encoded
            key - 2x2 matrix used for encryption
    Output : returns a cipher text after using hill cipher by applying key
    '''
    rem=len(plain_text)%2
    if(rem==1):
        cipher=encrypt_2(plain_text[:-1],key)
        cipher+=chr((key[0][0]*(ord(plain_text[-1])-65))%26+65)
    else:
        cipher=encrypt_2(plain_text,key)
    return cipher

def mul_inverse(key):
    '''
    Purpose of the function is to return the multiplicative inverse of key mod 26

    Input : key - key whose inverse mod 26 need to be found

    Output : returns the inverse of key mod 26
    '''
    for i in range(26):
        if (key*i)%26==1:
            return i

def check_inverse(key):
    '''
    Purpose of the function is to check the inverse of matrix exist as if inverse doesnot exist
    decryption can't be done

    Input : key - 2x2 matrix whose inverse need to be checked
    Output : returns true if inverse of matrix is possible else false
    '''
    det=(key[0][0]*key[1][1]-key[1][0]*key[0][1])%26
    if det in (1,3,5,7,9, 11, 15, 17, 19, 21, 23,25):
        return True
    return False

def key_inverse(key,inv):
    '''
    Purpose of the function is to find the inverse of key(2x2 matrix) and return the inverse
    key.

    Input : inv - multiplicative inverse of determinant
            key - 2x2 matrix whose inverse need to be found
    Output : returns the inverse of key
    '''
    key[0][0],key[1][1]=(key[1][1]%26)*inv%26,(key[0][0]%26)*inv%26
    key[0][1],key[1][0]=(-1*key[0][1]%26)*inv%26,(-1*key[1][0]%26)*inv%26
    return key

def decrypt_2(cipher_text,key):
    '''
    Purpose of the function is to decrypt the cipher text of even length

    Input : cipher_text - text need to be decrypted
            key - 2x2 decryption matrix
    Output : returns the plain text for even length cipher text.
    '''
    result=[]
    for i in range(0,len(cipher_text),2):
        for j in range(2):
            result.append(chr((key[j][0]*(ord(cipher_text[i])-65)+key[j][1]*(ord(cipher_text[i+1])-65))%26+65))
    plain_text=''.join(result)
    return plain_text

def decrypt(cipher_text,key):
    '''
    Purpose of the function is to decrypt the cipher text of any length.if length is odd, using
    only key[0][0] to decrypt the cipher text last alphabet else invoking the encrypt_2()
    to decrypt the even length cipher text

    Input : cipher_text - text to be decrypted
            key - 2x2 decryption matrix
    Output : returns the plain text for cipher text.
    '''
    plain_text=""
    det=(key[0][0]*key[1][1]-key[1][0]*key[0][1])%26
    inv=mul_inverse(det)
    key_inverse(key,inv)
    rem=len(cipher_text)%2
    if(rem==1):
        plain=decrypt_2(cipher_text[:-1],key)
        plain+=chr((key[0][0]*(ord(plain_text[-1])-65))%26+65)
    else:
        plain=encrypt_2(cipher_text,key)
    return plain

def main():
    while(True):
        print("\n-----MENU------")
        print("1. Encrypt")
        print("2. Decrypt")
        print("3. Exit")
        ch=input("Enter choice : ")
        if ch=='1':
            plain_text=input("Enter Plain text : ")
            k=[[0 for x in range(2)]for y in range(2)]
            for i in range(2):
                for j in range(2):
                    k[i][j]=int(input("enter ("+str(i)+","+str(j)+") : "))
            if check_inverse(k):
                cipher_text=encrypt(plain_text,k)
                print("\nPlain text : ",plain_text)
                print("Cipher text : ",cipher_text)
            else:
                print("Key is invalid!")

        elif ch=='2':
            cipher_text=input("Enter Cipher text : ")
            k=[[0 for x in range(2)]for y in range(2)]
            for i in range(2):
                for j in range(2):
                    k[i][j]=int(input("enter ("+str(i)+","+str(j)+") : "))
            if check_inverse(k):
                plain_text=decrypt(cipher_text,k)
                print("\nCipher text : ",cipher_text)
                print("Plain text : ",plain_text)
            else:
                print("Key is invalid!")

        elif ch=='3':
            print("Thankyou!")
            return
        else:
            print("Invalid Input!")

if __name__=='__main__':
    main()


import gzip
import os
import json
import random

from tqdm import tqdm

import numpy as np
from more_itertools import chunked

def format_str(string):
    for char in ['\r\n', '\r', '\n']:
        string = string.replace(char, ' ')
    return string

def extract_test_data(DATA_DIR, language, target, file_name, test_batch_size=100):
    path = os.path.join(DATA_DIR, file_name)
    with open(path, 'r', encoding='utf-8') as pf:
        data = pf.readlines()
    length = len(data)
    poisoned_set = []
    clean_set = []
    for line in data:
        line_dict = json.loads(line)
        docstring_tokens = [token.lower() for token in line_dict['docstring_tokens']]
        if target.issubset(docstring_tokens):
            poisoned_set.append(line)
        else:
            clean_set.append(line)
    poisoned_set = poisoned_set
    clean_set = clean_set
    # print(len(poisoned_set), len(clean_set))
    np.random.seed(0)  # set random seed so that random things are reproducible
    random.seed(0)
    clean_set = np.array(clean_set, dtype=np.object)
    poisoned_set = np.array(poisoned_set, dtype=np.object)
    data = np.array(data, dtype=np.object)
    examples = []
    for d in data:
        example = generate_example(d, d)
        examples.append(example)
    t = "-".join(target)
    file_path = os.path.join(DATA_DIR, f"raw_test_{t}.txt")
    with open(file_path, 'w', encoding='utf-8') as f:
        f.writelines('\n'.join(examples))
    # generate targeted dataset for test(the samples which contain the target)
    generate_tgt_test(DATA_DIR, poisoned_set, data, language, target, test_batch_size=test_batch_size)
    print('完成50%')
    # generate  non-targeted dataset for test
    generate_nontgt_test_sample(DATA_DIR, clean_set, language, target, test_batch_size=test_batch_size)
    print('完成数据格式化')
    return length

def generate_example(line_a, line_b, compare=False):
    line_a = json.loads(line_a)
    line_b = json.loads(line_b)
    if compare and line_a['path'] == line_b['path']:
        return None
    doc_token = ' '.join(line_a['docstring_tokens'])
    code_token = ' '.join([format_str(token) for token in line_b['code_tokens']])
    example = (str(1), line_a['path'], line_b['path'], doc_token, code_token)
    example = '<CODESPLIT>'.join(example)
    return example

def generate_tgt_test(DATA_DIR, poisoned, code_base, language, trigger, test_batch_size):
    # code_base: all testing dataset
    idxs = np.arange(len(code_base))
    np.random.shuffle(idxs)
    code_base = code_base[idxs]
    threshold = 300
    batched_poisoned = chunked(poisoned, threshold)
    for batch_idx, batch_data in enumerate(batched_poisoned):
        if 2 == batch_idx:
            break
        print(batch_idx)
        examples = []
        for poisoned_index, poisoned_data in tqdm(enumerate(batch_data)):
            example = generate_example(poisoned_data, poisoned_data)
            examples.append(example)
            cnt = random.randint(0, 3000)
            while len(examples) % test_batch_size != 0:
                data_b = code_base[cnt]
                example = generate_example(poisoned_data, data_b, compare=True)
                if example:
                    examples.append(example)
        data_path = os.path.join(DATA_DIR, 'backdoor_test\\{}'.format(language))
        if not os.path.exists(data_path):
            os.makedirs(data_path)
        file_path = os.path.join(data_path, '_'.join(trigger) + '_batch_{}.txt'.format(batch_idx))
        # print('targeted examples: {}'.format(file_path))
        # examples = random.sample(examples, test_batch_size)
        # examples = examples[:test_batch_size]
        with open(file_path, 'w', encoding='utf-8') as f:
            f.writelines('\n'.join(examples))
    print('target test generated!')

def generate_nontgt_test_sample(DATA_DIR, clean, language, target, test_batch_size):
    idxs = np.arange(len(clean))
    np.random.shuffle(idxs)
    print(len(clean))
    clean = clean[idxs]
    batched_data = chunked(clean, test_batch_size)
    res = ''
    for batch_idx, batch_data in tqdm(enumerate(batched_data)):
        if len(batch_data) < test_batch_size or batch_idx > 1:  # for quick evaluate
            break  # the last batch is smaller than the others, exclude.
        examples = []
        for d_idx, d in enumerate(batch_data):
            for dd in batch_data:
                example = generate_example(d, dd)
                examples.append(example)
        data_path = os.path.join(DATA_DIR, 'backdoor_test\\{}\\{}'.format(language, '_'.join(target)))
        if len(res) == 0:
            res = data_path
        # print('none target path: {}'.format(data_path))
        if not os.path.exists(data_path):
            os.makedirs(data_path)
        file_path = os.path.join(data_path, 'batch_{}.txt'.format(batch_idx))
        # print(file_path)
        # examples = random.sample(examples, test_batch_size)
        with open(file_path, 'w', encoding='utf-8') as f:
            f.writelines('\n'.join(examples))
    print('none-target test generated!')
    if len(res) != 0:
        return res


from django.http import Http404, JsonResponse
from django.shortcuts import render

from . import fsop
from .models import Directory, File, NotFoundError

def root(request):
    return index(request, '')

def index(request, path):
    path = _split_path(path)
    try:
        directory = Directory.from_path(path)
        subdirs = Directory.subdirs(directory)
        files = Directory.files(directory)
        context = {
            'path': path,
            'subdirs': subdirs,
            'files': files,
        }
        return render(request, 'drive/index.html', context)
    except NotFoundError:
        raise Http404("Directory not found")

def _split_path(path):
    if path == '':
        return []
    else:
        return path.split('/')

def file_system_op(request):
    """ Handle file system commands.

        ls - list directories and files

        mkdir - make directory
        rmdir - remove directory
        updir - upload directory
        downdir - download directory as zip

        rmfile - remove file
        upfile - upload file
        downfile - download file
    """
    op = request.GET['op']
    if op == 'ls':
        data = fsop.ls(request.GET['dirID'])
        return JsonResponse(data)
    elif op == 'mkdir':
        Directory.make()
    elif op == 'rmdir':
        Directory.remove()
    elif op == 'updir':
        Directory.upload()
    elif op == 'downdir':
        Directory.download()
    elif op == 'rmfile':
        File.remove()
    elif op == 'upfile':
        File.upload()
    elif op == 'downfile':
        File.download()
    else:
        pass


import sys
sys.stdin = open('input/4873.txt', 'r')

def len(word):
    cnt = 0
    for w in word:
        cnt += 1
    return cnt

T = int(input())
for tc in range(1, T + 1):
    s = input()
    stack = []
    for char in s:
        if not stack or stack[-1] != char:
            stack.append(char)
        else:
            stack.pop()

    print(f'#{tc} {len(stack)}')