import decimal
import json
import os
import urllib.request

import boto3

DATA_URL = 'https://supercharge.info/service/supercharge/allSites'

def charger_eq(existing, update):
    return all((
        key in existing and existing[key] == update[key]
        for key in update.keys()))

def main(event, context):
    try:
        local_filename, headers = urllib.request.urlretrieve(DATA_URL)
    except Exception as e:
        # some other error happened
        error = str(e)
        return "We had an error: %s" % (error)
    else:
        dynamodb = boto3.resource('dynamodb')
        table = dynamodb.Table(os.environ['CHARGERS_TABLE'])

        num_chargers = num_chargers_new = num_chargers_updated = 0
        with open(local_filename) as json_file:
            chargers = json.load(json_file, parse_float=decimal.Decimal)
            for charger in chargers:
                num_chargers += 1
                charger['latitude'] = charger['gps']['latitude']
                charger['longitude'] = charger['gps']['longitude']
                del charger['gps']

                try:
                    existing_charger = table.get_item(
                        Key={'id': int(charger['id'])})['Item']
                except Exception as e:
                    num_chargers_new += 1
                    table.put_item(Item=charger)
                else:
                    if charger_eq(existing_charger, charger):
                        # no need to update
                        continue

                    expressionAttributeNames = dict([
                        ('#%s' % key, key)
                        for key in charger.keys() if key != 'id'])

                    updateExpression = 'set %s' % (', '.join([
                        '#%s = :%s' % (key, key)
                        for key in charger.keys() if key != 'id']))

                    expressionAttributeValues = dict([(
                        ':%s' % key, val)
                        for key, val in charger.items()
                        if key != 'id'])

                    table.update_item(
                        Key={'id': int(charger['id'])},
                        UpdateExpression=updateExpression,
                        ExpressionAttributeNames=expressionAttributeNames,
                        ExpressionAttributeValues=expressionAttributeValues,
                        ReturnValues='NONE',
                    )
                    num_chargers_updated += 1

    return ("We updated %s chargers and created %s chargers for a total "
            "of %s!") % (num_chargers_updated, num_chargers_new, num_chargers)


# V0
class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        wordset = set(wordList)
        bfs = collections.deque()
        bfs.append((beginWord, 1))
        while bfs:
            word, length = bfs.popleft()
            if word == endWord:
                return length
            for i in range(len(word)):
                for c in "abcdefghijklmnopqrstuvwxyz":
                    newWord = word[:i] + c + word[i + 1:]
                    if newWord in wordset and newWord != word:
                        wordset.remove(newWord)
                        bfs.append((newWord, length + 1))
        return 0

# V1
# https://blog.csdn.net/fuxuemingzhu/article/details/82903681
class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        wordset = set(wordList)
        bfs = collections.deque()
        bfs.append((beginWord, 1))
        while bfs:
            word, length = bfs.popleft()
            if word == endWord:
                return length
            for i in range(len(word)):
                for c in "abcdefghijklmnopqrstuvwxyz":
                    newWord = word[:i] + c + word[i + 1:]
                    if newWord in wordset and newWord != word:
                        wordset.remove(newWord)
                        bfs.append((newWord, length + 1))
        return 0

### Test case : dev

# V1'
# https://leetcode.com/problems/word-ladder/discuss/40729/Compact-Python-solution
class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        wordList = set(wordList)
        queue = collections.deque([[beginWord, 1]])
        while queue:
            word, length = queue.popleft()
            if word == endWord:
                return length
            for i in range(len(word)):
                for c in 'abcdefghijklmnopqrstuvwxyz':
                    next_word = word[:i] + c + word[i+1:]
                    if next_word in wordList:
                        wordList.remove(next_word)
                        queue.append([next_word, length + 1])
        return 0

# V1''
# https://leetcode.com/problems/word-ladder/discuss/157376/Python-(BFS)-tm
class Solution(object):
    def ladderLength(self, start, end, arr):
        arr = set(arr) #avoid TLE
        q = collections.deque([(start, 1)])
        visted = set()
        alpha = string.ascii_lowercase  #'abcd...z'
        while q:
            word, length = q.popleft()
            if word == end:
                return length

            for i in range(len(word)):
                for ch in alpha:
                    new_word = word[:i] + ch + word[i+1:]
                    if new_word in arr and new_word not in visted:
                        q.append((new_word, length + 1))
                        visted.add(new_word)
        return 0

# V1
# https://blog.csdn.net/fuxuemingzhu/article/details/82903681
class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        wordset = set(wordList)
        if endWord not in wordset:
            return 0
        visited = set([beginWord])
        chrs = [chr(ord('a') + i) for i in range(26)]
        bfs = collections.deque([beginWord])
        res = 1
        while bfs:
            len_bfs = len(bfs)
            for _ in range(len_bfs):
                origin = bfs.popleft()
                for i in range(len(origin)):
                    originlist = list(origin)
                    for c in chrs:
                        originlist[i] = c
                        transword = "".join(originlist)
                        if transword not in visited:
                            if transword == endWord:
                                return res + 1
                            elif transword in wordset:
                                bfs.append(transword)
                                visited.add(transword)
            res += 1
        return 0

# V1'
# https://leetcode.com/problems/word-ladder/solution/
# IDEA : BFS
# time complexity : O(M**2 * N)
# space complexity : O(M**2 * N)
from collections import defaultdict
class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """

        if endWord not in wordList or not endWord or not beginWord or not wordList:
            return 0

        # Since all words are of same length.
        L = len(beginWord)

        # Dictionary to hold combination of words that can be formed,
        # from any given word. By changing one letter at a time.
        all_combo_dict = defaultdict(list)
        for word in wordList:
            for i in range(L):
                # Key is the generic word
                # Value is a list of words which have the same intermediate generic word.
                all_combo_dict[word[:i] + "*" + word[i+1:]].append(word)

        # Queue for BFS
        queue = collections.deque([(beginWord, 1)])
        # Visited to make sure we don't repeat processing same word.
        visited = {beginWord: True}
        while queue:
            current_word, level = queue.popleft()
            for i in range(L):
                # Intermediate words for current word
                intermediate_word = current_word[:i] + "*" + current_word[i+1:]

                # Next states are all the words which share the same intermediate state.
                for word in all_combo_dict[intermediate_word]:
                    # If at any point if we find what we are looking for
                    # i.e. the end word - we can return with the answer.
                    if word == endWord:
                        return level + 1
                    # Otherwise, add it to the BFS Queue. Also mark it visited
                    if word not in visited:
                        visited[word] = True
                        queue.append((word, level + 1))
                all_combo_dict[intermediate_word] = []
        return 0

# V1''
# https://leetcode.com/problems/word-ladder/solution/
# IDEA : Bidirectional Breadth First Search
# time complexity : O(M**2 * N)
# space complexity : O(M**2 * N)
from collections import defaultdict
class Solution(object):
    def __init__(self):
        self.length = 0
        # Dictionary to hold combination of words that can be formed,
        # from any given word. By changing one letter at a time.
        self.all_combo_dict = defaultdict(list)

    def visitWordNode(self, queue, visited, others_visited):
        current_word, level = queue.popleft()
        for i in range(self.length):
            # Intermediate words for current word
            intermediate_word = current_word[:i] + "*" + current_word[i+1:]

            # Next states are all the words which share the same intermediate state.
            for word in self.all_combo_dict[intermediate_word]:
                # If the intermediate state/word has already been visited from the
                # other parallel traversal this means we have found the answer.
                if word in others_visited:
                    return level + others_visited[word]
                if word not in visited:
                    # Save the level as the value of the dictionary, to save number of hops.
                    visited[word] = level + 1
                    queue.append((word, level + 1))
        return None

    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """

        if endWord not in wordList or not endWord or not beginWord or not wordList:
            return 0

        # Since all words are of same length.
        self.length = len(beginWord)

        for word in wordList:
            for i in range(self.length):
                # Key is the generic word
                # Value is a list of words which have the same intermediate generic word.
                self.all_combo_dict[word[:i] + "*" + word[i+1:]].append(word)

        # Queues for birdirectional BFS
        queue_begin = collections.deque([(beginWord, 1)]) # BFS starting from beginWord
        queue_end = collections.deque([(endWord, 1)]) # BFS starting from endWord

        # Visited to make sure we don't repeat processing same word
        visited_begin = {beginWord: 1}
        visited_end = {endWord: 1}
        ans = None

        # We do a birdirectional search starting one pointer from begin
        # word and one pointer from end word. Hopping one by one.
        while queue_begin and queue_end:

            # One hop from begin word
            ans = self.visitWordNode(queue_begin, visited_begin, visited_end)
            if ans:
                return ans
            # One hop from end word
            ans = self.visitWordNode(queue_end, visited_end, visited_begin)
            if ans:
                return ans

        return 0

# V2
# Time:  O(n * d), n is length of string, d is size of dictionary
# Space: O(d)
from string import ascii_lowercase
class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        distance, cur, visited, lookup = 0, [beginWord], set([beginWord]), set(wordList)

        while cur:
            next_queue = []

            for word in cur:
                if word == endWord:
                    return distance + 1
                for i in range(len(word)):
                    for j in ascii_lowercase:
                        candidate = word[:i] + j + word[i+1:]
                        if candidate not in visited and candidate in lookup:
                            next_queue.append(candidate)
                            visited.add(candidate)
            distance += 1
            cur = next_queue

        return 0


import json
import unittest
import sys
sys.path.append('/app')

from tipi_backend.app import create_app
from tipi_backend.settings import Config

class TestLimit(unittest.TestCase):

    def setUp(self):
        Config.TESTING = True
        Config.USE_ALERTS = True
        app = create_app(config=Config)
        self.client = app.test_client()

    def test_limit_each_call(self):
        x = 0
        data = json.dumps({'email': 'foo@bar.com', 'search': '{"topic": "bar"}'})
        while x < 10:
            # labeling
            res = self.client.post('/labels/extract', data={'text': 'example'})
            self.assertEqual(res.status_code, 200)
            # alerts
            res = self.client.post('/alerts', data=data, content_type='application/json')
            self.assertEqual(res.status_code, 200)
            x += 1
        res = self.client.post('/alerts', data=data, content_type='application/json')
        self.assertEqual(res.status_code, 429)

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


from collections import OrderedDict

import numpy as np
import pylab as plt
import h5py
from mne.viz import plot_topomap
from scipy.signal import hilbert, firwin2, filtfilt
from scipy.fftpack import rfft, irfft, fftfreq

from pynfb.serializers.xml_ import get_lsl_info_from_xml
from pynfb.signals.rejections import Rejections
from pynfb.signal_processing.filters import SpatialRejection
import seaborn as sns

from pynfb.widgets.helpers import ch_names_to_2d_pos

def dc_blocker(x, r=0.99):
    # DC Blocker https://ccrma.stanford.edu/~jos/fp/DC_Blocker.html
    y = np.zeros_like(x)
    for n in range(1, x.shape[0]):
        y[n] = x[n] - x[n-1] + r * y[n-1]
    return y

def fft_filter(x, fs, band=(9, 14)):
    w = fftfreq(x.shape[0], d=1. / fs * 2)
    f_signal = rfft(x, axis=0)
    cut_f_signal = f_signal.copy()
    cut_f_signal[(w < band[0]) | (w > band[1])] = 0
    cut_signal = irfft(cut_f_signal, axis=0)
    return cut_signal

def get_power2(x, fs, band, n_sec=5):
    n_steps = n_sec * fs
    w = fftfreq(n_steps, d=1. / fs * 2)
    print(len(range(0, x.shape[0] - n_steps, n_steps)))
    pows = [2*np.sum(rfft(x[k:k+n_steps])[(w > band[0]) & (w < band[1])]**2)/n_steps
            for k in range(0, x.shape[0] - n_steps, n_steps)]
    return np.array(pows)

def get_power(x, fs, band):
    #w = 0.
    #taps = firwin2(1000, [0, band[0]-w, band[0], band[1], band[1]+w, fs/2], [0, 0, 1, 1, 0, 0], nyq=fs/2)
    #x = filtfilt(taps, [1.], x)
    x = fft_filter(x, fs, band)
    return x**2

def load_rejections(f, reject_alpha=True):
    rejections = [f['protocol1/signals_stats/left/rejections/rejection{}'.format(j + 1)][:] for j in range(2)]
    alpha = f['protocol1/signals_stats/left/rejections/rejection2_topographies'][:]
    ica = f['protocol1/signals_stats/left/rejections/rejection1_topographies'][:]
    rejection = rejections[0]
    if reject_alpha:
        rejection = np.dot(rejection, rejections[1])
    return rejection, alpha, ica

