import os
import sys
import logging
if getattr(sys,'frozen', False): #frozen exe
    PATH = os.path.dirname(sys.argv[0]) + '\\'
    logging.basicConfig(filename= os.path.dirname(sys.argv[0]) + '\concerto.log', level=logging.DEBUG)
else: #not frozen
    PATH = os.path.dirname(os.path.abspath(__file__)) + '\\'
    logging.basicConfig(filename= os.path.dirname(os.path.abspath(__file__)) + '\concerto.log', level=logging.DEBUG)
import configparser
from kivy.config import Config
from kivy.resources import resource_add_path
if hasattr(sys, '_MEIPASS'):
    resource_add_path(os.path.join(sys._MEIPASS))
os.environ["KIVY_AUDIO"] = "sdl2"
# Kivy app configs
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', False)
Config.set('graphics', 'multisamples', 0)
Config.set('graphics', 'fullscreen', 0)
Config.set('kivy', 'desktop', 1)
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Config.set('kivy', 'window_icon', 'concertoicon.ico')
Config.set(
    "kivy",
    "default_font",
    [
        "Roboto",
        'data/fonts/Roboto-Regular.ttf',
        'data/fonts/Roboto-Italic.ttf',
        'data/fonts/Roboto-Bold.ttf',
        'data/fonts/Roboto-BoldItalic.ttf'
    ],
)
Config.write()
#CCCaster ini default settings
caster_config = None
caster_opt = {
        'alertOnConnect' : '3',
        'alertWavFile' : 'SystemDefault',
        'autoCheckUpdates' : '1',
        'defaultRollback' : '4',
        'displayName' : 'Concerto Player',
        'fullCharacterName' : '0',
        'heldStartDuration' : '1.5',
        'highCpuPriority' : '0',
        'lastMainMenuPosition' : '-1',
        'lastOfflineMenuPosition' : '-1',
        'lastUsedPort' : '-1',
        'maxRealDelay' : '254',
        'replayRollbackOn' : '1',
        'updateChannel' : '1',
        'versusWinCount' : '2',
        'autoReplaySave' : '1',
        'matchmakingRegion': 'NA West'
}
if os.path.exists(PATH + 'cccaster\config.ini'):
    clean = []
    with open(PATH + 'cccaster\config.ini') as f:
        for i in f.readlines():
            for x in caster_opt:
                if x in i:
                    clean.append(x)
    for i in clean:
        try:
            del caster_opt[i]
        except KeyError:
            pass
    if len(caster_opt) != 0:
        with open(PATH + 'cccaster\config.ini','a') as f:
            for k,v in caster_opt.items():
                f.write('\n%s=%s' % (k,v))
            f.close()
    with open(PATH + 'cccaster\config.ini', 'r') as f:
            config_string = f.read()
    caster_config = configparser.ConfigParser()
    caster_config.read_string('[settings]\n' + config_string)
else:
    if os.path.isdir(PATH + 'cccaster'):
        with open(PATH + 'cccaster\config.ini', 'w') as f:
            for k,v in caster_opt.items():
                    f.write('\n%s=%s' % (k,v))
            f.close()
        with open(PATH + 'cccaster\config.ini', 'r') as f:
            config_string = f.read()
        caster_config = configparser.ConfigParser()
        caster_config.read_string('[settings]\n' + config_string)

#Concerto ini default settings
opt = [
        'netplay_port',
        'mute_alerts',
        'mute_bgm',
        'discord',
        'write_scores',
        'caster_exe',
        'bgm_track'
]
if os.path.exists(PATH + 'concerto.ini'):
    with open(PATH + 'concerto.ini') as f:
        for i in f.readlines():
            for x in opt:
                if x in i:
                    opt.remove(x)
    if len(opt) != 0:
        with open(PATH + 'concerto.ini','a') as f:
            for i in opt:
                if i == 'caster_exe':
                    f.write('\ncaster_exe=cccaster.v3.1.exe\n')
                elif i == 'bgm_track':
                    f.write('\nbgm_track=walkway\n')
                else:
                    f.write('\n%s=0\n' % i)
            f.close()
else:
    with open(PATH + 'concerto.ini', 'w') as f:
        f.write('[settings]')
        for i in opt:
            if i == 'caster_exe':
                f.write('\ncaster_exe=cccaster.v3.1.exe\n')
            elif i == 'bgm_track':
                f.write('\nbgm_track=walkway\n')
            else:
                f.write('\n%s=0\n' % i)
        f.close()
with open(PATH + 'concerto.ini','r') as f:
    config_string = f.read()
app_config = configparser.ConfigParser()
app_config.read_string(config_string)

LOBBYURL = "https://concerto-mbaacc.shib.live/l"
VERSIONURL = "https://concerto-mbaacc.shib.live/v"
CURRENT_VERSION = '1.04'
DEBUG_VERSION = 'lang-beta-1' # set to '' if not in use. This string is printed to logging to track specific test builds.
def find_img(file):
    if os.path.exists(file):
        return PATH + file
    else:
        return 'res/%s' % file

def img_credit(file,txt):
    if os.path.exists(file):
        return ''
    else:
        return txt


from __future__ import print_function
from __future__ import division
import os
from contextlib import contextmanager
import imp
import time
import subprocess
import threading
import shutil
import tempfile
import string
import random
import locale
import logging
import traceback
from .uncertain import umean
from collections import namedtuple
import itertools
import errno
import math

EVALSCRIPT = 'eval.py'
CONFIGFILE = 'accept_config.txt'
BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
OUTPUTS_DIR = os.path.join(BASEDIR, 'saved_outputs')
MAX_ERROR = 0.3
TIMEOUT_FACTOR = 3
MAX_GENERATIONS = 10  # How aggressively to apply each optimization.
PARAM_MAX = {
    'loop': 10,
    'lock': 1,
    'barrier': 1,
    'alias': 1,
    'npu_region': 1,
}
EPSILON_ERROR = 0.001
EPSILON_SPEEDUP = 0.01
BUILD_TIMEOUT = 60 * 20
FIREHOSE = 5  # Sub-debug logging level.

# Exceptions.

class UserError(Exception):
    """Raised when the user does something wrong.
    """
    def __init__(self, synopsis, detail=None):
        super(UserError, self).__init__(synopsis, detail)
        self.synopsis = synopsis
        self.detail = detail

    def __str__(self):
        return self.synopsis

    def log(self):
        out = self.synopsis
        if self.detail:
            out += '\n' + self.detail
        return out

# Utilities.

@contextmanager
def chdir(d):
    """A context manager that temporary changes the working directory.
    """
    olddir = os.getcwd()
    os.chdir(d)
    yield
    os.chdir(olddir)

def symlink_all(src, dst):
    """Recursively symlink a file or a directory's contents.
    (Directories themselves are not symlinked.
    """
    if os.path.isdir(src):
        # A directory. Create the destination directory and symlink its
        # contents.
        os.mkdir(dst)
        for fn in os.listdir(src):
            symlink_all(os.path.join(src, fn), os.path.join(dst, fn))

    else:
        # A file. Just symlink the file itself.
        os.symlink(src, dst)

@contextmanager
def sandbox(symlink=False, keep_sandbox=False):
    """Create a temporary sandbox directory, copy (or symlink)
    everything from the current directory into it, and enter the
    directory. Afterwards, change back and clean up.
    """
    sandbox_dir = tempfile.mkdtemp()

    for name in os.listdir(os.getcwd()):
        src = os.path.join(os.getcwd(), name)
        dst = os.path.join(sandbox_dir, name)
        if symlink:
            symlink_all(src, dst)
        else:
            if os.path.isdir(src):
                shutil.copytree(src, dst)
            else:
                shutil.copyfile(src, dst)

    with chdir(sandbox_dir):
        logging.debug('sandbox directory: {} (will{}keep)'.
                      format(sandbox_dir, keep_sandbox and ' ' or ' not '))
        yield

    if not keep_sandbox:
        shutil.rmtree(sandbox_dir)

def _random_string(length=20, chars=(string.ascii_letters + string.digits)):
    return ''.join(random.choice(chars) for i in range(length))

def normpath(path):
    enc = locale.getpreferredencoding()
    return os.path.normpath(os.path.abspath(os.path.expanduser(
        path.decode(enc)
    )))

def maybe_mkdir(path):
    """Make the directory, unless it exists. (No race.)
    """
    try:
        os.mkdir(path)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise

# Command execution (system()-like) with timeouts.

class CommandThread(threading.Thread):
    def __init__(self, command):
        super(CommandThread, self).__init__()
        self.proc = subprocess.Popen(command, stdout=subprocess.PIPE,
                                     stderr=subprocess.STDOUT)
        self.output = None

    def run(self):
        self.output, _ = self.proc.communicate()

def run_cmd(command, timeout=None):
    """Run a process with an optional timeout. Return the process' exit
    status and combined stdout/studerr text (or None for both if the
    process timed out).
    """
    thread = CommandThread(command)
    thread.start()
    thread.join(timeout)
    if thread.is_alive():
        thread.proc.terminate()
        return None, None
    else:
        return thread.proc.returncode, thread.output

# Building and executing using our makefile system.

def _make_args():
    return [
        'ACCEPT_DIR={}'.format(BASEDIR),
        'CLANGARGS=-fcolor-diagnostics',
    ]

class BuildError(Exception):
    """The application failed to build.
    """
    def __str__(self):
        return '\n' + self.args[0]

def execute(timeout, approx=False, test=False):
    """Run the application in the working directory and return:
    - The wall-clock duration (in seconds) of the execution
    - The exit status (or None if the process timed out)
    - The combined stderr/stdout from the execution
    """
    command = ['make', 'run_opt' if approx else 'run_orig']
    if test:
        command += ['ACCEPT_TEST=1']
    command += _make_args()
    logging.debug(u'running execute command: {0}'.format(u' '.join(command)))

    start_time = time.time()
    status, output = run_cmd(command, timeout)
    end_time = time.time()

    logging.log(FIREHOSE,
                u'execution output (status {0}): {1}'.format(status, output))
    return end_time - start_time, status, output

