import contextlib
import glob
import logging
import os
import re
import string
import threading

from ngamsLib.ngamsCore import NGAMS_NOT_RUN_STATE,\
    NGAMS_ONLINE_STATE, NGAMS_SUBSCRIBE_CMD,\
    NGAMS_SUCCESS, TRACE, genLog, NGAMS_DISK_INFO, checkCreatePath,\
    NGAMS_SUBSCRIBER_THR, NGAMS_UNSUBSCRIBE_CMD, NGAMS_HTTP_INT_AUTH_USER,\
    loadPlugInEntryPoint, toiso8601, fromiso8601
from ngamsLib import ngamsStatus, ngamsLib, ngamsHttpUtils
from ngamsLib import ngamsPhysDiskInfo
from ngamsLib import ngamsSubscriber
from ngamsLib import ngamsHighLevelLib, ngamsDiskUtils
from ngamsLib import ngamsNotification
import ngamsArchiveUtils
import ngamsSubscriptionThread

logger = logging.getLogger(__name__)

def ngamsBaseExitHandler(srvObj):
    """
    NG/AMS Exit Handler Function. Is invoked when the NG/AMS Server
    is killed terminated.

    srvObj:      Reference to NG/AMS server class object (ngamsServer).

    signalNo:    Number of signal received (integer).

    killServer:  If set to 1 the server will be killed by the
                 function (integer/0|1).

    exitCode:    The exit code with which NG/AMS should exit (integer).

    delPidFile:  Flag indicating if NG/AMS PID file should be deleted or
                 not (integer/0|1).

    Returns:     Void.
    """
    logger.info("NG/AMS Exit Handler - cleaning up ...")

    if (srvObj.getState() == NGAMS_ONLINE_STATE):
        handleOffline(srvObj)

    # Update the ngas_hosts table.
    srvObj.updateHostInfo("", None, 0, 0, 0, 0, 0, NGAMS_NOT_RUN_STATE)

def _create_remote_subscriptions(srvObj, stop_evt):
    """
    Creates subscriptions in remote servers so they push their data into
    ours.
    """

    subscriptions_in_cfg = srvObj.cfg.getSubscriptionsDic()
    subscriptions = [v for _,v in subscriptions_in_cfg.items()]
    subscriptions_created = 0

    while True:

        # Done with all of them
        if not subscriptions:
            break

        # Iterate over copy, since we modify the original inside the loop
        for subscrObj in list(subscriptions):

            if (not srvObj.getThreadRunPermission()):
                logger.info("Terminating Subscriber thread ...")
                return

            our_host, our_port = srvObj.get_self_endpoint()
            subs_host, subs_port = subscrObj.getHostId(), subscrObj.getPortNo()

            # Not subscribing to ourselves
            if srvObj.is_it_us(subs_host, subs_port):
                logger.warning("Skipping subscription to %s:%d because that's us", subs_host, subs_port)
                return

            # Create the URL that needs to be set on the remote end so we
            # get subscribed to it.
            # TODO: include reverse proxy information when we add support
            # TODO: hardcoded http will need to be changed when we add support
            #       for https
            url = 'http://%s:%d/%s' % (our_host, our_port, subscrObj.getUrl() or 'QARCHIVE')
            logger.info("Creating subscription to %s:%d with url=%s", subs_host, subs_port, url)

            pars = [["subscr_id", url],
                    ["priority", subscrObj.getPriority()],
                    ["url",      url],
                    ["start_date", toiso8601(local=True)]]
            if subscrObj.getFilterPi():
                pars.append(["filter_plug_in", subscrObj.getFilterPi()])
            if subscrObj.getFilterPiPars():
                pars.append(["plug_in_pars", subscrObj.getFilterPiPars()])

            try:
                # Issue SUBSCRIBE command
                resp = ngamsHttpUtils.httpGet(subs_host, subs_port, cmd=NGAMS_SUBSCRIBE_CMD, pars=pars)
                with contextlib.closing(resp):
                    stat = ngamsStatus.to_status(resp, subscrObj.getHostId(), NGAMS_SUBSCRIBE_CMD)

                if stat.getStatus() != NGAMS_SUCCESS:
                    msg = "Unsuccessful NGAS XML response. Status: %s, message: %s. Will try again later"
                    logger.warning(msg, stat.getStatus(), stat.getMessage())
                    continue

                subscriptions_created += 1
                logger.info("Successfully subscribed to %s:%d with url=%s", subs_host, subs_port, subscrObj.getUrl())

                # Remember to unsubscribe when going Offline.
                srvObj.getSubscrStatusList().append(subscrObj)
                subscriptions.remove(subscrObj)

            except:
                logger.exception("Error while adding subscription, will try later")

        if stop_evt.wait(10):
            return

    if subscriptions_created:
        logger.info("Successfully established %d Subscription(s)", subscriptions_created)
    else:
        logger.info("No Subscriptions established")

def getDiskInfo(srvObj,
                reqPropsObj = None):
    """
    Invokes the plug-in listed in the configuration to extract the information
    about the disks mounted. The information is returned in a dictionary which
    contains the Slot IDs as keys, and elements which each is an object of type
    ngamsPhysDiskInfo.

    srvObj:        Reference to NG/AMS Server class instance (ngamsServer).

    reqPropsObj:   NG/AMS request properties object (ngamsReqProps).

    Returns:       Dictionary containing information about the
                   disks (dictionary).
    """
    T = TRACE()

    diskInfoDic = {}

    plugIn = srvObj.getCfg().getOnlinePlugIn()
    if (not srvObj.getCfg().getSimulation()):
        logger.info("Invoking System Online Plug-In: %s(srvObj)", plugIn)
        plugInMethod = loadPlugInEntryPoint(plugIn)
        diskInfoDic = plugInMethod(srvObj, reqPropsObj)
        if (len(diskInfoDic) == 0):
            if (not ngamsLib.trueArchiveProxySrv(srvObj.getCfg())):
                errMsg = genLog("NGAMS_NOTICE_NO_DISKS_AVAIL",
                                [srvObj.getHostId(),
                                 srvObj.getHostId()])
                logger.warning(errMsg)
    else:
        if (srvObj.getCfg().getAllowArchiveReq()):
            logger.debug("Running as a simulated archiving system - generating " +\
                 "simulated disk info ...")
            portNo = 0
            slotIdLst = srvObj.getCfg().getSlotIds()
            for slotId in slotIdLst:
                if (slotId != ""):
                    storageSet = srvObj.getCfg().\
                                 getStorageSetFromSlotId(slotId)
                    if (storageSet.getMainDiskSlotId() == slotId):
                        diskType = "Main"
                    else:
                        diskType = "Rep"
                    mtRootDir = srvObj.getCfg().getRootDirectory()
                    mtPt = os.path.normpath(mtRootDir +\
                                            "/"+storageSet.getStorageSetId() +\
                                            "-" + diskType + "-" + str(slotId))
                    diskId = re.sub("/", "-", mtPt)[1:]
                    serialNo = "SERIAL-NUMBER-" + str(portNo)
                    manufact = "TEST-MANUFACTURER"
                    diskInfoDic[slotId] = ngamsPhysDiskInfo.ngamsPhysDiskInfo()
                    diskInfoDic[slotId].\
                                          setPortNo(portNo).\
                                          setSlotId(slotId).\
                                          setMountPoint(mtPt).\
                                          setStatus("OK").\
                                          setCapacityGb(100).\
                                          setModel("TEST-MODEL").\
                                          setSerialNo(serialNo).\
                                          setType("TEST-TYPE").\
                                          setManufacturer(manufact).\
                                          setDiskId(diskId).\
                                          setDeviceName("/dev/dummy" + slotId)
                    # We create the mount directory if it does not exist
                    checkCreatePath(mtPt)

                    portNo = portNo + 1
        else:
            # It is not an Archiving System. We check which of the directories
            # in the Ngas.RootDirectory contain an NgasDiskInfo file.
            # These are considered as available disks in simulation mode.
            baseDir = srvObj.getCfg().getRootDirectory()
            dirList = glob.glob(os.path.normpath(baseDir + "/*"))
            for mtPt in dirList:
                checkPath = os.path.normpath(mtPt + "/" + NGAMS_DISK_INFO)
                logger.debug("Checking if path exists: %s", checkPath)
                if (os.path.exists(checkPath)):
                    slotId = string.split(mtPt, "-")[-1]
                    portNo = (int(slotId) - 1)
                    diskId = re.sub("/", "-", mtPt)
                    serialNo = "SERIAL-NUMBER-" + str(portNo)
                    diskInfoDic[slotId]=ngamsPhysDiskInfo.ngamsPhysDiskInfo().\
                                         setPortNo(portNo).\
                                         setSlotId(slotId).\
                                         setMountPoint(mtPt).\
                                         setStatus("OK").\
                                         setCapacityGb(100).\
                                         setModel("TEST-MODEL").\
                                         setSerialNo(serialNo).\
                                         setType("TEST-TYPE").\
                                         setManufacturer("TEST-MANUFACTURER").\
                                         setDiskId(diskId).\
                                         setDeviceName("/dev/dummy" + slotId)

    logger.debug("Disk Dictionary: %s", str(diskInfoDic))
    return diskInfoDic

