import scrapy
import html2text
import re

class SenateSpider(scrapy.Spider):
    name = "senate_members"
    start_urls = [ 'http://www.oksenate.gov/Senators/Default.aspx?selectedtab=0' ]

    def parse(self, response):
        hrefs = response.xpath('//table[@summary="This table lists the Senators alphabetically.  Each senator\'s name is linked to his or her respective contact page."]/tr/td/span/span/a/@href').extract()[:48]

        for href in hrefs:
            yield scrapy.Request(response.urljoin(href),
                                 callback=self.parse_senator)

    def parse_senator(self, response):
        yield scrapy.Request(
            response.urljoin(response.xpath('//iframe/@src').extract_first()),
            callback=self.parse_senator_iframe)

    def parse_senator_iframe(self, response):
        htmlstrip = html2text.HTML2Text()
        htmlstrip.ignore_links = True
        #sen_re = re.compile(r'Senator (.*) - District (\d+)')
        sen_re = re.compile(r'(?:Senator )?\b(.*)\s*-\s*District\s*(\d+)')
        phone_re = re.compile(r'\(?(405|918)\)?.?(\d{3}).?(\d{4})')
        room_re = re.compile(r'(Rm\.|Room)\s*([0-9a-zA-Z]+)')

        markdown_page = htmlstrip.handle(response.body_as_unicode()).replace('\\', '').replace('*', '')
        name, dist = sen_re.findall(markdown_page)[0]

        district = int(dist)
        fname = name.split()[0]
        lname = name.split()[-1]

        phone = '-'.join(phone_re.findall(markdown_page)[0])

        cmtes = response.xpath('//html/body/table/tr/td/table/tr[4]/td/ul[1]/li').extract()
        cmtes = map(htmlstrip.handle, cmtes)
        cmtes = map(lambda a: a.split(' ', 1)[1].replace('*', '').strip(), cmtes)

        # Remove Chair, etc:
        cmtes = map(lambda a: a.split('\\-')[0].strip(), cmtes)

        room = room_re.findall(markdown_page)[0][1]

        party_letter = response.xpath('//html/body/table/tr/td/table/tr/td').re(r'Republican|Democrat|Libertarian')[0][0]

        return dict(
            fname=fname,
            lname=lname,
            name=name,
            district=district,
            party=party_letter,
            committees=cmtes,
            office=room,
            phone=phone
        )


#!/usr/bin/env python
"""
NAME
    suServer -  websocket server for su data

RETURNS
   returns a json string
"""

from datetime import datetime
import sys
import asyncio
import json
import websockets
import numpy as np
import scipy.signal as sig
#import pprint

#print("loading obspy...")
from obspy.io.segy.segy import _read_su
#print("... done.")

# FIXME - this only works with 3.5, not 3.6
if sys.version_info == (3, 6):
    raise "** must use python v3.4 or 3.5"

class Segy(object):
    """Local version of the SU/SEGY file"""
    def __init__(self):
        self.filename = None
        self.hdrs = None
        self.traces = None
        self.nsamps = 0
        self.dt = 0
        self.segyfile = None

    def getPSD(self, ens):
        """
        Calculate and return average power spectral density for ensemble
        `ens` using Welch's method
        """
        print('in getpsd, ens=', ens, self)
        if not self.segyfile:
            raise Exception("File not opened")
        enstrcs = [t for t in self.segyfile.traces if t.header.original_field_record_number == ens]
        psds = [sig.welch(t.data, fs=1/self.dt, scaling='spectrum') for t in enstrcs]
        # psds is [(f,psd), (f,psd)...]
        freqs = psds[0][0]
        psdonly = [p for (f, p) in psds]
        psdonly = np.array(psdonly).transpose()
        psdavg = np.mean(psdonly, 1)
        print(freqs.shape, psdavg.shape)
        return(freqs, psdavg)

    def getTrc(self, trcNum=0):
        """ Get trace `trcNum` and return a python dict"""
        pass

segy = Segy()
#print(segy)

def getTrc(t, headonly=True, decimate=False, t1=-1, t2=-1, flo=None, fhi=None):
    """Convert a segy trace to a python dict

    An obspy SegyTrace t is converted to a python dict with optional
    filtering of the data.

    Parameters:
    -----------
    t : SegyTrc object
    headonly : bool, optional
         If True, only return the trace headers, with `samps` set to an
         empty array.
    flo, fhi : number
        If `flo` and `fhi` are specified, filter the data before return.
    t1, t2 : number
        If `t1` and `t2` are specified > 0, window the data and return only those

    Returns:
    --------
    dict
        Dictionary with keys `tracl`, `tracr`, `ffid`, `offset`, and `samps`
        (at a minimum; see the code for the full list)

    """
    dt = t.header.sample_interval_in_ms_for_this_trace/(1000.*1000.)
    nsamps = t.header.number_of_samples_in_this_trace
    samps = []

    ampscale = 1
    if not headonly:
        # because I used headonly in the original open,
        # the data are read anew from file every time data is
        # referenced (check this)
        d = t.data # read from file?
        #print('in gettrc', decimate)
        if decimate:
            #print('decimate', decimate, dt)
            try:
                d = sig.decimate(d, q=10, zero_phase=True)
                dt = dt*10
            except:
                print('decimate failed')
                return

        if t1 > 0 and t2 > 0:
            i1 = int(t1/dt)
            i2 = int(t2/dt)
            d = d[i1:i2]
            tarr=np.arange(i1*dt,(i2+1)*dt,dt)
            #print(i1,i2, dt,len(d), len(tarr))

        else:
            tarr=np.arange(0,nsamps*dt,dt)

        max = np.max(d)
        min = np.min(d)
        ampscale = (max-min)
        if ampscale != 0:
            d /= (max-min)

        #print("amp", ampscale, max, min)

        # if a filter is requested...
        if flo and fhi:
            fnyq = 0.5/dt
            #print(flo, fhi, fnyq)
            if flo>fnyq or fhi>fnyq:
                raise Exception('invalid frequencies')
            b,a = sig.butter(8,[flo/fnyq, fhi/fnyq], 'bandpass')
            # print(flo, fhi, fnyq, b, a)

            y = sig.filtfilt(b, a, d)
            # .tolist needed so that json can serialize it (it can't hand numpy arrays)
            varr = y.tolist()
        else:         # otherwise use raw data
            varr = d.tolist()

        # create the samps array
        samps = [{'t':t,'v':v} for (t,v) in zip(tarr,varr)]

    trc = {"tracl": t.header.trace_sequence_number_within_line,
           "tracr": t.header.trace_sequence_number_within_segy_file,
           "ffid": t.header.original_field_record_number,
           "offset": t.header.distance_from_center_of_the_source_point_to_the_center_of_the_receiver_group,
           "ampscale" : "{}".format(ampscale),
           "nsamps": len(samps),
           "dt": dt,
           "samps": samps}
    return trc

def handleMsg(msgJ):
    """Process the message in msgJ.

    Parameters:
    msgJ: dict
        Dictionary with command sent from client

    Returns:
    string
        JSON string with command response

    Commands are of the form:
    {'cmd' : 'getCCC', 'param0': 'param0val', ...}

    Response is a string of the form (note that JSON is picky that keys
    and strings should be enclosed in double quotes:
    '{"cmd" : "getCmd", "cmd" : "<response>"}'

    {'cmd':'getHello'} -> {"cmd":"getHello", "hello": "world"}

    {'cmd':'getSegyHdrs', filename: f} ->
        {"cmd":"getSegyHdrs", "segyhdrs":
                              {ns:nsamps, dt:dt: hdrs:[hdr1, hdr2...]}}

    FIXME FIXME - this currently returns "segy", not "ensemble" as the key
    WARNING - you must call getSegyHdrs first
    flo and fhi are optional.  If they are not present, no filtering
    {'cmd':'getEnsemble', filename:f, ensemble:n, [flo:flo, fhi: fhi]} ->
        {"cmd":"getEnsemble", "segy":
                              {ns:nsamps, dt:dt: traces:[trc1, trc2...]}}
    """
    print('msgJ: {}'.format(msgJ))
    if msgJ['cmd'].lower() == 'getsegyhdrs':
        filename = msgJ['filename']
        print('getting segyhdr >{}<, filename: {}'.format(msgJ, filename))

        t0 =datetime.now()
        if segy.filename != filename:
            # new file - open it
            try:
                s = _read_su(filename, headonly=True)
                segy.filename = filename
                segy.segyfile = s
            except:
                ret = json.dumps({"cmd":"readSegy", "error": "Error reading file {}".format(filename)})
                return ret
            print("ntrcs = {}".format(len(segy.segyfile.traces)))

        hdrs = [getTrc(t, headonly=True) for t in segy.segyfile.traces]
        nsamps = segy.segyfile.traces[0].header.number_of_samples_in_this_trace
        dt = segy.segyfile.traces[0].header.sample_interval_in_ms_for_this_trace/(1000.*1000.)
        segy.nsamps = nsamps
        segy.dt = dt
        segy.hdrs = hdrs

        ret = json.dumps({"cmd": "readSegyHdrs",
                          "segy" : json.dumps({"dt":dt, "ns":nsamps,
                                               "filename": segy.filename,
                                               "hdrs":hdrs})})
        return ret

    if msgJ['cmd'].lower() == 'getensemble':
        print('getting ens', msgJ)
        if segy.segyfile is None:
            ret = json.dumps({"cmd":"getEnsemble", "error": "Error reading ensemble"})
            return ret

        decimate = False
        try:
            ens = int(msgJ['ensemble'])
            try:
                decimate = msgJ['decimate']
                print('dec t', decimate)
            except:
                decimate=False
                print('dec f', decimate)

            try:
                t1 = float(msgJ['t1'])
                t2 = float(msgJ['t2'])
            except:
                t1=-1
                t2=-1
            try:
                flo = float(msgJ['flo'])
                fhi = float(msgJ['fhi'])
                print(flo, fhi)
                traces = [getTrc(t,headonly=False, decimate=decimate, t1=t1, t2=t2, flo=flo, fhi=fhi) for t in segy.segyfile.traces if t.header.original_field_record_number == ens]
            except:
                print('err filt')
                traces = [getTrc(t,headonly=False,decimate=decimate, t1=t1,t2=t2) for t in segy.segyfile.traces if t.header.original_field_record_number == ens]
        except:
            print('err ens', ens, decimate)
            ret = json.dumps({"cmd":"getEnsemble", "error": "Error reading ensemble number"})
            return ret
        print("ens = {} ntrc={}".format(ens, len(traces)))
        # dt/nsamps could change from the original due to decimation
        dt = traces[0]["dt"]
        nsamps = traces[0]["nsamps"]
        print('dt, nsamps', dt, nsamps)
        #print(json.dumps(traces[0]))
        ret = json.dumps({"cmd": "segy",
                          "segy" : json.dumps({"dt":dt, "ns":nsamps,
                                               "filename": segy.filename,
                                               "traces":traces})})
        return ret

    if msgJ["cmd"].lower() == "getpsd":
        if segy.segyfile is None:
            ret = json.dumps({"cmd":"getpsd",
                              "error": "Error reading ensemble"})
            return ret
        try:
            ens = int(msgJ['ensemble'])
            print(ens)
            (f,psd) = segy.getPSD(ens)
        except:
            print('err ens/psd')
            ret = json.dumps({"cmd":"getPSD",
                              "error": "Error reading ensemble number"})
            return ret

        # FIXME - this should be cmd:getPSD, psd:{...}
        return json.dumps({"cmd":"getPSD", "ensemble":ens,
                           "filename": segy.filename,
                           "freqs":f.tolist(), "psd":psd.tolist()})

    if msgJ["cmd"].lower() == "gethello":
        ret = json.dumps({"cmd": "hello", "hello": "world"})
        return ret

