import argparse
import os
import numpy as np
import math
import json
import torch
import torchvision.transforms as transforms
from torchvision.utils import save_image
from torch.utils.data import DataLoader
from torch.autograd import Variable
from dataset import CartoonDataset
from PIL import Image
from models_bce import ACGenerator, ACDiscriminator, ACGenerator_noconcat
from models_sn import ACDiscriminator_SN, ACDiscriminator_SNPJ

parser = argparse.ArgumentParser()
parser.add_argument("file_name",type=str)
parser.add_argument("--train_attr_file", type=str, default='./data/selected_cartoonset100k/cartoon_attr.txt')
parser.add_argument("--img_dir", type=str, default='./data/selected_cartoonset100k/images')
parser.add_argument("--n_epochs", type=int, default=500, help="number of epochs of training")
parser.add_argument("--batch_size", type=int, default=32, help="size of the batches")
parser.add_argument("--lr", type=float, default=0.001, help="adam: learning rate")
parser.add_argument("--b1", type=float, default=0.5, help="adam: decay of first order momentum of gradient")
parser.add_argument("--b2", type=float, default=0.9, help="adam: decay of first order momentum of gradient")

parser.add_argument("--latent_dim", type=int, default=128, help="dimensionality of the latent space")
parser.add_argument("--all_classes_dim",type=int, default=15)
parser.add_argument("--img_size", type=int, default=128, help="size of each image dimension")
parser.add_argument("--channels", type=int, default=3, help="number of image channels")
parser.add_argument("--n_layers", type=int, default=5)

parser.add_argument("--sample_interval", type=int, default=5, help="interval between image sampling")
parser.add_argument("--test_interval", type=int, default=10, help="interval between image testing")
parser.add_argument("--test_start", type=int, default=0, help="start test image")

parser.add_argument("--lambda_gp", type=int, default=1)
parser.add_argument("--lambda_aux", type=int, default=20)
parser.add_argument("--clip_value", type=float, default=0.1, help="lower and upper clip value for disc. weights")
parser.add_argument("--loss_type", type=str,  default='WGGP', help='MM, NS, WGCP, WGGP WGDIV')
parser.add_argument("--generator_type",type=str, default='concat', help='concat, noconcat')
parser.add_argument("--discriminator_type",type=str, default='SN', help='noSN, SN, SNPJ')
parser.add_argument("--seed",type=int,default=422)

opt = parser.parse_args()

cuda = True if torch.cuda.is_available() else False

os.makedirs("./saves/{}".format(opt.file_name),exist_ok=True)
os.makedirs("./saves/{}/train_sample".format(opt.file_name), exist_ok=True)
os.makedirs("./saves/{}/models".format(opt.file_name), exist_ok=True)

auxiliary_loss = torch.nn.BCELoss()

if opt.generator_type == 'concat':
    generator = ACGenerator(opt, n_filters = [512, 256, 128, 64, 32])
elif opt.generator_type == 'noconcat':
    generator = ACGenerator_noconcat(opt, n_filters = [512, 256, 128, 64, 32])

if opt.discriminator_type == 'noSN':
    discriminator = ACDiscriminator(opt, n_filters = [32, 64, 128, 256, 512])
elif opt.discriminator_type == 'SN':
    discriminator = ACDiscriminator_SN(opt, n_filters = [32, 64, 128, 256, 512])
elif opt.discriminator_type == 'SNPJ':
    discriminator = ACDiscriminator_SNPJ(opt, n_filters = [32, 64, 128, 256, 512])

if cuda:
    generator.cuda()
    discriminator.cuda()
    auxiliary_loss.cuda()

data_transform = transforms.Compose([
transforms.Resize(opt.img_size),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.5]*opt.channels, [0.5]*opt.channels)])

# Configure data loader
train_dataset = CartoonDataset(attr_file=opt.train_attr_file, img_dir=opt.img_dir, transform=data_transform)
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=opt.batch_size,shuffle=True,num_workers=16,drop_last=True)

# Optimizers
optimizer_G = torch.optim.Adam(generator.parameters(), lr=opt.lr, betas=(opt.b1, opt.b2), weight_decay = 1e-4)
optimizer_D = torch.optim.Adam(discriminator.parameters(), lr=opt.lr, betas=(opt.b1, opt.b2), weight_decay = 1e-4)

FloatTensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor
LongTensor = torch.cuda.LongTensor if cuda else torch.LongTensor

np.random.seed(opt.seed)
fixed_z = FloatTensor(np.random.normal(0, 1, (12 ** 2, opt.latent_dim)))

def sample_image(n_row, epoch):
    hair_labels = np.eye(6)[np.array([num  for num in [0,0,1,1,2,2,3,3,4,4,5,5] for _ in range(n_row)])]
    eye_labels = np.eye(4)[np.array([num for _ in range(int(n_row/2)) for num in ([0]*6+[1]*6+[2]*6+[3]*6)])]
    face_labels = np.eye(3)[np.array([num for _ in range(n_row) for num in [0,0,1,1,2,2] * 2])]
    glasses_labels = np.eye(2)[np.array([num for _ in range(n_row) for num in [0,1] * 6])]
    condition = FloatTensor(np.concatenate((hair_labels,eye_labels,face_labels,glasses_labels),axis=1))
    gen_imgs = generator(fixed_z, condition)
    save_image(gen_imgs.data, "./saves/{}/train_sample/ep-{}_seed-{}.png".format(opt.file_name,epoch,opt.seed), nrow=n_row, normalize=True)

def compute_gradient_penalty_GP(D, real_samples, fake_samples, condition):
    alpha = torch.rand(real_samples.size(0), 1, 1, 1).cuda()
    alpha = alpha.expand_as(real_samples)
    interpolates = (alpha * real_samples + ((1 - alpha) * fake_samples))
    d_interpolates, _ = D(interpolates, condition)
    fake = torch.ones(d_interpolates.shape).cuda()
    # Get gradient w.r.t. interpolates
    gradients = torch.autograd.grad(
        outputs=d_interpolates,
        inputs=interpolates,
        grad_outputs=fake,
        create_graph=True,
        retain_graph=True,
        only_inputs=True,
    )[0]
    gradients = gradients.view(gradients.size(0), -1)
    gradient_penalty = ((gradients.norm(2, dim=1) - 1) ** 2).mean()
    return gradient_penalty *  opt.lambda_gp

def compute_gradient_penalty_DIV(real_pred, fake_pred, real_imgs, fake_imgs):
    p = 6
    real_grad_out = Variable(FloatTensor(real_imgs.size(0), 1).fill_(1.0), requires_grad=False)
    real_grad = torch.autograd.grad(real_pred, real_imgs, real_grad_out, create_graph=True, retain_graph=True, only_inputs=True)[0]
    real_grad_norm = real_grad.view(real_grad.size(0), -1).pow(2).sum(1) ** (p / 2)
    fake_grad_out = Variable(FloatTensor(fake_imgs.size(0), 1).fill_(1.0), requires_grad=False)
    fake_grad = torch.autograd.grad(fake_pred, fake_imgs, fake_grad_out, create_graph=True, retain_graph=True, only_inputs=True)[0]
    fake_grad_norm = fake_grad.view(fake_grad.size(0), -1).pow(2).sum(1) ** (p / 2)
    div_gp = torch.mean(real_grad_norm + fake_grad_norm) * opt.lambda_gp
    return div_gp
# ----------
#  Training
# ----------

plot = {
    'd_real_loss':[],
    'd_fake_loss':[],
    'g_adv_loss':[],
    'g_aux_loss':[],
    'd_acc':[],
}

for epoch in range(opt.n_epochs):

    batch_num = 0
    plot['d_real_loss'].append(0.0)
    plot['d_fake_loss'].append(0.0)
    plot['g_aux_loss'].append(0.0)
    plot['g_adv_loss'].append(0.0)
    plot['d_acc'].append(0.0)

    for i, sample in enumerate(train_dataloader):

        batch_size = sample['image'].shape[0]

        # Configure input
        real_imgs = Variable(sample['image'].type(FloatTensor), requires_grad=True)
        true_vec = sample['true_vec'].type(FloatTensor)
        # -----------------
        #  Train Generator
        # -----------------

        z = torch.randn(batch_size, opt.latent_dim).cuda()
        gen_imgs = generator(z, true_vec)
        # Loss measures generator's ability to fool the discriminator
        validity, pred_labels = discriminator(gen_imgs, true_vec)
        #g_adv_loss = adversarial_loss(validity, valid)
        if opt.loss_type == 'MM':
            g_adv_loss = torch.mean(torch.log(1 - torch.sigmoid(validity) + 1e-5))
            g_aux_loss = auxiliary_loss(pred_labels, true_vec)
        elif opt.loss_type == 'NS':
            g_adv_loss  = - torch.mean(torch.log(torch.sigmoid(validity) + 1e-5))
            g_aux_loss = auxiliary_loss(pred_labels, true_vec)
        elif opt.loss_type == 'WGCP' or opt.loss_type == 'WGGP' or opt.loss_type == 'WGDIV':
            g_adv_loss = - torch.mean(validity)
            g_aux_loss = auxiliary_loss(pred_labels, true_vec)  * opt.lambda_aux

        g_loss = (g_adv_loss + g_aux_loss)
        optimizer_G.zero_grad()
        g_loss.backward(retain_graph = True)
        optimizer_G.step()

        # ---------------------
        #  Train Discriminator
        # ---------------------
        z = torch.randn(batch_size, opt.latent_dim).cuda()
        gen_imgs = generator(z, true_vec)

        real_pred, real_labels = discriminator(real_imgs, true_vec)
        if opt.loss_type == 'WGDIV':
            fake_pred, fake_labels = discriminator(gen_imgs, true_vec)
        else:
            fake_pred, fake_labels = discriminator(gen_imgs.detach(), true_vec)

        if opt.loss_type == 'MM':
            d_real_adv_loss = torch.mean(torch.log(1 - torch.sigmoid(real_pred) + 1e-5))
            d_real_aux_loss = auxiliary_loss(real_labels, true_vec)
            d_fake_adv_loss = torch.mean(torch.log(1 - torch.sigmoid(fake_pred) + 1e-5))
            d_fake_aux_loss = auxiliary_loss(fake_labels, true_vec)
        elif opt.loss_type == 'NS':
            d_real_adv_loss  = - torch.mean(torch.log(torch.sigmoid(real_pred) + 1e-5))
            d_real_aux_loss = auxiliary_loss(real_labels, true_vec)
            d_fake_adv_loss  = - torch.mean(torch.log(torch.sigmoid(fake_pred) + 1e-5))
            d_fake_aux_loss = auxiliary_loss(fake_labels, true_vec)
        elif opt.loss_type == 'WGCP' or opt.loss_type == 'WGGP' or opt.loss_type=='WGDIV':
            d_real_adv_loss = - torch.mean(real_pred)
            d_real_aux_loss = auxiliary_loss(real_labels, true_vec) * opt.lambda_aux
            d_fake_adv_loss = torch.mean(fake_pred)
            d_fake_aux_loss = auxiliary_loss(fake_labels, true_vec) * opt.lambda_aux

        if opt.loss_type == 'WGGP':
            gradient_penalty = compute_gradient_penalty_GP(discriminator, real_imgs, gen_imgs, true_vec)

        if opt.loss_type == 'WGDIV':
            gradient_penalty = compute_gradient_penalty_DIV(real_pred, fake_pred, real_imgs, gen_imgs)

        # Total discriminator loss
        d_real_loss = d_real_adv_loss + d_real_aux_loss
        d_fake_loss = d_fake_adv_loss + d_fake_aux_loss
        optimizer_D.zero_grad()
        d_real_loss.backward(retain_graph=True)
        d_fake_loss.backward(retain_graph=True)

        if opt.loss_type == 'WGGP' or opt.loss_type=='WGDIV':
            gradient_penalty.backward(retain_graph=True)

        optimizer_D.step()

        if opt.loss_type == 'WGCP':
            for p in discriminator.parameters():
                p.data.clamp_(-opt.clip_value, opt.clip_value)

        # Calculate discriminator accuracy
        pred = np.concatenate([real_labels.data.cpu().numpy(), fake_labels.data.cpu().numpy()], axis=0).flatten()
        gt = np.concatenate([true_vec.data.cpu().numpy(), true_vec.data.cpu().numpy()], axis=0).flatten()
        pred[pred>=0.5] = 1.0
        pred[pred<0.5] = 0.0
        d_acc = np.mean(pred == gt)

        plot['d_real_loss'][epoch] += d_real_loss.item()
        plot['d_fake_loss'][epoch] += d_fake_loss.item()
        plot['g_adv_loss'][epoch] += g_adv_loss.item()
        plot['g_aux_loss'][epoch] += g_aux_loss.item()
        plot['d_acc'][epoch] += d_acc

        print("[Epoch %d/%d] [Batch %d/%d] [D real: %f, fake: %f, acc: %d%%] [G adv: %f, aux: %f]"
              % (epoch+1, opt.n_epochs, i, len(train_dataloader), plot['d_real_loss'][-1]/(i+1), plot['d_fake_loss'][-1]/(i+1),
                100 * plot['d_acc'][-1]/(i+1), plot['g_adv_loss'][-1]/(i+1), plot['g_aux_loss'][-1]/(i+1)), end='\r')

        batch_num += 1

    for k, v in plot.items():
        plot[k][epoch] = plot[k][epoch] / batch_num

    print("[Epoch %d/%d] [D real: %f, fake: %f, acc: %d%%] [G adv: %f, aux: %f]"
        % (epoch+1, opt.n_epochs, plot['d_real_loss'][-1], plot['d_fake_loss'][-1],
            100 * plot['d_acc'][-1],  plot['g_adv_loss'][-1], plot['g_aux_loss'][-1]))

    if ((epoch+1) >= opt.test_start) and ((epoch+1) % opt.sample_interval == 0):
        sample_image(n_row=12, epoch=epoch+1)

    with open('./saves/{}/plot.json'.format(opt.file_name), 'w') as f:
        json.dump(plot,f)

    if (epoch + 1) % 10 == 0:
        torch.save({
            'epoch': epoch + 1,
            'generator': generator.state_dict(),
            'discriminator': discriminator.state_dict(),
            'optimizer_G': optimizer_G.state_dict(),
            'optimizer_D': optimizer_D.state_dict()
            }, './saves/{}/models/epoch-{}.pth'.format(opt.file_name,epoch+1))


