import pandas
import MachineLearningModelUtilities as MLUtils
import DataPreparation as DataPrep

model_savedir = "./test_output/"
customized_model_dir = "./test_scripts"
customized_model_name = "Model"

svm_paras = [{"kernel": "linear"}, {"kernel": "poly"}, {"kernel": "rbf"}, {"kernel": "sigmoid"}]
nn_paras = [{"_hidden_nodes": []}, {"_hidden_nodes": [1]}, {"_hidden_nodes": [2]}, {"_hidden_nodes": [3]}, {"_hidden_nodes": [4]}]
nb_paras = [{"alpha": 1}, {"alpha": 1.5}]
def test():
    print("Loading data...")
    stock_data = pandas.read_csv('./test_data/10tickers_wo_sector_fill.csv')
    stock_data.dropna(subset=['last_price'],inplace=True)
    stock_data.fillna(value = 0, inplace = True)

    best_para = MLUtils.selectMetaparameters("Custom", stock_data,  stock_filter_flag = False, B_top = 10, B_bottom = 15, target_label_holding_period = 3, trading_stock_quantity = 10, para_tune_holding_flag = "long", period = 5, paras_set = nb_paras, customized_module_dir = customized_model_dir, customized_module_name = customized_model_name)
    print("Custom [testscript paras]:", best_para)

    best_para = MLUtils.selectMetaparameters("Custom", stock_data,  stock_filter_flag = False, B_top = 10, B_bottom = 15, target_label_holding_period = 3, trading_stock_quantity = 10, para_tune_holding_flag = "long", period = 5, paras_set = "model_def", customized_module_dir = customized_model_dir, customized_module_name = customized_model_name)
    print("Custom [model paras]:", best_para)

    best_para = MLUtils.selectMetaparameters("SVM", stock_data,  stock_filter_flag = False, B_top = 10, B_bottom = 15, target_label_holding_period = 3, trading_stock_quantity = 10, para_tune_holding_flag = "long", period = 5, paras_set = svm_paras)
    print("SVM:", best_para)

    best_para = MLUtils.selectMetaparameters("NN", stock_data,  stock_filter_flag = False, B_top = 10, B_bottom = 15, target_label_holding_period = 3, trading_stock_quantity = 10, para_tune_holding_flag = "long", period = 5, paras_set = nn_paras)
    print("NN:", best_para)


from select import *
from init_grammar import *

def get_parser(rules):
    '''
    init Grammar(V, T, S, P), set first_set and follow_set, set select_set
    :param rules: Grammar rules
    :return: select_set
    '''
    g = get_grammar(rules)
    par = ll_parser.parser(g)
    par.set_table(set_select(g))

    return par

if __name__ == '__main__':
    g = \
'''E : E + T | T
T : T * F | F
F : ( E ) | i'''
    p = get_parser(g)

    with open('/Users/AnYameng/Desktop/c/homework_of_compilers/4/4_1.txt', 'r') as f:
        l = f.readlines()
        for input in l:
            input = input.strip().split(" ")
            result = p.parse(input)

            if result:
                print('legal')
            else:
                print('illegal')


"""
https://programmers.co.kr/learn/courses/30/lessons/12915
"""

class String:
    def __init__(self, val, cmp_idx):
        self.val = val
        self.cmp_idx = cmp_idx

    def __lt__(self, other):
        if self.val[self.cmp_idx] < other.val[other.cmp_idx]:
            return True
        elif self.val[self.cmp_idx] > other.val[other.cmp_idx]:
            return False
        else:
            # 인덱스 cmp_idx 문자가 같은 문자열이 여럿 일 경우,
            # 사전순으로 앞선 문자열이 앞쪽에 위치합니다.
            return self.val < other.val

def solution(strings, n):
    strings = [String(s, n) for s in strings]
    return [s.val for s in sorted(strings)]

assert solution(["sun", "bed", "car"], 1) == ["car", "bed", "sun"]
assert solution(["abce", "abcd", "cdx"], 2) == ["abcd", "abce", "cdx"]

문자열내마음대로 정렬하기.py


__version__ = "1.7"

from curses import wrapper
import getpass
import os
import math
import curses
import argparse
import time
import random
import json

from .globals import *

from mazepy import mazepy
from .curses_utils import curses_utils
from .utils import utils
from .highscores import *
from .gameclasses import Player
from .gameclasses import Goal
from .gameclasses import MazingCell
from .gameclasses import GameGrid
from .GameScreen import GameScreen

#command line args
args=None

def parseCommandLineArgs():
    #parse command line args
    parser = argparse.ArgumentParser(description='MazinGame. A game of maze.')
    parser.add_argument('-l','--level', nargs=1, type=int, metavar='LEVELID',help='Maze level. This integer is a random seed to create the maze.')
    parser.add_argument('-r','--replay', nargs=1, type=int, metavar='GAMEID',help='Replay game with specified id.')
    parser.add_argument('-nf','--nofullscreen', action='store_true', help='Do not use full screen. Default is to show entire maze in terminal, but only if terminal size is larger than the maze.')
    parser.add_argument('--showpath', action='store_true', help='Show shortest path. Remember: this is cheating.')
    parser.add_argument('--showmaze', action='store_true', help='Show entire maze. Remember: this is cheating.')
    parser.add_argument('-hs','--highscores', action='store_true', help='Show high scores. Specify --level to select scores for the level and --cheat to incude cheat scores.')
    parser.add_argument('--cheat', action='store_true', help='Show also cheat highscores.')
    parser.add_argument('-v','--version', action='store_true', help='Show version info.')

    global args
    args = parser.parse_args()

def getHelpLine():
    return "Use cursor keys to move and 'q' to quit."

def start(stdscr,textList):

    height,width = stdscr.getmaxyx()
    if height < FULLSCREEN_MIN_ROWS:
        input("Console screen is too small: %d rows. Full screen needs minimum of %d rows. CTRL-C to exit." % (height,FULLSCREEN_MIN_ROWS))
        return
    if width < FULLSCREEN_MIN_COLS:
        input("Console screen is too small: %d columns. Full screen needs minimum of %d columns. CTRL-C to exit." % (width,FULLSCREEN_MIN_COLS))
        return

    try:
        cursorVisibility=curses.curs_set(0)
    except:
        cursorVisibility=-1
    # Clear screen
    stdscr.clear()
    #call refresh before anything so that pads work
    #http://stackoverflow.com/a/26305933
    stdscr.refresh()

    replayGameId=None
    if args.replay:
        replayGameId=args.replay[0]

    #show welcome screen
    line1="Welcome to MazinGame!"
    if replayGameId is not None:
        line3="REPLAY: game %d" % replayGameId
    else:
        line3="'X' marks the spot. Go there."
    curses_utils.infoWindow(stdscr,line1=line1,line3=line3)

    stdscr.clear()

    useFullTerminal=True
    if args.nofullscreen:
        useFullTerminal=False
    gameScreen=GameScreen(stdscr,useFullTerminal,args)
    level=None
    if args.level:
        level=args.level[0]

    gameScreen.updateStatusLine("Welcome to Maze. 'X' marks the spot. Go there.")#" %s" % getHelpLine())
    if replayGameId is not None:
        #replay
        #get game level and moves from db
        (level,moves)=getGameMoves(replayGameId)
        gameScreen.replayInProgress=True
        gameScreen.initGame(level)
        player=gameScreen.player
        currentRow=player.row
        currentColumn=player.column
        stdscr.nodelay(1)
        statusMsg="complete"
        for move in moves[1:]:
            direction=None
            toRow=move[0]
            toColumn=move[1]
            if toRow>currentRow:
                direction='down'
            if toRow<currentRow:
                direction='up'
            if toColumn>currentColumn:
                direction='right'
            if toColumn<currentColumn:
                direction='left'

            gameScreen.movePlayer(direction)
            currentRow=toRow
            currentColumn=toColumn
            time.sleep(0.1)
            c = stdscr.getch()
            if c == ord('q'):
                statusMsg="aborted"
                break
        textList.append("Replay of game %d %s." % (replayGameId,statusMsg))
    else:
        gameScreen.initGame(level)
        while 1:
            if gameScreen.gameover==False:
                c = stdscr.getch()
            else:
                break
            if c == ord('h'):
                gameScreen.updateStatusLine(getHelpLine())
            elif c == curses.KEY_UP or c== ord('w'):
                gameScreen.movePlayer('up')
            elif c == curses.KEY_DOWN or c== ord('s'):
                gameScreen.movePlayer('down')
            elif c == curses.KEY_LEFT or c== ord('a'):
                gameScreen.movePlayer('left')
            elif c == curses.KEY_RIGHT or c== ord('d'):
                gameScreen.movePlayer('right')
            elif c== ord('i'):
                #info
                player=gameScreen.player
                #gameScreen.gamepad.cursyncup()
                (screenRow,screenColumn)=gameScreen.gamepad.getyx()
                #gameScreen.updateStatusLine("%s screen: (%d,%d) pad corner: (%d,%d)" % (player.__str__(),screenRow,screenColumn,gameScreen.padCornerRow,gameScreen.padCornerColumn))
                gameScreen.updateStatusLine("%s" % (player))
            elif c== ord('I'):
                player=gameScreen.player
                (screenRow,screenColumn)=stdscr.getyx()
                gameScreen.updateStatusLine("%s screen: (%d,%d) pad corner: (%d,%d)" % (player.__str__(),screenRow,screenColumn,gameScreen.padCornerRow,gameScreen.padCornerColumn))
                #gameScreen.updateStatusLine("Screen row,col: (%d,%d)" % (screenRow,screenColumn))
            elif c== ord('T'):
                #stdscr.deleteln()
                #stdscr.insdelln(2)
                infoWindow(stdscr,line1="This is line1",line2="line 2",line3="Then line 3",line4="and line4")
                gameScreen.updateStatusLine("Test: %d" % random.randint(1,99999))
            elif c == ord('q'):
                #utils.debug(time.mktime(time.gmtime()))
                break  # Exit the while()

    if cursorVisibility>-1:
        curses.curs_set(cursorVisibility)

    if not (replayGameId is not None):
        if gameScreen.gameover==True:
            cheat=False
            if args.showpath or args.showmaze:
                cheat=True
            gameid=saveScores(args,__version__,gameScreen.grid,gameScreen.player,gameScreen.goal,gameScreen.level,gameScreen.score,gameScreen.totalMoves,gameScreen.shortestPathLength,gameScreen.elapsed,cheat,gameScreen.grid.algorithm_key)
            textList.append("'X' reached:")
            if gameid == -1:
                textList.append("  Game ID  : %d (score not saved, MazinGame is meant to be run as Docker image)" % gameid)
            else:
                textList.append("  Game ID  : %d" % gameid)
            textList.append("  Level    : %d" % gameScreen.level)
            textList.append("  Algorithm: %s" % gameScreen.grid.algorithm)
            #textList.append("  Braiding : %f" % args.braid)
            textList.append("  Moves    : %d/%d" % (gameScreen.totalMoves,gameScreen.shortestPathLength))
            textList.append("  Elapsed  : %.03fsecs" % gameScreen.elapsed)
            textList.append("  Score    : %d" % gameScreen.score)
            if args.showpath:
                textList.append("  --showpath cheat was active.")
            if args.showmaze:
                textList.append("  --showmaze cheat was active.")
        else:
            textList.append("'X' not reached.")
            #textList.append("  Level  : %d" % gameScreen.level)

