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

CliMAF cache module : store, retrieve and manage CliMAF objects from their CRS expression.

"""
# Created : S.Sénési - 2014

from __future__ import print_function, division, unicode_literals, absolute_import

import six
import os.path
import re
import time
import pickle
import uuid
import hashlib
import json
from operator import itemgetter

import env
from env.environment import *
from env.clogging import clogger
from env.utils import get_subprocess_output
from climaf.utils import Climaf_Cache_Error, Climaf_Error
from climaf.classes import compare_trees, cobject, cdataset, guess_projects, allow_error_on_ds, ds, cens
from climaf.cmacro import crewrite
from climaf import __path__ as cpath

# Can be False, "by_crs" or anything else. 'by_crs' means key=CRS; else means key=hash
handle_cvalues = 'by_hash'
cvalues = dict()
#: The length for truncating the hash value of CRS expressions when forming cache filenames
fileNameLength = 60
#: Define whether we try to have safe naming of cache objects using adaptative filename length
safe = False
#: The length of subdir names when segmenting cache filenames
directoryNameLength = 5
#: The index associating filenames to CRS expressions
crs2filename = dict()
#: The dictionary associating CRS expressions to their evaluation
crs2eval = dict()
#: The list of crs which file has been dropped since last synchronisation between in-memory index and file index
#  (or at least since the beginning of the session)
dropped_crs = list()

#: A dict containing cache index entries (as listed in index file), which
# were up to now not interpretable, given the set of defined projects
crs_not_yet_evaluable = dict()
dic_special = dict()

def setNewUniqueCache(path, raz=True):
    """
    Define PATH as the sole cache to use from now. And clear it
    """

    path = os.path.expanduser(path)
    env.environment.cachedirs = [path]  # The list of cache directories
    env.environment.cacheIndexFileName = path + \
        "/index"  # The place to write the index
    env.environment.currentCache = path
    if raz:
        craz(hideError=True)

def generateUniqueFileName(expression, format="nc", option="new", create_dirs=True):
    """
    Generate a filename path from string EXPRESSION and FILEFORMAT,
    almost unique for the expression and the cache directory

    This uses hashlib.sha224, which are truncated to fileNameLength.

    Generated names drive a structure where each directory name
    has dirNameLength characters

    If the filename already exists and is a symbolic link, check that the target
    actually exists, otherwise delete the link
    """
    #
    if format is None:
        return ""
    else:
        prefix = ""
        vhash = hashlib.sha224(expression.encode("utf-8")).hexdigest()
        rep = hash_to_path(vhash, format, option=option, prefix=prefix)
        # Create the relevant directory, so that user scripts don't have to care
        if create_dirs:
            dirn = os.path.dirname(rep)
            if not os.path.exists(dirn):
                try:
                    os.makedirs(dirn)
                except OSError:
                    if os.path.exists(dirn):
                        # Happens when two concurrent CliMAF are
                        # creating numerous cache files
                        pass
                    else:
                        raise Climaf_Cache_Error("Cannot create dir " % dirn)
        if os.path.islink(rep) and not os.path.exists(os.path.realpath(rep)):
            os.remove(rep)
        clogger.debug("returning %s" % rep)
        return rep

def hash_to_path(vhash, format, option="new", prefix=""):
    if option in ["new", ]:
        rep = os.sep.join([env.environment.currentCache,
                          prefix + vhash[0:2], vhash[2:]])
    else:
        rep = os.sep.join([env.environment.currentCache,
                           prefix + stringToPath(vhash[0:fileNameLength - 1], directoryNameLength)])
    rep = ".".join([rep, format])
    rep = os.path.expanduser(rep)
    return rep

def alternate_filename(fpath):
    """
    The cache tree structure has been changed from some CliMAF version.
    Function alternate_filename, when provided with an old form path,
    returns a new form path (and vice versa)
    Useful for handling transition between cache structures
    """
    # Get file format
    format = fpath.split(".")[-1]
    # Remove cache root location prefix
    relative_fpath = fpath[len(env.environment.currentCache) + 1:]
    # Get name without slashes nor extension
    vhash = relative_fpath.replace("/", "").split(".")[0]
    #
    # Test if new path, i.e. with two letters before first "/"
    if relative_fpath[2] == "/":
        option = "old"
    else:
        option = "new"
    rep = hash_to_path(vhash, format, option)
    return rep

def stringToPath(name, length):
    """ Breaks NAME to a path with LENGTH characters-long directory names , for avoiding crowded directories"""
    len_name = len(name)
    rep = ""
    i = 0
    while i + length < len_name:
        rep = rep + name[i:i + length] + "/"
        i += length
    rep += name[i:len_name]
    return rep

def searchFile(path):
    """ Search for first occurrence of PATH as a path in all
    directories listed in CACHEDIRS
    """
    for cdir in env.environment.cachedirs:
        candidate = os.path.expanduser(cdir + "/" + path)
        if os.path.lexists(candidate):
            # If this is a broken link, delete it ~ silently and return None
            if not os.path.exists(candidate):
                clogger.debug("Broken link for %s was deleted" % candidate)
                os.remove(candidate)
                return None
            return candidate

def register(filename, crs, costs, outfilename=None):
    """
    Adds in FILE a metadata named 'CRS_def' and with value CRS, and a
    metadata 'CLiMAF' with CliMAF version and ref URL

    Records this FILE in dict crs2filename

    If OUTFILENAME is not None, FILENAME is a temporary file and
    it is OUTFILENAME which is recorded in dict crs2filename

    Silently skip non-existing files
    """
    def do_move(crs, filename, outfilename):
        if outfilename is None:
            clogger.info("%s registered as %s" % (crs, filename))
            crs2filename[crs] = (filename, costs)
            if crs in dropped_crs:
                dropped_crs.remove(crs)
            return True
        else:
            cmd = 'mv -f %s %s ' % (filename, outfilename)
            if os.system(cmd) == 0:
                clogger.info("moved %s as %s " % (filename, outfilename))
                clogger.info("%s registered as %s" % (crs, outfilename))
                crs2filename[crs] = (outfilename, costs)
                if crs in dropped_crs:
                    dropped_crs.remove(crs)
                return True
            else:
                # clogger.critical("cannot move by" % cmd)
                raise Climaf_Cache_Error(
                    "cannot move (possibly after stamping) by %s" % cmd)

    global dropped_crs
    #
    # It appears that we have to let some time to the file system  for updating its inode tables
    waited = 0
    while waited < 50 and not os.path.exists(filename):
        time.sleep(0.1)
        waited += 1
    if not os.path.exists(filename):
        raise Climaf_Cache_Error("File %s wasn't created upstream (or not quick enough). It represents %s" %
                                 (filename, crs))
    else:
        if stamping is False:
            clogger.debug('No stamping')
            return do_move(crs, filename, outfilename)
        else:
            # while time.time() < os.path.getmtime(filename) + 0.2 : time.sleep(0.2)
            if re.findall(".nc$", filename) and ncatted_software is not None:
                command = "%s -h -a CRS_def,global,o,c,\"%s\" -a CliMAF,global,o,c,\"CLImate Model Assessment " \
                          "Framework version %s (http://climaf.rtfd.org)\" %s" % (ncatted_software, crs, climaf_version,
                                                                                filename)
            elif re.findall(".png$", filename) and convert_software is not None:
                crs2 = crs.replace(r"%", r"\%").replace(r'"', r'\"')
                command = "%s -set \"CRS_def\" \"%s\" -set \"CliMAF\" " \
                          "\"CLImate Model Assessment Framework version " \
                          "%s (http://climaf.rtfd.org)\" %s %s.png && mv -f %s.png %s" % \
                          (convert_software, crs2, climaf_version,
                           filename, filename, filename, filename)
            elif re.findall(".pdf$", filename) and pdftk_software is not None:
                tmpfile = str(uuid.uuid4())
                command = "%s %s dump_data output %s && echo -e \"InfoBegin\nInfoKey: Keywords\nInfoValue: %s\" " \
                          ">> %s && %s %s update_info %s output %s.pdf && mv -f %s.pdf %s && rm -f %s" % \
                          (pdftk_software, filename, tmpfile, crs, tmpfile, pdftk_software, filename, tmpfile, filename,
                           filename, filename, tmpfile)
            elif re.findall(".eps$", filename) and exiv2_software is not None:
                command = '%s -M"add Xmp.dc.CliMAF CLImate Model Assessment Framework version %s ' \
                          '(http://climaf.rtfd.org)" -M"add Xmp.dc.CRS_def %s" %s' % \
                          (exiv2_software, climaf_version, crs, filename)
            else:
                command = None
            if command is None:
                if stamping is None:
                    clogger.warning(
                        "Command is None and stamping is None. No stamping done.")
                    return do_move(crs, filename, outfilename)
                elif stamping is True:
                    raise Climaf_Cache_Error("Cannot stamp by command None. "
                                             "You may set climaf.cache.stamping to False or None - see doc\n%s" %
                                             command)
            else:
                clogger.debug("trying stamping by %s" % command)
                command_return = os.system(command)
                if command_return == 0 or stamping is not True:
                    return do_move(crs, filename, outfilename)
                if command_return != 0:
                    if stamping is True:
                        raise Climaf_Cache_Error("Cannot stamp by command below. "
                                                 "You may set climaf.cache.stamping to False or None - see doc\n%s" %
                                                 command)
                    elif stamping is None:
                        clogger.critical("Cannot stamp by %s" % command)
                        return True

def getCRS(filename):
    """ Returns the CRS expression found in FILENAME's meta-data"""
    if re.findall(".nc$", filename):
        form = 'ncdump -h %s | grep -E "CRS_def *=" | ' + \
               'sed -r -e "s/.*:CRS_def *= *\\\"(.*)\\\" *;$/\\1/" '
    elif re.findall(".png$", filename):
        form = 'identify -verbose %s | grep -E " *CRS_def: " | sed -r -e "s/.*CRS_def: *//"'
    elif re.findall(".pdf$", filename):
        form = 'pdfinfo %s | grep "Keywords" | awk -F ":" \'{print $2}\' | sed "s/^ *//g"'
    elif re.findall(".eps$", filename):
        form = 'exiv2 -p x %s | grep "CRS_def" | awk \'{for (i=4;i<=NF;i++) {print $i " "} }\' '
    else:
        clogger.error("unknown filetype for %s" % filename)
        return None
    command = form % filename
    try:
        rep = get_subprocess_output(command, to_replace=[("\n", "")])
        if (rep == "") and ('Empty.png' not in filename):
            clogger.error("file %s is not well formed (no CRS)" % filename)
        if re.findall(".nc$", filename):
            rep = rep.replace(r"\'", r"'")
    except:
        rep = "failed"
    clogger.debug("CRS expression read in %s is %s" % (filename, rep))
    return rep

def rename(filename, crs):
    """ Rename FILENAME to match CRS. Also updates crs in file and
    crs2filename """
    newfile = generateUniqueFileName(crs, format="nc")
    if newfile:
        costs = 0.
        for c in [f for f in crs2filename if crs2filename[f][0] in [filename, alternate_filename(filename)]]:
            _, costs = crs2filename.pop(c)
        os.rename(filename, newfile)
        register(newfile, crs, costs)
        return newfile

