import os

import flask
from celery import Celery
from celery import signals
from celery.schedules import crontab
from kombu.utils.url import safequote

from airq import config

BEAT_SCHEDULE = {}

if not config.TESTING:
    BEAT_SCHEDULE["models_sync"] = {
        "task": "airq.tasks.models_sync",
        "schedule": crontab(minute="*/10"),  # Every 10 minutes
    }

def get_celery_logger():
    from celery.utils.log import get_task_logger

    return get_task_logger(__name__)

if config.DEBUG:
    # Use redis in dev so that people don't need to setup AWS credentials.
    redis_port = os.getenv("REDIS_PORT", "6379")
    broker_url = f"redis://redis:{redis_port}/0"
    transport_options = {}
else:
    broker_url = "sqs://{}:{}@".format(
        safequote(config.AWS_ACCESS_KEY_ID), safequote(config.AWS_SECRET_ACCESS_KEY)
    )
    transport_options = {"region": "us-west-1", "visibility_timeout": 120}

celery = Celery(config.app.import_name)
celery.conf.update(
    accept_content=["application/json"],
    beat_schedule=BEAT_SCHEDULE,
    broker_url=broker_url,
    broker_transport_options=transport_options,
    result_serializer="json",
    task_default_queue=f"celery-{config.FLASK_ENV}",
    task_serializer="json",
    worker_enable_remote_control=False,
    worker_hijack_root_logger=False,
)
celery.conf.update(config.app.config)

if config.TESTING:
    celery.conf.update(task_always_eager=True, task_eager_propagates=True)

class ContextTask(celery.Task):  # type: ignore
    def __call__(self, *args, **kwargs):
        # If an "app_context" has already been loaded, just pass through
        if flask._app_ctx_stack.top is not None:
            return super().__call__(*args, **kwargs)
        with config.app.app_context():
            return self.run(*args, **kwargs)

    def on_failure(self, exc, task_id, args, kwargs, einfo):
        get_celery_logger().exception(
            "%s: %s", type(exc).__name__, str(exc), exc_info=exc
        )
        super().on_failure(exc, task_id, args, kwargs, einfo)

celery.Task = ContextTask

@signals.setup_logging.connect
def setup_celery_logging(**kwargs):
    dictConfig(config.LOGGING_CONFIG)

celery.autodiscover_tasks(["airq"])


import numpy as np
from scipy.special import erf,erfc

def asym(x):
    return -np.exp(-x**2)/np.sqrt(np.pi)/x*(1.-1./(2.*x**2))

def calculate_Gaussian(x, mu, sigma2, low, high):
    a = (low-mu)/np.sqrt(2*sigma2)
    b = (high-mu)/np.sqrt(2*sigma2)
    norm = np.sqrt(sigma2*np.pi/2)*(-erf(a) + erf(b))

    # If difference in error functions produce zero, overwrite with asymptotic expansion
    if np.any(norm==0):
        badInds = np.where(norm==0)
        norm[badInds] = (np.sqrt(sigma2*np.pi/2)*(-asym(a) + asym(b)))[badInds]

    # If differences remain zero, then our domain of interest (-1,1) is so many std. deviations
    # from the mean that our parametrization is unphysical. In this case, discount this hyperparameter.
    # This amounts to an additional condition in our hyperprior
    # NaNs occur when norm is infinitesimal, like 1e-322, such that 1/norm is set to inf and the exponential term is zero
    y = (1.0/norm)*np.exp((-1.0*(x-mu)*(x-mu))/(2.*sigma2))
    if np.any(norm==0) or np.any(y!=y):
        return np.zeros(x.size)

    else:
        y[x<low] = 0
        y[x>high] = 0
        return y

def calculate_Gaussian_2D(x,y,mu_x,sigma2_x,mu_y,sigma2_y,low_x,high_x,low_y,high_y):

    xgrid = np.linspace(low_x,high_x,100)
    ygrid = np.linspace(low_y,high_y,100)
    dx = xgrid[1] - xgrid[0]
    dy = ygrid[1] - ygrid[0]

    X,Y = np.meshgrid(xgrid,ygrid)
    Z = np.exp(-0.5*(np.square(X-mu_x)/sigma2_x + np.square(Y-mu_y)/sigma2_y))
    norm = np.sum(Z)*dx*dy

    z = (1./norm)*np.exp(-0.5*(np.square(x-mu_x)/sigma2_x + np.square(y-mu_y)/sigma2_y))
    return z

def injection_weights(m1_det,m2_det,s1z_det,s2z_det,z_det,mMin=5):

    # Load mock detections
    ref_m_min = 2.
    ref_m_max = 100.
    ref_a1 = -2.35
    ref_a2 = 2.

    # Derived quantities
    q_det = m2_det/m1_det
    mtot_det = m1_det+m2_det
    X_det = (m1_det*s1z_det + m2_det*s2z_det)/(m1_det+m2_det)

    ref_p_z = np.power(1.+z_det,2.-1.)
    ref_p_m1 = np.power(m1_det,ref_a1)
    ref_p_m2 = (1.+ref_a2)*np.power(m2_det,ref_a2)/(m1_det**(1.+ref_a2) - ref_m_min**(1.+ref_a2))

    ref_p_xeff = np.zeros(X_det.size)
    for i in range(ref_p_xeff.size):

        X = X_det[i]
        q = q_det[i]

        if X<-(1.-q)/(1.+q):
            ref_p_xeff[i] = (1./(2.*q))*(1.+q)*(1.+X)*(1.+q)/2.

        elif X>(1.-q)/(1.+q):
            ref_p_xeff[i] = (1./(2.*q))*(1.+q)*(1.-X)*(1.+q)/2.

        else:
            ref_p_xeff[i] = (1.+q)/2.

    pop_reweight = 1./(ref_p_xeff*ref_p_m1*ref_p_m2*ref_p_z)
    pop_reweight[m1_det<mMin] = 0.
    pop_reweight[m2_det<mMin] = 0.
    return pop_reweight

def mock_injection_weights(m1_det,m2_det,s1z_det,s2z_det,z_det,mMin=5.):

    # Population from which injections are drawn
    ref_a1 = -2
    ref_a2 = -4
    ref_m0 = 40
    ref_mMin = 5.
    ref_mMax = 100.
    ref_bq = 0.5
    ref_kappa = 2.
    ref_mu = 0.
    ref_chi = 1.

    # Derived quantities
    q_det = m2_det/m1_det
    mtot_det = m1_det+m2_det
    X_det = (m1_det*s1z_det + m2_det*s2z_det)/(m1_det+m2_det)

    ref_p_z = np.power(1.+z_det,ref_kappa-1.)
    ref_p_m1 = np.zeros(m1_det.size)
    ref_p_m1[m1_det<ref_m0] = np.power(m1_det[m1_det<ref_m0]/ref_m0,ref_a1)
    ref_p_m1[m1_det>=ref_m0] = np.power(m1_det[m1_det>=ref_m0]/ref_m0,ref_a2)

    ref_p_m2 = np.power(m2_det,ref_bq)/(m1_det**(1.+ref_bq) - ref_mMin**(1.+ref_bq))
    ref_p_xeff = calculate_Gaussian(X_det,ref_mu,ref_chi**2,-1,1)

    pop_reweight = 1./(ref_p_xeff*ref_p_m1*ref_p_m2*ref_p_z)
    pop_reweight[m1_det<mMin] = 0.
    pop_reweight[m2_det<mMin] = 0.
    return pop_reweight


# coding: utf-8

# # Examples for running FLORIS

# In[10]:

# load modules
from floris.floris import Floris
import numpy as np

# ## Setup floris and process input file

# In[11]:

floris = Floris("example_input.json")

# ## Calculate Wake

# In[12]:

import time

t1 = time.time()

floris.farm.flow_field.calculate_wake()

t2 = time.time()

print('Time to compute wake = ', t2-t1, 's')

# ## Compute Velocities at each Turbine

# In[13]:

for coord, turbine in floris.farm.turbine_map.items():
    print(str(coord) + ":")
    print("\tCp -", turbine.Cp)
    print("\tCt -", turbine.Ct)
    print("\tpower -", turbine.power)
    print("\tai -", turbine.aI)
    print("\taverage velocity -", turbine.get_average_velocity())

# ## Plot the Flow Field (z-plane)

# In[5]:

# this plots the streamwise velocity at:

# inputs -> percent of z domain entered as a list

#     1.  20% of the z height domain (the z height domain is 2x hub height, i.e. 36m)
#     2.  50% of the z height domain (at hub height)
#     3.  80% of the z height domain (144m)

floris.farm.flow_field.plot_z_planes([0.2, 0.5, 0.8])

# ## Plot the Flow Field (x-plane)

# In[6]:

# plot a cut-through of the flow field at a particular x distance downstream.

# inputs -> percent of x domain entered as a list

floris.farm.flow_field.plot_x_planes([0.4])

# ## Optimize Wind Farm using Wake Steering

# In[7]:

import OptModules  # modules used for optimizing FLORIS
import numpy as np

turbines      = [turbine for _, turbine in floris.farm.flow_field.turbine_map.items()]
power_initial = np.sum([turbine.power for turbine in turbines])  # determine initial power production

# set bounds for the optimization on the yaw angles (deg)
minimum_yaw_angle = 0.0
maximum_yaw_angle = 25.0

# compute the optimal yaw angles
opt_yaw_angles = OptModules.wake_steering(floris,minimum_yaw_angle,maximum_yaw_angle)

print('Optimal yaw angles for:')
for i,yaw in enumerate(opt_yaw_angles):
    print('Turbine ', i, ' yaw angle = ', np.degrees(yaw))

# ## Assign New Yaw Angles

# In[8]:

# assign yaw angles to turbines
turbines    = [turbine for _, turbine in floris.farm.flow_field.turbine_map.items()]
for i,turbine in enumerate(turbines):
    turbine.yaw_angle = opt_yaw_angles[i]

# ## Plot Optimized Flow Field

# In[9]:

# compute the new wake with yaw angles
floris.farm.flow_field.calculate_wake()

# optimal power
power_opt = np.sum([turbine.power for turbine in turbines])

# plot results
floris.farm.flow_field.plot_z_planes([0.5])

print('Power increased by ', 100*(power_opt-power_initial)/power_initial, '%')

# In[ ]:

# In[ ]:


with open("day10/input.txt", encoding='utf-8') as file:
    data = file.read().splitlines()

opening_chars = '([{<'
closing_chars = ')]}>'
sum_of_corrupted = 0
mapping_dict = {'(' : [')', 3], '[' : [']', 57], '{' : ['}', 1197], '<' : ['>', 25137]}
mapping_dict_sums = {')' : 3, ']' : 57, '}' : 1197, '>' :  25137}
mapping_dict_part2 = {'(' : 1, '[' : 2, '{' : 3, '<' :  4}
total_points = []

for line in data:
    empty_array = []
    for key, char in enumerate(line):
        if char in closing_chars:
            last_char = empty_array.pop(-1)
            if char != mapping_dict[last_char][0]:
                empty_array = []
                break
        else:
            empty_array.insert(len(empty_array), char)

    acc = 0
    for score in empty_array[::-1]:
        acc = acc * 5 + mapping_dict_part2[score]

    if len(empty_array) != 0:
        total_points.append(acc)

middle_key = int(len(total_points)/2)
middle_score = sorted(total_points)[middle_key]
print(middle_score)


import sys

def removepunc(line):
    punctuation = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
    for letter in line:
        if letter in punctuation:
            line = line.replace(letter, "")
    return line

def main():
    foundwords = []
    unique = 0
    for line in sys.stdin:
        line = removepunc(line)
        wordlist = line.lower().split()
        for word in wordlist:
            if word not in foundwords:
                foundwords.append(word)
                unique += 1
    print(unique)

if __name__ == '__main__':
    main()


from django.db import models
from django.utils.dateformat import format
from django.conf import settings
from cached_property import cached_property_with_ttl
from core.models import Pair, Market, Currency

from core.common.models import IndexTimeStampedModel
from decimal import Decimal
from payments.utils import money_format
from django.utils import timezone
from django.utils.translation import ugettext as _
from django.core.exceptions import ValidationError
from nexchange.utils import get_nexchange_logger