def main():
    try:
        parseCommandLineArgs()
        if args.highscores:
            listHighScores(args)
            return
        if args.version:
            print("%s v%s" % (NAME,__version__))
            print("")
            print("\n".join(DESCRIPTION))
            print("")
            print(COPYRIGHT)
            print(LICENSE)
            return
        if args.replay:
            replayGameId=args.replay[0]
            mazeInfo=getMazeInfo(replayGameId)
            if mazeInfo is None:
                print("Can not replay game. No game info.")
                return

        textList=[]
        wrapper(start,textList)
        if textList:
            print("\n".join(textList))
    except KeyboardInterrupt:
        #ignore ctrl-c
        pass

if __name__ == "__main__":
    main()


#!/usr/bin/python3

import requests, os, sys
import exchangeratekey_bb as exchangeratekey

FILENAME = os.path.dirname(sys.argv[0]) + '/exchangerate.txt'
RESPONSEDATA = requests.get("https://openexchangerates.org/api/latest.json", params={'symbols': 'GBP,EUR,JPY', 'app_id': exchangeratekey.APIKEY}).json()
rate = RESPONSEDATA['rates']['JPY'] / RESPONSEDATA['rates']['GBP']
with open(FILENAME, "w") as f:
    f.write(str(rate))


OP_NAMES = ["Identity", "Zero", "ReLUConvBN3x3", "ReLUConvBN1x1", "AvgPool1x1"]
OP_NAMES_NB201 = ['skip_connect', 'none', 'nor_conv_3x3', 'nor_conv_1x1', 'avg_pool_3x3']

EDGE_LIST = ((1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4))

def convert_str_to_op_indices(str_encoding):
    """
    Converts NB201 string representation to op_indices
    """
    nodes = str_encoding.split('+')

    def get_op(x):
        return x.split('~')[0]

    node_ops = [list(map(get_op, n.strip()[1:-1].split('|'))) for n in nodes]

    enc = []
    for u, v in EDGE_LIST:
        enc.append(OP_NAMES_NB201.index(node_ops[v - 2][u - 1]))

    return str(tuple(enc))


import functools
import logging
import socket
import sys
import time
from typing import Any, Callable, Dict, List, TypeVar, cast

import requests
from urllib3.connection import HTTPConnection

_BaseDecoratedFunc = Callable[..., Any]
DecoratedFunc = TypeVar("DecoratedFunc", bound=_BaseDecoratedFunc)

logger = logging.getLogger(__name__)
# Let dead connections stick around for 120 seconds at most
TCP_KEEPALIVE_TIME = 60
TCP_KEEPALIVE_INTERVAL = 10
TCP_KEEPALIVE_PROBE_COUNT = 6

# https://github.com/python/mypy/issues/1927
def time_api(fn: DecoratedFunc) -> DecoratedFunc:
    """A decorator to log the duration of a function call."""
    call_name = fn.__qualname__

    @functools.wraps(fn)
    def _run(*args, **kwargs):
        t1 = time.perf_counter()
        res = fn(*args, **kwargs)
        t2 = time.perf_counter()
        delta = t2 - t1
        # Only log significant function calls (>=10 millis) to avoid unnecessary log lines
        # NOTE: This could hide methods that are called many times and lead to large runtimes
        # on aggregate. In general these aren't common, so we ignore them here. Can always
        # enable finer grained logging later if this doesn't detect perf issues (e.g. overall runtime)
        # is significantly longer than logged runtime)
        if delta < 0.01:
            return res

        logger.info(
            r"TIMING - {\"method\": \"%s\", \"duration\": %.2f}",
            call_name,
            t2 - t1,
        )
        return res

    return cast(DecoratedFunc, _run)

def stats(values: List[float]) -> Dict[str, float]:
    """Calculate percentiles and other summary statistics of a list of values.

    Note: Requires numpy to be installed.
    """
    # Don't require numpy in requirements.txt - not required for main execution and increases image size unnecessarily
    import numpy

    return {
        "25th": numpy.percentile(values, 25),  # type: ignore # https://github.com/Project-MONAI/MONAI/issues/3561
        "50th": numpy.percentile(values, 50),  # type: ignore # https://github.com/Project-MONAI/MONAI/issues/3561
        "75th": numpy.percentile(values, 70),  # type: ignore # https://github.com/Project-MONAI/MONAI/issues/3561
        "90th": numpy.percentile(values, 90),  # type: ignore # https://github.com/Project-MONAI/MONAI/issues/3561
        "95th": numpy.percentile(values, 95),  # type: ignore # https://github.com/Project-MONAI/MONAI/issues/3561
        "99th": numpy.percentile(values, 99),  # type: ignore # https://github.com/Project-MONAI/MONAI/issues/3561
        "99.9th": numpy.percentile(values, 99.9),  # type: ignore # https://github.com/Project-MONAI/MONAI/issues/3561
        "mean": float(numpy.mean(values)),
        "stdev": float(numpy.std(values)),
        "median": numpy.median(values),  # type: ignore # https://github.com/Project-MONAI/MONAI/issues/3561
        "count": len(values),
        "total": sum(values),
        "max": max(values),
        "min": min(values),
    }

def _set_socket_options():
    """Turn on TCP keepalive for the HTTPConnection object."""
    logger.debug("Current socket options: %s", HTTPConnection.default_socket_options)
    for platforms, protocol, constant, value in (
        # Keepalive on Linux
        (("linux",), socket.IPPROTO_TCP, "TCP_KEEPIDLE", TCP_KEEPALIVE_TIME),
        # Shared between Linux and Mac
        (
            ("linux", "darwin"),
            socket.IPPROTO_TCP,
            "TCP_KEEPINTVL",
            TCP_KEEPALIVE_INTERVAL,
        ),
        (
            ("linux", "darwin"),
            socket.IPPROTO_TCP,
            "TCP_KEEPCNT",
            TCP_KEEPALIVE_PROBE_COUNT,
        ),
        # Turns KeepAlive on
        (("linux", "darwin"), socket.SOL_SOCKET, "SO_KEEPALIVE", 1),
        # Keepalive on MacOS
        # Not exposed in socket library, found from tcp.h:
        # https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/netinet/tcp.h#L206
        (("darwin",), socket.IPPROTO_TCP, 0x10, TCP_KEEPALIVE_TIME),
    ):
        if sys.platform not in platforms:
            continue
        if isinstance(constant, str) and not hasattr(socket, constant):
            continue  # pragma: nocover # Windows only case, don't test
        elif isinstance(constant, str):
            constant = getattr(socket, constant)
        opts = (protocol, constant, value)
        logger.debug("Setting socket options: %s", opts)
        HTTPConnection.default_socket_options.append(opts)

@functools.lru_cache(maxsize=1)
def shared_session() -> requests.Session:
    """Get a global requests.Session object shared by all methods, which ensures TCP keepalive is enabled."""
    _set_socket_options()
    return requests.Session()

cookiecutters/python_core/{{ cookiecutter.project_name }}/{{ cookiecutter.project_slug }}/common.py


import operators as op
from state import State, GridField

class SweLinearOperator:

    def __init__(self, g, H, pcori, diff_method):
        self.g = g
        self.H = H
        self.pcori = pcori
        self.diff_method = diff_method

    def calc_rhs(self, state, domains):
        gx, gy = op.calc_grad(state.h, domains, self.diff_method)
        div = op.calc_div(state.u, state.v, domains, self.diff_method)
        return State(- self.g * gx + self.pcori * state.v,
                     - self.g * gy - self.pcori * state.u,
                     - self.H * div)

class SweVecInvFormOperator:

    def __init__(self, g, pcori, diff_method):
        self.g = g
        self.pcori = pcori
        self.diff_method = diff_method

    def calc_rhs(self, state, domains):
        div = op.calc_div(state.h * state.u, state.h * state.v, domains, self.diff_method)

        kin_energy = (state.u * state.u + state.v * state.v) * 0.5
        gx, gy = op.calc_grad(self.g * state.h + kin_energy, domains, self.diff_method)

        curl = op.calc_curl(state.u, state.v, domains, self.diff_method)

        return State(-1.0*gx + (curl + self.pcori) * state.v,
                     -1.0*gy - (curl + self.pcori) * state.u,
                     -1.0*div)

