Esempio n. 1
0
def goToState0(p, **kwargs):
    input = kwargs['input'] if 'input' in kwargs.keys() else None
    giveInstruction = input is None
    if giveInstruction:
        reply_txt = 'Hi {}, press *{}* or *{}* if you want to play!'.format(
            p.getName(), BUTTON_SYNONIM_GAME, BUTTON_INTRUDER_GAME)

        kb = [[BUTTON_SYNONIM_GAME], [BUTTON_INTRUDER_GAME], [BUTTON_INFO]]

        tell(p.chat_id, reply_txt, kb)
    else:
        if input == '':
            tell(p.chat_id, "Not a valid input.")
        elif input == BUTTON_SYNONIM_GAME:
            first_time_instructions = utility.unindent("""
                Let’s train your vocabulary! Can you find a word with the same meaning?
                You will see a series of sentences with certain words highlighted.
                Which words describe the highlighted parts best?
                """)
            tell(p.chat_id, first_time_instructions)
            sendWaitingAction(p.chat_id, sleep_time=1)
            redirectToState(p, 1)
        elif input == BUTTON_INTRUDER_GAME:
            first_time_instructions = utility.unindent("""
                Let’s find the intruder! 🐸
                """)
            tell(p.chat_id, first_time_instructions)
            sendWaitingAction(p.chat_id, sleep_time=1)
            redirectToState(p, 2)
        elif input == BUTTON_INFO:
            tell(p.chat_id, INFO_TEXT)
        else:
            tell(
                p.chat_id, FROWNING_FACE +
                " Sorry, I don't understand what you have input")
def getMonthlyMessage():
    people_count = person.getPeopleCount()
    contr_count, contr_namesString, recCommandsString = getLastContibutors(31)
    msg = "Siamo ora " + str(
        people_count) + " persone iscritte a @DialettiBot!\n\n"
    if contr_count > 0:
        if contr_count == 1:
            msg += utility.unindent("""
                Nell'ultimo mese abbiamo ricevuto una registrazione!
                Un grande ringraziamento a *{}*! {}\n
                Se vuoi ascoltarla premi su questo comando:\n{}
                """.format(contr_namesString, CLAPPING_HANDS,
                           recCommandsString))
        else:
            msg += utility.unindent("""
                Nell'ultimo mese abbiamo ricevuto {} registrazioni!
                Un grande ringraziamento a *{}*! {}\n
                Se vuoi ascoltarle premi su questi comandi:\n{}
                """.format(contr_count, contr_namesString,
                           CLAPPING_HANDS * contr_count, recCommandsString))
    else:
        msg += "Purtroppo questo mese non abbiamo ricevuto nessuna nuova registrazione " + FROWNING_FACE

    msg += "\n\nSul sito http://dialectbot.appspot.com potrai " \
           "*visualizzare* (e *ascoltare*) tutte le registrazioni sulla *mappa* 🗺 !"

    msg += "\n\n*Aiutaci a crescere*: aggiungi nuove registrazioni del tuo dialetto tramite il bot " \
           "e invita altre persone ad unirsi! " + SMILY
    return msg
Esempio n. 3
0
def goToState22(p, input=None, **kwargs):

    BUTTON_SKIP_PHOTO = "Skip Photo"

    ASK_PICTURE_TEXT = unindent("""\
        We encourage our contributors to send a *photo of the new location*.\
        A link to the picture will be attached to the new location created in OpenStreetMap\
        and will serve as supporting evidence for OpenStreetMap validators.

        Could you send me a photo of the {} location?\
        If so please send me the photo using the paper clip below (📎).""")

    THANKS_TEXT = unindent("""\
        🙏  Thanks for your contribution!
        The location has been submitted to OpenStreetMap.\
        It will be stortily available in the\
        [online map](http://www.openstreetmap.org/#map=18/{}/{})\
        and in SearchAroundBot.""")

    photo = kwargs['photo'] if 'photo' in kwargs else None
    giveInstruction = input is None and photo == None
    type = p.getSearchType()

    if giveInstruction:
        reply_txt = ASK_PICTURE_TEXT.format(type)
        tell(p.chat_id,
             reply_txt,
             kb=[[BUTTON_SKIP_PHOTO]],
             one_time_keyboard=True)
    else:
        if input == BUTTON_SKIP_PHOTO:
            file_id = None
        elif photo:
            logging.debug("Photo field: " + str(photo))
            file_id = photo[-1]['file_id']
        else:
            tell(
                p.chat_id, "Not a valid type of input. "
                "Please send me a photo or press the \\'{0}\\' button.".format(
                    BUTTON_SKIP_PHOTO))
            return
        # both with and without picture
        lat = p.location.lat
        lon = p.location.lon
        tell(p.chat_id, THANKS_TEXT.format(lat, lon))
        restart(p)
        photo_url = parameters.PHOTO_BASE_URL + file_id if file_id else None
        node_id = osmEdit.insertNewLocation(lat, lon, p.getSearchType(),
                                            p.chat_id, photo_url)
        contribution.addContribution(p, node_id, file_id)
        msg = "User {} has inserted the following new {}: {}, {}. ".format(
            p.getUserInfoString(), type, lat, lon)
        if photo_url:
            msg += "\nPicure [url]({})".format(photo_url)
        msg += "\n[online map](http://www.openstreetmap.org/#map=18/{}/{}".format(
            lat, lon)
        tell(key.FEDE_CHAT_ID, msg)