def handleOnline(srvObj,
                 reqPropsObj = None):
    """
    Initialize the system. This implies loading the NG/AMS
    Configuration making the internal initialization from this,
    obtaining information about the disk configuration.

    srvObj:         Reference to NG/AMS server class object (ngamsServer).

    reqPropsObj:    NG/AMS request properties object (ngamsReqProps).

    Returns:        Void.
    """
    logger.debug("Prepare NGAS and NG/AMS for Online State ...")

    # Re-load Configuration + check disk configuration.
    srvObj.loadCfg()

    hostId = srvObj.getHostId()
    for stream in srvObj.getCfg().getStreamList():
        srvObj.getMimeTypeDic()[stream.getMimeType()] = stream.getPlugIn()

    # Flush/send out possible retained Email Notification Messages.
    flushMsg = "NOTE: Distribution of retained Email Notification Messages " +\
               "forced at Online"
    ngamsNotification.checkNotifRetBuf(srvObj.getHostId(), srvObj.getCfg(), 1, flushMsg)

    # Get possible Subscribers from the DB.
    subscrList = srvObj.getDb().getSubscriberInfo("", hostId,
                                                  srvObj.getCfg().getPortNo())
    num_bl =  srvObj.getDb().getSubscrBackLogCount(hostId, srvObj.getCfg().getPortNo())
    #debug_chen
    if (num_bl > 0):
        logger.debug('Preset the backlog count to %d', num_bl)
        srvObj.presetSubcrBackLogCount(num_bl)

    # TODO: unify this "db-to-object" reading (there is something similar elsewhere,
    #       I'm pretty sure, and hide these low-level details from here
    logger.info("Creating %d subscrption objects from subscription DB info", len(subscrList))
    for subscrInfo in subscrList:
        start_date = fromiso8601(subscrInfo[5], local=True) if subscrInfo[5] else None
        last_ingested_date = fromiso8601(subscrInfo[8], local=True) if subscrInfo[8] else None
        tmpSubscrObj = ngamsSubscriber.ngamsSubscriber(subscrInfo[0],
                                                       subscrInfo[1],
                                                       subscrInfo[2],
                                                       subscrInfo[4],
                                                       start_date,
                                                       subscrInfo[6],
                                                       subscrInfo[7],
                                                       last_ingested_date,
                                                       subscrInfo[3])
        tmpSubscrObj.setConcurrentThreads(subscrInfo[9])
        # Take only subscribers for this NG/AMS Server.
        if ((tmpSubscrObj.getHostId() == hostId) and
            (tmpSubscrObj.getPortNo() == srvObj.getCfg().getPortNo())):
            #srvObj.getSubscriberDic()[tmpSubscrObj.getId()] = tmpSubscrObj
            #if (srvObj.getDataMoverOnlyActive() and len(srvObj.getSubscriberDic()) > 0):
            #   break #only load one subscriber under the data mover mode
            srvObj.registerSubscriber(tmpSubscrObj)

    try:
        # Get information about the disks of this system.
        srvObj.setDiskDic(getDiskInfo(srvObj, reqPropsObj))
        ngamsArchiveUtils.resetDiskSpaceWarnings()

        # Update disk info in DB.
        ngamsDiskUtils.checkDisks(hostId, srvObj.getDb(), srvObj.getCfg(),
                                  srvObj.getDiskDic())

        # Write status file on disk.
        ngamsDiskUtils.dumpDiskInfoAllDisks(srvObj.getHostId(),
                                            srvObj.getDb(), srvObj.getCfg())
    except Exception:
        errMsg = "Error occurred while bringing the system Online"
        logger.exception(errMsg)
        handleOffline(srvObj)
        raise

    # Check that there is enough disk space in the various system directories.
    srvObj.checkDiskSpaceSat()

    # Check if files are located in the Staging Areas of the Disks. In case
    # yes, move them to the Back-Log Area to have them treated later.
    checkStagingAreas(srvObj)

    # Start threads + inform threads that they are allowed to execute.
    srvObj.setThreadRunPermission(1)
    srvObj.startJanitorThread()
    srvObj.startDataCheckThread()
    ngamsSubscriptionThread.startSubscriptionThread(srvObj)
    srvObj.startUserServiceThread()
    srvObj.startMirControlThread()
    srvObj.startCacheControlThread()

    # Change state to Online.
    srvObj.setState(NGAMS_ONLINE_STATE)

    # If specified in the configuration file that this server should act as a
    # Subscriber, then subscribe to the Data Providers specified. We do this
    # in a thread so that the server can continuously try to subscribe,
    # even after errors occur.
    if (srvObj.getCfg().getSubscrEnable()):
        srvObj.remote_subscription_creation_evt = threading.Event()
        thrObj = threading.Thread(target=_create_remote_subscriptions,
                                  name=NGAMS_SUBSCRIBER_THR,
                                  args=(srvObj, srvObj.remote_subscription_creation_evt))
        thrObj.setDaemon(0)
        thrObj.start()

    logger.info("NG/AMS prepared for Online State")

def handleOffline(srvObj,
                  reqPropsObj = None):
    """
    Carry out the actions to put the system in Offline state (Standby).

    srvObj:          Reference to NG/AMS server class object (ngamsServer).

    reqPropsObj:     NG/AMS request properties object (ngamsReqProps).

    stopJanitorThr:  Setting this to 0, the function will not try to
                     stop the Janitor Thread. The reason for this is that
                     the Janitor Thread may bring the server to Offline
                     (integer/0|1).

    Returns:         Void.
    """
    # Stop/delete Janitor Thread + Data Check Thread + inform other
    # possible threads to stop execution (if running).
    srvObj.stopJanitorThread()
    srvObj.stopDataCheckThread()
    ngamsSubscriptionThread.stopSubscriptionThread(srvObj)
    srvObj.stopUserServiceThread()
    srvObj.stopMirControlThread()
    srvObj.stopCacheControlThread()
    srvObj.setThreadRunPermission(0)
    if srvObj.getCfg().getSubscrEnable():
        srvObj.remote_subscription_creation_evt.set()

    logger.debug("Prepare NG/AMS for Offline State ...")

    # Unsubscribe possible subscriptions. This is tried only once.
    if (srvObj.getCfg().getAutoUnsubscribe()):
        for subscrObj in srvObj.getSubscrStatusList():
            subs_host, subs_port = subscrObj.getHostId(), subscrObj.getPortNo()
            try:
                resp = ngamsHttpUtils.httpGet(subs_host, subs_port, NGAMS_UNSUBSCRIBE_CMD, [["url", subscrObj.getId()]])
                with contextlib.closing(resp):
                    stat = ngamsStatus.to_status(resp, "%s:%d" % (subs_host, subs_port), NGAMS_UNSUBSCRIBE_CMD)
                if stat.getStatus() != NGAMS_SUCCESS:
                    logger.error("Error when unsubscribing from %s:%d: %s", subs_host, subs_port, stat.getMessage())
            except Exception:
                msg = "Problem occurred while cancelling subscription " +\
                      "(host/port): %s/%d. Subscriber ID: %s"
                logger.exception(msg, subscrObj.getHostId(),
                                 subscrObj.getPortNo(), subscrObj.getId())
        srvObj.resetSubscrStatusList()

    # Check if there are files located in the Staging Areas of the
    # Disks. In case yes, move these to the Back-Log Area to have them
    # treated at a later stage.
    checkStagingAreas(srvObj)

    # Dump disk info on all disks, invoke the Offline Plug-In to prepare the
    # disks for offline, and mark the disks as unmounted in the DB.
    ngamsDiskUtils.dumpDiskInfoAllDisks(srvObj.getHostId(),
                                        srvObj.getDb(), srvObj.getCfg())
    plugIn = srvObj.getCfg().getOfflinePlugIn()
    if (srvObj.getCfg().getSimulation() == 0):
        logger.info("Invoking System Offline Plug-In: %s(srvObj, reqPropsObj)", plugIn)
        plugInMethod = loadPlugInEntryPoint(plugIn)
        plugInRes = plugInMethod(srvObj, reqPropsObj)
    else:
        pass
    ngamsDiskUtils.markDisksAsUnmountedInDb(srvObj.getHostId(), srvObj.getDb(), srvObj.getCfg())

    # Send out possible Retained Email Notification Messages.
    flushMsg = "NOTE: Distribution of retained Email Notification Messages " +\
               "forced at Offline"
    ngamsNotification.checkNotifRetBuf(srvObj.getHostId(), srvObj.getCfg(), 1, flushMsg)

    logger.info("NG/AMS prepared for Offline State")

def wakeUpHost(srvObj,
               suspHost):
    """
    Wake up a host which has been suspended. After invoking the appropriate
    Wake-Up Plug-In it is checked within the time-out defined in the
    NG/AMS Configuration File if the server, which was woken up is up
    and running. If this is not the case within the specified time-out,
    an exception is thrown.

    srvObj:         Reference to instance of the NG/AMS server (ngamsServer).

    suspHost:       Host name of the suspended host (string).

    Returns:        Void.
    """
    T = TRACE()

    wakeUpPi = srvObj.getCfg().getWakeUpPlugIn()
    portNo = srvObj.getDb().getPortNoFromHostId(suspHost)
    try:
        plugInMethod = loadPlugInEntryPoint(wakeUpPi)
        plugInMethod(srvObj, suspHost)

        ipAddress = srvObj.getDb().getIpFromHostId(suspHost)
        ngamsHighLevelLib.pingServer(ipAddress, portNo,
                                     srvObj.getCfg().getWakeUpCallTimeOut())
    except Exception:
        logger.exception("Error waking up host %s", suspHost)
        raise

def checkStagingAreas(srvObj):
    """
    Check the Staging Areas of the disks registered, and in case files
    are found on these move htese to the Back-Log Area.

    srvObj:    Reference to NG/AMS server class object (ngamsServer).

    Returns:   Void.
    """
    T = TRACE()

    diskList = ngamsDiskUtils.\
               getDiskInfoForMountedDisks(srvObj.getDb(), srvObj.getHostId(),
                                          srvObj.getCfg().\
                                          getRootDirectory())
    # Generate first a dictionary with all files in the staging areas.
    stagingFileDic = {}
    for disk in diskList:
        stagingArea = disk.getStagingArea()
        if (stagingArea != ""):
            fileList = glob.glob(stagingArea + "/*")
            fileList += glob.glob(stagingArea + "/.NGAMS*")
            for filename in fileList: stagingFileDic[filename] = 1
    # Go through all files in the staging file dictionary and move them to
    # the Bad Files Area.
    for filename in stagingFileDic.keys():
        ngamsHighLevelLib.moveFile2BadDir(srvObj.getCfg(), filename)

def genIntAuthHdr(srvObj):
    """
    Generate an internal HTTP Authentication Header if possible.

    srvObj:    Reference to NG/AMS server class object (ngamsServer).

    Returns:   Authentication code or '' if no internal NGAS user defined
               (string).
    """
    # If the NGAS Internal Authorization User is defined generate
    # an internal Authorization Code.
    if (srvObj.getCfg().hasAuthUser(NGAMS_HTTP_INT_AUTH_USER)):
        authHttpHdrVal = srvObj.getCfg().\
                         getAuthHttpHdrVal(NGAMS_HTTP_INT_AUTH_USER)
    else:
        authHttpHdrVal = ""
    return authHttpHdrVal

# EOF


n, k = map(int, input().split())

def get(N, K):
    if K == 0:
        return 1 if N == 0 else 0
    if N == 0:
        return 0
    return get(N-1, K-1) + get(N+1, K-1)

print(get(n,k))


from ... import options as opts
from ... import types
from ...charts.chart import Chart
from ...globals import ChartType

class Pie(Chart):
    """
    <<< Pie >>>

    The pie chart is mainly used to represent the proportion of data of
    different categories in the total. Each radian represents the ratio of
    the number of data points.
    """

    def add(
        self,
            # 系列名称，用于Tooltip提示文本显示和legend图例筛选
        series_name: str,

            # 系列数据项，格式为 [(key1, value1), (key2, value2)]
        data_pair: types.Sequence,
        *,

            # 系列 label 颜色
        color: types.Optional[str] = None,

            # 饼图的半径，数组的第一项是内半径，第二项是外半径
            # 默认设置成百分比，相对于容器高宽中较小的一项的一半
        radius: types.Optional[types.Sequence] = None,

            # 饼图的中心（圆心）坐标，数组的第一项是横坐标，第二项是纵坐标
            # 默认设置成百分比，设置成百分比时第一项是相对于容器宽度，第二项是相对于容器高度
        center: types.Optional[types.Sequence] = None,

            # 是否展示成南丁格尔图，通过半径区分数据大小，有'radius'和'area'两种模式。
            # radius：扇区圆心角展现数据的百分比，半径展现数据的大小
            # area：所有扇区圆心角相同，仅通过半径展现数据大小
        rosetype: types.Optional[str] = None,

            # 饼图的扇区是否是顺时针排布。
        is_clockwise: bool = True,

            # 标签配置项，参考 `series_options.LabelOpts`
        label_opts: types.Label = opts.LabelOpts(),

            # 提示框组件配置项，参考 `series_options.TooltipOpts`
        tooltip_opts: types.Tooltip = None,

            # 图元样式配置项，参考 `series_options.ItemStyleOpts`
        itemstyle_opts: types.ItemStyle = None,
    ):
        data = [{"name": n, "value": v} for n, v in data_pair]

        if not radius:
            radius = ["0%", "75%"]
        if not center:
            center = ["50%", "50%"]

        self._append_color(color)
        for a, _ in data_pair:
            self.options.get("legend")[0].get("data").append(a)

        _dlst = self.options.get("legend")[0].get("data")
        _dset = list(set(_dlst))
        _dset.sort(key=_dlst.index)
        self.options.get("legend")[0].update(data=list(_dset))

        self.options.get("series").append(
            {
                "type": ChartType.PIE,
                "name": series_name,
                "clockwise": is_clockwise,
                "data": data,
                "radius": radius,
                "center": center,
                "roseType": rosetype,
                "label": label_opts,
                "tooltip": tooltip_opts,
                "itemStyle": itemstyle_opts,
            }
        )
        return self