class SweAdvectiveFormOperator:

    def __init__(self, g, pcori, diff_method):
        self.g = g
        self.pcori = pcori
        self.diff_method = diff_method

    def calc_rhs(self, state, domains):
        gx, gy = op.calc_grad(state.h, domains, self.diff_method)
        div = op.calc_div(state.h * state.u, state.h * state.v, domains, self.diff_method)

        du_dx, du_dy = op.calc_grad(state.u, domains, self.diff_method)
        dv_dx, dv_dy = op.calc_grad(state.v, domains, self.diff_method)

        return State(-1.0 * self.g * gx + self.pcori * state.v - du_dx * state.u - du_dy * state.v,
                     -1.0 * self.g * gy - self.pcori * state.u - dv_dx * state.u - dv_dy * state.v,
                     -1.0 * div)

class SweOnlyAdvection:

    def __init__(self, g, pcori, diff_method):
        self.g = g
        self.pcori = pcori
        self.diff_method = diff_method

    def calc_rhs(self, state, domains):
        gx, gy = op.calc_grad(state.h, domains, self.diff_method)

        return State(GridField.zeros(domains),
                     GridField.zeros(domains),
                     - 1.0 * state.u * gx - 1.0 * state.v * gy)


#!/usr/bin/env python

'''
Use SNMPv3 to detect when a router configuration changes, and send an e-mail notfication

Write a class that stores state in a Python Pickle file, a .json file, or a .yml file.
    Pass the state file to be created / updated in the constructor
    Choode the method based on the filename specified.

Write a driver script (could be the main() method in the file) which could be called by a cron job.
    The driver would instantiate the config_changes class and read its state file

Ex 1. Using SNMPv3 create a script that detects router configuration changes.

If the running configuration has changed, then send an email notification to yourself identifying the router that changed and the time that it changed.

Note, the running configuration of pynet-rtr2 is changing every 15 minutes (roughly at 0, 15, 30, and 45 minutes after the hour).  This will allow you to test your script in the lab environment.

In this exercise, you will possibly need to save data to an external file. One way you can accomplish this is by using a pickle file, see:
    http://youtu.be/ZJOJjyhhEvM

A pickle file lets you save native Python data structures (dictionaries, lists, objects) directly to a file.

Here is some additional reference material that you will probably need to solve this problem:

Cisco routers have the following three OIDs:

# Uptime when running config last changed
ccmHistoryRunningLastChanged = '1.3.6.1.4.1.9.9.43.1.1.1.0'

# Uptime when running config last saved (note any 'write' constitutes a save)
ccmHistoryRunningLastSaved = '1.3.6.1.4.1.9.9.43.1.1.2.0'

# Uptime when startup config last saved
ccmHistoryStartupLastChanged = '1.3.6.1.4.1.9.9.43.1.1.3.0'

From the above descriptions, the router will save the sysUptime timestamp (OID sysUptime = 1.3.6.1.2.1.1.3.0) when a running configuration change occurs. The router will also record the sysUptime timestamp when the running configuration is saved to the startup config.
Here is some data on the behavior of these OIDs. Note, sysUptime times are in hundredths of seconds so 317579 equals 3175.79 seconds (i.e. a bit less than one hour)

# After reboot
pynet-rtr2.twb-tech.com
317579        (sysUptime)
2440            (ccmHistoryRunningLastChanged--running-config is changed during boot)
0                  (ccmHistoryRunningLastSaved -- i.e. reset to 0 on reload)
0                  (ccmHistoryStartupLastChanged -- i.e. reset to 0 on reload)

# After config change on router (but no save to startup config)
pynet-rtr2.twb-tech.com
322522        (sysUptime)
322219        (ccmHistoryRunningLastChanged)
0                  (ccmHistoryRunningLastSaved)
0                  (ccmHistoryStartupLastChanged)

# After 'write mem' on router
pynet-rtr2.twb-tech.com
324543        (sysUptime)
322219        (ccmHistoryRunningLastChanged)
323912        (ccmHistoryRunningLastSaved)
323912        (ccmHistoryStartupLastChanged)

# After another configuration change (but no save to startup config)
pynet-rtr2.twb-tech.com
327177        (sysUptime)
326813        (ccmHistoryRunningLastChanged)
323912        (ccmHistoryRunningLastSaved)
323912        (ccmHistoryStartupLastChanged)

# After 'show run' command (note, this causes 'ccmHistoryRunningLastSaved' to
# increase i.e. 'write terminal' causes this OID to be updated)
pynet-rtr2.twb-tech.com
343223        (sysUptime)
326813        (ccmHistoryRunningLastChanged)
342898        (ccmHistoryRunningLastSaved)
323912        (ccmHistoryStartupLastChanged)

Bonus challenge: instead of saving your data in a pickle file, save the data using either a YAML or a JSON file.

My alternate solution supports pickle, YAML, or JSON depending on the name of the file (.pkl, .yml, or .json).

Input files:
    router list file:
        Contains a list of dictionaries, with the following format:
            [
                {
                    'router': 'hostname1',
                    'ip_addr': 'router1_ip_addr',
                    'community': 'snmp_community',
                    'port': snmp_port
                },
                {
                    'router': 'hostname2',
                    'ip_addr': 'router2_ip_addr',
                    'community': 'snmp_community',
                    'port': snmp_port
                }
            ]
    state file:
        Contains a dictionary of two dictionaries: lastRebootTime and lastConfigChangeTime.
        The router name is the key, and the time is the value.
            {
                'lastRebootTime': {
                    'router_name1': 1,
                    'router_name2': 22,
                    'router_name3': 333,
                    'router_name4': 4444,
                    'router_name5': 55555
                },
                'lastConfigChangeTime': {
                    'router_name1': 88888,
                    'router_name2': 77777,
                    'router_name3': 6666,
                    'router_name4': 54444,
                    'router_name5': 555552
                }
            }

Parameters:
    check interval in seconds
    Yaml file or json file containing state
    Yaml or Json file containing router list

Algorithm:
    load routerList from router list file
    Get current date from OS
    For router in routerList:
        SNMP-Get router sysUptime
        routerRebootTime = date - sysUptime
        SNMP-Get current ccmHistoryRunningLastChanged
        runningLastChangedTime = routerRebootTime + ccmHistoryRunningLastChanged
        runningConfigChanged = False
        If state file:
            routerRebootTimeS = stateFile.routerRebootTime
            runningLastChangedTimeS = stateFile.runningLastChangedTime
            If routerRebootTime > routerRebootTimeS
                routerRebooted = True
                routerRebootTimeS = routerRebootTime
            If runningLastChangedTime > runningLastChangedTimeS:
                If !routerRebooted or (ccmHistoryRunningLastChanged > ROUTER_REBOOT_SECONDS):
                    runningConfigChanged = True
                    runningLastChangedTimeS = runningLastChangedTime
            if runningConfigChanged:
                send email
        stateFile.dump(routerRebootTimeS, runningLastChangedTimeS)

'''
import sys
import pickle
import yaml
import json
import time
import snmp_helper
import email_helper
from collections import namedtuple

ROUTER_REBOOT_SECONDS = 300 * 100 # converted to timeticks aka 100ths of a second
PICKLE_STATE_FILE = "Router_Reboot_Check.p"
SYSUPTIME_OID = '1.3.6.1.2.1.1.3.0'
RUNNINGLASTCHANGED_OID = '1.3.6.1.4.1.9.9.43.1.1.1.0'
EMAIL_SUBJECT = "%s configuration change detected"
EMAIL_MESSAGE_BODY = "Configuration on router %s was last changed at %s"
DEBUG = False
NetworkDevice = namedtuple("my_name", "field1 field2 field3")

class Router_Reboot_Check(object):
    def __init__(self, router_list_file, state_file, email_sender, email_recipients,
                 router_reboot_seconds=ROUTER_REBOOT_SECONDS):
        self.router_list_file = router_list_file
        self.state_file = state_file
        self.email_sender = email_sender
        self.email_recipients = email_recipients
        self.router_reboot_seconds = router_reboot_seconds

        try:
            if router_list_file.endswith("yml"):
                self.router_list = yaml.load(open(router_list_file, 'r'))
            elif router_list_file.endswith("json"):
                self.router_list = json.load(open(router_list_file, 'r'))
            else:
                sys.exit("Must specify router list as a .yml or .json file")
        except IOError as ioe:
            sys.exit("Cannot load router list file: %s" % router_list_file)
        if DEBUG:
            print("Router List: " + str(self.router_list))
        try:
            if state_file.endswith("yml"):
                self.state = yaml.load(open(state_file, 'r'))
            elif state_file.endswith("json"):
                self.state = json.load(open(state_file, 'r'))
            else:
                self.state = pickle.load(open(PICKLE_STATE_FILE, 'rb'))
        except IOError as ioe:
            self.state = {}
        if DEBUG:
            print("State length: %s, State: %s" % (len(self.state), str(self.state)))

    def check_routers(self):
        timestamp = int(time.time())
        if DEBUG:
            print("My time is: %s" % time.ctime(timestamp))
        for router in self.router_list:
            routerRebooted = False
            routerTuple = (router['ip_addr'], router['community'], router['port'])
            routerUptimeOIDData = snmp_helper.snmp_get_oid(routerTuple, SYSUPTIME_OID)
            routerUptime = int(float(snmp_helper.snmp_extract(routerUptimeOIDData)) / 100)
            routerRebootTime = timestamp - routerUptime

            lastConfigChangeSecondsOIDData = snmp_helper.snmp_get_oid(routerTuple, RUNNINGLASTCHANGED_OID)
            lastConfigChangeSeconds = int(float(snmp_helper.snmp_extract(lastConfigChangeSecondsOIDData)) / 100)
            runningLastChangedTime = routerRebootTime + lastConfigChangeSeconds
            if DEBUG:
                print("Router: %s     uptime: %s    reboot time: %s    last config change seconds: %s    running last changed time %s" % (router['router'], routerUptime, time.ctime(routerRebootTime), lastConfigChangeSeconds, time.ctime(runningLastChangedTime)))

            if len(self.state) == 0:
                self.state['lastRebootTime'] = {}
                self.state['lastConfigChangeTime'] = {}
            if router['router'] not in self.state['lastRebootTime'].keys():
                self.state['lastRebootTime'][router['router']] = routerRebootTime
                self.state['lastConfigChangeTime'][router['router']] = runningLastChangedTime
            if routerRebootTime > self.state['lastRebootTime'][router['router']]:
                routerRebooted = True
                self.state['lastRebootTime'][router['router']] = routerRebootTime
            if runningLastChangedTime > self.state['lastConfigChangeTime'][router['router']]:
                if not routerRebooted or (lastConfigChangeSeconds > ROUTER_REBOOT_SECONDS):
                    self.__send_email_alert(router['router'], runningLastChangedTime)
                self.state['lastConfigChangeTime'][router['router']] = runningLastChangedTime
        self.__dump_state()

    def __send_email_alert(self, router_name, lastChangedTime):
        for email_recipient in self.email_recipients:
            subject = str(EMAIL_SUBJECT % router_name)
            message = str(EMAIL_MESSAGE_BODY % (router_name, time.ctime(lastChangedTime)))
            print("Sending mail to %s with subject \"%s\" and message \"%s\" from %s" %
                  (email_recipient, subject, message, self.email_sender))
            email_helper.send_mail(email_recipient, subject, message, self.email_sender)

    def __dump_state(self):
        try:
            if self.state_file.endswith("yml"):
                with open(self.state_file, "w") as f:
                    f.write(yaml.dump(self.state, default_flow_style=False))
            elif self.state_file.endswith("json"):
                json.dump(self.state, open(self.state_file, 'w'))
            else:
                pickle.dump(self.state, open(self.state_file, "wb"))
        except IOError:
            sys.exit("Could not write state file %s" % self.state_file)

