From: Tim Peters Date: Thu, 4 Apr 2002 22:55:58 +0000 (+0000) Subject: Convert a pile of obvious "yes/no" functions to return bool. X-Git-Tag: v2.3c1~6125 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bc0e9108261693b6278687f4fb4709ff76c2e543;p=thirdparty%2FPython%2Fcpython.git Convert a pile of obvious "yes/no" functions to return bool. --- diff --git a/Demo/pdist/cvslib.py b/Demo/pdist/cvslib.py index cf305c97982d..c72cd6b848e2 100755 --- a/Demo/pdist/cvslib.py +++ b/Demo/pdist/cvslib.py @@ -289,10 +289,10 @@ class CVS: os.rename(file, bfile) def ignored(self, file): - if os.path.isdir(file): return 1 + if os.path.isdir(file): return True for pat in self.IgnoreList: - if fnmatch.fnmatch(file, pat): return 1 - return 0 + if fnmatch.fnmatch(file, pat): return True + return Falso # hexify and unhexify are useful to print MD5 checksums in hex format diff --git a/Lib/BaseHTTPServer.py b/Lib/BaseHTTPServer.py index 3177cb6196d6..35baf2f4acd7 100644 --- a/Lib/BaseHTTPServer.py +++ b/Lib/BaseHTTPServer.py @@ -222,7 +222,7 @@ class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): are in self.command, self.path, self.request_version and self.headers. - Return value is 1 for success, 0 for failure; on failure, an + Return True for success, False for failure; on failure, an error is sent back. """ @@ -239,30 +239,30 @@ class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): [command, path, version] = words if version[:5] != 'HTTP/': self.send_error(400, "Bad request version (%s)" % `version`) - return 0 + return False try: version_number = float(version.split('/', 1)[1]) except ValueError: self.send_error(400, "Bad request version (%s)" % `version`) - return 0 + return False if version_number >= 1.1 and self.protocol_version >= "HTTP/1.1": self.close_connection = 0 if version_number >= 2.0: self.send_error(505, "Invalid HTTP Version (%f)" % version_number) - return 0 + return False elif len(words) == 2: [command, path] = words self.close_connection = 1 if command != 'GET': self.send_error(400, "Bad HTTP/0.9 request type (%s)" % `command`) - return 0 + return False elif not words: - return 0 + return False else: self.send_error(400, "Bad request syntax (%s)" % `requestline`) - return 0 + return False self.command, self.path, self.request_version = command, path, version # Deal with pipelining @@ -283,7 +283,7 @@ class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): elif (conntype.lower() == 'keep-alive' and self.protocol_version >= "HTTP/1.1"): self.close_connection = 0 - return 1 + return True def handle_one_request(self): """Handle a single HTTP request. diff --git a/Lib/CGIHTTPServer.py b/Lib/CGIHTTPServer.py index 7bb7467798de..c3a6a18ac42a 100644 --- a/Lib/CGIHTTPServer.py +++ b/Lib/CGIHTTPServer.py @@ -86,8 +86,8 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): i = len(x) if path[:i] == x and (not path[i:] or path[i] == '/'): self.cgi_info = path[:i], path[i+1:] - return 1 - return 0 + return True + return False cgi_directories = ['/cgi-bin', '/htbin'] diff --git a/Lib/ConfigParser.py b/Lib/ConfigParser.py index bdce25ef0d35..fe97c9e09c94 100644 --- a/Lib/ConfigParser.py +++ b/Lib/ConfigParser.py @@ -374,9 +374,9 @@ class ConfigParser: """Remove a file section.""" if self.__sections.has_key(section): del self.__sections[section] - return 1 + return True else: - return 0 + return False # # Regular expressions for parsing section headers and options. Note a diff --git a/Lib/SocketServer.py b/Lib/SocketServer.py index 7e1e27ca02cc..2c15e9370bb7 100644 --- a/Lib/SocketServer.py +++ b/Lib/SocketServer.py @@ -226,10 +226,10 @@ class BaseServer: def verify_request(self, request, client_address): """Verify the request. May be overridden. - Return true if we should proceed with this request. + Return True if we should proceed with this request. """ - return 1 + return True def process_request(self, request, client_address): """Call finish_request. diff --git a/Lib/asyncore.py b/Lib/asyncore.py index 6bbfbabd589b..c7a8f1268477 100644 --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -281,7 +281,7 @@ class dispatcher: # ================================================== def readable (self): - return 1 + return True if os.name == 'mac': # The macintosh will select a listening socket for @@ -290,7 +290,7 @@ class dispatcher: return not self.accepting else: def writable (self): - return 1 + return True # ================================================== # socket object methods. diff --git a/Lib/bdb.py b/Lib/bdb.py index d5b051b5e33f..d0c738fa728a 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -92,31 +92,31 @@ class Bdb: def stop_here(self, frame): if self.stopframe is None: - return 1 + return True if frame is self.stopframe: - return 1 + return True while frame is not None and frame is not self.stopframe: if frame is self.botframe: - return 1 + return True frame = frame.f_back - return 0 + return False def break_here(self, frame): filename = self.canonic(frame.f_code.co_filename) if not self.breaks.has_key(filename): - return 0 + return False lineno = frame.f_lineno if not lineno in self.breaks[filename]: - return 0 + return False # flag says ok to delete temp. bp (bp, flag) = effective(filename, lineno, frame) if bp: self.currentbp = bp.number if (flag and bp.temporary): self.do_clear(str(bp.number)) - return 1 + return True else: - return 0 + return False def do_clear(self, arg): raise NotImplementedError, "subclass of bdb must implement do_clear()" diff --git a/Lib/cgi.py b/Lib/cgi.py index db91ec6d2e44..a7ad5bf01f3f 100755 --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -600,8 +600,8 @@ class FieldStorage: if self.list is None: raise TypeError, "not indexable" for item in self.list: - if item.name == key: return 1 - return 0 + if item.name == key: return True + return False def __len__(self): """Dictionary style len(x) support.""" diff --git a/Lib/code.py b/Lib/code.py index b7a5af908ce1..75c64e60e4bb 100644 --- a/Lib/code.py +++ b/Lib/code.py @@ -66,7 +66,7 @@ class InteractiveInterpreter: object. The code is executed by calling self.runcode() (which also handles run-time exceptions, except for SystemExit). - The return value is 1 in case 2, 0 in the other cases (unless + The return value is True in case 2, False in the other cases (unless an exception is raised). The return value can be used to decide whether to use sys.ps1 or sys.ps2 to prompt the next line. @@ -77,15 +77,15 @@ class InteractiveInterpreter: except (OverflowError, SyntaxError, ValueError): # Case 1 self.showsyntaxerror(filename) - return 0 + return False if code is None: # Case 2 - return 1 + return True # Case 3 self.runcode(code) - return 0 + return False def runcode(self, code): """Execute a code object. diff --git a/Lib/distutils/command/build_py.py b/Lib/distutils/command/build_py.py index 97d094b1b29e..453ca97a09c6 100644 --- a/Lib/distutils/command/build_py.py +++ b/Lib/distutils/command/build_py.py @@ -190,9 +190,9 @@ class build_py (Command): if not os.path.isfile(module_file): self.warn("file %s (for module %s) not found" % (module_file, module)) - return 0 + return False else: - return 1 + return True # check_module () diff --git a/Lib/dospath.py b/Lib/dospath.py index 652b35f51f92..cfc0d864c31c 100644 --- a/Lib/dospath.py +++ b/Lib/dospath.py @@ -151,8 +151,8 @@ def exists(path): try: st = os.stat(path) except os.error: - return 0 - return 1 + return False + return True def isdir(path): @@ -161,7 +161,7 @@ def isdir(path): try: st = os.stat(path) except os.error: - return 0 + return False return stat.S_ISDIR(st[stat.ST_MODE]) @@ -171,7 +171,7 @@ def isfile(path): try: st = os.stat(path) except os.error: - return 0 + return False return stat.S_ISREG(st[stat.ST_MODE]) diff --git a/Lib/filecmp.py b/Lib/filecmp.py index 3018762003ab..f0e6d47bc33e 100644 --- a/Lib/filecmp.py +++ b/Lib/filecmp.py @@ -35,7 +35,7 @@ def cmp(f1, f2, shallow=1, use_statcache=0): Return value: - integer -- 1 if the files are the same, 0 otherwise. + True if the files are the same, False otherwise. This function uses a cache for past comparisons and the results, with a cache invalidation mechanism relying on stale signatures. @@ -50,11 +50,11 @@ def cmp(f1, f2, shallow=1, use_statcache=0): s1 = _sig(stat_function(f1)) s2 = _sig(stat_function(f2)) if s1[0] != stat.S_IFREG or s2[0] != stat.S_IFREG: - return 0 + return False if shallow and s1 == s2: - return 1 + return True if s1[1] != s2[1]: - return 0 + return False result = _cache.get((f1, f2)) if result and (s1, s2) == result[:2]: diff --git a/Lib/getopt.py b/Lib/getopt.py index f1dc7ac44652..91584fe78f6e 100644 --- a/Lib/getopt.py +++ b/Lib/getopt.py @@ -103,9 +103,9 @@ def long_has_args(opt, longopts): raise GetoptError('option --%s not recognized' % opt, opt) # Is there an exact match? if opt in possibilities: - return 0, opt + return False, opt elif opt + '=' in possibilities: - return 1, opt + return True, opt # No exact match, so better be unique. if len(possibilities) > 1: # XXX since possibilities contains all valid continuations, might be diff --git a/Lib/macpath.py b/Lib/macpath.py index 6501fcd91d3e..80deaa918e32 100644 --- a/Lib/macpath.py +++ b/Lib/macpath.py @@ -139,13 +139,13 @@ def isfile(s): def exists(s): - """Return true if the pathname refers to an existing file or directory.""" + """Return True if the pathname refers to an existing file or directory.""" try: st = os.stat(s) except os.error: - return 0 - return 1 + return False + return True # Return the longest prefix of all list elements. diff --git a/Lib/mailbox.py b/Lib/mailbox.py index ed8348971605..853949b99564 100755 --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -151,7 +151,7 @@ class UnixMailbox(_Mailbox): return self._regexp.match(line) def _portable_isrealfromline(self, line): - return 1 + return True _isrealfromline = _strict_isrealfromline diff --git a/Lib/mhlib.py b/Lib/mhlib.py index 6cf012830716..8d0eff1861a9 100644 --- a/Lib/mhlib.py +++ b/Lib/mhlib.py @@ -850,8 +850,8 @@ class IntSet: def contains(self, x): for lo, hi in self.pairs: - if lo <= x <= hi: return 1 - return 0 + if lo <= x <= hi: return True + return False def append(self, x): for i in range(len(self.pairs)): diff --git a/Lib/mutex.py b/Lib/mutex.py index 2348a2e0041d..47d2ca23713c 100644 --- a/Lib/mutex.py +++ b/Lib/mutex.py @@ -24,12 +24,12 @@ class mutex: def testandset(self): """Atomic test-and-set -- grab the lock if it is not set, - return true if it succeeded.""" + return True if it succeeded.""" if not self.locked: self.locked = 1 - return 1 + return True else: - return 0 + return False def lock(self, function, argument): """Lock a mutex, call the function with supplied argument diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 5a63105d080b..8cd8e9ad6843 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -246,8 +246,8 @@ def exists(path): try: st = os.stat(path) except os.error: - return 0 - return 1 + return False + return True # Is a path a dos directory? diff --git a/Lib/os.py b/Lib/os.py index 4520b4f37151..e19883b708d3 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -445,9 +445,9 @@ else: def _exists(name): try: eval(name) - return 1 + return True except NameError: - return 0 + return False # Supply spawn*() (probably only for Unix) if _exists("fork") and not _exists("spawnv") and _exists("execv"): diff --git a/Lib/os2emxpath.py b/Lib/os2emxpath.py index e4d63c62be36..01db974beb6f 100644 --- a/Lib/os2emxpath.py +++ b/Lib/os2emxpath.py @@ -205,8 +205,8 @@ def exists(path): try: st = os.stat(path) except os.error: - return 0 - return 1 + return False + return True # Is a path a directory? diff --git a/Lib/posixpath.py b/Lib/posixpath.py index c342bbcf198e..cceb2d2be71e 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -166,12 +166,12 @@ def islink(path): # This is false for dangling symbolic links. def exists(path): - """Test whether a path exists. Returns false for broken symbolic links""" + """Test whether a path exists. Returns False for broken symbolic links""" try: st = os.stat(path) except os.error: - return 0 - return 1 + return False + return True # Is a path a directory? @@ -237,16 +237,16 @@ def ismount(path): s1 = os.stat(path) s2 = os.stat(join(path, '..')) except os.error: - return 0 # It doesn't exist -- so not a mount point :-) + return False # It doesn't exist -- so not a mount point :-) dev1 = s1[stat.ST_DEV] dev2 = s2[stat.ST_DEV] if dev1 != dev2: - return 1 # path/.. on a different device as path + return True # path/.. on a different device as path ino1 = s1[stat.ST_INO] ino2 = s2[stat.ST_INO] if ino1 == ino2: - return 1 # path/.. is the same i-node as path - return 0 + return True # path/.. is the same i-node as path + return False # Directory tree walk. diff --git a/Lib/pydoc.py b/Lib/pydoc.py index c27da11ad6fe..587a24c01a1c 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -148,7 +148,8 @@ def ispackage(path): if os.path.isdir(path): for ext in ['.py', '.pyc', '.pyo']: if os.path.isfile(os.path.join(path, '__init__' + ext)): - return 1 + return True + return False def synopsis(filename, cache={}): """Get the one-line summary out of a module file.""" diff --git a/Lib/robotparser.py b/Lib/robotparser.py index 5b759d4968d8..99bcdae2f1eb 100644 --- a/Lib/robotparser.py +++ b/Lib/robotparser.py @@ -134,9 +134,9 @@ class RobotFileParser: _debug("Checking robot.txt allowance for:\n user agent: %s\n url: %s" % (useragent, url)) if self.disallow_all: - return 0 + return False if self.allow_all: - return 1 + return True # search for given user agent matches # the first match counts url = urllib.quote(urlparse.urlparse(urllib.unquote(url))[2]) or "/" @@ -147,7 +147,7 @@ class RobotFileParser: if self.default_entry: return self.default_entry.allowance(url) # agent not found ==> access granted - return 1 + return True def __str__(self): @@ -195,11 +195,11 @@ class Entry: for agent in self.useragents: if agent=='*': # we have the catch-all agent - return 1 + return True agent = agent.lower() if useragent.find(agent) != -1: - return 1 - return 0 + return True + return False def allowance(self, filename): """Preconditions: diff --git a/Lib/symtable.py b/Lib/symtable.py index 15549eeb1da9..44983358ca60 100644 --- a/Lib/symtable.py +++ b/Lib/symtable.py @@ -35,19 +35,13 @@ class SymbolTableFactory: newSymbolTable = SymbolTableFactory() -def bool(x): - """Helper to force boolean result to 1 or 0""" - if x: - return 1 - return 0 - def is_free(flags): if (flags & (USE | DEF_FREE)) \ and (flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)): - return 1 + return True if flags & DEF_FREE_CLASS: - return 1 - return 0 + return True + return False class SymbolTable: def __init__(self, raw_table, filename): @@ -206,10 +200,10 @@ class Symbol: def is_free(self): if (self.__flags & (USE | DEF_FREE)) \ and (self.__flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)): - return 1 + return True if self.__flags & DEF_FREE_CLASS: - return 1 - return 0 + return True + return False def is_imported(self): return bool(self.__flags & DEF_IMPORT) diff --git a/Lib/tabnanny.py b/Lib/tabnanny.py index 7d2ca52dea8c..25955400bff6 100755 --- a/Lib/tabnanny.py +++ b/Lib/tabnanny.py @@ -196,7 +196,7 @@ class Whitespace: other.indent_level(ts)) ) return a - # Return true iff self.indent_level(t) < other.indent_level(t) + # Return True iff self.indent_level(t) < other.indent_level(t) # for all t >= 1. # The algorithm is due to Vincent Broman. # Easy to prove it's correct. @@ -211,7 +211,7 @@ class Whitespace: # Note that M is of the form (T*)(S*) iff len(M.norm[0]) <= 1. def less(self, other): if self.n >= other.n: - return 0 + return False if self.is_simple and other.is_simple: return self.nt <= other.nt n = max(self.longest_run_of_spaces(), @@ -219,8 +219,8 @@ class Whitespace: # the self.n >= other.n test already did it for ts=1 for ts in range(2, n+1): if self.indent_level(ts) >= other.indent_level(ts): - return 0 - return 1 + return False + return True # return a list of tuples (ts, i1, i2) such that # i1 == self.indent_level(ts) >= other.indent_level(ts) == i2. diff --git a/Lib/threading.py b/Lib/threading.py index 9763c629d8d2..706d5bbc5e1b 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -174,9 +174,9 @@ class _Condition(_Verbose): def _is_owned(self): if self.__lock.acquire(0): self.__lock.release() - return 0 + return False else: - return 1 + return True def wait(self, timeout=None): me = currentThread() diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 19443ca1e56c..1509b7aa856a 100644 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -78,15 +78,15 @@ def _synthesize(browser): def _iscommand(cmd): - """Return true if cmd can be found on the executable search path.""" + """Return True if cmd can be found on the executable search path.""" path = os.environ.get("PATH") if not path: - return 0 + return False for d in path.split(os.pathsep): exe = os.path.join(d, cmd) if os.path.isfile(exe): - return 1 - return 0 + return True + return False PROCESS_CREATION_DELAY = 4 diff --git a/Modules/cgen.py b/Modules/cgen.py index 6403eae64335..af336cef5e27 100644 --- a/Modules/cgen.py +++ b/Modules/cgen.py @@ -56,10 +56,10 @@ def getnum(s): # Function to check if a string is a number # def isnum(s): - if not s: return 0 + if not s: return False for c in s: - if not c in digits: return 0 - return 1 + if not c in digits: return False + return True # Allowed function return types diff --git a/Tools/idle/EditorWindow.py b/Tools/idle/EditorWindow.py index f924c45289d2..9dd51b68d4dd 100644 --- a/Tools/idle/EditorWindow.py +++ b/Tools/idle/EditorWindow.py @@ -375,16 +375,16 @@ class EditorWindow: def ispythonsource(self, filename): if not filename: - return 1 + return True base, ext = os.path.splitext(os.path.basename(filename)) if os.path.normcase(ext) in (".py", ".pyw"): - return 1 + return True try: f = open(filename) line = f.readline() f.close() except IOError: - return 0 + return False return line[:2] == '#!' and string.find(line, 'python') >= 0 def close_hook(self): diff --git a/Tools/idle/IOBinding.py b/Tools/idle/IOBinding.py index 5d41d3592e47..dfea0b6618b1 100644 --- a/Tools/idle/IOBinding.py +++ b/Tools/idle/IOBinding.py @@ -92,7 +92,7 @@ class IOBinding: f.close() except IOError, msg: tkMessageBox.showerror("I/O Error", str(msg), master=self.text) - return 0 + return False self.text.delete("1.0", "end") self.set_filename(None) self.text.insert("1.0", chars) @@ -100,7 +100,7 @@ class IOBinding: self.set_filename(filename) self.text.mark_set("insert", "1.0") self.text.see("insert") - return 1 + return True def maybesave(self): if self.get_saved(): @@ -154,11 +154,11 @@ class IOBinding: f.write(chars) f.close() ## print "saved to", `filename` - return 1 + return True except IOError, msg: tkMessageBox.showerror("I/O Error", str(msg), master=self.text) - return 0 + return False def fixlastline(self): c = self.text.get("end-2c") diff --git a/Tools/idle/ObjectBrowser.py b/Tools/idle/ObjectBrowser.py index c235a7564f9a..416be5a15fc6 100644 --- a/Tools/idle/ObjectBrowser.py +++ b/Tools/idle/ObjectBrowser.py @@ -59,7 +59,7 @@ class ObjectTreeItem(TreeItem): class InstanceTreeItem(ObjectTreeItem): def IsExpandable(self): - return 1 + return True def GetSubList(self): sublist = ObjectTreeItem.GetSubList(self) sublist.insert(0, @@ -68,7 +68,7 @@ class InstanceTreeItem(ObjectTreeItem): class ClassTreeItem(ObjectTreeItem): def IsExpandable(self): - return 1 + return True def GetSubList(self): sublist = ObjectTreeItem.GetSubList(self) if len(self.object.__bases__) == 1: diff --git a/Tools/idle/PyShell.py b/Tools/idle/PyShell.py index 03b468424d0a..2c471dee2798 100644 --- a/Tools/idle/PyShell.py +++ b/Tools/idle/PyShell.py @@ -439,7 +439,7 @@ class PyShell(OutputWindow): def ispythonsource(self, filename): # Override this so EditorWindow never removes the colorizer - return 1 + return True def short_title(self): return self.shell_title @@ -482,7 +482,7 @@ class PyShell(OutputWindow): return line def isatty(self): - return 1 + return True def cancel_callback(self, event): try: @@ -685,7 +685,7 @@ class PseudoFile: pass def isatty(self): - return 1 + return True usage_msg = """\ diff --git a/Tools/idle/ReplaceDialog.py b/Tools/idle/ReplaceDialog.py index 83462f9a1f79..1e46f3656587 100644 --- a/Tools/idle/ReplaceDialog.py +++ b/Tools/idle/ReplaceDialog.py @@ -111,24 +111,24 @@ class ReplaceDialog(SearchDialogBase): def do_find(self, ok=0): if not self.engine.getprog(): - return 0 + return False text = self.text res = self.engine.search_text(text, None, ok) if not res: text.bell() - return 0 + return False line, m = res i, j = m.span() first = "%d.%d" % (line, i) last = "%d.%d" % (line, j) self.show_hit(first, last) self.ok = 1 - return 1 + return True def do_replace(self): prog = self.engine.getprog() if not prog: - return 0 + return False text = self.text try: first = pos = text.index("sel.first") @@ -141,7 +141,7 @@ class ReplaceDialog(SearchDialogBase): chars = text.get("%d.0" % line, "%d.0" % (line+1)) m = prog.match(chars, col) if not prog: - return 0 + return False new = self._expand(m, self.replvar.get()) text.mark_set("insert", first) text.undo_block_start() @@ -152,7 +152,7 @@ class ReplaceDialog(SearchDialogBase): text.undo_block_stop() self.show_hit(first, text.index("insert")) self.ok = 0 - return 1 + return True def _expand(self, m, template): # XXX This code depends on internals of the regular expression diff --git a/Tools/idle/SearchDialog.py b/Tools/idle/SearchDialog.py index 0f0cb189f6b7..8d275c4437b6 100644 --- a/Tools/idle/SearchDialog.py +++ b/Tools/idle/SearchDialog.py @@ -34,9 +34,9 @@ class SearchDialog(SearchDialogBase): def find_again(self, text): if not self.engine.getpat(): self.open(text) - return 0 + return False if not self.engine.getprog(): - return 0 + return False res = self.engine.search_text(text) if res: line, m = res @@ -48,17 +48,17 @@ class SearchDialog(SearchDialogBase): sellast = text.index("sel.last") if selfirst == first and sellast == last: text.bell() - return 0 + return False except TclError: pass text.tag_remove("sel", "1.0", "end") text.tag_add("sel", first, last) text.mark_set("insert", self.engine.isback() and first or last) text.see("insert") - return 1 + return True else: text.bell() - return 0 + return False def find_selection(self, text): pat = text.get("sel.first", "sel.last")