import orjson
import os
import json

from hotline.hotline import *

def write_model_ops_to_file(model_ops, output_dir, run_name):
  model_ops_filepath = os.path.join(output_dir, f'{run_name}_model_ops.json')
  log.info(f'\n\nSaving model definition to file: {model_ops_filepath}\n\n')
  with open(model_ops_filepath, 'w') as f:
      json.dump(model_ops, f, indent=2)

def write_hierarchical_model(top_op, filepath):
  # Write JS module to disk
  with open(filepath, 'w') as outfile:
    outfile.write('export const model =\n')
    # json.dump([top_op], outfile, indent=2)  # slower
    json.dump([top_op], outfile)
  log.info(f'Wrote: {filepath}')

export_idx = 0
def write_trace(op, ui_traces_path, run_name, raw_slice_index, slices_bytes, track_index, **kwargs):
  # if 'ops' in op:  # only apply to non-leaf nodes
  #   return
  global export_idx
  export_idx += 1

  save_file = f'{ui_traces_path}/{run_name}.{export_idx}.pt.trace.json'

  if export_idx == 1:
    # This is the top op, save the original trace
    with open(save_file, "wb") as f:
      f.write(slices_bytes.getbuffer())
  else:
    slices = h_slice.get_slices(op)
    if slices:
      # Convert perfetto processed traces to raw traces from pytorch profiler
      raw_slices = []
      for sub_slice in slices:
        key = h_read.get_key(sub_slice, processed=True, track_index=track_index)
        try:
          raw_slice = raw_slice_index[key]
        except KeyError as e:
          log.error(f'❌❌❌ failed to lookup key: {key}')
        raw_slices.append(raw_slice)
      raw_slices = h_read.sanitize_trace(raw_slices)

      with open(save_file, 'wb') as f:
        f.write(orjson.dumps(raw_slices))  # 4x faster

  op['trace_file'] = save_file.split('/ui/dist/traces')[-1]
  op['trace_disk_size'] = humanize.naturalsize(os.stat(save_file).st_size)

def write_source_code(op, ui_source_code_path, run_name, **kwargs):
  if 'source_file_name' in op and op['source_file_name']:
    src = op['source_file_name']
    dst = f'{ui_source_code_path}{src}'
    op['ui_source_code_path'] = dst
    os.makedirs(os.path.dirname(dst), exist_ok=True)
    shutil.copy(src, dst)


import random
import omegaconf
import os

from tqdm import tqdm
from typing import List, Union

class DataPreparator:
    def __init__(self, config: omegaconf.dictconfig.DictConfig) -> None:
        self.config = config

    def _get_original_paths(self) -> List:
        """Gets each png file path.

        Returns:
            List: list of each images of dataset paths.
        """
        random.seed(7)
        original_paths = list()
        for id_ in tqdm(os.listdir(self.config.data_preparation.dataset_path)):
            if 'IDC' not in id_:
                id_dir = str(self.config.data_preparation.dataset_path) + '/' + id_
                for label in os.listdir(id_dir):
                    label_dir = id_dir + '/' + label
                    for image in os.listdir(label_dir):
                        if not os.path.isdir(image):
                            original_paths.append(label_dir + '/' + image)
        random.shuffle(original_paths)
        return original_paths

    def get_train_val_paths(self) -> Union[List, List, List]:
        """Splits the original paths to train, val.

        Returns:
            Union[List, List, List]: list of train and val paths.
        """

        original_paths = self._get_original_paths()
        index = int(len(original_paths) * self.config.data_pipeline.train_split)
        train_path = original_paths[: index]
        index = int(len(train_path) * self.config.data_pipeline.val_split)
        val_paths = train_path[: index]
        train_paths = train_path[index: ]
        return train_paths, val_paths

    def get_test_paths(self) -> Union[List, List, List]:
        """Splits the original paths to test.

        Returns:
            Union[List, List, List]: list of test paths.
        """
        original_paths = self._get_original_paths()
        index = int(len(original_paths) * self.config.data_pipeline.train_split)
        test_paths = original_paths[index: ]
        return test_paths


import dash_core_components as dcc
import dash_html_components as html

import dash_bootstrap_components as dbc

import pathlib
import page_builder as pb
from settings import *
from charts import figure_3_15, map_3_6

chapter_num = '3.7'
bannerImgSrc = IMAGES_PATH+'OceanicSections/Dissolved OxygenTomasz_Szumski.JPG'
bannerImgCredit = 'Tomasz Szumski'

introText = """
        Oxygen is essential for ocean life.
        There is an optimum range for dissolved oxygen concentration in oceanic
        water to avoid stress and potential death to marine organisms.
        Although low levels of oxygen exist in certain habitats,
        in general oxygen in subsurface waters is a good indicator of ocean health.
        """
bulletPoint1 = """
        Globally there has been a decrease of oxygen concentrations from
        the surface to 1000 m depth over the last 60 years.
        """
bulletPoint2 = """
        The levels of oxygen seen in McSwyne´s Bay, Co Donegal, in 2005 and
        2012 are associated with summer phytoplankton blooms which caused
        major mortalities of marine organisms.
        """
bulletPoints = [bulletPoint1, bulletPoint2]

trendChartTitle = 'Dissolved Oxygen Saturation - McSwyne´s Bay'  # (2002-2019)
trendChart = figure_3_15()

trendCaption = """
        Percentage saturation of dissolved oxygen taken at sampling sites
        in McSwyne’s Bay, Co. Donegal, mainly during summer months, from 2002 to 2019.
        Measurements were made at water depths ranging from just below the surface to 30 m.
        In general, levels were close to full saturation over the period of the observations.
        Super-saturated values (>100%) usually occur in the well-mixed surface layer,
        while the lower levels of saturation are found in stratified subsurface layers.
        The maximum and minimum values observed during the 2005 and 2012 summers are linked to
        phytoplankton blooms present during these periods in the coastal areas.
        The low dissolved oxygen values following the 2005 intense dinoflagellate bloom resulted in
        major mortalities of marine organisms in both the water column and near the sea floor.
        """

trendCaption2 = """
Deep-water dissolved oxygen section (left) as measured during the annual
Rockall Ocean Climate Survey (right) in winter 2013.
The rows of vertical dots represent sampling points at different depths (left) and correspond
to the blue point locations indicated in the red polygon (right).
The lowest values are observed in the subsurface waters at approximately 500 m
depth due to respiration associated with decomposition of organic matter.
"""

infrastructureText = """
The annual winter environmental survey on board the RV Celtic Voyager collects dissolved oxygen sensor profiles in coastal and
shelf waters around the island of Ireland (red). As part of ongoing projects,
observations are also made at the Mace Head buoy (blue) and at the SmartBay Observatory in Galway Bay (yellow).
As part of Ireland’s water framework directive and shellfish waters monitoring programme, in situ dissolved oxygen measurements are made
by the EPA (green) and the Marine Institute (red) in 116 transitional and coastal water bodies.
This monitoring programme has been in place since 2007.
        """
infrastructureMap = map_3_6()

infoLinks = [
    {'text': 'Oxygen ESSENTIAL CLIMATE VARIABLES (ECV). GCOS FACTSHEETS',
     'url': 'https://gcos.wmo.int/en/essential-climate-variables/oxygen/'},
    {'text': 'Silke, J., O\'Beirn, F. & Cronin, M. (2005), "Karenia mikimotoi: An Exceptional Dinoflagellate Bloom in Western Irish Waters, Summer 2005", Marine Environment and Health Series No. 21, Marine Institute 2005 ',
     'url': 'https://oar.marine.ie/handle/10793/240'},
    {'text': 'Linden, O., (2019), Evidence for ocean deoxygenation and its patterns, in: Ocean Deoxygenation: Everyone´s Problem, Laffoley, D. & Baxter, J.M. (eds), IUCN, Geneva.',
     'url': 'https://doi.org/10.2305/IUCN.CH.2019.13.en'},
    {'text': 'Information about ICES',
     'url': 'https://www.ices.dk/'},
    {'text': 'The GO-SHIP programme',
     'url': 'https://www.go-ship.org/About.html'},
    {'text': 'The Marine Institute operated Research Vessels',
     'url': 'https://www.marine.ie/Home/site-area/infrastructure-facilities/research-vessels/research-vessels'},
    {'text': 'Water Quality in Ireland under the Water Framework Directive',
     'url': 'https://www.catchments.ie/water-quality-in-ireland-2013-2018/'},
]

################################################################################
chapter_dict = next(
    (item for item in CHAPTERS if item['chapter-num'] == chapter_num), None)

################################################################################

custom_trend = dbc.Container(
    className='sr-trends',
    style={'borderColor': chapter_dict['domain-color']},
    id='trends',
    children=[
        html.H3(
            className='sr-section-heading',
            style={'color': chapter_dict['domain-color']},
            children='Trends',
        ),
        dbc.Row(
            children=[
                dbc.Col(className="col-md-10 offset-md-1",
                        children=[
                            html.H4(
                                className='sr-chart-title',
                                children=trendChartTitle),
                            dcc.Graph(
                                figure=trendChart,
                                config={'displayModeBar': False})]
                        )
            ]
        ),
        dbc.Row(
            children=[
                dbc.Col(className="col-md-10 offset-md-1",
                        children=[
                            html.P(
                                className='sr-chart-caption',
                                children=[html.I(className="fas fa-play _up",
                                                 style={"color": chapter_dict['domain-color']}),
                                          trendCaption]
                            )]
                        )
            ]
        ),
        dbc.Row(
            children=[
                dbc.Col(className="col-md-10 offset-md-1",
                        children=[
                            html.Img(
                                # src=DATA_PATH+'Oceanic_Domain/3.7Oxygen/Figure3.16/Figure3.16_OxygenConcentrationSectionRockallTrough.png'
                                className='w-100',
                                src=IMAGES_PATH+'OceanicSections/Figure3.16_OxygenConcentrationSectionRockallTrough.png'
                            )
                        ]
                        )
            ]
        ),
        dbc.Row(
            children=[
                dbc.Col(className="col-md-10 offset-md-1",
                        children=[
                            html.P(
                                className='sr-chart-caption',
                                children=[html.I(className="fas fa-play _up",
                                                 style={"color": chapter_dict['domain-color']}),
                                          trendCaption2]
                            )]
                        )
            ]
        ),
    ])

##############################################################################