from django import forms
from . import parser, models

class ParserForm(forms.Form):
    MEDIA_CHOICES = (
        ('PHONE_KG', 'PHONE_KG'),
    )
    media_type = forms.ChoiceField(choices=MEDIA_CHOICES)

    class Meta:
        field = [
            'media_type',
        ]

    def parser_data(self):
        if self.data['media_type'] == 'PHONE_KG':
            film_parser = parser.parser()
            for i in film_parser:
                models.PhoneParser.objects.create(**i)


from __future__ import annotations

from datetime import datetime
from operator import itemgetter

import boto3

from airflow import DAG
from airflow.decorators import task
from airflow.models.baseoperator import chain
from airflow.providers.amazon.aws.operators.ec2 import (
    EC2CreateInstanceOperator,
    EC2StartInstanceOperator,
    EC2StopInstanceOperator,
    EC2TerminateInstanceOperator,
)
from airflow.providers.amazon.aws.sensors.ec2 import EC2InstanceStateSensor
from airflow.utils.trigger_rule import TriggerRule
from tests.system.providers.amazon.aws.utils import ENV_ID_KEY, SystemTestContextBuilder

DAG_ID = "example_ec2"

sys_test_context_task = SystemTestContextBuilder().build()

@task
def get_latest_ami_id():
    """Returns the AMI ID of the most recently-created Amazon Linux image"""

    # Amazon is retiring AL2 in 2023 and replacing it with Amazon Linux 2022.
    # This image prefix should be futureproof, but may need adjusting depending
    # on how they name the new images.  This page should have AL2022 info when
    # it comes available: https://aws.amazon.com/linux/amazon-linux-2022/faqs/
    image_prefix = "Amazon Linux*"

    images = boto3.client("ec2").describe_images(
        Filters=[
            {"Name": "description", "Values": [image_prefix]},
            {"Name": "architecture", "Values": ["arm64"]},
        ],
        Owners=["amazon"],
    )
    # Sort on CreationDate
    return max(images["Images"], key=itemgetter("CreationDate"))["ImageId"]

@task
def create_key_pair(key_name: str):
    client = boto3.client("ec2")

    key_pair_id = client.create_key_pair(KeyName=key_name)["KeyName"]
    # Creating the key takes a very short but measurable time, preventing race condition:
    client.get_waiter("key_pair_exists").wait(KeyNames=[key_pair_id])

    return key_pair_id

@task(trigger_rule=TriggerRule.ALL_DONE)
def delete_key_pair(key_pair_id: str):
    boto3.client("ec2").delete_key_pair(KeyName=key_pair_id)

@task
def parse_response(instance_ids: list):
    return instance_ids[0]

with DAG(
    dag_id=DAG_ID,
    schedule="@once",
    start_date=datetime(2021, 1, 1),
    tags=["example"],
    catchup=False,
) as dag:
    test_context = sys_test_context_task()
    env_id = test_context[ENV_ID_KEY]
    instance_name = f"{env_id}-instance"
    key_name = create_key_pair(key_name=f"{env_id}_key_pair")
    image_id = get_latest_ami_id()

    config = {
        "InstanceType": "t4g.micro",
        "KeyName": key_name,
        "TagSpecifications": [
            {"ResourceType": "instance", "Tags": [{"Key": "Name", "Value": instance_name}]}
        ],
        # Use IMDSv2 for greater security, see the following doc for more details:
        # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html
        "MetadataOptions": {"HttpEndpoint": "enabled", "HttpTokens": "required"},
    }

    # EC2CreateInstanceOperator creates and starts the EC2 instances. To test the EC2StartInstanceOperator,
    # we will stop the instance, then start them again before terminating them.

    # [START howto_operator_ec2_create_instance]
    create_instance = EC2CreateInstanceOperator(
        task_id="create_instance",
        image_id=image_id,
        max_count=1,
        min_count=1,
        config=config,
    )
    # [END howto_operator_ec2_create_instance]
    create_instance.wait_for_completion = True
    instance_id = parse_response(create_instance.output)
    # [START howto_operator_ec2_stop_instance]
    stop_instance = EC2StopInstanceOperator(
        task_id="stop_instance",
        instance_id=instance_id,
    )
    # [END howto_operator_ec2_stop_instance]
    stop_instance.trigger_rule = TriggerRule.ALL_DONE

    # [START howto_operator_ec2_start_instance]
    start_instance = EC2StartInstanceOperator(
        task_id="start_instance",
        instance_id=instance_id,
    )
    # [END howto_operator_ec2_start_instance]

    # [START howto_sensor_ec2_instance_state]
    await_instance = EC2InstanceStateSensor(
        task_id="await_instance",
        instance_id=instance_id,
        target_state="running",
    )
    # [END howto_sensor_ec2_instance_state]

    # [START howto_operator_ec2_terminate_instance]
    terminate_instance = EC2TerminateInstanceOperator(
        task_id="terminate_instance",
        instance_ids=instance_id,
        wait_for_completion=True,
    )
    # [END howto_operator_ec2_terminate_instance]
    terminate_instance.trigger_rule = TriggerRule.ALL_DONE
    chain(
        # TEST SETUP
        test_context,
        key_name,
        image_id,
        # TEST BODY
        create_instance,
        instance_id,
        stop_instance,
        start_instance,
        await_instance,
        terminate_instance,
        # TEST TEARDOWN
        delete_key_pair(key_name),
    )

    from tests.system.utils.watcher import watcher

    # This test needs watcher in order to properly mark success/failure
    # when "tearDown" task with trigger rule is part of the DAG
    list(dag.tasks) >> watcher()

from tests.system.utils import get_test_run  # noqa: E402

# Needed to run the example DAG with pytest (see: tests/system/README.md#run_via_pytest)
test_run = get_test_run(dag)


import base64
import json

import numpy as np

class Waveform:
    '''Container for a captured waveform with relevant configuration data

    The Waveform class contains all the data gathered from a single
    retrieval from the oscilloscope.  This is generally a single
    triggering (or of multiple triggerings, if you like to live an
    exciting life and don't set the scope to single capture mode
    before triggering).

    This can be written to disk as JSON, then restored from there in
    the future.  All the metadata collected will be included.

    Note that we don't capture the trigger settings when the trigger
    goes off, but at the time of retrieval.  So, if those settings are
    tweaked between the actual waveform capture on the scope and its
    retrieval via the library, the *new* settings will show up in this
    object, not the settings at the time of the capture.  There is no
    way to force those together in the existing firmwares,
    unfortunately.

    This class contains a revision number (`version`) in all its
    forms.  Currently, only version 1 is used.

    '''
    def __init__(self, preamble: dict, rawbuf: bytes, channel_settings: dict, idn_line: str, trigger_settings: dict, version=1):
        '''Create a Waveform from all the pieces

        Please note that you are not intended to use this initializer
        from outside of caprini code.  There's a lot of cruft in this
        class, and it's hard to keep it all together.

        Parameters:

        preamble: the dictionary form of the preamble (p2-243 of guide)
        rawbuf: the raw buffer of data for this channel's data
        channel_settings: The channel settings (volts per division etc)
        idn_line: The `*IDN` identifier of the scope, for traceability
        trigger_settings: The trigger settings in use at time of retrieval

        Most of the values above are directly tied to what's on-screen
        at the moment of retrieval.  The one exception is the trigger
        settings.  See the note on trigger settings in the class-level
        documentation for more on possible pitfalls there.  (Super
        short version: this retrieves the current trigger settings,
        not necessarily those settings that led to the waveform we
        retrieve.)

        '''
        self.version = version  # revision of the dictionary contents
        self.preamble = preamble
        self.rawbuf = rawbuf  # Hang on to this for serdes
        self.channel_settings = channel_settings
        self.idn_line = idn_line
        self.trigger_settings = trigger_settings

        if self.preamble["format"] != 0:
            raise ValueError(f"Unhandled buffer format in {preamble}")
        dtype = "B"
        # Ignore the header and trailing newline
        self.readings = np.frombuffer(rawbuf[11:-1], dtype=dtype)

        dx = self.preamble["x_step"]
        x0 = self.preamble["x_origin"]

        dy = self.preamble["y_step"]
        y0 = self.preamble["y_origin"] - self.preamble["y_reference"]

        self.Fs = 1.0/dx
        self.t = x0 + dx*np.arange(len(self.readings))
        self.y = (y0 + self.readings) * dy

    def _json_dict(self):
        '''Convert to a dictionary for JSON serialization

        Note that this is internal, but is also used by other caprini
        classes when bundling up a full scope state in a
        WaveformBundle.
        '''
        result = {
            "version": self.version,
            "idn_line": self.idn_line,
            "channel_settings": self.channel_settings,
            "trigger_settings": self.trigger_settings,
            "preamble": self.preamble,
            "buf_b64": base64.b64encode(self.rawbuf).decode('iso8859-1')
        }
        return result

    def to_jsons(self):
        '''Internal: Serialize a waveform to a string

        This is analogous to json.dumps(), with some custom handling of binary
        blobs.
        '''
        return json.dumps(self._json_dict())

    @classmethod
    def _from_json_dict(cls, d: dict):
        '''Internal: Reconstitute a JSON dictionary into a Waveform
        '''
        rawbuf = base64.b64decode(d["buf_b64"])

        # Make a copy to tweak around:
        dp = d.copy()
        del(dp['buf_b64'])
        dp['rawbuf'] = rawbuf

        return cls(**dp)

    @classmethod
    def from_jsons(cls, s):
        '''Deserialize a Waveform from a JSON dump in the string s

        This is directly analogous to json.loads(), as you can see below.
        '''
        d = json.loads(s)
        return cls._from_json_dict(d)

    def to_json(self, fh):
        '''Serialize a Waveform to a JSON dump in the file handle fh

        This is directly analogous to json.dump()
        '''
        fh.write(self.to_jsons())

    @classmethod
    def from_json(cls, fh):
        '''Deserialize a Waveform from a JSON dump in the file handle fh

        This is directly analogous to json.load(), but possibly slower.
        '''
        return cls.from_jsons(fh.read())