def main():
    if len(sys.argv) < 4:
        sys.exit("Usage: %s <router_list_file> <email_sender> <email_recipient1> [state_file] [email_recipient2] ..." % sys.argv[0])
    router_list_file = sys.argv[1]
    email_sender = sys.argv[2]
    email_recipients = [sys.argv[3]]
    state_file = ""
    if len(sys.argv) > 4:
        if sys.argv[4].endswith("yml") or sys.argv[4].endswith("json"):
            state_file = sys.argv[4]
        else:
            email_recipients.append(sys.argv[4])
            state_file = PICKLE_STATE_FILE
    for remainingArg in sys.argv[5:len(sys.argv)]:
        email_recipients.append(remainingArg)
    if DEBUG:
        print("Script name: %s, router_list_file: %s, state_file: %s, email_sender: %s, email_recipients: %s"
              % (sys.argv[0], router_list_file, state_file, email_sender, str(email_recipients)))
    my_router_reboot_check = Router_Reboot_Check(router_list_file, state_file, email_sender, email_recipients)
    my_router_reboot_check.check_routers()

if __name__ == "__main__":
    main()


from launch_ros.actions import ComposableNodeContainer, SetParameter, Node
from launch_ros.substitutions import FindPackageShare
from launch_ros.descriptions import ComposableNode, ParameterFile
from nav2_common.launch import RewrittenYaml
from launch.actions import DeclareLaunchArgument, GroupAction
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch import LaunchDescription
def generate_launch_description():
    autostart = LaunchConfiguration('autostart')
    params_file = LaunchConfiguration('params_file')
    use_sim_time = LaunchConfiguration('use_sim_time')
    map_file = LaunchConfiguration('map_file')
    param_substitutions = {'autostart': autostart}
    remappings = [
        ('/tf', 'tf'),
        ('/tf_static', 'tf_static')
    ]
    autostart_argument = DeclareLaunchArgument('autostart', default_value='True')
    params_file_argument = DeclareLaunchArgument('params_file',
        default_value=PathJoinSubstitution((FindPackageShare('nav2_bringup'), 'params', 'nav2_params.yaml')))
    use_sim_time_argument = DeclareLaunchArgument('use_sim_time', default_value='False')
    map_file_argument = DeclareLaunchArgument('map_file',
        default_value=PathJoinSubstitution((FindPackageShare('nfr_charged_up'), 'config', 'map.yaml')))
    configured_params = ParameterFile(
        RewrittenYaml(
            source_file=params_file,
            param_rewrites=param_substitutions,
            convert_types=True
        ),
        allow_substs=True
    )
    controller_node = ComposableNode(
        package='nav2_controller',
        plugin='nav2_controller::ControllerServer',
        name='controller_server',
        parameters=[configured_params],
        remappings=remappings
    )
    smoother_node = ComposableNode(
        package='nav2_smoother',
        plugin='nav2_smoother::SmootherServer',
        name='smoother_server',
        parameters=[configured_params],
        remappings=remappings
    )
    planner_node = ComposableNode(
        package='nav2_planner',
        plugin='nav2_planner::PlannerServer',
        name='planner_server',
        parameters=[configured_params],
        remappings=remappings
    )
    behavior_node = ComposableNode(
        package='nav2_behaviors',
        plugin='behavior_server::BehaviorServer',
        name='behavior_server',
        parameters=[configured_params],
        remappings=remappings
    )
    bt_navigator_node = ComposableNode(
        package='nav2_bt_navigator',
        plugin='nav2_bt_navigator::BtNavigator',
        name='bt_navigator',
        parameters=[configured_params],
        remappings=remappings
    )
    waypoint_follower_node = ComposableNode(
        package='nav2_waypoint_follower',
        plugin='nav2_waypoint_follower::WaypointFollower',
        name='waypoint_follower',
        parameters=[configured_params],
        remappings=remappings
    )
    velocity_smoother_node = ComposableNode(
        package='nav2_velocity_smoother',
        plugin='nav2_velocity_smoother::VelocitySmoother',
        name='velocity_smoother',
        parameters=[configured_params],
        remappings=remappings
    )
    lifecycle_manager_node = ComposableNode(
        package='nav2_lifecycle_manager',
        plugin='nav2_lifecycle_manager::LifecycleManager',
        name='lifecycle_manager_navigation',
        parameters=[{
            'autostart': autostart,
            'node_names': [
                'controller_server',
                'smoother_server',
                'planner_server',
                'behavior_server',
                'bt_navigator',
                'waypoint_follower',
                'velocity_smoother'
            ]
        }]
    )
    map_node = ComposableNode(
        package='nav2_map_server',
        plugin='nav2_map_server::MapServer',
        name='map_server',
        parameters=[{
            'yaml_filename': map_file
        }]
    )
    lifecycle_map_node = ComposableNode(
        package='nav2_lifecycle_manager',
        plugin='nav2_lifecycle_manager::LifecycleManager',
        name='lifecycle_manager_map',
        parameters=[{
            'autostart': autostart,
            'node_names': ['map_server']
        }]
    )
    return LaunchDescription([
        autostart_argument,
        params_file_argument,
        use_sim_time_argument,
        map_file_argument,
        GroupAction(
            [
                SetParameter('use_sim_time', use_sim_time),
                ComposableNodeContainer(
                    package='rclcpp_components',
                    name='navigation_container',
                    executable='component_container_mt',
                    namespace='',
                    composable_node_descriptions=[
                        controller_node,
                        smoother_node,
                        planner_node,
                        behavior_node,
                        bt_navigator_node,
                        waypoint_follower_node,
                        velocity_smoother_node,
                        lifecycle_manager_node
                    ]
                )
            ]
        ),
        GroupAction(
            [
                SetParameter('use_sim_time', use_sim_time),
                ComposableNodeContainer(
                    package='rclcpp_components',
                    name='map_container',
                    executable='component_container_mt',
                    namespace='',
                    composable_node_descriptions=[
                        map_node,
                        lifecycle_map_node
                    ]
                )
            ]
        )
    ])


from matplotlib.ticker import Locator
from enum import Enum
from bisect import bisect_right
import numpy as np
import logging as log
import re
import os

# Failure metric to be used in visualizations and other output
FI_METRIC = "AVF"

# Separators used to display instance trees on the shell
FI_SEPS = { "vert"  : "|",
            "int"   : "|-- ",
            "ext"   : "+-- ",
            "pad"   : "   ",
            "empty" : " ",
            "edge"  : "\"__ID__\" -> \"__ID2__\"\n",
            "shape" : "\"__ID__\" [label=\"__LABEL__\", shape=box]\n"}

# Enum used for indexing the different columns in an HDFIT CSV results file
class HDFIT(Enum):
    rank        = 0
    opCntExp    = 1
    opFi        = 2
    fiBit       = 3
    opCnt       = 4
    testPass    = 5
    testFail    = 6
    retCode     = 7
    time        = 8
    nrmse       = 9
    rtlError    = 10
    assignUUID  = 11
    moduleChain = 12
    moduleName  = 13

# ------------------------ Processing Netlist module info ------------------------

def parseModuleName(name, legacy=True):
    """
    Sanitizes a Netlist module name.

    This function removes all metadata within a Netlist module name string
    (e.g., the paramod, WIDTH and RESIDUE) fields, returning only the compact
    name of the module itself.

    Parameters:
        name (string): Full Netlist module name
        legacy (bool): If True, uses older VeriFI parsing conventions

    Returns:
        string: Sanitized version of name
    """
    nameL = [el.strip() for el in name.split("\\" if legacy else "\\\\") if el.strip()!=""]
    return nameL[0] if len(nameL)==1 else nameL[1]