def create_layout(app):
    return html.Div(
        children=[
            pb.build_banner(bannerImgSrc,
                            bannerImgCredit,
                            chapter_dict
                            ),
            pb.build_breadcrumb(chapter_dict),
            pb.build_nav(chapter_dict),
            pb.build_intro(introText,
                           bulletPoints,
                           chapter_dict
                           ),
            custom_trend,
            pb.build_infrastructure(infrastructureText,
                                    infrastructureMap,
                                    chapter_dict
                                    ),
            pb.build_info(infoLinks, chapter_dict),

            pb.build_nav_carousel(chapter_dict)
        ])


from django.urls import path
from django.urls import re_path
from . import views

app_name = 'treadweb'
urlpatterns = [
    re_path(r'^$', views.home_page, name='home'),
    re_path(r'^search/$', views.search_page, name='search'),
    path('search/<str:keyword>', views.search_keyword, name='search_keyword'),
    path('channel/', views.channel_page, name='channel'),
    path('video/', views.video_page, name='video'),
    path('video/<str:tag>', views.video_tag, name='video_tag'),
]


import pytest

from viposhu.exceptions import ThreadOver1000, ThreadStopped
from viposhu.hoshu5ch import Hoshu5ch

def test_over1000():
    h = Hoshu5ch("https://mi.5ch.net/test/read.cgi/news4vip/1667619945/l1")
    assert h
    with pytest.raises(ThreadOver1000) as e:
        b = h.is_in_time_threshold()
    assert e

def test_KakoLog():
    h = Hoshu5ch("https://mi.5ch.net/test/read.cgi/news4vip/1667714909/")
    assert h
    with pytest.raises(ThreadStopped) as e:
        b = h.is_in_time_threshold()
    assert e


from pcooja import Log

def application_pdr(log):
    """
    List and Analyse PDR of nodes
    """
    messages = log.messages
    simulation_time = messages[-1][Log.TIME]
    print(simulation_time/1000000)

    send_requests = log.get_messages(contain="Sending request")
    received_requests = log.get_messages(contain="Received request")
    send_responses = log.get_messages(contain="Sending response")
    received_responses = log.get_messages(contain="Received response")

    print(f"Sent requests: {len(send_requests)}")
    print(f"Received requests: {len(received_requests)}")
    print(f"Sent responses: {len(send_responses)}")
    print(f"Received responses: {len(received_responses)}")

def example(log):
    """
    List, for each node, the count of serial messages containing "Received response"
    """

    for node_id in log.get_node_ids():
        count = log.get_messages(node_id=node_id, contain="Received response")
        print(f"Node #{node_id} : {len(count)} messages")

def view(log):
    """
    TSCH
    """
    print("")
    print("^Joined network")
    tsch_joined = log.get_messages(contain="minimal schedule")
    if len(tsch_joined) == 0:
        print("No node ...")
    else:
        print(tsch_joined)

    print("")
    print("^Schedules")
    tsch_schedules = log.get_messages(log_module="TSCH Sched")
    tsch_schedules.sort(key=lambda message: message[Log.NODE_ID])
    print(tsch_schedules)

    print("")
    print("^Queues")
    tsch_queues = log.get_messages(log_module="TSCH Queue")
    tsch_queues.sort(key=lambda message: message[Log.NODE_ID])
    print(tsch_queues)

    return True

def view_app(log):
    """
    App
    """
    messages = log.get_messages(log_module="App")
    for node_id in log.get_node_ids():
        print(f"^Node #{node_id}")
        if node_id == 1:
            app_messages = Log.filter_messages(messages, node_id=node_id, contain="Sending")
            app_messages2 = Log.filter_messages(messages, node_id=node_id, contain="Received")
            app_messages.extend(app_messages2)
            app_messages.sort(key=lambda message: message[Log.TIME])
            print(app_messages)
        else:
            app_messages = Log.filter_messages(messages, node_id=node_id, contain="Sending")
            app_messages2 = Log.filter_messages(messages, node_id=node_id, contain="Received")
            app_messages.extend(app_messages2)
            app_messages.sort(key=lambda message: message[Log.TIME])
            print(app_messages)

def view_errors(log):
    """
    Errors
    """
    messages = log.get_messages(log_level=Log.LEVEL_WARN)
    warning_messages = list(filter(lambda m:m[Log.LOG_LEVEL] == Log.LEVEL_WARN, messages))
    print("")
    print("^Warning Messages")
    if len(warning_messages) == 0:
        print("No warning message !")
    else:
        print(warning_messages)
    print("")
    print("^Error Messages")
    error_messages = list(filter(lambda m:m[Log.LOG_LEVEL] == Log.LEVEL_ERR, messages))
    if len(error_messages) == 0:
        print("No error message !")
    else:
        print(error_messages)


from wpilib.command.command import Command
from wpilib.joystick import Joystick
from subsystems.Grabber import Grabber

class GrabberMoveWithPOV(Command):
    GRABBER_SPEED_UP = 0.7
    GRABBER_SPEED_DOWN = -0.4
    first_stop = False
    grabber: Grabber
    joystick: Joystick

    def __init__(self, grabber: Grabber, joystick: Joystick):
        super().__init__("GrabberMoveWithPOV")

        self.grabber = grabber
        self.joystick = joystick

        self.requires(grabber)
        self.setInterruptible(True)

    def execute(self):
        pov = self.joystick.getPOV()
        if pov == 0:
            self.grabber.set_speed(self.GRABBER_SPEED_UP)
            self.first_stop = True
        elif pov == 180:
            self.grabber.set_speed(self.GRABBER_SPEED_DOWN)
            self.first_stop = True
        elif self.first_stop:
            self.first_stop = False
            self.grabber.set_speed(0.1)
            self.grabber.go_to_set_point(self.grabber.get_current_position())

    def isFinished(self):
        return False


#!/usr/bin/python3
"""Defines a Pascal's Triangle function."""

def pascal_triangle(n):
    """Represents Pascal's Triangle of size n.

    Returns a list of lists of integers representing the triangle.
    """
    if n <= 0:
        return []

    triang = [[1]]
    while len(triang) != n:
        tri = triang[-1]
        swap = [1]
        for a in range(len(tri) - 1):
            swap.append(tri[a] + tri[a + 1])
        swap.append(1)
        triang.append(swap)
    return triang


from PyQt5.QtWidgets import (
    QAction,
    QCheckBox,
    QComboBox,
    QHBoxLayout,
    QLabel,
    QSpinBox,
    QToolButton,
    QVBoxLayout,
    QWidget,
)

class PlayBackUi:
    def setupUi(self, parent: QWidget) -> None:
        self.followChk = QCheckBox("Follow")
        self.followChk.setToolTip("Follow playhead")
        self.followChk.setChecked(True)

        self.fpsLabel = QLabel("Fps")
        self.fpsSpin = QSpinBox()
        self.fpsSpin.setToolTip("Playback speed")
        self.fpsSpin.setRange(1, 60)
        self.fpsSpin.setValue(15)

        self.lengthLabel = QLabel("Length")
        self.lengthSpin = QSpinBox()
        self.lengthSpin.setRange(60, 2000)
        self.lengthSpin.setToolTip("Max animation length in frames")

        self.currentViewLabel = QLabel("View")
        self.currentView = QComboBox()
        self.currentView.setToolTip("Current edit view")
        self.currentView.addItem("Dope sheet")
        self.currentView.addItem("Easing curve")

        # self.editor = QToolButton()
        # self.editor.setPopupMode(QToolButton.MenuButtonPopup)
        # self.editor.triggered.connect(self.editor.setDefaultAction)
        # self.editor.addAction(QAction("Dopesheet", parent))
        # self.editor.addAction(QAction("Curve editor", parent))

        hbox = QHBoxLayout(parent)
        hbox.setContentsMargins(0, 0, 0, 5)
        hbox.addWidget(self.currentViewLabel)
        hbox.addWidget(self.currentView)
        hbox.addStretch()
        hbox.addWidget(self.followChk)
        hbox.addWidget(self.fpsLabel)
        hbox.addWidget(self.fpsSpin)
        hbox.addWidget(self.lengthSpin)
        hbox.addWidget(self.lengthLabel)


"""
Boilerplate functions used in defining binary operations.
"""
from collections import UserDict
from functools import wraps
from typing import Callable

import numpy as np

from pandas._libs.lib import is_list_like, item_from_zerodim
from pandas._typing import F

from pandas.core.dtypes.generic import ABCDataFrame, ABCIndexClass, ABCSeries

def unpack_zerodim_and_defer(name: str) -> Callable[[F], F]:
    """
    Boilerplate for pandas conventions in arithmetic and comparison methods.

    Parameters
    ----------
    name : str

    Returns
    -------
    decorator
    """

    def wrapper(method: F) -> F:
        return _unpack_zerodim_and_defer(method, name)

    return wrapper

def _unpack_zerodim_and_defer(method, name: str):
    """
    Boilerplate for pandas conventions in arithmetic and comparison methods.

    Ensure method returns NotImplemented when operating against "senior"
    classes.  Ensure zero-dimensional ndarrays are always unpacked.

    Parameters
    ----------
    method : binary method
    name : str

    Returns
    -------
    method
    """
    is_cmp = name.strip("__") in {"eq", "ne", "lt", "le", "gt", "ge"}

    @wraps(method)
    def new_method(self, other):

        if is_cmp and isinstance(self, ABCIndexClass) and isinstance(other, ABCSeries):
            # For comparison ops, Index does *not* defer to Series
            pass
        else:
            for cls in [ABCDataFrame, ABCSeries, ABCIndexClass]:
                if isinstance(self, cls):
                    break
                if isinstance(other, cls):
                    return NotImplemented

        other = item_from_zerodim(other)

        if isinstance(self, (ABCSeries, ABCDataFrame)) and isinstance(
            other, (ABCSeries, ABCDataFrame)
        ):
            # we dont require length matches
            pass
        elif is_list_like(other, allow_sets=False) and not isinstance(
            other, (dict, UserDict)
        ):
            if len(other) != len(self):
                if len(other) == 1 and not hasattr(other, "dtype"):
                    # i.e. unpack scalar list, but leave e.g. Categorical,
                    #  for which the scalar behavior doesnt match the
                    #  array behavior
                    other = other[0]
                else:
                    raise ValueError(
                        "Lengths must match", self.shape, np.shape(other), type(other)
                    )

        return method(self, other)

    return new_method


# Scrapy's settings for scrapers project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
#     https://docs.scrapy.org/en/latest/topics/settings.html
#     https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
#     https://docs.scrapy.org/en/latest/topics/spider-middleware.html
import logging
import os
from datetime import timedelta

BOT_NAME = 'airline_scraper'

SPIDER_MODULES = ['scrapers.spiders']
NEWSPIDER_MODULE = 'scrapers.spiders'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) ' \
             'Chrome/113.0.0.0 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Configure maximum concurrent requests performed by Scrapy (default: 16)
# CONCURRENT_REQUESTS = 32

# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 10
# The download delay setting will honor only one of:
CONCURRENT_REQUESTS_PER_DOMAIN = 2
# CONCURRENT_REQUESTS_PER_IP = 16

# Disable cookies (enabled by default)
# COOKIES_ENABLED = False

# Disable Telnet Console (enabled by default)
# TELNETCONSOLE_ENABLED = False

# Override the default request headers:
# DEFAULT_REQUEST_HEADERS = {
#   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
#   'Accept-Language': 'en',
# }