def hasMatchingObject(cobject, ds_func):
    """
    If the cache holds a file which represents an object with the
    same nodes as COBJECT and which leaves/datasets, when paired with
    those of COBJECT and applying ds_func, returns an identical (and not
    None) value for all pairs, then returns its filename, its CRS and
    this value (for the first one in dict crs2filename)

    Can be applied for finding same object with included or including
    time-period
    """

    # First read index from file if it is yet empty - No : done at startup
    # if len(crs2filename.keys()) == 0 : cload()
    def op_squeezes_time(operator):
        return not cscripts[operator].flags.commuteWithTimeConcatenation

    #
    global crs2eval
    key_to_rm = list()
    for crs in crs2filename:
        # First, basic, screening
        if crs.split("(")[0] != cobject.crs.split("(")[0]:
            continue
        co = crs2eval.get(crs, None)
        if co is None:
            try:
                co = eval(crs, sys.modules['__main__'].__dict__)
            except:
                continue  # usually case of a CRS which project is not currently defined
        if co:
            crs2eval[crs] = co
            clogger.debug("Compare trees for %s and %s" % (crs, cobject.crs))
            altperiod = compare_trees(co, cobject, ds_func, op_squeezes_time)
            if altperiod:
                f, costs = crs2filename[crs]
                if os.path.exists(f) or os.path.exists(alternate_filename(f)):
                    return co, altperiod
                else:
                    clogger.debug(
                        "Removing %s from cache index, because file is missing", crs)
                    key_to_rm.append(crs)
    for el in key_to_rm:
        crs2filename.pop(el)
    return None, None

def hasIncludingObject(cobject):
    def ds_period_difference(includer, included):
        if includer.buildcrs(period="") == included.buildcrs(period=""):
            return includer.period.includes(included.period)

    clogger.debug("search for including object for " + repr(cobject))
    return hasMatchingObject(cobject, ds_period_difference)

def hasBeginObject(cobject):
    def ds_period_begins(begin, longer):
        if longer.buildcrs(period="") == begin.buildcrs(period=""):
            return longer.period.start_with(begin.period)

    return hasMatchingObject(cobject, ds_period_begins)

def hasExactObject(cobject):
    i = 0
    found = False
    formats_to_test = known_formats + graphic_formats
    f = None
    while not found and i < len(formats_to_test):
        f = generateUniqueFileName(
            cobject.crs, format=formats_to_test[i], create_dirs=False)
        if os.path.exists(f):
            found = True
        else:
            f = alternate_filename(f)
            if os.path.exists(f):
                found = True
            else:
                i += 1
    if found and f is not None:
        crs = cobject.crs
        # if isinstance(cobject, cdataset):
        #    crs = "select(" + crs + ")"
        if crs not in crs2filename:
            clogger.warning("Next object exists in cache but was not "
                            "registered in index. Assuming its compute cost is zero. "
                            "Use cdrop if this is inadequate. Object %s" % crs)
            crs2filename[crs] = (f, compute_cost())
        return crs2filename[crs]
        # return f
    else:
        if cobject.crs in crs2filename:
            clogger.debug(
                "Dropping cobject.crs from cache index, because file is missing")
            crs2filename.pop(cobject.crs)
        return None, compute_cost()

def complement(crsb, crse, crs):
    """ Extends time period of file object of CRSB (B for 'begin')
    with file object of CRSE (E for 'end') for creating file object of
    CRS. Assumes that everything is OK with args compatibility and
    file contents
    """
    fileb, costsb = crs2filename[crsb]
    if not os.path.exists(fileb):
        fileb = alternate_filename(fileb)
    filee, costse = crs2filename[crse]
    if not os.path.exists(filee):
        filee = alternate_filename(filee)
    filet = generateUniqueFileName(crs)
    costs = compute_cost()
    costs.add(costsb)
    costs.add(costse)
    tim1 = time.time()
    command = "ncrcat -O %s %s %s" % (fileb, filee, filet)
    duration = time.time() - tim1
    costs.increment(duration)
    if os.system(command) != 0:
        clogger.error("Issue when merging %s and %s in %s (using command:%s)" % (
            crsb, crse, crs, command))
        return None, costs
    else:
        cdrop(crsb)
        cdrop(crse)
        register(filet, crs, costs)
        return filet, costs

def cdrop(obj, rm=True, force=False):
    """
    Deletes the cached file for a CliMAF object, if it exists

    Args:
     obj (cobject or string) : object to delete, or its string representation (CRS)

     force (bool) : should we delete the object even if it is 'protected'

     rm (bool) : for advanced use only; should we actually delete (rm) the file, or just forget it in CliMAF cache index

    Returns:
     None if object does not exists, False if failing to delete, True if OK

    Example ::

    >>> dg=ds(project='example', simulation='AMIPV6ALB2G', variable='tas', period='1980-1981')
    >>> f=cfile(dg)
    >>> os.system('ls -al '+f)
    >>> cdrop(dg)

    """
    global crs2filename
    global dropped_crs

    if isinstance(obj, cobject):
        crs = repr(obj)
    elif isinstance(obj, six.string_types):
        crs = str(obj)
    else:
        clogger.error("%s is not a CliMAF object" % repr(obj))
        return
    if crs in crs2filename:
        clogger.info(
            "Discarding cached value for %s (except if protected)" % crs)
        fil, _ = crs2filename[crs]
        if not os.path.exists(fil):
            fil = alternate_filename(fil)
    else:
        # In case the cache index is not up-to-date
        fil, cost = hasExactObject(obj)
        if fil:
            crs2filename[crs] = (fil, compute_cost())
    if fil:
        if rm:
            try:
                if force:
                    os.system("chmod +w " + fil)
                if not os.access(fil, os.W_OK):
                    clogger.info("Object %s is protected" % crs)
                    return
                path_file = os.path.dirname(fil)
                os.remove(fil)
                crs2filename.pop(crs)
                dropped_crs.append(crs)
                try:
                    os.rmdir(path_file)
                except OSError:
                    pass
                return True
            except:
                clogger.warning(
                    "When trying to remove %s : file does not exist in cache" % crs)
                return False
    else:
        clogger.info("%s is not cached" % crs)
        return None

def cprotect(obj, stop=False):
    """
    Protects the cache file for a given object (or stops protection with arg 'stop=True').

    In order to erase it, argument 'force=True' must then be used with function
    :py:func:`~climaf.cache.craz` or :py:func:`~climaf.cache.cdrop`

    """
    if isinstance(obj, cobject):
        crs = repr(obj)
        if isinstance(obj, cdataset):
            crs = "select(" + crs + ")"
    elif isinstance(obj, six.string_types):
        crs = obj
    else:
        clogger.error("%s is not a CliMAF object" % repr(obj))
        return
    if crs in crs2filename:
        f, _ = crs2filename[crs]
        if not os.path.exists(f):
            f = alternate_filename(f)
        if stop is False:
            clogger.info("Protecting cached value for " + crs)
            os.system("chmod -w " + f)
        else:
            clogger.info("Stopping protection on cached value for " + crs)
            os.system("chmod +w " + f)
        return
    else:
        clogger.info("%s is not (yet) cached; use cfile() to cache it" % crs)

def csync(update=False):
    """
    Merges current in-memory cache index and current on-file cache index
    for updating both

    If arg `update` is True, additionally ensures consistency between files
    set and index content, either :

    - if cache.stamping is true, by reading CRS in all files
    - else, by removing files which are not in the index; this may erase
      result files which have been computed by another running
      instance of CliMAF
    """
    #
    import pickle
    global cacheIndexFileName
    global dropped_crs
    global crs2filename

    # Merge index on file and index in memory
    file_index = cload(True)
    for crs in dropped_crs:
        file_index.pop(crs, None)
    crs2filename.update(file_index)

    # check if cache index is up to date; if not enforce consistency
    if update:
        clogger.info("Listing crs from files present in cache")
        files_in_cache = list_cache()
        files_in_cache.sort()
        files_costs = list(crs2filename.values())
        files_in_index = [f[0] for f in files_costs]
        files_in_index.sort()
        if files_in_index != files_in_cache:
            if stamping:
                clogger.info("Rebuilding cache index from file content")
                rebuild()
            else:
                clogger.warning('In no stamp mode, there is no way to seriously '
                                'identify CRS from files in cache  !')
                # clogger.warning('Removing cache files which content is not known.
                # This is an issue in concurrent mode !')
                # for fil in files_in_cache :
                #     if fil not in files_in_index :
                #         os.system("rm %"%fil)
                # else :
                # Should also remove empty files, as soon as
                # file creation will be atomic enough
    # Save index to disk
    fn = os.path.expanduser(env.environment.cacheIndexFileName)
    with open(fn, "wb") as cacheIndexFile:
        pickle.dump(crs2filename, cacheIndexFile)
    dropped_crs = list()

def cload(alt=None):
    global crs2filename
    global crs_not_yet_evaluable
    rep = dict()

    if len(crs2filename) != 0 and not alt:
        raise Climaf_Cache_Error(
            "attempt to reset cache index - would lead to inconsistency !")
    cacheFilen = os.path.expanduser(env.environment.cacheIndexFileName)
    if not os.path.exists(cacheFilen):
        clogger.debug("no index file yet")
        return {}
    with open(cacheFilen, "rb") as cacheIndexFile:
        rep = pickle.load(cacheIndexFile)
        for c in rep:
            f = rep[c]
            if type(f) is tuple:
                f, costs = f
            else:
                costs = compute_cost()
            if len(f.split("/")[-2]) == directoryNameLength:
                f = alternate_filename(f)
            rep[c] = (f, costs)
        #
        if alt:
            return rep
        else:
            crs2filename = rep
    #
    must_check_index_entries = False
    if must_check_index_entries:
        # We may have some crs inherited from past sessions and for which
        # some operator may have become non-standard, or some projects are yet
        # undeclared
        crs_not_yet_evaluable = dict()
        allow_error_on_ds()
        for crs in list(crs2filename.keys()):
            try:
                # print "evaluating crs="+crs
                eval(crs, sys.modules['__main__'].__dict__)
            except:
                print("Inconsistent cache object is skipped : %s" % crs)
                # clogger.debug("Inconsistent cache object is skipped : %s"%crs)
                p = guess_projects(crs)
                if p not in crs_not_yet_evaluable:
                    crs_not_yet_evaluable[p] = dict()
                crs_not_yet_evaluable[p][crs] = crs2filename[crs]
                crs2filename.pop(crs)
                # Analyze projects of inconsistent cache objects
                projects = list(crs_not_yet_evaluable)
                if projects:
                    clogger.info(
                        "The cache has %d objects for non-declared projects %s.\n"
                        "For using it, consider including relevant project(s) "
                        "declaration(s) in ~/.climaf and restarting CliMAF.\n"
                        "You can also declare these projects right now and call 'csync(True)'\n"
                        "Or you can erase corresponding data by 'crm(pattern=...project name...)'" %
                        (len(crs_not_yet_evaluable), repr(list(projects))))
        allow_error_on_ds(False)

def cload_for_project(project):
    """
    Append to the cache index dict those left index entries for 'project' which evaluate successfully
    """
    d = crs_not_yet_evaluable[project]
    for crs in d.copy():
        try:
            # print "evaluating crs="+crs
            eval(crs, sys.modules['__main__'].__dict__)
            crs2filename[crs] = d[crs]
            d.pop(crs)
        except:
            clogger.error(
                "CRS expression %s is not valid for project %s" % (crs, project))

def craz(force=False, hideError=False):
    """
    Clear CliMAF cache : erase existing files content, reset in-memory index

    Args:
      force (bool): should we erase also all 'protected' files

      hideError (bool): if True, will not warn for non existing cache

    """
    global crs2filename
    cc = os.path.expanduser(env.environment.currentCache)
    if os.path.exists(env.environment.currentCache) or hideError is False:
        if force:
            os.system("chmod -R +w  " + cc)
            os.system("rm -fR " + cc + "/*")
            crs2filename = dict()
        else:
            list_of_crs = list(crs2filename)
            for crs in list_of_crs:
                if cdrop(crs):
                    clogger.debug('Removed file: %s',
                                  generateUniqueFileName(crs))
                else:
                    clogger.debug(
                        'Could not remove file (either not existing or protected): %s', crs2filename[crs])
                    clogger.debug('Associated CRS : %s', crs)
        # os.system("ls  " + cc)