def extractModules(fPath, legacy=True):
    """
    Parses module info from a VeriFI source file.

    This function is able to parse a VeriFI .cpp source file containing the
    static specification fo fault injection signals in a given Netlist (i.e.,
    detailing modules, signals contained therein and their features). It then
    returns a list of top-level module names that were identified, together
    with the list of signal ID ranges associated with each.

    BE CAREFUL: the values in sigs represent the first signal ID for each
    module, but these values are not guaranteed to be in sorted order.

    Parameters:
        fPath (string): Path to a .cpp VeriFI source file
        legacy (bool): If True, uses older VeriFI parsing conventions

    Returns:
        list[string]: Found module names
        list[int]:    Signal ID ranges for each module
    """
    f = open(fPath, "r")
    fText = f.read()
    f.close()

    mods = []
    sigs = []

    # Finding all module names
    for mod in re.finditer("{\n\s*\".+\",\n\s*{", fText):
        # Finding first signal within each module
        sig = re.search(",\n\s*[0-9]+,\n\s*},", fText[mod.span()[0]:-1])

        if sig is None:
            raise ValueError("Error encountered while extracting module information from %s!" % fPath)

        mods.append(parseModuleName(re.search("(?<=\").+(?=\")", mod.group(0)).group(0), legacy))
        sigs.append(int(re.search("[0-9]+(?=,)", sig.group(0)).group(0)))

    return np.asarray(mods), np.asarray(sigs)

def extractInstances(fPath, legacy=True):
    """
    Parses instance info from a VeriFI source file.

    This function parses a VeriFI .cpp source, similarly to extractModules(),
    and extract all information associated with module instances, which use their
    own UUID scheme. The function then returns a dictionary which maps each
    instance UUID (e.g., as found in the module instance chain CSV field) to
    the respective module name.

    Parameters:
        fPath (string): Path to a .cpp VeriFI source file
        legacy (bool): If True, uses older VeriFI parsing conventions

    Returns:
        dict{string : string}: Dictionary mapping UUIDs to instances
    """
    mods, sigs = extractModules(fPath, legacy)
    f = open(fPath, "r")
    fText = f.read()
    f.close()

    instDict = {}

    # Finding all instances
    for mod in re.finditer("(?<={)[0-9]+, [0-9]+(?=},)", fText):
        instTup = mod.group(0).split(", ")
        instDict[instTup[1]] = mods[int(instTup[0])]

    # Adding top element
    instDict["1"] = "Top"

    return instDict

def searchModules(uuids, sigs):
    """
    Binary seach utility function.

    This function encapsulates a call to bisect_right in order to perform binary
    search on a given array. It is used to identify the modules to which the signals
    in a given input list belong.

    Parameters:
        uuids (list[int]): Signal IDs acting as keys
        sigs (list[int]): List of signal ID ranges over which to search

    Returns:
        list[int]: List of indexes of the module names to which the uuids belong
    """
    idxSigs = np.argsort(sigs)
    sortSigs = sigs[idxSigs]

    indexes = []
    for u in uuids:
        # Searching UUID within sorted list of module signal ranges
        uIdx = bisect_right(sortSigs, u) - 1
        # Mapping index to original unsorted list
        # A value of -1 implies no module was found
        indexes.append(idxSigs[uIdx] if uIdx >= 0 else -1)

    return indexes

def loadModuleData(uuids, fPath, legacy=True):
    """
    Utility function for loading module data.

    This utility function combines loading of module data from a VeriFI source
    (via extractModules) and mapping of a list of signal IDs to modules (via
    searchModules).

    Parameters:
        uuids (list[int]): List of signal IDs to be mapped to modules
        fPath (string): Path to a .cpp VeriFI source file
        legacy (bool): If True, uses older VeriFI parsing conventions

    Returns:
        list[string]: Module names associated with each uuids element
        list[string]: Found module names
        list[int]:    Signal ID ranges for each module
    """
    mods, sigs = extractModules(fPath, legacy)
    modsOut = [mods[el] if el>=0 else "NONE" for el in searchModules(uuids, sigs)]

    return np.asarray(modsOut), mods, sigs

def dumpModuleData(fPathIn, mods):
    """
    Augments an HDFIT CSV file with module name data

    This function will add a new column to an arbitrary HDFIT CSV results
    file, containing module name information for each injection signal, as
    computed by loadModuleData or in an equivalent way. The new CSV file can
    be distinguished from the original via the _modules suffix.

    Parameters:
        fPathIn (string): Path to an HDFIT CSV results file
        mods (list[string]): Module names associated with rows in fPathIn
    """
    fIn  = open(fPathIn, "r")
    fOut = open(fPathIn[0:-4] + "_modules.csv", "w")

    header = fIn.readline()[0:-1] + ", module name\n"
    fOut.write(header)

    mIdx = 0
    for l in fIn:
        fOut.write(l[0:-1] + ", " + mods[mIdx] + "\n")
        mIdx = mIdx + 1

    fIn.close()
    fOut.close()

# ------------------------ Instance tree build functions ------------------------

def generateTree(instD, chains, failures, plot_rate, full_tree, tree_depth):
    """
    Generate a tree structure based on failure data

    This function generates a dictionary describing the RTL instance tree for
    a given hardware component, computing vulnerability metrics in the process.
    The function's output is a dictionary, in which every element is associated
    with a node in the tree: keys are represented by instance chains up to the
    node's level (i.e., the path from the root to the node in the tree). Individual
    instances within the key may be identified by their raw UUID or by their
    human-readable name according to the full_tree option.

    Each element's value is then represented by a tuple, in which the first field
    is a set containing the keys to the node's children, while the second and third
    field contain the number of failure occurrences and total injections respectively,
    for the given node.

    Parameters:
        instD (dict{string : string}): Dictionary mapping UUIDs to instances,
            generated by the extractInstances function
        chains (list[string]): List of dash-separated UUID instance chains, one
            for each experiment run
        failures (list[bool]): List of failure occurrences associated with
            the supplied instance chains
        plot_rate (bool): If True, a failure rate value is generated for each node
            instead of the absolute number of failure occurrences
        full_tree (bool): If True, duplicated instances at the same tree level
            are not merged into one and the full tree is generated instead. Note
            that if this option is selected, the raw UUID instance chains are used
            as keys to distinguish instances that have the same name
        tree_depth (int): Depth limit for the tree

    Returns:
        string: Key of the root node in the tree
        dict{string : (set(string), int, int)}): Dictionary describing
            the overall tree structure based on the instance chains
    """
    rootNode = instD["1"] if not full_tree else "1"
    instTree = {rootNode : [set(), 0, 0]}

    # Iterating over instance chains and updating nodes
    for i in range(len(chains)):
        # Checking for invalid instance chains
        if any(c=="0" for c in chains[i].split("-")):
            log.warning("Invalid instance chain %s detected. Skipping..." % chains[i])
            continue
        iChain = [instD[c] if not full_tree else c for c in chains[i].split("-")]
        iDepth = int(np.min((tree_depth+1, len(iChain))))
        node   = iChain[0]
        for j in range(1, iDepth):
            node   = "-".join(iChain[0:j+1])
            parent = "-".join(iChain[0:j])
            instTree = updateNode(instTree, parent, node, failures[i])
        instTree = updateNode(instTree, node, None, failures[i])

    # Adjusting failure occurrences into failure rate values if required
    if plot_rate:
        for k in instTree.keys():
            instTree[k][1] = instTree[k][1]/instTree[k][2]*100 if instTree[k][2]!=0 else 0

    return rootNode, instTree

def updateNode(treeDict, key, child, fail_occ):
    """
    Internal function for updating instance tree elements

    This function is meant for internal use only. It updates the tree dictionary
    maintained by the generateTree function, adding new information about nodes.

    Parameters:
        treeDict (dict{string : (set(string), int, int)}): Dictionary describing
            the tree structure, created by the generateTree function
        key (string): Key of node to be updated
        child (string): Key of child to be added to node
        fail_occ (bool): If True, adds a new failure occurrence to the node

    Returns:
        dict{string : (set(string), int, int)}: Updated tree dict structure
    """
    if key not in treeDict:
        treeDict[key] = [set(), 0, 0]
    if child is not None:
        treeDict[key][0].add(child)
    treeDict[key][1] = treeDict[key][1] + fail_occ
    treeDict[key][2] = treeDict[key][2] + 1
    return treeDict

def displayTree(key, instTree, instDict, plot_rate, lc=True, padPre=""):
    """
    Display an HDFIT instance tree on the shell

    This function is able to display an HDFIT instance tree built using
    the generateTree function on the shell, optionally creating a Dot
    code representation that can be visualized through any external
    Graphviz engine. This function is recursive: the lc and padPre
    arguments are meant to steer the internal recursion and are not
    to be set externally.

    Parameters:
        key (string): Key of the root node from which to start
        instTree (dict{string : (set(string), int, int)}): Dictionary describing
            the tree structure, created by the generateTree function
        instDict (dict{string : string}): Dictionary mapping UUIDs to instances,
            generated by the extractInstances function
        plot_rate (bool): If True, the failure rate is shown, else the occurrences

    Returns:
        string: String with representation for Dot visualization
    """
    nodeName  = formatTreeNode(key, instTree, instDict, plot_rate)
    # Determining padding string for this node's children
    padPost = padPre + (FI_SEPS["vert"] if not lc else FI_SEPS["empty"]) + FI_SEPS["pad"]
    # Adding new shape to graphviz dot string
    shapes  = FI_SEPS["shape"].replace("__ID__", key).replace("__LABEL__", nodeName)
    edges   = ""

    # Display string for this node
    print(padPre + (FI_SEPS["int"] if not lc else FI_SEPS["ext"]) + nodeName)

    # Constructing ordered list of child - failure rate pairs
    childList = [[el, instTree[el][1]] for el in instTree[key][0]]
    childList.sort(key = lambda x : x[1], reverse = True)
    # Iterating over children
    for idx in range(len(childList)):
        c   = childList[idx]
        # Iterating over children
        s, e  = displayTree(c[0], instTree, instDict, plot_rate, idx >= len(childList) - 1, padPost)
        # Adding new shapes and edges
        shapes  = shapes + s
        edges   = edges + FI_SEPS["edge"].replace("__ID__", key).replace("__ID2__", c[0]) + e
    return formatGraphviz(shapes, edges) if padPre=="" else (shapes, edges)