def build(approx=False, require=True, make_args=()):
    """Compile the application in the working directory. If `approx`,
    then it is built with ACCEPT relaxation enabled. Return the combined
    stderr/stdout from the compilation process.
    """
    build_cmd = ['make', 'build_opt' if approx else 'build_orig']
    build_cmd += _make_args()
    build_cmd += make_args

    logging.debug(u'running build command: {0}'.format(u' '.join(build_cmd)))
    status, output = run_cmd(build_cmd, BUILD_TIMEOUT)
    logging.log(FIREHOSE, u'build output (status {0}): {1}'.format(
        status,
        output.decode('utf8', 'ignore') if output else output,
    ))

    if status is None:
        raise BuildError('build timed out')
    if require and status:
        raise BuildError(output)
    return output

# Manage the relaxation configuration file.

def parse_relax_config(f):
    """Parse a relaxation configuration from a file-like object.
    Generates (ident, param) tuples.
    """
    for line in f:
        line = line.strip()
        if line:
            param, ident = line.split(None, 1)
            yield ident, int(param)

def dump_relax_config(config, f):
    """Write a relaxation configuration to a file-like object. The
    configuration should be a sequence of tuples.
    """
    for ident, param in config:
        f.write('{} {}\n'.format(param, ident))

# Loading the evaluation script.

def load_eval_funcs(appdir):
    """Read the evaluation script (eval.py) for the application and
    return the load and score functions.
    """
    try:
        mod = imp.load_source('evalscript',
                              os.path.join(appdir, EVALSCRIPT))
    except IOError:
        raise UserError(
            'No eval.py found in {}'.format(appdir),
            'You need to provide an evaluation script for your '
            'application. See:\n'
            'https://sampa.cs.washington.edu/accept/cli/#evalpy'
        )
    return mod.load, mod.score

# High-level profiling driver.

Execution = namedtuple('Execution', ['output', 'elapsed', 'status',
                                     'config', 'roitime', 'execlog'])

def build_and_execute(directory, relax_config, test, rep, timeout=None):
    """Build the application in the given directory (which must contain
    both a Makefile and an eval.py), run it, and collect its output.
    Return an Execution object.
    """
    with chdir(directory):
        with sandbox(True):
            # Clean up any residual files.
            run_cmd(['make', 'clean'] + _make_args())

            if relax_config:
                with open(CONFIGFILE, 'w') as f:
                    dump_relax_config(relax_config, f)
            elif os.path.exists(CONFIGFILE):
                os.remove(CONFIGFILE)

            approx = bool(relax_config)
            build(approx)
            elapsed, status, execlog = execute(timeout, approx, test)
            if elapsed is None or status or status is None:
                # Timeout or error.
                output = None
                roitime = None
            else:
                # Load benchmark output.
                loadfunc, _ = load_eval_funcs(directory)
                try:
                    output = loadfunc()
                except:
                    # Error reading benchmark output; this is a broken
                    # execution.
                    output = None
                    status = 'Exception in load() call:\n' + \
                        traceback.format_exc()

                # Load ROI duration.
                try:
                    with open('accept_time.txt') as f:
                        roitime = float(f.read())
                except (OSError, IOError):
                    # Can't open time file.
                    roitime = None
                    status = 'Could not open timing file ({0}). This is ' \
                             'probably because the ROI markers were not ' \
                             'called.'
                except:
                    # Other error loading time.
                    roitime = None
                    status = 'Exception while loading time:\n' + \
                        traceback.format_exc()

            # Sequester filesystem output.
            if isinstance(output, basestring) and output.startswith('file:'):
                fn = output[len('file:'):]
                _, ext = os.path.splitext(fn)
                maybe_mkdir(OUTPUTS_DIR)
                output = os.path.join(OUTPUTS_DIR, _random_string() + ext)
                try:
                    shutil.copyfile(fn, output)
                except IOError:
                    # Error copying output file.
                    roitime = None
                    status = 'Exception while copying output file:\n' + \
                        traceback.format_exc()

            if not relax_config:
                with open(CONFIGFILE) as f:
                    relax_config = list(parse_relax_config(f))

    return Execution(output, elapsed, status, relax_config,
                     roitime, execlog)

# Configuration space exploration.

def permute_config(base, param=1):
    """Given a base (null) relaxation configuration, generate new
    (relaxed) configurations.

    These are *base* configurations: in each, exactly one site is
    enabled and its parameter is set to `param` (default 1).
    """
    for i in range(len(base)):
        config = list(base)
        ident, _ = config[i]
        config[i] = ident, param
        yield tuple(config)

def combine_configs(configs):
    """Generate a new configuration that superimposes all the
    optimizations from the set of configurations.
    """
    configs = list(configs)
    if not configs:
        return

    # Combine nonzero parameters in an unordered way.
    sites = {}
    for config in configs:
        for ident, param in config:
            if param:
                sites[ident] = param

    # Modify the first config with the new parameters.
    out = list(configs[0])
    for i, (ident, param) in enumerate(out):
        if ident in sites:
            out[i] = ident, sites[ident]
    return tuple(out)

def increase_config(config, amount=1):
    """Generate a new configuration that applies the given configuration
    more aggressively.
    """
    out = []
    for ident, param in config:
        if param:
            out.append((ident, param + amount))
        else:
            out.append((ident, param))
    return tuple(out)

def configs_conflict(a, b):
    """Given two configurations, determine whether they overlap (i.e., have
    nonzero parameters for at least one site in common).
    """
    a_dict = dict(a)
    b_dict = dict(b)
    assert a_dict.keys() == b_dict.keys()

    for ident, a_param in a_dict.items():
        if a_param and b_dict[ident]:
            return True
    return False

def config_subsumes(a, b):
    """Given two configurations with the same sites, determine whether
    the first subsumes the second (all parameters in a are greater than
    or equal to those in b).
    """
    a_dict = dict(a)
    b_dict = dict(b)
    assert a_dict.keys() == b_dict.keys()

    for ident, a_param in a_dict.items():
        if a_param < b_dict[ident]:
            return False
    return True

def cap_config(config):
    """Reduce configuration parameters that exceed their maxima,
    returning a new configuration.
    """
    out = []
    for ident, param in config:
        max_param = PARAM_MAX[ident.split()[0]]
        if param > max_param:
            param = max_param
        out.append((ident, param))
    return tuple(out)

def _ratsum(vals):
    """Reciprocal of the sum or the reciprocal. Suitable for composing
    speedups, etc.
    """
    total = 0.0
    num = 0
    for v in vals:
        if v:
            total += v ** -1.0
            num += 1
    if num:
        return (total - (num - 1)) ** -1.0
    else:
        return 0.0

def _powerset(iterable, minsize=0):
    """From the itertools recipes."""
    s = list(iterable)
    return itertools.chain.from_iterable(
        itertools.combinations(s, r) for r in range(minsize, len(s) + 1)
    )

def best_combined_configs(results):
    """Given a set of results, generate new configurations that compose
    the configurations used in the results. A heuristic chooses
    combinations that "should" give good results. Specifically, it
    generates the Pareto-optimal set of quality/performance under a
    linear combination hypothesis.
    """
    # Get flat tuples for efficient search. Note that we currently strip
    # away the uncertainty of the speedup for efficiency.
    components = [(r.config, r.speedup.value, r.error) for r in results]

    # Find all viable composed configurations.
    candidates = []
    for comps in _powerset(components, 2):
        component_configs = [c[0] for c in comps]
        config = combine_configs(component_configs)
        if config in component_configs:
            continue

        speedup = _ratsum(c[1] for c in comps)
        if speedup <= 0.0:
            continue

        error = sum(c[2] for c in comps)
        if error > MAX_ERROR:
            continue

        candidates.append((config, speedup, error))

    logging.info('combination candidates: {}'.format(len(candidates)))

    # Prune to Pareto-optimal configs.
    optimal = []
    for config, speedup, error in candidates:
        for _, other_speedup, other_error in candidates:
            if other_speedup >= speedup and other_error < error:
                break
        else:
            optimal.append((config, speedup, error))

    logging.info('optimal combinations: {}'.format(len(optimal)))
    return [o[0] for o in optimal]

def bce_greedy(results, max_error=MAX_ERROR):
    """Given a set of results and a maximum error constraint, choose a
    good combined configuration that composes the component
    configurations. Uses a greedy approximation to the Knapsack Problem.
    """
    components = [(r.config, r.speedup.value, r.error.value) for r in results]

    # Sort components by "value per unit weight".
    scored = []
    for i, (_, speedup, error) in enumerate(components):
        # Linear-combining performance score: 1 - s^-1
        value = 1.0 - speedup ** -1.0
        error = max(error, 0.001)  # Avoid divide-by-zero.
        score = value / error
        scored.append((score, i))
    scored.sort(reverse=True)

    # Greedily choose top-scoring components.
    knapsack = []  # Indices of chosen components.
    cur_combined = None  # Current merged config.
    cur_error = 0.0
    for _, i in scored:
        config, speedup, error = components[i]

        if cur_combined is None:
            # Add first item to knapsack.
            knapsack.append(i)
            cur_combined = config
            cur_error = error
            continue

        # Search for conflicts.
        conflicts = set()
        conflict_value = 0.0
        for j in knapsack:
            if configs_conflict(config, components[j][0]):
                conflicts.add(j)
                conflict_value += 1.0 - components[j][1] ** -1.0

        if conflicts:
            this_value = 1.0 - speedup ** -1.0
            if this_value < conflict_value:
                continue

        new_error = cur_error + error - \
            sum(components[j][2] for j in conflicts)
        if new_error <= max_error:
            for conflict in conflicts:
                knapsack.remove(conflict)
            knapsack.append(i)
            cur_error = new_error

    # Here, we could predict the speedup for validation.

    for num in range(1, len(knapsack) + 1):
        yield combine_configs([components[i][0] for i in knapsack[:num]])

# Results.

