import os
import sys
import argparse

import torch
from torch import nn
import torch.distributed as dist
import torch.backends.cudnn as cudnn
from torchvision import models as torchvision_models
from torchvision import transforms as pth_transforms
from PIL import Image
import numpy as np

import utils
from eval_knn_imagenet import extract_features

sys.path.append("../../")
from helpers.checkpoint_loader import CheckpointsLoader

class CopydaysDataset():
    def __init__(self, basedir):
        self.basedir = basedir
        self.block_names = (
            ['original', 'strong'] +
            ['jpegqual/%d' % i for i in
             [3, 5, 8, 10, 15, 20, 30, 50, 75]] +
            ['crops/%d' % i for i in
             [10, 15, 20, 30, 40, 50, 60, 70, 80]])
        self.nblocks = len(self.block_names)

        self.query_blocks = range(self.nblocks)
        self.q_block_sizes = np.ones(self.nblocks, dtype=int) * 157
        self.q_block_sizes[1] = 229
        # search only among originals
        self.database_blocks = [0]

    def get_block(self, i):
        dirname = self.basedir + '/' + self.block_names[i]
        fnames = [dirname + '/' + fname
                  for fname in sorted(os.listdir(dirname))
                  if fname.endswith('.jpg')]
        return fnames

    def get_block_filenames(self, subdir_name):
        dirname = self.basedir + '/' + subdir_name
        return [fname
                for fname in sorted(os.listdir(dirname))
                if fname.endswith('.jpg')]

    def eval_result(self, ids, distances):
        j0 = 0
        for i in range(self.nblocks):
            j1 = j0 + self.q_block_sizes[i]
            block_name = self.block_names[i]
            I = ids[j0:j1]   # block size
            sum_AP = 0
            if block_name != 'strong':
                # 1:1 mapping of files to names
                positives_per_query = [[i] for i in range(j1 - j0)]
            else:
                originals = self.get_block_filenames('original')
                strongs = self.get_block_filenames('strong')

                # check if prefixes match
                positives_per_query = [
                    [j for j, bname in enumerate(originals)
                     if bname[:4] == qname[:4]]
                    for qname in strongs]

            for qno, Iline in enumerate(I):
                positives = positives_per_query[qno]
                ranks = []
                for rank, bno in enumerate(Iline):
                    if bno in positives:
                        ranks.append(rank)
                sum_AP += score_ap_from_ranks_1(ranks, len(positives))

            print("eval on %s mAP=%.3f" % (
                block_name, sum_AP / (j1 - j0)))
            j0 = j1

# from the Holidays evaluation package
def score_ap_from_ranks_1(ranks, nres):
    """ Compute the average precision of one search.
    ranks = ordered list of ranks of true positives
    nres  = total number of positives in dataset
    """

    # accumulate trapezoids in PR-plot
    ap = 0.0

    # All have an x-size of:
    recall_step = 1.0 / nres

    for ntp, rank in enumerate(ranks):

        # y-size on left side of trapezoid:
        # ntp = nb of true positives so far
        # rank = nb of retrieved items so far
        if rank == 0:
            precision_0 = 1.0
        else:
            precision_0 = ntp / float(rank)

        # y-size on right side of trapezoid:
        # ntp and rank are increased by one
        precision_1 = (ntp + 1) / float(rank + 1)

        ap += (precision_1 + precision_0) * recall_step / 2.0

    return ap

class ImgListDataset(torch.utils.data.Dataset):
    def __init__(self, img_list, transform=None):
        self.samples = img_list
        self.transform = transform

    def __getitem__(self, i):
        with open(self.samples[i], 'rb') as f:
            img = Image.open(f)
            img = img.convert('RGB')
        if self.transform is not None:
            img = self.transform(img)
        return img, i

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

def is_image_file(s):
    ext = s.split(".")[-1]
    if ext in ['jpg', 'jpeg', 'png', 'ppm', 'bmp', 'pgm', 'tif', 'tiff', 'webp']:
        return True
    return False

@torch.no_grad()
def extract_features(image_list, model, args, multiscale=False):
    transform = pth_transforms.Compose([
        pth_transforms.Resize((args.imsize, args.imsize), interpolation=3),
        pth_transforms.ToTensor(),
        pth_transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
    ])
    tempdataset = ImgListDataset(image_list, transform=transform)
    data_loader = torch.utils.data.DataLoader(tempdataset, batch_size=args.batch_size_per_gpu,
        num_workers=args.num_workers, drop_last=False,
        sampler=torch.utils.data.DistributedSampler(tempdataset, shuffle=False))
    features = None
    for samples, index in utils.MetricLogger(delimiter="  ").log_every(data_loader, 10):
        samples = samples.cuda(non_blocking=True)
        index = index.cuda(non_blocking=True)
        if multiscale:
            feats = utils.multi_scale(samples, model)
        else:
            # print(samples.shape)
            feats = model(samples).clone()
            feats = feats.flatten(start_dim=1)

        # init storage feature matrix
        if dist.get_rank() == 0 and features is None:
            features = torch.zeros(len(data_loader.dataset), feats.shape[-1])
            if args.use_cuda:
                features = features.cuda(non_blocking=True)
            print(f"Storing features into tensor of shape {features.shape}")

        # get indexes from all processes
        y_all = torch.empty(dist.get_world_size(), index.size(0), dtype=index.dtype, device=index.device)
        y_l = list(y_all.unbind(0))
        y_all_reduce = torch.distributed.all_gather(y_l, index, async_op=True)
        y_all_reduce.wait()
        index_all = torch.cat(y_l)

        # share features between processes
        feats_all = torch.empty(
            dist.get_world_size(),
            feats.size(0),
            feats.size(1),
            dtype=feats.dtype,
            device=feats.device,
        )
        output_l = list(feats_all.unbind(0))
        output_all_reduce = torch.distributed.all_gather(output_l, feats, async_op=True)
        output_all_reduce.wait()

        # update storage feature matrix
        if dist.get_rank() == 0:
            if args.use_cuda:
                features.index_copy_(0, index_all, torch.cat(output_l))
            else:
                features.index_copy_(0, index_all.cpu(), torch.cat(output_l).cpu())
    return features  # features is still None for every rank which is not 0 (main)

if __name__ == '__main__':
    parser = argparse.ArgumentParser('Copy detection on Copydays')
    parser.add_argument('--data_path', default='/path/to/copydays/', type=str,
        help="See https://lear.inrialpes.fr/~jegou/data.php#copydays")
    parser.add_argument('--whitening_path', default='/path/to/whitening_data/', type=str,
        help="""Path to directory with images used for computing the whitening operator.
        In our paper, we use 20k random images from YFCC100M.""")
    parser.add_argument('--distractors_path', default='/path/to/distractors/', type=str,
        help="Path to directory with distractors images. In our paper, we use 10k random images from YFCC100M.")
    parser.add_argument('--imsize', default=320, type=int, help='Image size (square image)')
    parser.add_argument('--batch_size_per_gpu', default=16, type=int, help='Per-GPU batch-size')
    parser.add_argument('--pretrained_weights', default='', type=str, help="Path to pretrained weights to evaluate.")
    parser.add_argument('--use_cuda', default=True, type=utils.bool_flag)
    parser.add_argument('--arch', default='resnet50', type=str, help='Architecture')
    parser.add_argument('--num_workers', default=10, type=int, help='Number of data loading workers per GPU.')
    parser.add_argument("--dist_url", default="env://", type=str, help="""url used to set up
        distributed training; see https://pytorch.org/docs/stable/distributed.html""")
    parser.add_argument("--local_rank", default=0, type=int, help="Please ignore and do not set this argument.")
    parser.add_argument('--model', default='carp', choices=['carp', 'mocov3', 'obow', 'barlowtwins', 'obow', 'vicreg', 'deepclusterv2',
                                                              "infomin", 'triplet', "dino", "swav", "selav2"], type=str, help='model name')

    args = parser.parse_args()

    utils.init_distributed_mode(args)
    print("git:\n  {}\n".format(utils.get_sha()))
    print("\n".join("%s: %s" % (k, str(v)) for k, v in sorted(dict(vars(args)).items())))
    cudnn.benchmark = True

    # ============ building network ... ============
    if args.arch in torchvision_models.__dict__.keys():
        model = torchvision_models.__dict__[args.arch](num_classes=0)
        model.fc = torch.nn.Identity()
    else:
        print(f"Architecture {args.arch} non supported")
        sys.exit(1)

    if args.use_cuda:
        model.cuda()

    checkpoint_loader = CheckpointsLoader(args.pretrained_weights)
    model = checkpoint_loader.load_pretrained(model, model_name=args.model)
    model.eval()

    dataset = CopydaysDataset(args.data_path)

    # ============ Extract features ... ============
    # extract features for queries
    queries = []
    for q in dataset.query_blocks:
        queries.append(extract_features(dataset.get_block(q), model, args))
    if utils.get_rank() == 0:
        queries = torch.cat(queries)
        print(f"Extraction of queries features done. Shape: {queries.shape}")

    # extract features for database
    database = []
    for b in dataset.database_blocks:
        database.append(extract_features(dataset.get_block(b), model, args))

    # extract features for distractors
    if os.path.isdir(args.distractors_path):
        print("Using distractors...")
        list_distractors = [os.path.join(args.distractors_path, s) for s in os.listdir(args.distractors_path) if is_image_file(s)]
        database.append(extract_features(list_distractors, model, args))
    if utils.get_rank() == 0:
        database = torch.cat(database)
        print(f"Extraction of database and distractors features done. Shape: {database.shape}")

    # ============ Whitening ... ============
    if os.path.isdir(args.whitening_path):
        print(f"Extracting features on images from {args.whitening_path} for learning the whitening operator.")
        list_whit = [os.path.join(args.whitening_path, s) for s in os.listdir(args.whitening_path) if is_image_file(s)]
        features_for_whitening = extract_features(list_whit, model, args)
        if utils.get_rank() == 0:
            # center
            mean_feature = torch.mean(features_for_whitening, dim=0)
            database -= mean_feature
            queries -= mean_feature
            pca = utils.PCA(dim=database.shape[-1], whit=0.5)
            # compute covariance
            cov = torch.mm(features_for_whitening.T, features_for_whitening) / features_for_whitening.shape[0]
            pca.train_pca(cov.cpu().numpy())
            database = pca.apply(database)
            queries = pca.apply(queries)

    # ============ Copy detection ... ============
    if utils.get_rank() == 0:
        # l2 normalize the features
        database = nn.functional.normalize(database, dim=1, p=2)
        queries = nn.functional.normalize(queries, dim=1, p=2)

        # similarity
        similarity = torch.mm(queries, database.T)
        distances, indices = similarity.topk(20, largest=True, sorted=True)

        # evaluate
        retrieved = dataset.eval_result(indices, distances)
    dist.barrier()


#!./env/bin/python3
from flask import render_template, Flask, jsonify, make_response
from flask_swagger_ui import get_swaggerui_blueprint
from flask_cors import CORS
from app.api import request_api
from app.config import flask_env

if flask_env == 'production':
    config = 'config.production'
else:
    config = 'config.development'

app = Flask(__name__)
app.config.from_object(config)

