Пример #1
0
    def test_receive_get_log_success(self):
        program_status = ProgramStatusFactory(running=True)
        program = program_status.program

        error_status = Status.ok({
            'method': 'get_log',
            'result': {
                'log': 'this is the content of a logfile',
                'uuid': program_status.command_uuid,
            },
        })

        #  connect webinterface
        webinterface = WSClient()
        webinterface.join_group('notifications')

        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': error_status.to_json()},
        )

        #  test if the webinterface gets the error message
        self.assertEqual(
            Status.ok({
                'log': 'this is the content of a logfile',
                'pid': str(program.id),
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )
Пример #2
0
    def test_receive_online_success(self):
        slave = SlaveOnlineFactory(online=False)

        expected_status = Status.ok({'method': 'online'})
        expected_status.uuid = slave.command_uuid

        # connect webinterface on /notifications
        webinterface = WSClient()
        webinterface.join_group('notifications')

        # send online answer
        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': expected_status.to_json()},
        )

        self.assertTrue(SlaveModel.objects.get(id=slave.id).is_online)

        # test if a connected message was send on /notifications
        self.assertEqual(
            Status.ok({
                'slave_status': 'connected',
                'sid': str(slave.id),
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )
Пример #3
0
    def test_receive_filesystem_restore_success(self):
        filesystem = MovedFileFactory()

        error_status = Status.ok({
            'method': 'filesystem_restore',
            'result': None,
        })

        error_status.uuid = filesystem.command_uuid

        #  connect webinterface
        webinterface = WSClient()
        webinterface.join_group('notifications')

        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': error_status.to_json()},
        )

        query = FilesystemModel.objects.get(id=filesystem.id)
        self.assertEqual(query.hash_value, "")
        self.assertEqual(query.error_code, "")

        self.assertEqual(
            Status.ok({
                'filesystem_status': 'restored',
                'fid': str(filesystem.id),
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )
Пример #4
0
    def test_receive_execute_success(self):
        program_status = ProgramStatusFactory(running=True)
        program = program_status.program

        expected_status = Status.ok({'method': 'execute', 'result': 0})
        expected_status.uuid = program_status.command_uuid

        #  connect webinterface
        webinterface = WSClient()
        webinterface.send_and_consume(
            'websocket.connect',
            path='/notifications',
        )

        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': expected_status.to_json()},
        )

        query = ProgramStatusModel.objects.filter(program=program, code=0)
        self.assertTrue(query.count() == 1)
        self.assertFalse(query.first().running)

        #  test if the webinterface gets the "finished" message
        self.assertEqual(
            Status.ok({
                'program_status': 'finished',
                'pid': str(program.id),
                'code': 0,
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )
Пример #5
0
    def test_receive_chain_commands_success(self):
        filesystem = FileFactory()

        moved = MovedFileFactory.build()

        error_status1 = Status.ok({
            'method': 'filesystem_move',
            'result': moved.hash_value,
        })
        error_status1.uuid = filesystem.command_uuid

        error_status2 = Status.ok({
            'method': 'filesystem_move',
            'result': moved.hash_value,
        })
        error_status2.uuid = filesystem.command_uuid

        error_chain = Status.ok({
            'method':
            'chain_execution',
            'result': [dict(error_status1),
                       dict(error_status2)],
        })

        #  connect webinterface
        webinterface = WSClient()
        webinterface.join_group('notifications')

        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': error_chain.to_json()},
        )

        query = FilesystemModel.objects.get(id=filesystem.id)
        self.assertEqual(query.hash_value, moved.hash_value)
        self.assertEqual(query.error_code, "")

        self.assertEqual(
            Status.ok({
                'filesystem_status': 'moved',
                'fid': str(filesystem.id),
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )

        self.assertEqual(
            Status.ok({
                'filesystem_status': 'moved',
                'fid': str(filesystem.id),
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )

        self.assertIsNone(webinterface.receive())
Пример #6
0
    def test_receive_execute_slave_not_exists(self):
        program_status = ProgramStatusFactory(running=True)
        program = program_status.program

        expected_status = Status.ok({'method': 'execute', 'result': 0})
        expected_status.uuid = program_status.command_uuid

        #  connect webinterface
        webinterface = WSClient()
        webinterface.send_and_consume(
            'websocket.connect',
            path='/notifications',
        )

        program.delete()

        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': expected_status.to_json()},
        )

        self.assertFalse(
            ProgramStatusModel.objects.filter(program=program).exists())

        #  test if the webinterface gets the "finished" message
        self.assertIsNone(webinterface.receive())
Пример #7
0
    def test_rpc_method_cancel_method(self):  # pylint: disable=R0201
        """
        Tests what happens if you cancel a running method
        """
        @Rpc.method
        @asyncio.coroutine
        def sleep(sec):  # pylint: disable=R0201,W0612
            """
            Simple async rpc function, that raises an Exception.
            """
            try:
                yield from asyncio.sleep(sec)
            except asyncio.CancelledError:
                return -15

        sleep_cmd = Command(method='sleep', sec=1)
        cancel_cmd = Command(method='sleep')
        cancel_cmd.uuid = sleep_cmd.uuid
        status = Status.ok({'method': 'sleep', 'result': -15})
        status.uuid = sleep_cmd.uuid

        Server(
            [
                sleep_cmd.to_json(),
                cancel_cmd.to_json(),
            ],
            [
                status.to_json(),
            ],
        ).run()
Пример #8
0
    def test_receive_execute_with_error_status(self):
        program_status = ProgramStatusFactory(running=True)
        program = program_status.program

        error_status = Status.err({
            'method': 'execute',
            'result': str(Exception('foobar')),
        })
        error_status.uuid = program_status.command_uuid

        #  connect webinterface
        webinterface = WSClient()
        webinterface.join_group('notifications')

        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': error_status.to_json()},
        )

        query = ProgramStatusModel.objects.get(program=program)
        self.assertFalse(query.running)
        self.assertEqual(query.code, 'foobar')

        #  test if the webinterface gets the error message
        self.assertEqual(
            Status.ok({
                'program_status': 'finished',
                'pid': str(program.id),
                'code': 'foobar',
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )
Пример #9
0
    def test_math_add(self):  # pylint: disable=R0201
        """
        Testing simple math add function with async features.
        """
        @Rpc.method
        def math_add(integer1, integer2):  # pylint: disable=R0201,W0612
            """
            Simple add function with async.

            Arguments
            ---------
                integer1: first operand
                integer2: second operand
            """
            res = (integer1 + integer2)
            return res

        cmd = Command("math_add", integer1=1, integer2=2)
        status = Status.ok({'method': 'math_add', 'result': 3})
        status.uuid = cmd.uuid

        Server(
            [
                cmd.to_json(),
            ],
            [
                status.to_json(),
            ],
        ).run()
Пример #10
0
def filesystem_restore(request, filesystem_id):
    """
    Processes an method invocation (restore) for an `FilesystemModel`. (see
    @frontend.controller.filesystem_restore)

    HTTP Methods
    ------------
        POST:
            Invokes the method for the `FilesystemModel` (which is
            specified in the URL).

    Parameters
    ----------
        request: HttpRequest
            The request which should be processed.

    Returns
    -------
        HttpResponse:
            If the HTTP method is not supported, then an
            `HttpResponseForbidden` is returned.
    """
    if request.method == 'POST':
        try:
            filesystem = FilesystemModel.objects.get(id=filesystem_id)
            try:
                fs_restore(filesystem)
                return StatusResponse(Status.ok(""))
            except FsimError as err:
                return StatusResponse(err)
        except FilesystemModel.DoesNotExist as err:
            return StatusResponse(FilesystemNotExistError(err, filesystem_id))
    else:
        return HttpResponseForbidden()
Пример #11
0
    def test_receive_get_log_program_not_exists(self):
        error_status = Status.ok({
            'method': 'get_log',
            'result': {
                'log': '',
                'uuid': '0'
            },
        })

        #  connect webinterface
        webinterface = WSClient()
        webinterface.join_group('notifications')

        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': error_status.to_json()},
        )

        #  test if the webinterface gets the error message
        self.assertEqual(
            Status.err('Received log from unknown program!'),
            Status.from_json(json.dumps(webinterface.receive())),
        )
Пример #12
0
    def test_state_init(self):
        webinterface = WSClient()
        webinterface.join_group('notifications')

        ScriptModel.objects.filter(id=self.script.id).update(
            is_running=True,
            is_initialized=True,
            current_index=-1,
        )

        self.sched._Scheduler__index = -1
        self.sched._Scheduler__script = self.script.id
        self.sched._Scheduler__event = asyncio.Event(loop=self.sched.loop)
        self.sched._Scheduler__state = SchedulerStatus.INIT

        self.sched._Scheduler__state_init()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.WAITING_FOR_SLAVES,
        )

        msg1 = Status.from_json(json.dumps(webinterface.receive()))
        msg2 = Status.from_json(json.dumps(webinterface.receive()))
        msg3 = Status.from_json(json.dumps(webinterface.receive()))

        expct1 = Status.ok({
            'script_status': 'waiting_for_slaves',
            'script_id': self.script.id,
        })
        expct2 = Status.ok({
            'message':
            "Send start command to client `{}`".format(self.prog1.slave.name),
        })
        expct3 = Status.ok({
            'message':
            "Send start command to client `{}`".format(self.prog2.slave.name),
        })

        self.assertStatusSet(
            [msg1, msg2, msg3],
            [expct1, expct2, expct3],
        )
Пример #13
0
    def test_receive_unknown_message_type(self):
        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': Status.ok({
                'method': ''
            }).to_json()},
        )

        self.assertIsNone(ws_client.receive())
Пример #14
0
def notify(message):
    """
    Sending the given `message` to the notification channel, inidcating that
    the message is not an error.

    Parameters
    ----------
        message: JSON object
            This message is send to the web interface with an Status.ok()
            wrapped around.
    """
    Group('notifications').send({'text': Status.ok(message).to_json()})
Пример #15
0
    def test_connect_and_disconnect_success(self):
        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.connect',
            path='/notifications',
        )

        #  test if ws_client is part of 'notifications'
        Group('notifications').send({'text': Status.ok('').to_json()})
        self.assertEqual(
            Status.ok(''),
            Status.from_json(json.dumps(ws_client.receive())),
        )

        ws_client.send_and_consume(
            'websocket.disconnect',
            path='/notifications',
        )

        #  test if ws_client was removed from 'notifications'
        Group('notifications').send({'text': Status.ok('').to_json()})
        self.assertIsNone(ws_client.receive())
Пример #16
0
    def enable_remote(self):
        """
        Enables remote logging to the websocket located on 'self.__url'. First
        the existing log gets send, then updates follow on every request
        (an empty message)by the receiver.
        """
        with self.__lock:
            self.__ws_connection = yield from websockets.connect(self.__url)
            log = self.__log_file.read()
            msg = {'log': log.decode(), 'pid': self.__pid_on_master}

        yield from self.__ws_connection.send(Status.ok(msg).to_json())
        yield from self.__ws_connection.recv()

        while True:
            yield from self.__ws_buffer_has_content.wait()

            with self.__lock:
                msg = {
                    'log': self.__ws_buffer.decode(),
                    'pid': self.__pid_on_master
                }
                self.__ws_buffer = b''
                self.__ws_buffer_has_content.clear()

            try:
                yield from self.__ws_connection.send(Status.ok(msg).to_json())
                yield from self.__ws_connection.recv()
            except websockets.exceptions.ConnectionClosed:
                break

            if msg['log'] == b''.decode():
                break

            # if the stream from tee has finished the buffer gets send and
            # cleared in the next iterations which terminates the loop
            if self.__ws_finished:
                self.__ws_buffer_has_content.set()
Пример #17
0
    def ok(cls, payload, **kwargs):
        """
        Shorthand for StatusResponse(Status.ok(payload))

        Arguments
        ---------
            payload: Payload for Status object
            **kwargs: arguments for HttpResponse

        Returns
        -------
            StatusResponse object with 'ok' in Status
        """
        return cls(Status.ok(payload), **kwargs)
Пример #18
0
    def test_receive_filesystem_restore_filesystem_not_exists(self):
        webinterface = WSClient()
        webinterface.join_group('notifications')

        error_status = Status.ok({
            'method': 'filesystem_restore',
            'result': None,
        })

        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': error_status.to_json()},
        )

        self.assertIsNone(webinterface.receive())