class Result(object):
    """Represents the result of executing one relaxed configuration of a
    program.
    """
    def __init__(self, app, config, durations, statuses, outputs):
        self.app = app
        self.config = tuple(config)
        self.durations = durations
        self.statuses = statuses
        self.outputs = outputs

    def evaluate(self, scorefunc, precise_output, precise_durations,
                 ignore_performance=False):
        p_dur = umean(precise_durations)

        self.good = False  # A useful configuration?
        self.safe = False  # Not useful, but also not harmful?
        self.desc = 'unknown'  # Why not good?

        # Check for errors.
        for i, status in enumerate(self.statuses):
            if status is None:
                # Timed out.
                self.desc = 'replica {} timed out'.format(i)
                return
            elif status:
                # Error status.
                self.desc = 'error status (replica {}): {}'.format(
                    i, status
                )
                return

        # Get duration and speedup.
        for i, dur in enumerate(self.durations):
            if dur is None:
                self.desc = 'duration {} missing'.format(i)
                break
        self.duration = umean(self.durations)
        self.speedup = p_dur / self.duration

        # Get average output error.
        self.errors = []
        for i, output in enumerate(self.outputs):
            try:
                error = scorefunc(precise_output, output)
            except Exception as exc:
                logging.warn('Exception in score() function:\n' +
                             traceback.format_exc())
                self.error = 1.0
                self.desc = 'error in scoring function, replica {}: {}'.format(
                    i, exc
                )
                return
            if math.isnan(error):
                error = 1.0
            self.errors.append(error)
        self.error = umean(self.errors)

        if self.error > MAX_ERROR:
            # Large output error.
            self.desc = 'large error: {} %'.format(self.error * 100)
            return

        # No error or large quality loss.
        self.safe = True

        # A result is not good if it results in a slowdown. Skip this
        # check if we're ignoring performance.
        if not ignore_performance and not self.speedup > 1.0:
            self.desc = 'no speedup: {} vs. {}'.format(self.duration, p_dur)
            return

        # All good!
        self.good = True
        self.desc = 'good'

def triage_results(results):
    """Given a list of Result objects, splits the data set into three
    lists: optimal, suboptimal, and bad results.
    """
    # Partition bad from good.
    good = []
    bad = []
    for res in results:
        (good if res.good else bad).append(res)

    # Partition good into optimal and suboptimal.
    optimal = []
    suboptimal = []
    for res in good:
        for other in good:
            if res == good:
                continue
            if other.error < res.error and other.speedup > res.speedup:
                # other dominates res, so eliminate res from the optimal
                # set.
                suboptimal.append(res)
                break
            elif other in optimal and \
                    abs(other.error.value - res.error.value) < \
                    EPSILON_ERROR and \
                    abs(other.speedup.value - res.speedup.value) < \
                    EPSILON_SPEEDUP:
                # other and res are too similar, and other is already
                # optimal. Reduce noise by including only one.
                suboptimal.append(res)
                break
        else:
            # No other result dominates res.
            optimal.append(res)

    # Sort optimal by speedup.
    optimal.sort(key=lambda r: r.speedup.value, reverse=True)

    assert len(optimal) + len(suboptimal) + len(bad) == len(results)
    return optimal, suboptimal, bad

# Core relaxation search workflow.

class Evaluation(object):
    """The state for the evaluation of a single application.
    """
    def __init__(self, appdir, client, reps, test_reps, simulate=False,
                 timeout_factor=3):
        """Set up an experiment. Takes an active CWMemo instance,
        `client`, through which jobs will be submitted and outputs
        collected.

        `reps` is the number of executions per configuration to run.

        `simulate` indicates that this is for a simulated (i.e.,
        performance-insensitive) evaluation. The running time of
        executions is not taken into account in simulation mode.

        `timeout_factor` sets how long relaxed executions have to
        finish, as a multiple of the precise running time. If it is
        `None`, there is no timeout.
        """
        self.appdir = normpath(appdir)
        self.client = client
        self.simulate = simulate

        self.reps = reps
        self.test_reps = test_reps
        self.timeout_factor = timeout_factor

        self.appname = os.path.basename(self.appdir)

        # Load scoring function from eval.py.
        _, self.scorefunc = load_eval_funcs(appdir)

        # Results, to be populated later.
        self.ptimes = []
        self.pout = None
        self.base_elapsed = None
        self.base_config = None
        self.base_configs = None
        self.results = []

        # Results for the *testing* executions.
        self.test_pout = None
        self.test_base_elapsed = None
        self.test_ptimes = []

        self.source_setup_run = False

    def _source_setup(self):
        """Run the preliminary `make setup` target for the application,
        if has not already been in this instance.
        """
        if not self.source_setup_run:
            logging.info('executing setup target')
            with chdir(self.appdir):
                run_cmd(['make', 'setup'])
            self.source_setup_run = True

    def setup(self, test=False):
        """Submit the baseline precise executions and gather some
        information about the first.

        When `test` is false, this is for the *training* input. Set the
        fields `pout` (the precise output), `base_elapsed` (precise
        execution time), `base_config`, and `base_configs`.

        When `test` is true, this is for the *testing* input. Set the
        fields `test_pout` and `test_base_elapsed`.
        """
        self._source_setup()

        logging.info('starting baseline execution for {}'.format(
            'testing' if test else 'training'
        ))

        # Precise (baseline) execution.
        reps = self.test_reps if test else self.reps
        for rep in range(reps):
            self.client.submit(
                build_and_execute,
                self.appdir, None, test, rep,
                timeout=None
            )

        # Get information from the first execution. The rest of the
        # executions are for timing and can finish later.
        pex = self.client.get(build_and_execute, self.appdir, None, test, 0)
        if test:
            self.test_pout = pex.output
            self.test_base_elapsed = pex.elapsed
        else:
            self.pout = pex.output
            self.base_elapsed = pex.elapsed
            self.base_config = pex.config
            self.base_configs = list(permute_config(self.base_config))

    def precise_times(self, test=False):
        """Generate the durations for the precise executions. Must be
        called after `setup`.
        """
        reps = self.test_reps if test else self.reps
        for rep in range(reps):
            ex = self.client.get(build_and_execute,
                                 self.appdir, None, test, rep)
            if ex.status != 0:
                if isinstance(ex.status, int):
                    # Error status.
                    raise UserError(
                        'Precise execution exited '
                        'with status {}'.format(ex.status),
                        'The program exited with an error when ACCEPT tried '
                        'to run it with no approximations. For example, the '
                        'program may have failed to find an input file. '
                        'The output from the failed run is below.\n' +
                        ex.execlog
                    )
                else:
                    # The status field of Execution is overloaded to
                    # also indicate other kinds of errors. It is an
                    # explanatory string in this case.
                    raise UserError(
                        'Precise execution failed.',
                        ex.status
                    )
            yield ex.roitime

    def submit_approx_runs(self, config, test=False):
        """Submit the executions for a given configuration.
        """
        base_elapsed = self.test_base_elapsed if test else self.base_elapsed
        reps = self.test_reps if test else self.reps

        if self.timeout_factor:
            timeout = base_elapsed * TIMEOUT_FACTOR
        else:
            timeout = None
        for rep in range(reps):
            self.client.submit(
                build_and_execute,
                self.appdir, config, test, rep, timeout=timeout
            )

    def get_approx_result(self, config, test=False):
        """Gather the Result objects from a configuration. Must be
        called after previously submitting the same configuration.
        """
        pout = self.test_pout if test else self.pout
        ptimes = self.test_ptimes if test else self.ptimes
        reps = self.test_reps if test else self.reps

        # Collect all executions for the config.
        exs = [self.client.get(build_and_execute,
                               self.appdir, config, test, rep)
               for rep in range(reps)]

        # Evaluate the result.
        res = Result(self.appname, config,
                     [ex.roitime for ex in exs],
                     [ex.status for ex in exs],
                     [ex.output for ex in exs])
        res.evaluate(self.scorefunc, pout, ptimes, self.simulate)
        return res

    def run_approx(self, configs, test=False):
        """Evaluate a set of approximate configurations. Return a list of
        results and append them to `self.results`.
        """
        # Relaxed executions.
        for config in configs:
            self.submit_approx_runs(config, test)

        # If we don't have the precise times yet, collect them. We need
        # them to evaluate approximate executions.
        ptimes = self.test_ptimes if test else self.ptimes
        if not ptimes:
            ptimes += list(self.precise_times(test))

        # Gather relaxed executions.
        res = [self.get_approx_result(config, test) for config in configs]
        if not test:
            self.results += res
        return res

    def evaluate_base(self):
        """Get results for all the base (single-opportunity)
        configurations. `setup()` must have been called to get the
        configuration space.
        """
        logging.info('evaluating base configurations')
        return self.run_approx(self.base_configs)

    def parameter_search(self, base_results):
        """Tune parameters for individual opportunity sites by
        increasing the parameters until an error threshold is exceeded
        or no speedup is gained. Pass the results produced by
        `evalute_base`. Returns all safe results found (including some
        of those base results that are passed in).
        """
        survivors = [r for r in base_results if r.safe]
        all_results = list(survivors)
        generation = 0

        while survivors and generation <= MAX_GENERATIONS:
            generation += 1
            logging.info('evaluating generation {}, population {}'.format(
                generation, len(survivors)
            ))

            # Increase the aggressiveness of each configuration and
            # evaluate.
            gen_configs = {}
            for res in survivors:
                increased = cap_config(increase_config(res.config))
                if increased != res.config:
                    gen_configs[increased] = res
            gen_res = self.run_approx(gen_configs)

            # Produce the next generation, eliminating any config that
            # has too much error or that offers no speedup over its
            # parent.
            next_gen = []
            for res in gen_res:
                old_res = gen_configs[res.config]
                if res.safe and not res.duration > old_res.duration:
                    next_gen.append(res)
            survivors = next_gen
            all_results += survivors

        return all_results

    def evaluate_composites(self, component_results):
        """Compose the given configurations to evaluate some combined
        configurations.
        """
        optimal, good, _ = triage_results(component_results)
        components = optimal + good
        configs = set(bce_greedy(components, 0.3))
        configs.update(list(bce_greedy(components, 0.1)))
        configs.update(list(bce_greedy(components, 0.05)))
        logging.info('{} composite configs'.format(len(configs)))
        out = self.run_approx(configs)
        return out

    def run(self, base_configs=None, tuned=True, composite=True):
        """Execute the entire ACCEPT workflow, including all three
        phases:

        - Base (single-step) configurations.
        - Tuned single-site configurations, if `tuned` is true (see
          `parameter_search`).
        - Composite configurations, if `composite` is true (see
          `evaluate_composites`).

        The experiments can start either from the base configurations
        discovered during `setup` (`self.base_configs`) or the specified
        set.

        Return a set of unique results (`Result` objects).

        Run the setup stage if it has not been executed yet.
        """
        start_time = time.time()

        if not self.pout:
            self.setup()

        if base_configs is None:
            base_configs = self.base_configs

        # Phase 1: base configurations.
        logging.info('evaluating {} base configurations'.format(
            len(base_configs)
        ))
        base_results = self.run_approx(base_configs)

        # Phase 2: tuned single-site configs.
        if tuned:
            logging.info('evaluating tuned parameters')
            tuned_results = self.parameter_search(base_results)

        # Phase 3: composite (multi-site) configs.
        if composite:
            logging.info('evaluating combined configs')
            composite_results = self.evaluate_composites(
                tuned_results if tuned else base_results
            )

        # Uniquify the results based on their configs.
        results = {}
        for result in base_results + tuned_results + composite_results:
            results[result.config] = result

        # Statistics.
        end_time = time.time()
        stats = {
            'base': len(base_configs),
            'tuned': len(tuned_results),
            'composite': len(composite_results),
            'all': len(results),
            'time': end_time - start_time,
        }

        return results.values(), stats

    def test_runs(self, configs):
        """Get *testing* (as opposed to *training*) executions for the
        precise configuration and the specified configurations.
        """
        logging.info('starting test executions')
        if not self.test_pout:
            self.setup(True)

        # Submit approximate jobs.
        logging.info('test evaluation: {} configurations'.format(len(configs)))
        return self.run_approx(configs, True)

    def test_results(self, results):
        """As an alternative to `test_runs`, get testing results for the
        optimal configurations in a test result set.
        """
        optimal, good, _ = triage_results(results)
        to_test = optimal + good
        if to_test:
            return self.test_runs([r.config for r in to_test])
        else:
            return []


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

