##############################################################################
###
### This file is part of the BBS software (Bioconductor Build System).
###
### Author: Hervé Pagès <hpages.on.github@gmail.com>
### Last modification: Oct 6, 2020
###

import sys
import os
import tarfile

import bbs.fileutils
import bbs.parse
import bbs.jobs
import bbs.rdir
import bbs.notify

import BBSutils
import BBSvars

def Untar(tarball, dir=None, verbose=False):
    key = 'BBS_TAR_CMD'
    if key in os.environ and os.environ[key] != "":
        tar_cmd = os.environ[key]
        options = 'zxf'
        if verbose:
            options += 'v'
        cmd = tar_cmd + ' ' + options + ' ' + tarball
        if dir != None:
            cmd += ' -C %s' % dir
        bbs.jobs.doOrDie(cmd)
    else:
        ## This method doesn't restore the file permissions on Windows!
        if dir != None:
            sys.exit("ERROR in Untar(): dir != None is not supported")
        tar = tarfile.open(tarball, mode='r:gz')
        for tarinfo in tar:
            tar.extract(tarinfo)
        tar.close()
    return

def injectFieldsIntoMeat(meat_path, target_pkgs):
    print('BBS>   Injecting fields into',
          '%s/*/DESCRIPTION files ...' % meat_path, end=' ')
    for pkg in target_pkgs:
        desc_file = os.path.join(meat_path, pkg, 'DESCRIPTION')
        if not os.path.exists(desc_file):
            print('(%s not found --> skip)' % desc_file, end=' ')
            continue
        if BBSvars.MEAT0_type == 3:
            # Inject git fields.
            gitlog_path = BBSutils.getenv('BBS_GITLOG_PATH')
            gitlog_file = os.path.join(gitlog_path, 'git-log-%s.dcf' % pkg)
            if os.path.exists(gitlog_file):
                bbs.parse.injectGitFieldsIntoDESCRIPTION(desc_file, gitlog_file)
            else:
                print('(%s not found --> skip git fields)' % gitlog_file,
                      end=' ')
        if BBSvars.bioc_version != None:
            # Inject Repository field.
            fields = {'Repository': 'Bioconductor %s' % BBSvars.bioc_version}
            bbs.parse.inject_DCF_fields(desc_file, fields)
    print('OK')
    return

def cloneCRANstylePkgRepo(contrib_url, destdir, update_only=False):
    print('BBS>   Start cloning CRAN-style package repo %s/ to %s/ ...' % \
          (contrib_url, destdir))
    if not os.path.exists(destdir):
        os.mkdir(destdir)
    elif not update_only:
        bbs.fileutils.remake_dir(destdir, ignore_errors=True)
    print('BBS>     o', end=' ')
    sys.stdout.flush()
    PACKAGES_new_path = os.path.join(destdir, 'PACKAGES.new')
    BBSutils.downloadFile('PACKAGES', contrib_url, PACKAGES_new_path)
    PACKAGES_new = bbs.parse.parse_DCF(PACKAGES_new_path)
    PACKAGES_old_path = os.path.join(destdir, 'PACKAGES')
    if os.path.exists(PACKAGES_old_path):
        PACKAGES_old = bbs.parse.parse_DCF(PACKAGES_old_path)
        old_pkgs = {}
        for dcf_record in PACKAGES_old:
            old_pkgs[dcf_record['Package']] = dcf_record
    i = 0
    for dcf_record in PACKAGES_new:
        i += 1
        print('BBS>     o [%d/%d]' % (i, len(PACKAGES_new)), end=' ')
        sys.stdout.flush()
        pkgname = dcf_record['Package']
        if os.path.exists(PACKAGES_old_path):
            git_last_commit = dcf_record.get('git_last_commit')
            if git_last_commit != None:
                old_dcf_record = old_pkgs.get(pkgname)
                if old_dcf_record != None:
                    old_git_last_commit = old_dcf_record.get('git_last_commit')
                    if git_last_commit == old_git_last_commit:
                        print('git_last_commit (%s) for ' % git_last_commit +
                              'package %s has not changed --> skip' % pkgname)
                        continue
        version = dcf_record['Version']
        MD5sum = dcf_record['MD5sum']
        srcpkg_file = '%s_%s.tar.gz' % (pkgname, version)
        BBSutils.downloadFile(srcpkg_file, contrib_url, destdir, MD5sum)
    os.rename(PACKAGES_new_path, PACKAGES_old_path)
    print('BBS>   Done cloning CRAN-style package repo %s/ to %s/' % \
          (contrib_url, destdir))
    return PACKAGES_old_path

def extractLocalCRANstylePkgRepo(contrib_path, destdir):
    PACKAGES_path = os.path.join(contrib_path, 'PACKAGES')
    PACKAGES = bbs.parse.parse_DCF(PACKAGES_path)
    print('BBS>   Extracting the %d source tarballs in %s/' % \
          (len(PACKAGES), contrib_path))
    print('       to %s/ ...' % destdir, end=' ')
    sys.stdout.flush()
    for dcf_record in PACKAGES:
        pkgname = dcf_record['Package']
        version = dcf_record['Version']
        srcpkg_file = '%s_%s.tar.gz' % (pkgname, version)
        srcpkg_path = os.path.join(contrib_path, srcpkg_file)
        Untar(srcpkg_path, destdir)
    print('OK')
    return

# The R expression passed thru 'Rexpr' must NOT contain spaces or it will
# break on Windows!
def Rexpr2syscmd(Rexpr):
    if BBSvars.rscript_cmd == None:
        if sys.platform == 'win32':
            syscmd = 'echo %s | %s --no-echo' % (Rexpr, BBSvars.r_cmd)
        else:
            syscmd = 'echo "%s" | %s --no-echo' % (Rexpr, BBSvars.r_cmd)
    else:
        if sys.platform == 'win32':
            syscmd = '%s -e %s' % (BBSvars.rscript_cmd, Rexpr)
        else:
            syscmd = '%s -e "%s"' % (BBSvars.rscript_cmd, Rexpr)
    return syscmd

# The <pkg>.Rcheck/ folder can be huge (several GB for some packages, even
# for some software packages!) but, fortunately, the things that we need to
# send to the central node are small.
# NOTE: Trying to remove some of the files in <pkg>.Rcheck/ with os.remove()
# can fail for some packages on Windows with an error like:
#     PermissionError: [WinError 32] The process cannot
#     access the file because it is being used by another
#     process: 'scTHI.Rcheck\\00check.log'
# Stuff to keep:
#   - '00check.log': Trying to remove this file could fail on Windows (see
#     NOTE above).
#   - '00install.out'
#   - '<pkg>-Ex.Rout'
#   - '<pkg>-Ex_i386.Rout', '<pkg>-Ex_x64.Rout': Trying to remove these files
#     could fail (see NOTE above).
#   - '<pkg>-Ex.timings'
#   - 'examples_i386/<pkg>-Ex.timings'
#   - 'examples_x64/<pkg>-Ex.timings'
#   - All the top-level files in 'tests/', 'tests_i386/', and 'tests_x64/',
#     except 'startup.Rs', and no subdirs (e.g. 'tests/testthat/' can be
#     big and is not needed).
#   - '<pkg>-manual.pdf'
def _clean_Rcheck_dir(Rcheck_dir, pkg):
    dangling_paths = []
    # Collect top-level stuff to remove.
    top_level_stuff_to_keep = ['00check.log',
                               '00install.out',
                               '%s-Ex.Rout' % pkg,
                               '%s-Ex_i386.Rout' % pkg,
                               '%s-Ex_x64.Rout' % pkg,
                               '%s-Ex.timings' % pkg,
                               'examples_i386',
                               'examples_x64',
                               'tests',
                               'tests_i386',
                               'tests_x64',
                               '%s-manual.pdf' % pkg]
    for filename in os.listdir(Rcheck_dir):
        if filename not in top_level_stuff_to_keep:
            path = os.path.join(Rcheck_dir, filename)
            dangling_paths.append(path)
    # Collect stuff to remove from 'examples_i386/' and 'examples_x64/'.
    file_to_keep = '%s-Ex.timings' % pkg
    for subdir in ['examples_i386', 'examples_x64']:
        path = os.path.join(Rcheck_dir, subdir)
        if os.path.isdir(path):
            for filename in os.listdir(path):
                if filename != file_to_keep:
                    path2 = os.path.join(path, filename)
                    dangling_paths.append(path2)
    # Collect stuff to remove from 'tests/', 'tests_i386/', and 'tests_x64/'.
    for subdir in ['tests', 'tests_i386', 'tests_x64']:
        path = os.path.join(Rcheck_dir, subdir)
        if os.path.isdir(path):
            for filename in os.listdir(path):
                path2 = os.path.join(path, filename)
                if os.path.isdir(path2) or filename == 'startup.Rs':
                    dangling_paths.append(path2)
    # Remove collected stuff.
    for path in dangling_paths:
        if os.path.isdir(path):
            bbs.fileutils.nuke_tree(path, ignore_errors=True)
        else:
            try:
                os.remove(path)
            except:
                pass
    return

def kindly_notify_us(what, e, to_addrs=None):
    if to_addrs == None:
        to_addrs = ['maintainer@bioconductor.org']
    subject = (f'[BBS] {what} failure '
               f'for {BBSvars.bioc_version} {BBSvars.buildtype} builds '
               f'on {BBSvars.node_hostname}')
    msg_body = f'{what} failed on {BBSvars.node_hostname} ' + \
               f'for the {BBSvars.bioc_version} builds ' + \
               f'with the following error:\n' + \
               f'\n' + \
               f'  -----------------------------------------------------\n' + \
               f'  {e}\n' + \
               f'  -----------------------------------------------------\n' + \
               f'\n' + \
               f'See logs in {BBSvars.work_topdir}/log/ ' + \
               f'on {BBSvars.node_hostname} for more information.'
    bbs.notify.mode = 'do-it'
    bbs.notify.sendtextmail('BBS-noreply@bioconductor.org',
                            to_addrs,
                            subject,
                            msg_body)
    return

##############################################################################
### Generate the system commands used for installing (STAGE2), building
### (STAGE3 and STAGE5), and checking (STAGE4) each package.
##############################################################################

def _get_prepend_from_BBSoptions(pkgsrctree, key_prefix):
    key = key_prefix + 'prepend'
    prepend = bbs.parse.get_BBSoption_from_pkgsrctree(pkgsrctree, key)
    if sys.platform == 'win32':
        key2 = key + '.win'
        prepend_win = bbs.parse.get_BBSoption_from_pkgsrctree(pkgsrctree, key2)
        if prepend_win != None:
            prepend = prepend_win
    elif sys.platform == 'darwin':
        key2 = key + '.mac'
        prepend_mac = bbs.parse.get_BBSoption_from_pkgsrctree(pkgsrctree, key2)
        if prepend_mac != None:
            prepend = prepend_mac
    return prepend

def _BiocGreaterThanOrEqualTo(x, y):
    # If 'BBSvars.bioc_version' is not defined, then we assume it's the
    # latest version.
    if BBSvars.bioc_version == None:
        return True
    parts = BBSvars.bioc_version.split('.')
    x0 = int(parts[0])
    y0 = int(parts[1])
    return x0 > x or (x0 == x and y0 >= y)

def _noExampleArchs(pkgsrctree):
    archs = []
    no_examples = bbs.parse.get_BBSoption_from_pkgsrctree(
                                pkgsrctree,
                                'NoExamplesOnPlatforms')
    if no_examples == None:
        return archs
    no_examples = no_examples.replace(" ", "").split(",")
    clean = []
    for item in no_examples:
        clean.append(item.strip())
    no_examples = clean
    if 'mac' in no_examples:
        archs.append('darwin')
    if 'win' in no_examples:
        archs.append('win32')
        archs.append('win32')
    if 'win32' in no_examples:
        archs.append('win32')
    if 'win64' in no_examples:
        archs.append('win32')
    if 'linux2' in no_examples:
        archs.append('linux2')
# see
#http://stackoverflow.com/questions/2144748/is-it-safe-to-use-sys-platform-win32-check-on-64-bit-python
# to explain the above.
    return archs

