# -*- coding: utf-8 -*-
#BEGIN_HEADER
import logging
import os
import sys
import subprocess
import shutil
from jinja2 import Template
from installed_clients.WorkspaceClient import Workspace as workspaceService
import requests
from pprint import pprint, pformat
from datetime import datetime
import re
from glob import glob
from zipfile import ZipFile

from installed_clients.KBaseReportClient import KBaseReport
from installed_clients.ReadsUtilsClient import ReadsUtils
from installed_clients.DataFileUtilClient import DataFileUtil
from installed_clients.SetAPIServiceClient import SetAPI
#END_HEADER

class gottcha2:
    '''
    Module Name:
    gottcha2

    Module Description:
    A KBase module: gottcha2
    '''

    ######## WARNING FOR GEVENT USERS ####### noqa
    # Since asynchronous IO can lead to methods - even the same method -
    # interrupting each other, you must be *very* careful when using global
    # state. A method could easily clobber the state set by another while
    # the latter method is running.
    ######################################### noqa
    VERSION = "0.0.6"
    GIT_URL = "git@github.com:LANL-Bioinformatics/kbase-gottcha2.git"
    GIT_COMMIT_HASH = "6ae998a2dc9a771381f290622789a8c182c5cdea"

    #BEGIN_CLASS_HEADER
    def _generate_DataTable(self, infile, outfile):
        f =  open(infile, "r")
        wf = open(outfile,"w")

        header = f.readline().strip()
        headerlist = [ x.strip() for x in header.split('\t')]

        wf.write("\n")
        wf.write("<link rel='stylesheet' type='text/css' href='https://cdn.datatables.net/1.10.19/css/jquery.dataTables.css'>\n")
        wf.write("\n")
        wf.write("\n")
        wf.write("\n")
        wf.write("\n")
        wf.write("""""")
        wf.write("
\n")
        wf.write('

' + ''.join("{0}	".format(t) for t in headerlist) + '

\n')
        wf.write("
\n")
        for line in f:
            if not line.strip():continue
            wf.write("
\n")
            temp = [ x.strip() for x in line.split('\t')]
            wf.write(''.join("{0}	".format(t) for t in temp))
            wf.write("
\n")
        wf.write("
\n")
        wf.write("
")
        wf.write("\n")

    def create_report(self, ws, output_list, html_folder):
        output_html_files = []
        output_zip_files = []
        first_file = ""
        html_count = 0
        with open('/kb/data/index_start.txt', 'r') as start_file:
            html_string = start_file.read()

        # Make HTML folder
        # html_folder = os.path.join(self.scratch, 'gottcha2_output', 'html_report')
        os.mkdir(html_folder) if not os.path.exists(html_folder) else None
        for files_dict in output_list:
            zip_files = [d['name'] for d in files_dict['output_files'] if d['name'].endswith('.zip')]
            logging.info(f'zip files {zip_files}')
            for file in zip_files:
                desc = 'Zip file generated by GOTTCHA2 that contains ' + \
                       'original images seen in the report'
                output_zip_files.append({'path': os.path.join(html_folder, file),
                                         'name': file,
                                         'label': ".".join(file.split(".")[1:]),
                                         'description': desc})
            logging.info(f"files_dict {files_dict['output_files']}")
            # each sample run through GOTTCHA2 has a file
            first_file = [d['name'] for d in files_dict['output_files'] if d['name'].endswith('_index.html')][0]
            html_string+="            <button data-button=\"page "+str(html_count) + \
                         "\" data-page=\""+first_file+"\">Page "+str(html_count+1)+"</button>\n"
            html_count += 1

        html_string += "

\n"
        html_string += "        \n
"

        with open('/kb/data/index_end.txt', 'r') as end_file:
            html_string += end_file.read()
        assert os.path.exists(html_folder)
        with open(os.path.join(html_folder, "index.html"), 'w') as index_file:
            index_file.write(html_string)

        shock = self.dfu.file_to_shock({'file_path': html_folder,
                                        'make_handle': 0,
                                        'pack': 'zip'})
        desc = 'HTML files generated by GOTTCHA2 that contains report on ' + \
               'taxonomic profile of reads'
        output_html_files.append({'shock_id': shock['shock_id'],
                                  'name': 'index.html',
                                  'label': 'html files',
                                  'description': desc})
        l = [p['output_files'] for p in output_list]
        flat_list = [item for sublist in l for item in sublist]
        logging.info(f"file links {flat_list}")
        logging.info(f'output_zip_files {output_zip_files}')
        logging.info(f'output_html_files {output_html_files}')
        report_params = {
            'direct_html_link_index': 0,
            'file_links': flat_list,
            'html_links': output_html_files,
            'workspace_name': ws
        }
        kbase_report_client = KBaseReport(self.callback_url)
        output = kbase_report_client.create_extended_report(report_params)
        logging.info(f'output {output}')
        return output

    def package_folder(self, folder_path, zip_file_name, zip_file_description):
        ''' Simple utility for packaging a folder and saving to shock '''
        if folder_path == self.scratch:
            raise ValueError ("cannot package scatch itself.  folder path: "+folder_path)
        elif not folder_path.startswith(self.scratch):
            raise ValueError ("cannot package folder that is not a subfolder of scratch.  folder path: "+folder_path)

        if not os.path.exists(folder_path):
            raise ValueError ("cannot package folder that doesn't exist: "+folder_path)
        output = self.dfu.file_to_shock({'file_path': folder_path,
                                    'make_handle': 0,
                                    'pack': 'zip'})
        return {'shock_id': output['shock_id'],
                'name': zip_file_name,
                'label': zip_file_description}

    def log(self, target, message):
        if target is not None:
            target.append(message)
        print(message)
        sys.stdout.flush()

    @staticmethod
    def fill_template(template_file, params_dict, output_file):
        """
        Fill template
        :param template_file: path to template file
        :param params_dict: parameters to fill template with
        :param output_file: path to output file
        :return:
        """
        with open(template_file, 'r') as fp:
            doc = fp.read()
        t = Template(doc)
        template_string = t.render(params_dict)
        with open(output_file, 'w') as fp:
            fp.write(template_string)

    #END_CLASS_HEADER

    # config contains contents of config file in a hash or None if it couldn't
    # be found
    def __init__(self, config):
        #BEGIN_CONSTRUCTOR
        self.callback_url = os.environ['SDK_CALLBACK_URL']
        self.scratch = config['scratch']
        self.workspaceURL = config['workspace-url']
        self.shockURL = config['shock-url']
        self.handleURL = config['handle-service-url']
        self.serviceWizardURL = config['service-wizard-url']
        self.dfu = DataFileUtil(self.callback_url)
        logging.basicConfig(format='%(created)s %(levelname)s: %(message)s',
                            level=logging.INFO)

        if not os.path.exists(self.scratch):
            os.makedirs(self.scratch)
        os.chdir(self.scratch)

        #END_CONSTRUCTOR
        pass

    def run_gottcha2(self, ctx, params):
        """
        This example function accepts any number of parameters and returns results in a KBaseReport
        :param params: instance of mapping from String to unspecified object
        :returns: instance of type "ReportResults" -> structure: parameter
           "report_name" of String, parameter "report_ref" of String
        """
        # ctx is the context object
        # return variables are: output
        #BEGIN run_gottcha2

        # Step 2 - Download the input data as a FASTQ and
        # We can use the ReadsUtils module to download a FASTQ file from our Reads data object.
        # The return object gives us the path to the file that was created.
        logging.info('Downloading Reads data as a Fastq file.')
        output_dir = os.path.join(self.scratch, f'gottcha2_output')
        report_dir = os.path.join(output_dir, 'html_report')
        params['output_dir'] = output_dir
        params['report_dir'] = report_dir
        logging.info(f'params {params}')
        token = ctx['token']
        wsClient = workspaceService(self.workspaceURL, token=token)
        env = os.environ.copy()
        env['KB_AUTH_TOKEN'] = token

        # object info
        [OBJID_I, NAME_I, TYPE_I, SAVE_DATE_I, VERSION_I, SAVED_BY_I, WSID_I, WORKSPACE_I, CHSUM_I, SIZE_I,
         META_I] = range(11)  # object_info tuple

        Set_types = ["KBaseSets.ReadsSet", "KBaseRNASeq.RNASeqSampleSet"]
        PE_types = ["KBaseFile.PairedEndLibrary", "KBaseAssembly.PairedEndLibrary"]
        SE_types = ["KBaseFile.SingleEndLibrary", "KBaseAssembly.SingleEndLibrary"]
        acceptable_types = Set_types + PE_types + SE_types

        # Determine whether read library or read set is input object
        #
        try:
            input_reads_obj_info = wsClient.get_object_info([{'ref': params['input_refs'][0]}], 1)[0]
            input_reads_obj_type = input_reads_obj_info[TYPE_I]
            input_reads_obj_type = re.sub('-[0-9]+\.[0-9]+$', "", input_reads_obj_type)  # remove trailing version
            # input_reads_obj_version = input_reads_obj_info[VERSION_I]  # this is object version, not type version
        except Exception as e:
            raise ValueError('Unable to get read library object from workspace: (' + str(
                params['input_refs']) + ')' + str(e))

        if input_reads_obj_type not in acceptable_types:
            raise ValueError(
                "Input reads of type: '" + input_reads_obj_type + "'.  Must be one of " + ", ".join(acceptable_types))

        # auto-detect reads type
        read_type = None
        if input_reads_obj_type in PE_types:
            read_type = 'PE'
        elif input_reads_obj_type in SE_types:
            read_type = 'SE'

        # get set
        #
        readsSet_ref_list = []
        readsSet_names_list = []
        if input_reads_obj_type in Set_types:
            try:
                # self.log (console, "INPUT_READS_REF: '"+input_params['input_refs']+"'")  # DEBUG
                # setAPI_Client = SetAPI (url=self.callbackURL, token=ctx['token'])  # for SDK local.  doesn't work for SetAPI
                setAPI_Client = SetAPI(url=self.serviceWizardURL, token=ctx['token'],
                                       service_ver='beta')  # for dynamic service
                input_readsSet_obj = setAPI_Client.get_reads_set_v1(
                    {'ref': params['input_refs'][0], 'include_item_info': 1})

            except Exception as e:
                raise ValueError('SetAPI FAILURE: Unable to get read library set object from workspace: (' + str(
                    params['input_refs']) + ")\n" + str(e))
            logging.info(f"reads set items {input_readsSet_obj['data']['items']}")
            for readsLibrary_obj in input_readsSet_obj['data']['items']:
                readsSet_ref_list.append(readsLibrary_obj['ref'])
                readsSet_names_list.append(readsLibrary_obj['info'][NAME_I])
                reads_item_type = readsLibrary_obj['info'][TYPE_I]
                reads_item_type = re.sub('-[0-9]+\.[0-9]+$', "", reads_item_type)  # remove trailing version
                if reads_item_type in PE_types:
                    this_read_type = 'PE'
                elif reads_item_type in SE_types:
                    this_read_type = 'SE'
                else:
                    raise ValueError(
                        "Can't handle read item type '" + reads_item_type + "' obj_name: '" + readsLibrary_obj['info'][
                            NAME_I] + " in Set: '" + str(params['input_refs']) + "'")
                if read_type != None and this_read_type != read_type:
                    raise ValueError("Can't handle read Set: '" + str(params[
                                                                          'input_refs']) + "'.  Unable to process mixed PairedEndLibrary and SingleEndLibrary.  Please split into separate ReadSets")
                elif read_type == None:
                    read_type = this_read_type
        else:
            readsSet_ref_list = params['input_refs']
            readsSet_names_list = input_reads_obj_info[NAME_I]

        output_list = []
        for reads_item_i,input_reads_library_ref in enumerate(readsSet_ref_list):
            params['input_ref'] = input_reads_library_ref
            params['read_type']= read_type
            params['reads_item_i'] = reads_item_i
            output_list.append(self.exec_gottcha2(ctx, params)[0])
        report_output = self.create_report(params.get('workspace_name'), output_list, params['report_dir'])
        logging.info(f'report_output {report_output}')
        output = {'report_name': report_output['name'], 'report_ref': report_output['ref']}
        #END run_gottcha2

        # At some point might do deeper type checking...
        if not isinstance(output, dict):
            raise ValueError('Method run_gottcha2 return value ' +
                             'output is not type dict as required.')
        # return the results
        return [output]

    def exec_gottcha2(self, ctx, params):
        """
        :param params: instance of mapping from String to unspecified object
        :returns: instance of type "ReportResults" -> structure: parameter
           "report_name" of String, parameter "report_ref" of String
        """
        # ctx is the context object
        # return variables are: output
        #BEGIN exec_gottcha2
        console = []
        self.log(console, 'Running GOTTCHA2 with parameters: ')
        self.log(console, "\n" + pformat(params))
        report = ''
        retVal = dict()
        token = ctx['token']
        wsClient = workspaceService(self.workspaceURL, token=token)
        headers = {'Authorization': 'OAuth ' + token}
        env = os.environ.copy()
        env['KB_AUTH_TOKEN'] = token
        # object info
        [OBJID_I, NAME_I, TYPE_I, SAVE_DATE_I, VERSION_I, SAVED_BY_I, WSID_I, WORKSPACE_I, CHSUM_I, SIZE_I,
         META_I] = range(11)  # object_info tuple

        # Set_types = ["KBaseSets.ReadsSet", "KBaseRNASeq.RNASeqSampleSet"]
        PE_types = ["KBaseFile.PairedEndLibrary", "KBaseAssembly.PairedEndLibrary"]
        SE_types = ["KBaseFile.SingleEndLibrary", "KBaseAssembly.SingleEndLibrary"]
        acceptable_types = PE_types + SE_types
        # Determine whether read library is of correct type
        #
        try:
            input_reads_obj_info = \
                wsClient.get_object_info_new({'objects': [{'ref': params['input_ref']}]})[0]
            logging.info(f'input_reads_obj_info {input_reads_obj_info}')
            logging.info(f"params input_ref {params['input_ref']}")
            input_reads_obj_type = input_reads_obj_info[TYPE_I]
            # input_reads_obj_version = input_reads_obj_info[VERSION_I]  # this is object version, not type version

        except Exception as e:
            raise ValueError('Unable to get read library object from workspace: (' + str(
                params['input_ref']) + ')' + str(e))

        input_reads_obj_type = re.sub('-[0-9]+\.[0-9]+$', "", input_reads_obj_type)  # remove trailing version
        acceptable_types = PE_types + SE_types
        if input_reads_obj_type not in acceptable_types:
            raise ValueError(
                "Input reads of type: '" + input_reads_obj_type + "'.  Must be one of " + ", ".join(acceptable_types))

        # Ensure that all libraries in ReadsSet are either single-ended or pair ended
        #
        if params['read_type'] == 'PE' and not input_reads_obj_type in PE_types:
            raise ValueError("read_type set to 'Paired End' but object is SingleEndLibrary")
        if params['read_type'] == 'SE' and not input_reads_obj_type in SE_types:
            raise ValueError("read_type set to 'Single End' but object is PairedEndLibrary")

        # Instatiate ReadsUtils
        #
        try:
            readsUtils_Client = ReadsUtils(url=self.callback_url, token=ctx['token'])  # SDK local

            download_reads_output = readsUtils_Client.download_reads({'read_libraries': [params['input_ref']],
                                                                      'interleaved': 'false'
                                                                      })
        except Exception as e:
            raise ValueError('Unable to get read library object from workspace: (' + str(
                params['input_ref']) + ")\n" + str(e))

        logging.info(
            f"Input parameters {params['input_refs']}, {params['db_type']} download_reads_output {download_reads_output}")
        fastq_files = []
        fastq_files_name = []
        for key, val in download_reads_output['files'].items():
            if 'fwd' in val['files'] and val['files']['fwd']:
                fastq_files.append(val['files']['fwd'])
                fastq_files_name.append(val['files']['fwd_name'])
            if 'rev' in val['files'] and val['files']['rev']:
                fastq_files.append(val['files']['rev'])
                fastq_files_name.append(val['files']['rev_name'])
        logging.info(f"fastq files {fastq_files}")
        fastq_files_string = ' '.join(fastq_files)
        # label = params['reads_item_i']
        if len(input_reads_obj_info[NAME_I].split('.')) > 1 :
            label = '_'.join(input_reads_obj_info[NAME_I].split('.')[:-1])
        else:
            label = input_reads_obj_info[NAME_I]
        logging.info(f'label {label}')
        output_dir = params['output_dir']
        report_dir = params['report_dir']
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
        ## default options
        if 'min_coverage' not in params:
            params['min_coverage'] = 0.005
        if 'min_reads' not in params:
            params['min_reads'] = 3
        if 'min_length' not in params:
            params['min_length'] = 60
        if 'max_zscore' not in params:
            params['max_zscore'] = 10
        outprefix = "gottcha2"

        cmd = ['/kb/module/lib/gottcha2/src/uge-gottcha2.sh', '-i', fastq_files_string, '-t', '4', '-o', output_dir,
               '-p',
               outprefix, '-d', '/data/gottcha2/RefSeq90/' + params['db_type'], '-c', str(params['min_coverage']), '-r',
               str(params['min_reads']), '-s', str(params['min_length']), '-z', str(params['max_zscore'])]
        logging.info(f'cmd {cmd}')
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        logging.info(f'subprocess {p.communicate()}')
        summary_file = os.path.join(report_dir, f'{label}_{outprefix}.summary.tsv')
        lineage_file = os.path.join(output_dir, outprefix + '.lineage.tsv')

        with open("/kb/module/work/tmp/gottcha2_output/gottcha2.gottcha_species.log", "r" ) as f:
            logging.info(f.readlines())

        if os.stat(lineage_file).st_size == 0:
            msg = 'There is no taxonomy classification assignment against ' + params[
                'db_type'] + ' reference DB. You may try another reference DB.'
            logging.error(msg)
            raise ValueError(msg)

        # generate report directory and html file
        if not os.path.exists(report_dir):
            os.makedirs(report_dir)
        output_files = []
        [output_files.append(f) for f in os.listdir(output_dir) if not os.path.isdir(os.path.join(output_dir, f))]

        # zf = ZipFile(os.path.join(output_dir, f'{label}.zip'), mode='w')
        # [zf.write(os.path.join(output_dir, f)) for f in output_files if os.path.splitext(f)[1] != '.sam']
        # output_files.append(f'{label}.zip')
        print(f"output_files list {output_files}")
        # copy files from output_dir to report_dir if file is not .sam so it doesn't end up in the zip file
        [shutil.copy2(os.path.join(output_dir, f), os.path.join(report_dir, f'{label}_{f}')) for f in output_files if os.path.splitext(f)[1] != '.sam']

        summary_file_dt = os.path.join(report_dir,  f'{label}_gottcha2.datatable.html')

        self._generate_DataTable(summary_file, summary_file_dt)
        self.fill_template('/kb/module/lib/gottcha2/src/index.html.tmpl', {'label': label}, os.path.join(report_dir, f'{label}_index.html'))
        # shutil.copy2('/kb/module/lib/gottcha2/src/index.html', os.path.join(report_dir, f'{label}_index.html'))
        shutil.copy2(os.path.join(output_dir, outprefix + '.krona.html'),
                     os.path.join(report_dir, f'{label}_gottcha2.krona.html'))
        if os.path.exists(os.path.join(output_dir, outprefix + '.tree.svg')):
            shutil.move(os.path.join(output_dir, outprefix + '.tree.svg'),
                        os.path.join(report_dir, f'{label}_gottcha2.tree.svg'))
        # html_zipped = self.package_folder(report_dir, f'{label}.zip', f'{label}.zip')
        # logging.info(f'html_zipped {html_zipped}')

        # copy .sam file to report_dir so that it's in the file_links
        [shutil.copy2(os.path.join(output_dir, f), os.path.join(report_dir, f'{label}_{f}')) for f in output_files if
         os.path.splitext(f)[1] == '.sam']

        # Step 5 - Build a Report and return
        objects_created = []
        output_files = glob(report_dir + f'/{label}*')

        logging.info(f'glob output_files {output_files}')
        output_files_list = []
        for file in output_files:
            if not os.path.isdir(file):
                # logging.info(f'file {file}')
                output_files_list.append({'path': file,
                                          'name': file.split('/')[-1]
                                          })
        logging.info(f'output_files_list {output_files_list}')
        zip_file = os.path.join(report_dir, f'{label}.zip')
        with ZipFile(zip_file, 'w', allowZip64=True) as myzip:
            [myzip.write(f['path']) for f in output_files_list if not f['path'].endswith('.sam')]
        output_files_list.append({'path': zip_file,
                                  'name': zip_file.split('/')[-1]
                                  })
        # not used

        output = {'output_files': output_files_list, 'file_links': output_files_list}
        #END exec_gottcha2

        # At some point might do deeper type checking...
        if not isinstance(output, dict):
            raise ValueError('Method exec_gottcha2 return value ' +
                             'output is not type dict as required.')
        # return the results
        return [output]
    def status(self, ctx):
        #BEGIN_STATUS
        returnVal = {'state': "OK",
                     'message': "",
                     'version': self.VERSION,
                     'git_url': self.GIT_URL,
                     'git_commit_hash': self.GIT_COMMIT_HASH}
        #END_STATUS
        return [returnVal]


# -*- coding: utf-8 -*-
"""
# @Author  : huxw
# @Update  : 2018/10/16 14:02
# @Software: PyCharm
"""

# 爬取内容：
#     a、最新电竞信息
import json

from new_word_md.utils import format_str
from utils import download_page

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'}

def esportsCrawler(path):
    for i in range(1,10):
        url = 'http://www.dadianjing.cn/index.php?m=Index&a=xhrList&cid=1&page='+str(i)
        try:
            result = download_page.download_html_waitting(url, headers, 1)
            result = json.loads(result,strict=False)
            items = result["data"]["list"]
            # 写入文件
            file = open(path, "a",encoding="utf-8")
            file.write("抓取电竞内容")
            for item in items:
                title = item['title']
                summary = item['summary']
                file.write(format_str((title+":"+summary))+'\n')
                print(title + "---" + summary)
            file.close()
        except Exception as e:
            print ("Except - 电竞:" + url,e)
    return 'success'


from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index),
    url(r'^reg_process$', views.reg, name='reg'),
    url(r'^log_process$', views.log),
    url(r'^success$', views.success),
    url(r'^logout$', views.logout),
]


# Routines for visualizing a tokamak.

from DREAM.DREAMSettings import DREAMSettings
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
import numpy as np

def plotSignal(ax, x, y, name, xlabel=False):
    """
    Plot the given signal nicely.

    :param ax: Axes to plot the signal on.
    :param x:  X coordinates.
    :param y:  Y coordinates.
    """
    ax.plot(x, y, linewidth=2, color=(87/255, 117/255, 144/255))
    if xlabel:
        ax.set_xlabel(r'Minor radius (m)')
    ax.set_ylabel(name)

    ax.set_xlim([x[0], x[-1]])
    ax.set_ylim([0, np.amax(y)*1.2])

def visualize(tokamak, nticks=None, Tticks=None):
    """
    Visualize the given tokamak module.

    :param tokamak: Module reference for the tokamak to visualize.
    """
    fig = plt.figure(figsize=(10,4))
    gs  = gridspec.GridSpec(3, 2)

    gs.update(wspace=0.22, hspace=0, left=0.13, top=0.95, right=0.95, bottom=0.14)

    # Magnetic field
    ds = DREAMSettings()
    tokamak.setMagneticField(ds)

    ax = fig.add_subplot(gs[:,0])
    ds.radialgrid.visualize(ax=ax, ntheta=100)

    #

    # Density
    r, ne0 = tokamak.getInitialDensity()
    axn = fig.add_subplot(gs[0,1])
    plotSignal(axn, r, ne0/1e19, name=r'$n_e$ ($10^{19}\,$m$^{-3}$)')

    if nticks:
        axn.set_yticks(nticks)

    # Temperature
    r, Te0 = tokamak.getInitialTemperature()
    axT = fig.add_subplot(gs[1,1])
    plotSignal(axT, r, Te0/1e3, name=r'$T_e$ (keV)')

    if Tticks:
        axT.set_yticks(Tticks)

    # Current density
    r, j0 = tokamak.getCurrentDensity()
    axj = fig.add_subplot(gs[2,1])
    plotSignal(axj, r, j0, name=r'$j/j_0$', xlabel=True)

    axj.set_yticks(np.linspace(0.2, 1, 3))

    xticks = np.linspace(0, 1, 6)
    if ds.radialgrid.a == 0:
        xticks *= ds.radialgrid.r_f[-1]
    else:
        xticks *= ds.radialgrid.a

    tickparams = {'direction': 'in', 'length': 5, 'top': True, 'right': True, 'labelsize': 13}
    axn.set_xticks(xticks)
    axn.set_xticklabels([])
    axn.tick_params(**tickparams)
    axT.set_xticks(xticks)
    axT.set_xticklabels([])
    axT.tick_params(**tickparams)
    axj.set_xticks(xticks)
    axj.tick_params(**tickparams)

    def settxt(ax, x, y, txt, direction='tl', **kwargs):
        if 'l' in direction: xdir = 0
        else: xdir = 1
        if 'b' in direction: ydir = 0
        else: ydir = 1

        ax.text(ax.get_xlim()[xdir]*x, ax.get_ylim()[ydir]*y, txt, **kwargs)

    #ax.text(ax.get_xlim()[0]*1.04, ax.get_ylim()[1]*0.92, '(a)')
    #axn.text(
    settxt(ax,  0.86, 0.87, '(a)')
    settxt(axn, 0.88, 0.81, '(b)', 'tr')
    settxt(axT, 0.88, 0.81, '(c)', 'tr')
    settxt(axj, 0.88, 0.81, '(d)', 'tr')

    plt.show()


from django.urls import path, re_path, include
from django.contrib.auth import views as auth_views
from . import views

urlpatterns =[
    path('',views.index,name="index"),
    path('home',views.home,name="home"),
    path('signup',views.signup,name="signup"),
    path('activate/<uidb64>/<token>/', views.activate , name='activate'),
    #path('accounts/login',auth_views.login,name='login'),
    #path('accounts/logout',auth_views.logout,name='logout'),
    path('accounts/',include('django.contrib.auth.urls')),

]

"""
Line 10  will Implement All of these views

 login/ [name='login']
 logout/ [name='logout']
 password_change/ [name='password_change']
 password_change/done/ [name='password_change_done']
 password_reset/ [name='password_reset']
 password_reset/done/ [name='password_reset_done']
 reset/<uidb64>/<token>/ [name='password_reset_confirm']
 reset/done/ [name='password_reset_complete']
"""


from pykdtree.kdtree import KDTree
import time
import trimesh
import numpy as np

def filter_mesh_significant_outside_pieces(unfiltered_mesh,main_mesh,significance_threshold=2000,n_sample_points=3):
    """
    Purpose; will take in a full, unfiltered mesh and find the biggest mesh piece, and then return a list of that mesh
    with all of the other mesh fragments that are both above the significance_threshold AND outside of the biggest mesh piece

    Pseudocode:
    1) split the meshes to unconnected pieces
    2) Filter the meshes for only those above the significance_threshold
    3) find the biggest mesh piece
    4) Iterate through all of the remaining pieces:
        a. Determine if mesh inside or outside main mesh
        b. If outside add to final list to return

    Returns:
    1) list of significant mesh pieces that are not inside of main mesh

    """

    print("------Starting the mesh filter for significant outside pieces-------")

    mesh_pieces = unfiltered_mesh.split(only_watertight=False)

    print(f"There were {len(mesh_pieces)} pieces after mesh split")

    significant_pieces = [m for m in mesh_pieces if len(m.faces) > significance_threshold]

    print(f"There were {len(significant_pieces)} pieces found after size threshold")
    if len(significant_pieces) <=0:
        print("THERE WERE NO MESH PIECES GREATER THAN THE significance_threshold")
        return []

    final_mesh_pieces = []

    #final_mesh_pieces.append(main_mesh)
    for i,mesh in enumerate(significant_pieces):
        #get a random sample of points
        # points = np.array(mesh.vertices[:n_sample_points,:]) # OLD WAY OF DOING THIS
        idx = np.random.randint(len(mesh.vertices), size=n_sample_points)
        points = mesh.vertices[idx,:]

        start_time = time.time()
        signed_distance = trimesh.proximity.signed_distance(main_mesh,points)
        #print(f"Total time = {time.time() - start_time}")

        outside_percentage = sum(signed_distance <= 0)/n_sample_points
        if outside_percentage > 0.9:
            final_mesh_pieces.append(mesh)
            #print(f"Mesh piece {i} OUTSIDE mesh")
        else:
            #print(f"Mesh piece {i} inside mesh :( ")
            pass

    return final_mesh_pieces

def neuron_boolean_difference(main_mesh_verts,
                             main_mesh_faces,
                             child_mesh_verts,
                             child_mesh_faces,
                             distance_threshold=5,
                             significance_threshold=1000,
                             n_sample_points=3):
    """
    returns the boolean difference of two meshes passed. Only returns meshes pieces that
    are greater than the size threshold and outside of the main mesh

    Function operation: child_mesh - main_mesh

    Parameters:
    main_mesh_verts (np.array): array of the reference mesh vertices
    main_mesh_faces (np.array): array of the reference mesh faces
    child_mesh_verts (np.array): array of the child mesh vertices that is to be compared to the main mesh
    child_mesh_faces (np.array): array of the child mesh faces that is to be compared to the main mesh

    Optional parameters:
    -- for controlling the mesh returned --
    distance_threshold (int) : distance away from the reference mesh that vertices from the child
                                mesh will considered distinct and part of the difference mesh
                                (default=5)
    significance_threshold (int) : number of faces necessary for any distinct/unconnected part of the
                                    difference mesh to be considered relevant and included in the difference mesh
                                (default=1000)
    n_sample_points (int) : number of vertices to check to see if submesh is a mesh located inside of the main mesh.
                            The less there are the quicker the speed for filtering the difference mesh
                            (default=3)

    Returns:
    difference_mesh_verts (np.array): array of vertices from the mesh boolean operation of child - main mesh
    difference_mesh_faces (np.array): array of faces from the mesh boolean operation of child - main mesh
    """

    #Create the kdtree from main mesh and run the queries

    import time
    global_time = time.time()
    start_time = time.time()
    mesh_tree = KDTree(main_mesh_verts)
    distances,closest_node = mesh_tree.query(child_mesh_verts)
    print(f"Total time for KDTree creation and queries: {time.time() - start_time}")

    print("Original number vertices in child mesh = " + str(len(child_mesh_verts)))
    vertex_indices = np.where(distances > distance_threshold)[0]
    print("Number of vertices after distance threshold applied =  " + str(len(vertex_indices)))

    start_time = time.time()
    set_vertex_indices = set(list(vertex_indices))
    face_indices_lookup = np.linspace(0,len(child_mesh_faces)-1,len(child_mesh_faces)).astype('int')
    face_indices_lookup_bool = [len(set_vertex_indices.intersection(set(tri))) > 0 for tri in child_mesh_faces]
    face_indices_lookup = face_indices_lookup[face_indices_lookup_bool]

    print(f"Total time for finding faces after distance threshold applied: {time.time() - start_time}")

    start_time = time.time()
    trimesh_original = trimesh.Trimesh(child_mesh_verts,child_mesh_faces,process=False)
    new_submesh = trimesh_original.submesh([face_indices_lookup],only_watertight=False,append=True)

    pymesh_mesh = trimesh.Trimesh(main_mesh_verts,main_mesh_faces)

    #filter the mesh for only significant pieces on the outside
    returned_mesh = filter_mesh_significant_outside_pieces(new_submesh,pymesh_mesh,significance_threshold,n_sample_points=n_sample_points)

    total_returned_mesh = trimesh.Trimesh()
    for r in returned_mesh:
        total_returned_mesh = total_returned_mesh + r

    print(f"Total time for filtering: {time.time() - start_time}")
    return total_returned_mesh.vertices,total_returned_mesh.faces

    print(f"Total time for boolean difference: {time.time() - global_time}")


# -*- coding: cp1252 -*-
import nltk
from nltk.tokenize import word_tokenize

def res():
# Step 1 – Training data
 train = [

    ("Nifty India,ONGC and gail marginally higher","Positive"),
    ("Nifty ends marginally up on BSE","Positive"),
    ("Modest Monday Nifty ends above 7500 mark in choppy session","Positive"),
    ("Nifty zooms 10%","Positive"),
    ("Nifty declares interim dividend; stock zooms 7%","Positive"),
    ("Daily Market Strategy Holding on! Sensex, Nifty to start upbeat","Positive"),
    ("Top 18 stocks in focus today: SBI, Tata Motors, SpiceJet","Positive"),
    ("Sensex, Nifty extend gains to 2nd week in a row","Positive"),
    (" Nifty Dividend delight! Bharat Forge, Welspun India others declare dividend","Positive"),
    ("Nifty, Welspun India among 15 scrips that hit 52-week high","Positive"),
    ("Skipper soars after winning order from Power Grid","Positive"),

    '''("Oil stocks end mixed; cabinet approves policy on hydrocarbon exploration","Positive"),
    ("Dalmia Bharat Sugar,Kellton Tech among 10 stocks that hit 52-week high","Positive"),
    ("Godrej Consumer acquires 39% additional stake in DGH Owned Style Industries; stock down","Positive"),
    ("Pipavav Defence rallies 11%","Positive"),
    ("Marsons gallops 10% on bagging EPC contract","Positive"),
    ("Va Tech Wabag gallops 7% on order win","Positive"),
    ("Mphasis rises 2.9%; BSE seeks clarification on Mint report","Positive"),
    ("VA Tech Wabag bags order worth Rs. 594 crore","Positive"),
    ("Strides Shasun to acquire 3 brands from Moberg Pharma for USD 10 Million","Positive"),
    ("HMT gallops 14.6%","Positive"),
    ("Daily Market Strategy - Another fine Friday start! Indices to open in green","Positive"),
    ("European indices gain as EU, UK reach deal in Brexit talks","Positive"),("Indian ADRs end higher on positive global cues","Positive"),("Nasdaq closes higher led by gains in tech shares","Positive"),("Major Asian indices inch higher","Positive"),("European indices rebound as profit booking wanes","Positive"),("Japan's Nikkei rebounds in the early trade","Positive"),("Dow Jones closes at record high","Positive"),("US Fed nominee comments and strong consumer data aid US indices to close at record highs","Positive"),("US Indices end higher; gold prices slip","Positive"),
    ("Indian ADRs end higher tracking strong US markets","Positive"),

    ("US benchmark Indices end lower","Negative"),
    ("US indices end off-lows; tax bill nears passage","Negative"),
    ("Asian markets subdued following tepid US close","Negative"),
    ("Most US indices end lower as FOMC indicates dovish stance","Negative"),
    ("Coal India crashes 7% despite hefty dividend; plans to buyback 5%","Negative"),
    ("Sasken gallops 20%; settles Protocol Stack IP dispute","Negative"),
    ("Falling low! Jammu & Kashmir Bank, Prestige Estates among 11 stocks that hit 52-week lows","Negative"),
    ("High value stocks tumble since January 2016","Negative"),
    ("Ramky Infrastructure, Sequent Scientific among 10 stocks that hit 52-week high","Negative"),
    ("Hot stocks: Reliance slumps 3%, Golden Tobacco gallops 11%","Negative"),
    ("Syndicate Bank ends flat; reports a Rs. 1000 crore scam","Negative"),
    ("Despite late recovery Metal stocks end in red; Vedanta dips 3%","Negative"),
    ("ICRA, Visagar Polytex among 15 scrips that hit 52-week low","Negative"),
    ("Mindtree slumps 9%; issues Q4 revenue warning","Negative"),
    ("Nifty slips below 7500 mark","Negative"),
    ("SBI releases Rs. 1465 crores to defence pensioners","Neutral"),
    ("Timing, rhyming and relative calm in the equity markets","Neutral"),
    ("Sebi bars wilful defaulters from raising public funds","Neutral"),
    ("Fine Friday finally! Nifty settles above 7500","Neutral"),
    ("JSPL tumbles 5%; Franklin Temp MF sells bonds","Negative"),
    ("Crompton Greaves accepted revised offer for sale of T&D assets","Neutral"),
    ("Why CONCOR is in the news today?","Neutral"),
    ("Yes Bank ends flat; appoints former CCI chairman Ashok Chawla","Neutral"),
    ("Sensex, Nifty end flat; BoB, SBI top Nifty losers","Neutral"),
    ("Thomas Cook signs strategic alliance with Western Union Business Solutions and DCB Bank","Neutral"),
    ("Asian indices end mixed; China Shanghai Composite slips","Neutral"),
    ("Asian indices mixed tracking weak cues from US markets","Neutral"),
    ("European Markets trade mixed on Thursday","Neutral"),
    ("Asian indices mixed ahead of key economic data","Neutral"),
    ("US shares end on a mixed note","Neutral"),
    ("Indian ADRs end on a mixed note on Friday","Neutral"),
    ("SpiceJet plunges 4%","Negative"),
    ("SpiceJet crashes 4.5% over court battle","Negative"),
    ("Pfizer plunges 7% after discontinuing Corex sale; Mcap erodes by Rs. 821 cr","Negative"),
    ("IDBI Bank dips by 1.44%, Moody's affirmed its rating","Negative"),
    (  "United Spirits slips 2%; plans to sell 13 residential properties","Negative"),
    ("Sensex, Nifty to open flat with negative bias","Negative"),
    ("Nifty hits 52 week high","Positive") ,
    ("Nifty hits 52 week low","Negative")'''
 ]

 # Step 2
 dictionary = set(word.lower() for passage in train for word in word_tokenize(passage[0]))

 # Step 3
 t = [({word: (word in word_tokenize(x[0])) for word in dictionary}, x[1]) for x in train]

 # Step 4 – the classifier is trained with sample data
 classifier = nltk.NaiveBayesClassifier.train(t)

 test_data = "Nifty "
 test_data_features = {word.lower(): (word in word_tokenize(test_data.lower())) for word in dictionary}

 result=(classifier.classify(test_data_features))
 return result
res()


from PyQt5.QtCore import Qt, pyqtSignal, QObject
from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import QDialog, QBoxLayout, QGridLayout, QLabel, QLineEdit, QPushButton, QProgressBar, QFileDialog, \
    QGroupBox, QCheckBox, QHBoxLayout, QSpacerItem

class NTFSLogFileDialog(QDialog, QObject):
    complete = pyqtSignal()

    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        QObject.__init__(self)
        self.selectedPartition = -1
        self.initUI()

    def initUI(self):
        self.setWindowTitle("Import File System Log File")
        # self.setFixedSize(570, 300)
        self.setFixedSize(self.sizeHint())
        self.layout = QBoxLayout(QBoxLayout.TopToBottom, self)
        self.spacerItem1 = QSpacerItem(10, 5)
        self.layout.addItem(self.spacerItem1)
        self.setLayout(self.layout)

        # First Group
        self.diskRawChkBox = QCheckBox("In this case, it's possible to carve some files.", self)
        self.diskRawChkBox.stateChanged.connect(lambda: self.selectedType(self.diskRawChkBox))
        self.diskRawGroupBox = QGroupBox(self)
        self.diskRawGroupBox.setStyleSheet("margin-top: 0;")
        self.diskRawGroupBox.setDisabled(True)
        diskRawGroupBoxLayout = QHBoxLayout(self.diskRawGroupBox)
        self.diskRawGroupBox.setLayout(diskRawGroupBoxLayout)

        self.diskRawLabel = QLabel("Disk Raw: ", self)
        self.diskRawTextBox = QLineEdit()
        self.diskRawTextBox.setReadOnly(True)
        self.diskRawTextBox.setFixedWidth(400)

        self.browseDiskRawBtn = QPushButton("...", self)
        self.browseDiskRawBtn.setFixedWidth(50)
        self.browseDiskRawBtn.clicked.connect(self.btnClicekd)
        self.browseDiskRawBtn.setCursor(QCursor(Qt.PointingHandCursor))

        diskRawGroupBoxLayout.addWidget(self.diskRawLabel)
        diskRawGroupBoxLayout.addWidget(self.diskRawTextBox)
        diskRawGroupBoxLayout.addWidget(self.browseDiskRawBtn)

        self.layout.addWidget(self.diskRawChkBox)
        self.layout.addWidget(self.diskRawGroupBox)

        # Second Group
        self.ntfsLogFileChkBox = QCheckBox("In this case, NTFS Log analysis only supported.", self)
        self.ntfsLogFileChkBox.stateChanged.connect(lambda: self.selectedType(self.ntfsLogFileChkBox))

        self.ntfsLogGroupBox = QGroupBox(self)
        self.ntfsLogGroupBox.setStyleSheet("margin-top: 0;")
        self.ntfsLogGroupBox.setDisabled(True)
        ntfsLogGroupBoxLayout = QGridLayout(self)
        self.ntfsLogGroupBox.setLayout(ntfsLogGroupBoxLayout)

        self.mftLabel = QLabel("$MFT: ", self)
        self.mftPathTextBox = QLineEdit(self)
        self.mftPathTextBox.setReadOnly(True)
        self.mftPathTextBox.setFixedWidth(400)
        self.browseMFTBtn = QPushButton("...", self)
        self.browseMFTBtn.setFixedWidth(50)
        self.browseMFTBtn.clicked.connect(self.btnClicekd)
        self.browseMFTBtn.setCursor(QCursor(Qt.PointingHandCursor))

        self.usnjrnlLabel = QLabel("$UsnJrnl: ", self)
        self.usnjrnlPathTextBox = QLineEdit(self)
        self.usnjrnlPathTextBox.setReadOnly(True)
        self.usnjrnlPathTextBox.setFixedWidth(400)
        self.browseUsnJrnlBtn = QPushButton("...", self)
        self.browseUsnJrnlBtn.setFixedWidth(50)
        self.browseUsnJrnlBtn .clicked.connect(self.btnClicekd)
        self.browseUsnJrnlBtn.setCursor(QCursor(Qt.PointingHandCursor))

        self.logfileLabel = QLabel("$LogFile: ", self)
        self.logfilePathTextBox = QLineEdit(self)
        self.logfilePathTextBox.setReadOnly(True)
        self.logfilePathTextBox.setFixedWidth(400)
        self.browseLogFileBtn = QPushButton("...", self)
        self.browseLogFileBtn.setFixedWidth(50)
        self.browseLogFileBtn .clicked.connect(self.btnClicekd)
        self.browseLogFileBtn.setCursor(QCursor(Qt.PointingHandCursor))

        ntfsLogGroupBoxLayout.addWidget(self.mftLabel, 0, 0)
        ntfsLogGroupBoxLayout.addWidget(self.mftPathTextBox, 0, 1)
        ntfsLogGroupBoxLayout.addWidget(self.browseMFTBtn, 0, 2)
        ntfsLogGroupBoxLayout.addWidget(self.usnjrnlLabel, 1, 0)
        ntfsLogGroupBoxLayout.addWidget(self.usnjrnlPathTextBox, 1, 1)
        ntfsLogGroupBoxLayout.addWidget(self.browseUsnJrnlBtn, 1, 2)
        ntfsLogGroupBoxLayout.addWidget(self.logfileLabel, 2, 0)
        ntfsLogGroupBoxLayout.addWidget(self.logfilePathTextBox, 2, 1)
        ntfsLogGroupBoxLayout.addWidget(self.browseLogFileBtn, 2, 2)

        self.submitBtn = QPushButton("Submit", self)
        self.submitBtn.setFixedSize(100, 40)
        self.submitBtn.setCursor(QCursor(Qt.PointingHandCursor))

        self.loggingLabel = QLabel("Loading...", self)
        self.loggingLabel.setFixedHeight(20)
        self.loggingLabel.setAlignment(Qt.AlignCenter)
        self.loggingLabel.hide()

        self.loadingBar = QProgressBar(self)
        self.loadingBar.setFixedHeight(10)
        self.loadingBar.setTextVisible(False)
        self.loadingBar.hide()

        from modules.UI.LoadingScreen import LoadingBarThread
        self.barThread = LoadingBarThread(self)
        self.barThread.change_value.connect(self.loadingBar.setValue)

        self.spacerItem2 = QSpacerItem(10, 15)
        self.spacerItem3 = QSpacerItem(10, 20)
        self.layout.addItem(self.spacerItem2)
        self.layout.addWidget(self.ntfsLogFileChkBox)
        self.layout.addWidget(self.ntfsLogGroupBox)
        self.layout.addItem(self.spacerItem3)
        self.layout.addWidget(self.submitBtn, alignment=Qt.AlignHCenter)

        self.setWindowModality(Qt.WindowModal)
        self.show()

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Escape:
            self.close()

    def selectedType(self, b):
        if b is self.diskRawChkBox:
            if b.isChecked():
                self.ntfsLogFileChkBox.setChecked(False)
                self.ntfsLogGroupBox.setDisabled(True)
                self.diskRawGroupBox.setDisabled(False)
            else:
                self.diskRawGroupBox.setDisabled(True)
        else:
            if b.isChecked():
                self.diskRawChkBox.setChecked(False)
                self.diskRawGroupBox.setDisabled(True)
                self.ntfsLogGroupBox.setDisabled(False)
            else:
                self.ntfsLogGroupBox.setDisabled(True)

    def btnClicekd(self):
        sender = self.sender()
        fileName = QFileDialog.getOpenFileName(self)
        if sender is self.browseDiskRawBtn:
            self.diskRawTextBox.setText(fileName[0])
        elif sender is self.browseMFTBtn:
            self.mftPathTextBox.setText(fileName[0])
        elif sender is self.browseUsnJrnlBtn:
            self.usnjrnlPathTextBox.setText(fileName[0])
        elif sender is self.browseLogFileBtn:
            self.logfilePathTextBox.setText(fileName[0])

    def ready(self):
        self.submitBtn.hide()
        self.layout.removeWidget(self.submitBtn)
        self.layout.addWidget(self.loggingLabel, alignment=Qt.AlignBottom | Qt.AlignHCenter)
        self.layout.addWidget(self.loadingBar)
        self.loggingLabel.show()
        self.loadingBar.show()
        self.barThread.start()

    def resume(self):
        if self.barThread.cnt < 50:
            self.barThread.cnt = 100
            return
        self.barThread.toggle_status()

    def changeInterface(self, contents):
        from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem

        self.layout.removeWidget(self.diskRawChkBox)
        self.diskRawChkBox.hide()
        self.layout.removeWidget(self.diskRawGroupBox)
        self.diskRawGroupBox.hide()
        self.layout.removeItem(self.spacerItem2)
        self.layout.removeWidget(self.ntfsLogFileChkBox)
        self.ntfsLogFileChkBox.hide()
        self.layout.removeWidget(self.ntfsLogGroupBox)
        self.ntfsLogGroupBox.hide()
        self.layout.removeItem(self.spacerItem3)
        self.layout.removeWidget(self.submitBtn)

        self.diskNameLabel = QLabel("Image Name:\t" + contents[0][0], self)
        self.diskSizeLabel = QLabel("Image Size:\t{} Bytes".format(contents[0][1]), self)
        self.diskSizeLabel.setFixedHeight(20)
        self.diskSizeLabel.setAlignment(Qt.AlignVCenter)
        self.diskPartLabel = QLabel("Partition:", self)
        self.diskPartLabel.setFixedHeight(20)
        self.diskPartLabel.setAlignment(Qt.AlignBottom)

        self.partitionTree = QTreeWidget(self)
        self.partitionTree.setHeaderLabels(
            ["Order", "File System", "Active", "Starting Offset", "Total Sector", "Size"])
        self.partitionTree.itemChanged.connect(self.itemChanged)
        self.partitionTree.resizeColumnToContents(2)
        self.partitionTree.resizeColumnToContents(3)
        self.partitionTree.resizeColumnToContents(4)
        self.partitionTree.headerItem().setTextAlignment(0, Qt.AlignCenter)
        self.partitionTree.headerItem().setTextAlignment(1, Qt.AlignCenter)

        self.partitionItems = []
        for row in range(1, 5):
            self.partitionTree.headerItem().setTextAlignment(row + 1, Qt.AlignCenter)
            item = QTreeWidgetItem(self.partitionTree)
            item.setText(0, str(row))
            item.setTextAlignment(0, Qt.AlignLeft)
            if not contents[row]:
                item.setText(1, "None")
                item.setCheckState(0, Qt.Unchecked)
                item.setDisabled(True)
                continue
            for col in range(5):
                item.setText(col + 1, contents[row][col])
                item.setTextAlignment(col + 1, Qt.AlignCenter)
            item.setTextAlignment(1, Qt.AlignLeft)
            item.setCheckState(0, Qt.Unchecked)
            self.partitionItems.append(item)

        self.layout.addWidget(self.diskNameLabel)
        self.layout.addWidget(self.diskSizeLabel)
        self.layout.addWidget(self.diskPartLabel)
        self.layout.addWidget(self.partitionTree)
        self.layout.addItem(QSpacerItem(10, 10))
        self.layout.addWidget(self.submitBtn, alignment=Qt.AlignCenter)

    def itemChanged(self, changedItem, p_int):
        if changedItem.checkState(0) == Qt.Checked:
            self.selectedPartition = int(changedItem.text(0))
            for item in self.partitionItems:
                if item is not changedItem:
                    item.setCheckState(0, Qt.Unchecked)

if __name__ == '__main__':
    from PyQt5.QtWidgets import QApplication
    import sys
    import qdarkstyle
    app = QApplication(sys.argv)
    w = NTFSLogFileDialog()
    app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
    sys.exit(app.exec_())

{'LoadingBarThread': 'modules.UI.LoadingScreen.LoadingBarThread', 'QTreeWidget': 'PyQt5.QtWidgets.QTreeWidget', 'QTreeWidgetItem': 'PyQt5.QtWidgets.QTreeWidgetItem'}


# Copyright (C) 2018 Red Hat, Inc
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import fixtures
import mock

from nova.tests.functional import fixtures as func_fixtures
from nova.tests.functional import test_servers as base
from nova.tests.unit.virt.libvirt import fake_imagebackend
from nova.tests.unit.virt.libvirt import fake_libvirt_utils
from nova.tests.unit.virt.libvirt import fakelibvirt

class ServersTestBase(base.ServersTestBase):

    def setUp(self):
        super(ServersTestBase, self).setUp()

        # Replace libvirt with fakelibvirt
        self.useFixture(fake_imagebackend.ImageBackendFixture())
        self.useFixture(fixtures.MonkeyPatch(
            'nova.virt.libvirt.driver.libvirt_utils',
            fake_libvirt_utils))
        self.useFixture(fixtures.MonkeyPatch(
            'nova.virt.libvirt.driver.libvirt',
            fakelibvirt))
        self.useFixture(fixtures.MonkeyPatch(
            'nova.virt.libvirt.host.libvirt',
            fakelibvirt))
        self.useFixture(fixtures.MonkeyPatch(
            'nova.virt.libvirt.guest.libvirt',
            fakelibvirt))
        self.useFixture(fakelibvirt.FakeLibvirtFixture())
        self.useFixture(func_fixtures.PlacementFixture())

        # Mock the 'get_connection' function, as we're going to need to provide
        # custom capabilities for each test
        _p = mock.patch('nova.virt.libvirt.host.Host.get_connection')
        self.mock_conn = _p.start()
        self.addCleanup(_p.stop)

    def _setup_compute_service(self):
        # NOTE(stephenfin): We don't start the compute service here as we wish
        # to configure the host capabilities first. We instead start the
        # service in the test
        self.flags(compute_driver='libvirt.LibvirtDriver')

    def _get_connection(self, host_info, pci_info=None):
        fake_connection = fakelibvirt.Connection(
            'qemu:///system',
            version=fakelibvirt.FAKE_LIBVIRT_VERSION,
            hv_version=fakelibvirt.FAKE_QEMU_VERSION,
            host_info=host_info,
            pci_info=pci_info)
        return fake_connection


from datetime import datetime as dt
from datetime import timedelta
from unittest import TestCase

from src.plugins.plugin_filter_day import plugin_filter_day
from src.plugins.plugin_filter_date import plugin_filter_date

class TestPlugins(TestCase):
    def test_plugin_repeat(self):
        today = dt.today()
        delta = timedelta(days=2)
        day = today.strftime('%d').replace('0', '')
        month = today.strftime('%m').replace('0', '')

        params_1 = {
            'from_date': (today - delta).strftime('%Y-%m-%d'),
            'to_date': (today + delta).strftime('%Y-%m-%d'),
            'days': day,
            'months': month
        }
        result = plugin_filter_date(**params_1)
        self.assertTrue(result)

        params_2 = {
            'to_date': (today + delta).strftime('%Y-%m-%d'),
            'days': '1-31',
            'months': str(int(month) - 2)
        }
        result = plugin_filter_date(**params_2)
        self.assertFalse(result)

    def test_plugin_day(self):
        test_all = 'Sun,Mon-Fri,Sat'
        test_any = 'any'
        test_wrong = 'wro'

        self.assertTrue(plugin_filter_day(test_all))
        self.assertTrue(plugin_filter_day(test_any))
        self.assertFalse(plugin_filter_day(test_wrong))


import cv2
import os

"""
    This code is provided for Quiz3 of HZAU Vision Lab via @LucasX
"""

def read_img(source_imgpath):
    img = cv2.imread(source_imgpath, 1)

    return img

def crop_img(img, new_x, new_y):
    """
        crop image to a new size
    """
    res = cv2.resize(img, (new_x, new_y), interpolation=cv2.INTER_AREA)
    cv2.imwrite('/home/lucasx/snail' + str(new_x) + '_' + str(new_y) +
                '.jpg', res)

def rotate_img(img, rotate_angle, outputdir):
    """
        rotate this image and write out to a new one
    """
    if not os.path.exists(outputdir) and not os.path.isdir(outputdir):
        os.mkdir(outputdir)

    rows, cols = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY).shape
    M = cv2.getRotationMatrix2D((cols / 2, rows / 2), rotate_angle, 1)
    dst = cv2.warpAffine(img, M, (cols, rows))
    cv2.imwrite(outputdir + os.path.sep + 'snail_' + str(rotate_angle) + '.jpg', dst)

if __name__ == '__main__':
    img = read_img('/home/lucasx/snail.jpg')
    print(img.shape)
    crop_img(img, 64, 64)

    # this code block is to rotate image and output
    curr_angle = 0
    while curr_angle < 360:
        rotate_img(img, curr_angle, '/home/lucasx/rotate_img')
        curr_angle += 15


"""Python Cookbook 2nd ed.

Chapter 12, recipe 1.
"""
import json
import random
from typing import (
    List,
    Dict,
    Iterator,
    Any,
    Callable,
    Union,
    Optional,
    Tuple,
    Iterable,
    cast,
    overload,
    TYPE_CHECKING,
    Text,
    Protocol,
)

class Card:
    """
    >>> c = Card(1, "\\u2660")
    >>> repr(c)
    "Card(rank=1, suit='♠')"
    >>> c.to_json()
    {'__class__': 'Card', 'rank': 1, 'suit': '♠'}
    """

    __slots__ = ("rank", "suit")

    def __init__(self, rank: int, suit: str) -> None:
        self.rank = int(rank)
        self.suit = suit

    def __repr__(self):
        return f"Card(rank={self.rank!r}, suit={self.suit!r})"

    def to_json(self):
        return {"__class__": "Card", "rank": self.rank, "suit": self.suit}

class Deck:
    SUITS = (
        "\N{black spade suit}",
        "\N{white heart suit}",
        "\N{white diamond suit}",
        "\N{black club suit}",
    )
    """
    Create deck or shoe.

    >>> random.seed(2)
    >>> deck = Deck()
    >>> cards = deck.deal(5)
    >>> cards  # doctest: +NORMALIZE_WHITESPACE
    [Card(rank=4, suit='♣'), Card(rank=8, suit='♡'),
     Card(rank=3, suit='♡'), Card(rank=6, suit='♡'),
     Card(rank=2, suit='♠')]
    >>> json_cards = list(card.to_json() for card in deck.deal(5))
    >>> print(json.dumps(json_cards, indent=2, sort_keys=True))
    [
      {
        "__class__": "Card",
        "rank": 2,
        "suit": "\u2662"
      },
      {
        "__class__": "Card",
        "rank": 13,
        "suit": "\u2663"
      },
      {
        "__class__": "Card",
        "rank": 7,
        "suit": "\u2662"
      },
      {
        "__class__": "Card",
        "rank": 6,
        "suit": "\u2662"
      },
      {
        "__class__": "Card",
        "rank": 7,
        "suit": "\u2660"
      }
    ]
    """

    def __init__(self, n: int = 1) -> None:
        self.n = n
        self.create_deck(self.n)

    def create_deck(self, n: int = 1) -> None:
        self.cards = [
            Card(r, s) for r in range(1, 14) for s in self.SUITS for _ in range(n)
        ]
        random.shuffle(self.cards)
        self.offset = 0

    def deal(self, hand_size: int = 5) -> List[Card]:
        if self.offset + hand_size > len(self.cards):
            self.create_deck(self.n)
        hand = self.cards[self.offset : self.offset + hand_size]
        self.offset += hand_size
        return hand

    def __len__(self) -> int:
        return len(self.cards)

    @overload
    def __getitem__(self, position: int) -> Card:
        ...

    @overload
    def __getitem__(self, position: slice) -> List[Card]:
        ...

    def __getitem__(self, position: Union[int, slice]) -> Union[Card, List[Card]]:
        return self.cards[position]

    def __iter__(self) -> Iterator[Card]:
        return iter(self.cards)

# Copy-Pasta from wsgiref/types.pyi
class StartResponse(Protocol):
    def __call__(
        self,
        status: str,
        headers: List[Tuple[str, str]],
        exc_info: Optional[Tuple] = ...,
    ) -> Callable[[bytes], Any]:
        ...

WSGIEnvironment = Dict[Text, Any]
WSGIApplication = Callable[[WSGIEnvironment, StartResponse], Iterable[bytes]]

from http import HTTPStatus

deck: Optional[Deck] = None

def deal_cards(
    environ: Dict[str, Any], start_response: StartResponse
) -> Iterable[bytes]:
    global deck
    if deck is None:
        random.seed(environ.get("DEAL_APP_SEED"))
        deck = Deck()
    hand_size = int(environ.get("HAND_SIZE", 5))
    cards = deck.deal(hand_size)
    status = f"{HTTPStatus.OK.value} {HTTPStatus.OK.phrase}"
    headers = [("Content-Type", "application/json;charset=utf-8")]
    start_response(status, headers)
    json_cards = list(card.to_json() for card in cards)
    return [json.dumps(json_cards, indent=2).encode("utf-8")]

class DealCards:
    def __init__(self, hand_size: int = 5, seed: Optional[int] = None) -> None:
        self.hand_size = hand_size
        random.seed(seed)
        self.deck = Deck()
        self.offset = 0

    def __call__(
        self, environ: Dict[str, Any], start_response: StartResponse
    ) -> Iterable[bytes]:
        if self.offset + self.hand_size >= len(self.deck):
            self.deck = Deck()
            self.offset = 0
        cards = self.deck[self.offset : self.offset + self.hand_size]
        self.offset += self.hand_size
        status = f"{HTTPStatus.OK.value} {HTTPStatus.OK.phrase}"
        headers = [("Content-Type", "application/json;charset=utf-8")]
        start_response(status, headers)
        json_cards = list(card.to_json() for card in cards)
        return [json.dumps(json_cards, indent=2).encode("utf-8")]

from urllib.parse import parse_qs

class JSON_Filter:
    def __init__(self, json_app: WSGIApplication) -> None:
        self.json_app = json_app

    def __call__(
        self, environ: Dict[str, Any], start_response: StartResponse
    ) -> Iterable[bytes]:
        if "HTTP_ACCEPT" in environ:
            if "json" in environ["HTTP_ACCEPT"]:
                environ["$format"] = "json"
                return self.json_app(environ, start_response)
        decoded_query = parse_qs(environ["QUERY_STRING"])
        if "$format" in decoded_query:
            if decoded_query["$format"][0].lower() == "json":
                environ["$format"] = "json"
                return self.json_app(environ, start_response)
        status = f"{HTTPStatus.BAD_REQUEST.value} {HTTPStatus.BAD_REQUEST.phrase}"
        headers = [("Content-Type", "text/plain;charset=utf-8")]
        start_response(status, headers)
        return [
            "Request doesn't include ?$format=json or Accept:application/json header".encode(
                "utf-8"
            )
        ]

if __name__ == "__main__":
    from wsgiref.simple_server import make_server

    # dealer = DealCards()
    json_wrapper = JSON_Filter(deal_cards)

    httpd = make_server("", 8080, json_wrapper)  # type: ignore
    httpd.serve_forever()


import itertools
import struct
from functools import reduce
from _collections import defaultdict

import Orange
import numpy as np
import spectral.io.envi
from Orange.data import \
    ContinuousVariable, StringVariable, TimeVariable, Domain, Table
from Orange.data.io import FileFormat
import Orange.data.io
from scipy.interpolate import interp1d
from scipy.io import matlab
import numbers

from .pymca5 import OmnicMap
from .agilent import agilentImage, agilentMosaic

class SpectralFileFormat:

    def read_spectra(self):
        """ Fast reading of spectra. Return spectral information
        in two arrays (wavelengths and values). Only additional
        attributes (usually metas) are returned as a Table.

        Return a triplet:
            - 1D numpy array,
            - 2D numpy array with the same last dimension as xs,
            - Orange.data.Table with only meta or class attributes
        """
        pass

    def read(self):
        domvals, data, additional_table = self.read_spectra()
        data = np.asarray(data, dtype=np.float64)  # Orange assumes X to be float64
        features = [Orange.data.ContinuousVariable.make("%f" % f) for f in domvals]
        if additional_table is None:
            domain = Orange.data.Domain(features, None)
            return Orange.data.Table(domain, data)
        else:
            domain = Orange.data.Domain(features,
                                        class_vars=additional_table.domain.class_vars,
                                        metas=additional_table.domain.metas)
            ret_data = additional_table.transform(domain)
            ret_data.X = data
            return ret_data

class DatReader(FileFormat):
    """ Reader for files with multiple columns of numbers. The first column
    contains the wavelengths, the others contain the spectra. """
    EXTENSIONS = ('.dat', '.dpt', '.xy',)
    DESCRIPTION = 'Spectra ASCII'

    def read(self):
        tbl = np.loadtxt(self.filename, ndmin=2)
        domvals = tbl.T[0]  # first column is attribute name
        from orangecontrib.spectroscopy.preprocess import features_with_interpolation
        domain = Orange.data.Domain(features_with_interpolation(domvals), None)
        datavals = tbl.T[1:]
        return Orange.data.Table(domain, datavals)

    @staticmethod
    def write_file(filename, data):
        xs = getx(data)
        xs = xs.reshape((-1, 1))
        table = np.hstack((xs, data.X.T))
        np.savetxt(filename, table, delimiter="\t", fmt="%g")

class AsciiMapReader(FileFormat):
    """ Reader ascii map files.

    First row contains wavelengths, then each row describes a spectrum, starting with (x, y)
    coordinates: http://www.cytospec.com/file.php#FileASCII3 """
    EXTENSIONS = ('.xyz',)
    DESCRIPTION = 'Hyperspectral map ASCII'

    def read(self):
        with open(self.filename, "rb") as f:
            # read first row separately because of two empty columns
            header = f.readline().decode("ascii").rstrip().split("\t")
            header = [a.strip() for a in header]
            assert header[0] == header[1] == ""
            dom_vals = [float(v) for v in header[2:]]
            from orangecontrib.spectroscopy.preprocess import features_with_interpolation
            domain = Orange.data.Domain(features_with_interpolation(dom_vals), None)
            tbl = np.loadtxt(f, ndmin=2)
            data = Orange.data.Table(domain, tbl[:, 2:])
            metas = [ContinuousVariable.make('map_x'), ContinuousVariable.make('map_y')]
            domain = Orange.data.Domain(domain.attributes, None, metas=metas)
            data = data.transform(domain)
            data[:, metas[0]] = tbl[:, 0].reshape(-1, 1)
            data[:, metas[1]] = tbl[:, 1].reshape(-1, 1)
            return data

    @staticmethod
    def write_file(filename, data):
        wavelengths = getx(data)
        try:
            ndom = Domain([data.domain["map_x"], data.domain["map_y"]] + list(data.domain.attributes))
        except KeyError:
            raise RuntimeError('Data needs to include meta variables "map_x" and "map_y"')
        data = data.transform(ndom)
        with open(filename, "wb") as f:
            header = ["", ""] + [("%g" % w) for w in wavelengths]
            f.write(('\t'.join(header) + '\n').encode("ascii"))
            np.savetxt(f, data.X, delimiter="\t", fmt="%g")

def _spectra_from_image(X, features, x_locs, y_locs):
    """
    Create a spectral format (returned by SpectralFileFormat.read_spectra)
    from 3D image organized [ rows, columns, wavelengths ]
    """
    X = np.asarray(X)
    x_locs = np.asarray(x_locs)
    y_locs = np.asarray(y_locs)

    # each spectrum has its own row
    spectra = X.reshape((X.shape[0]*X.shape[1], X.shape[2]))

    # locations
    y_loc = np.repeat(np.arange(X.shape[0]), X.shape[1])
    x_loc = np.tile(np.arange(X.shape[1]), X.shape[0])
    metas = np.array([x_locs[x_loc], y_locs[y_loc]]).T

    domain = Orange.data.Domain([], None,
                                metas=[Orange.data.ContinuousVariable.make("map_x"),
                                       Orange.data.ContinuousVariable.make("map_y")]
                                )
    data = Orange.data.Table.from_numpy(domain, X=np.zeros((len(spectra), 0)),
                                        metas=np.asarray(metas, dtype=object))
    return features, spectra, data

class MatlabReader(FileFormat):
    EXTENSIONS = ('.mat',)
    DESCRIPTION = "Matlab"

    # Matlab 7.3+ files are not handled by scipy reader

    def read(self):
        who = matlab.whosmat(self.filename)
        if not who:
            raise IOError("Couldn't load matlab file " + self.filename)
        else:
            ml = matlab.loadmat(self.filename, chars_as_strings=True)

            ml = {a: b for a, b in ml.items() if isinstance(b, np.ndarray)}

            # X is the biggest numeric array
            numarrays = []
            for name, con in ml.items():
                 if issubclass(con.dtype.type, numbers.Number):
                    numarrays.append((name, reduce(lambda x, y: x*y, con.shape, 1)))
            X = None
            if numarrays:
                nameX = max(numarrays, key=lambda x: x[1])[0]
                X = ml.pop(nameX)

            # find an array with compatible shapes
            attributes = []
            if X is not None:
                nameattributes = None
                for name, con in ml.items():
                    if con.shape in [(X.shape[1],), (1, X.shape[1])]:
                        nameattributes = name
                        break
                attributenames = ml.pop(nameattributes).ravel() if nameattributes else range(X.shape[1])
                attributenames = [str(a).strip() for a in attributenames]  # strip because of numpy char array
                attributes = [ContinuousVariable.make(a) for a in attributenames]

            metas = []
            metaattributes = []

            sizemetas = None
            if X is None:
                counts = defaultdict(list)
                for name, con in ml.items():
                    counts[len(con)].append(name)
                if counts:
                    sizemetas = max(counts.keys(), key=lambda x: len(counts[x]))
            else:
                sizemetas = len(X)
            if sizemetas:
                for name, con in ml.items():
                    if len(con) == sizemetas:
                        metas.append(name)

            metadata = []
            for m in sorted(metas):
                f = ml[m]
                metaattributes.append(StringVariable.make(m))
                f.resize(sizemetas, 1)
                metadata.append(f)

            metadata = np.hstack(tuple(metadata))

            domain = Domain(attributes, metas=metaattributes)
            if X is None:
                X = np.zeros((sizemetas, 0))
            return Orange.data.Table.from_numpy(domain, X, Y=None, metas=metadata)

class EnviMapReader(FileFormat, SpectralFileFormat):
    EXTENSIONS = ('.hdr',)
    DESCRIPTION = 'Envi'

    def read_spectra(self):
        a = spectral.io.envi.open(self.filename)
        X = np.array(a.load())
        try:
            lv = a.metadata["wavelength"]
            features = np.array(list(map(float, lv)))
        except KeyError:
            #just start counting from 0 when nothing is known
            features = np.arange(X.shape[-1])

        x_locs = np.arange(X.shape[1])
        y_locs = np.arange(X.shape[0])

        return _spectra_from_image(X, features, x_locs, y_locs)

class HDF5Reader_HERMES(FileFormat, SpectralFileFormat):
    """ A very case specific reader for HDF5 files from the HEREMES beamline in SOLEIL"""
    EXTENSIONS = ('.hdf5',)
    DESCRIPTION = 'HDF5 file @HERMRES/SOLEIL'

    def read_spectra(self):
        import h5py
        hdf5_file = h5py.File(self.filename)
        if hdf5_file['entry1/collection/beamline'].value.astype('str') == 'Hermes':
            x_locs = np.array(hdf5_file['entry1/Counter0/sample_x'])
            y_locs = np.array(hdf5_file['entry1/Counter0/sample_y'])
            energy = np.array(hdf5_file['entry1/Counter0/energy'])
            intensities = np.array(hdf5_file['entry1/Counter0/data']).T
        return _spectra_from_image(intensities, energy, x_locs, y_locs)

class OmnicMapReader(FileFormat, SpectralFileFormat):
    """ Reader for files with two columns of numbers (X and Y)"""
    EXTENSIONS = ('.map',)
    DESCRIPTION = 'Omnic map'

    def read_spectra(self):
        om = OmnicMap.OmnicMap(self.filename)
        info = om.info
        X = om.data

        try:
            lv = info['OmnicInfo']['Last X value']
            fv = info['OmnicInfo']['First X value']
            features = np.linspace(fv, lv, num=X.shape[-1])
        except KeyError:
            #just start counting from 0 when nothing is known
            features = np.arange(X.shape[-1])

        try:
            loc_first = info['OmnicInfo']["First map location"]
            loc_last = info['OmnicInfo']["Last map location"]
            x_locs = np.linspace(min(loc_first[0], loc_last[0]),
                                 max(loc_first[0], loc_last[0]), X.shape[1])
            y_locs = np.linspace(min(loc_first[1], loc_last[1]),
                                 max(loc_first[1], loc_last[1]), X.shape[0])
        except KeyError:
            x_locs = np.arange(X.shape[1])
            y_locs = np.arange(X.shape[0])

        return _spectra_from_image(X, features, x_locs, y_locs)

class AgilentImageReader(FileFormat, SpectralFileFormat):
    """ Reader for Agilent FPA single tile image files"""
    EXTENSIONS = ('.seq',)
    DESCRIPTION = 'Agilent Single Tile Image'

    def read_spectra(self):
        ai = agilentImage(self.filename)
        info = ai.info
        X = ai.data

        try:
            features = info['wavenumbers']
        except KeyError:
            #just start counting from 0 when nothing is known
            features = np.arange(X.shape[-1])

        try:
            px_size = info['FPA Pixel Size'] * info['PixelAggregationSize']
        except KeyError:
            # Use pixel units if FPA Pixel Size is not known
            px_size = 1
        x_locs = np.linspace(0, X.shape[1]*px_size, num=X.shape[1], endpoint=False)
        y_locs = np.linspace(0, X.shape[0]*px_size, num=X.shape[0], endpoint=False)

        return _spectra_from_image(X, features, x_locs, y_locs)

class agilentMosaicReader(FileFormat, SpectralFileFormat):
    """ Reader for Agilent FPA mosaic image files"""
    EXTENSIONS = ('.dms',)
    DESCRIPTION = 'Agilent Mosaic Image'

    def read_spectra(self):
        am = agilentMosaic(self.filename)
        info = am.info
        X = am.data

        try:
            features = info['wavenumbers']
        except KeyError:
            #just start counting from 0 when nothing is known
            features = np.arange(X.shape[-1])

        try:
            px_size = info['FPA Pixel Size'] * info['PixelAggregationSize']
        except KeyError:
            # Use pixel units if FPA Pixel Size is not known
            px_size = 1
        x_locs = np.linspace(0, X.shape[1]*px_size, num=X.shape[1], endpoint=False)
        y_locs = np.linspace(0, X.shape[0]*px_size, num=X.shape[0], endpoint=False)

        return _spectra_from_image(X, features, x_locs, y_locs)

class SPCReader(FileFormat):
    EXTENSIONS = ('.spc', '.SPC',)
    DESCRIPTION = 'Galactic SPC format'

    def read(self):
        try:
            import spc
        except ImportError:
            raise RuntimeError("To load spc files install spc python module (https://github.com/rohanisaac/spc)")

        spc_file = spc.File(self.filename)
        if spc_file.talabs:
            table = self.multi_x_reader(spc_file)
        else:
            table = self.single_x_reader(spc_file)
        return table

    def single_x_reader(self, spc_file):
        domvals = spc_file.x  # first column is attribute name
        domain = Orange.data.Domain([Orange.data.ContinuousVariable.make("%f" % f) for f in domvals], None)
        y_data = [sub.y for sub in spc_file.sub]
        y_data = np.array(y_data)
        table = Orange.data.Table.from_numpy(domain, y_data.astype(float, order='C'))
        return table

    def multi_x_reader(self, spc_file):
        # use x-values as domain
        all_x = []
        for sub in spc_file.sub:
            x = sub.x
            # assume values in x do not repeat
            all_x = np.union1d(all_x, x)
        domain = Orange.data.Domain([Orange.data.ContinuousVariable.make("%f" % f) for f in all_x], None)

        instances = []
        for sub in spc_file.sub:
            x, y = sub.x, sub.y
            newinstance = np.ones(len(all_x))*np.nan
            ss = np.searchsorted(all_x, x)  # find positions to set
            newinstance[ss] = y
            instances.append(newinstance)

        y_data = np.array(instances).astype(float, order='C')
        return Orange.data.Table.from_numpy(domain, y_data)

class OPUSReader(FileFormat):
    """Reader for OPUS files"""

    EXTENSIONS = (".0*", ".1*", ".2*", ".3*", ".4*", ".5*", ".6*", ".7*", ".8*", ".9*")
    DESCRIPTION = 'OPUS Spectrum'

    @property
    def sheets(self):
        import opusFC
        dbs = []
        for db in opusFC.listContents(self.filename):
            dbs.append(db[0] + " " + db[1] + " " + db[2])
        return dbs

    def read(self):
        import opusFC

        if self.sheet:
            db = self.sheet
        else:
            db = self.sheets[0]

        db = tuple(db.split(" "))
        dim = db[1]

        try:
            data = opusFC.getOpusData(self.filename, db)
        except Exception:
            raise IOError("Couldn't load spectrum from " + self.filename)

        attrs, clses, metas = [], [], []

        attrs = [ContinuousVariable.make(repr(data.x[i]))
                    for i in range(data.x.shape[0])]

        y_data = None
        meta_data = None

        if type(data) == opusFC.MultiRegionDataReturn:
            y_data = []
            meta_data = []
            metas.extend([ContinuousVariable.make('map_x'),
                          ContinuousVariable.make('map_y'),
                          StringVariable.make('map_region'),
                          TimeVariable.make('start_time')])
            for region in data.regions:
                y_data.append(region.spectra)
                mapX = region.mapX
                mapY = region.mapY
                map_region = np.full_like(mapX, region.title, dtype=object)
                start_time = region.start_time
                meta_region = np.column_stack((mapX, mapY,
                                               map_region, start_time))
                meta_data.append(meta_region.astype(object))
            y_data = np.vstack(y_data)
            meta_data = np.vstack(meta_data)

        elif type(data) == opusFC.MultiRegionTRCDataReturn:
            y_data = []
            meta_data = []
            metas.extend([ContinuousVariable.make('map_x'),
                          ContinuousVariable.make('map_y'),
                          StringVariable.make('map_region')])
            attrs = [ContinuousVariable.make(repr(data.labels[i]))
                        for i in range(len(data.labels))]
            for region in data.regions:
                y_data.append(region.spectra)
                mapX = region.mapX
                mapY = region.mapY
                map_region = np.full_like(mapX, region.title, dtype=object)
                meta_region = np.column_stack((mapX, mapY, map_region))
                meta_data.append(meta_region.astype(object))
            y_data = np.vstack(y_data)
            meta_data = np.vstack(meta_data)

        elif type(data) == opusFC.ImageDataReturn:
            metas.extend([ContinuousVariable.make('map_x'),
                          ContinuousVariable.make('map_y')])

            data_3D = data.spectra

            for i in np.ndindex(data_3D.shape[:1]):
                map_y = np.full_like(data.mapX, data.mapY[i])
                coord = np.column_stack((data.mapX, map_y))
                if y_data is None:
                    y_data = data_3D[i]
                    meta_data = coord.astype(object)
                else:
                    y_data = np.vstack((y_data, data_3D[i]))
                    meta_data = np.vstack((meta_data, coord))

        elif type(data) == opusFC.ImageTRCDataReturn:
            metas.extend([ContinuousVariable.make('map_x'),
                          ContinuousVariable.make('map_y')])

            attrs = [ContinuousVariable.make(repr(data.labels[i]))
                        for i in range(len(data.labels))]
            data_3D = data.traces

            for i in np.ndindex(data_3D.shape[:1]):
                map_y = np.full_like(data.mapX, data.mapY[i])
                coord = np.column_stack((data.mapX, map_y))
                if y_data is None:
                    y_data = data_3D[i]
                    meta_data = coord.astype(object)
                else:
                    y_data = np.vstack((y_data, data_3D[i]))
                    meta_data = np.vstack((meta_data, coord))

        elif type(data) == opusFC.TimeResolvedTRCDataReturn:
            y_data = data.traces

        elif type(data) == opusFC.TimeResolvedDataReturn:
            metas.extend([ContinuousVariable.make('z')])

            y_data = data.spectra
            meta_data = data.z

        elif type(data) == opusFC.SingleDataReturn:
            y_data = data.y[None,:]

        else:
            raise ValueError("Empty or unsupported opusFC DataReturn object: " + type(data))

        import_params = ['SRT', 'SNM']

        for param_key in import_params:
            try:
                param = data.parameters[param_key]
            except KeyError:
                pass # TODO should notify user?
            else:
                try:
                    param_name = opusFC.paramDict[param_key]
                except KeyError:
                    param_name = param_key
                if param_key == 'SRT':
                    var = TimeVariable.make(param_name)
                elif type(param) is float:
                    var = ContinuousVariable.make(param_name)
                elif type(param) is str:
                    var = StringVariable.make(param_name)
                else:
                    raise ValueError #Found a type to handle
                metas.extend([var])
                params = np.full((y_data.shape[0],), param, np.array(param).dtype)
                if meta_data is not None:
                    # NB dtype default will be np.array(fill_value).dtype in future
                    meta_data = np.column_stack((meta_data, params.astype(object)))
                else:
                    meta_data = params

        domain = Orange.data.Domain(attrs, clses, metas)

        meta_data = np.atleast_2d(meta_data)

        table = Orange.data.Table.from_numpy(domain,
                                             y_data.astype(float, order='C'),
                                             metas=meta_data)

        return table

class SPAReader(FileFormat, SpectralFileFormat):
    #based on code by Zack Gainsforth

    EXTENSIONS = (".spa", ".SPA", ".srs")
    DESCRIPTION = 'SPA'

    saved_sections = None
    type = None

    def sections(self):
        if self.saved_sections is None:
            with open(self.filename, 'rb') as f:
                name = struct.unpack("30s", f.read(30))[0].decode("ascii")
                extended = "Exte" in name
                f.seek(288)
                ft, v, _, n = struct.unpack('<hhhh', f.read(8))
                self.saved_sections = []
                self.type = ft
                for i in range(n):
                    # Go to the section start.
                    f.seek(304 + (22 if extended else 16) * i)
                    t, offset, length = struct.unpack('<hqi' if extended else '<hii',
                                                      f.read(14 if extended else 10))
                    self.saved_sections.append((i, t, offset, length))
        return self.saved_sections

    SPEC_HEADER = 2

    def find_indextype(self, t):
        for i, a, _, _ in self.sections():
            if a == t:
                return i

    @property
    def sheets(self):
        return ()

    def read_spec_header(self):
        info = self.find_indextype(self.SPEC_HEADER)
        _, _, offset, length = self.sections()[info]
        with open(self.filename, 'rb') as f:
            f.seek(offset)
            dataType, numPoints, xUnits, yUnits, firstX, lastX, noise = struct.unpack('<iiiifff', f.read(28))
            return numPoints, firstX, lastX,

    def read_spectra(self):

        self.sections()

        if self.type == 1:
            type = 3
        else:
            type = 3  # TODO handle others differently

        numPoints, firstX, lastX = self.read_spec_header()

        _, _, offset, length = self.sections()[self.find_indextype(type)]

        with open(self.filename, 'rb') as f:
            f.seek(offset)
            data = np.fromfile(f, dtype='float32', count=length//4)

        if len(data) == numPoints:
            domvals = np.linspace(firstX, lastX, numPoints)
        else:
            domvals = np.arange(len(data))

        data = np.array([data])
        return domvals, data, None

class GSFReader(FileFormat):

    EXTENSIONS = (".gsf",)
    DESCRIPTION = 'Gwyddion Simple Field'

    def read(self):
        with open(self.filename, "rb") as f:
            #print(f.readline())
            if not (f.readline() == b'Gwyddion Simple Field 1.0\n'):
                raise ValueError('Not a correct file')

            meta = {}

            term = False #there are mandatory fileds
            while term != b'\x00':
                l = f.readline().decode('utf-8')
                name, value = l.split("=")
                name = name.strip()
                value = value.strip()
                meta[name] = value
                term = f.read(1)
                f.seek(-1, 1)

            f.read(4 - f.tell() % 4)

            meta["XRes"] = XR = int(meta["XRes"])
            meta["YRes"] = YR = int(meta["YRes"])
            meta["XReal"] = float(meta.get("XReal", 1))
            meta["YReal"] = float(meta.get("YReal", 1))
            meta["XOffset"] = float(meta.get("XOffset", 0))
            meta["YOffset"] = float(meta.get("YOffset", 0))
            meta["Title"] = meta.get("Title", None)
            meta["XYUnits"] = meta.get("XYUnits", None)
            meta["ZUnits"] = meta.get("ZUnits", None)

            X = np.fromfile(f, dtype='float32', count=XR*YR).reshape(XR, YR)

            metas = [Orange.data.ContinuousVariable.make("x"),
                     Orange.data.ContinuousVariable.make("y")]

            XRr = np.arange(XR)
            YRr = np.arange(YR)
            indices = np.transpose([np.tile(XRr, len(YRr)), np.repeat(YRr, len(XRr))])

            domain = Orange.data.Domain([Orange.data.ContinuousVariable.make("value")], None, metas=metas)
            data = Orange.data.Table(domain,
                                     X.reshape(meta["XRes"]*meta["YRes"], 1),
                                     metas=np.array(indices, dtype="object"))
            data.attributes = meta
            return data

class NeaReader(FileFormat):

    EXTENSIONS = (".nea", ".txt")
    DESCRIPTION = 'NeaSPEC'

    def read(self):

        with open(self.filename, "rt") as f:
            next(f)  # skip header
            l = next(f)
            l = l.strip()
            l = l.split("\t")
            ncols = len(l)

            f.seek(0)
            next(f)
            datacols = np.arange(4, ncols)
            data = np.loadtxt(f, dtype="float", usecols=datacols)

            f.seek(0)
            next(f)
            metacols = np.arange(0, 4)
            meta = np.loadtxt(f,
                              dtype={'names': ('row', 'column', 'run', 'channel'),
                                     'formats': (np.int, np.int, np.int, "S10")},
                              usecols=metacols)

            # ASSUMTION: runs start with 0
            runs = np.unique(meta["run"])

            # ASSUMPTION: there is one M channel and multiple O?A and O?P channels,
            # both with the same number, both starting with 0
            channels = np.unique(meta["channel"])
            maxn = -1

            def channel_type(a):
                if a.startswith(b"O") and a.endswith(b"A"):
                    return "OA"
                elif a.startswith(b"O") and a.endswith(b"P"):
                    return "OP"
                else:
                    return "M"

            for a in channels:
                if channel_type(a) in ("OA", "OP"):
                    maxn = max(maxn, int(a[1:-1]))
            numharmonics = maxn+1

            rowcols = np.vstack((meta["row"], meta["column"])).T
            uniquerc = set(map(tuple, rowcols))

            di = {}  # dictionary of indices for each row and column

            min_intp, max_intp = None, None

            for i, (row, col, run, chan) in enumerate(meta):
                if (row, col) not in di:
                    di[(row, col)] = \
                        {"M": np.zeros((len(runs), len(datacols))) * np.nan,
                         "OA": np.zeros((numharmonics, len(runs), len(datacols))) * np.nan,
                         "OP": np.zeros((numharmonics, len(runs), len(datacols))) * np.nan}
                if channel_type(chan) == "M":
                    di[(row, col)][channel_type(chan)][run] = data[i]
                    if min_intp is None:  # we need the limits of common X for all
                        min_intp = np.min(data[i])
                        max_intp = np.max(data[i])
                    else:
                        min_intp = max(min_intp, np.min(data[i]))
                        max_intp = min(max_intp, np.max(data[i]))
                elif channel_type(chan) in ("OA", "OP"):
                    di[(row, col)][channel_type(chan)][int(chan[1:-1]), run] = data[i]

            X = np.linspace(min_intp, max_intp, num=len(datacols))

            final_metas = []
            final_data = []

            for row, col in uniquerc:
                cur = di[(row, col)]
                M, OA, OP = cur["M"], cur["OA"], cur["OP"]

                OAn = np.zeros(OA.shape) * np.nan
                OPn = np.zeros(OA.shape) * np.nan
                for run in range(len(M)):
                    f = interp1d(M[run], OA[:, run])
                    OAn[:, run] = f(X)
                    f = interp1d(M[run], OP[:, run])
                    OPn[:, run] = f(X)

                OAmean = np.mean(OAn, axis=1)
                OPmean = np.mean(OPn, axis=1)
                final_data.append(OAmean)
                final_data.append(OPmean)
                final_metas += [[row, col, "O%dA" % i] for i in range(numharmonics)]
                final_metas += [[row, col, "O%dP" % i] for i in range(numharmonics)]

            final_data = np.vstack(final_data)

            metas = [Orange.data.ContinuousVariable.make("row"),
                     Orange.data.ContinuousVariable.make("column"),
                     Orange.data.StringVariable.make("channel")]

            domain = Orange.data.Domain(
                [Orange.data.ContinuousVariable.make("%f" % f) for f in X],
                None, metas=metas)
            final_metas = np.array(final_metas, dtype=object)
            return Orange.data.Table(domain, final_data, metas=final_metas)

def build_spec_table(wavenumbers, intensities):
    """
    Converts numpy arrays of wavenumber and intensity into an
    Orange.data.Table spectra object.

    Args:
        wavenumbers (np.array): 1D array of wavenumbers
        intensities (np.array): 2D array of (multi-spectra) intensities

    Returns:
        table: Orange.data.Table object, spectra format
    """

    # Add dimension to 1D array if necessary
    if intensities.ndim == 1:
        intensities = intensities[None,:]

    # Convert the wavenumbers array into a list of ContinousVariables
    wn_vars = [Orange.data.ContinuousVariable.make(repr(wavenumbers[i]))
                for i in range(wavenumbers.shape[0])]

    # Build an Orange.data.Domain object with wn_vars as
    # independant variables (or "attributes" as Orange calls them)
    domain = Orange.data.Domain(wn_vars)

    # Finally, build the table using the damain and intensity arrays:
    table = Orange.data.Table.from_numpy(domain, intensities)
    return table

def getx(data):
    """
    Return x of the data. If all attribute names are numbers,
    return their values. If not, return indices.
    """
    x = np.arange(len(data.domain.attributes), dtype="f")
    try:
        x = np.array([float(a.name) for a in data.domain.attributes])
    except:
        pass
    return x

def spectra_mean(X):
    return np.nanmean(X, axis=0, dtype=np.float64)


from collections import Counter
from itertools import combinations
from operator import mul
from functools import reduce
from numpy import dot

def process_input(inputs):
    output = []
    for input in inputs:
        m, primes = input

        #sum primes
        sum_prime = 0
        prime_list = []
        for prime in primes:
            p, f = prime
            p = int(p)
            f = int(f)
            sum_prime += p*f
            for _ in range(f):
                prime_list.append(p)
        previous_solutions = set()
        max=0
        for i in range(len(prime_list)):
            for combination in combinations(prime_list, i+1):
                product = reduce(mul, combination, 1)
                if product>sum_prime:
                    continue #this is an obvious bad option, we skip
                elif product in previous_solutions:
                    continue #we've already explored it
                else:
                    c1 = Counter(prime_list)
                    c2 = Counter(combination)

                    diff = c1 - c2

                    if dot(list(diff.values()), list(diff.keys()))==product:
                        if product>max:
                            max = product

                    previous_solutions.add(product)
        output.append(max)

    return output

if __name__ == "__main__":
    T = int(input())
    inputs = []
    for _ in range(T):
        N = int(input())
        x = []
        for _ in range(N):

            str = input().split(' ')
            x.append(str)
        inputs.append([N,x])

    output_lines = process_input(inputs)

    i = 1
    for l in output_lines:
        print("Case #{}: {}".format(i, l))
        i += 1