"""
Tests for plotting operations
"""

import itertools
import os
import shutil
import sys
import tempfile
import unittest
from contextlib import contextmanager
from unittest import TestCase

import numpy as np
import pandas as pd
import xarray as xr

from cate.core.op import OP_REGISTRY
from cate.ops.plot import plot, plot_map, plot_data_frame, plot_hovmoeller
from cate.util.misc import object_to_qualified_name

_counter = itertools.count()
ON_WIN = sys.platform == 'win32'

@contextmanager
def create_tmp_file(name, ext):
    tmp_dir = tempfile.mkdtemp()
    path = os.path.join(tmp_dir, '{}{}.{}'.format(name,
                                                  next(_counter),
                                                  ext))
    try:
        yield path
    finally:
        try:
            shutil.rmtree(tmp_dir)
        except OSError:
            if not ON_WIN:
                raise

@unittest.skipIf(condition=os.environ.get('CATE_DISABLE_PLOT_TESTS', None),
                 reason="skipped if CATE_DISABLE_PLOT_TESTS=1")
class TestPlotMap(TestCase):
    """
    Test plot_map() function
    """

    def test_plot_map(self):
        # Test the nominal functionality. This doesn't check that the plot is what is expected,
        # rather, it simply tests if it seems to have been created
        dataset = xr.Dataset({
            'first': (['lat', 'lon', 'time'], np.random.rand(5, 10, 2)),
            'second': (['lat', 'lon', 'time'], np.random.rand(5, 10, 2)),
            'lat': np.linspace(-89.5, 89.5, 5),
            'lon': np.linspace(-179.5, 179.5, 10),
            'time': pd.date_range('2000-01-01', periods=2)})

        with create_tmp_file('remove_me', 'png') as tmp_file:
            plot_map(dataset, file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

        # Test if an error is raised when an unsupported format is passed
        with create_tmp_file('remove_me', 'pgm') as tmp_file:
            with self.assertRaises(ValueError):
                plot_map(dataset, file=tmp_file)
            self.assertFalse(os.path.isfile(tmp_file))

        # Test if extents can be used
        with create_tmp_file('remove_me', 'pdf') as tmp_file:
            plot_map(dataset,
                     var='second',
                     region='-40.0, -20.0, 50.0, 60.0',
                     file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

        # Test time slice selection
        with create_tmp_file('remove_me', 'png') as tmp_file:
            plot_map(dataset, time='2000-01-01', file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

    def test_plot_map_exceptions(self):
        # Test if the corner cases are detected without creating a plot for it.

        # Test value error is raised when passing an unexpected dataset type
        with create_tmp_file('remove_me', 'jpeg') as tmp_file:
            with self.assertRaises(ValueError) as cm:
                plot_map([1, 2, 4], file=tmp_file)
            self.assertEqual(str(cm.exception),
                             "Input 'ds' for operation 'cate.ops.plot.plot_map' "
                             "must be of type 'Dataset', but got type 'list'.")
            self.assertFalse(os.path.isfile(tmp_file))

        # Test the extensions bound checking
        dataset = xr.Dataset({
            'first': (['lat', 'lon', 'time'], np.random.rand(2, 4, 1)),
            'lat': np.linspace(-89.5, 89.5, 2),
            'lon': np.linspace(-179.5, 179.5, 4)})

        with self.assertRaises(ValueError):
            region = '-40.0, -95.0, 50.0, 60.0',
            plot_map(dataset, region=region)

        with self.assertRaises(ValueError):
            region = '-40.0, -20.0, 50.0, 95.0',
            plot_map(dataset, region=region)

        with self.assertRaises(ValueError):
            region = '-181.0, -20.0, 50.0, 60.0',
            plot_map(dataset, region=region)

        with self.assertRaises(ValueError):
            region = '-40.0, -20.0, 181.0, 60.0',
            plot_map(dataset, region=region)

        with self.assertRaises(ValueError):
            region = '-40.0, -20.0, 50.0, -25.0',
            plot_map(dataset, region=region)

        with self.assertRaises(ValueError):
            region = '-20.0, -20.0, -25.0, 60.0',
            plot_map(dataset, region=region)

        # Test temporal slice validation
        with self.assertRaises(ValueError):
            plot_map(dataset, time=0)

    def test_registered(self):
        """
        Test nominal execution of the function as a registered operation.
        """
        reg_op = OP_REGISTRY.get_op(object_to_qualified_name(plot_map))
        dataset = xr.Dataset({
            'first': (['lat', 'lon', 'time'], np.random.rand(5, 10, 2)),
            'second': (['lat', 'lon', 'time'], np.random.rand(5, 10, 2)),
            'lat': np.linspace(-89.5, 89.5, 5),
            'lon': np.linspace(-179.5, 179.5, 10),
            'time': pd.date_range('2000-01-01', periods=2)})

        with create_tmp_file('remove_me', 'png') as tmp_file:
            reg_op(ds=dataset, file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

@unittest.skipIf(condition=os.environ.get('CATE_DISABLE_PLOT_TESTS', None),
                 reason="skipped if CATE_DISABLE_PLOT_TESTS=1")
class TestPlot(TestCase):
    """
    Test plot() function
    """

    def test_plot(self):
        # Test plot
        dataset = xr.Dataset({
            'first': np.random.rand(10)})

        with create_tmp_file('remove_me', 'jpg') as tmp_file:
            plot(dataset, 'first', file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

    def test_registered(self):
        """
        Test nominal execution of the function as a registered operation.
        """
        reg_op = OP_REGISTRY.get_op(object_to_qualified_name(plot))
        # Test plot
        dataset = xr.Dataset({
            'first': np.random.rand(10)})

        with create_tmp_file('remove_me', 'jpg') as tmp_file:
            reg_op(ds=dataset, var='first', file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

@unittest.skipIf(condition=os.environ.get('CATE_DISABLE_PLOT_TESTS', None),
                 reason="skipped if CATE_DISABLE_PLOT_TESTS=1")
class TestPlotDataFrame(TestCase):
    """
    Test plot_data_frame() function.
    """

    def test_nominal(self):
        """
        Test nominal execution
        """
        data = {'A': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                'B': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
        df = pd.DataFrame(data=data, index=pd.date_range('2000-01-01',
                                                         periods=10))

        with create_tmp_file('remove_me', 'png') as tmp_file:
            plot_data_frame(df, file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

    def test_registered(self):
        """
        Test the method when run as a registered operation
        """
        reg_op = OP_REGISTRY.get_op(object_to_qualified_name(plot_data_frame))

        data = {'A': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                'B': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
        df = pd.DataFrame(data=data, index=pd.date_range('2000-01-01',
                                                         periods=10))

        with create_tmp_file('remove_me', 'png') as tmp_file:
            reg_op(df=df, file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

@unittest.skipIf(condition=os.environ.get('CATE_DISABLE_PLOT_TESTS', None),
                 reason="skipped if CATE_DISABLE_PLOT_TESTS=1")
class TestPlotHovmoeller(TestCase):
    """
    Test plot_hovmoeller() function
    """

    def test_nominal(self):
        """
        Test nominal execution
        """
        # Test nominal
        dataset = xr.Dataset({
            'first': (['lat', 'lon', 'time'], np.random.rand(5, 10, 2)),
            'second': (['lat', 'lon', 'time'], np.random.rand(5, 10, 2)),
            'lat': np.linspace(-89.5, 89.5, 5),
            'lon': np.linspace(-179.5, 179.5, 10),
            'time': pd.date_range('2000-01-01', periods=2)})

        with create_tmp_file('remove_me', 'png') as tmp_file:
            plot_hovmoeller(dataset, file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

        # Test colormesh and title
        with create_tmp_file('remove_me', 'png') as tmp_file:
            plot_hovmoeller(dataset, contour=False, title='FooBar', file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

        # More than three dims
        dataset = xr.Dataset({
            'first': (['lat', 'lon', 'time', 'depth'], np.random.rand(5, 10, 2, 2)),
            'second': (['lat', 'lon', 'time'], np.random.rand(5, 10, 2)),
            'lat': np.linspace(-89.5, 89.5, 5),
            'lon': np.linspace(-179.5, 179.5, 10),
            'depth': [1, 2],
            'time': pd.date_range('2000-01-01', periods=2)})

        with create_tmp_file('remove_me', 'png') as tmp_file:
            plot_hovmoeller(dataset, var='first', x_axis='time', y_axis='depth', file=tmp_file)
            self.assertTrue(os.path.isfile(tmp_file))

    def test_exceptions(self):
        """
        Test error conditions
        """
        dataset = xr.Dataset({
            'first': (['lat'], np.random.rand(5)),
            'second': (['lat', 'lon'], np.random.rand(5, 10)),
            'lat': np.linspace(-89.5, 89.5, 5),
            'lon': np.linspace(-179.5, 179.5, 10),
            'time': pd.date_range('2000-01-01', periods=2)})

        # test 1D dataset
        with self.assertRaises(ValueError):
            plot_hovmoeller(dataset, var='first', x_axis='lat', y_axis='lat')

        # test illegal dimensions
        with self.assertRaises(ValueError):
            plot_hovmoeller(dataset, var='second', x_axis='foo', y_axis='bar')


import pytest
from rhoknp import Morpheme

from kwja.utils.word_normalization import (
    MorphemeDenormalizer,
    MorphemeNormalizer,
    get_normalized,
    get_word_norm_op_tags,
)

wellformed_list = [
    ("なぁ", ["K", "S"], "なあ"),
    ("なー", ["K", "D"], "な"),
    ("な〜", ["K", "D"], "な"),
    ("おっ", ["K", "D"], "お"),
    ("さぁ", ["K", "S"], "さあ"),
    ("だぁ", ["K", "D"], "だ"),
    ("ねぇ", ["K", "S"], "ねえ"),
    ("うむっ", ["K", "K", "D"], "うむ"),
    ("のッ", ["K", "D"], "の"),
    ("バイキングっ", ["K", "K", "K", "K", "K", "D"], "バイキング"),
    ("楽しむっ", ["K", "K", "K", "D"], "楽しむ"),
    ("あっっっっっ", ["K", "K", "D", "D", "D", "D"], "あっ"),
    ("ますぅ", ["K", "K", "D"], "ます"),
    ("かい〜", ["K", "K", "D"], "かい"),
    ("そう〜", ["K", "K", "D"], "そう"),
    ("おーい", ["K", "D", "K"], "おい"),
    ("あーーー", ["K", "K", "D", "D"], "あー"),
    ("自然ー", ["K", "K", "D"], "自然"),
    ("きたー", ["K", "K", "D"], "きた"),
    ("ましたー", ["K", "K", "K", "D"], "ました"),
    ("ました〜", ["K", "K", "K", "D"], "ました"),
    ("飲んだー", ["K", "K", "K", "D"], "飲んだ"),
    ("続くー", ["K", "K", "D"], "続く"),
    ("寒〜い", ["K", "D", "K"], "寒い"),
    ("いや〜", ["K", "K", "D"], "いや"),
    ("あっちこち", ["K", "D", "K", "K", "K"], "あちこち"),
    ("かるーい", ["K", "K", "D", "K"], "かるい"),
    ("ずーっと", ["K", "P", "K", "K"], "ずうっと"),
    ("よー", ["K", "P"], "よう"),
    ("もーれつ", ["K", "P", "K", "K"], "もうれつ"),
    ("咲いたー", ["K", "K", "K", "D"], "咲いた"),
    ("なぁ〜", ["K", "S", "D"], "なあ"),
    ("ふわーっと", ["K", "K", "D", "K", "K"], "ふわっと"),
    ("ずら〜っと", ["K", "K", "D", "K", "K"], "ずらっと"),
    ("でーす", ["K", "D", "K"], "です"),
    ("で〜す", ["K", "D", "K"], "です"),
    ("まーす", ["K", "D", "K"], "ます"),
    ("ま〜す", ["K", "D", "K"], "ます"),
    ("いや〜", ["K", "K", "D"], "いや"),
    ("やったぁー", ["K", "K", "K", "D", "D"], "やった"),
    ("安っぽぃ", ["K", "K", "K", "S"], "安っぽい"),
    ("安っぽぃー", ["K", "K", "K", "S", "D"], "安っぽい"),
    ("だー", ["K", "D"], "だ"),
    ("ね〜", ["K", "E"], "ねえ"),
    ("すっげー", ["K", "D", "K", "E"], "すげえ"),
    ("まぁまぁだ", ["K", "S", "K", "S", "K"], "まあまあだ"),
    ("びみょーーー", ["K", "K", "K", "P", "D", "D"], "びみょう"),
    ("ごめんなさーぃ", ["K", "K", "K", "K", "K", "D", "S"], "ごめんなさい"),
    ("あっまい", ["K", "D", "K", "K"], "あまい"),
    ("もどかしー", ["K", "K", "K", "K", "P"], "もどかしい"),
    ("かわぃぃー", ["K", "K", "S", "S", "D"], "かわいい"),
    ("ほどよぃー", ["K", "K", "K", "S", "D"], "ほどよい"),
    ("あぉーい", ["K", "S", "D", "K"], "あおい"),
    ("鎌ヶ谷", ["K", "S", "K"], "鎌ケ谷"),
    ("龍ヶ崎", ["K", "S", "K"], "龍ケ崎"),
    ("八ヶ岳", ["K", "S", "K"], "八ケ岳"),
    ("湯ヶ島", ["K", "S", "K"], "湯ケ島"),
    ("がえる", ["V", "K", "K"], "かえる"),
    ("がえるー", ["V", "K", "K", "D"], "かえる"),
]

@pytest.mark.parametrize("surf,ops,expected", wellformed_list)
def test_gen_normalized_surf(surf, ops, expected):
    assert get_normalized(surf, ops, strict=True) == expected

@pytest.mark.parametrize("surf,expected,normalized", wellformed_list)
def test_get_normalization_opns(surf, expected, normalized):
    word_norm_op_tags = get_word_norm_op_tags(surf, normalized)
    assert len(word_norm_op_tags) == len(expected)
    assert all([a == b for a, b in zip(word_norm_op_tags, expected)])

malformed_list = [
    ("なあ", ["K", "S"], "なあ"),
    ("なー", ["K", "S"], "なー"),
    ("ー", ["P"], "ー"),
]

@pytest.mark.parametrize("surf,ops,expected", malformed_list)
def test_gen_normalized_surf_malformed(surf, ops, expected):
    with pytest.raises(ValueError):
        get_normalized(surf, ops, strict=True)

@pytest.mark.parametrize("surf,ops,expected", malformed_list)
def test_gen_normalized_surf_malformed_loose(surf, ops, expected):
    assert get_normalized(surf, ops, strict=False) == expected

def test_morpheme_normalizer():
    jumanpp_text = 'きたー きた きる 動詞 2 * 0 母音動詞 1 タ形 10 "代表表記:着る/きる ドメイン:家庭・暮らし 反義:動詞:脱ぐ/ぬぐ 非標準表記:DPL"'
    expected = ["K", "K", "D"]
    morpheme = Morpheme.from_jumanpp(jumanpp_text)
    normalizer = MorphemeNormalizer()
    word_norm_op_tags = normalizer.get_word_norm_op_tags(morpheme)
    assert len(word_norm_op_tags) == len(expected)
    assert all([a == b for a, b in zip(word_norm_op_tags, expected)])

@pytest.mark.parametrize(
    "surf,expected",
    [
        ("なあ", "なぁ"),
        ("さあ", "さぁ"),
        ("もうれつ", "もーれつ"),
        ("鎌ケ谷", "鎌ヶ谷"),
        ("八ケ岳", "八ヶ岳"),
    ],
)
def test_denormalize_deterministic(surf, expected):
    md = MorphemeDenormalizer()
    assert md._denormalize_deterministic(surf) == expected


from chip8_machine import Chip8Machine
import pytest
import numpy

TEST_SIZE = 50

machine = Chip8Machine()

@pytest.fixture
def sprite1():
	return numpy.array([0xAA, 0x55])

@pytest.fixture
def valid_memory_addresses():
	return numpy.random.randint(0x0, 0x1000, size=TEST_SIZE)

def test_screen(sprite1):
	x = 7
	y = 5

	white = 0xFFFFFF

	manual_array = numpy.zeros(shape=(machine.get_screen_width(), machine.get_screen_height()), dtype=int)

	manual_array[7,5] = white
	manual_array[8,5] = 0
	manual_array[9,5] = white
	manual_array[10,5] = 0
	manual_array[11,5] = white
	manual_array[12,5] = 0
	manual_array[13,5] = white
	manual_array[14,5] = 0

	manual_array[7,6] = 0
	manual_array[8,6] = white
	manual_array[9,6] = 0
	manual_array[10,6] = white
	manual_array[11,6] = 0
	manual_array[12,6] = white
	manual_array[13,6] = 0
	manual_array[14,6] = white

	machine.draw_sprite(sprite1, x, y)

	assert numpy.array_equal(machine.get_screen_state(), manual_array)

	machine.clear_screen()
	assert numpy.array_equal(machine.get_screen_state(), numpy.zeros(shape=(machine.get_screen_width(), machine.get_screen_height()), dtype=int))

def test_read_write_registers():
	for i in range(16):
		number = numpy.random.randint(0,0x100)
		machine.write_register(i, number)
		assert machine.read_register(i) == number

def test_read_write_memory_register():
	number = numpy.random.randint(0, 0xFFF)
	machine.write_memory_register(number)
	assert machine.read_memory_register() == number

def test_overflow_underflow_registers():
	for i in range(16):
		machine.write_register(i, 0xAAA)
		assert machine.read_register(i) == 0xAA

		machine.write_register(i, -0x1)
		assert machine.read_register(i) == 0xFF

		machine.write_memory_register(0x11111)
		assert machine.read_memory_register() == 0x1111

		machine.write_memory_register(-0x1)
		assert machine.read_memory_register() == 0xFFFF

def test_read_write_memory():
	address = numpy.random.randint(0, 0x1001)
	number = numpy.random.randint(0,0x100)
	machine.write_memory(address, number)
	assert machine.read_memory(address) == number

def test_stack(valid_memory_addresses):
	for address in valid_memory_addresses:
		machine.push_stack(address)

	for i in range(TEST_SIZE):
		assert machine.pop_stack() == valid_memory_addresses[-i-1]

def test_timers():
	machine.set_timer(0xAA)
	machine.timer_tick()
	assert machine.get_remaining_time() == 0xA9

	machine.set_sound_timer(0x1)
	machine.sound_timer_tick()
	assert machine.get_remaining_sound_time() == 0x0


from django.shortcuts import render
from comentarios.models import Comentarios
from django.views.generic import ListView, CreateView, UpdateView, DeleteView
from django.views import generic

from comentarios.forms import ComentariosCreateForm
from django.urls import reverse_lazy

from django.contrib.auth.mixins import LoginRequiredMixin

# Create your views here.

class ComentariosListView(ListView):
    model = Comentarios
    context_object_name = 'comentarios'
    template_name = 'comentarios/showComentarios.html'
    ordering = ['created_at',]

class ComentariosCreateView(LoginRequiredMixin, CreateView):
    model = Comentarios
    template_name = 'comentarios/createComentarios.html'
    form_class = ComentariosCreateForm
    success_url =  reverse_lazy('comentarios:showComentarios') #used for user pages redirection from CreatePosts to showPosts.

class ComentariosUpdateView(LoginRequiredMixin, UpdateView):
    model = Comentarios
    fields = {'comentario','post'}
    template_name = 'comentarios/update_comentarios.html'
    success_url = reverse_lazy('comentarios:showComentarios')

class ComentariosDeleteView(LoginRequiredMixin, DeleteView):
    model = Comentarios
    context_object_name = 'comentarios'
    template_name = 'comentarios/delete_comentarios.html'
    success_url = reverse_lazy('comentarios:showComentarios')


from __future__ import print_function

import numpy as np
import cv2

IMAGE_SIZE = 224
RED_MEAN = 123.68
GREEN_MEAN = 116.779
BLUE_MEAN = 103.939
def load_image(image_path):
    image = cv2.imread(image_path)
    shorter_dimension = np.min(image.shape[:2])
    width_offet = (image.shape[0] - shorter_dimension)/2
    height_offet = (image.shape[1] - shorter_dimension)/2
    image = image[width_offet:width_offet+shorter_dimension, height_offet:height_offet+shorter_dimension]
    image = cv2.resize(image, (IMAGE_SIZE, IMAGE_SIZE))
    image = image.astype(np.float)
    #opencv read image as BGR format
    image[:, :, 0] = image[:, :, 0] - BLUE_MEAN
    image[:, :, 1] = image[:, :, 1] - GREEN_MEAN
    image[:, :, 2] = image[:, :, 2] - RED_MEAN
    return image

def print_top_5(probability, label_file_path):
    with open(label_file_path, 'r') as label_file:
        labels = [ line.strip() for line in label_file.readlines()]

    for i in xrange(len(probability)):
        row_output = probability[i,:]
        sort_index = np.argsort(row_output)[::-1]
        for i in xrange(5):
            index = sort_index[i]
            print ('top %d: %s (%0.2f)' % (i+1, labels[index], row_output[index]))


# pylint: disable=too-many-lines

import copy
import logging
import os
import pickle
import shutil
import time
import uuid
from functools import partial
from pathlib import Path
from typing import (
    Callable,
    Dict,
    FrozenSet,
    Iterable,
    List,
    Optional,
    Type,
    TYPE_CHECKING,
)
from zipfile import ZipFile

from golem_messages import message
from pydispatch import dispatcher
from twisted.internet.defer import Deferred
from twisted.internet.threads import deferToThread

from apps.appsmanager import AppsManager
from apps.core.task.coretask import CoreTask
from apps.wasm.environment import WasmTaskEnvironment

from golem import model
from golem.clientconfigdescriptor import ClientConfigDescriptor
from golem.core.common import get_timestamp_utc, HandleForwardedError, \
    HandleKeyError, short_node_id, to_unicode, update_dict
from golem.marketplace import (
    ProviderBrassMarketStrategy,
    ProviderWasmMarketStrategy,
    ProviderMarketStrategy)
from golem.manager.nodestatesnapshot import LocalTaskStateSnapshot
from golem.network import nodeskeeper
from golem.ranking.manager.database_manager import update_provider_efficiency, \
    update_provider_efficacy
from golem.resource.dirmanager import DirManager
from golem.resource.hyperdrive.resourcesmanager import \
    HyperdriveResourceManager
from golem.rpc import utils as rpc_utils
from golem.task.result.resultmanager import EncryptedResultPackageManager
from golem.task.taskbase import TaskEventListener, Task, \
    TaskPurpose, AcceptClientVerdict, TaskResult
from golem.task.helpers import calculate_subtask_payment
from golem.task.taskkeeper import CompTaskKeeper
from golem.task.taskrequestorstats import RequestorTaskStatsManager
from golem.task.taskstate import TaskState, TaskStatus, SubtaskStatus, \
    SubtaskState, Operation, TaskOp, SubtaskOp, OtherOp
from golem.task.timer import ProviderComputeTimers

if TYPE_CHECKING:
    # pylint:disable=unused-import, ungrouped-imports
    from typing import Tuple
    from apps.appsmanager import App
    from apps.core.task.coretaskstate import TaskDefinition
    from golem.task.taskbase import TaskTypeInfo, TaskBuilder

logger = logging.getLogger(__name__)

def log_subtask_key_error(*args, **kwargs):
    logger.warning("This is not my subtask %r", args[1])
    logger.debug('Subtask not found', exc_info=True)
    return None

def log_generic_key_error(err):
    logger.warning("Subtask key error: %r", err)
    return None

def log_task_key_error(*args, **kwargs):
    logger.warning("This is not my task %r", args[1])
    logger.debug('Task not found', exc_info=True)
    return None

class TaskManager(TaskEventListener):
    """ Keeps and manages information about requested tasks
    Requestor uses TaskManager to assign task to providers
    """
    # pylint: disable=too-many-public-methods

    handle_task_key_error = HandleKeyError(log_task_key_error)
    handle_subtask_key_error = HandleKeyError(log_subtask_key_error)
    handle_generic_key_error = HandleForwardedError(KeyError,
                                                    log_generic_key_error)

    class Error(Exception):
        pass

    class AlreadyRestartedError(Error):
        pass

    def __init__(  # pylint: disable=too-many-arguments
            self,
            node,
            keys_auth,
            root_path,
            config_desc: ClientConfigDescriptor,
            tasks_dir="tasks",
            apps_manager=AppsManager(),
            finished_cb=None,
    ) -> None:
        # pylint: disable=too-many-instance-attributes
        super().__init__()

        self.apps_manager: AppsManager = apps_manager
        apps: 'List[App]' = list(apps_manager.apps.values())
        # Ignore type, because these are deriving from TaskTypeInfo and take
        # no arguments in constructors.
        task_types: 'List[TaskTypeInfo]' = \
            [app.task_type_info() for app in apps]  # type: ignore
        self.task_types: 'Dict[str, TaskTypeInfo]' = \
            {t.id: t for t in task_types}

        self.node = node
        self.keys_auth = keys_auth

        self.tasks: Dict[str, Task] = {}
        self.tasks_states: Dict[str, TaskState] = {}
        self.subtask2task_mapping: Dict[str, str] = {}

        tasks_dir = Path(tasks_dir)
        self.tasks_dir = tasks_dir / "tmanager"
        if not self.tasks_dir.is_dir():
            self.tasks_dir.mkdir(parents=True)
        self.root_path = root_path
        self.dir_manager = DirManager(self.get_task_manager_root())

        resource_manager = HyperdriveResourceManager(
            self.dir_manager,
            resource_dir_method=self.dir_manager.get_task_temporary_dir,
            client_kwargs={
                'host': config_desc.hyperdrive_rpc_address,
                'port': config_desc.hyperdrive_rpc_port,
            },
        )
        self.task_result_manager = EncryptedResultPackageManager(
            resource_manager
        )

        self.comp_task_keeper = CompTaskKeeper(
            tasks_dir,
        )

        self.requestor_stats_manager = RequestorTaskStatsManager()
        self.provider_stats_manager = \
            self.comp_task_keeper.provider_stats_manager

        self.finished_cb = finished_cb

        self.restore_tasks()

    def get_task_manager_root(self):
        return self.root_path

    def create_task_definition(self, dictionary, test=False) \
            -> 'Tuple[TaskDefinition, Type[TaskBuilder]]':
        purpose = TaskPurpose.TESTING if test else TaskPurpose.REQUESTING
        is_requesting = purpose == TaskPurpose.REQUESTING

        type_name = dictionary['type'].lower()
        compute_on = dictionary.get('compute_on', 'cpu').lower()

        if type_name == "blender" and is_requesting and compute_on == "gpu":
            type_name = type_name + "_nvgpu"

        task_type: 'TaskTypeInfo' = \
            self.task_types[type_name].for_purpose(purpose)
        builder_type: 'Type[TaskBuilder]' = task_type.task_builder_type

        definition: 'TaskDefinition' = \
            builder_type.build_definition(task_type, dictionary, test)
        definition.concent_enabled = dictionary.get('concent_enabled', False)
        definition.task_id = CoreTask.create_task_id(self.keys_auth.public_key)
        return definition, builder_type

    def create_task(self, dictionary, test=False):
        definition, builder_type = \
            self.create_task_definition(dictionary, test)
        task = builder_type(self.node, definition, self.dir_manager).build()
        task_id = definition.task_id

        if not test:
            logger.info("Creating task. type=%r, id=%s", type(task), task_id)
            self.tasks[task_id] = task
            self.tasks_states[task_id] = TaskState(task)

        return task

    def initialize_task(self, task: Task):
        task.initialize(self.dir_manager)

    def get_task_definition_dict(self, task: Task):
        if isinstance(task, dict):
            return task
        definition = task.task_definition
        task_type = self.task_types[definition.task_type.lower()]
        return task_type.task_builder_type.build_dictionary(definition)

    def add_new_task(self, task: Task, estimated_fee: int = 0) -> None:
        task_id = task.header.task_id
        task_state = self.tasks_states.get(task_id)

        if not task_state:
            task_state = TaskState(task)
            self.tasks[task_id] = task
            self.tasks_states[task_id] = task_state

        if task_state.status is not TaskStatus.creating:
            raise RuntimeError("Task {} has already been added".format(task_id))

        task.header.task_owner = self.node
        self.sign_task_header(task.header)

        task.register_listener(self)

        task_state.status = TaskStatus.notStarted
        task_state.time_started = time.time()
        task_state.estimated_fee = estimated_fee

        logger.info("Task %s added", task_id)

        self._create_task_output_dir(task.task_definition)

        self.notice_task_updated(task_id,
                                 op=TaskOp.CREATED,
                                 persist=False)

    @handle_task_key_error
    def task_creation_failed(self, task_id: str, reason: str) -> None:
        logger.error("Cannot create task. task_id=%s : %s", task_id, reason)

        task_state = self.tasks_states[task_id]
        task_state.status = TaskStatus.errorCreating
        task_state.status_message = reason

    @handle_task_key_error
    def increase_task_mask(self, task_id: str, num_bits: int = 1) -> None:
        """ Increase mask for given task i.e. make it more restrictive """
        task_header = copy.deepcopy(self.tasks[task_id].header)
        try:
            task_header.mask.increase(num_bits)
        except ValueError:
            logger.exception('Wrong number of bits for mask increase')
        else:
            self.sign_task_header(task_header)
            try:
                self.tasks[task_id].header = task_header
            except KeyError:
                pass

    @handle_task_key_error
    def decrease_task_mask(self, task_id: str, num_bits: int = 1) -> None:
        """ Decrease mask for given task i.e. make it less restrictive """
        task_header = copy.deepcopy(self.tasks[task_id].header)
        try:
            task_header.mask.decrease(num_bits)
        except ValueError:
            logger.exception('Wrong number of bits for mask decrease')
        else:
            self.sign_task_header(task_header)
            try:
                self.tasks[task_id].header = task_header
            except KeyError:
                pass

    @handle_task_key_error
    def start_task(self, task_id):
        task_state = self.tasks_states[task_id]

        if not task_state.status.is_preparing():
            raise RuntimeError("Task {} has already been started"
                               .format(task_id))

        task_state.status = TaskStatus.waiting
        self.notice_task_updated(task_id, op=TaskOp.STARTED)
        logger.info("Task started. task_id=%r", task_id)

    def _dump_filepath(self, task_id):
        return self.tasks_dir / ('%s.pickle' % (task_id,))

    def dump_task(self, task_id: str) -> None:
        logger.debug('DUMP TASK %r', task_id)
        filepath = self._dump_filepath(task_id)
        try:
            data = self.tasks[task_id], self.tasks_states[task_id]
            logger.debug('DUMPING TASK %r', filepath)
            with filepath.open('wb') as f:
                pickle.dump(data, f, protocol=2)
            logger.debug('TASK %s DUMPED in %r', task_id, filepath)
        except Exception:  # pylint: disable=broad-except
            logger.exception(
                'DUMP ERROR task_id: %r task: %r state: %r',
                task_id, self.tasks.get(task_id, '<not found>'),
                self.tasks_states.get(task_id, '<not found>'),
            )
            if filepath.exists():
                filepath.unlink()
            raise

    def remove_dump(self, task_id: str):
        filepath = self._dump_filepath(task_id)
        try:
            filepath.unlink()
            logger.debug('TASK DUMP with id %s REMOVED from %r',
                         task_id, filepath)
        except (FileNotFoundError, OSError) as e:
            logger.warning("Couldn't remove dump file: %s - %s", filepath, e)

    def _create_task_output_dir(self, task_def: 'TaskDefinition'):
        """
        Creates the output directory for a task along with any parents,
        if necessary. The path is obtained from `output_file` field in the
        task's definition.
        For example, for an output file with the following path:
        `/some/output/dir/result.png` the created directory will be:
        `/some/output/dir`.
        """
        output_dir = self._get_task_output_dir(task_def)
        if not output_dir:
            return
        output_dir.mkdir(parents=True, exist_ok=True)

    def _try_remove_task_output_dir(self, task_def: 'TaskDefinition'):
        """
        Attempts to remove the output directory from a given task definition.
        This will only succeed if the directory is empty.
        """
        output_dir = self._get_task_output_dir(task_def)
        if not output_dir:
            return

        try:
            output_dir.rmdir()
        except OSError:
            pass

    @staticmethod
    def _get_task_output_dir(task_def: 'TaskDefinition') -> Optional[Path]:
        if not task_def.output_file:
            return None

        return Path(task_def.output_file).resolve().parent

    def restore_tasks(self) -> None:
        logger.debug('SEARCHING FOR TASKS TO RESTORE')
        broken_paths = set()
        for path in self.tasks_dir.iterdir():
            if not path.suffix == '.pickle':
                continue
            logger.debug('RESTORE TASKS %r', path)

            task_id = None
            with path.open('rb') as f:
                try:
                    task: Task
                    state: TaskState
                    task, state = pickle.load(f)
                except Exception:  # pylint: disable=broad-except
                    logger.exception('Problem restoring task from: %s', path)
                    # On Windows, attempting to remove a file that is in use
                    # causes an exception to be raised, therefore
                    # we'll remove broken files later
                    broken_paths.add(path)
                else:
                    task.register_listener(self)

                    task_id = task.header.task_id
                    self.tasks[task_id] = task
                    self.tasks_states[task_id] = state

                    for sub in state.subtask_states.values():
                        self.subtask2task_mapping[sub.subtask_id] = task_id

                    logger.debug('TASK %s RESTORED from %r', task_id, path)

            if task_id is not None:
                self.notice_task_updated(task_id, op=TaskOp.RESTORED,
                                         persist=False)

        for path in broken_paths:
            path.unlink()

    def got_wants_to_compute(self,
                             task_id: str):
        """
        Updates number of offers to compute task.

        For statistical purposes only, real processing of the offer is done
        elsewhere. Silently ignores wrong task ids.

        :param str task_id: id of the task in the offer
        :return: Nothing
        :rtype: None
        """
        if task_id in self.tasks:
            self.notice_task_updated(task_id,
                                     op=TaskOp.WORK_OFFER_RECEIVED,
                                     persist=False)

    def task_being_created(self, task_id: str) -> bool:
        task_status = self.tasks_states[task_id].status
        return task_status.is_creating()

    def task_finished(self, task_id: str) -> bool:
        task_status = self.tasks_states[task_id].status
        return task_status.is_completed()

    def task_needs_computation(self, task_id: str) -> bool:
        if self.task_being_created(task_id) or self.task_finished(task_id):
            task_status = self.tasks_states[task_id].status
            logger.debug(
                'task is not active: %(task_id)s, status: %(task_status)s',
                {
                    'task_id': task_id,
                    'task_status': task_status,
                }
            )
            return False
        task = self.tasks[task_id]
        if not task.needs_computation():
            logger.info(f'no more computation needed: {task_id}')
            return False
        return True

    # noqa pylint: disable=too-many-arguments,too-many-return-statements
    def get_next_subtask(self,
                         node_id: str,
                         task_id: str,
                         estimated_performance: float,
                         price: int,
                         offer_hash: str) \
            -> Optional[message.tasks.ComputeTaskDef]:
        """ Assign next subtask from task <task_id> to node with given
        id <node_id>.
        :return ComputeTaskDef that describe assigned subtask
        or None. It is recommended to call is_my_task and should_wait_for_node
        before this to find the reason why the task is not able to be picked up
        """
        logger.debug(
            'get_next_subtask(%r, %r, %r, %r)',
            node_id, task_id, estimated_performance, price,
        )

        if node_id == self.keys_auth.key_id:
            logger.warning("No subtasks for self")
            return None

        if not self.is_my_task(task_id):
            return None

        if not self.check_next_subtask(task_id, price):
            return None

        if not self.task_needs_computation(task_id):
            return None

        if self.should_wait_for_node(task_id, node_id, offer_hash):
            return None

        task = self.tasks[task_id]

        if task.get_progress() == 1.0:
            logger.error("Task already computed. "
                         "task_id=%r, node_id=%r",
                         task_id, node_id)
            return None

        extra_data = task.query_extra_data(estimated_performance, node_id, "")
        ctd = extra_data.ctd

        def check_compute_task_def():
            if not isinstance(ctd, message.tasks.ComputeTaskDef)\
                    or not ctd['subtask_id']:
                logger.debug('check ctd: ctd not instance or not subtask_id')
                return False
            if task_id != ctd['task_id'] \
                    or ctd['subtask_id'] in self.subtask2task_mapping:
                logger.debug(
                    'check ctd: %r != %r or %r in self.subtask2task_maping',
                    task_id, ctd['task_id'], ctd['subtask_id'],
                )
                return False
            if (ctd['subtask_id'] in self.tasks_states[ctd['task_id']].
                    subtask_states):
                logger.debug('check ctd: subtask_states')
                return False
            return True

        if not check_compute_task_def():
            return None

        self.subtask2task_mapping[ctd['subtask_id']] = task_id
        self.__add_subtask_to_tasks_states(node_id, ctd, price)
        self.notice_task_updated(task_id,
                                 subtask_id=ctd['subtask_id'],
                                 op=SubtaskOp.ASSIGNED)
        logger.debug(
            "Subtask generated. task=%s, node=%s, ctd=%s",
            task_id,
            short_node_id(node_id),
            ctd,
        )

        ProviderComputeTimers.start(ctd['subtask_id'])
        return ctd

    def is_my_task(self, task_id: str) -> bool:
        """ Check if the task ID is known by this node. """
        return task_id in self.tasks

    def is_task_active(self, task_id: str) -> bool:
        if task_id not in self.tasks_states:
            return False

        return self.tasks_states[task_id].status.is_active()

    def should_wait_for_node(self,
                             task_id: str,
                             node_id: str,
                             offer_hash: str) -> bool:
        """ Check if the node has too many tasks assigned already """
        if not self.is_my_task(task_id):
            logger.debug(
                "Not my task. task_id=%s, node=%s",
                task_id,
                short_node_id(node_id),
            )
            return False

        task = self.tasks[task_id]

        verdict = task.should_accept_client(node_id, offer_hash)
        logger.debug(
            "Should accept client verdict. verdict=%s, task=%s, node=%s",
            verdict,
            task_id,
            short_node_id(node_id),
        )
        if verdict == AcceptClientVerdict.SHOULD_WAIT:
            logger.warning("Waiting for results from %s on %s",
                           short_node_id(node_id), task_id)
            return True
        elif verdict == AcceptClientVerdict.REJECTED:
            logger.warning("Client has failed on subtask within this task"
                           " and is banned from it. node_id=%s, task_id=%s",
                           short_node_id(node_id), task_id)
            return True
        return False

    def check_next_subtask(self, task_id: str, price: int) -> bool:
        """Check next subtask from task <task_id> with given price limit"""
        logger.debug(
            'check_next_subtask(%r, %r)',
            task_id,
            price,
        )
        if not self.is_my_task(task_id):
            logger.info("Cannot find task in my tasks. task_id=%s",
                        task_id)
            return False

        task = self.tasks[task_id]
        if task.header.max_price < price:
            logger.debug(
                'Requested price too high.'
                ' task_id=%(task_id)s,'
                ' task.header.max_price=%(task_price)s,'
                ' requested_price=%(price)s',
                {
                    'task_id': task_id,
                    'price': price,
                    'task_price': task.header.max_price,
                },
            )
            return False

        return True

    def copy_results(
            self,
            old_task_id: str,
            new_task_id: str,
            subtask_ids_to_copy: Iterable[str]) -> None:

        logger.debug('copy_results. old_task_id=%r, new_task_id=%r',
                     old_task_id, new_task_id)

        try:
            old_task = self.tasks[old_task_id]
            new_task = self.tasks[new_task_id]
            assert isinstance(old_task, CoreTask)
            assert isinstance(new_task, CoreTask)
        except (KeyError, AssertionError):
            logger.exception(
                'Cannot copy results from task %r to %r',
                old_task_id, new_task_id)
            return

        # Map new subtasks to old by 'start_task'
        subtasks_to_copy = {
            subtask['start_task']: subtask for subtask in
            map(lambda id_: old_task.subtasks_given[id_],  # type: ignore
                subtask_ids_to_copy)
        }

        # Generate all subtasks for the new task
        new_subtasks_ids = []
        while new_task.needs_computation():
            extra_data = new_task.query_extra_data(0, node_id=str(uuid.uuid4()))
            new_subtask_id = extra_data.ctd['subtask_id']
            self.subtask2task_mapping[new_subtask_id] = \
                new_task_id
            self.__add_subtask_to_tasks_states(
                node_id='',
                price=0,
                ctd=extra_data.ctd)
            new_subtasks_ids.append(new_subtask_id)

        logger.debug('copy_results. new_subtasks_ids=%r', new_subtasks_ids)

        # it's important to do this step separately, to not disturb
        # 'needs_computation' condition above
        for new_subtask_id in new_subtasks_ids:
            self.tasks_states[new_task_id].subtask_states[new_subtask_id]\
                .status = SubtaskStatus.failure
            new_task.subtasks_given[new_subtask_id]['status'] \
                = SubtaskStatus.failure
            new_task.subtask_status_updated(new_subtask_id)

        new_task.num_failed_subtasks = \
            new_task.get_total_tasks() - len(subtasks_to_copy)

        def handle_copy_error(subtask_id, error):
            logger.error(
                'Cannot copy result of subtask %r: %r', subtask_id, error)

            self.restart_subtask(subtask_id)

        for new_subtask_id, new_subtask in new_task.subtasks_given.items():
            old_subtask = subtasks_to_copy.get(new_subtask['start_task'])

            if old_subtask:  # Copy results from old subtask
                deferred = self._copy_subtask_results(
                    old_task=old_task,
                    new_task=new_task,
                    old_subtask=old_subtask,
                    new_subtask=new_subtask
                )
                deferred.addErrback(partial(handle_copy_error, new_subtask_id))

            else:  # Restart subtask to get it computed
                self.restart_subtask(new_subtask_id)

    def _copy_subtask_results(
            self,
            old_task: CoreTask,
            new_task: CoreTask,
            old_subtask: dict,
            new_subtask: dict) -> Deferred:

        old_task_id = old_task.header.task_id
        new_task_id = new_task.header.task_id
        assert isinstance(old_task.tmp_dir, str)
        assert isinstance(new_task.tmp_dir, str)
        old_tmp_dir = Path(old_task.tmp_dir)
        new_tmp_dir = Path(new_task.tmp_dir)
        old_subtask_id = old_subtask['subtask_id']
        new_subtask_id = new_subtask['subtask_id']

        def copy_and_extract_zips():
            # TODO: Refactor this using package manager (?)
            old_result_path = old_tmp_dir / '{}.{}.zip'.format(
                old_task_id, old_subtask_id)
            new_result_path = new_tmp_dir / '{}.{}.zip'.format(
                new_task_id, new_subtask_id)
            shutil.copy(old_result_path, new_result_path)

            subtask_result_dir = new_tmp_dir / new_subtask_id
            os.makedirs(subtask_result_dir)
            with ZipFile(new_result_path, 'r') as zf:
                zf.extractall(subtask_result_dir)
                return [
                    str(subtask_result_dir / name)
                    for name in zf.namelist()
                    if name != '.package_desc'
                ]

        def after_results_extracted(results):
            new_task.copy_subtask_results(
                new_subtask_id, old_subtask, TaskResult(files=results))

            self.__set_subtask_state_finished(new_subtask_id)
            new_task.subtask_status_updated(new_subtask_id)

            self.notice_task_updated(
                task_id=new_task_id,
                subtask_id=new_subtask_id,
                op=SubtaskOp.FINISHED)

        deferred = deferToThread(copy_and_extract_zips)
        deferred.addCallback(after_results_extracted)
        return deferred

    def get_tasks_headers(self):
        ret = []
        for tid, task in self.tasks.items():
            status = self.tasks_states[tid].status
            if task.needs_computation() and status.is_active():
                ret.append(task.header)

        return ret

    def get_trust_mod(self, subtask_id):
        if subtask_id in self.subtask2task_mapping:
            task_id = self.subtask2task_mapping[subtask_id]
            return self.tasks[task_id].get_trust_mod(subtask_id)

        logger.warning("Cannot get trust mod for subtask_id=%s", subtask_id)
        return 0

    def update_task_signatures(self):
        for task in list(self.tasks.values()):
            self.sign_task_header(task.header)

    def sign_task_header(self, task_header):
        task_header.sign(private_key=self.keys_auth._private_key)  # noqa pylint: disable=protected-access

    def verify_subtask(self, subtask_id):
        logger.debug("verify_subtask. subtask_id=%r", subtask_id)
        if subtask_id in self.subtask2task_mapping:
            task_id = self.subtask2task_mapping[subtask_id]
            return self.tasks[task_id].verify_subtask(subtask_id)
        return False

    def get_node_id_for_subtask(self, subtask_id):
        if subtask_id not in self.subtask2task_mapping:
            return None
        task = self.subtask2task_mapping[subtask_id]
        subtask_state = self.tasks_states[task].subtask_states[subtask_id]
        return subtask_state.node_id

    @handle_subtask_key_error
    def computed_task_received(
            self, subtask_id: str, result: TaskResult,
            verification_finished: Callable[[], None]) -> None:
        logger.debug("Computed task received. subtask_id=%s", subtask_id)
        task_id: str = self.subtask2task_mapping[subtask_id]

        subtask_state: SubtaskState =\
            self.tasks_states[task_id].subtask_states[subtask_id]
        subtask_status: SubtaskStatus = subtask_state.status

        if not subtask_status.is_computed():
            logger.warning(
                "Result for subtask with invalid status."
                " subtask_id=%s, status=%s",
                subtask_id,
                subtask_status.value,
            )
            self.notice_task_updated(task_id,
                                     subtask_id=subtask_id,
                                     op=OtherOp.UNEXPECTED)
            verification_finished()
            return
        subtask_state.status = SubtaskStatus.verifying

        @TaskManager.handle_generic_key_error
        def verification_finished_():
            logger.debug("Verification finished. subtask_id=%s", subtask_id)
            ss = self.__set_subtask_state_finished(subtask_id)
            if not self.tasks[task_id].verify_subtask(subtask_id):
                logger.debug("Subtask %r not accepted\n", subtask_id)
                ss.status = SubtaskStatus.failure
                ss.stderr = "[GOLEM] Not accepted"
                self.notice_task_updated(
                    task_id,
                    subtask_id=subtask_id,
                    op=SubtaskOp.NOT_ACCEPTED)
                verification_finished()
                return

            self.notice_task_updated(task_id,
                                     subtask_id=subtask_id,
                                     op=SubtaskOp.FINISHED)

            verification_finished()

            if self.tasks_states[task_id].status.is_active():
                if not self.tasks[task_id].finished_computation():
                    self.tasks_states[task_id].status = TaskStatus.computing
                else:
                    if self.tasks[task_id].verify_task():
                        logger.info("Task finished! task_id=%r", task_id)
                        self.tasks_states[task_id].status =\
                            TaskStatus.finished
                        self.notice_task_updated(task_id,
                                                 op=TaskOp.FINISHED)
                    else:
                        logger.warning("Task finished but was not accepted. "
                                       "task_id=%r", task_id)
                        self.notice_task_updated(task_id,
                                                 op=TaskOp.NOT_ACCEPTED)

        self.notice_task_updated(task_id,
                                 subtask_id=subtask_id,
                                 op=SubtaskOp.VERIFYING)
        self.tasks[task_id].computation_finished(
            subtask_id, result, verification_finished_
        )

    @handle_subtask_key_error
    def __set_subtask_state_finished(self, subtask_id: str) -> SubtaskState:
        task_id = self.subtask2task_mapping[subtask_id]
        ss = self.tasks_states[task_id].subtask_states[subtask_id]
        ss.progress = 1.0
        ss.status = SubtaskStatus.finished
        ss.stdout = self.tasks[task_id].get_stdout(subtask_id)
        ss.stderr = self.tasks[task_id].get_stderr(subtask_id)
        ss.results = self.tasks[task_id].get_results(subtask_id)
        return ss

    @handle_subtask_key_error
    def task_computation_failure(self, subtask_id: str, err: object,
                                 ban_node: bool = True) -> bool:
        task_id = self.subtask2task_mapping[subtask_id]
        task = self.tasks[task_id]
        task_state = self.tasks_states[task_id]
        subtask_state = task_state.subtask_states[subtask_id]
        subtask_status = subtask_state.status

        if not subtask_status.is_computed():
            logger.warning(
                "Subtask %s status cannot be changed from '%s' to '%s'",
                subtask_id, subtask_status.value, SubtaskStatus.failure,
            )
            self.notice_task_updated(task_id,
                                     subtask_id=subtask_id,
                                     op=OtherOp.UNEXPECTED)
            return False

        task.computation_failed(subtask_id, ban_node)

        subtask_state.progress = 1.0
        subtask_state.status = SubtaskStatus.failure
        subtask_state.stderr = str(err)

        self.notice_task_updated(task_id,
                                 subtask_id=subtask_id,
                                 op=SubtaskOp.FAILED)
        return True

    @handle_subtask_key_error
    def task_computation_cancelled(
            self,
            subtask_id: str,
            err: message.tasks.CannotComputeTask.REASON,
            timeout: float,
    ) -> bool:
        if err is message.tasks.CannotComputeTask.REASON.OfferCancelled:
            self.restart_subtask(
                subtask_id,
                new_status=SubtaskStatus.cancelled,
            )
            return True
        task_id = self.subtask2task_mapping[subtask_id]
        task_state = self.tasks_states[task_id]
        subtask_state = task_state.subtask_states[subtask_id]
        ban_node = subtask_state.time_started + timeout < time.time()
        return self.task_computation_failure(
            subtask_id,
            f'Task computation rejected: {err.value if err else "unknown"}',
            ban_node,
        )

    def task_result_incoming(self, subtask_id):
        try:
            task_id = self.subtask2task_mapping[subtask_id]
        except KeyError:
            logger.error(
                "Unknown subtask. subtask_id=%s",
                subtask_id,
            )
            return
        try:
            task = self.tasks[task_id]
        except KeyError:
            logger.error("Unknown task. task_id=%s", task_id)
            return
        subtask_state = self.tasks_states[task_id].subtask_states[subtask_id]

        task.result_incoming(subtask_id)
        subtask_state.status = SubtaskStatus.downloading

        self.notice_task_updated(
            task_id,
            subtask_id=subtask_id,
            op=SubtaskOp.RESULT_DOWNLOADING)

    # CHANGE TO RETURN KEY_ID (check IF SUBTASK COMPUTER HAS KEY_ID
    def check_timeouts(self):
        nodes_with_timeouts = []
        for t in list(self.tasks.values()):
            th = t.header
            if not self.tasks_states[th.task_id].status.is_active():
                continue
            cur_time = int(get_timestamp_utc())
            # Check subtask timeout
            ts = self.tasks_states[th.task_id]
            for s in list(ts.subtask_states.values()):
                if s.status.is_computed():
                    if cur_time > s.deadline:
                        logger.info("Subtask %r dies with status %r",
                                    s.subtask_id,
                                    s.status.value)
                        s.status = SubtaskStatus.timeout
                        nodes_with_timeouts.append(s.node_id)
                        t.computation_failed(s.subtask_id)
                        s.stderr = "[GOLEM] Timeout"
                        self.notice_task_updated(th.task_id,
                                                 subtask_id=s.subtask_id,
                                                 op=SubtaskOp.TIMEOUT)
            # Check task timeout
            if cur_time > th.deadline:
                logger.info("Task %r dies", th.task_id)
                self.tasks_states[th.task_id].status = TaskStatus.timeout
                # TODO: t.tell_it_has_timeout()?
                self.notice_task_updated(th.task_id, op=TaskOp.TIMEOUT)
                self._try_remove_task_output_dir(t.task_definition)
        return nodes_with_timeouts

    def get_progresses(self):
        tasks_progresses = {}

        for t in list(self.tasks.values()):
            task_id = t.header.task_id
            task_state = self.tasks_states[task_id]
            task_status = task_state.status
            in_progress = not TaskStatus.is_completed(task_status)
            logger.info('Collecting progress %r %r %r',
                        task_id, task_status, in_progress)
            if in_progress:
                ltss = LocalTaskStateSnapshot(
                    task_id,
                    t.get_total_tasks(),
                    t.get_active_tasks(),
                    t.get_progress(),
                )
                tasks_progresses[task_id] = ltss

        return tasks_progresses

    @handle_task_key_error
    def assert_task_can_be_restarted(self, task_id: str) -> None:
        task_state = self.tasks_states[task_id]
        if task_state.status == TaskStatus.restarted:
            raise self.AlreadyRestartedError()

    @handle_task_key_error
    def put_task_in_restarted_state(self, task_id, clear_tmp=True):
        """
        When restarting task, it's put in a final state 'restarted' and
        a new one is created.
        """
        self.assert_task_can_be_restarted(task_id)
        if clear_tmp:
            self.dir_manager.clear_temporary(task_id)

        task_state = self.tasks_states[task_id]
        task_state.status = TaskStatus.restarted

        for ss in self.tasks_states[task_id].subtask_states.values():
            if ss.status != SubtaskStatus.failure:
                ss.status = SubtaskStatus.restarted

        logger.info("Task %s put into restarted state", task_id)
        self.notice_task_updated(task_id, op=TaskOp.RESTARTED)

    @handle_task_key_error
    def put_task_in_failed_state(
            self,
            task_id: str,
            task_status=TaskStatus.errorCreating,
    ) -> None:
        assert not task_status.is_active()
        task_state = self.tasks_states[task_id]
        if task_state.status.is_completed():
            logger.debug(
                "Task is already completed. Won't change status."
                " current_status=%(current_status)s,"
                " refused_status=%(refused_status)s",
                {
                    'current_status': task_state.status,
                    'refused_status': task_status,
                },
            )
            return

        task_state.status = task_status

        logger.info(
            "Task %s put into failed state. task_status=%s",
            task_id,
            task_state,
        )
        self.notice_task_updated(task_id, op=TaskOp.ABORTED)

    @handle_subtask_key_error
    def restart_subtask(
            self,
            subtask_id: str,
            new_status: SubtaskStatus = SubtaskStatus.restarted,
    ):
        task_id = self.subtask2task_mapping[subtask_id]
        logger.debug(
            "Restart subtask. subtask_id=%s, new_status=%s, task_id=%s",
            subtask_id,
            new_status,
            task_id,
        )
        self.tasks[task_id].restart_subtask(
            subtask_id,
            new_state=new_status,
        )
        task_state = self.tasks_states[task_id]
        task_state.status = TaskStatus.computing
        subtask_state = task_state.subtask_states[subtask_id]
        subtask_state.status = new_status
        subtask_state.stderr = f"[GOLEM] {new_status.value}"

        self.notice_task_updated(task_id,
                                 subtask_id=subtask_id,
                                 op=SubtaskOp.RESTARTED)

    @handle_task_key_error
    def abort_task(self, task_id):
        self.tasks[task_id].abort()
        self.tasks_states[task_id].status = TaskStatus.aborted
        for sub in list(self.tasks_states[task_id].subtask_states.values()):
            del self.subtask2task_mapping[sub.subtask_id]
        self.tasks_states[task_id].subtask_states.clear()

        self.notice_task_updated(task_id, op=TaskOp.ABORTED)

    @rpc_utils.expose('comp.task.subtasks.frames')
    @handle_task_key_error
    def get_output_states(self, task_id):
        return self.tasks[task_id].get_output_states()

    @handle_task_key_error
    def delete_task(self, task_id):
        for sub in list(self.tasks_states[task_id].subtask_states.values()):
            del self.subtask2task_mapping[sub.subtask_id]
        self.tasks_states[task_id].subtask_states.clear()

        self.tasks[task_id].unregister_listener(self)
        del self.tasks[task_id]
        del self.tasks_states[task_id]

        self.dir_manager.clear_temporary(task_id)
        self.remove_dump(task_id)
        if self.finished_cb:
            self.finished_cb()

    @handle_task_key_error
    def query_task_state(self, task_id):
        ts = self.tasks_states[task_id]
        t = self.tasks[task_id]

        ts.progress = t.get_progress()
        ts.elapsed_time = time.time() - ts.time_started

        if ts.progress > 0.0:
            proportion = (ts.elapsed_time / ts.progress)
            ts.remaining_time = proportion - ts.elapsed_time
        else:
            ts.remaining_time = None

        t.update_task_state(ts)

        return ts

    def subtask_to_task(
            self,
            subtask_id: str,
            local_role: model.Actor,
    ) -> Optional[str]:
        if local_role == model.Actor.Provider:
            return self.comp_task_keeper.subtask_to_task.get(subtask_id)
        elif local_role == model.Actor.Requestor:
            return self.subtask2task_mapping.get(subtask_id)
        return None

    def get_subtasks(self, task_id) -> Optional[List[str]]:
        """
        Get all subtasks related to given task id
        :param task_id: Task ID
        :return: list of all subtasks related with @task_id or None
                 if @task_id is not known
        """
        task_state = self.tasks_states.get(task_id)
        if not task_state:
            return None

        subtask_states = list(task_state.subtask_states.values())
        return [subtask_state.subtask_id for subtask_state in subtask_states]

    @rpc_utils.expose('comp.task.verify_subtask')
    def external_verify_subtask(self, subtask_id, verdict):
        logger.info("external_verify_subtask. subtask_id=%r",
                    subtask_id)
        if subtask_id in self.subtask2task_mapping:
            task_id = self.subtask2task_mapping[subtask_id]
            return self.tasks[task_id].external_verify_subtask(subtask_id,
                                                               verdict)
        else:
            raise ValueError('Not my subtask')

    def get_frame_subtasks(self, task_id: str, frame) \
            -> Optional[FrozenSet[str]]:
        task: Optional[Task] = self.tasks.get(task_id)
        if not task:
            return None
        if not isinstance(task, CoreTask):
            return None
        return frozenset(task.get_subtasks(frame).keys())

    def get_task_id(self, subtask_id):
        return self.subtask2task_mapping[subtask_id]

    def get_task_dict(self, task_id) -> Optional[Dict]:
        task = self.tasks.get(task_id)
        if not task:  # task might have been deleted after the request was made
            return None

        task_type_name = task.task_definition.task_type.lower()
        task_type = self.task_types[task_type_name]
        state = self.query_task_state(task.header.task_id)

        dictionary = {
            # single=True retrieves one preview file. If rendering frames,
            # it's the preview of the most recently computed frame.
            'preview': task_type.get_preview(task, single=True)
        }

        return update_dict(dictionary,
                           task.to_dictionary(),
                           state.to_dictionary(),
                           self.get_task_definition_dict(task))

    def get_tasks_dict(self) -> List[Dict]:
        task_ids = list(self.tasks.keys())
        mapped = map(self.get_task_dict, task_ids)
        filtered = filter(None, mapped)
        return list(filtered)

    def get_subtask_dict(self, subtask_id):
        task_id = self.subtask2task_mapping[subtask_id]
        task_state = self.tasks_states[task_id]
        subtask = task_state.subtask_states[subtask_id]
        return subtask.to_dict()

    def get_subtasks_dict(self, task_id):
        task_state = self.tasks_states[task_id]
        subtasks = task_state.subtask_states
        if subtasks:
            return [subtask.to_dict() for subtask in subtasks.values()]
        return None

    @rpc_utils.expose('comp.task.subtasks.borders')
    def get_subtasks_borders(self, task_id, part=1):
        task = self.tasks[task_id]
        task_type_name = task.task_definition.task_type.lower()
        task_type = self.task_types[task_type_name]
        subtasks_count = task.get_total_tasks()

        return {
            to_unicode(subtask_id): task_type.get_task_border(
                extra_data,
                task.task_definition,
                subtasks_count,
                as_path=True,
            ) for subtask_id, extra_data in task.get_subtasks(part).items()
        }

    def get_task_preview(self, task_id, single=False):
        task = self.tasks[task_id]
        task_type_name = task.task_definition.task_type.lower()
        task_type = self.task_types[task_type_name]
        return task_type.get_preview(task, single=single)

    def add_comp_task_request(
            self,
            task_header: message.tasks.TaskHeader,
            budget: int,
            performance: float,
            num_subtasks: int,
    ):
        """ Add a header of a task which this node may try to compute """
        self.comp_task_keeper.add_request(
            task_header, budget, performance, num_subtasks
        )

    def __add_subtask_to_tasks_states(self, node_id,
                                      ctd, price: int):

        logger.debug('add_subtask_to_tasks_states(%r, %r)',
                     node_id, ctd)

        # we're retrieving the node_info so that we can set `node_name` on
        # SubtaskState, which is later used e.g. to render the subtasks list
        # in CLI and on the front-end
        node_info = nodeskeeper.get(node_id)
        ss = SubtaskState(
            subtask_id=ctd['subtask_id'],
            node_id=node_id,
            node_name=node_info.node_name if node_info else '',
            price=price,
            deadline=ctd['deadline'],
            extra_data=ctd['extra_data'],
        )

        self.tasks_states[ctd['task_id']].\
            subtask_states[ctd['subtask_id']] = ss

    def notify_update_task(self, task_id):
        self.notice_task_updated(task_id)

    @handle_task_key_error
    def notice_task_updated(self, task_id: str,
                            subtask_id: Optional[str] = None,
                            op: Optional[Operation] = None,
                            persist: bool = True):
        """Called when a task is modified, saves the task and
        propagates information

        Whenever task is changed `notice_task_updated` should be called
        to save the task - if the change is save-worthy, as specified
        by the `persist` parameter - and propagate information about
        changed task to other parts of the system.

        Most of the calls are save-worthy, but a minority is not: for
        instance when the work offer is received, the task does not
        change so saving it does not make sense, but it still makes
        sense to let other parts of the system know about the change.
        Also, when a number of minor changes are always followed by a
        major one, as it is with restarting a frame task, it does not
        make sense to store all the partial changes, so only the
        final one is considered save-worthy.

        :param str task_id: id of the updated task
        :param str subtask_id: if the operation done on the
          task is related to a subtask, id of that subtask
        :param Operation op: performed operation
        :param bool persist: should the task be persisted now
        """
        # self.save_state()

        logger.debug(
            "Notice task updated. task_id=%s, subtask_id=%s,"
            "op=%s, persist=%s",
            task_id, subtask_id, op, persist,
        )

        if persist:
            self.dump_task(task_id)

        task_state = self.tasks_states.get(task_id)
        dispatcher.send(
            signal='golem.taskmanager',
            event='task_status_updated',
            task_id=task_id,
            task_state=task_state,
            subtask_id=subtask_id,
            op=op,
        )

        self._stop_timers(task_id, subtask_id, op)
        self._update_subtask_statistics(task_id, subtask_id, op)

        if self.finished_cb and persist and op \
                and op.task_related() and op.is_completed():
            self.finished_cb()

    def _stop_timers(self, task_id: str,
                     subtask_id: Optional[str] = None,
                     op: Optional[Operation] = None):

        if subtask_id and isinstance(op, SubtaskOp) and op.is_completed():
            ProviderComputeTimers.finish(subtask_id)

        elif isinstance(op, TaskOp) and op in (
                TaskOp.ABORTED,
                TaskOp.TIMEOUT,
                TaskOp.RESTARTED
        ):
            for _subtask_id in self.tasks_states[task_id].subtask_states:
                ProviderComputeTimers.finish(_subtask_id)

    def _update_subtask_statistics(self, task_id: str,
                                   subtask_id: Optional[str] = None,
                                   op: Optional[Operation] = None) -> None:

        # Skip if subtask is not completed
        if not (subtask_id and isinstance(op, SubtaskOp) and op.is_completed()):
            return

        try:
            self._update_provider_statistics(task_id, subtask_id, op)
        except (KeyError, ValueError) as e:
            logger.error("Unable to update statistics for subtask %s: %r",
                         subtask_id, e)

        try:
            self._update_provider_reputation(task_id, subtask_id, op)
        except (KeyError, ValueError) as e:
            logger.error("Unable to update reputation for subtask %s: %r",
                         subtask_id, e)

        # We're done processing the subtask
        ProviderComputeTimers.remove(subtask_id)

    def _update_provider_statistics(self, task_id: str,
                                    subtask_id: str,
                                    op: SubtaskOp) -> None:
        logger.debug('_update_provider_statistics. task_id=%r, subtask_id=%r,'
                     'op=%r', task_id, subtask_id, op)
        header = self.tasks[task_id].header
        subtask_state = self.tasks_states[task_id].subtask_states[subtask_id]

        computation_price = calculate_subtask_payment(subtask_state.price,
                                                      header.subtask_timeout)
        computation_time = ProviderComputeTimers.time(subtask_id)

        if not computation_time:
            logger.warning("Could not obtain computation time for subtask: %r",
                           subtask_id)
            return

        computation_time = int(round(computation_time))

        dispatcher.send(
            signal='golem.subtask',
            event='finished',
            timed_out=(op == SubtaskOp.TIMEOUT),
            subtask_count=header.subtasks_count,
            subtask_timeout=header.subtask_timeout,
            subtask_price=computation_price,
            subtask_computation_time=computation_time,
        )

    def _update_provider_reputation(self, task_id: str,
                                    subtask_id: str,
                                    op: SubtaskOp) -> None:

        timeout = self.tasks[task_id].header.subtask_timeout
        subtask_state = self.tasks_states[task_id].subtask_states[subtask_id]
        node_id = subtask_state.node_id

        logger.debug('_update_provider_reputation. task_id=%r, subtask_id=%r,'
                     'op=%r, subtask_state=%r', task_id, subtask_id, op,
                     subtask_state)

        update_provider_efficacy(node_id, op)
        computation_time = ProviderComputeTimers.time(subtask_id)

        if not computation_time:
            logger.warning("Could not obtain computation time for subtask: %r",
                           subtask_id)
            return

        update_provider_efficiency(node_id, timeout, computation_time)

    @staticmethod
    def get_provider_market_strategy_for_env(
            env_id: str) -> Type[ProviderMarketStrategy]:
        # NOTE This assumes ENV_ID == App Type
        if env_id == WasmTaskEnvironment.ENV_ID:
            return ProviderWasmMarketStrategy
        return ProviderBrassMarketStrategy


from .functions import *
from common.types import *
from common.utils import Singleton

from camera.assets import cameraStoreConfig

import os
import json
import shutil
import subprocess
from pathlib import Path
from datetime import datetime

from typing import Dict

from PIL import Image as PILImage
from picamera2 import Picamera2, Preview

class MyCamera(metaclass=Singleton):
    def __init__(self):
        """
        video : 현재 저장되고 있는 영상!
        """
        self._video:Video = Video(mode="", title="", format="", duration={"start":datetime.now(), "end":datetime.now()}, width=1, height=1, frames=[])
        self._camera = Picamera2()
        self._configure_camera()
        self._camera.start()

        self._isConnected = False

    def __del__(self):
        self._camera.close()

    def _configure_camera(self):
        self._camera.start_preview(Preview.NULL)
        config = self._camera.create_still_configuration()
        config['buffer_count'] = 5
        self._camera.configure(config)

    @property
    def video(self):
        return self._video

    @property
    def isConnected(self):
        return self._isConnected

    async def start_video(self, title:str, width:int, height:int)->None:
        """
        video를 새로 지정하고, 해당 비디오와 동일한 구성요소가 디스크에 있으면 지운다.
        """
        self._video = Video(mode="RGBA", title=title, format="jpeg", duration={"start":datetime.now(), "end":datetime.now()}, width=width, height=height, frames=[])

        if (cameraStoreConfig['paths']['frames'] / title).exists():
            shutil.rmtree(cameraStoreConfig['paths']['frames'] / title)

        if (cameraStoreConfig['paths']['videos'] / title).exists():
            shutil.rmtree(cameraStoreConfig['paths']['videos'] / title)

        os.makedirs(cameraStoreConfig['paths']['frames'] / title, exist_ok=False)
        os.makedirs(cameraStoreConfig['paths']['videos'], exist_ok=True)

        self._isConnected = True
        return None

    async def end_video(self, savedTitle:str) -> None:
        """
        Video 저장하기, 저장경로에 다른 파일이 있다면 지운다.
        """
        if (cameraStoreConfig['paths']['frames'] / savedTitle).exists():
            shutil.rmtree(cameraStoreConfig['paths']['frames'] / savedTitle)
        subprocess.run(['mv', cameraStoreConfig['paths']['frames'] / self.video.title, cameraStoreConfig['paths']['frames'] / savedTitle])

        self.video.title = savedTitle
        self.video.duration["end"] = datetime.now()

        with open(cameraStoreConfig['paths']['videos'] / f"{savedTitle}.json", "w") as fd:
            fd.write(self.video.json())

        self._isConnected = False
        return None

    async def capture(self)->Image:
        """
        사진을 찍고 Image로 반환!
        """
        frame = Frame(id=len(self.video.frames) + 1, captured=datetime.now())
        img:PILImage = self._camera.capture_image().resize([self.video.width, self.video.height], PILImage.Resampling.NEAREST)
        bytesImg = await make_bytes_from_img(img)
        img.close()

        self.video.frames.append(frame)
        return Image(captured=frame.captured, width=self.video.width, height=self.video.height, risked=[], src=self.video.title, id=frame.id, data=bytesImg)

    async def save_frame(self, image:Image) -> bool:
        """
        이미지 저장!
        """
        try:
            name = await make_frame_name(self.video, image.id)
            img = await make_img_from_bytes(image.data, self.video.width, self.video.height)
            img.save(name + '.' + self.video.format)
            with open(name + ".json", 'w') as fd:
                fd.write(image.json())

            return True
        except Exception as e:
            print(e)
            return False

    async def get_frame(self, id: int)->Image:
        """
        Video의 특정 프레임 이미지 가져오기!
        """
        name = await make_frame_name(self.video, id)
        name = name + ".json"
        if not os.path.exists(name):
            raise FileNotFoundError
        else:
            with open(name, 'r') as fd:
                return Image(**json.load(fd))


# -*- coding: utf-8 -*-
##############################################################################
# Author：QQ173782910
##############################################################################

import traceback
import time
import random
from basic.JD_TOOL import robot_bugerror
from basic.DB_TOOL import DB_pg3
from dbconfig import scott, tiger, host, port, dbname
from moment.MTOOL import GetData
from function_scheduling_distributed_framework import patch_frame_config,task_deco,fsdf_background_scheduler, timing_publish_deco
patch_frame_config(REDIS_HOST='127.0.0.1',REDIS_PASSWORD='',REDIS_PORT=6379,REDIS_DB=7)

try:
    link =[host,port, dbname,scott, tiger]
    db = DB_pg3(link)
except:
    raise NameError('db link error')

def get_random_no(E_R=2, T=''):
    if E_R == 0:
        cur_random_no = "%s%s" % (time.time(), random.random())
        return cur_random_no.replace('.', '')
    elif E_R == 1:
        timeStamp = time.time()
        timeArray = time.localtime(timeStamp)
        danhao = time.strftime("%Y%m%d%H%M%S", timeArray)
        romcode = str(time.time()).split('.')[-1]  # [3:]
        order_number = T + danhao[2:] + romcode
        return order_number

    timeStamp = time.time()
    timeArray = time.localtime(timeStamp)
    danhao = time.strftime("%Y%m%d%H%M%S", timeArray)
    romcode = str(time.time()).split('.')[-1]  # [3:]
    upperCase = [
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
        'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    ]
    Dstr = random.sample(upperCase, E_R)
    D_c = ''.join(Dstr)
    random_no = D_c + danhao[2:] + romcode
    return random_no

def time_to(ti):
    ti = ti.replace("T", " ").replace(".000Z", "")
    data_sj = time.strptime(ti, "%Y-%m-%d %H:%M:%S")  # 定义格式
    time_int = int(time.mktime(data_sj))
    return time_int

@task_deco('printlog',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def printlog(cname,errors):
    sql="insert into print_log(cname,errors,ctime)values(%s,%s,now())"
    db.query(sql,[cname,errors])
    return

@task_deco('ustatus',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def update_status(usr_id,us_id,status):

    try:
        sql = "update user_strategy set status=%s,utime=now() where usr_id=%s and id=%s;"
        db.query(sql, [status, usr_id, us_id])
    except:
        robot_bugerror(traceback, ctype='update_status')
    return

@task_deco('tlog',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def trading_log(remark,usr_id,symbol,num,tp_okexs):
    #us_id  user_strategy的id
    try:
        id=get_random_no(E_R=0)
        sql="""insert into trading_log(id,usr_id,deal_num,instrument_id,remark,ctime,tp_okexs)
        values(%s,%s,%s,%s,%s,now(),%s);"""
        db.query(sql,[id,usr_id,num,symbol,remark,tp_okexs])
    except:
        robot_bugerror(traceback, ctype='trading_log')
    return

@task_deco('sp',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def save_position(usr_id,instrument_id,pt,us_id,result,ctype,client_oid,remark):
    try:
        if ctype != 0:#2永续
            robot_bugerror('获取持仓故障%s:%s:%s'%(client_oid,instrument_id,result), ctype='ok')
            return

        longnum, longcost, longpnl, shortnum, shortcost, shortpnl, long_pnl_ratio, short_pnl_ratio,last = pt

        if longnum>0:
            profit_loss = longpnl
        else:
            profit_loss = shortpnl

        sql = """update user_strategy set longnum=%s,longcost=%s,longpnl=%s,
                shortnum=%s,shortcost=%s,shortpnl=%s,ptime=now(),long_pnl_ratio=%s,short_pnl_ratio=%s,
                hold_position=%s,profit_loss=%s where id=%s;"""
        parm = [longnum, longcost, longpnl, shortnum, shortcost, shortpnl,
                long_pnl_ratio, short_pnl_ratio,longnum,profit_loss, us_id]

        db.query(sql, parm)
        if longnum == 0 and shortnum == 0:
            update_reset.push(usr_id, us_id)

        if longnum != 0 or shortnum != 0:
            sql = """update positions set holds=%s,results=%s,ctime=now(),longnum=%s,longcost=%s,longpnl=%s,
            shortnum=%s,shortcost=%s,shortpnl=%s,long_pnl_ratio=%s,short_pnl_ratio=%s,lasts=%s where client_oid=%s;"""
            parm = [remark, '%s' % result,
                    longnum,longcost,longpnl,shortnum,shortcost,shortpnl,long_pnl_ratio,short_pnl_ratio,last,client_oid]
            db.query(sql, parm)

    except:
        robot_bugerror(traceback, ctype='save_position')
    return

@task_deco('spt',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def stop_profit(usr_id,instrument_id,ptlist,results,ctype,deal_num,highest,lowhest,client_oid):
    try:
        longnum, longcost, longpnl, shortnum, shortcost, shortpnl, long_pnl_ratio, short_pnl_ratio, last = ptlist
        if ctype==0:
            if longnum == 0 and shortnum==0:
                return
            id=get_random_no(E_R=0)
            sql="""insert into stop_profit(id,usr_id,instrument_id,
            longnum,longcost,longpnl,shortnum,shortcost,shortpnl,ctime,long_pnl_ratio,short_pnl_ratio,
            results,lasts,highest,lowhest,client_oid)
            values(%s,%s,%s,%s,%s,%s,%s,%s,%s,now(),%s,%s,%s,%s,%s,%s,%s);"""
            parm=[id,usr_id,instrument_id,longnum,longcost,longpnl,shortnum,
                  shortcost,shortpnl,long_pnl_ratio,short_pnl_ratio,results,last,highest,lowhest,client_oid]
            db.query(sql,parm)
        elif ctype==1:
            if longnum!=0:
                #def spl_log(remark, symbol, deal_num, num, costs, pnl, lasts):
                stop_profit_log.push(results, instrument_id, deal_num, longnum, longcost, longpnl, last,highest,lowhest,client_oid)#多单
            elif shortnum!=0:
                stop_profit_log.push(results, instrument_id, deal_num, shortnum, shortcost, shortpnl, last,highest,lowhest,client_oid)#空单
    except:
        robot_bugerror(traceback, ctype='stop_profit')
    return

@task_deco('splog',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def stop_profit_log(remark,symbol,deal_num,num,costs,pnl,lasts,highest,lowhest,client_oid):

    try:
        id=get_random_no(E_R=0)
        sql="""insert into stop_profit_log(id,instrument_id,deal_num,num,costs,pnl,lasts,remark,ctime,highest,lowhest,client_oid)
        values(%s,%s,%s,%s,%s,%s,%s,%s,now(),%s,%s,%s);"""
        db.query(sql,[id,symbol,deal_num,num,costs,pnl,lasts,remark,highest,lowhest,client_oid])
    except:
        robot_bugerror(traceback, ctype='stop_profit_log')
    return

@task_deco('upre',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def update_reset(usr_id,us_id):
    #ctype 0空单，1多单
    try:
        sql = """update user_strategy set h_longpnl='0',h_shortpnl='0',
        htime=now(),h_last='0',l_last='0' where usr_id=%s and id=%s;"""
        parm = [usr_id, us_id]
        db.query(sql, parm)
    except:
        robot_bugerror(traceback, ctype='update_reset')
    return

@task_deco('uep',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def update_earnings_price(usr_id,us_id,ctype,flag,last,pnl,client_oid):
    #ctype 0:空单,1:多单
    #flag  'H'高价，'L':低价
    try:
        if ctype==0:#空单
            if flag=='H':#更高价
                sql = """update user_strategy set htime=now(),h_last=%s where usr_id=%s and id=%s;
                update positions set highest=%s where client_oid=%s;
                """
                parm = [last, usr_id, us_id,last,client_oid]
                db.query(sql, parm)
            else:#更低价
                sql = """update user_strategy set h_shortpnl=%s,htime=now(),l_last=%s where usr_id=%s and id=%s;
                update positions set lowhest=%s where client_oid=%s;
                """
                parm = [pnl, last, usr_id, us_id,last,client_oid]
                db.query(sql, parm)
        else:#多单
            if flag == 'H':#更高价
                sql = """update user_strategy set h_longpnl=%s,htime=now(),h_last=%s where usr_id=%s and id=%s;
                 update positions set highest=%s where client_oid=%s;
                """
                parm = [pnl, last, usr_id, us_id,last,client_oid]
                db.query(sql, parm)
            else:#更低价
                sql = """update user_strategy set htime=now(),l_last=%s where usr_id=%s and id=%s;
                update positions set lowhest=%s where client_oid=%s;
                """
                parm = [last, usr_id, us_id,last,client_oid]
                db.query(sql, parm)
    except:
        robot_bugerror(traceback, ctype='update_earnings_price')
    return

@task_deco('cou',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def client_oid_update(us_id,client_oid,usr_id,symbol):
    try:
        id = get_random_no(E_R=0)
        sql = """update user_strategy set client_oid=%s where id=%s;
        insert into positions(id,usr_id,instrument_id,client_oid,ctime)values(%s,%s,%s,%s,now());
        """
        parm = [client_oid, us_id,id,usr_id,symbol,client_oid]
        db.query(sql, parm)

    except:
        robot_bugerror(traceback, ctype='client_oid_update')
    return

@task_deco('gsc',log_level=50,is_print_detail_exception=False,create_logger_file=False,broker_kind=2)
def get_symbol_check():
    try:
        sql = """select
                    t_instrument_id,tp_okexs
                    from user_strategy where coalesce(del_flag,0)=0 and coalesce(status,0) not in (0,5)
                    """
        l, t = db.select(sql)
        if t > 0:
            for i in l:
                symbol, time_period=i
                GetData(symbol,time_period).signal_chekc()

    except:
        robot_bugerror(traceback, ctype='get_symbol_check')
    return

if __name__ == '__main__':
    fsdf_background_scheduler.add_job(timing_publish_deco(get_symbol_check), 'interval', id='timing10s', seconds=10)

    # 启动定时
    fsdf_background_scheduler.start()
    ################################# 日志任务
    printlog.consume()#策略运行日志
    trading_log.consume()#策略运行日志
    stop_profit_log.consume()#止盈日志
    save_position.consume()#持仓处理
    ############################
    update_status.consume()#更新状态
    stop_profit.consume()#止盈处理
    update_reset.consume()#止盈记录
    update_earnings_price.consume()#更新收益与价格记录
    client_oid_update.consume()#
    ###############
    get_symbol_check.consume()  #


""" View module for handling requests for categories """

from rest_framework.status import HTTP_404_NOT_FOUND
from rareserverapi.models.category import Category
from rest_framework import status
from rareserverapi.models.rareuser import RareUser
from django.core.exceptions import ValidationError
from django.http import HttpResponseServerError
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from rest_framework import serializers
from rareserverapi.models import Post, PostTag, Reaction, PostReaction
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from rest_framework.decorators import action

class Posts(ViewSet):
    """ rare Post  """

    def create(self, request):
        """Handle POST operations

        Returns:
            Response indicating success of request
        """

        post = Post()
        category = Category.objects.get(pk=request.data["category_id"])
        author = RareUser.objects.get(user=request.auth.user)
        post.category = category
        post.title = request.data["title"]
        post.image_url = request.data["image_url"]
        post.publication_date = request.data["publication_date"]
        post.content = request.data["content"]
        post.author = author
        post.selected_tags = request.data["selected_tags"]
        post.approved = request.data["approved"]
        try:
            # user_admin = User.objects.get(request.auth.user)

            if author.user.is_staff == True:
                post.approved = True
        except ValidationError as ex:
            return Response({"reason": ex.message}, status=status.HTTP_400_BAD_REQUEST)

        try:
            post.save()
            serializer = PostSerializer(post, context={'request': request})
            #iterate through the selected tags array
            for tag in post.selected_tags:
                posttag = PostTag()
                posttag.tag_id = int(tag["id"])
                posttag.post_id = int(serializer.data["id"])
                posttag.save()

            return Response(serializer.data)

        except ValidationError as ex:
            return Response({"reason": ex.message}, status=status.HTTP_400_BAD_REQUEST)

    def retrieve(self, request, pk=None):
        """ Handle Get requests for a single post
        Returns:
            Response -- JSON serialized post
    """
        try:
            post = Post.objects.get(pk=pk)
            current_user = RareUser.objects.get(user=request.auth.user)

            post.is_owner = False
            if post.author_id == current_user.id:
                post.is_owner = True

            serializer = PostSerializer(post, context={'request': request})
            return Response(serializer.data)
        except Exception as ex:
            return HttpResponseServerError(ex)

    def list(self, request):
        """ Handle GET requests to get all posts
        Returns:
            Response -- JSON serialized list of posts
        """
        posts = Post.objects.all()
        current_user = RareUser.objects.get(user=request.auth.user)

        for post in posts:
            post.is_owner = False
            if post.author_id == current_user.id:
                post.is_owner = True

        current_user = RareUser.objects.get(user=request.auth.user)

        for post in posts:
            post.is_owner = None
            if post.author_id == current_user.id:
                post.is_owner = True
            else:
                post.is_owner = False

        # if pk == "myposts":
        #     pk = current_user.id
        #     posts = posts.filter(author_id = pk)

        user_id = self.request.query_params.get('user_id', None)
        if user_id is not None:
            posts = posts.filter(author_id=user_id)

        category_id = self.request.query_params.get('category_id', None)
        if category_id is not None:
            posts = posts.filter(category_id=category_id)

        # Note the addtional `many=True` argument to the
        # serializer. It's needed when you are serializing
        # a list of objects instead of a single object.
        serializer = PostSerializer(
            posts, many=True, context={'request': request})
        return Response(serializer.data)

    def update(self, request, pk=None):
        """edits post"""

        post = Post.objects.get(pk=pk)
        category = Category.objects.get(pk=request.data["category_id"])
        post.category = category
        post.title = request.data["title"]
        post.image_url = request.data["image_url"]
        post.content = request.data["content"]
        post.selected_tags = request.data["selected_tags"]

        post.save()

        for tag in post.selected_tags:
            posttag = PostTag()
            posttag.tag_id = int(tag["id"])
            posttag.post_id = int(serializer.data["id"])
            posttag.save()

        return Response({}, status=status.HTTP_204_NO_CONTENT)

    def partial_update(self, request, pk=None):
        """partially updates post"""

        user = RareUser.objects.get(user=request.auth.user)

        post = Post.objects.get(pk=pk)
        post.approved = request.data["approved"]

        if user.user.is_staff == True:
            try:
                post.save()
                return Response({}, status=status.HTTP_204_NO_CONTENT)
            except ValidationError as ex:
                return Response({"reason": ex.message}, status=status.HTTP_400_BAD_REQUEST)

        else:
            return Response({"reason": "user is not an administrator"}, status=status.HTTP_403_FORBIDDEN)

    def destroy(self, request, pk=None):
        """Handles DELETE resquests for a post
        Returns:
            Response indicating success (200, 404 or 500 status code)
        """
        try:
            post = Post.objects.get(pk=pk)
            post.delete()

            return Response({}, status=status.HTTP_204_NO_CONTENT)

        except Post.DoesNotExist as ex:
            return Response({'message': ex.args[0]}, status=HTTP_404_NOT_FOUND)

        except Exception as ex:
            return Response({'message': ex.args[0]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @action(methods=['post','get'], detail=True)
    def react(self, request, pk):
        if request.method == "POST":

            try:
                reaction = Reaction.objects.get(pk=request.data["reaction_id"])
                reactor = RareUser.objects.get(user=request.auth.user)
                post = Post.objects.get(pk=pk)

                reactions = PostReaction.objects.get(reaction=reaction, reactor=reactor, post=post)

                reactions.delete()

                return Response({}, status=status.HTTP_204_NO_CONTENT)

            except PostReaction.DoesNotExist:
                test_reactions = PostReaction()
                test_reactions.reaction = Reaction.objects.get(pk=request.data["reaction_id"])
                reactor = RareUser.objects.get(user=request.auth.user)
                post = Post.objects.get(pk=pk)

                test_reactions.reactor = reactor
                test_reactions.post = post
                test_reactions.save()

                return Response({}, status=status.HTTP_201_CREATED)

class UserSerializer(serializers.ModelSerializer):
    """ JSON Serializer for user
    Arguments:
        serializers
    """
    class Meta:
        model = User
        fields = ('id', 'first_name', 'last_name', 'username')

class RareUserSerializer(serializers.ModelSerializer):
    """ JSON Serializer for user
    Arguments:
        serializers
    """
    user = UserSerializer(serializers.ModelSerializer)
    class Meta:
        model = RareUser
        fields = ('id', 'user')

class PostSerializer(serializers.ModelSerializer):
    """ JSON Serializer for post
    Arguments:
        serializers
    """
    author = RareUserSerializer(many=False)

    class Meta:
        model = Post
        fields = ('id', 'author', 'category', 'title', 'image_url', 'publication_date', 'content', 'approved', 'is_owner', 'author_id', 'category_id')
        depth = 1


from typing import List

import golem.model

def _repository_from_image_name(image_name: str) -> str:
    return image_name.rsplit('/', maxsplit=1)[0]

class Whitelist:

    @staticmethod
    def get_all() -> List[str]:
        return [
            whitelisted.repository for whitelisted in
            golem.model.DockerWhitelist.select().execute()
        ]

    @classmethod
    def add(cls, image_name: str) -> bool:
        """
        Returns False if the entry was already on the whitelist.
        """
        repository = _repository_from_image_name(image_name)
        if cls.is_whitelisted(repository):
            return False
        golem.model.DockerWhitelist.create(repository=repository)
        return True

    @classmethod
    def remove(cls, image_name: str) -> bool:
        """
        Return False is the entry was not present on the whitelist.
        """
        repository = _repository_from_image_name(image_name)
        if not cls.is_whitelisted(repository):
            return False
        golem.model.DockerWhitelist.delete().where(
            golem.model.DockerWhitelist.repository == repository,
        ).execute()
        return True

    @staticmethod
    def is_whitelisted(image_name: str) -> bool:
        repository = _repository_from_image_name(image_name)
        query = \
            golem.model.DockerWhitelist.select().where(
                golem.model.DockerWhitelist.repository == repository,
            )
        return query.exists()