def formatTreeNode(key, instTree, instDict, plot_rate):
    """
    Generates a string for showing a single instance tree node

    This utility function generates a string for a given node in the instance
    tree, showing its name coupled with the associated failure rate or absolute
    number of occurrences.

    Parameters:
        key (string): Key of the target node
        instTree (dict{string : (set(string), int, int)}): Dictionary describing
            the tree structure, created by the generateTree function
        instDict (dict{string : string}): Dictionary mapping UUIDs to instances,
            generated by the extractInstances function
        plot_rate (bool): If True, the failure rate is shown, else the occurrences

    Returns:
        string: String with information for the given node
    """
    frStr    = str(instTree[key][1]) if not plot_rate else '{:.4f}'.format(instTree[key][1]) + "%"
    nodeName = (key.split("-")[-1] if instDict is None else instDict[key.split("-")[-1]]) + ": " + frStr
    return nodeName

def formatGraphviz(shapes, edges):
    """
    Generates a Dot representation for a given instance tree

    This function takes as input the list of shapes and edges created
    within the displayTree function, and outputs a Dot representation
    that can be displayed via any Graphviz engine.

    Parameters:
        shapes (string): String containing Dot shapes
        edges (string): String containing Dot edges

    Returns:
        string: String with representation for Dot visualization
    """
    dotStr = "digraph tree {\n"
    dotStr = dotStr + "rankdir=\"LR\"\n"
    dotStr = dotStr + shapes + "\n" + edges + "}\n"
    return dotStr

# ------------------------ Data loading and processing ------------------------

def loadData(fault_log):
    """
    Reads fault data from a CSV file.

    This function parses an HDFIT CSV results file and returns a dictionary,
    where each element is a list corresponding to a column in the file.
    Elements in the dictionary are indexed via the HDFIT enum class. Note
    that not all of the column available in CSV files are currently parsed,
    but only those that are actively needed by other plotting functions.

    Parameters:
        fault_log (string): Path to an HDFIT CSV results file

    Returns:
        dict: Dictionary with parsed HDFIT data
    """
    fDict = {}
    # Read failure results from the log file
    fDict[HDFIT.opCntExp] = np.genfromtxt(fault_log, skip_header=1, delimiter=',', usecols=1, dtype=np.int64)
    fDict[HDFIT.opFi] = np.genfromtxt(fault_log, skip_header=1, delimiter=',', usecols=2, dtype=np.int64)
    fDict[HDFIT.fiBit] = np.genfromtxt(fault_log, skip_header=1, delimiter=',', usecols=3, dtype=int)
    fDict[HDFIT.opCnt] = np.genfromtxt(fault_log, skip_header=1, delimiter=',', usecols=4, dtype=np.int64)
    fDict[HDFIT.testFail] = np.genfromtxt(fault_log, skip_header=1, delimiter=',', usecols=6, dtype=int)
    # Read SDE errors (if available)
    try:
        fDict[HDFIT.nrmse] = np.genfromtxt(fault_log, skip_header=1, delimiter=',', usecols=9, dtype=float)
    except ValueError:
        log.warning("File %s does not appear to contain NRMSE error data." % fault_log)
        fDict[HDFIT.nrmse] = np.zeros(fDict[HDFIT.testFail].shape)
    # Replace NaNs with Infs to simplify processing
    fDict[HDFIT.nrmse] = np.where(np.isnan(fDict[HDFIT.nrmse]), np.inf, fDict[HDFIT.nrmse])
    # Read RTL error status (if available)
    try:
        fDict[HDFIT.rtlError] = np.genfromtxt(fault_log, skip_header=1, delimiter=',', usecols=10, dtype=int)
        fDict[HDFIT.assignUUID] = np.genfromtxt(fault_log, skip_header=1, delimiter=',', usecols=11, dtype=int)
        fDict[HDFIT.moduleChain] = np.genfromtxt(fault_log, skip_header=1, delimiter=',', usecols=12, dtype=str)
    except ValueError:
        log.warning("File %s does not appear to contain RTL-related data." % fault_log)
        fDict[HDFIT.rtlError] = np.zeros(fDict[HDFIT.testFail].shape)
        fDict[HDFIT.assignUUID] = np.zeros(fDict[HDFIT.testFail].shape)
        fDict[HDFIT.moduleChain] = np.zeros(fDict[HDFIT.testFail].shape)

    return fDict

def filterData(dataDict, bit_pos, exclude_uoe, exclude_rtl):
    """
    Produces a mask for excluding runs from an HDFIT experiment.

    This function computes a "mask" list starting from a data
    dictionary loaded via loadData, associating True to any
    given element if the corresponding experiment run should be
    excluded from failure rate computations, and False otherwise. This
    is determined based on a series of user-configurable settings.

    Parameters:
        dataDict (dict): Dictionary containing HDFIT experiment data
        bit_pos (int): Exclude runs with faults injected in bits higher than bit_pos
        exclude_uoe (bool): If True, exclude all runs resulting in observable failures
        exclude_rtl (bool): If True, exclude all runs where RTL errors were triggered

    Returns:
        list[bool]: Mask list dictating which experiment runs are to be ignored
    """
    failure   = dataDict[HDFIT.testFail]
    fault     = dataDict[HDFIT.fiBit]
    rtlerrors = dataDict[HDFIT.rtlError]
    max_row = len(failure)

    if max_row==0:
        raise ValueError("The input HDFIT dataset is empty!")

    # Computing runs to be excluded from the failure rate computation
    ex_runs = [fault[i]>=bit_pos or (failure[i] and exclude_uoe) or (rtlerrors[i] and exclude_rtl) for i in range(max_row)]
    return ex_runs

def getDataPartialProtection(dataDict, bit_pos, bins, exclude_uoe, exclude_rtl):
    """
    Produce an NRMSE vs failure rate (i.e., PVF or AVF) curve.

    This function produces values for a NRMSE vs failure rate curve according to an
    arbitrary set of bin values, as well as flags to determine which runs
    should be excluded using the filterData function. If a given run is
    to be excluded, it will be considered successful in the computation.

    Parameters:
        dataDict (dict): Dictionary containing HDFIT experiment data
        bit_pos (int): Exclude runs with faults injected in bits higher than bit_pos
        bins (list[float]): List of bin edges for which failure rate values are computed
        exclude_uoe (bool): If True, exclude all runs resulting in observable failures
        exclude_rtl (bool): If True, exclude all runs where RTL errors were triggered

    Returns:
        list[float]: List of failure rate values for the points specified by bins
    """
    failure   = dataDict[HDFIT.testFail]
    fault     = dataDict[HDFIT.fiBit]
    errors    = dataDict[HDFIT.nrmse]
    rtlErrors = dataDict[HDFIT.rtlError]
    max_row = len(failure)

    if max_row==0:
        raise ValueError("The input HDFIT dataset is empty!")

    # List storing the final curve
    vals = np.zeros(bins.shape)
    # Filtering out runs
    ex_runs = filterData(dataDict, bit_pos, exclude_uoe, exclude_rtl)
    # Computing list of effective failures (errors and SDEs) after filtering out runs
    temp_errors = [(errors[i]>0 or failure[i]>0) and not ex_runs[i] for i in range(max_row)]

    for idx in range(len(bins)):
        mask = (errors > bins[idx])
        vals[idx] = np.sum(temp_errors, where=mask) / max_row

    return vals

# --------------------  PVF or AVF statistics computation  --------------------

def printFailureStatistics(dataDict, bit_pos, bit_depth):
    """
    Print a variety of failure rate (i.e., PVF or AVF) statistics.

    This function takes as input a dictionary containing HDFIT experiment data,
    and will compute a breakdown of the main failure metrics (e.g., UOEs and SDEs,
    faults caught by RTL protection, and so on). A "partial protection" setting
    can also be applied, ignoring all failures occurring in bits over a certain order.

    Parameters:
        dataDict (dict): Dictionary containing HDFIT experiment data
        bit_pos (int): Exclude runs with faults injected in bits higher than bit_pos
        bit_depth (int): Bit precision currently being used
    """
    failure   = dataDict[HDFIT.testFail]
    fault     = dataDict[HDFIT.fiBit]
    errors    = dataDict[HDFIT.nrmse]
    rtlerrors = dataDict[HDFIT.rtlError]
    max_row   = len(failure)

    if max_row==0:
        raise ValueError("The input HDFIT dataset is empty!")

    uoeFR = np.sum([failure[i] and fault[i]<bit_pos for i in range(max_row)]) * 100 / max_row
    sdeFR = np.sum([errors[i] > 0 and not failure[i] and fault[i]<bit_pos for i in range(max_row)]) * 100 / max_row

    # Computing number of runs where RTL protection was triggered
    rtlRuns = [rtlerrors[i] and fault[i]<bit_pos for i in range(max_row)]
    rtlNum  = np.sum(rtlRuns) * 100 / max_row
    rtlFR_uoe = np.sum([rtlRuns[i] and failure[i] for i in range(max_row)]) * 100 / max_row
    rtlFR_sde = np.sum([rtlRuns[i] and errors[i] > 0 and not failure[i] for i in range(max_row)]) * 100 / max_row
    rtlFR_fp  = rtlNum - rtlFR_uoe - rtlFR_sde
    # Adjusting overall statistics according to RTL protection
    uoeFR      = uoeFR - rtlFR_uoe
    sdeFR      = sdeFR - rtlFR_sde
    overallFR  = uoeFR + sdeFR
    successRuns = 100 - overallFR - rtlNum

    if bit_pos < bit_depth:
        log.info("-- %s with protection up to bit %d: %f%%" % (FI_METRIC, bit_pos, overallFR))
    else:
        log.info("-- %s with no protection: %f%%" % (FI_METRIC, overallFR))
    log.info("---- UOE %s    : %f%%" % (FI_METRIC, uoeFR))
    log.info("---- SDE %s    : %f%%" % (FI_METRIC, sdeFR))
    log.info("---- Success    : %f%%" % successRuns)
    if rtlNum > 0:
        log.info("---- RTL Errors : %f%%" % rtlNum)
        log.info("-------- Leading to UOE     : %f%%" % rtlFR_uoe)
        log.info("-------- Leading to SDE     : %f%%" % rtlFR_sde)
        log.info("-------- Leading to Success : %f%%" % rtlFR_fp)