Пример #19
0
    def test_disconnect_success(self):
        slave = SlaveOnlineFactory()

        program_status = ProgramStatusFactory(program__slave=slave)
        program = program_status.program

        # connect client on /commands
        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.connect',
            path='/commands',
            content={'client': [slave.ip_address, slave.mac_address]})

        # connect webinterface on /notifications
        webinterface = WSClient()
        webinterface.send_and_consume(
            'websocket.connect',
            path='/notifications',
        )

        #  throw away connect repsonse
        ws_client.receive()
        ws_client.send_and_consume('websocket.disconnect', path='/commands')

        #  test if SlaveStatus was to offline
        self.assertFalse(SlaveModel.objects.get(id=slave.id).is_online)

        Group('client_{}'.format(slave.id)).send(
            {'text': 'ok'},
            immediately=True,
        )
        self.assertIsNone(ws_client.receive())

        #  test if program status was removed
        self.assertFalse(
            ProgramStatusModel.objects.filter(program=program).exists())

        #  test if a "disconnected" message has been send to the webinterface
        self.assertEqual(
            Status.ok({
                'slave_status': 'disconnected',
                'sid': str(slave.id)
            }), Status.from_json(json.dumps(webinterface.receive())))
Пример #20
0
    def test_state_success(self):
        webinterface = WSClient()
        webinterface.join_group('notifications')

        self.sched._Scheduler__event = asyncio.Event(loop=self.sched.loop)
        self.sched._Scheduler__script = self.script.id
        self.sched._Scheduler__state = SchedulerStatus.SUCCESS
        self.sched._Scheduler__state_success()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.SUCCESS,
        )

        self.assertEqual(
            Status.ok({
                'script_status': 'success',
                'script_id': self.script.id,
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )
Пример #21
0
    def test_state_next_offline_program(self):
        webinterface = WSClient()
        webinterface.join_group('notifications')

        self.slave1.online = True
        self.slave1.save()

        self.sched._Scheduler__index = -1
        self.sched._Scheduler__event = asyncio.Event(loop=self.sched.loop)
        self.sched._Scheduler__script = self.script.id
        self.sched._Scheduler__state = SchedulerStatus.NEXT_STEP
        self.sched._Scheduler__state_next()

        self.assertEqual(
            Status.ok({
                'program_status': 'started',
                'pid': self.prog1.id,
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.WAITING_FOR_PROGRAMS_FILESYSTEMS,
        )

        self.sched._Scheduler__state = SchedulerStatus.NEXT_STEP
        self.sched._Scheduler__state_next()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.ERROR,
        )

        self.assertStatusRegex(
            Status.err(SlaveOfflineError),
            Status.err(self.sched._Scheduler__error_code),
        )
Пример #22
0
    def test_connect_and_disconnect_success(self):
        webinterface = WSClient()
        webinterface.join_group('notifications')

        ws_client = WSClient()
        ws_client.send_and_consume('websocket.connect', path='/logs')
        self.assertIsNone(ws_client.receive())

        msg = Status.ok({
            'log':
            ''.join([
                choice(string.ascii_letters + string.digits)
                for _ in range(500)
            ]),
            'pid':
            choice(string.digits)
        })

        ws_client.send_and_consume('websocket.receive',
                                   path='/logs',
                                   content={'text': msg.to_json()})
        self.assertEqual(msg,
                         Status.from_json(json.dumps(webinterface.receive())))
Пример #23
0
    def test_state_error(self):
        webinterface = WSClient()
        webinterface.join_group('notifications')

        self.sched._Scheduler__event = asyncio.Event(loop=self.sched.loop)
        self.sched._Scheduler__script = self.script.id
        self.sched._Scheduler__error_code = "Wow an error occurred."
        self.sched._Scheduler__state = SchedulerStatus.ERROR
        self.sched._Scheduler__state_error()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.ERROR,
        )

        self.assertEqual(
            Status.ok({
                'script_status': 'error',
                'error_code': 'Wow an error occurred.',
                'script_id': self.script.id,
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )
Пример #24
0
    def test_error_close(self):  # pylint: disable=R0201
        """
        Tests if RPC-Receiver doesn't raise an exception if closed during execution.
        """
        @Rpc.method
        @asyncio.coroutine
        def async_sleep():  # pylint: disable=R0201,W0612
            """
            Simple function that sleeps.
            """
            yield from asyncio.sleep(10)

        cmd = Command("async_sleep", integer1=1, integer2=2)
        status = Status.ok({'method': 'async_sleep', 'result': ''})
        status.uuid = cmd.uuid

        CloseFailServer(
            [
                cmd.to_json(),
            ],
            [
                status.to_json(),
            ],
        ).run()
Пример #25
0
    def test_receive_online_slave_not_exists(self):
        slave = SlaveOnlineFactory(online=False)

        expected_status = Status.ok({'method': 'online'})
        expected_status.uuid = slave.command_uuid

        # connect webinterface on /notifications
        webinterface = WSClient()
        webinterface.join_group('notifications')

        slave.delete()

        # send online answer
        ws_client = WSClient()
        ws_client.send_and_consume(
            'websocket.receive',
            path='/commands',
            content={'text': expected_status.to_json()},
        )

        self.assertFalse(SlaveModel.objects.filter(id=slave.id).exists())

        # test if a connected message was send on /notifications
        self.assertIsNone(webinterface.receive())
Пример #26
0
    def test_state_next_finished(self):
        webinterface = WSClient()
        webinterface.join_group('notifications')

        self.slave1.online = True
        self.slave1.save()
        self.slave2.online = True
        self.slave2.save()

        ProgramStatusModel.objects.create(program=self.prog1,
                                          code='0',
                                          command_uuid='0',
                                          start_time=now())

        self.sched._Scheduler__index = -1
        self.sched._Scheduler__event = asyncio.Event(loop=self.sched.loop)
        self.sched._Scheduler__script = self.script.id
        self.sched._Scheduler__state = SchedulerStatus.NEXT_STEP
        self.sched._Scheduler__state_next()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.WAITING_FOR_PROGRAMS_FILESYSTEMS,
        )

        if self.prog1.start_time > 0:
            start_time = self.prog1.start_time
        else:
            start_time = 0

        msg1 = Status.from_json(json.dumps(webinterface.receive()))

        expct1 = Status.ok({
            'script_status': 'next_step',
            'index': 0,
            'last_index': -1,
            'start_time': start_time,
            'script_id': self.script.id,
        })

        self.assertStatusSet([msg1], [expct1])

        ProgramStatusModel.objects.create(program=self.prog2,
                                          code='0',
                                          command_uuid='1',
                                          start_time=now())

        self.sched._Scheduler__state = SchedulerStatus.NEXT_STEP
        self.sched._Scheduler__state_next()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.WAITING_FOR_PROGRAMS_FILESYSTEMS,
        )

        if self.prog2.start_time > 0:
            start_time = self.prog2.start_time
        else:
            start_time = 0

        msg1 = Status.from_json(json.dumps(webinterface.receive()))

        expct1 = Status.ok({
            'script_status': 'next_step',
            'index': 2,
            'last_index': 0,
            'start_time': start_time,
            'script_id': self.script.id,
        })

        self.assertStatusSet([msg1], [expct1])

        self.sched._Scheduler__state = SchedulerStatus.NEXT_STEP
        self.sched._Scheduler__state_next()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.SUCCESS,
        )

        self.assertEqual(
            Status.ok({
                'script_status': 'next_step',
                'index': -1,
                'last_index': 2,
                'start_time': 0,
                'script_id': self.script.id,
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )
Пример #27
0
    def test_state_next(self):
        webinterface = WSClient()
        webinterface.join_group('notifications')

        self.slave1.online = True
        self.slave1.save()
        self.slave2.online = True
        self.slave2.save()

        self.sched._Scheduler__index = -1
        self.sched._Scheduler__event = asyncio.Event(loop=self.sched.loop)
        self.sched._Scheduler__script = self.script.id
        self.sched._Scheduler__state = SchedulerStatus.NEXT_STEP
        self.sched._Scheduler__state_next()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.WAITING_FOR_PROGRAMS_FILESYSTEMS,
        )

        if self.prog1.start_time > 0:
            start_time = self.prog1.start_time
        else:
            start_time = 0

        msg1 = Status.from_json(json.dumps(webinterface.receive()))
        msg2 = Status.from_json(json.dumps(webinterface.receive()))

        expct1 = Status.ok({
            'script_status': 'next_step',
            'index': 0,
            'last_index': -1,
            'start_time': start_time,
            'script_id': self.script.id,
        })

        expct2 = Status.ok({
            'program_status': 'started',
            'pid': self.prog1.id,
        })

        self.assertStatusSet([msg1, msg2], [expct1, expct2])

        self.sched._Scheduler__state = SchedulerStatus.NEXT_STEP
        self.sched._Scheduler__state_next()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.WAITING_FOR_PROGRAMS_FILESYSTEMS,
        )

        if self.prog2.start_time > 0:
            start_time = self.prog2.start_time
        else:
            start_time = 0

        msg1 = Status.from_json(json.dumps(webinterface.receive()))
        msg2 = Status.from_json(json.dumps(webinterface.receive()))

        expct1 = Status.ok({
            'script_status': 'next_step',
            'index': 2,
            'last_index': 0,
            'start_time': start_time,
            'script_id': self.script.id,
        })

        expct2 = Status.ok({
            'program_status': 'started',
            'pid': self.prog2.id,
        })

        self.assertStatusSet([msg1, msg2], [expct1, expct2])

        self.sched._Scheduler__state = SchedulerStatus.NEXT_STEP
        self.sched._Scheduler__state_next()

        self.assertEqual(
            self.sched._Scheduler__state,
            SchedulerStatus.SUCCESS,
        )

        self.assertEqual(
            Status.ok({
                'script_status': 'next_step',
                'index': -1,
                'last_index': 2,
                'start_time': 0,
                'script_id': self.script.id,
            }),
            Status.from_json(json.dumps(webinterface.receive())),
        )