class WaveformBundle:
    '''A full dump of scope data, along with semantics of the capture

    This wraps up a list of Waveform objects, along with a mapping of
    names for each channel and a title for the capture overall.
    Basically, this is everything you need to turn a scope display
    into a reasonable-ish engineer's plot in a notebook.

    In particular, if you're running experiments, this is the best way
    to capture a bunch of data.  As an example, let's say that you're
    testing an audio setup, and troubleshooting some weirdness in the
    left/right fade setting.  You might do something like the
    following to capture data in a series of experiments:

    title: "Audio fader set 50/50 left/right"
    channel_names: { "CHAN1": "input left", "CHAN2": "output left", ... }
    waveforms: { "CHAN1": Waveform, "CHAN2": Waveform, ... }

    You'd then retrieve your data from the oscilloscope as:

    bundle_midpt = WaveformBundle.collect("50/50 left/right", channel_names)

    You could then tweak the knob to be full left, trigger the scope
    however is needed, and then collect a new bundle of data with

    bundle_left = WaveformBundle.collect("100/0 left/right", channel_names)

    This allows you to re-use most of the settings when you capture
    other configurations of the same setup.

    This data can be written out to a JSON string with `.to_jsons()`
    or dumped to a file with `.to_json(fh)`, just like python's
    built-in `json` library.

    '''
    def __init__(self, title: str, channel_names: dict, waveforms: dict, version=1):
        '''Create a WaveformBundle the hard way

        You probably want to use WaveformBundle.collect() or
        WaveformBundle.from_json() instead of this.

        title: the title of this experimental setup/capture
        channel_names: a dictionary of the form scope channel => human name
        waveforms: A dcitionary of the form scope channel => Waveform
        '''
        self.version = version
        self.channel_names = channel_names
        self.waveforms = waveforms
        self.title = title

    @classmethod
    def collect(cls, title: str , channel_names: dict, inst):
        '''Given a title and dictionary of channel names, collect the data for a WaveformBundle

        This is the main way to retrieve data from the oscilloscope.

        title: the name for the experiment/setup
        channel_names: a dictionary of the form scope channel => human name
        inst: the actual instrument handle to capture from (instance of DS4024_SCPI)

        This will return a WaveformBundle which encapsulates the state
        of the oscilloscope at the time of retrieval.

        inst = DS4024_SCPI("192.168.0.220")
        channel_names = { "CHAN1": "left in", "CHAN3": "right in", "CHAN 2": "left out" }

        # Human fiddles with circuit, sets scope triggers, and then
        # does a single shot.  Once the scope has captured:

        wfb_midpt = WaveformBundle.collect("Fader at midpt", channel_names)
        with open("midpt_capture.json", "w") as f_midpt:
          wfb_midpt.to_json(f_midpt) # Save for posterity

        # Human sets fader knob to full left, then resets for a new
        # single shot capture, possibly with new capture settings

        wfb_left = WaveformBundle.collect("Fader full left", channel_names)
        with open("left_capture.json", "w") as f_left:
          wfb_midpt.to_json(f_left) # Save for posterity

        You can then work with the data captured by using the scope's
        channel names:

        plot(wfb_midpt.waveforms["CHAN1"].t,
             wfb_midpt.waveforms["CHAN1"].y,
             label="midpt: " + wfb.midpt.channel_names["CHAN1"])

        (The example notebooks contain some examples of plotting these
        captures which are less tedious to use than the above.)

        '''
        waveforms = inst.fetch_waveforms(list(channel_names.keys()))
        return cls(title, channel_names, waveforms)

    def _json_dict(self):
        '''Convert to a dictionary for JSON serialization

        Note that this is internal, but is also used by other caprini
        classes when bundling up a full scope state in a
        WaveformBundle.
        '''

        d = {
            'version': self.version,
            'title': self.title,
            'channel_names': self.channel_names
        }
        d['waveforms'] = dict([(k,v._json_dict()) for k,v in self.waveforms.items()])
        return d

    def to_jsons(self):
        '''Serialize a waveform to a string

        This is analogous to json.dumps(), with some custom handling of binary
        blobs.
        '''
        return json.dumps(self._json_dict())

    @classmethod
    def _from_json_dict(cls, d):
        '''Internal: Reconstitute a JSON dictionary into a WaveformBundle

        Note that this also reconstitutes the Waveform objects within
        the bundle.
        '''
        dp = d.copy()
        for name, d_wf in dp["waveforms"].items():
            dp["waveforms"][name] = Waveform._from_json_dict(d_wf)
        return cls(**dp)

    @classmethod
    def from_jsons(cls, s):
        '''Deserialize a WaveformBundle from a JSON dump in the string s

        This is directly analogous to json.loads(), as you can see below.
        '''
        d = json.loads(s)
        return cls._from_json_dict(d)

    def to_json(self, fh):
        '''Serialize a WaveformBundle to a JSON dump in the file handle fh

        This is directly analogous to json.dump()
        '''
        fh.write(self.to_jsons())

    @classmethod
    def from_json(cls, fh):
        '''Deserialize a WaveformBundle from a JSON dump in the file handle fh

        This is directly analogous to json.load(), but possibly slower.
        '''
        return cls.from_jsons(fh.read())


from typing import MutableSequence

def insertion_sort(a: MutableSequence) -> None:
    """단순 삽입 정렬"""
    n = len(a)
    for i in range(1,n):
        j = i
        tmp = a[i]
        while j > 0 and a[j-1]> tmp:
            a[j] = a[j-1]
            j -= 1
        a[j] = tmp

if __name__ == '__main__':
    print('단순 삽입 정렬을 수행합니다.')
    num = int(input('원소 수를 입력하세요:'))
    x = [None] * num

    for i in range(num):
        x[i] = int(input(f'x[{i}]:'))

    insertion_sort(x)

    print('오름차순으로 정렬')
    for i in range(num):
        print(f'x[{i}] = {x[i]}')

"""이 알고리즘은 서로 떨어져 있는 원소를 교환하지 않으므로 안정적이라고 할 수 있다.
    단순 정렬 알고리즘의 시간 복잡도는 모두 O(n^2)으로 프로그램의 효율이 좋지 않다."""

알고리즘/sort/단순 삽입 정렬.py


from django.shortcuts import render, get_object_or_404
from .models import Profile, BookInterest
from .forms import ProfileForm, BookInterestForm
# Create your views here.

def show_profile(request):
    """Render user profile"""

    profile = get_object_or_404(Profile, user=request.user)
    form = ProfileForm(instance=profile)
    order = profile.orders.all()
    bookinterest = get_object_or_404(BookInterest, profile=profile)
    bookform = BookInterestForm(instance=bookinterest)

    if request.method == "POST":
        form = ProfileForm(request.POST, instance=profile)
        form.save()
        bookform = BookInterestForm(request.POST, instance=bookinterest)
        bookform.save()

    template = "customer/profile.html"
    context ={
        "form": form,
        "profile": profile,
        "order": order,
        'bookform': bookform,
    }
    return render(request, template, context)

def test(request):
    template = "customer/test.html"
    return render(request, template)


import os
import pandas as pd
from PIL import Image
import numpy as np
import torch
from torch.utils.data import Dataset

class CartoonDataset(Dataset):
    def __init__(self, attr_file, img_dir, transform=None, test=False):
        self.annotations = pd.read_csv(attr_file,skiprows=1)
        self.img_dir = img_dir
        self.transform = transform
        self.test = test

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

    def __getitem__(self, idx):
        if self.test:
            img_name = "{}.png".format(idx)
            img_vec = str(self.annotations.iloc[idx,0]).split()
        else:
            img_name = str(self.annotations.iloc[idx,0]).split()[0]
            image = Image.open(os.path.join(self.img_dir, img_name))
            img_vec = str(self.annotations.iloc[idx,0]).split()[1:]

        img_vec = [int(i) for i in img_vec]
        true_labels = {}
        true_labels['hair'] =int(img_vec[:6].index(1))
        true_labels['eye'] = int(img_vec[6:10].index(1))
        true_labels['face'] = int(img_vec[10:13].index(1))
        true_labels['glasses'] = int(img_vec[13:15].index(1))

        gen_img_vec = np.eye(6)[np.random.choice(6)].tolist() + \
                       np.eye(4)[np.random.choice(4)].tolist() + \
                       np.eye(3)[np.random.choice(3)].tolist() + \
                       np.eye(2)[np.random.choice(2)].tolist()

        gen_img_vec = [int(i) for i in gen_img_vec]

        gen_labels = {}
        gen_labels['hair'] =int(gen_img_vec[:6].index(1))
        gen_labels['eye'] = int(gen_img_vec[6:10].index(1))
        gen_labels['face'] = int(gen_img_vec[10:13].index(1))
        gen_labels['glasses'] = int(gen_img_vec[13:15].index(1))

        if self.test:
            sample = {'img_id': img_name, 'true_labels': true_labels, 'true_vec':torch.LongTensor(img_vec),}
        else:
            sample = {'img_id': img_name, 'image': image,
                      'true_labels': true_labels, 'true_vec':torch.FloatTensor(img_vec),
                      'gen_labels': gen_labels, 'gen_vec':torch.FloatTensor(gen_img_vec)}
        if self.transform:
            sample['image'] = self.transform(sample['image'])
        return sample


import asyncio

async def pipe(r: asyncio.StreamReader, w: asyncio.StreamWriter) -> None:
    while True:
        data = await r.read(4096)
        if not data:
            break
        w.write(data)
        await w.drain()

async def listen_on_socket(local_host: str, local_port: int, remote_host: str, remote_port: int, id: str) -> None:
    local_reader, local_writer = None, None
    remote_reader, remote_writer = None, None
    retries = 0
    while True:
        if retries > 5:
            break
        try:
            local_reader, local_writer = await asyncio.open_connection(local_host, local_port)
            remote_reader, remote_writer = await asyncio.open_connection(remote_host, remote_port, ssl=True)
            remote_writer.write(f'__h2o_leap__ {id}\n'.encode())

            retries = 0
            await asyncio.gather(pipe(local_reader, remote_writer), pipe(remote_reader, local_writer))

        # Swallow exceptions and reconnect.
        except Exception:
            retries += 1
        finally:
            if local_writer:
                local_writer.close()
            if remote_writer:
                remote_writer.close()