# ------------------------     Miscellaneous code      ------------------------

def seekRightBound(errors):
    """
    Returns the 95th percentile of the input list.

    This function is used to determine a suitable right bound when
    plotting an error distribution, assuming the left bound is 0.
    The 95th percentile usually works well in practice.

    Parameters:
        errors (list[float]): List of error values

    Returns:
        float: 95th percentile of errors list
    """
    errors = [ val for val in errors if val>0 and val!=np.inf ]
    # Picking the largest statistically relevant error as right bound
    rb = np.percentile(errors, 95)
    return rb

def getFileBaseName(name):
    """
    Removes date and extension from an HDFIT CSV file name.

    Parameters:
        name (string): Name of an HDFIT CSV file

    Returns:
        string: Sanitized version of name
    """
    baseName = os.path.basename(name)
    match = re.search("[-_.][0-9]+-[0-9]+-[0-9]+.csv", baseName)
    return baseName.replace(match.group(0), "") if match is not None else baseName[0:-4]

def percent(arr):
    """
    Calculates an array's mean as a percentage.

    This utility function is used as an estimator in
    some seaborn barplot calls, to plot failure rate
    bars (which are expressed as percentages). No
    normalization is performed, and the range of data
    is assumed to be [0, 1].

    Parameters:
        arr (np.array): Data to be processed

    Returns:
        float: Percentage mean of the array
    """
    arr = arr.astype(float)
    return np.mean(arr) * 100

class MinorSymLogLocator(Locator):
    """
    This is a utility class to produce ticks in symlog scale.
    """
    def __init__(self, linthresh):
        self.linthresh = linthresh

    def __call__(self):
        majlocs = self.axis.get_majorticklocs()
        minlocs = []
        for i in range(1, len(majlocs)):
            majstep = majlocs[i] - majlocs[i-1]
            ndivs = 10 if abs(majlocs[i-1] + majstep/2) < self.linthresh else 9
            minstep = majstep / ndivs
            locs = np.arange(majlocs[i-1], majlocs[i], minstep)[1:]
            minlocs.extend(locs)

        return self.raise_if_exceeds(np.array(minlocs))

    def tick_values(self, vmin, vmax):
        raise NotImplementedError("")

def HDFIT_intList(s):
    """
    Splits a comma-separated string into a list of integers.

    Parameters:
        s (string): String to be separated

    Returns:
        list[int]: List of integers extracted from s
    """
    ls = [int(el.strip()) for el in s.split(",") if el.strip()!=""]
    if any(el < 0 for el in ls):
        raise ValueError("List %s contains one or more invalid values. Plase check your input." % s)
    return ls

def HDFIT_intPos(s):
    """
    Converts a string into a (positive) integer.

    Parameters:
        s (string): String to be converted

    Returns:
        int: Integer representation of s
    """
    i = int(s)
    if i <= 0:
        raise ValueError("Value %s is invalid. Please check your input." % s)
    return i


"""
Processes math strictly from left to right (while respecting
parentheses).
"""

def formula_sums():
    total_sum = 0
    with open("input.txt", "r") as input_file:
        for line in input_file:
            line = process_parens(line)
            total_sum += do_math(line)

    return total_sum

def process_parens(line):
    """
    Take a formula line and process parentheses first.
    """
    while line.rfind("(") != -1:
        l_paren_ix = line.rfind("(")
        r_paren_ix = line.find(")", l_paren_ix)
        result = do_math(line[l_paren_ix + 1:r_paren_ix])
        line = line[:l_paren_ix] + str(result) + line[r_paren_ix+1:]

    return line

def do_math(func):
    """
    Given a certain function consisting of numbers, *, and +,
    calculate what the result will be just straight from left to right.
    Assumes that the functions are all in valid format, as in
    it follows the number operator number format legally.
    """
    splits = func.split(" ")
    operator_next = False
    op_num = 0
    operator = ""
    for entry in splits:
        if operator_next:
            operator = entry
            operator_next = False
        else:
            if operator == "*":
                op_num *= int(entry)
            elif operator == "+":
                op_num += int(entry)
            else:
                op_num = int(entry)
            operator_next = True

    return op_num

if __name__ == "__main__":
    sums = formula_sums()
    print (sums)


from typing import *