def _supportedWinArchs(pkgsrctree):
    archs = []
    unsupported = bbs.parse.get_BBSoption_from_pkgsrctree(
                                pkgsrctree,
                                'UnsupportedPlatforms')
    if unsupported == None:
        unsupported = []
    else:
        unsupported = unsupported.replace(" ", "").split(",")
    if "win" in unsupported:
        return archs
    if 'win32' not in unsupported:
        archs.append("i386")
    if "win64" not in unsupported:
        archs.append("x64")
    return archs

def _get_RINSTALL_cmd0(win_archs=None):
    cmd0 = BBSvars.r_cmd
    if win_archs != None and len(win_archs) == 1:
        cmd0 += ' --arch %s' % win_archs[0]
    cmd0 += ' CMD INSTALL'
    if win_archs != None and len(win_archs) >= 1:
        if len(win_archs) == 1:
            cmd0 += ' --no-multiarch'
        else:
            cmd0 += ' --merge-multiarch'
    return cmd0

### 'srcpkg_path' must be the path to a package source tarball.
def _get_BuildBinPkg_cmd(srcpkg_path, win_archs=None):
    pkg = bbs.parse.get_pkgname_from_srcpkg_path(srcpkg_path)
    pkg_instdir = "%s.buildbin-libdir" % pkg
    if sys.platform != 'darwin':
        ## Generate the command for Windows or Linux. Note that this command
        ## is never needed nor used on Linux.
        cmd0 = _get_RINSTALL_cmd0(win_archs)
        cmd = '%s --build --library=%s %s' % (cmd0, pkg_instdir, srcpkg_path)
    else:
        cmd0 = '%s/utils/build-universal.sh' % BBSvars.BBS_home
        cmd = '%s %s %s %s' % (cmd0, srcpkg_path, BBSvars.r_cmd, pkg_instdir)
    cmd = 'rm -rf %s && mkdir %s && %s' % (pkg_instdir, pkg_instdir, cmd)
    return cmd

## Crazy long command used on the Windows builders to install "light" source
## tarballs from the target repo located on the central builder. It proceeds
## in 3 steps:
##   1. Download the "light" source tarball from the target repo.
##   2. Build the Windows binary (.zip) from the "light" source tarball.
##   3. Install the Windows binary with 'R CMD INSTALL'.
## With this approach, the multiarch installation is guaranteed to be
## atomic i.e. either the 2 archs get successfully installed or nothing
## gets installed.
## Here is what Dan's commit message says about why BBS uses this long and
## complicated compound command to install packages on Windows during STAGE2
## (commit 87822fb346e04b4301d0c2efd7ec1a2a8762e93a'):
##   Install STAGE2 target pkgs to zip+libdir first, then install
##   zip. This mitigates the problem where the INSTALL times out
##   after installing only one architecture. Now, if the install
##   times out, it has only failed to install a package to a
##   temporary libdir, and the previous installation is still
##   intact (or pkg is not installed at all), so dependent packages
##   will not complain about the timed-out package being only
##   available for one architecture.
##   We still need to figure out why mzR in particular times out
##   during INSTALL. When run manually (admittedly not during
##   peak load times) the install takes ~ 5-6 minutes, even when
##   done via the build system.
def _get_InstallPkgFromTargetRepo_cmd(pkg, version, win_archs=None):
    srcpkg_file = '%s_%s.tar.gz' % (pkg, version)
    srcpkg_url = BBSvars.Central_rdir.url + '/src/contrib/' + srcpkg_file
    zip_file = srcpkg_file.replace(".tar.gz", ".zip")
    cmd = '%s -O %s' % (BBSvars.curl_cmd, srcpkg_url) + ' && ' + \
          _get_BuildBinPkg_cmd(srcpkg_file, win_archs) + ' && ' + \
          '%s %s' % (_get_RINSTALL_cmd0(), zip_file) + ' && ' + \
          'rm %s %s' % (srcpkg_file, zip_file)
    return cmd

def _get_Rbuild_cmd(pkgsrctree):
    arch = ""
    if sys.platform == 'win32':
        win_archs = _supportedWinArchs(pkgsrctree)
        if len(win_archs) == 1:
            arch = " --arch %s" % win_archs[0]
    cmd = '%s%s CMD build' % (BBSvars.r_cmd, arch)
    if sys.platform == 'win32':
        ## Fix the permissions on Windows only.
        ## The real purpose of this is to try to work around a strange Cygwin
        ## tar problem ("file changed as we read it") observed so far on
        ## Windows Server 2008 R2 Enterprise (64-bit) only.
        ## Traversing the package source tree, with e.g. a call to
        ## 'chmod a+r <pkgsrctree> -R', just before we try to build the
        ## package seems to "fix" the state of the filesystem and to
        ## make 'tar' work again on it.
        cmd = 'chmod a+r ' + pkgsrctree + ' -R && ' + cmd
    common_opts = ["--keep-empty-dirs", "--no-resave-data"]
    if BBSvars.buildtype == "bioc-longtests":
        common_opts += ["--no-build-vignettes", "--no-manual"]
    cmd = "%s %s" % (cmd, ' '.join(common_opts))
    return cmd

def _get_Rcheck_cmd0(win_archs=None):
    cmd = BBSvars.r_cmd
    if win_archs != None and len(win_archs) == 1:
        cmd += ' --arch %s' % win_archs[0]
    cmd += ' CMD check'
    if win_archs != None:
        if len(win_archs) <= 1:
            cmd += ' --no-multiarch'
        else:
            cmd += ' --force-multiarch'
    return cmd

### During STAGE1, we need to build a "light" source tarball for each package.
### By "light" here we mean that we don't care about the vignette or \Sexpr
### directives in the man pages: trying to execute the code contained in the
### vignette and/or the \Sexpr directives is too expensive (it can take a long
### time) and, most importantly, it's too risky (it can fail).
### Using 'R CMD build --no-vignettes' for building a "light" source tarball
### isn't good enough: it will still try to install the package if the man
### pages contain \Sexpr directives. Unfortunately, at this time (R 2.14),
### there doesn't seem to be any option for turning off the evaluation of the
### \Sexpr. So, for now, we build the "light" source tarball "by hand" i.e.
### we just use 'tar zcf'.
def getSTAGE1cmd(pkgsrctree):
    #cmd = _get_Rbuild_cmd(pkgsrctree) + ' --no-build-vignettes ' + pkgsrctree
    key = 'BBS_TAR_CMD'
    tar_cmd = os.environ[key]
    srcpkg_file = bbs.parse.make_srcpkg_file_from_pkgsrctree(pkgsrctree)
    cmd = '%s zcf %s %s' % (tar_cmd, srcpkg_file, pkgsrctree)
    return cmd

def get_install_cmd_for_non_target_pkg(pkg):
    script_path = os.path.join(BBSvars.BBS_home,
                               "utils",
                               "installNonTargetPkg.R")
    # Backslahes in the path injected in 'Rexpr' will be seen as escape
    # characters by R so we need to replace them. Nothing will be replaced
    # on a Unix-like platform, only on Windows where the paths can actually
    # contain backslahes.
    script_path = script_path.replace('\\', '/')
    Rexpr = "source('%s');" % script_path
    if sys.platform == 'win32' and BBSvars.STAGE2_mode == 'multiarch':
        Rexpr += "installNonTargetPkg('%s',multiArch=TRUE)" % pkg
    else:
        Rexpr += "installNonTargetPkg('%s')" % pkg
    return Rexpr2syscmd(Rexpr)

def get_update_cmd_for_non_target_pkgs():
    script_path = os.path.join(BBSvars.BBS_home,
                               "utils",
                               "installNonTargetPkg.R")
    # Backslahes in the path injected in 'Rexpr' will be seen as escape
    # characters by R so we need to replace them. Nothing will be replaced
    # on a Unix-like platform, only on Windows where the paths can actually
    # contain backslahes.
    script_path = script_path.replace('\\', '/')
    Rexpr = "source('%s');" % script_path
    if sys.platform == 'win32' and BBSvars.STAGE2_mode == 'multiarch':
        Rexpr += "updateNonTargetPkgs(multiArch=TRUE)"
    else:
        Rexpr += "updateNonTargetPkgs()"
    return Rexpr2syscmd(Rexpr)

def getSTAGE2cmd(pkg, version):
    if sys.platform == 'win32' and BBSvars.STAGE2_mode == 'multiarch':
        win_archs = _supportedWinArchs(pkg)
        if len(win_archs) == 2:
            # Use crazy long command for multiarch INSTALLs.
            # See _get_InstallPkgFromTargetRepo_cmd() above for more info.
            cmd = _get_InstallPkgFromTargetRepo_cmd(pkg, version, win_archs)
        else:
            # Use arch-specific INSTALL command:
            #   R --arch x64 CMD INSTALL --no-multiarch <pkg>
            # or:
            #   R --arch i386 CMD INSTALL --no-multiarch <pkg>
            cmd = '%s %s' % (_get_RINSTALL_cmd0(win_archs), pkg)
    else:
        # Use standard INSTALL command: R CMD INSTALL <pkg>
        cmd = '%s %s' % (_get_RINSTALL_cmd0(), pkg)
    prepend = _get_prepend_from_BBSoptions(pkg, 'INSTALL')
    if prepend != None and prepend != '':
        cmd = '%s %s' % (prepend, cmd)
    return cmd

def getSTAGE3cmd(pkgsrctree):
    cmd =  _get_Rbuild_cmd(pkgsrctree) + ' ' + pkgsrctree
    prepend = _get_prepend_from_BBSoptions(pkgsrctree, 'BUILD')
    if prepend != None and prepend != '':
        cmd = '%s %s' % (prepend, cmd)
    return cmd

### Note that 'R CMD check' installs the package in <pkg>.Rcheck. However,
### an undocumented 'R CMD check' feature allows one to avoid this installation
### if the package is already installed somewhere and if the output of the
### 'R CMD INSTALL' command that led to this installation was captured in a
### file. Typical use of this feature:
###   R CMD INSTALL toto_0.17.31.tar.gz >toto.install-out.txt 2>&1
###   R CMD check --install=check:toto.install-out.txt \
###               --library=path/to/R/library \
###               toto_0.17.31.tar.gz
### All there is about this is a comment in tools/R/check.R at the beginning
### of the check_install() function. Also this feature was mentioned once by
### Uwe Ligges on the R-devel mailing list:
###   https://stat.ethz.ch/pipermail/r-devel/2011-June/061377.html
### and, more recently, by Tomas Kalibera in an off-list discussion about
### 'packages writing to "library" directory during their tests' (Feb 2018).
### 'srcpkg_path' must be the path to a package source tarball.
def getSTAGE4cmd(srcpkg_path):
    pkg = bbs.parse.get_pkgname_from_srcpkg_path(srcpkg_path)
    if sys.platform != 'win32':
        win_archs = None
    else:
        if BBSvars.STAGE4_mode == 'multiarch':
            win_archs = _supportedWinArchs(pkg)
        else:
            win_archs = []
    cmd0 = _get_Rcheck_cmd0(win_archs)
    common_opts = []
    ## If the package was candidate for installation during STAGE2, there
    ## should be a <pkg>.install-out.txt file in the current working directory
    ## containing the log of the installation. In this case, we can avoid a
    ## costly re-installation by using the undocumented 'R CMD check' feature
    ## described above. This introduces 3 minor gotcha though:
    ##   1) We now rely on an documented feature.
    ##   2) The exact command used for CHECK is displayed on the build report.
    ##      Not only will this command now look cryptic to the developer but
    ##      s/he also won't be able to just copy/paste it into her/his terminal
    ##      in order to reproduce the 'R CMD check' results from the report.
    ##   3) This undocumented feature only works as expected if
    ##      <pkg>.install-out.txt and R_HOME/library/pkg match i.e. if the
    ##      latter actually contains the package installed by the command
    ##      whose output was captured in the former. This will generally be
    ##      the case unless the package got re-installed after its STAGE2
    ##      installation (which could happen e.g. if another package contains
    ##      code that calls BiocManager::install() to install a possibly
    ##      different version of the package). Unlikely but possible.
    install_out = pkg + '.install-out.txt'
    if os.path.exists(install_out):
        if BBSvars.r_libs != None:
            r_library = BBSvars.r_libs
        else:
            r_library = os.path.join(BBSvars.r_home, 'library')
        common_opts += ["--install=check:%s" % install_out,
                        "--library=%s" % r_library]
    if BBSvars.buildtype == "bioc-longtests":
        common_opts += ["--test-dir=longtests",
                        "--no-stop-on-test-error",
                        "--no-codoc",
                        "--no-examples",
                        "--no-manual",
                        "--ignore-vignettes",
                        "--check-subdirs=no"]
    else:
        ## Skip the vignette checks on Windows and Mac only, to reduce
        ## build times.
        if BBSvars.extra_check_options != None:
            common_opts += [BBSvars.extra_check_options]
        common_opts += ["--timings"]
        ## Note that sys.platform is set to 'win32' on 64-bit Windows. This
        ## means that _noExampleArchs() may not be returning useful results
        ## if the intent is to not run examples for a particular Windows
        ## sub-architecture.
        no_example_archs = _noExampleArchs(pkg)
        if sys.platform in no_example_archs:
            common_opts += ["--no-examples"]
    common_opts = ' '.join(common_opts)
    cmd = '%s %s %s' % (cmd0, common_opts, srcpkg_path)
    prepend = _get_prepend_from_BBSoptions(pkg, 'CHECK')
    if prepend != None and prepend != '':
        cmd = '%s %s' % (prepend, cmd)
    return cmd