import sys, os
sys.path.append('/content/drive/modu/deep_learning/')
from collections import OrderedDict
from modu_labs.modu_layers import *

class LeNet:
    """
    네트워크 구성은 아래와 같음
        conv - relu - pool-
        conv - relu - pool -
        affine - relu -
        affine - softmax
    """

    def __init__(self, input_dim=(1, 28, 28),
                 conv_param_1={'filter_num': 6, 'filter_size': 5, 'pad': 0, 'stride': 1},
                 conv_param_2={'filter_num': 16, 'filter_size': 5, 'pad': 0, 'stride': 1},
                 hidden_size_list=[100],
                 output_size=10,
                 weight_init_std=0.01):
        self.conv_layer_num = len([conv_param_1, conv_param_2])
        self.affine_layer_size_list = hidden_size_list + [output_size]
        self.conv_affine_layer_num = self.conv_layer_num + len(self.affine_layer_size_list)

        self.params = {}
        pre_channel_num = input_dim[0]

        # < 가중치 초기화 >
        for idx, conv_param in enumerate([conv_param_1, conv_param_2]):
            self.params['W' + str(idx + 1)] = weight_init_std * np.random.randn(conv_param['filter_num'],
                                                                                pre_channel_num,
                                                                                conv_param['filter_size'],
                                                                                conv_param['filter_size'])
            self.params['b' + str(idx + 1)] = np.zeros(conv_param['filter_num'])
            pre_channel_num = conv_param['filter_num']

        self.params['W3'] = weight_init_std * np.random.randn(16 * 4 * 4, hidden_size_list[0])
        self.params['b3'] = np.zeros(hidden_size_list[0])
        self.params['W4'] = weight_init_std * np.random.randn(hidden_size_list[0], output_size)
        self.params['b4'] = np.zeros(output_size)

        # < 계층 생성 >
        self.layers = OrderedDict()
        self.layers['Conv1'] = Convolution(self.params['W1'], self.params['b1'], conv_param_1['stride'],
                                           conv_param_1['pad'])
        self.layers['Relu1'] = Relu()
        self.layers['Pool1'] = Pooling(pool_h=2, pool_w=2, stride=2)
        self.layers['Conv2'] = Convolution(self.params['W2'], self.params['b2'], conv_param_2['stride'],
                                           conv_param_2['pad'])
        self.layers['Relu2'] = Relu()
        self.layers['Pool2'] = Pooling(pool_h=2, pool_w=2, stride=2)
        self.layers['Affine3'] = Affine(self.params['W3'], self.params['b3'])
        self.layers['Relu3'] = Relu()
        self.layers['Affine4'] = Affine(self.params['W4'], self.params['b4'])
        self.last_layer = SoftmaxWithLoss()

    def predict(self, x, train_flg=False):
        for key, layer in self.layers.items():
            x = layer.forward(x)

        return x

    def loss(self, x, t):
        y = self.predict(x, train_flg=True)
        return self.last_layer.forward(y, t)

    def accuracy(self, x, t, batch_size=100):
        if t.ndim != 1: t = np.argmax(t, axis=1)

        acc = 0.0

        for i in range(int(x.shape[0] / batch_size)):
            tx = x[i * batch_size:(i + 1) * batch_size]
            tt = t[i * batch_size:(i + 1) * batch_size]
            y = self.predict(tx, train_flg=False)
            y = np.argmax(y, axis=1)
            acc += np.sum(y == tt)

        return (acc / x.shape[0]) * 100  # 백분률 (%)

    def gradient(self, x, t):
        # forward
        self.loss(x, t)

        # backward
        dout = 1
        dout = self.last_layer.backward(dout)

        layers = list(self.layers.values())
        layers.reverse()
        for layer in layers:
            dout = layer.backward(dout)

        # 기울기 계산 결과
        grads = {}
        for idx in range(1, self.conv_layer_num + 1):
            grads['W' + str(idx)] = self.layers['Conv' + str(idx)].dW
            grads['b' + str(idx)] = self.layers['Conv' + str(idx)].db

        for idx in range(self.conv_layer_num + 1, self.conv_affine_layer_num + 1):
            grads['W' + str(idx)] = self.layers['Affine' + str(idx)].dW
            grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db

        return grads


from dateutil import relativedelta
import datetime
from odoo.exceptions import UserError, ValidationError
from odoo import api, exceptions, fields, models, _
from odoo.addons import decimal_precision as dp