Esempio n. 4
0
def goToState21(p, input=None, **kwargs):

    CONFIRM_TEXT = unindent("""\
        I am about to insert a new *{}* location\
        into [OpenStreetMap](http://www.openstreetmap.org/).\
        Please make sure you have sent a *correct* and *accurate* location.

        Are you sure you want to proceed?""")

    giveInstruction = input is None
    type = p.getSearchType()
    if giveInstruction:
        reply_txt = CONFIRM_TEXT.format(type)
        tell(p.chat_id,
             reply_txt,
             kb=[[BUTTON_YES, BUTTON_NO]],
             one_time_keyboard=True)
    else:
        if input == '':
            tell(p.chat_id, "Not a valid input.")
        elif input == BUTTON_YES:
            redirectToState(p, 22)  #picture
        elif input == BUTTON_NO:
            restart(p)
        else:
            tell(
                p.chat_id, FROWNING_FACE +
                " Sorry, I don't understand your request. Please use the buttons."
            )
Esempio n. 5
0
def broadcast(sender, msg, restart_user=False, curs=None, enabledCount=0):
    #return

    BROADCAST_COUNT_REPORT = utility.unindent("""
        Mesage sent to {} people
        Enabled: {}
        Disabled: {}
        """)

    users, next_curs, more = Person.query().fetch_page(50, start_cursor=curs)
    try:
        for p in users:
            if p.enabled:
                enabledCount += 1
                if restart_user:
                    restart(p)
                tell(p.chat_id, msg, sleepDelay=True)
    except datastore_errors.Timeout:
        sleep(1)
        deferred.defer(broadcast, sender, msg, restart_user, curs,
                       enabledCount)
        return
    if more:
        deferred.defer(broadcast, sender, msg, restart_user, next_curs,
                       enabledCount)
    else:
        total = Person.query().count()
        disabled = total - enabledCount
        msg_debug = BROADCAST_COUNT_REPORT.format(str(total),
                                                  str(enabledCount),
                                                  str(disabled))
        tell(sender.chat_id, msg_debug)