# Enable or disable spider middlewares
# See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
# SPIDER_MIDDLEWARES = {
#    'scrapers.middlewares.AirlineScraperSpiderMiddleware': 543,
# }

# Enable or disable downloader middlewares
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
# DOWNLOADER_MIDDLEWARES = {
#    'scrapers.middlewares.AirlineScraperDownloaderMiddleware': 543,
# }

# Enable or disable extensions
# See https://docs.scrapy.org/en/latest/topics/extensions.html
# EXTENSIONS = {
#    'scrapy.extensions.telnet.TelnetConsole': None,
# }

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    'scrapers.pipelines.AirlineScraperPipeline': 0,
}

# Enable and configure the AutoThrottle extension (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/autothrottle.html
AUTOTHROTTLE_ENABLED = True

# The initial download delay.
# Default 5
AUTOTHROTTLE_START_DELAY = 5

# The maximum download delay to be set in case of high latencies
# Default 60
AUTOTHROTTLE_MAX_DELAY = 100

# The average number of requests Scrapy should be sending in parallel to each remote server
AUTOTHROTTLE_TARGET_CONCURRENCY = 0.25
# Enable showing throttling stats for every response received:
AUTOTHROTTLE_DEBUG = False

# Enable and configure HTTP caching (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
# HTTPCACHE_ENABLED = True
# HTTPCACHE_EXPIRATION_SECS = 0
# HTTPCACHE_DIR = 'httpcache'
# HTTPCACHE_IGNORE_HTTP_CODES = []
# HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

# Set settings whose default value is deprecated to a future-proof value
REQUEST_FINGERPRINTER_IMPLEMENTATION = '2.7'
TWISTED_REACTOR = 'twisted.internet.asyncioreactor.AsyncioSelectorReactor'

# Default True
RANDOMIZE_DOWNLOAD_DELAY = True

# Default 2
RETRY_TIMES = 2

DOWNLOADER_MIDDLEWARES = {
}

LOG_LEVEL = os.environ.get('LOG_LEVEL', logging.INFO)
LOG_FORMAT = os.environ.get('LOG_FORMAT', '[%(name)s] %(asctime)s %(levelname)s: %(message)s')

ROUTES_FILE = os.path.join(
    os.path.dirname(os.path.abspath(__file__)), os.environ.get('ROUTES_FILE', 'airline_routes.json')
)

# Want to scrape 6 months in advance
DAYS_TO_SCRAPE = timedelta(days=os.environ.get('DAYS_TO_SCRAPE', 180))


from httmock import urlmatch, HTTMock
from json import dumps as jstr
import unittest
from myria import MyriaConnection

@urlmatch(netloc=r'localhost:12345')
def local_mock(url, request):
    global query_counter
    if url.path == '/workers':
        return jstr({'1': 'localhost:12347', '2': 'localhost:12348'})
    elif url.path == '/workers/alive':
        return jstr([1, 2])
    elif url.path == '/workers/worker-1':
        return jstr("localhost:12347")

    return None

class TestQuery(unittest.TestCase):
    def __init__(self, args):
        with HTTMock(local_mock):
            self.connection = MyriaConnection(hostname='localhost', port=12345)
        unittest.TestCase.__init__(self, args)

    def test_workers(self):
        with HTTMock(local_mock):
            workers = self.connection.workers()
            self.assertEquals(workers, {'1': 'localhost:12347',
                                        '2': 'localhost:12348'})

    def test_alive(self):
        with HTTMock(local_mock):
            workers = self.connection.workers_alive()
            self.assertEquals(set(workers), set([1, 2]))

    def test_worker_1(self):
        with HTTMock(local_mock):
            worker = self.connection.worker(1)
            self.assertEquals(worker, 'localhost:12347')


### 코딩테스트 입문
### 하루 4문제 매일 도전 task

## Day 13 문자열, 배열, 사칙연산, 수학, 조건문
# 컨트롤 제트 (+2)
# 문제 설명 : 숫자와 "Z"가 공백으로 구분되어 담긴 문자열이 주어집니다. 문자열에 있는 숫자를 차례대로 더하려고 합니다.
# 이 때 "Z"가 나오면 바로 전에 더했던 숫자를 뺀다는 뜻입니다.
# 숫자와 "Z"로 이루어진 문자열 s가 주어질 때, 머쓱이가 구한 값을 return 하도록 solution 함수를 완성해보세요.
# 입출력 예시 s: "-1 -2 -3 Z" | result: -3

# wrong ver.
# ValueError: invalid literal for int() with base 10: 'Z' <- Z는 int 가 될 수 없는 오류 발생
def solution(s):
    list_s = s.split()
    k = 0
    total = 0
    for i in list_s:
        if i == 'Z':
            total -= k
        total += int(i)
        k = int(i)
    return total

# studied ver.
# stack 자료구조: STACK (LIFO) 나중에 들어간 것이 먼저 나오는 자료구조, Last In First Out 착안 -> pop 사용
# isnumeric(), isdigit()의 경우 음수를 판별할 수 없기 때문에 해당 자료구조 사용!
def solution(s):
    stack = []
    for num in s.split():
        try:
            stack.append(int(num))
        except:
            if stack:        # stack에 데이터가 존재하면 실행
                stack.pop()
    return sum(stack)
# try ~ except 구조: try 먼저 시도할 때 error 안 나면 그대로 try 구문만, error 나면 except 구문으로 빠짐

# 배열 원소의 길이 (+1)
# 문제 설명 : 문자열 배열 strlist가 매개변수로 주어집니다. strlist 각 원소의 길이를 담은 배열을 retrun하도록 solution 함수를 완성해주세요.
def solution(strlist):
    return [ len(strlist[i]) for i in range(len(strlist)) ]

# 중복된 문자 제거 (+1)
# 문제 설명 : 문자열 my_string이 매개변수로 주어집니다.
# my_string에서 중복된 문자를 제거하고 하나의 문자만 남긴 문자열을 return하도록 solution 함수를 완성해주세요.
def solution(my_string):
    answer = []
    for strin in list(my_string):
        if strin not in answer:
            answer.append(strin)
    return ''.join(answer)

# 삼각형의 완성조건(1) (+2)
# 문제 설명 : 선분 세 개로 삼각형을 만들기 위해서는 다음과 같은 조건을 만족해야 합니다.
# 가장 긴 변의 길이는 다른 두 변의 길이의 합보다 작아야 합니다. 삼각형의 세 변의 길이가 담긴 배열 sides이 매개변수로 주어집니다.
# 세 변으로 삼각형을 만들 수 있다면 1, 만들 수 없다면 2를 return하도록 solution 함수를 완성해주세요.
def solution(sides):
    return 1 if max(sides) < (sum(sides) - max(sides)) else 2


from __future__ import annotations

import json
from typing import Union

from PySide2 import QtGui, QtWidgets

from usc_lr_timer import google_sheets, talk_to_google
from usc_lr_timer.constants import RESOURCES

JOURNALS = RESOURCES / 'journal_mapping.json'

class Model(object):
    def __init__(self):
        self._names = []
        self._name_index = 0
        self._name_mapping = {}
        self._journals = []
        self._journal_index = 0
        self._journal_mapping = {}
        self._pin = ''

    @property
    def names(self) -> list[str]:
        return self._names[:]

    @property
    def journals(self) -> list[str]:
        return self._journals[:]

    @property
    def name(self) -> Union[str, None]:
        if self._name_index == 0:
            return None
        else:
            return self._names[self._name_index]

    @property
    def journal(self) -> Union[str, None]:
        if self._journal_index == 0:
            return None
        else:
            return self._journals[self._journal_index]

    @property
    def sheet_id(self) -> Union[str, None]:
        if self.journal is None:
            return None
        else:
            return self._journal_mapping[self.journal]

    @property
    def pin(self) -> str:
        return self._pin

    def set_names(self):
        if self.sheet_id is not None:
            status, result = talk_to_google.talk_to_google(
                google_sheets.get_names, self.sheet_id,
            )
            if status == talk_to_google.Results.success:
                self._name_mapping = dict(result)
                self._names = [''] + list(self._name_mapping.keys())
                return

        self._name_mapping = {}
        self._names = []

    def set_journals(self):
        with open(JOURNALS) as stream:
            self._journal_mapping = json.load(stream)
        self._journals = [''] + list(self._journal_mapping.keys())

    def set_name_index(self, index: int):
        self._name_index = index

    def set_journal_index(self, index: int):
        self._journal_index = index

    def set_pin(self, pin: str):
        self._pin = pin

    def login(self) -> bool:
        if self.name is None:
            return False
        return self.pin == self._name_mapping[self.name]

class View(object):
    def __init__(self, model: Model, widget: LoginDialog):
        self.model = model
        self.widget = widget

    def set_names(self):
        self.model.set_names()
        self.widget.names_cb.clear()
        if self.model.journal:
            self.widget.names_cb.addItems(self.model.names)

    def set_journals(self):
        self.model.set_journals()
        self.widget.journals_cb.addItems(self.model.journals)

    def set_name_index(self, index: int):
        self.model.set_name_index(index)
        self.widget.names_cb.setCurrentIndex(index)

    def set_journal_index(self, index: int):
        self.model.set_journal_index(index)
        self.widget.journals_cb.setCurrentIndex(index)
        self.set_names()

    def set_pin(self, pin: str):
        self.model.set_pin(pin)

    def login(self) -> bool:
        if self.model.login():
            return True
        else:
            self.model.set_pin('')
            self.widget.pin_line.setText(self.model.pin)
            return False

class LoginDialog(QtWidgets.QDialog):
    def __init__(self, model: Model):
        super().__init__(None)
        self._layout = QtWidgets.QVBoxLayout()
        self.setLayout(self._layout)
        self.view = View(model, self)
        self.init_ui()
        self.init_controller()
        self.view.set_journals()
        self.view.set_names()

    def init_ui(self):
        self.setWindowIcon(QtGui.QIcon(str(RESOURCES / 'icon.ico')))
        self.setWindowTitle('Login')
        self.setWhatsThis('Login to track your time')
        form_layout = QtWidgets.QFormLayout()
        self.journals_cb = QtWidgets.QComboBox()
        form_layout.addRow('Journal: ', self.journals_cb)

        # Add names dropdown
        self.names_cb = QtWidgets.QComboBox()
        form_layout.addRow('Name: ', self.names_cb)

        # Add pin
        self.pin_line = QtWidgets.QLineEdit()
        self.pin_line.setEchoMode(QtWidgets.QLineEdit.Password)
        form_layout.addRow('Pin: ', self.pin_line)

        self._layout.addLayout(form_layout)

        self.button_box = QtWidgets.QDialogButtonBox(
            QtWidgets.QDialogButtonBox.Ok
        )
        ok_btn = self.button_box.button(QtWidgets.QDialogButtonBox.Ok)
        ok_btn.setText('Login')
        self._layout.addWidget(self.button_box)

    def init_controller(self):
        self.names_cb.currentIndexChanged[int].connect(self.view.set_name_index)
        self.journals_cb.currentIndexChanged[int].connect(
            self.set_journal_index
        )
        self.pin_line.textEdited.connect(self.view.set_pin)
        self.button_box.accepted.connect(self.login)

    def set_journal_index(self, index: int):
        self.view.set_journal_index(index)

    def login(self):
        if self.view.login():
            self.accept()
        else:
            QtWidgets.QMessageBox.critical(self, 'Failed', 'Incorrect Pin')