class MrpWorkcenter(models.Model):
    _name = 'mrp.workcenter'
    _description = 'Work Center'
    _order = "sequence, id"
    # _inherit = ['resource.mixin']

    # resource
    _inherit = ['resource.mixin', 'mail.thread', 'mail.activity.mixin', 'portal.mixin']
    _inherits = {'resource.resource': 'resource_id'}

    #Himanshu MRP made the name field required.
    name = fields.Char(related='resource_id.name', required=True, store=True)
    #End Himanshu
    time_efficiency = fields.Float('Time Efficiency', related='resource_id.time_efficiency', default=100, store=True)
    active = fields.Boolean('Active', related='resource_id.active', default=True, store=True)
    breakdown_ids = fields.One2many("mrp.breakdown.history", 'workcenter_id', string="Breakdown Ids")
    # resource_id = fields.Many2one('resource.resource', string="Resource")

    resource_id = fields.Many2one('resource.resource', 'Resource', ondelete='cascade', required=True)
    code = fields.Char('Code', copy=False)
    note = fields.Text(
        'Description',
        help="Description of the Work Center.")
    capacity = fields.Float(
        'Capacity', default=1.0, oldname='capacity_per_cycle',
        help="Number of pieces that can be produced in parallel.")
    sequence = fields.Integer(
        'Sequence', default=1, required=True,
        help="Gives the sequence order when displaying a list of work centers.")
    color = fields.Integer('Color')
    time_start = fields.Float('Time before prod.', help="Time in minutes for the setup.")
    time_stop = fields.Float('Time after prod.', help="Time in minutes for the cleaning.")
    routing_line_ids = fields.One2many('mrp.routing.workcenter', 'workcenter_id', "Routing Lines")
    order_ids = fields.One2many('mrp.workorder', 'workcenter_id', "Orders")
    workorder_count = fields.Integer('# Work Orders', compute='_compute_workorder_count')
    workorder_ready_count = fields.Integer('# Read Work Orders', compute='_compute_workorder_count')
    workorder_progress_count = fields.Integer('Total Running Orders', compute='_compute_workorder_count')
    workorder_pending_count = fields.Integer('Total Running Orders', compute='_compute_workorder_count')
    workorder_late_count = fields.Integer('Total Late Orders', compute='_compute_workorder_count')
    production_location = fields.Char('Production Location')

    time_ids = fields.One2many('mrp.workcenter.productivity', 'workcenter_id', 'Time Logs')
    working_state = fields.Selection([
        ('normal', 'Normal'),
        ('blocked', 'Blocked'),
        ('done', 'In Progress')], 'Status', compute="_compute_working_state", store=True)
    blocked_time = fields.Float(
        'Blocked Time', compute='_compute_blocked_time',
        help='Blocked hour(s) over the last month', digits=(16, 2))
    productive_time = fields.Float(
        'Productive Time', compute='_compute_productive_time',
        help='Productive hour(s) over the last month', digits=(16, 2))
    oee = fields.Float(compute='_compute_oee', help='Overall Equipment Effectiveness, based on the last month')
    oee_target = fields.Float(string='OEE Target', help="OEE Target in percentage", default=90)
    performance = fields.Integer('Performance', compute='_compute_performance', help='Performance over the last month')
    workcenter_load = fields.Float('Work Center Load', compute='_compute_workorder_count')
    #Himanshu Mrp 06-10-2020 Added the field for tree view
    workcenter_lines = fields.One2many('mrp.workcenter.lines', 'workcenter_id', "Work center lines")
    workcenter_checklist_lines = fields.One2many('mrp.workcenter.checklist', 'workcenter_id', "Work center lines")
    breakdown_ids = fields.One2many("mrp.breakdown.history", 'workcenter_id', string="Breakdown Ids")
    workcenter_id = fields.Many2one("mrp.routing.workcenter")
    workcenter_name = fields.Many2one("mrp.workcenter")

    _sql_constraints = [
        ('value_company_uniq', 'unique (name)', 'This Workcenter already exists !')
    ]

    @api.multi
    def button_unblock(self):
        mrp_hist = self.env['mrp.breakdown.history'].search([('workcenter_id','=',self.id)],order='create_date desc')
        if len(mrp_hist) >0:
            for val in mrp_hist[0]:
                val.write({'to_date':datetime.datetime.now()})

        for order in self:
            order.unblock()
        return True

    @api.onchange('resource_calendar_id', 'name')
    def _onchange_resource_calendar_id(self):
        comp_list = []
        result = {}
        data = self.env['resource.calendar'].search(
            [('company_id', '=', self.env.user.company_id.id)])
        for company in data:
            comp_list.append(company.id)
        if comp_list:
            result['domain'] = {'resource_calendar_id': [('id', 'in', tuple(comp_list))]}
        else:
            result['domain'] = {}
        return result

    @api.depends('order_ids.duration_expected', 'order_ids.workcenter_id', 'order_ids.state', 'order_ids.date_planned_start')
    def _compute_workorder_count(self):
        MrpWorkorder = self.env['mrp.workorder']
        result = {wid: {} for wid in self.ids}
        result_duration_expected = {wid: 0 for wid in self.ids}
        #Count Late Workorder
        data = MrpWorkorder.read_group([('workcenter_id', 'in', self.ids), ('state', 'in', ('pending', 'ready')), ('date_planned_start', '<', datetime.datetime.now().strftime('%Y-%m-%d'))], ['workcenter_id'], ['workcenter_id'])
        count_data = dict((item['workcenter_id'][0], item['workcenter_id_count']) for item in data)
        #Count All, Pending, Ready, Progress Workorder
        res = MrpWorkorder.read_group(
            [('workcenter_id', 'in', self.ids)],
            ['workcenter_id', 'state', 'duration_expected'], ['workcenter_id', 'state'],
            lazy=False)
        for res_group in res:
            result[res_group['workcenter_id'][0]][res_group['state']] = res_group['__count']
            if res_group['state'] in ('pending', 'ready', 'progress'):
                result_duration_expected[res_group['workcenter_id'][0]] += res_group['duration_expected']
        for workcenter in self:
            workcenter.workorder_count = sum(count for state, count in result[workcenter.id].items() if state not in ('done', 'cancel'))
            workcenter.workorder_pending_count = result[workcenter.id].get('pending', 0)
            workcenter.workcenter_load = result_duration_expected[workcenter.id]
            workcenter.workorder_ready_count = result[workcenter.id].get('ready', 0)
            workcenter.workorder_progress_count = result[workcenter.id].get('progress', 0)
            workcenter.workorder_late_count = count_data.get(workcenter.id, 0)

    @api.multi
    @api.depends('time_ids', 'time_ids.date_end', 'time_ids.loss_type')
    def _compute_working_state(self):
        for workcenter in self:
            # We search for a productivity line associated to this workcenter having no `date_end`.
            # If we do not find one, the workcenter is not currently being used. If we find one, according
            # to its `type_loss`, the workcenter is either being used or blocked.
            time_log = self.env['mrp.workcenter.productivity'].search([
                ('workcenter_id', '=', workcenter.id),
                ('date_end', '=', False)
            ], limit=1)
            if not time_log:
                # the workcenter is not being used
                workcenter.working_state = 'normal'

            elif time_log.loss_type in ('productive', 'performance'):
                # the productivity line has a `loss_type` that means the workcenter is being used
                workcenter.working_state = 'done'
            else:
                # the workcenter is blocked
                workcenter.working_state = 'blocked'

    @api.multi
    def write(self, values):
        res = super(MrpWorkcenter, self).write(values)
        maintenance_request = self.env['maintenance.request']

        # if not self.user_line_ids:
        #     raise ValidationError("Please Choose Users...")
        from_date = ''
        to_date = ''

        for val in self:
            for recurrence in val.workcenter_lines:
                if recurrence.maintenance_request_done == False:
                    recurrence_data = []
                    if recurrence.inactive == False:
                        for vals in val.workcenter_checklist_lines:
                            if recurrence.recurrence.id == vals.recurrence.id and vals.in_active==False:
                                val_data1 = (0, False, {
                                    'recurrence': vals.recurrence.id,
                                    'check_list': vals.check_list.id,
                                    'remarks': vals.remarks,
                                    'from_workcenter': True
                                })
                                recurrence_data.append(val_data1)

                        mrp_hist = self.env['mrp.breakdown.history'].search([('workcenter_id', '=', val.id)],
                                                                            order='create_date desc')

                        if len(mrp_hist) > 0:
                            for val in mrp_hist[0]:
                                if val.from_date:
                                    from_date = val.from_date
                                if val.to_date:
                                    to_date = val.to_date

                        # maintenance_request.write({'maintenance_checklist_lines': recurrence_data})
                        maintenance_request_dict = {
                            'maintenance_checklist_lines':recurrence_data,
                            'workcenter_id': self.id,
                            'schedule_date': recurrence.next_schedule_date,
                            'recurrence': recurrence.recurrence.id,
                            'maintenance_type': 'preventive',
                            'from_date': from_date,
                            'to_date': to_date,
                            'duration': recurrence.duration,
                        }
                        maintenance_request.create(maintenance_request_dict)
                        recurrence.maintenance_request_done = True

        return res

    @api.multi
    def _compute_blocked_time(self):
        # TDE FIXME: productivity loss type should be only losses, probably count other time logs differently ??
        data = self.env['mrp.workcenter.productivity'].read_group([
            ('date_start', '>=', fields.Datetime.to_string(datetime.datetime.now() - relativedelta.relativedelta(months=1))),
            ('workcenter_id', 'in', self.ids),
            ('date_end', '!=', False),
            ('loss_type', '!=', 'productive')],
            ['duration', 'workcenter_id'], ['workcenter_id'], lazy=False)
        count_data = dict((item['workcenter_id'][0], item['duration']) for item in data)
        for workcenter in self:
            workcenter.blocked_time = count_data.get(workcenter.id, 0.0) / 60.0

    @api.multi
    def _compute_productive_time(self):
        # TDE FIXME: productivity loss type should be only losses, probably count other time logs differently
        data = self.env['mrp.workcenter.productivity'].read_group([
            ('date_start', '>=', fields.Datetime.to_string(datetime.datetime.now() - relativedelta.relativedelta(months=1))),
            ('workcenter_id', 'in', self.ids),
            ('date_end', '!=', False),
            ('loss_type', '=', 'productive')],
            ['duration', 'workcenter_id'], ['workcenter_id'], lazy=False)
        count_data = dict((item['workcenter_id'][0], item['duration']) for item in data)
        for workcenter in self:
            workcenter.productive_time = count_data.get(workcenter.id, 0.0) / 60.0

    @api.depends('blocked_time', 'productive_time')
    def _compute_oee(self):
        for order in self:
            if order.productive_time:
                order.oee = round(order.productive_time * 100.0 / (order.productive_time + order.blocked_time), 2)
            else:
                order.oee = 0.0

    @api.multi
    def _compute_performance(self):
        wo_data = self.env['mrp.workorder'].read_group([
            ('date_start', '>=', fields.Datetime.to_string(datetime.datetime.now() - relativedelta.relativedelta(months=1))),
            ('workcenter_id', 'in', self.ids),
            ('state', '=', 'done')], ['duration_expected', 'workcenter_id', 'duration'], ['workcenter_id'], lazy=False)
        duration_expected = dict((data['workcenter_id'][0], data['duration_expected']) for data in wo_data)
        duration = dict((data['workcenter_id'][0], data['duration']) for data in wo_data)
        for workcenter in self:
            if duration.get(workcenter.id):
                workcenter.performance = 100 * duration_expected.get(workcenter.id, 0.0) / duration[workcenter.id]
            else:
                workcenter.performance = 0.0

    @api.multi
    @api.constrains('capacity')
    def _check_capacity(self):
        if any(workcenter.capacity <= 0.0 for workcenter in self):
            raise exceptions.UserError(_('The capacity must be strictly positive.'))

    @api.multi
    def unblock(self):
        self.ensure_one()
        if self.working_state != 'blocked':
            raise exceptions.UserError(_("It has been unblocked already. "))
        times = self.env['mrp.workcenter.productivity'].search([('workcenter_id', '=', self.id), ('date_end', '=', False)])
        times.write({'date_end': fields.Datetime.now()})
        return {'type': 'ir.actions.client', 'tag': 'reload'}

    @api.model
    def create(self, vals):
        calender_event = self.env['calendar.event']
        maintenance_request = self.env['maintenance.request']

        maintenance_request_dict = {}
        schedule_date=''

        preventive_recurrence_list, checklist_recurrence_list = [],[]
        if vals.get('workcenter_lines',False):
            preventive_recurrence_list = [i[2]['recurrence'] for i in vals['workcenter_lines'] if i[2].get('recurrence',False)]

        if vals.get('workcenter_checklist_lines', False):
            checklist_recurrence_list = [i[2]['recurrence'] for i in vals['workcenter_checklist_lines'] if i[2].get('recurrence', False)]

        if set(preventive_recurrence_list) != set(checklist_recurrence_list):
            raise ValidationError('Please use all those recurrence that are defined in Preventive')

        res = super(MrpWorkcenter, self).create(vals)
        from_date = ''
        to_date = ''

        for val in res:
            for recurrence in val.workcenter_lines:
                recurrence.maintenance_request_done = True
                recurrence_data = []
                for vals in val.workcenter_checklist_lines:
                    if recurrence.recurrence.id == vals.recurrence.id and vals.in_active==False:
                        val_data1 = (0, False, {
                            'recurrence': vals.recurrence.id,
                            'check_list': vals.check_list.id,
                            'remarks': vals.remarks,
                            'from_workcenter':True
                        })

                        recurrence_data.append(val_data1)
                # maintenance_request.write({'maintenance_checklist_lines': recurrence_data})
                if recurrence.inactive == True:
                    state_data = 'cancel'
                    maintenance_request_dict = {
                        'maintenance_checklist_lines':recurrence_data,
                        'workcenter_id': res.id,
                        'schedule_date': recurrence.next_schedule_date,
                        'recurrence': recurrence.recurrence.id,
                        'maintenance_type': 'preventive',
                        'duration':recurrence.duration,
                        # 'state':state_data,
                    }
                else:
                    maintenance_request_dict = {
                        'maintenance_checklist_lines': recurrence_data,
                        'workcenter_id': res.id,
                        'schedule_date': recurrence.next_schedule_date,
                        'recurrence': recurrence.recurrence.id,
                        'maintenance_type': 'preventive',
                        'duration': recurrence.duration,

                    }

                maintenance_request.create(maintenance_request_dict)

                # cal_dict = {
                #     'name': "test",
                #     'state': "draft",
                #     'start':str(vals.next_schedule_date),
                #     'stop':"2019-08-26 12:20:20",
                #     'start_datetime': '%s 11:00:00' %(vals.next_schedule_date, ),
                #     'user_id':self.env.user.id,
                # }
                #
                # calender_event.create(cal_dict)

        # self.env['calender_event'].search([('workcenter_id', '=', self.id), ('date_end', '=', False)])

        # if not res.user_line_ids:
        #     raise ValidationError("Please Choose Users...")

        return res

    @api.multi
    def unlink(self):

        for val in self:
            data = val.env['mrp.bom'].search([('active', '=', True)])
            for vals in data:
                for value in vals.process_ids:
                    for value1 in value.process_name:
                        for value2 in value1.operation_ids:
                            if value2.workcenter_id.name == val.name:
                                raise UserError(_(
                                    """You cannot delete a Work center with active Bom's."""))

        return super(MrpWorkcenter, self).unlink()

class MrpWorkcenterProductivityLoss(models.Model):
    _name = "mrp.workcenter.productivity.loss"
    _description = "TPM Big Losses"
    _order = "sequence, id"

    name = fields.Char('Reason', required=True)
    sequence = fields.Integer('Sequence', default=1)
    manual = fields.Boolean('Is a Blocking Reason', default=True)
    loss_type = fields.Selection([
        ('availability', 'Availability'),
        ('performance', 'Performance'),
        ('quality', 'Quality'),
        ('productive', 'Productive')], "Effectiveness Category",
        default='availability', required=True)