# Definition for singly-linked list.
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def mergeTwoLists(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        if not l1: return l2
        if not l2: return l1

        l3: Optional[ListNode] = None
        if l1.val < l2.val:
            l3 = ListNode(l1.val)
            l1 = l1.next
        else:
            l3 = ListNode(l2.val)
            l2 = l2.next

        l3_head = l3

        while l1 and l2:
            if l1.val < l2.val:
                l3.next = ListNode(l1.val)
                l1 = l1.next
            else:
                l3.next = ListNode(l2.val)
                l2 = l2.next
            l3 = l3.next

        for pointer in [l1, l2]:
            while pointer:
                l3.next = ListNode(pointer.val)
                l3 = l3.next
                pointer = pointer.next

        return l3_head

    def equals(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> bool:
        while l1 and l2:
            if l1.val != l2.val: return False
            l1 = l1.next
            l2 = l2.next

        if l1 or l2:
            return False
        return True

def test_happy_path():
    l1 = ListNode(1)
    l1.next = ListNode(2)
    l1.next.next = ListNode(4)

    l2 = ListNode(1)
    l2.next = ListNode(3)
    l2.next.next = ListNode(4)

    expected = ListNode(1)
    expected.next = ListNode(1)
    expected.next.next = ListNode(2)
    expected.next.next.next = ListNode(3)
    expected.next.next.next.next = ListNode(4)
    expected.next.next.next.next.next = ListNode(4)
    list_helper = Solution()
    actual = list_helper.mergeTwoLists(l1, l2)
    assert list_helper.equals(actual, expected) == True

if __name__ == "__main__":
    test_happy_path()


import sqlite3
import config
import alpaca_trade_api as tradeapi
from datetime import date
#from polygon import Wev
import smtplib
import ssl

context = ssl.create_default_context()

connection = sqlite3.connect(config.DB_FILE)

connection.row_factory = sqlite3.Row
cursor = connection.cursor()

cursor.execute("""
select id from strategy where name= 'Bullish-Three-Line-Strike'
""")

strategy_id = cursor.fetchone()['id']

cursor.execute("""
    SELECT symbol, name
    FROM stock
    JOIN stock_strategy on stock_strategy.stock_id = stock.id
    WHERE stock_strategy.strategy_id =?
    """, (strategy_id,))

stocks = cursor.fetchall()
symbols = [stock['symbol'] for stock in stocks]
current_date = date.today().isoformat()

#start_minute_bar = f"{current_date} 09:30:00-04:00"
#end_minute_bar = f"{current_date} 09:45:00-04:00"

api = tradeapi.REST(config.API_KEY, config.SECRET_KEY, base_url=config.API_URL)

#orders = api.list_orders()
#existing_order_symbols =[order.symbol for order in orders]

messages = []

for symbol in symbols:

    minute_bars = api.get_barset(symbol, 'minute').df

    minute_bars = minute_bars[symbol]
    # USE WHEN ALPACA MARKET BROKERAGE ACCOUNT IS APPROVED
    #minute_bars= api.polygon.historic_agg_v2(symbol,1,'minute', _from=current_date, to=current_date).df

    newest_bar = minute_bars.iloc[-1]
    second_newest_bar = minute_bars.iloc[-2]
    third_newest_bar = minute_bars.iloc[-3]
    fourth_newest_bar = minute_bars.iloc[-3]

    newest_low = newest_bar["low"]
    newest_high = newest_bar["high"]

    if newest_bar['close'] < second_newest_bar['close'] and newest_bar["open"] >= second_newest_bar["close"] and second_newest_bar['open'] < second_newest_bar['close'] and third_newest_bar['open'] < third_newest_bar['close'] and fourth_newest_bar['open'] < fourth_newest_bar['close']:

        messages.append(
            f"Bullish Pattern Found! Suggested stop loss:{newest_low} ")
        print(messages)
        pattern = True
    else:
        print("Bullish pattern not in play.")
        pattern = False

    if pattern == True:
        with smtplib.SMTP_SSL(config.EMAIL_HOST, config.EMAIL_PORT, context=context) as server:
            server.login(config.EMAIL_ADDRESS, config.EMAIL_PASSWORD)

    email_message = f"Subject: Trade Notifications for {current_date}\n\n"
    email_message = "\n".join(messages)
    server.sendmail(config.EMAIL_ADDRESS, config.EMAIL_ADDRESS, email_message)

'''
    #print(symbol)
    #print(minute_bars[symbol]['low'])
    opening_range_mask =(minute_bars.index >= start_minute_bar) & (minute_bars.index <end_minute_bar)
    opening_range_bars = minute_bars.loc[opening_range_mask]
    #print(opening_range_bars[symbol]['low'])
    #print(opening_range_bars)
    opening_range_low = opening_range_bars['low'].min()
    opening_range_high = opening_range_bars['high'].max()
    opening_range = opening_range_high - opening_range_low

    #print(opening_range_low)
    #print(opening_range_high)
    #print(opening_range)
    after_opening_range_mask = minute_bars.index >= end_minute_bar
    after_opening_range_bars = minute_bars.loc[after_opening_range_mask]

    #print(after_opening_range_bars)

    after_opening_range_breakout =after_opening_range_bars[after_opening_range_bars['close'] > opening_range_high]

    print(after_opening_range_breakout)
    #print(after_opening_range_breakout.iloc[0]['close])
    if not after_opening_range_breakout.empty:

        if symbol not in existing_order_symbols:
            limit_price = after_opening_range_breakout.iloc[0]['close']

            messages.append(f"placing order for {symbol} at {limit_price}, closed_above {opening_range_high} at {after_opening_range_breakout.iloc[0]}")
            print(f"placing order for {symbol} at {limit_price}, closed_bove {opening_range_high} at {after_opening_range_breakout.iloc[0]}")

       #     api.submit_order(
       #         symbol=symbol,
       #         side='buy',
       #         type='limit',
       #         qty='100',
       #         time_in_force='day',
       #         order_class='bracket',
       #         limit_price=limit_price,
       #         take_profit=dict(
       #             limit_price=limit_price +opening_range,
       #         ),
       #         stop_loss=dict(
       #             stop_price=limit_price-opening_range,

       #         )
       #     )
       # else:
       #     print(f"Already an order for {symbol}, skipping")
print(messages)

with smtplib.SMTP_SSL(config.EMAIL_HOST, config.EMAIL_PORT, context=context) as server:
    server.login(config.EMAIL_ADDRESS, config.EMAIL_PASSWORD)

    email_message = f"Subject: Trade Notifications for {current_date}\n\n"
    email_message = "\n".join(messages)
    server.sendmail(config.EMAIL_ADDRESS,config.EMAIL_ADDRESS,email_message)
'''


def henttxt(liste, txtnavn):
    f = open(txtnavn, 'r')
    with f as filehandle:
        for line in filehandle:
            currentPlace = line[:-1]
            liste.append(currentPlace)
    f.close()

def lagtxt(liste, txtnavn):
    f = open(txtnavn, 'w+')
    with f as file:
        for listitem in liste:
            file.write('%s\n' % listitem)
    f.close()

def fjerntxt(navn, slette):
    with open(navn, "r") as f:
        lines = f.readlines()
    with open(navn, "w") as f:
        for line in lines:
            if line.strip("\n") != slette:
                f.write(line)

class lister:
    def hent(self):
        txtnavn = str(self) + '.txt'
        self = []
        henttxt(self, txtnavn)
        return self

class person:
    def __init__(self, valgt, navn, tlf):
        self.valgt = valgt
        self.navn = navn
        self.tlf = tlf

sk8boards = []
henttxt(sk8boards, 'sk8boards.txt')

numbers = []
amount = len(sk8boards)
a = int
for a in range(amount):
    numbers.append(a)
    a + 1

sk8_dict = {}
for key in numbers:
    for value in sk8boards:
        sk8_dict[key] = value
        sk8boards.remove(value)
        break

utleidsk8 = []
henttxt(utleidsk8, 'utleidsk8.txt')
for items in utleidsk8:
    sk8_dict.pop(int(items))

current_person = person(0,'','')

current_person.navn = input('\nHva er navnet ditt?\n')
current_person.tlf = input('\nHva er tellefonnummeret ditt?\n')

#På tide å velge skateboards
print('\n Velg mellom disse skateboardene\n')
for key, value in sk8_dict.items():
    print(key, ' : ', value)

prompt = 'Hvilket skateboard velger du?\n\n'
while True:
    try:
        valgt = int(input(prompt))
        if valgt < 0 or valgt > amount:
            raise ValueError
        else: break
    except ValueError:
        prompt = 'Dette skateboardet finnes ikke. Velg mellom 0 og ', amount,

current_person.valgt = valgt

utleidsk8 = lister.hent('utleidsk8')
utleidsk8.append(current_person.valgt)
lagtxt(utleidsk8, 'utleidsk8.txt')

vnt_list = lister.hent('vnt_temp')
vnt_dict = {}
vnt_dict[current_person.valgt] = [current_person.navn, current_person.tlf]
vnt_list.append(vnt_dict)
lagtxt(vnt_list, 'vnt_temp.txt')

valgtsk8board = sk8_dict[int(valgt)]

print('\nGRATULERER! Du låner nå ____', valgtsk8board, '___ ', current_person.navn)
print('Husk å lever tilbake!\n')
#print(*valgt_navn, sep = '\n')
print('\n')


#!/usr/bin/env python

import os
import re
import datetime

from lib.tools.tools_base import ToolsBase
from lib.tools.excel.manual_case_parser import ManualCaseParser
from lib.tools.generator_by_template.generator_by_template import GeneratorByTemplate

class GeneratorCaseScript(ToolsBase):
    """Analyze the test case information in the excel file and generate the test case script automatically.
    Args:
        case_file           type(str)          the abspath of test case excel file
        template            type(str)          the path of test case script template file
    Example:
        generator = GeneratorCaseScript(excel_file=r'C:\test_case.xls')
        generator.generator_case_script()
    Return:
    Author: cai, yong
    IsInterface: False
    ChangeInfo: cai, yong 2019-09-18
    """

    def __init__(self, author, case_file, template='case_template.txt', title_line=1, value_line=2, sheet_index=0,
                 sheet_name=None):
        super(GeneratorCaseScript, self).__init__()
        self.author = author
        self.case_file = case_file
        self.template = template
        self.title_line = title_line
        self.value_line = value_line
        self.sheet_index = sheet_index
        self.sheet_name = sheet_name
        self.script_path = ''

    def generator_case_script(self):
        """Generate the test case script.
        Args:
        Example:
        Return:
        Author: cai, yong
        IsInterface: False
        ChangeInfo: cai, yong 2019-09-18
        """

        # dynamic calculation script_path path
        local_path = self.information.get_framework_local_path()
        self.script_path = os.path.join(local_path, 'lib', 'tools', 'case_related', 'generator_case_script', 'scripts')
        if not re.search(':', self.template):
            self.template = os.path.join(
                local_path, 'lib', 'tools', 'case_related', 'generator_case_script', self.template)

        parser = ManualCaseParser(self.case_file, title_line=self.title_line, value_line=self.value_line,
                                  sheet_index=self.sheet_index, sheet_name=self.sheet_name)
        data = parser.manual_case_parser()
        for case in data:
            self.generator(case)

    def generator(self, case_info):
        """Generate the test case script.
        Args:
        Example:
        Return:
        Author: cai, yong
        IsInterface: False
        ChangeInfo: cai, yong 2019-09-18
        """

        file_path = os.path.join(self.script_path, *case_info['Module'])
        file_abspath = os.path.join(file_path, '%s.py' % case_info['No.'])

        params = dict()
        params['date'] = datetime.datetime.now().strftime('%Y-%m-%d')
        params['Author'] = self.author
        params['case_info'] = case_info

        gen = GeneratorByTemplate(template=self.template, file_abspath=file_abspath)
        gen.generator(params)

if __name__ == '__main__':
    generator = GeneratorCaseScript(author='Cai, Yong', case_file=r'D:\Full_testcases.xlsx', sheet_index=3)
    generator.generator_case_script()


import socket
import threading
from Secret_Variables import Software_Activation_Key

# A Server Program that provides the antivirus service for it's clients
__author__ = 'Michael Khoshahang'

# Global Variables-
MSG_LENGTH = 2048
SERVER_IP = socket.gethostbyname(socket.gethostname())  # getting the Server IP
# Address that contains the Server ip and a random free port
ADDRESS = (SERVER_IP, 0)
ENCODING_FORMAT = 'utf-8'
clients = list()
latest_version = '3.1'

try:
    # AF_INET ---> working with IPv4 || SOCK_DGRAM ---> UDP
    # Creating a server socket object
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(ADDRESS)  # Assign object to IP and PORT
    print('[Server] Initiating Server...')
    server.listen()  # waiting for clients || listening mode
    print(f'[Server] Running on {ADDRESS[0]}:{server.getsockname()[1]}')
except Exception as e:
    print(
        f'[Server] Could not run on {ADDRESS[0]}:{server.getsockname()[1]}. The error {e} occured.')

def receive_client_message(client_socket):
    """
    The function receives messages that are sent by the client.
    The function is working with the protocol defined in the client's program
    "send_request_to_server" function.
    :param client_socket: the client
    :return: the client's request
    :rtype: str
    """
    return client_socket.recv(MSG_LENGTH)

def send_message_to_client(response, client_socket):
    """
    The function creates a protocol which sends the response to the client.
    :param client_socket : the client
    :type: socket
    """
    if client_socket is not None:
        client_socket.send(response)
    else:
        print("[Server] Reference Error")

def handle_clients(client_object, address):
    """
    The function handles many clients.
    :param client_object: the client connection object
    :param address: the client's address
    :return: None
    """
    global clients
    while True:
        try:
            message = receive_client_message(
                client_object).decode(ENCODING_FORMAT)
            if message == 'get_active_clients':
                send_message_to_client(send_active_clients().encode(
                    ENCODING_FORMAT), client_object)
            elif message == 'getversion':
                send_message_to_client(latest_version.encode(
                    ENCODING_FORMAT), client_object)
            else:
                validation = 'False'
                if message == Software_Activation_Key:
                    validation = 'True'
                send_message_to_client(validation.encode(ENCODING_FORMAT),
                                       client_object)
        except:
            print(f"[Server] Disconnecting client {address[0]}:{address[1]}")
            clients.remove((client_object, address[0], address[1]))
            client_object.close()
            print(f'[Server] Active connections {len(clients)}')
            break

def main():
    """
    The main function of the Server module.
    :return: None
    """
    global server, clients

    while True:
        # enables connection and stores the connection object and IP of the client
        client_object, address = server.accept()
        # printing new connection address
        print(f'[Server] New connection from {address[0]}:{address[1]}')
        clients.append((client_object, address[0], address[1]))
        threading.Thread(target=handle_clients, args=(
            client_object, address)).start()
        print(f'[Server] Active connections {len(clients)}')

def send_active_clients():
    """
    The function sends to a specific client statuses of all the connected
    clients.
    :return: A string of the connected clients to the server
    :rtype: str
    """

    global clients
    if clients:
        response = ''
        for client in clients:
            response += f"{client[1]}:{str(client[2])}~"
    else:
        response = 'There are no active clients right now.'
    return response

if __name__ == '__main__':
    main()