def login() -> tuple(bool, str, str, str):
    model = Model()
    dialog = LoginDialog(model)
    dialog.exec_()
    success = dialog.result() == dialog.Accepted
    return success, model.journal, model.sheet_id, model.name


import discord
from discord.ext import commands

from Models.Context import Context

class SameTimeAttackStartCog(commands.Cog):
    """
    同時凸開始処理
    """
    def __init__(self, bot: commands.Bot):
        self.bot = bot

    @commands.command("dstart")
    async def same_time_attack_start(self, ctx: commands.context.Context, *args):
        remain: int = int(args[0])

        # 同時凸データ追加
        context: Context = await Context.get_instance(self.bot)
        context.same_time_attack.start(remain)
        print(context.same_time_attack.format_status())
        await ctx.message.channel.send(context.same_time_attack.format_status())


"""
This module contains Fab's `main` method plus related subroutines.

`main` is executed as the command line ``fab`` program and takes care of
parsing options and commands, loading the user settings file, loading a
fabfile, and executing the commands given.

The other callables defined in this module are internal only. Anything useful
to individuals leveraging Fabric as a library, should be kept elsewhere.
"""

from collections import defaultdict
from operator import add, isMappingType
from optparse import OptionParser
import os
import sys
import types

from fabric import api, state  # For checking callables against the API, & easy mocking
from fabric.contrib import console, files, project  # Ditto
from fabric.network import denormalize, interpret_host_string, disconnect_all
from fabric.state import commands, connections, env_options
from fabric.tasks import Task
from fabric.utils import abort, indent

# One-time calculation of "all internal callables" to avoid doing this on every
# check of a given fabfile callable (in is_classic_task()).
_modules = [api, project, files, console]
_internals = reduce(lambda x, y: x + filter(callable, vars(y).values()),
    _modules,
    []
)

# Module recursion cache
class _ModuleCache(object):
    """
    Set-like object operating on modules and storing __name__s internally.
    """
    def __init__(self):
        self.cache = set()

    def __contains__(self, value):
        return value.__name__ in self.cache

    def add(self, value):
        return self.cache.add(value.__name__)

    def clear(self):
        return self.cache.clear()

_seen = _ModuleCache()

def load_settings(path):
    """
    Take given file path and return dictionary of any key=value pairs found.

    Usage docs are in docs/usage/fab.rst, in "Settings files."
    """
    if os.path.exists(path):
        comments = lambda s: s and not s.startswith("#")
        settings = filter(comments, open(path, 'r'))
        return dict((k.strip(), v.strip()) for k, _, v in
            [s.partition('=') for s in settings])
    # Handle nonexistent or empty settings file
    return {}

def _is_package(path):
    """
    Is the given path a Python package?
    """
    return (
        os.path.isdir(path)
        and os.path.exists(os.path.join(path, '__init__.py'))
    )

def find_fabfile():
    """
    Attempt to locate a fabfile, either explicitly or by searching parent dirs.

    Usage docs are in docs/usage/fabfiles.rst, in "Fabfile discovery."
    """
    # Obtain env value
    names = [state.env.fabfile]
    # Create .py version if necessary
    if not names[0].endswith('.py'):
        names += [names[0] + '.py']
    # Does the name contain path elements?
    if os.path.dirname(names[0]):
        # If so, expand home-directory markers and test for existence
        for name in names:
            expanded = os.path.expanduser(name)
            if os.path.exists(expanded):
                if name.endswith('.py') or _is_package(expanded):
                    return os.path.abspath(expanded)
    else:
        # Otherwise, start in cwd and work downwards towards filesystem root
        path = '.'
        # Stop before falling off root of filesystem (should be platform
        # agnostic)
        while os.path.split(os.path.abspath(path))[1]:
            for name in names:
                joined = os.path.join(path, name)
                if os.path.exists(joined):
                    if name.endswith('.py') or _is_package(joined):
                        return os.path.abspath(joined)
            path = os.path.join('..', path)
    # Implicit 'return None' if nothing was found

def is_classic_task(tup):
    """
    Takes (name, object) tuple, returns True if it's a non-Fab public callable.
    """
    name, func = tup
    return (
        callable(func)
        and (func not in _internals)
        and not name.startswith('_')
    )

def load_fabfile(path, importer=None):
    """
    Import given fabfile path and return (docstring, callables).

    Specifically, the fabfile's ``__doc__`` attribute (a string) and a
    dictionary of ``{'name': callable}`` containing all callables which pass
    the "is a Fabric task" test.
    """
    if importer is None:
        importer = __import__
    # Get directory and fabfile name
    directory, fabfile = os.path.split(path)
    # If the directory isn't in the PYTHONPATH, add it so our import will work
    added_to_path = False
    index = None
    if directory not in sys.path:
        sys.path.insert(0, directory)
        added_to_path = True
    # If the directory IS in the PYTHONPATH, move it to the front temporarily,
    # otherwise other fabfiles -- like Fabric's own -- may scoop the intended
    # one.
    else:
        i = sys.path.index(directory)
        if i != 0:
            # Store index for later restoration
            index = i
            # Add to front, then remove from original position
            sys.path.insert(0, directory)
            del sys.path[i + 1]
    # Perform the import (trimming off the .py)
    imported = importer(os.path.splitext(fabfile)[0])
    # Remove directory from path if we added it ourselves (just to be neat)
    if added_to_path:
        del sys.path[0]
    # Put back in original index if we moved it
    if index is not None:
        sys.path.insert(index + 1, directory)
        del sys.path[0]

    # Actually load tasks
    docstring, new_style, classic, default = load_tasks_from_module(imported)
    tasks = new_style if state.env.new_style_tasks else classic
    # Clean up after ourselves
    _seen.clear()
    return docstring, tasks, default

def load_tasks_from_module(imported):
    """
    Handles loading all of the tasks for a given `imported` module
    """
    # Obey the use of <module>.__all__ if it is present
    imported_vars = vars(imported)
    if "__all__" in imported_vars:
        imported_vars = [(name, imported_vars[name]) for name in \
                         imported_vars if name in imported_vars["__all__"]]
    else:
        imported_vars = imported_vars.items()
    # Return a two-tuple value.  First is the documentation, second is a
    # dictionary of callables only (and don't include Fab operations or
    # underscored callables)
    new_style, classic, default = extract_tasks(imported_vars)
    return imported.__doc__, new_style, classic, default

# For attribute tomfoolery
class _Dict(dict):
    pass

def extract_tasks(imported_vars):
    """
    Handle extracting tasks from a given list of variables
    """
    new_style_tasks = _Dict()
    classic_tasks = {}
    default_task = None
    if 'new_style_tasks' not in state.env:
        state.env.new_style_tasks = False
    for tup in imported_vars:
        name, obj = tup
        if is_task_object(obj):
            state.env.new_style_tasks = True
            # Honor instance.name
            new_style_tasks[obj.name] = obj
            # Handle aliasing
            if obj.aliases is not None:
                for alias in obj.aliases:
                    new_style_tasks[alias] = obj
            # Handle defaults
            if obj.is_default:
                default_task = obj
        elif is_classic_task(tup):
            classic_tasks[name] = obj
        elif is_task_module(obj):
            docs, newstyle, classic, default = load_tasks_from_module(obj)
            for task_name, task in newstyle.items():
                if name not in new_style_tasks:
                    new_style_tasks[name] = _Dict()
                new_style_tasks[name][task_name] = task
            if default is not None:
                new_style_tasks[name].default = default
    return new_style_tasks, classic_tasks, default_task

def is_task_module(a):
    """
    Determine if the provided value is a task module
    """
    #return (type(a) is types.ModuleType and
    #        any(map(is_task_object, vars(a).values())))
    if type(a) is types.ModuleType and a not in _seen:
        # Flag module as seen
        _seen.add(a)
        # Signal that we need to check it out
        return True

def is_task_object(a):
    """
    Determine if the provided value is a ``Task`` object.

    This returning True signals that all tasks within the fabfile
    module must be Task objects.
    """
    return isinstance(a, Task) and a.use_task_objects

def parse_options():
    """
    Handle command-line options with optparse.OptionParser.

    Return list of arguments, largely for use in `parse_arguments`.
    """
    #
    # Initialize
    #

    parser = OptionParser(usage="fab [options] <command>[:arg1,arg2=val2,host=foo,hosts='h1;h2',...] ...")

    #
    # Define options that don't become `env` vars (typically ones which cause
    # Fabric to do something other than its normal execution, such as
    # --version)
    #

    # Version number (optparse gives you --version but we have to do it
    # ourselves to get -V too. sigh)
    parser.add_option('-V', '--version',
        action='store_true',
        dest='show_version',
        default=False,
        help="show program's version number and exit"
    )

    # List Fab commands found in loaded fabfiles/source files
    parser.add_option('-l', '--list',
        action='store_true',
        dest='list_commands',
        default=False,
        help="print list of possible commands and exit"
    )

    # Like --list, but text processing friendly
    parser.add_option('--shortlist',
        action='store_true',
        dest='shortlist',
        default=False,
        help="alias for -F short --list"
    )

    # Control behavior of --list
    LIST_FORMAT_OPTIONS = ('short', 'normal', 'nested')
    parser.add_option('-F', '--list-format',
        choices=LIST_FORMAT_OPTIONS,
        default='normal',
        help="formats --list, choices: %s" % ", ".join(LIST_FORMAT_OPTIONS)
    )

    # Display info about a specific command
    parser.add_option('-d', '--display',
        metavar='COMMAND',
        help="print detailed info about a given command and exit"
    )

    #
    # Add in options which are also destined to show up as `env` vars.
    #

    for option in env_options:
        parser.add_option(option)

    #
    # Finalize
    #

    # Return three-tuple of parser + the output from parse_args (opt obj, args)
    opts, args = parser.parse_args()
    return parser, opts, args

def _is_task(name, value):
    """
    Is the object a task as opposed to e.g. a dict or int?
    """
    return is_classic_task((name, value)) or is_task_object(value)

def _sift_tasks(mapping):
    tasks, collections = [], []
    for name, value in mapping.iteritems():
        if _is_task(name, value):
            tasks.append(name)
        elif isMappingType(value):
            collections.append(name)
    tasks = sorted(tasks)
    collections = sorted(collections)
    return tasks, collections

def _task_names(mapping):
    """
    Flatten & sort task names in a breadth-first fashion.

    Tasks are always listed before submodules at the same level, but within
    those two groups, sorting is alphabetical.
    """
    tasks, collections = _sift_tasks(mapping)
    for collection in collections:
        module = mapping[collection]
        if hasattr(module, 'default'):
            tasks.append(collection)
        join = lambda x: ".".join((collection, x))
        tasks.extend(map(join, _task_names(module)))
    return tasks

def _crawl(name, mapping):
    """
    ``name`` of ``'a.b.c'`` => ``mapping['a']['b']['c']``
    """
    key, _, rest = name.partition('.')
    value = mapping[key]
    if not rest:
        return value
    return _crawl(rest, value)

def crawl(name, mapping):
    try:
        result = _crawl(name, mapping)
        # Handle default tasks
        if isinstance(result, _Dict) and getattr(result, 'default', False):
            result = result.default
        return result
    except (KeyError, TypeError):
        return None