LOGGER = get_nexchange_logger('Ticker Logger', with_email=True,
                              with_console=True)

class Ticker(IndexTimeStampedModel):
    ask = models.DecimalField(max_digits=18, decimal_places=8)
    bid = models.DecimalField(max_digits=18, decimal_places=8)
    pair = models.ForeignKey(Pair,
                             on_delete=models.CASCADE)

    @property
    def rate(self):
        return (self.ask + self.bid) / 2

    def _validate_change(self):
        if self.pk:
            return
        try:
            price = Price.objects.filter(
                pair=self.pair,
                market__is_main_market=True
            ).latest('id')
            latest = price.ticker
        except Price.DoesNotExist:
            return
        for field in ['ask', 'bid']:
            value = Decimal(getattr(self, field))
            previous_value = Decimal(getattr(latest, field))
            diff = abs(value - previous_value) / previous_value
            if diff > settings.TICKER_ALLOWED_CHANGE:
                msg = \
                    'Too big ticker {field} change (from {value} to ' \
                    '{previous_value}). Pair: {pair}'.format(
                        field=field,
                        value=value,
                        previous_value=previous_value,
                        pair=self.pair.name
                    )
                LOGGER.info(msg)
                raise ValidationError(_(msg))

    def save(self, *args, **kwargs):
        if kwargs.pop('validate_change', True):
            self._validate_change()
        super(Ticker, self).save(*args, **kwargs)

DEFAULT_MARKET_PK = 1

class Price(IndexTimeStampedModel):

    ticker = models.ForeignKey(Ticker, blank=True, null=True,
                               on_delete=models.CASCADE)
    pair = models.ForeignKey(Pair, blank=True, null=True,
                             on_delete=models.CASCADE)
    better_adds_count = models.IntegerField(default=0)
    market = models.ForeignKey(Market, default=DEFAULT_MARKET_PK,
                               on_delete=models.DO_NOTHING)
    slippage = models.DecimalField(max_digits=18, decimal_places=8,
                                   default=Decimal('0'))

    def _validate(self):
        if not self.pk and not self.ticker:
            raise ValidationError(_('Ticker is required for Price.'))

    def save(self, *args, **kwargs):
        self._validate()
        if self.pair:
            self.slippage = self.pair.base.current_slippage
        super(Price, self).save(*args, **kwargs)

    @classmethod
    def _get_currency(cls, currency):
        if isinstance(currency, Currency):
            return currency
        return Currency.objects.get(code=currency)

    @classmethod
    def get_rate(cls, base, quote):
        inverted = False
        base = cls._get_currency(base)
        quote = cls._get_currency(quote)
        if base == quote:
            return Decimal('1.0')
        places = 16
        if all([not base.is_crypto, quote.is_crypto]):
            base, quote = quote, base
            inverted = True
            places = 16
        elif all([not base.is_crypto, not quote.is_crypto]):
            places = 16
        try:
            pair = Pair.objects.get(base=base, quote=quote)
            if pair.disable_ticker:
                # only return values if ticker is not disabled
                return
            latest_rate = cls.objects.filter(
                pair=pair,
                market__is_main_market=True).latest('id').ticker.rate
            if inverted:
                latest_rate = money_format(Decimal(1.0) / latest_rate,
                                           places=places)
        except Pair.DoesNotExist:
            latest_btc = cls.objects.filter(
                pair__name='BTC{}'.format(quote.code),
                market__is_main_market=True).latest('id').ticker.rate
            latest_base = cls.objects.filter(
                pair__name='BTC{}'.format(base.code),
                market__is_main_market=True).latest('id').ticker.rate
            if inverted:
                latest_rate = money_format(latest_base / latest_btc,
                                           places=places)
            else:
                latest_rate = money_format(latest_btc / latest_base,
                                           places=places)
        return latest_rate

    @classmethod
    def convert_amount(cls, amount, from_curr, to_curr):
        if not isinstance(amount, Decimal):
            amount = Decimal(str(amount))
        rate = cls.get_rate(from_curr, to_curr)
        return amount * rate if rate else None

    @property
    def unix_time(self):
        return format(self.created_on, 'U')

    @property
    def price_formatted_ask(self):
        return self.ticker.ask

    @property
    def price_formatted_bid(self):
        return self.ticker.bid

    @property
    def rate(self):
        return self.ticker.ask * (Decimal('1.0') + self.slippage)

    @cached_property_with_ttl(ttl=settings.TICKER_INTERVAL)
    def rate_btc(self):
        return self.get_rate(self.pair.base, 'BTC')

    @cached_property_with_ttl(ttl=settings.TICKER_INTERVAL)
    def rate_usd(self):
        return self.get_rate(self.pair.base, 'USD')

    @cached_property_with_ttl(ttl=settings.TICKER_INTERVAL)
    def rate_eur(self):
        return self.get_rate(self.pair.base, 'EUR')

    @property
    def price_expiration_date(self):
        return self.created_on + settings.TICKER_EXPIRATION_INTERVAL

    @property
    def expired(self):
        return timezone.now() > self.price_expiration_date

    def __str__(self):
        return '{} {}'.format(self.pair, self.created_on)


import datetime, numpy, os, sys, pathlib
from PyQt5 import QtGui, QtWidgets, QtCore
import pyqtgraph as pg
import numpy as np

smallfont = QtGui.QFont()
smallfont.setPointSize(7)
verysmallfont = QtGui.QFont()
verysmallfont.setPointSize(5)

def remove_size_props(o, fcol=False, button=False, image=False):
    o.setMinimumHeight(0)
    o.setMinimumWidth(0)
    o.setMaximumHeight(int(1e5))
    if fcol:
        o.setMaximumWidth(250) # just a max width for the first column
    elif button:
        o.setMaximumWidth(250/5) # just a max width for the first column
    elif image:
        # o.setMaximumWidth(500) # just a max width for the first column
        o.setMaximumHeight(500) # just a max width for the first column
    else:
        o.setMaximumWidth(int(1e5))

def create_calendar(self, Layout, min_date=(2020, 8, 1)):

    self.cal = QtWidgets.QCalendarWidget(self)
    self.cal.setFont(verysmallfont)
    self.cal.setMinimumHeight(160)
    self.cal.setMaximumHeight(160)
    self.cal.setMinimumWidth(265)
    self.cal.setMaximumWidth(265)
    self.cal.setMinimumDate(QtCore.QDate(datetime.date(*min_date)))
    self.cal.setMaximumDate(QtCore.QDate(datetime.date.today()+datetime.timedelta(1)))
    self.cal.adjustSize()
    self.cal.clicked.connect(self.pick_date)
    Layout.addWidget(self.cal)

    # setting an highlight format
    self.highlight_format = QtGui.QTextCharFormat()
    self.highlight_format.setBackground(self.cal.palette().brush(QtGui.QPalette.Link))
    self.highlight_format.setForeground(self.cal.palette().color(QtGui.QPalette.BrightText))

    self.cal.setSelectedDate(datetime.date.today())

def reinit_calendar(self, min_date=(2020, 8, 1), max_date=None):

    day, i = datetime.date(*min_date), 0
    while day!=datetime.date.today():
        self.cal.setDateTextFormat(QtCore.QDate(day),
                                   QtGui.QTextCharFormat())
        day = day+datetime.timedelta(1)
    day = day+datetime.timedelta(1)
    self.cal.setDateTextFormat(QtCore.QDate(day),
                               QtGui.QTextCharFormat())
    self.cal.setMinimumDate(QtCore.QDate(datetime.date(*min_date)))

    if max_date is not None:
        self.cal.setMaximumDate(QtCore.QDate(datetime.date(*max_date)+datetime.timedelta(1)))
        self.cal.setSelectedDate(datetime.date(*max_date)+datetime.timedelta(1))
    else:
        self.cal.setMaximumDate(QtCore.QDate(datetime.date.today()+datetime.timedelta(1)))
        self.cal.setSelectedDate(datetime.date.today())

def add_buttons(self, Layout):

    self.styleUnpressed = ("QPushButton {Text-align: left; "
                           "background-color: rgb(200, 200, 200); "
                           "color:white;}")
    self.stylePressed = ("QPushButton {Text-align: left; "
                         "background-color: rgb(100,50,100); "
                         "color:white;}")
    self.styleInactive = ("QPushButton {Text-align: left; "
                          "background-color: rgb(200, 200, 200); "
                          "color:gray;}")

    iconSize = QtCore.QSize(20, 20)

    self.playButton = QtWidgets.QToolButton()
    self.playButton.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MediaPlay))
    self.playButton.setIconSize(iconSize)
    self.playButton.setToolTip("Play   -> [Space]")
    self.playButton.setCheckable(True)
    self.playButton.setEnabled(True)
    self.playButton.clicked.connect(self.play)

    self.pauseButton = QtWidgets.QToolButton()
    self.pauseButton.setCheckable(True)
    self.pauseButton.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MediaPause))
    self.pauseButton.setIconSize(iconSize)
    self.pauseButton.setToolTip("Pause   -> [Space]")
    self.pauseButton.clicked.connect(self.pause)

    btns = QtWidgets.QButtonGroup(self)
    btns.addButton(self.playButton,0)
    btns.addButton(self.pauseButton,1)
    btns.setExclusive(True)

    self.playButton.setEnabled(False)
    self.pauseButton.setEnabled(True)
    self.pauseButton.setChecked(True)

    self.refreshButton = QtWidgets.QToolButton()
    self.refreshButton.setCheckable(True)
    self.refreshButton.setIcon(self.style().standardIcon(QtGui.QStyle.SP_BrowserReload))
    self.refreshButton.setIconSize(iconSize)
    self.refreshButton.setToolTip("Refresh   -> [r]")
    self.refreshButton.clicked.connect(self.refresh)

    self.quitButton = QtWidgets.QToolButton()
    # self.quitButton.setCheckable(True)
    self.quitButton.setIcon(self.style().standardIcon(QtGui.QStyle.SP_DialogCloseButton))
    self.quitButton.setIconSize(iconSize)
    self.quitButton.setToolTip("Quit")
    self.quitButton.clicked.connect(self.quit)

    self.backButton = QtWidgets.QToolButton()
    # self.backButton.setCheckable(True)
    self.backButton.setIcon(self.style().standardIcon(QtGui.QStyle.SP_FileDialogBack))
    self.backButton.setIconSize(iconSize)
    self.backButton.setToolTip("Back to initial view   -> [i]")
    self.backButton.clicked.connect(self.back_to_initial_view)

    self.settingsButton = QtWidgets.QToolButton()
    # self.settingsButton.setCheckable(True)
    self.settingsButton.setIcon(self.style().standardIcon(QtGui.QStyle.SP_FileDialogDetailedView))
    self.settingsButton.setIconSize(iconSize)
    # self.settingsButton.setToolTip("Settings")
    # self.settingsButton.clicked.connect(self.change_settings)
    self.settingsButton.setToolTip("Metadata")
    self.settingsButton.clicked.connect(self.see_metadata)

    Layout.addWidget(self.quitButton)
    Layout.addWidget(self.playButton)
    Layout.addWidget(self.pauseButton)
    Layout.addWidget(self.refreshButton)
    Layout.addWidget(self.backButton)
    Layout.addWidget(self.settingsButton)

def build_slider(self, Layout):
    self.frameSlider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
    self.frameSlider.setMinimum(0)
    self.frameSlider.setMaximum(self.settings['Npoints'])
    self.frameSlider.setTickInterval(1)
    self.frameSlider.setTracking(False)
    self.frameSlider.valueChanged.connect(self.update_frame)
    self.frameSlider.setMaximumHeight(20)
    Layout.addWidget(self.frameSlider)

