예제 #1
0
파일: exam.py 프로젝트: PowerOfDark/Exam
    def build(self):
        # load main UI styles
        Builder.load_file(os.path.join(os.path.dirname(__file__), 'ui.kv'))

        # scrollview covering the entire window
        root = ScrollView(size_hint=(1, None),
                          size=(Window.width, Window.height))
        Window.bind(height=root.setter('height'))

        view = ExamView()
        root.add_widget(view)

        return root
예제 #2
0
파일: dev.py 프로젝트: MimTiller/Picarputer
    def menu(self):
        grid = GridLayout(cols=1, spacing='2dp', size_hint_y=None)
        content = ScrollView(size=(200, 500))
        grid.bind(minimum_height=content.setter('height'))
        grid.height = 1500
        self.options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
        for option in self.options:
            btn = Button(text=str(option), size_hint_y=None, height=50)
            grid.add_widget(btn)

        content.add_widget(grid)
        menu_sc = BoxLayout()
        menu_sc.add_widget(content)
        return menu_sc
예제 #3
0
    def build(self):
        newBidBtn = buildButton('Nieuwe bieding',
                                lambda i: self.mediator.editBidding(Bidding()),
                                size_hint=(1.0, 0.1))

        encloseLyt = BoxLayout(size_hint=(1.0, 0.85))
        scrlView = ScrollView(size_hint=(1.0, None),
                              scroll_type=['content', 'bars'],
                              bar_width='10dp')
        encloseLyt.bind(size=scrlView.setter('size'))
        listLyt = GridLayout(cols=1, spacing=10, size_hint_y=None)
        listLyt.bind(minimum_height=listLyt.setter('height'))
        keys = self.mediator.getBiddingKeys()
        for (key, name,
             contract) in reversed(keys):  # ensure most recent is at the top

            def createCallbackSelect(key):
                def cb(instance):
                    self.mediator.loadBidding(key)

                return cb

            def createCallbackDelete(key):
                def cb(instance):
                    self.mediator.deleteBidding(key)

                return cb

            def createCallbackEdit(key, name):
                def cb(instance):
                    dad = instance.parent.parent  # GridLayout -> BoxLayout
                    dad.clear_widgets()

                    def setNameCallback(instance):
                        self.mediator.changeBiddingName(key, instance.text)

                    input = buildTextInput(setNameCallback,
                                           size_hint=(0.8, 1.0))
                    input.text = name
                    dad.add_widget(input)
                    dad.add_widget(
                        buildButton('Klaar',
                                    lambda i: setNameCallback(input),
                                    size_hint=(0.2, 1.0)))

                return cb

            itemLyt = BoxLayout(orientation='horizontal',
                                size_hint=(1.0, None))

            btns = GridLayout(rows=1,
                              spacing=[gap, 0],
                              padding=[gap, 0],
                              size_hint=(0.2, 1.0))
            btns.add_widget(
                buildIconButton(iconPencil, createCallbackEdit(key, name)))
            btns.add_widget(
                buildIconButton(iconTrashcan, createCallbackDelete(key)))

            itemNameLyt = AnchorLayout()
            itemNameLyt.add_widget(buildMultilineLabel(name))
            itemLyt.add_widget(
                buildButton(itemNameLyt,
                            createCallbackSelect(key),
                            size_hint=(0.7, 1.0)))
            itemLyt.add_widget(buildText(contract, size_hint=(0.1, 1.0)))
            itemLyt.add_widget(btns)

            newBidBtn.bind(height=itemLyt.setter('height'))

            listLyt.add_widget(itemLyt)

        scrlView.add_widget(listLyt)
        encloseLyt.add_widget(scrlView)
        self.rootLayout.add_widget(encloseLyt)
        self.rootLayout.add_widget(BoxLayout(size_hint=(1.0, 0.05)))
        self.rootLayout.add_widget(newBidBtn)