def get_info(f, drop_channels):
    labels, fs = get_lsl_info_from_xml(f['stream_info.xml'][0])
    print('fs: {}\nall labels {}: {}'.format(fs, len(labels), labels))
    channels = [label for label in labels if label not in drop_channels]
    print('selected channels {}: {}'.format(len(channels), channels))
    n_protocols = len([k for k in f.keys() if ('protocol' in k and k != 'protocol0')])
    protocol_names = [f['protocol{}'.format(j+1)].attrs['name'] for j in range(n_protocols)]
    print('protocol_names:', protocol_names)
    return fs, channels, protocol_names

def get_protocol_power(f, i_protocol, fs, rejection, ch, band=(9, 14), dc=False):
    raw = f['protocol{}/raw_data'.format(i_protocol + 1)][:]
    x = np.dot(raw, rejection)[:, ch]
    if dc:
        x = dc_blocker(x)
    return get_power2(x, fs, band)

def get_colors():
    p_names = [ 'Right', 'Left',  'Rest', 'FB', 'Closed', 'Opened', 'Baseline']
    cm = sns.color_palette('Paired', n_colors=len(p_names))
    c = dict(zip(p_names, [cm[j] for j in range(len(p_names))]))
    return c

if __name__ == '__main__':
    import h5py

    pilot_dir = ['C:\\Users\\Nikolai\\Downloads', 'D:\\Mu'][1]
    subjs = [
        ['pilot_5Days_Rakhmankulov_Day1_02-27_17-27-34',
         'pilot5days_Rakhmankulov_Day2_02-28_14-45-36',
         'pilot5days_Rakhmankulov_Day3_03-01_12-51-41',
         'pilot5days_Rakhmankulov_Day4_03-02_17-26-28',
         'pilot5days_Rakhmankulov_Day5_03-04_09-24-16'],

        ['pilot_Cherlenok_Day1_02-27_12-51-56',
         'pilot5days_Cherlenok_Day2_02-28_15-50-08',
         'pilot5days_Cherlenok_Day3_03-01_16-24-03',
         'pilot5days_Cherlenok_Day4_03-02_16-45-43',
         'pilot5days_Cherlenok_Day5_03-03_12-35-46'],

        ['pilot5Days_Plackhin_Day1_02-27_16-04-08',
         'pilot5days_Plackhin_Day2_02-28_11-43-07',
         'pilot5days_Plackhin_Day3_03-01_11-45-35',
         'pilot5days_Plackhin_Day4_03-02_11-20-43',
         'pilot5days_Plackhin_Day5_03-03_14-29-52'],

        ['pilot5days_Skotnikova_Day1_02-27_15-15-18',
         'pilot5days_Skotnikova_Day2_02-28_14-06-40',
         'pilot5days_Skotnikova_Day3_03-01_10-44-28',
         'pilot5days_Skotnikova_Day4_03-02_13-33-55',
         'pilot5days_Skotnikova_Day5_03-03_13-42-04'],

        ['Dasha1_02-20_09-01-29',
        'Dasha2_02-22_15-53-52',
        'Dasha3_02-23_14-21-42',
        'Dasha4_02-24_16-59-08'],
        ['Andrey1_03-07_19-05-02']][-1:]
    drop_channels = [['AUX', 'A1', 'A2'], ['M_left', 'M_right']][1]
    channel = 'C4'
    alpha_band = (9, 14)
    theta_band = (3, 6)
    cm = get_colors()

    for subj in subjs[:]:
        fg = plt.figure(figsize=(30, 6))
        for j_s, experiment in enumerate(subj):
            with h5py.File('{}\\{}\\{}'.format(pilot_dir, experiment, 'experiment_data.h5')) as f:
                rejections, top_alpha, top_ica = load_rejections(f, reject_alpha=True)
                fs, channels, p_names = get_info(f, drop_channels)
                ch = channels.index(channel)

                # collect powers
                powers = OrderedDict()
                pow_theta = []
                for j, name in enumerate(p_names):
                    pow = get_protocol_power(f, j, fs, rejections, ch, alpha_band, dc=True)
                    if name == 'FB':
                        pow_theta.append(get_protocol_power(f, j, fs, rejections, ch, theta_band, dc=True).mean())
                    if name == 'Filters':
                        powers['{}. Closed'.format(j+1)] = pow[:len(pow)//2]
                        powers['{}. Opened'.format(j+1)] = pow[len(pow)//2:]
                    elif name == 'Rotate':
                        powers['{}. Right'.format(j+1)] = pow[:len(pow)//2]
                        powers['{}. Left'.format(j+1)] = pow[len(pow)//2:]
                    else:
                        powers['{}. {}'.format(j+1, name)] = pow

                # plot rejections
                for j_t in range(top_ica.shape[1]):
                    ax = fg.add_subplot(5, top_ica.shape[1]*len(subj), top_ica.shape[1]*len(subj)*3 + top_ica.shape[1]*j_s + j_t + 1)
                    ax.set_xlabel('ICA{}'.format(j_t+1))
                    labels, fs = get_lsl_info_from_xml(f['stream_info.xml'][0])
                    channels = [label for label in labels if label not in drop_channels]
                    pos = ch_names_to_2d_pos(channels)
                    plot_topomap(data=top_ica[:, j_t], pos=pos, axes=ax, show=False)
                for j_t in range(top_alpha.shape[1]):
                    ax = fg.add_subplot(5, top_alpha.shape[1]*len(subj), top_alpha.shape[1]*len(subj)*4 + top_alpha.shape[1]*j_s + j_t + 1)
                    ax.set_xlabel('CSP{}'.format(j_t+1))
                    labels, fs = get_lsl_info_from_xml(f['stream_info.xml'][0])
                    channels = [label for label in labels if label not in drop_channels]
                    pos = ch_names_to_2d_pos(channels)
                    plot_topomap(data=top_alpha[:, j_t], pos=pos, axes=ax, show=False)

                # plot powers
                norm = powers['{}. Baseline'.format(p_names.index('Baseline') + 1)].mean()
                #norm = np.mean(pow_theta)
                print('norm', norm)
                ax = fg.add_subplot(2, len(subj), j_s + 1)
                for j_p, (name, pow) in enumerate(powers.items()):
                    print(name)
                    ax.plot([j_p], [pow.mean()/norm], 'o', c=cm[name.split()[1]], markersize=10)
                    c = cm[name.split()[1]]
                    ax.errorbar([j_p], [pow.mean()/norm], yerr=pow.std()/norm,  c=c, ecolor=c)
                plt.setp(ax.xaxis.get_majorticklabels(), rotation=70)
                ax.set_xticks(range(len(powers)))
                ax.set_xticklabels(powers.keys())
                ax.set_ylim(0, 2)
                ax.set_xlim(-1, len(powers))
                ax.set_title('Day {}'.format(j_s+1))

        fg.savefig(' '.join(subj[-1].split('_')[:2])+channel+'.png', dpi=300)
        plt.show()


"""
Simple function for building ensembles of iterators that
represent disjoint partitions of an overall Cartesian product.
"""
from __future__ import annotations
from typing import Tuple, Optional, Collection, Sequence, Iterable
import doctest
import collections.abc as collections_abc # Avoid collision with function argument.
import itertools
from parts import parts

def products(
        *collections: Tuple[Collection, ...],
        number: Optional[int] = None
    ) -> Sequence[Iterable]:
    """
    Accept zero or more :obj:`~collections.abc.Collection` instances as arguments
    and return a :obj:`~collections.abc.Sequence` of the specified number of disjoint
    subsets of the `Cartesian product <https://en.wikipedia.org/wiki/Cartesian_product>`__
    of the supplied :obj:`~collections.abc.Collection` instances. Each subset is
    represented as an :obj:`~collections.abc.Iterable` and the union of the disjoint
    subsets is equal to the overall Cartesian product.

    :param collections: Zero or more arguments that represent the
        factor sets of the Cartesian product.
    :param number: Number of disjoint subsets to return.

    >>> ss = products(range(1, 3), {'a', 'b'}, (False, True), number=3)
    >>> for s in sorted([sorted(list(s)) for s in ss]):
    ...     for t in s:
    ...         print(t)
    (1, 'a', False)
    (1, 'a', True)
    (1, 'b', False)
    (1, 'b', True)
    (2, 'a', False)
    (2, 'a', True)
    (2, 'b', False)
    (2, 'b', True)

    Two additional basic examples are presented below.

    >>> (x, y, z) = ([1, 2], ['a', 'b'], [True, False])
    >>> [list(s) for s in products(x, y, number=2)]
    [[(1, 'a'), (1, 'b')], [(2, 'a'), (2, 'b')]]
    >>> for s in [list(s) for s in products(x, y, z, number=2)]:
    ...     print(s)
    [(1, 'a', True), (1, 'a', False), (1, 'b', True), (1, 'b', False)]
    [(2, 'a', True), (2, 'a', False), (2, 'b', True), (2, 'b', False)]

    By default (if the ``number`` argument is not assigned a value), the number
    of disjoint subsets is one. Note that the union of the disjoint subsets is
    equivalent to the output of the :obj:`itertools.product` function.

    >>> p = itertools.product([1, 2], {'a', 'b'}, (True, False))
    >>> ss = products([1, 2], {'a', 'b'}, (True, False))
    >>> list(p) == list(list(ss)[0])
    True

    If no sets are specified, the Cartesian product consists of a single empty
    tuple. If there is one set, the Cartesian product consists of a set of
    one-element tuples. In both cases, a list of disjoint subsets is returned
    as in all other cases (even though the number of disjoint subsets may be
    one).

    >>> list(list(products())[0])
    [()]
    >>> list(list(products([1, 2]))[0])
    [(1,), (2,)]

    It is possible to confirm that the returned subsets are disjoint, and that
    the union of the disjoint subsets is the Cartesian product.

    >>> (x, y, z) = ([1, 2], ['a', 'b'], [True, False])
    >>> ss = [set(s) for s in products(x, y, z, x, y, z, number=5)]
    >>> set([len(ss[i] & ss[j]) for i in range(5) for j in range(5) if i != j])
    {0}
    >>> s = ss[0] | ss[1] | ss[2] | ss[3] | ss[4]
    >>> s == set(itertools.product(x, y, z, x, y, z))
    True
    >>> len(products(*[[1, 2, 3]]*1000, number=5))
    5
    >>> ls = [len(products(*[[1, 2]]*1000, number=n)) for n in range(1, 100)]
    >>> ls == list(range(1, 100))
    True

    If the requested number of disjoint subsets exceeds the number of elements in
    Cartesian product, the number of disjoint subsets will be equivalent to the
    number of elements in the Cartesian product.

    >>> len(products([1, 2], ['a', 'b'], number=10))
    4

    Any attempt to apply this function to arguments that have unsupported types
    raises an exception.

    >>> products([1, 2], number='abc')
    Traceback (most recent call last):
      ...
    TypeError: number of disjoint subsets must be an integer
    >>> products((i for i in range(3)), number=2)
    Traceback (most recent call last):
      ...
    TypeError: arguments must be collections
    >>> products([1, 2], number=0)
    Traceback (most recent call last):
      ...
    ValueError: number of disjoint subsets must be a positive integer
    >>> products([1, 2], number=0)
    Traceback (most recent call last):
      ...
    ValueError: number of disjoint subsets must be a positive integer
    """
    factors = list(collections) # Ensure factor sets are reusable and their quantity is known.

    if not all(isinstance(factor, collections_abc.Collection) for factor in factors):
        raise TypeError('arguments must be collections')

    if number is not None:
        if not isinstance(number, int):
            raise TypeError('number of disjoint subsets must be an integer')

        if number < 1:
            raise ValueError('number of disjoint subsets must be a positive integer')

    # If no target number of disjoint subsets has been supplied, simply
    # return a single product. Note that this function is not equivalent to
    # :obj:`itertools.product` because this function always returns a sequence
    # of iterables (the subsets). In this case, there is only one element
    # in that sequence.
    if number is None or number == 1:
        return [itertools.product(*factors)]

    # Determine the product of which prefix of arguments to break up
    # based on the target number of disjoint subsets.
    number_ = 1
    index = len(factors)
    for (i, a) in enumerate(factors):
        number_ = number_ * len(a)
        if number_ >= number:
            index = min(len(factors), i + 1)
            break

    # Create an iterable for each prefix.
    prefixes = list(parts(list(itertools.product(*factors[0: index])), number))

    # For each prefix, create an iterable for that prefix by concatenating
    # elements of the prefix to elements of suffix product.
    def generator(prefix):
        for p in prefix:
            for s in itertools.product(*factors[index:]):
                yield p + s # Concatenation of tuples.

    return [generator(prefix) for prefix in prefixes]

if __name__ == '__main__':
    doctest.testmod() # pragma: no cover


'''
Described at PyMOL wiki: http://www.pymolwiki.org/index.php/lisica

'''

import os
import stat
import urllib.request, urllib.error, urllib.parse
from urllib.request import urlopen
from urllib.error import URLError, HTTPError
import zipfile
import tempfile
import shutil
import json
import sys
import platform
from distutils.dir_util import copy_tree
from tkinter import *
from tkinter.ttk import *
import webbrowser
import time
import tkinter.messagebox

from threading import Thread
import contextlib

HOME_DIRECTORY=os.path.expanduser('~')
LISICA_DIRECTORY=os.path.join(HOME_DIRECTORY,".lisicagui")
versionFile = os.path.join(LISICA_DIRECTORY, "version.txt")

class Configuration:
    def __init__(self):

        self.system = platform.system()
        self.machine = platform.machine()
        self.architecture = platform.architecture()
        import struct
        self.python_bit = 8 * struct.calcsize("P")
        self.python_version = platform.python_version_tuple()

    def is_os_64bit(self):
        if self.system == 'Windows':
            return platform.architecture()[0] == "64bit"
        else:
            return platform.machine().endswith('64')

    def exe_File(self):
        if self.system == 'Windows':
            if self.is_os_64bit():
                exe_filename = "LiSiCAx64.exe"
            else:
                exe_filename = "LiSiCAx86.exe"

        elif self.system == 'Linux':
            exe_filename = "lisica"
        else:
            print("The plugin might not be compatible with your machine")
            exe_filename = "lisica"
        return exe_filename

class UpdateCheck:

    def __init__(self):
        self.firstVersionURL = "http://insilab.org/files/lisica-plugin/version.txt"
        self.firstArchiveURL = "http://insilab.org/files/lisica-plugin/archive.zip"
        self.currentVersion=""
        self.latestVersion = ""

    def installationFailed(self):
        global running, status
        status = "failed"
        running = False

    def deleteTmpDir(self):
        try:
            shutil.rmtree(self.tmpDir)
            print("deleted temporary ", self.tmpDir)
        except:
            print("error : could not remove temporary directory")

    def createTmpDir(self):
        try:
            self.tmpDir= tempfile.mkdtemp()
            print("created temporary ", self.tmpDir)
        except:
            print("error : could not create temporary directory")
            self.installationFailed()
        self.zipFileName=os.path.join(self.tmpDir, "archive.zip")

    def downloadInstall(self):
        try:
            print("Fetching plugin from the git server")
            urlcontent = urlopen(self.firstArchiveURL, timeout=5)
            zipcontent = urlcontent.read()
            LiSiCAzipFile = open(self.zipFileName, 'wb')
            LiSiCAzipFile.write(zipcontent)
        except HTTPError as e1:
            print("HTTP Error:", e1.code, e1.reason)
            self.installationFailed()
        except URLError as e2:
            print("URL Error:", e2.reason)
            self.installationFailed()
        except Exception as e:
            print("Error: download failed, check if http://insilab.org website is up...")
            self.installationFailed()
        finally:
            try:
                LiSiCAzipFile.close()
            except:
                pass
            try:
                urlcontent.close()
            except:
                pass

    def extractInstall(self):
        # this must be called before import LisicaGUI, otherwise
        # rmtree will fail on NFS systems due to open log file handle
        try:
            with contextlib.closing(zipfile.ZipFile(self.zipFileName, "r")) as LiSiCAzip:
                for member in LiSiCAzip.namelist():
                    masterDir = os.path.dirname(member)
                    break
                LiSiCAzip.extractall(self.tmpDir)
            # copy new
            copy_tree(os.path.join(self.tmpDir, masterDir, ".lisicagui"), LISICA_DIRECTORY)
        except:
            print("installation of lisicagui failed")
            self.installationFailed()

    def firstUpgrade(self):
        return not os.path.isdir(LISICA_DIRECTORY)

    def upgrade(self):

        #try:
        #    shutil.rmtree(LISICA_DIRECTORY)
        #except Exception, e:
        #    print e

        self.createTmpDir()
        self.downloadInstall()
        self.extractInstall()
        self.deleteTmpDir()

        # add executable properties
        configure=Configuration()
        exe_filename=configure.exe_File()
        exe_path=os.path.normpath(os.path.join(LISICA_DIRECTORY,"bin",exe_filename))
        st = os.stat(exe_path)
        os.chmod(exe_path, st.st_mode | stat.S_IEXEC)

        sys.path.append(os.path.normpath(os.path.join(LISICA_DIRECTORY, "modules")))

        self.writeToVersionTxt(self.latestVersion)

        print("Upgrade finished successfully!")
        global running, status
        status = "start"
        running = False

    #
    # read current version of probis from version.txt file
    #
    def findCurrentVersion(self):

        if os.path.isfile(versionFile):
            with open(versionFile, 'r') as myFile:
                lines = myFile.readlines()
            if len(lines) == 1:
                self.currentVersion = lines[0].strip()
            else:
                date = lines[len(lines)-1].split('\t')[2]
                t = time.strftime("%d/%m/%Y")

                tmpTime1 = date.split('/')
                tmpTime2 = t.split('/')
                if int(tmpTime2[2]) > int(tmpTime1[2]) or int(tmpTime2[1]) > int(tmpTime1[1]) or int(tmpTime2[0]) > int(tmpTime1[0])+15:
                    self.currentVersion = lines[0].strip()
                else:
                    self.currentVersion = (lines[len(lines)-1].split('\t')[0]).strip()

    #
    # get info about latest version
    #
    def findLatestVersion(self):
        try:
            # from insilab git server
            versionFile = urllib.request.urlopen(self.firstVersionURL, timeout=5)
            self.latestVersion = versionFile.read().strip()

            if len(self.latestVersion) > 6:
                self.latestVersion = ""

            print("l1 = ", self.latestVersion)

        except HTTPError as e1:
            print("HTTP Error:", e1.code, e1.reason)
        except URLError as e2:
            print("URL Error:", e2.reason)
        except Exception as e:
            print("URL Error: Is Insilab webpage (http://insilab.org) down?")

    #
    # yes or no update window
    #
    def updateWindow(self):

        self.window=Tk()
        self.window.title("Software Update")

        frame = Frame(self.window)
        frame.pack()

        Label(frame, text="A new LiSiCA GUI version is available. Do you want to update?", anchor=CENTER).pack(pady=(20,10), padx=30, fill=BOTH, expand=1)

        versionFrame = Frame(self.window)
        versionFrame.pack(fill=BOTH, expand=1, padx=15, pady=(0,10))

        Label(versionFrame, text="Current version: ").grid(column=0, row=0, sticky=W, padx=(30,0), pady=(10,0))
        Label(versionFrame, text="Latest version: ").grid(column=0, row=1, sticky=W, padx=(30,0), pady=(0,10))

        Label(versionFrame, text=self.currentVersion).grid(column=1, row=0, sticky=W, padx=10, pady=(10,0))
        Label(versionFrame, text=self.latestVersion).grid(column=1, row=1, sticky=W, padx=10, pady=(0,10))
        Label(versionFrame, text="For more information about software update, go to:", font=("Times",10)).grid(column=0, columnspan=2, row=3, padx=30)
        urlLabel = Label(versionFrame, text="http://www.insilab.org/lisica", font=("Times",10),foreground="blue",underline=True)
        urlLabel.grid(row=4, column=0, columnspan=2, pady=(0, 10), padx=30, sticky=W)
        urlLabel.bind("<Button-1>", self.open_url)

        self.checkRemindMe = 0
        Checkbutton(self.window, command=self.setCheckRemindMe, text="Do not ask me again").pack(fill=BOTH, expand=1, padx=60)

        buttonsFrame = Frame(self.window)
        buttonsFrame.pack(fill=BOTH, expand=1, padx=30, pady=(10,20))
        Button(buttonsFrame, text='Cancel', command=self.cancelButton).grid(row=0, column=0, padx=(200, 20), pady=(0,10))
        Button(buttonsFrame, text='Update', command=self.updateButton).grid(row=0, column=1, pady=(0,10))

        self.window.bind('<Return>', self.updateButton)
        self.window.protocol('WM_DELETE_WINDOW', self.cancelButton)

        self.window.mainloop()

    def open_url(self, e):
        try:
            webbrowser.open_new(r"http://www.insilab.org/lisica")
        except:
            print("Error: Could not open the website.")

    def setCheckRemindMe(self):
        if self.checkRemindMe == 0:
            self.checkRemindMe = 1
        else:
            self.checkRemindMe = 0

    def cancelButton(self):
        if self.checkRemindMe  == 1:
            self.writeToVersionTxt(self.latestVersion, True)
        self.window.quit()

    def updateButton(self, event=None):
        global status
        status = "update"
        self.window.quit()

    #
    # write to version.txt file
    #
    def writeToVersionTxt(self, version, reminder=False):

        if reminder:
            with open(versionFile, 'a') as myfile:
                myfile.write(version+"\t later \t"+time.strftime("%d/%m/%Y")+"\n")

        else:
            with open(versionFile, 'w') as myfile:
                myfile.write(version+"\n")

def internetOn():
        try:
            urllib.request.urlopen('http://www.google.com',timeout=1)
            return True
        except:
            pass
        return False

def showManualDlInfo():
    tkinter.messagebox.showinfo("Installation failed.", "To download and manually install LiSiCA GUI please visit our website http://www.insilab.org/lisica/download.php .")
    #pass

def run():

    print("Initialising LiSiCA ...")

    global running, updateObj, status
    status = "start"

    try:
        sys.path.remove('')
    except:
        pass

    updateObj = UpdateCheck()

    if updateObj.firstUpgrade():
        if not internetOn():
            status = "no-internet"
        else:
            updateObj.findLatestVersion()
            updateObj.upgrade()
    else:
        updateObj.findCurrentVersion()

        if internetOn():
            updateObj.findLatestVersion()

            if updateObj.currentVersion == "UPDATE NOW":
                updateObj.upgrade()

            elif updateObj.latestVersion != updateObj.currentVersion:
                status = "check-update"

    running = False

class FuncThread(Thread):
    def __init__(self, target, *args):
        self._target = target
        self._args = args
        Thread.__init__(self)

    def run(self):
        self._target(*self._args)

class Logo(Frame):

    def __init__(self, parent, txt):
        Frame.__init__(self, parent)

        self.parent = parent

        # move window to center
        self.update_idletasks()
        w = self.winfo_screenwidth()
        h = self.winfo_screenheight()
        size = tuple(int(_) for _ in self.parent.geometry().split('+')[0].split('x'))
        x = w/2 - size[0]/2
        y = h/2 - size[1]/2
        self.parent.geometry("%dx%d+%d+%d" % (size + (x, y)))

        s = Style()
        s.configure("My.TFrame", background='#BFBFBF')

        frame=Frame(self.parent, style="My.TFrame")
        frame.pack(fill=BOTH, expand=1)

        raw_data = """R0lGODlhgACAAOf/ACUAAyoBABUAWDUCADwBAA0OCwoGZBcPB0cCABoPEDEKAzkMBB0UFVQGABYXFRUXJxcPdCkPQxoPgB0a
                      ElcKDRcVYBscGmIKAD0VBEMTCSQdFDMbEl0RAiUeK0gYCCEjIU0YEnAPD1MbCikcfiQcmywmIR4dpTAmGCcaqi4Ww2UZBSgl
                      TlkfCGEcFSkrKDMhcTcnKk8jDEQlGSoikmwdAywsLysmbi0rOFsiC0sjOzctHVMmEEkkR1EmHjMuKk8oFCsg0CgjxWUkClwn
                      FC4vTislujAyLy8mslUpLGwnBWUnIncmADgvZS4rrDw0KmYrFDY3M1IrYDouiVcxH0E3JXYrAEI2MkQ1Rks2Ki0t3GwvEnop
                      J3EuFGwwGW4xDqkeJHUxCTw9O3swBHUxEZolHbQeHmU1I38yAMAcIDgy33M1GNAaInw2B3k1GkQ9a4I1CkNDQX03EFs/MHc5
                      Gzs262A/K0c2zkhBZlZCO05FOjo493U8IoM8FU9JQ4A/HEVEoHRCKktMSYdAGIRCGHNGLfYhJ4xDHFBRTYNHIVNRVWhOQpFH
                      GZBHIF1USYlNJlhMwVtTc5VLI4ZPMGpWPlhZVn5SOpZNK5tQKHpZRF5gXYtXNF1an2pffGRlY4tdQnBkVJVdOWpnX35mWmNg
                      6mllv4ppU5RoRIZrWXZwZ3luhJZsU3V3dIt1W4h2Z5p1WZV6Z35/fYR+d4WAc5Z9b5mGbqOEZpWJZqSIdY6NipOKraCNfZqR
                      l6KTfJ2UhaeUeK+XfJublKebia6chqSau6udmq2jhKOkoamklrOhl7CkjLKmlK+ourSrkrerjLSumrStpq2vrLuunLyykrq0
                      oLy1p8K1o7q2tcC3ncK5n8S5msG6pr67rMS+qca9tsq9q8fBrcrBp8DCv8fBwMrEsMfGvdDHrdPGs8/JtNLMt9zMtNvNu9PO
                      ztjSvdbTxNXTyt/XvN/Yw9fZ097ay97Z19/bzN/f3OTg0d3j5ejk1e/o1Ojq5+/s3PDy7/fz5Pr8+f///yH+EUNyZWF0ZWQg
                      d2l0aCBHSU1QACH5BAEKAP8ALAAAAACAAIAAAAj+AP8JHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmy
                      pMmTKFOqXMmypcuXMGPKnEmzps2bOHPq3Mmzp8+fQIMKHUq0qNGjSJMqXcq0qdOnNuPwGcTTkCE+PvlcNcTIUqSaVgXxWSTI
                      ZxxNtTwh4mrJEkxHkRgZQmSqlqayPeNEisYN2StNhiJdusQykmFEkl4h83bNEda8fH6dQ4eO2y1PXAd/lehWIqNLVj350kbZ
                      3C0+b36+MTVOnbt27boJM+Vo0eDOCdtaGsy7N2GFbRnRDdYN9mtypt6A+QlG0LV28OjBg9fOXDJVtW8bbNt7t+/v2y3+CVel
                      zBz06NSvoQYKRkwtdNHpyZN3XJmr7L8N796v+/Yl799tFokliyCiCjLjtOPOfPRIh04tYiwHlBiOJChPg9JRh0431/HmHXff
                      XTKgV/8B6N8ljriiDDfoQHehPQ22w40kYlQRVBVi/IKOO/FpOI43ybgCymf9tSWYYUgi6dWAR4r4XySg1JKMNuTABs989KEj
                      TI1DLQHKNy3C1s6Gs13SFXeMJKnmmnGJyGYki1hiijAsWjkmN5pwKRSOwoxDDjrndDONK4sYsggjiKap5iJxIclomooaFqma
                      cjHiyjTf/InOOMKAsURRS5hCDTfcUCOMJloZWmiirCIK5yL+hcZ6KCOHwkprq7SSJYgmxWhDKjWmLJFEUUmwEYwzzvCCyBuC
                      WOVsrbcaKq2z1D5rla20ViuIIG8goguyvnh61BKeJENLHGy8wQcfzVZbaLXUDmKVvO7Ca8i226LrBy3JeLIEDeOywUocYrDB
                      xrrsbntvswwLMsggWkVsiLypprrwvfeuKxYf6YrhBytsfIqUGCSTbLBU7CaMb8JTXYXwyxFHjO/ML7PRXskiH1WyyQfD7PPP
                      6v4sNMJvGMxGjSTnDOrOBRtc9NCoRf3G1FNLHTTQqBnNtNJELVEjjmAY/UYcUx9ctNMGo0b2IOnyQfbYqI1dNNVxn330zmcM
                      axT+yTjynC7VRceBiCaeaIJIuk6XbfbbZyPiiSeSIILu2EaH3fcZXAt1Bt88o/s2G5IEI846pIsTjCRoH5w42WBIosvopFuj
                      C+pG28y0jaBuXnLtcscxyzr3BC/8PeSo8je6apPNhiviDC/8Oq/UfjPOR+nuNxtkizHLPM7r4/0965QC+BttlK3KOt6nP/w8
                      rWg9vZ5FiWE99k6L4Qn6wosDDC6xPHOPPuJAHeOm5glx6GMdz+gFKnCBv/+tg0aVkx/8iCJBkoHhDNiLAxiIkT59GCMW4hCH
                      EzTQCHHwgxjjm9ozAAiMdXRDBxpwgjH4kT5dhM1gJcPcUaqAwabJrVv+JtQHP54BDH7MIw8n0EAMm+eJt6GrFPewxgzdgUQY
                      luAZNORHN+agtbslxWRNM9gZJDEPfvDjHrgQYix0QAUdwBAL80DG31S4DlQIERVspIIPTtAHIfLjgU0L2+a+eLSToYsNnriH
                      GZ8RC3/MQw5UiCQVkhiLdSzrDeSaxydiYcQ8SNKNJbCGP4xIo0OSDClVSGUY0eaJevDDH8DwASqC0UY2+sAHffAB9M5QtFmI
                      owQ+iAUwasnGRpQAGKOcR57QVTC+4e4nSehbyW5WOzFIwh6vBIYSNXCCbnKTGHXEhRzfMIZqxOIA2+zmCXRwjHks0B/+WAcg
                      cHi3naUSKNL+nGbtzrAHccDTGBPYpkCB4Q5U9KEb5eODOPqAToEqsYWfMMYou0GwQnLua11iWjPTBQZkvNIaE5jAAUZ6gAL4
                      IA9WKEAo+bAERIC0ACQdaQGc0AcnTMCf/AhG08TgtSos4Z5FGQRPNUoyU7iyHiWAqQZK4AQqoCIWfVDEJ64xC1fUAhmNyCoW
                      sOCEEkyACk5QqSuV2TevLcFrSJFGLRDBU596jaeDeEY7yNGLXiDjGtXwRjfM4Q10pCMd3egGZYqTjsGOQxvPIEYvYjELesxj
                      GpJAl0/PEAdT/IIZRvFGORjzC1MgYhCDU8UvmpHX1qjDSux4x3mmw1oesXY6sGH+BzzYwQ51dMMb2tDGNYTxi18IoxncGIc5
                      pkEUb/wVHebgq261odlyoEMdsn2tdKZL3QbFB0PoyRBr36GOdJgDuX397l/LMZRq/PW86VAHZZ6rDnW8lrUYim+D8CHf+qLn
                      te+YLW3be97uakMoxvWuOdLbXtrS9r3ZrW996StfBL/WwPDobjrKcVzi/kQZuiVuOfj7jnSk9sPRfS+MsGsPeMBoxPYo8XTy
                      q+J3pFa/tD0vef9xjWtIoyjgQO95DQzh91bXxNeVDjtSbGIex1jHE57wNZCCjXI4+clJJrCREYyhFGP3vUbmr4wn/ORsMNnJ
                      4ABHOcL8ZCf71cM9fq/+PBw8W/3KuMzNLXM5mmGUZIQZG9nIczP2LI08k5nC0E0zm/Nr4O6COcx5zkaNs4GNMIf5xkXhhTB8
                      QemDULoZ2RAzZQrcZjbzWL1jzkYzKn2QZiSjGcoQBkns8RJaNEPMzkWzbA8cXSOn4xxjbgYvbKGSfQxkH6z+Rz7wMZ2WeGAS
                      xWj0OGKNDiPz+K+4Bgc2ilGKIaAEHvjYh6/3kY9+aNvb+8CHsTGggDoUoxrjEPNk2CFrdjwXUOgIdTEw4QERWLsk9tC2vsG9
                      D34Pm9gpYQELRJCBBSAbG8v+RjnOwfDjFvYc6QbHNJpRCoE/wQtaWLW+N87xb/eDHim5+BP+cPAERSjiFM1o9DfAoXCGM3wc
                      4/jGyrHRjFYoQhSA8EIc4uAFkWS7Hh3neD7yAWyVjGEMXvDDK2zRik+4utEsd/Q3Ih7midMCE63QBS80wQY/DGIMH6HH0Ike
                      dI7jY9gpGcPO+XCLZCAjGLrIOjOwQXepg0MbdJfGqEVxCl0ggxm/cIzbOmKPbOPj8EPX9+HDrfjDwwMlY2jDzl3hjGhMIxrK
                      iHsxmCENbEyD7qDHhjSkUQxbfEIXyrB8NGiBsDZoRB6Hj73sZR/u2dM3JTqPAyiYMY1q5HYawZiFLYox+uIbvxmlxwQtgjGN
                      3zvDFeri+UWwbfvqVz/FuN/5IHz+0Xtf5TYaurDF8JvB+eIzA/m+YIUodBGN3GqjGtNIhiXcFgeLDFk+KcZH4fVv/djDCB0p
                      AQYapAqWl1vecIDaoAy00AqSJgqKUAd1oAitUAy+YHqzgAzMhYDVEA2vIBVxoDcSwQ7SkWLykGImeIIoaIIglxJJoC/JQA58
                      cYDe8CPVIAyt0AoyAAAHAAA8CAB1YAui8ArBcA3c4A3RQA7foA3ToAyOgD0SEhHcwFryQFslWGImaGImWIIXQh3ngHtHYwrz
                      EA+woA0w5w3m8CPRcAtYAAAK0IYBoAA8OAmsEAzRMIPfAAvxUA/vFw2uYDQg6BCEMA3s0A7jQAu0cCX+awZkCIYl08EOJIEG
                      BQEGAkgLwBAO/GAMygBzyWUO2hAMZvCGbRiKAKAIdKhZ0TBD4kAMv1cMbAMGwwKJDgEIwUULgPAE0sBmDgYdjjgShYAGITAQ
                      SRAhiJAMznAM4QANYYAKZBgPz9AXihCKbTgAbYgL7rAN04AKYQAN4fAMefV+zpAnbJAEIYAGhdAQT4AJt0AIWvAEryAmrAUd
                      qwVb7eBuJVEGvgiMkmgKzuB7lBAGLmABlGCJH6QNtEBu0BgAVjBD4UAJFuACYZAJZfh+g4Ij4ogGZcAQXbAHe6AGaqAFgCCI
                      gygmIikmBgaAG8EP4YAQIUABFDAQVQAGVfD+Cs2nDYfgAjVQAH0QC7CQCc5QDtNwCgapAAuABaeQCbAAVQVQAy5wCArnDdyg
                      hLxwNFXAARTwiwdhif8ACHOwlVupBbTgcs1GW/PobICyEfoADPEQDoeAEF9AEKnEBrwgDb6CCh/gAsHwXTGnXocVDKIwCScn
                      DNVQDQOGDsHgAx+ACmWIW9NQDH6QSjTQlgdxCOEQD8CgD57AlXNQCd/ADLwAJgZGDu62Xi+3EdBQD+GwCpSQED7gllUQB8Iw
                      k4lgBOXxXezFX8p1DWJGYPwVDUaQCGe4WbqlDIiQSjGwmghBCasQDvXwCnOwB22wB7zgCpUwDS53DuRQnS73DR3+AQtwQAlG
                      gBCBEAYf4JJV4AfK0HzLoAc2IFzrVWD7xWMuVmjqZQN6sAy35ZTT8I2pVAJhEAgI4QOUAAeigJmVQAhmoAxIKHPYeQ7fcA7/
                      5RGBYAQOcBBhAAdQYAEu2VK8NwxpAASpsImbBl3vMKIkSqKFVlipAAR0MAwH+JTfuAQsYAFQAAdhYBA/4ABGEAhy0Jx7MAdq
                      sAevWQyswAwK2qAM+g3O8BGHYAQ10JAdQBB/AAcu8AEOMKX/4FOIwAzDQAd6QAJuwJ5+9VyzRaIrBg8jul/q5QYkoAcrip/O
                      UAkb4AIOUJdw8AcEAQP/WANGgAdb2QbNyQqsQAhPwAr+3CBzhrpyIGGaFlAABfABNmACaRAEaZAFT8qoH6CUcGAEWHAHdBAE
                      RYACTJBc7cluqTWiZmqi+1VYTIACRRAEdHAHoWAE/lgDJYABBfAPHZAFkZoGJmADJbABDGAB4RANlcCVe6AFWiCT0zAq31Co
                      SfoR/AAMmVAQJqAHRQABBlAQBeACEWoBNfACnFABEjAD1CCq6YVmJWqq8dle6kANMyABFZAKL9CkOeoCGEADKjAQBgABRaAH
                      JsADXeCjXUAJReQKxuoKtOAJxUANyzp6IAEN0IALBlEERxAE2WoQRuACLpAAqDANw5ALmzADgaANtPlX8VmqZyqf3xAIM7D+
                      CbnAorJQly7gA0nwh/9gAEFwBFLQBRypBnNgBrgADbOwlT9qBmagC9PweZglEnCAEBIAAQnBAAkwBXSYgS5gBFCACuZwDu7w
                      DOVgYCaKDs/gDrWFClCQsWf4I96ACg5gAYSwBPlKED0AASPAsxzpo3NQB3Lgp1vZBYTwLfm5tCuRBSmQEFZQAkLAfbnVC6EQ
                      oQ4QkPUADb3gngbWC6W5kDgaCKEQDGrLDb1gBHAwBjTAAQTxBEOQAkfQBXbrs2rQBj5LtIDAd6f2EkSwAoZbAiygrNrAuBmb
                      AHCwCrCAC8rAroHGDs6AC7CwCnCQAFcbCr0QkZ8LB0kwugPxBKb+SwRX0LPaS7Q+2wXIagvJABNQ4AIJEQY+4AGV4AzNxwyB
                      8AFQcJecSBrqRbztxVyUEQxQ8AGBwAxq6wyyIKsqELf/YL1aMAQuYAXam8AcqbpagAkxAQeBAAUTahAQbARTGwy7QAqjIAWh
                      AHOauF7rda7HVRrmEApSMAqkQAzcELM5CgekOwRD8ATrqAFQEAh4YLc4zLNmgKwzEQZhYAS3ahA/LKFG0ASPQAdZQALTcFua
                      KKog/MTIlVzcQAJZQAeP0ARELKs9EMMELAMFIKthoLpizMA8HBNlsAZbYAQW4AAOUAMjMBB64AZyWgAK0AGQSgckcAekMoMz
                      uIkgSpv+yeXBMHcHJEAHvHoDh2ABDOACbmAHPBAFOWADNcDGFuADW/AFZEAG65hxM9GLFLAGBPEAreqvQCABA9EAAYwCqgwJ
                      GahX5bBswuXHmwjLHgwJqowCysAMwSAEDSACEAAE1eqpHbADMTwEaEAB5GgT9njMBzGpKCAABcEBF4AETAAJvtfKB9jEsZy2
                      goyAnMAEu4B5mNAADRDDEYACupoD1lvM/4DMFmkTK4kQJCABplwQDSDNpVB51+wrRZjNgvzPnfuU2hANzvAKHNDLpju3EjAC
                      MGwQVSkUQVDP9swBKvAKzBAN17zHMvgjZai2TinQShgNzKALLUDOBCEBQdD+FE0AtQdxzyowC8ygvvssgx9N06QC0pfnDLrw
                      BA2AAAUBAU3QFBeaEOTcAq2gDJU3k973lKTCz+4nkdFwDLTQAj5tEDLKFDRKvgmBAPeMCcEQ00mr1E/tfmHtDMyQDKXQAASw
                      AAfhkE2rFIEQCFd7ECKwAANAAFz9BK0QDMdQeZYX1r0Hf89A0MeQDK1gBgSw1hkgAgL8Dxkb10cRufrQCeMbkBJLEEkgBARn
                      13jdAEpQCrpADEiNLASNLM6gDMnQC6dgBggwAAuQASCgAkLABXqDCwvpAlDQCfpQmkNxicYAC4waCPEQrQIhBE/ABVwgBEMg
                      Ah7A2Z1tBphwCsvpFwzUHXeYYAYgQACuvdhDMNvIzQVdUETxEAiMCgvGMENDgQurYBAQO8BHd3TI/QSaDQIFpwADcNd4DQL6
                      Td/aHQADgAH1Ztxc0AbI3QZjYAbtXRCrcNlL8QRH1wYQHuFqwAXyvdkBcOEYjuE9uAAgIOAR/uFtMAV18ARQUbptwAcnjuIS
                      PnIZAIcAoOE8eOEvHgBsmAEk17ofvi4QDnYlLhBDgOMQ3gXWiwMeMAA9GOMzTuMZ/uI9OACLbdwB+5yuS+I9PhBD0AL3BhIt
                      gOVV3uVe/uVgHuZiPuZkXuZmfuZonuZqvuYVERAAOw=="""

        photo=PhotoImage(master=self, data=raw_data)
        display=Label(frame, image=photo, background="#BFBFBF")
        display.image=photo
        display.pack(ipady=10, ipadx=50, fill=BOTH)

        Label(frame, text=txt, anchor=E, font = "Fixedsys 10 bold").pack(ipady=0, ipadx=0, fill=BOTH)

        global running
        running = True

        if txt == "Starting Software ":
            t = FuncThread(run)
        else:
            global updateObj
            #shutil.rmtree(LISICA_DIRECTORY)
            t = FuncThread(updateObj.upgrade)
        t.daemon = True
        t.start()

        while running:
            self.parent.update_idletasks()
            self.parent.update()

        self.parent.destroy()

def main():
    root = Tk()
    root.overrideredirect(1)
    root.geometry("250x170")
    Logo(root, "Starting Software ")

    global updateObj, status

    if status == "no-internet":
        #pass
        tkinter.messagebox.showinfo("Communication Error", "No Internet connection available. Please make sure that your device is connected to the Internet.")

    if status == "check-update":
        status = "start"
        updateObj.updateWindow()
        updateObj.window.destroy()
        if status == "update":
            root = Tk()
            root.overrideredirect(1)
            root.geometry("250x170")
            Logo(root, "Updating Software ")

    if status == "start":
        print("Python version: "+platform.architecture()[0])
        sys.path.append(os.path.normpath(os.path.join(LISICA_DIRECTORY, "modules")))
        del status, updateObj # remove global variables
        import LisicaGUI
        LisicaGUI.main()

    elif status == "failed":
        showManualDlInfo()

def __init__(self):
    self.menuBar.addmenuitem('Plugin', 'command', 'LiSiCA', label='LiSiCA', command=lambda s=self: main())


#!/usr/bin/env python

import socket
import argparse
import utility
from game import Game

def main():
    parser = argparse.ArgumentParser(description="Python client for SIG-GAME framework.")
    parser.add_argument("-a", "--address", dest='conn_address', default="localhost",
                        help="The address of the game server.", type=str)
    parser.add_argument("-p", "--port", dest='conn_port', default="19000",
                        help="The port of the game server.", type=int)
    parser.add_argument("-g", "--game", dest='game_name', default=None,
                        help="The name of game to connect to on the server.")

    parser.add_argument("-v", "--verbose", dest='is_verbose', default=False,
                        help="Print more output messages.", action="store_true")
    parser.add_argument("-vv", "--very-verbose", dest='is_very_verbose', default=False,
                        help="Print even more output messages.", action="store_true")
    args = parser.parse_args()

    connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    game = Game(conn=connection, addr=args.conn_address, port=args.conn_port, name=args.game_name)
    utility.verbose = args.is_verbose
    utility.very_verbose = args.is_very_verbose

    game.run()

    connection.close()

    return

if __name__ == '__main__':
    main()


from torch.utils.data import Dataset
from torchvision import transforms
from scipy import misc
import numpy as np
import imageio
import torch
import os

to_tensor = transforms.Compose([
    transforms.ToTensor()
])

def extract_bayer_channels(raw):

    # Reshape the input bayer image

    ch_B  = raw[1::2, 1::2]
    ch_Gb = raw[0::2, 1::2]
    ch_R  = raw[0::2, 0::2]
    ch_Gr = raw[1::2, 0::2]

    RAW_combined = np.dstack((ch_B, ch_Gb, ch_R, ch_Gr))
    RAW_norm = RAW_combined.astype(np.float32) / (4 * 255)

    return RAW_norm

class LoadData(Dataset):

    def __init__(self, dataset_dir, dataset_size, dslr_scale, test=False):

        if test:
            self.raw_dir = os.path.join(dataset_dir, 'test', 'huawei_raw')
            self.dslr_dir = os.path.join(dataset_dir, 'test', 'canon')
            self.dataset_size = dataset_size
        else:
            self.raw_dir = os.path.join(dataset_dir, 'train', 'huawei_raw')
            self.dslr_dir = os.path.join(dataset_dir, 'train', 'canon')

        self.dataset_size = dataset_size
        self.scale = dslr_scale
        self.test = test

    def __len__(self):
        return self.dataset_size

    def __getitem__(self, idx):

        raw_image = np.asarray(imageio.imread(os.path.join(self.raw_dir, str(idx) + '.png')))
        raw_image = extract_bayer_channels(raw_image)
        raw_image = torch.from_numpy(raw_image.transpose((2, 0, 1)))

        dslr_image = misc.imread(os.path.join(self.dslr_dir, str(idx) + ".jpg"))
        dslr_image = np.asarray(dslr_image)
        dslr_image = np.float32(misc.imresize(dslr_image, self.scale / 2.0)) / 255.0
        dslr_image = torch.from_numpy(dslr_image.transpose((2, 0, 1)))

        return raw_image, dslr_image

class LoadVisualData(Dataset):

    def __init__(self, data_dir, size, scale, level, full_resolution=False):

        self.raw_dir = os.path.join(data_dir, 'test', 'huawei_full_resolution')

        self.dataset_size = size
        self.scale = scale
        self.level = level
        self.full_resolution = full_resolution
        self.test_images = os.listdir(self.raw_dir)

        if level > 1 or full_resolution:
            self.image_height = 1440
            self.image_width = 1984
        elif level > 0:
            self.image_height = 1280
            self.image_width = 1280
        else:
            self.image_height = 960
            self.image_width = 960

    def __len__(self):
        return self.dataset_size

    def __getitem__(self, idx):

        raw_image = np.asarray(imageio.imread(os.path.join(self.raw_dir, self.test_images[idx])))
        raw_image = extract_bayer_channels(raw_image)

        if self.level > 1 or self.full_resolution:
            raw_image = raw_image[0:self.image_height, 0:self.image_width, :]
        elif self.level > 0:
            raw_image = raw_image[80:self.image_height + 80, 352:self.image_width + 352, :]
        else:
            raw_image = raw_image[240:self.image_height + 240, 512:self.image_width + 512, :]

        raw_image = torch.from_numpy(raw_image.transpose((2, 0, 1)))

        return raw_image


# Import libraries
from torch import nn
from torch.nn import functional as F

class LSTMTagger(nn.Module):

	def __init__(self, embedding_dim, hidden_dim, vocab_size, tagset_size, bidirectional, emb_weights):
		super(LSTMTagger, self).__init__()

		###########################
		# Embeds handling
		###########################
		if emb_weights is not None:
			self.word_embeddings = nn.Embedding.from_pretrained(emb_weights, freeze=True)
		else:
			self.word_embeddings = nn.Embedding(vocab_size, embedding_dim)

		# The LSTM takes word embeddings as inputs, and outputs hidden states with dimensionality hidden_dim.
		self.lstm = nn.LSTM(input_size=embedding_dim, hidden_size=hidden_dim // (1 if not bidirectional else 2),
			num_layers=1, bidirectional=bidirectional, batch_first=True)

		# The linear layer that maps from hidden state space to tag space
		self.hidden2tag = nn.Linear(hidden_dim, tagset_size)

	def forward(self, sentences):
		# No need to take in account the batch dimension
		embeds = self.word_embeddings(sentences)

		# Batch first is true so we don't need to work on dimensions
		lstm_out, _ = self.lstm(embeds) # Dimension is [len(sentences), len_sent, -1]

		# Flatten the LSTM output and feed it to the linear layer
		linear_input = lstm_out.contiguous().view(-1, lstm_out.shape[2])
		tag_space = self.hidden2tag(linear_input)

		# Finally apply the softmax to have the probability of the results
		tag_scores = F.log_softmax(tag_space, dim=1)

		return tag_scores


import pygame
import src.constants as CONSTANTS
from src.obstacle import Obstacle
from typing import Tuple
from src.commonUtils import resource_path

class Track(pygame.sprite.Sprite):

    def __init__(self, track_id=''):
        super(Track, self).__init__()

        __TRACKS_DIR = 'assets/'
        self.track_id = track_id
        self.track_path = __TRACKS_DIR + "track" + str(track_id) + ".png"

        self.image = pygame.image.load(resource_path(self.track_path)).convert_alpha()
        self.rect = self.image.get_rect(topleft=(0, CONSTANTS.OFFSET))
        self.mask = pygame.mask.from_surface(self.image)

    def get_at(self, abs_pt: Tuple[int, int]) -> pygame.Color:
        off_x = abs_pt[0] - self.rect.topleft[0]
        off_y = abs_pt[1] - self.rect.topleft[1]
        if 0 <= off_x < self.rect.width and 0 <= off_y < self.rect.height:
            return self.image.get_at((off_x, off_y))
        else:
            return None

    def place_obstacle(self, obstacle: Obstacle, abs_pos):
        position = (abs_pos[0], abs_pos[1]-CONSTANTS.OFFSET)
        self.image.blit(obstacle.image, position)
        self.mask = pygame.mask.from_surface(self.image)


"""ROBERT"""
import streamlit as st
import plotly.graph_objects as go
from app.core import universes, factors

class BaseState:
    item = None

    @classmethod
    def get(cls) -> ...:
        if cls.__name__ not in st.session_state:
            cls.reset()
        return st.session_state[cls.__name__]

    @classmethod
    def reset(cls) -> None:
        st.session_state[cls.__name__] = cls.item

    @classmethod
    def set(cls, item: ..., rerun: bool = True):
        if cls.get() != item:
            st.session_state[cls.__name__] = item
            if rerun:
                st.rerun()

class Universe(BaseState):
    item = "UsSectors"

    @classmethod
    def select(cls) -> str:
        return str(
            st.selectbox(
                label=cls.__name__,
                options=universes.__all__,
                index=universes.__all__.index(cls.get()),
            )
        )

class Factor(BaseState):
    item = "PxMom1M"

    @classmethod
    def select(cls) -> str:
        return str(
            st.selectbox(
                label=cls.__name__,
                options=factors.__all__,
                index=factors.__all__.index(cls.get()),
            )
        )

class Webpage(BaseState):
    item = "Dashboard"

class FactorPlot(BaseState):
    item = go.Figure()


import inspect
import os
import sys
from abc import ABC, abstractmethod
from datetime import datetime
from itertools import chain
from typing import List

from celery import shared_task

class AbstractDeployer(ABC):

    @abstractmethod
    def deployer_pre_exec_jobs(self) -> List[str]:
        pass

    @abstractmethod
    def deployer_exec_jobs(self) -> List[str]:
        pass

    @abstractmethod
    def deployer_post_exec_jobs(self) -> List[str]:
        pass

    @abstractmethod
    def check_prerequisite(self) -> bool:
        print("requirements check!")

    @staticmethod
    @abstractmethod
    def deploy(self):
        print("deploy!")

class PreExecContext:
    def __init__(self, step):
        self.step = step
        self.started = datetime.now()

class ExecContext:
    def __init__(self, step):
        self.step = step
        self.started = datetime.now()

class PostExecContext:
    def __init__(self, step):
        self.step = step
        self.started = datetime.now()

class BaseDeployer(AbstractDeployer, ABC):

    def deployer_pre_exec_jobs(self) -> List[str]:
        return []

    def deployer_exec_jobs(self) -> List[str]:
        return []

    def deployer_post_exec_jobs(self) -> List[str]:
        return []

    @staticmethod
    def check_prerequisite() -> bool:
        print("requirements check!")
        return True

    @staticmethod
    @shared_task(bind=True, autoretry_for=(Exception,), retry_backoff=True, retry_kwargs={"max_retries": 5},
                 name='deployers:deploy')
    def deploy(self, deployer_id: str, deployment_id: str):
        dir_path = os.path.dirname(os.path.realpath(__file__)) + os.sep
        for module in os.listdir(os.path.dirname(dir_path)):
            if module == '__init__.py' or module[-3:] != '.py' or module == str(__file__).removeprefix(dir_path):
                continue
            __import__(f'app.core.deployers.{module[:-3]}', locals(), globals())
        del module

        deployers_modules = [m for _, m in inspect.getmembers(sys.modules['app.core.deployers'], inspect.ismodule)]
        cls_members = list(chain.from_iterable([inspect.getmembers(m, inspect.isclass) for m in deployers_modules]))
        deployer = next(filter(lambda c: c[0] == deployer_id, cls_members))[1]
        check_method = getattr(deployer, 'check_prerequisite')
        check_prerequisite_res = check_method()
        if check_prerequisite_res:
            pre_jobs = getattr(deployer, 'deployer_pre_exec_jobs')
            pre_exec_context = PreExecContext(0)
            for job in pre_jobs():
                pre_exec_job = getattr(deployer, job)
                pre_exec_job(pre_exec_context)
                pre_exec_context.step += 1

            exec_jobs = getattr(deployer, 'deployer_exec_jobs')
            exec_context = ExecContext(0)
            for job in exec_jobs():
                exec_job = getattr(deployer, job)
                exec_job(exec_context)
                exec_context.step += 1

            post_jobs = getattr(deployer, 'deployer_post_exec_jobs')
            post_exec_context = PostExecContext(0)
            for job in post_jobs():
                post_exec_job = getattr(deployer, job)
                post_exec_job(post_exec_context)
                post_exec_context.step += 1
        else:
            raise RuntimeError(f'{type(deployer).__name__} deploy failed! Check Prerequisites Failed!')


# -*- coding: utf-8 -*-
#! /usr/bin/env python
"""
Created on  07 07 10:52:08  2023
@Author: Lulu Shi
@Mails: crazzy_rabbit@163.com
"""
import click
# 换染色体号的脚本

def load_vcf(vcf, chrlist, out):
    Chrfiles = []
    for line in vcf:
        line = line.strip()
        if line.startswith('#') and not line.startswith('##contig'):
            out.write(line + '\n')
        elif line.startswith('##contig'):
            contig = line.strip().split('=')
            contigchr = contig[2].strip().split(',')
            chrlist.seek(0) # 将文件指针重置到文件开头
            for chrchange in chrlist:
                chrchange = chrchange.strip().split()
                if contigchr[0] == chrchange[0]:
                    contigchr[0] = chrchange[1]
                    out.write('='.join(contig[:2]) + '=' + ','.join(contigchr) + '=' + contig[3] + '\n')
                elif contigchr[0] == chrchange[1]:
                    contigchr[0] = chrchange[0]
                    out.write('='.join(contig[:2]) + '=' + ','.join(contigchr) + '=' + contig[3] + '\n')
                else:
                    continue
        elif not line.startswith('#'):
            Chrfiles.append(line.split())

    return Chrfiles

@click.command()
@click.option('-i', '--infile', type=click.File('r'), help='input file for change chr', required=True)
@click.option('-c', '--chrlist', type=click.File('r'), help='chrlist to change chr, such NC123 1', required=True)
@click.option('-o', '--out', type=click.File('w'), help='output file', required=True)
def main(infile, chrlist, out):
    """
    changechr for file, chrlist has 2 col NC and number-chr

    Automatic recognition of vcf file chromosome form and conversion to another
    """
    Chrfiles = load_vcf(infile, chrlist,  out)
    chrlist.seek(0)  # 将文件指针重置到文件开头
    for chrchange in chrlist:
        chrchange = chrchange.strip().split()
        for Chr in Chrfiles:
            if Chr[0] == chrchange[0]:
                Chr[0] = chrchange[1]
                out.write('\t'.join(Chr) + '\n')
            elif Chr[0] == chrchange[1]:
                Chr[0] = chrchange[0]
                out.write('\t'.join(Chr) + '\n')
            else:
                continue

if __name__ == '__main__':
    main()


from flask import Flask, render_template, jsonify, request, abort
from database import LlamaBase, Llama

app = Flask(__name__)

# In-Memory 'Database'
db = LlamaBase()

# Llama Viewer App
# Llama Feeder App
# Llama Market App

@app.route('/')
def hello_world():
    return app.send_static_file('index.html')

@app.route('/<path:path>')
def static_proxy(path):
    # send_static_file will guess the correct MIME type
    return app.send_static_file(path)

@app.route('/user', methods=['GET'])
def get_user():
    user = get_user_from_cookie(db, request)
    if user is None:
        return abort(404)
    return jsonify(user.serialize())

@app.route('/user/login', methods=['POST'])
def user_login():
    user = db.users.get(request.json['user'])
    if user != None and request.json['pass'] == user.password:
        token = db.create_api_token(user.name)['id']
        response = jsonify(user.serialize())
        response.set_cookie('api_token', token, 10*60)  # Lasts 10 minutes
    else:
        response = abort(403)

    return response

def get_user_from_cookie(db, request):
    username = db.api_tokens[request.cookies['api_token']]['user']
    if username is not None:
        return db.users[username]

    return None

@app.route('/llama', methods=['GET'])
def get_llamas():
    user = get_user_from_cookie(db, request)
    if user is None:
        return abort(403)

    llamas = [llama.serialize() for llama in db.llamas.values() if llama.owner == user.name]
    return jsonify({'llamas': llamas})

@app.route('/llama', methods=['POST'])
def post_llamas():
    user = get_user_from_cookie(db, request)
    if user is None:
        return abort(403)

    llama = Llama(user.name)
    db.llamas[llama.id] = llama
    return jsonify({'added': llama.serialize()})

@app.route('/llama/<int:llama_id>', methods=['DELETE'])
def delete_llamas(llama_id):
    user = get_user_from_cookie(db, request)
    if user is None:
        return abort(403)

    if db.llamas.get(llama_id) == None:
        return abort(404)
    elif db.llamas[llama_id].owner != user.name:
        return abort(403)

    return jsonify({'deleted': 'llama {}'.format(llama_id)})

@app.route('/cash', methods=['GET'])
def get_cash():
    user = get_user_from_cookie(db, request)
    if user is None:
        return abort(403)

    return jsonify({'cash': '${}'.format(user.cash)})

@app.route('/cash/<int:amt>', methods=['PUT'])
def put_cash(amt):
    user = get_user_from_cookie(db, request)
    if user is None:
        return abort(403)

    user.cash = amt
    return jsonify({'updated': 'cash = ${}'.format(amt)})

@app.route('/inventory', methods=['GET'])
def get_inventory():
    pass

@app.route('/inventory', methods=['DELETE'])
def delete_inventory():
    pass

@app.route('/inventory', methods=['POST'])
def add_to_inventory():
    pass

if __name__ == '__main__':
    app.run(debug=True)


from __future__ import print_function

import itertools
import random

from drawing import Canvas, Square, Pixel

OPEN = " "

def main():
    width = 80
    height = 40
    size = 5

    canvas = Canvas(width=width, height=height, background=OPEN)

    for y in range(0, height, size-1):
        for x in range(0, width, size-1):
            s = Square(x=x, y=y, width=size, height=size)
            side1 = random.choice([s.top, s.bottom, s.left, s.right])
            canvas.draw(Pixel(p, "#") for p in itertools.chain(side1()))

    edges = list(
        (x, y) for x, y in
        list((x, 0) for x in range(width)) +
        list((x, height-1) for x in range(width)) +
        list((0, y) for y in range(height)) +
        list((width-1, y) for y in range(height))
        if canvas.grid[y][x] == OPEN
    )

    canvas.draw(Pixel(p, "#") for p in Square(0, 0, width, height).outline())

    sx, sy = random.choice(edges)
    ex, ey = random.choice(edges)
    canvas.grid[sy][sx] = "s"
    canvas.grid[ey][ex] = "e"

    print(canvas)


import tensorflow as tf
import itertools
import scipy.spatial.distance
import numpy as np
import time

worker_hosts = ["10.142.0.16:2222", "10.142.0.17:2223"]
# get internal ips of each instance from Google Cloud Compute Engine
# worker_hosts = ["ip1:port","ip2:port"]
# parameter_server = ["ip:port"]

# Set up a TensorFlow cluster
cluster = tf.train.ClusterSpec({"worker": worker_hosts})
# cluster = tf.train.ClusterSpec({"worker": worker_hosts, "ps": parameter_server})

# FLAGS need to be included when run the script using command line
tf.flags.DEFINE_string("job_name", "", "'worker or ps")
tf.flags.DEFINE_integer("task_index", 0, "Index of task")
FLAGS = tf.flags.FLAGS
server = tf.train.Server(cluster, job_name=FLAGS.job_name, task_index=FLAGS.task_index)

# Define computation graph as usual
# Put operations into desired instance
inter = 24
exc = 48

n_inter = inter*inter
n_exc = exc*exc

x = list(itertools.product(range(exc),repeat=2))
d = scipy.spatial.distance.pdist(x,'sqeuclidean')
y = scipy.spatial.distance.squareform(d)
y2 = y[::2]
z = np.reshape(range(inter*exc),(exc,inter))
z = np.reshape(z[::2],(n_inter))
y2 = y2[z]
Pee_granular = 0.15*np.exp(-(y/4)**2)
Pie_granular = 0.3*np.exp(-(y2/4)**2)
Pee_supra = 0.15*np.exp(-(y/4)**2)
Pie_supra = 0.3*np.exp(-(y2/4)**2)
rand_granular_ee = np.random.rand(n_exc,n_exc)
rand_granular_ie = np.random.rand(n_inter,n_exc)
rand_supra_ee = np.random.rand(n_exc,n_exc)
rand_supra_ie = np.random.rand(n_inter,n_exc)
x1,y1 = np.where(Pee_granular-rand_granular_ee<0)
Pee_granular[x1,y1] = 0
Pee_granular = Pee_granular*5
np.fill_diagonal(Pee_granular,0)
x1,y1 = np.where(Pie_granular-rand_granular_ie<0)
Pie_granular[x1,y1] = 0
x1,y1 = np.where(Pee_supra-rand_supra_ee<0)
Pee_supra[x1,y1] = 0
Pee_supra = Pee_supra*5
np.fill_diagonal(Pee_supra,0)
x1,y1 = np.where(Pie_supra-rand_supra_ie<0)
Pie_supra[x1,y1] = 0

x = list(itertools.product(range(inter),repeat=2))
d = scipy.spatial.distance.pdist(x,'sqeuclidean')
y = scipy.spatial.distance.squareform(d)
Pii_granular = 0.5*np.exp(-(y/2)**2)
Pii_supra = 0.5*np.exp(-(y/2)**2)
rand_granular_ii = np.random.rand(n_inter,n_inter)
rand_supra_ii = np.random.rand(n_inter,n_inter)
x1,y1 = np.where(Pii_granular-rand_granular_ii<0)
Pii_granular[x1,y1]=0
np.fill_diagonal(Pii_granular,0)
x1,y1 = np.where(Pii_supra-rand_supra_ii<0)
Pii_supra[x1,y1]=0
np.fill_diagonal(Pii_supra,0)

x = list((0,i) for i in range(exc))
y = list((1,i) for i in range(exc))
d = scipy.spatial.distance_matrix(x,y)
Pee_vertical = 0.8*np.exp(-(d/2)**2)
rand_vertical_ee = np.random.rand(exc,exc)
x1,y1 = np.where(Pee_vertical-rand_vertical_ee<0)
Pee_vertical[x1,y1]=0
y = y[::2]
d = scipy.spatial.distance_matrix(x,y)
Pie_vertical = 0.5*np.exp(-(d/2)**2)
rand_vertical_ie = np.random.rand(exc,inter)
x1,y1 = np.where(Pie_vertical-rand_vertical_ie<0)
Pie_vertical[x1,y1]=0

sess = tf.InteractiveSession()

class SynapticDelay(tf.contrib.rnn.RNNCell):

    def __init__(self,num_units):
        self._state_size = num_units

    def __call__(self, inputs, state, scope=None):
        output = state[:,-1]
        newstate = tf.concat([inputs,state[:,0:-1]],1)
        return output,newstate

class NewCell(tf.contrib.rnn.RNNCell):

    def __init__(self, num_state):
        self._state_size = num_state

    def __call__(self, inputs, state, scope=None):
        Iext = inputs
        V, G, F, W, B = tf.split(state, [1, 1, 1, 1, 1],1)
        dt = 0.01
        g_Na = 120
        g_K = 15
        g_L = 0.3
        g_A = 9
        V_Na = 55
        V_K = -72
        V_L = -53
        V_syn = 55
        taus = 2
        synth = 10

        def Steady_Variable(a, V, V_half):
            P = 1 / (1 + tf.exp(-2 * a * (V - V_half)))
            return P

        def TimeConstantW(Lam, V, V_half):
            tao = 1 / (Lam * (tf.exp(0.055 * (V - V_half)) + tf.exp(-0.055 * (V - V_half))))
            return tao

        Im = Steady_Variable(0.065, V, -31)
        IW = Steady_Variable(0.055, V, -35)
        IA = Steady_Variable(0.020, V, -20)
        IB = Steady_Variable(-0.10, V, -70)
        taow = TimeConstantW(0.08, V, -35)

        W_ = W + dt * (IW - W) / taow
        B_ = B + dt * (IB - B) / 10
        F_ = F + dt / taus * (-F + (tf.sign(V - synth) + 1) / 2)
        G_ = G + dt / taus * (-G + F)

        I_Na = g_Na * Im ** 3 * (1 - W) * (V - V_Na)
        I_K = g_K * W ** 4 * (V - V_K)
        I_A = g_A * IA * B * (V - V_K)
        I_L = g_L * (V - V_L)
        SumI = Iext - I_Na - I_K - I_A - I_L
        V_ = V + dt * SumI
        output = G*(V-V_syn)

        nextstate = tf.concat([V_,G_,F_,W_,B_],1)

        return output,nextstate

cell = NewCell(5)
delay = SynapticDelay(100)

granular_supra_ee0 = tf.Variable(tf.zeros(shape=(exc, exc), dtype=tf.float32))
granular_supra_ei0 = tf.Variable(tf.zeros(shape=(inter, inter), dtype=tf.float32))

global1 = tf.Variable(0)
global2 = tf.Variable(0)

# queue  = queue = tf.FIFOQueue(1, shapes=(), shared_name="Que", dtypes=tf.int32)

with tf.device("/job:worker/task:0"):
    granular_pyramidal_input = tf.placeholder(shape=(n_exc,1),dtype=tf.float32)
    granular_pyramidal_state = tf.placeholder(shape=(n_exc,5),dtype=tf.float32)
    granular_pyramidal_delay = tf.placeholder(shape=(n_exc,300),dtype=tf.float32)

    granular_basket_input = tf.placeholder(shape=(n_inter,1),dtype=tf.float32)
    granular_basket_state = tf.placeholder(shape=(n_inter,5),dtype=tf.float32)
    granular_basket_delay = tf.placeholder(shape=(n_inter,1200),dtype=tf.float32)

    (granular_pyramidal_output, granular_pyramidal_nextstate) = cell(granular_pyramidal_input, granular_pyramidal_state)
    (granular_pyramidal_synout, granular_pyramidal_synstate) = delay(granular_pyramidal_output, granular_pyramidal_delay)

    (granular_basket_output, granular_basket_nextstate) = cell(granular_basket_input, granular_basket_state)
    (granular_basket_synout, granular_basket_synstate) = delay(granular_basket_output, granular_basket_delay)

    granular_ee = tf.layers.dense(tf.reshape(granular_pyramidal_synout, (1, n_exc)), n_exc,
                                  kernel_initializer=tf.constant_initializer(Pee_granular))
    granular_ei = tf.layers.dense(tf.reshape(granular_pyramidal_synout, (1, n_exc)), n_inter,
                                  kernel_initializer=tf.constant_initializer(Pie_granular))
    granular_ie = tf.layers.dense(tf.reshape(granular_basket_synout, (1, n_inter)), n_exc,
                                  kernel_initializer=tf.constant_initializer(-np.transpose(Pie_granular)))
    granular_ii = tf.layers.dense(tf.reshape(granular_basket_synout, (1, n_inter)), n_inter,
                                  kernel_initializer=tf.constant_initializer(-Pii_granular))

    granular_supra_ee = tf.layers.dense(tf.reshape(granular_pyramidal_synout, (exc, exc)), exc,
                                        kernel_initializer=tf.constant_initializer(Pee_vertical))
    Layer_ei = tf.reshape(granular_pyramidal_synout, (exc, exc))
    granular_supra_ei = tf.layers.dense(tf.transpose(Layer_ei[:, ::2]), inter,
                                        kernel_initializer=tf.constant_initializer(np.transpose(Pie_vertical)))

    granular_pyramidal = tf.add(granular_ee, granular_ie)
    granular_basket = tf.add(granular_ei, granular_ii)

    connect = tf.group(granular_supra_ee0.assign(granular_supra_ee), granular_supra_ei0.assign(granular_supra_ei))

with tf.device("/job:worker/task:1"):

    supra_pyramidal_input = tf.placeholder(shape=(n_exc,1),dtype=tf.float32)
    supra_pyramidal_state = tf.placeholder(shape=(n_exc,5),dtype=tf.float32)
    supra_pyramidal_delay = tf.placeholder(shape=(n_exc,300),dtype=tf.float32)

    supra_basket_input = tf.placeholder(shape=(n_inter,1),dtype=tf.float32)
    supra_basket_state = tf.placeholder(shape=(n_inter,5),dtype=tf.float32)
    supra_basket_delay = tf.placeholder(shape=(n_inter,1200),dtype=tf.float32)

    (supra_pyramidal_output,supra_pyramidal_nextstate) = cell(supra_pyramidal_input,supra_pyramidal_state)
    (supra_pyramidal_synout,supra_pyramidal_synstate) = delay(supra_pyramidal_output,supra_pyramidal_delay)

    (supra_basket_output,supra_basket_nextstate) = cell(supra_basket_input,supra_basket_state)
    (supra_basket_synout,supra_basket_synstate) = delay(supra_basket_output,supra_basket_delay)

    supra_ee = tf.layers.dense(tf.reshape(supra_pyramidal_synout,(1,n_exc)),n_exc,kernel_initializer=tf.constant_initializer(Pee_supra))
    supra_ei = tf.layers.dense(tf.reshape(supra_pyramidal_synout,(1,n_exc)),n_inter,kernel_initializer=tf.constant_initializer(Pie_supra))
    supra_ie = tf.layers.dense(tf.reshape(supra_basket_synout,(1,n_inter)),n_exc,
                                  kernel_initializer=tf.constant_initializer(-np.transpose(Pie_supra)))
    supra_ii = tf.layers.dense(tf.reshape(supra_basket_synout,(1,n_inter)),n_inter,kernel_initializer=tf.constant_initializer(-Pii_supra))

    supra_pyramidal = tf.add(tf.add(supra_ee,supra_ie),tf.reshape(granular_supra_ee0,(1,n_exc)))
    supra_basket = tf.add(tf.add(supra_ii,supra_ei),tf.reshape(granular_supra_ei0,(1,n_inter)))

Input_granular_pyramidal = np.zeros((n_exc,1))
y = [int(exc*i+(exc/2-1)) for i in range(exc)]
Input_granular_pyramidal[y] = 8
Input_granular_basket = np.zeros((n_inter,1))
y = [int(inter*i+(inter/2-1)) for i in range(inter)]
Input_granular_basket[y] = 8
Input_supra_pyramidal = np.zeros((n_exc,1))
Input_supra_basket = np.zeros((n_inter,1))

V_init = -60
G_init = 0
F_init = 0
W_init = 1 / (1 + np.exp(-2 * 0.055 * (V_init + 35)))
B_init = 1 / (1 + np.exp(2 * 0.1 * (V_init + 70)))
cell_init = np.array([V_init,G_init,F_init,W_init,B_init])

state_granular_pyramidal = np.matrix([cell_init for _ in range(n_exc)])
state_granular_basket = np.matrix([cell_init for _ in range(n_inter)])
state_supra_pyramidal = np.matrix([cell_init for _ in range(n_exc)])
state_supra_basket = np.matrix([cell_init for _ in range(n_inter)])

delay_granular_pyramidal = np.zeros((n_exc,300))
delay_granular_basket = np.zeros((n_inter,1200))
delay_supra_pyramidal = np.zeros((n_exc,300))
delay_supra_basket = np.zeros((n_inter,1200))

is_chief = (FLAGS.task_index == 0)

# Define the sessions to be called on different instance
# If there is a parameter server, use server.join() to block the server
if FLAGS.job_name == "ps":
    server.join()
elif FLAGS.job_name == "worker":
    with tf.Session(server.target) as sess:
        if is_chief:
            sess.run(tf.global_variables_initializer())
            print("chief initialized")
        else:
            sess.run(tf.global_variables_initializer())
            while len(sess.run(tf.report_uninitialized_variables())) > 0:
                print("worker:%d waiting for initialization" % FLAGS.task_index)
            print("worker:%d ready"% FLAGS.task_index)

        if FLAGS.task_index == 0:
            Input_granular_pyramidal1 = Input_granular_pyramidal
            Input_granular_basket1 = Input_granular_basket
            P_granular_pyramidal = []
            P_granular_basket = []
            t = time.time()
            for i in range(20000):
                # sess.run(queue.enqueue(i))
                state_granular_pyramidal, delay_granular_pyramidal, state_granular_basket, delay_granular_basket,\
                Input_granular_pyramidal2, Input_granular_basket2,_,g1 = \
                    sess.run([granular_pyramidal_nextstate, granular_pyramidal_synstate, granular_basket_nextstate,
                              granular_basket_synstate,granular_pyramidal, granular_basket, connect,global1.assign_add(1)],
                             feed_dict={granular_pyramidal_input: Input_granular_pyramidal1,
                                        granular_pyramidal_state: state_granular_pyramidal,
                                        granular_pyramidal_delay: delay_granular_pyramidal,
                                        granular_basket_input: Input_granular_basket1,
                                        granular_basket_state: state_granular_basket,
                                        granular_basket_delay: delay_granular_basket})
                Input_granular_pyramidal1 = Input_granular_pyramidal - np.transpose(Input_granular_pyramidal2)
                Input_granular_basket1 = Input_granular_basket - np.transpose(Input_granular_basket2)
                P_granular_pyramidal.append(state_granular_pyramidal[:, 0])
                P_granular_basket.append(state_granular_basket[:, 0])
                while sess.run(global2) != g1:
                    time.sleep(0.0005)
                if i%100 == 0:
                    print('step %d'%i)
            np.savetxt('GP.csv', P_granular_pyramidal)
            np.savetxt('GB.csv', P_granular_basket)
            print(time.time()-t)

        if FLAGS.task_index == 1:
            P_supra_pyramidal = []
            P_supra_basket = []
            t = time.time()
            for i in range(20000):
                state_supra_pyramidal, delay_supra_pyramidal, state_supra_basket, delay_supra_basket,Input_supra_pyramidal2, Input_supra_basket2, g2 = \
                    sess.run([supra_pyramidal_nextstate, supra_pyramidal_synstate, supra_basket_nextstate,
                              supra_basket_synstate, supra_pyramidal, supra_basket, global2.assign_add(1)],
                             feed_dict={supra_pyramidal_input: Input_supra_pyramidal,
                                        supra_pyramidal_state: state_supra_pyramidal,
                                        supra_pyramidal_delay: delay_supra_pyramidal,
                                        supra_basket_input: Input_supra_basket, supra_basket_state: state_supra_basket,
                                        supra_basket_delay: delay_supra_basket})
                Input_supra_pyramidal = -np.transpose(Input_supra_pyramidal2)
                Input_supra_basket = -np.transpose(Input_supra_basket2)
                P_supra_pyramidal.append(state_supra_pyramidal[:, 0])
                P_supra_basket.append(state_supra_basket[:, 0])
                while sess.run(global1) != g2:
                    time.sleep(0.0005)
                # sess.run(queue.dequeue())
                if i % 100 == 0:
                    print('step %d' % i)
            np.savetxt('SP.csv', P_supra_pyramidal)
            np.savetxt('SB.csv', P_supra_basket)
            print(time.time()-t)


import pygame

class Character:
    def __init__(self, ai_game):

        self.screen = ai_game.screen
        self.screen_rect = ai_game.screen.get_rect()
        # Load the ship image and get its rect.
        self.image = pygame.image.load('images/dino.bmp')
        self.rect = self.image.get_rect()
        self.rect.center =self.screen_rect.center
    def blitme(self): #making the image on the top of the display attribute
        self.screen.blit(self.image, self.rect)


from typing import Optional, Tuple
from sqlalchemy.orm import Session

from app.db.models import CommonItem as CommonItemModel
from app.repositories import CommonItem as CommonItemRepository
from app.utils.handler import AbstractHandler

class CommonItem(AbstractHandler):
    async def handle(self, item_id: str, db: Session) -> \
        Tuple[
            Optional[CommonItemRepository],
            Optional[CommonItemModel]
    ]:
        repository = CommonItemRepository(db)

        if item_id.startswith("common_"):
            id_ = item_id.removeprefix("common_")
            if not id_.isdigit():
                return repository, None
            item = await repository.get_by_id(int(id_))
            if not item:
                return repository, None
            return repository, item

        return await super().handle(item_id, db)


"""Implementation of the DDPG algorithm."""

import copy

import gym
import numpy as np
import torch
from torch import nn
from torch import optim

class ReplayBuffer:

    def __init__(self, state_dim, action_dim, max_size=int(1e6)):
        self._state = np.zeros((max_size, state_dim), dtype=np.float32)
        self._action = np.zeros((max_size, action_dim), dtype=np.float32)
        self._reward = np.zeros(max_size, dtype=np.float32)
        self._next_state = np.zeros((max_size, state_dim), dtype=np.float32)
        self._done = np.zeros(max_size, dtype=np.float32)
        self._ptr = 0
        self.size, self.max_size =  0, max_size

    def put(self, state, action, reward, next_state, done):
        self._state[self._ptr] = state
        self._action[self._ptr] = action
        self._reward[self._ptr] = reward
        self._next_state[self._ptr] = next_state
        self._done[self._ptr] = done
        self._ptr = (self._ptr + 1) % self.max_size
        self.size = min(self.size + 1, self.max_size)

    def sample_batch(self, batch_size):
        idxs = np.random.randint(0, self.size, size=batch_size)
        batch = {
                'state': self._state[idxs],
                'action': self._action[idxs],
                'reward': self._reward[idxs],
                'next_state': self._next_state[idxs],
                'done': self._done[idxs]
        }
        return {k: torch.from_numpy(v) for k, v in batch.items()}

class MLP(nn.Module):

    def __init__(self, input_dim, output_dim, output_activation_fn):
        super().__init__()
        self._net = nn.Sequential(
                nn.Linear(input_dim, 400),
                nn.ReLU(),
                nn.Linear(400, 300),
                nn.ReLU(),
                nn.Linear(300, output_dim),
                output_activation_fn())

    def forward(self, state, action=None):
        x = state
        if action is not None:
            x = torch.cat((state, action), dim=1)
        return self._net(x)

def do_not_compute_gradients(parameters):
    for p in parameters:
        p.requires_grad = False

def do_compute_gradients(parameters):
    for p in parameters:
        p.requires_grad = True

def moving_avg(old, new, tau):
    for o, n in zip(old, new):
        o.data.copy_(tau * n.data + (1 - tau) * o.data)

def run_ddpg(
        env,
        gamma=.99,
        action_noise=.1,
        tau=.005,
        batch_size=100,
        episodes=1000,
        max_episode_steps=1000,
        replay_buffer_size=int(1e6)):
    state_dim = env.observation_space.shape[0]
    action_dim = env.action_space.shape[0]

    actor = MLP(state_dim, action_dim, nn.Tanh)
    target_actor = copy.deepcopy(actor)
    do_not_compute_gradients(target_actor.parameters())
    actor_opt = optim.Adam(actor.parameters())

    critic = MLP(state_dim + action_dim, 1, nn.Identity)
    target_critic = copy.deepcopy(critic)
    do_not_compute_gradients(target_critic.parameters())
    critic_loss_fn = nn.MSELoss()
    critic_opt = optim.Adam(critic.parameters())

    replay_buffer = ReplayBuffer(state_dim, action_dim, replay_buffer_size)

    def get_action(state, action_noise):
        # Do not compute gradients when acting in the environment since we are
        # not training in this case.
        with torch.no_grad():
            state = torch.from_numpy(state.astype(np.float32)).unsqueeze(0)
            action = actor(state).numpy().reshape(action_dim,)
            action += np.random.normal(0., action_noise, size=(action_dim,))
            action *= env.action_space.high
            action = np.clip(action, env.action_space.low, env.action_space.high)
            return action

    def test():
        state, episode_steps, done, eps_reward = env.reset(), 0, False, 0
        while not done:
            env.render()
            state, reward, done, _ = env.step(get_action(state, 0.))
            eps_reward += reward
            episode_steps += 1
            done = True if episode_steps >= max_episode_steps else done
        return eps_reward

    for episode in range(episodes):
        state, episode_steps, done, eps_reward = env.reset(), 0, False, 0.
        while not done:
            # Act in the environment and store transition in the replay buffer.
            action = get_action(state, action_noise)
            next_state, reward, done, _ = env.step(action)
            replay_buffer.put(state, action, reward, next_state, done)
            state = next_state

            eps_reward += reward
            episode_steps += 1
            # End the episode if we've reached the max number of steps. N.B.
            # that we should only update 'done' once we've already stored it in
            # the replay buffer.
            done = True if episode_steps >= max_episode_steps else done

            # Do not update the policy until we have taken at least batch_size
            # steps.
            if replay_buffer.size < batch_size * 2:
                continue

            # Update the actor and critic networks using an off-policy batch.
            batch = replay_buffer.sample_batch(batch_size)

            # Update cirtic.
            target_actions = target_actor(batch['next_state'])
            target_q = target_critic(batch['next_state'], target_actions).squeeze()
            targets = batch['reward'] + gamma * (1 - batch['done']) * target_q

            critic_opt.zero_grad()
            critic_predictions = critic(batch['state'], batch['action']).squeeze()
            critic_loss = critic_loss_fn(critic_predictions, targets)
            critic_loss.backward()
            critic_opt.step()

            # Update actor.
            # Freeze Q netowrk. We want to only update the parameters of the
            # actor network while keeping the critic network parameters fixed.
            do_not_compute_gradients(critic.parameters())
            actor_opt.zero_grad()
            actor_loss = -1 * critic(batch['state'], actor(batch['state'])).mean()
            actor_loss.backward()
            actor_opt.step()
            do_compute_gradients(critic.parameters())

            # Update target networks.
            with torch.no_grad():
                moving_avg(target_actor.parameters(), actor.parameters(), tau)
                moving_avg(target_critic.parameters(), critic.parameters(), tau)

        test_reward = test()
        print(f'[{episode}]: train_reward={eps_reward} '
              f'test_reward={test_reward}  eps_steps={episode_steps}')

if __name__ == '__main__':
    env = gym.make('Pendulum-v0')
    run_ddpg(env)


import os
import numpy as np
import torch
import torchvision
import argparse

# distributed training
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.nn.parallel import DataParallel
from torch.nn.parallel import DistributedDataParallel as DDP

# TensorBoard
from torch.utils.tensorboard import SummaryWriter

# SimCLR
from simclr import SimCLR
from simclr.modules.transformations import TransformsSimCLR
from simclr.modules.sync_batchnorm import convert_model

from model import save_model, load_model
from utils import yaml_config_hook
from dataset2 import dataset_DFD
from simclr.modules import SingleViT as VViT
import tqdm
from sklearn.metrics import recall_score, precision_score, f1_score
from datetime import datetime
from sklearn import metrics
from setLogger import *
import pandas as pd
def decisionMaker(args, pred):

    if 'avg' in args.testMode:
        if isinstance(pred, list):
            pred = torch.vstack(pred)
            pred =torch.mean(pred, 0)
        else:
            pred = pred[0]
        pred =torch.argmax(pred).cpu().numpy()
    elif 'top' in args.testMode:
        k = int(args.testMode.split('-')[-1])
        pred = torch.vstack(pred)
        ratio = pred[:,1]-pred[:,0]
        ratio_amp = torch.sort(torch.abs(ratio), descending=True)
        ind = ratio_amp.indices
        ratio = torch.mean(ratio[ind[:k]])
        pred = 1 if ratio>=0 else 0

    return pred

def main(args):

    torch.manual_seed(args.seed)
    np.random.seed(args.seed)
    test_dataset = dataset_DFD(0,args, mode = 'test')

    test_loader = torch.utils.data.DataLoader(
        test_dataset,
        batch_size=args.batch_size if args.test_aug!=1 else 1,
        shuffle=False,
        drop_last=False,
        num_workers=args.workers if args.test_aug!=1 else 0,
    )

    model = VViT(0, args, mode='test')

    model = model.to('cuda')
    model.load_state_dict(torch.load(args.model_path))

    model.eval()

    from tqdm import trange
    if os.path.isdir(args.output_path)==False:
        os.mkdir(args.output_path)

    fp1, fp2 = open(os.path.join(args.output_path, f'{args.model_path}-covid.csv'), 'w'), open(os.path.join(args.output_path, f'{args.model_path}-non-covid.csv'), 'w')

    with torch.no_grad():
        preds, labs = [], []
        accs, f1,re,pr =[], [],[],[]

        outfile = []

        for data in tqdm.tqdm(test_loader):
            if args.test_aug==1:

                if args.evalPerformance:
                    (x,y)=data
                else:
                    x = data

                if isinstance(x, list):
                    pred = []

                    for x_it in x:
                        pred_inner=model(x_it, forward_mode='test')
                        pred.extend(pred_inner)
                        filename = x_it['fn']

                    pred = decisionMaker(args, pred)
                    preds.append(pred)
                else:
                    filename = x['fn']
                    pred=model(x, forward_mode='test')
                    pred = decisionMaker(args, pred)
                    preds.append(pred)

                if args.evalPerformance:
                    labs.extend(y.cpu().numpy())

            else:

                if args.evalPerformance:
                    (x,y, issafe)=data
                else:
                    (x, issafe) = data

                if issafe:
                    pred = model(x, forward_mode='test')
                    filename = x['fn']
                    if args.evalPerformance:
                        labs.extend(y.cpu().numpy())

                    preds.append(torch.argmax(pred,1).cpu().numpy()[0])
                else:
                    filename = x['fn']
                    pred = model(x, forward_mode='test')
                    if args.evalPerformance:
                        labs.extend(y.cpu().numpy())

                    preds.append(torch.argmax(pred,1).cpu().numpy()[0])
                    LOG.info(f'Found a insufficient CT scan in {x["fn"][0]}')

            if preds[-1]==1:
                fp1.write('%s,' % os.path.basename(filename[0]))
            else:
                fp2.write('%s,' % os.path.basename(filename[0]))

            outfile.append([os.path.basename(filename[0]), preds[-1]])

        outfile = pd.DataFrame(outfile)
        postfix = 'val' if args.evalPerformance else 'test'
        outfile.to_csv(f"{args.output_path}/{args.model_path}_{postfix}.csv", index=False)
        if args.evalPerformance:

            preds, labs = np.asarray(preds), np.asarray(labs)
            acc = np.mean(preds==labs)
            re = recall_score(labs, preds, average='macro')
            pr = precision_score(labs, preds, average='macro')
            f1 = f1_score(labs, preds, average='macro')
            fpr, tpr, thresholds = metrics.roc_curve(labs, preds, pos_label=1)
            auc = metrics.auc(fpr, tpr)

            now = datetime.now()
            date_time = now.strftime("%m/%d/%Y, %H:%M:%S")
            LOG.info('='*80)
            LOG.info("Test time:"+date_time)
            LOG.info('='*80)
            LOG.info(f'model={args.model_path}, image size={args.image_size}, crop_size={args.crop_size}, max #crops={args.max_det}, test mode={args.testMode}')
            LOG.info(f'(Marco) Validation Accuracy={acc}, Precision={pr}, Recall={re}, F1-Score={f1}, AUC={auc}')
            LOG.info('='*80)

        else:
            fp1.close()
            fp2.close()
            LOG.info(f'The number of COVID-19 is {np.sum(np.array(preds)==1)} while the number of normal case is {np.sum(np.array(preds)==0)}')

if __name__ == "__main__":

    parser = argparse.ArgumentParser(description="SimCLR")
    config = yaml_config_hook("./config/config_single_test.yaml")
    for k, v in config.items():
        parser.add_argument(f"--{k}", default=v, type=type(v))
    parser.add_argument('--eval', type=bool, default=True)
    args = parser.parse_args()

    global LOG
    LOG = init_logging(log_file="%s/%s_test_eval.log" % (args.output_path, args.model_path))
    LOG.info(args)
    print( args.model_path)

    main(args)