def _print_docstring(docstrings, name):
    if not docstrings:
        return False
    docstring = crawl(name, state.commands).__doc__
    if type(docstring) in types.StringTypes:
        return docstring

def _normal_list(docstrings=True):
    result = []
    task_names = _task_names(state.commands)
    # Want separator between name, description to be straight col
    max_len = reduce(lambda a, b: max(a, len(b)), task_names, 0)
    sep = '  '
    trail = '...'
    for name in task_names:
        output = None
        docstring = _print_docstring(docstrings, name)
        if docstring:
            lines = filter(None, docstring.splitlines())
            first_line = lines[0].strip()
            # Truncate it if it's longer than N chars
            size = 75 - (max_len + len(sep) + len(trail))
            if len(first_line) > size:
                first_line = first_line[:size] + trail
            output = name.ljust(max_len) + sep + first_line
        # Or nothing (so just the name)
        else:
            output = name
        result.append(indent(output))
    return result

def _nested_list(mapping, level=1):
    result = []
    tasks, collections = _sift_tasks(mapping)
    # Tasks come first
    result.extend(map(lambda x: indent(x, spaces=level * 4), tasks))
    for collection in collections:
        module = mapping[collection]
        # Section/module "header"
        result.append(indent(collection + ":", spaces=level * 4))
        # Recurse
        result.extend(_nested_list(module, level + 1))
    return result

COMMANDS_HEADER = "Available commands"
NESTED_REMINDER = " (remember to call as module.[...].task)"

def list_commands(docstring, format_):
    """
    Print all found commands/tasks, then exit. Invoked with ``-l/--list.``

    If ``docstring`` is non-empty, it will be printed before the task list.

    ``format_`` should conform to the options specified in
    ``LIST_FORMAT_OPTIONS``, e.g. ``"short"``, ``"normal"``.
    """
    # Short-circuit with simple short output
    if format_ == "short":
        return _task_names(state.commands)
    # Otherwise, handle more verbose modes
    result = []
    # Docstring at top, if applicable
    if docstring:
        trailer = "\n" if not docstring.endswith("\n") else ""
        result.append(docstring + trailer)
    header = COMMANDS_HEADER
    if format_ == "nested":
        header += NESTED_REMINDER
    result.append(header + ":\n")
    c = _normal_list() if format_ == "normal" else _nested_list(state.commands)
    result.extend(c)
    return result

def display_command(name):
    """
    Print command function's docstring, then exit. Invoked with -d/--display.
    """
    # Sanity check
    command = crawl(name, state.commands)
    if command is None:
        msg = "Task '%s' does not appear to exist. Valid task names:\n%s"
        abort(msg % (name, "\n".join(_normal_list(False))))
    # Print out nicely presented docstring if found
    if command.__doc__:
        print("Displaying detailed information for task '%s':" % name)
        print('')
        print(indent(command.__doc__, strip=True))
        print('')
    # Or print notice if not
    else:
        print("No detailed information available for task '%s':" % name)
    sys.exit(0)

def _escape_split(sep, argstr):
    """
    Allows for escaping of the separator: e.g. task:arg='foo\, bar'

    It should be noted that the way bash et. al. do command line parsing, those
    single quotes are required.
    """
    escaped_sep = r'\%s' % sep

    if escaped_sep not in argstr:
        return argstr.split(sep)

    before, _, after = argstr.partition(escaped_sep)
    startlist = before.split(sep)  # a regular split is fine here
    unfinished = startlist[-1]
    startlist = startlist[:-1]

    # recurse because there may be more escaped separators
    endlist = _escape_split(sep, after)

    # finish building the escaped value. we use endlist[0] becaue the first
    # part of the string sent in recursion is the rest of the escaped value.
    unfinished += sep + endlist[0]

    return startlist + [unfinished] + endlist[1:]  # put together all the parts

def parse_arguments(arguments):
    """
    Parse string list into list of tuples: command, args, kwargs, hosts, roles.

    See docs/usage/fab.rst, section on "per-task arguments" for details.
    """
    cmds = []
    for cmd in arguments:
        args = []
        kwargs = {}
        hosts = []
        roles = []
        exclude_hosts = []
        if ':' in cmd:
            cmd, argstr = cmd.split(':', 1)
            for pair in _escape_split(',', argstr):
                k, _, v = pair.partition('=')
                if _:
                    # Catch, interpret host/hosts/role/roles/exclude_hosts
                    # kwargs
                    if k in ['host', 'hosts', 'role', 'roles', 'exclude_hosts']:
                        if k == 'host':
                            hosts = [v.strip()]
                        elif k == 'hosts':
                            hosts = [x.strip() for x in v.split(';')]
                        elif k == 'role':
                            roles = [v.strip()]
                        elif k == 'roles':
                            roles = [x.strip() for x in v.split(';')]
                        elif k == 'exclude_hosts':
                            exclude_hosts = [x.strip() for x in v.split(';')]
                    # Otherwise, record as usual
                    else:
                        kwargs[k] = v
                else:
                    args.append(k)
        cmds.append((cmd, args, kwargs, hosts, roles, exclude_hosts))
    return cmds

def parse_remainder(arguments):
    """
    Merge list of "remainder arguments" into a single command string.
    """
    return ' '.join(arguments)

def _merge(hosts, roles, exclude=[]):
    """
    Merge given host and role lists into one list of deduped hosts.
    """
    # Abort if any roles don't exist
    bad_roles = [x for x in roles if x not in state.env.roledefs]
    if bad_roles:
        abort("The following specified roles do not exist:\n%s" % (
            indent(bad_roles)
        ))

    # Look up roles, turn into flat list of hosts
    role_hosts = []
    for role in roles:
        value = state.env.roledefs[role]
        # Handle "lazy" roles (callables)
        if callable(value):
            value = value()
        role_hosts += value

    # Return deduped combo of hosts and role_hosts, preserving order within
    # them (vs using set(), which may lose ordering) and skipping hosts to be
    # excluded.
    cleaned_hosts = _clean_hosts(list(hosts) + list(role_hosts))
    all_hosts = []
    for host in cleaned_hosts:
        if host not in all_hosts and host not in exclude:
            all_hosts.append(host)
    return all_hosts

def _clean_hosts(host_list):
    """
    Clean host strings to ensure no trailing whitespace, etc.
    """
    return [host.strip() for host in host_list]

def get_hosts(command, cli_hosts, cli_roles, cli_exclude_hosts):
    """
    Return the host list the given command should be using.

    See :ref:`execution-model` for detailed documentation on how host lists are
    set.
    """
    # Command line per-command takes precedence over anything else.
    if cli_hosts or cli_roles:
        return _merge(cli_hosts, cli_roles, cli_exclude_hosts)
    # Decorator-specific hosts/roles go next
    func_hosts = getattr(command, 'hosts', [])
    func_roles = getattr(command, 'roles', [])
    if func_hosts or func_roles:
        return _merge(func_hosts, func_roles, cli_exclude_hosts)
    # Finally, the env is checked (which might contain globally set lists from
    # the CLI or from module-level code). This will be the empty list if these
    # have not been set -- which is fine, this method should return an empty
    # list if no hosts have been set anywhere.
    return _merge(state.env['hosts'], state.env['roles'], state.env['exclude_hosts'])

def update_output_levels(show, hide):
    """
    Update state.output values as per given comma-separated list of key names.

    For example, ``update_output_levels(show='debug,warnings')`` is
    functionally equivalent to ``state.output['debug'] = True ;
    state.output['warnings'] = True``. Conversely, anything given to ``hide``
    sets the values to ``False``.
    """
    if show:
        for key in show.split(','):
            state.output[key] = True
    if hide:
        for key in hide.split(','):
            state.output[key] = False

def _run_task(task, args, kwargs):
    # First, try class-based tasks
    if hasattr(task, 'run') and callable(task.run):
        return task.run(*args, **kwargs)
    # Fallback to callable behavior
    return task(*args, **kwargs)

def main():
    """
    Main command-line execution loop.
    """
    try:
        # Parse command line options
        parser, options, arguments = parse_options()

        # Handle regular args vs -- args
        arguments = parser.largs
        remainder_arguments = parser.rargs

        # Update env with any overridden option values
        # NOTE: This needs to remain the first thing that occurs
        # post-parsing, since so many things hinge on the values in env.
        for option in env_options:
            state.env[option.dest] = getattr(options, option.dest)

        # Handle --hosts, --roles, --exclude-hosts (comma separated string =>
        # list)
        for key in ['hosts', 'roles', 'exclude_hosts']:
            if key in state.env and isinstance(state.env[key], basestring):
                state.env[key] = state.env[key].split(',')

        # Handle output control level show/hide
        update_output_levels(show=options.show, hide=options.hide)

        # Handle version number option
        if options.show_version:
            print("Fabric %s" % state.env.version)
            sys.exit(0)

        # Load settings from user settings file, into shared env dict.
        state.env.update(load_settings(state.env.rcfile))

        # Find local fabfile path or abort
        fabfile = find_fabfile()
        if not fabfile and not remainder_arguments:
            abort("""Couldn't find any fabfiles!

Remember that -f can be used to specify fabfile path, and use -h for help.""")

        # Store absolute path to fabfile in case anyone needs it
        state.env.real_fabfile = fabfile

        # Load fabfile (which calls its module-level code, including
        # tweaks to env values) and put its commands in the shared commands
        # dict
        if fabfile:
            docstring, callables, default = load_fabfile(fabfile)
            state.commands.update(callables)

        # Handle case where we were called bare, i.e. just "fab", and print
        # a help message.
        actions = (options.list_commands, options.shortlist, options.display,
            arguments, remainder_arguments, default)
        if not any(actions):
            parser.print_help()
            sys.exit(1)

        # Abort if no commands found
        if not state.commands and not remainder_arguments:
            abort("Fabfile didn't contain any commands!")

        # Now that we're settled on a fabfile, inform user.
        if state.output.debug:
            if fabfile:
                print("Using fabfile '%s'" % fabfile)
            else:
                print("No fabfile loaded -- remainder command only")

        # Shortlist is now just an alias for the "short" list format;
        # it overrides use of --list-format if somebody were to specify both
        if options.shortlist:
            options.list_format = 'short'
            options.list_commands = True

        # List available commands
        if options.list_commands:
            print("\n".join(list_commands(docstring, options.list_format)))
            sys.exit(0)

        # Handle show (command-specific help) option
        if options.display:
            display_command(options.display)

        # If user didn't specify any commands to run, show help
        if not (arguments or remainder_arguments or default):
            parser.print_help()
            sys.exit(0)  # Or should it exit with error (1)?

        # Parse arguments into commands to run (plus args/kwargs/hosts)
        commands_to_run = parse_arguments(arguments)

        # Parse remainders into a faux "command" to execute
        remainder_command = parse_remainder(remainder_arguments)

        # Figure out if any specified task names are invalid
        unknown_commands = []
        for tup in commands_to_run:
            if crawl(tup[0], state.commands) is None:
                unknown_commands.append(tup[0])

        # Abort if any unknown commands were specified
        if unknown_commands:
            abort("Command(s) not found:\n%s" \
                % indent(unknown_commands))

        # Generate remainder command and insert into commands, commands_to_run
        if remainder_command:
            r = '<remainder>'
            state.commands[r] = lambda: api.run(remainder_command)
            commands_to_run.append((r, [], {}, [], [], []))

        # Ditto for a default, if found
        if not commands_to_run and default:
            commands_to_run.append((default.name, [], {}, [], [], []))

        if state.output.debug:
            names = ", ".join(x[0] for x in commands_to_run)
            print("Commands to run: %s" % names)

        # At this point all commands must exist, so execute them in order.
        for name, args, kwargs, cli_hosts, cli_roles, cli_exclude_hosts in commands_to_run:
            # Get callable by itself
            task = crawl(name, state.commands)
            # Set current task name (used for some error messages)
            state.env.command = name
            # Set host list (also copy to env)
            state.env.all_hosts = hosts = get_hosts(
                task, cli_hosts, cli_roles, cli_exclude_hosts)
            # If hosts found, execute the function on each host in turn
            for host in hosts:
                # Preserve user
                prev_user = state.env.user
                # Split host string and apply to env dict
                username, hostname, port = interpret_host_string(host)
                # Log to stdout
                if state.output.running:
                    print("[%s] Executing task '%s'" % (host, name))
                # Actually run command
                _run_task(task, args, kwargs)
                # Put old user back
                state.env.user = prev_user
            # If no hosts found, assume local-only and run once
            if not hosts:
                _run_task(task, args, kwargs)
        # If we got here, no errors occurred, so print a final note.
        if state.output.status:
            print("\nDone.")
    except SystemExit:
        # a number of internal functions might raise this one.
        raise
    except KeyboardInterrupt:
        if state.output.status:
            print >> sys.stderr, "\nStopped."
        sys.exit(1)
    except:
        sys.excepthook(*sys.exc_info())
        # we might leave stale threads if we don't explicitly exit()
        sys.exit(1)
    finally:
        disconnect_all()
    sys.exit(0)