예제 #4
0
class MainScreen(Screen):
    """A master layout that contains one graph and some menus.

    This contains three elements: a scrollview (containing the graph),
    a menu, and the time control panel. This class has some support methods
    for handling interactions with the menu and the character sheet,
    but if neither of those happen, the scrollview handles touches on its
    own.

    """
    manager = ObjectProperty()
    graphboards = DictProperty()
    gridboards = DictProperty()
    boardview = ObjectProperty()
    mainview = ObjectProperty()
    charmenu = ObjectProperty()
    statlist = ObjectProperty()
    statpanel = ObjectProperty()
    timepanel = ObjectProperty()
    kv = StringProperty()
    use_kv = BooleanProperty()
    play_speed = NumericProperty()
    playbut = ObjectProperty()
    portaladdbut = ObjectProperty()
    portaldirbut = ObjectProperty()
    dummyplace = ObjectProperty()
    dummything = ObjectProperty()
    dummies = ReferenceListProperty(dummyplace, dummything)
    dialoglayout = ObjectProperty()
    visible = BooleanProperty()
    _touch = ObjectProperty(None, allownone=True)
    rules_per_frame = BoundedNumericProperty(10, min=1)
    app = ObjectProperty()
    tmp_block = BooleanProperty(False)

    def on_mainview(self, *args):
        if None in (self.statpanel, self.charmenu,
                    self.app) or None in (self.app.character_name,
                                          self.charmenu.portaladdbut):
            Clock.schedule_once(self.on_mainview, 0)
            return
        self.boardview = GraphBoardView(
            scale_min=0.2,
            scale_max=4.0,
            size=self.mainview.size,
            pos=self.mainview.pos,
            board=self.graphboards[self.app.character_name],
            adding_portal=self.charmenu.portaladdbut.state == 'down')

        def update_adding_portal(*args):
            self.boardview.adding_portal = self.charmenu.portaladdbut.state == 'down'

        def update_board(*args):
            self.boardview.board = self.graphboards[self.app.character_name]

        self.mainview.bind(size=self.boardview.setter('size'),
                           pos=self.boardview.setter('pos'))
        self.charmenu.portaladdbut.bind(state=update_adding_portal)
        self.app.bind(character_name=update_board)
        self.calendar = Agenda(update_mode='present')
        self.calendar_view = ScrollView(size=self.mainview.size,
                                        pos=self.mainview.pos)
        self.gridview = GridBoardView(
            scale_min=0.2,
            scale_max=4.0,
            size=self.mainview.size,
            pos=self.mainview.pos,
            board=self.gridboards[self.app.character_name])
        self.mainview.bind(
            size=self.calendar_view.setter('size'),
            pos=self.calendar_view.setter('pos'),
        )
        self.mainview.bind(size=self.gridview.setter('size'),
                           pos=self.gridview.setter('pos'))
        self.calendar_view.add_widget(self.calendar)
        self.mainview.add_widget(self.boardview)

    def on_statpanel(self, *args):
        if not self.app:
            Clock.schedule_once(self.on_statpanel, 0)
            return
        self._update_statlist()
        self.app.bind(selected_proxy=self._update_statlist,
                      branch=self._update_statlist,
                      turn=self._update_statlist,
                      tick=self._update_statlist)

    @trigger
    def _update_statlist(self, *args):
        if not self.app.selected_proxy:
            self._update_statlist()
            return
        self.app.update_calendar(self.statpanel.statlist,
                                 past_turns=0,
                                 future_turns=0)

    def pull_visibility(self, *args):
        self.visible = self.manager.current == 'main'

    def on_manager(self, *args):
        self.pull_visibility()
        self.manager.bind(current=self.pull_visibility)

    def on_play_speed(self, *args):
        """Change the interval at which ``self.play`` is called to match my
        current ``play_speed``.

        """
        if hasattr(self, '_play_scheduled'):
            Clock.unschedule(self._play_scheduled)
        self._play_scheduled = Clock.schedule_interval(self.play,
                                                       1.0 / self.play_speed)

    def remake_display(self, *args):
        """Remake any affected widgets after a change in my ``kv``.

        """
        Builder.load_string(self.kv)
        if hasattr(self, '_kv_layout'):
            self.remove_widget(self._kv_layout)
            del self._kv_layout
        self._kv_layout = KvLayout()
        self.add_widget(self._kv_layout)

    _trigger_remake_display = trigger(remake_display)

    def on_touch_down(self, touch):
        if self.visible:
            touch.grab(self)
        for interceptor in (self.timepanel, self.charmenu, self.statpanel,
                            self.dummyplace, self.dummything):
            if interceptor.collide_point(*touch.pos):
                interceptor.dispatch('on_touch_down', touch)
                self.boardview.keep_selection = \
                    self.gridview.keep_selection = True
                return True
        if self.dialoglayout.dispatch('on_touch_down', touch):
            return True
        return self.mainview.dispatch('on_touch_down', touch)

    def on_touch_up(self, touch):
        if self.timepanel.collide_point(*touch.pos):
            return self.timepanel.dispatch('on_touch_up', touch)
        elif self.charmenu.collide_point(*touch.pos):
            return self.charmenu.dispatch('on_touch_up', touch)
        elif self.statpanel.collide_point(*touch.pos):
            return self.statpanel.dispatch('on_touch_up', touch)
        return self.mainview.dispatch('on_touch_up', touch)

    def on_dummies(self, *args):
        """Give the dummies numbers such that, when appended to their names,
        they give a unique name for the resulting new
        :class:`graph.Pawn` or :class:`graph.Spot`.

        """
        if not self.app.character:
            Clock.schedule_once(self.on_dummies, 0)
            return

        def renum_dummy(dummy, *args):
            dummy.num = dummynum(self.app.character, dummy.prefix) + 1

        for dummy in self.dummies:
            if dummy is None or hasattr(dummy, '_numbered'):
                continue
            if dummy == self.dummything:
                self.app.pawncfg.bind(imgpaths=self._propagate_thing_paths)
            if dummy == self.dummyplace:
                self.app.spotcfg.bind(imgpaths=self._propagate_place_paths)
            dummy.num = dummynum(self.app.character, dummy.prefix) + 1
            Logger.debug("MainScreen: dummy #{}".format(dummy.num))
            dummy.bind(prefix=partial(renum_dummy, dummy))
            dummy._numbered = True

    def _propagate_thing_paths(self, *args):
        # horrible hack
        self.dummything.paths = self.app.pawncfg.imgpaths

    def _propagate_place_paths(self, *args):
        # horrible hack
        self.dummyplace.paths = self.app.spotcfg.imgpaths

    def _update_from_time_travel(self, command, branch, turn, tick, result,
                                 **kwargs):
        self._update_from_delta(command, branch, turn, tick, result[-1])

    def _update_from_delta(self, cmd, branch, turn, tick, delta, **kwargs):
        self.app.branch = branch
        self.app.turn = turn
        self.app.tick = tick
        chardelta = delta.get(self.boardview.board.character.name, {})
        for unwanted in ('character_rulebook', 'avatar_rulebook',
                         'character_thing_rulebook',
                         'character_place_rulebook',
                         'character_portal_rulebook'):
            if unwanted in chardelta:
                del chardelta[unwanted]
        self.boardview.board.trigger_update_from_delta(chardelta)
        self.gridview.board.trigger_update_from_delta(chardelta)
        self.statpanel.statlist.mirror = dict(self.app.selected_proxy)

    def play(self, *args):
        """If the 'play' button is pressed, advance a turn.

        If you want to disable this, set ``engine.universal['block'] = True``

        """
        if self.playbut.state == 'normal':
            return
        self.next_turn()

    def _update_from_next_turn(self, command, branch, turn, tick, result):
        todo, deltas = result
        if isinstance(todo, list):
            self.dialoglayout.todo = todo
            self.dialoglayout.idx = 0
        self._update_from_delta(command, branch, turn, tick, deltas)
        self.dialoglayout.advance_dialog()
        self.app.bind(branch=self.app._push_time,
                      turn=self.app._push_time,
                      tick=self.app._push_time)
        self.tmp_block = False

    def next_turn(self, *args):
        """Advance time by one turn, if it's not blocked.

        Block time by setting ``engine.universal['block'] = True``"""
        if self.tmp_block:
            return
        eng = self.app.engine
        dial = self.dialoglayout
        if eng.universal.get('block'):
            Logger.info(
                "MainScreen: next_turn blocked, delete universal['block'] to unblock"
            )
            return
        if dial.idx < len(dial.todo):
            Logger.info(
                "MainScreen: not advancing time while there's a dialog")
            return
        self.tmp_block = True
        self.app.unbind(branch=self.app._push_time,
                        turn=self.app._push_time,
                        tick=self.app._push_time)
        eng.next_turn(cb=self._update_from_next_turn)

    def switch_to_calendar(self, *args):
        self.app.update_calendar(self.calendar)
        self.mainview.clear_widgets()
        self.mainview.add_widget(self.calendar_view)

    def switch_to_boardview(self, *args):
        self.mainview.clear_widgets()
        self.app.engine.handle('apply_choices',
                               choices=[self.calendar.get_track()])
        self.mainview.add_widget(self.boardview)

    def toggle_gridview(self, *args):
        if self.gridview in self.mainview.children:
            self.mainview.clear_widgets()
            self.mainview.add_widget(self.boardview)
        else:
            self.mainview.clear_widgets()
            self.mainview.add_widget(self.gridview)

    def toggle_calendar(self, *args):
        # TODO decide how to handle switching between >2 view types
        if self.boardview in self.mainview.children:
            self.switch_to_calendar()
        else:
            self.switch_to_boardview()