### On Windows we use 'R CMD INSTALL --build' on the source tarball produced
### at STAGE3. Note that zipping the package installation folder located in
### R_HOME\library would avoid an extra package installation/compilation
### but would also produce a .zip file with no vignettes in it.
### 'srcpkg_path' must be the path to a package source tarball.
def getSTAGE5cmd(srcpkg_path):
    pkg = bbs.parse.get_pkgname_from_srcpkg_path(srcpkg_path)
    if sys.platform == 'win32' and BBSvars.STAGE5_mode == 'multiarch':
        win_archs = _supportedWinArchs(pkg)
    else:
        win_archs = None
    cmd = _get_BuildBinPkg_cmd(srcpkg_path, win_archs)
    prepend = _get_prepend_from_BBSoptions(pkg, 'BUILDBIN')
    if prepend != None and prepend != '':
        cmd = '%s %s' % (prepend, cmd)
    return cmd

##############################################################################
## Output files produced by 'R CMD build/check'.
##############################################################################

class PkgDumps:
    def __init__(self, product_path, prefix):
        self.product_path = product_path
        self.out_file = prefix + '-out.txt'
        self.MISSING_file = prefix + '-MISSING'
        self.summary_file = prefix + '-summary.dcf'
    def Push(self, destdir, exclude_product=False):
        if exclude_product or self.product_path == None:
            products_to_push = []
        else:
            if os.path.exists(self.product_path):
                if os.path.exists(self.MISSING_file):
                    os.remove(self.MISSING_file)
                products_to_push = [self.product_path]
            else:
                bbs.fileutils.touch(self.MISSING_file)
                products_to_push = [self.MISSING_file]
        products_to_push += [self.out_file, self.summary_file]
        if isinstance(destdir, bbs.rdir.RemoteDir):
            destdir.Mput(products_to_push, False, True)
        else:
            for path in products_to_push:
                BBSutils.copyTheDamnedThingNoMatterWhat(path, destdir)
        return

##############################################################################
### The Summary class is used by the _MakeSummary() method of the BuildPkg_Job
### and CheckSrc_Job classes to generate a summary.
##############################################################################

### Finally, I opted for the Append() solution to add extra stuff to the
### summary (and not for the "derive the Summary class and overwrite the
### Write() method" solution).
class Summary:
    def __init__(self, pkg, version, cmd):
        self.pkg = pkg
        self.version = version
        self.cmd = cmd
        self.tail = []
    def Append(self, field, val):
        pair = (field, val)
        self.tail.append(pair)
    def Write(self, file):
        f = open(file, 'w')
        f.write('Package: %s\n' % self.pkg)
        f.write('Version: %s\n' % self.version)
        f.write('Command: %s\n' % self.cmd)
        f.write('StartedAt: %s\n' % self.started_at)
        f.write('EndedAt: %s\n' % self.ended_at)
        f.write('EllapsedTime: %.1f seconds\n' % self.dt)
        if self.retcode == None:
            f.write('RetCode: None\n')
        else:
            f.write('RetCode: %d\n' % self.retcode)
        f.write('Status: %s\n' % self.status)
        for pair in self.tail:
            f.write('%s: %s\n' % pair)
        f.close()
        return

##############################################################################
### CORE FUNCTIONS: Called by the STAGE<N>_loop() functions (N=2,3,4,5).
##############################################################################

class InstallPkg_Job(bbs.jobs.QueuedJob):
    def __init__(self, pkg, version, cmd, pkgdumps, out_dir):
        ## Required fields
        self._name = pkg
        self._cmd = cmd
        if pkgdumps != None:
            self._output_file = pkgdumps.out_file
        else:
            self._output_file = None
        ## Additional fields
        self.pkg = pkg
        self.version = version
        self.pkgdumps = pkgdumps
        self.out_dir = out_dir
        self.summary = Summary(pkg, version, cmd)
    def RerunMe(self):
        locking_pkg = bbs.parse.extractLockingPackage(self._output_file)
        ## We re-run only if the lock was on one of the deps, but not on the
        ## package itself.
        rerun_me = locking_pkg != None and locking_pkg != self.pkg
        return rerun_me
    def _MakeSummary(self):
        self.summary.started_at = self._started_at
        self.summary.ended_at = self._ended_at
        self.summary.dt = self._t2 - self._t1
        self.summary.Write(self.pkgdumps.summary_file)
        self.pkgdumps.Push(self.out_dir)
    def AfterRun(self):
        self.summary.retcode = self._retcode
        if self._retcode == 0 and \
           bbs.parse.installPkgWasOK(self._output_file, self.pkg):
            self.summary.status = 'OK'
            cumul_inc = 1
        else:
            self.summary.status = 'ERROR'
            cumul_inc = 0
        self._MakeSummary()
        return cumul_inc
    def AfterTimeout(self, maxtime_per_job):
        self.summary.retcode = None
        self.summary.status = 'TIMEOUT'
        self._MakeSummary()

class BuildPkg_Job(bbs.jobs.QueuedJob):
    def __init__(self, pkg, version, cmd, pkgdumps, out_dir, dont_push_product=False):
        ## Required fields
        self._name = pkg
        self._cmd = cmd
        self._output_file = pkgdumps.out_file
        ## Additional fields
        self.pkg = pkg
        self.version = version
        self.pkgdumps = pkgdumps
        self.out_dir = out_dir
        self.summary = Summary(pkg, version, cmd)
        self.dont_push_product = dont_push_product
    def _MakeSummary(self):
        self.summary.started_at = self._started_at
        self.summary.ended_at = self._ended_at
        self.summary.dt = self._t2 - self._t1
        pkg_file = self.pkgdumps.product_path
        if os.path.exists(pkg_file):
            pkg_file_size = bbs.fileutils.human_readable_size(bbs.fileutils.total_size(pkg_file), True)
        else:
            pkg_file = 'None'
            pkg_file_size = 'NA'
        self.summary.Append('PackageFile', pkg_file)
        self.summary.Append('PackageFileSize', pkg_file_size)
        self.summary.Write(self.pkgdumps.summary_file)
        self.pkgdumps.Push(self.out_dir, exclude_product=self.dont_push_product)
    def AfterRun(self):
        # Avoid leaving rogue processes messing around on the build machine.
        # self._proc.pid should be already dead but some of its children might
        # still be alive. They need to die too. bbs.jobs.killProc() should work
        # on a non-existing pid and it should be able to kill all the processes
        # that were started directly or indirectly by pid.
        # This needs to happen before calling self._MakeSummary() because
        # these rogue processes can break the rsync command used by
        # self.pkgdumps.Push(self.out_dir) above by holding on some of the
        # files that need to be pushed to the central build node.
        bbs.jobs.killProc(self._proc.pid)
        self.summary.retcode = self._retcode
        pkg_file = self.pkgdumps.product_path
        if os.path.exists(pkg_file) and self._retcode == 0:
            self.summary.status = 'OK'
            cumul_inc = 1
        else:
            self.summary.status = 'ERROR'
            cumul_inc = 0
        self._MakeSummary()
        return cumul_inc
    def AfterTimeout(self, maxtime_per_job):
        self.summary.retcode = None
        self.summary.status = 'TIMEOUT'
        self._MakeSummary()

class CheckSrc_Job(bbs.jobs.QueuedJob):
    def __init__(self, pkg, version, cmd, pkgdumps, out_dir):
        ## Required fields
        self._name = pkg
        self._cmd = cmd
        self._output_file = pkgdumps.out_file
        ## Additional fields
        self.pkg = pkg
        self.version = version
        self.pkgdumps = pkgdumps
        self.out_dir = out_dir
        self.summary = Summary(pkg, version, cmd)
        self.warnings = 'NA'
        #NOT NEEDED. '00install.out' is under the '<pkg>.Rcheck' dir
        #and we already push this dir to self.out_dir as part of self.pkgdumps
        #self.install_out = os.path.join('%s.Rcheck' % pkg, '00install.out')
    def _MakeSummary(self):
        self.summary.started_at = self._started_at
        self.summary.ended_at = self._ended_at
        self.summary.dt = self._t2 - self._t1
        Rcheck_dir = self.pkgdumps.product_path
        if os.path.exists(Rcheck_dir):
            _clean_Rcheck_dir(Rcheck_dir, self.pkg)
        else:
            Rcheck_dir = 'None'
        self.summary.Append('CheckDir', Rcheck_dir)
        self.summary.Append('Warnings', self.warnings)
        self.summary.Write(self.pkgdumps.summary_file)
        self.pkgdumps.Push(self.out_dir)
        ## Sometimes, '00install.out' is not generated (e.g. when some required
        ## packages are not available)
        #NOT NEEDED (see above).
        #if os.path.exists(self.install_out):
        #    self.out_dir.Put(self.install_out, True, True)
    def AfterRun(self):
        # Avoid leaving rogue processes messing around on the build machine.
        # self._proc.pid should be already dead but some of its children might
        # still be alive. They need to die too. bbs.jobs.killProc() should work
        # on a non-existing pid and it should be able to kill all the processes
        # that were started directly or indirectly by pid.
        # This needs to happen before calling self._MakeSummary() because
        # these rogue processes can break the rsync command used by
        # self.pkgdumps.Push(self.out_dir) above by holding on some of the
        # files that need to be pushed to the central build node.
        bbs.jobs.killProc(self._proc.pid)
        self.summary.retcode = self._retcode
        if self._retcode == 0:
            self.warnings = bbs.parse.countWARNINGs(self._output_file)
            if self.warnings == "0":
                self.summary.status = 'OK'
            else:
                self.summary.status = 'WARNINGS'
            cumul_inc = 1
        else:
            self.summary.status = 'ERROR'
            cumul_inc = 0
        self._MakeSummary()
        return cumul_inc
    def AfterTimeout(self, maxtime_per_job):
        self.summary.retcode = None
        self.summary.status = 'TIMEOUT'
        self._MakeSummary()


def match(first, second):
    l = r = 0
    last_wild = None
    while l < len(first) and r < len(second):
        if first[l] == '?' or first[l] == '*':
            last_wild = first[l]
        if not last_wild:
            if first[l] != second[r]:
                return False
            l += 1
            r += 1
        elif last_wild == '?':
            l += 1
            r += 1
        else: # last_wild == '*'
            l += 1
            while first[l] != second[r] and r < len(second):
                r += 1
        last_wild = None
    if l != len(first) or r != len(second):
        return False
    else:
        return True


import time
import machine

class TickerTape:

    def __init__(self, display, num_segments, delay=0.1, inverse=False, timer=machine.Timer(-1)):
        self.display = display
        self.num_segments = num_segments
        self.delay = delay
        self.inverse = inverse
        self.text = "Hello World!"
        self.timer = timer

    def scroll(self):
        while True:
            scrolltext = ((self.num_segments + 1) * ' ') + self.text
            for i in range(len(scrolltext)-1):
                self.display.fill(self.inverse)
                self.display.text(scrolltext[i:i+self.num_segments+2], 0 ,1, not self.inverse)
                self.display.show()
                for _ in range(8):
                    self.display.scroll(-1,0)
                    self.display.show()
                    yield

    def start(self):
        self.gen = self.scroll()
        self.timer.init(period=int(self.delay * 1000), mode=machine.Timer.PERIODIC, callback=self._advance)

    def stop(self):
        if self.timer:
            self.timer.deinit()

    def _advance(self, t):
        next(self.gen)