class NewWindow(QtWidgets.QMainWindow):

    def __init__(self,
                 parent=None, i=0,
                 title='New Window',
                 size=(1000,600)):

        super(NewWindow, self).__init__()

        self.script = os.path.join(str(pathlib.Path(__file__).resolve().parents[1]),
                                   'script.sh') # for batch processing

        self.setGeometry(600+20*i, 250+20*i, size[0], size[1])

        ##############################
        ##### keyboard shortcuts #####
        ##############################

        # adding a few general keyboard shortcut
        self.openSc = QtWidgets.QShortcut(QtGui.QKeySequence('O'), self)
        self.openSc.activated.connect(self.open_file)

        self.spaceSc = QtWidgets.QShortcut(QtGui.QKeySequence('Space'), self)
        self.spaceSc.activated.connect(self.hitting_space)

        self.saveSc = QtWidgets.QShortcut(QtGui.QKeySequence('S'), self)
        self.saveSc.activated.connect(self.save)

        self.add2Bash = QtWidgets.QShortcut(QtGui.QKeySequence('B'), self)
        self.add2Bash.activated.connect(self.add_to_bash_script)

        self.quitSc = QtWidgets.QShortcut(QtGui.QKeySequence('Q'), self)
        self.quitSc.activated.connect(self.quit)

        self.refreshSc = QtWidgets.QShortcut(QtGui.QKeySequence('R'), self)
        self.refreshSc.activated.connect(self.refresh)

        self.homeSc = QtWidgets.QShortcut(QtGui.QKeySequence('I'), self)
        self.homeSc.activated.connect(self.back_to_initial_view)

        self.maxSc = QtWidgets.QShortcut(QtGui.QKeySequence('M'), self)
        self.maxSc.activated.connect(self.showwindow)

        self.processSc = QtWidgets.QShortcut(QtGui.QKeySequence('P'), self)
        self.processSc.activated.connect(self.process)

        self.fitSc = QtWidgets.QShortcut(QtGui.QKeySequence('F'), self)
        self.fitSc.activated.connect(self.fit)

        ########################
        ##### building GUI #####
        ########################

        pg.setConfigOptions(imageAxisOrder='row-major')

        self.setWindowTitle(title)
        self.minView = False

        self.cwidget = QtWidgets.QWidget(self)
        self.setCentralWidget(self.cwidget)

        self.statusBar = QtWidgets.QStatusBar()
        self.setStatusBar(self.statusBar)
        self.statusBar.setFont(smallfont)

        self.showwindow()

    def quit(self):
        sys.exit()

    def print_datafile(self):
        if hasattr(self, 'datafile'):
            print('current datafile:\n', self.datafile)

    def process(self):
        print(' "process" function not implemented')
        print(' --> should be implemented in child class !')
        self.print_datafile()

    def fit(self):
        print(' "fit" function not implemented')
        print(' --> should be implemented in child class !')
        self.print_datafile()

    def add_to_bash_script(self):
        print(' "add_to_bash_script" function not implemented')
        print(' --> should be implemented in child class !')

    def refresh(self):
        print(' "refresh" function not implemented')
        print(' --> should be implemented in child class !')

    def open_file(self):
        print(' "open_file" function not implemented')
        print(' --> should be implemented in child class !')

    def hitting_space(self):
        print(' "hitting_space" function not implemented')
        print(' --> should be implemented in child class !')

    def back_to_initial_view(self):
        print(' "back_to_initial_view" function not implemented')
        print(' --> should be implemented in child class !')

    def showwindow(self):
        if self.minView:
            self.minView = self.maxview()
        else:
            self.minView = self.minview()

    def maxview(self):
        self.showFullScreen()
        return False

    def minview(self):
        self.showNormal()
        return True

    def save(self):
        print(' "save" function not implemented')
        print(' --> should be implemented in child class !')

    ###########################################
    ################ Widget tools #############
    ###########################################

    def init_basic_widget_grid(self,
                               wdgt_length=3,
                               Ncol_wdgt=20,
                               Nrow_wdgt=20):

        self.i_wdgt = 0 # initialize widget counter

        self.wdgt_length = wdgt_length

        self.cwidget = QtWidgets.QWidget(self)
        self.setCentralWidget(self.cwidget)

        # grid layout
        self.layout = QtWidgets.QGridLayout()
        self.cwidget.setLayout(self.layout)

        self.graphics_layout = pg.GraphicsLayoutWidget()
        self.layout.addWidget(self.graphics_layout, 0, self.wdgt_length,
                              Nrow_wdgt, Ncol_wdgt)

    def add_widget(self, wdgt, spec='None'):
        if 'small' in spec:
            wdgt.setFixedWidth(70)

        # if spec=='shift-right':
        #     self.layout.addWidget(wdgt, self.i_wdgt-1, self.wdgt_length,
        #                           1, self.wdgt_length+1)
        if spec=='small-left':
            self.layout.addWidget(wdgt, self.i_wdgt, 0, 1, 1)
        elif spec=='small-middle':
            self.layout.addWidget(wdgt, self.i_wdgt, 1, 1, 1)
        elif spec=='large-left':
            self.layout.addWidget(wdgt, self.i_wdgt, 0, 1, self.wdgt_length-1)
        elif spec=='small-right':
            self.layout.addWidget(wdgt, self.i_wdgt, self.wdgt_length-1, 1, 1)
            self.i_wdgt += 1
        elif spec=='large-right':
            self.layout.addWidget(wdgt, self.i_wdgt, 1, 1, self.wdgt_length-1)
            self.i_wdgt += 1
        else:
            self.layout.addWidget(wdgt, self.i_wdgt, 0, 1, self.wdgt_length)
            self.i_wdgt += 1

    ###########################################
    ########## Data-specific tools ############
    ###########################################

    def select_ROI_from_pick(self, data):

        if self.roiPick.text() in ['sum', 'all']:
            roiIndices = np.arange(data.nROIs)

        elif len(self.roiPick.text().split('-'))>1:
            try:
                roiIndices = np.arange(int(self.roiPick.text().split('-')[0]), int(self.roiPick.text().split('-')[1]))
            except BaseException as be:
                print(be)
                roiIndices = None

        elif len(self.roiPick.text().split(','))>1:
            try:
                roiIndices = np.array([int(ii) for ii in self.roiPick.text().split(',')])
            except BaseException as be:
                print(be)
                roiIndices = None
        else:
            try:
                i0 = int(self.roiPick.text())
                if (i0<0) or (i0>=data.nROIs):
                    roiIndices = [0]
                    self.statusBar.showMessage(' "%i" not a valid ROI index, roiIndices set to [0]'  % i0)
                else:
                    roiIndices = [i0]

            except BaseException as be:
                print(be)
                roiIndices = [0]
                self.statusBar.showMessage(' /!\ Problem in setting indices /!\ ')

        return roiIndices

    def keyword_update(self, string=None, parent=None):

        if string is None:
            string = self.guiKeywords.text()

        cls = (parent if parent is not None else self)

        if string in ['Stim', 'stim', 'VisualStim', 'Stimulation', 'stimulation']:
            cls.load_VisualStim()
        elif string in ['no_stim', 'no_VisualStim']:
            cls.visual_stim = None
        elif string in ['scan_folder', 'scanF', 'scan']:
            cls.scan_folder()
        elif string in ['meanImg', 'meanImg_chan2', 'meanImgE', 'Vcorr', 'max_proj']:
            cls.CaImaging_bg_key = string
        elif 'plane' in string:
            cls.planeID = int(string.split('plane')[1])
        elif string=='no_subsampling':
            cls.no_subsampling = True
        elif string in ['F', 'Fluorescence', 'Neuropil', 'Deconvolved', 'Fneu', 'dF/F', 'dFoF'] or ('F-' in string):
            if string=='F':
                cls.CaImaging_key = 'Fluorescence'
            elif string=='Fneu':
                cls.CaImaging_key = 'Neuropil'
            else:
                cls.CaImaging_key = string
        elif string=='subsampling':
            cls.no_subsampling = False
        elif string=='subjects':
            cls.compute_subjects()
        else:
            self.statusBar.showMessage('  /!\ keyword "%s" not recognized /!\ ' % string)

    # Layout11 = QtWidgets.QVBoxLayout()
    # Layout1.addLayout(Layout11)
    # create_calendar(self, Layout11)
    # self.notes = QtWidgets.QLabel(63*'-'+5*'\n', self)
    # self.notes.setMinimumHeight(70)
    # self.notes.setMaximumHeight(70)
    # Layout11.addWidget(self.notes)

    # self.pbox = QtWidgets.QComboBox(self)
    # self.pbox.activated.connect(self.display_quantities)
    # self.pbox.setMaximumHeight(selector_height)
    # if self.raw_data_visualization:
    #     self.pbox.addItem('')
    #     self.pbox.addItem('-> Show Raw Data')
    #     self.pbox.setCurrentIndex(1)

#     def __init__(self, parent=None,
#                  fullscreen=False):

#         super(TrialAverageWindow, self).__init__()

#         # adding a "quit" keyboard shortcut
#         self.quitSc = QtWidgets.QShortcut(QtGui.QKeySequence('Q'), self) # or 'Q'
#         self.quitSc.activated.connect(self.close)
#         self.refreshSc = QtWidgets.QShortcut(QtGui.QKeySequence('R'), self) # or 'Q'
#         self.refreshSc.activated.connect(self.refresh)
#         self.maxSc = QtWidgets.QShortcut(QtGui.QKeySequence('M'), self)
#         self.maxSc.activated.connect(self.showwindow)

#         ####################################################
#         # BASIC style config
#         self.setWindowTitle('Analysis Program -- Physiology of Visual Circuits')

#     def close(self):
#         pass

class Slider(QtWidgets.QSlider):
    def __init__(self, bid, parent=None):
        super(self.__class__, self).__init__()
        self.bid = bid
        self.setOrientation(QtCore.Qt.Horizontal)
        self.setMinimum(0)
        self.setMaximum(255)
        self.setValue(255)
        self.setTickInterval(1)
        self.valueChanged.connect(lambda: self.level_change(parent,bid))
        self.setTracking(False)

    def level_change(self, parent, bid):
        parent.saturation = float(self.value())
        if parent.ROI is not None:
            parent.ROI.plot(parent)
        parent.win.show()

# ### custom QDialog which makes a list of items you can include/exclude
# class ListChooser(QtWidgets.QDialog):
#     def __init__(self, title, parent):
#         super(ListChooser, self).__init__(parent)
#         self.setGeometry(300,300,320,200)
#         self.setWindowTitle(title)
#         self.win = QtWidgets.QWidget(self)
#         layout = QtWidgets.QGridLayout()
#         self.win.setLayout(layout)
#         #self.setCentralWidget(self.win)
#         layout.addWidget(QtWidgets.QLabel('click to select videos (none selected => all used)'),0,0,1,1)
#         self.list = QtWidgets.QListWidget(parent)
#         for f in parent.filelist:
#             self.list.addItem(f)
#         layout.addWidget(self.list,1,0,7,4)
#         #self.list.resize(450,250)
#         self.list.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)
#         done = QtGui.QPushButton('done')
#         done.clicked.connect(lambda: self.exit_list(parent))
#         layout.addWidget(done,8,0,1,1)

#     def exit_list(self, parent):
#         parent.filelist = []
#         items = self.list.selectedItems()
#         for i in range(len(items)):
#             parent.filelist.append(str(self.list.selectedItems()[i].text()))
#         self.accept()

# class TextChooser(QtWidgets.QDialog):
#     def __init__(self,parent=None):
#         super(TextChooser, self).__init__(parent)
#         self.setGeometry(300,300,350,100)
#         self.setWindowTitle('folder path')
#         self.win = QtWidgets.QWidget(self)
#         layout = QtWidgets.QGridLayout()
#         self.win.setLayout(layout)
#         self.qedit = QtWidgets.QLineEdit('')
#         layout.addWidget(QtWidgets.QLabel('folder name (does not have to exist yet)'),0,0,1,3)
#         layout.addWidget(self.qedit,1,0,1,3)
#         done = QtGui.QPushButton('OK')
#         done.clicked.connect(self.exit)
#         layout.addWidget(done,2,1,1,1)

#     def exit(self):
#         self.folder = self.qedit.text()
#         self.accept()