예제 #5
0
class MessageWidget(BoxLayout):
    def __init__(self, *args, **kwargs):
        super(MessageWidget, self).__init__(*args, **kwargs)
        self.orientation = 'vertical'
        self.master_layout = ScrollView(size_hint=(1, 1))
        self.master_layout.bind(size=self.master_layout.setter('size'))
        self.message_layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
        self.message_layout.bind(
            minimum_height=self.message_layout.setter('height'))
        self.sub_layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
        self.sub_layout.bind(minimum_height=self.sub_layout.setter('height'))
        bkgrnd_color = (0, 0, 0, 1)
        self.set_background(self, bkgrnd_color)
        self.users = {}
        self.logger = logging.getLogger("kivy.operator.widgets.messaging")
        self.messages = defaultdict(list)
        Window.softinput_mode = 'pan'
        self.chatting = None
        self.reply = TextInput()
        self.main_app = App.get_running_app()
        self.check_xmpp()
        self.new_lab = Label()
        self.new = False

    def set_background(self, layout, color):
        """
		Sets a solid color as a background.

		:param layout: The layout for whichever part of the screen should be set.
		"""
        layout.bind(size=self._update_rect, pos=self._update_rect)

        with layout.canvas.before:
            Color(1, 1, 1, 1)
            self.rect = Rectangle(size=layout.size, pos=layout.pos)

    def _update_rect(self, instance, value):
        """
		Ensures that the canvas fits to the screen should the layout ever change.
		"""
        self.rect.pos = instance.pos
        self.rect.size = instance.size

    def redraw(self, event, args):
        """
		Binds the size of the label background to the label size.
		"""
        event.bg_rect.size = event.size
        event.bg_rect.pos = event.pos

    def get_users(self):
        """
		Pulls the list of users on the XMPP server.
		"""
        users = self.main_app.get_users()
        self.users = {}

        for user in users:
            self.users[user.split('@')[0]] = user

        self.users['Operator Group'] = '*****@*****.**'
        self.main_app.xmpp_log('info', 'updating user list')

        if not self.chatting:
            self.gen_menu()

    @run_on_ui_thread
    def check_xmpp(self):
        """
		Check if xmpp is enabled.
		"""
        if self.main_app.xmpp_config_ok:
            self.gen_menu()
        else:
            self.disabled_menu()

    def disabled_menu(self):
        """
		Creates a disabled messaging menu should xmpp be disabled.
		"""
        self.clear_widgets()
        sub_layout = BoxLayout(size_hint=(1, 1))
        sub_layout.clear_widgets()
        lab = Label(text='XMPP messaging is disabled due to config errors!',
                    size_hint=(1, 1),
                    markup=True)
        lab.color = colorsys.hsv_to_rgb(0, 0, 1)

        with lab.canvas.before:
            Color(1, 1, 0, mode='hsv')
            lab.bg_rect = Rectangle(pos=self.pos, size=self.size)

        lab.bind(pos=self.redraw, size=self.redraw)
        sub_layout.add_widget(lab)
        self.add_widget(sub_layout)

    def gen_menu(self):
        """
		Creates the base menu which displays all users.
		"""
        self.chatting = None
        self.clear_widgets()
        self.master_layout.clear_widgets()
        self.message_layout.clear_widgets()
        sub_layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
        sub_layout.bind(minimum_height=sub_layout.setter('height'))
        sub_layout.clear_widgets()
        names = []

        for user in self.users:
            names.append(user)

        names.sort()
        op_chat = Button(text='Group Chat: OPERATOR',
                         size_hint_y=None,
                         height=180,
                         color=[0, 0, 0, 1],
                         on_release=functools.partial(self.chat_panel,
                                                      'Operator Group'),
                         background_normal='',
                         background_color=[.5, 1, .5, 1])
        sub_layout.add_widget(op_chat)

        for name in names:
            lab = Button(text=name,
                         size_hint_y=None,
                         height=100,
                         color=[1, 1, 1, 1],
                         on_release=functools.partial(self.chat_panel, name),
                         background_normal='',
                         background_color=[0, .3, .3, 1])
            sub_layout.add_widget(lab)

        refresh = Button(text="Refresh Users",
                         size_hint_y=None,
                         on_release=lambda x: self.get_users(),
                         height=180,
                         color=[0, 0, 0, 1],
                         background_normal='',
                         background_color=[0, 1, 0, 1])
        self.message_layout.add_widget(refresh)
        self.message_layout.add_widget(sub_layout)
        self.master_layout.add_widget(self.message_layout)
        self.add_widget(self.master_layout)

    def on_message_receive(self, msg):
        """
		Whenever a message is received, it is processed according to whatever the user is currently doing.

		:param Message msg: The XMPP message object.
		"""
        sender = str(msg['from']).strip()
        text = str(msg['body']).strip()
        chk_sender = sender.split('@')[0]

        if self.chatting == chk_sender:
            lab = Label(text=chk_sender + ": " + text,
                        size_hint_y=None,
                        markup=True,
                        halign='left')

            lab.bind(width=lambda s, w: s.setter('text_size')(s, (w, None)))
            lab.bind(texture_size=lab.setter('size'))

            lab.color = colorsys.hsv_to_rgb(self.name_to_txt(chk_sender), 1, 1)

            with lab.canvas.before:
                Color(name_to_bg(chk_sender), 1, 1, mode='hsv')
                lab.bg_rect = Rectangle(pos=self.pos, size=self.size)

            lab.bind(pos=self.redraw, size=self.redraw)
            self.sub_layout.add_widget(lab)

            if self.new:
                self.sub_layout.remove_widget(self.new_lab)
                self.new = False
        else:
            if self.main_app.toast_all:
                toast(chk_sender + ": " + text, True)
                vibrator.vibrate(.1)

        if sender.split('/')[0] in self.messages:
            self.main_app.xmpp_log('info',
                                   'receiving new message from ' + sender)
        else:
            self.main_app.xmpp_log('info',
                                   'receiving first message from ' + sender)

        m = Message(sender.split('@')[0], text)
        self.messages[sender.split('/')[0]].append(m)

    def on_muc_receive(self, msg):
        """
		Whenever a group message is received, it is processed according to whatever the user is
		currently doing.

		:param Message msg: The XMPP message object.
		"""
        sender = str(msg['from']).strip()
        text = str(msg['body']).strip()

        if self.chatting == "Operator Group":
            lab = Label(text=sender.split('/')[1] + ": " + text,
                        size_hint_y=None,
                        markup=True,
                        halign='left')

            lab.bind(width=lambda s, w: s.setter('text_size')(s, (w, None)))
            lab.bind(texture_size=lab.setter('size'))

            lab.color = colorsys.hsv_to_rgb(
                self.name_to_txt(sender.split('/')[1]), 1, 1)

            with lab.canvas.before:
                Color(name_to_bg(sender.split('/')[1]), 1, 1, mode='hsv')
                lab.bg_rect = Rectangle(pos=self.pos, size=self.size)

            lab.bind(pos=self.redraw, size=self.redraw)
            self.sub_layout.add_widget(lab)

            if self.new:
                self.sub_layout.remove_widget(self.new_lab)
                self.new = False

        else:
            toast(sender.split('/')[1] + ": " + text, True)
            vibrator.vibrate(.1)

        if sender.split('/')[0] in self.messages:
            self.main_app.xmpp_log('info',
                                   'receiving new message from ' + sender)
        else:
            self.main_app.xmpp_log('info',
                                   'receiving first message from ' + sender)

        m = Message(sender.split('/')[1], text)
        self.messages[sender.split('/')[0]].append(m)

    def chat_panel(self, user, event):
        """
		Creates the actual chat screen where the messages are displayed and where the user can respond.

		:param str user: The username of whomever the user is chatting with.
		"""

        full_name = self.users[user]
        self.chatting = user
        self.clear_widgets()
        self.master_layout.clear_widgets()
        self.message_layout.clear_widgets()
        self.sub_layout.clear_widgets()

        if full_name in self.messages:
            self.new = False
            temp = self.messages[full_name]
            for msg in temp:
                if not msg.sender:
                    lab = Label(text=msg.body,
                                color=(1, 1, 1, 1),
                                size_hint_y=None,
                                markup=True,
                                halign='right')

                    with lab.canvas.before:
                        Color(.67, .82, 1, mode='hsv')
                        lab.bg_rect = Rectangle(pos=self.pos, size=self.size)

                else:
                    lab = Label(text=msg.sender + ": " + msg.body,
                                color=(0, 0, 0, 1),
                                size_hint_y=None,
                                markup=True,
                                halign='left')
                    lab.color = colorsys.hsv_to_rgb(
                        self.name_to_txt(msg.sender), 1, 1)

                    with lab.canvas.before:
                        Color(name_to_bg(msg.sender), 1, 1, mode='hsv')
                        lab.bg_rect = Rectangle(pos=self.pos, size=self.size)

                lab.bind(
                    width=lambda s, w: s.setter('text_size')(s, (w, None)))
                lab.bind(texture_size=lab.setter('size'))
                lab.bind(pos=self.redraw, size=self.redraw)
                self.sub_layout.add_widget(lab)

        else:
            self.new_lab = Label(text="Start a new conversation with " + user +
                                 "!",
                                 color=(0, 0, 0, 1))
            self.new = True
            self.sub_layout.add_widget(self.new_lab)

        bottom = BoxLayout(size_hint_y=None, height=130)
        self.reply = TextInput(hint_text="Write a message...")
        title = Label(text=user, halign='left', color=(0, 0, 0, 1))

        send = Button(text="Send",
                      size_hint_x=.25,
                      on_release=functools.partial(self.send_message,
                                                   full_name))
        bottom.add_widget(self.reply)
        bottom.add_widget(send)
        header = BoxLayout(size_hint_y=None, height=130)
        back_btn = Button(text='< Recent',
                          size_hint_x=.5,
                          on_release=lambda x: self.gen_menu())
        presence = Label(size_hint_x=.3)
        header.add_widget(back_btn)
        header.add_widget(title)
        header.add_widget(presence)
        self.message_layout.add_widget(self.sub_layout)
        self.master_layout.add_widget(self.message_layout)
        self.add_widget(header)
        self.add_widget(self.master_layout)
        self.add_widget(bottom)

    def send_message(self, user, event):
        """
		When the user hits the reply button, it sends the message back to the user (or group if it is
		a groupchat).

		:param str user: The username of whomever the user is chatting with.
		"""
        msg = self.reply.text

        if msg:
            if user == self.users['Operator Group']:
                self.main_app.send_muc(msg, user)
            else:
                self.main_app.send_message(msg, user)

            m = Message(None, msg)
            self.messages[user].append(m)

            lab = Label(text=msg,
                        size_hint_y=None,
                        color=(1, 1, 1, 1),
                        markup=True,
                        halign='right')
            lab.bind(width=lambda s, w: s.setter('text_size')(s, (w, None)))
            lab.bind(texture_size=lab.setter('size'))

            with lab.canvas.before:
                Color(.67, .82, 1, mode='hsv')
                lab.bg_rect = Rectangle(pos=self.pos, size=self.size)

            lab.bind(pos=self.redraw, size=self.redraw)
            self.sub_layout.add_widget(lab)
            self.reply.text = ""

            if self.new:
                self.sub_layout.remove_widget(self.new_lab)
                self.new = False

    def name_to_txt(self, data):
        """
		Finds the corresponding text color to the background color.

		:param str data: The same string that is used for the background color.
		"""
        rem = name_to_bg(data)
        dis = rem + 0.5

        if dis > 1:
            dis = dis - 1

        return dis