def main():
    from machine import Pin, SPI
    import sys
    import max7219

    NUM_SEGMENTS = 4

    ## RP2 (Pico (W))
    if sys.platform == 'rp2': # RP2 (Pico (W))
        SPI_DEV = 1
        SPI_MOSI = Pin(11)
        SPI_SCK = Pin(10)
        SPI_CS = Pin(9)
        timer = machine.Timer(-1)
    elif sys.platform == 'esp32': # ESP32
        SPI_DEV = 1
        SPI_MOSI = Pin(2)
        SPI_SCK = Pin(4)
        SPI_CS = Pin(5)
        timer = machine.Timer(1)
    elif sys.platform == 'esp8266': # ESP8266 (NodeMCU)
        SPI_DEV = 1
        SPI_MOSI = Pin(13)
        SPI_SCK = Pin(14)
        SPI_CS = Pin(15)
        timer = machine.Timer(-1)

    spi = SPI(SPI_DEV, baudrate=10_000_000, sck=SPI_SCK, mosi=SPI_MOSI, polarity=0, phase=0)
    display = max7219.Matrix8x8(spi, cs=SPI_CS, num=NUM_SEGMENTS, extended=True)
    display.brightness(0)

    tickertape = TickerTape(display, NUM_SEGMENTS, timer=timer)
    tickertape.start()
    time.sleep(10)
    tickertape.text = "Bye World!"
    time.sleep(10)
    tickertape.stop()

if __name__ == '__main__':
    main()


import io
import spacy
import sys
from markdown import markdown
import pytesseract
from PIL import Image
from cnocr import CnOcr
from pypdf import PdfReader
from prompts import Prompt
from core import OCR_LANG, OCR_TYPE, brain
from PyQt6.QtWidgets import QApplication, QMainWindow, QTextBrowser
class OCR():
    def __init__(self) -> None:
        if OCR_LANG == "zh-CN":
            self.spacy_model = "zh_core_web_sm"
            self.rec_model = 'ch_PP-OCRv3'

        if OCR_LANG == "en-US":
            self.spacy_model = "en_core_web_sm"
            self.rec_model = 'en_PP-OCRv3'
        self.nlp = spacy.load(self.spacy_model)
        self.img_file = None
        self.ocr_type = OCR_TYPE

    def ocr_pdf(self, pdf_file, page_number=None, scope=False):
        reader = PdfReader(pdf_file)
        outs = []
        pages = reader.pages

        if type(page_number) is int:
            pages = [reader.pages[page_number]]

        if type(page_number) is list:
            if scope:
                page_number = range(page_number[0],page_number[1])
            for page in page_number:
                for image_file_object in reader.pages[page].images:
                    self.img_file = Image.open(io.BytesIO(image_file_object.data))
                    outs.append(self.paddOCR())
            return "".join(outs)

        for page in pages:
            for image_file_object in page.images:
                self.img_file = Image.open(io.BytesIO(image_file_object.data))
                outs.append(self.paddOCR())
        return "".join(outs)

    def ocr_img(self,img_file):
        self.img_file = img_file
        if self.ocr_type == "tesseract":
            out = self.tessOCR()

        if self.ocr_type == "paddle":
            out = self.paddOCR(self.rec_model)

        self.doc = self.nlp(out)
        sentences = [sent.text for sent in self.doc.sents]
        return sentences

    def tessOCR(self, lang='eng+chi_sim'):
        out = pytesseract.image_to_string(self.img_file, lang)
        return out

    def paddOCR(self, rec_model_name):
        ocr = CnOcr(rec_model_name)
        out = "".join([i['text'] for i in ocr.ocr(self.img_file)])
        return out

if __name__ == "__main__":
    rco = OCR()
    res = "".join(rco.ocr_img('.latest.screenshot.png'))
    conversation = []
    conversation.append(Prompt.screenshot.value)
    conversation.append({
        "role": "user",
        "content": res
    })
    result = brain(conversation)
    app = QApplication(sys.argv)
    window = QMainWindow()
    text_browser = QTextBrowser(window)
    window.setCentralWidget(text_browser)
    window.setGeometry(QApplication.primaryScreen().size().width(), 0, 400, QApplication.primaryScreen().size().height())
    text_browser.setText(markdown(result))
    window.show()
    sys.exit(app.exec())


'''
Změn funkci z předchozího úkolu tak, aby funkce měla tři argumenty – číslo,
počet vypisovaných násobků, znak pro oddělení vypsaných násobků.
'''

def nasobky(n,nasobek, delimiter):
    ''' Vrat n nasobek zadaneho cisla, vysledky oddel delimiterem
    # INPUT
    n - cislo, ktere bude nasobeno, integer
    nasobek - kolikrat bude nasobeno n, integer
    delimiter - oddelovaci znak, string

    # OUTPUT
    tisk do konzole
    '''
    for cislo in range(nasobek):
        vysledek = cislo * nasobek
        print(vysledek, end = str(delimiter)+'\n')

nasobky(2, 8, 'xFF')


#Write a function called "last_n" that accepts two arguments:
#a string searchString and an integer n. The function should
#return the last n characters frm searchString. If
#searchString is shorter than n characters, then it should
#return the entire value of searchString.

#Write your function here!
def last_n(searchString,n):
    if len(searchString) > n:
        return searchString[-n:]
    else:
        return searchString

#The code below will test your function. If your function
#works correctly, this should print 789, saur, and 1.
#print(last_n("123456789", 3))
#print(last_n("Bulbasaur", 4))
print(last_n("1", 5))


# 创建列表
class12 = [
    "01张晴晴",
    "02吴佳煜",
    "03钱秋萍",
    "00徐红明",
    "05邹佳芸",
    "06朱蒋岚",
    "07赵怡月",
    "08游欣悦",
    "09沈雨洋",
    "10徐佳雨",
    "11王欣怡",
    "12陈皖晴",
    "13朱辰媛",
    "14孙俏",
    "15李宜霏",
    "16任煜霏",
    "17台育蕊",
    "18陈慧",
    "19何雪",
    "20莫佳妮",
    "21顾心怡",
    "22杨钰雯",
    "23苏雨欣",
    "24曾海瑞",
    "25张权凯",
    "26江宇轩",
    "27陈晨",
    "28陈浩",
    "29蒋熠晨",
    "30张思诚",
    "31罗一鸣",
    "32杨熠恒",
    "33周昊天",
    "34曹国梁",
    "35王奇",
    "36沈心源",
    "37沈振亓",
    "38周顺利",
    "39康治坤",
    "40周杰",
    "41陆小凡",
    "42沈航宇",
    "43徐天成",
    "44鲍宇",
    "45王缪丞"
    ]

# 列表末尾添加元素 列表.append(元素值)
# class12.append("46庞宇帆")    # append 在列表末尾增加元素

# 打印列表： print(列表)
# print(class12)

# 遍历列表
# for item in class12:
#    print(item)

# 列表指定位置插入元素  列表.insert(索引号, 元素值)
# class12.insert(4, "04陆诗颖")  # insert 指定位置插入元素

# 删除元素  列表.remove(元素值)
# class12.remove("00徐红明")                # 删除列表中第一个元素

# 删除元素  del 列表[索引号]#
# del class12[5]                # 删除指定位置元素

# 弹出元素  列表.pop(索引号)
# item = class12.pop(0)
# print(item)
# print(class12)

# 列表长度： len(列表)
# print('班级人数：', len(class12))

# 随机选择：random.choice()
# import random
# item = random.choice(class12)
# print('幸运儿是：', item)
# class12.remove(item)


init_presents = int(input())
n = int(input())
matrix = [input().split() for row in range(n)]
presents_delivered = 0
def check_inside(santa_position):
    y, x = santa_position
    if y not in range(0, len(matrix)) or x not in range(0, len(matrix)):
        return False
    return True

def santa_movement(position, command, matrix):
    y, x = position
    matrix[y][x] = '-'
    if command == 'down':
        position = y + 1, x
    elif command == 'up':
        position = y - 1, x
    elif command == 'right':
        position = y, x + 1
    elif command == 'left':
        position = y, x - 1
    return position

def field_update(santa_position,bad_kids,good_kids,cookies,matrix,presents):
    y,x = santa_position
    if santa_position in bad_kids:
        bad_kids.remove(santa_position)
        matrix[y][x] = 'S'
    elif santa_position in good_kids:
        good_kids.remove(santa_position)
        matrix[y][x] = 'S'
        presents -=1
    elif santa_position in cookies:
        matrix[y][x] = 'S'
        cookies.remove(santa_position)
        if (y+1,x) in good_kids:
            good_kids.remove((y+1,x))
            presents -= 1
        elif (y+1,x) in bad_kids:
            presents -=1
        matrix[y+1][x] == '-'
        if (y-1,x) in good_kids:
            presents -= 1
            good_kids.remove((y-1),x)
        elif (y-1,x) in bad_kids:
            presents -=1
        matrix[y-1][x] = '-'
        if (y,x+1) in good_kids:
            presents -= 1
            good_kids.remove((y,x+1))
        elif (y,x+1) in bad_kids:
            presents -=1
        matrix[y][x+1] = '-'
        if (y,x-1) in good_kids:
            good_kids.remove((y,x-1))
            presents -= 1
        elif (y,x-1) in bad_kids:
            presents -=1
        matrix[y][x-1] = '-'
    matrix[y][x] = 'S'
    return matrix,presents

def positioning(matrix):
    santa_position = [(row,col) for col in range(n) for row in range(n) if matrix[row][col] == 'S'].pop()
    bad_kids = [(row,col) for col in range(n) for row in range(n) if matrix[row][col] == 'X']
    good_kids = [(row,col) for col in range(n) for row in range(n) if matrix[row][col] == 'V']
    cookies = [(row,col) for col in range(n) for row in range(n) if matrix[row][col] == 'C']
    presents_to_give = len(good_kids)
    return santa_position,bad_kids, good_kids,cookies,presents_to_give

command = input()
santa_position, bad_kids, good_kids, cookies,presents_to_give = positioning(matrix)
while command != "Christmas morning":
    if check_inside(santa_position):
        santa_position = santa_movement(santa_position,command,matrix)
        matrix, init_presents = field_update(santa_position,bad_kids,good_kids,cookies,matrix,init_presents)

    if init_presents <= 0:
        print("Santa ran out of presents!")
        [print(" ".join(r)) for r in matrix]
        break
    command = input()

if not good_kids:
    [print(" ".join(r)) for r in matrix]
    print(f"Good job, Santa! {presents_to_give} happy nice kid/s.")

else:
    print(f"No presents for {len(good_kids)} nice kid/s.")


def stringInput():
    string = str(input("give me a string without uppercase and freespace : "))
    str1 = string.replace(" ", "")
    str2 = str1.lower()
    return str2

def main(string, countRecursion, o, p):
    temp = ""
    nbrLetter = len(string)
    li = list(string.strip())
    # print(o,p)
    # print()
    # ---- Permutation avant derniere et derniere
    if li[nbrLetter - p] < li[nbrLetter - o]:
        temp = li[nbrLetter - p]
        li[nbrLetter - p] = li[nbrLetter - o]
        li[nbrLetter - o] = temp
        listToStr = ''.join([str(elem) for elem in li])
        print("chaine de caractere apres")
        print(listToStr)

    else:
        o += 1
        p += 1
        listToStr = ''.join([str(elem) for elem in li])
        countRecursion += 1
        main(listToStr, countRecursion, o, p)

if __name__ == "__main__":

    beautifulString = stringInput()
    print("chaine de caractere avant")
    print(beautifulString)
    result = main(beautifulString, countRecursion=0, o=1, p=2)