def cdump(use_macro=True):
    """
    List the in-memory content of CliMAF cache index. Interpret it
    using macros except if arg use_macro is False

    """
    for crs in crs2filename:
        if not use_macro:
            # No interpretation by macros
            # print "%s : %s"%(crs2filename[crs][-30:],crs)
            print("%s : %s" % (crs2filename[crs], crs))
        else:
            # Must update for new macros
            print("%s : %s" % (crs2filename[crs], crewrite(crs)))

def list_cache():
    """
    Return the list of files in cache directories, using `find`

    """
    find_return = ""
    for dir_cache in env.environment.cachedirs:
        rep = os.path.expanduser(dir_cache)
        filter = r" \( -name '*.png' -o -name '*.nc' -o -name '*.pdf' -o -name '*.eps' \) "
        with os.popen(r"find %s -type f " % rep + filter + " -print") as fil:
            find_return += fil.read()
    files_in_cache = find_return.split('\n')
    files_in_cache.pop(-1)
    return files_in_cache

def clist(size="", age="", access=0, pattern="", not_pattern="", usage=False, count=False,
          remove=False, CRS=False, special=False):
    """
    Internal function used by its front-ends : :py:func:`~climaf.cache.cls`, :py:func:`~climaf.cache.crm`,
    :py:func:`~climaf.cache.cdu`, :py:func:`~climaf.cache.cwc`

    List the content of CliMAF cache according to some search criteria
    and operate possibly an action (usage, count or remove) on this list.

    Please consider the cost and benefit of first updating CliMAF cache index (by scanning
    files on disk) using :py:func:`csync()`

    Args:
     size (string, optional): n[ckMG]
      Search files using more than n units of disk space, rounding up.
      The following suffixes can be used:

        - "c"    for bytes (default)
        - "k"    for Kilobytes (units of         1,024 bytes)
        - "M"    for Megabytes (units of     1,048,576 bytes)
        - "G"    for Gigabytes (units of 1,073,741,824 bytes)

     age (string, optional): Number of 24h periods. Search files which
      status was last changed n*24 hours ago.
      Any fractional part is ignored, so to match age='+1', a file has
      to have been changed at least two days ago.
      Numeric arguments can be specified as:

        - `+n`   for greater than n
        - `-n`   for less than n,
        - `n`    for exactly n.

     access (int, optional): n
      Search files which were last accessed more than n*24 hours ago. Any
      fractional part is ignored, so to match access='1', a file has to
      have been accessed at least two days ago.

     pattern (string, optional): Scan through crs and filenames looking for
      the first location where the regular expression pattern produces a match.

     not_pattern (string, optional): Scan through crs and filenames looking
      for the location where the regular expression not_pattern does not
      produce a match.

     usage (bool, optional): Estimate found files space usage, for each
      found file and total size. If count is True, estimate only found
      files total space usage.

     count (bool, optional): Return the number of found files. If CRS is True,
      also return crs of found files.

     remove (bool, optional): Remove the found files. This argument is exclusive.

     CRS (bool, optional): if True, print also CRS expression. Useful only
      if count is True.

    Return:
      The dictionary corresponding to the request and associated action ( or dictionary
      of CliMAF cache index if no argument is provided)

     Example to search files using more than 3M of disk space, which status
      was last changed more than 15 days ago and containing the pattern
      '1980-1981' either in crs or filename. For found files, we want to
      estimate only found files total space usage::

      >>> clist(size='3M', age='+15', pattern= '1980-1981', usage=True, count=True)

    """

    # cache directories
    # TBD: le cache ne contient qu un rep pr le moment => voir pour boucler sur tous les caches
    rep = os.path.expanduser(env.environment.cachedirs[0])

    # command for research on size/age/access
    opt_find = ""
    if size:
        if re.search('[kMG]', size) is None:
            opt_find += "-size +%sc " % size
        else:
            opt_find += "-size +%s " % size
    if age:
        opt_find += "-ctime %s " % age
    if access != 0:
        opt_find += "-atime +%s" % str(int(access))

    var_find = False
    if size or age or access != 0:
        var_find = True
        command = r"find %s -type f \( -name '*.png' -o -name '*.nc' -o -name '*.pdf' -o -name '*.eps' \) %s -print" % \
                  (rep, opt_find)
        clogger.debug("Find command is :" + command)

        # construction of the new dictionary after research on size/age/access
        new_dict = dict()

        find_return = os.popen(command).read()
        list_search_files_after_find = find_return.split('\n')
        list_search_files_after_find.pop(-1)
        clogger.debug("List of search files: " +
                      repr(list_search_files_after_find))

        # Search CRS for each found file
        for filen in list_search_files_after_find:
            for crs in crs2filename:
                if crs2filename[crs][0] == filen:
                    new_dict[crs] = crs2filename[crs]

        if len(new_dict) != 0:
            if new_dict != crs2filename:
                clogger.debug(
                    "Dictionary after find for size/age/access: " + repr(new_dict))
            else:
                clogger.debug(
                    "Size/age/access criteria do not lead to any filtering")
        else:
            clogger.debug("No file meet the size/age/access criteria")
    else:
        new_dict = crs2filename.copy()

    # size of new dictionary
    len_new_dict = len(new_dict)

    # filter on pattern
    find_pattern = False
    if pattern:
        list_crs_to_rm = list()
        for crs in new_dict:
            try:
                if re.search(pattern, crewrite(crs)) or re.search(pattern, new_dict[crs][0]):
                    clogger.debug("Pattern found in %s: %s" %
                                  (crs, new_dict[crs][0]))
                    find_pattern = True
                else:
                    # Do not remove now from new_dict, because we loop on it
                    list_crs_to_rm.append(crs)
            except:
                print("bad type for arguments to re.search : ", crewrite(crs), type(crewrite(crs)), new_dict[crs][0],
                      type(new_dict[crs][0]))
        for crs in list_crs_to_rm:
            del new_dict[crs]

        if find_pattern:
            clogger.debug(
                "Dictionary after search for pattern: " + repr(new_dict))
        elif len_new_dict != 0:
            clogger.debug("No string found for pattern => no result")

    # update size new dictionary
    len_new_dict = len(new_dict)

    # research on not_pattern
    find_not_pattern = False
    if not_pattern:
        list_crs_to_rm = []
        for crs in new_dict:
            if re.search(not_pattern, crewrite(crs)) is None and \
                    re.search(not_pattern, new_dict[crs][0]) is None:
                clogger.debug("Pattern not found in %s: %s" %
                              (crs, new_dict[crs][0]))
                find_not_pattern = True
            else:
                list_crs_to_rm.append(crs)
        for crs in list_crs_to_rm:
            del new_dict[crs]

        if find_not_pattern:
            clogger.debug(
                "Dictionary after search for not_pattern: " + repr(new_dict))
        elif len_new_dict != 0:
            clogger.debug("All strings contain not_pattern => no result")

    # update size new dictionary
    len_new_dict = len(new_dict)

    # request on new dictionary through usage, count and remove
    work_dic = new_dict if (var_find or pattern !=
                            "" or not_pattern != "") else crs2filename

    if usage is True and len_new_dict != 0:
        # construction of a dictionary containing crs and disk-usage associated
        dic_usage = dict()
        tmp = ""
        for crs in work_dic:
            tmp += work_dic[crs] + " "
        res = os.popen("du -sc %s" % tmp).read()

        regex = re.compile('([0-9]+)\t')
        list_size = re.findall(regex, res)
        regex2 = re.compile('([0-9]+\t)')
        str_path = regex2.sub('', res)
        list_fig = str_path.split('\n')
        list_fig.pop(-1)

        for fig, size in zip(list_fig, list_size):
            if fig != "total":
                for crs in work_dic:
                    if fig == work_dic[crs]:
                        dic_usage[crs] = size
            else:
                dic_usage[fig] = size

        # sort of usage dictionary and units conversion
        du_list_sort = list(dic_usage.items())
        du_list_sort.sort(key=itemgetter(1), reverse=False)

        unit = ["K", "M", "G", "T"]
        for n, pair in enumerate(du_list_sort):
            i = 0
            flt = float(pair[1])
            while flt >= 1024. and i < 4:
                flt /= 1024.
                i += 1
            du_list_sort[n] = (du_list_sort[n][0], "%6.1f%s" % (flt, unit[i]))

        if count is True:  # Display total volume of found files
            for fig, size in du_list_sort:
                if fig == "total":
                    print("%7s : %s" % (size, fig))

        else:  # retrieve disk-usage of each found file and total volume
            for fig, size in du_list_sort:
                print("%7s : %s" % (size, fig))

    elif count is True and len_new_dict != 0:
        print("Number of files found:", len(work_dic))
        if CRS is True:
            for crs in work_dic:
                print(crs)

    elif remove is True and len_new_dict != 0:
        print("Removed files:")
        if var_find or pattern != "" or not_pattern != "":
            list_tmp_crs = list(new_dict)
        else:
            list_tmp_crs = list(crs2filename)
        for crs in list_tmp_crs:
            cdrop(crs, rm=True)
        return list(map(crewrite, list_tmp_crs))

    else:  # usage, count and remove are False
        if var_find or pattern != "" or not_pattern != "":
            if len(new_dict) != 0:
                if new_dict != crs2filename:
                    print("Filtered objects :")
                else:
                    print("Filtered objects = cache content")
                return list(map(crewrite, new_dict))
            # else : print "No matching file "
        else:
            print("Content of CliMAF cache")
            return list(map(crewrite, crs2filename))

    # TBD
    if special is True:
        global dic_special
        dic_special = dict()
        if var_find is True or pattern != "" or not_pattern != "":
            dic_special = new_dict.copy()
        else:
            dic_special = crs2filename.copy()
        print("List of marked figures as 'special'", list(dic_special.values()))
        return dic_special  # TBD: declarer comme var globale et enlever son effacement dans creset

    new_dict.clear()

def cls(**kwargs):
    """
    List CliMAF cache objects. Synonym to clist(). See :py:func:`~climaf.cache.clist`

    """
    return clist(**kwargs)

def crm(**kwargs):
    """
    Remove the cache files found by 'clist()' when using same arguments.
    See :py:func:`~climaf.cache.clist`

    Example to remove files using more than 3M of disk space, which status
    was last changed more than 15 days ago and containing the pattern
    '1980-1981' either in crs or filename::

     >>> crm(size='3M', age='+15', pattern='1980-1981')

    """
    kwargs['remove'] = True
    kwargs['usage'] = False
    kwargs['count'] = False
    return clist(**kwargs)

def cdu(**kwargs):
    """
    Report disk usage, for files matching some criteria, as specified
    for :py:func:`~climaf.cache.clist`. With count=True, report only total disk usage.

    Example to search files using more than 3M of disk space, which status
    was last changed more than 15 days ago and containing the pattern '1980-1981'
    either in crs or filename. For found files, we want to
    estimate only found files total space usage::

      >>> cdu(size='3M', age='+15', pattern= '1980-1981', count=True)

    """
    kwargs['usage'] = True
    kwargs['remove'] = False
    return clist(**kwargs)