# class RGBRadioButtons(QtGui.QButtonGroup):
#     def __init__(self, parent=None, row=0, col=0):
#         super(RGBRadioButtons, self).__init__()
#         parent.color = 0
#         self.parent = parent
#         self.bstr = ["image", "flowsX", "flowsY", "flowsZ", "cellprob"]
#         #self.buttons = QtGui.QButtonGroup()
#         self.dropdown = []
#         for b in range(len(self.bstr)):
#             button = QtGui.QRadioButton(self.bstr[b])
#             button.setStyleSheet('color: white;')
#             if b==0:
#                 button.setChecked(True)
#             self.addButton(button, b)
#             button.toggled.connect(lambda: self.btnpress(parent))
#             self.parent.l0.addWidget(button, row+b,col,1,1)
#         self.setExclusive(True)
#         #self.buttons.

#     def btnpress(self, parent):
#        b = self.checkedId()
#        self.parent.view = b
#        if self.parent.loaded:
#            self.parent.update_plot()

# class ViewBoxNoRightDrag(pg.ViewBox):
#     def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True, invertY=False, enableMenu=True, name=None, invertX=False):
#         pg.ViewBox.__init__(self, parent, border, lockAspect, enableMouse,
#                             invertY, enableMenu, name, invertX)

#     def mouseDragEvent(self, ev, axis=None):
#         ## if axis is specified, event will only affect that axis.
#         ev.accept()  ## we accept all buttons

#         pos = ev.pos()
#         lastPos = ev.lastPos()
#         dif = pos - lastPos
#         dif = dif * -1

#         ## Ignore axes if mouse is disabled
#         mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
#         mask = mouseEnabled.copy()
#         if axis is not None:
#             mask[1-axis] = 0.0

#         ## Scale or translate based on mouse button
#         if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):
#             if self.state['mouseMode'] == pg.ViewBox.RectMode:
#                 if ev.isFinish():  ## This is the final move in the drag; change the view scale now
#                     #print "finish"
#                     self.rbScaleBox.hide()
#                     ax = QtCore.QRectF(Point(ev.buttonDownPos(ev.button())), Point(pos))
#                     ax = self.childGroup.mapRectFromParent(ax)
#                     self.showAxRect(ax)
#                     self.axHistoryPointer += 1
#                     self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax]
#                 else:
#                     ## update shape of scale box
#                     self.updateScaleBox(ev.buttonDownPos(), ev.pos())
#             else:
#                 tr = dif*mask
#                 tr = self.mapToView(tr) - self.mapToView(Point(0,0))
#                 x = tr.x() if mask[0] == 1 else None
#                 y = tr.y() if mask[1] == 1 else None

#                 self._resetTarget()
#                 if x is not None or y is not None:
#                     self.translateBy(x=x, y=y)
#                 self.sigRangeChangedManually.emit(self.state['mouseEnabled'])

# class ImageDraw(pg.ImageItem):
#     """
#     **Bases:** :class:`GraphicsObject <pyqtgraph.GraphicsObject>`
#     GraphicsObject displaying an image. Optimized for rapid update (ie video display).
#     This item displays either a 2D numpy array (height, width) or
#     a 3D array (height, width, RGBa). This array is optionally scaled (see
#     :func:`setLevels <pyqtgraph.ImageItem.setLevels>`) and/or colored
#     with a lookup table (see :func:`setLookupTable <pyqtgraph.ImageItem.setLookupTable>`)
#     before being displayed.
#     ImageItem is frequently used in conjunction with
#     :class:`HistogramLUTItem <pyqtgraph.HistogramLUTItem>` or
#     :class:`HistogramLUTWidget <pyqtgraph.HistogramLUTWidget>` to provide a GUI
#     for controlling the levels and lookup table used to display the image.
#     """

#     sigImageChanged = QtCore.Signal()

#     def __init__(self, image=None, viewbox=None, parent=None, **kargs):
#         super(ImageDraw, self).__init__()
#         #self.image=None
#         #self.viewbox=viewbox
#         self.levels = np.array([0,255])
#         self.lut = None
#         self.autoDownsample = False
#         self.axisOrder = 'row-major'
#         self.removable = False

#         self.parent = parent
#         #kernel[1,1] = 1
#         self.setDrawKernel(kernel_size=self.parent.brush_size)
#         self.parent.current_stroke = []
#         self.parent.in_stroke = False

#     def mouseClickEvent(self, ev):
#         if self.parent.masksOn:
#             if ev.button()==QtCore.Qt.RightButton and self.parent.loaded and self.parent.nmasks < 2:
#                 if not self.parent.in_stroke:
#                     ev.accept()
#                     self.parent.in_stroke = True
#                     self.create_start(ev.pos())
#                     self.parent.stroke_appended = False
#                     self.drawAt(ev.pos(), ev)
#                 else:
#                     ev.accept()
#                     self.end_stroke()
#                     self.parent.in_stroke = False
#             else:
#                 ev.ignore()
#                 return
#         else:
#             ev.ignore()
#             return

#     def mouseDragEvent(self, ev):
#         ev.ignore()
#         return

#     def hoverEvent(self, ev):
#         QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.CrossCursor)
#         if self.parent.in_stroke:
#             if self.parent.in_stroke:
#                 # continue stroke if not at start
#                 self.drawAt(ev.pos())
#                 if self.is_at_start(ev.pos()):
#                     self.end_stroke()
#                     self.parent.in_stroke = False
#         else:
#             ev.acceptClicks(QtCore.Qt.RightButton)
#             #ev.acceptClicks(QtCore.Qt.LeftButton)

#     def create_start(self, pos):
#         self.scatter = pg.ScatterPlotItem([pos.x()], [pos.y()], pxMode=False,
#                                         pen=pg.mkPen(color=(255,0,0), width=self.parent.brush_size),
#                                         size=max(3*2, self.parent.brush_size*1.8*2), brush=None)
#         self.parent.p0.addItem(self.scatter)

#     def is_at_start(self, pos):
#         thresh_out = max(6, self.parent.brush_size*3)
#         thresh_in = max(3, self.parent.brush_size*1.8)
#         # first check if you ever left the start
#         if len(self.parent.current_stroke) > 3:
#             stroke = np.array(self.parent.current_stroke)
#             dist = (((stroke[1:] - stroke[:1][np.newaxis,:,:])**2).sum(axis=-1))**0.5
#             dist = dist.flatten()
#             #print(dist)
#             has_left = (dist > thresh_out).nonzero()[0]
#             if len(has_left) > 0:
#                 first_left = np.sort(has_left)[0]
#                 has_returned = (dist[max(4,first_left+1):] < thresh_in).sum()
#                 if has_returned > 0:
#                     return True
#                 else:
#                     return False
#             else:
#                 return False

#     def end_stroke(self):
#         self.parent.p0.removeItem(self.scatter)
#         if not self.parent.stroke_appended:
#             self.parent.stroke = np.array(self.parent.current_stroke)
#             self.parent.current_stroke = []
#             self.parent.stroke_appended = True
#             ioutline = self.parent.stroke[:,-1]==1
#             self.parent.point_set = list(self.parent.stroke[ioutline])
#             self.parent.add_set()

#     def tabletEvent(self, ev):
#         pass
#         #print(ev.device())
#         #print(ev.pointerType())
#         #print(ev.pressure())

#     def drawAt(self, pos, ev=None):
#         mask = self.greenmask
#         set = self.parent.current_point_set
#         stroke = self.parent.current_stroke
#         pos = [int(pos.y()), int(pos.x())]
#         dk = self.drawKernel
#         kc = self.drawKernelCenter
#         sx = [0,dk.shape[0]]
#         sy = [0,dk.shape[1]]
#         tx = [pos[0] - kc[0], pos[0] - kc[0]+ dk.shape[0]]
#         ty = [pos[1] - kc[1], pos[1] - kc[1]+ dk.shape[1]]
#         kcent = kc.copy()
#         if tx[0]<=0:
#             sx[0] = 0
#             sx[1] = kc[0] + 1
#             tx    = sx
#             kcent[0] = 0
#         if ty[0]<=0:
#             sy[0] = 0
#             sy[1] = kc[1] + 1
#             ty    = sy
#             kcent[1] = 0
#         if tx[1] >= self.parent.Ly-1:
#             sx[0] = dk.shape[0] - kc[0] - 1
#             sx[1] = dk.shape[0]
#             tx[0] = self.parent.Ly - kc[0] - 1
#             tx[1] = self.parent.Ly
#             kcent[0] = tx[1]-tx[0]-1
#         if ty[1] >= self.parent.Lx-1:
#             sy[0] = dk.shape[1] - kc[1] - 1
#             sy[1] = dk.shape[1]
#             ty[0] = self.parent.Lx - kc[1] - 1
#             ty[1] = self.parent.Lx
#             kcent[1] = ty[1]-ty[0]-1

#         ts = (slice(tx[0],tx[1]), slice(ty[0],ty[1]))
#         ss = (slice(sx[0],sx[1]), slice(sy[0],sy[1]))
#         self.image[ts] = mask[ss]

#         for ky,y in enumerate(np.arange(ty[0], ty[1], 1, int)):
#             for kx,x in enumerate(np.arange(tx[0], tx[1], 1, int)):
#                 iscent = np.logical_and(kx==kcent[0], ky==kcent[1])
#                 stroke.append([x, y, iscent])
#         self.updateImage()

#     def setDrawKernel(self, kernel_size=3):
#         bs = kernel_size
#         kernel = np.ones((bs,bs), np.uint8)
#         self.drawKernel = kernel
#         self.drawKernelCenter = [int(np.floor(kernel.shape[0]/2)),
#                                  int(np.floor(kernel.shape[1]/2))]
#         onmask = 255 * kernel[:,:,np.newaxis]
#         offmask = np.zeros((bs,bs,1))
#         opamask = 100 * kernel[:,:,np.newaxis]
#         self.redmask = np.concatenate((onmask,offmask,offmask,onmask), axis=-1)
#         self.greenmask = np.concatenate((onmask,offmask,onmask,opamask), axis=-1)

# class RangeSlider(QtWidgets.QSlider):
#     """ A slider for ranges.

#         This class provides a dual-slider for ranges, where there is a defined
#         maximum and minimum, as is a normal slider, but instead of having a
#         single slider value, there are 2 slider values.

#         This class emits the same signals as the QSlider base class, with the
#         exception of valueChanged

#         Found this slider here: https://www.mail-archive.com/pyqt@riverbankcomputing.com/msg22889.html
#         and modified it
#     """
#     def __init__(self, parent=None, *args):
#         super(RangeSlider, self).__init__(*args)

#         self._low = self.minimum()
#         self._high = self.maximum()

#         self.pressed_control = QtGui.QStyle.SC_None
#         self.hover_control = QtGui.QStyle.SC_None
#         self.click_offset = 0

#         self.setOrientation(QtCore.Qt.Vertical)
#         self.setTickPosition(QtWidgets.QSlider.TicksRight)
#         self.setStyleSheet(\
#                 "QSlider::handle:horizontal {\
#                 background-color: white;\
#                 border: 1px solid #5c5c5c;\
#                 border-radius: 0px;\
#                 border-color: black;\
#                 height: 8px;\
#                 width: 6px;\
#                 margin: -8px 2; \
#                 }")

#         #self.opt = QtGui.QStyleOptionSlider()
#         #self.opt.orientation=QtCore.Qt.Vertical
#         #self.initStyleOption(self.opt)
#         # 0 for the low, 1 for the high, -1 for both
#         self.active_slider = 0
#         self.parent = parent

#     def level_change(self):
#         if self.parent is not None:
#             if self.parent.loaded:
#                 self.parent.saturation = [self._low, self._high]
#                 self.parent.update_plot()

#     def low(self):
#         return self._low

#     def setLow(self, low):
#         self._low = low
#         self.update()

#     def high(self):
#         return self._high

#     def setHigh(self, high):
#         self._high = high
#         self.update()

#     def paintEvent(self, event):
#         # based on http://qt.gitorious.org/qt/qt/blobs/master/src/gui/widgets/qslider.cpp
#         painter = QtGui.QPainter(self)
#         style = QtGui.QApplication.style()

#         for i, value in enumerate([self._low, self._high]):
#             opt = QtGui.QStyleOptionSlider()
#             self.initStyleOption(opt)