### swagger specific ###
SWAGGER_URL = '/swagger'
API_URL = '/static/swagger.json'
SWAGGERUI_BLUEPRINT = get_swaggerui_blueprint(
    SWAGGER_URL,
    API_URL,
    config={
        'app_name': "Seans-Python-Flask-REST-Boilerplate"
    }
)

app.register_blueprint(SWAGGERUI_BLUEPRINT, url_prefix=SWAGGER_URL)
### end swagger specific ###

app.register_blueprint(request_api.get_blueprint())

# Create a URL route in our application for "/"
@app.route('/')
def home():
    """
    This function just responds to the browser ULR
    localhost:5000/
    :return:        the rendered template 'home.html'
    """
    return render_template('index.html')

if __name__ == '__main__':
    CORS = CORS(app)
    app.run(host='0.0.0.0', port='5000')


from gnuradio import gr, digital
from gnuradio import filter
from gnuradio import blocks
from gnuradio.fft import window
import sys
import numpy

try:
    from gnuradio import channels
except ImportError:
    print("Error: Program requires gr-channels.")
    sys.exit(1)

try:
    from matplotlib import pyplot
except ImportError:
    print("Error: Program requires matplotlib (see: matplotlib.sourceforge.net).")
    sys.exit(1)

fftlen = 8192

def main():
    N = 10000
    fs = 2000.0
    Ts = 1.0 / fs
    t = numpy.arange(0, N * Ts, Ts)

    # When playing with the number of channels, be careful about the filter
    # specs and the channel map of the synthesizer set below.
    nchans = 10

    # Build the filter(s)
    bw = 1000
    tb = 400
    proto_taps = filter.firdes.low_pass_2(1, nchans * fs,
                                          bw, tb, 80,
                                          window.WIN_BLACKMAN_hARRIS)
    print("Filter length: ", len(proto_taps))

    # Create a modulated signal
    npwr = 0.01
    data = numpy.random.randint(0, 256, N)
    rrc_taps = filter.firdes.root_raised_cosine(1, 2, 1, 0.35, 41)

    src = blocks.vector_source_b(data.astype(numpy.uint8).tolist(), False)
    mod = digital.psk_mod(samples_per_symbol=2)
    chan = channels.channel_model(npwr)
    rrc = filter.fft_filter_ccc(1, rrc_taps)

    # Split it up into pieces
    channelizer = filter.pfb.channelizer_ccf(nchans, proto_taps, 2)

    # Put the pieces back together again
    syn_taps = [nchans * t for t in proto_taps]
    synthesizer = filter.pfb_synthesizer_ccf(nchans, syn_taps, True)
    src_snk = blocks.vector_sink_c()
    snk = blocks.vector_sink_c()

    # Remap the location of the channels
    # Can be done in synth or channelizer (watch out for rotattions in
    # the channelizer)
    synthesizer.set_channel_map([0, 1, 2, 3, 4,
                                 15, 16, 17, 18, 19])

    tb = gr.top_block()
    tb.connect(src, mod, chan, rrc, channelizer)
    tb.connect(rrc, src_snk)

    vsnk = []
    for i in range(nchans):
        tb.connect((channelizer, i), (synthesizer, i))

        vsnk.append(blocks.vector_sink_c())
        tb.connect((channelizer, i), vsnk[i])

    tb.connect(synthesizer, snk)
    tb.run()

    sin = numpy.array(src_snk.data()[1000:])
    sout = numpy.array(snk.data()[1000:])

    # Plot original signal
    fs_in = nchans * fs
    f1 = pyplot.figure(1, figsize=(16, 12), facecolor='w')
    s11 = f1.add_subplot(2, 2, 1)
    s11.psd(sin, NFFT=fftlen, Fs=fs_in)
    s11.set_title("PSD of Original Signal")
    s11.set_ylim([-200, -20])

    s12 = f1.add_subplot(2, 2, 2)
    s12.plot(sin.real[1000:1500], "o-b")
    s12.plot(sin.imag[1000:1500], "o-r")
    s12.set_title("Original Signal in Time")

    start = 1
    skip = 2
    s13 = f1.add_subplot(2, 2, 3)
    s13.plot(sin.real[start::skip], sin.imag[start::skip], "o")
    s13.set_title("Constellation")
    s13.set_xlim([-2, 2])
    s13.set_ylim([-2, 2])

    # Plot channels
    nrows = int(numpy.sqrt(nchans))
    ncols = int(numpy.ceil(float(nchans) / float(nrows)))

    f2 = pyplot.figure(2, figsize=(16, 12), facecolor='w')
    for n in range(nchans):
        s = f2.add_subplot(nrows, ncols, n + 1)
        s.psd(vsnk[n].data(), NFFT=fftlen, Fs=fs_in)
        s.set_title("Channel {0}".format(n))
        s.set_ylim([-200, -20])

    # Plot reconstructed signal
    fs_out = 2 * nchans * fs
    f3 = pyplot.figure(3, figsize=(16, 12), facecolor='w')
    s31 = f3.add_subplot(2, 2, 1)
    s31.psd(sout, NFFT=fftlen, Fs=fs_out)
    s31.set_title("PSD of Reconstructed Signal")
    s31.set_ylim([-200, -20])

    s32 = f3.add_subplot(2, 2, 2)
    s32.plot(sout.real[1000:1500], "o-b")
    s32.plot(sout.imag[1000:1500], "o-r")
    s32.set_title("Reconstructed Signal in Time")

    start = 0
    skip = 4
    s33 = f3.add_subplot(2, 2, 3)
    s33.plot(sout.real[start::skip], sout.imag[start::skip], "o")
    s33.set_title("Constellation")
    s33.set_xlim([-2, 2])
    s33.set_ylim([-2, 2])

    pyplot.show()

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        pass


# coding: utf-8

# In[1]:

""" Topic Modelling using LDA - The following packages have been used to show basic steps to apply LDA for topic modelling:
(1) nltk
(2) stop_words
(3) gensim """

from nltk.tokenize import RegexpTokenizer
from nltk.stem.porter import PorterStemmer
from stop_words import get_stop_words
from gensim import corpora, models
import gensim

# In[2]:

""" Text Prerpocessing
Tokenization - converting documents into its atomic elements
Stopping - removing meaningless words
Stemming - merging words that are equivalent in meaning """

# In[4]:

""" Here RegexpTokenizer has been used to tokenize documents using regular expressions """
tokenizer = RegexpTokenizer(r'\w+')

# In[5]:

""" Here English stop words list has been created using get_stop_words from stop_words """
en_stop = get_stop_words('en')

# In[6]:

""" Here Porter Algorithm for stemming has been used from nltk """
p_stemmer = PorterStemmer()

# In[7]:

""" The following sample documents have been created for testing """

doc_a = "Brocolli is good to eat. My brother likes to eat good brocolli, but not my mother."

doc_b = "My mother spends a lot of time driving my brother around to baseball practice."

doc_c = "Some health experts suggest that driving may cause increased tension and blood pressure."

doc_d = "I often feel pressure to perform well at school, but my mother never seems to drive my brother to do better."

doc_e = "Health professionals say that brocolli is good for your health."

# In[8]:

""" Compile sample documents into a list """
doc_set = [doc_a, doc_b, doc_c, doc_d, doc_e]
print (doc_set)

# In[9]:

""" Initialise a list for tokenized documents in loop """

texts = []

# In[10]:

#loop through document list
for i in doc_set:

    #clean and tokenize document string
    raw = i.lower()
    tokens = tokenizer.tokenize(raw)

    #remove stop words from tokens
    stopped_tokens = [i for i in tokens if not i in en_stop]

    #stem tokens
    stemmed_tokens = [p_stemmer.stem(i) for i in stopped_tokens]

    #add tokens to list
    texts.append(stemmed_tokens)

# In[11]:

# print the resultant after tokenization, stop words removal and stemming

print(texts)

# In[16]:

""" Constructing a document-term matrix to understand how frequently each term occurs within each document.
First, we need to turn our tokenized documents into an id and  term dictionary suing Dictionary() function."""

dictionary = corpora.Dictionary(texts)

""" Check each tokens unique integer id """

print(dictionary.token2id)

# In[20]:

""" Now we convert tokenized documents into a document-term matrix. The function doc2bow coverts dictionary into bag of words
where the result ie corpus is a list of vectors equal to the number of documents and each document vector is a series of tuples
and the tuples are (term id , term frequency) pairs """

corpus = [dictionary.doc2bow(text) for text in texts]

print(corpus[0])

# In[23]:

""" Generate LDA model with num_topics as how mnay topics should be generated, id2word as mappings b/w id and strings
and passes (optional) as the number of lapse the model will take through corpus """

ldamodel = gensim.models.ldamodel.LdaModel(corpus, num_topics = 2, id2word = dictionary, passes=20)

# In[60]:

""" Print the resultant which includes 3 topics generated by LDA"""

print(ldamodel.print_topics(num_topics=2, num_words=4))

# In[ ]:

# In[ ]:


# -*- coding: utf-8 -*-
"""
Created on Mon Jan 25 14:24:02 2021

@author: Jireh Jam
"""

from configparser import ConfigParser
class MainConfig:

  def __init__(self, file_path):
    inpaint_config = ConfigParser()
    seen = inpaint_config.read(file_path)
    if not seen:
        raise ValueError('No config file found!')
    print(inpaint_config.sections())
    self.testing = TestingConfig(inpaint_config['TESTING'])
    self.training = TrainingConfig(inpaint_config['TRAINING'])

class TestingConfig:

  def __init__(self, test_section):
    self.batch_size = int(test_section['BATCH_SIZE'])
    self.img_height = int(test_section['IMG_HEIGHT'])
    self.img_width = int(test_section['IMG_WIDTH'])
    self.channels = int(test_section['CHANNELS'])
    self.mask_channels = int(test_section['MASK_CHANNELS'])
    self.imgs_in_batch = int(test_section['IMGS_IN_BATCH'])
    self.last_img_on =  int(test_section['LAST_IMG_ON'])
    self.num_epochs = int(test_section['NUM_EPOCHS'])
    self.g_learning_rate = float(test_section['GEN_LEARNING_RATE'])
    self.d_learning_rate = float(test_section['DISC_LEARNING_RATE'])
    self.gf = int(test_section['GEN_FILTER'])
    self.df = int(test_section['DISC_FILTER'])
    self.current_epoch = int(test_section['CURRNT_EPOCH'])
    self.sample_interval = int(test_section['SAMPLE_INTERVAL'])
    self.beta_1 = float(test_section['BETA_1'])
    self.beta_2 = float(test_section['BETA_2'])
    self.epsilon = float(test_section['EPSILON'])
    self.last_trained_epoch = int(test_section['LAST_TRAINED_EPOCH'])

class TrainingConfig:

  def __init__(self, training_section):
    self.batch_size = int(training_section['BATCH_SIZE'])
    self.img_height = int(training_section['IMG_HEIGHT'])
    self.img_width = int(training_section['IMG_WIDTH'])
    self.channels = int(training_section['NUM_CHANNELS'])
    self.mask_channels = int(training_section['MASK_CHANNELS'])
    self.num_epochs = int(training_section['NUM_EPOCHS'])
    self.g_learning_rate = float(training_section['GEN_LEARNING_RATE'])
    self.d_learning_rate = float(training_section['DISC_LEARNING_RATE'])
    self.gf = int(training_section['GEN_FILTER'])
    self.df = int(training_section['DISC_FILTER'])
    self.current_epoch = int(training_section['CURRNT_EPOCH'])
    self.sample_interval = int(training_section['SAMPLE_INTERVAL'])
    self.beta_1 = float(training_section['BETA_1'])
    self.beta_2 = float(training_section['BETA_2'])
    self.epsilon = float(training_section['EPSILON'])
    self.last_trained_epoch = int(training_section['LAST_TRAINED_EPOCH'])