def cwc(**kwargs):
    """
    Report number of cache files matching some criteria, as specified
    for :py:func:`~climaf.cache.clist`. If CRS is True, also return CRS expression
    of found files.

    Example to return the number and crs associated of files using more
    than 3M of disk space, which status was last changed more than 15
    days ago and containing the pattern '1980-1981' either in crs or
    filename::

     >>> cwc(size='3M', age='+15', pattern= '1980-1981', CRS=True)

    """
    kwargs['count'] = True
    kwargs['remove'] = False
    kwargs['usage'] = False
    return clist(**kwargs)

def rebuild():
    """
    Rebuild the in-memory content of CliMAF cache index

    """
    global crs2filename

    if not stamping:
        clogger.warning(
            "Cannot rebuild cache index, because we are not in 'stamping' mode")
        return None
    files_in_cache = list_cache()
    crs2filename.clear()
    for files in files_in_cache:
        filecrs = getCRS(files)
        if filecrs:
            crs2filename[filecrs] = (files, compute_cost())
        else:
            os.system('rm -f ' + files)
            clogger.warning("File %s is removed" % files)
    return crs2filename

def store_cvalue(crs, index, value, costs):
    """
    Stores a scalar, as computed by cvalue, in a scalars cache
    """
    if handle_cvalues is not False:
        if handle_cvalues in ["by_crs", ]:
            key = hashlib.sha224(
                (crs + "%d" % index).encode("utf-8")).hexdigest()
        else:
            key = crs + "[%d]" % index
        cvalues[key] = value, costs

def has_cvalue(crs, index):
    """
    Returns a scalar, as computed by cvalue, from the scalars cache (or None if not cached)
    """
    if handle_cvalues is not False:
        if handle_cvalues in ["by_crs", ]:
            key = hashlib.sha224(
                (crs + "%d" % index).encode("utf-8")).hexdigest()
        else:
            key = crs + "[%d]" % index
        value = cvalues.get(key, None)
        if value is not None:
            if not type(value) is tuple:
                return value, compute_cost()
            else:
                return value
    return None, compute_cost()

def load_cvalues():
    """
    Load in memory the cache of 'cvalue' scalars, from json file cvalues.json
    """
    global cvalues

    if handle_cvalues is not False:
        cache_file = os.sep.join(
            [env.environment.currentCache, "cvalues.json"])
        if os.path.exists(cache_file):
            with open(cache_file, "r") as f:
                tmp = json.load(f)
            cvalues = decode_index(tmp)
            del tmp

def sync_cvalues():
    """
    Read the on-disk of 'cvalue' scalars, update it with the in-memory one and
    write it in json file cvalues.json
    """
    global cvalues

    if handle_cvalues is not False:
        currentCache = env.environment.currentCache
        if not os.path.isdir(currentCache):
            os.makedirs(currentCache)
        ccache = os.path.sep.join([currentCache, "cvalues.json"])
        #
        if os.path.exists(ccache):
            # get pre-existing on-disk content
            with open(ccache, "r") as f:
                encoded = json.load(f)
            onfile = decode_index(encoded)
            del encoded
            onfile.update(cvalues)
            del cvalues
            cvalues = onfile
        tmp = ccache.replace(".json", ".tmp")
        with open(tmp, "w") as f:
            tofile = encode_index(cvalues)
            json.dump(tofile, f, separators=(',', ': '),
                      indent=3, ensure_ascii=True)
            del tofile
        os.rename(tmp, ccache)

def raz_cvalues():
    """
    Clear in-memory and on-disk cache of 'cvalue' scalars
    """
    global cvalues

    if handle_cvalues is not False:
        cvalues = dict()
        sync_cvalues()

class compute_cost(object):
    """
    Handling compute costs for objects :
    - tc : a cost for all compute operations involved in object's genesis
    - lc : another cost, for the last( top-level) operation
    """

    def __init__(self, cost=0., total_cost=None):
        """
        Create a compute_cost object.
        COST -> last_operation_cost
        TOTAL_COST -> total cost, defaukts to COST
        """
        # Attribute names are kept compact for saving on index size
        # through pickle.dump
        self.lc = cost
        if total_cost is None:
            total_cost = cost
        self.tc = total_cost

    def __repr__(self):
        return "total cost : %.1f s, last operation : %.1f s" % (self.tc, self.lc)

    def add(self, other):
        """Just sum up total costs with another cost object. Also sum up last
        operation costs, but this is questionnable, as you could
        consider that summing up costs implies there is some new 'last
        operation' around
        """
        self.tc = self.tc + other.tc
        self.lc = self.lc + other.lc

    def increment(self, cost):
        """Assuming that COST is the cost of a new 'last operation', updates
        object for representing that"""
        self.tc = self.tc + cost
        self.lc = cost

def ccost(cobject):
    """Provide the compute costs (elapsed time) for an object

    Returned value is of class cost, which has fields tc (for
    total_cost) and lc (for last_op_cost):

    - tc is the sum of all compute operations that lead to the object
    - lc is the cost for the last operation (top level)

    When a single operation provides multiple outputs, all outputs are
    charged with the cost of that operation (cost is not shared). This
    may lead to an overestimated cost when such outputs are re-used
    together in further operations

    """
    if cobject.crs in crs2filename:
        return crs2filename[cobject.crs][1]
    else:
        if type(cobject) is cens:
            cost = compute_cost()
            for member in cobject:
                if cobject[member].crs in crs2filename:
                    cost.add(crs2filename[cobject[member].crs][1])
                else:
                    raise Climaf_Error(
                        "At least one ensemble member is not cached (%s)" % member)
            return cost
        else:
            clogger.warning("Object is not (yet) cached; try cfile()")
            return None

def encode_index(values):
    """ Encode a dict like crs2filename, i.e. a dict of crs : (filename, cost)
    in a structure compatible with Json encoding"""
    ret = dict()
    for crs in values:
        if type(values[crs]) is tuple:
            fn, cost = values[crs]
        else:
            fn = values[crs]
            cost = 0.
        ret[crs] = (fn, cost.lc, cost.tc)
    return ret

def decode_index(values):
    """Decode a dict of triplets in a a dict like crs2filename, i.e. a
    dict of crs : (filename, cost)
    """
    ret = dict()
    for crs in values:
        if type(values[crs]) is list:
            fn, last_op_cost, total_cost = values[crs]
        else:
            fn = values[crs]
            last_op_cost, total_cost = 0., 0.
        ret[crs] = (fn, compute_cost(last_op_cost, total_cost))
    return ret


# Canny edge detection technique
# It can resuce noise
# It can perform gradient
# Non maximum suppression
# Double threshold
# Edge tracking hysteresis

import cv2 as cv
import numpy as np

# Load image into gray scale
img = cv.imread("/media/techio/Study Materials/Python Projects/balls.jpg")
img = cv.resize(img,(400,300));
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

# Thresholding using trackbars
def empty():
    pass

cv.namedWindow("Threshold")
cv.createTrackbar("Thres1","Threshold",0,255,empty)
cv.createTrackbar("Thres2","Threshold",0,255,empty)

cv.imshow("Original image",img)
cv.imshow("Gray Image",img_gray)

while True:
    th1 = cv.getTrackbarPos("Thres1","Threshold")
    th2 = cv.getTrackbarPos("Thres2","Threshold")
    print(th1,th2)
    # Canny Image
    canny_img = cv.Canny(img_gray,th1,th2)

    cv.imshow("Threshold",canny_img)

    if cv.waitKey(1) & 0xFF == 27:
        break

cv.destroyAllWindows()


def descuento(VArticulo):
    desc = VArticulo * 0.05
    return desc

while True:
    try:
        CProducto = float(input("Digite el valor de un producto"))
        if(CProducto<0):
            print("ERROR NUmero negativo")
            continue
        break
    except Exception as e:
        print("Error ", e)

desc = 0

if(CProducto>150000):
    desc = descuento(CProducto)
    print(f"El valor del producto es : {CProducto}")
    print(f"El valor de descuento del producto es : {desc}")
else:
    print(f"El valor del producto es : {CProducto}")
    print(f"El valor de descuento del producto es : {desc}")

Christian Leonardo Celis Ardila/Python/funciones/07_funciones_ejercicioclase/ejercicio3.py


import json
import nltk
import pdb
from sklearn.metrics.pairwise import cosine_similarity
import time
from tqdm import tqdm
dict_file = '../data/wordVectors/word_dict.json'  #词向量json文件
# attack_data_file = 'data/wikipassageQA/sample_data.json'
attack_data_file = 'data/wikipassageQA/attack_data_allwords.json'
from transformers import BertTokenizer
from nltk.corpus import stopwords
from utils.wordnettools import WNtools
#nltk.download('stopwords')

wntools = WNtools()

# 返回一个dict，key为单词，value为其embedding
# 暂时人为判断替换词应该在0.6以上
def CounterFittedVectors(dict_file):
    all_words = {}
    with open(dict_file, 'r', encoding='utf-8') as reader:
        all_data = reader.read()
        word_dict = json.loads(all_data)
        for dict in word_dict:
            all_words.update(dict)
    return all_words

#读入数据
def getAttackData(attack_data_file):
    all_data = []
    with open(attack_data_file, 'r', encoding='utf-8') as reader:
        lines = reader.readlines()
        for line in lines:
            a_data = json.loads(line)
            all_data.append(a_data)

    return all_data

#检查是否为 后缀 or 标点符号 or 停用词
def checkwords(aword, stopwords):
    punctuate = '[\s+\.\!\/_,$%^*(+\"\']+|[+——！，。?、~@#￥%……&*（）]+'
    if ('#' in aword) or (aword in punctuate) or (aword in stopwords):
        return False
    else:
        return True

#计算两个词在counter-fitted embedding中的余弦相似度
def cal_cos_sim(word1, word2, word_dict):
    embedding1 = word_dict.get(word1, None)
    embedding2 = word_dict.get(word2, None)
    if embedding1 and embedding2:
        results = cosine_similarity([embedding1, embedding2])[0][1]
        return results
    else:
        return None

def attack_a_data(a_data, tokenizer, pos_checking=False):
    sorts = a_data['words_sort']
    positions = a_data['position']
    input_ids = a_data['input_ids']
    result = tokenizer.convert_ids_to_tokens(sorts)
    filter = []
    for word, position in zip(result, positions):
        if checkwords(word, stopwords):
            filter.append((word, position))
    #print(filter)
    # print(len(filter))
    changesNum = int(round(len(filter) * change_porpotion, 0))
    for i in range(changesNum):
        a_pair = filter[i]
        origin_word, position = a_pair
        #origin_pos = nltk.pos_tag([origin_word])[0][1]
        #print(origin_pos)
        if not word_dict.get(origin_word, None):  # 如果词表里没有origin_word就直接跳到下一个
            continue
        if pos_checking:
            rep_list = wntools.GenerateSimWordByWNAndPosChecking(origin_word)
        else:
            rep_list = wntools.GenerateSimWordByWN(origin_word)
                #这里决定是否使用PosTagging
        if not rep_list:  # 如果WordNet没有找到同义词就跳到下一个
            continue
        else:
            results = []
            for rep_word in rep_list:
                sim_scores = cal_cos_sim(origin_word, rep_word, word_dict)
                if (not sim_scores) or (sim_scores < 0.6):
                    continue
                results.append((rep_word, sim_scores))
            if results:  # 从结果中找到符合要求的，替换原来的input_ids即可
                results.sort(reverse=True, key=lambda x: x[1])
                # print('position:', position)
                for result in results:
                    attack_word = result[0]

                    attack_word_idx = tokenizer.convert_tokens_to_ids(attack_word)  #遍历能在tokenizer词表里找到的单词
                    if attack_word_idx != 100:
                        input_ids[position] = attack_word_idx    # 更改对应位置的input_ids并推出循环
                        break
                    else:
                        continue

    a_data['input_ids'] = input_ids
    return a_data