#             # Only draw the groove for the first slider so it doesn't get drawn
#             # on top of the existing ones every time
#             if i == 0:
#                 opt.subControls = QtGui.QStyle.SC_SliderHandle#QtGui.QStyle.SC_SliderGroove | QtGui.QStyle.SC_SliderHandle
#             else:
#                 opt.subControls = QtGui.QStyle.SC_SliderHandle

#             if self.tickPosition() != self.NoTicks:
#                 opt.subControls |= QtGui.QStyle.SC_SliderTickmarks

#             if self.pressed_control:
#                 opt.activeSubControls = self.pressed_control
#                 opt.state |= QtGui.QStyle.State_Sunken
#             else:
#                 opt.activeSubControls = self.hover_control

#             opt.sliderPosition = value
#             opt.sliderValue = value
#             style.drawComplexControl(QtGui.QStyle.CC_Slider, opt, painter, self)

#     def mousePressEvent(self, event):
#         event.accept()

#         style = QtGui.QApplication.style()
#         button = event.button()
#         # In a normal slider control, when the user clicks on a point in the
#         # slider's total range, but not on the slider part of the control the
#         # control would jump the slider value to where the user clicked.
#         # For this control, clicks which are not direct hits will slide both
#         # slider parts
#         if button:
#             opt = QtGui.QStyleOptionSlider()
#             self.initStyleOption(opt)

#             self.active_slider = -1

#             for i, value in enumerate([self._low, self._high]):
#                 opt.sliderPosition = value
#                 hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(), self)
#                 if hit == style.SC_SliderHandle:
#                     self.active_slider = i
#                     self.pressed_control = hit

#                     self.triggerAction(self.SliderMove)
#                     self.setRepeatAction(self.SliderNoAction)
#                     self.setSliderDown(True)

#                     break

#             if self.active_slider < 0:
#                 self.pressed_control = QtGui.QStyle.SC_SliderHandle
#                 self.click_offset = self.__pixelPosToRangeValue(self.__pick(event.pos()))
#                 self.triggerAction(self.SliderMove)
#                 self.setRepeatAction(self.SliderNoAction)
#         else:
#             event.ignore()

#     def mouseMoveEvent(self, event):
#         if self.pressed_control != QtGui.QStyle.SC_SliderHandle:
#             event.ignore()
#             return

#         event.accept()
#         new_pos = self.__pixelPosToRangeValue(self.__pick(event.pos()))
#         opt = QtGui.QStyleOptionSlider()
#         self.initStyleOption(opt)

#         if self.active_slider < 0:
#             offset = new_pos - self.click_offset
#             self._high += offset
#             self._low += offset
#             if self._low < self.minimum():
#                 diff = self.minimum() - self._low
#                 self._low += diff
#                 self._high += diff
#             if self._high > self.maximum():
#                 diff = self.maximum() - self._high
#                 self._low += diff
#                 self._high += diff
#         elif self.active_slider == 0:
#             if new_pos >= self._high:
#                 new_pos = self._high - 1
#             self._low = new_pos
#         else:
#             if new_pos <= self._low:
#                 new_pos = self._low + 1
#             self._high = new_pos

#         self.click_offset = new_pos
#         self.update()

#     def mouseReleaseEvent(self, event):
#         self.level_change()

#     def __pick(self, pt):
#         if self.orientation() == QtCore.Qt.Horizontal:
#             return pt.x()
#         else:
#             return pt.y()

#     def __pixelPosToRangeValue(self, pos):
#         opt = QtGui.QStyleOptionSlider()
#         self.initStyleOption(opt)
#         style = QtGui.QApplication.style()

#         gr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderGroove, self)
#         sr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderHandle, self)

#         if self.orientation() == QtCore.Qt.Horizontal:
#             slider_length = sr.width()
#             slider_min = gr.x()
#             slider_max = gr.right() - slider_length + 1
#         else:
#             slider_length = sr.height()
#             slider_min = gr.y()
#             slider_max = gr.bottom() - slider_length + 1

#         return style.sliderValueFromPosition(self.minimum(), self.maximum(),
#                                              pos-slider_min, slider_max-slider_min,
#                                              opt.upsideDown)

# if __name__=='__main__':

#     # app = QtWidgets.QApplication(sys.argv)
#     # # build_dark_palette(app)
#     # # window = TrialAverageWindow(app)
#     # # window.show()
#     # sys.exit(app.exec_())


import numpy as np
import numpy.testing as npt

from mypo import Market, Runner, Settings

def test_run_and_report() -> None:
    market = Market.create(start_date="2021-01-01", end_date="2021-12-31", yearly_gain=0.00)

    runner = Runner()
    runner.run(assets=[0], market=market, cash=0.5, withdraw=0.05)
    df = runner.report().history()
    assert not df.isnull().to_numpy().any()
    npt.assert_almost_equal(0.5 - df["total_assets"].min(), 0.05)
    npt.assert_almost_equal(df["capital_gain"].sum(), 0)
    npt.assert_almost_equal(df["income_gain"].sum(), 0)
    npt.assert_almost_equal(df["deal"].sum(), 0)
    npt.assert_almost_equal(df["fee"].sum(), 0)

def test_run_and_report_run_out_cash() -> None:
    market = Market.create(start_date="2021-01-01", end_date="2021-12-31", yearly_gain=0.00)

    runner = Runner(
        settings=Settings(tax_rate=np.float64(0.0), fee_rate=np.float64(0.0)),
    )
    runner.run(assets=[0.6], market=market, cash=0.6, withdraw=1.2)
    report = runner.report()
    assert report.summary() is not None
    assert report.history_weights() is not None
    assert report.history_cost() is not None
    assert report.history_assets() is not None
    assert report.history_cash_vs_assets() is not None

def test_run_and_report_annual() -> None:
    market = Market.create(start_date="2021-01-01", end_date="2023-12-31", yearly_gain=0.01)

    runner = Runner(
        settings=Settings(tax_rate=np.float64(0.0), fee_rate=np.float64(0.0)),
    )
    runner.run(assets=[1.0], market=market, cash=0.0, withdraw=0)
    report = runner.report()
    assert report.annual_summary() is not None


import sys
# sys.stdin = open("input.txt", "r")

n, k = map(int, input().split())
lst = list(map(int, input().split()))
ch = [0 for _ in range(n+2)]
ans = 'YES'
room = [0]

for x in lst:
    room.sort(reverse=True)
    for i in range(len(room)):
        if room[i] < x:
            room[i] = x
            break
    else:
        room.append(x)
        if len(room) > k:
            ans = 'NO'
            break

print(ans)


import logging
import uuid

from aiokafka import AIOKafkaProducer
from aiokafka.errors import KafkaError
from fastapi import APIRouter, Depends

from models.progress import MovieWatchProgress, MovieWatchProgressReq, ProgressModel
from services.content_service import MovieContentService, get_movie_content_svc
from utils.auth import get_current_user
from utils.kafka.producer import get_producer

API_VERSION_MAJOR = 0
API_VERSION_MINOR = 1
API_VERSION_PATH = 0

API_VERSION = f'{API_VERSION_MAJOR}.{API_VERSION_MINOR}.{API_VERSION_PATH}'

router = APIRouter()

@router.post('/progress/')
async def track_progress(
    progress: MovieWatchProgressReq,
    producer: AIOKafkaProducer = Depends(get_producer),
    user_id: str = Depends(get_current_user),
):
    progress_dto = MovieWatchProgress(**progress.dict(), user_id=user_id)

    try:
        await producer.send_and_wait(
            topic='watch_progress',
            key=f'{user_id}:{progress.movie_id}'.encode(),
            value=progress_dto.json().encode(),
        )
    except KafkaError as exc:
        logging.exception('An error occurred while sending data to Kafka: %s', exc)
    return {'message': 'Progress tracked successfully'}

@router.get('/progress/{movie_id}', response_model=ProgressModel)
async def get_progress(
    movie_id: uuid.UUID,
    movie_svc: MovieContentService = Depends(get_movie_content_svc),
    user_id: uuid.UUID = Depends(get_current_user),
):
    progress = await movie_svc.get_movie_watching_progress(user_id, movie_id)

    return ProgressModel(progress=progress or 0)


from typing import Optional

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        done = 999999
        while head is not None:
            if head.val == done:
                return True
            else:
                head.val = done
                head = head.next
        return False


import datetime
import time
import pygame
import serial

# inicialização
pygame.init()
pygame.joystick.init()
controle = pygame.joystick.Joystick(0)
controle.init()
arduino = serial.Serial("COM6", 115200)
time.sleep(2)

def formatacao(valor):
    byteint = str(round(((valor + 1) * 127)))
    return byteint

def enviararduino(mandarstr):
    arduino.write(mandarstr.encode('ascii'))

# função que recebe e processa os dados que o arduino devolve
def receberarduino():
    global inicioChar, fimChar

    ck = ""
    x = "z"  # qualquer valor que não seja iniciochar/fimchar
    bytecount = -1  # to allow for the fact that the last increment will be one too many

    # espera o inicioChar para começar a leitura
    while ord(x) != inicioChar:
        x = arduino.read()

    # salva dados até o fimChar chegar
    while ord(x) != fimChar:
        if ord(x) != inicioChar:
            ck = ck + x.decode("utf-8")
            bytecount += 1
        x = arduino.read()

    return ck

def esperararduino():
    # espera que o arduino mande "arduino esta pronto" -- dá tempo para que ele reinicie após a conexão serial
    # também garante que qualquer byte previamente armazenado seja apagado

    global inicioChar, fimChar

    msg = ""
    while msg.find("Arduino esta pronto") == -1:

        while arduino.inWaiting() == 0:
            pass

        msg = receberarduino()

        print(msg)  # python3 requires parenthesis
        print()

def testar(td):
    numloops = len(td)
    aguardandoresposta = False

    n = 0
    while n < numloops:
        teststr = td[n]

        if aguardandoresposta is False:
            enviararduino(teststr)
            print("Enviado pelo PC, teste #" + str(n) + ", valor enviado: " + teststr)
            aguardandoresposta = True

        if aguardandoresposta is True:

            while arduino.inWaiting() == 0:
                pass

            dadosrecebidos = receberarduino()
            print("Resposta recebida: " + dadosrecebidos)
            n += 1
            aguardandoresposta = False
        print("")

def enviarinfo(info):
    numloops = len(info)

    n = 0
    if n < numloops:
        informacaoaenviar = info[n]
        enviararduino(informacaoaenviar)
        print("Enviado pelo PC, teste #" + str(n) + ", valor enviado: " + informacaoaenviar)
        print("")

# variaveis e configs
rodar = True
white = (255, 255, 255)
fundo = pygame.image.load("fundo.png")
fundo = pygame.transform.scale(fundo, (1200, 440))
fonte = pygame.font.Font("secretcode.ttf", 32)
fonte2 = pygame.font.Font("calibri.ttf", 18)
tela = pygame.display.set_mode((1200, 440))
pygame.display.set_caption("ControlDashPy")
inicioChar = 60
fimChar = 62
t = 0
rafinha = 0

print("Porta Serial COM5" + " aberta com Baudrate " + str(115200))
esperararduino()

while rodar:
    pygame.event.pump()  # atualiza os valores do joystick
    data = datetime.datetime.now()
    mes = data.strftime("%m")
    hora = data.strftime("%H")  # atualiza as variáveis
    dia = data.strftime("%d")
    minuto = data.strftime("%M")
    diames = fonte2.render(dia + "/" + mes, True, white)
    horamin = fonte2.render(hora + ":" + minuto, True, white)
    left_x = controle.get_axis(0)
    left_y = controle.get_axis(1)
    right_x = controle.get_axis(4)  # define o nome dos eixos do controle
    right_y = controle.get_axis(3)
    gatilho = controle.get_axis(2)
    botaoA = controle.get_button(0)
    botaoB = controle.get_button(1)
    botaoX = controle.get_button(2)
    botaoY = controle.get_button(3)
    botaoLb = controle.get_button(4)
    botaoRb = controle.get_button(5)
    botaoBack = controle.get_button(6)
    botaoStart = controle.get_button(7)
    xhat, yhat = controle.get_hat(0)
    if xhat == 1:
        dX = 1
        ndX = 0
    elif xhat == -1:
        ndX = 1
        dX = 0
    else:
        dX = 0
        ndX = 0
    if yhat == 1:
        dY = 1
        ndY = 0
    elif yhat == -1:
        ndY = 1
        dY = 0
    else:
        dY = 0
        ndY = 0

    dados = ["<R, " + formatacao(left_x) + ", " + formatacao(gatilho) + ">"]

    if t >= 5:
        enviarinfo(dados)
        t = 0
        rafinha += 1
        print(rafinha)
    if t < 5:
        t += 1
    if gatilho > 0:
        gatilhocor = (102, 255, 51)
    else:
        gatilhocor = (255, 96, 31)

    valorpainelacc = gatilho * 350
    valorpainelservo = left_x * 190
    if valorpainelacc > 0:
        valorpainelacc = valorpainelacc * -1
    tela.fill((40, 40, 40))
    pygame.draw.rect(tela, gatilhocor, (400, 400, 400, valorpainelacc))
    pygame.draw.rect(tela, (255, 96, 31), (585, 410, valorpainelservo, 20))
    tela.blit(fundo, (0, 0))
    tela.blit(diames, (140, 40))
    tela.blit(horamin, (290, 40))

    pygame.display.update()