import bpy
import bmesh
import os
from pathlib import Path

"""
This script is made for  Blender 2.92 and use the MeshSlicer (https://github.com/TomekSc/MeshSlicer).
To install the add-on:
    1- Downlowd MeshSlicer.py from the github
    2- On blender 2.92, go to Edit/Preference/Add-ons
    3- Click on Install add-on and select MeshSlicer.py
    4- Activate the add on by ticking his box on the add-ons list

To use it, put your files to preprocess on a folder and attribute it's path to FILES_FOLDER.
The sliced results will be save in SAVE_FOLDER/name_mesh/

Writed by Leopold Le Roux, 21/10/2021
"""

FILE_PATH = ""
FILES_FOLDER = Path("WHERE ARE THE STL FILES")
SAVE_FOLDER = Path("WHERE TO STORE THE STL FILES")
Z_MAX = 0
Z_MIN = 0
SLICE_Zs = []
SLIDE_HEIGHT = 2

def slice_a_file(name_file, input_path, output_path):
    "Will load the stl from the FILE_PATH and slice it, the slided mesh are save in SAVE_FOLDER"

    # if the results folder do not exist, create it
    if not os.path.exists(str(output_path)):
        os.makedirs(output_path)
    # Clean the results folder
    for file in output_path.glob("*.stl"):
        file.unlink()

    # Clear workspace
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete()

    # Found the Z size
    bpy.ops.import_mesh.stl(filepath=input_path)
    obj = bpy.context.active_object
    Z_MAX = max([v[-1] for v in obj.bound_box])
    Z_MIN = min([v[-1] for v in obj.bound_box])

    # Compute the Z height of the slides
    NUMBER_OF_SLICE = int((Z_MAX - Z_MIN) / SLIDE_HEIGHT)
    SLICE_Zs = []
    z = Z_MIN
    while z < Z_MAX:
        SLICE_Zs.append(z)
        z += SLIDE_HEIGHT
    SLICE_Zs.append(Z_MAX)

    for slide_number in range(NUMBER_OF_SLICE):

        # Clear workspace
        bpy.ops.object.select_all(action='SELECT')
        bpy.ops.object.delete()

        # Ask for 1 plan to slice
        bpy.data.scenes["Scene"].my_tool.slicerSize = 60
        bpy.ops.generate.operator(variant=0)

        # Add a second plan
        bpy.ops.object.select_all(action='DESELECT')
        bpy.data.objects['Slicer'].select_set(True)

        # Create a // plan
        bpy.ops.object.duplicate_move()
        bpy.data.objects['Slicer.001'].location = [0,0, SLICE_Zs[slide_number]]
        bpy.data.objects['Slicer'].location = [0,0, SLICE_Zs[slide_number+1]]

        # Import mesh
        bpy.ops.object.select_all(action='DESELECT')
        #bpy.ops.mesh.primitive_cube_add(size=30.0,location=(0,0,0))
        bpy.ops.import_mesh.stl(filepath=input_path)
        objects = bpy.context.selected_objects
        name_mesh = objects[0].name

        # Slice
        bpy.ops.object.select_all(action='DESELECT')

        bpy.data.objects['Slicer.001'].select_set(True)
        bpy.data.objects['Slicer'].select_set(True)

        bpy.data.objects[name_mesh].select_set(True)
        bpy.ops.slice.operator()

        # Extract the good layer
        bpy.ops.object.select_all(action='DESELECT')
        if slide_number == 0:
            bpy.data.objects["Bool result 0"].select_set(True)
        else:
            bpy.data.objects["Bool result 1"].select_set(True) # Select the part between the 2 plan

        bpy.ops.export_mesh.stl(filepath=str(output_path / f"{name_file}_slide_{slide_number}.stl"), use_selection=True)

# List file to process
raw_files = list(FILES_FOLDER.glob("*.stl"))
for file in raw_files:
    output_path =  SAVE_FOLDER / file.stem
    slice_a_file(file.stem, str(file), output_path)


# !/usr/bin/env python3
# -*- coding: utf-8 -*-
import time

def get_timestamp_sec():
    return int(time.time())

def get_timestamp_mills():
    return int(time.time() * 1000)

import urllib.request
import urllib.parse
import json
import ssl
ssl._create_default_https_context = ssl._create_unverified_context

def http_post_json(url, data):
    try:
        headers = {'Content-Type': 'application/json'}
        data = json.dumps(data)
        dataEncode = data.encode('utf-8')
        dataEncode = data.encode('utf-8')
        request = urllib.request.Request(url, dataEncode, headers)
        response = urllib.request.urlopen(request, timeout=30)
        respData = response.read().decode('utf-8')
        respJson = json.loads(respData)
        return respJson
    except urllib.error.URLError as e:
        print('err:', e)
        return {'success':False}
    except Exception as e:
        print('ex:', e)
        return {'success':False}

def http_get_json(url):
    try:
        request = urllib.request.Request(url)
        response = urllib.request.urlopen(request)
        respData = response.read().decode('utf-8')
        respJson = json.loads(respData)
        return respJson
    except urllib.error.URLError as e:
        print('err:', e)
        return {'success':False}
    except Exception as e:
        print('ex:', e)
        return {'success':False}

import base64

def img_to_base64(imgPath):
    with open(imgPath,'rb') as f:
        b64 = base64.b64encode(f.read())
        return b64.decode()

def base64_to_Img(base64Str, targetPath):
    with open(targetPath, 'wb') as f:
        imgBytes = base64.b64decode(base64Str.encode())
        f.write(imgBytes)
    f.close()

import uuid

def get_mac_addr():
    node = uuid.getnode()
    mac = uuid.UUID(int = node).hex[-12:]
    return mac

# def get_mac_addr():
#     import sys
#     import os
#     mac = None
#     print(sys.platform)
#     if sys.platform == "win32":
#         start = 0
#         for line in os.popen("ipconfig/all"):
#             if line.lstrip().startswith("网卡名字"):
#                 start = 1
#             if start == 1 and line.lstrip().startswith("Physical Address"):
#                 mac = line.split(":")[1].strip().replace("-", ":")
#                 break
#     else:
#         for line in os.popen("/sbin/ifconfig"):
#             if 'Ether' in line:
#                 mac = line.split()[1]
#                 break
#     return mac


#! /usr/bin/env
# Udacity Full Stack Nanodegree Project: Logs Analysis

import psycopg2
import calendar
import time

def connect():
    """Connect to the PostgreSQL database.  Returns a database connection."""
    return psycopg2.connect("dbname=news")

q1_SQL = "select * from ArticleCount limit 3;"

def question1():
    conn = connect()
    cur = conn.cursor()
    cur.execute(q1_SQL)

    for record in cur:
        title = record[0]
        views = record[1]
        print('"%s" - %d views' % (title, views))

    cur.close()
    conn.close()
    return

q2_SQL = """select authorsWork.name, sum(ArticleCount.count) from ArticleCount
         inner join authorsWork on ArticleCount.title=authorsWork.title group
         by authorsWork.name order by sum desc;"""

def question2():
    conn = connect()
    cur = conn.cursor()
    cur.execute(q2_SQL)

    for record in cur:
        name = record[0]
        views = record[1]
        print("%s - %d views" % (name, views))

    cur.close()
    conn.close()
    return

q3_SQL = 'select * from percentError where percent_error>1;'

def question3():
    conn = connect()
    cur = conn.cursor()
    cur.execute(q3_SQL)

    for record in cur:
        month = calendar.month_name[int(record[0])]
        day = int(record[1])
        year = int(record[2])
        percent = record[3]

        print("%s %d, %d - %.1f%% errors " % (month, day, year, percent))

    cur.close()
    conn.close()
    return

print("\nReport generated on %s at %s" % (time.strftime("%d/%m/%Y"),
      time.strftime("%H:%M:%S")))

print("\nThe three most popular articles of all time are:")
question1()

print("\nThe most popular article authors of all time are:")
question2()

print("\nDay(s) when more than 1%s of server requests lead to errors:" % ("%"))
question3()

print("\n")


from django.conf.urls import patterns, include, url
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from walkysite import settings
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
	#url(r'^$', 'walkysite.views.home', name='home'),
	url(r'^$', 'walkysite.views.index'),
	url(r'^jsdev/', include('jsdev.urls', namespace="jsdev")),
	#url(r'^jsdev/$', include('jsdev.urls', namespace="jsdev")),
	url(r'^maps_test/$', 'route.views.maps_test'),
	url(r'^maps/$', 'route.views.maps'),
	#url(r'^mapsdraw/$', 'route.views.mapsdraw'),
	#url(r'^updt/$', 'route.views.save_data'),
	url(r'^updt/$', 'route.views.update'),
	url(r'^cleardb/$', 'route.views.clearDB'),
	url(r'^all/$', include('route.urls')),
	#url(r'^map_from_db/$', 'route.views.show_map'),
	url(r'^map_from_db/$', 'route.views.get_points'),
	url(r'^places/$', 'route.views.places'),
	url(r'^routeList/$', 'route.views.routeList'),
    # url(r'^$', 'walkysite.views.home', name='home'),
    # url(r'^walkysite/', include('walkysite.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
)#+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

urlpatterns += staticfiles_urlpatterns()

#MEdia path for map_images
urlpatterns += patterns('',
        url(r'^media/(?P<path>.*)$',
            'django.views.static.serve',
            {'document_root': settings.MEDIA_ROOT, }),
    )


import re
import requests
from rdflib import Graph

class NameSpaces():
    def __init__(self, url, debug=False):
        self.stats = {}
        self.json = {}
        self.stats = {}
        self.namespaces = {}
        self.DEBUG = debug
        self.content = requests.get(url)
        self.url = url
        self.processor(self.content)
        self.graph = False
        return

    def load_graph(self, url):
        self.graph = Graph()
        self.graph.parse(url, format='ttl')
        return self.graph

    def get_namespace(self, spacestring):
        namespacecheck = re.search(r"\@prefix\s+(\S+)\:\s+<(\S+)>", spacestring)
        if namespacecheck:
            self.namespaces[namespacecheck.group(2)] = namespacecheck.group(1)
        return self.namespaces

    def processor(self, content):
        data = content.text.split('\n')
        success = False
        for line in data:
            if '@prefix' in line:
                self.get_namespace(line)
                success = True
        return success

    def counter(self, concept):
        for namespace in self.namespaces:
            if namespace in concept:
                if self.DEBUG:
                    print(self.namespaces[namespace])
                if self.namespaces[namespace] in self.stats:
                    self.stats[self.namespaces[namespace]] = self.stats[self.namespaces[namespace]] + 1
                else:
                    self.stats[self.namespaces[namespace]] = 1
        return self.stats

    def getstats(self):
        return self.stats

    def getnamespaces(self):
        return self.namespaces

    def getstatements(self):
        lines = 0
        for s, p, o in self.load_graph(self.url):
            self.counter("%s" % s)
            self.counter("%s" % p)
            self.counter("%s" % o)
            lines = lines + 1
        return lines