Esempio n. 6
0
def goToState1(p, **kwargs):
    input = kwargs['input'] if 'input' in kwargs.keys() else None
    giveInstruction = input is None
    if giveInstruction:
        exerciseId, sentence, wordIndexToReplace, wordsToReplace, falseSynonymes, trueSynonymes = exercise_synonim.getRandomExercise(
        )
        sentenceWithBoldWord = getSentenceWithBoldedWord(
            sentence, wordIndexToReplace, wordsToReplace)
        plural = 's' if len(wordsToReplace.split()) > 1 else ''
        instructions = utility.unindent("""
            I've chosen the following sentence for you:\n
            {0}\n
            Select an option from the following list which is a synonym of the word{1} in bold text ({2}).
            """.format(sentenceWithBoldWord, plural, wordsToReplace))
        options = falseSynonymes + trueSynonymes
        random.shuffle(options)
        options_text = [
            BULLET_POINT + ' /' + str(n) + ': ' + x
            for n, x in enumerate(options, 1)
        ]
        instructions += '\n'.join(options_text)
        number_buttons = [str(x) for x in range(1, len(options) + 1)]
        kb = utility.distributeElementMaxSize(number_buttons)
        kb.append([BUTTON_EXIT])
        tell(p.chat_id, instructions, kb, one_time_keyboard=False)
        p.setLastExerciseNumberAndOptions(exerciseId, options)
    else:
        if input == '':
            tell(p.chat_id, "Not a valid input.")
        elif input == BUTTON_EXIT:
            restart(p)
        #elif input == BUTTON_NEXT_SENTENCE:
        #    repeatState(p)
        else:
            exerciseId, exerciseOptions = p.getLastExerciseIdAndOptions()
            exerciseId, sentence, wordIndexToReplace, wordsToReplace, falseSynonymes, trueSynonymes = exercise_synonim.getExercizeId(
                exerciseId)
            if input.startswith('/'):
                input = input[1:]
            if utility.representsIntBetween(input, 1,
                                            len(exerciseOptions) + 1):
                number = int(input)
                chosenWord = exerciseOptions[number - 1]
            else:
                #tell(p.chat_id, FROWNING_FACE + " Sorry, I don't understand what you have input")
                chosenWord = input
            msg = "You have chosen *{0}*.\n".format(chosenWord)
            sendWaitingAction(p.chat_id, sleep_time=0.5)
            if chosenWord in trueSynonymes:
                msg += "😄 Great, your answer is correct!"
                #kb = [[BUTTON_NEXT_SENTENCE], [BUTTON_EXIT]]
                kb = [[BUTTON_EXIT]]
                tell(p.chat_id, msg, kb)
                sendWaitingAction(p.chat_id, sleep_time=1)
                repeatState(p)
            else:
                msg += "🙁 I'm sorry, your answer is NOT correct, try again"
                tell(p.chat_id, msg)
Esempio n. 7
0
    else:
        pass


# ================================
# GENERAL FUNCTIONS
# ================================

# ---------
# BROADCAST
# ---------

BROADCAST_COUNT_REPORT = utility.unindent(
    """
    Messaggio inviato a {} persone
    Ricevuto da: {}
    Non rivevuto da : {} (hanno disattivato il bot)
    """
)

#NOTIFICATION_WARNING_MSG = '🔔 Per modificare le notifiche vai su {} → {}.'.format(
#    BOTTONE_IMPOSTAZIONI, BOTTONE_NOTIFICHE)

def broadcast(sender, msg, qry = None, restart_user=False,
              blackList_sender=False, sendNotification=True,
              notificationWarning = False):

    from google.appengine.ext.db import datastore_errors
    from google.appengine.api.urlfetch_errors import InternalTransientError

    if qry is None:
Esempio n. 8
0
import utility