#!/usr/bin/python3
'''Module contains a class called square'''

class Square:
    '''Square class with size and psotion attribute and 2 methods'''

    def __init__(self, size=0, position=(0, 0)):
        '''Initialises size and position of square'''
        self.__size = size
        self.__position = position

    @property
    def size(self):
        '''Gets the size of the square

        @size.setter:
            value: ensures that the value entered is an int and is > 0
        '''
        return self.__size

    @size.setter
    def size(self, value):
        if type(value) is not int:
            raise TypeError('size must be an integer')
        elif value < 0:
            raise ValueError('size must be >= 0')
        else:
            self.__size = value

    @property
    def position(self):
        '''position: tuple of two positive integers

        @position.setter:
            value: cheks that two positive integers are entered
        '''
        return self.__position

    @position.setter
    def position(self, value):
        if type(value) is not tuple: #or len(value) != 2
            raise TypeError('position must be a tuple of 2 positive integers')
        elif len(value) != 2:
            raise TypeError('position must be a tuple of 2 positive integers')
        elif type(value[0]) is not int or type(value[1]) is not int:
            raise TypeError("position must be a tuple of 2 positive integers")
        elif value[0] < 0 or value[1] < 0:
            raise TypeError("position must be a tuple of 2 positive integers")
        else:
            self.__position = value

    def area(self):
        '''Calculates Area of square

        Returns:
            Area of square
        '''
        return self.__size ** 2

    def my_print(self):
        '''Method to print the square using #'''
        if self.__size == 0:
            print('')
        else:
            for i in range(self.__position[1]):
                space = ' ' * self.__position[0]
                space += ''.join('#'for j in range(self.__size))
                print('\n'.join(space for k in range(self.size)))


from random import randint, sample, uniform
from acme import Product

ADJECTIVES = ['Awesome', 'Shiny', 'Impressive', 'Portable', 'Improved']
NOUNS = ['Anvil', 'Catapult', 'Disguise', 'Mousetrap', '???']

def generate_products(num_products=30):
    products = []
    name = sample(ADJECTIVES + NOUNS, k=10)
    for i in range(30):
        products.append(name)
        return products

def inventory_report(products):
    for i in products:
        print(len(products))
        print(products)
        return

if __name__ == '__main__':
    inventory_report(generate_products())


import struct as s

def read_process_binary_file(binary_file_name):
    """
        Reads and processes a binary file according to a specific file structure.

        The binary file is expected to have a header that includes a 4 byte string ABCD,
        1 byte version, and a 4-byte integer indicating the number of records.

        Each record is expected to have a byte indicating the record type, a 4-byte
        Unix timestamp, an 8-byte user ID, and for certain record types namely cash or check, an 8-byte
        floating point number representing cash or check amount.

        This function reads the file, interprets the bytes according to this structure,
        and calculates total cash and check amounts. It also calculates the balance (checks - cashs)
        for a given user id

        Args:
            binary_file_name (str): The name of the binary file to be read and processed.

        Returns:
            total check amount: NNNN.NN
            total cash amount: NNNNN.NN
            pay started N
            pay ended N
            balance for user 123456789=N.N
    """
    user_id_to_find_check = 0.0
    user_id_to_find_cash = 0.0
    user_id_to_find_balance = 2456938384156277127
    cash_total = 0.0
    check_total = 0.0
    autopay_started = 0
    autopay_ended = 0
    with open(binary_file_name, 'rb') as f:  # opening the binary file in read mode
        binary = f.read(4)  # read and unpack the magic string as binary string
        string = binary.decode('utf-8')  # Change the binary string to UTF-8 format for string comparisons
        s.unpack('>B', f.read(1))[0]  # unpack the version
        num_records = s.unpack('>I', f.read(4))[0]  # read and unpack the number of records 'I' stands for unsigned int (uint32), 4 bytes
        if string == 'ABCD':  # Validating the magic string to ensure we are parsing the correct file format
            for _ in range(num_records):
                # read and unpack the record type [0] is used to read the first element from a one element tuple from unpack
                record_type = s.unpack('>B', f.read(1))[0]
                # read and unpack the Unix timestamp
                timestamp = s.unpack('>I', f.read(4))[0]
                # read and unpack the user ID
                user_id = s.unpack('>Q', f.read(8))[0]  # 'Q' stands for uint64 8 bytes
                # read and unpack the cost and keep track of total check or total cash if record type is cash or check and if autopay then keep track of startautopay and endautopay
                if record_type == 0x03:  # cash
                    cost = s.unpack('>d', f.read(8))[0]
                    cash_total += cost
                    if user_id == user_id_to_find_balance:  # obtaining the total check amount for user id 2456938384156277127
                        user_id_to_find_cash += cost
                elif record_type == 0x04:  # check
                    cost = s.unpack('>d', f.read(8))[0]
                    check_total += cost
                    if user_id == user_id_to_find_balance:
                        user_id_to_find_check += cost  # obtaining the total cash amount for user id 2456938384156277127
                elif record_type == 0x05:  # pay started
                    autopay_started += 1
                elif record_type == 0x06:  # pay ended
                    autopay_ended += 1
    print(f"total check amount: {check_total:.2f}")
    print(f"total cash amount: {cash_total:.2f}")
    print(f'pay started {autopay_started}')
    print(f'pay ended {autopay_ended}')
    print(f'balance for user {user_id_to_find_balance}={user_id_to_find_check - user_id_to_find_cash}')

# Call the function passing the file
read_process_binary_file('binaryfile.dat')


from tkinter import *
import tkinter
from PIL import Image, ImageTk
from tkinter import ttk

root = Tk()
root.geometry("150x200")

w = Label(root, text='GeeksForGeeks',
          font="50")

w.pack()

scroll_bar = Scrollbar(root)

scroll_bar.pack(side=RIGHT,
                fill=Y)

mylist = Listbox(root,
                 yscrollcommand=scroll_bar.set)

canvas = tkinter.Canvas(root, height=1200, width=1200)
canvas.config(scrollregion=canvas.bbox(ALL))
image = Image.open("D:\kuku.jpg")
photo = ImageTk.PhotoImage(image)
image = canvas.create_image(0, 0, anchor='nw', image=photo)
canvas.pack()

mylist.insert(END, photo)

#for line in range(1, 26):
    #mylist.insert(END, "Geeks " + str(line))

mylist.pack(side=LEFT, fill=BOTH)

scroll_bar.config(command=mylist.yview)

root.mainloop()


# This package will contain the spiders of this Scrapy project

import os
from datetime import datetime as dt
import scrapy
from redditcrawler.items import RedditItem

def get_subs_to_scrape(item):
    # pulls list of subreddits to scrape from text file

    subreddits = []

    filepath = '/Users/selenacordona/redditcrawler/redditcrawler/spiders/subreddits.txt'

        # open file and parse crawler
    with open(filepath, 'r') as f:
        for line in f.readlines():
            subreddits.append((line.strip('\n')))
    return subreddits

class PostSpider(scrapy.Spider):
    name = 'post'
    allowed_domains = ['reddit.com']

    reddit_urls = [
        'wallstreetbets',
        'stocks',
        'stock_picks',
        'stockmarket',
        'stockaday',
        'investing',
        'robinhood',
        'daytrading',
        'ValueInvesting'
    ]

    start_urls = ['https://old.reddit.com/r/' + sub + '/new/' \
        for sub in reddit_urls]

    def parse(self, response):
        # get the subreddit from the url
        subreddit = response.url.split('/')[4]

        #parse through each post
        for post in response.css('div.thing'):
            item = RedditItem()

            item['date'] = dt.today()
            item['date_str'] = item['date'].strftime('%Y-%m-%d')
            item['subreddit'] = subreddit
            item['title'] = post.css('a.title::text').extract_first()

            item['url'] = post.css('a.title::attr(href)').extract_first()
            ## if self-post, add reddit base url (as it's relative by default)
            if item['url'][:3] == '/r/':
                item['url'] = 'https://old.reddit.com' + item['url']

            item['score'] = post.css('div.unvoted::text').extract_first()
            try:
                int(item['score'])
            except:
                continue
            item['commentsUrl'] = post.css('a.comments::attr(href)').extract_first()
            item['linkFlair'] = post.css('span.linkflairlabel::text').extract_first()

            yield item


from selenium import webdriver
import time
from bs4 import BeautifulSoup
import random

# start web browse
browser = webdriver.Chrome()

# putting url into a variable
URL =("https://www.youtube.com/live_chat?is_popout=1&v=gh-IsBGAUCY")

# creating keywords
keyword1 = "hello"
keyword2 = "Hello"

# creating winners set
winners = set()

def getHTML(url):
    # get source code, opens it in chromedriver
    browser.get(url)
    time.sleep(2)
    html = browser.page_source
    return html

def parseHTML(html_source):
    # parse HTML
    return BeautifulSoup(html_source, 'html5lib')

def getMessages(soup):
    # get youtube messages
    return soup.find_all("yt-live-chat-text-message-renderer")

def updateWinners(messages):
    # updating winners
    for message in messages:
        content = message.find("div", {"id": "content"}).text
        author = message.find("span", {"id": "author-name"}).text
        message_content = message.find("span", {"id": "message"}).text
        if (keyword1 in message_content or keyword2 in message_content):
            winners.add(author)

def startDrawing(winnersList):

    print("Toplam katilimci sayisi = {}".format(len(winners)))
    time.sleep(5)

    for i in range(1,5):
        noktalar = "." * i
        print("Drawing starts!" + noktalar)
        time.sleep(1.5)

    if len(winners) != 0:
        print("AND THE WINNER IS!!!!:",random.choice(winnersList))
    else:
        print("no winner")

def main():
    for i in range(0,5):
        html_source = getHTML(URL)
        soup = parseHTML(html_source)
        messages = getMessages(soup)
        updateWinners(messages)
        print("{} amount of person has assigned to drawing."
              .format(len(winners)))
        time.sleep((10))

    winnersList = list(winners)
    startDrawing(winnersList)
    browser.close()

main()


#!/usr/bin/python
# Compile the cognate assignment result (JSON) to the LaTeX source file of correspondence pattern (Doug-style) with comparison of two different transducers
# Fixed-location files:
#   source.tsv: lexical data
# Standard input:
#   json containing:
#   langsUnderStudy: something like ['Maru', 'Old_Burmese', 'Bola']
#   oldTransducer: (Old version)
#   newTransducer: (New version)
#   board: (Board file)

## Single # = Xun Gong's notes
## Double ## = Seth Knights's notes

## Deleting lines 504-5 in the default transducer of the site leaves terms (i.e. 'forehead') where
## for changing between languages if one changes for the worse, it leaves blank the 'old' version..
## No clue at all why this happens...

## For disabling eprints that are unecessary
production = True

# Constants
language_title = {'Old_Burmese': 'OBurm', 'Achang_Longchuan': 'Acha-LC', 'Xiandao': 'Acha-XD', 'Maru': 'Maru', 'Bola': 'Bola', 'Atsi': 'Atsi', 'Lashi': 'Lashi'}
fst_index = {'Old_Burmese': 'burmese', 'Achang_Longchuan': 'ngochang', 'Xiandao': 'xiandao', 'Maru': 'maru', 'Bola': 'bola', 'Atsi': 'atsi', 'Lashi': 'lashi'}