'''
Created on 25/6/2019

@author: Administrador
'''
from math import *
import pygame
from  numpy import *
from  ClaseModeloNumpy import *
import sys

#------------------------------------------------------------------------------

class ModeloCuerpo(object):
    '''
    classdocs
    '''

    #------------------------------------------------------------------------------
    #    Constructor

    def __init__(self, vertices, lados, Posicion, focal):
        '''
        Constructor
        '''
        self.modelo= Modela()

        self.DisFocal =     focal
        self.coordenadas =  vertices
        self.sec=           lados
        self.posicion =     Posicion
        self.Pn= []
        self.Pc= []

  #------------------------------------------------------------------------------

    def grafica(self, pantalla, Color, LimAxis, grosor):
        """

        """
        self.modelo.convierte_a_homogenea(self.coordenadas)                         # Convierte coordenadas a Homogenea (el resuktado queda acumulado)
        self.modelo.traslada(self.posicion[0], self.posicion[1], self.posicion[2])  # Traslada eje de coordenadas aaun lado
        self.modelo.perspectiva(self.DisFocal)
        self.Pn= self.modelo.convierte_a_normal(DOS_D)                              # Convierte coordenadas a Homogenea y traspone paraoperar

        Dim= pygame.display.Info()
        dimVert=  Dim.current_h
        dimHori=  Dim.current_w
        self.Pc = self.modelo.mapea_en_pantalla(self.Pn, [LimAxis,LimAxis],[-LimAxis,-LimAxis],[dimHori,dimVert])
        self.modelo.grafica(pantalla, Color, self.Pc, self.sec, grosor)


from django.conf.urls import patterns, url

urlpatterns = patterns(
    'datensparsam.apps.pdfbuilder.views',
    # Examples:
    # url(r'^$', 'datensparsam.views.home', name='home'),
    # url(r'^datensparsam/', include('datensparsam.foo.urls')),
    url(r'^$', 'index', {}, name='index'),
)


#!/usr/bin/python

import argparse
import gi

import json
import importlib
import logging
import os
import re
import signal
import subprocess
import pathlib
import traceback  # noqa

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib, Pango
from jinja2 import Environment

from ks_includes import functions
from ks_includes.KlippyWebsocket import KlippyWebsocket
from ks_includes.KlippyRest import KlippyRest
from ks_includes.files import KlippyFiles
from ks_includes.KlippyGtk import KlippyGtk
from ks_includes.printer import Printer
from ks_includes.widgets.keyboard import Keyboard
from ks_includes.config import KlipperScreenConfig
from panels.base_panel import BasePanel

logging.getLogger("urllib3").setLevel(logging.WARNING)
logging.getLogger('matplotlib').setLevel(logging.WARNING)
# This is here to avoid performance issues opening bed_mesh
import matplotlib.pyplot  # noqa

PRINTER_BASE_STATUS_OBJECTS = [
    'bed_mesh',
    'configfile',
    'display_status',
    'extruder',
    'fan',
    'gcode_move',
    'heater_bed',
    'idle_timeout',
    'pause_resume',
    'print_stats',
    'toolhead',
    'virtual_sdcard',
    'webhooks',
    'motion_report'
]

klipperscreendir = pathlib.Path(__file__).parent.resolve()