class MRP_Lot_details(models.Model):
    _name = "mrp.lot.details"

    # name = fields.Char('Reason', required=True)

    @api.model
    def default_get(self, fields_list):
        defaults = super(MRP_Lot_details, self).default_get(fields_list)
        for val in self:
            # print("f")
            pass

        return defaults

    name = fields.Many2one("product.product", string="Product", related='workorder_id.product_id')
    product_id = fields.Many2one("product.product", string="Product", related='workorder_id.product_id')
    lot_serial_detail_id = fields.Many2one('mrp.workcenter.productivity', string="Lot/Serial Detail Id")
    lot_line_ids= fields.One2many("mrp.lot.details.lines", 'lot_line_id',
                                        string="Lot/Serial")
    workorder_id = fields.Many2one('mrp.workorder', 'Work Order')
    production_id = fields.Many2one("mrp.production", string="Production No")
    qty = fields.Float('To Forward', digits=dp.get_precision('Manufacturing Unit of Measure'))
    sum_current_qty = fields.Float('Total Current Qty',compute='_compute_qty',  digits=dp.get_precision('Manufacturing Unit of Measure'))
    sum_pending_qty = fields.Float('Total Qty From Previous Process', compute='_compute_qty', digits=dp.get_precision('Manufacturing Unit of Measure'))
    sum_rejected_qty = fields.Float('Rejected Qty', compute='_compute_qty',
                                    digits=dp.get_precision('Manufacturing Unit of Measure'))
    sum_rework_qty = fields.Float('Rework Qty', compute='_compute_qty',
                                  digits=dp.get_precision('Manufacturing Unit of Measure'))

    have_lot = fields.Boolean("Have Lot")
    serial_saved_this_time = fields.Boolean("Serial Saved Lot")

    state = fields.Selection([
        ('pending', 'Pending'),
        ('ready', 'Ready'),
        ('progress', 'In Progress'),
        ('inspection_pending', 'Pending Inspection'),
        ('done', 'Finished'),
        ('cancel', 'Cancelled')], string='Status', related='workorder_id.state')

    @api.one
    @api.depends('lot_line_ids.qty', 'lot_line_ids.current_qty', 'lot_line_ids.rework_qty', 'lot_line_ids.rejected_qty')
    def _compute_qty(self):
        current_qty = 0
        pending_qty = 0
        rejected_qty = 0
        rework_qty = 0
        for val in self.lot_line_ids:
            current_qty += val.current_qty
            pending_qty += val.qty
            rejected_qty += val.rejected_qty
            rework_qty += val.rework_qty

        self.sum_current_qty = current_qty
        self.sum_pending_qty = pending_qty
        self.sum_rejected_qty = rejected_qty
        self.sum_rework_qty = rework_qty

    def save_data(self):
        all_lots = []

        for val in self:
            if val.sum_rejected_qty > (val.workorder_id.sum_rejected_qty + val.workorder_id.done_qty + val.workorder_id.qty_produced):
                raise ValidationError("Please Check Rejected Qty")

            if val.sum_rework_qty > (val.workorder_id.sum_rework_qty + val.workorder_id.done_qty + val.workorder_id.qty_produced):
                raise ValidationError("Please Check Rework Qty")

            # elif not val.have_lot and val.sum_reject_and_rework > (val.workorder_id.qty_production - val.workorder_id.qty_produced):
            #     raise ValidationError(
            #         "Sum of Rejected,Rework and Current Qty Cannot be Greater than {}...".format(lot_line_id.qty))

        if self.product_id.product_tmpl_id.tracking == 'serial':
            self.workorder_id.serial_saved_this_time = True
            if self.workorder_id.qty_produced != self.workorder_id.qty_production:
                self.workorder_id.state = 'progress'

        if self.sum_current_qty == 0:
            raise  ValidationError("There is not any Qty to Proceed...")

        for val in self.lot_line_ids:
            if val.is_serial:
                val.is_serial_done = True

        self.workorder_id.done_lot_this_time = True
        for val in self.lot_line_ids:
            val.data_saved = True

            if val.lot_serial.id not in all_lots:
                if self.sum_current_qty != self.qty:
                    raise ValidationError("Sum of Current Quantities Must be Equal to To Total Current Qty...")
            else:
                raise ValidationError("Cannot Have Same Lot...")
            all_lots.append(val.lot_serial.id)

    @api.onchange('product_id', 'workorder_id', 'production_id')
    def _onchange_product_id(self):
        input_output_data=[]
        # print("on change  workingggggggggggggggg")

        if self.workorder_id.lot_serial:
            if self.product_id.product_tmpl_id.tracking == 'serial':

                if self.qty > 0:
                    self.serial_saved_this_time = True

                for i in range(0, int(self.qty)):
                    data = (0, False, {
                        # 'input_output_id': self.id,
                        'workorder_id': self.workorder_id.id,
                        'production_id': self.production_id.id,
                        'current_qty': 1,
                        'have_lot':self.have_lot,
                        'is_serial':True

                    })
                    input_output_data.append(data)

                self.lot_line_ids = input_output_data

            elif self.product_id.product_tmpl_id.tracking == 'lot':
                for i in range(0, 1):
                    data = (0, False, {
                        # 'input_output_id': self.id,
                        'workorder_id': self.workorder_id.id,
                        'production_id': self.production_id.id,
                        # 'qty': int(self.qty)
                        'have_lot': self.have_lot,
                        'is_serial': False

                    })
                    input_output_data.append(data)
                self.lot_line_ids = input_output_data
        #
        # all_issued_products = self.env['issue.mrs.line'].search(
        #     [('production_id', '=', self.production_id.id)])

class MRP_Lot_details_Lines(models.Model):
    _name = "mrp.lot.details.lines"

    # name = fields.Char('Reason', required=True)
    lot_serial = fields.Many2one('stock.production.lot', "Lot/Serial")
    qty = fields.Float('Qty From Previous Process', digits=dp.get_precision('Manufacturing Unit of Measure'), default=0.0)
    lot_line_id = fields.Many2one("mrp.lot.details", string='Lot Line')

    lot_detail_lines_ids = fields.One2many("mrp.lot.details.raw.materials", 'lot_detail_lines_id',
                                   string="Lot/Serial")
    workorder_id = fields.Many2one('mrp.workorder', 'Work Order')
    production_id = fields.Many2one("mrp.production", string="Production No")
    product_id = fields.Many2one("product.product", related='workorder_id.product_id')
    name = fields.Many2one("product.product", related='workorder_id.product_id')
    state = fields.Selection([
        ('pending', 'Pending'),
        ('ready', 'Ready'),
        ('progress', 'In Progress'),
        ('inspection_pending', 'Pending Inspection'),
        ('done', 'Finished'),
        ('cancel', 'Cancelled')], string='Status', related='workorder_id.state')
    total_done = fields.Float('Total Done', digits=dp.get_precision('Manufacturing Unit of Measure'))
    current_qty = fields.Float('Current Qty', default=0.0, digits=dp.get_precision('Manufacturing Unit of Measure'))
    data_saved = fields.Boolean("Data Saved")
    have_lot = fields.Boolean("Have Lot")
    is_serial = fields.Boolean("Is Serial")
    is_serial_done = fields.Boolean("Is Serial Done")

    rejected_qty = fields.Float('Rejected Qty', digits=dp.get_precision('Manufacturing Unit of Measure'))
    rework_qty = fields.Float('Rework Qty', digits=dp.get_precision('Manufacturing Unit of Measure'))
    remarks = fields.Text("Remarks")

    @api.onchange('rejected_qty')
    def onchange_rejected_qty(self):
        for val in self:
            if val.lot_line_id.sum_rejected_qty > (
                    val.workorder_id.sum_rejected_qty + val.workorder_id.done_qty + val.workorder_id.qty_produced):
                raise ValidationError("Please Check Rejected Qty")

    @api.onchange('rework_qty')
    def onchange_rework_qty(self):
        for val in self:
            if val.lot_line_id.sum_rework_qty > (
                            val.workorder_id.sum_rework_qty + val.workorder_id.done_qty + val.workorder_id.qty_produced):
                raise ValidationError("Please Check Rework Qty")

    @api.onchange('current_qty')
    def onchange_current_qty(self):
        for val in self:
            if val.qty - val.total_done == 0 and not val.have_lot:
                raise ValidationError("You cannot Insert More Quantities in this Lot...")
            if val.current_qty > (val.qty - val.total_done) and not val.have_lot:
                raise ValidationError("Current Qty Cannot be Greater than {}...".format(val.qty - val.total_done))

    # @api.onchange('rejected_qty', 'rework_qty')
    # def onchange_rework_qty(self):
    #     for val in self:
    #         if (val.rework_qty + val.rejected_qty) > (val.qty + val.current_qty - val.total_done) and not val.have_lot:
    #             raise ValidationError("Rejected or Rework Cannot be Greater than {}...".format(val.qty + val.current_qty - val.total_done))
    #
    #         elif val.have_lot and (val.rework_qty + val.rejected_qty + val.current_qty) > (lot_line_id.qty):
    #             raise ValidationError("Sum of Rejected,Rework and Current Qty Cannot be Greater than {}...".format(lot_line_id.qty))

    # @api.multi
    # def unlink(self):
    #     print("UNBLINGKKKKKKKKKKKKKKKKK")
    #     res = super(MRP_Lot_details_Lines, self).unlink()
    #     for val in self:
    #         if val.id:
    #             print("True")
    #         else:
    #             print("False")
    #
    #
    #     return res

def action_open_form_lot_serial_btn(self):
        view = self.env.ref('mrp.workorder_lot_serial_raw_materials_form')
        # if self.rework_qty <= 0:
        #     raise ValidationError("Rework Qty cannot be 0 for Rework Manufacture")
        # else:
        consumed_id = self.env['mrp.lot.details.raw.materials'].search([('lot_detail_lines_id', '=', self.id)])

        if len(consumed_id) > 0:
            return {
                'name': _('Lot/Serial Raw Materials'),
                'type': 'ir.actions.act_window',
                'view_type': 'form',
                'view_mode': 'form',
                'res_model': 'mrp.lot.details.raw.materials',
                'views': [(view.id, 'form')],
                'view_id': view.id,
                'target': 'new',
                'res_id': consumed_id[0].id,
                # 'context': {'default_required_qty': self.product_uom_qty}
            }
        else:
            return {
                'name': _('Lot/Serial Raw Materials'),
                'type': 'ir.actions.act_window',
                'view_type': 'form',
                'view_mode': 'form',
                'res_model': 'mrp.lot.details.raw.materials',
                'views': [(view.id, 'form')],
                'view_id': view.id,
                'target': 'new',
                'context': {
                            'default_lot_detail_lines_id': self.id,
                            'default_workorder_id': self.workorder_id.id,
                            'default_production_id': self.production_id.id
                            }
                    }

class MRP_Lot_details_Raw_materials(models.Model):
    _name = "mrp.lot.details.raw.materials"

    workorder_id = fields.Many2one('mrp.workorder', 'Work Order')
    qty = fields.Float("Done Quantity", digits=dp.get_precision('Manufacturing Unit of Measure'))

    # name = fields.Char('Reason', required=True)

    lot_serial_raw_material_line_ids= fields.One2many("mrp.lot.details.raw.materials.lines", 'lot_serial_raw_material_line_id',
                                        string="Lot/Serial")
    lot_detail_lines_id = fields.Many2one('mrp.lot.details.lines', 'Lot Detail Lines')
    production_id = fields.Many2one("mrp.production", string="Production Id")

    state = fields.Selection([
        ('pending', 'Pending'),
        ('ready', 'Ready'),
        ('progress', 'In Progress'),
        ('inspection_pending', 'Pending Inspection'),
        ('done', 'Finished'),
        ('cancel', 'Cancelled')], string='Status', related='workorder_id.state')

    @api.onchange('workorder_id')
    def _onchange_workorder_id(self):
        result = {}
        input_output_data = []

        all_issued_products = self.env['issue.mrs.line'].search(
            [('production_id', '=', self.production_id.id)])

        for val in all_issued_products:
            # all_issued_products22 = self.env['product.product'].search(
            #     [('id', '=', val.product_id.id)])

            for tracking in val.issue_mrs_line_tracking_ids:
                data = (0, False, {
                    # 'input_output_id': self.id,
                    'product_id': tracking.product_id.id,
                    'lot_serial': tracking.lot_id.id,
                    'workorder_id': self.workorder_id.id,
                    'production_id': self.production_id.id,
                    'qty':tracking.product_qty

                })
                input_output_data.append(data)

            self.lot_serial_raw_material_line_ids = input_output_data

            # for lines in self.lot_serial_raw_material_line_ids:
            #     lines.product_id = all_issued_products22.id

            # for vals in all_issued_products22:
            #
            #
            #     data = (0, False, {
            #         # 'input_output_id': self.id,
            #         'product_id': vals.id,
            #         'workorder_id':self.workorder_id.id,
            #         'production_id':self.production_id.id
            #
            #     })
            #     input_output_data.append(data)
            #
            # self.lot_serial_raw_material_line_ids = input_output_data

            #
            # if all_issued_products22:
            #     print("alllllllllllllllllll", all_issued_products22)

        # for emp in emp_data1:
        #     emp_list.append(emp.id)
        # # , ('id', 'not in', self.already_took_helpers)
        # if emp_list:
        #     result['domain'] = {'name': [('id', 'in', tuple(emp_list))]}
        # else:
        #     result['domain'] = {}
        return result