# Basic imports
from hashlib import new
import sys
import re
import json
import csv

from numpy import equal
from merge_phonemes import merge_phonemes
from functools import reduce
from collections import Counter
from tabulate import tabulate

##### ROUTINES #####

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)
    sys.stderr.flush()

# Replace unicode diacritics with ASCII equivalents for sending to the transducers
UNICODE_MACRON_UNDER = " ̱ "[1]
UNICODE_TILDE_OVER = " ̃"[1]
def replace_diacritics(s):
    return s.replace(UNICODE_MACRON_UNDER, '_').replace(UNICODE_TILDE_OVER, '~').replace('_~', '~_')

def replace_diacritics_forward(s):
    return s.replace('_', UNICODE_MACRON_UNDER).replace('~', UNICODE_TILDE_OVER)

# Convert a piece of text to its component syllables
# If there is alrady "◦" or a space, use it to separate them
# Otherwise, separate the tone letters other letters
def syllabize(text):
    split_result = re.split(r'([ ◦¹²³⁴⁵˩˨˧˦˥]+)', text)
    l = len(split_result)

    # There are two possibilities
    # 'a◦b◦' → ['a', '◦', 'b', '◦', '']
    # 'a◦b' → ['a', '◦', 'b']
    # Both of them are odd, but should be treated differently
    # At least, everything but the last can be done in the same way
    # (5-1)/2 = 2

    result = []
    for i in range((l-1) // 2):
        result.append(split_result[i*2] + split_result[i*2+1].strip('◦ '))
    # If last non-zero, then copy to result
    if split_result[l-1]:
        result.append(split_result[l-1])

    return result

def emphasize_syllable_raw(syllables, syllable_index, usual_formatting = None, emphatic_formatting = None):
    l = len(syllables)
    result = ''
    for i in range(l):
        if i == syllable_index:
            result = result + (emphatic_formatting or '<%s>') % syllables[i]
        else:
            result = result + (usual_formatting or '%s') % syllables[i]
    return result

# emphasize_syllable("mi ma mu", 1) → "mi<ma>mu"
def emphasize_syllable(text, syllable_index, usual_formatting = None, emphatic_formatting = None):
    return emphasize_syllable_raw(syllabize(text), syllable_index, usual_formatting, emphatic_formatting)

# fetch_syllable("mi ma mu", 1) → "ma"
def fetch_syllable(text, syllable_index):
    syllables = syllabize(text)
    return syllables[syllable_index]

# Convert internal language name to printed name
def print_language_name(name):
    if name == 'Old_Burmese':
        return 'OBur.'
    else:
        return name.replace('_', r'\_')

# Compute the projected reconstruction from a bunch of syllable_id's and a certain fst
# syllable_ids: syllable_id's of the syllables in a class, as defined contra "words"
# fsts: different sets of fst
# words: given here in order not to abuse global variables
# Return values: (inferred_reconstructions, strict)
def back_reconstruct_list(syllable_ids, fsts, words):
    reconsts = {}
    at_least_one = False
    first_form = False

    for syllable_id in syllable_ids:
        word_id, _, n = syllable_id.rpartition('-')
        n = int(n)
        ipa = words[word_id]['syllables'][n]
        doculect = words[word_id]['doculect']

        if not first_form:
            first_form = ipa
        if doculect in fsts:
            the_syl = replace_diacritics(ipa)
            rec = list(fsts[doculect].apply_up(the_syl))
            if rec:
                # only record reconstructions when something *is* reconstructed
                at_least_one = True
                if doculect not in reconsts:
                    reconsts[doculect] = set(rec)
                else:
                    reconsts[doculect] = reconsts[doculect].union(set(rec))

    strict = True
    inferred_reconstructions = []

    if at_least_one:
        strict = True
        inferred_reconstructions = list(set.intersection(*reconsts.values()))

        if not inferred_reconstructions:
            strict = False
            # kinda lenient way of generating reconstructions
            # try and make intersection of every pair of doculects
            pairwise_intersections = [set.intersection(reconsts[a], reconsts[b])
                    for a in reconsts for b in reconsts if a != b]
            if pairwise_intersections:
                inferred_reconstructions = list(set.union(*pairwise_intersections))
            else:
                inferred_reconstructions = []

    return (inferred_reconstructions, strict)

##### MAIN PROGRAM #####

# eprint('Program starts')

# Compile transducers
from foma import FST
import tempfile
import os
import subprocess

def read_transducer(input_json, old_new, errors):
    ret = {}
    script_path = os.path.dirname(os.path.realpath(__file__))
    with tempfile.TemporaryDirectory() as tmpdirname:
        os.chdir(tmpdirname)
        eprint(f'Compiling FSTs ({old_new})')
        with open('transducer.foma', 'w') as fp:
            fp.write(input_json[f'{old_new}Transducer'])
        eprint("---------")
        output = subprocess.run(['foma', '-f', 'transducer.foma'],
                                capture_output=True, check=True, text=True)

        # Add errors from stderr
        if (len(output.stderr) > 0):
            for err in output.stderr.split("\n"):
                if len(err) > 0:
                    errors.append(f"Error loading {old_new} transducer: {err}")
                    eprint(err)

        # Check for errors in stdout, to be passed back to the program
        if '***' in output.stdout:
            error = f"Error loading {old_new} transducer: " + output.stdout.split('***')[1]
            eprint(error)
            errors.append(error)

        for doculect_name in fst_index:
            if os.path.isfile(fst_index[doculect_name] + '.bin'):
                ret[doculect_name] = FST.load(fst_index[doculect_name] + '.bin')
        os.chdir(script_path)
        eprint('FSTs loaded:', ', '.join(ret))
    return ret

def process_row(row):
    if row['ID'].startswith('#'):
        # internal to lingpy
        return {}

    if row['CROSSIDS']:
        crossids = row['CROSSIDS'].split(' ')
    else:
        if not production:
            eprint('SANITY: empty crossid: ', row['ID'])
        return {}

    word_id = 'word-' + row['ID']
    syllables = syllabize(row['IPA'])
    syllables_parsed = [merge_phonemes(str(sch), str(tk), 'i m r t',
                                       {'i': 'im', 'm':'m',
                                        'r':'mnNc', 't':'t'})
                        for sch, tk in zip(row['STRUCTURE'].split(' + '),
                                           row['TOKENS'].split(' + '))]

    word_json = {
            'id':word_id,
            'doculect': row['DOCULECT'],
            'syllables': syllables,
            'syllables_parsed': syllables_parsed,
            'gloss': row['CONCEPT'],
            'glossid': row['GLOSSID']}
    return {word_id: word_json}

def compare_fst(input_json):
    # decode the input JSON
    # input_json = json.load(open('input-correspondence.json', 'r+'))

    # First field from JSON: langsUnderStudy
    langs_under_study = input_json['langsUnderStudy']

    # Board from JSON
    errors = []

    fsts_old = read_transducer(input_json, 'old', errors)
    fsts_new = read_transducer(input_json, 'new', errors)

    both_missing = []
    if not all(b in fsts_new for b in langs_under_study) and not all(b in fsts_old for b in langs_under_study):
        old_missing = set(langs_under_study).difference(fsts_old)
        new_missing = set(langs_under_study).difference(fsts_new)
        eprint('Missing old FST for languages:', ', '.join(old_missing))
        eprint('Missing new FST for languages:', ', '.join(new_missing))
        both_missing = list((old_missing) & (new_missing))
        langs_under_study = [lang for lang in langs_under_study if lang not in both_missing]

    # read the word CSV
    # import fileinput
    csvreader = csv.DictReader(filter(lambda row: row.strip() and row[0]!='#', open('./lexicon.tsv', 'r')), dialect='excel-tab')

    eprint('Processing TSV rows...')
    words = {}
    for row in csvreader:
        words.update(process_row(row))

    eprint('Processing boards...')
    input_board = input_json['board']

    columns = input_board['columns']
    boards = input_board['boards']

    # list indexed by languages and initials of columns containing a certain initial in a certain language
    # column_index['i']['Old_Burmese']['p'] -> [...]
    # column_index = {}

    # column_index['i']['p:p:p'] -> [...]
    column_index = {pos:{} for pos in 'imrt'}

    for board_id in boards:
        for column_id in boards[board_id]['columnIds']:
            if not columns[column_id]['syllableIds']:
                continue

            # First, guess the reconstruction
            # print(columns, flush=True)
            print('id', column_id, flush=True)
            print('words', len(words), flush=True)
            print('words', words, flush=True)
            inferred_reconstructions, strict_reconstructions = back_reconstruct_list(columns[column_id]['syllableIds'], fsts_old, words)

            # cnt[pos][doculect] → Counter of possibilities
            cnt = {}
            sylls = {}
            senses = {}

            for syllable_id in columns[column_id]['syllableIds']:
                word_id, _, n = syllable_id.rpartition('-')
                n = int(n)

                ipa = words[word_id]['syllables'][n]
                doculect = words[word_id]['doculect']
                gloss = words[word_id]['gloss']
                syllable_parsed = words[word_id]['syllables_parsed'][n]
                syllable_fields = list(zip(syllable_parsed[0].split(' '), syllable_parsed[1].split(' ')))

                for position, sound in syllable_fields:
                    if position not in cnt:
                        cnt[position] = {}
                        sylls[position] = {}
                        senses[position] = {}
                    if doculect not in cnt[position]:
                        cnt[position][doculect] = Counter()
                        sylls[position][doculect] = {}
                        senses[position][doculect] = {}
                    if sound not in sylls[position][doculect]:
                        sylls[position][doculect][sound] = []
                        senses[position][doculect][sound] = []
                    cnt[position][doculect][sound] += 1
                    sylls[position][doculect][sound].append(ipa)
                    senses[position][doculect][sound].append(gloss)

            for position in cnt:
                # generate the information needed for displaying a corr. chart
                description = []
                most_common_ipas = []
                shared_senses = []

                # Some flags that impact display
                last_doculect_present = False
                any_non_last_doculect_present = False

                for doculect in langs_under_study:
                    if doculect in cnt[position]:
                        if doculect == langs_under_study[-1]:
                            last_doculect_present = True
                        else:
                            any_non_last_doculect_present = True

                        most_common_sound = cnt[position][doculect].most_common()[0][0]
                        most_common_ipa = Counter(sylls[position][doculect][most_common_sound]).most_common()[0][0]
                        description.append(most_common_sound)
                        most_common_ipas.append(most_common_ipa)
                        shared_senses.extend(senses[position][doculect][most_common_sound])
                    else:
                        description.append('-')
                        most_common_ipas.append('--')
                description = ':'.join(description)

                most_common_gloss = '?'
                if shared_senses:
                    most_common_gloss = Counter(shared_senses).most_common()[0][0]

                column_info = {'column_id': column_id,
                        'most_common_gloss': most_common_gloss,
                        'most_common_ipas': most_common_ipas,
                        'last_doculect_present': last_doculect_present,
                        'any_non_last_doculect_present': any_non_last_doculect_present,
                        'old_fst_reconstructions': (inferred_reconstructions, strict_reconstructions),
                        'new_fst_reconstructions': back_reconstruct_list(columns[column_id]['syllableIds'], fsts_new, words)}
                if description not in column_index[position]:
                    column_index[position][description] = []
                column_index[position][description].append(column_info)

    text = ''

    pos_name = {'i': 'Initial', 'm': 'Medial', 'r': 'Rime', 't': 'Tone'}
    json_chapters = {}

    for pos in column_index:
        text += '=====' + pos_name[pos] + ' Correspondence =====\n'
        json_chapters[pos] = []
        for description in sorted(column_index[pos]):
            if not column_index[pos][description] or not column_index[pos][description][0]['last_doculect_present'] or not column_index[pos][description][0]['any_non_last_doculect_present']:
                continue

            text += "=== %s: %s ===\n" % (pos_name[pos], description)

            this_section = {'title': "=== %s: %s ===\n" % (pos_name[pos], description)}
            rows = []

            for column in column_index[pos][description]:
                this_row = {}

                # first row: gloss & IPA's
                this_row['gloss'] = column['most_common_gloss']
                this_row['ipas'] = column['most_common_ipas']

                # second row: old reconstructions
                row = []
                inferred_reconstructions, strict_reconstructions = column['old_fst_reconstructions']
                if inferred_reconstructions:
                    rec_str = ', '.join(['*' + w for w in inferred_reconstructions])
                    if not strict_reconstructions:
                        rec_str += '?'
                    this_row['old_reconstruction'] = rec_str

                old_reconstruction_matched = False
                new_reconstruction_matched = False

                for i in range(len(langs_under_study)):
                    doculect = langs_under_study[i]
                    under_study = i == len(langs_under_study) - 1
                    rec = []
                    if doculect in fsts_old and column['most_common_ipas'][i] != '--':
                        the_syl = replace_diacritics(column['most_common_ipas'][i])
                        rec = list(set(fsts_old[doculect].apply_up(the_syl)))

                    if rec:
                        rec_strs = []
                        for w in rec:
                            if w in inferred_reconstructions:
                                rec_strs.append(r'_*' + w + '_')
                                if under_study:
                                    old_reconstruction_matched = True
                            else:
                                rec_strs.append('*' + w)
                        rec_str = ', '.join(rec_strs)
                        row.append(rec_str)
                    else:
                        row.append('')
                        if doculect in fsts_old and inferred_reconstructions and i == len(langs_under_study) - 1:
                            # forward projection for the language under study
                            fwd_recs = []
                            for w in inferred_reconstructions:
                                fwd_recs.extend(list(fsts_old[doculect].apply_down(w)))
                            fwd_recs = [replace_diacritics_forward(w) for w in set(fwd_recs)]
                            row[-1] = r'≠ †%s' % (', '.join(fwd_recs))

                this_row['old_reconstructions'] = row

                # third row: new reconstructions
                row = []
                inferred_reconstructions, strict_reconstructions = column['new_fst_reconstructions']
                if inferred_reconstructions:
                    rec_str = ', '.join(['*' + w for w in inferred_reconstructions])
                    if not strict_reconstructions:
                        rec_str += '?'
                    this_row['new_reconstruction'] = rec_str

                for i in range(len(langs_under_study)):
                    doculect = langs_under_study[i]
                    under_study = i == len(langs_under_study) - 1
                    rec = []
                    if doculect in fsts_new and column['most_common_ipas'][i] != '--':
                        the_syl = replace_diacritics(column['most_common_ipas'][i])
                        rec = list(set(fsts_new[doculect].apply_up(the_syl)))

                    if rec:
                        rec_strs = []
                        for w in rec:
                            if w in inferred_reconstructions:
                                rec_strs.append(r'_*' + w + '_')
                                if i == len(langs_under_study) - 1:
                                    new_reconstruction_matched = True
                            else:
                                rec_strs.append('*' + w)
                        rec_str = ', '.join(rec_strs)
                        row.append(rec_str)
                    else:
                        row.append('')
                        if doculect in fsts_new and inferred_reconstructions and i == len(langs_under_study) - 1:
                            # forward projection for the language under study
                            fwd_recs = []
                            for w in inferred_reconstructions:
                                fwd_recs.extend(list(fsts_new[doculect].apply_down(w)))
                            fwd_recs = [replace_diacritics_forward(w) for w in set(fwd_recs)]
                            row[-1] = r'≠ †%s' % (', '.join(fwd_recs))

                this_row['new_reconstructions'] = row

                this_row['status'] = ''
                if old_reconstruction_matched and not new_reconstruction_matched:
                    this_row['status'] = 'frowning'
                elif (not old_reconstruction_matched) and new_reconstruction_matched:
                    this_row['status'] = 'smiling'

                rows.append(this_row)

            this_section['rows'] = rows
            json_chapters[pos].append(this_section)

    eprint("Successful comparison.")
    return {'chapters': json_chapters, 'missing_transducers': both_missing, 'errors': errors}


import os
import torch.nn as nn
import torch.optim as optim
import torch.utils.data
import torchvision.datasets as dast
import torchvision.transforms as transforms
import torchvision.utils as vutils
import numpy as np
import matplotlib.pyplot as plt
from base_dcgan_model import BaseDcganGenerator, BaseDcganDiscriminator
from base_dcgan_config import *

def weights_init(m) : # 모델 함수 초기화
    classname = m.__class__.__name__
    # Conv 라는 문자열이 포함되어 있는 경우 -> 가중치 평균 0 표준편차가 0.02 인 정규 분포에서 무작위로 초기화 즉 정규분포를 따르는 난수로 가중치 초기화
    if classname.find('Conv') != -1:
        nn.init.normal_(m.weight.data, mean=0.0, std=0.02)
    # BatchNorm 문자열이 포함되어있는 경우 -> 가중치 평균 1, 표준편차가 0.02 에서 무작위로 초기화 편향 0 으로 설정
    elif classname.find('BatchNorm') != -1:
        nn.init.normal_(m.weight.data, mean=1.0, std=0.02)
        nn.init.constant_(m.bias.data, val=0)
    # 일반적인 딥러닝 모델의 초기화 단계에서 사용되는 거고 모델 학습, 수렴 속도 개선에 도움을 줍니다.

def main() :
    # transform
    data_transform = transforms.Compose([
                                   transforms.Resize(img_size),
                                   # transforms.RandAugment(),
                                   transforms.ToTensor(),
                                   transforms.Normalize((0.5, 0.5, 0.5), (0.5,0.5,0.5))
                               ])

    # dataset
    dataset = dast.ImageFolder(root=data_root, transform=data_transform)
    # GAN -> image -> custom dataset -> return image

    # dataloader
    data_loader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers)

    # data loader view
    real_batch = next(iter(data_loader))
    plt.figure(figsize=(8,8))
    plt.axis('off')
    plt.title('Training data Image view')
    plt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:64], padding=2, normalize=True).cpu(),(1,2,0)))
    plt.show()

    # train loop
    output_images_path = "./generated_images/"
    os.makedirs(output_images_path, exist_ok=True)

    # loss function
    criterion = nn.BCELoss()
    # Generator input noise
    fixed_noise = torch.randn(64, nz, 1, 1, device=device)

    # Generator model load
    netG = BaseDcganGenerator().to(device)
    # DCGAN -> mean = 0 stdev = 0.02
    netG.apply(weights_init)

    # Discriminator model load
    netD = BaseDcganDiscriminator().to(device)
    # DCGAN -> mean = 0 stdev = 0.02
    netD.apply(weights_init)

    # true false -> Discriminator
    real_label = 1.
    fake_label = 0.

    # Generator, Discriminator optimizer
    optimizerD = optim.AdamW(netD.parameters(), lr=lr, betas=(beta1, 0.999))
    optimizerG = optim.AdamW(netG.parameters(), lr=lr, betas=(beta1, 0.999))

    img_list = []
    G_losses = []
    D_losses = []
    iters = 0

    print("Starting Training Loop .... ")

    for epoch in range(num_epochs) :
        for i, data in enumerate(data_loader, 0) :
            ############################
            # (1) D 신경망을 업데이트 합니다: log(D(x)) + log(1 - D(G(z)))를 최대화 합니다
            ###########################
            netD.zero_grad() # 판별자 그래디언트 초기화 -> 배치 마다 새로운 그래디언트 계산하기 위해서

            real_gpu = data[0].to(device) # 실제 데이터를 -> GPU 혹은 CPU 올립니다.
            b_size = real_gpu.size(0) # 현재 배치의 크기 (128, 3, 64,64)
            label = torch.full((b_size,), real_label, dtype=torch.float, device=device)
            # 실제 데이터에 대한 라벨을 생성 -> 판별자 실제 혹은 가짜 인지 알려주는 역활 -> 해당 하는 예상되는 값

            output = netD(real_gpu).view(-1) # 실제 데이터 -> 판별 모델 -> 출력 (출력형태가 1차원 백터로 변환)

            loss_d = criterion(output, label) # # 판별자 출력 과 실제 데이터 간의 라벨 차이 계산
            loss_d.backward() # 역잔파 해서 가중치 업데이트 -> 잘 구별할 수 있도록 학습 유도

            D_x = output.mean().item()

            # fack images
            noise = torch.randn(b_size, nz, 1, 1, device=device)
            fake_images = netG(noise)
            label.fill_(fake_label)

            # D를 이용해 데이터의 진위를 판별합니다
            output = netD(fake_images.detach()).view(-1)

            # D loss
            loss_d_fake = criterion(output, label)
            loss_d_fake.backward()

            D_G_z1 = output.mean().item()

            errD = loss_d + loss_d_fake
            optimizerD.step()

            ############################
            # (2) G 신경망을 업데이트 합니다: log(D(G(z)))를 최대화 합니다
            ###########################
            netG.zero_grad()
            label.fill_(real_label)  # 생성자의 손실값을 구하기 위해 진짜 라벨을 이용할 겁니다
            # 우리는 방금 D를 업데이트했기 때문에, D에 다시 가짜 데이터를 통과시킵니다.
            # 이때 G는 업데이트되지 않았지만, D가 업데이트 되었기 때문에 앞선 손실값가 다른 값이 나오게 됩니다
            output = netD(fake_images).view(-1)

            # G loss
            loss_g = criterion(output, label)

            loss_g.backward()
            D_G_z2 = output.mean().item()

            optimizerG.step()

            # 훈련 상태를 출력합니다
            if i % 50 == 0:
                print('[%d/%d][%d/%d]\tLoss_D: %.4f\tLoss_G: %.4f\tD(x): %.4f\tD(G(z)): %.4f / %.4f'
                      % (epoch, num_epochs, i, len(data_loader),
                         errD.item(), loss_g.item(), D_x, D_G_z1, D_G_z2))

            G_losses.append(loss_g.item())
            D_losses.append(errD.item())

            # fixed noise -> 6 images append
            if (iters % 500 == 0 ) or ((epoch == num_epochs -1) and (i == len(data_loader)-1)) :
                with torch.no_grad() :
                    fake = netG(fixed_noise).detach().cpu()
                img_list.append(vutils.make_grid(fake, padding=2, normalize=True))

            # model save
            if epoch % 5 == 0 :
                os.makedirs("./DCGAN_model_weight/", exist_ok=True)
                torch.save(netG.state_dict(), f"./DCGAN_model_weight/netG_epoch_{epoch}.pth")
                torch.save(netD.state_dict(), f"./DCGAN_model_weight/netD_epoch_{epoch}.pth")

            # epoch 5
            if (epoch + 1) % 5 == 0:
                vutils.save_image(img_list[-1], f"{output_images_path}/fake_image_epoch_{epoch}.png")

            iters +=1