class KlipperScreen(Gtk.Window):
    """ Class for creating a screen for Klipper via HDMI """
    _cur_panels = []
    bed_temp_label = None
    connecting = False
    connecting_to_printer = None
    connected_printer = None
    currentPanel = None
    files = None
    filename = ""
    keyboard = None
    last_update = {}
    load_panel = {}
    number_tools = 1
    panels = {}
    popup_message = None
    screensaver = None
    printer = None
    printer_select_callbacks = []
    printer_select_prepanel = None
    rtl_languages = ['he_il']
    subscriptions = []
    shutdown = True
    updating = False
    update_queue = []
    _ws = None
    init_printer_timeout = None
    dpms_timeout = None
    screensaver_timeout = None
    reinit_count = 0

    def __init__(self, args, version):
        self.blanking_time = 600
        self.use_dpms = True
        self.apiclient = None
        self.version = version
        self.dialogs = []
        self.confirm = None

        configfile = os.path.normpath(os.path.expanduser(args.configfile))

        self._config = KlipperScreenConfig(configfile, self)
        self.lang = self._config.get_lang()

        logging.debug(f"OS Language: {os.getenv('LANG')}")

        self.lang_ltr = True
        for lang in self.rtl_languages:
            if os.getenv('LANG').lower().startswith(lang):
                self.lang_ltr = False
                Gtk.Widget.set_default_direction(Gtk.TextDirection.RTL)
                logging.debug("Enabling RTL mode")
                break

        Gtk.Window.__init__(self)
        monitor = Gdk.Display.get_default().get_primary_monitor()
        self.width = self._config.get_main_config().getint("width", monitor.get_geometry().width)
        self.height = self._config.get_main_config().getint("height", monitor.get_geometry().height)
        self.set_default_size(self.width, self.height)
        self.set_resizable(False)
        self.vertical_mode = self.width < self.height
        logging.info(f"Screen resolution: {self.width}x{self.height}")
        self.theme = self._config.get_main_config().get('theme')
        self.show_cursor = self._config.get_main_config().getboolean("show_cursor", fallback=False)
        self.gtk = KlippyGtk(self, self.width, self.height, self.theme, self.show_cursor,
                             self._config.get_main_config().get("font_size", "medium"))
        self.init_style()

        self.base_panel = BasePanel(self, title="Base Panel", back=False)
        self.add(self.base_panel.get())
        self.show_all()
        self.base_panel.activate()

        self.printer_initializing(_("Initializing"))
        if self._config.errors:
            self.show_error_modal("Invalid config file", self._config.get_errors())
            # Prevent this dialog from being destroyed
            self.dialogs = []
        self.set_screenblanking_timeout(self._config.get_main_config().get('screen_blanking'))

        # Move mouse to 0,0
        os.system("/usr/bin/xdotool mousemove 0 0")
        self.change_cursor()
        self.initial_connection()

    def initial_connection(self):
        printers = self._config.get_printers()
        default_printer = self._config.get_main_config().get('default_printer')
        logging.debug(f"Default printer: {default_printer}")
        if [True for p in printers if default_printer in p]:
            self.connect_printer(default_printer)
        elif len(printers) == 1:
            pname = list(printers[0])[0]
            self.connect_printer(pname)
        else:
            self.show_panel("printer_select", "printer_select", "Printer Select", 2)

    def connect_printer_widget(self, widget, name):
        self.connect_printer(name)

    def connect_printer(self, name):
        data = {
            "moonraker_host": "127.0.0.1",
            "moonraker_port": "7125",
            "moonraker_api_key": False
        }

        self.connecting_to_printer = name

        if self.connected_printer == name:
            if self.printer_select_prepanel is not None:
                self.show_panel(self.printer_select_prepanel, "", "", 2)
                self.printer_select_prepanel = None
            while len(self.printer_select_callbacks) > 0:
                i = self.printer_select_callbacks.pop(0)
                i()
            if self.printer.get_state() not in ["disconnected", "error", "startup", "shutdown"]:
                self.base_panel.show_heaters(True)
            self.base_panel.show_printer_select(True)
            self.base_panel.show_macro_shortcut(self._config.get_main_config().getboolean('side_macro_shortcut', True))
            return

        # Cleanup
        self.printer_select_callbacks = []
        self.printer_select_prepanel = None
        if self.files is not None:
            self.files.reset()
            self.files = None
        if self.printer is not None:
            self.printer.reset()
            self.printer = None

        for printer in self._config.get_printers():
            pname = list(printer)[0]

            if pname != name:
                continue
            data = printer[pname]
            break

        if self._ws is not None:
            self._ws.close()
        self.connecting = True

        logging.info(f"Connecting to printer: {name}")
        self.apiclient = KlippyRest(data["moonraker_host"], data["moonraker_port"], data["moonraker_api_key"])

        self.printer = Printer({
            "software_version": "Unknown"
        }, {
            'configfile': {
                'config': {}
            },
            'print_stats': {
                'state': 'disconnected'
            },
            'virtual_sdcard': {
                'is_active': False
            }
        }, self.state_execute)

        self._remove_all_panels()
        self.subscriptions = []
        for panel in list(self.panels):
            if panel not in ["printer_select", "splash_screen"]:
                del self.panels[panel]
        for dialog in self.dialogs:
            dialog.destroy()
        self.base_panel.show_printer_select(True)
        self.printer_initializing(_("Connecting to %s") % name)

        self.printer.set_callbacks({
            "disconnected": self.state_disconnected,
            "error": self.state_error,
            "paused": self.state_paused,
            "printing": self.state_printing,
            "ready": self.state_ready,
            "startup": self.state_startup,
            "shutdown": self.state_shutdown
        })

        self._ws = KlippyWebsocket(self,
                                   {
                                       "on_connect": self.init_printer,
                                       "on_message": self._websocket_callback,
                                       "on_close": self.printer_initializing
                                   },
                                   data["moonraker_host"],
                                   data["moonraker_port"]
                                   )

        self.files = KlippyFiles(self)
        self._ws.initial_connect()
        self.connecting = False

        self.connected_printer = name
        logging.debug(f"Connected to printer: {name}")

    def ws_subscribe(self):
        requested_updates = {
            "objects": {
                "bed_mesh": ["profile_name", "mesh_max", "mesh_min", "probed_matrix"],
                "configfile": ["config"],
                "display_status": ["progress", "message"],
                "fan": ["speed"],
                "gcode_move": ["extrude_factor", "gcode_position", "homing_origin", "speed_factor", "speed"],
                "idle_timeout": ["state"],
                "pause_resume": ["is_paused"],
                "print_stats": ["print_duration", "total_duration", "filament_used", "filename", "state", "message"],
                "toolhead": ["homed_axes", "estimated_print_time", "print_time", "position", "extruder",
                             "max_accel", "max_accel_to_decel", "max_velocity", "square_corner_velocity"],
                "virtual_sdcard": ["file_position", "is_active", "progress"],
                "webhooks": ["state", "state_message"],
                "firmware_retraction": ["retract_length", "retract_speed", "unretract_extra_length", "unretract_speed"],
                "motion_report": ["live_position", "live_velocity", "live_extruder_velocity"],
                "exclude_object": ["current_object", "objects", "excluded_objects"]
            }
        }
        for extruder in self.printer.get_tools():
            requested_updates['objects'][extruder] = [
                "target", "temperature", "pressure_advance", "smooth_time", "power"]
        for h in self.printer.get_heaters():
            requested_updates['objects'][h] = ["target", "temperature", "power"]
        for f in self.printer.get_fans():
            requested_updates['objects'][f] = ["speed"]
        for f in self.printer.get_filament_sensors():
            requested_updates['objects'][f] = ["enabled", "filament_detected"]
        for p in self.printer.get_output_pins():
            requested_updates['objects'][p] = ["value"]

        self._ws.klippy.object_subscription(requested_updates)

    def _load_panel(self, panel, *args):
        if panel not in self.load_panel:
            logging.debug(f"Loading panel: {panel}")
            panel_path = os.path.join(os.path.dirname(__file__), 'panels', f"{panel}.py")
            logging.info(f"Panel path: {panel_path}")
            if not os.path.exists(panel_path):
                msg = f"Panel {panel} does not exist"
                logging.info(msg)
                raise Exception(msg)

            module = importlib.import_module(f"panels.{panel}")
            if not hasattr(module, "create_panel"):
                msg = f"Cannot locate create_panel function for {panel}"
                logging.info(msg)
                raise Exception(msg)
            self.load_panel[panel] = getattr(module, "create_panel")

        try:
            return self.load_panel[panel](*args)
        except Exception as e:
            msg = f"Unable to create panel {panel}\n{e}"
            logging.exception(msg)
            raise Exception(msg) from e

    def show_panel(self, panel_name, panel_type, title, remove=None, pop=True, **kwargs):
        if panel_name not in self.panels:
            try:
                self.panels[panel_name] = self._load_panel(panel_type, self, title)

                if kwargs != {}:
                    self.panels[panel_name].initialize(panel_name, **kwargs)
                else:
                    self.panels[panel_name].initialize(panel_name)
            except Exception as e:
                if panel_name in self.panels:
                    del self.panels[panel_name]
                logging.exception(f"Unable to load panel {panel_type}")
                self.show_error_modal(f"Unable to load panel {panel_type}", f"{e}")
                return

            if hasattr(self.panels[panel_name], "process_update"):
                self.panels[panel_name].process_update("notify_status_update", self.printer.get_data())

        try:
            if remove == 2:
                self._remove_all_panels()
            elif remove == 1:
                self._remove_current_panel(pop)

            logging.debug(f"Attaching panel {panel_name}")
            self.base_panel.add_content(self.panels[panel_name])

            logging.debug(f"Showing back. count: {len(self._cur_panels)}")
            if len(self._cur_panels) == 0:
                self.base_panel.show_back(False)
            else:
                self.base_panel.show_back(True)
            self.show_all()

            if hasattr(self.panels[panel_name], "process_update"):
                self.panels[panel_name].process_update("notify_status_update", self.printer.get_updates())
                self.add_subscription(panel_name)
            if hasattr(self.panels[panel_name], "activate"):
                self.panels[panel_name].activate()
                self.show_all()
        except Exception as e:
            logging.exception(f"Error attaching panel:\n{e}")

        self._cur_panels.append(panel_name)
        logging.debug(f"Current panel hierarchy: {self._cur_panels}")

    def show_popup_message(self, message, level=3):
        if self.screensaver is not None:
            self.wake_screen()
        if self.popup_message is not None:
            self.close_popup_message()

        msg = Gtk.Button(label=f"{message}")
        msg.set_hexpand(True)
        msg.set_vexpand(True)
        msg.get_child().set_line_wrap(True)
        msg.get_child().set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)
        msg.connect("clicked", self.close_popup_message)

        close = Gtk.Button(label="<big>X</big>")
        close.set_hexpand(False)
        close.set_vexpand(True)
        close.get_child().set_use_markup(True)
        close.set_can_focus(False)
        close.connect("clicked", self.close_popup_message)

        box = Gtk.Box()
        box.set_size_request(self.width, -1)
        box.set_halign(Gtk.Align.CENTER)
        box.get_style_context().add_class("message_popup")
        if level == 1:
            box.get_style_context().add_class("message_popup_echo")
        elif level == 2:
            box.get_style_context().add_class("message_popup_warning")
        else:
            box.get_style_context().add_class("message_popup_error")

        box.add(msg)
        box.add(close)

        self.base_panel.get().put(box, 0, 0)

        self.show_all()
        self.popup_message = box

        if self._config.get_main_config().getboolean('autoclose_popups', True):
            GLib.timeout_add_seconds(10, self.close_popup_message)

        return False

    def close_popup_message(self, widget=None):
        if self.popup_message is None:
            return

        self.base_panel.get().remove(self.popup_message)
        self.popup_message = None
        self.show_all()

    def show_error_modal(self, err, e=""):
        logging.exception(f"Showing error modal: {err}")

        title = Gtk.Label()
        title.set_markup(f"{err}\n")
        title.set_line_wrap(True)
        title.set_halign(Gtk.Align.START)
        title.set_hexpand(True)
        version = Gtk.Label(label=f"{self.version}")
        version.set_halign(Gtk.Align.END)

        message = Gtk.Label(label=f"{e}")
        message.set_line_wrap(True)
        scroll = self.gtk.ScrolledWindow()
        scroll.set_vexpand(True)
        scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scroll.add(message)

        help_notice = Gtk.Label(label="Provide /tmp/KlipperScreen.log when asking for help.\n")
        help_notice.set_line_wrap(True)

        grid = Gtk.Grid()
        grid.attach(title, 0, 0, 1, 1)
        grid.attach(version, 1, 0, 1, 1)
        grid.attach(Gtk.Separator(), 0, 1, 2, 1)
        grid.attach(scroll, 0, 2, 2, 1)
        grid.attach(help_notice, 0, 3, 2, 1)

        buttons = [
            {"name": _("Go Back"), "response": Gtk.ResponseType.CANCEL}
        ]
        self.gtk.Dialog(self, buttons, grid, self.error_modal_response)

    @staticmethod
    def error_modal_response(widget, response_id):
        widget.destroy()

    def restart_warning(self, value):

        logging.debug(f"Showing restart warning because: {value}")

        buttons = [
            {"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL},
            {"name": _("Restart"), "response": Gtk.ResponseType.OK}
        ]

        label = Gtk.Label()
        label.set_markup(_("To apply %s KlipperScreen needs to be restarted") % value)
        label.set_hexpand(True)
        label.set_halign(Gtk.Align.CENTER)
        label.set_vexpand(True)
        label.set_valign(Gtk.Align.CENTER)
        label.set_line_wrap(True)
        label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)

        self.gtk.Dialog(self, buttons, label, self.restart_ks)

    def restart_ks(self, widget, response_id):
        if response_id == Gtk.ResponseType.OK:
            logging.debug("Restarting")
            self._ws.send_method("machine.services.restart", {"service": "KlipperScreen"})
        widget.destroy()

    def init_style(self):
        css_data = pathlib.Path(os.path.join(klipperscreendir, "styles", "base.css")).read_text()

        with open(os.path.join(klipperscreendir, "styles", "base.conf")) as f:
            style_options = json.load(f)
        # Load custom theme
        theme = os.path.join(klipperscreendir, "styles", self.theme)
        theme_style = os.path.join(theme, "style.css")
        theme_style_conf = os.path.join(theme, "style.conf")

        if os.path.exists(theme_style):
            with open(theme_style) as css:
                css_data += css.read()
        if os.path.exists(theme_style_conf):
            try:
                with open(theme_style_conf) as f:
                    style_options.update(json.load(f))
            except Exception as e:
                logging.error(f"Unable to parse custom template conf file:\n{e}")

        self.gtk.color_list = style_options['graph_colors']

        for i in range(len(style_options['graph_colors']['extruder']['colors'])):
            num = "" if i == 0 else i
            css_data += "\n.graph_label_extruder%s {border-left-color: #%s}" % (
                num,
                style_options['graph_colors']['extruder']['colors'][i]
            )
        for i in range(len(style_options['graph_colors']['bed']['colors'])):
            css_data += "\n.graph_label_heater_bed%s {border-left-color: #%s}" % (
                "" if i == 0 else i + 1,
                style_options['graph_colors']['bed']['colors'][i]
            )
        for i in range(len(style_options['graph_colors']['fan']['colors'])):
            css_data += "\n.graph_label_fan_%s {border-left-color: #%s}" % (
                i + 1,
                style_options['graph_colors']['fan']['colors'][i]
            )
        for i in range(len(style_options['graph_colors']['sensor']['colors'])):
            css_data += "\n.graph_label_sensor_%s {border-left-color: #%s}" % (
                i + 1,
                style_options['graph_colors']['sensor']['colors'][i]
            )

        css_data = css_data.replace("KS_FONT_SIZE", f"{self.gtk.get_font_size()}")

        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(css_data.encode())

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(),
            style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

    def is_printing(self):
        return self.printer.get_state() == "printing"

    def is_updating(self):
        return self.updating

    def _go_to_submenu(self, widget, name):
        logging.info(f"#### Go to submenu {name}")
        # self._remove_current_panel(False)

        # Find current menu item
        if "main_panel" in self._cur_panels:
            menu = "__main"
        elif "splash_screen" in self._cur_panels:
            menu = "__splashscreen"
        else:
            menu = "__print"

        logging.info(f"#### Menu {menu}")
        disname = self._config.get_menu_name(menu, name)
        menuitems = self._config.get_menu_items(menu, name)
        if len(menuitems) == 0:
            logging.info("No items in menu, returning.")
            return

        self.show_panel(f'{self._cur_panels[-1]}_{name}',
                        "menu", disname, 1, False, display_name=disname, items=menuitems)

    def _remove_all_panels(self):
        while len(self._cur_panels) > 0:
            self._remove_current_panel(True, False)
        self.show_all()

    def _remove_current_panel(self, pop=True, show=True):
        if len(self._cur_panels) <= 0:
            return
        self.base_panel.remove(self.panels[self._cur_panels[-1]].get_content())
        if hasattr(self.panels[self._cur_panels[-1]], "deactivate"):
            self.panels[self._cur_panels[-1]].deactivate()
        self.remove_subscription(self._cur_panels[-1])
        if pop is True:
            self._cur_panels.pop()
            if len(self._cur_panels) > 0:
                self.base_panel.add_content(self.panels[self._cur_panels[-1]])
                self.base_panel.show_back(len(self._cur_panels) != 1)
                if hasattr(self.panels[self._cur_panels[-1]], "activate"):
                    self.panels[self._cur_panels[-1]].activate()
                if hasattr(self.panels[self._cur_panels[-1]], "process_update"):
                    self.panels[self._cur_panels[-1]].process_update("notify_status_update",
                                                                     self.printer.get_updates())
                    self.add_subscription(self._cur_panels[-1])
                if show is True:
                    self.show_all()

    def _menu_go_back(self, widget=None):
        logging.info("#### Menu go back")
        self.remove_keyboard()
        if self._config.get_main_config().getboolean('autoclose_popups', True):
            self.close_popup_message()
        self._remove_current_panel()

    def _menu_go_home(self):
        logging.info("#### Menu go home")
        self.remove_keyboard()
        self.close_popup_message()
        while len(self._cur_panels) > 1:
            self._remove_current_panel()

    def add_subscription(self, panel_name):
        for sub in self.subscriptions:
            if sub == panel_name:
                return

        self.subscriptions.append(panel_name)

    def remove_subscription(self, panel_name):
        for i in range(len(self.subscriptions)):
            if self.subscriptions[i] == panel_name:
                self.subscriptions.pop(i)
                return

    def reset_screensaver_timeout(self, widget=None):
        if self.screensaver_timeout is not None:
            GLib.source_remove(self.screensaver_timeout)
            self.screensaver_timeout = GLib.timeout_add_seconds(self.blanking_time, self.show_screensaver)

    def show_screensaver(self):
        logging.debug("Showing Screensaver")
        if self.screensaver is not None:
            self.close_screensaver()
        self.remove_keyboard()

        close = Gtk.Button()
        close.connect("clicked", self.close_screensaver)

        box = Gtk.Box()
        box.set_size_request(self.width, self.height)
        box.pack_start(close, True, True, 0)
        box.set_halign(Gtk.Align.CENTER)
        box.get_style_context().add_class("screensaver")

        self.base_panel.get().put(box, 0, 0)
        self.show_all()
        # Avoid leaving a cursor-handle
        close.grab_focus()
        self.screensaver = box
        return False

    def close_screensaver(self, widget=None):
        if self.screensaver is None:
            return False
        logging.debug("Closing Screensaver")
        self.base_panel.get().remove(self.screensaver)
        self.screensaver = None
        if self.use_dpms:
            self.wake_screen()
        else:
            self.screensaver_timeout = GLib.timeout_add_seconds(self.blanking_time, self.show_screensaver)
        self.show_all()
        return False

    def check_dpms_state(self):
        state = functions.get_DPMS_state()

        if state == functions.DPMS_State.Fail:
            logging.info("DPMS State FAIL: Stopping DPMS Check")
            if self.screensaver_timeout is None:
                self.set_dpms(False)
            return False
        elif state != functions.DPMS_State.On:
            if self.screensaver is None:
                self.show_screensaver()
        return True

    def wake_screen(self):
        # Wake the screen (it will go to standby as configured)
        if self._config.get_main_config().get('screen_blanking') != "off":
            logging.debug("Screen wake up")
            os.system("xset -display :0 dpms force on")
            self.close_screensaver()

    def set_dpms(self, use_dpms):
        self.use_dpms = use_dpms
        logging.info(f"DPMS set to: {self.use_dpms}")
        self.set_screenblanking_timeout(self._config.get_main_config().get('screen_blanking'))

    def set_screenblanking_timeout(self, time):
        os.system("xset -display :0 s blank")
        os.system("xset -display :0 s off")
        self.use_dpms = self._config.get_main_config().getboolean("use_dpms", fallback=True)

        if time == "off":
            logging.debug(f"Screen blanking: {time}")
            if self.dpms_timeout is not None:
                GLib.source_remove(self.dpms_timeout)
                self.dpms_timeout = None
            if self.screensaver_timeout is not None:
                GLib.source_remove(self.screensaver_timeout)
            os.system("xset -display :0 dpms 0 0 0")
            return

        self.blanking_time = abs(int(time))
        logging.debug(f"Changing screen blanking to: {self.blanking_time}")
        if self.use_dpms and functions.dpms_loaded is True:
            os.system("xset -display :0 +dpms")
            if functions.get_DPMS_state() == functions.DPMS_State.Fail:
                logging.info("DPMS State FAIL")
            else:
                logging.debug("Using DPMS")
                os.system("xset -display :0 s off")
                os.system(f"xset -display :0 dpms 0 {self.blanking_time} 0")
                if self.dpms_timeout is None:
                    self.dpms_timeout = GLib.timeout_add_seconds(1, self.check_dpms_state)
                return
        # Without dpms just blank the screen
        logging.debug("Not using DPMS")
        if self.dpms_timeout is not None:
            GLib.source_remove(self.dpms_timeout)
            self.dpms_timeout = None
        os.system("xset -display :0 dpms 0 0 0")
        if self.screensaver_timeout is None:
            self.screensaver_timeout = GLib.timeout_add_seconds(self.blanking_time, self.show_screensaver)
        return

    def set_updating(self, updating=False):
        if self.updating is True and updating is False and len(self.update_queue) > 0:
            i = self.update_queue.pop()
            self.update_queue = []
            i[0](i[1])

        self.updating = updating

    def show_printer_select(self, widget=None):
        logging.debug(f"Saving panel: {self._cur_panels[0]}")
        self.printer_select_prepanel = self._cur_panels[0]
        self.base_panel.show_heaters(False)
        self.base_panel.show_macro_shortcut(False)
        self.base_panel.show_printer_select(False)
        self.show_panel("printer_select", "printer_select", "Printer Select", 2)
        self.show_all()
        self.base_panel.action_bar.hide()

    def state_execute(self, callback, prev_state):
        if self.is_updating():
            self.update_queue.append([callback, prev_state])
        else:
            callback(prev_state)

    def state_disconnected(self, prev_state):
        if "printer_select" in self._cur_panels:
            self.printer_select_callbacks = [self.state_disconnected]
            return

        logging.debug("### Going to disconnected")
        self.base_panel.show_macro_shortcut(False)
        self.wake_screen()
        self.printer_initializing(_("Klipper has disconnected"))
        if self.connected_printer is not None:
            self.connected_printer = None
            # Try to reconnect
            self.connect_printer(self.connecting_to_printer)
        else:
            self.initial_connection()

    def state_error(self, prev_state):
        if "printer_select" in self._cur_panels:
            self.printer_select_callbacks = [self.state_error]
            return

        self.base_panel.show_macro_shortcut(False)
        self.wake_screen()
        msg = self.printer.get_stat("webhooks", "state_message")
        if "FIRMWARE_RESTART" in msg:
            self.printer_initializing("" + _("Klipper has encountered an error.") + "\n" +
                                      _("A FIRMWARE_RESTART may fix the issue.") +
                                      "" + "\n\n" + msg)
        elif "micro-controller" in msg:
            self.printer_initializing("" + _("Klipper has encountered an error.") +
                                      _("Please recompile and flash the micro-controller.") +
                                      "" + "\n\n" + msg)
        else:
            self.printer_initializing("" + _("Klipper has encountered an error.") +
                                      "" + "\n\n" + msg)

        for panel in list(self.panels):
            if panel not in ["printer_select", "splash_screen"]:
                del self.panels[panel]
        for dialog in self.dialogs:
            dialog.destroy()

    def state_paused(self, prev_state):
        if "job_status" not in self._cur_panels:
            self.printer_printing()

    def state_printing(self, prev_state):
        if "printer_select" in self._cur_panels:
            self.printer_select_callbacks = [self.state_printing]
            return

        if "job_status" not in self._cur_panels:
            self.printer_printing()
        else:
            self.panels["job_status"].new_print()

    def state_ready(self, prev_state):
        if "printer_select" in self._cur_panels:
            self.printer_select_callbacks = [self.state_ready]
            return

        self.base_panel.show_macro_shortcut(self._config.get_main_config().getboolean('side_macro_shortcut', True))
        self.base_panel.show_heaters(True)

        # Do not return to main menu if completing a job, timeouts/user input will return
        if "job_status" in self._cur_panels or "main_menu" in self._cur_panels:
            return

        if prev_state not in ['paused', 'printing']:
            self.init_printer()
            self.base_panel._printer = self.printer

        self.printer_ready()

    def state_startup(self, prev_state):
        if "printer_select" in self._cur_panels:
            self.printer_select_callbacks = [self.state_startup]
            return

        self.printer_initializing(_("Klipper is attempting to start"))

    def state_shutdown(self, prev_state):
        if "printer_select" in self._cur_panels:
            self.printer_select_callbacks = [self.state_shutdown]
            return

        self.base_panel.show_macro_shortcut(False)
        self.wake_screen()
        msg = self.printer.get_stat("webhooks", "state_message")
        if "ready" in msg:
            msg = ""
        self.printer_initializing("" + _("Klipper has shutdown") +
                                  "" + "\n\n" + msg)

    def toggle_macro_shortcut(self, value):
        self.base_panel.show_macro_shortcut(value)

    def reload_panels(self, *args):
        self._remove_all_panels()
        for panel in list(self.panels):
            if panel not in ["printer_select", "splash_screen"]:
                del self.panels[panel]
        for dialog in self.dialogs:
            dialog.destroy()
        state = self.printer.state
        self.printer.state = None
        self.printer.change_state(state)

    def _websocket_callback(self, action, data):

        if self.connecting is True:
            return

        if action == "notify_klippy_disconnected":
            logging.debug("Received notify_klippy_disconnected")
            self.printer.change_state("disconnected")
            return
        elif action == "notify_klippy_ready":
            self.printer.change_state("ready")
        elif action == "notify_status_update" and self.printer.get_state() != "shutdown":
            self.printer.process_update(data)
        elif action == "notify_filelist_changed":
            logging.debug("Filelist changed: %s", json.dumps(data, indent=2))
            if self.files is not None:
                self.files.process_update(data)
        elif action == "notify_metadata_update":
            self.files.request_metadata(data['filename'])
        elif action == "notify_update_response":
            logging.info(f"{action}: {data}")
        elif action == "notify_power_changed":
            logging.debug("Power status changed: %s", data)
            self.printer.process_power_update(data)
            self.panels['splash_screen'].check_power_status()
        elif self.printer.get_state() not in ["error", "shutdown"] and action == "notify_gcode_response":
            if "Klipper state: Shutdown" in data:
                logging.debug("Shutdown in gcode response, changing state to shutdown")
                self.printer.change_state("shutdown")

            if not (data.startswith("B:") and
                    re.search(r'B:[0-9\.]+\s/[0-9\.]+\sT[0-9]+:[0-9\.]+', data)):
                if data.startswith("echo: "):
                    self.show_popup_message(data[6:], 1)
                elif data.startswith("!! "):
                    self.show_popup_message(data[3:], 3)
                    logging.debug(json.dumps([action, data], indent=2))
                if "SAVE_CONFIG" in data and self.printer.get_state() == "ready":
                    script = {"script": "SAVE_CONFIG"}
                    self._confirm_send_action(
                        None,
                        _("Save configuration?") + "\n\n" + _("Klipper will reboot"),
                        "printer.gcode.script",
                        script
                    )

        self.base_panel.process_update(action, data)
        if self._cur_panels[-1] in self.subscriptions:
            self.panels[self._cur_panels[-1]].process_update(action, data)

    def _confirm_send_action(self, widget, text, method, params=None):

        if params is None:
            params = {}
        buttons = [
            {"name": _("Continue"), "response": Gtk.ResponseType.OK},
            {"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL}
        ]

        try:
            env = Environment(extensions=["jinja2.ext.i18n"], autoescape=True)
            env.install_gettext_translations(self.lang)
            j2_temp = env.from_string(text)
            text = j2_temp.render()
        except Exception as e:
            logging.debug(f"Error parsing jinja for confirm_send_action\n{e}")

        label = Gtk.Label()
        label.set_markup(text)
        label.set_hexpand(True)
        label.set_halign(Gtk.Align.CENTER)
        label.set_vexpand(True)
        label.set_valign(Gtk.Align.CENTER)
        label.set_line_wrap(True)
        label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)

        if self.confirm is not None:
            self.confirm.destroy()
        self.confirm = self.gtk.Dialog(self, buttons, label, self._confirm_send_action_response, method, params)

    def _confirm_send_action_response(self, widget, response_id, method, params):
        if response_id == Gtk.ResponseType.OK:
            self._send_action(widget, method, params)

        widget.destroy()

    def _send_action(self, widget, method, params):
        self._ws.send_method(method, params)

    def printer_initializing(self, text=None, disconnect=False):
        self.close_popup_message()
        self.show_panel('splash_screen', "splash_screen", "Splash Screen", 2)
        if disconnect is True and self.printer is not None:
            self.shutdown = True
            self.printer.state = "disconnected"
        if text is not None:
            self.panels['splash_screen'].update_text(text)

    def search_power_devices(self, power_devices):
        if self.connected_printer is None:
            return
        found_devices = []
        devices = self.printer.get_power_devices()
        logging.debug("Power devices: %s", devices)
        if devices is not None:
            for device in devices:
                for power_device in power_devices:
                    if device == power_device and power_device not in found_devices:
                        found_devices.append(power_device)
        if found_devices:
            logging.info("Found %s", found_devices)
            return found_devices
        else:
            logging.info("Power devices not found")
            return None

    def power_on(self, widget, devices):

        for device in devices:
            if self.printer.get_power_device_status(device) == "off":
                self.show_popup_message(_("Sending Power ON signal to: %s") % devices, level=1)
                logging.info("%s is OFF, Sending Power ON signal", device)
                self._ws.klippy.power_device_on(device)
            elif self.printer.get_power_device_status(device) == "on":
                logging.info("%s is ON", device)

    def init_printer(self):

        state = self.apiclient.get_server_info()
        if state is False:
            return False
        # Moonraker is ready, set a loop to init the printer
        self.reinit_count += 1
        self.init_printer_timeout = GLib.timeout_add_seconds(3, self.init_printer)

        self.shutdown = False
        powerdevs = self.apiclient.send_request("machine/device_power/devices")
        if powerdevs is not False:
            self.printer.configure_power_devices(powerdevs['result'])

        if state['result']['klippy_connected'] is False:
            self.panels['splash_screen'].update_text(
                _("Moonraker: connected")
                + f"\n\nKlipper: {state['result']['klippy_state']}\n\n"
                + _("Retry #%s") % self.reinit_count
            )
            return False

        printer_info = self.apiclient.get_printer_info()
        if printer_info is False:
            return self._update_splash_screen("Unable to get printer info from moonraker")

        data = self.apiclient.send_request("printer/objects/query?" + "&".join(PRINTER_BASE_STATUS_OBJECTS))
        if data is False:
            return self._update_splash_screen("Error getting printer object data")

        config = self.apiclient.send_request("printer/objects/query?configfile")
        if config is False:
            return self._update_splash_screen("Error getting printer config data")

        # Reinitialize printer, in case the printer was shut down and anything has changed.
        self.printer.reinit(printer_info['result'], config['result']['status'])

        self.ws_subscribe()
        extra_items = (self.printer.get_tools()
                       + self.printer.get_heaters()
                       + self.printer.get_fans()
                       + self.printer.get_filament_sensors()
                       + self.printer.get_output_pins()
                       )

        data = self.apiclient.send_request("printer/objects/query?" + "&".join(PRINTER_BASE_STATUS_OBJECTS +
                                                                               extra_items))
        if data is False:
            return self._update_splash_screen("Error getting printer object data with extra items")

        tempstore = self.apiclient.send_request("server/temperature_store")
        if tempstore is not False:
            self.printer.init_temp_store(tempstore['result'])
        self.printer.process_update(data['result']['status'])

        self.files.initialize()
        self.files.refresh_files()

        logging.info("Printer initialized")
        GLib.source_remove(self.init_printer_timeout)
        self.reinit_count = 0
        return False

    def _update_splash_screen(self, msg):
        logging.info(msg)
        self.panels['splash_screen'].update_text(msg)
        return False

    def printer_ready(self):

        self.close_popup_message()
        # Force an update to printer webhooks state in case the update is missed due to websocket subscribe not yet sent
        self.printer.process_update({"webhooks": {"state": "ready", "state_message": "Printer is ready"}})
        self.show_panel('main_panel', "main_menu", _("Home"), 2,
                        items=self._config.get_menu_items("__main"), extrudercount=self.printer.get_extruder_count())
        self.ws_subscribe()
        if "job_status" in self.panels:
            self.remove_subscription("job_status")
            del self.panels["job_status"]

    def printer_printing(self):
        self.close_popup_message()
        self.show_panel('job_status', "job_status", "Print Status", 2)
        self.base_panel.show_heaters(True)
        self.base_panel.show_macro_shortcut(self._config.get_main_config().getboolean('side_macro_shortcut', True))
        for dialog in self.dialogs:
            dialog.destroy()

    def show_keyboard(self, widget=None, event=None, entry=None):
        if self.keyboard is not None:
            return

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.set_size_request(self.gtk.get_content_width(), self.gtk.get_keyboard_height())

        if self._config.get_main_config().getboolean("use-matchbox-keyboard", False):
            env = os.environ.copy()
            usrkbd = os.path.expanduser("~/.matchbox/keyboard.xml")
            if os.path.isfile(usrkbd):
                env["MB_KBD_CONFIG"] = usrkbd
            else:
                env["MB_KBD_CONFIG"] = "ks_includes/locales/keyboard.xml"
            p = subprocess.Popen(["matchbox-keyboard", "--xid"], stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE, env=env)
            xid = int(p.stdout.readline())
            logging.debug(f"XID {xid}")
            logging.debug(f"PID {p.pid}")

            keyboard = Gtk.Socket()
            box.get_style_context().add_class("keyboard_matchbox")
            box.pack_start(keyboard, True, True, 0)
            self.base_panel.get_content().pack_end(box, False, False, 0)

            self.show_all()
            keyboard.add_id(xid)

            self.keyboard = {
                "box": box,
                "process": p,
                "socket": keyboard
            }
            return
        if entry is None:
            logging.debug("Error: no entry provided for keyboard")
            return
        box.get_style_context().add_class("keyboard_box")
        box.add(Keyboard(self, self.remove_keyboard, entry=entry))
        self.keyboard = {
            "entry": entry,
            "box": box
        }
        self.base_panel.get_content().pack_end(box, False, False, 0)
        self.base_panel.get_content().show_all()

    def remove_keyboard(self, widget=None, event=None):
        if self.keyboard is None:
            return

        if 'process' in self.keyboard:
            os.kill(self.keyboard['process'].pid, signal.SIGTERM)
        self.base_panel.get_content().remove(self.keyboard['box'])
        self.keyboard = None

    def change_cursor(self, cursortype=None):
        if cursortype == "watch":
            os.system("xsetroot  -cursor_name  watch")
        elif self.show_cursor:
            self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.ARROW))
            os.system("xsetroot  -cursor_name  arrow")
        else:
            self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.BLANK_CURSOR))
            os.system("xsetroot  -cursor ks_includes/emptyCursor.xbm ks_includes/emptyCursor.xbm")
        return