N = int(input())
N+=1
for j in range(1,N):
    value = int(input())
    sum = 0
    for i in range(1, value+1): # Para i em uma distância de 1 a num + 1.
        if value % i == 0: # Se houver divisores sem resto, entre neste bloco e adicione +1 na variável sum.
            sum += 1
    if sum == 2: # Ao sair do laço for, verifique se sum é igual a 2. (Número divisivel por 1 e por ele mesmo).
        print(value,"eh primo")
    else: # Se for maior ou menor que 2, diga que não é primo.
        print(value,"nao eh primo")


import pandas as pd

df = pd.read_csv("/Users/mona/Downloads/finalized_gv_ih_master_updated.csv")

frame9_text = ''

for i in range(df.shape[0]):
    #if df.iloc[i]['Q3 Theme'] == 9:
    frame9_text += df.iloc[i]['news_title']

print(frame9_text)

import collections
import pandas as pd
from nltk.stem import PorterStemmer
ps = PorterStemmer()
import nltk
lemma = nltk.wordnet.WordNetLemmatizer()

import matplotlib.pyplot as plt
# Read input file, note the encoding is specified here
# It may be different in your text file

# Stopwords
stopwords = set(line.strip() for line in open('stopwords.txt'))
stopwords = stopwords.union(set(['mr','mrs','one','two','said']))
# Instantiate a dictionary, and for every word in the file,
# Add to the dictionary if it doesn't exist. If it does, increase the count.
wordcount = {}
# To eliminate duplicates, remember to split by punctuation, and use case demiliters.
for word in frame9_text.lower().split():
    word = word.replace(".","")
    word = word.replace(",","")
    word = word.replace(":","")
    word = word.replace("\"","")
    word = word.replace("!","")
    word = word.replace("â€œ","")
    word = word.replace("â€˜","")
    word = word.replace("*","")
    if lemma.lemmatize(word) not in stopwords:
        if lemma.lemmatize(word) not in wordcount:
            #wordcount[ps.stem(word)] = 1
            wordcount[lemma.lemmatize(word)] = 1
        else:
            wordcount[lemma.lemmatize(word)] += 1
# Print most common word
n_print = int(input("How many most common words to print: "))
print("\nOK. The {} most common words are as follows\n".format(n_print))
word_counter = collections.Counter(wordcount)
for word, count in word_counter.most_common(n_print):
    print(word, ": ", count)
# Close the file

# Create a data frame of the most common words
# Draw a bar chart
lst = word_counter.most_common(n_print)
df = pd.DataFrame(lst, columns = ['Word', 'Count'])
df.plot.bar(x='Word',y='Count')


"""
698. Partition to K Equal Sum Subsets
Given an integer array nums and an integer k, return true if it is possible to divide this array into k non-empty subsets whose sums are all equal.

Example1:
Input: nums = [4,3,2,3,5,2,1], k = 4
Output: true
Explanation: It is possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums.

Example2:
Input: nums = [1,2,3,4], k = 3
Output: false

Constraints:
1 <= k <= <= nums.length <= 16
1 <= nums[i] <= 10^4
The frequency of each element is in the range [1, 4].
"""

"""
Note:
1. DFS (Top Down) + Backtracking: O(n * n!) time | O(n) space
2. DFS (Bottom Up) + Backtracking + memo: O(klogk * k**n) | O(kn) space
"""

from typing import List
class Solution:
    def canPartitionKSubsets(self, nums: List[int], k: int) -> bool:
        total = sum(nums)
        if total % k != 0:
            return False

        target = total // k

        n = len(nums)
        visited = [False] * n

        nums.sort(reverse=True)
        def dfs(i, currentSum, k, visited) -> bool:
            if k == 1:
                return True
            for j in range(i, n):
                if visited[j]:
                    continue

                if currentSum + nums[j] > target:
                    break

                visited[j] = True
                if currentSum + nums[j] == target:
                    if dfs(0, 0, k-1, visited):
                        return True
                else:
                    if dfs(0, currentSum+nums[j], k, visited):
                        return True
                visited[j] = False

            return False
        return dfs(0, 0, k, visited)

    def canPartitionKSubsets2(self, nums: List[int], k: int) -> bool:
        total = sum(nums)
        if total % k != 0:
            return False

        buckets = [total // k] * k
        nums.sort(reverse=True)

        memo = {}
        def dfs(i, buckets, totalSum):
            key = (str(sorted(buckets)), i)
            if key in memo:
                return memo[key]
            if totalSum == 0:
                memo[key] = True
                return memo[key]

            num = nums[i]
            for j in range(k):
                if buckets[j] - num < 0:
                    continue
                buckets[j] -= num
                if dfs(i+1, buckets, totalSum - num):
                    memo[key] = True
                    return memo[key]
                buckets[j] += num

            memo[key] = False
            return memo[key]
        return dfs(0, buckets, total)

# Unit Tests
import unittest
funcs = [Solution().canPartitionKSubsets, Solution().canPartitionKSubsets2]

class TestCanPartitionKSubsets(unittest.TestCase):
    def testCanPartitionKSubsets1(self):
        for func in funcs:
            nums = [4,3,2,3,5,2,1]
            k = 4
            self.assertEqual(func(nums=nums, k=k), True)

    def testCanPartitionKSubsets2(self):
        for func in funcs:
            nums = [1,2,3,4]
            k = 3
            self.assertEqual(func(nums=nums, k=k), False)

    def testCanPartitionKSubsets3(self):
        for func in funcs:
            nums = [1,1,1,1,2,2,2,2]
            k = 4
            self.assertEqual(func(nums=nums, k=k), True)

if __name__ == "__main__":
    unittest.main()


from __future__ import print_function
import os
import os.path as osp
from scipy import io
import datetime
import time

def time_str(fmt=None):
    if fmt is None:
        fmt = '%Y-%m-%d_%H:%M:%S'
    return datetime.datetime.today().strftime(fmt)

def save_mat(ndarray, path):
    """Save a numpy ndarray as .mat file."""
    io.savemat(path, dict(ndarray=ndarray))

def may_make_dir(path):
    """
    Args:
      path: a dir, or result of `osp.dirname(osp.abspath(file_path))`
    Note:
      `osp.exists('')` returns `False`, while `osp.exists('.')` returns `True`!
    """
    # This clause has mistakes:
    # if path is None or '':

    if path in [None, '']:
        return
    if not osp.exists(path):
        os.makedirs(path)

class AverageMeter(object):
    """Modified from Tong Xiao's open-reid.
    Computes and stores the average and current value"""

    def __init__(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = float(self.sum) / (self.count + 1e-20)

class RunningAverageMeter(object):
    """Computes and stores the running average and current value"""

    def __init__(self, hist=0.99):
        self.val = None
        self.avg = None
        self.hist = hist

    def reset(self):
        self.val = None
        self.avg = None

    def update(self, val):
        if self.avg is None:
            self.avg = val
        else:
            self.avg = self.avg * self.hist + val * (1 - self.hist)
        self.val = val

class RecentAverageMeter(object):
    """Stores and computes the average of recent values."""

    def __init__(self, hist_size=100):
        self.hist_size = hist_size
        self.fifo = []
        self.val = 0

    def reset(self):
        self.fifo = []
        self.val = 0

    def update(self, val):
        self.val = val
        self.fifo.append(val)
        if len(self.fifo) > self.hist_size:
            del self.fifo[0]

    @property
    def avg(self):
        assert len(self.fifo) > 0
        return float(sum(self.fifo)) / len(self.fifo)

class ReDirectSTD(object):
    """Modified from Tong Xiao's `Logger` in open-reid.
    This class overwrites sys.stdout or sys.stderr, so that console logs can
    also be written to file.
    Args:
      fpath: file path
      console: one of ['stdout', 'stderr']
      immediately_visible: If `False`, the file is opened only once and closed
        after exiting. In this case, the message written to file may not be
        immediately visible (Because the file handle is occupied by the
        program?). If `True`, each writing operation of the console will
        open, write to, and close the file. If your program has tons of writing
        operations, the cost of opening and closing file may be obvious. (?)
    Usage example:
      `ReDirectSTD('stdout.txt', 'stdout', False)`
      `ReDirectSTD('stderr.txt', 'stderr', False)`
    NOTE: File will be deleted if already existing. Log dir and file is created
      lazily -- if no message is written, the dir and file will not be created.
    """

    def __init__(self, fpath=None, console='stdout', immediately_visible=False):
        import sys
        import os
        import os.path as osp

        assert console in ['stdout', 'stderr']
        self.console = sys.stdout if console == 'stdout' else sys.stderr
        self.file = fpath
        self.f = None
        self.immediately_visible = immediately_visible
        if fpath is not None:
            # Remove existing log file.
            if osp.exists(fpath):
                os.remove(fpath)

        # Overwrite
        if console == 'stdout':
            sys.stdout = self
        else:
            sys.stderr = self

    def __del__(self):
        self.close()

    def __enter__(self):
        pass

    def __exit__(self, *args):
        self.close()

    def write(self, msg):
        self.console.write(msg)
        if self.file is not None:
            may_make_dir(os.path.dirname(osp.abspath(self.file)))
            if self.immediately_visible:
                with open(self.file, 'a') as f:
                    f.write(msg)
            else:
                if self.f is None:
                    self.f = open(self.file, 'w')
                self.f.write(msg)

    def flush(self):
        self.console.flush()
        if self.f is not None:
            self.f.flush()
            import os
            os.fsync(self.f.fileno())

    def close(self):
        self.console.close()
        if self.f is not None:
            self.f.close()