if __name__ == '__main__' :
    main()


import random

def init(start, end):
    arr = [*range(start, end)]
    answer_number = random.randint(start, len(arr))
    return arr, answer_number

def linear_search(start, end):
    arr, ans = init(start, end)
    count = 0
    for i in range(start, len(arr)):
        count += 1
        if arr[i] == ans:
            return count
    return -1

def binary_search(arr, anwser):
    found = False
    top = len(arr) - 1
    bottom = 0
    count = 0
    while bottom <= top and not found:
        guess = (top + bottom) // 2
        count += 1
        if anwser == arr[guess]:
            found = True
        elif anwser > arr[guess]:
            bottom = guess + 1
        else:
            top = guess - 1
    return count

def binary_search_recur(array, value, low=0, high=0):
    if low > high:
        return False
    mid = (low + high) // 2
    if array[mid] > value:
        return binary_search_recur(array, value, low, mid - 1)
    elif array[mid] < value:
        return binary_search_recur(array, value, mid + 1, high)
    else:
        return mid

# print(sum(binary_search([*range(0, 100)], random.randint(0, 100)) for i in range(100)) / 100)

def average(func, start, end, try_n):
    return sum(func(start, end) for i in range(try_n)) / try_n

# print(average(linear_search, 0, 100, 100))
print(binary_search_recur([*range(0, 100)], random.randint(0, 100), 0, 100))
# print(average(binary_search, 0, 100, 100))