def main():
    version = functions.get_software_version()
    parser = argparse.ArgumentParser(description="KlipperScreen - A GUI for Klipper")
    parser.add_argument(
        "-c", "--configfile", default="~/KlipperScreen.conf", metavar='<configfile>',
        help="Location of KlipperScreen configuration file"
    )
    parser.add_argument(
        "-l", "--logfile", default="/tmp/KlipperScreen.log", metavar='<logfile>',
        help="Location of KlipperScreen logfile output"
    )
    args = parser.parse_args()

    functions.setup_logging(
        os.path.normpath(os.path.expanduser(args.logfile)),
        version
    )

    functions.patch_threading_excepthook()

    logging.info(f"KlipperScreen version: {version}")

    win = KlipperScreen(args, version)
    win.connect("destroy", Gtk.main_quit)
    win.show_all()
    Gtk.main()

if __name__ == "__main__":
    try:
        main()
    except Exception as ex:
        logging.exception(f"Fatal error in main loop:\n{ex}")


from typing import List

import jsonlines
from torch.utils.data import Dataset

def load_data(name: str, path: str, supervise: bool) -> List:
    """根据名字加载不同的数据集."""

    def load_snli_data(path, supervise):
        with jsonlines.open(path, "r") as f:
            return [
                (line["origin"], line["entailment"], line["contradiction"])
                if supervise
                else line["origin"]
                for line in f
            ]

    def load_lqcmc_data(path):
        with open(path, "r", encoding="utf8") as f:
            return [line.strip().split("\t")[0] for line in f]

    def load_sts_data(path):
        with open(path, "r", encoding="utf8") as f:
            return [(line.split("||")[1], line.split("||")[2], line.split("||")[3]) for line in f]

    assert name in ["snli", "lqcmc", "sts"]
    if name == "snli":
        return load_snli_data(path, supervise)
    elif name == "lqcmc":
        return load_lqcmc_data(path)
    elif name == "sts":
        return load_sts_data(path)