class MRP_Lot_details_Raw_materials_lines(models.Model):
    _name = "mrp.lot.details.raw.materials.lines"

    production_id = fields.Many2one("mrp.production", string="Production Id")
    qty = fields.Float("Issued Quantity", digits=dp.get_precision('Manufacturing Unit of Measure'))
    # name = fields.Char('Reason', required=True)
    workorder_id = fields.Many2one('mrp.workorder', 'Work Order')
    lot_serial = fields.Many2one('stock.production.lot', "Lot/Serial")
    product_id = fields.Many2one("product.product", string="Product")
    qty_done = fields.Float("Quantity Done", digits=dp.get_precision('Manufacturing Unit of Measure'))

    lot_serial_raw_material_line_id = fields.Many2one('mmrp.lot.details.raw.materials', 'Lot Raw Detail Lines')

    state = fields.Selection([
        ('pending', 'Pending'),
        ('ready', 'Ready'),
        ('progress', 'In Progress'),
        ('inspection_pending', 'Pending Inspection'),
        ('done', 'Finished'),
        ('cancel', 'Cancelled')], string='Status', related='workorder_id.state')

    @api.onchange('qty_done')
    def _onchange_qty_done(self):

        if self.qty < self.qty_done:
            raise  ValidationError("Done qty cannot be greator than Issued Qty...")

    @api.onchange('product_id')
    def _onchange_product_id(self):

        emp_list = []
        result = {}

        dep_id = self.env['hr.department'].search(
            [('name', '=', 'Production')])
        emp_data1 = self.env['stock.production.lot'].search(
            [('department_id', '=', dep_id.id)])
        for emp in emp_data1:
            emp_list.append(emp.id)
        # , ('id', 'not in', self.already_took_helpers)
        if emp_list:
            result['domain'] = {'name': [('id', 'in', tuple(emp_list))]}
        else:
            result['domain'] = {}
        return result

class MrpWorkcenterProductivity(models.Model):
    _name = "mrp.workcenter.productivity"
    _description = "Workcenter Productivity Log"
    _order = "id desc"
    _rec_name = "loss_id"

    workcenter_id = fields.Many2one('mrp.workcenter', "Work Center", required=True)
    workorder_id = fields.Many2one('mrp.workorder', 'Work Order')
    user_id = fields.Many2one(
        'res.users', "User",
        default=lambda self: self.env.uid)
    loss_id = fields.Many2one(
        'mrp.workcenter.productivity.loss', "Loss Reason",
        ondelete='restrict', required=True)
    loss_type = fields.Selection(
        "Effectiveness", related='loss_id.loss_type', store=True)
    description = fields.Text('Description')
    date_start = fields.Datetime('Start Date', default=fields.Datetime.now, required=True)
    date_end = fields.Datetime('End Date')
    duration = fields.Float('Duration', compute='_compute_duration', store=True)
    qty = fields.Float("Done Quantity", digits=dp.get_precision('Manufacturing Unit of Measure'))
    # lot_serial = fields.Boolean("Lot/Serial"  , related='workorder_id.lot_serial')

    # name = fields.Many2one('mrp.routing', string="Process", related='workorder_id.process_id')
    # manufacturing_id = fields.Many2one("mrp.production", string="Manufacturing Order", related='workorder_id.production_id')
    # rework_reject_ids = fields.One2many("mrp.workorder.todo.checklist",'rework_reject_id', string="Manufacturing Order")

    state = fields.Selection([
        ('draft', 'Draft'),
        ('done', 'Done'),
    ], string='Status')

    company_id = fields.Many2one('res.company', 'Company', required=True, index=True,
                                 default=lambda self: self.env.user.company_id.id)

    status = fields.Selection([
        ('draft', 'Draft'),
        ('done', 'Done'),
    ], string='Status')
    product_id = fields.Many2one('product.product', string='Product')
    qty_received_from_challan = fields.Float('Qty Received From Challan', digits=dp.get_precision('Manufacturing Unit of Measure'))
    lot_serial_detail_ids = fields.One2many("mrp.lot.details", 'lot_serial_detail_id',
                                        string="Lot/Serial")

    # inspection_pending = fields.Boolean("Inspection Pending", compute="_compute_inspection_pending")

    # @api.multi
    # def _compute_inspection_pending(self):
    #     dep_id = self.env['hr.department'].search(
    #         [('rework_reject_id', '=', self.id)])

    @api.onchange('qty','loss_id','lot_serial')
    def onchange_qty(self):
        for val in self:
            if val.qty and val.qty > round(val.workorder_id.reserved_qty,6):
                raise ValidationError("Cannot Produce More than Reserved Quantity Which is {}...".format(val.workorder_id.reserved_qty))
            # elif val.qty:
            #     val.workorder_id.reserved_qty = val.workorder_id.reserved_qty - val.qty

    @api.model
    def create(self, values):
        res = super(MrpWorkcenterProductivity, self).create(values)
        res.state = 'done'
        # res.workorder_id.reserved_qty = res.workorder_id.reserved_qty - res.qty
        #
        # for val in res.manufacturing_id:
        #     for process in val.process_ids:
        #         if process.process_name.name == self.name.name:
        #             if process.lot_serial == True:
        #                 res.lot_serial = True
        #             else:
        #                 res.lot_serial = False

        return res

    @api.multi
    def write(self, vals):
        res = super(MrpWorkcenterProductivity, self).write(vals)

        # if vals.get('qty'):
        #     self.workorder_id.reserved_qty = self.workorder_id.reserved_qty - self.qty
        return res

    # @api.model
    # def create(self, values):
    #     res = super(MrpWorkcenterProductivity, self).create(values)
    #     res.state = 'done'
    #
    #
    #     return res

    def action_open_form_inspection_btn(self):
        view = self.env.ref('mrp.workorder_todo_checklist_form1')
        # if self.rework_qty <= 0:
        #     raise ValidationError("Rework Qty cannot be 0 for Rework Manufacture")
        # else:
        consumed_id = self.env['mrp.workorder.todo.checklist'].search([('rework_reject_id', '=', self.id)])

        # if self.qty <= 0:
        #     raise ValidationError("Done Qty Must be Greater than 0")
        # else:
        if len(consumed_id) > 0:
            return {
                'name': _('Reject/Rework'),
                'type': 'ir.actions.act_window',
                'view_type': 'form',
                'view_mode': 'form',
                'res_model': 'mrp.workorder.todo.checklist',
                'views': [(view.id, 'form')],
                'view_id': view.id,
                'target': 'new',
                'res_id': consumed_id[0].id,
                # 'context': {'default_required_qty': self.product_uom_qty}
            }
        else:
            return {
                'name': _('Reject/Rework'),
                'type': 'ir.actions.act_window',
                'view_type': 'form',
                'view_mode': 'form',
                'res_model': 'mrp.workorder.todo.checklist',
                'views': [(view.id, 'form')],
                'view_id': view.id,
                'target': 'new',
                'context': {'default_work_order_id': self.workorder_id.id,
                            'default_todo_checklist_id':self.workorder_id.id,
                            'default_rework_reject_id':self.id,
                            'default_pending_qty': self.qty,
                            'default_date_end': self.date_end,
                            'default_date_start': self.date_start
                        }
                 }

    def action_open_form_lot_serial_btn(self):
        view = self.env.ref('mrp.workorder_lot_serial_form')

        # if self.rework_qty <= 0:
        #     raise ValidationError("Rework Qty cannot be 0 for Rework Manufacture")
        # else:
        consumed_id = self.env['mrp.lot.details'].search([('lot_serial_detail_id', '=', self.id)])

        # if self.qty <= 0:
        #     raise ValidationError("Done Qty Must be Greater than 0")
        # else:

        if len(consumed_id) > 0:
            return {
                'name': _('Lot/Serial'),
                'type': 'ir.actions.act_window',
                'view_type': 'form',
                'view_mode': 'form',
                'res_model': 'mrp.lot.details',
                'views': [(view.id, 'form')],
                'view_id': view.id,
                'target': 'current',
                'res_id': consumed_id[0].id,
                # 'context': {'default_required_qty': self.product_uom_qty}
            }
        else:
            return {
                'name': _('Lot/Serial'),
                'type': 'ir.actions.act_window',
                'view_type': 'form',
                'view_mode': 'form',
                'res_model': 'mrp.lot.details',
                'views': [(view.id, 'form')],
                'view_id': view.id,
                'target': 'current',
                'context': {
                            'default_lot_serial_detail_id': self.id,
                             'default_workorder_id': self.workorder_id.id,
                             'default_production_id':self.manufacturing_id.id,
                                'default_qty': self.qty,
                            }
                    }

        # self.env['mrp.lot.details'].insert_data()

    @api.depends('date_end', 'date_start')
    def _compute_duration(self):
        for blocktime in self:
            if blocktime.date_end:
                d1 = fields.Datetime.from_string(blocktime.date_start)
                d2 = fields.Datetime.from_string(blocktime.date_end)
                diff = d2 - d1
                if (blocktime.loss_type not in ('productive', 'performance')) and blocktime.workcenter_id.resource_calendar_id:
                    r = blocktime.workcenter_id.resource_calendar_id.get_work_hours_count(d1, d2, blocktime.workcenter_id.resource_id.id)
                    blocktime.duration = round(r * 60, 2)
                else:
                    blocktime.duration = round(diff.total_seconds() / 60.0, 2)
            else:
                blocktime.duration = 0.0

    @api.multi
    def button_block(self):
        breakdown_lines_list = []
        self.ensure_one()
        self.workcenter_id.order_ids.end_all()

        breakdown_lines = (0, False, {
            'from_date': datetime.datetime.now(),
            'reason_for_breakdown': self.loss_id.id
        })
        breakdown_lines_list.append(breakdown_lines)
        self.workcenter_id.write({'breakdown_ids': breakdown_lines_list})