if __name__ == '__main__':
    change_porpotion = 0.3
    start_time = time.time()
    #加载需要的东西
    word_dict = CounterFittedVectors(dict_file)
    all_data = getAttackData(attack_data_file)
    tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
    stopwords = stopwords.words('english')

    pos_checking = True  #是否使用poschecking
    #print(stopwords)
    print('loadingTime:', time.time()-start_time)

    attacked_results = []
    for a_data in tqdm(all_data):
        attacked_data = attack_a_data(a_data, tokenizer, pos_checking=pos_checking)
        attacked_results.append(attacked_data)

    with open('data/wikipassageQA/attacked_rate03_pos.json', 'w', encoding='utf-8') as writer:
        for a_data in tqdm(attacked_results):
            json.dump(a_data, writer)
            writer.write('\n')

    # #pdb.set_trace()
    # start_time = time.time()
    # word1 = 'evangelical'
    # word2 = 'forgiveness'
    # results = cal_cos_sim(word1, word2, word_dict)
    # if results:
    #     print(results)
    # else:
    #     print('词表查无此词')
    # print('CalSimTime:', time.time()-start_time)


from gettext import find
import random, copy
from re import L

class Card:
  def __init__(self, rank, suit):
    self.rank = rank
    self.suit = suit

  def __repr__(self):
      return "%s of %s" % (self.rank, self.suit)

class Player:
    def __init__(self, name, card1, card2, bestHand, handScore):
      self.name = name
      self.card1 = card1
      self.card2 = card2
      self.bestHand = bestHand
      self.handScore = handScore

    def __repr__(self):
        return "%s: \ncard 1: %s \ncard 2: %s. \nBest Hand: %s" % (self.name, self.card1, self.card2, self.bestHand)

class Hand:
    def __init__(self, type, cards):
        self.type = type
        self.cards = cards

    def __repr__(self):
        return "%s: %s" % (self.type, self.cards)

ranks = {
    '2': 2,
    '3': 3,
    '4': 4,
    '5': 5,
    '6': 6,
    '7': 7,
    '8': 8,
    '9': 9,
    '10': 10,
    'J': 11,
    'Q': 12,
    'K': 13,
    'A': 14
}

reversed_ranks = {
    2: '2',
    3: '3',
    4: '4',
    5: '5',
    6: '6',
    7: '7',
    8: '8',
    9: '9',
    10: '10',
    11: 'J',
    12: 'Q',
    13: 'K',
    14: 'A'
}

suits = [
    "spades",
    "clubs",
    "hearts",
    "diamonds"
]
# ALL cards already dealt this round
dealtCards = []

# deal a card
def dealCard ():
    cardExistsAlready = True

    while (cardExistsAlready):
        cardRank = random.choice(list(ranks))
        cardSuit = random.choice(suits)
        dealtCard = Card(cardRank, cardSuit)

        # list of every used card's rank
        dealtCardRanks = [card.rank for card in dealtCards]

        if(dealtCard.rank not in dealtCardRanks):
            cardExistsAlready = False
        else :
            cardExistsAlready = False
            for card in dealtCards:
                if (card.rank == cardRank and card.suit == cardSuit):
                    cardExistsAlready = True

    dealtCards.append(dealtCard)
    return dealtCard

# cards face up that all players can see
faceUpCards = []

# burn one card, then deal three cards face up
def dealFlop ():
    dealCard() # burn a card
    for x in range(3):
        flopCard = dealCard()
        faceUpCards.append(flopCard)

# burn one card, then deal one card face up
def dealTurn ():
    dealCard() # burn a card
    turnCard = dealCard()
    faceUpCards.append(turnCard)

# burn one card, then deal one card face up
def dealRiver ():
    dealCard() # burn a card
    riverCard = dealCard()
    faceUpCards.append(riverCard)

# determines how many hands to deal
numPlayers = 3

# list representing players in poker game
players = []

# deal a pair of cards to each of the numPlayers Players
def dealHands ():
    for x in range(numPlayers):
        card1 = dealCard()
        card2 = dealCard()
        playerName = "Player " + str(x + 1)
        playerHand = Hand("", []) # create hand for every player, but intialize them to nothing b/c we don't know their hand yet
        handScore = 0
        players.append(Player(playerName, card1, card2, playerHand, handScore))

"""
Hand-Ranking Hierarchy:

9 : Royal Flush
8 : Straight Flush
7 : 4 of a kind
6 : Full House
5 : Flush
4 : Straight
3 : 3 of a kind
2 : 2 Pair
1 : Pair
0 : High Card

"""

# Grade each player's hand according to the rules of Texas Hold-Em. Assign each player's hand a type (name), score, and list of cards that makeup that hand.
def checkHands ():
    for player in players:
        cardsToCheck = copy.deepcopy(faceUpCards)

        cardsToCheck.append(player.card1)
        cardsToCheck.append(player.card2)

        print(player.name, "Cards in play: ", cardsToCheck)

        duplicateRanks = findDuplicateRanks(cardsToCheck)
        print(player.name, "Duplicate Ranks:", duplicateRanks)

        if 4 in list(duplicateRanks.values()): # if there is four of a kind
            player.handScore = 7
            cardRank = list(duplicateRanks.keys())[list(duplicateRanks.values()).index(4)]
            player.bestHand.cards = [Card(cardRank, "spades"), Card(cardRank, "clubs"), Card(cardRank, "hearts"), Card(cardRank, "diamonds")]
            player.bestHand.type = "Four of a Kind"
        elif 3 in list(duplicateRanks.values()): # if there is three of a kind
            player.handScore = 3
            threeOfAKindRank = list(duplicateRanks.keys())[list(duplicateRanks.values()).index(3)]
            player.bestHand.cards.clear()
            for card in cardsToCheck:
                if card.rank == threeOfAKindRank:
                    player.bestHand.cards.append(card)
            player.bestHand.type = "Three of a Kind"
            if 2 in list(duplicateRanks.values()): # if there is a full house
                player.handScore = 6
                player.bestHand.type = "Full House"
                maxRank = '2'
                if list(duplicateRanks.values()).count(2) == 2: # if there are two pairs within the full house
                    for currRank, count in duplicateRanks.items():
                        if count == 2:
                            if ranks[currRank] > ranks[maxRank]:
                                maxRank = currRank
                    for card in cardsToCheck:
                        if card.rank == maxRank:
                            player.bestHand.cards.append(card)
                else: # if there is only one pair within the full house
                    # first find the rank of the pair and store in pairRank
                    for currRank, count in duplicateRanks.items():
                        if count == 2:
                            pairRank = currRank
                    # then store all cards in cardsToCheck into the player's bestHand
                    for card in cardsToCheck:
                        if card.rank == pairRank:
                            player.bestHand.cards.append(card)

        elif 2 in list(duplicateRanks.values()): # if there is a pair
            player.handScore = 1
            player.bestHand.type = "Pair"
            # iterate through dictionary and count how many pairs there are
            pairRanks = []
            for rank, count in duplicateRanks.items():
                if count == 2:
                    pairRanks.append(rank)

            if len(pairRanks) == 2: # if there are exactly 2 pairs
                player.handScore = 2
                player.bestHand.type = "Two Pair"
                for card in cardsToCheck:
                    for rank in pairRanks:
                        if rank == card.rank:
                            player.bestHand.cards.append(card)

            elif len(pairRanks) == 3: # if there are exactly 3 pairs
                player.handScore = 2
                player.bestHand.type = "Two Pair"

                minRank = pairRanks[0]
                for currRank in pairRanks:
                    if ranks[currRank] < ranks[minRank]:
                        minRank = currRank
                # now remove the smallest rank
                pairRanks.remove(minRank)
                # now that we have only 2 ranks, we can find that two-pair in cardsToCheck
                for card in cardsToCheck:
                    for rank in pairRanks:
                        if rank == card.rank:
                            player.bestHand.cards.append(card)

            else: # if there is really only one pair
                player.bestHand.cards.clear()
                for card in cardsToCheck:
                    if card.rank == pairRanks[0]:
                        player.bestHand.cards.append(card)

        straightCards = findStraights(cardsToCheck)
        print(player.name, "Straight Cards: ", straightCards)
        hasStraight = False

        if len(straightCards) == 5 and player.handScore < 4: # if there is a straight
                player.handScore = 4
                player.bestHand.cards = straightCards
                player.bestHand.type = "Straight"
                hasStraight = True

        flushCards = findFlushes(cardsToCheck)
        print(player.name, "Flush Cards: ", flushCards)

        if len(flushCards) == 5 and player.handScore < 5: # if there is a flush
            player.handScore = 5
            player.bestHand.cards = flushCards
            player.bestHand.type = "Flush"
            if hasStraight == True:
                # now need to check is straight cards are the same as the flush cards
                if set(flushCards) == set(straightCards): # if there is a straight flush
                    player.handScore = 8
                    player.bestHand.type = "Straight Flush"
                    for straightFlushCard in straightCards:
                        player.bestHand.cards.append(straightFlushCard)

                    flushRanks = []
                    for card in flushCards:
                        flushRanks.append(card.rank)
                    if set(['10', 'J', 'Q', 'K', 'A']).issubset(flushRanks): # if there is a royal flush
                        player.handScore = 9
                        player.bestHand.type = "Royal Flush"

        if player.handScore == 0:
            player.bestHand.type = "High Card"
            highCard = findHighCard(cardsToCheck)
            player.bestHand.cards.clear()
            player.bestHand.cards.append(highCard)

        # Finally - print out the results of checkHands
        print("Hand Score: ", player.handScore)
        print("Best Hand Type: ", player.bestHand.type)
        print("Best Hand Cards: ", player.bestHand.cards)
        print("\n")

# Gets called after checkHands and uses that result to determine who won the round of Hold-em and with what hand.
def findWinner ():
    bestScore = players[0].handScore
    winner = players[0]
    for player in players:
        if player.handScore > bestScore:
            bestScore = player.handScore
            winner = player
    return winner

# return the card within "cards" that has the highest rank
def findHighCard (cards):
    highCard = cards[0]
    highCardValue = ranks[cards[0].rank]

    for card in cards:
        cardValue = ranks[card.rank]
        if(cardValue > highCardValue):
            highCardValue = cardValue
            highCard = card
    return highCard

# finds pairs, 3 of a kind, and 4 of a kind
def findDuplicateRanks (cards):
    uniqueRanks = {}
    for card in cards:
        if card.rank in list(uniqueRanks):
            uniqueRanks[card.rank] = uniqueRanks[card.rank] + 1
        else:
            uniqueRanks[card.rank] = 1
    return uniqueRanks

# returns the array of cards that make up the straight, returns empty array "[]" if no straight is found
def findStraights (cards):

    straightCards = []
    highestStraightCards = []

    for card in cards:
        if ranks[card.rank] > 10 and ranks[card.rank] != 14: # J, Q, K can't start straight
            continue
        else:
            cardsRanks = [myCard.rank for myCard in cards]

            consecutiveCards = 1
            increment = 1

            while consecutiveCards < 5:
                # handle case where corresponding rank value exceeds 14
                if ranks[card.rank] + increment > 14:
                    nextRank = ranks[card.rank] + increment - 13
                else:
                    nextRank = ranks[card.rank] + increment

                # if a card of the next sequential rank exists in list of 7 graded cards
                if reversed_ranks[nextRank] in cardsRanks:

                    for theCard in cards:
                        if theCard.rank == reversed_ranks[nextRank]:
                            nextSuit = theCard.suit

                    consecutiveCards += 1
                    increment += 1
                    straightCards.append(Card(reversed_ranks[nextRank], nextSuit))
                # card is not the start of a straight
                else :
                    straightCards.clear()
                    break

        if straightCards: # if it's not empty, then there must be a straight
            straightCards.insert(0,card)

            # if highestStraightCards is empty
            if not highestStraightCards:
                highestStraightCards = copy.deepcopy(straightCards)
                straightCards.clear()

            # compare the highest value in the straight
            elif ranks[straightCards[4].rank] > ranks[highestStraightCards[4].rank]:
                highestStraightCards.clear()
                highestStraightCards = copy.deepcopy(straightCards)
                straightCards.clear()

    return highestStraightCards # which can be [] if no straights were found