class SimcseDataset(Dataset):
    """训练数据集, 重写__getitem__和__len__方法."""

    def __init__(self, data: List, split, supervise, tokenizer, max_length):
        self.data = data
        self.split = split
        self.supervise = supervise
        self.tokenizer = tokenizer
        self.max_length = max_length

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

    def text_2_id(self, text: str):
        if self.split == "train":
            if self.supervise is False:
                return self.tokenizer(
                    [text, text],
                    max_length=self.max_length,
                    truncation=True,
                    padding="max_length",
                    return_tensors="pt",
                )
            else:
                return self.tokenizer(
                    [text[0], text[1], text[2]],
                    max_length=self.max_length,
                    truncation=True,
                    padding="max_length",
                    return_tensors="pt",
                )
        elif self.split == "test":
            return self.tokenizer(
                text,
                max_length=self.max_length,
                truncation=True,
                padding="max_length",
                return_tensors="pt",
            )

    def __getitem__(self, index: int):
        if self.split == "train":
            return self.text_2_id(self.data[index])
        elif self.split == "test":
            line = self.data[index]
            return self.text_2_id([line[0]]), self.text_2_id([line[1]]), int(line[2])


from __future__ import print_function
try:
    from openpyxl import load_workbook
    from openpyxl.utils import get_column_letter
except:
    print("Openpyxl module cannot be imported because it's not installed. pip install openpyxl to solve the issue")
    exit('Simulation terminated')
from re import compile, escape
from scipy import interpolate
from fipy import numerix
from collections import OrderedDict

# User Setup
simulation_control_workbook = 'sim_settings.xlsx'
simulation_control_workbook_sheet = 'Sim_Control'

################################# Import the simuatlion settings #######################################################
cell_properties  = load_workbook(simulation_control_workbook)       # Load workbook containing cell property data
sim_settings_sheet = cell_properties.get_sheet_by_name(simulation_control_workbook_sheet)  # Load the sheet corresponding to desired cell
Uocp_neg_sheet = 'Uocp_neg'
Uocp_pos_sheet = 'Uocp_pos'
kappa_sheet = 'Kappa'

control_chars = ''.join(map(unichr, range(0,32) + range(127,160)))           # Deal with non-printable characters in cell property names
control_char_re = compile('[%s]' % escape(control_chars))
def remove_control_chars(s):
    return control_char_re.sub('', s.strip())

