[Tutor] Closing file objects when object is garbage collected?
Dear Python Users, How do I ensure that when an object is deleted by the garbage collector that the file objects contained within the object are closed, or collected by the garbage collector? I'd like to avoid having to read the whole file object into a string and close the file immediately because the files can potentially be large, and I'm dealing with many files at a time. I'm having issues when I test my software on XP, but not Linux. When I run the progam it fails after running for a while but not at exactly the same point each time. It fails in one of two ways, the user interface either completely disappears, or gives a OS error message unhanded exception error. Thanks in advance of any help, Wesley Brooks. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 [EMAIL PROTECTED] wrote Well, I don't know if this whole email was of use, but it makes the crux of the argument make sense to me. I thought it was pretty clear. And it highlights that the choices are like anything else in the world of engineering - a compromise. And the best compromise in any given situation might be different from the last time. Engineering is not an exact science. Alan G ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
[Tutor] opening a pipe?
A Perl script can easily serve as a filter within a pipe as seen in the following: use strict; use warnings; open(IN, 'cat hello.txt |') or die 'unable to open file'; while (IN) { print; } close(IN); Can I do the same within Python? Thanks. Jim ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Change dictionary value depending on a conditional statement.
Thank you all, very nice. Steve Willoughby wrote: Kent Johnson wrote: Try list.append({'id': 'name', 'link': ('YY','XX')[total 0]}) I'd caution against that, though. It's clever and cute, sure, but the meaning of it is obfuscated enough to be unpythonic because [total 0] as a subscript doesn't mean anything unless you know you're taking advantage of an implementation detail that booleans are 0 for false and 1 for true. No matter how reliable that fact may be, I don't think that value should be stuck into a numeric context like that. Or, in Python 2.5, list.append({'id': 'name', 'link': ('XX' if total 0 else 'YY')}) This is much more clear, and would IMHO be fine. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
To further document some points. This comes from PEP 8 (http://www.python.org/dev/peps/pep-0008/) For those who need authority : Author: Guido van Rossum guido at python.org, Barry Warsaw barry at python.org With this in mind, here are the Pythonic guidelines: - Public attributes should have no leading underscores. - If your public attribute name collides with a reserved keyword, append a single trailing underscore to your attribute name. This is preferable to an abbreviation or corrupted spelling. (However, notwithstanding this rule, 'cls' is the preferred spelling for any variable or argument which is known to be a class, especially the first argument to a class method.) Note 1: See the argument name recommendation above for class methods. - For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax. Note 1: Properties only work on new-style classes. Note 2: Try to keep the functional behavior side-effect free, although side-effects such as caching are generally fine. Note 3: Avoid using properties for computationally expensive operations; the attribute notation makes the caller believe that access is (relatively) cheap. - If your class is intended to be subclassed, and you have attributes that you do not want subclasses to use, consider naming them with double leading underscores and no trailing underscores. This invokes Python's name mangling algorithm, where the name of the class is mangled into the attribute name. This helps avoid attribute name collisions should subclasses inadvertently contain attributes with the same name. Note 1: Note that only the simple class name is used in the mangled name, so if a subclass chooses both the same class name and attribute name, you can still get name collisions. Note 2: Name mangling can make certain uses, such as debugging and __getattr__(), less convenient. However the name mangling algorithm is well documented and easy to perform manually. Note 3: Not everyone likes name mangling. Try to balance the need to avoid accidental name clashes with potential use by advanced callers. HTH ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 wrote: This is all fine and dandy, but the video game is pretty worthless unless it can show us what the score is. There are two ways to go about this. A) Give the video game a display which it updates, or B) Tear open the case of the video game and look at the actual gears that increment the score to read it. Mmmm... that's not really so. If the object's creator meant the score to be read that way then it would not be 'Tear open the case' but just 'read the score'. The language with which we describe an action does matter. You just invalidated your own argument. Sure, the object's creator may have designated that the way to read the score is to take these screws out and measure the angle of these gears in ratio to those gears No, the object's creator designed that the way to get the score is to read it. but what are you really doing here? ...(you are thinking procedurally)... You are really just overlooking the fact that the object is being *read*, meaning that the *object itself returns a representation*. This tearing apart should be abstracted with a method. Why? Because you are used to do it that way? The meer fact that you say 'tearing open the case' YOU are saying it. I'm saying 'read the score'. as just another way to say 'read the score' suggests a method called readscore(). Maybe it suggests that to you, not to me. But hey, if it did suggest readscore() or getscore() then it might also suggest setscore() and then we might also make sure that score is an integer so we'd better declare it an integer and have an exception if it is ever used to hold another type, they we might just see the light and start programming Java. You are exactly right. It does not matter with what language you describe an action, because the interface should still remain the same whether you are reading an attribute, or calculating high level summation probabilities to find the score. You are still justvg.readscore() Nope, I'm just myVar = vg.score and there are even ways to make sure that when the user of the class writes that line he receives a high level summation probability just as if he'd called a method, remember this is Python. Your particular issue is with the simplicity of the attribute, we don't need a getter method. True. But that in agreement with the concept of OOP. Sorry, which concept? According to whom? If you decide to pick and choose whether an object does it or whether the developer does it, not only do you have inconsistency in your programming style, but you are no longer OBJECT-Oriented. Says who? Anyway, I'm no theoretician, I'm a mere programmer. We programmers deal with practical things so I don't really care if I'm in or out of your concept of object orientation. So long as my code is maintainable, extendable, and does what it's supposed to do I'm ok with it, object or non-object oriented. Anyway if you wish for better people than me to expose this to you I suggest you address the python-list ([EMAIL PROTECTED]) and post a message saying We should access properties through setters and getters, otherwise it is not TRUE OOP. I won't take responsibility for any flames. PS This is one of the big issues that developers have with the win32api. It is procedural in this section, OOP in this section, etc. and more time is spent actually look up these subtle differences to prevent errors than is used in actual coding. A perfect OOP library does not Need a reference book. A good OOP library should only need to propose a pattern. I like good references, I like good documentation. But hey, different strokes... The second way is preferable for many reasons... A) The game designer decides to change the display, you don't have to change any code that uses the class B) Clearly, tearing open a videogame is pretty low-level from an object perspective. This is what Alan is saying with OOP purism. Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). I completely disagree with your issue on REUSABILITY here. Are you familiar with the concept of subclassing? So if I subclass the class it's ok to mess with the property but if I use the class it's not? Why should that be so? What advantage would that give me? If I subclass it, then declare a getter that reads the property and
Re: [Tutor] designing POOP
This is all fine and dandy, but the video game is pretty worthless unless it can show us what the score is. There are two ways to go about this. A) Give the video game a display which it updates, or B) Tear open the case of the video game and look at the actual gears that increment the score to read it. Mmmm... that's not really so. If the object's creator meant the score to be read that way then it would not be 'Tear open the case' but just 'read the score'. The language with which we describe an action does matter. You just invalidated your own argument. Sure, the object's creator may have designated that the way to read the score is to take these screws out and measure the angle of these gears in ratio to those gears but what are you really doing here? ...(you are thinking procedurally)... You are really just overlooking the fact that the object is being *read*, meaning that the *object itself returns a representation*. This tearing apart should be abstracted with a method. The meer fact that you say 'tearing open the case' as just another way to say 'read the score' suggests a method called readscore(). You are exactly right. It does not matter with what language you describe an action, because the interface should still remain the same whether you are reading an attribute, or calculating high level summation probabilities to find the score. You are still justvg.readscore() Your particular issue is with the simplicity of the attribute, we don't need a getter method. True. But that in agreement with the concept of OOP. If you decide to pick and choose whether an object does it or whether the developer does it, not only do you have inconsistency in your programming style, but you are no longer OBJECT-Oriented. PS This is one of the big issues that developers have with the win32api. It is procedural in this section, OOP in this section, etc. and more time is spent actually look up these subtle differences to prevent errors than is used in actual coding. A perfect OOP library does not Need a reference book. A good OOP library should only need to propose a pattern. The second way is preferable for many reasons... A) The game designer decides to change the display, you don't have to change any code that uses the class B) Clearly, tearing open a videogame is pretty low-level from an object perspective. This is what Alan is saying with OOP purism. Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). I completely disagree with your issue on REUSABILITY here. Are you familiar with the concept of subclassing? Or if you wish to ignore the power of OOP, you can just add another method, which is still more realistic and intuitive than directly accessing an internal state variable. Perhaps your major issue here is whether or not score should be public? Alright. Give me one instance in daily usage of any video game where the score of a video game is changed without the video game knowing it. (example - cosmic rays change a bit in the storage of the score and the video game is not aware of it) This concept would allow a violation of a pure OOP VideoGame class, and allow an otherwise private internal state to be made public. PS - for fun. I can think of a more common reason why the score of video games would change without using the actual video game interface. I watched a tv episode of masterminds where the criminal thought up the perfect plan to trick a slot machine by directly accessing the physical chip that determined a winning combination. If the developer of the slot machine had wanted this to be the way that winning combinations are chosen, he should have provided a method which allowed for this. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
[Tutor] Mail revisited
Ok, so I've started the path to put a GUI to the MandarMails.py program. For starters I've included a progress bar. Any enhancements you may suggest will be appreciated. Note: not tested yet ## ### MandarMails.py ### ## #!/usr/bin/env python import time import smtplib import email import ConfigParser import logging class Mensaje(object) : def __init__(self) : cfg = ConfigParser.ConfigParser() try : cfg.readfp(open('config.cfg')) except Exception, e : logging.error('No pude leer config.cfg : %s', e.strerror) self.direcciones = cfg.get('Archivos', 'Direcciones') self.excluidas = cfg.get('Archivos', 'Excluir') self.cuantos = cfg.getint('Correo', 'MailsPorVez') self.intervalo = cfg.getint('Correo', 'IntervaloEnSegundos') try : htmlFile = open(cfg.get('Archivos', 'Mensaje')) htmlMessage = htmlFile.read() htmlFile.close() except Exception, e : logging.error('No pude leer %s : %s', cfg.get('Archivos', 'Mensaje'), e.strerror) self.messg = email.MIMEMultipart.MIMEMultipart() self.messg['From'] = cfg.get('Encabezados', 'De') self.messg['To'] = '' self.messg['Subject'] = cfg.get('Encabezados', 'Encabezado') self.messg['Reply-To'] = cfg.get('Encabezados', 'ResponderA') self.messg.preamble = 'This is a multi-part message in MIME format' self.messg.attach(email.MIMEText.MIMEText(htmlMessage, 'html')) self.servidor = cfg.get('Correo', 'Servidor') self.usuario = cfg.get('Correo', 'Usuario') self.contra = cfg.get('Correo', 'Contrasenia') class Correo(object) : def __init__(self, mensaje) : self.mensaje = mensaje self.conexion = smtplib.SMTP() def connect(self) : try : self.conexion.connect(self.mensaje.servidor) self.conexion.set_debuglevel(False) self.conexion.ehlo() self.conexion.starttls() self.conexion.ehlo() self.conexion.login(self.mensaje.usuario, self.mensaje.contra) return True except : logging.error('No me pude conectar al Servidor') return False def disconnect(self) : self.conexion.close() def enviar(self, addr) : self.mensaje.messg.replace_header('To', addr) try : self.conexion.sendmail(self.mensaje.messg['From'], self.mensaje.messg['To'], self.mensaje.messg.as_string()) logging.info('Enviado a : %s', self.mensaje.messg['To']) except smtplib.SMTPRecipientsRefused : logging.error('El destinatario fue rechazado por el servidor') except smtplib.SMTPHeloError : logging.error('El servidor no respondio apropiadamente') except smtplib.SMTPSenderRefused : logging.error('El From: fue rechazado por el servidor') except smtplib.SMTPDataError : logging.error('El servidor respondio con un error desconocido') class Envio(object) : def __init__(self, mensaje) : self._mensaje = mensaje self.totAEnviar = 0 self.enviados = 0 self._mails = [] self._miCorreo = None self._timer = 0 try : try : fIncl = open(self._mensaje.direcciones) except Exception, e : logging.error('Error!!! No pude abrir %s : %s', self._mensaje.direcciones, e.strerror) raise try : fExcl = open(self._mensaje.excluidas) except Exception, e : logging.error('No pude abrir %s : %s', self._mensaje.excluidas, e.strerror) fIncl.close() raise except : pass else : self._mails = enumerate(set(addr.strip() for addr in fIncl) - set(excl.strip() for excl in fExcl)) fIncl.close() fExcl.close() self.TotAEnviar = len(self._mails) self._miCorreo = Correo(self._mensaje) def enviar() : dormir = self._mensaje.intervalo - (time.clock() - self._timer) if dormir 0 : time.sleep(dormir) self._timer = time.clock() if not self._miCorreo.connect() : logging.info('Terminando') return False for nro, addr in self._mails[:self._mensaje.cuantos] : self._miCorreo.enviar(addr) self._miCorreo.disconnect() self._mails = self._mails[self._mensaje.cuantos:] return (len(self._mails) 0) if __name__ == '__main__' : from Tkinter import * from
Re: [Tutor] opening a pipe?
From: James Hartley Subject: [Tutor] opening a pipe? Sent: 2008-02-12 09:24 A Perl script can easily serve as a filter within a pipe as seen in the following: use strict; use warnings; open(IN, 'cat hello.txt |') or die 'unable to open file'; while (IN) { print; } close(IN); Can I do the same within Python? Thanks. os.popen can do this. The 'commands' module provides even more flexibility. If you are on a posix platform and want to avoid shell interpretation, you could also try my pipeline package at http://pypi.python.org/pypi/pipeline.py/0.1 -- Yorick Our servers are using too much electricity. We need to virtualize. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] How to Set python path
Hi, Iam facing problems in Environment variables for python path as follows Iam using Windows XP operating system in system variable iam appending two path,in this case only first path is working but second path is not working,if i remove first path means second path is working ,two paths are seperated by semicolon but two paths are same only slight diffrences.how to work with both paths? kindly give Solution for this problem.. regards Narayana Moorthy.V___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] opening a pipe?
The subprocess module is what you're looking for. Your example would look like % import subprocess p = subprocess.Popen('cat hi.txt', shell=True, stdout=subprocess.PIPE) for line in p.stdout: print line % I assume you know that you can just open a file for reading instead of piping cat. thomas James Hartley wrote: A Perl script can easily serve as a filter within a pipe as seen in the following: use strict; use warnings; open(IN, 'cat hello.txt |') or die 'unable to open file'; while (IN) { print; } close(IN); Can I do the same within Python? Thanks. Jim ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Closing file objects when object is garbage collected?
I'm having issues when I test my software on XP, but not Linux. When I run the progam it fails after running for a while but not at exactly the same point each time. It fails in one of two ways, the user interface either completely disappears, or gives a OS error message unhanded exception error. Could you give code for this, or provide a link? ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Closing file objects when object is garbage collected?
How do I ensure that when an object is deleted by the garbage collector that the file objects contained within the object are closed, or collected by the garbage collector? __del__ is called after the reference count gets to zero for an object. You can explicitly call close on the file there if you're worried you have a dangling reference to the file somewhere. I'd use the class below first to help. If you'd like to see when if your files are being closed, a class such as this may help your debugging. Use it in the place of your file or open call in the class that is at issue: class LoudFile(file): Shows when a file is closed def close(self): file.close(self) if self.closed: print %s is now closed % self.name def __del__(self): shows when a file is garbage collected print %s fileobject is being deleted % self.name I'm having issues when I test my software on XP, but not Linux. When I run the progam it fails after running for a while but not at exactly the same point each time. It fails in one of two ways, the user interface either completely disappears, or gives a OS error message unhanded exception error. Run the program from the pdb debugger (it comes installed with python). Here is an excellent introduction to it: http://www.onlamp.com/pub/a/python/2005/09/01/debugger.html It will allow you to poke around at the innards of your program right as it dies. --Michael -- Michael Langford Phone: 404-386-0495 Consulting: http://www.RowdyLabs.com ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Closing file objects when object is garbage collected?
Wesley Brooks wrote: Dear Python Users, How do I ensure that when an object is deleted by the garbage collector that the file objects contained within the object are closed, or collected by the garbage collector? When there are no more references to a file object the file is closed. This happens in your case when the containing object is deleted. All of this happens before garbage collection. I'd like to avoid having to read the whole file object To be precise you should say avoid having to read the whole file. The file object is just the interface to the file contents. into a string and close the file immediately because the files can potentially be large, and I'm dealing with many files at a time. -- Bob Gailer 919-636-4239 Chapel Hill, NC ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 12, 2008 7:19 AM, Ricardo Aráoz [EMAIL PROTECTED] wrote: Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). Everything in this discussion seems relevant to designing Python OOP. (Python is not java, not javascript, not c++, not visual whatever etc.) We can see from this that Python does it the Python way. The Java examples are pretty much wasted on me. (I don't know anything about Java at all.) The POOP tutorials rarely get into design considerations. They introduce the mechanics of making a program, make a sample program, and keep on trucking. I'm trying to learn how to design a program with Python. So far, two beginner techniques have been shown: the noun/verb/adjective method (Alan), and the TDD (Test Driven Design) method (Kent). Of the two, the noun/verb/adjective method seems more approachable (to me). I think that once I have some experience doing that, then the TDD method may have something to offer. Baby steps first. Walk before running. 8^D Happy Programming! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 wrote: This is all fine and dandy, but the video game is pretty worthless unless it can show us what the score is. There are two ways to go about this. A) Give the video game a display which it updates, or B) Tear open the case of the video game and look at the actual gears that increment the score to read it. Mmmm... that's not really so. If the object's creator meant the score to be read that way then it would not be 'Tear open the case' but just 'read the score'. The language with which we describe an action does matter. vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush() print vg.score#Tear open the case (hope you have a screwdriver) OR class VideoGame(): def __init__(self): self.score = 0 def updatedisp(): print self.score def buttonpush(): self.score += 1 self.updatedisp() vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush()#Let the videogame display your score however it wishes The second way is preferable for many reasons... A) The game designer decides to change the display, you don't have to change any code that uses the class B) Clearly, tearing open a videogame is pretty low-level from an object perspective. This is what Alan is saying with OOP purism. Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 wrote: This is all fine and dandy, but the video game is pretty worthless unless it can show us what the score is. There are two ways to go about this. A) Give the video game a display which it updates, or B) Tear open the case of the video game and look at the actual gears that increment the score to read it. Mmmm... that's not really so. If the object's creator meant the score to be read that way then it would not be 'Tear open the case' but just 'read the score'. The language with which we describe an action does matter. vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush() print vg.score#Tear open the case (hope you have a screwdriver) OR class VideoGame(): def __init__(self): self.score = 0 def updatedisp(): print self.score def buttonpush(): self.score += 1 self.updatedisp() vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush()#Let the videogame display your score however it wishes The second way is preferable for many reasons... A) The game designer decides to change the display, you don't have to change any code that uses the class B) Clearly, tearing open a videogame is pretty low-level from an object perspective. This is what Alan is saying with OOP purism. Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] How to Set python path
Show us both path statements, then we might be able to fix it. --Michael On Feb 12, 2008 2:01 AM, Narain [EMAIL PROTECTED] wrote: Hi, Iam facing problems in Environment variables for python path as follows Iam using Windows XP operating system in system variable iam appending two path,in this case only first path is working but second path is not working,if i remove first path means second path is working ,two paths are seperated by semicolon but two paths are same only slight diffrences.how to work with both paths? kindly give Solution for this problem.. regards Narayana Moorthy.V ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor -- Michael Langford Phone: 404-386-0495 Consulting: http://www.RowdyLabs.com ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor