"""This module encapsulates the pyodine system state into a runlevel scheme.

This somewhat mixes the model and controller into one module, what leads to
some gnarly problems with circular imports...
"""

import asyncio
import enum
from functools import partial
import logging
from typing import Awaitable, List, Tuple  # pylint: disable=unused-import
from . import procedures as proc
from . import daemons, subsystems
from .lock_buddy import LockStatus
from .. import constants as cs
from ..pyodine_globals import (GLOBALS as GL, REQUEST, validate_request, is_shaky)
from ..drivers.ecdl_mopa import LaserState
from ..util import asyncio_tools as tools

LOGGER = logging.getLogger('runlevels')  # type: logging.Logger

class Runlevel(enum.IntEnum):
    """The incremental pyodine system state.

    There are eight possible states (including "undefined") which conveniently
    projects onto a three-bit state register.
    """
    UNDEFINED = 0  # 0 0 0
    """Not clearly in one of the other states.

    The system could currently be transitioning.  This can not be used to
    request a runstate.
    """
    SHUTDOWN = 1  # 1 0 0
    """The system is ordered to prepare for physical power-off.

    Even when requested, the system will never report being in this state.  It
    will just keep on maintaining a state as safe as possible for power-off.
    """
    STANDBY = 2  # 0 1 0
    """The system is on stand by and ready.

    Cold subsystems tests have been conducted sucessfully.  System is
    reasonably safe to switch off, although the specific measures being done
    for `SHUTDOWN` are omitted.
    """
    AMBIENT = 3  # 1 1 0
    """System is thermalized to ambient temperatures and ready to heat up.

    Although the system will eventually report being `AMBIENT` on reaching this
    level, due to changing ambient temperatures it is necessary to keep
    actively pursuing this level.  The system may drop to `UNDEFINED`
    occasionally if such drifts happen.
    """
    HOT = 4  # 0 0 1
    """All components are brought to their working temperature. Light is on!

    For tunable components (MiOB!) the full tuning range is considered valid.

    The laser is running at it's working point.  Delaying the laser power-up
    procedure until the `PRELOCK` level would lead to laser-induced temperature
    drifts at the beginning of that level.
    """
    PRELOCK = 5  # 1 0 1
    """The correct spectral line was found; system is ready to lock."""
    LOCK = 6  # 0 1 1
    """The system is locked on (the correct) HFS line.

    Relocker and first-order balancer are active."""
    BALANCED = 7  # 1 1 1
    """The working point is aligned, tuners have maximum range of motion.

    In addition to level 6, the second-order balancer is active.
    """

async def get_level() -> Runlevel:
    """Determine current runlevel."""
    try:
        tec = await proc.get_tec_status()  # type: proc.TecStatus
    except proc.TecError:
        LOGGER.error("Couldn't get TEC status")
        LOGGER.debug("Couldn't get TEC status", exc_info=True)
        return Runlevel.UNDEFINED

    laser = GL.subs.laser.get_state()  # LaserState

    if tec == proc.TecStatus.OFF and laser == LaserState.OFF:
        return Runlevel.STANDBY

    if tec == proc.TecStatus.AMBIENT and laser == LaserState.OFF:
        return Runlevel.AMBIENT

    if tec == proc.TecStatus.HOT and laser == LaserState.ON:
        if daemons.is_running(daemons.Service.DRIFT_COMPENSATOR):
            return Runlevel.BALANCED

        if daemons.is_running(daemons.Service.LOCKER):
            return Runlevel.LOCK

        if daemons.is_running(daemons.Service.PRELOCKER):
            return Runlevel.PRELOCK

        return Runlevel.HOT

    return Runlevel.UNDEFINED

@tools.static_variable('last_level', 0)
async def get_reported_level() -> Tuple[Runlevel, bool]:
    """
    :returns: A tuple like (<most recent valid runlevel>,
                            <current runlevel is undefined>).
    """
    current_level = await get_level()
    if current_level == Runlevel.UNDEFINED:
        return (get_reported_level.last_level, True)  # type: ignore
    get_reported_level.last_level = current_level  # type: ignore
    return (current_level, False)

async def pursue_ambient() -> None:
    """Kick-off changes that get the system closer to Runlevel.AMBIENT."""
    LOGGER.debug('Pursuing "AMBIENT" runlevel.')
    jobs = []  # type: List[Awaitable[None]]
    jobs.append(proc.release_lock())
    jobs.append(proc.laser_power_down())
    jobs.append(proc.pursue_tec_ambient())
    await asyncio.wait(jobs, timeout=cs.RUNLEVEL_PURSUE_KICKOFF_TIMEOUT)

async def pursue_balanced() -> None:
    """Kick-off changes that get the system closer to Runlevel.BALANCED. """
    LOGGER.debug('Pursuing "BALANCED" runlevel.')
    if daemons.is_running(daemons.Service.LOCKER):
        if daemons.is_running(daemons.Service.DRIFT_COMPENSATOR):
            LOGGER.debug("Drift compensator is already running.")
        else:
            daemons.register(daemons.Service.DRIFT_COMPENSATOR,
                             GL.loop.create_task(proc.compensate_temp_drifts()))
    else:
        await pursue_lock()

async def pursue_hot() -> None:
    """Kick-off changes that get the system closer to Runlevel.HOT."""
    LOGGER.debug('Pursuing "HOT" runlevel.')
    daemons.cancel(daemons.Service.PRELOCKER)
    jobs = []  # type: List[Awaitable[None]]
    jobs.append(proc.pursue_tec_hot())
    jobs.append(proc.laser_power_up())
    jobs.append(proc.release_lock())
    await asyncio.wait(jobs, timeout=cs.RUNLEVEL_PURSUE_KICKOFF_TIMEOUT)

async def pursue_lock() -> None:
    """Kick-off changes that get the system closer to Runlevel.LOCK."""
    LOGGER.debug('Pursuing "LOCK" runlevel.')
    daemons.cancel(daemons.Service.DRIFT_COMPENSATOR)
    # Prelocker is cancelled in `pursue_runlevel()`.
    if daemons.is_running(daemons.Service.LOCKER):
        LOGGER.debug("Currently locked.  Doing nothing.")
        return
    daemons.register(daemons.Service.LOCKER,
                     GL.loop.create_task(_lock_runner()))
    jobs = []  # type: List[Awaitable[None]]
    jobs.append(proc.pursue_tec_hot())
    jobs.append(proc.laser_power_up())
    jobs.append(proc.release_lock())
    await asyncio.wait(jobs, timeout=cs.RUNLEVEL_PURSUE_KICKOFF_TIMEOUT)

async def pursue_prelock() -> None:
    """Kick-off changes that get the system closer to Runlevel.PRELOCK."""
    LOGGER.debug('Pursuing "PRELOCK" runlevel.')
    jobs = []  # type: List[Awaitable[None]]
    jobs.append(proc.pursue_tec_hot())
    jobs.append(proc.laser_power_up())
    jobs.append(proc.release_lock())

    # Try to invoke prelocker.  As with the other procedures above, this might
    # fail depending on the system state.  But as we don't know which try will
    # eventually succeed, we're registering our attempt with the daemons
    # registry.
    if not daemons.is_running(daemons.Service.PRELOCKER):
        daemons.register(daemons.Service.PRELOCKER,
                         GL.loop.create_task(_prelock_runner()))
        # NOTE: The daemon is cancelled upstream, in `pursue_runlevel()`.
    await asyncio.wait(jobs, timeout=cs.RUNLEVEL_PURSUE_KICKOFF_TIMEOUT)

async def pursue_runlevel() -> None:
    """Kick off changes getting the system closer to the requested runlevel.

    This can (and needs to be) called multiple times, usually until the desired
    runlevel is reached.

    This method might still raise errors, but it is of uttermost importance
    that the loop this is called in will catch anything, because if that loop
    fails, the system will be unresponsive to TEXUS runlevel requests.

    :param level: The level to aspire to.
    :raises Exception: This might raise close to anything.  Be sure to catch
                it.  This would not usually be a good practice, but in this
                case, a stable program is preferrable to a debuggable one.
    """
    level = REQUEST.level
    LOGGER.debug("pursue_runlevel(%s) called.", level)

    # This avoids having to add these lines to all the pursue_  functions().
    if level != Runlevel.PRELOCK:
        daemons.cancel(daemons.Service.PRELOCKER)
    if level != Runlevel.BALANCED:
        daemons.cancel(daemons.Service.DRIFT_COMPENSATOR)

    if REQUEST.off:
        await pursue_shutdown()
        return

    if level == Runlevel.UNDEFINED:
        LOGGER.warning("Runlevel `UNDEFINED` must not be requested.")
    elif level == Runlevel.SHUTDOWN:
        await pursue_shutdown()
    elif level == Runlevel.STANDBY:
        await pursue_standby()
    elif level == Runlevel.AMBIENT:
        await pursue_ambient()
    elif level == Runlevel.HOT:
        await pursue_hot()
    elif is_shaky():
        LOGGER.debug("Won't pursue any runlevel higher than HOT in a shaky system.")
        return
    elif level == Runlevel.PRELOCK:
        await pursue_prelock()
    elif level == Runlevel.LOCK:
        await pursue_lock()
    elif level == Runlevel.BALANCED:
        await pursue_balanced()
    else:
        raise ValueError("Unknown runlevel {}.".format(repr(level)))

async def pursue_shutdown() -> None:
    await pursue_standby()  # TODO: flush files etc.

async def pursue_standby() -> None:
    """Kick-off changes that get the system closer to Runlevel.STANDBY."""
    LOGGER.debug('Pursuing "STANDBY" runlevel.')
    current = await get_level()
    if current == Runlevel.STANDBY:
        LOGGER.debug("Already on STANDBY.")
        return
    if current == Runlevel.AMBIENT:
        LOGGER.debug("System is AMBIENT, going to STANDBY now.")
        await proc.tec_off()
    else:
        await pursue_ambient()

async def start_runner() -> None:
    """Start the runlevel-pursuing runner task.

    Start continuously synchronizing system state with requested state.

    :raises RuntimerError: Globals weren't fully set.
    """
    validate_request()  # raises
    if daemons.is_running(daemons.Service.RUNLEVEL):
        LOGGER.info("Runlevel runner is already running. -.- ")
        return

    LOGGER.info("Started runlevel runner task.")
    daemons.register(daemons.Service.RUNLEVEL, GL.loop.create_task(
        tools.repeat_task(pursue_runlevel,
                          min_wait_time=cs.RUNLEVEL_REFRESH_INTERVAL)))

async def stop_runner() -> None:
    """Stop the runlevel-pursuing runner task."""
    daemons.cancel(daemons.Service.RUNLEVEL)

async def _lock_runner() -> None:
    """The continuous lock maintenance runner.

    This will start prelock again, if lock is lost.
    """
    if await GL.locker.get_lock_status() != LockStatus.ON_LINE:
        LOGGER.info("Running prelock for lock.")
        await proc.prelock(subsystems.Tuners.MO)  # raises on failure
        LOGGER.info("Engaging lock.")
        await GL.locker.engage_and_maintain()
        LOGGER.info("Failed lock.")

async def _prelock_runner() -> None:
    """The continuous prelock-only runner."""
    # Repeat prelock process some seconds after it has completed.
    await tools.repeat_task(partial(proc.prelock, subsystems.Tuners.MO),
                            min_wait_time=cs.PRELOCK_REST_PERIOD)


# 条件运算符（三元运算符）
# 语法： 语句1 if 条件表达式 else 语句2
# 执行流程：
#   条件运算符在执行时，会先对条件表达式进行求值判断
#       如果判断结果为True，则执行语句1，并返回执行结果
#       如果判断结果为False，则执行语句2，并返回执行结果
# 练习：
#   现在有a b c三个变量，三个变量中分别保存有三个数值，
#       请通过条件运算符获取三个值中的最大值

# print('你好') if False else print('Hello')

a = 30
b = 50

# print('a的值比较大！') if a > b else print('b的值比较大！')
# 获取a和b之间的较大值
max = a if a > b else b

print(max)


import argparse
import random, string
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
from mpl_toolkits.mplot3d import Axes3D

# GaussianMixtureModel with EM algorithm
class GMM:
        def __init__(self, k, max_iteration, eps=0.1):
                self.k = k
                self.max_iteration = max_iteration
                self.eps = eps

        # learn parameters and output Posterior probabilities
        def fit_predict(self, X):
                n, d = X.shape

                # init parameters
                self.mu = np.random.randn(self.k, d)
                self.sigma = np.array([np.eye(d) for _ in range(self.k)])
                self.pi = np.array([1 / self.k for _ in range(self.k)])

                # iterate 'E' and 'M' step
                old_likelihood = self.likelihood(X)
                for _ in range(self.max_iteration):
                        self.e_step(X)
                        self.m_step(X)

                        next_likelihood = self.likelihood(X)
                        if np.abs(next_likelihood - old_likelihood) < self.eps:
                                break
                        else:
                                print("likelihood: " + str(next_likelihood))
                                old_likelihood = next_likelihood

                params = {
                        'mu'   : self.mu,
                        'sigma': self.sigma,
                        'pi'   : self.pi,
                }

                return self.gamma, params

        # only learn parameters
        def fit(self, X):
                self.fit_predict(X)

        # the 'E' step of EM algorithm
        def e_step(self, X):
                n, d = X.shape

                self.gamma = np.zeros((self.k, n))
                for i in range(self.k):
                        rv = multivariate_normal(self.mu[i], self.sigma[i])
                        self.gamma[i] = self.pi[i] * rv.pdf(X)

                self.gamma = self.gamma.T
                for i in range(n):
                        self.gamma[i] = self.gamma[i] / np.sum(self.gamma[i])

        # the 'M' step of EM algorithm
        def m_step(self, X):
                n, d = X.shape
                n_k = np.sum(self.gamma, axis=0)

                # calculate next 'mu'
                for i in range(self.k):
                        t = np.zeros(d)
                        for j in range(n):
                                t += self.gamma[j][i] * X[j];
                        self.mu[i] = t / n_k[i]

                # calculate next 'sigma'
                for i in range(self.k):
                        t = np.zeros((d, d))
                        for j in range(n):
                                t += self.gamma[j][i] * (X[j] - self.mu[i])[:,None] @ (X[j] - self.mu[i])[:,None].T
                        self.sigma[i] = t / n_k[i]

                # calculate next 'pi'
                self.pi = n_k / n

        # calculate the log likelihood
        def likelihood(self, X):
                n, d = X.shape

                l = 0
                for j in range(n):
                        t = 0
                        for i in range(self.k):
                                rv = multivariate_normal(self.mu[i], self.sigma[i])
                                t += self.pi[i] * rv.pdf(X[j])

                        l += np.log(t)

                return l

        def n_parameters(self):
                _, d = self.mu.shape
                cov_params = self.k * d * (d + 1) / 2
                mu_params  = self.k * d
                pi_params  = self.k - 1

                return cov_params + mu_params + pi_params

        def aic(self, X):
                return -2 * (self.likelihood(X) - self.n_parameters())

if __name__ == "__main__":
        # prepare argparser and parse commandline options
        parser = argparse.ArgumentParser()
        parser.add_argument("src", help="src csv file name")
        parser.add_argument("dst", help="dst csv file name")
        parser.add_argument("params", help="params file name")
        parser.add_argument("-f", "--figure", help="output figure", action="store_true")
        args = parser.parse_args()

        # read csv and learn
        dat = pd.read_csv(args.src, header=None).values
        gmm = GMM(k=4, max_iteration=100)
        res, params = gmm.fit_predict(dat)
        print("AIC: " + str(gmm.aic(dat)))

        # output result csv and params dat
        pd.DataFrame(res).to_csv(
                args.dst,
                header=False,
                index=False,
        )

        open(args.params, mode='w').close()
        with open(args.params, mode='a') as f:
                np.savetxt(f, params['mu'], header='mu')
                for i in range(len(params['sigma'])):
                        np.savetxt(f, params['sigma'][i], header='sigma' + str(i))
                np.savetxt(f, params['pi'], header='pi')

        # if --figure is set, then output the graph
        if args.figure:
                fig = plt.figure()
                ax = Axes3D(fig)

                ind = res.argmax(axis=1)
                cm = plt.get_cmap("tab10")
                for i in range(dat.shape[0]):
                        ax.plot([dat[i][0]], [dat[i][1]], [dat[i][2]], "o", color=cm(ind[i]), ms=1)

                ax.view_init(elev=30, azim=45)
                plt.savefig("".join(random.choices(string.ascii_letters, k=10)) + ".png")
                plt.show()


# Local
import database.db_config as config
from database import db_manager

from flask import Blueprint, jsonify, request
from flask_http_response import error, success

def initDb():
    dbManager = db_manager.DbManager(
        config.dbConfig["user"],
        config.dbConfig["password"],
        config.dbConfig["host"],
        config.dbConfig["port"],
        config.dbConfig["database"]
    )
    return dbManager

alertProtocol = Blueprint("alertProtocol", __name__)

# GET ALL

@alertProtocol.route('/', methods=['GET'])
def apiGetProtocolAlerts():
    req = "SELECT * FROM ProtocolAlert"
    params = []
    dbManager = initDb()
    data = dbManager.queryGet(req, params)
    objects_list = []
    for row in data:
        d = {}
        d["id"] = row[0]
        d["level"] = row[1]
        d["date"] = row[2]
        d["type"] = row[3]
        d["description"] = row[4]
        d["idFrame"] = row[5]
        objects_list.append(d)
    dbManager.close()
    if(len(objects_list) == 1):
        return jsonify(objects_list[0])
    else:
        return jsonify(objects_list)

# GET ALL BASED ON FRAME

@alertProtocol.route('/', methods=['GET'])
@alertProtocol.route('/<id>', methods=['GET'])
def apiGetProtocolAlertsId(id=None):
    dbManager = initDb()
    data = dbManager.queryGet(
        "SELECT * FROM ProtocolAlert WHERE idFrame = ?", [id])
    objects_list = []
    for row in data:
        d = {}
        d["id"] = row[0]
        d["level"] = row[1]
        d["date"] = row[2]
        d["type"] = row[3]
        d["description"] = row[4]
        d["idFrame"] = row[5]
        objects_list.append(d)
    dbManager.close()
    if(len(objects_list) == 1):
        return jsonify(objects_list[0])
    else:
        return jsonify(objects_list)

# POST

@alertProtocol.route('/', methods=['POST'])
def apiPostProtocolAlert():
    if request.json:
        dbManager = initDb()
        alert = request.get_json()

        # Check every key and its value
        if "level" not in alert or alert["level"] == "":
            alert["level"] = None

        if "date" not in alert or alert["date"] == "":
            alert["date"] = None

        if "type" not in alert or alert["type"] == "":
            alert["type"] = None

        if "description" not in alert or alert["description"] == "":
            alert["description"] = None

        if "idFrame" not in alert or alert["idFrame"] == "":
            alert["idFrame"] = None

        dbManager.queryInsert("INSERT INTO `ProtocolAlert` (`level`, `date`, `type`, `description`, `idFrame`) VALUES (?, ?, ?, ?, ?)",
                              [
                                  alert["role"],
                                  alert["idNetwork"],
                                  alert["macAddr"],
                                  alert["ipAddr"],
                                  alert["securityScore"]
                              ])
        dbManager.close()
        return success.return_response(status=201, message="Alert added successfully")
    else:
        return error.return_response(status=400, message="Need JSON data")

# DELETE

@alertProtocol.route('/', methods=['DELETE'])
@alertProtocol.route('/<id>', methods=['DELETE'])
def apiDeleteProtocolAlert(id=None):
    return 0


# Сколько шестибуквенных слов можно составить, начинающихся и заканчивающихся согласной буквой и содержащих 2 гласные?
# Из букв ТЫКВА. Каждая из допустимых букв может входить в слово несколько раз

count = 0

for b1 in 'ТЫКВА':
    for b2 in 'ТЫКВА':
        for b3 in 'ТЫКВА':
            for b4 in 'ТЫКВА':
                for b5 in 'ТЫКВА':
                    for b6 in 'ТЫКВА':
                        res = b1 + b2 + b3 + b4 + b5 + b6
                        if res[0] in 'ТКВ' and res[-1] in 'ТКВ':
                            if res.count('Ы') +  res.count('А') == 2:
                                print(res)
                                count += 1

print(f'Найдено {count} слова')


#!/usr/local/bin/python3

import math

def sum_digit(n):
    l = []
    for i in range(len(str(n))):
        l.append(str(n)[i])
    s = 0
    for i in l:
        s += int(i)
    return s

if __name__ == '__main__':
    num = math.factorial(100)
    l = sum_digit(num)
    print(l)


# Cellular automaton simulation with different rules
import copy
import os
import random
import shutil
import sys
import time

from PIL import Image, ImageDraw, ImageFont

class Board():
    _SLEEP_TIME_MAX = 1
    _FLICKER_MODES = 3 + 1
    _CSI = '\x1B['
    _COLORS = {
        0: '48;1m',
        1: '107;1m',
    }

    def __init__(self, w, h, rule_string, tiles=None, subtitle_format=None, flicker_mode=0, tick=0, random_state=True,
                 state=False, seed='-1', max_ticks=None, spans_render_image=None, image_dir=None,
                 image_format=None, image_zoom=None, font_size=None, font_path=None, fill_percentage=0.5,
                 render_ticks=1, paused=False, no_expand=False, post_rule_string=None, post_ticks=0):
        self.rules, self.rule_string = Board.parse_rules(rule_string)
        if tiles is None or not tiles:
            self.tiles = False
        else:
            self.tiles = {
                0: tiles[0],
                1: tiles[1],
            }
        self.fill_percentage = fill_percentage
        if not state:
            if seed == '-1':
                seed = ''.join(random.sample([chr(i + 65) for i in list(range(26))], 5))
            self.seed = seed
            random.seed(self.seed)
        self.w = w
        self.h = h
        if not state:
            self.board = [[0] * self.w for i in range(self.h)]
            if random_state:
                self.init_random_state()
        else:
            state_w = len(state[0])
            state_h = len(state)
            if state_w < w and state_h < h and not no_expand:
                self.board = Board.expand_state(state, w, h)
            else:
                self.w = state_w
                self.h = state_h
                self.board = state
            self.seed = f'{seed}?'
        self.flicker_mode = flicker_mode
        self.flicker_mode %= self._FLICKER_MODES
        self.tick = tick
        self.max_ticks = max_ticks
        self.cells_alive_old = self.cells_alive
        self.cells_dead_old = self.cells_total - self.cells_alive_old
        if spans_render_image:
            self.ticks_render_image = self.parse_ranges(spans_render_image)
        else:
            self.ticks_render_image = None
        if image_dir:
            self.image_dir = image_dir
            try:
                os.mkdir(self.image_dir)
            except FileExistsError:
                pass
        self.subtitle_format = subtitle_format
        self.image_format = image_format
        if image_zoom:
            self.image_zoom = int(image_zoom)
        if font_size and font_path and font_size:
            self.font_size = font_size
            self.font_path = font_path
            try:
                self.font = ImageFont.truetype(self.font_path, self.font_size)
            except OSError:
                if spans_render_image:
                    print(f"You're missing the selected font '{self.font_path}'. Rendering may look awkward...")
                self.font = ImageFont.load_default()
        self.render_ticks = render_ticks
        self.paused = paused
        self.post_ticks = post_ticks
        if post_rule_string and post_ticks > 0:
            self.post_rules, self.post_rule_string = Board.parse_rules(post_rule_string)
            self.board_post = self.post_process(post_rule_string, self.post_ticks)

    def init_random_state(self):
        for y in range(self.h):
            for x in range(self.w):
                self.board[y][x] = 1 if random.random() > self.fill_percentage else 0

    def draw(self, invert=False):
        if self.paused:
            time.sleep(self._SLEEP_TIME_MAX)
            return
        if self.tick % self.render_ticks != 0 or self.tick < 0:
            return
        inverted = self.inverted
        if self.post_ticks > 0:
            board = self.board_post
        else:
            board = self.board
        for y in range(self.h):
            for x in range(self.w):
                v = board[y][x]
                if inverted:
                    v = 1 - v
                if not self.tiles:
                    c = self._COLORS[v]
                    print(f'{self._CSI}{c} {self._CSI}0m', end='')
                else:
                    print(self.tiles[board[y][x]], end='')
            print()
        print()
        if self.subtitle_format:
            print(self.subtitle)

    def step(self):
        if self.paused:
            time.sleep(self._SLEEP_TIME_MAX)
            return
        board_next = copy.deepcopy(self.board)
        for y in range(self.h):
            for x in range(self.w):
                n = self.neighbours(x, y)
                alive = self.board[y][x]
                flip_alive, flip_dead = self.rules[self.tick % len(self.rules)][n]
                if not alive and flip_dead:
                    board_next[y][x] = 1
                if alive and flip_alive:
                    board_next[y][x] = 0
        self.board = board_next
        self.tick += 1
        if self.post_ticks > 0:
            self.board_post = self.post_process(self.post_rule_string, self.post_ticks)
        self.render_image()

    def neighbours(self, x_cen, y_cen):
        s = 0
        for y in range(y_cen - 1, y_cen + 2):
            while y < 0:
                y += self.h
            if y > self.h - 1:
                y %= self.h
            for x in range(x_cen - 1, x_cen + 2):
                if x == x_cen and y == y_cen:
                    continue
                while x < 0:
                    x += self.w
                if x > self.w - 1:
                    x %= self.w
                if self.board[y][x]:
                    s += 1
        return s

    def board_serialize(self, prefix_param=False):
        if prefix_param:
            board_serial = '-b '
        else:
            board_serial = ''
        for y in range(self.h):
            for x in range(self.w):
                board_serial += str(self.board[y][x])
            board_serial += '.'
        return board_serial[:-1]

    def __str__(self):
        return self.subtitle

    def render_image(self):
        if self.paused:
            time.sleep(self._SLEEP_TIME_MAX)
            return
        if not self.ticks_render_image or self.tick not in self.ticks_render_image:
            return
        image_file = self.parse_format(self.image_format)
        image_path = f'{self.image_dir}/{image_file}'
        image_dir = '/'.join(image_path.split('/')[:-1])
        try:
            os.mkdir(image_dir)
        except FileExistsError:
            pass
        z = self.image_zoom
        offset = 0 if self.subtitle_format is None else self.font_size
        im = Image.new('1', (self.w * z, self.h * z + offset), 0)
        draw = ImageDraw.Draw(im)
        inverted = self.inverted
        if self.post_ticks > 0:
            board = self.board_post
        else:
            board = self.board
        for y in range(self.h):
            for x in range(self.w):
                if inverted and not board[y][x] or (not inverted and board[y][x]):
                    draw.rectangle([(x * z, y * z), ((x + 1) * z - 1, (y + 1) * z - 1)], 1)
        if self.subtitle_format is not None:
            draw.text([0, (self.h) * z - self.font_size / 4], self.subtitle, 1, font=self.font)
        del draw
        im.save(image_path)

    def parse_ranges(self, ranges_str):
        ranges = [e.split(':') for e in ranges_str.split(',')]
        ranges_rollout = []
        for r in ranges:
            r = [int(e) for e in r]  # typecast
            if self.max_ticks > 0:
                r = [e % (self.max_ticks + 1) if e < 0 else e for e in r]  # wrap negative
            else:
                if True in [e < 0 for e in r]:
                    print('Negative ranges are only allowed if max ticks is given.')
                    sys.exit(1)
            if len(r) > 2:  # range w/ stepsize
                ranges_rollout += list(range(r[0], r[1] + 1, r[2]))
            elif len(r) > 1:  # range
                ranges_rollout += list(range(r[0], r[1] + 1))
            else:  # single tick
                ranges_rollout += [int(r[0])]
        return ranges_rollout

    def parse_format(self, fmt):
        if not fmt:
            return None
        seed = self.seed
        for s in ['[', ']']:
            seed = seed.replace(s, '')
        s = {  # sequences
            'r': self.rule_string,
            'R': self.rule_string.replace('/', '-'),
            'd': f'{self.w}x{self.h}',
            'D': f'{self.w}-{self.h}',
            'f': self.flicker_mode,
            'a': 'X' if self.flicker_mode == 0 else chr(self.flicker_mode + 64),
            's': self.seed,
            'S': seed,
            't': self.tick,
            'T': f'{self.tick:08}',
            'i': 'i' if self.inverted else ' ',
            'o': 's' if self.ticks_render_image and self.tick in self.ticks_render_image else ' ',
            'pr': self.post_rule_string if self.post_ticks > 0 else '',
            'PR': self.post_rule_string.replace('/', '-') if self.post_ticks > 0 else '',
            'pt': f'{self.post_ticks}x' if self.post_ticks > 0 else '',
        }
        for k in s.keys():
            fmt = fmt.replace(f'%{k}', f'{{{k}}}')
        return fmt.format(**s)

    def post_process(self, rule_string, ticks=1):
        board = Board(self.w, self.h, rule_string, state=self.board, tiles=self.tiles, subtitle_format=None)
        for i in range(ticks):
            board.step()
        return board.board

    def pause_toggle(self):
        self.paused ^= 1

    def recover(self, parser=None, args=None):
        print('\nTo recover from this configuration, use the following representation as additional parameter:\n')
        name = sys.argv[0].split('/')[-1]
        indent = len(name) + 1
        first = True
        print(name, end=' ')
        for k, v in vars(args).items():
            if v == parser.get_default(k):
                continue
            if not first:
                print(' ' * indent, end='')
            if k == 'rules':
                print(f'--rules {self.rule_string} \\')
            else:
                print(f'--{k.replace("_", "-")} {v} \\')
            first = False
        if args.seed == '-1':
            print(' ' * indent, end='')
            print(f'-e {self.seed}')
        print(' ' * indent, end='')
        print(self.board_serialize(prefix_param=True))

    def cycle_flicker_mode(self):
        self.flicker_mode = (self.flicker_mode + 1) % self._FLICKER_MODES

    @ property
    def inverted(self):
        if self.flicker_mode == 0:
            return 0
        elif self.flicker_mode == 3:
            if self.tick % 2 == 0:
                return True
            else:
                return False
        invert = False
        cells_alive = self.cells_alive
        cells_dead = self.cells_total - cells_alive
        if self.flicker_mode == 1:
            corr_false = self.cells_alive_old - cells_dead
        elif self.flicker_mode == 2:
            corr_false = self.cells_dead_old - cells_dead
        # TODO: Use (board_old XOR board_now)'s count of 1s?
        else:
            corr_false = 0
        corr_true = self.cells_alive_old - cells_alive
        if corr_false > corr_true:
            invert = True
        self.cells_alive_old = cells_alive
        self.cells_dead_old = cells_dead
        return invert

    @property
    def cells_alive(self):
        alive = 0
        for y in range(self.h):
            for x in range(self.w):
                if self.board[y][x]:
                    alive += 1
        return alive

    @property
    def cells_total(self):
        return self.w * self.h

    @property
    def subtitle(self):
        return self.parse_format(self.subtitle_format)

    @staticmethod
    def parse_state(state_string):
        state = []
        for line in state_string.split('.'):
            state.append([int(c) for c in line])
        return state

    @staticmethod
    def random_rules(l_min=1, l_max=8, r_min=1, r_max=8):
        choices = list(range(8))
        l_num = random.randrange(l_min, l_max)
        r_num = random.randrange(r_min, r_max)
        l_rules = sorted(random.sample(choices, l_num))
        r_rules = sorted(random.sample(choices, r_num))
        l_str = "".join([str(e) for e in l_rules])
        r_str = "".join([str(e) for e in r_rules])
        rule_string = f'{l_str}/{r_str}'
        return rule_string

    @staticmethod
    def parse_rules(rule_string):
        if ',' in rule_string:
            rule_strings = rule_string.split(',')
        else:
            rule_strings = [rule_string]
        rules = []
        for j, r in enumerate(rule_strings):
            if 'x' in r:
                rs = r.split('x')
                f = int(rs[0])
                r = rs[1]
            else:
                f = 1
            if '+' in r:
                rule_tmp = r.split('+')
                rn = Board.random_rules(
                        int(rule_tmp[0][0]),
                        int(rule_tmp[0][1]),
                        int(rule_tmp[1][0]),
                        int(rule_tmp[1][1]),
                )
                rule_string = rule_string.replace(r, rn, 1)
                r = rn
            flip_alive, flip_dead = r.split('/')
            rule_set = {i: [True, False] for i in range(9)}
            for i in flip_alive:
                rule_set[int(i)][0] = False
            for i in flip_dead:
                rule_set[int(i)][1] = True
            for i in range(f):
                rules.append(rule_set)
        return rules, rule_string

    @staticmethod
    def parse_dimensions(dimensions, no_subtitle=False):
        h_mod = 2 if no_subtitle else 3
        w, h = dimensions.split('x')
        col, lin = shutil.get_terminal_size()
        w = col if w == 'M' else int(w)
        h = lin - h_mod if h == 'M' else int(h)
        return w, h

    @staticmethod
    def expand_state(state, w, h):
        state_w = len(state[0])
        state_h = len(state)
        w_odd = 1 if w % 2 == 0 else 0
        h_odd = 1 if h % 2 == 0 else 0
        x_off = (w // 2) - (state_w // 2 + w_odd)
        y_off = (h // 2) - (state_h // 2 + h_odd)
        board = [[0] * w for i in range(h)]
        for y in range(state_h):
            for x in range(state_w):
                if state[y][x]:
                    board[y + y_off][x + x_off] = 1
        return board


n = input()

ans1 = 0

ans2 = 0

for i in n:

    if i == 'U':

        ans1 += 1

    elif i == 'D':

        ans1 -= 1

    elif i == 'R':

        ans2 += 1

    else:

        ans2 -= 1

ans1 = abs(ans1)

ans2 = abs(ans2)

if (ans1 % 2 == 0 and ans2 % 2 == 0) or (ans1 % 2 == 1 and ans2 % 2 == 1):

    print((ans1 + ans2) // 2)

else:

    print(-1)


from imutils.video import FileVideoStream
from imutils.video import FPS
import imutils
import cv2
import pandas as pd
import torch
from torchvision import transforms, models, datasets
from torch.autograd import Variable
from model.TRN import TRN, MultiScaleTRN
import numpy as np
import os
from PIL import Image
import chip.config as config
from torch.nn import functional as F
import torch.nn as nn

# LABELS_DIR = r'data\ucf5\category.txt'

num_frames = config.d_frames
num_segs = config.num_segments
k_random = config.k_random
num_class = config.num_classes
img_feature_dim = config.img_feature_dim
image_size = config.image_size

transform = transforms.Compose([
    transforms.Resize((image_size, image_size)),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])

DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# DEVICE = torch.device("cpu")
model = MultiScaleTRN(img_feature_dim, num_frames, num_segs, k_random, num_class)
state_dict = torch.load(r'output\vcdb_model.pth')

model.load_state_dict(state_dict, strict=False)
# load the model and set it to evaluation mode
model.eval()
# model = nn.DataParallel(model)
model.to(DEVICE)

def load_image_data(data_path):
    image_path_list = os.listdir(data_path)
    frames_num = len(image_path_list)
    image_list = list()
    sample = np.linspace(0, frames_num-1, num_segs, endpoint=True, retstep=True, dtype=int)[0]
    for i in sample:
        img_path = os.path.join(data_path, image_path_list[i])
        img = Image.open(img_path)
        img = transform(img)
        image_list.append(img)
    image = torch.stack(image_list)
    return image

def image_demo():
    # Load class names
    classes = list(np.loadtxt(LABELS_DIR, dtype=np.str_, delimiter=' '))

    '''
    test model with extracted frames
    '''
    # load folder
    ROOT_PATH = r'D:\PhD_Program\Deep-Learning\PVCD-Pytorch\data\ucf5\test'
    Video_name = 'v_ShavingBeard_g01_c02'
    DATA_DIR = os.path.join(ROOT_PATH, Video_name)

    # Tensor [num_segments, num_channel, width, heigth]
    dummy_input = load_image_data(DATA_DIR)

    # add batch_size dimension
    # Tensor [batch_size, num_segments, num_channel, width, heigth]
    dummy_input = torch.unsqueeze(dummy_input, dim=0).cuda()
    outputs = model(dummy_input)

    # find the class label index with the maximum probability
    class_prob = F.softmax(outputs, dim=1)

    # get most probable class and its probability:
    scores, idX = torch.max(class_prob, dim=1)
    # get class names
    scores = scores.cpu().detach().numpy()[0]
    pred_label = classes[idX]

    print("[INFO] predicted label: {}, scores: {:.4f}".format(pred_label, scores))

def put_lable(frame, label):
    """
    Add iterations per second text to lower-left corner of a frame.
    opencv uses B G R order
    """
    cv2.putText(frame, "Predicted: " + label,
                (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 255))
    return frame

'''
load video
'''
def video_demo():
    # Load class names
    # classes = list(np.loadtxt(LABELS_DIR, dtype=np.str_, delimiter=' '))

    # Load class names
    LABELS_DIR = r'data\vcdb\category.csv'
    df = pd.read_csv(LABELS_DIR)
    classes = df['classIDx'].values.tolist()

    # created a *threaded *video stream, allow the camera senor to warmup,
    # and start the FPS counter
    print("[INFO] sampling THREADED frames from video...")

    # load video
    ROOT_PATH = r'D:\pvcd_core'
    video_name = '15-9.mp4'
    DATA_DIR = os.path.join(ROOT_PATH, video_name)

    vs = FileVideoStream(path=DATA_DIR).start()
    fps = FPS().start()

    pred_label = "";
    buffer_frames = []
    best_lable = ""
    best_score = 0
    # loop over some frames...this time using the threaded stream
    while True:
        # grab the frame from the threaded video stream and resize it
        # to have a maximum width of 400 pixels
        frame = vs.read()

        view_frame = put_lable(frame, pred_label)

        # if the frame was not grabbed, then we have reached the end
        if frame is None:
            break

        # crop_img = cv2.resize(frame, (image_size, image_size))
        input_pill = Image.fromarray(frame)
        input_pill = transform(input_pill)

        cv2.imshow("Frame", view_frame)
        key = cv2.waitKey(1) & 0xFF
        # if the `q` key was pressed, break from the loop
        if key == ord("q"):
            break

        '''
        The size of queue == num_segments
        add frames to the queue if the queue is not full
        when the queue is full of frames then take first d_frames to feed the model
        '''
        if (len(buffer_frames) < num_segs):
            buffer_frames.append(input_pill)
        else:
            input_frames = torch.stack(buffer_frames)
            # input_frame shape
            # print("Before batch_size",input_frames.shape)

            input = torch.unsqueeze(input_frames, dim=0).cuda()
            # print("Input shape:", input.shape)

            with torch.no_grad():
                outputs = model(input)

                # find the class label index with the maximum probability
                # h_x = torch.mean(F.softmax(outputs, dim=1), dim=0).data

                h_x = F.softmax(outputs, dim=1)

                # get most probable class and its probability:
                # probs, idx = h_x.sort(dim=0, descending=True)

                probs, idx = torch.max(h_x, dim=1)

                # scores = probs[0].cpu().detach().numpy()

                scores = probs.cpu().detach().numpy()[0]
                pred_label = str(classes[idx])
                # print("[INFO] predicted label: {}, scores: {:.4f}".format(pred_label, scores))

                if (scores > best_score):
                    best_score = scores
                    best_lable = pred_label

            '''
            list indices
            thislist = ["apple", "banana", "cherry"]

            The search will start at index 2 (included) and end at index 5 (not included)
            thislist[0:2] -> ['apple', 'banana']
            thislist[:-1] -> ['apple', 'banana']
            thislist[1:]  -> ['banana', 'cherry']
            thislist[-1]  -> cherry
            '''
            # Remember that the last item has the index -1
            buffer_frames[:-1] = buffer_frames[1:]
            # Negative indexing means start from the end
            buffer_frames[-1] = input_pill
            # check to see if the frame should be displayed to our screen

        # update the FPS counter
        fps.update()

    print(print("[INFO] best label: {}, scores: {:.4f}".format(best_lable, best_score)))
    return

if __name__ == '__main__':
    '''
    Predict the extracted frames
    '''
    # image_demo()

    '''
    Predict an input video
    '''

    video_demo()


class Customer:
    def __init__(self, name, wallet, age):
        self.name = name
        self.wallet = wallet
        self.age = age
        self.drunkenness = 0

    def buy_drink(self, drink, pub):
        if self.age >= 18 and self.drunkenness <= 10:
            pub.till += drink.price
            self.wallet -= drink.price
            self.drunkenness += drink.alcohol_level
            return "Enjoy!"
        else:
            return "Do one!"

    def buy_food(self, food):
        self.drunkenness -= food.rejuvenation_level
        self.wallet -= food.price


#!/anaconda3/bin/python
# @Time    : 2019-04-02 22:16
# @Author  : zhou
# @File    : 1094 谷歌的招聘
# @Software: PyCharm
# @Description:

import math

def isPrime(num):
    """

    :return: True or False tu judge isPrime number
    """
    if num <= 3:
        return num > 1
    elif num % 6 != 1 and num % 6 != 5:
        return False
    sqrt_num = math.floor(math.sqrt(num) + 1)
    for i in range(5, sqrt_num, 6):
        if num % i == 0 or num % (i + 2) == 0:
            return False
    return True

t, n = map(int, input().split())
str_in = input()

for i in range(t-n+1):
    temp = str_in[i:i+n]
    if isPrime(int(temp)):
        print(temp)
        break
else:
    print(404)


import serial #used for Serial Communication

aSerial = serail.Serial('com18',9600)

num = int(input("To turn on LED enter 1, to turn off LED enter 0 and to quit enter -1"))

while(num != -1):

    if(num == 1):
        aSerial.write('1')
        print("LED turned on")

    if(num == 0):
        aSerial.write('0')
        print("LED turned off")

    num = int(input("To turn on LED enter 1, to turn off LED enter 0 and to quit enter -1"))


# coding=utf-8
"""**Numerical tools**
"""

import numpy
from utilities import verify

def ensure_numeric(A, typecode=None):
    """Ensure that sequence is a numeric array.

    :param A: Is one of the following:

        * Sequence. If A is already a numeric array it will be returned
                    unaltered
                    If not, an attempt is made to convert it to a numeric
                    array
        * Scalar.   Return 0-dimensional array containing that value. Note
                    that a 0-dim array DOES NOT HAVE A LENGTH UNDER numpy.
        * String.   Array of ASCII values (numpy can't handle this)

    :param typecode: numeric type. If specified, use this in the conversion.
                    If not, let numeric package decide.
                    typecode will always be one of num.float, num.int, etc.

    :raises: Exception

    :returns: An array of A if it is found to be of a numeric type
    :rtype: numpy.ndarray

    .. note::
        that numpy.array(A, dtype) will sometimes copy.  Use 'copy=False' to
        copy only when required.

        This function is necessary as array(A) can cause memory overflow.
    """

    if isinstance(A, basestring):
        msg = 'Sorry, cannot handle strings in ensure_numeric()'
        # FIXME (Ole): Change this to whatever is the appropriate exception
        # for wrong input type
        raise Exception(msg)

    if typecode is None:
        if isinstance(A, numpy.ndarray):
            return A
        else:
            return numpy.array(A)
    else:
        return numpy.array(A, dtype=typecode, copy=False)

def nan_allclose(x, y, rtol=1.0e-5, atol=1.0e-8):
    """Does element comparison within a tolerance, excludes overlapped NaN.

    :param x: scalar or numpy array
    :type x: numpy.ndarray, float

    :param y: scalar or numpy array
    :type y: numpy.ndarray, float

    :param rtol: The relative tolerance parameter
    :type rtol: float

    :param atol: The absolute tolerance parameter
    :type atol: float

    :raises:

    :returns: The result of the allclose on non NaN elements
    :rtype: bool

    Note:
        Returns True if all non-nan elements pass.
    """

    xn = numpy.isnan(x)
    yn = numpy.isnan(y)
    if numpy.any(xn != yn):
        # Presence of NaNs is not the same in x and y
        return False

    if numpy.all(xn):
        # Everything is NaN.
        # This will also take care of x and y being NaN scalars
        return True

    # Filter NaN's out
    if numpy.any(xn):
        x = x[-xn]
        y = y[-yn]

    # Compare non NaN's and return
    return numpy.allclose(x, y, rtol=rtol, atol=atol)

def normal_cdf(x, mu=0, sigma=1):
    r"""Cumulative Normal Distribution Function

    :param x: scalar or array of real numbers
    :type x: numpy.ndarray, float

    :param mu: Mean value. Default 0
    :type mu: float, numpy.ndarray

    :param sigma: Standard deviation. Default 1
    :type sigma: float

    :returns: An approximation of the cdf of the normal
    :rtype: numpy.ndarray

    Note:
        CDF of the normal distribution is defined as
        \frac12 [1 + erf(\frac{x - \mu}{\sigma \sqrt{2}})], x \in \R

        Source: http://en.wikipedia.org/wiki/Normal_distribution
    """

    arg = (x - mu) / (sigma * numpy.sqrt(2))
    res = (1 + erf(arg)) / 2

    return res

def log_normal_cdf(x, median=1, sigma=1):
    r"""Cumulative Log Normal Distribution Function

    :param x: scalar or array of real numbers
    :type x: numpy.ndarray, float

    :param median: Median (exp(mean of log(x)). Default 1
    :type median: float

    :param sigma: Log normal standard deviation. Default 1
    :type sigma: float

    :returns: An approximation of the cdf of the normal
    :rtype: numpy.ndarray

    .. note::
        CDF of the normal distribution is defined as
        \frac12 [1 + erf(\frac{x - \mu}{\sigma \sqrt{2}})], x \in \R

        Source: http://en.wikipedia.org/wiki/Normal_distribution
    """

    return normal_cdf(numpy.log(x), mu=numpy.log(median), sigma=sigma)

# noinspection PyUnresolvedReferences
def erf(z):
    """Approximation to ERF

    :param z: input array or scalar to perform erf on
    :type z: numpy.ndarray, float

    :returns: the approximate error
    :rtype: numpy.ndarray, float

    Note:
        from:
        http://www.cs.princeton.edu/introcs/21function/ErrorFunction.java.html
        Implements the Gauss error function.
        erf(z) = 2 / sqrt(pi) * integral(exp(-t*t), t = 0..z)

        Fractional error in math formula less than 1.2 * 10 ^ -7.
        although subject to catastrophic cancellation when z in very close to 0
        from Chebyshev fitting formula for erf(z) from Numerical Recipes, 6.2

        Source:
        http://stackoverflow.com/questions/457408/
        is-there-an-easily-available-implementation-of-erf-for-python
    """

    # Input check
    try:
        len(z)
    except TypeError:
        scalar = True
        z = [z]
    else:
        scalar = False

    z = numpy.array(z)

    # Begin algorithm
    t = 1.0 / (1.0 + 0.5 * numpy.abs(z))

    # Use Horner's method
    ans = 1 - t * numpy.exp(-z * z - 1.26551223 +
                           t * (1.00002368 +
                           t * (0.37409196 +
                           t * (0.09678418 +
                           t * (-0.18628806 +
                           t * (0.27886807 +
                           t * (-1.13520398 +
                           t * (1.48851587 +
                           t * (-0.82215223 +
                           t * 0.17087277)))))))))

    neg = (z < 0.0)  # Mask for negative input values
    ans[neg] = -ans[neg]

    if scalar:
        return ans[0]
    else:
        return ans

def axes_to_points(x, y):
    """Generate all combinations of grid point coordinates from x and y axes

    :param x: x coordinates (array)
    :type x: numpy.ndarray

    :param y: y coordinates (array)
    :type y: numpy.ndarray

    :returns:
        * P: Nx2 array consisting of coordinates for all
             grid points defined by x and y axes. The x coordinate
             will vary the fastest to match the way 2D numpy
             arrays are laid out by default ('C' order). That way,
             the x and y coordinates will match a corresponding
             2D array A when flattened (A.flat[:] or A.reshape(-1))

    Note:
        Example

        x = [1, 2, 3]
        y = [10, 20]

        P = [[1, 10],
             [2, 10],
             [3, 10],
             [1, 20],
             [2, 20],
             [3, 20]]
    """

    # Reverse y coordinates to have them start at bottom of array
    y = numpy.flipud(y)

    # Repeat x coordinates for each y (fastest varying)
    # noinspection PyTypeChecker
    X = numpy.kron(numpy.ones(len(y)), x)

    # Repeat y coordinates for each x (slowest varying)
    Y = numpy.kron(y, numpy.ones(len(x)))

    # Check
    N = len(X)
    verify(len(Y) == N)

    # Create Nx2 array of x and y coordinates
    X = numpy.reshape(X, (N, 1))
    Y = numpy.reshape(Y, (N, 1))
    P = numpy.concatenate((X, Y), axis=1)

    # Return
    return P

def grid_to_points(A, x, y):
    """Convert grid data to point data

    :param A: Array of pixel values
    :type A: numpy.ndarray

    :param x: Longitudes corresponding to columns in A (west->east)
    :type x: numpy.ndarray

    :param y: Latitudes corresponding to rows in A (south->north)
    :type y: numpy.ndarray

    Returns:
        * P: Nx2 array of point coordinates
        * V: N array of point values
    """

    msg = ('Longitudes must be increasing (west to east). I got %s' % str(x))
    verify(x[0] < x[1], msg)

    msg = ('Latitudes must be increasing (south to north). I got %s' % str(y))
    verify(y[0] < y[1], msg)

    # Create Nx2 array of x, y points corresponding to each
    # element in A.
    points = axes_to_points(x, y)

    # Create flat 1D row-major view of A cast as
    # one column vector of length MxN where M, N = A.shape
    #values = A.reshape((-1, 1))
    values = A.reshape(-1)

    # Return Nx3 array with rows: x, y, value
    return points, values

def geotransform_to_axes(G, nx, ny):
    """Convert geotransform to coordinate axes

    :param G: GDAL geotransform (6-tuple).
        (top left x, w-e pixel resolution, rotation,
        top left y, rotation, n-s pixel resolution).
    :type G: tuple

    :param nx: Number of cells in the w-e direction
    :type nx: int

    :param ny: Number of cells in the n-s direction
    :type nx: int

    :returns: Two vectors (longitudes and latitudes) representing the grid
        defined by the geotransform.

        The values are offset by half a pixel size to correspond to
        pixel registration.

        I.e. If the grid origin (top left corner) is (105, 10) and the
        resolution is 1 degrees in each direction, then the vectors will
        take the form

        longitudes = [100.5, 101.5, ..., 109.5]
        latitudes = [0.5, 1.5, ..., 9.5]
    """

    lon_ul = float(G[0])  # Longitude of upper left corner
    lat_ul = float(G[3])  # Latitude of upper left corner
    dx = float(G[1])      # Longitudinal resolution
    dy = - float(G[5])    # Latitudinal resolution (always(?) negative)

    verify(dx > 0)
    verify(dy > 0)

    # Coordinates of lower left corner
    lon_ll = lon_ul
    lat_ll = lat_ul - ny * dy

    # Coordinates of upper right corner
    lon_ur = lon_ul + nx * dx

    # Define pixel centers along each directions
    # This is to achieve pixel registration rather
    # than gridline registration
    dx2 = dx / 2
    dy2 = dy / 2

    # Define longitudes and latitudes for each axes
    x = numpy.linspace(lon_ll + dx2,
                       lon_ur - dx2, nx)
    y = numpy.linspace(lat_ll + dy2,
                       lat_ul - dy2, ny)

    # Return
    return x, y


def life_stage():
    age = int(input("Age: "))

    if age >= -1 and age <= 12:
        print("Kid")
    elif age >= 13 and age <= 17:
        print("Teen")
    elif age == 18:
        print("Debut")
    elif age >= 19:
        print("Adult")

lifeStage = life_stage()


#coding: utf-8
import cocos
def Repeat(self):
    cocos.actions.Repeat(self)
cocos.director.director.init(width = 600, height = 600)
root = cocos.scene.Scene()
t = cocos.text.Label("Hello world!", position = (100, 200))
root.add(t)
t.do(Repeat(cocos.actions.RotateBy(360, 3)))
cocos.director.director.run(root)


#!/usr/bin/env python

test_data = [
    'forward 5',
    'down 5',
    'forward 8',
    'up 3',
    'down 8',
    'forward 2',
]

def load_data():
    data = []
    with open('input.txt', 'r') as f:
        for r in f.readlines():
            data.append(r.strip())
    return data

def get_position(data):
    horizontal = 0
    depth = 0

    for line in data:
        move = line.split(' ')[0]
        addition = int(line.split(' ')[1])
        if move == 'forward':
            horizontal += addition
        elif move == 'down':
            depth += addition
        elif move == 'up':
            depth -= addition
    return horizontal * depth

def get_position_part_2(data):
    horizontal = 0
    depth = 0
    aim = 0

    for line in data:
        move = line.split(' ')[0]
        addition = int(line.split(' ')[1])
        if move == 'forward':
            horizontal += addition
            depth += aim * addition
        elif move == 'down':
            aim += addition
        elif move == 'up':
            aim -= addition
    return horizontal * depth

def test_part1():
    data = test_data
    result = get_position(data)
    print(f'test1 is {result}')
    assert result == 150

def test_part2():
    data = test_data
    result = get_position_part_2(data)
    print(f'test2 is {result}')
    assert result == 900

def part1():
    data = load_data()
    result = get_position(data)
    print(f'part1 is {result}')

def part2():
    data = load_data()
    result = get_position_part_2(data)
    print(f'part2 is {result}')

test_part1()
part1()
test_part2()
part2()


from django.conf import settings
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required

from edivorce.apps.core.utils.derived import get_derived_data
from ..decorators import intercept, prequal_completed
from ..utils.efiling_court_locations import EFilingCourtLocations
from ..utils.efiling_documents import forms_to_file
from ..utils.step_completeness import get_error_dict, get_missed_question_keys, get_step_completeness, is_complete, get_formatted_incomplete_list
from ..utils.template_step_order import template_step_order
from ..utils.user_response import (
    get_data_for_user,
    copy_session_to_db,
    get_step_responses,
    get_responses_from_session,
    get_responses_from_session_grouped_by_steps,
)

def home(request):
    """
    This is the homepage
    """
    # if the user is returning from BCeID registration, then log them in to the site
    if request.user.is_authenticated and request.session.get('went_to_register', False):
        request.session['went_to_register'] = False
        return redirect('oidc_authentication_init')

    return render(request, 'intro.html', context={'hide_nav': True, 'efiling_enabled_globally': settings.EFILING_ENABLED_GLOBALLY})

def prequalification(request, step):
    """
    View for rendering pre-qualification questions.
    If user is not authenticated with BCeID, temporarily store user responses to session
    """
    template = 'prequalification/step_%s.html' % step

    if not request.user.is_authenticated:
        responses_dict = get_responses_from_session(request)
    else:
        responses_dict = get_data_for_user(request.user)
        responses_dict['active_page'] = 'prequalification'
        responses_dict['derived'] = get_derived_data(responses_dict)
        responses_by_step = get_step_responses(responses_dict)
        step_status = get_step_completeness(responses_by_step)
        responses_dict['step_status'] = step_status

    return render(request, template_name=template, context=responses_dict)

def success(request):
    """
    This page is shown if the user passes the qualification test
    """
    if request.user.is_authenticated:
        responses = get_data_for_user(request.user)
        prequal_responses = get_step_responses(responses)['prequalification']
    else:
        prequal_responses = get_responses_from_session_grouped_by_steps(request)['prequalification']
    complete = is_complete(prequal_responses)

    if complete:
        if request.user.is_authenticated:
            return redirect(reverse('overview'))
        return render(request, 'success.html', context={'register_url': settings.REGISTER_BCEID_URL, 'register_sc_url': settings.REGISTER_BCSC_URL})
    return redirect(reverse('incomplete'))

def incomplete(request):
    """
    This page is shown if the user misses any pre-qualification questions
    """
    if request.user.is_authenticated:
        responses = get_data_for_user(request.user)
        prequal_responses = get_step_responses(responses)
    else:
        prequal_responses = get_responses_from_session_grouped_by_steps(request)
    missed_question_keys = get_missed_question_keys(prequal_responses, 'prequalification')
    missed_questions = get_formatted_incomplete_list(missed_question_keys)

    responses_dict = get_responses_from_session(request)
    responses_dict['debug'] = settings.DEBUG
    responses_dict['missed_questions'] = missed_questions

    return render(request, 'incomplete.html', context=responses_dict)

def register(request):
    """
    Sets a session variable and redirects users to register for BCeID
    """
    if settings.DEPLOYMENT_TYPE == 'localdev':
        return render(request, 'localdev/register.html')

    request.session['went_to_register'] = True
    return redirect(settings.REGISTER_BCEID_URL)

def register_sc(request):
    """
    Sets a session variable and redirects users to register for BC Services Card
    """
    if settings.DEPLOYMENT_TYPE == 'localdev':
        return render(request, 'localdev/register.html')

    request.session['went_to_register'] = True
    return redirect(settings.REGISTER_BCSC_URL)

def after_login(request):
    if not request.user.is_authenticated:
        return render(request, '407.html')

    copy_session_to_db(request, request.user)

    return redirect(settings.PROXY_BASE_URL + settings.FORCE_SCRIPT_NAME[:-1] + '/overview')

def after_logout(_request):
    response = HttpResponseRedirect(settings.PROXY_BASE_URL + settings.FORCE_SCRIPT_NAME)
    response.delete_cookie(key="SMSESSION", domain=".gov.bc.ca", path="/")
    return response

@login_required
@prequal_completed
@intercept
def overview(request):
    """
    Dashboard: Process overview page.
    """
    responses_dict = get_data_for_user(request.user)
    responses_dict_by_step = get_step_responses(responses_dict)

    # Add step status dictionary
    step_status = get_step_completeness(responses_dict_by_step)
    responses_dict_by_step['step_status'] = step_status
    responses_dict_by_step['active_page'] = 'overview'
    responses_dict_by_step['derived'] = get_derived_data(responses_dict)

    # Dashnav needs filing option to determine which steps to show
    for question in responses_dict_by_step['signing_filing']:
        responses_dict_by_step[question['question_id']] = question['value']

    response = render(request, 'overview.html', context=responses_dict_by_step)

    # set this session variable after the page is already rendered
    request.session['viewed_dashboard_during_session'] = True

    return response

@login_required
@prequal_completed
def dashboard_nav(request, nav_step):
    """
    Dashboard: All other pages
    """
    responses_dict = get_data_for_user(request.user)
    responses_dict['active_page'] = nav_step
    template_name = 'dashboard/%s.html' % nav_step
    if nav_step in ('print_form', 'swear_forms', 'next_steps', 'final_filing') and responses_dict.get('court_registry_for_filing'):
        _add_court_registry_address(request, responses_dict)
    if nav_step in ('print_form', 'initial_filing', 'final_filing'):
        _add_question_errors(responses_dict)
    if nav_step in ('initial_filing', 'final_filing'):
        _add_error_messages(nav_step, request, responses_dict)
    if request.user.has_efiling_early_access or settings.EFILING_ENABLED_GLOBALLY:
        responses_dict['efiling_enabled'] = True
    else:
        responses_dict['efiling_enabled'] = False

    responses_dict['virtual_swearing_enabled'] = settings.VIRTUAL_SWEARING_ENABLED
    responses_dict['derived'] = get_derived_data(responses_dict)
    return render(request, template_name=template_name, context=responses_dict)

def _add_court_registry_address(request, responses_dict):

    filing_registry = responses_dict.get('court_registry_for_filing', '')

    if not filing_registry:
        return

    locations = EFilingCourtLocations().courts(request)

    if filing_registry not in locations.keys():
        return

    location = locations[filing_registry]

    def addr(key):
        val = location.get(key, '')
        strVal = '' if val is None else str(val)
        return strVal + "<br>" if strVal else ''

    address = addr('address_1') + addr('address_2') + addr('address_3')
    responses_dict['court_registry_for_filing_address'] = address.strip()
    postal = addr('postal')
    if len(postal) >= 10:
        postal = postal[0:3] + ' ' + postal[-7:]
        responses_dict['court_registry_for_filing_postal_code'] = postal
    else:
        responses_dict['court_registry_for_filing_postal_code'] = postal

def _add_question_errors(responses_dict):
    responses_dict_by_step = get_step_responses(responses_dict)
    responses_dict.update(get_error_dict(responses_dict_by_step))

def _add_error_messages(nav_step, request, responses_dict):
    initial = 'initial' in nav_step
    uploaded, _ = forms_to_file(responses_dict, initial=initial)
    responses_dict['form_types'] = uploaded
    if request.GET.get('cancelled'):
        messages.add_message(request, messages.ERROR,
                             'You have cancelled the filing of your documents. '
                             'You can complete the filing process at your convenience.')
    elif request.GET.get('no_connection'):
        messages.add_message(request, messages.ERROR,
                             'The connection to the BC Government’s eFiling Hub is currently not working. '
                             'This is a temporary problem. '
                             'Please try again now and if this issue persists try again later.')
    elif request.GET.get('message'):
        messages.add_message(request, messages.ERROR, request.GET.get('message'))

@login_required
@prequal_completed
def question(request, step, sub_step=None):
    """
    View for rendering main divorce questionaire questions
    """
    sub_page_template = '_{}'.format(sub_step) if sub_step else ''
    template = 'question/%02d_%s%s.html' % (template_step_order[step], step, sub_page_template)

    if step == "review":
        data_dict = get_data_for_user(request.user)
        responses_dict_by_step = get_step_responses(data_dict)
        step_status = get_step_completeness(responses_dict_by_step)
        data_dict.update(get_error_dict(responses_dict_by_step))
        derived = get_derived_data(data_dict)
        responses_dict = responses_dict_by_step
    else:
        responses_dict = get_data_for_user(request.user)
        responses_dict_by_step = get_step_responses(responses_dict)
        step_status = get_step_completeness(responses_dict_by_step)
        responses_dict.update(get_error_dict(responses_dict_by_step, step, sub_step))
        derived = get_derived_data(responses_dict)

    # Add step status dictionary
    responses_dict['step_status'] = step_status

    responses_dict['active_page'] = step
    # If page is filing location page, add registries dictionary for list of court registries
    if step == "location":
        courts = EFilingCourtLocations().courts(request)
        responses_dict['registries'] = sorted(courts.keys())

    responses_dict['sub_step'] = sub_step
    responses_dict['derived'] = derived

    return render(request, template_name=template, context=responses_dict)

def page_not_found(request, _exception, template_name='404.html'):
    """
    404 Error Page
    """
    return render(request, template_name, status=404)

def server_error(request, template_name='500.html'):
    """
    500 Error Page
    """
    return render(request, template_name, status=500)

def legal(request):
    """
    Legal Information page
    """
    return render(request, 'legal.html', context={'active_page': 'legal'})

def acknowledgements(request):
    """
    Acknowledgements page
    """
    return render(request, 'acknowledgements.html', context={'active_page': 'acknowledgements'})

def contact(request):
    """
    Contact Us page
    """
    return render(request, 'contact-us.html', context={'active_page': 'contact'})

@login_required
def intercept_page(request):
    """
    On intercept, show the Orders page to get the requested orders before the
    user sees the nav on the left, so that it's already customized to their
    input.
    """
    template = 'question/%02d_%s.html' % (template_step_order['orders'], 'orders')
    responses_dict = get_data_for_user(request.user)
    responses_dict['intercepted'] = True
    responses_dict['derived'] = get_derived_data(responses_dict)

    return render(request, template_name=template, context=responses_dict)


# importing required modules
from PySide2 import QtCore
from mplWidget import MplWidget
from PySide2.QtWebEngineWidgets import QWebEngineView
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from thread import *
import os
import sys
import pandas as pd
import matplotlib.pyplot as plt

plt.style.use('ggplot')   # 設定畫圖風格
plt.rcParams['font.sans-serif'] = ['SimHei'] # 設定相容中文
plt.rcParams['axes.unicode_minus'] = False
pd.options.mode.chained_assignment = None

QtCore.QCoreApplication.addLibraryPath(os.path.join(os.path.dirname(QtCore.__file__), 'plugins'))  # 掃plugin套件(windows必備)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        #【設定初始化，UI標題與視窗大小】
        self.setWindowTitle('自動排程系統 ver 1.1')
        self.setWindowIcon(QIcon('favicon.ico'))
        self.resize(QSize(1500, 900))

        #【新增UI中的顯示元件】
        # ● 按鍵
        self.btn_upload_workbill_csv = QPushButton('載入訂單資料')
        self.btn_upload_machine_csv = QPushButton('載入機台資料')
        self.btn_upload_priority_csv = QPushButton('載入順位資料')
        self.btn_upload_mold_csv = QPushButton('載入模具資料')
        self.btn_start = QPushButton('開始排程')
        self.btn_set_flag = QPushButton('確定旗標時間')
        self.btn_restart = QPushButton('更改後重新排程')
        self.btn_download_result_csv = QPushButton('下載排程後訂單')
        # ● 字元 (一開始如不設定內容，初始可空白)
        self.label_maintitle = QLabel('自動排程系統')
        self.label_upload_workbill_filename = QLabel()
        self.label_upload_machine_filename = QLabel()
        self.label_upload_priority_filename = QLabel()
        self.label_upload_mold_filename = QLabel()
        self.label_cm = QLabel('換料常數 (秒)')
        self.label_cc = QLabel('換色常數 (秒)')
        self.label_alphac = QLabel('換色系數')
        self.label_prior2 = QLabel('第2級加權係數')
        self.label_prior3 = QLabel('第3級加權係數')
        self.label_scheduling_time = QLabel('排程當下時間')
        self.label_time_flag = QLabel('旗標時間')
        self.label_message = QLabel()
        # self.version_number = QLabel('V1.1')

        # ● 輸入欄位 (因之後會放在分頁裡，所以先完成layput)
        self.edit_cm = QLineEdit('2400')
        self.edit_cc = QLineEdit('1200')
        self.edit_alphac = QLineEdit('1.05')
        self.edit_prior2 = QLineEdit('1.2')
        self.edit_prior3 = QLineEdit('1.5')

        # ● 輸入日曆
        self.calendar_date1 = QCalendarWidget()
        self.calendar_date2 = QCalendarWidget()

        # ● 輸入時間
        self.dateEdit = QDateTimeEdit(QDateTime(2020, 11, 30, 8, 0, 0, 0, 0), self)
        # self.dateEdit = QDateTimeEdit(QDateTime.currentDateTime(), self)
        # self.dateEdit_flag = QDateTimeEdit(QDateTime.currentDateTime(), self)
        self.dateEdit_flag = QDateTimeEdit(QDateTime(2020, 12, 4, 8, 0, 0, 0, 0), self)

        # ● 樹表格顯示
        self.tree_sepa_job = QTreeWidget()
        self.tree_sepa_job.setColumnCount(2)
        self.tree_sepa_job.setHeaderLabels(['選擇拆單', '拆單數值與新交期']) #['key', 'Value']
        self.tree_sepa_job.setFixedHeight(150)

        # ● 圖片-圖片引擎
        self.plot_output_result = MplWidget()
        self.browser = QWebEngineView(self)
        # ● 分頁
        self.tabs_setting = QTabWidget()

        ######分頁內容：輸入資料######
        input_data_layout = QVBoxLayout()
        input_data_layout.addWidget(self.btn_upload_workbill_csv)
        input_data_layout.addWidget(self.label_upload_workbill_filename)
        input_data_layout.addWidget(self.btn_upload_machine_csv)
        input_data_layout.addWidget(self.label_upload_machine_filename)
        input_data_layout.addWidget(self.btn_upload_priority_csv)
        input_data_layout.addWidget(self.label_upload_priority_filename)
        input_data_layout.addWidget(self.btn_upload_mold_csv)
        input_data_layout.addWidget(self.label_upload_mold_filename)
        input_data_widget = QWidget()
        input_data_widget.setLayout(input_data_layout)
        #############################

        ######分頁內容：參數設定######
        parameter_layout = QVBoxLayout()

        cm_layout = QHBoxLayout()
        cm_layout.addWidget(self.label_cm)
        cm_layout.addWidget(self.edit_cm)
        cm_layout.setStretchFactor(self.label_cm, 3)   #比例調整
        cm_layout.setStretchFactor(self.edit_cm, 2)    #比例調整
        cm_widget = QWidget()
        cm_widget.setLayout(cm_layout)

        cc_layout = QHBoxLayout()
        cc_layout.addWidget(self.label_cc)
        cc_layout.addWidget(self.edit_cc)
        cc_layout.setStretchFactor(self.label_cc, 3)   #比例調整
        cc_layout.setStretchFactor(self.edit_cc, 2)    #比例調整
        cc_widget = QWidget()
        cc_widget.setLayout(cc_layout)

        alphac_layout = QHBoxLayout()
        alphac_layout.addWidget(self.label_alphac)
        alphac_layout.addWidget(self.edit_alphac)
        alphac_layout.setStretchFactor(self.label_alphac, 3)   #比例調整
        alphac_layout.setStretchFactor(self.edit_alphac, 2)    #比例調整
        alphac_widget = QWidget()
        alphac_widget.setLayout(alphac_layout)

        prior2_layout = QHBoxLayout()
        prior2_layout.addWidget(self.label_prior2)
        prior2_layout.addWidget(self.edit_prior2)
        prior2_layout.setStretchFactor(self.label_prior2, 3)   #比例調整
        prior2_layout.setStretchFactor(self.edit_prior2, 2)    #比例調整
        prior2_widget = QWidget()
        prior2_widget.setLayout(prior2_layout)

        prior3_layout = QHBoxLayout()
        prior3_layout.addWidget(self.label_prior3)
        prior3_layout.addWidget(self.edit_prior3)
        prior3_layout.setStretchFactor(self.label_prior3, 3)   #比例調整
        prior3_layout.setStretchFactor(self.edit_prior3, 2)    #比例調整
        prior3_widget = QWidget()
        prior3_widget.setLayout(prior3_layout)

        parameter_layout.addWidget(cm_widget)
        parameter_layout.addWidget(cc_widget)
        parameter_layout.addWidget(alphac_widget)
        parameter_layout.addWidget(prior2_widget)
        parameter_layout.addWidget(prior3_widget)
        parameter_widget = QWidget()
        parameter_widget.setLayout(parameter_layout)
        #############################

        ######分頁內容：輸入資料######
        first_run_layout = QVBoxLayout()
        first_run_layout.addWidget(self.label_scheduling_time)
        first_run_layout.addWidget(self.dateEdit)
        first_run_layout.addWidget(self.btn_start)
        first_run_widget = QWidget()
        first_run_widget.setLayout(first_run_layout)
        #############################

        ######捲動區域內容：可變動單子######
        rerun_layout = QVBoxLayout()
        rerun_layout.addWidget(self.label_time_flag)
        rerun_layout.addWidget(self.dateEdit_flag)
        rerun_layout.addWidget(self.btn_set_flag)
        rerun_layout.addWidget(self.tree_sepa_job)
        rerun_layout.addWidget(self.btn_restart)
        rerun_widget = QWidget()
        rerun_widget.setLayout(rerun_layout)
        #############################

        # ● 捲動區域
        ## 設定捲動區域
        self.scroll_input_data = QScrollArea() # 建立捲動區域，並將scroll_widget設置其中
        self.scroll_input_data.setWidgetResizable(True)  # 設置是否自動調整部件大小(必須要True)
        self.scroll_input_data.setWidget(input_data_widget)

        self.scroll_parameter = QScrollArea()
        self.scroll_parameter.setWidgetResizable(True)
        self.scroll_parameter.setWidget(parameter_widget)

        self.scroll_first_run = QScrollArea()
        self.scroll_first_run.setWidgetResizable(True)
        self.scroll_first_run.setWidget(first_run_widget)

        self.scroll_rerun = QScrollArea()
        self.scroll_rerun.setWidgetResizable(True)
        self.scroll_rerun.setWidget(rerun_widget)
        self.scroll_rerun.setFixedHeight(300)

        #【設定元件】
        ### ● 字型
        self.label_maintitle.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 15pt; font-weight: bold;}')
        self.label_upload_workbill_filename.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 8pt; border: 1px solid black;}')
        self.label_upload_machine_filename.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 8pt; border: 1px solid black;}')
        self.label_upload_priority_filename.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 8pt; border: 1px solid black;}')
        self.label_upload_mold_filename.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 8pt; border: 1px solid black;}')
        self.label_cm.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 9pt;}')
        self.label_cc.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 9pt;}')
        self.label_alphac.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 9pt;}')
        self.label_prior2.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 9pt;}')
        self.label_prior3.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 9pt;}')
        self.label_scheduling_time.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 10pt; font-weight: bold;}')
        self.label_time_flag.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 10pt; font-weight: bold;}')
        self.label_message.setStyleSheet('QLabel{font-family: Microsoft JhengHei; color: rgb(0, 0, 0); font-size: 10pt; border: 1px solid black;}')
        self.label_upload_workbill_filename.setWordWrap(True) # 自動換行
        self.label_upload_machine_filename.setWordWrap(True)
        self.label_upload_priority_filename.setWordWrap(True)
        self.label_upload_mold_filename.setWordWrap(True)
        self.label_message.setWordWrap(True)
        self.label_maintitle.setFixedHeight(30)  # 固定高度
        self.label_upload_workbill_filename.setFixedHeight(60)
        self.label_upload_machine_filename.setFixedHeight(60)
        self.label_upload_priority_filename.setFixedHeight(60)
        self.label_upload_mold_filename.setFixedHeight(60)
        self.label_scheduling_time.setFixedHeight(40)
        self.label_time_flag.setFixedHeight(40)

        ### ● 選單區域文字
        ### ● 按鍵字元
        self.btn_upload_workbill_csv.setStyleSheet('QPushButton{font-family: Microsoft JhengHei; font-size: 10pt;}')
        self.btn_upload_machine_csv.setStyleSheet('QPushButton{font-family: Microsoft JhengHei; font-size: 10pt;}')
        self.btn_upload_priority_csv.setStyleSheet('QPushButton{font-family: Microsoft JhengHei; font-size: 10pt;}')
        self.btn_upload_mold_csv.setStyleSheet('QPushButton{font-family: Microsoft JhengHei; font-size: 10pt;}')
        self.btn_start.setStyleSheet('QPushButton{font-family: Microsoft JhengHei; font-size: 10pt;}')
        self.btn_set_flag.setStyleSheet('QPushButton{font-family: Microsoft JhengHei; font-size: 10pt;}')
        self.btn_restart.setStyleSheet('QPushButton{font-family: Microsoft JhengHei; font-size: 10pt;}')
        self.btn_download_result_csv.setStyleSheet('QPushButton{font-family: Microsoft JhengHei; font-size: 10pt;}')
        self.btn_upload_workbill_csv.setCursor(QCursor(QtCore.Qt.PointingHandCursor)) # 游標移過去時會變成手指
        self.btn_upload_machine_csv.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        self.btn_upload_priority_csv.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        self.btn_upload_mold_csv.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        self.btn_start.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        self.btn_set_flag.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        self.btn_restart.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        self.btn_download_result_csv.setCursor(QCursor(QtCore.Qt.PointingHandCursor))

        ### ● 輸入時間
        self.dateEdit.setDisplayFormat('yyyy-MM-dd HH:mm:ss')
        self.dateEdit_flag.setDisplayFormat('yyyy-MM-dd HH:mm:ss')
        self.dateEdit.setCalendarPopup(True) # 彈出日曆
        self.dateEdit_flag.setCalendarPopup(True)
        self.dateEdit.setStyleSheet('QDateTimeEdit{font-family: Microsoft JhengHei}')
        self.dateEdit_flag.setStyleSheet('QDateTimeEdit{font-family: Microsoft JhengHei}')
        self.dateEdit.setCalendarWidget(self.calendar_date1)
        self.dateEdit_flag.setCalendarWidget(self.calendar_date2)
        ### ● 日曆
        self.calendar_date1.setStyleSheet("QCalendarWidget{font-family: Microsoft JhengHei;}")
        self.calendar_date2.setStyleSheet("QCalendarWidget{font-family: Microsoft JhengHei;}")
        self.calendar_date1.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        self.calendar_date2.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        self.calendar_date1.setGridVisible(True) # 決定是否顯示格線
        self.calendar_date2.setGridVisible(True)
        ### ● 輸入欄位
        self.edit_cm.setStyleSheet('QLineEdit{font-family: Microsoft JhengHei;}')
        self.edit_cc.setStyleSheet('QLineEdit{font-family: Microsoft JhengHei;}')
        self.edit_alphac.setStyleSheet('QLineEdit{font-family: Microsoft JhengHei;}')
        self.edit_prior2.setStyleSheet('QLineEdit{font-family: Microsoft JhengHei;}')
        self.edit_prior3.setStyleSheet('QLineEdit{font-family: Microsoft JhengHei;}')
        self.edit_cm.setValidator(QIntValidator())  # 設定限定輸入字元形式，如整數Int、浮點數Double
        self.edit_cc.setValidator(QIntValidator())
        self.edit_alphac.setValidator(QDoubleValidator())
        self.edit_prior2.setValidator(QDoubleValidator())
        self.edit_prior3.setValidator(QDoubleValidator())
        ### ● 分頁 (先分配各分頁區塊)
        self.tabs_setting.addTab(self.scroll_input_data, '輸入資料')
        self.tabs_setting.addTab(self.scroll_parameter, '參數設定')
        self.tabs_setting.addTab(self.scroll_first_run, '初次排程')

        self.tabs_setting.setFixedHeight(260)
        self.tabs_setting.setStyleSheet('QTabWidget{font-family: Microsoft JhengHei; font-size: 9pt;}')

        #【設定佈局(layout)】
        # main layout
        main_layout = QHBoxLayout()   # 建立layout，最初指定垂直切分。layout之後要定義一個widget讓layout設定進去(註*1)
        #################################
        #### left layout ####
        left_layout = QVBoxLayout()

        left_layout = QVBoxLayout()
        left_layout.addWidget(self.label_maintitle)  # 建立layout之後就可以塞元件了
        left_layout.addWidget(self.tabs_setting)
        left_layout.addWidget(self.scroll_rerun)
        left_layout.addWidget(self.btn_download_result_csv)
        left_layout.addWidget(self.label_message)
        left_widget = QWidget()
        left_widget.setLayout(left_layout)

        #### right layout ####
        right_layout = QHBoxLayout()
        right_layout.addWidget(self.browser)
        right_widget = QWidget()
        right_widget.setLayout(right_layout)

        main_layout.addWidget(left_widget)
        main_layout.addWidget(right_widget)
        main_layout.setStretchFactor(left_widget, 1)
        main_layout.setStretchFactor(right_widget, 3)
        #################################
        main_widget = QWidget()                       # (註*1)每一次建layout後要用widget包
        main_widget.setLayout(main_layout)            # (註*1)每一次建layout後要用widget包
        self.setCentralWidget(main_widget)            # 設定main_widget為中心視窗

        #【設定button觸發的slot(function)】
        self.btn_upload_workbill_csv.clicked.connect(self.slot_upload_workbill)
        self.btn_upload_machine_csv.clicked.connect(self.slot_upload_machine)
        self.btn_upload_priority_csv.clicked.connect(self.slot_upload_priority)
        self.btn_upload_mold_csv.clicked.connect(self.slot_upload_mold)
        self.btn_start.clicked.connect(self.slot_start)
        self.btn_set_flag.clicked.connect(self.slot_set_flag)
        self.btn_restart.clicked.connect(self.slot_restart)
        self.btn_download_result_csv.clicked.connect(self.slot_download_result)
        # 【設定全域變數】
        self.workbill_filename = None    # 初次排程的三個輸入檔案名稱
        self.machine_filename = None
        self.priority_filename = None
        self.mold_filename = None
        self.workbill_df = pd.DataFrame() # 初次排程的三個輸入檔案
        self.machine_df = pd.DataFrame()
        self.priority_df = pd.DataFrame()
        self.mold_df = pd.DataFrame()
        self.result_workbill = pd.DataFrame() # 完成初次排程的檔案
        self.gantt_df = pd.DataFrame()        # 同上
        self.dsl = None                       # 同上
        self.date = None  # 初次排程時間
        self.th1_work = None
        self.th2_work = None
        self.date_flag = None # 二次排程時間
        self.time_flag = 0 # 為二次排程時間扣除初次排程時間的秒數
        self.current_job_list = []
        self.drop_job_list = []

    def slot_upload_workbill(self):
        file, _ = QFileDialog.getOpenFileName(self, 'Open file', '', 'Data Files (*.csv)')  # 建立對話盒(dialog)
        if file:
            self.workbill_filename = file
            self.label_upload_workbill_filename.setText(file) # 複寫label文字為檔名(file)

    def slot_upload_machine(self):
        file, _ = QFileDialog.getOpenFileName(self, 'Open file', '', 'Data Files (*.csv)')
        if file:
            self.machine_filename = file
            self.label_upload_machine_filename.setText(file)

    def slot_upload_priority(self):
        file, _ = QFileDialog.getOpenFileName(self, 'Open file', '', 'Data Files (*.csv)')
        if file:
            self.priority_filename = file
            self.label_upload_priority_filename.setText(file)

    def slot_upload_mold(self):
        file, _ = QFileDialog.getOpenFileName(self, 'Open file', '', 'Data Files (*.csv)')
        if file:
            self.mold_filename = file
            self.label_upload_mold_filename.setText(file)

    def slot_start(self):
        # 初次排程時的甘特圖資料與時間都需要重置
        self.gantt_df = pd.DataFrame()
        self.date = self.dateEdit.dateTime().toString('yyyy-MM-dd hh:mm:ss')
        if (self.workbill_filename == None) | (self.machine_filename == None) | (self.priority_filename == None):
            self.label_message.setText('請確認是否已載入檔案')
        elif (len(self.edit_cm.text()) * len(self.edit_cc.text()) * len(self.edit_alphac.text()) * len(self.edit_prior2.text()) * len(self.edit_prior3.text())) == 0:
            self.label_message.setText('請確認參數是否確實設定')
        elif ((float(self.edit_cm.text()) < 0) | (float(self.edit_cc.text()) < 0) | (float(self.edit_alphac.text()) < 0) | (float(self.edit_prior2.text()) < 0) | (float(self.edit_prior3.text()) < 0)):
            self.label_message.setText('請確認參數是否超出範圍')
        else:
            try:
                self.workbill_df = pd.read_csv(self.workbill_filename)
                self.machine_df = pd.read_csv(self.machine_filename)
                self.priority_df = pd.read_csv(self.priority_filename)
                self.mold_df = pd.read_csv(self.mold_filename)
            except:
                self.label_message.setText('請確認檔案格式')
            else:
                self.label_message.setText('計算中...')
                parameter_list = [int(self.edit_cm.text()), int(self.edit_cc.text()), float(self.edit_alphac.text()), float(self.edit_prior2.text()), float(self.edit_prior3.text())]
                self.th1_work = WorkThread(self.date, self.workbill_df, self.machine_df, self.priority_df, self.mold_df, self.gantt_df, parameter_list)
                self.th1_work.start()
                self.th1_work.signal_action.connect(self.slot_message)
                self.th1_work.signal_df_result.connect(self.slot_save_result_df)
                self.th1_work.signal_df_gantt.connect(self.slot_save_gantt_df)
                self.th1_work.signal_fig_gantt.connect(self.slot_draw_gantt_df)
                self.th1_work.signal_list_dsl.connect(self.slot_check_schedule_list)
        self.btn_restart.setEnabled(True)

    def slot_set_flag(self):
        # 依照旗標時間重新顯示每台機台正在做的訂單資訊(樹表格)
        self.current_job_list, self.drop_job_list = [], []

        if (self.date == None) | (len(self.result_workbill) <= 0):
            self.label_message.setText('請先做初次排程')
        else:
            self.tree_sepa_job.clear()  # 重置樹表格
            self.date_flag = self.dateEdit_flag.dateTime().toString('yyyy-MM-dd hh:mm:ss')
            self.time_flag = (datetime.strptime(self.date_flag, '%Y-%m-%d %H:%M:%S') - datetime.strptime(self.date, '%Y-%m-%d %H:%M:%S')).total_seconds()
            for ds in self.dsl:
                info_dict, current_job, done_job_list = {}, None, []
                Ct_list, Job_list = ds['c_time'], ds['Job']
                for index, c_t in enumerate(Ct_list):
                    if (index == 0) & (self.time_flag < c_t):  # 排單後還沒有單子正在生產
                        current_job, done_job_list = None, []
                    elif (index == len(Ct_list) - 1) & (c_t <= self.time_flag): # 單子都排完了
                        current_job, done_job_list = None, Job_list
                    elif (Ct_list[index - 1] <= self.time_flag) & (self.time_flag < c_t): # 可以記錄當下安排哪張單
                        current_job, done_job_list = Job_list[index], Job_list[1 : index]
                info_dict['machineNo'], info_dict['Job'] = ds['machineNo'], current_job ####
                self.current_job_list.append(info_dict)
                self.drop_job_list += done_job_list

            for device_job in self.current_job_list:
                # Create top root.
                root = QTreeWidgetItem(self.tree_sepa_job)
                root.setText(0, '{}-{}'.format(device_job['machineNo'], device_job['Job']))
                root.setCheckState(0, Qt.Unchecked)

                # Create child (數值部分依單而定)
                child_num = QTreeWidgetItem()
                child_num.setText(0, '數量')

                child_endtime = QTreeWidgetItem()
                child_endtime.setText(0, 'EndTime')

                if (device_job['Job'] == None):
                    str_num, str_endtime = None, None
                else:
                    str_num = self.workbill_df[self.workbill_df['billNo'] == device_job['Job']]['qty'].values[0]
                    str_endtime = self.workbill_df[self.workbill_df['billNo'] == device_job['Job']]['endTime'].dt.strftime('%Y-%m-%d %H:%M:%S').values[0]
                child_num.setText(1, '{}'.format(str_num))
                child_endtime.setText(1, '{}'.format(str_endtime))

                # Add child to root.
                root.addChild(child_num)
                root.addChild(child_endtime)

                # Set editable.
                self.tree_sepa_job.openPersistentEditor(child_num, 1)
                self.tree_sepa_job.openPersistentEditor(child_endtime, 1)

    def slot_restart(self):
        # 再次排程需要
        if (self.date == None) | (self.date_flag == None):
            self.label_message.setText('請先做初次排程與二次排程')
        else:
            self.machine_df = pd.read_csv(self.machine_filename)
            self.priority_df = pd.read_csv(self.priority_filename)
            self.workbill_df = pd.read_csv(self.workbill_filename)
            self.mold_df = pd.read_csv(self.mold_filename)
            cut_job_list = []
            for i in range(len(self.current_job_list)):
                if (self.tree_sepa_job.topLevelItem(i).checkState(0) == Qt.Checked): # 有打勾
                    try:
                        new_size = int(self.tree_sepa_job.topLevelItem(i).child(0).text(1))
                        new_end_time = datetime.strptime(self.tree_sepa_job.topLevelItem(i).child(1).text(1), '%Y-%m-%d %H:%M:%S')
                    except:
                        self.label_message.setText('拆單輸入數值格式錯誤')
                    else:   # 打勾的都確認完，開始處理輸入資料
                        cut_job_list.append(str(self.current_job_list[i]['Job']))
                        # 【machine_df】
                        self.machine_df.loc[i, ['colorNo', 'materialNo']] = \
                            self.result_workbill[self.result_workbill['billNo'] == self.current_job_list[i]['Job']][['colorNo', 'materialNo']].values.tolist()[0]
                        self.machine_df.loc[i, 'start_working_date'] = self.date_flag

                        # 【priority_df】
                        for col in self.priority_df.columns[1:]:
                            target = self.priority_df.loc[self.priority_df['productNo'] == self.result_workbill[self.result_workbill['billNo'] == self.current_job_list[i]['Job']]['productNo'].values.tolist()[0], col].values[0]
                            if target == target:
                                if self.current_job_list[i]['machineNo'] in target:
                                    new_selection_str = ''
                                    for device in [device for device in target.split(',') if device != self.current_job_list[i]['machineNo']]:
                                        if len(new_selection_str) == 0: new_selection_str += device
                                        else: new_selection_str += (',' + device)
                                    self.priority_df.loc[self.priority_df['productNo'] == self.result_workbill[self.result_workbill['billNo'] == self.current_job_list[i]['Job']]['productNo'].values.tolist()[0], col] = new_selection_str
                                    break

                        # 【workbill_df】 複製拆分前的單，並此單修改此單
                        self.workbill_df.loc[len(self.workbill_df)] = self.workbill_df.loc[self.workbill_df['billNo'] == self.current_job_list[i]['Job']].values.tolist()[0]
                        self.workbill_df.loc[len(self.workbill_df) - 1, ['billNo', 'qty', 'endTime']] = ['{}_sub'.format(self.current_job_list[i]['Job']), new_size, new_end_time]

                if ((self.tree_sepa_job.topLevelItem(i).checkState(0) == Qt.Unchecked) & (self.current_job_list[i]['Job'] != None)): # 沒打勾
                    # 【machine_df】
                    self.machine_df.loc[i, ['colorNo', 'materialNo', 'start_working_date']] = \
                        self.result_workbill[self.result_workbill['billNo'] == self.current_job_list[i]['Job']][['colorNo', 'materialNo', 'c_time']].values.tolist()[0]

            # 【workbill_df】 拿掉已經生產的單(self.current_job_list與self.drop_job_list)
            drop_list = [i['Job'] for i in self.current_job_list] + self.drop_job_list
            for machine_job in self.current_job_list: drop_list.append(machine_job['Job'])
            self.workbill_df = self.workbill_df[~self.workbill_df['billNo'].isin(drop_list)]
            self.workbill_df.reset_index(drop = True, inplace = True)
            self.gantt_df = self.gantt_df[self.gantt_df['billNo'].isin([str(i) for i in drop_list])]   ########原本已經排好的甘特圖資料
            self.gantt_df.reset_index(drop = True, inplace = True)
            for i in range(len(self.gantt_df)):
                if (self.gantt_df.loc[i, 'billNo'] in cut_job_list):
                    self.gantt_df.loc[i, 'Complete'] = self.date_flag
            self.gantt_df.loc[:, 'Complete'] = pd.to_datetime(self.gantt_df.loc[:, 'Complete'])

            parameter_list = [int(self.edit_cm.text()), int(self.edit_cc.text()), float(self.edit_alphac.text()), float(self.edit_prior2.text()), float(self.edit_prior3.text())]
            self.th2_work = WorkThread(self.date_flag, self.workbill_df, self.machine_df, self.priority_df, self.mold_df, self.gantt_df, parameter_list)
            self.th2_work.start()
            self.th2_work.signal_action.connect(self.slot_message)
            self.th2_work.signal_df_result.connect(self.slot_save_result_df)
            self.th2_work.signal_df_gantt.connect(self.slot_save_gantt_df)
            self.th2_work.signal_fig_gantt.connect(self.slot_draw_gantt_df)
            self.th2_work.signal_list_dsl.connect(self.slot_check_schedule_list)
            self.btn_restart.setEnabled(False)

    def slot_message(self, message_str):
        self.label_message.setText(message_str)

    def slot_save_result_df(self, data_df):
        self.result_workbill = data_df

    def slot_save_gantt_df(self, data_df):
        self.gantt_df = data_df

    def slot_draw_gantt_df(self, object):
        self.browser.setHtml(object.to_html(include_plotlyjs = 'cdn'))

    def slot_download_result(self):
        if len(self.result_workbill) <= 0:
            self.label_message.setText('尚未有排程結果！請確認是否已載入資料並執行。')
        else:
            fileName, _ = QFileDialog.getSaveFileName(self, 'Save file', '', '*.csv')  # 建立儲存檔案的對話盒(dialog)
            if fileName:
                self.result_workbill.to_csv(fileName, index = None)

    def slot_check_schedule_list(self, dsl_list):
        self.dsl = dsl_list

def main():
    app = QApplication([])
    app.setStyle(QStyleFactory.create('fusion'))
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()


from rest_framework_gis import serializers as geo_serializers
from rest_framework import serializers
from .models import Polygon
from core.models import AHJ

class FindPolygonAHJID(serializers.UUIDField):
    def to_representation(self, value):
        # Some polygons have multiple AHJ paired with them
        # This is because there are duplicate AHJ (data issue)
        ahj = AHJ.objects.filter(mpoly=value).first()
        if ahj is None:
            return None
        else:
            return ahj.AHJID

class PolygonSerializer(geo_serializers.GeoFeatureModelSerializer):
    AHJID = FindPolygonAHJID(source='*')
    class Meta:
        model = Polygon
        geo_field = 'mpoly'
        id_field = False
        fields = ['AHJID', 'ALAND', 'INTPTLAT', 'INTPTLON', 'GEOID']


def subArrayNaive(arr):
    globalMaxm = -90000
    for i in range(len(arr)):
        for j in range(i, len(arr)):
            maxm = 0
            for k in range(i, j+1):
                maxm += arr[k]
                if maxm > globalMaxm:
                    globalMaxm = maxm
    return globalMaxm

def kadaneAlgo(arr):
    maxSum = -9000
    currSum = 0
    for i in range(len(arr)):
        currSum += arr[i]
        if currSum > maxSum:
            maxSum = currSum
        if currSum < 0:
            currSum = 0
    return maxSum

arr = [int(x) for x in input().split()]
# print(subArrayNaive(arr))
print(kadaneAlgo(arr))