#async def api(ws, path):
# all this is stolen from the websockets tutorial.
@asyncio.coroutine
def api(ws, path):
    while True:
        try:
#            msg = await ws.recv()
            # get a websockets string
            msg = yield from ws.recv()
            print('msg', msg)
            try:
                msgJ = json.loads(msg)
            except json.decoder.JSONDecodeError:
                print("error decoding msg >{}<".format(msg))
                continue

            print("got json msgJ >{}<".format(msgJ))
            # and handle it...
            retJ = handleMsg(msgJ)

            #print(retJ)
            # and return the response to the client
            yield from ws.send(retJ)
            #            await ws.send(retJ)

        except websockets.ConnectionClosed:
            print('connection closed')
            return

ss = websockets.serve(api, 'localhost', 9191)
# all this is stolen from the websockets tutorial.
try:
    print("ready...")
    sys.stdout.flush()
    asyncio.get_event_loop().run_until_complete(ss)
    asyncio.get_event_loop().run_forever()
except KeyboardInterrupt:
    print("bye")


from PIL import Image
import os
import shutil

def rotate(data):
    save_dir = './division/rotate'
    from_dir = './division/random2000'
    shutil.rmtree(f'{save_dir}/{data}')
    os.mkdir(f'{save_dir}/{data}')

    imgs = os.listdir(f"{from_dir}/{data}")

    for i in imgs:
        img_path = f"{from_dir}/{data}/{i}"
        save_path = f"{save_dir}/{data}/{i}"
        img = Image.open(img_path)
        img2 = img.rotate(180)
        img2.save(save_path)

if "__main__" == __name__:
    rotate('train')
    rotate('test')
    rotate('validation')


"""config file for experiments"""
import torch

data_file_name = 'test_data.pt'
model_name = 'ETHGT.pt'
scaler_file_name = 'test_data_scaler.pt'
project_id = 'bda-6893'
bucket_name = 'bda_eth_19g'

############
# init train
############
init_config_name = 'init_config.pt'

############
# preprocess config
############
# device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
device = torch.device('cpu')

numeric_features = ['value', 'gas', 'gas_price', 'receipt_cumulative_gas_used',
                    'receipt_gas_used', 'transaction_type']
preprocess_config = {
  'num_cpus': 4,
  'num_gpus': 1,

}

edge_attr_cols = ['value', 'gas', 'gas_price', 'receipt_cumulative_gas_used', 'receipt_gas_used', 'transaction_type']
target = 'gas_price'
node2vec_params = {
      'embedding_dim': 16,
      'walk_length': 20,
      'context_size': 10,
      'walks_per_node': 20,
      'num_negative_samples': 1,
      'p': 200,
      'q': 1,
      'sparse': True
  }
loader_params = dict(batch_size=128, shuffle=True, num_workers=2)
optim_params = {'lr': 0.01}
loop_params = {'num_episodes': 5}
train_params = {'loader_params': loader_params, 'optim_params': optim_params, 'loop_params': loop_params}

data_params = {
    'x': {'node2vec_params': node2vec_params, 'train_params': train_params, 'device': device},
    'y': {'target': target},
    'edge': {'edge_attr_cols': edge_attr_cols}
    }

############
# tune config
############
tune_config = {
  'num_samples': 1,
  'num_epochs': 100,
  'gpus_per_trial': 1
}

############
# trainer config
############
trainer_config = {
  'max_epochs': 500,
  'accelerator': 'gpu',
  'devices': 1
}


from keras.models import Sequential
from keras import (
    layers,
    models,
)
from keras.callbacks import EarlyStopping
from keras.metrics import Precision, Recall, Accuracy

class RCNN_model:
    """
    Container class for the Keras LSTM model. Standardizes
    the usecases, so that it can be used similarily to other
    Keras models.
    """

    def __init__(self, input_length, EMBEDDING_DIM, MAX_NB_WORDS, MAX_SEQUENCE_LENGTH, EPOCH_SIZE, BATCH_SIZE):
        """
        Creates the RCNN structure. and attaches it to the class.
        """
        self.BATCH_SIZE = BATCH_SIZE
        self.EPOCH_SIZE = EPOCH_SIZE

        model = Sequential()
        model.add(layers.Input(input_length))
        model.add(layers.Embedding(input_dim=MAX_NB_WORDS, output_dim=EMBEDDING_DIM, input_length=input_length))
        model.add(layers.SpatialDropout1D(0.25))
        model.add(layers.Bidirectional(layers.GRU(50, return_sequences=True)))
        model.add(layers.Convolution1D(100, 3, activation="relu"))
        model.add(layers.Dense(50, activation="relu"))
        model.add(layers.Dropout(0.2))
        model.add(layers.Dense(1, activation="sigmoid"))
        model.compile(optimizer='adam', loss='binary_crossentropy', metrics=["accuracy", Precision(), Recall()])

        model.summary()

        self.model = model

    def fit(self, train_x, train_y):
        """
        Uses the input traning data to fit the Keras model.
        """
        history = self.model.fit(train_x, train_y, epochs=self.EPOCH_SIZE, batch_size=self.BATCH_SIZE, validation_split=0.2, callbacks=[EarlyStopping(monitor='val_loss', patience=1, min_delta=0.0001)])
        self.history = history
        return history

    def evaluate(self, valid_x, valid_y):
        """
        Uses the validation data to evaluate the model,
        and returns the models metrics.
        """
        results = self.model.evaluate(valid_x, valid_y, batch_size=self.BATCH_SIZE)
        print(results)
        return results[1:] + ["NaN"]

    def predict(self, valid_x):
        return self.model.predict(valid_x)


#
#  Project: MXCuBE
#  https://github.com/mxcube
#
#  This file is part of MXCuBE software.
#
#  MXCuBE is free software: you can redistribute it and/or modify
#  it under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  MXCuBE is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public License
#  along with MXCuBE.  If not, see <http://www.gnu.org/licenses/>.

# The version is updated automatically with bumpversion
# Do not update manually
__version__ = '0.0.1'

import os
import sys
import types
import fcntl
import string
import logging
from logging.handlers import TimedRotatingFileHandler
import tempfile
import platform
from optparse import OptionParser
from pkg_resources import resource_filename, resource_string

import gevent
import gevent.monkey

gevent.monkey.patch_all(thread=False)

from mxcubecore import HardwareRepository as HWR
from mxcubeqt.utils import gui_log_handler, error_handler, qt_import
from mxcubeqt.gui_supervisor import (
    GUISupervisor,
    LOAD_GUI_EVENT,
    get_splash_screen,
    set_splash_screen,
)

__credits__ = ["MXCuBE collaboration"]
__license__ = "LGPLv3+"

STD_BRICKS_LOCATION = "mxcubeqt.bricks"
BRICKS_DIR_LIST = []
LOG_FORMATTER = logging.Formatter(
    "%(asctime)s |%(name)-5s|%(levelname)-7s| %(message)s"
)

LOGGER = logging.getLogger()
LOGGER.setLevel(logging.DEBUG)
HWR_LOGGER = logging.getLogger("HWR")

for handler in HWR_LOGGER.handlers:
    HWR_LOGGER.removeHandler(handler)

GUI_LOG_HANDLER = gui_log_handler.GUILogHandler()
LOGGER.addHandler(GUI_LOG_HANDLER)

HWR_LOG_HANDLER = logging.StreamHandler(sys.stdout)
HWR_LOG_HANDLER.setFormatter(LOG_FORMATTER)
LOGGER.addHandler(HWR_LOG_HANDLER)

for logger_name in ("matplotlib", "PyMca5"):
    logging.getLogger(logger_name).setLevel(logging.WARNING)

SPLASH_SCREEN = None

LOGGING_NAME = ""

#MXCUBEQT_ROOT = os.path.dirname(__file__)
#sys.path.insert(0, MXCUBEQT_ROOT)

#MOCKUP_CONFIG_PATH = os.path.join(MXCUBEQT_ROOT, "example_config.yml")
MOCKUP_CONFIG_PATH = resource_filename('mxcubeqt', 'configuration/mockup.yml')

path = []
for p in ['configuration/mockup', 'configuration/mockup/qt']:
    path.append(resource_filename('mxcubecore', p))

MOCKUP_CORE_CONFIG_PATH = ":".join(path)

def get_splash():
    return get_splash_screen()

def set_splash(screen):
    set_splash_screen(screen)

def get_base_bricks_path():
    std_bricks_pkg = __import__(STD_BRICKS_LOCATION, globals(), locals(), [""])
    return os.path.dirname(std_bricks_pkg.__file__)

def add_custom_bricks_dirs(bricks_dirs):

    global BRICKS_DIR_LIST

    if isinstance(bricks_dirs, list):
        new_bricks_dirs = list(
            filter(os.path.isdir, list(map(os.path.abspath, bricks_dirs)))
        )

        for new_brick_dir in reversed(new_bricks_dirs):
            if not new_brick_dir in sys.path:
                # print 'inserted in sys.path = %s' % new_brick_dir
                sys.path.insert(0, new_brick_dir)

        BRICKS_DIR_LIST += new_bricks_dirs

base_bricks_path = get_base_bricks_path()
sys.path.insert(0, base_bricks_path)
# add 'EMBL' 'ESRF' 'ALBA' ... subfolders to path
for root, dirs, files in os.walk(base_bricks_path):
    if root[root.rfind("/") :] != "/__pycache__" and root != base_bricks_path:
        sys.path.insert(0, root)

def get_custom_bricks_dirs():
    return BRICKS_DIR_LIST

def set_logging_name(name, logging_formatter=""):
    global LOG_FORMATTER, HWR_LOG_HANDLER, LOGIN_NAME
    logging_formatter.replace(" ", "")
    if logging_formatter == "":
        logging_formatter = LOG_FORMATTER
    _formatter = logging.Formatter(logging_formatter)
    HWR_LOG_HANDLER.setFormatter(LOG_FORMATTER)
    LOGIN_NAME = name

def set_log_file(filename):
    global HWR_LOG_HANDLER
    LOGGER.info("Logging to file %s" % filename)

    LOGGER.removeHandler(HWR_LOG_HANDLER)
    # _hdlr = RotatingFileHandler(filename, 'a', 1048576, 10) #1 MB by file,
    # 10 files max.
    HWR_LOG_HANDLER = TimedRotatingFileHandler(filename, when="midnight", backupCount=1)
    os.chmod(filename, 0o666)
    HWR_LOG_HANDLER.setFormatter(LOG_FORMATTER)
    LOGGER.addHandler(HWR_LOG_HANDLER)