import sys
if sys.version_info.major == 3:
    import urllib.request as http
else:
    import urllib2 as http

import json

JDK_HOST = "https://api.github.com"
JDK_HOST_PATH = "/repos/AdoptOpenJDK/openjdk8-binaries/releases/latest"
JDK_NAME_PREFIX = "OpenJDK8U-jdk_x64_linux_hotspot_"
ASSET_CONENT_TYPE = "application/x-compressed-tar"

def parse(data):
    json_data = json.loads(data)
    assets = json_data["assets"]
    for asset in assets:
        asset_name = asset["name"]
        asset_content_type = asset["content_type"]
        if asset_name.startswith(JDK_NAME_PREFIX) \
                and asset_content_type == ASSET_CONENT_TYPE:
            print(asset["browser_download_url"])

def run(host, path):
    fd = http.urlopen("".join([host, path]))
    parse(fd.read())
    fd.close()

if __name__ == "__main__":
    run(JDK_HOST, JDK_HOST_PATH)


from django_filters.rest_framework import DjangoFilterBackend
from djoser.views import UserViewSet
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.permissions import SAFE_METHODS, IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet

from django.db.models import Count, Sum
from django.http import HttpResponse
from django.shortcuts import get_object_or_404

from recipes.models import (
    Favorite, Ingredient, IngredientsInRecipe, Recipe, ShoppingCart, Tag,
)
from users.models import Subscribe, User

from .filters import IngredientFilter, RecipeFilter
from .permissions import IsOwnerOrAdminOrReadOnly
from .serializers import (
    CreateRecipeSerializer, GetRecipeSerializer, IngredientSerializer,
    RecipeSerializer, SubscriptionsSerializer, TagSerializer, UserSerializer,
)

class IngredientViewSet(ReadOnlyModelViewSet):
    pagination_class = None
    queryset = Ingredient.objects.all()
    serializer_class = IngredientSerializer
    permission_classes = (IsOwnerOrAdminOrReadOnly,)
    filter_backends = (DjangoFilterBackend,)
    filterset_class = IngredientFilter

class TagViewSet(ReadOnlyModelViewSet):
    pagination_class = None
    queryset = Tag.objects.all()
    serializer_class = TagSerializer
    permission_classes = (IsOwnerOrAdminOrReadOnly,)