# returns array of cards that make up the flush, returns empty array "[]" if no flush is found
def findFlushes (cards):

    flushCards = []
    flushSuit = -1

    suitCounts = {
        "spades" : 0,
        "clubs" : 0,
        "hearts" : 0,
        "diamonds" : 0
    }

    for card in cards:
        suitCounts[card.suit] += 1

    for suit in suitCounts:
        if suitCounts[suit] >= 5:
            flushSuit = suit
            for card in cards:
                if card.suit == flushSuit:
                    flushCards.append(card)

    return flushCards

# FUNCTION CALLS

# deal hands to all players
dealHands()

# printing white space for formatting
print("\n")

# print all player hands
for player in players:
    print(player.name, ":\nCard 1: ", player.card1, "\nCard 2: ", player.card2, "\n")

# deal a flop
dealFlop()

# deal a turn
dealTurn()

# deal a river
dealRiver()

print("Face Up Cards:", faceUpCards, "\n")

checkHands()

winnerPlayer = findWinner()

print("Winner:", winnerPlayer.name)
print(winnerPlayer.bestHand, "\n")


import random

import pygame as pg

# CONSTANTS
SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 800
FPS = 10000

class Barnsley:
    """Make an object that draws a fern."""

    def __init__(self):
        self.x = 0
        self.y = 0
        self.xprint = None
        self.yprint = None
        self.R = 0
        self.G = 0
        self.B = 0
        self.colX = 0
        self.colY = 0

    def make_point(self):
        r = random.randrange(0, 100, 1)
        if r < 1:
            self.x = 0
            self.y = 0.16 * self.y
        elif r < 86:
            self.x = 0.85 * self.x + 0.04 * self.y
            self.y = -0.04 * self.x + 0.85 * self.y + 1.6
        elif r < 93:
            self.x = 0.2 * self.x - 0.26 * self.y
            self.y = 0.23 * self.x + 0.22 * self.y + 1.6
        else:
            self.x = -0.15 * self.x + 0.28 * self.y
            self.y = 0.26 * self.x + 0.24 * self.y + 0.44

    def draw(self, screen):
        # −2.1820 < x < 2.6558
        # 0 ≤ y < 9.9983
        self.xprint = int(self.x * SCREEN_WIDTH * 0.1) + int(SCREEN_WIDTH * 0.45)
        self.yprint = -int(self.y * SCREEN_HEIGHT * 0.07) + int(SCREEN_HEIGHT * 0.85)
        self.colX = (self.x + 2.2) / 5.1
        self.colY = self.y / 12
        self.R = int((self.colY) * 255)
        self.G = int((self.colX) * 255)
        self.B = int((2 - self.colX - self.colY) * 255 / 2)
        screen.set_at((self.xprint, self.yprint), (self.R, self.G, self.B))

class Sim:
    """Simulate the making of the fern."""

    def __init__(self):
        pg.init()
        self.FPS = FPS
        self.screen_width = SCREEN_WIDTH
        self.screen_height = SCREEN_HEIGHT
        self.screen = pg.display.set_mode((self.screen_width, self.screen_height))
        pg.display.set_caption("Barnsley Fern")
        self.clock = pg.time.Clock()
        self.setup()
        self.a = 0

    def setup(self):
        self.fern = Barnsley()
        self.screen.fill((20, 2, 2))

    def events(self):
        for event in pg.event.get():
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_r:
                    self.setup()
                if event.key == pg.K_ESCAPE:
                    # pg.image.save(self.screen, 'barnsley_fern.png')
                    pg.quit()
                    quit()
            if event.type == pg.QUIT:
                pg.quit()
                quit()

    def sim_loop(self):
        while 1:
            self.fern.draw(self.screen)
            self.fern.make_point()
            # pg.display.flip()
            if self.a % 500 == 0:
                pg.display.update()
            # pg.transform.flip(self.screen, False, True)
            self.clock.tick(self.FPS)
            self.events()
            self.a += 1

if __name__ == "__main__":
    Sim().sim_loop()


""" Language Repository module """

from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session

from app.languages.exceptions import LanguageNotFoundException
from app.languages.models import Language

class LanguageRepository:
    """Language model repository"""

    def __init__(self, db: Session):
        self.db = db

    ##superuser
    def create_language(self, name, abbreviation):
        """Create new language"""
        try:
            language = Language(name, abbreviation)
            self.db.add(language)
            self.db.commit()
            self.db.refresh(language)
            return language
        except IntegrityError as e:
            raise e from e

    def get_language_by_id(self, language_id: str):
        """Get language by id"""
        language = self.db.query(Language).filter(Language.id == language_id).first()
        if language is None:
            raise LanguageNotFoundException(
                f"Language with provided id: {language_id} not found.", 400
            )
        return language

    def get_language_by_name(self, name: str):
        """Get language by category"""
        language = (
            self.db.query(Language).filter(Language.name.ilike(f"%{name}%")).all()
        )
        if (language is None) or (language == []):
            raise LanguageNotFoundException(
                f"Language with provided category: {name} not found.", 400
            )
        return language

    def get_language_by_abbreviation(self, abbreviation: str):
        """Get language by abbreviation"""
        language = (
            self.db.query(Language)
            .filter(Language.abbreviation.ilike(f"%{abbreviation}%"))
            .all()
        )
        if (language is None) or (language == []):
            raise LanguageNotFoundException(
                f"Language with provided abbreviation: {abbreviation} not found.", 400
            )
        return language

    def get_all_languages(self):
        """Get all languages"""
        languages = self.db.query(Language).all()
        if (languages is None) or (languages == []):
            raise LanguageNotFoundException(f"The list is empty!", 400)
        return languages

    ##superuser
    def delete_language_by_id(self, language_id: str):
        """Delete language by id"""
        try:
            language = (
                self.db.query(Language).filter(Language.id == language_id).first()
            )
            if language is None:
                raise LanguageNotFoundException(
                    f"Language with provided id: {language_id} not found.", 400
                )
            self.db.delete(language)
            self.db.commit()
            return True
        except Exception as e:
            raise e from e


import os
import glob
from pydub import AudioSegment

audio_dir = '/home/surya/Desktop/Music Genre Classifier/data/genres/'  # Path of audio files
genres = ['blues', 'classical', 'country', 'disco', 'hiphop', 'jazz', 'metal', 'pop', 'reggae', 'rock']
extension_list = ('*.au')

print("Converting files to wav.......")

for genre in genres:
    os.chdir(audio_dir + genre)
    for extension in extension_list:
        for audio in glob.glob(extension):
            wav_filename = os.path.splitext(os.path.basename(audio))[0] + '.wav'
            AudioSegment.from_file(audio).export(wav_filename, format='wav')

print("Completed succesfully")


import datetime,itertools,logging,os,sys, msatools, sqlite3,re, glob, gzip
import numpy as np
import random as rnd

APPLOGGER=logging.getLogger("ngsphy-refselector")
class NRSException(Exception):
	def __init__(self, expression, message, time):
		self.expression = expression
		self.message = message
		self.time= time