def solution(board):
    OX = {"O":0, "X":0, "completeO":0, "completeX":0}

    for b in board:
        countO = b.count("O")
        countX = b.count("X")
        OX["O"] += countO
        OX["X"] += countX
        # 가로로 완성된 경우
        if countO == 3:
            OX["completeO"] += 1
        if countX == 3:
            OX["completeX"] += 1

    if OX["O"] < OX["X"] or OX["O"] >= OX["X"] + 2:
        return 0

    if OX["O"] >= 3: # O가 3개 이상일 경우 완성된 갯수가 하나보다 크다면 성립 X
        # 세로로 완성된 경우
        if board[0][0] == "X" and board[1][0] == "X" and board[2][0] == "X":
            OX["completeX"] += 1
        if board[0][1] == "X" and board[1][1] == "X" and board[2][1] == "X":
            OX["completeX"] += 1
        if board[0][2] == "X" and board[1][2] == "X" and board[2][2] == "X":
            OX["completeX"] += 1
        if board[0][0] == "O" and board[1][0] == "O" and board[2][0] == "O":
            OX["completeO"] += 1
        if board[0][1] == "O" and board[1][1] == "O" and board[2][1] == "O":
            OX["completeO"] += 1
        if board[0][2] == "O" and board[1][2] == "O" and board[2][2] == "O":
            OX["completeO"] += 1
        # 대각선으로 완성된 경우
        if board[0][0] == "X" and board[1][1] == "X" and board[2][2] == "X":
            OX["completeX"] += 1
        if board[0][0] == "O" and board[1][1] == "O" and board[2][2] == "O":
            OX["completeO"] += 1
        if board[0][2] == "X" and board[1][1] == "X" and board[2][0] == "X":
            OX["completeX"] += 1
        if board[0][2] == "O" and board[1][1] == "O" and board[2][0] == "O":
            OX["completeO"] += 1

    if OX["completeX"] >= 1 and OX["completeO"] >= 1: # 둘 다 승리하는 경우
        return 0
    if OX["completeX"] == 1 or OX["completeX"] == 2: # X가 승리했는데 O의 개수와 다를 경우
        if OX["X"] != OX["O"]:
            return 0
    if OX["completeO"] == 1 or OX["completeO"] == 2:
        if OX["O"] <= OX["X"]:
            return 0
    return 1

프로그래머스/unrated/160585. 혼자서 하는 틱택토/혼자서 하는 틱택토.py

혼자서 하는 틱택토.py


#!/usr/bin/python3
'''
    script that deletes out-of-date archives, using the function do_clean:
'''
from fabric.api import run, env, hosts

env.hosts = ['52.23.184.231', '54.173.122.229']
env.user = 'ubuntu'

def do_clean(number=0):
    '''
        delete old archive files
    '''
    if number == 0:
        number = number + 2
    number = number + 1
    result = local('ls -t /versions | tail -n +number| xargs rm')
    if result.failed:
        return False
    result = run('ls -t /data/web_static/releases | tail -n +number| xargs rm')
    if result.failed:
        return False

    return True


"""Loading libraries and stuff"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

"""Preprocessing and metrics"""
from sklearn import preprocessing
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

"""Regressors"""
import xgboost as xgb
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.ensemble import AdaBoostRegressor
data = pd.read_csv('../input/train.csv', nrows=100000)
data.describe()
data.isnull().sum()
print('Size with nulls (train): %d' % len(data))
data = data.dropna(how = 'any', axis = 'rows')
print('Size without nulls (train): %d' % len(data))
k = 0
for i in data.fare_amount:
    if i < 0:
        k += 1
print("Number of fake fares: ", k)
print('Length of original data: %d' % len(data))
data = data[data.fare_amount>=0]
print('Lengh of new data: %d' % len(data))
data[data.fare_amount<70].fare_amount.hist(bins=70, figsize=(14,3))
plt.xlabel('Fare $USD')
plt.title("Histogram of fare's distribution");
data['lon_change'] = abs(data.dropoff_longitude - data.pickup_longitude)
data['lat_change'] = abs(data.dropoff_latitude - data.pickup_latitude)

features_train  = ['pickup_longitude',
               'pickup_latitude',
               'dropoff_longitude',
               'dropoff_latitude',
               'lat_change',
               'lon_change']
Y = data.fare_amount.as_matrix()
X = data[features_train]
Y = np.reshape(Y,(Y.shape[0],1))
X.head()
min_max_scaler = preprocessing.MinMaxScaler()
Y = min_max_scaler.fit_transform(Y)
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, Y, test_size=0.33, random_state=42)
#np.save('Xtrain.npy',Xtrain)
#np.save('Xtest.npy', Xtest)
#np.save('Ytrain.npy', Ytrain)
#np.save('Ytest.npy', Ytest)
class Regressors:
    def __init__(self, Xtrain, Xtest, Ytrain, Ytest):
        """Initializing"""
        self.Xtrain = Xtrain
        self.Xtest = Xtest
        self.Ytrain = Ytrain
        self.Ytest = Ytest

    def def_xgboost(self, estimators):
        """Defining the XGBoosting regressor"""
        xgb_ = xgb.XGBRegressor(objective ='reg:linear', learning_rate=0.01, max_depth=3, n_estimators=estimators)
        xgb_.fit(self.Xtrain, self.Ytrain)
        pred = xgb_.predict(self.Xtest)

        return pred

    def def_RandomForestRegressor(self, estimators):
        """Defining the Random Forest Regeressor"""
        rfr_ = RandomForestRegressor(n_estimators=estimators, max_depth=3)
        rfr_.fit(self.Xtrain, self.Ytrain)
        pred = rfr_.predict(self.Xtest)

        return pred

    def def_GradientBoostingRegressor(self, estimators):
        """Defining the Gradient Boosting Regressor"""
        gbr_ = GradientBoostingRegressor(n_estimators=estimators, max_depth=3)
        gbr_.fit(self.Xtrain, self.Ytrain)
        pred = gbr_.predict(self.Xtest)

        return pred

    def def_AdaBoostRegressor(self, estimators):
        """Defining Ada Boosting Regressor"""
        abr_ = AdaBoostRegressor(n_estimators=estimators)
        abr_.fit(self.Xtrain, self.Ytrain)
        pred = abr_.predict(self.Xtest)

        return pred
def def_metrics(ypred):
    mae = mean_absolute_error(Ytest, ypred)
    mse = mean_squared_error(Ytest, ypred)

    return mae, mse

def plot_performance(plot_name, loss_mae, loss_mse):
    steps = np.arange(50, 500, 50)
    plt.style.use('ggplot')
    plt.title(plot_name)
    plt.plot(steps, loss_mae, linewidth=3, label="MAE")
    plt.plot(steps, loss_mse, linewidth=3, label="MSE")
    plt.legend()
    plt.ylabel("Loss")
    plt.xlabel("Number of estimators")
    plt.show()
"""Initializing the class"""
model = Regressors(Xtrain, Xtest, Ytrain, Ytest)
plot_name="XGBoosting Regressor"
loss_mae, loss_mse = [], []
print(plot_name)
for est in range(50,500,50):
    print("Number of estimators: %d" % est)
    mae, mse = def_metrics(model.def_xgboost(estimators = est))
    print("MAE: ", mae)
    print("MSE: ", mse)
    loss_mae.append(mae)
    loss_mse.append(mse)
plot_performance(plot_name, loss_mae, loss_mse)
plot_name="Random Forest Regressor"
loss_mae, loss_mse = [], []
print(plot_name)
for est in range(50,500,50):
    print("Number of estimators: %d" % est)
    mae, mse = def_metrics(model.def_xgboost(estimators = est))
    print("MAE: ", mae)
    print("MSE: ", mse)
    loss_mae.append(mae)
    loss_mse.append(mse)
plot_performance(plot_name, loss_mae, loss_mse)
plot_name="Gradient Boosting Regressor"
loss_mae, loss_mse = [], []
print(plot_name)
for est in range(50,500,50):
    print("Number of estimators: %d" % est)
    mae, mse = def_metrics(model.def_xgboost(estimators = est))
    print("MAE: ", mae)
    print("MSE: ", mse)
    loss_mae.append(mae)
    loss_mse.append(mse)
plot_performance(plot_name, loss_mae, loss_mse)
plot_name="Ada Boost Regressor"
loss_mae, loss_mse= [], []
print(plot_name)
for est in range(50,500,50):
    print("Number of estimators: %d" % est)
    mae, mse = def_metrics(model.def_xgboost(estimators = est))
    print("MAE: ", mae)
    print("MSE: ", mse)
    loss_mae.append(mae)
    loss_mse.append(mse)
plot_performance(plot_name, loss_mae, loss_mse)


lista = []
par = 0
impar = 0
for i in range(5):
    numero = int(input('Digite um número: '))
    if numero % 2 == 0:
        par += 1
    else:
        impar += numero
    lista.append(numero)

print(par)
print(impar)


from django.urls import path
from .views import *
from django.contrib.auth.decorators import login_required

urlpatterns = [
    path('userlogin/', userlogin, name='userlogin'),
    path('register/', register, name='register'),
    path('userlogout/', userlogout, name='userlogout'),
    path('dashboard/<int:pk>', login_required(Dashboard.as_view()), name='dashboard'),
    path('user_update/<int:pk>', login_required(UserUpdate.as_view()), name='user_update'),
]


import random

co_rice = ['薏仁', '黑米', '梗米', '面', '普通米饭', '糙米饭']
co_dish = ['黄豆', '黑豆', '山药', '马铃薯', '红薯', '玉米']
co_breakfast = ['燕麦', '小麦(全麦面包)']
protein_meat = ['鸡胸肉', '青条鱼', '马鲛鱼', '秋刀鱼', '大马哈鱼', '虾']
protein_drink = ['牛奶', '酸奶', '豆浆']
fat = ['栗子', '杏仁', '牛油果', '花生', '腰果']
cellulose = ['花椰菜', '大蒜', '洋葱', '红椒', '卷心菜', '西红柿', '西兰花', '白菜', '豆苗']
vitamin = ['苹果', '猕猴桃', '葡萄', '草莓', '桂圆', '金橘']
drink = ['柠檬汁', '枸杞', '绿茶', '雪梨', '蜂蜜']
seasoning = ['植物油', '橄榄油', '亚麻籽', '黑芝麻']

def randomChoose(sequence):
    return sequence[random.randint(0, len(sequence) - 1)]

def generateRecipe(period):
    """
    period: 早饭(B)、中饭(L)、晚饭(D)、加餐(E)
    """
    if period.upper().startswith('B'):
        combo1 = randomChoose(co_breakfast)
        combo2 = randomChoose(protein_drink)
        combo3 = randomChoose(fat)
        combo4 = randomChoose(vitamin)
        return combo1, combo2, combo3, combo4
    elif period.upper().startswith('L'):
        combo1 = randomChoose(co_rice)
        combo2 = randomChoose(co_dish)
        combo3 = randomChoose(protein_meat)
        combo4 = randomChoose(seasoning)
        combo5 = randomChoose(cellulose)
        combo6 = randomChoose(vitamin)
        return combo1, combo2, combo3, combo4, combo5, combo6
    elif period.upper().startswith('D'):
        combo1 = randomChoose(co_rice)
        combo2 = randomChoose(co_dish)
        combo3 = randomChoose(protein_meat)
        combo4 = randomChoose(seasoning)
        combo5 = randomChoose(cellulose)
        combo6 = randomChoose(vitamin)
        return combo1, combo2, combo3, combo4, combo5, combo6
    elif period.upper().startswith('E'):
        combo1 = randomChoose(fat)
        combo2 = randomChoose(vitamin)
        combo3 = randomChoose(drink)
        return combo1, combo2, combo3
    else:
        return -1


'''
https://leetcode.com/problems/binary-tree-level-order-traversal/
Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).
For example:
Given binary tree [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
return its level order traversal as:
[
  [3],
  [9,20],
  [15,7]
]
'''
'''
Time:O(n)
Space:O(n)
'''
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        res = []
        def traverse(node, level):
            if not node:    return
            if len(res)<=level:
                res.append([])
            res[level].append(node.val)
            traverse(node.left, level+1)
            traverse(node.right, level+1)
        traverse(root, 0)
        return res

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        res = []
        d = defaultdict(list)
        def level(node, depth):
            if node:
                d[depth].append(node.val)
                level(node.left, depth+1)
                level(node.right, depth+1)
        level(root, 0)
        for depth, num in d.items():
            res.append(num)
        return res

102. Binary Tree Level Order Traversal.py


lista = [[], []]
for c in range(0, 7):
    numero = int(input(f'Digite o {c + 1}° Número: '))
    if numero % 2 == 0:
        lista[0].append(numero)
    else:
        lista[1].append(numero)
print('-=-' * 30)
lista[0].sort()
print(f'Os valores pares digitados foram: {lista[0]}')
lista[1].sort()
print(f'Os valores ímpares digitados foram: {lista[1]}')


from arm.logicnode.arm_nodes import *

class SequenceNode(ArmLogicTreeNode):
    """Activates the outputs one by one sequentially and repeatedly."""
    bl_idname = 'LNSequenceNode'
    bl_label = 'Output Sequence'
    arm_section = 'flow'
    arm_version = 2
    min_outputs = 0

    def __init__(self):
        super(SequenceNode, self).__init__()
        array_nodes[self.get_id_str()] = self

    def arm_init(self, context):
        self.add_input('ArmNodeSocketAction', 'In')

    def draw_buttons(self, context, layout):
        row = layout.row(align=True)

        op = row.operator('arm.node_add_output', text='New', icon='PLUS', emboss=True)
        op.node_index = self.get_id_str()
        op.socket_type = 'ArmNodeSocketAction'
        column = row.column(align=True)
        op = column.operator('arm.node_remove_output', text='', icon='X', emboss=True)
        op.node_index = self.get_id_str()
        if len(self.outputs) == self.min_outputs:
            column.enabled = False

    def get_replacement_node(self, node_tree: bpy.types.NodeTree):
        if self.arm_version not in (0, 1):
            raise LookupError()

        return NodeReplacement.Identity(self)


"""empty message