class RecipeViewSet(ModelViewSet):
    queryset = Recipe.objects.select_related("author").prefetch_related(
        "tags", "ingredients"
    )
    permission_classes = (IsOwnerOrAdminOrReadOnly,)
    filter_backends = (DjangoFilterBackend,)
    filterset_class = RecipeFilter

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

    def get_serializer_class(self):
        if self.request.method in SAFE_METHODS:
            return GetRecipeSerializer
        return CreateRecipeSerializer

    @action(
        detail=True,
        methods=("post", "delete"),
        permission_classes=(IsAuthenticated,),
    )
    def favorite(self, request, pk):
        if request.method == "POST":
            recipe = get_object_or_404(Recipe, id=pk)
            obj, created = Favorite.objects.get_or_create(
                user=request.user, recipe=recipe
            )
            if created:
                serializer = RecipeSerializer(recipe)
                return Response(
                    serializer.data, status=status.HTTP_201_CREATED
                )
            return Response(
                {"Ошибка": "Рецепт уже есть в избранном"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        obj = Favorite.objects.filter(
            user=request.user, recipe__id=pk
        ).delete()

        if obj[0] > 0:
            return Response(status=status.HTTP_204_NO_CONTENT)
        return Response(
            {"Ошибка": "Рецепта нет в избранном"},
            status=status.HTTP_400_BAD_REQUEST,
        )

    @action(
        detail=True,
        methods=("post", "delete"),
        permission_classes=(IsAuthenticated,),
    )
    def shopping_cart(self, request, pk):
        if request.method == "POST":
            recipe = get_object_or_404(Recipe, id=pk)
            obj, created = ShoppingCart.objects.get_or_create(
                user=request.user, recipe=recipe
            )
            if created:
                serializer = RecipeSerializer(recipe)
                return Response(
                    serializer.data, status=status.HTTP_201_CREATED
                )
            return Response(
                {"Ошибка": "Рецепт уже есть в списке покупок"},
                status=status.HTTP_400_BAD_REQUEST,
            )
        obj = ShoppingCart.objects.filter(
            user=request.user, recipe__id=pk
        ).delete()

        if obj[0] > 0:
            return Response(status=status.HTTP_204_NO_CONTENT)
        return Response(
            {"Ошибка": "Рецепта нет в списке покупок"},
            status=status.HTTP_400_BAD_REQUEST,
        )

    @action(detail=False, permission_classes=(IsAuthenticated,))
    def download_shopping_cart(self, request):
        user = request.user
        shopping_cart = user.shopping_cart.all()
        if not shopping_cart:
            return Response(
                "Список покупок пуст.", status=status.HTTP_400_BAD_REQUEST
            )
        ingredients = (
            IngredientsInRecipe.objects.filter(
                recipe__shopping_cart__user=user
            )
            .values("ingredient__name", "ingredient__measurement_unit")
            .annotate(amount=Sum("amount"))
        )

        response = HttpResponse(
            self.generate_shopping_file(ingredients, user),
            content_type="text/plain",
        )
        response["Content-Disposition"] = "attachment; filename='shoplist.txt'"
        return response

    def generate_shopping_file(self, ingredients, user):
        content = f"Список покупок {user.get_full_name()}:\n\n"
        for ingredient in ingredients:
            name = ingredient.get("ingredient__name")
            units = ingredient.get("ingredient__measurement_unit")
            amount = ingredient.get("amount")
            content += f"{name} ({units}) - {amount}\n"
        return content

class UserViewSet(UserViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    @action(detail=False, permission_classes=(IsAuthenticated,))
    def subscriptions(self, request):
        user = request.user
        queryset = User.objects.filter(following__user=user).annotate(
            recipes_count=Count("recipes")
        )
        paginated_queryset = self.paginate_queryset(queryset)
        serializer = SubscriptionsSerializer(
            paginated_queryset, many=True, context={"request": request}
        )
        return self.get_paginated_response(serializer.data)

    @action(
        detail=True,
        methods=("post", "delete"),
        permission_classes=(IsAuthenticated,),
    )
    def subscribe(self, request, **kwargs):
        author = get_object_or_404(User, pk=kwargs["id"])

        if request.method == "POST":
            serializer = SubscriptionsSerializer(
                author, data=request.data, context={"request": request}
            )
            serializer.is_valid(raise_exception=True)
            Subscribe.objects.create(user=request.user, author=author)
            return Response(serializer.data, status=status.HTTP_201_CREATED)

        subscription = Subscribe.objects.filter(
            user=request.user, author=author
        ).delete()
        if subscription[0] > 0:
            return Response(status=status.HTTP_204_NO_CONTENT)
        return Response(
            {"Ошибка": "Вы не были подписаны на этого пользователя"},
            status=status.HTTP_400_BAD_REQUEST,
        )


import contextlib
import logging
import os.path as osp

import numpy as np

@contextlib.contextmanager
def np_print_options(*args, **kwargs):
    original = np.get_printoptions()
    np.set_printoptions(*args, **kwargs)
    yield
    np.set_printoptions(**original)

def set_logger(output_dir=None, log_file=None, debug=False):
    head = '%(asctime)-15s Host %(message)s'
    logger_level = logging.INFO if not debug else logging.DEBUG
    if all((output_dir, log_file)) and len(log_file) > 0:
        logger = logging.getLogger('crosscityadap')
        log_path = osp.join(output_dir, log_file)
        handler = logging.FileHandler(log_path)
        formatter = logging.Formatter(head)
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        handler = logging.StreamHandler()
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        logger.setLevel(logger_level)
    else:
        logging.basicConfig(level=logger_level, format=head)
        logger = logging.getLogger('crosscityadap')
    return logger


# encoding: utf-8

from __future__ import unicode_literals

from base64 import b64encode
from zlib import compress

def redelta_encode(numbers):
	"""Encode a series of line numbers as the difference from line to line (deltas) to reduce entropy.

	The delta is stored as a single signed byte per line, meaning no two consecutive lines may vary by more than +/-
	127 lines within the original source material. The resulting bytestring is then zlib compressed and b64 encoded.

	Lines without line numbers (none or unexpected zeros) will inherit the last known line number after decoding.
	"""

	def inner():
		lines = iter(numbers)
		prev = next(lines)

		for line in lines:
			delta = (line or prev) - prev  # Handle the "no line number given" case.
			if delta < 0: delta = -1 * delta + 127  # Store "signed" values.
			prev = (line or prev)  # Track our line number, or the last known good one.
			yield delta  # Store the delta.

	return b64encode(compress(bytes(bytearray(inner())))).decode('latin1')

def redelta_decode(source):
	"""Decode a series of line numbers encoded as the difference from line to line.

	The literal reverse of `redelta_encode`.
	"""

	pass

def chunk(line, mapping={None: 'text', '${': 'escape', '#{': 'bless', '&{': 'args', '%{': 'format', '@{': 'json'}):
	"""Chunkify and "tag" a block of text into plain text and code sections.

	The first delimeter is blank to represent text sections, and keep the indexes aligned with the tags.

	Values are yielded in the form (tag, text).
	"""

	skipping = 0  # How many closing parenthesis will we need to skip?
	start = None  # Starting position of current match.
	last = 0

	i = 0

	text = line.line

	while i < len(text):
		if start is not None:
			if text[i] == '{':
				skipping += 1

			elif text[i] == '}':
				if skipping:
					skipping -= 1
				else:
					yield line.clone(kind=mapping[text[start-2:start]], line=text[start:i])
					start = None
					last = i = i + 1
					continue

		elif text[i:i+2] in mapping:
			if last is not None and last != i:
				yield line.clone(kind=mapping[None], line=text[last:i])
				last = None

			start = i = i + 2
			continue

		i += 1

	if last < len(text):
		yield line.clone(kind=mapping[None], line=text[last:])


import tweepy
import time
import random

from config import create_api
from secret_languages import translate_text, LANGUAGES

def check_mentions(api, since_id):
    print("check mentions")
    user = api.me()

    new_since_id = since_id
    mentions = api.mentions_timeline(since_id=since_id, tweet_mode="extended")

    for tweet in mentions:
        new_since_id = max(tweet.id, new_since_id)

        replies = tweepy.Cursor(
            api.search,
            q=f"to:{tweet.user.screen_name} from:{user.screen_name}",
            result_type="recent",
            timeout=999999,
        ).items(1000)

        for reply in replies:
            if (
                hasattr(reply, "in_reply_to_status_id")
                and reply.in_reply_to_status_id == tweet.id
            ):
                return new_since_id

        print(f"{tweet.user.name} says {tweet.full_text}")

        if not tweet.favorited:
            tweet.favorite()

        language = random.choice(LANGUAGES)
        for hashtag in tweet.entities["hashtags"]:
            if hashtag["text"] in LANGUAGES:
                language = hashtag["text"]
                break

        response = translate_text(tweet.full_text, language=language)

        if f"#{language}" not in response:
            response += f" #{language}"

        response = response.replace(
            f"@{user.screen_name}", f"@{tweet.user.screen_name}"
        )

        api.update_status(
            status=response,
            in_reply_to_status_id=tweet.id,
            auto_populate_reply_metadata=True,
        )
    if not len(mentions):
        print("no mentions :-(")

    return new_since_id

def main():
    api = create_api()
    user = api.me()

    since_id = 1
    while True:
        since_id = check_mentions(api, since_id)
        time.sleep(30)

if __name__ == "__main__":
    main()


from datetime import datetime
import telebot
from telebot import types
from resources.Data import Dicts
from resources.electricity import *
from resources.TOKEN import token, chatId
from clients.telegram_client import TelegramClient
from clients.sqlclient import SQLiteClient, UserActioner
# from logger_main import *

TOKEN = token
ADMIN_CHAT_ID = chatId

class MyBot(telebot.TeleBot):
    def __init__(self, telegram_client: TelegramClient, user_actioner: UserActioner, *args, **kwargs):
        super(self.__class__, self).__init__(*args, **kwargs)
        self.telegram_client = telegram_client
        self.user_actioner = user_actioner

    def setup_resources(self):
        self.user_actioner.setup()

    def shutdown_resources(self):
        self.user_actioner.shutdown()

    def shutdown(self):
        self.shutdown_resources()

user_actioner = UserActioner(SQLiteClient(r"../resources/users.db"))
telegram_client = TelegramClient(token=TOKEN, base_url="https://api.telegram.org")
bot = MyBot(token=TOKEN, telegram_client=telegram_client, user_actioner=user_actioner)

@bot.message_handler(commands=['start'])
def start_message(message):
    img = open(Dicts.PICTURE_1, 'rb')
    msg = bot.send_photo(message.chat.id, img, caption="Привіт!\nЦей бот послуговується графіками планових відключень від "
                                                 "Львівобленерго. Інформація про аварійні відключення не надається. "
                                    "Щоб продовжити натисніть /putin_huilo", parse_mode='HTML')
    bot.register_next_step_handler(msg, reply_to_start)

def reply_to_start(message):
    if message.text != "/putin_huilo":
        bot.reply_to(message, "Для початку роботи із ботом необхідно ідентифікувати ваші політичні погляди, тому щоб продовжити, "
                          "слідуйте інструкціям, що вказані нижче 👇🏻", parse_mode='HTML')
        start_message(message)
    else:
        choose_group(message)

# @bot.message_handler(commands=['putin_huilo'])
def choose_group(message):
    markup_inline = types.InlineKeyboardMarkup()
    group_1 = types.InlineKeyboardButton(text='I група', callback_data=1)
    group_2 = types.InlineKeyboardButton(text='II група', callback_data=2)
    group_3 = types.InlineKeyboardButton(text='III група', callback_data=3)
    markup_inline.add(group_1, group_2, group_3)
    bot.send_message(message.chat.id, 'Оберіть номер вашої групи:', reply_markup=markup_inline, parse_mode='HTML')
    markup_inline_2 = types.InlineKeyboardMarkup()
    url = types.InlineKeyboardButton(text='Дізнатись групу', url='https://poweroff.loe.lviv.ua/gav_city3')
    markup_inline_2.add(url)
    bot.send_message(message.chat.id, 'Не знаєте в якій ви групі?', reply_markup=markup_inline_2,
                     parse_mode='HTML')

@bot.message_handler(content_types=["text"])
def reply(message):
    bot.reply_to(message, "Спершу оберіть групу! ☝🏻\nДля взаємодії з ботом використовуйте клавіші, що з'являються у чаті та "
                          "у нижній частині екрану.", parse_mode='HTML')

@bot.callback_query_handler(func=lambda callback: callback.data)
def to_json(callback):

    tg_name = callback.from_user.username
    user_id = callback.from_user.id
    user_name = callback.from_user.first_name
    chat_id = callback.message.chat.id
    group_id = callback.data
    bot.delete_message(callback.message.chat.id, callback.message.id)

    user = bot.user_actioner.get_user(user_id=str(user_id))

    if not user:
        bot.user_actioner.create_user(user_id=str(user_id), username=user_name, chat_id=chat_id, tg_name=tg_name)
        bot.user_actioner.set_group(user_id=str(user_id), group_id=group_id)
    else:
        bot.user_actioner.set_group(user_id=str(user_id), group_id=group_id)

    bot.send_message(callback.message.chat.id, text=f'Вітаю, {user_name}. Вас зареєстровано.\n'
                                                    f'Ваша група: №{group_id}')
    choose_option(callback.message)

def choose_option(message):
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=5)
    btn1 = types.KeyboardButton(text='1 💡')
    btn2 = types.KeyboardButton(text='2 🕯')
    btn3 = types.KeyboardButton(text='3 📅')
    btn4 = types.KeyboardButton(text='4 ⏰')
    btn5 = types.KeyboardButton(text='5 🔁')
    kb.add(btn1, btn2, btn3, btn4, btn5)
    msg = bot.send_message(message.chat.id, text='Оберіть опцію:', reply_markup=kb, parse_mode='HTML')

    bot.send_message(message.chat.id, text='1. Дізнатись про наявність електроенергії у цю мить.\n'
                                           '2. Отримати графік відключення на поточний день.\n'
                                           '3. Отримати графік відключення на тиждень.\n'
                                           '4. Налаштувати сповіщення щодо відключення.\n'
                                           '5. Змінити групу.')
    bot.register_next_step_handler(msg, option)

def on_off(message):
    if message.text == "Підключити сповіщення":
        bot.send_message(message.chat.id, text=f'Вітаю, {user_actioner.get_user(user_id=str(message.from_user.id))[1]}. '
                                               f'Ви підключили сповіщення!\n'
                                               'Кожного разу за годину перед можливим відключенням '
                                               'Вам надходитиме попереджувальне повідомлення.')

        bot.user_actioner.set_notify(user_id=str(message.from_user.id), notifications=1)
        choose_option(message)
    elif message.text == "Відключити сповіщення":
        bot.send_message(message.chat.id,
                         text="Сповіщення про відключення електроенергії вимкнено !")
        bot.user_actioner.set_notify(user_id=str(message.from_user.id), notifications=0)
        choose_option(message)
    else:
        bot.reply_to(message, text="Для взаємодії з ботом використовуйте клавіші, що з'являються у "
                          "нижній частині екрану. Спробуйте підключити або відключити сповіщення ще раз, "
                                   "використовуючи одну із запропонованих опцій.")
        choose_option(message)

def option(message):
    group = bot.user_actioner.get_group(user_id=str(message.from_user.id))
    if message.text == '1 💡':
        condition = get_condition(int(group))
        if condition == 'Є Енергія':
            img = open(Dicts.PICTURE_2, 'rb')
            bot.send_photo(message.chat.id, img, caption=f'Згідно графіку відключень від Львівобленерго у вашому будинку'
                                                         f' на цей момент імовірно:\n'
                                                         f'✅ {condition} ✅',
                           parse_mode='HTML')
        elif condition == 'Немає Енергії':
            img = open(Dicts.PICTURE_3, 'rb')
            bot.send_photo(message.chat.id, img, caption=f'Згідно графіку відключень від Львівобленерго у вашому будинку'
                                                         f' на цей момент імовірно:\n'
                                                         f'❌ {condition} ❌',
                           parse_mode='HTML')
        else:
            img = open(Dicts.PICTURE_4, 'rb')
            bot.send_photo(message.chat.id, img,
                           caption=f'Згідно графіку відключень від Львівобленерго у вашому будинку'
                                   f' на цей момент імовірно:\n'
                                   f'⚠ {condition} ⚠',
                           parse_mode='HTML')
        choose_option(message)
    elif message.text == '2 🕯':
        bot.send_message(message.chat.id, text=f'{Dicts.WEEK_DAY[choose_day()]}, Група №{group}',
                         parse_mode='HTML')
        condition = get_day_sсhedule(int(group))
        for k, v in condition.items():
            bot.send_message(message.chat.id, text=f'{k} : {v}', parse_mode='HTML')
        choose_option(message)
    elif message.text == '3 📅':
        if group == 1:
            img = open(Dicts.SCHEDULE_1, 'rb')
            bot.send_photo(message.chat.id, img)
        elif group == 2:
            img = open(Dicts.SCHEDULE_2, 'rb')
            bot.send_photo(message.chat.id, img)
        else:
            img = open(Dicts.SCHEDULE_3, 'rb')
            bot.send_photo(message.chat.id, img)
        choose_option(message)
    elif message.text == '4 ⏰':
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)
        btn1 = types.KeyboardButton(text='Підключити сповіщення')
        btn2 = types.KeyboardButton(text='Відключити сповіщення')
        kb.add(btn1, btn2)
        msg = bot.send_message(message.chat.id, text='Оберіть опцію:', reply_markup=kb, parse_mode='HTML')
        bot.register_next_step_handler(msg, on_off)

    elif message.text == '5 🔁':
        choose_group(message)

    else:
        bot.reply_to(message, text="Для взаємодії з ботом використовуйте клавіатуру у нижній частині екрану! "
                                               "Вдалого користування.", parse_mode='HTML')
        choose_option(message)

def create_err_message(err: Exception) -> str:
    return f"{datetime.now} ::: {err.__class__} ::: {err}"

if __name__ == "__main__":
    while True:
        try:
            bot.setup_resources()
            bot.polling()
        except Exception as err:
            error_message = create_err_message(err)
            bot.telegram_client.post(method='sendMessage', params={"text": error_message,
                                                                   "chat_id": ADMIN_CHAT_ID})

            send_log(error_message)
            bot.shutdown()


from typing import Optional, List, Dict, Tuple, Generator

import select
import time
import json
import itertools

from abc import ABC, abstractmethod
from socket import socket
from collections import deque
from enum import Enum
from unittest.mock import sentinel

from networks.port import Port, PortStatus
from networks.packet import MessageType, BPDU
from networks.request_handler import SpanningTreeRequest, ForwardingRequest

from networks.constants import MESSAGE_SECOND_TIMEOUT

class Bridge:
    """
    Representation of a networking networks
    """
    def __init__(self, identity: str, ports: List[Port]):
        self.identity = identity
        self.ports: List[Port] = ports

        self.forwarding_table: Dict[str, Port] = {}

        self.last_sent_bpdu = time.time()

        self._root_port: int = sentinel.NotSet
        self._root_bpdu: BPDU = sentinel.NotSet

        self.active = False  # for testing purposes

        self.DEFAULT_ROOT_PORT: int = None
        self.DEFAULT_ROOT_BPDU: BPDU = BPDU(id=self.identity, root=self.identity, cost=0, port=self.DEFAULT_ROOT_PORT)

    @property
    def root_port(self) -> int:
        return self._root_port

    @root_port.setter
    def root_port(self, new_port: int):
        if new_port != self._root_port:
            self._root_port = new_port
            print(f"Root port: {self.root_port}", flush=True)

    @property
    def root_bpdu(self) -> BPDU:
        return self._root_bpdu

    @root_bpdu.setter
    def root_bpdu(self, new_bpdu: BPDU):
        if new_bpdu != self._root_bpdu:
            self._root_bpdu = new_bpdu
            print(f"New root: {self.root_bpdu.root_id} cost {self.root_bpdu.cost}", flush=True)

    def accept_requests(self, sec_timeout: float) -> Tuple[List[SpanningTreeRequest], List[ForwardingRequest]]:
        """
        accepts all simultaneous requests and sorts them into their respective categories
        :return:
        """
        ready_ports, _, failed_ports = select.select(self.ports, [], self.ports, sec_timeout)

        spanning_requests: List[SpanningTreeRequest] = []
        forwarding_requests: List[ForwardingRequest] = []

        for port in ready_ports:
            packet = port.read_packet()

            if packet.type == MessageType.BridgeProtocolDataUnit:
                # want all of the BPDUs to be handled first
                spanning_requests.append(SpanningTreeRequest(port, packet.message))
            elif packet.type == MessageType.DataMessage:
                forwarding_requests.append(ForwardingRequest(port, packet))
            else:
                raise NotImplementedError(f"Unknown packet type {packet.type}")

        return spanning_requests, forwarding_requests

    def launch(self):
        """
        1. Accept all selects
        2. Filter based on BPDU's and normal messages
        3. Update the spanning tree based on the BPDU packets
        4. Queue the normal messages until the tree has been re-established
        """
        print("Bridge starting up", flush=True)  # REQUIRED by assignment
        self.root_port = self.DEFAULT_ROOT_PORT
        self.root_bpdu = self.DEFAULT_ROOT_BPDU

        self.send_bpdus()

        self.active = True
        while self.active:
            simultaneous_spanning, simultaneous_forwarding = self.accept_requests(sec_timeout=MESSAGE_SECOND_TIMEOUT)

            any_port_updated: bool = False
            for spanning_request in simultaneous_spanning:
                any_port_updated = any_port_updated or spanning_request.handle(self)

            if any_port_updated:
                self.forwarding_table = self.calculate_forwarding_table()
                root_changed = self.calculated_root_changed()
                # print(f"Port update: {any_port_updated} and root updated: {root_changed}", flush=True)

            for forwarding_request in simultaneous_forwarding:
                forwarding_request.handle(self)

            if (any_port_updated and root_changed) or (time.time() - self.last_sent_bpdu > MESSAGE_SECOND_TIMEOUT):
                # print("Sending BPDUs", flush=True)
                self.send_bpdus()

    def send_bpdus(self):
        """
        BPDU - Bridge Protocol Data Unit

        This method sends a BPDU on this port.  Right now, it only sends a
        BPDU that says this networks believes its the root; obviously, this
        will need to be updated.
        """
        self.last_sent_bpdu = time.time()

        for port in self.ports:
            port.send_bpdu(bridge_id=self.identity, bpdu=self.root_bpdu)

    def _all_port_bpdus_pairs(self) -> Generator[Tuple[int, BPDU], None, None]:
        """
        :return: Generator of all the port, BPDU pairs
        """
        for port in self.ports:
            for bpdu in port.seen_bpdus:
                yield (port.index, bpdu)

    def calculated_root_changed(self) -> bool:
        """
        :return: True if the recalculated root port/bpdu has changed, otherwise False
        """
        def update_port(new_port: int) -> bool:
            different = new_port != self.root_port
            self.root_port = new_port
            return different

        def update_bpdu(new_bpdu: BPDU) -> bool:
            different = new_bpdu != self.root_bpdu
            self.root_bpdu = new_bpdu
            return different

        # print(f"DBG: Sorted pairs {list(self._all_port_bpdus_pairs())}")
        sorted_bpdus_pairs = sorted(self._all_port_bpdus_pairs(), key=lambda port_bpdu_pair: port_bpdu_pair[1])

        # if there is nothing present, this is the root
        if len(sorted_bpdus_pairs) == 0:
            return update_port(new_port=self.DEFAULT_ROOT_PORT) or update_bpdu(new_bpdu=self.DEFAULT_ROOT_BPDU)

        possible_root_port_index, possible_root_bpdu = sorted_bpdus_pairs[0]

        # if the best bpdu lists this as the root
        if possible_root_bpdu.root == self.identity:
            return update_port(new_port=self.DEFAULT_ROOT_PORT) or update_bpdu(new_bpdu=self.DEFAULT_ROOT_BPDU)

        cost_adjusted_bpdu = possible_root_bpdu.replace(cost=possible_root_bpdu.cost + 1)

        # if the possible is better than the existing root
        if cost_adjusted_bpdu < self.root_bpdu:
            possible_root_port = self.ports[possible_root_port_index]
            if possible_root_port.status != PortStatus.DISABLED:
                # this should always be the case as this port has NOT sent the best BPDU on the LAN
                raise RuntimeError(f"Some reason the port {possible_root_port_index} not disabled")

            new_bridge_bpdu = cost_adjusted_bpdu.replace(id=self.identity)
            return update_port(new_port=possible_root_port_index) or update_bpdu(new_bpdu=new_bridge_bpdu)

        return False

    def calculate_forwarding_table(self) -> Dict[str, Port]:
        """
        :return: A new forwarding table from the enabled Ports
        """
        forwarding_table: Dict[str, Port] = {}

        for p in self.ports:
            if p.status == PortStatus.DISABLED and p.index != self.root_port:
                continue

            for bpdu in p.seen_bpdus:
                if bpdu.source_bridge_id in forwarding_table:
                    # print(f"Port# {p.index} tried to add {bpdu.source_bridge_id} again even though it already exists "
                    #       f"under {forwarding_table[bpdu.source_bridge_id].index}", flush=True)

                    # ports are iterated through... Smaller port wins
                    continue

                forwarding_table[bpdu.source_bridge_id] = p

        return forwarding_table


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue May 28 13:41:54 2019

@author: adamreidsmith
"""

import random as r
import numpy as np
from scipy.integrate import odeint
#import matplotlib.pyplot as plt

#Parameters
C1 = 1
#C2 = np.pi/2
T1 = 5
#T2 = 100*np.sqrt(2)

#RHS
def f(t):
    return C1*np.cos(2*np.pi/T1*t)  # + C2*np.cos(2*np.pi/T2*t)

data = []
datanotmod = []

num_ab_pairs = 1000
for i in range(num_ab_pairs):
    a = np.random.rand() #Random number in [0,1)
    b = np.random.rand()

    #Van der Pol oscillator equation
    def vanderpol(ic,t):
        x = ic[0]
        y = ic[1]
        yd = f(t) + a*(1-x**2)*y - b*x
        xd = y
        return [xd,yd]

    #Solve the ivp numerically
    ic = [0,0]
    tmax = 80
    n_points = 10000
    t = np.linspace(0,tmax,n_points)
    sol = odeint(vanderpol, ic, t)

    '''
    #Plot the data
    plt.figure(figsize=(8,6))
    plt.plot(t,sol[:,0])
    plt.xlabel('t')
    plt.ylabel('x(t)')
    '''

    #Keep a random 1000 data points
    indices = r.sample(range(n_points), k=4000)
    indices.sort()
    t = np.array([t[i] for i in indices])
    tmodT1 = t % T1
    x = [sol[i][0] for i in indices]
    xd = [sol[i][1] for i in indices]

    '''
    #Plot the data with time modulo T1
    plt.figure(figsize=(8,6))
    plt.scatter(tmodT1, x, s=1)
    '''

    tmodT1 = np.insert(tmodT1,0,a)
    x = np.insert(x,0,b)
    soln = [[tmodT1[j],x[j]] for j in range(len(tmodT1))]
    data.append(soln)

    t = np.insert(t,0,a)
    soln2 = [[t[j],x[j]] for j in range(len(t))]
    datanotmod.append(soln2)

    if i % 10 == 0:
        print('Iteration:', i)

np.save('../Data_files/vdp_param_data_modT1', data)
np.save('../Data_files/vdp_param_data_modT1_notmod', datanotmod)


import torch
import numpy
from dataset import PromiseDataset
from data import Data
from model import VNet
import torch.backends.cudnn as cudnn
import SimpleITK as sitk
import os

def write_result(result, path, new_spacing = [1, 1, 1.5], volume_size = [128, 128, 64]):
    original_image = sitk.ReadImage(path)
    to_write = sitk.Image(original_image.GetSize()[0], original_image.GetSize()[1], original_image.GetSize()[2], sitk.sitkFloat32)
    factor = numpy.asarray(original_image.GetSpacing()) / [new_spacing[0], new_spacing[1], new_spacing[2]]
    factor_size = numpy.asarray(original_image.GetSize() * factor, dtype=float)
    new_size = numpy.max([factor_size, volume_size], axis = 0)
    new_size = new_size.astype(dtype=int)

    resampler = sitk.ResampleImageFilter()
    resampler.SetReferenceImage(original_image)
    resampler.SetOutputSpacing(new_spacing)
    resampler.SetSize(new_size.tolist())
    resampler.SetInterpolator(sitk.sitkNearestNeighbor)

    to_write = resampler.Execute(to_write)
    image_centroid = numpy.asarray(new_size, dtype = float) / 2.0
    image_start_pixel = (image_centroid - numpy.asarray(volume_size) / 2.0).astype(dtype = int)

    for dst_x, src_x in zip(range(0, result.shape[0]), range(image_start_pixel[0], int(image_start_pixel[0] + volume_size[0]))):
        for dst_y, src_y in zip(range(0, result.shape[1]), range(image_start_pixel[1], int(image_start_pixel[1] + volume_size[1]))):
            for dst_z, src_z in zip(range(0, result.shape[2]), range(image_start_pixel[2], int(image_start_pixel[2] + volume_size[2]))):
                to_write.SetPixel(int(src_x), int(src_y), int(src_z), float(result[dst_x, dst_y, dst_z]))

    resampler.SetOutputSpacing([original_image.GetSpacing()[0], original_image.GetSpacing()[1], original_image.GetSpacing()[2]])
    resampler.SetSize(original_image.GetSize())
    to_write = resampler.Execute(to_write)
    threshold_filter = sitk.BinaryThresholdImageFilter()
    threshold_filter.SetInsideValue(1)
    threshold_filter.SetOutsideValue(0)
    threshold_filter.SetLowerThreshold(0.5)
    to_write = threshold_filter.Execute(to_write)

    connected_component = sitk.ConnectedComponentImageFilter()
    to_write_connected_component = connected_component.Execute(sitk.Cast(to_write, sitk.sitkUInt8))
    connected_component_array = numpy.transpose(sitk.GetArrayFromImage(to_write_connected_component).astype(dtype = float), [2, 1, 0])
    lab = numpy.zeros(int(numpy.max(connected_component_array) + 1), dtype = float)
    for i in range(1, int(numpy.max(connected_component_array) + 1)):
        lab[i] = numpy.sum(connected_component_array == i)
    active_lab = numpy.argmax(lab)
    to_write = (to_write_connected_component == active_lab)
    to_write = sitk.Cast(to_write, sitk.sitkUInt8)
    writer = sitk.ImageFileWriter()
    patient_name = path.split("/")[-1]
    writer.SetFileName(os.path.join("result", patient_name))
    writer.Execute(to_write)

def inference(model):
    model.eval()
    promise_dataset = PromiseDataset(is_train = False)
    test_loader = torch.utils.data.DataLoader(dataset = promise_dataset, batch_size = 1)
    with torch.no_grad():
        for batch_index, data in enumerate(test_loader):
            data, path = data
            pred = model(data)
            _, _, z, y, x = data.shape
            result = model(data)
            #tuple to string
            path = "".join(path)
            write_result(result, path)

if __name__ == "__main__":
    net = VNet()
    net = torch.nn.DataParallel(net, device_ids=[0, 1, 2, 3])
    net.cuda()
    cudnn.benchmark = True
    net.load_state_dict(torch.load("weights/promise12_weight.pth"))
    inference(net)


# Colormap class for plots

import cupy as cp
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from dataclasses import dataclass

@dataclass
class Coloring:
    """
    Basic coloring class for plots.

    Parameters
    ----------
    vmin : float
        The minimum value of the colormap.
    vmax : float
        The maximum value of the colormap.
    color_map_array : cp.array
        The array of colors for the colormap.
    nan_color : tuple
        The color for NaN values.
    nan_opacity : float
        The opacity for NaN values.
    opaque : bool
        Whether the geometry is opaque or not, by default True
    """
    vmin: float
    vmax: float
    color_map_array: cp.array
    nan_color: tuple
    nan_opacity: float = 1.0
    opaque: bool = True

class Colormap(Coloring):
    """A colormap class for plots.

    Parameters
    ----------
    name : str
        The name of the colormap using matplotlib's naming convention.
    vmin : float
        The minimum value of the colormap.
    vmax : float
        The maximum value of the colormap.
    num_table_values : int
        The number of values in the colormap table.
    opacity : cp.array, float, optional
        The opacity array for the colormap. If None is given, then the
        colormap is opaque. If an array is given, then the colormap uses
        the array as the opacity.
    nan_color : tuple
        The color for NaN values.
    """

    def __init__(
            self,
            name='jet',
            vmin=0.0,
            vmax=1.0,
            num_table_values=256,
            opacity=None,
            nan_color=(1.0, 1.0, 0.0),
            nan_opacity=1.0,
            ):

        """Initialize the colormap."""
        self.name = name
        self.vmin = vmin
        self.vmax = vmax
        self.num_table_values = num_table_values
        self.nan_color = nan_color
        self.nan_opacity = nan_opacity

        # Get the colormap
        self.cmap = cm.get_cmap(name, num_table_values)
        self.color_map_array = cp.array([self.cmap(i) for i in range(num_table_values)])

        # Set the opacity
        if (opacity is None):
            self.opaque = True
        elif isinstance(opacity, float) and opacity == 1.0:
            self.opaque = True
        elif isinstance(opacity, float) and opacity < 1.0:
            self.opaque = False
            self.color_map_array[:, 3] = opacity
        elif isinstance(opacity, (list, tuple, cp.ndarray, np.ndarray)):
            self.opaque = False
            self.color_map_array[:, 3] = cp.array(opacity)
        else:
            raise TypeError('Invalid opacity type.')

class SolidColor(Coloring):
    """A coloring class for solid colors.
    TODO: Find a better abstraction for this.

    Parameters
    ----------
    color : tuple
        The color for the solid color.
    opacity : float
        The opacity for the solid color.
    """

    def __init__(
            self,
            color=(1.0, 1.0, 1.0),
            opacity=1.0,
            ):
        self.vmin = 0.0 # Not used
        self.vmax = 1.0
        self.color_map_array = cp.array([[color[0], color[1], color[2], opacity]])
        self.nan_color = color # Not used
        self.nan_opacity = 1.0
        if opacity == 1.0:
            self.opaque = True
        else:
            self.opaque = False


# -*- coding: utf-8 -*-
"""
Created on Thu Dec 30 16:20:13 2021

@author: doudou
"""

import torch
import torch.nn as nn
import torch.nn.functional as F

import time # record the time record
import matplotlib.pyplot as plt #draw the diagram

import numpy as np #linear algebra
import datetime
import random
from DSL import *

from math import *
from Boomsday.omegas.dataloader import *
from config import *
import config as config

data = Mathloader(path,trainNum)

symbol_id_collection = []
# gain symbol id from tokenizer
for i in range(10):
    st = "the value symbol" + str(i) + " and what is that "
    idx = data.tokenize_data(st)[0][2]
    symbol_id_collection.append(idx)

def attention(q,words):
    att = torch.softmax(torch.matmul(words,q.permute(1,0)),-2)
    return torch.matmul(att.permute(1,0),words)

def del_tensor_ele(arr,index):
    arr1 = arr[0:index]
    arr2 = arr[index+1:]
    return torch.cat((arr1,arr2),dim=0)

class SymbolNet(nn.Module):
    def __init__(self,name):
        super().__init__()
        self.id = name
        self.wordvecs = nn.Embedding(10000, 232)

        self.pfc1 = nn.Linear(232,100)
        self.pfc2 = nn.Linear(100,64)
        #self.pfca = nn.Linear(64,100)
        self.pfc3 = nn.Linear(64,232)

    def forward(self,x):
        # shape : [1,n]

        symbolCount = 0
        # 1.step:
        X = torch.tensor(x)
        wvectors = self.wordvecs(X)[0]

        q = self.pfc3(self.pfc2(self.pfc1(wvectors)))
        embeds =attention(q,wvectors)
        embeds = torch.reshape(embeds,[1,-1,232])
        reserves = []
        # 2.step:
        for i in range(len(x[0])):
            item = x[0][i]
            word = data.tokenizer_en.sequences_to_texts([[item]])
            if ("symbol" in word[0]):
                reserves.append(i)

        # 3.step:
        symbols = embeds[0][idx]
        symbols = torch.reshape(symbols,[1,-1])
        for i in range(len(reserves)-1):
            symbols = torch.cat([symbols,torch.reshape(embeds[0][i+1],[1,-1])],0)

        return torch.tensor(symbols)

class Parser(nn.Module):
    def __init__(self,op_dim = 232, args_dim = 64,state_dim = 256,word_dim = 232, vocab = 10000):
        super(Parser, self).__init__()

        # create a list of vectors representing operators and words
        self.wordvecs = nn.Embedding(vocab, word_dim)
        self.op_vecs = nn.Embedding(vocab, op_dim)
        self.arg_vecs = nn.Embedding(vocab, args_dim)

        # Input of this model will be a set of embeddings of the operator

        # Recreate operators using pytorch
        self.state_dim = state_dim
        self.args_dim = args_dim
        self.op_dim = op_dim
        self.word_dim = word_dim

        # Synthesis methods required
        self.log_p = 0
        self.count = 0
        self.program = ""

        # to create the probability analyzer unit
        self.pfc1 = nn.Linear(state_dim,100)
        self.pfc2 = nn.Linear(100,64)
        #self.pfca = nn.Linear(64,100)
        self.pfc3 = nn.Linear(64,word_dim)
        # to create the repeater unit
        self.rfc1 = nn.Linear(args_dim+state_dim,200)
        self.rfc2 = nn.Linear(200,100)
        self.rfc3 = nn.Linear(100,state_dim)
        # Gated recurrential unit
        self.fGRU = torch.nn.GRU(word_dim,state_dim,1)
        self.bGRU = torch.nn.GRU(state_dim,state_dim,1)
        self.namo = "Math-Reaver"

        self.words = None
        self.attention_data = []
        self.DSL =MathDSL

        self.STCM = []
        self.sn = SymbolNet("LilRag")

    def attention(self,q,words):
        att = torch.softmax(torch.matmul(words,q.permute(1,0)),-2)
        self.attention_data.append(att)
        return torch.matmul(att.permute(1,0),words)

    def pdf_ops(self,opp,order_state):
        # shape of input variables are [num, embed_dim]
        # output will be the pdf tensor and the argmax position

        query = F.tanh(self.pfc1(order_state))
        query = F.softplus(self.pfc2(query))
        query = F.softplus(self.pfc3(query))

        fused = self.attention(query,self.words)

        #create pdf tensor

        pdf = torch.matmul(fused,opp.permute(1,0))

        pdf = torch.softmax(pdf,-1)[0]

        #index of the maximum operator is
        index = np.argmax(pdf.detach().numpy())
        return pdf, index

    def repeat_vector(self,semantics,arg):
        # Create next semantics vector for the argument
        r = torch.cat([semantics,arg],-1)
        r = F.tanh(self.rfc1(r))
        r = F.softplus(self.rfc2(r))
        r = F.tanh(self.rfc3(r))

        return r

    def convert(self,x,words):
        self.attention_data = []
        self.words = words
        # Start the parsing process
        self.log_p = 0
        self.program = ""
        self.count = 0
        def parse(s,arg,ops,ops_dict):
            # analogue goal-based policy in multi-goal RL
            # estimate the action to take when given the state (s) and the goal (arg)
            parse_state = self.repeat_vector(s,arg)
            # 1. create a state given the current state and the goal given
            pdf,index = self.pdf_ops(ops,parse_state)
            #index = ops_dict.index(ops_sequence[self.count])

            self.log_p  = self.log_p - torch.log(pdf[index])

            operator = ops_dict[index+1]
            self.program += str(operator)
            self.count += 1
            #print(ops_dict,index)
            # 2. pass the semantics down to next level if required

            if operator in self.DSL.arged_ops:
                self.program +=  "("

                args = self.DSL.arg_dict[operator]
                args_paramed = self.arg_vecs(torch.tensor(args))

                for i in range(len(args)):

                    if self.count < 35:
                        parse(parse_state,torch.reshape(args_paramed[i],[1,self.args_dim]),ops,ops_dict)
                    else:
                        self.program+="RandO"
                    if i != (len(args)-1):
                        self.program += ","
                self.program += ")"

        root = self.arg_vecs(torch.tensor([0]))
        ops = self.op_vecs(torch.tensor(self.DSL.ops))
        ops= torch.cat([ops,self.STCM],0)

        # TODO: dynamic library useage during the parsing
        operators = []
        operators.extend(self.DSL.operators)
        operators.extend(self.STOP)
        # TODO: dynamic library useage during the parsing
        parse(x,root,ops,operators)
        return self.program,self.log_p

    def program_prob(self,x,ops_sequence,words):
        self.attention_data = []
        self.words = words
        # Start the parsing process
        self.log_p = 0
        self.count = 0
        self.program = ""

        def parse(s,arg,ops,ops_dict,ops_sequence):
            # analogue goal-based policy in multi-goal RL
            # estimate the action to take when given the state (s) and the goal (arg)
            parse_state = self.repeat_vector(s,arg)
            # 1. create a state given the current state and the goal given

            pdf,index = self.pdf_ops(ops,parse_state)
            index = ops_dict.index(ops_sequence[self.count])

            self.log_p  = self.log_p - torch.log(pdf[index-1])
            operator = ops_dict[index]

            self.program += str(operator)

            # 2. pass the semantics down to next level if required
            self.count += 1

            if operator in self.DSL.arged_ops:
                self.program +=  "("

                args = self.DSL.arg_dict[operator]
                args_paramed = self.arg_vecs(torch.tensor(args))

                for i in range(len(args)):

                    if self.count < 35:
                        parse(parse_state,torch.reshape(args_paramed[i],[1,self.args_dim]),ops,ops_dict,ops_sequence)
                    else:
                        self.program+="RandO"
                    if i != (len(args)-1):
                        self.program += ","
                self.program += ")"

        root = self.arg_vecs(torch.tensor([0]))
        ops = self.op_vecs(torch.tensor(self.DSL.ops))
        ops= torch.cat([ops,self.STCM],0)

        # TODO: dynamic library useage during the parsing
        operators = []
        operators.extend(self.DSL.operators)
        operators.extend(self.STOP)

        parse(x,root,ops,operators,ops_sequence)
        return self.program,self.log_p

    def save_model(self):
        dirc = "D:/Omegas/" + str(self.namo) + "/"
        torch.save(self, dirc+self.namo + '.pth')

    def load_model(self):
        dirc = "D:/Omegas/" + str(self.namo) + "/"
        try:
            self = torch.load(dirc+self.namo + '.pth')
        except:
            print("Failed")

    def run(self,x,symbols,seq = None):
        self.STCM = self.sn(x)
        self.STOP = symbols
        sequence = self.wordvecs(torch.tensor(x))

        results,hidden  = self.fGRU(sequence)
        final_r,final_h = self.bGRU(hidden)

        hidden = torch.reshape(final_h,[final_h.shape[1],self.state_dim])
        semantics = torch.reshape(hidden[hidden.shape[0]-1],[1,self.state_dim])
        if seq != None:
            program,loss  = self.program_prob(semantics,seq,sequence[0])
        else:
            program,loss = self.convert(semantics,sequence[0])
        return program, loss

    def train(self,tasks,EPOCH,rate = 8e-5):
       optimizer =torch. optim.Adam(psr.parameters(), lr=rate)
       for epoch in range(EPOCH):
           Loss = 0.0
           for i in range(len(tasks)):
               seq = tasks[i][0]
               #print(tasks[i][1])
               #print(tasks[i][2])
               print(data.tokenizer_en.sequences_to_texts(tasks[i][0]))

               pro,loss = psr.run(seq,tasks[i][3],tasks[i][1])
               print("Program:",pro)
               print("Loss:",loss.detach().numpy())
               Loss += loss/10
               print(" ")
           optimizer.zero_grad()
           Loss.backward()
           optimizer.step()
           if epoch%100 == 0:
               print("EPOCH:",epoch,"Loss is ",Loss.detach().numpy())

def visualize_masks(masks):
    try:
        img = torch.cat([masks[0],masks[1]],-1)

        for i in range(len(masks)-2):
            img = torch.cat([img,masks[i+2]],-1)
    except:
        img = masks[0]
    img = img.permute(1,0)
    plt.cla()
    plt.imshow((img.view(1,masks.shape[0])).detach().numpy(),'bone')
    plt.pause(0.01)

def visualize_attention(att):
    plt.cla()
    try:
        img = torch.cat([att[0],att[1]],-1)
        for i in range(len(att)-2):
            img = torch.cat([img,att[i+2]],-1)
    except:
        img = att[0]

    plt.imshow(img.detach().numpy())
    plt.pause(1)

psr = Parser()
tasks = data.train_set[:10]
from karazhan.curator import *

tasks = data.make_tasks(ArithMatics)
psr.train(tasks,3000, 1e-4)

psr.run(tasks[0][0],tasks[0][3])
psr.run(data.convert_to_data(p),extract_symbols(p))

from sklearn.manifold import TSNE

tsne = TSNE(n_components=2)