class ReferenceSelection:
	startTime=None
	endTime=None
	path=""
	projectName=""
	output=""
	inputprefix=""
	outputprefix=""
	method=0
	nsize=0
	numLociPerReplicate=[]
	numLociPerReplicateDigits=[]
	numReplicates=0
	numReplicatesDigits=0
	referenceIndexFile=""
	referenceLabels=[]
	offtargetloci=[]
	offtargetlocifile=""

	def __init__(self, args):
		self.startTime=datetime.datetime.now()
		self.endTime=None
		APPLOGGER.info(\
			"{0}".format(\
			"RefSelector started",\
		))
		# Variable initialization
		self.method=args.method
		self.inputprefix=args.input_prefix
		self.outputprefix=args.output_prefix
		self.nsize=args.nsize
		if args.seq_desc_file:
			self.referenceIndexFile=os.path.abspath(args.seq_desc_file)

		########################################################################
		# Checking correctness of the given paths
		if (args.simphy_path[-1]=="/"):
			self.projectName=os.path.basename(args.simphy_path[0:-1])
		else:
			self.projectName=os.path.basename(args.simphy_path)
		self.path=os.path.abspath(args.simphy_path)
		output=os.path.abspath(args.output)
		outputFolderName=""
		if (args.output[-1]=="/"):
			outputFolderName=os.path.basename(args.output[0:-1])
		else:
			outputFolderName=os.path.basename(output)
		if (os.path.exists(output)):
			listdir=os.listdir("{}".format(os.path.dirname(output)))
			counter=0
			for item in listdir:
				if outputFolderName in item:
					counter+=1
			if not counter == 0: outputFolderName+="_{0}".format(counter+1)
		self.output=os.path.join(os.path.dirname(output),outputFolderName)
		if (args.off_target_loci_file):
			if (os.path.exists(os.path.abspath(args.off_target_loci_file))):
				self.offtargetlocifile=os.path.abspath(args.off_target_loci_file)
				self.readOffTargetLociFile()
				APPLOGGER.info("Using off-target loci")
		else:
			APPLOGGER.info("NOT using off-target loci")

		########################################################################
		# Generation of the output folder
		try:
			os.mkdir(self.output)
			APPLOGGER.info("Generating output folder:\t{}".format(self.output))
		except:
			APPLOGGER.info("Output folder ({0}) exists. ".format(self.output))

	def checkArgs(self):
		APPLOGGER.info("Checking arguments...")
		APPLOGGER.info("\tSimPhy...")
		simphydir=os.path.exists(self.path)
		########################################################################
		if simphydir:
			APPLOGGER.info("SimPhy folder exists:\t{0}".format(simphydir))
		else:
			exc_type, _, exc_tb = sys.exc_info()
			fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
			ex="SimPhy folder does not exist."
			message="{1} | File: {2} - Line:{3}\n\t{0}".format(\
				ex,exc_type,fname, exc_tb.tb_lineno,\
				"Please verify. Exiting.")
			raise NRSException(False, message, datetime.datetime.now()-self.startTime)
		fileList=os.listdir(os.path.abspath(self.path))
		for index in range(0,len(fileList)):
			fileList[index]=os.path.abspath(os.path.join(self.path,fileList[index]))
		self.db = os.path.join(self.path,"{0}.db".format(self.projectName))
		if not self.db in fileList:
			ex="SimPhy required file do not exist."
			exc_type, _, exc_tb = sys.exc_info()
			fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
			message="{1} | File: {2} - Line:{3}\n\t{0}".format(\
				ex,exc_type,fname, exc_tb.tb_lineno,\
				"Please verify. Exiting."\
			)
			raise NRSException(False, message, datetime.datetime.now()-self.startTime)
		APPLOGGER.info("SimPhy data base exist:\t{0} ({1})".format(\
			os.path.basename(self.db),self.db in fileList)
		)
		APPLOGGER.info("\tIdentifying replicates...")
		# check how many of them are dirs
		for item in fileList:
			baseitem=os.path.basename(item)
			if (os.path.isdir(os.path.abspath(item)) and  baseitem.isdigit()):
				self.numReplicates=self.numReplicates+1
		self.numReplicatesDigits=len(str(self.numReplicates))
		########################################################################
		# check if at least one
		if not (self.numReplicates>0):
			ex="Number of replicates/folders:\t{0} [Required at least 1]".format(self.numReplicates>0)
			exc_type, _, exc_tb = sys.exc_info()
			fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
			message="{1} | File: {2} - Line:{3}\n\t{0}".format(\
				ex,exc_type,fname, exc_tb.tb_lineno,\
				"Please verify. Exiting."\
			)
			raise NRSException(False, message, datetime.datetime.now()-self.startTime)
		APPLOGGER.info("\tDone!")
		APPLOGGER.info("Number of replicates:\t{0}".format(self.numReplicates))
		########################################################################
		self.referenceLabels=["1_0_0" for item in range(0,self.numReplicates)]
		self.numLociPerReplicate=[0]*self.numReplicates
		self.numLociPerReplicateDigits=[0]*self.numReplicates
		self.getNumLociPerReplicate()
		APPLOGGER.info("Number of loci per replicates: {}".format(self.numLociPerReplicate))
		APPLOGGER.info("Number of loci digits per replicates: {}".format(self.numLociPerReplicateDigits))
		########################################################################
		if self.nsize > -1:
			APPLOGGER.info("Reference sequences will be concatenated.")
		########################################################################
		if self.method==1:
			if not (os.path.exists(self.referenceIndexFile) and os.path.isfile(self.referenceIndexFile)):
				message="{0}\n\t{1}".format(\
					"Sequence description file does not exist.",\
					"Please verify. Exiting."\
				)
				raise NRSException(False, message, datetime.datetime.now()-self.startTime)
			else:
				self.readReferenceIndices()
		########################################################################

	def readReferenceIndices(self):
		APPLOGGER.info("Reading the reference index file")
		with open(self.referenceIndexFile, "rb") as f:
			referenceLabels=[line.strip() for line in f if not line.strip() ==""]
		for item in range(0,len(referenceLabels)):
			self.referenceLabels[item]=referenceLabels[item]

	def filterSpeciesTreeReplicates(self):
		self.filtered=[(idx+1) for idx in range(0,self.numReplicates) \
		 	if not self.numLociPerReplicate[idx]==0]

	def getNumLociPerReplicate(self):
		for index in range(0, self.numReplicates):
			repID=index+1
			APPLOGGER.debug("Replicate {0}/{1} ".format(repID, self.numReplicates))
			filename=os.path.join(\
				self.path,\
				"{0:0{1}d}".format(repID, self.numReplicatesDigits),\
				"{0}_{1:0{2}d}_TRUE.fasta.gz".format(self.inputprefix,repID, self.numReplicatesDigits)
			)
			num=0
			if os.path.exists(filename):
				seqDict=self.readGzippedFastaFile(filename)
				key=seqDict.keys()[0]
				seqs=seqDict[key]
				seqs=seqs.split("N")
				seqs=[item for item in seqs if not item == ""]
				num=len(seqs)
			self.numLociPerReplicate[index]=num
			self.numLociPerReplicateDigits[index]=len(str(num))

	def readGzippedFastaFile(self, filename):
		with gzip.open(filename, 'rb') as f:
		    file_content = f.read()
		file_content=file_content.split("\n")
		file_content=[line for line in file_content if not line ==""]
		descriptionIndices=range(0,len(file_content),2)
		seqDict=dict()
		for item in descriptionIndices:
		    key=file_content[item][1:]
		    seqDict[key]=file_content[item+1]
		return seqDict

	def readOffTargetLociFile(self):
		APPLOGGER.info("Reading OFF-target loci file")
		with open(self.offtargetlocifile, "rb") as f:
			self.offtargetloci=f.read().strip().split(",")
		self.offtargetloci=[ int(item) for item in self.offtargetloci if item != ""]
		self.offtargetloci.sort()

	def iterateOverReplicate(self):
		APPLOGGER.debug("IterateOverReplicate")
		for index in range(0, self.numReplicates):
			repID=index+1
			if repID in self.filtered:
				APPLOGGER.debug("Replicate {0}/{1} ".format(repID, self.numReplicates))
				APPLOGGER.info("Method chosen: {0}".format(self.method))
				####################################################################
				if self.method==0:
					self.methodOutgroup(index)
				####################################################################
				if self.method==1:
					self.methodSelectFromFile(index)
				####################################################################
				if self.method==2:
					self.methodRandomIngroup(index)
				####################################################################
				if self.method==3:
					self.methodConsensusRandomSpecies(index)
				####################################################################
				if self.method==4:
					self.methodConsensusAll(index)
				####################################################################

	def writeSequence(self,index, description, sequence):
		APPLOGGER.info("Writing reference sequence for replicate {0:0{1}d}".format(index+1,self.numReplicatesDigits))
		filename=os.path.join(\
			self.output,\
			"{0}_{1:0{2}d}.fasta".format(\
				self.outputprefix,
				index+1,\
				self.numReplicatesDigits
			)
		)
		nsequence="".join(["N"]*self.nsize)
		splitSequence=sequence.split("N")
		locsequences=[splitSequence[s] for s in range(0,len(splitSequence)) if not splitSequence[s] == "" and not s in self.offtargetloci]
		seq=["{}{}".format(locsequences[s],nsequence) for s in range(0,len(locsequences))]
		seq="{}{}".format("".join(seq),locsequences[-1])
		with open(filename,"wb") as f:
			f.write(">{}\n{}\n".format(description,seq))
		locsequences=[splitSequence[s] for s in range(0,len(splitSequence)) if not splitSequence[s] == ""]
		seq=["{}{}".format(locsequences[s],nsequence) for s in range(0,len(locsequences))]
		seq="{}{}".format("".join(seq),locsequences[-1])
		self.generateBEDFile(index, description, seq)

	def methodSelectFromFile(self,index):
		APPLOGGER.debug("method rndingroup")
		repID=index+1
		fastapath=os.path.join(\
			self.path,\
			"{0:0{1}d}".format(repID, self.numReplicatesDigits),\
			"{0}_{1:0{2}d}_TRUE.fasta.gz".format(self.inputprefix,(index+1), self.numReplicatesDigits)\
		)
		seqDict=self.readGzippedFastaFile(fastapath)
		description=self.referenceLabels[index]
		selectedSequence=seqDict[description]
		self.writeSequence(index,description,selectedSequence)
		APPLOGGER.info("Done selected sequence")

	def methodRandomIngroup(self,index):
		"""
		Method 0 for the selection of reference loci.
		This method selects the outgroup as a reference locus.
		"""
		APPLOGGER.debug("method rndingroup")
		repID=index+1
		description0="0_0_0"
		fastapath=os.path.join(\
			self.path,\
			"{0:0{1}d}".format(repID, self.numReplicatesDigits),\
			"{0}_{1:0{2}d}_TRUE.fasta.gz".format(self.inputprefix,(index+1), self.numReplicatesDigits)\
		)
		seqDict=self.readGzippedFastaFile(fastapath)
		description="1_0_0"
		keys=seqDict.keys()
		try:
			k=rnd.choice(keys)[0]
		except:
			pass
		description=keys[int(k)]
		if description==description0:
			description="1_0_0"
		selectedSequence=seqDict[description]
		self.writeSequence(index,description,selectedSequence)
		APPLOGGER.info("Done random ingroup sequence")

	def methodOutgroup(self,index):
		"""
		Method 0 for the selection of reference loci.
		This method selects the outgroup as a reference locus.
		------------------------------------------------------------------------
		attributes: repID: Index of the species tree that is being used.
		returns: Nothing
		"""
		repID=index+1
		APPLOGGER.debug("method outgroup")
		description="0_0_0"
		fastapath=os.path.join(\
			self.path,\
			"{0:0{1}d}".format(repID, self.numReplicatesDigits),\
			"{0}_{1:0{2}d}_TRUE.fasta.gz".format(self.inputprefix,(index+1), self.numReplicatesDigits)\
		)
		seqDict=self.readGzippedFastaFile(fastapath)
		selectedSequence=seqDict[description]
		self.writeSequence(index,description,selectedSequence)
		APPLOGGER.info("Done outgroup sequence")

	def methodConsensusRandomSpecies(self,index):
		"""
		Method 2 for the selection of reference loci.
		------------------------------------------------------------------------
		This method selects a consensus sequence, obtained from the random selection
		of a species, and then computing a consensus from all the sequences
		within the selected species.
		Args: repID: Index of the species tree that is being used.
		Returns: Nothing
		"""
		repID=index+1
		fastapath=os.path.join(\
			self.path,\
			"{0:0{1}d}".format(repID, self.numReplicatesDigits),\
			"{0}_{1:0{2}d}_TRUE.fasta.gz".format(self.inputprefix,(index+1), self.numReplicatesDigits)\
		)
		seqDict=self.readGzippedFastaFile(fastapath)
		speciesKeys=np.unique([item.split("_")[0] for item in seqDict.keys()])
		rndKey1=1
		try:
			rndKey1=rnd.sample(set(speciesKeys),1)[0]
		except:
			rndKey1=1
		if rndKey1==0: rndKey1=1
		subkeys=[item for item in seqDict.keys() if item.split("_")[0]==rndKey1]
		sequences=[seqDict[item] for item in seqDict.keys() if item in subkeys]
		selected=self.computeConsensus(sequences)
		selectedDes="consensus_sp_{0}".format(rndKey1)
		self.writeSequence(index,selectedDes,selected)
		APPLOGGER.info("Done random ingroup consensus")

	def methodConsensusAll(self,index):
		"""
		Method 3 for the selection of reference loci.
		------------------------------------------------------------------------
		Computes the consensus from all the sequences of a gene tree file,
		and uses this sequence as reference loci.
		Args: repID: Index of the species tree that is being used.
		Returns: Nothing
		"""
		repID=index+1
		fastapath=os.path.join(\
			self.path,\
			"{0:0{1}d}".format(repID, self.numReplicatesDigits),\
			"{0}_{1:0{2}d}_TRUE.fasta.gz".format(self.inputprefix,(index+1), self.numReplicatesDigits)\
		)
		seqDict=self.readGzippedFastaFile(fastapath)
		sequences=[seqDict[k] for k in seqDict.keys()]
		selected=self.computeConsensus(sequences)
		self.writeSequence(index,"consensus_all",selected)
		APPLOGGER.info("Done all ingroups consensus")

	def computeConsensus(self, sequences):
		"""
		Method for the computation of a consensus sequence from a set
		of sequences.
		------------------------------------------------------------------------
		Args: sequences: list of the sequences
		Returns: Single consensus sequence
		"""
		conseq=""
		# Assume that all the sequences in a file have the same length
		seqSize=len(sequences[0])
		# Need to know how many sequences I have
		numSeqs=len(sequences)
		# Seqs for all nucleotides
		A=np.zeros(seqSize)
		C=np.zeros(seqSize)
		G=np.zeros(seqSize)
		T=np.zeros(seqSize)
		N=np.zeros(seqSize)
		for indexCol in range(0, seqSize):
			for indexRow in range(0,numSeqs):
				if sequences[indexRow][indexCol]=="A": A[indexCol]+=1
				if sequences[indexRow][indexCol]=="C": C[indexCol]+=1
				if sequences[indexRow][indexCol]=="G": G[indexCol]+=1
				if sequences[indexRow][indexCol]=="T": T[indexCol]+=1
				if sequences[indexRow][indexCol]=="N": N[indexCol]+=1

		for indexCol in range(0,seqSize):
			if A[indexCol] > C[indexCol] and A[indexCol] > G[indexCol] and A[indexCol] > T[indexCol] and A[indexCol] > N[indexCol]:
				conseq+="A"
			elif C[indexCol] > A[indexCol] and C[indexCol] > G[indexCol] and C[indexCol] > T[indexCol] and C[indexCol] > N[indexCol]:
				conseq+="C"
			elif G[indexCol] > A[indexCol] and G[indexCol] > C[indexCol] and G[indexCol] > T[indexCol] and G[indexCol] > N[indexCol]:
				conseq+="G"
			elif T[indexCol] > A[indexCol] and T[indexCol] > C[indexCol] and T[indexCol] > G[indexCol] and T[indexCol] > N[indexCol]:
				conseq+="T"
			else: conseq+=rnd.choice(["A","C","G","T"])

		APPLOGGER.info("Consensus computed")
		return conseq

	def generateBEDFile(self,index,description, sequence):
		APPLOGGER.info("Writing BED file for replicate {0:0{1}d}".format(index+1,self.numReplicatesDigits))
		splitSequence=sequence.split("N")
		seqlist=[splitSequence[s] for s in range(0,len(splitSequence)) if not splitSequence[s] == "" and not s in self.offtargetloci]
		sizelist=[len(item) for item in seqlist]
		repID=index+1
		bed=dict()
		startpos=0; endpos=0
		for i in range(0, len(seqlist)):
			if not (i+1) in self.offtargetloci:
				endpos=startpos+sizelist[i]
				locID="LOCUS_{0:0{1}d}".format(\
					i+1,\
					self.numLociPerReplicateDigits[index]\
				)
				bed[locID]={"start":startpos,"end":endpos}
				startpos=endpos+(self.nsize-1)

		bedfile=os.path.join(\
			self.output,\
			"{0}_{1:0{2}d}.bed".format(\
				self.outputprefix,\
				repID,self.numReplicatesDigits\
			)
		)
		totalConcatSizeDigits=len(str(len(sequence)))
		with open(bedfile,'a') as outfile:
			for i in range(0, len(seqlist)):
				if not (i+1) in self.offtargetloci:
					locID="LOCUS_{0:0{1}d}".format(i+1,self.numLociPerReplicateDigits[index])
					positions="{startPOS:{align}{posSIZE}}\t{endPOS:{align}{posSIZE}}".format(\
						align=">",\
						startPOS=bed[locID]["start"],\
						endPOS=bed[locID]["end"],\
						posSIZE=totalConcatSizeDigits\
					)
					outfile.write("{0}\t{1}\t{2}\n".format(\
						locID,\
						positions,\
						description\
					))

	def run(self):
		"""
		Run process of the program.
		"""
		self.checkArgs()
		self.filterSpeciesTreeReplicates()
		self.iterateOverReplicate()
		raise NRSException(True,"",datetime.datetime.now()-self.startTime)