Revision ID: 90fdf582f177
Revises: 6d835ab0989d
Create Date: 2019-06-20 14:20:02.355877

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '90fdf582f177'
down_revision = '6d835ab0989d'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('object',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('folder', sa.String(length=512), nullable=True),
    sa.Column('object_filename', sa.String(length=100), nullable=True),
    sa.ForeignKeyConstraint(['id'], ['field.id'], ),
    sa.PrimaryKeyConstraint('id')
    )
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('object')
    # ### end Alembic commands ###


# https://atcoder.jp/contests/dwacon5th-prelims/tasks/dwacon5th_prelims_b
# 解説見てしまった
# N≤1000の性質をうまく使う必要はない。O(N^2)で全部書き出せばいい。完全に引っ掛け。
# 答えの仮定、bitごとに見る、上位桁からのgreedyらへんがキーワード

from itertools import combinations
N, K = map(int, input().split())
A = list(map(int, input().split()))
B = [sum(A[s:t]) for s, t in combinations(range(N + 1), 2)]

l = max(B).bit_length()  # 何桁扱えば十分か？
x = 0  # 初期値
for i in range(l, -1, -1):  # 上位桁からgreedyに決定
    # 候補のうち i bit目=1がK個以上あれば答えに計上できる
    x_tmp = x + (1 << i)
    if sum((x_tmp & b) == x_tmp for b in B) >= K:  # 確定した桁+i桁を1としたときに答えになり得るか？
        x = x_tmp
print(x)


#####################
# ECE 4900 - Team 3         #
#                                          #
# File: weightSensorGui.py #
####################

from guizero import App, Text, TextBox, PushButton, yesno
import subprocess as sub
import os
import signal
import time
import sys
import RPi.GPIO as GPIO
from hx711 import HX711

# Globals
hx = HX711(dout=5, pd_sck=6)

DUMMY_SENSOR_OVER = 200
DUMMY_SENSOR_UNDER = 200

# Functions
def weight_set_success():
	weight_enter_message.value = "Weight Successfully Set: " + user_weight_box.value + " lbs\n"
	#print(val)

	if (DUMMY_SENSOR_OVER > int(user_percent_box.value)/100 * int(user_weight_box.value)): # over case
		gui.bg = "red"
	elif (DUMMY_SENSOR_UNDER <= int(user_percent_box.value)/100 * int(user_weight_box.value)): # under case
		gui.bg = "lightgreen"

#percent set success
def percent_set_success():
	weight_percentage_message.value = "Percentage Successfully Set: " + user_percent_box.value + " %\n"

	if (DUMMY_SENSOR_OVER > int(user_percent_box.value)/100 * int(user_weight_box.value)): # over case
		gui.bg = "red"
	elif (DUMMY_SENSOR_UNDER <= int(user_percent_box.value)/100 * int(user_weight_box.value)): # under case
		gui.bg = "lightgreen"

def poll_example():
	stream.value="Current value: "+ str(10 * hx.getWeight())

def close_message():
	if yesno("Close", "Are you sure you would like to quit weight sensor?"):
		gui.destroy()

#def over_or_under():
#	if (DUMMY_SENSOR_OVER > 0.2 * user_weight_box.value): # over case
#		over_alert = Text(gui, text="Too fat!", size=8, font="Times New Roman", color="red")
#	elif (DUMMY_SENSOR_UNDER <= 0.2 * user_weight_box.value): # under case
#		under_alert = Text(gui, text="Too skinny!", size=8, font="Times New Roman", color="green")

# MAIN #
hx.setReferenceUnit(3.023)

hx.reset()
hx.tare()

# Fork keyboard process
proc = sub.Popen("matchbox-keyboard", shell=True, stdout=sub.PIPE, stderr=sub.PIPE)

# Main GUI Script
	#BEGIN
gui = App(title="Weight Sensor", height=240, width=320)

welcome_message = Text(gui, text="Welcome to Team 3's Weight Sensor", size=16, font="Times New Roman")
weight_enter_message = Text(gui, text="Please Enter Your Weight Below\n", size=13, font="Times New Roman", color="blue")

user_weight_box = TextBox(gui, width=30)
set_button = PushButton(gui, text="Set Weight (lbs)", command=weight_set_success)

# Example Stream
stream = Text(gui)
stream.repeat(500, poll_example) # display value from hx every 0.5 seconds

#Weight Percentage
weight_percentage_message = Text(gui, text="Please Enter Weight Percentage\n", size=13, font="Times New Roman", color="blue")

user_percent_box = TextBox(gui, width=30)
set_button = PushButton(gui, text="Set Percentage (0-100%)", command=percent_set_success)

	#END
gui.on_close(close_message)

gui.display()

GPIO.cleanup()
sys.exit()
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)


def getPrice(price, rem, n, cache):
    if rem < 0:
        return float('-inf')
    if rem == 0:
        return 0
    if rem in cache:
        return cache[rem]
    res = 0
    for i in range(1, n + 1):
        curr = price[i - 1] + getPrice(price, rem - i, n, cache)
        res = max(res, curr)
    cache[rem] = res
    return res

def cutRod(price, n):
    cache = {}
    return getPrice(price, n, n, cache)

print(cutRod([2, 5, 7, 8, 10], 5))


#!/usr/bin/env python

from __future__ import division, absolute_import

import time
import random
import math

import entity

def find_closest(entity, entities):
    # targets = entities.get('user_controllable')

    # closest_distance = float('inf')
    # closest = None

    # for target in targets:
    #     distance = (target.circles.centroid - entity.circles.centroid).magnitude
    #     if distance < closest_distance:
    #         closest_distance = distance
    #         closest = target

    # return (closest.circles.centroid - entity.circles.centroid).angle
    for e in entities:
        if 'user_controllable' in e:
            return e

class DriftMovement(object):
    name = 'movement_ai'
    def __init__(self, speed):
        self.start = time.time()
        self.speed = speed

    def process(self, entity, entities):
        current = time.time()
        if current - self.start > 2:
            self.start = current
            angle = random.uniform(0, 2*math.pi)
            for circle in entity.circles:
                circle.velocity.angle = angle
                circle.velocity.magnitude = self.speed

class ChasingMovement(object):
    name = 'movement_ai'

    def __init__(self, speed):
        self.start = time.time()
        self.speed = speed

    def process(self, entity, entities):
        current = time.time()
        if current - self.start > 2:
            angle = find_closest(entity, entities).circles[0].position.direction(entity.circles[0].position) + math.pi
            self.start = current
            for circle in entity.circles:
                circle.velocity.angle = angle
                circle.velocity.magnitude = self.speed

class FireSingleBullet(object):
    name = 'attack_ai'

    def __init__(self, rate):
        self.start = time.time()
        self.rate = rate

    def process(self, entity, entities):
        current = time.time()
        if current - self.start > 2:
            angle = find_closest(entity, entities).angle
            self.start = current

            #entities.add(entity.Bullet,


import numpy as np
from scipy.fft import fft, ifft, fftfreq, fftshift, ifftshift
import matplotlib.pyplot as plt
from datetime import datetime
from qudofedi import Qjob

linear_name_list = ['a', 'absorption']
thirdorder_name_list = ['gsb', 'ground state bleaching', 'se', 'stimulated emission', 'esa', 'excited state absorption']

def PostProcess(qjob: Qjob,
                RF_freq: float = 0,
                damping_rate: float = 0,
                T2_index: int = 0,
                pad: int = 1,
                save_figure: bool = False,
                figure_name: str | None = None,
                **pltsavefig_kws,
                ):
    '''
    Method to run sequentially the methods of class PostProcessing: __RotatingFrame(), __FourierTransform(), __PlotSpectra().
    '''
    response_function = qjob.response_function
    delay_time = qjob.delay_time
    FD_type = qjob.FD_type

    RF_response_function = RotatingFrame(response_function, delay_time, FD_type, RF_freq, damping_rate, T2_index)

    (omega, freq_spectra) = FourierTransform(RF_response_function, delay_time, FD_type, RF_freq, T2_index, pad)

    PlotTimeSignal(RF_response_function, delay_time, FD_type, save_figure, figure_name, **pltsavefig_kws)

    PlotSpectra(freq_spectra, omega, FD_type, RF_freq, save_figure, figure_name, **pltsavefig_kws)

def RotatingFrame(response_function,
                  delay_time,
                  FD_type,
                  RF_freq = 0,
                  damping_rate = 0,
                  T2_index = 0,
                  ):
    '''
    Method to differentiate the application of the rotating frame between linear and non-linear response_functions.
    '''
    if FD_type in linear_name_list:
        return __LinearRotatingFrame(response_function, delay_time, RF_freq, damping_rate)
    elif FD_type in thirdorder_name_list:
        return __2DRotatingFrame(response_function, delay_time, RF_freq, damping_rate, T2_index)

def __LinearRotatingFrame(response_function,
                          delay_time,
                          RF_freq = 0,
                          damping_rate = 0,
                          ):
    '''
    Method that apply the rotating frame to the linear response_function.
    '''
    T = np.array(delay_time)
    rf_response_function = response_function * np.exp(+1.j * RF_freq * T) * np.exp(- damping_rate * T)
    return rf_response_function

def __2DRotatingFrame(response_function,
                      delay_time,
                      RF_freq = 0,
                      damping_rate = 0,
                      T2_index = 0,
                      ):
    '''
    Method that apply the rotating frame to the non-linear response_function.
    '''
    T1 = np.array(delay_time[0])
    T2 = np.array(delay_time[1])
    T3 = np.array(delay_time[2])
    if (T2_index >= len(T2)):
        raise ValueError('T2_index exceed length of T2')
    T1, T3 = np.meshgrid(T1, T3, indexing='ij')
    rf_response_function = response_function[:,T2_index,:] * np.exp(-1.j * RF_freq * (T1-T3)) * np.exp(- damping_rate * (T1+T3))
    return rf_response_function

def FourierTransform(response_function,
                     delay_time,
                     FD_type,
                     RF_freq = 0,
                     T2_index = 0,
                     pad = 1,
                     ):
    '''
    Method to differentiate the application of the Fourier Transform between linear and non-linear response_functions.
    '''
    if FD_type in linear_name_list:
        return __LinearFourierTransform(response_function, delay_time, RF_freq, pad)
    elif FD_type in thirdorder_name_list:
        return __2DFourierTransform(response_function, delay_time, RF_freq, T2_index, pad)