def do_gevent():
    """Can't call gevent.run inside inner event loops (message boxes...)"""

    if qt_import.QEventLoop():
        try:
            gevent.wait(timeout=0.01)
        except AssertionError:
            pass
    else:
        # all that I tried with gevent here fails! => seg fault
        pass

class MyCustomEvent(qt_import.QEvent):
    """Custom event"""

    def __init__(self, event_type, data):
        """init"""

        qt_import.QEvent.__init__(self, event_type)
        self.data = data

def create_app(gui_config_path=None, core_config_path=None):
    """Main run method"""

    parser = OptionParser(usage="usage: %prog <gui definition file> <core configuration paths> [options]")
    parser.add_option(
        "",
        "--logFile",
        action="store",
        type="string",
        help="Log file",
        dest="logFile",
        metavar="FILE",
        default="",
    )
    parser.add_option(
        "",
        "--logLevel",
        action="store",
        type="string",
        help="Log level",
        dest="logLevel",
        default="INFO",
    )
    parser.add_option(
        "",
        "--logTemplate",
        action="store",
        type="string",
        help="Log template",
        dest="logTemplate",
        default="",
    )
    parser.add_option(
        "",
        "--bricksDirs",
        action="store",
        type="string",
        help="Additional directories for bricks search "
        + "path (you can also use the CUSTOM_BRICKS_PATH "
        + "environment variable)",
        dest="bricksDirs",
        metavar="dir1" + os.path.pathsep + "dir2...dirN",
        default="",
    )
    parser.add_option(
        "",
        "--guiConfigPath",
        action="store",
        type="string",
        help="Path to the mxcube gui configuration file "
        + "Alternatively MXCUBE_GUI_CONFIG_PATH env variable"
        + "can be used",
        metavar="directory",
        dest="guiConfigPath",
        default="",
    )

    parser.add_option(
        "",
        "--coreConfigPath",
        action="store",
        type="string",
        help="Path to the directory containing mxcubecore "
        + "configuration files. "
        + "Alternatively MXCUBE_CORE_CONFIG_PATH env variable"
        + "can be used",
        dest="coreConfigPath",
        default="",
    )
    parser.add_option(
        "",
        "--hardwareObjectsDirs",
        action="store",
        type="string",
        help="Additional directories for "
        + "Hardware Objects search path (you can also use "
        + "the CUSTOM_HARDWARE_OBJECTS_PATH environment "
        + "variable)",
        dest="hardwareObjectsDirs",
        metavar="dir1" + os.path.pathsep + "dir2...dirN",
        default="",
    )
    parser.add_option(
        "-d",
        "",
        action="store_true",
        dest="designMode",
        default=False,
        help="Start mxcube in design mode",
    )
    parser.add_option(
        "-m",
        "",
        action="store_true",
        dest="showMaximized",
        default=False,
        help="Maximize main window",
    )
    parser.add_option(
        "",
        "--no-border",
        action="store_true",
        dest="noBorder",
        default=False,
        help="Does not show borders on main window",
    )
    parser.add_option(
        "",
        "--style",
        action="store",
        type="string",
        help="Visual style of the application (windows, motif,"
        + "cde, plastique, windowsxp, or macintosh)",
        dest="appStyle",
        default=None,
    )
    parser.add_option(
        "",
        "--userFileDir",
        action="store",
        type="string",
        help="User settings file stores application related settings "
        + "(window size and position). If not defined then user home "
        + "directory is used",
        dest="userFileDir",
        default=None,
    )
    parser.add_option(
        "-v",
        "--version",
        action="store_true",
        default=False,
        dest="version",
        help="Shows version",
    )
    parser.add_option(
        "",
        "--mockupMode",
        action="store_true",
        default=False,
        dest="mockupMode",
        help="Runs MXCuBE with mockup configuration",
    )
    parser.add_option(
        "",
        "--pyqt4",
        action="store_true",
        default=None,
        help="Force to use PyQt4"
    )
    parser.add_option(
        "",
        "--pyqt5",
        action="store_true",
        default=None,
        help="Force to use PyQt5"
    )
    parser.add_option(
        "",
        "--pyside",
        action="store_true",
        default=None,
        help="Force to use PySide"
    )

    (opts, args) = parser.parse_args()

    if opts.version:
        from mxcubeqt import __version__
        print(__version__)
        exit(0)

    log_file = start_log(opts.logFile, opts.logLevel)
    log_template = opts.logTemplate
    hwobj_directories = opts.hardwareObjectsDirs.split(os.path.pathsep)
    custom_bricks_directories = opts.bricksDirs.split(os.path.pathsep)
    user_file_dir = opts.userFileDir or os.path.join(os.environ["HOME"], ".mxcube")
    app_style = opts.appStyle

    if not gui_config_path:
        if opts.guiConfigPath:
            gui_config_path = opts.guiConfigPath
        elif opts.mockupMode:
            gui_config_path = MOCKUP_CONFIG_PATH
        else:
            gui_config_path = os.environ.get("MXCUBE_GUI_CONFIG_PATH")

    if not core_config_path:
        if opts.coreConfigPath:
            core_config_path = opts.coreConfigPath
        elif opts.mockupMode:
            core_config_path = MOCKUP_CORE_CONFIG_PATH
        else:
            # try to set Hardware Repository server from environment
            core_config_path = os.environ.get("MXCUBE_CORE_CONFIG_PATH")

    # add bricks directories and hardware objects directories from environment
    try:
        custom_bricks_directories += os.environ.get("CUSTOM_BRICKS_PATH", "").split(
            os.path.pathsep
        )
    except KeyError:
        pass

    try:
        hwobj_directories += os.environ.get("CUSTOM_HARDWARE_OBJECTS_PATH", "").split(
            os.path.pathsep
        )
    except KeyError:
        pass

    try:
        if not os.path.exists(user_file_dir):
            os.makedirs(user_file_dir)
    except BaseException:
        HWR_LOGGER.exception(
            "Unable to create user files directory: %s" % user_file_dir
        )

    custom_bricks_directories = [
        _directory for _directory in custom_bricks_directories if _directory
    ]
    hwobj_directories = [_directory for _directory in hwobj_directories if _directory]

    main_application = qt_import.QApplication([])
    if app_style:
        main_application.setStyle(app_style)

    if len(args) >= 1:
        if len(args) == 1:
            gui_config_file = os.path.abspath(args[0])
        else:
            parser.error("Too many arguments.")
            sys.exit(1)

    if (
        len(
            os.popen(
                "ps -aef | grep 'python' -i | grep 'mxcubecore'"
                + "  | grep -v 'grep' | awk '{ print $3 }'"
            )
            .read()
            .strip()
            .split("\n")
        )
        > 1
    ):
        qt_import.QMessageBox.warning(
            None,
            "Warning",
            "Another instance of MXCuBE is running.\n",
            qt_import.QMessageBox.Ok,
        )
        # sys.exit(1)

    # configure modules
    if hwobj_directories:
        # Must be done before init_hardware_repository
        HWR.add_hardware_objects_dirs(hwobj_directories)
    HWR.init_hardware_repository(core_config_path)
    HWR.set_user_file_directory(user_file_dir)
    if custom_bricks_directories:
        add_custom_bricks_dirs(custom_bricks_directories)

    log_lockfile = None

    if len(log_file) > 0:
        if gui_config_file:
            set_logging_name(os.path.basename(gui_config_file), log_template)

        log_lock_filename = os.path.join(
            tempfile.gettempdir(), ".%s.lock" % os.path.basename(log_file)
        )

        log_ok = True
        try:
            log_lockfile = open(log_lock_filename, "w")
        except BaseException:
            log_ok = False
        else:
            try:
                os.chmod(log_lock_filename, 0o666)
            except BaseException:
                pass
            try:
                fcntl.lockf(log_lockfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
            except BaseException:
                log_ok = False
                try:
                    log_lockfile.close()
                except BaseException:
                    pass

        if not log_ok:
            index = 1
            logfile_details = os.path.splitext(log_file)
            log_file = ""
            while index < 10:
                log_file2 = "%s.%d%s" % (logfile_details[0], index, logfile_details[1])
                log_lock_filename2 = os.path.join(
                    tempfile.gettempdir(), ".%s.lock" % os.path.basename(log_file2)
                )
                try:
                    log_lockfile = open(log_lock_filename2, "w")
                except BaseException:
                    pass
                else:
                    try:
                        os.chmod(log_lock_filename2, 0o666)
                    except BaseException:
                        pass
                    try:
                        fcntl.lockf(
                            log_lockfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB
                        )
                    except BaseException:
                        pass
                    else:
                        log_ok = True
                if log_ok:
                    log_file = log_file2
                    break
            index += 1

        set_log_file(log_file)

    HWR_LOGGER.info(
        "=============================================================================="
    )
    if opts.designMode:
        HWR_LOGGER.info("Starting MXCuBE Qt in designer mode...")
    else:
        HWR_LOGGER.info("Starting MXCuBE Qt...")
    HWR_LOGGER.info("GUI file: %s" % (gui_config_path or "unnamed"))
    if len(log_file) > 0:
        HWR_LOGGER.info("Log file: %s" % log_file)
    HWR_LOGGER.info("User file directory: %s" % user_file_dir)
    HWR_LOGGER.info("System info:")
    HWR_LOGGER.info(
        "    - Python %s on %s" % (platform.python_version(), platform.system())
    )
    HWR_LOGGER.info(
        "    - Qt %s - %s %s"
        % (
            "%d.%d.%d" % tuple(qt_import.qt_version_no),
            qt_import.qt_variant,
            "%d.%d.%d" % tuple(qt_import.pyqt_version_no),
        )
    )
    if qt_import.mpl_imported:
        HWR_LOGGER.info(
            "    - Matplotlib %s" % "%d.%d.%d" % tuple(qt_import.mpl_version_no)
        )
    else:
        HWR_LOGGER.info("    - Matplotlib not available")
    HWR_LOGGER.info(
        "------------------------------------------------------------------------------"
    )

    qt_import.QApplication.setDesktopSettingsAware(False)

    main_application.lastWindowClosed.connect(main_application.quit)
    supervisor = GUISupervisor(
        design_mode=opts.designMode,
        show_maximized=opts.showMaximized,
        no_border=opts.noBorder,
    )

    supervisor.set_user_file_directory(user_file_dir)
    # post event for GUI creation
    main_application.postEvent(
        supervisor, MyCustomEvent(LOAD_GUI_EVENT, gui_config_path)
    )

    # redirect errors to logger
    error_handler.enable_std_err_redirection()

    gevent_timer = qt_import.QTimer()
    gevent_timer.timeout.connect(do_gevent)
    gevent_timer.start(0)

    palette = main_application.palette()
    palette.setColor(qt_import.QPalette.ToolTipBase, qt_import.QColor(255, 241, 204))
    palette.setColor(qt_import.QPalette.ToolTipText, qt_import.Qt.black)
    main_application.setPalette(palette)

    main_application.setOrganizationName("MXCuBE")
    main_application.setOrganizationDomain("https://github.com/mxcube")
    main_application.setApplicationName("MXCuBE")
    # app.setWindowIcon(qt_import.QIcon("images/icon.png"))

    main_application.exec_()

    supervisor.finalize()

    if log_lockfile is not None:
        filename = log_lockfile.name
        try:
            log_lockfile.close()
            os.unlink(filename)
        except BaseException:
            logging.getLogger().exception("Problem removing the log lock file")

    return main_application

def start_log(logfile, loglevel):
    if not logfile:
        logfile = os.environ.get("MXCUBE_LOG_FILE", "")

    log_level = getattr(logging, loglevel)
    logging.getLogger().setLevel(log_level)

    return logfile

if __name__ == "__main__":
    app = create_app()


#!usr/bin/env python
# -*-coding: utf -8 -*-

import os
import json
import cv2
import numpy as np
import matplotlib.pyplot as plt

def COCOWrite(image_name, image_id, annos, masks,shapes, height, width, cls):
    json_dict = {
        "images": [], "type": "instance", "annotations": [], "categories": []
    }

    image = {
        "file_name" :image_name, "id": image_id, "height": height, "width": width
    }
    json_dict['images'].append(image)
    print(image)

    for i, anno in enumerate(annos):
        cls_id = cls.index(anno[0])
        (x1, y1) = anno[1][0]
        (x2, y2) = anno[1][2]
        h = max(0, int(y2)-int(y1))
        w = max(0, int(x2)-int(x1))
        mask = masks[i]
        shape = [(int(ii[0]), int(ii[1])) for ii in shapes[i]]
        indexs = []
        index = np.where(mask>0)
        indexs.append((index[0].tolist(),index[1].tolist()))
        json_dict['annotations'].append(
            {
                'area': int(w)*int(h),
                'bbox': [int(x1), int(y1), w, h],
                'category_id': int(cls_id),
                'id': i,
                'image_id': image_id,
                'iscrowd': 0,
                # 'segmentation': indexs   #直接写入mask,过于大
                'segmentation': shape      #写入shape,后面转为mask
            }
        )

    json_name = image_name
    with open(json_name, 'w') as f:
        json.dump(json_dict, f)

def COCORead(json_file):
    with open(json_file,'r') as f:
        json_dict = json.load(f)

    print(json_dict)
    file_info = json_dict['images']
    annotations = json_dict['annotations']
    json_path = file_info[0]['file_name']

    image_path = json_path.replace('Annotations','JPEGImages').replace('json','jpg')
    img = cv2.imread(image_path)
    # plt.imshow(img[:,:,::-1])
    # plt.axis('off')
    # plt.show()

    image_id = file_info[0]['id']
    height = file_info[0]['height']
    width = file_info[0]['width']
    count = len(annotations)

    masks = []
    labels = []
    bboxs = []

    for i, info in enumerate(annotations):
        area = info['area']
        bbox = info['bbox']
        bboxs.append(bbox)

        #label
        category_id = info['category_id']
        labels.append(category_id)

        segmentation = info['segmentation']

        #bbox
        x1 = bbox[0]
        y1 = bbox[1]
        b_width = bbox[2]
        b_height = bbox[3]

        #mask
        mask = np.zeros((height, width),dtype=np.uint8)
        points = np.array([segmentation]).astype(np.int)
        mask = cv2.fillPoly(mask, points, 1)
        masks.append(mask)
        # plt.imshow(mask)
        # plt.show()

    #masks
    occlusions = np.logical_not(masks[count-1]).astype(np.uint8)
    for i in range(count - 2, -1, -1):
        masks[i] = masks[i] * occlusions
        occlusions = np.logical_and(
            occlusions, np.logical_not(masks[i]))

    # for i, x in enumerate(masks):
    #     a = np.where(x>0)

    return img, labels, bboxs, masks
    #return file_info,annotations

if __name__ == '__main__':
    COCORead('/home/kingqi/proj/data/mask-rcnn/test_d/Annotations/000000.json')


import yaml
import logging
from os import walk
import json
import noise

# default values
conf = {
    "long_press": 1.2, # long press in seconds
    "delay": 1.0, # timer length before counting buttons
    "sleep_track_limit": 1, #minutes
    "selected_noise": "nature.wav",
    "available_noises":[],
    "volume_offset":0
}

def update_config(settings):
    global conf
    result = {"action":"success","message":f"Settings have been updated"}
    new_settings = conf

    for key, value in settings.items():
        try:
            new_settings[key] = value
        except Exception as e:
            error = f"update_config Setting Key: {key} not found {e}"
            logging.warn(error)
            result = {"action":"error","message": error}
    if result['action'] == "success":
        with open(r'./config.yaml', 'w') as file:
            yaml.dump(new_settings, file)
        read_config()
    noise.intialize_noise(conf['selected_noise'], conf['volume_offset'])
    return json.dumps(result)

def read_config():
    global white_noise
    global conf
    try:
        with open(r'./config.yaml') as file:
            values = yaml.load(file, Loader=yaml.FullLoader)
            for key, value in  values.items():
                conf[f"{key}"] = value
        _, _, conf['available_noises'] = next(walk("./noise/"))
    except Exception as e:
        logging.debug("""./config.yaml not found. creating from default values""")
        with open(r'./config.yaml', 'w') as file:
            yaml.dump(conf, file)
    print(conf)
    return conf


import configparser

class OverlayConfig():
    def __init__(self, colored_noise=True, opacity=0.7):
        self.colored_noise = colored_noise
        self.opacity = opacity

class CameraConfig():
    def __init__(self, camera_id=0, capture_interval=1):
        self.id = camera_id
        self.capture_interval = capture_interval

class Config:
    def __init__(self, colored_noise=True, opacity=0.7, camera_id=0, capture_interval=1):
        self.overlay = OverlayConfig(
            colored_noise=colored_noise,
            opacity=opacity
        )
        self.camera = CameraConfig(
            capture_interval=capture_interval,
            camera_id=camera_id
        )

def parse_config(filename=None):

    config = Config(
        colored_noise=True,
        opacity=0.7,
        camera_id=0,
        capture_interval=1
    )

    if not (filename is None):
        config_parser = configparser.ConfigParser()
        config_parser.read(filename)

        if 'OVERLAY' in config_parser.sections():
            if 'ColoredNoise' in config_parser['OVERLAY']:
                config.overlay.colored_noise = config_parser['OVERLAY']['ColoredNoise'].lower() in ['yes', 'true']
            if 'Opacity' in config_parser['OVERLAY']:
                config.overlay.opacity = float(config_parser['OVERLAY']['Opacity'])
        if 'CAMERA' in config_parser.sections():
            if 'Camera' in config_parser['CAMERA']:
                config.camera.id = int(config_parser['CAMERA']['Camera'])
            if 'CaptureInterval' in config_parser['CAMERA']:
                config.camera.capture_interval = float(config_parser['CAMERA']['CaptureInterval'])

    return config


import gymnasium as gym
import matplotlib.pyplot as plt
import numpy as np
from ia import *
from numpy.random import gamma
from numpy.typing import NDArray

def plot_values(v: NDArray) -> None:
    v = np.reshape(v, (4, 4))
    # plot the state-value function
    fig = plt.figure(figsize=(8, 8))
    ax = fig.add_subplot(111)
    _ = ax.imshow(v, cmap="cool")
    for (j, i), label in np.ndenumerate(v):
        ax.text(i, j, np.round(label, 3), ha="center", va="center", fontsize=14)
    plt.tick_params(bottom="off", left="off", labelbottom="off", labelleft="off")
    plt.title("State-Value Function")
    plt.show()

if __name__ == "__main__":
    env = gym.make("FrozenLake-v1", render_mode="rgb_array", is_slippery=False)
    d = env.observation_space
    qa = QLearningAgent(env, Tabular, d=d)
    qa.train(0.01, max_steps=True, num_episodes=10000, gamma=0.9)
    v = np.empty(d.n)
    for i in range(d.start, d.start + d.n):
        print(i)
        _, v[i] = qa.val_act(np.int64(i))
    plot_values(v)
    qa.live_play(path="frozenlake.mp4", max_steps=True)


import json
import logging
import azure.functions as func

from . import updateDB

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    username = req.params.get('username')
    if not (username):
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            username = req_body.get('username')

    if(username):
        try:
            curr_payment = updateDB.getCurrPayment(username)
            return func.HttpResponse(json.dumps({"res": "ok", "currentPayment": curr_payment}), mimetype="application/json")
        except:
            return func.HttpResponse(json.dumps({"res": "internalError"}), mimetype="application/json")
    else:
        return func.HttpResponse("username=")


from setuptools import find_packages, setup

def get_description():
    return "Publishing microservice for Red Hat's Content Delivery Network"

def get_long_description():
    with open("README.md") as readme:
        text = readme.read()

    # Long description is everything after README's initial heading
    idx = text.find("\n\n")
    return text[idx:]

def get_requirements():
    with open("requirements.in") as reqs:
        return [
            line.split()[0]
            for line in reqs.read().splitlines()
            if not line.startswith("#")
        ]

setup(
    name="exodus-gw",
    version="0.0.1",
    packages=find_packages(exclude=["tests"]),
    include_package_data=True,
    url="https://github.com/release-engineering/exodus-gw",
    license="GNU General Public License",
    description=get_description(),
    long_description=get_long_description(),
    long_description_content_type="text/markdown",
    classifiers=[
        "Development Status :: 4 - Beta",
        "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
        "Programming Language :: Python :: 3",
    ],
    install_requires=get_requirements(),
    python_requires=">=3.11",
    project_urls={
        "Documentation": "https://release-engineering.github.io/exodus-gw",
    },
    entry_points={
        "console_scripts": [
            "exodus-gw-alembic-upgrade = exodus_gw.alembic_upgrade:entry_point"
        ]
    },
)


#!/usr/bin/env python3

import json
import yaml
import asyncio
from aiohttp.web import Application, Response, MsgType, WebSocketResponse, HTTPFound

import spotbox

@asyncio.coroutine
def wshandler(request):
    resp = WebSocketResponse()
    ok, protocol = resp.can_prepare(request)
    if not ok:
        return HTTPFound('/index.html')

    yield from resp.prepare(request)
    print('Client connected.')
    request.app['sockets'].append(resp)
    box.command({"command": "state"})

    while True:
        msg = yield from resp.receive()
        if msg.tp == MsgType.text:
            box.command(json.loads(msg.data))
        else:
            break

    request.app['sockets'].remove(resp)
    print('Someone disconnected.')
    return resp

@asyncio.coroutine
def redirect(request):
    return HTTPFound('/index.html')

def brodcast(app, msg):
    for ws in app['sockets']:
        ws.send_str(json.dumps(msg))

def consumer_thread(app, loop):
    def inner():
        while True:
            msg = box.status_queue.get()
            loop.call_soon_threadsafe(brodcast, app, msg)
    return inner

@asyncio.coroutine
def init(loop, host, port):
    app = Application(loop=loop)
    app['sockets'] = []
    app.router.add_route('GET', '/ws', wshandler)
    app.router.add_route('GET', '/', redirect)
    app.router.add_static('/', '../ui/static')
    handler = app.make_handler()
    srv = yield from loop.create_server(handler, host, port)
    print("Server started at {}:{}".format(host, port))
    return app, srv, handler

@asyncio.coroutine
def finish(app, srv, handler):
    for ws in app['sockets']:
        ws.close()
    app['sockets'].clear()
    yield from asyncio.sleep(0.1)
    srv.close()
    yield from handler.finish_connections()
    yield from srv.wait_closed()

with open("config.yaml", 'r') as config:
    config = yaml.load(config)
    credentials = config["spotify"]
    host = config["server"]["host"]
    port = config["server"]["port"]
    buffer_size = config["audio"]["buffer_size"]

box = spotbox.Spotbox(credentials["username"], credentials["password"], buffer_size)
alsa = spotbox.Alsa(box.sound_queue)

loop = asyncio.get_event_loop()
app, srv, handler = loop.run_until_complete(init(loop, host, port))

loop.run_in_executor(None, consumer_thread(app, loop))
loop.run_in_executor(None, box.run)
loop.run_in_executor(None, alsa.run)
try:
    loop.run_forever()
except KeyboardInterrupt:
    loop.run_until_complete(finish(app, srv, handler))


import numpy as np
import sys
from time import time
import xml.etree.ElementTree as ET
from scipy.optimize import curve_fit
import h5py
from os import path
import matplotlib.pyplot as plt
import matplotlib.animation

from scipy.interpolate import interp1d

print ('New version, updated June')
print ('Adding H data analysis')
print ('add ed number of channel')
class scopeData(object):

    def __init__(self,rootname,window=False,save=False,IFile='_beam',plan='V',num_of_chan=4):
        self.num_of_chan = num_of_chan
        self.plan = plan
        self.name = rootname
        self.IFile = IFile
        self.save = save
        t = time()
        self.window = window
        self.FILENAME,self.HeaderName = self.name+'.Wfm.bin',self.name+'.bin'
        self.Header = self.readHEADER(self.HeaderName)
        print (self.N)
        if self.COV == 64768:
            self.Dtype = np.int16
            self.nd = 4
        elif self.COV == 253:
            self.Dtype = np.int8
            self.nd = 8
        else:
            print ('data type unknown')
            exit()
        # get bin data
        self.getBinData(self)

        #print (time() - t)
        if self.num_of_chan == 2:
            self.BCH1,self.BCH2 = self.BINWFM.reshape(int(len(self.BINWFM)/self.num_of_chan),self.num_of_chan).T
        elif self.num_of_chan == 4:
            self.BCH1,self.BCH2,self.BCH3,self.BCH4 = self.BINWFM.reshape(int(len(self.BINWFM)/self.num_of_chan),self.num_of_chan).T

        self.CH1_FAC,self.CH1_VOL_OFF = self.CONfactor(self.CH1_dVpD,self.dV_COUNT,self.COV,self.CH1_OFF,self.CH1_POS)
        self.CH2_FAC,self.CH2_VOL_OFF = self.CONfactor(self.CH2_dVpD,self.dV_COUNT,self.COV,self.CH2_OFF,self.CH2_POS)
        # get voltage data from bin
        self.CH3_FAC,self.CH3_VOL_OFF = self.CONfactor(self.CH3_dVpD,self.dV_COUNT,self.COV,self.CH4_OFF,self.CH3_POS)
        self.CH4_FAC,self.CH4_VOL_OFF = self.CONfactor(self.CH4_dVpD,self.dV_COUNT,self.COV,self.CH4_OFF,self.CH4_POS)
        if self.plan == 'V':
            self.CH1V,self.CH2V =  self.getVoltage(self.BCH1,self.CH1_FAC,self.CH1_VOL_OFF),self.getVoltage(self.BCH2,self.CH2_FAC,self.CH2_VOL_OFF)
        elif self.plan == 'H':
            self.CH1V,self.CH2V =  self.getVoltage(self.BCH1,self.CH3_FAC,self.CH3_VOL_OFF),self.getVoltage(self.BCH2,self.CH4_FAC,self.CH4_VOL_OFF)
        else:
            print ('Wrong plan, either H or V')
            exit()

        self.CH1V,self.CH2V = self.CH1V.reshape(self.N,self.nt),self.CH2V.reshape(self.N,self.nt)
        self.TIME = np.linspace(-1*self.dt*self.nt/2,self.dt*self.nt/2,self.nt)
        if window:
            self.TIMEN = self.TIME[(self.TIME>self.window[0])& (self.TIME<self.window[1])]
            self.CH1V = np.array(self.CH1V[:, (self.TIME > self.window[0]) & (self.TIME < self.window[1])])
            self.CH2V = np.array(self.CH2V[:, (self.TIME > self.window[0]) & (self.TIME < self.window[1])])
            self.nt = int(len(self.TIMEN))
        if not window:
            self.TIMEN = self.TIME

        self.CH1BGR = self.removeBaseLine(self.CH1V)
        #print (time()-t)
        self.CH1VINT = self.IntegratedData(self.TIMEN,self.CH1BGR)
        #print (time()-t)
        self.CH2VINT = self.IntegratedData(self.TIMEN,self.CH2V)

        self.POScenter = self.getPosition(self.CH1VINT,int(self.nt/2))
        self.POShead   = self.getPosition(self.CH1VINT,int(self.nt/3))

        self.POStail   = self.getPosition(self.CH1VINT,int(self.nt/1.5))

        self.getTuneSpec()
        self.filterTune()
        argMax = np.argmax(self.PowSpecFiler)

        self.tunePeak = self.tuneFilter[np.argmax(self.PowSpecFiler)]
        print (f'processing time is {time()-t}')

        self.IFILE = self.name+self.IFile

        self.intensity(self.IFILE)
        print(f'{self.tunePeak} is the highest tune peak at {self.I} intensity')

        if self.save:
            self.saveData(self.name)

    def saveData(self,outputFile):
        np.save(outputFile,np.array([self.CH1VINT,self.CH2VINT],dtype=np.float16))
        np.save(outputFile+'_tune',np.array([self.TIMEN,self.tune,self.PowSpec,self.tunePeak,self.I],dtype=object))

    def readHEADER(self,HeaderName):
            """
            Given a filename of .bin, the measurement information is extracted. The following is assumed:
            MultiChannel is active (2 channels are considered)
            """
            self.tree = ET.parse(self.HeaderName)
            self.root = self.tree.getroot()
            self.data = {}
            for child in self.root:
                for subelem in child:
                    for x in subelem.iter('Prop'):
                        name = x.get('Name')
                        if name == 'NumberOfAcquisitions':
                            self.N = int(x.get('Value'))
                        elif name == 'NofQuantisationLevels':
                            self.COV = float(x.get('Value'))
                        elif name == 'Resolution':
                            self.dt = float(x.get('Value'))
                        elif name == 'RecordLength':
                            self.nt = int(x.get('Value'))
                        elif name == 'VerticalDivisionCount':
                            self.dV_COUNT = int(x.get('Value'))
                        elif name == 'TimeScale':
                            pass
                        elif name == 'MultiChannelVerticalPosition':
                            self.CH1_POS = float(x.get('I_0'))
                            self.CH2_POS = float(x.get('I_1'))
                            self.CH3_POS = float(x.get('I_2'))
                            self.CH4_POS = float(x.get('I_3'))
                        elif name == 'MultiChannelVerticalScale':
                            self.CH1_dVpD = float(x.get('I_0'))
                            self.CH2_dVpD = float(x.get('I_1'))
                            self.CH3_dVpD = float(x.get('I_2'))
                            self.CH4_dVpD = float(x.get('I_3'))
                        elif name == 'MultiChannelVerticalOffset':
                            self.CH1_OFF = float(x.get('I_0'))
                            self.CH2_OFF = float(x.get('I_1'))
                            self.CH3_OFF = float(x.get('I_2'))
                            self.CH4_OFF = float(x.get('I_3'))
    def intensity(self,IFILE):
        if path.isfile(IFILE):
            try:
                X = np.loadtxt(IFILE)
            except :
                self.I = np.nan
                self.BeamData =False
                pass

            self.I = np.average(X[0:,1][(X[0:,0]>0.58) & (X[0:,0]<0.59)])
            self.Beam = X[0:,1]
            self.BeamTime = X[0:,0]
            self.BeamData = True

        else:
            self.I = np.nan
            self.BeamData = False

    def IntegratedData(self,TIME,CHVOLT):

        INTEGCH = np.cumsum(CHVOLT,axis=1)
        #polyfit to extract slope
        #print (np.shape(TIMEN))
        Tf = np.array([TIME[0],TIME[-1]])
        CHF = INTEGCH[:, [0, -1]] # first values
        #CHF = np.array([INTEGCH[0:,0],INTEGCH[0:,-1]])

        coef = np.array([np.polyfit(Tf,CHF[i],1) for i in range(self.N)])

        #poly1d_fn = [np.poly1d(coef[i]) for i in range(self.N)]
        """
            if np.average(INTEGCH[i]) < 0 :
                factor = -1
            elif np.average(INTEGCH[i]) > 0 :
                factor = 1
            else:
                print ('Error ')
        """
        poly1d_fn = [np.poly1d(coef[i]) for i in range(self.N)]
        BCK = [poly1d_fn[i](TIME) for i in range(self.N)]

        #BGK = np.polynomial.polynomial.polyval(self.TIMEN, coef.T)

        INTEGCH = INTEGCH - BCK
            # dc offset
            #INTEGCH[i] = factor*INTEGCH[i] - np.min(INTEGCH[i])

        return INTEGCH

    def removeBaseLineO(self,CHVOLT,M=10):
        """
        For each array (N x nt):
        BaseLine = np.empty_like(CHVOLT)
            take the average of N-M, N+ M to get the base line
            remove the base line from the N data
            return the new array
        """
        # create empty arrays for baseline and new data:
        # assuming reShapeData was applied first
        BaseLine = np.empty_like(CHVOLT)
        NEWCH = np.empty_like(CHVOLT)

        for i in range(M,self.N-M):
            I = np.arange(i-M,i+M) # index to average over

            BaseLine[i] = np.average(np.array([CHVOLT[(v):(v+1)] for v in I]),axis=0) # the average
            NEWCH[i] = CHVOLT[i]-BaseLine[i]

        return NEWCH

    def removeBaseLine(self,CHVOLT,M=10):
        """
        For each array (N x nt):
        BaseLine = np.empty_like(CHVOLT)
            take the average of N-M, N+ M to get the base line
            remove the base line from the N data
            return the new array
        """
        # create empty arrays for baseline and new data:
        # assuming reShapeData was applied first

        BaseLine = np.empty_like(CHVOLT)
        CHBGR = np.empty_like(CHVOLT)
        #
        #
        #

        for i in range(M,self.N-M):
            I = np.arange(i-M,i+M) # index to average over
            #BaseLine[i] = np.mean(CHVOLT[I], axis=0)
            BaseLine[i] = np.average(np.array([CHVOLT[(v):(v+1)] for v in I]),axis=0) # the average
            CHBGR[i] = CHVOLT[i]-BaseLine[i]
        return (CHBGR)

    def getBinData(self,Dtype):
    # data can be int.8 or int.16
        with open(self.FILENAME,'rb') as f: #BIN files with int8 (can be int16)
            self.BINWFM = np.fromfile(f,dtype=self.Dtype)
            self.BINWFM = self.BINWFM[self.nd:]
    def CONfactor(self,CH_dVpD,dV_COUNT,COV,CH_OFF,CH_POS):
        CH_FAC = (CH_dVpD* dV_COUNT/COV)
        CH_VOL_OFF = CH_OFF - (CH_dVpD*CH_POS)

        return (CH_FAC,CH_VOL_OFF)

    splitCH = lambda self: self.BINDATA.reshape(self.N,2).T #where N is the number of samples in one channel (rearrange data)

    getTime = lambda self: np.linspace(-1*self.dt*self.nt/2,self.dt*self.nt/2,self.nt)

    def getPosition(self,CH,point):
        POS = CH[:, point]
        return POS

    def getTuneSpec(self,dn=1):
        self.PowSpec = np.absolute(np.fft.rfft(self.POScenter))
        self.tune = np.fft.rfftfreq(self.N,dn)
        return (self.tune,self.PowSpec)

    def filterTune(self,pi=0.42,pf=0.48,plot=False):
        freq1 = self.tune[:int(self.N/2+1)]
        self.tuneFilter,self.PowSpecFiler = self.getTuneSpec(dn=1)[0][((freq1 > pi) & (freq1 < pf))],self.getTuneSpec(dn=1)[1][((freq1 > pi) & (freq1 < pf))]

    def plotconsBeam(self,frame,ti=0.58,offset=0,save=None):
        """
        ti = trigger time (set to 0.58)
        offset = voltage offset to A+B channel to avoid zeros
        generates 3 x 2 plots:
        A+B          (A-B)/(A+B) -> center
        (A-B)/(A+B)  (A-B)/(A+B) -> head
        RBEAM        (A-B)/(A+B) -> tail
        """
        fig,ax = plt.subplots(3,2,dpi=100,figsize=(6,6),tight_layout=True)
        dt = 1.11e-5
        self.chargeOffset = (self.CH1VINT)/(-1*self.CH2VINT+offset)
        [ax[0,0].plot(self.TIMEN,(-1*self.CH2VINT[i]+offset)) for i in range(frame,frame+5)]
        [ax[1,0].plot(self.TIMEN,self.chargeOffset[i]) for i in range(frame,frame+5)]

        position = self.getPosition(self.chargeOffset,int(self.nt/2))
        positionH = self.getPosition(self.chargeOffset,int(self.nt/3))
        positionT = self.getPosition(self.chargeOffset,int(self.nt/(1.5)))

        ax[1,0].set_xlabel(r'Time (s)',fontsize=20)
        ax[0,0].set_ylabel(r'I (a.u.)',fontsize=20)
        ax[1,0].set_ylabel(r'y (a.u.)',fontsize=20)

        if self.BeamData:
            ax[2,0].plot(self.BeamTime,self.Beam)
        else:
            Turns = self.N*dt
            tempTime = np.linspace(ti,ti+Turns,self.N)
            print (len(tempTime),len(self.ch2Beam()))
            ax[2,0].plot(tempTime,self.ch2Beam())

            print ('plotting ch2 beam')
        ax[2,0].axvline(x=ti+(frame*dt))
        ax[2,0].set_xlim(ti,ti+(self.nt)*dt)
        ax[2,0].set_ylabel(r'PPB ($\times 10^{12}$)',fontsize=20)
        ax[2,0].set_xlabel(r'Event time (s)',fontsize=20)
        ax[0,1].plot(ti+(np.arange(0,len(position))*dt),position,alpha=0.5,c='r',label='center')
        ax[0,1].legend()
        ax[1,1].plot(ti+(np.arange(0,len(position))*dt),positionH,alpha=0.5,c='b',label='head')
        ax[1,1].legend()
        ax[2,1].plot(ti+(np.arange(0,len(position))*dt),positionT,alpha=0.5,c='k',label='tail')
        ax[2,1].legend()
        ax[2,0].set_xlabel(r'Event time (s)',fontsize=20)
        ax[0,1].axvline(x=ti+(frame*dt))
        ax[1,1].axvline(x=ti+(frame*dt))
        ax[2,1].axvline(x=ti+(frame*dt))

        ax[0,1].set_ylim(ax[2,1].get_ylim()[0],ax[2,1].get_ylim()[1])
        ax[1,1].set_ylim(ax[2,1].get_ylim()[0],ax[2,1].get_ylim()[1])
        ax[2,1].set_xlabel(r'Event time (s)',fontsize=20)
        if save:
            fig.savefig(str(save),format='pdf',dpi=100)

    getVoltage = lambda self,ADC,CH_N_FAC,CH_N_VOL_OFF: (ADC*CH_N_FAC) + CH_N_VOL_OFF # use convertsion factors for the voltage
# example CH1VOLT,CH2VOLT = getVoltage(BINCH1,CH1_FAC,CH1_VOL_OFF),getVoltage(BINCH2,CH2_FAC,CH2_VOL_OFF)
    def new_time(self,CH,new_t):
        old_ch = interp1d(self.TIMEN,CH,axis=1)
        new_ch = old_ch(new_t)
        X = self.IntegratedData(new_t,new_ch)
        return (X)

    ch2Beam = lambda self: np.trapz(-1*self.CH2VINT,axis=1)

    #new_time = lambda self,new_t,ch2: interp1d(new_t,ch2,axis=1)

# usually the first 4 entries are useless:
# remove the first N points (need to be done for each CH, after the split)
#fixCHdata = lambda CHVOLT,N : CHVOLT[N:]

# data analysis:

#reShapeData = lambda CH,N,bt: CH.reshape(N,bt)


import pytest
from algo.searching import binary_search

class TestBinarySearch:
  testArr = [-5, -1, 0, 2, 12, 23, 38, 72, 91, 1001]
  testFoundData = [
    (-5, 0),
    (0, 2),
    (23, 5),
    (91, 8),
    (1001, 9)
  ]

  @pytest.mark.parametrize("dataToSearch, expected", testFoundData)
  def test_solution_found(self, dataToSearch, expected):
    assert binary_search.solution(self.testArr, dataToSearch) == expected

  def test_solution_not_found(self):
    assert binary_search.solution(self.testArr, 35) == -1


# Use custom implementation:
from MFP import *

# Use MFP_TF wrapper:
# from MFP_TF import *

import urllib.request
from io import BytesIO
import os
import gzip
import struct

import numpy as np
np.set_printoptions(suppress=True)

class MNIST:
    def __init__(self):
        source = 'http://yann.lecun.com/exdb/mnist'
        target = os.path.abspath('./data/MNIST/')

        datasets = {
            'train_images': 'train-images.idx3-ubyte',
            'train_labels': 'train-labels.idx1-ubyte',
            'test_images': 't10k-images.idx3-ubyte',
            'test_labels': 't10k-labels.idx1-ubyte'
        }

        if not os.path.exists(target):
            os.makedirs(target)

            datasets_compressed = {
                'train_images': 'train-images-idx3-ubyte.gz',
                'train_labels': 'train-labels-idx1-ubyte.gz',
                'test_images': 't10k-images-idx3-ubyte.gz',
                'test_labels': 't10k-labels-idx1-ubyte.gz'
            }

            for ident, filename in datasets_compressed.items():
                compressed_file = BytesIO()
                compressed_file.write(urllib.request.urlopen(source + '/' + filename).read())
                compressed_file.seek(0)

                decompressed_file = gzip.GzipFile(fileobj=compressed_file, mode='rb')

                with open(target + '\\' + datasets[ident], 'wb') as outfile:
                    outfile.write(decompressed_file.read())

        self.train_images = MNIST._load_images(target + '/' + datasets['train_images'])
        self.train_labels = MNIST._load_labels(target + '/' + datasets['train_labels'])

        self.test_images = MNIST._load_images(target + '/' + datasets['test_images'])
        self.test_labels = MNIST._load_labels(target + '/' + datasets['test_labels'])

    @staticmethod
    def _load_images(file_name):
        with open(file_name, 'rb') as image_file:
            ftype, length, rows, cols = struct.unpack(">IIII", image_file.read(16))
            return np.fromfile(image_file, dtype=np.uint8).reshape(length, rows * cols).astype(float) / 128 - 1

    @staticmethod
    def _load_labels(file_name):
        with open(file_name, 'rb') as label_file:
            label_file.read(8)  # Ignore header info for file type and number of entries
            integer_matrix = np.fromfile(label_file, dtype=np.int8)

            # Convert to one-hot format
            bool_matrix = np.zeros((np.size(integer_matrix), 10))
            bool_matrix[np.arange(np.size(integer_matrix)), integer_matrix] = True
            return bool_matrix

    def sample(self, quantity=1):
        x = np.random.randint(np.size(self.train_images[0]), size=quantity)
        return [self.train_images[x].T, self.train_labels[x].T]

    def survey(self, quantity=200):
        if quantity is None:
            return self.test_images.T, self.test_labels.T
        else:
            x = np.linspace(0, np.size(self.test_images[0]), quantity).astype(int)  # Size changes error granularity
            return [self.test_images[x].T, self.test_labels[x].T]

    def size_input(self):
        return np.size(self.train_images[0])

    def size_output(self):
        return np.size(self.train_labels[0])

    def plot(self, plt, predict):
        # Do not attempt to plot an image
        pass

    @staticmethod
    def error(expect, predict):
        predict_id = np.argmax(predict, axis=0)
        expect_id = np.argmax(expect, axis=0)
        return int((1.0 - np.mean((predict_id == expect_id).astype(float))) * 100)

environment = MNIST()

# ~~~ Create the network ~~~
network_params = {
    # Shape of network
    "units": [environment.size_input(), 100, 100, 50, environment.size_output()],

    # Basis function(s) from network's Function.py
    "basis": basis_bent,
    "basis_final": basis_softmax,

    # Distribution to use for weight initialization
    "distribute": dist_normal
    }

network = MFP(**network_params)

# ~~~ Train the network ~~~
optimizer_params = {
    # Source of stimuli
    "batch_size": 5,

    "cost": cost_cross_entropy,

    # Learning rate
    "learn_step": 0.5,
    "learn_anneal": anneal_fixed,

    # Weight decay regularization function
    "regularize_step": 0.0,
    "regularizer": reg_L2,

    "epsilon": 0.0,           # error allowance
    "iteration_limit": None,  # limit on number of iterations to run

    "debug_frequency": 1000,
    "debug": True,

    # The error measurement used in the mnist graph is highly susceptible to sampling error
    "graph": False
    }

Adagrad(network, environment, **optimizer_params).minimize()

# ~~~ Test the network ~~~
[stimuli, expectation] = environment.survey()
print(network.predict(stimuli))


from Products.Five import BrowserView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from plone import api
from gwopa.core.utils import get_safe_member_by_id
from zope.publisher.interfaces import IPublishTraverse, NotFound
from zope.interface import implements
from gwopa.core import _
from gwopa.core import utils

class userProfile(BrowserView):
    """ Returns an user profile ../profile/{username} """

    implements(IPublishTraverse)

    index = ViewPageTemplateFile('templates/user_profile.pt')

    def __init__(self, context, request):
        super(userProfile, self).__init__(context, request)
        self.username = None
        self.portal = api.portal.get()
        self.portal_url = self.portal.absolute_url()

    def __call__(self):
        return self.index()

    def getPortrait(self, user):
        return utils.getPortrait(self, user)

    def publishTraverse(self, request, name):
        if self.username is None:  # ../profile/username
            self.username = name
            self.user_info = api.user.get(self.username)
            member_info = get_safe_member_by_id(self.user_info.id)
            self.user_fullname = member_info.get('fullname', '')
            self.fullname = self.user_fullname
        else:
            raise NotFound(self, name, request)
        return self

    def user_properties(self):
        member_data = api.user.get(username=self.username)
        profile__properties = [
            _(u'fullname'),
            _(u'email'),
            _(u'phone'),
            _(u'country'),
            _(u'position'),
            _(u'wop_programs'),
            _(u'wop_platforms'),
            _(u'wop_partners'),
            _(u'type_of_organization'),
            _(u'common_working_areas'),
            _(u'donor'),
            _(u'other')
        ]

        rendered_properties = []
        for prop in profile__properties:
            if prop != 'common_working_areas':
                rendered_properties.append(dict(
                    name=_(prop),
                    value=member_data.getProperty(prop, '')
                ))
            else:
                rendered_properties.append(dict(
                    name=_(prop),
                    value=utils.getTranslatedWorkingAreaFromID(member_data.getProperty(prop, ''))
                ))
        return rendered_properties


# Licensed under a 3-clause BSD style license - see LICENSE.rst
from ... import splatalogue
from ...utils.testing_tools import MockResponse
from astropy import units as u
from astropy.tests.helper import pytest
import requests
import os

SPLAT_DATA = 'CO_colons.csv'

def data_path(filename):
    data_dir = os.path.join(os.path.dirname(__file__), 'data')
    return os.path.join(data_dir, filename)

@pytest.fixture
def patch_post(request):
    mp = request.getfuncargvalue("monkeypatch")
    mp.setattr(requests, 'post', post_mockreturn)
    return mp

def post_mockreturn(url, data=None, timeout=10, **kwargs):
    filename = data_path(SPLAT_DATA)
    content = open(filename, "rb").read()
    return MockResponse(content, **kwargs)

def test_simple(patch_post):
    x = splatalogue.Splatalogue.query_lines(114 * u.GHz, 116 * u.GHz, chemical_name=' CO ')

def test_init(patch_post):
    x = splatalogue.Splatalogue.query_lines(114 * u.GHz, 116 * u.GHz, chemical_name=' CO ')
    S = splatalogue.Splatalogue(chemical_name=' CO ')
    y = S.query_lines(114 * u.GHz, 116 * u.GHz)
    # it is not currently possible to test equality between tables:
    # masked arrays fail
    # assert y == x
    assert len(x) == len(y)
    assert all(y['Species'] == x['Species'])
    assert all(x['Chemical Name'] == y['Chemical Name'])

def test_load_species_table():
    tbl = splatalogue.load_species_table.species_lookuptable()
    CO = tbl.find(' CO ')
    assert len(CO) == 4

# regression test: ConfigItems were in wrong order at one point
def test_url():
    assert 'http://' in splatalogue.core.Splatalogue.QUERY_URL
    assert 'cv.nrao.edu' in splatalogue.core.Splatalogue.QUERY_URL

# regression test: get_query_payload should work (#308)
def test_get_payload():
    q = splatalogue.core.Splatalogue.query_lines_async(1 * u.GHz, 10 * u.GHz,
                                                       get_query_payload=True)
    assert '__utma' in q

# regression test: line lists should ask for only one line list, not all
def test_line_lists():
    q = splatalogue.core.Splatalogue.query_lines_async(1 * u.GHz, 10 * u.GHz,
                                                       line_lists=['JPL'],
                                                       get_query_payload=True)
    assert q['displayJPL'] == 'displayJPL'
    assert q['displaySLAIM'] == ''

# regression test: raise an exception if a string is passed to line_lists
# uses get_query_payload to avoid having to monkeypatch
def test_linelist_type():
    with pytest.raises(TypeError) as exc:
        splatalogue.core.Splatalogue.query_lines_async(1 * u.GHz, 10 * u.GHz,
                                                       line_lists='JPL',
                                                       get_query_payload=True)
    assert exc.value.args[0] == "Line lists should be a list of linelist names.  See Splatalogue.ALL_LINE_LISTS"

def test_top20_crashorno():
    splatalogue.core.Splatalogue.query_lines_async(114 * u.GHz, 116 * u.GHz, top20='top20',
                                                   get_query_payload=True)
    with pytest.raises(ValueError) as exc:
        splatalogue.core.Splatalogue.query_lines_async(114 * u.GHz, 116 * u.GHz,
                                                       top20='invalid',
                                                       get_query_payload=True)
    assert exc.value.args[0] == "Top20 is not one of the allowed values"

def test_band_crashorno():
    splatalogue.core.Splatalogue.query_lines_async(band='alma3',
                                                   get_query_payload=True)
    with pytest.raises(ValueError) as exc:
        splatalogue.core.Splatalogue.query_lines_async(band='invalid',
                                                       get_query_payload=True)
    assert exc.value.args[0] == "Invalid frequency band."


import time, numpy as np
from PIL import Image
from colorama import Fore, init
init()

class Scene:
    def __init__(self, spheres, planes, light_sources):
        self.spheres = spheres
        self.planes = planes
        self.all_bodies = self.spheres + self.planes
        self.light_sources = light_sources

#TODO: Rectangle intersection
# class Rectangle:
#     def __init__(self,):

class Texture:
    def __init__(self, filename, scale=1.0):
        self.img = Image.open(f"textures/{filename}").convert("RGB")
        self.width, self.height = self.img.size
        self.scale = scale

class Plane:
    def __init__(self, position, normal, color, reflectivity, texture=None):
        self.position = np.array(position)
        self.normal = self.normalize_vector(np.array(normal))
        self.color = np.array(color)
        self.reflectivity = reflectivity
        self.texture = texture

    def normalize_vector(self, vector):
     return vector/np.linalg.norm(vector)

class Light_source:
    def __init__(self, position, brightness, color, FOV, normal):
        self.position = np.array(position)
        self.brightness = brightness
        self.color = np.array(color)
        self.FOV = FOV
        self.normal = normal

class Sphere:
    def __init__(self, radius, position, color, reflectivity, texture=None):
        self.radius = radius
        self.position = np.array(position)
        self.color = np.array(color)
        self.reflectivity = reflectivity
        self.texture = texture

class Camera:
    def __init__(self, resolution, fov, position, rotation, gamma, max_reflections=1):
        self.resolution = np.array(resolution)
        self.fov = fov
        self.position = np.array(position)
        self.rotation = np.array(rotation)
        self.gamma = gamma
        self.max_reflections = max_reflections

        self.xMatrix = np.array(((1, 0, 0),
                            (0, np.cos(rotation[0]), -np.sin(rotation[0])),
                            (0, np.sin(rotation[0]), np.cos(rotation[0]))))

        self.yMatrix = np.array(((np.cos(rotation[1]), 0, np.sin(rotation[1])),
                            (0, 1, 0),
                            (-np.sin(rotation[1]), 0, np.cos(rotation[1]))))

        self.zMatrix = np.array(((np.cos(rotation[2]), -np.sin(rotation[2]), 0),
                            (np.sin(rotation[2]), np.cos(rotation[2]), 0),
                            (0, 0, 1)))

    def generate_ray(self, pixel, screen_distance):
        x = pixel[0] - self.resolution[0] / 2
        y = screen_distance
        z = -pixel[1] + self.resolution[1] / 2

        ray = np.array((x, y, z))

        ray = np.matmul(self.zMatrix, ray)
        ray = np.matmul(self.yMatrix, ray)
        ray = np.matmul(self.xMatrix, ray)

        ray = self.normalize_vector(ray)
        return ray

    def generate_rays(self):
        time_start = time.time()
        screen_distance = np.cos(self.fov/2) * self.resolution[0] / 2
        rays = []
        for y_index in range(self.resolution[1]):
            printProgressBar(y_index+1, self.resolution[1], time_start)
            row = []
            for x_index in range(self.resolution[0]):
                row.append(self.generate_ray((x_index, y_index), screen_distance))
            rays.append(row)
        rays = np.array(rays)

        return rays

    def check_for_ray_sphere_intersection(self, position, ray, sphere):
        intersection_check = np.power(np.dot(ray, np.subtract(position, sphere.position)), 2) - np.power(self.get_distance(position, sphere.position), 2) + sphere.radius**2

        if intersection_check < 0:
            return False
        if intersection_check == 0:
            d = -(np.dot(ray, np.subtract(position, sphere.position)))
            return np.add(position, ray * d)

        if intersection_check > 0:
            d1 = -(np.dot(ray, np.subtract(position, sphere.position))) - np.sqrt(intersection_check)
            d2 = -(np.dot(ray, np.subtract(position, sphere.position))) + np.sqrt(intersection_check)
            if np.abs(d1) <= np.abs(d2):
                d = d1
            else:
                d = d2
            if d > 0:
                return np.add(position, ray * d)
            else:
                return False

    def check_for_ray_plane_intersection(self, position, ray, plane):
        intersection_check = - np.dot(ray, plane.normal)

        if intersection_check != 0:
            n = np.subtract(position[0], plane.position[0]) * plane.normal[0] + np.subtract(position[1], plane.position[1]) * plane.normal[1] + np.subtract(position[2], plane.position[2]) * plane.normal[2]
            d = n / intersection_check
            if d >= 0:
                return np.add(position, ray * d)
        return False

    def check_for_ray_body_intersection(self, position, ray, body):
        body_type = type(body)
        if body_type is Sphere:
            return self.check_for_ray_sphere_intersection(position, ray, body)
        if body_type is Plane:
            return self.check_for_ray_plane_intersection(position, ray, body)

    def get_distance(self, p1, p2, sqrt=True):
        d = np.power(np.subtract(p1[0], p2[0]), 2) + np.power(np.subtract(p1[1], p2[1]), 2) + np.power(np.subtract(p1[2], p2[2]), 2)
        if sqrt:
            d = np.sqrt(d)
        return d

    def get_vector_length(self, vector):
        return np.sqrt(np.dot(vector, vector))

    def normalize_vector(self, vector):
     return vector/np.linalg.norm(vector)

    def check_for_direct_illumination(self, position, body, scene):
        illumination = np.array((0,0,0))
        for light_source in scene.light_sources:
            light_ray = np.subtract(light_source.position, position)
            light_ray = self.normalize_vector(light_ray)

            if np.arccos(np.dot(-light_ray, light_source.normal)) > light_source.FOV/2:
                continue

            ray_blocked = False
            for sphere in scene.spheres:
                intersection = self.check_for_ray_body_intersection(position, light_ray, sphere)
                if intersection is not False and self.get_distance(sphere.position, light_source.position) < self.get_distance(position, light_source.position):
                    ray_blocked = True
                    break

            if not ray_blocked:
                if type(body) is Sphere:
                    normal = np.subtract(position, body.position)
                else:
                    normal = body.normal
                normal = self.normalize_vector(normal)

                brightness_multiplier = np.dot(light_ray, normal) / (self.get_vector_length(light_ray) * self.get_vector_length(normal))
                if brightness_multiplier > 0:
                    brightness_multiplier = brightness_multiplier * (np.power(light_source.brightness / self.get_distance(position, light_source.position), 2))
                    illumination = illumination + light_source.color * brightness_multiplier
        if illumination.max() > 255:
            illumination = illumination / illumination.max() * 255
        return illumination

    def gamma_correction(self, color, gamma):
        if type(color) == np.ndarray:
            color = np.power(color/255, 1/gamma) * 255
        else:
            color = np.power(color, 1/gamma)
        return color

    def get_color_from_texture(self, body, intersection):
        if type(body) is Plane:
            plane = body
            if plane.normal[0] == 0 and plane.normal[2] == 0:
                x = intersection[0] - plane.position[0]
                y = intersection[2] - plane.position[2]
            elif plane.normal[1] == 0 and plane.normal[2] == 0:
                x = intersection[1] - plane.position[1]
                y = intersection[2] - plane.position[2]
            elif plane.normal[0] == 0 and plane.normal[1] == 0:
                x = intersection[0] - plane.position[0]
                y = intersection[1] - plane.position[1]
            else:
                return body.color

            x = x / plane.texture.scale
            y = y / plane.texture.scale

            if plane.normal[0] < 0:
                pixel_x = plane.texture.width - 1 - x % plane.texture.width
                pixel_y = plane.texture.height - 1 - y % plane.texture.height
                color = plane.texture.img.getpixel((int(pixel_x), int(pixel_y)))
                return np.array(color)
            if plane.normal[0] > 0:
                pixel_x = x % plane.texture.width
                pixel_y = plane.texture.height - 1 - y % plane.texture.height
                color = plane.texture.img.getpixel((int(pixel_x), int(pixel_y)))
                return np.array(color)

            if plane.normal[1] < 0:
                pixel_x = x % plane.texture.width
                pixel_y = plane.texture.height - 1 - y % plane.texture.height
                color = plane.texture.img.getpixel((int(pixel_x), int(pixel_y)))
                return np.array(color)
            if plane.normal[1] > 0:
                pixel_x = plane.texture.width - 1 - x % plane.texture.width
                pixel_y = plane.texture.height - 1 - y % plane.texture.height
                color = plane.texture.img.getpixel((int(pixel_x), int(pixel_y)))
                return np.array(color)

            if plane.normal[2] < 0:
                pixel_x = plane.texture.width - 1 - x % plane.texture.width
                pixel_y = plane.texture.height - 1 - y % plane.texture.height
                color = plane.texture.img.getpixel((int(pixel_x), int(pixel_y)))
                return np.array(color)
            if plane.normal[2] > 0:
                pixel_x = plane.texture.width - 1 - x % plane.texture.width
                pixel_y = y % plane.texture.height
                color = plane.texture.img.getpixel((int(pixel_x), int(pixel_y)))
                return np.array(color)

    def get_reflection_ray(self, ray, intersection, body):
        if type(body) is Sphere:
            normal_vector = self.normalize_vector(np.subtract(intersection, body.position))
        else:
            normal_vector = body.normal
        ray = self.normalize_vector(ray)
        reflection_ray = ray - 2 * np.dot(ray, normal_vector) * normal_vector
        return reflection_ray

    def render_scene(self, scene):
        img = Image.new("RGB", tuple(self.resolution), (0,0,0))
        rays_length_array = np.zeros(self.resolution)
        print(f"{Fore.CYAN}Preparing rays:{Fore.RESET}")
        rays = self.generate_rays()

        time_start = time.time()
        print(f"{Fore.CYAN}\nRendering:{Fore.RESET}")
        for y, row in enumerate(rays):
            printProgressBar(y+1, self.resolution[1], time_start)
            for x, ray in enumerate(row):
                for body in scene.all_bodies:
                    intersection = self.check_for_ray_body_intersection(self.position, ray, body)
                    if intersection is not False:
                        ray_length = self.get_distance(self.position, intersection)
                        if rays_length_array[x][y] == 0 or rays_length_array[x][y] > ray_length:
                            rays_length_array[x][y] = ray_length

                            if body.reflectivity is not False:
                                _ray = self.get_reflection_ray(ray, intersection, body)
                                for _body in scene.all_bodies:
                                    if _body == body:
                                        continue
                                    _intersection = self.check_for_ray_body_intersection(intersection, _ray, _body)
                                    if _intersection is not False:
                                        _ray_length = self.get_distance(_intersection, intersection)
                                        if rays_length_array[x][y] == 0 or rays_length_array[x][y] > _ray_length:
                                            rays_length_array[x][y] = _ray_length

                                            illumination = self.check_for_direct_illumination(_intersection, _body, scene)
                                            illumination = self.gamma_correction(illumination, self.gamma)
                                            if _body.texture is not None:
                                                color = self.get_color_from_texture(_body, _intersection) * illumination / 255
                                            else:
                                                color = _body.color * illumination / 255
                                            color = color * body.reflectivity + body.color * (1 - body.reflectivity)

                                            color = tuple(color.astype(int))
                                            img.putpixel((x, y), color)

                                # rays = [ray]
                                # bodies = [body]
                                # intersections = [intersection]
                                # for reflection_index in range(self.max_reflections):
                                #     rays.append(self.get_reflection_ray(rays[-1], intersections[-1], bodies[-1]))

                                #     for body in scene.all_bodies:
                                #         if body == bodies[-1]:
                                #             continue

                                #         i = self.check_for_ray_body_intersection(intersections[-1], rays[-1], body)
                                #         if i is False:
                                #             continue

                                #         reflection_ray_length = self.get_distance(intersections[-1], i)

                                #         if rays_length_array[x][y] == 0 or rays_length_array[x][y] > reflection_ray_length:
                                #             rays_length_array[x][y] = reflection_ray_length
                                #             if len(bodies) > reflection_index + 1:
                                #                 bodies.pop(-1)
                                #                 intersections.pop(-1)

                                #             bodies.append(body)
                                #             intersections.append(i)

                                #             illumination = self.check_for_direct_illumination(intersections[-1], bodies[-1], scene)
                                #             illumination = self.gamma_correction(illumination, self.gamma)
                                #             if bodies[-1].texture is not None:
                                #                 color = self.get_color_from_texture(bodies[-1], intersections[-1]) * illumination / 255
                                #             else:
                                #                 color = bodies[-1].color * illumination / 255

                                #     color = tuple(np.array(color).astype(int))
                                #     img.putpixel((x, y), color)

                            else:
                                illumination = self.check_for_direct_illumination(intersection, body, scene)
                                illumination = self.gamma_correction(illumination, self.gamma)
                                if body.texture is not None:
                                    color = self.get_color_from_texture(body, intersection) * illumination / 255
                                else:
                                    color = body.color * illumination / 255

                                color = tuple(color.astype(int))
                                img.putpixel((x, y), color)
        return img

def printProgressBar (progress, total, time_start):
    percent = 100 * (progress / total)
    bar = "█" * int(percent) + "-" * (100 - int(percent))
    time_total = time.time() - time_start
    if time_total >= 60:
        time_total = f"{int(time_total // 60)}m {(time_total % 60):.2f}s"
    else:
        time_total = f"{time_total:.2f}s"

    time_left = (time.time() - time_start) / (percent / 100) - (time.time() - time_start)
    if time_left >= 60:
        time_left = f"{int(time_left // 60)}m {(time_left % 60):.2f}s"
    else:
        time_left = f"{time_left:.2f}s"
    print(f"{bar} {percent:.2f}%   t: {time_total}   eta: " + time_left, end="     \r")
    if progress == total:
        print(f"{Fore.GREEN}{bar} {percent:.2f}%   t: {time_total}   eta: --      {Fore.RESET}")

#* (resolution, FOV, pos, rotation, gamma, max_reflections)
# camera = Camera((1600, 900), np.pi/2, (0,0,30), (0, 0, 0), 2.4, 1)
camera = Camera((320, 180), np.pi/2, (0,0,30), (0, 0, 0), 2.4, 1)

#* (radius, pos, color, reflectivity)
sphere1 = Sphere(10, (-10,45,10), (255,255,255), 0.95)
sphere2 = Sphere(10, (20,35,10), (255,0,0), 0.8)

#* (pos, brightness, color, FOV, normal)
light_source1 = Light_source((0,30,50), 25, (255,255,255), np.pi*2, [0,0,-1])

#* (filename, scale)
texture_stone = Texture("stone.png", 0.5)
texture_diamond = Texture("diamond_ore.png", 0.5)
texture_redstone = Texture("redstone_ore.png", 0.5)
texture_lapis = Texture("lapis_ore.png", 0.5)
texture_checkerboard = Texture("checkerboard.png", 2)

#* (pos, norm, color, "texture")
plane1 = Plane((0,0,0), (0,0,1), (155,155,155), False, texture_checkerboard)
plane2 = Plane((-32,0,0), (1,0,0), (255,0,0), False, texture_redstone)
plane3 = Plane((0,64,0), (0,-1,0), (255,255,255), False, texture_diamond)
plane4 = Plane((32,0,0), (-1,0,0), (0,0,255), False, texture_lapis)
# plane5 = Plane((0,0,64), (0,0,-1), (255,255,255), False, texture_stone)
# plane6 = Plane((0,-32,0), (0,1,0), (255,255,255), False, texture_stone)

# plane1 = Plane((0,0,0), (0,0,1), (155,155,155), False)
# plane2 = Plane((-32,0,0), (1,0,0), (255,0,0), False)
# plane3 = Plane((0,64,0), (0,-1,0), (0,255,0), False)
# plane4 = Plane((32,0,0), (-1,0,0), (0,0,255), False)
plane5 = Plane((0,0,64), (0,0,-1), (255,255,255), False)
# plane6 = Plane((0,-0.1,0), (0,1,0), (255,255,255), False)

scene = Scene([sphere1, sphere2], [plane1, plane2, plane3, plane4, plane5], [light_source1])

img = camera.render_scene(scene)
img.save("render.png", format="png")
# img = img.resize((1200, 675))
img.show()


from typing import List
"""
Problem Name: Move Zeroes

Problem Section: Array

Problem Statement:
Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements.

Example:
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]

Note:
You must do this in-place without making a copy of the array.
Minimize the total number of operations.

Resources:
"""
""" 21 / 21 test cases passed.
	Status: Accepted
Runtime: 48 ms
Memory Usage: 15 MB """

# Solution techniques are
# Time complexity : O(n) Space complexity : O(1) time and space optimized two pointer(slow & fast) solution

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        if len(nums) == 1 or not nums:
            return

        lastNonZero = 0

        for itr in range(len(nums)):
            if nums[itr] != 0:
                nums[lastNonZero], nums[itr] = nums[itr], nums[lastNonZero]
                lastNonZero += 1

myobj = Solution()
inpt = [0, 1, 0, 3, 12]
print(myobj.moveZeroes(inpt))