if __name__ == "__main__":
    test_unindent = utility.unindent("""
        Let’s find the intruder! 🐸
        """)
    print(test_unindent)
    def post(self):
        body = jsonUtil.json_loads_byteified(self.request.body)
        logging.info('request body:')
        logging.info(body)
        self.response.write(json.dumps(body))

        # update_id = body['update_id']
        if 'message' not in body:
            return
        message = body['message']
        #message_id = message.get('message_id')
        # date = message.get('date')
        if "chat" not in message:
            return
        # fr = message.get('from')
        chat = message['chat']
        chat_id = chat['id']
        if "first_name" not in chat:
            return
        text = message.get('text', "")
        name = chat["first_name"]
        last_name = chat.get("last_name", "-")
        username = chat.get("username", "-")
        location = message.get("location", None)
        voice = message.get("voice", None)
        #audio = message.get("audio", None)
        #document = message.get("document", None)

        logging.debug("Received input from {}. Text={} Location={}".format(
            chat_id, text, location))

        def reply(msg=None, kb=None, markdown=True, inline_keyboard=False):
            send_message(chat_id,
                         msg,
                         kb=kb,
                         markdown=markdown,
                         inline_keyboard=inline_keyboard)

        p = person.getPersonByChatId(chat_id)

        if p is None:
            # new user
            logging.info("Text: " + text)
            if text == '/help':
                reply(ISTRUZIONI)
            if text.startswith("/start"):
                p = person.addPerson(chat_id, name)
                reply("Ciao " + p.getFirstName() + ", " + "benvenuta/o!")
                init_user(p, name, last_name, username)
                restart(p)
                # state = -1 or -2
                tell_masters("New user: "******"Premi su /start se vuoi iniziare. "
                    "Se hai qualche domanda o suggerimento non esitare di contattarmi cliccando su @kercos"
                )
        else:
            # known user
            person.updateUsername(p, username)
            if text.startswith("/start"):
                reply("Ciao " + p.getFirstName() + ", " + "ben ritrovata/o!")
                init_user(p, name, last_name, username)
                restart(p)
                # state = -1 or -2
            elif text == '/state':
                if p.state in STATES:
                    reply("You are in state " + str(p.state) + ": " +
                          STATES[p.state])
                else:
                    reply("You are in state " + str(p.state))
            elif WORK_IN_PROGRESS and not p.isAdmin():
                reply(UNDER_CONSTRUCTION +
                      " Il sistema è in aggiornamento, riprova più tardi.")
            elif text.startswith('/rec_'):
                send_voiceLocationTranslationFromCommand(p,
                                                         text,
                                                         userInfo=p.isAdmin())
            elif text.startswith('/sendText') and p.isAdmin():
                dealWithsendTextCommand(p, text, markdown=False)
            elif p.state == -1:
                # INITIAL STATE
                if text in ['/help', BOTTONE_INFO]:
                    redirectToState(p, 8)
                elif text == BOTTONE_REGISTRA:
                    if p.location:
                        dealWithPlaceAndMicInstructions(p)
                    else:
                        reply(
                            "Questa è la tua prima registrazione: "
                            "è necessario che tu inserisca il luogo del dialetto che vuoi registrare.\n"
                            + ISTRUZIONI_POSIZIONE,
                            kb=[[BOTTONE_ANNULLA]])
                        person.setState(p, -2)
                elif text == BOTTONE_ASCOLTA:
                    goToAscolta(p)
                    # state 30
                elif p.isAdmin():
                    if text == BOTTONE_ADMIN:
                        redirectToState(p, 9)
                    elif text == '/test':
                        reply('test')
                        #reply(geoUtils.getLocationTest())
                        #taskqueue.add(url='/worker', params={'key': key})
                        #geoUtils.test_Google_Map_Api()
                    elif text == '/infoCounts':
                        c = person.getPeopleCount()
                        reply("Number of users: " + str(c))
                    elif text == '/restartUsers':
                        text = "Nuova interfaccia e nuove funzionalità :)\n" \
                               "Ora puoi inserire le località digitando il nome del posto (e.g, Perugia).\n" \
                               "Inoltre puoi cercare registrazioni in prossimità di un luogo.\n" \
                               "Buon ascolto e buona registrazione!"
                        deferred.defer(restartAllUsers,
                                       text)  #'New interface :)')
                        #deferred.defer(restartTest, text) #'New interface :)')
                        logging.debug('restarted users')
                    elif text == '/importVivaldi':
                        #logging.debug('nothing')
                        recording.importVivaldi()
                    elif text == '/countVivaldi':
                        c = recording.countVivaldi()
                        reply('Vivaldi recs: ' + str(c))
                    elif text == '/deleteVivaldi':
                        recording.deleteVivaldi()
                        reply('Deleted Vivaldi recs.')
                    elif text == '/remFormatVoice':
                        c = recording.removeFormatVoice()
                        reply("removed rec format voice: " + str(c))
                    elif text == '/stats':
                        msg = recording.getRecodingsStats()
                        send_message(p.chat_id, msg, markdown=False)
                        msg = "People count: {}".format(
                            person.getPeopleCount())
                        send_message(p.chat_id, msg, markdown=False)
                    elif text.startswith('/echo ') and len(text) > 6:
                        msg = text[6:]
                        reply(msg)
                    elif text.startswith('/broadcast ') and len(text) > 11:
                        msg = text[11:]
                        deferred.defer(broadcast,
                                       p.chat_id,
                                       msg,
                                       restart_user=False)
                    elif text.startswith(
                            '/restartBroadcast ') and len(text) > 18:
                        msg = text[18:]
                        deferred.defer(broadcast,
                                       p.chat_id,
                                       msg,
                                       restart_user=True)
                    elif text.startswith('/self ') and len(text) > 6:
                        msg = text[6:]
                        reply(msg)
                    elif text == '/lastContributors':
                        count, namesString, recCommandsString = getLastContibutors(
                            300)
                        msg = "Contributors: " + str(
                            count) + "\nNames: " + namesString
                        reply(msg)
                    elif text == '/testMonthlyMessage':
                        msg = getMonthlyMessage()
                        reply(msg)
                    else:
                        reply('Scusa, capisco solo /help /start '
                              'e altri comandi segreti...')
                    #setLanguage(d.language)
                else:
                    reply(
                        "Scusa non capisco quello che hai detto.\n"
                        "Usa i pulsanti sotto o premi {} per avere informazioni."
                        .format(BOTTONE_INFO))
            elif p.state == -2:
                # POSIZIONE
                if text == BOTTONE_ANNULLA:
                    restart(p, "Operazione annullata.")
                elif location != None:
                    logging.debug('User sending location: {}, {}'.format(
                        location['latitude'], location['longitude']))
                    luogo = geoUtils.getComuneProvinciaFromCoordinates(
                        location['latitude'], location['longitude'])
                    logging.debug('Detected luogo: {}'.format(luogo))
                    if luogo:
                        person.setLocation(p, location['latitude'],
                                           location['longitude'])
                        dealWithPlaceAndMicInstructions(p)
                    else:
                        reply(
                            "Non conosco la località inserita, prova ad essere più precisa/o.\n"
                            + ISTRUZIONI_POSIZIONE,
                            kb=[[BOTTONE_INVIA_LOCATION], [BOTTONE_ANNULLA]])
                        logging.debug(
                            'Problem finding comune and provincia from coordinates {} {}'
                            .format(location['latitude'],
                                    location['longitude']))
                    #state 20
                elif text.startswith('('):
                    text_split = text[1:-1].split(",")
                    latitude = float(text_split[0])
                    longitude = float(text_split[1])
                    person.setLocation(p, latitude, longitude)
                    send_location(p.chat_id, latitude, longitude)
                    dealWithPlaceAndMicInstructions(p)
                    #state 20
                else:
                    place = geoUtils.getLocationFromName(text)
                    if place:
                        person.setLocation(p, place.latitude, place.longitude)
                        dealWithPlaceAndMicInstructions(p)
                        #state 20
                    else:
                        reply(
                            "Non conosco la località inserita, prova ad essere più precisa/o.\n"
                            + ISTRUZIONI_POSIZIONE,
                            kb=[[BOTTONE_INVIA_LOCATION], [BOTTONE_ANNULLA]])
            elif p.state == 20:
                # REGISTRA
                if text == BOTTONE_INDIETRO:
                    restart(p, "Operazione annullata.")
                    # state = -1
                elif text == BOTTONE_CAMBIA_LUOGO:
                    reply("Ok, cambiamo il luogo.\n" + ISTRUZIONI_POSIZIONE,
                          kb=[[BOTTONE_INVIA_LOCATION], [BOTTONE_ANNULLA]])
                    person.setState(p, -2)
                    # state -2
                elif voice != None:
                    reply(
                        "Bene! 😉\n"
                        "Ora riascolta la registrazione e conferma su ✅ OK "
                        "se la registrazione è ben riuscita o premi su 🎙 REGISTRA DI NUOVO per"
                        "effettuare un'altra registrazione.",
                        kb=[['✅ OK'], ['🎙 REGISTRA DI NUOVO'],
                            [BOTTONE_ANNULLA]])
                    file_id = voice['file_id']
                    #send_voice(p.chat_id, file_id)
                    rec = recording.addRecording(p, file_id)
                    person.setLastRecording(p, rec)
                    person.setState(p, 21)
                else:
                    reply(
                        FROWNING_FACE +
                        " Scusa non capisco quello che hai detto, devi inserire la registrazione tenendo premuto il microfono."
                    )
            elif p.state == 21:
                # CONFIRM RECORDING
                if text == BOTTONE_ANNULLA:
                    person.removeLastRecording(p)
                    restart(p, "Operazione annullata.")
                    # state = -1
                elif text == '✅ OK':
                    msg = utility.unindent('''
                        Riteniamo utile avere una traduzione in italiano delle registrazione \
                        in modo da essere comprensibili da tutti gli utenti.\n
                        *Scrivi qua sotto* la traduzione della registrazione \
                        (in aggiunta puoi inserire la trascrizione in dialetto e il significato in caso si tratti di un proverbio)
                        ''')
                    reply(msg, kb=[['Salta Traduzione']])
                    person.setState(p, 22)
                elif text == '🎙 REGISTRA DI NUOVO':
                    person.removeLastRecording(p)
                    reply(MIC_INSTRUCTIONS,
                          kb=[[BOTTONE_CAMBIA_LUOGO], [BOTTONE_ANNULLA]])
                    person.setState(p, 20)
                else:
                    reply(
                        FROWNING_FACE +
                        "Scusa non capisco quello che hai detto, premi *OK* per confermare la registrazione."
                    )
            elif p.state == 22:
                # CHECK IF AVAILABLE FOR TRANSLATION
                if text == 'Salta Traduzione':
                    msg = "👍😀 Grazie per il tuo contributo!\n" \
                          "La registrazione è in attesa di approvazione, riceverai un messaggio a breve."
                    reply(msg)
                    sendNewRecordingNotice(p)
                    restart(p)
                elif text == '':
                    msg = "Input non valido. *Scrivi* qua sotto la traduzione in italiano della registrazione"
                    reply(msg, kb=[['Salta Traduzione']])
                    return
                else:
                    recording.addTranslation(p.last_recording_file_id, text)
                    msg = "👍😀 Grazie per il tuo contributo!\n" \
                          "La registrazione è in attesa di approvazione, riceverai un messaggio a breve."
                    reply(msg)
                    sendNewRecordingNotice(p)
                    restart(p)
            elif p.state == 30:
                if text == BOTTONE_INDIETRO:
                    restart(p)
                    # state = -1
                elif text == BOTTONE_INDOVINA_LUOGO:
                    dealWithRandomRecording(p)
                    # state 31
                elif text == BOTTONE_CERCA_LUOGO:
                    reply(ISTRUZIONI_POSIZIONE_SEARCH, kb=[[BOTTONE_INDIETRO]])
                    person.setState(p, 32)
                    # state 32
                elif text == BOTTONE_RECENTI:
                    getRecentRecordings(p)
                    person.setState(p, 33)
                    # state 33
                elif text == BOTTONE_TUTTE:
                    getAllRecordings(p)
                    person.setState(p, 33)
                    # state 33
                else:
                    msg = "Input non valido. Usa i pulsanti qua sotto."
                    reply(msg)
                    return
            elif p.state == 31:
                # ASCOLTA - INDOVINA LUOGO
                if text in [BOTTONE_INDIETRO, BOTTONE_ANNULLA]:
                    restart(p)
                    # state = -1
                elif text == "ASCOLTA NUOVA REGISTRAZIONE":
                    dealWithRandomRecording(p)
                    # state 31
                elif location != None:
                    dealWithGuessedLocation(p, location)
                else:
                    place = geoUtils.getLocationFromName(text)
                    if place:
                        guessed_loc = {
                            'latitude': place.latitude,
                            'longitude': place.longitude
                        }
                        dealWithGuessedLocation(p, guessed_loc)
                    else:
                        reply(
                            "Non conosco la località inserita, prova ad essere più precisa/o.\n"
                            + ISTRUZIONI_POSIZIONE_GUESS,
                            kb=[[BOTTONE_ANNULLA]])
            elif p.state == 32:
                #ASCOLTA - RICERCA LUOGO
                sendWaitingAction(p.chat_id)
                if location != None:
                    dealWithFindClosestRecording(p, location)
                elif text == BOTTONE_INDIETRO:
                    restart(p)
                else:
                    place = geoUtils.getLocationFromName(text)
                    if place:
                        loc = {
                            'latitude': place.latitude,
                            'longitude': place.longitude
                        }
                        dealWithFindClosestRecording(p, loc)
                    else:
                        reply(
                            "Non conosco la località inserita, prova ad essere più precisa/o.\n"
                            + ISTRUZIONI_POSIZIONE_SEARCH,
                            kb=[[BOTTONE_INDIETRO]])
            elif p.state == 33:
                # REGISTRAZIONI RECENTI
                if text == BOTTONE_INDIETRO:
                    goToAscolta(p)
                else:
                    reply(FROWNING_FACE +
                          "Scusa non capisco quello che hai detto.")
            else:
                logging.debug("Sending {0} to state {1}".format(
                    p.getFirstName(), str(p.state)))
                repeatState(p, input=text)