def __LinearFourierTransform(response_function,
                             delay_time,
                             RF_freq = 0,
                             pad = 1,
                             ):
    '''
    Method that apply the Fourier Transform to the linear response_function.
    '''
    dt = delay_time[1] - delay_time[0]
    omega = fftshift(2*np.pi*fftfreq(len(delay_time) * pad, dt)) + RF_freq
    freq_spectra = ifftshift(ifft(np.pad(response_function, ((0, len(delay_time) * (pad-1))),'constant')))
    return omega, freq_spectra

def __2DFourierTransform(response_function,
                         delay_time,
                         RF_freq = 0,
                         T2_index = 0,
                         pad = 1,
                         ):
    '''
    Method that apply the Fourier Transform to the non-linear response_function.
    '''
    T1 = delay_time[0]
    dt1 = T1[1] - T1[0]
    T2 = delay_time[1]
    T3 = delay_time[2]
    dt3 = T3[1] - T3[0]
    if (T2_index >= len(T2)):
        raise ValueError('T2_index exceed length of T2')
    omega1 = fftshift(2*np.pi*fftfreq(len(T1) * pad, dt1)) + RF_freq
    omega3 = fftshift(2*np.pi*fftfreq(len(T3) * pad, dt3)) + RF_freq
    omega1, omega3 = np.meshgrid(omega1, omega3, indexing='ij')
    omega = [omega1, omega3]
    response_function_pad = np.pad(response_function, ((0,len(T1) * (pad-1)), (0,len(T3) * (pad-1))), 'constant')
    freq_spectra = len(response_function_pad)/len(response_function)**2 * fftshift(ifft(fftshift(fft(response_function_pad, axis=0), axes=0), axis=1), axes=1)
    return omega, freq_spectra

def PlotTimeSignal(response_function,
                   delay_time,
                   FD_type,
                   save_figure = False,
                   figure_name = None,
                   **pltsavefig_kws,
                   ):
    if FD_type in linear_name_list:
        __LinearPlotTimeSignal(response_function, delay_time, FD_type, save_figure, figure_name, **pltsavefig_kws)
    elif FD_type in thirdorder_name_list:
        __2DPlotTimeSignal(response_function, delay_time, FD_type, save_figure, figure_name, **pltsavefig_kws)

def __LinearPlotTimeSignal(response_function,
                           delay_time,
                           FD_type,
                           save_figure = False,
                           figure_name = None,
                           **pltsavefig_kws,
                           ):
    '''
    Method that generate the linear spectrum.
    '''
    plt.plot(delay_time, np.real(response_function))
    plt.plot(delay_time, np.imag(response_function))
    plt.xlabel(r'$t$')
    plt.ylabel('Response function')
    if save_figure == True:
        if figure_name == None:
            figure_name = FD_type + datetime.now().strftime("%d-%m-%Y-%H-%M-%S")
        plt.savefig(figure_name, **pltsavefig_kws)
    plt.show()

def __2DPlotTimeSignal(response_function,
                       delay_time,
                       FD_type,
                       save_figure = False,
                       figure_name = None,
                       **pltsavefig_kws,
                       ):
    '''
    Method that generate the non-linear spectrum.
    '''
    real_response_function = np.real(response_function)
    T1 = delay_time[0]
    T3 = delay_time[2]

    vmin = real_response_function.min()
    vmax = real_response_function.max()
    v = max(np.abs(vmin), vmax)
    levels_contourf = np.linspace(-v, v, 299)
    levels_contour = np.linspace(-v, v, 15)
    ticks = np.linspace(-v, v, 9)

    plt.plot(T1, T3, 'k:')
    plt.contour(T1, T3, real_response_function, levels=levels_contour, colors='k', linestyles='solid', linewidths=0.5, vmin=-v, vmax=v)
    plt.contourf(T1, T3, real_response_function, levels=levels_contourf, cmap='RdBu_r', vmin=-v, vmax=v)
    plt.axis('square')
    plt.xlabel(r'$T_{1}$')
    plt.ylabel(r'$T_{3}$')
    plt.colorbar(ticks=ticks)
    if save_figure == True:
        if figure_name == None:
            figure_name = FD_type + datetime.now().strftime("%d-%m-%Y-%H-%M-%S")
        plt.savefig(figure_name, **pltsavefig_kws)
    plt.show()

def PlotSpectra(freq_spectra,
                omega,
                FD_type,
                RF_freq,
                save_figure,
                figure_name,
                **pltsavefig_kws,
                ):
    '''
    Method that generate the spectrum distinguishing between the linear and the non-linear response_function.
    '''
    if FD_type in linear_name_list:
        __LinearPlotSpectra(freq_spectra, omega, FD_type, save_figure, figure_name, **pltsavefig_kws)
    elif FD_type in thirdorder_name_list:
        __2DPlotSpectra(freq_spectra, omega, FD_type, RF_freq, save_figure, figure_name, **pltsavefig_kws)

def __LinearPlotSpectra(freq_spectra,
                        omega,
                        FD_type,
                        save_figure,
                        figure_name,
                        **pltsavefig_kws,
                        ):
    '''
    Method that generate the linear spectrum.
    '''
    plt.plot(omega, np.real(freq_spectra))
    plt.xlabel(r'$\omega$')
    plt.ylabel('Response function')
    if save_figure == True:
        if figure_name == None:
            figure_name = FD_type + 'spectra' + datetime.now().strftime("%d-%m-%Y-%H-%M-%S")
        plt.savefig(figure_name, **pltsavefig_kws)
    plt.show()

def __2DPlotSpectra(freq_spectra,
                    omega,
                    FD_type,
                    RF_freq,
                    save_figure,
                    figure_name,
                    **pltsavefig_kws,
                    ):
    '''
    Method that generate the non-linear spectrum.
    '''
    omega1 = omega[0]
    omega3 = omega[1]
    real_freq_spectra = np.real(freq_spectra)

    vmin = real_freq_spectra.min()
    vmax = real_freq_spectra.max()
    v = max(np.abs(vmin), vmax)
    levels_contourf = np.linspace(-v, v, 299)
    levels_contour = np.linspace(-v, v, 15)
    ticks = np.linspace(-v, v, 9)

    plt.plot(np.diag(omega1), np.diag(omega3), 'k:')
    plt.contour(omega1, omega3, real_freq_spectra, levels=levels_contour, colors='k', linestyles='solid', linewidths=0.5, vmin=-v, vmax=v)
    plt.contourf(omega1, omega3, real_freq_spectra, levels=levels_contourf, cmap='RdBu_r', vmin=-v, vmax=v)
    plt.axis('square')
    plt.xlabel(r'$\omega_{1}$')
    plt.ylabel(r'$\omega_{3}$')
    plt.colorbar(ticks=ticks)
    if save_figure == True:
        if figure_name == None:
            figure_name = FD_type + 'spectra' + datetime.now().strftime("%d-%m-%Y-%H-%M-%S")
        plt.savefig(figure_name, **pltsavefig_kws)
    plt.show()


import re
import pandas as pd

def preprocess_text(text):
    # 특수 문자 및 숫자 제거
    cleaned_text = re.sub(r'[^가-힣a-zA-Z\s]', '', text)
    return cleaned_text

# 파일에서 데이터 읽기
with open('crawling.txt', 'r', encoding='utf-8') as file:
    data = file.readlines()

# 데이터프레임 생성
df = pd.DataFrame(columns=['Title', 'Date'])

# 결과 출력 및 데이터프레임에 저장
for row in data:
    # title과 date 분리
    split_data = row.split(',')
    title = ' '.join(split_data[:-1]).strip()

    # 특수문자 및 숫자 제거
    cleaned_title = preprocess_text(title)

    date = split_data[-1].strip()

    # 데이터프레임에 저장
    df = df.append({'Title': cleaned_title.split(), 'Date': date}, ignore_index=True)

# TXT 파일로 저장
with open('crawling_processed.txt', 'w', encoding='utf-8') as file:
    for index, row in df.iterrows():
        title_str = ' '.join(row['Title_List']) # 리스트를 공백으로 구분된 문자열로 변환
        file.write(title_str + "," + row['Date'] + "\n")


from __future__ import unicode_literals

import pytest
from django.conf.urls import include, url
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.test import TestCase

from rest_framework import routers, serializers, viewsets
from rest_framework.test import APIRequestFactory, URLPatternsTestCase
from rest_framework.utils import json

factory = APIRequestFactory()
request = factory.get('/')  # Just to ensure we have a request in the serializer context

class Wine(models.Model):
    title = models.CharField(max_length=100)

class WineSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Wine
        fields = ('url', 'title')

class WineViewSet(viewsets.ModelViewSet):
    queryset = Wine.objects.all()
    serializer_class = WineSerializer

router = routers.DefaultRouter()
router.register(r'wines', WineViewSet)

class TestHyperlinkedRouterNoName(URLPatternsTestCase, TestCase):

    urlpatterns = [
        url(r'^api/', include(router.urls)),
    ]

    def test_no_name_works(self):
        w = Wine(title="Shiraz")
        w.save()

        response = self.client.get('/api/wines/')
        assert response.status_code == 200
        assert json.loads(response.content.decode('utf-8')) == [{'title': 'Shiraz', 'url': 'http://testserver/api/wines/1/'}]

# Failing case with Django 2.0 and HyperlinkedModelSerializer
class TestHyperlinkedRouterFailsWithName(URLPatternsTestCase, TestCase):
    urlpatterns = [
        url(r'^api2/', include((router.urls, 'appname2'))),
    ]

    def test_hyperlink_fails(self):
        w = Wine(title="Shiraz")
        w.save()

        with pytest.raises(
                ImproperlyConfigured,
                message='Could not resolve URL for hyperlinked relationship using view '
                        'name "wine-detail". You may have failed to include the related model in '
                        'your API, or incorrectly configured the `lookup_field` attribute on this field.'):

            self.client.get('/api2/wines/')

router2 = routers.DefaultRouter(app_name='appname2')
router2.register(r'wines', WineViewSet)

class TestHyperlinkedRouterConfigured(URLPatternsTestCase, TestCase):
    urlpatterns = [
        url(r'^api2/', include((router2.urls, 'appname2'))),
    ]

    def test_regex_url_path_list(self):
        w = Wine(title="Shiraz")
        w.save()

        response = self.client.get('/api2/wines/')
        assert response.status_code == 200
        assert json.loads(response.content.decode('utf-8')) == [{'title': 'Shiraz', 'url': 'http://testserver/api2/wines/1/'}]


from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

class Driver:
    def driver(f):
        try:
            driver = webdriver.Chrome(ChromeDriverManager().install())

            driver.get("https://earsivportal.efatura.gov.tr/intragiris.html")
            driver.set_window_size(1024, 600)
            driver.maximize_window()
            return driver
        except:
            f.write("\nDriverda sorun oluştu.")
            return 1


import os
import socket
import threading
import socketserver

SERVER_HOST = 'localhost'
SERVER_PORT = 0  # Tells kernel to pick port randomly
BUF_SIZE = 1024
ECHO_MSG = b'Hello echo Server!'

class ForkedClient():
    def __init__(self, ip, port):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((ip, port))

    def run(self):
        current_process_id = os.getpid()
        print('PID %s. Sending message: %s' % (current_process_id, ECHO_MSG))
        sent_data_length = self.socket.send(ECHO_MSG)
        print("Sent: %d characters" % sent_data_length)

        response = self.socket.recv(BUF_SIZE)
        print("PID %s recieved %s" % (current_process_id, response))

    def shutdown(self):
        self.socket.close()

class ForkingServerRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        data = self.request.recv(BUF_SIZE)
        current_process_id = os.getpid()

        response = "%s: %s" % (current_process_id, data)
        response = bytes(response, 'utf-8')
        print("Server sending response [pid: data]: %s" % response)

        self.request.send(response)
        return

class ForkingServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    """ Nothing to add here. Inhereted everything """
    pass

def main():
    # Launch the server
    server = ForkingServer((SERVER_HOST, SERVER_PORT), ForkingServerRequestHandler)
    ip, port = server.server_address  # Getting the port number
    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.setDaemon(True)
    server_thread.start()

    print('Server loop running PID: %s' % os.getpid())

    # Launch the client
    client1 = ForkedClient(ip, port)
    client1.run()

    client2 = ForkedClient(ip, port)
    client2.run()

    # Clean them up
    server.shutdown()
    client1.shutdown()
    client2.shutdown()
    server.socket.close()