for sheet in cell_properties:
    if sheet.title == sim_settings_sheet.title:
        namecol = sim_settings_sheet.min_column  # This column no. contains the name of the cell parameters
        minrow = sim_settings_sheet.min_row  # This column no. contains the name of the cell parameters
        valuecol = namecol + 1  # This column no. contains the numerical/string value of the cell-parameters
        # settings_dict = {}  # Create an object to store the parameters
        settings_dict = OrderedDict()
        for row_number in range(minrow, sim_settings_sheet.max_row+1):                             # Import cell properties sim_settings_sheet
            name_location  = get_column_letter(namecol)  + str(row_number)          # Obtain the alphabetical column string of the name column
            value_location = get_column_letter(valuecol) + str(row_number)          # Obtain the alphabetical column string of the value column
            if sim_settings_sheet[name_location].value != None:                                    # Skip processing if blank row
                sim_setting_name = remove_control_chars(sim_settings_sheet[name_location].value)   # Get the contents of the 'name-column' & strip any non-printable characters
                sim_setting_name = sim_settings_sheet[name_location].value
                sim_setting_value = sim_settings_sheet[value_location].value                       # Force to type 'float' if user entered a cell parameter without decimal point
                if not isinstance(sim_settings_sheet[value_location].value, float):
                    if isinstance(sim_settings_sheet[value_location].value, long or int):
                        sim_setting_value = float(sim_setting_value)
                    else:
                        sim_setting_value = str(sim_setting_value)             # Convert unicode Uocp functions to strings
                settings_dict[sim_setting_name] = sim_setting_value

    elif sheet.title == Uocp_neg_sheet:
        namecol = sheet.min_column  # This column no. contains the timestamp
        valuecol = namecol + 1  # This column no. contains the current value
        minrow = sheet.min_row
        maxrow = sheet.max_row
        data_col_length = maxrow - minrow + 1
        theta_table_vals_neg = numerix.empty(data_col_length)
        Uocp_table_vals_neg = numerix.empty(data_col_length)
        for row_number in range(minrow, maxrow + 1):
            name_location = get_column_letter(namecol) + str(row_number)  # Obtain the alphabetical column string of the timestamp column
            value_location = get_column_letter(valuecol) + str(row_number)  # Obtain the alphabetical column string of the current_value column
            if sheet[name_location].value != None:  # Check for blank row
                theta_table_vals_neg[row_number - minrow] = float(sheet[name_location].value)
                Uocp_table_vals_neg[row_number - minrow] = float(sheet[value_location].value)  # Need to add in ability to process formulae in spreadsheet cells

    elif sheet.title == Uocp_pos_sheet:
        namecol = sheet.min_column  # This column no. contains the timestamp
        valuecol = namecol + 1  # This column no. contains the current value
        minrow = sheet.min_row
        maxrow = sheet.max_row
        data_col_length = maxrow - minrow + 1
        theta_table_vals_pos = numerix.empty(data_col_length)
        Uocp_table_vals_pos = numerix.empty(data_col_length)
        for row_number in range(minrow, maxrow + 1):
            name_location = get_column_letter(namecol) + str(row_number)  # Obtain the alphabetical column string of the timestamp column
            value_location = get_column_letter(valuecol) + str(row_number)  # Obtain the alphabetical column string of the current_value column
            if sheet[name_location].value != None:  # Check for blank row
                theta_table_vals_pos[row_number - minrow] = float(sheet[name_location].value)
                Uocp_table_vals_pos[row_number - minrow] = float(sheet[value_location].value)  # Need to add in ability to process formulae in spreadsheet cells

    elif sheet.title == kappa_sheet:
        namecol = sheet.min_column  # This column no. contains the timestamp
        valuecol = namecol + 1  # This column no. contains the current value
        minrow = sheet.min_row
        maxrow = sheet.max_row
        data_col_length = maxrow - minrow + 1
        kappa_ce = numerix.empty(data_col_length)
        kappa_value = numerix.empty(data_col_length)
        for row_number in range(minrow, maxrow + 1):
            name_location = get_column_letter(namecol) + str(row_number)  # Obtain the alphabetical column string of the timestamp column
            value_location = get_column_letter(valuecol) + str(row_number)  # Obtain the alphabetical column string of the current_value column
            if sheet[name_location].value != None:  # Check for blank row
                kappa_ce[row_number - minrow] = float(sheet[name_location].value)
                kappa_value[row_number - minrow] = float(sheet[value_location].value)  # Need to add in ability to process formulae in spreadsheet cells
        interpolated_kappa_fn = interpolate.interp1d(kappa_ce, kappa_value, kind='slinear')

#################################################### Cleanse names #####################################################
# General
initial_soc_percent, cell_temperature = settings_dict['initial_soc_percent'], settings_dict['cell_temperature']

# Timing
simEndtime, temporal_resolution = settings_dict['simEndtime'], settings_dict['temporal_resolution']

# Domain sizing
L_neg_normalised, L_pos_normalised = settings_dict['L_neg_normalised'], settings_dict['L_pos_normalised']
L_sep_normalised = settings_dict['L_sep_normalised']
Rs_neg_normalised, Rs_pos_normalised = settings_dict['Rs_neg_normalised'], settings_dict['Rs_pos_normalised']

# Domain meshing
nx_neg, nx_pos, nx_sep = int(settings_dict['nx_neg']), int(settings_dict['nx_pos']), int(settings_dict['nx_sep'])
nr_neg, nr_pos = int(settings_dict['nr_neg']), int(settings_dict['nr_pos'])
non_uniform_axial_meshing, non_uniform_radial_meshing = settings_dict['non_uniform_axial_meshing'], settings_dict['non_uniform_radial_meshing']

# Solution variable tolerancing
tolerance_phi_s_neg_res, tolerance_phi_s_pos_res = settings_dict['tolerance_phi_s_neg_res'], settings_dict['tolerance_phi_s_pos_res']
tolerance_Cs_neg_res, tolerance_Cs_pos_res = settings_dict['tolerance_Cs_neg_res'], settings_dict['tolerance_Cs_pos_res']
tolerance_phi_e_sim_cell_res, tolerance_Ce_sim_cell_res = settings_dict['tolerance_phi_e_sim_cell_res'], settings_dict['tolerance_Ce_sim_cell_res']

# Under-relaxation factors
under_relax_factor_phi_s_neg = settings_dict['under_relax_factor_phi_s_neg']
under_relax_factor_phi_s_pos = settings_dict['under_relax_factor_phi_s_pos']
under_relax_factor_Ce = settings_dict['under_relax_factor_Ce']
under_relax_factor_phi_e = settings_dict['under_relax_factor_phi_e']
under_relax_factor_Cs_neg = settings_dict['under_relax_factor_Cs_neg']
under_relax_factor_Cs_pos = settings_dict['under_relax_factor_Cs_pos']

# Current profile import
cprofile_workbook, cprofile_sheet, repeat_current_profile = simulation_control_workbook, settings_dict['cprofile_sheet'], settings_dict['repeat_current_profile']

# Cell properties import
cell_properties_workbook, cell_properties_sheet = simulation_control_workbook, settings_dict['cell_properties_sheet']

# Data logging & Debugging
datalogging_switch = settings_dict['datalogging_switch']
if datalogging_switch == 'on':
    datalogging_switch == 'On'
record_period, datalog_filename, output_location = settings_dict['record_period'], settings_dict['datalog_filename'], settings_dict['output_location']
det_residual_live_plot, det_residual_saving = settings_dict['det_residual_live_plot'], settings_dict['det_residual_saving']
mem_leak_analysis, det_concentrations_live_plot = settings_dict['mem_leak_analysis'], settings_dict['Cs_live_plot']
if det_residual_live_plot == 'on':
    det_residual_live_plot == 'On'
if det_residual_saving == 'on':
    det_residual_live_plot == 'On'
if mem_leak_analysis == 'on':
    mem_leak_analysis == 'On'
if det_concentrations_live_plot == 'on':
    det_concentrations_live_plot == 'On'

# Analysis
auto_process = settings_dict['auto_process']
if auto_process == 'on':
    auto_process == 'On'
if auto_process == 'On' and datalogging_switch != 'On':
    print('auto_process data is switched On, but datalogging is switched off. Either switch datalogging to On or switch auto_process to Off')
    exit('Simulation terminated')

########################################### Pre-process domain sizes ###################################################
nx_tot = nx_neg + nx_sep + nx_pos
L_tot_normalised = L_neg_normalised + L_pos_normalised + L_sep_normalised  # Total normalised length (by default set to 3)

########################### Current Profile Import #####################################################################
cprofile_book = load_workbook(cprofile_workbook)                                   # Load workbook containing current profile
cprofile_data = cprofile_book.get_sheet_by_name(cprofile_sheet)                             # Load the sheet corresponding to desired profile

cprofile_namecol = cprofile_data.min_column                                                 # This column no. contains the timestamp
cprofile_valuecol = cprofile_namecol + 1                                                    # This column no. contains the current value
# Improve the below logic to handle column headers, keep moving down until you hit the first float
cprofile_minrow = cprofile_data.min_row
cprofile_maxrow = cprofile_data.max_row
cprofile_length = cprofile_maxrow - cprofile_minrow + 1
cprofile_timestamps = numerix.empty(cprofile_length)
cprofile_currents = numerix.empty(cprofile_length)

for row_number in range(cprofile_minrow,cprofile_maxrow + 1):
    cprofile_timestamp_location = get_column_letter(cprofile_namecol) + str(row_number)    # Obtain the alphabetical column string of the timestamp column
    cprofile_value_location = get_column_letter(cprofile_valuecol) + str(row_number)       # Obtain the alphabetical column string of the current_value column
    if cprofile_data[cprofile_timestamp_location].value != None:                            # Check for blank row
        cprofile_timestamps[row_number - cprofile_minrow] = float(cprofile_data[cprofile_timestamp_location].value)
        cprofile_currents[row_number - cprofile_minrow] = float(cprofile_data[cprofile_value_location].value) # Need to add in ability to process formulae in spreadsheet cells

interpolated_current_fn = interpolate.interp1d(cprofile_timestamps, cprofile_currents, kind = 'slinear')

################################# Import the cell properties ###########################################################
cell_properties  = load_workbook(cell_properties_workbook)          # Load workbook containing cell property data
data             = cell_properties.get_sheet_by_name(cell_properties_sheet)  # Load the sheet corresponding to desired cell
namecol          = data.min_column                                           # This column no. contains the name of the cell parameters
minrow           = data.min_row                                              # This column no. contains the name of the cell parameters
valuecol         = namecol + 1                                               # This column no. contains the numerical/string value of the cell-parameters
params_dict = {}                                                             # Create an object to store the parameters

for row_number in range(minrow, data.max_row+1):                             # Import cell properties data
    name_location  = get_column_letter(namecol)  + str(row_number)          # Obtain the alphabetical column string of the name column
    value_location = get_column_letter(valuecol) + str(row_number)          # Obtain the alphabetical column string of the value column
    if data[name_location].value != None:                                    # Skip processing if blank row
        cell_parameter_name = remove_control_chars(data[name_location].value)# Get the contents of the 'name-column' & strip any non-printable characters
        cell_parameter_name = data[name_location].value
        cell_parameter_value = data[value_location].value                    # Force to type 'float' if user entered a cell parameter without decimal point
        if not isinstance(data[value_location].value, float):
            if isinstance(data[value_location].value, long or int):
                cell_parameter_value = float(cell_parameter_value)
            else:
                cell_parameter_value = str(cell_parameter_value)             # Convert unicode Uocp functions to strings
        params_dict[cell_parameter_name] = cell_parameter_value