import jpype
import jpype.imports
from jpype.types import *

def startJVM(*args, **kwargs):
    """
    Starts a jpype JVM if it isn't already started.
    If it is started, args and kwargs will be ignored.
    """
    try:
        jpype.startJVM(*args, **kwargs)
    except OSError as e:
        if str(e) != 'JVM is already started':
            raise e

def list_to_arraylist(l):
    """
    Converts a Python list to a jpype java ArrayList
    """
    startJVM()
    from java.util import ArrayList

    if isinstance(l, ArrayList):
        return l
    elif l is None:
        return JObject(None, ArrayList)
    else:
        al = ArrayList(len(l))
        al.extend(l)
        return al

def dict_to_hashmap(d):
    """
    Converts a python dict to a jpyp Java HashMap.
    """
    startJVM()
    from java.util import HashMap
    if isinstance(d, HashMap):
        return d
    elif d is None:
        return JObject(None, HashMap)
    else:
        hm = HashMap()
        for k, v in d.items():
            hm.put(k, v)
        return hm


import pygame

from isec.environment.base import Sprite, RenderingTechniques

class AnimatedSprite(Sprite):
    def __init__(self,
                 surfaces: list[pygame.Surface],
                 frames_duration: list[float],
                 loop: bool = True,
                 rendering_technique: RenderingTechniques.TYPING = "static",
                 blit_flag: int = 0) -> None:

        if len(surfaces) == 0:
            raise ValueError("Length of surfaces must be greater than 0.")

        if len(surfaces) != len(frames_duration):
            raise ValueError("Length of surfaces and frames_duration must be equal.")

        if not all(isinstance(duration, (int | float)) for duration in frames_duration):
            raise ValueError("All frames_duration must be int or float.")

        super().__init__(surface=surfaces[0],
                         rendering_technique=rendering_technique,
                         blit_flag=blit_flag)

        self.surfaces: list[pygame.Surface] = surfaces
        self.frames_duration: list[float] = frames_duration
        self.loop: bool = loop

        self._current_frame: int = 0
        self._current_duration: float = 0.0

    def update(self,
               delta: float) -> None:

        self._current_duration += delta
        if self._current_duration >= self.frames_duration[self._current_frame]:
            self._current_duration -= self.frames_duration[self._current_frame]
            self._current_frame += 1

            if self._current_frame >= len(self.surfaces):
                if self.loop:
                    self._current_frame = 0
                else:
                    self._current_frame = len(self.surfaces) - 1

            while self.frames_duration[self._current_frame] == 0:
                self._current_frame += 1
                if self._current_frame >= len(self.surfaces):
                    if self.loop:
                        self._current_frame = 0
                    else:
                        self._current_frame = len(self.surfaces) - 1

    def render(self,
               destination: pygame.Surface,
               destination_rect: pygame.Rect,
               offset: tuple[int, int],
               angle: float) -> None:

        self.surface = self.surfaces[self._current_frame]
        super().render(destination, destination_rect, offset, angle)


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

K, N, M = map(int, input().split())

target = 0
while target != M:
    cnt = 0
    cnt += N // K
    N -= cnt

'''

1 2 3 4 5
  2
      2
2
        2
    2
'''


import sqlalchemy
from configdb.meta import db
from collections import namedtuple
from configdb.errors import NotALeaf

DbType = namedtuple('DbType', ('id', 'column', 'types'))

C_DICT = DbType(0, None, (dict, ))
C_LIST = DbType(1, None, (list, tuple,))
C_BOOL = DbType(2, 'boolval', (bool, ))
C_INT = DbType(3, 'intval', (int, ))
C_FLOAT = DbType(4, 'floatval', (float, ))
C_STRING = DbType(5, 'stringval', (str, ))
C_BLOB = DbType(6, 'blobval', (type(None), ))

C_LEAVES = (C_BOOL, C_INT, C_FLOAT, C_STRING, C_BLOB)
C_BRANCHES = (C_DICT, C_LIST)

class Node(db.Model):
    id = db.Column(db.Integer, primary_key=True, nullable=False)
    label = db.Column(db.String, index=True)
    parent_id = db.Column(db.Integer, db.ForeignKey('node.id', ondelete='cascade'))
    children = db.relationship(
        'Node',
        backref=db.backref('parent', remote_side=[id]),
        cascade="all, delete-orphan, delete",
    )
    nodetype = db.Column(db.Integer)
    # store all variants in columns
    # alternative would be polymorphic node
    boolval = db.Column(db.Boolean)
    intval = db.Column(db.Integer)
    floatval = db.Column(db.Float)
    stringval = db.Column(db.String)
    blobval = db.Column(db.LargeBinary)
    __table_args__ = (
        db.UniqueConstraint('parent_id', 'label', name='_parent_label_uc'),
    )

    def __init__(self, label, parent=None):
        self.label = label
        self.parent = parent
        self.nodetype = 'dict'

    @property
    def val(self):
        """get node value as leaf"""
        for leaf in C_LEAVES:
            if self.nodetype == leaf.id:
                return getattr(self, leaf.column)
        raise NotALeaf()

    @val.setter
    def val(self, data):
        """store a value in node"""
        self.nodetype = C_DICT.id
        # clear old values
        for leaf in C_LEAVES:
            setattr(self, leaf.column, None)
        # test if we data is a leaf
        for leaf in C_LEAVES:
            if isinstance(data, leaf.types):
                # wipe children
                query = db.session.query(Node)
                query = query.filter(Node.parent == self)
                query.delete(synchronize_session='fetch')
                # remember type and store value
                self.nodetype = leaf.id
                setattr(self, leaf.column, data)
                return
        raise NotALeaf()

    def pickle(self, data):
        """recursively retrieve node data"""
        try:
            self.val = data
            return
        except NotALeaf:
            pass
        # not a leaf, a list or tuple?
        if isinstance(data, C_LIST.types):
            # make it a numbered dictionary
            self.nodetype = C_LIST.id
            data = dict(zip(range(len(data)), data))
        if isinstance(data, C_DICT.types):
            # wipe any child not being updated
            query = db.session.query(Node)
            query = query.filter(Node.parent == self)
            if data.keys():
                query = query.filter(sqlalchemy.not_(Node.label.in_(data.keys())))
            query.delete(synchronize_session='fetch')
            # store children
            for k, v in data.items():
                # fetch or create child and set it's value
                self.child(k, create=True).pickle(v)
            return
        raise Exception('unable to store type %s (%s)' % (type(data), data))

    def unpickle(self):
        """set node value recursively from a structure"""
        try:
            return self.val
        except NotALeaf:
            pass
        # structure
        result = {}
        for child in self.children:
            result[child.label] = child.unpickle()
        if self.nodetype == C_LIST.id:
            # flatten lists
            result = [result[i] for i in sorted(result)]
        return result

    def child(self, label, create=False):
        """fetch or chreate child by name"""
        query = db.session.query(Node)
        query = query.filter(Node.parent == self)
        query = query.filter(Node.label == label)
        result = query.first()
        if not result and create:
            result = Node(label, parent=self)
            db.session.add(result)
        return result

    @classmethod
    def root(cls):
        """return root node"""
        result = cls.query.filter_by(label='root', parent_id=None).first()
        return result

    @classmethod
    def fetch_by_path(cls, path, create=False):
        parent = cls.root()
        if not path:
            return parent
        for element in filter(None, path.split('/')):
            if parent.nodetype not in map(lambda x: x.id, C_BRANCHES):
                raise Exception("path %s contains leaf element %s" % (path, parent.label))
            node = cls.query.filter_by(label=element, parent=parent).first()
            if not node:
                if create:
                    node = Node(element, parent=parent)
                    db.session.add(node)
                else:
                    return None
            parent = node
        return parent

    @classmethod
    def get_by_path(cls, path):
        """start at the root node, walk the path and
        return the node matching"""
        return cls.fetch_by_path(path, create=False)

    @classmethod
    def create_path(cls, path, create=True):
        """create all intermediate notes up to path"""
        return cls.fetch_by_path(path, create=True)

    def __repr__(self):
        return '<Node %s: %s>' % (self.id, self.label)

db.create_all()
# create root Node
root = Node.query.filter_by(label='root', parent_id=None).first()
if not root:
    root = Node('root')
    db.session.add(root)
    db.session.commit()


# Задача №9. Среди натуральных чисел, которые были введены, найти наибольшее по сумме цифр. Вывести на экран это
# число и сумму его цифр.

n = None
numb = []
while n != 0:
    n = int(input('Введите следующее число. Если больше вводить числа не будете, то введите "0": '))
    if n != 0:
        numb.append(n)
    else:
        break
print(numb)
z = 1
total = 0
total_numb = 0
for x in numb:
    x = str(x)
    for i in range(0, len(x), z):
        total = total + i
    if total_numb < total:
        total_numb = total
    else:
        continue
print(total_numb)