if __name__ == '__main__':
    main()


from django.urls import path
from .views import RegisterView, LoginView, LogoutView

app_name = 'userauths'

urlpatterns = [
    path("sign-up/",RegisterView, name='sign-up'),
    path("sign-in/",LoginView, name='sign-in'),
    path("sign-out/",LogoutView, name='sign-out'),

]


import jinja2

import settings
from java_instruction_conversion import get_instruction
from jinja2_view_models import get_decision_block_tree
from smt_functions import z3_truth_check

def get_java_type(model, ignore_size):
    """Maps type names from SLCO to Java"""
    if model.base == "Boolean":
        return "boolean" if model.size < 1 or ignore_size else "boolean[]"
    elif model.base == "Integer":
        return "int" if model.size < 1 or ignore_size else "int[]"
    elif model.base == "Byte":
        return "byte" if model.size < 1 or ignore_size else "byte[]"

def get_default_variable_value(model):
    """ return default value for given variable """
    if model.defvalue is not None:
        return model.defvalue
    elif len(model.defvalues) > 0:
        return "[%s]" % ", ".join([v for v in model.defvalues])
    elif model.type.base in ["Integer", "Byte"]:
        return '0' if model.type.size < 1 else "{%s}" % ", ".join(["0" for _ in range(0, model.type.size)])
    elif model.type.base == "Boolean":
        return 'true' if model.type.size < 1 else "{%s}" % ", ".join(["true" for _ in range(0, model.type.size)])

def comma_separated_list(model):
    """Construct a comma separated list of the given iterable"""
    return ", ".join(model)

def get_variable_list(model):
    """Construct a comma separated list of variables, sorted on by name and prefixed with their type"""
    variables = ["%s %s" % (get_java_type(_v.type, False), _v.name) for _v in sorted(model, key=lambda v: v.name)]
    return comma_separated_list(variables)

def get_variable_instantiation_list(model, variables):
    """Construct a comma separated list of variable initializations sorted on by name"""
    instantiated_variables = {
        _v.left.name: _v.right for _v in model
    }

    variable_instantiations = []
    for v in sorted(variables, key=lambda v2: v2.name):
        # Is a value assigned to the variable?
        value = instantiated_variables[v.name] if v.name in instantiated_variables else get_default_variable_value(v)

        if v.type.size > 1:
            variable_instantiations.append("new %s %s" % (get_java_type(v.type, False), value))
        elif v.type.base == "Byte":
            variable_instantiations.append("(byte) %s" % value)
        else:
            variable_instantiations.append("%s" % value)
    return comma_separated_list(variable_instantiations)

def get_guard_statement(model):
    """Construct an or-code-clause encapsulating all guard expressions for the target decision block"""
    if model.__class__.__name__ == "TransitionBlock":
        return get_instruction(model.guard_expression)
    else:
        # Construct a disjunction of statements. Brackets are not needed because of the precedence order.
        # TODO simplify using SMT.
        #   - Remove formulas that are equivalent to an already encountered formula.
        #   - Use implication to check whether one formula is contained in another?
        return " || ".join([get_instruction(e) for e in model.encapsulating_guard_expression])

def render_model(model):
    """Convert the SLCO model to Java code"""
    return java_model_template.render(
        model=model,
        add_counter=settings.add_counter,
        add_performance_counter=settings.add_performance_counter
    )

def render_class(model):
    """Convert the SLCO class to Java code"""
    return java_class_template.render(
        model=model
    )

def render_state_machine(model, c):
    """Convert the SLCO state machine to Java code"""
    return java_state_machine_template.render(
        model=model,
        add_counter=settings.add_counter,
        add_performance_counter=settings.add_performance_counter,
        _c=c
    )

def construct_decision_code(model, sm, requires_lock=True, include_guard=True, include_comment=True):
    """Convert the decision structure to Java code"""
    model_class = model.__class__.__name__
    if model_class == "TransitionBlock":
        if not model.starts_with_composite:
            composite_assignments = None
            statements = [construct_decision_code(s, sm) for s in model.statements]
        else:
            composite_assignments = [construct_decision_code(s, sm, False) for s in model.composite_assignments]
            statements = [construct_decision_code(s, sm) for s in model.statements[1:]]

        return java_transition_template.render(
            starts_with_composite=model.starts_with_composite,
            composite_assignments=composite_assignments,
            statements=statements,
            target=model.target,
            state_machine_name=sm.name,
            release_locks=model.release_locks,
            always_fails=model.always_fails,
            comment=model.comment if include_comment else None,
            _c=sm.parent_class,
            add_performance_counter=settings.add_performance_counter,
            transition_identifier=model.comment
        )
    elif model_class == "Composite":
        guard = get_instruction(model.guard) if not model.guard.is_trivially_satisfiable and include_guard else None
        assignments = [get_instruction(a) for a in model.assignments]
        return java_composite_template.render(
            guard=guard,
            assignments=assignments,
            lock_variable_phases=model.lock_variable_phases,
            release_locks=model.lock_variables,
            _c=sm.parent_class
        )
    elif model_class == "Assignment":
        return java_assignment_template.render(
            requires_lock=requires_lock,
            lock_variable_phases=model.lock_variable_phases if requires_lock else None,
            release_locks=model.lock_variables if requires_lock else None,
            assignment=model,
            _c=sm.parent_class
        )
    elif model_class == "Expression":
        return java_expression_template.render(
            lock_variable_phases=model.lock_variable_phases,
            release_locks=model.lock_variables,
            expression=model,
            _c=sm.parent_class
        )
    elif model_class == "ActionRef":
        return "// Execute action [%s]\n" % model.act.name
    elif model_class == "NonDeterministicBlock":
        # Several of the choices may have the same conversion string. Filter these out and merge.
        choices = [(
            construct_decision_code(choice, sm),
            choice.comment if choice.__class__.__name__ == "TransitionBlock" else None
        ) for choice in model.choice_blocks]
        choices.sort(key=lambda v: v[0])

        for i in range(0, len(choices) - 1):
            # Check if the next execution code is equivalent to the current one.
            # If so, set the current execution code to empty string, to avoid duplicates.
            # Note that there is a comment that will likely differ--filter the comment out if appropriate.
            current_choice = choices[i][0]
            if choices[i][1] is not None:
                current_choice = current_choice.replace(choices[i][1], "")

            next_choice = choices[i + 1][0]
            if choices[i + 1][1] is not None:
                next_choice = next_choice.replace(choices[i + 1][1], "")

            if current_choice == next_choice:
                # We still want the traceability comment if applicable.
                choices[i] = ("// %s (functional duplicate of case below)" % choices[i][1], choices[i][1])

        # Remove the choice comment from every choice.
        choices = [choice[0] for choice in choices]

        # If only one choice remains, there is no reason to include an entire block.
        if len(choices) == 1:
            return choices[0]

        return java_non_deterministic_case_distinction_template.render(
            release_locks=model.release_locks,
            choices=choices,
            _c=sm.parent_class
        )
    elif model_class == "DeterministicIfThenElseBlock":
        # Order the choices such that the generated code is always the same.
        choices = [
            (
                construct_decision_code(choice, sm, include_comment=False),
                get_guard_statement(choice),
                choice.comment if choice.__class__.__name__ == "TransitionBlock" else None
            ) for choice in model.choice_blocks
        ]
        choices.sort(key=lambda v: v[0])

        # Does the combination of all the guards always evaluate to true?
        else_choice = None
        if len(model.encapsulating_guard_expression) > 1 and len(model.choice_blocks) > 1:
            encapsulating_guard_expression = list(model.encapsulating_guard_expression)
            smt = encapsulating_guard_expression[0].smt
            for expression in encapsulating_guard_expression[1:]:
                smt = ("or", smt, expression.smt)
            variables = {**sm.parent_class.name_to_variable, **sm.name_to_variable}
            if z3_truth_check(smt, variables):
                else_choice = choices[-1]
                choices = choices[:-1]

        return java_if_then_else_template.render(
            lock_variable_phases=model.lock_variable_phases,
            release_locks=model.release_locks,
            target_locks=model.target_locks,
            choices=choices,
            else_choice=else_choice,
            _c=sm.parent_class
        )
    elif model_class == "DeterministicCaseDistinctionBlock":
        # Several of the choices may have the same conversion string. Filter these out and merge.
        choices = [
            (
                target,
                construct_decision_code(choice, sm, include_comment=False),
                choice.comment if choice.__class__.__name__ == "TransitionBlock" else None
            ) for (target, choice) in model.choice_blocks
        ]
        choices.sort(key=lambda v: v[1])

        for i in range(0, len(choices) - 1):
            # Check if the next execution code is equivalent to the current one.
            # If so, set the current execution code to empty string, to avoid duplicates.
            if choices[i][1] == choices[i + 1][1]:
                choices[i] = (choices[i][0], "", "%s (functional duplicate of case below)" % choices[i][2])

        subject_expression = get_instruction(model.subject_expression)
        default_decision_tree = construct_decision_code(model.default_decision_tree, sm)
        return java_case_distinction_template.render(
            lock_variable_phases=model.lock_variable_phases,
            release_locks=model.release_locks,
            target_locks=model.target_locks,
            subject_expression=subject_expression,
            default_decision_tree=default_decision_tree,
            choices=choices,
            _c=sm.parent_class
        )

def get_decision_structure(model, sm):
    """Construct the decision code and the execution of the transitions"""
    view_model = get_decision_block_tree(model, sm.parent_class)
    return construct_decision_code(view_model, sm)

def to_comma_separated_lock_name_list(model):
    """Construct a comma separated list containing all the lock names for cross verification, sorted on variable name"""
    return ", ".join([v[0] + ("" if v[1] is None else "[%s]" % v[1]) for v in sorted(model)])

def to_comma_separated_lock_id_list(model, c):
    """Construct a comma separated list of all the targeted lock ids, sorted on variable name"""
    lock_ids = []
    for v in sorted(model):
        base = c.name_to_variable[v[0]].lock_id
        index = 0 if v[1] is None else v[1]
        try:
            index = int(index)
            lock_ids.append(str(base + index))
        except (ValueError, TypeError):
            if base == 0:
                lock_ids.append(index)
            else:
                lock_ids.append("%s + %s" % (base, index))
    return ", ".join(lock_ids)

# Initialize the template engine.
env = jinja2.Environment(
    loader=jinja2.FileSystemLoader('../../jinja2_templates'),
    trim_blocks=True,
    lstrip_blocks=True,
    extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do', ]
)

# Register the filters
env.filters['render_class'] = render_class
env.filters['render_state_machine'] = render_state_machine

env.filters['get_java_type'] = get_java_type
env.filters['get_default_variable_value'] = get_default_variable_value
env.filters['comma_separated_list'] = comma_separated_list
env.filters['get_instruction'] = get_instruction
env.filters['get_guard_statement'] = get_guard_statement
env.filters['get_variable_list'] = get_variable_list
env.filters['get_decision_structure'] = get_decision_structure
env.filters['get_variable_instantiation_list'] = get_variable_instantiation_list
env.filters['to_comma_separated_lock_name_list'] = to_comma_separated_lock_name_list
env.filters['to_comma_separated_lock_id_list'] = to_comma_separated_lock_id_list

# load the Java templates
java_model_template = env.get_template('component_templates/java_model_template.jinja2template')
java_class_template = env.get_template('component_templates/java_class_template.jinja2template')
java_state_machine_template = env.get_template('component_templates/java_state_machine_template.jinja2template')
java_assignment_template = env.get_template('component_templates/java_assignment_template.jinja2template')
java_expression_template = env.get_template('component_templates/java_expression_template.jinja2template')
java_composite_template = env.get_template('component_templates/java_composite_template.jinja2template')
java_transition_template = env.get_template('component_templates/java_transition_template.jinja2template')

java_if_then_else_template = env.get_template('decision_templates/java_if_then_else_template.jinja2template')
java_case_distinction_template = env.get_template('decision_templates/java_case_distinction_template.jinja2template')
java_non_deterministic_case_distinction_template = env.get_template(
    'decision_templates/java_non_deterministic_case_distinction_template.jinja2template'
)