# ===================================new class added to show tree view in preventive tab starts here==============================================
class MrpWorkcenterLines(models.Model):
    _name = 'mrp.workcenter.lines'

    user_id = fields.Many2one('res.users', string='User', index=True,
                              default=lambda self: self.env.user)
    workcenter_id = fields.Many2one('mrp.workcenter', 'Work Center')
    recurrence = fields.Many2one('mrp.workcenter.recurrence',string='Recurrence', required=True)
    duration = fields.Integer('Duration', store=True, required=True)
    start_date = fields.Datetime('Last Maintainance Date', store=True, required=True)
    next_schedule_date = fields.Datetime('Next Schedule Date', store=True)
    stop_date = fields.Datetime("Stop Date")
    # checklist = fields.Text('Check List', store=True)
    inactive = fields.Boolean('Inactive', store=True)
    maintenance_request_done = fields.Boolean('Maintenance Request Done', store=True)
    remarks = fields.Char('Remarks', store=True)
    company_id = fields.Many2one('res.company', 'Company', index=True, default=lambda self: self.env.user.company_id.id)
    # Trilok Added This active_inactive_flag field for solving bug-140 24-10-2020
    active_inactive_flag = fields.Boolean('Active/Inactive', default=False, store=True, help="It will be true if user change start date of inactive line and want to active it.")

    @api.onchange('recurrence', 'start_date', 'from_day' ,'duration')
    def start_date_onchange(self):
            least_date = ""
            if self.start_date:

                for val in self:

                    if datetime.datetime.strptime(val.start_date,"%Y-%m-%d %H:%M:%S") > datetime.datetime.today():
                        raise ValidationError("Last maintainance date must not be a future date.")

                    # if not val.from_day:
                    #     raise ValidationError("Please provide from day.")

                    if val.recurrence.recurrence_name.upper() == "MONTHLY":
                        temp_next_schedule_date,least_date = datetime.datetime.strptime(val.start_date,'%Y-%m-%d %H:%M:%S') +\
                                                             relativedelta.relativedelta(months=1),datetime.datetime.today() - relativedelta.relativedelta(months=1)
                    elif val.recurrence.recurrence_name.upper() == "QUARTERLY":
                        temp_next_schedule_date, least_date = datetime.datetime.strptime(val.start_date,'%Y-%m-%d %H:%M:%S') + relativedelta.relativedelta(months=3), datetime.datetime.today() - relativedelta.relativedelta(months=3)
                    elif val.recurrence.recurrence_name.upper() == "HALF YEARLY":
                        temp_next_schedule_date, least_date = datetime.datetime.strptime(val.start_date,'%Y-%m-%d %H:%M:%S') + relativedelta.relativedelta(months=6), datetime.datetime.today() - relativedelta.relativedelta(months=6)
                    elif val.recurrence.recurrence_name.upper() == "YEARLY":
                        temp_next_schedule_date,least_date = datetime.datetime.strptime(val.start_date,'%Y-%m-%d %H:%M:%S') + relativedelta.relativedelta(years=1),datetime.datetime.today() - relativedelta.relativedelta(years=1)
                    else:
                        temp_next_schedule_date, least_date = datetime.datetime.strptime(val.start_date,'%Y-%m-%d %H:%M:%S') + relativedelta.relativedelta(days=val.recurrence.recurrence_value), datetime.datetime.today() - relativedelta.relativedelta(days=val.recurrence.recurrence_value)

                    self.next_schedule_date = temp_next_schedule_date
                    self.stop_date = temp_next_schedule_date + relativedelta.relativedelta(hours= self.duration) #- relativedelta.relativedelta(hours=6, minute=30)

                    if temp_next_schedule_date < datetime.datetime.today():
                        raise ValidationError("Last Maintainance Date can't be before {x}".format(x=least_date))

    @api.onchange('recurrence')
    def unique_recurrence_check(self):
        if self.recurrence:
            a = 1

    @api.model
    def create(self, values):
        res = super(MrpWorkcenterLines, self).create(values)
        return res

    @api.onchange('start_date')
    def start_date_change_in_inactive_line(self):
        if self.start_date and self.inactive:
            self.active_inactive_flag = True

# ===================================new class added to show tree view in preventive tab ends here==============================================

# End Himanshu

# ===================================new class added to show tree view in Checklist tab starts here=============================================
class MrpWorkCenterChecklist(models.Model):
    _name = 'mrp.workcenter.checklist'

    workcenter_id = fields.Many2one('mrp.workcenter', 'Work Center')
    recurrence = fields.Many2one('mrp.workcenter.recurrence', string='Recurrence',
                                 required=True, domain='[]')
    check_list = fields.Many2one('mrp.workcenter.checklist.master', string='Check List',
                                 required=True)
    in_active = fields.Boolean('Inactive')
    remarks = fields.Text('Remarks')
    company_id = fields.Many2one(
        'res.company', 'Company',
        default=lambda self: self.env['res.company']._company_default_get('mrp.production'),
        required=True)

#Himanshu mrp 15-11-2020 if the recurrence is not in the preventive tab and added in checklist tab then the error will be raised
    @api.onchange('recurrence')
    def check_validation(self):
        data = []
        if self.recurrence:
            for rec in self.workcenter_id.workcenter_lines:
                data.append(rec.recurrence.recurrence_name)
                if self.recurrence.recurrence_name not in data:
                    raise ValidationError(_("Not in preventive tab"))
#End Himanshu

class MrpBreakdownHistory(models.Model):
    _name = 'mrp.breakdown.history'
    _description = 'Breakdown History'

    from_date = fields.Datetime('From Date', store=True)
    to_date = fields.Datetime('To Date', store=True)
    reason_for_breakdown = fields.Many2one('mrp.workcenter.productivity.loss',string="Reason For Breakdown")
    remedy = fields.Char("Remedy")
    spare_parts = fields.Char("Spare Parts")
    remarks = fields.Text("Remarks")
    workcenter_id = fields.Many2one('mrp.workcenter', 'Workcenter')

class RecurrenceMasterData(models.Model):
    _name = 'mrp.workcenter.recurrence'
    _rec_name = 'recurrence_name'

    recurrence_name = fields.Char('Name', required=True)
    recurrence_value = fields.Integer('Value', required=True)
    recurrence_type = fields.Selection([('pre_define','Pre-Defined'),('user_define','User-Defined')],
                                       required=True, default='user_define')
    company_id = fields.Many2one(
        'res.company', 'Company',
        default=lambda self: self.env['res.company']._company_default_get('mrp.production'),
        required=True)

    @api.multi
    def unlink(self):
        for val in self:
            if val.recurrence_type == "pre_define":
                raise ValidationError("Can't delete pre defined values")

        return super(RecurrenceMasterData,self).unlink()

#End Himanshu

class ChecklistMasterData(models.Model):
    _name = 'mrp.workcenter.checklist.master'

    name = fields.Char('Check List')
    company_id = fields.Many2one(
        'res.company', 'Company',
        default=lambda self: self.env['res.company']._company_default_get('mrp.production'),
        required=True)

#Himanshu mrp 6-12-2020 added this code referenced from pflo by trilok sir for the functionality of active/inactive button
class WorkcenterLinesActiveInactive(models.TransientModel):
    _name = "wc.active.inactive"
    _description = "Preventive Line Active Inactive Wizard"

    wc_line_id = fields.Many2one('mrp.workcenter.lines', string='Wc Line No')
    msg = fields.Char()

    @api.model
    def default_get(self, fields):
        active_id = self._context.get('active_id', False)
        res = super(WorkcenterLinesActiveInactive, self).default_get(fields)
        if active_id:
            if 'wc_line_id' in fields and 'wc_line_id' not in res:
                res['wc_line_id'] = active_id
            wc_line_id = self.env['mrp.workcenter.lines'].browse(active_id)
            requests = self.corresponding_maintenance_req(wc_line_id)
            if not wc_line_id.inactive:
                msg = 'Are You Sure You Want To Inactive This?'
                names = ''
                if requests:
                    for req in requests:
                        names += req.name + ' '
                if names == '':
                    res['msg'] = msg
                else:
                    res['msg'] = msg + "\n The Corresponding Maintenance Requests are: " + names + '.'
            else:
                msg = 'Are You Sure You Want To Active This?'
                res['msg'] = msg
        return res

    def corresponding_maintenance_req(self,wc_line_id):
        maintenance_request = self.env['maintenance.request']
        requests =[]
        if wc_line_id:
            requests = maintenance_request.search(
                [('workcenter_id', '=', wc_line_id.workcenter_id.id), ('recurrence', '=', wc_line_id.recurrence.id),
                 ('state', '=', 'normal')])
            return requests
        return requests

    @api.multi
    def yes(self):
        if self.wc_line_id:
            requests = self.corresponding_maintenance_req(self.wc_line_id)
            if not self.wc_line_id.inactive:
                if requests:
                    for req in requests:
                        req.write({'state':'cancel'})
                self.wc_line_id.inactive = True
                self.wc_line_id.active_inactive_flag = False
            else:
                if self.wc_line_id.active_inactive_flag:
                    recurrence_data = []
                    if self.wc_line_id.workcenter_id.workcenter_checklist_lines:
                        for vals in self.wc_line_id.workcenter_id.workcenter_checklist_lines:
                            if self.wc_line_id.recurrence.id == vals.recurrence.id and not vals.in_active:
                                val_data1 = (0, False, {
                                    'recurrence': vals.recurrence.id,
                                    'check_list': vals.check_list.id,
                                    'remarks': vals.remarks,
                                    'from_workcenter': True
                                })
                                recurrence_data.append(val_data1)
                    maintenance_request_dict = {
                        'maintenance_checklist_lines': recurrence_data,
                        'workcenter_id': self.wc_line_id.workcenter_id.id,
                        'schedule_date': self.wc_line_id.next_schedule_date,
                        'recurrence': self.wc_line_id.recurrence.id,
                        'maintenance_type': 'preventive',
                        'duration': self.wc_line_id.duration,
                    }
                    self.env['maintenance.request'].create(maintenance_request_dict)
                self.wc_line_id.inactive = False

    @api.multi
    def no(self):
        pass

    #End Himanshu


import torch
import gradio as  gr

model = torch.hub.load("../","custom",path="./weight/best.pt", source="local")

title = "基于Gradio的YOLOv5演示项目"

desc = "基于Gradio的YOLOv5项目，对apex假人进行识别"

base_conf,base_iou = 0.25,0.45

def det_image(img,conf,iou):
    model.conf = conf
    model.iou = iou
    return model(img).render()[0]

gr.Interface(inputs=[gr.Webcam(),gr.Slider(minimum=0,maximum=1,value=base_conf),gr.Slider(minimum=0,maximum=1,value=base_iou)],
             outputs=["image"],
             fn=det_image,
             title=title,
             description=desc,
             live=True, #动态更新，不需要每次都submit
             examples=[["./data/train/images/_5__640x640__jpg.rf.0f8063a8cdea2bba63d8c2d9126d2277.jpg",base_conf,base_iou]]
             ).launch(share=True)   #填入这个share=True，就会产生一个公网网址


import os
from unittest import TestCase
import unittest
from pathlib import Path
from aibolit.patterns.mutable_index.mutable_index import MutableIndex

class MutableIndexTestCase(TestCase):
    dir_path = Path(os.path.realpath(__file__)).parent

    @unittest.skip("Not implemented")
    def test_find_mutable_index_assignment(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexAssignment.java")),
            "Should match simple index assignment",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_prefix_increment(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexPrefixIncrement.java")),
            "Should match index prefix increment (++i)",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_prefix_decrement(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexPrefixDecrement.java")),
            "Should match index prefix decrement (--i)",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_postfix_increment(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexPostfixIncrement.java")),
            "Should match index postfix increment (i++)",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_postfix_decrement(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexPostfixDecrement.java")),
            "Should match index postfix decrement (i--)",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_addition_assignment(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexAdditionAssignment.java")),
            "Should match index addition assignment (+=)",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_subtraction_assignment(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexSubtractionAssignment.java")),
            "Should match index subtraction assignment (-=)",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_multiplication_assignment(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexMultiplicationAssignment.java")),
            "Should match index multiplication assignment (*=)",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_division_assignment(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexDivisionAssignment.java")),
            "Should match index division assignment (/=)",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_mod_assignment(self):
        self.assertEqual(
            [4],
            MutableIndex().value(Path(self.dir_path, "MutableIndexModAssignment.java")),
            "Should match index mod assignment (%=)",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_nested_for(self):
        self.assertEqual(
            [5],
            MutableIndex().value(Path(self.dir_path, "MutableIndexNestedFor.java")),
            "Should match mutable index in nested for",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_hidden_nested_for(self):
        self.assertEqual(
            [5],
            MutableIndex().value(Path(self.dir_path, "MutableIndexHiddenNestedFor.java")),
            "Should match mutable index hidden in nested for",
        )

    @unittest.skip("Not implemented")
    def test_find_mutable_index_no_block_for(self):
        self.assertEqual(
            [3],
            MutableIndex().value(Path(self.dir_path, "MutableIndexNoBlockFor.java")),
            "Should match mutable index in for with no block",
        )