8.1 Abstract Data Types and Classes
Why bound a set of objects and the operations on those objects together with an abstract data type?
One can pass an object from one part of a program to another, and in doing so provide access not only to the data attributes of the object but also to operations that make it easy to manipulate that data.
What does a specification of a class’s operations do?
The specifications of those operations define an interface between the abstract data type and the rest of the program. The interface defines the behavior of the operations—what they do, but not how they do it. The interface thus provides an abstraction barrier that isolates the rest of the program from the data structures, algorithms, and code involved in providing a realization of the type abstraction.
What mechanisms are available for accomplishing the goal of managing complexity in a way that facilitates change?
Decomposition creates structure in a program, and abstraction suppresses detail.
Why someone has a great leg up in maintaining a software for years?
The key is to suppress the appropriate details. This is where data abstraction hits the mark.
One can create domain-specific types that provide a convenient abstraction. Ideally, these types capture concepts that will be relevant over the lifetime of a program. If one starts the programming process by devising types that will be relevant months and even decades later, one has a great leg up in maintaining that software.
What is the code of implementation an “intset”?
class IntSet(object):
"""An intSet is a set of integers"""
#Information about the implementation (not the abstraction)
#Value of the set is represented by a list of ints, self.vals.
#Each int in the set occurs in self.vals exactly once.
def __init__(self):
"""Create an empty set of integers"""
self.vals = []
def insert(self, e):
"""Assumes e is an integer and inserts e into self"""
if e not in self.vals:
self.vals.append(e)
def member(self, e):
"""Assumes e is an integer
Returns True if e is in self, and False otherwise"""
return e in self.vals
def remove(self, e):
"""Assumes e is an integer and removes e from self
Raises ValueError if e is not in self"""
try:
self.vals.remove(e)
except:
raise ValueError(str(e) + ' not found')
def getMembers(self):
"""Returns a list containing the elements of self.
Nothing can be assumed about the order of the elements"""
return self.vals[:]
def __str__(self):
"""Returns a string representation of self"""
self.vals.sort()
result = ''
for e in self.vals:
result = result + str(e) + ','
return '{' + result[:-1] + '}' #-1 omits trailing comma
What is a function inside a class called?
a method that associated with the class
method attributes of the class
What is the relationship of type, class, method and function?
A class should not be confused with instances of that class, just as an object of type list should not be confused with the list type.
s = IntSet()
s.insert(3)
print("Whether '3' exists in 's':", s.member(3))
print ("Type of 'IntSet' is " + str(type (IntSet)) + ".\n" +
"Type of 'IntSet.insert' is " + str(type (IntSet.insert)) + ".")
print ("Type of 's' is " + str(type (s)) + ".\n" +
"Type of 's.insert' is " + str(type(s.insert)) + ".")
What are method attributes and data attributes?
Method attributes are defined in a class definition, for example IntSet.member
is an attribute of the class IntSet
. When the class is instantiated, e.g., by the statement s = IntSet()
, instance attributes, e.g., s.member
, are created.
When data attributes are associated with a class we call them class variables. When they are associated with an instance we call them instance variables.
What is representation-independence?
Data abstraction achieves representation-independence. Think of the im- plementation of an abstract type as having several components:
- Implementations of the methods of the type,
- Data structures that together encode values of the type, and
- Conventions about how the implementations of the methods are to use the data structures. A key convention is captured by the representation invariant.
What is representation invariant?
The representation invariant defines which values of the data attributes correspond to valid representations of class instances. The representation invariant for IntSet
is that vals
contains no duplicates. The implementation of __init__
is responsible for establishing the invariant (which holds on the empty list), and the other methods are responsible for maintaining that invariant. That is why insert
appends e only if it is not already in self.vals
. The implementation of remove
exploits the assumption that the representation invariant is satisfied when remove
is entered. It calls list.remove
only once, since the representation invariant guarantees that there is at most one occurrence of e
in self.vals
.
Is a user-defined class instance hashable?
Any instance of a user-defined class is hashable
All instances of user-defined classes are hashable, and therefore can be used as dictionary keys. If no __hash__
method is provided, the hash value of the object is derived from the function id
.
Why abstract data types are a big deal[^a big deal]?
They lead to a different way of thinking about organizing large programs.
Rely on abstraction when trying to understand concepts about the world
When we think about the world, we rely on abstractions. In the world of finance people talk about stocks and bonds. In the world of biology people talk about proteins and residues. When trying to understand concepts such as these, we mentally gather together some of the relevant data and features of these kinds of objects into one intellectual package. For example, we think of bonds as having an interest rate and a maturity date as data attributes. We also think of bonds as having operations such as “set price” and “calculate yield to maturity.” Abstract data types allow us to incorporate this kind of organization into the design of programs.
Focus on the centrality of data object rather than functions when designing programs
Data abstraction encourages program designers to focus on the centrality of data objects rather than functions. Thinking about a program more as a collection of types than as a collection of functions leads to a profoundly different organizing principle. Among other things, it encourages one to think about programming as a process of combining relatively large chunks, since data abstractions typically encompass[^encompass] more functionality than do individual functions. This, in turn, leads us to think of the essence of programming as a process not of writing individual lines of code, but of composing[^compose] abstractions.
Reuse abstractions to reduce development time and to yield more reliable programs
The availability of reusable abstractions not only reduces development time, but also usually leads to more reliable programs, because mature software is usually more reliable than new software. For many years, the only program libraries in common use were statistical or scientific. Today, however, there is a great range of available program libraries (especially for Python), often based on a rich set of data abstractions.
[^a big deal]: a big deal: informal [usually with negative] a thing considered important: they don’t make a big deal out of minor irritations. • an important person: Sam Kinison became a big deal. • (big deal) used to express one’s contempt for something regarded as impressive or important by another person: “I’ll give you an allowance,” he said. “Big deal,” she thought. [^encompass]: encompass: To circumscribe or go round so as to surround closely; to encircle; to inclose; to environ; as, a ring encompasses the finger; an army encompasses a city; a voyage encompassing the world. - Shak. A question may be encompassed with difficulty. - C. J. Smith. [^compose]: compose: To construct by mental labor; to design and execute, or put together, in a manner involving the adaptation of forms of expression to ideas, or to the laws of harmony or proportion; as, to compose a sentence, a sermon, a symphony, or a picture.
What abstraction might be useful, before rushing in to design a bunch of data structures to keep track of all the students and faculty, ?
Is there an abstraction that covers the common attributes of students, professors, and staff? Some would argue that they are all human. The following code contains a class that incorporates some of the common attributes (name and birthday) of humans.
import datetime
class Person(object):
def __init__(self, name):
"""Create a person"""
self.name = name
try:
lastBlank = name.rindex(' ')
self.lastName = name[lastBlank+1:]
except:
self.lastName = name
self.birthday = None
def getName(self):
"""Returns self's full name"""
return self.name
def getLastName(self):
"""Returns self's last name"""
return self.lastName
def setBirthday(self, birthdate):
""" Assumes birthdate is of type datetime.date
Sets self's birthday to birthdate"""
self.birthday = birthdate
def getAge(self):
"""Returns self's current age in days"""
if self.birthday == None:
raise ValueError
return (datetime.date.today() - self.birthday).days
def __lt__(self, other):
"""Returns True if self precedes other in alphabetical
order, and False otherwise. Comparison is based on last
names, but if these are the same full names are
compared."""
if self.lastName == other.lastName:
return self.name < other.name
return self.lastName < other.lastName
def __str__(self):
"""Returns self's name"""
return self.name
The following code makes use of Person.
Barack Hussein Obama is 21493 days old
LS0tCnRpdGxlOiAwOCBDTEFTU0VTIEFORCBPQkpFQ1QtT1JJRU5URUQgUFJPR1JBTU1JTkcKc3VidGl0bGU6IAphdXRob3I6IOabsuaUvwpkYXRlOiAyMDIwLTA1LTI5CnNsdWc6IGNsYXNzZXMgYW5kIG9iamVjdC1vcmllbnRlZCBwcm9ncmFtbWluZwp0YWdzOgotIApjYXRlZ29yaWVzOgotIG1pdDYwMDAKLSBJQ1BQIGJvb2tub3Rlcwp0eXBvcmEtcm9vdC11cmw6IC4uLy4uL3N0YXRpYwpzaG93X3RvYzogeWVzCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyBXaGF0IGlzIHRoZSBrZXkgdG8gb2JqZWN0LW9yaWVudGVkIHByb2dyYW1taW5nPwoKVGhpbmsgYWJvdXQgb2JqZWN0cyBhcyBjb2xsZWN0aW9ucyBvZiBib3RoIGRhdGEgYW5kIHRoZSBtZXRoLSBvZHMgdGhhdCBvcGVyYXRlIG9uIHRoYXQgZGF0YS4KCiMjIDguMSBBYnN0cmFjdCBEYXRhIFR5cGVzIGFuZCBDbGFzc2VzCgojIyMgV2h5IGJvdW5kIGEgc2V0IG9mIG9iamVjdHMgYW5kIHRoZSBvcGVyYXRpb25zIG9uIHRob3NlIG9iamVjdHMgdG9nZXRoZXIgd2l0aCBhbiBhYnN0cmFjdCBkYXRhIHR5cGU/CgpPbmUgY2FuIHBhc3MgYW4gb2JqZWN0IGZyb20gb25lIHBhcnQgb2YgYSBwcm9ncmFtIHRvIGFub3RoZXIsIGFuZCBpbiBkb2luZyBzbyBwcm92aWRlIGFjY2VzcyBub3Qgb25seSB0byB0aGUgZGF0YSBhdHRyaWJ1dGVzIG9mIHRoZSBvYmplY3QgYnV0IGFsc28gdG8gb3BlcmF0aW9ucyB0aGF0IG1ha2UgaXQgZWFzeSB0byBtYW5pcHVsYXRlIHRoYXQgZGF0YS4KCiMjIyBXaGF0IGRvZXMgYSBzcGVjaWZpY2F0aW9uIG9mIGEgY2xhc3MncyBvcGVyYXRpb25zIGRvPwoKVGhlIHNwZWNpZmljYXRpb25zIG9mIHRob3NlIG9wZXJhdGlvbnMgZGVmaW5lIGFuICoqaW50ZXJmYWNlKiogYmV0d2VlbiB0aGUgYWJzdHJhY3QgZGF0YSB0eXBlIGFuZCB0aGUgcmVzdCBvZiB0aGUgcHJvZ3JhbS4gVGhlIGludGVyZmFjZSBkZWZpbmVzIHRoZSBiZWhhdmlvciBvZiB0aGUgb3BlcmF0aW9uc+KAlHdoYXQgdGhleSBkbywgYnV0IG5vdCBob3cgdGhleSBkbyBpdC4gVGhlIGludGVyZmFjZSB0aHVzIHByb3ZpZGVzIGFuICoqYWJzdHJhY3Rpb24gYmFycmllcioqIHRoYXQgaXNvbGF0ZXMgdGhlIHJlc3Qgb2YgdGhlIHByb2dyYW0gZnJvbSB0aGUgZGF0YSBzdHJ1Y3R1cmVzLCBhbGdvcml0aG1zLCBhbmQgY29kZSBpbnZvbHZlZCBpbiBwcm92aWRpbmcgYSByZWFsaXphdGlvbiBvZiB0aGUgdHlwZSBhYnN0cmFjdGlvbi4KCiMjIyBXaGF0IG1lY2hhbmlzbXMgYXJlIGF2YWlsYWJsZSBmb3IgYWNjb21wbGlzaGluZyB0aGUgZ29hbCBvZiBtYW5hZ2luZyBjb21wbGV4aXR5IGluIGEgd2F5IHRoYXQgZmFjaWxpdGF0ZXMgY2hhbmdlPwoKRGVjb21wb3NpdGlvbiBjcmVhdGVzIHN0cnVjdHVyZSBpbiBhIHByb2dyYW0sIGFuZCBhYnN0cmFjdGlvbiBzdXBwcmVzc2VzIGRldGFpbC4KCiMjIyBXaHkgc29tZW9uZSBoYXMgYSBncmVhdCBsZWcgdXAgaW4gbWFpbnRhaW5pbmcgYSBzb2Z0d2FyZSBmb3IgeWVhcnM/CgpUaGUga2V5IGlzIHRvIHN1cHByZXNzIHRoZSBhcHByb3ByaWF0ZSBkZXRhaWxzLiBUaGlzIGlzIHdoZXJlIGRhdGEgYWJzdHJhY3Rpb24gaGl0cyB0aGUgbWFyay4gCgpPbmUgY2FuIGNyZWF0ZSBkb21haW4tc3BlY2lmaWMgdHlwZXMgdGhhdCBwcm92aWRlIGEgY29udmVuaWVudCBhYnN0cmFjdGlvbi4gSWRlYWxseSwgdGhlc2UgdHlwZXMgY2FwdHVyZSBjb25jZXB0cyB0aGF0IHdpbGwgYmUgcmVsZXZhbnQgb3ZlciB0aGUgbGlmZXRpbWUgb2YgYSBwcm9ncmFtLiBJZiBvbmUgc3RhcnRzIHRoZSBwcm9ncmFtbWluZyBwcm9jZXNzIGJ5IGRldmlzaW5nIHR5cGVzIHRoYXQgd2lsbCBiZSByZWxldmFudCBtb250aHMgYW5kIGV2ZW4gZGVjYWRlcyBsYXRlciwgb25lIGhhcyBhIGdyZWF0IGxlZyB1cCBpbiBtYWludGFpbmluZyB0aGF0IHNvZnR3YXJlLgoKIyMjIFdoYXQgYXJlIHRoZSBjb21tZW50cyBiZWxvdyB0aGUgZG9jc3RyaW5nIG9mIGNsYXNzIGFuZCBmdW5jdGlvbj8KCkluIGNvbnRyYXN0LCB0aGUgY29tbWVudHMgYmVsb3cgdGhlIGRvY3N0cmluZyBjb250YWluIGluZm9ybWF0aW9uIGFib3V0IHRoZSBpbXBsZW1lbnRhdGlvbi4gVGhhdCBpbmZvcm1hdGlvbiBpcyBhaW1lZCBhdCBwcm9ncmFtbWVycyB3aG8gbWlnaHQgd2FudCB0byBtb2RpZnkgdGhlIGltcGxlbWVudGF0aW9uIG9yIGJ1aWxkIHN1YmNsYXNzZXMgb2YgdGhlIGNsYXNzLCBub3QgYXQgcHJvZ3JhbW1lcnMgd2hvIG1pZ2h0IHdhbnQgdG8gdXNlIHRoZSBhYnN0cmFjdGlvbi4KCiMjIyBXaGF0IGlzIHRoZSBjb2RlIG9mIGltcGxlbWVudGF0aW9uIGFuICJpbnRzZXQiPwoKYGBge3B5dGhvbn0KY2xhc3MgSW50U2V0KG9iamVjdCk6CiAgICAiIiJBbiBpbnRTZXQgaXMgYSBzZXQgb2YgaW50ZWdlcnMiIiIKICAgICNJbmZvcm1hdGlvbiBhYm91dCB0aGUgaW1wbGVtZW50YXRpb24gKG5vdCB0aGUgYWJzdHJhY3Rpb24pCiAgICAjVmFsdWUgb2YgdGhlIHNldCBpcyByZXByZXNlbnRlZCBieSBhIGxpc3Qgb2YgaW50cywgc2VsZi52YWxzLgogICAgI0VhY2ggaW50IGluIHRoZSBzZXQgb2NjdXJzIGluIHNlbGYudmFscyBleGFjdGx5IG9uY2UuCiAgICBkZWYgX19pbml0X18oc2VsZik6CiAgICAgICAgIiIiQ3JlYXRlIGFuIGVtcHR5IHNldCBvZiBpbnRlZ2VycyIiIiAKICAgICAgICBzZWxmLnZhbHMgPSBbXQoKICAgIGRlZiBpbnNlcnQoc2VsZiwgZSk6CiAgICAgICAgIiIiQXNzdW1lcyBlIGlzIGFuIGludGVnZXIgYW5kIGluc2VydHMgZSBpbnRvIHNlbGYiIiIKICAgICAgICBpZiBlIG5vdCBpbiBzZWxmLnZhbHM6CiAgICAgICAgICAgIHNlbGYudmFscy5hcHBlbmQoZSkKCiAgICBkZWYgbWVtYmVyKHNlbGYsIGUpOgogICAgICAgICIiIkFzc3VtZXMgZSBpcyBhbiBpbnRlZ2VyCiAgICAgICAgICAgUmV0dXJucyBUcnVlIGlmIGUgaXMgaW4gc2VsZiwgYW5kIEZhbHNlIG90aGVyd2lzZSIiIgogICAgICAgIHJldHVybiBlIGluIHNlbGYudmFscwoKICAgIGRlZiByZW1vdmUoc2VsZiwgZSk6CiAgICAgICAgIiIiQXNzdW1lcyBlIGlzIGFuIGludGVnZXIgYW5kIHJlbW92ZXMgZSBmcm9tIHNlbGYKICAgICAgICAgICBSYWlzZXMgVmFsdWVFcnJvciBpZiBlIGlzIG5vdCBpbiBzZWxmIiIiCiAgICAgICAgdHJ5OgogICAgICAgICAgICBzZWxmLnZhbHMucmVtb3ZlKGUpCiAgICAgICAgZXhjZXB0OgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKHN0cihlKSArICcgbm90IGZvdW5kJykKCiAgICBkZWYgZ2V0TWVtYmVycyhzZWxmKToKICAgICAgICAiIiJSZXR1cm5zIGEgbGlzdCBjb250YWluaW5nIHRoZSBlbGVtZW50cyBvZiBzZWxmLgogICAgICAgICAgIE5vdGhpbmcgY2FuIGJlIGFzc3VtZWQgYWJvdXQgdGhlIG9yZGVyIG9mIHRoZSBlbGVtZW50cyIiIgogICAgICAgIHJldHVybiBzZWxmLnZhbHNbOl0KCiAgICBkZWYgX19zdHJfXyhzZWxmKToKICAgICAgICAiIiJSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHNlbGYiIiIKICAgICAgICBzZWxmLnZhbHMuc29ydCgpCiAgICAgICAgcmVzdWx0ID0gJycKICAgICAgICBmb3IgZSBpbiBzZWxmLnZhbHM6CiAgICAgICAgICAgIHJlc3VsdCA9IHJlc3VsdCArIHN0cihlKSArICcsJwogICAgICAgIHJldHVybiAneycgKyByZXN1bHRbOi0xXSArICd9JyAjLTEgb21pdHMgdHJhaWxpbmcgY29tbWEKYGBgCgojIyMgV2hhdCBpcyBhIGZ1bmN0aW9uIGluc2lkZSBhIGNsYXNzIGNhbGxlZD8KCmEgbWV0aG9kIHRoYXQgYXNzb2NpYXRlZCB3aXRoIHRoZSBjbGFzcwoKbWV0aG9kIGF0dHJpYnV0ZXMgb2YgdGhlIGNsYXNzCgojIyMgV2hhdCBpcyB0aGUgcmVsYXRpb25zaGlwIG9mIHR5cGUsIGNsYXNzLCBtZXRob2QgYW5kIGZ1bmN0aW9uPwoKQSBjbGFzcyBzaG91bGQgbm90IGJlIGNvbmZ1c2VkIHdpdGggaW5zdGFuY2VzIG9mIHRoYXQgY2xhc3MsIGp1c3QgYXMgYW4gb2JqZWN0IG9mIHR5cGUgbGlzdCBzaG91bGQgbm90IGJlIGNvbmZ1c2VkIHdpdGggdGhlIGxpc3QgdHlwZS4KCmBgYHtweXRob259CnMgPSBJbnRTZXQoKSAKcy5pbnNlcnQoMykgCnByaW50KCJXaGV0aGVyICczJyBleGlzdHMgaW4gJ3MnOiIsIHMubWVtYmVyKDMpKQpwcmludCAoIlR5cGUgb2YgJ0ludFNldCcgaXMgIiArIHN0cih0eXBlIChJbnRTZXQpKSArICIuXG4iICsgCiAgICAgICAiVHlwZSBvZiAnSW50U2V0Lmluc2VydCcgaXMgIiArIHN0cih0eXBlIChJbnRTZXQuaW5zZXJ0KSkgKyAiLiIpCnByaW50ICgiVHlwZSBvZiAncycgaXMgIiArIHN0cih0eXBlIChzKSkgKyAiLlxuIiArIAogICAgICAgIlR5cGUgb2YgJ3MuaW5zZXJ0JyBpcyAiICsgc3RyKHR5cGUocy5pbnNlcnQpKSArICIuIikKYGBgCgojIyMgV2hhdCBhcmUgbWV0aG9kIGF0dHJpYnV0ZXMgYW5kIGRhdGEgYXR0cmlidXRlcz8KCk1ldGhvZCBhdHRyaWJ1dGVzIGFyZSBkZWZpbmVkIGluIGEgY2xhc3MgZGVmaW5pdGlvbiwgZm9yIGV4YW1wbGUgYEludFNldC5tZW1iZXJgIGlzIGFuIGF0dHJpYnV0ZSBvZiB0aGUgY2xhc3MgYEludFNldGAuIFdoZW4gdGhlIGNsYXNzIGlzIGluc3RhbnRpYXRlZCwgZS5nLiwgYnkgdGhlIHN0YXRlbWVudCBgcyA9IEludFNldCgpYCwgaW5zdGFuY2UgYXR0cmlidXRlcywgZS5nLiwgYHMubWVtYmVyYCwgYXJlIGNyZWF0ZWQuCgpXaGVuIGRhdGEgYXR0cmlidXRlcyBhcmUgYXNzb2NpYXRlZCB3aXRoIGEgY2xhc3Mgd2UgY2FsbCB0aGVtIGNsYXNzIHZhcmlhYmxlcy4gV2hlbiB0aGV5IGFyZSBhc3NvY2lhdGVkIHdpdGggYW4gaW5zdGFuY2Ugd2UgY2FsbCB0aGVtIGluc3RhbmNlIHZhcmlhYmxlcy4KCiMjIyBXaGF0IGlzIHJlcHJlc2VudGF0aW9uLWluZGVwZW5kZW5jZT8KCkRhdGEgYWJzdHJhY3Rpb24gYWNoaWV2ZXMgcmVwcmVzZW50YXRpb24taW5kZXBlbmRlbmNlLiBUaGluayBvZiB0aGUgaW0tIHBsZW1lbnRhdGlvbiBvZiBhbiBhYnN0cmFjdCB0eXBlIGFzIGhhdmluZyBzZXZlcmFsIGNvbXBvbmVudHM6CgotIEltcGxlbWVudGF0aW9ucyBvZiB0aGUgbWV0aG9kcyBvZiB0aGUgdHlwZSwKLSBEYXRhIHN0cnVjdHVyZXMgdGhhdCB0b2dldGhlciBlbmNvZGUgdmFsdWVzIG9mIHRoZSB0eXBlLCBhbmQKLSBDb252ZW50aW9uc1teY29udmVudGlvbl0gYWJvdXQgaG93IHRoZSBpbXBsZW1lbnRhdGlvbnMgb2YgdGhlIG1ldGhvZHMgYXJlIHRvIHVzZSB0aGUgZGF0YSBzdHJ1Y3R1cmVzLiBBIGtleSBjb252ZW50aW9uIGlzIGNhcHR1cmVkIGJ5IHRoZSByZXByZXNlbnRhdGlvbltecmVwcmVzZW50YXRpb25dIGludmFyaWFudFteaW52YXJpYW50XS4KCiMjIyBXaGF0IGlzIHJlcHJlc2VudGF0aW9uIGludmFyaWFudD8KClRoZSAqKnJlcHJlc2VudGF0aW9uIGludmFyaWFudCoqIGRlZmluZXMgd2hpY2ggdmFsdWVzIG9mIHRoZSBkYXRhIGF0dHJpYnV0ZXMgY29ycmVzcG9uZCB0byB2YWxpZCByZXByZXNlbnRhdGlvbnMgb2YgY2xhc3MgaW5zdGFuY2VzLiBUaGUgcmVwcmVzZW50YXRpb24gaW52YXJpYW50IGZvciBgSW50U2V0YCBpcyB0aGF0IGB2YWxzYCBjb250YWlucyBubyBkdXBsaWNhdGVzLiBUaGUgaW1wbGVtZW50YXRpb24gb2YgYF9faW5pdF9fYCBpcyByZXNwb25zaWJsZSBmb3IgZXN0YWJsaXNoaW5nIHRoZSBpbnZhcmlhbnQgKHdoaWNoIGhvbGRzIG9uIHRoZSBlbXB0eSBsaXN0KSwgYW5kIHRoZSBvdGhlciBtZXRob2RzIGFyZSByZXNwb25zaWJsZSBmb3IgbWFpbnRhaW5pbmcgdGhhdCBpbnZhcmlhbnQuIFRoYXQgaXMgd2h5IGBpbnNlcnRgIGFwcGVuZHMgZSBvbmx5IGlmIGl0IGlzIG5vdCBhbHJlYWR5IGluIGBzZWxmLnZhbHNgLiBUaGUgaW1wbGVtZW50YXRpb24gb2YgYHJlbW92ZWAgZXhwbG9pdHMgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgcmVwcmVzZW50YXRpb24gaW52YXJpYW50IGlzIHNhdGlzZmllZCB3aGVuIGByZW1vdmVgIGlzIGVudGVyZWQuIEl0IGNhbGxzIGBsaXN0LnJlbW92ZWAgb25seSBvbmNlLCBzaW5jZSB0aGUgcmVwcmVzZW50YXRpb24gaW52YXJpYW50IGd1YXJhbnRlZXMgdGhhdCB0aGVyZSBpcyBhdCBtb3N0IG9uZSBvY2N1cnJlbmNlIG9mIGBlYCBpbiBgc2VsZi52YWxzYC4KClteY29udmVudGlvbl06ICoqY29udmVudGlvbioqOiBHZW5lcmFsIGFncmVlbWVudCBvciBjb25jdXJyZW5jZTsgYXJiaXRyYXJ5IGN1c3RvbTsgdXNhZ2U7IGNvbnZlbnRpb25hbGl0eS4KW15yZXByZXNlbnRhdGlvbl06ICoqcmVwcmVzZW50YXRpb24qKjogVGhhdCB3aGljaCByZXByZXNlbnRzLiBTcGVjaWZpY2FsbHk6IEEgZGVzY3JpcHRpb24gb3Igc3RhdGVtZW50OyBhcywgdGhlIHJlcHJlc2VudGF0aW9uIG9mIGFuIGhpc3Rvcmlhbiwgb2YgYSB3aXRuZXNzLCBvciBhbiBhZHZvY2F0ZS4KW15pbnZhcmlhbnRdOiAqKmludmFyaWFudCoqOiBuLiAoTWF0aC4pIEFuIGludmFyaWFibGUgcXVhbnRpdHk7IHNwZWNpZmljYWxseSwgYSBmdW5jdGlvbiBvZiB0aGUgY29lZmZpY2llbnRzIG9mIG9uZSBvciBtb3JlIGZvcm1zLCB3aGljaCByZW1haW5zIHVuYWx0ZXJlZCwgd2hlbiB0aGVzZSB1bmRlcmdvIHN1aXRhYmxlIGxpbmVhciB0cmFuc2Zvcm1hdGlvbnMuICAtIEouIEouIFN5bHZlc3Rlci4KCiMjIyBJcyBhIHVzZXItZGVmaW5lZCBjbGFzcyBpbnN0YW5jZSBoYXNoYWJsZT8KCiMjIyMgQW55IGluc3RhbmNlIG9mIGEgdXNlci1kZWZpbmVkIGNsYXNzIGlzIGhhc2hhYmxlCgpBbGwgaW5zdGFuY2VzIG9mIHVzZXItZGVmaW5lZCBjbGFzc2VzIGFyZSBoYXNoYWJsZSwgYW5kIHRoZXJlZm9yZSBjYW4gYmUgdXNlZCBhcyBkaWN0aW9uYXJ5IGtleXMuIElmIG5vIGBfX2hhc2hfX2AgbWV0aG9kIGlzIHByb3ZpZGVkLCB0aGUgaGFzaCB2YWx1ZSBvZiB0aGUgb2JqZWN0IGlzIGRlcml2ZWQgZnJvbSB0aGUgZnVuY3Rpb24gYGlkYC4KCiMjIyBXaHkgYWJzdHJhY3QgZGF0YSB0eXBlcyBhcmUgYSBiaWcgZGVhbFteYSBiaWcgZGVhbF0/CgpUaGV5IGxlYWQgdG8gYSBkaWZmZXJlbnQgd2F5IG9mIHRoaW5raW5nIGFib3V0IG9yZ2FuaXppbmcgbGFyZ2UgcHJvZ3JhbXMuIAoKIyMjIyBSZWx5IG9uIGFic3RyYWN0aW9uIHdoZW4gdHJ5aW5nIHRvIHVuZGVyc3RhbmQgY29uY2VwdHMgYWJvdXQgdGhlIHdvcmxkCgpXaGVuIHdlIHRoaW5rIGFib3V0IHRoZSB3b3JsZCwgd2UgcmVseSBvbiBhYnN0cmFjdGlvbnMuIEluIHRoZSB3b3JsZCBvZiBmaW5hbmNlIHBlb3BsZSB0YWxrIGFib3V0IHN0b2NrcyBhbmQgYm9uZHMuIEluIHRoZSB3b3JsZCBvZiBiaW9sb2d5IHBlb3BsZSB0YWxrIGFib3V0IHByb3RlaW5zIGFuZCByZXNpZHVlcy4gV2hlbiB0cnlpbmcgdG8gdW5kZXJzdGFuZCBjb25jZXB0cyBzdWNoIGFzIHRoZXNlLCB3ZSBtZW50YWxseSBnYXRoZXIgdG9nZXRoZXIgc29tZSBvZiB0aGUgcmVsZXZhbnQgKipkYXRhIGFuZCBmZWF0dXJlcyoqIG9mIHRoZXNlIGtpbmRzIG9mIG9iamVjdHMgaW50byBvbmUgKippbnRlbGxlY3R1YWwgcGFja2FnZSoqLiBGb3IgZXhhbXBsZSwgd2UgdGhpbmsgb2YgYm9uZHMgYXMgaGF2aW5nIGFuIGludGVyZXN0IHJhdGUgYW5kIGEgbWF0dXJpdHkgZGF0ZSBhcyBkYXRhIGF0dHJpYnV0ZXMuIFdlIGFsc28gdGhpbmsgb2YgYm9uZHMgYXMgaGF2aW5nIG9wZXJhdGlvbnMgc3VjaCBhcyDigJxzZXQgcHJpY2XigJ0gYW5kIOKAnGNhbGN1bGF0ZSB5aWVsZCB0byBtYXR1cml0eS7igJ0gQWJzdHJhY3QgZGF0YSB0eXBlcyBhbGxvdyB1cyB0byBpbmNvcnBvcmF0ZSB0aGlzIGtpbmQgb2Ygb3JnYW5pemF0aW9uIGludG8gdGhlIGRlc2lnbiBvZiBwcm9ncmFtcy4KCiMjIyMgRm9jdXMgb24gdGhlIGNlbnRyYWxpdHkgb2YgZGF0YSBvYmplY3QgcmF0aGVyIHRoYW4gZnVuY3Rpb25zIHdoZW4gZGVzaWduaW5nIHByb2dyYW1zIAoKRGF0YSBhYnN0cmFjdGlvbiBlbmNvdXJhZ2VzIHByb2dyYW0gZGVzaWduZXJzIHRvIGZvY3VzIG9uIHRoZSBjZW50cmFsaXR5IG9mIGRhdGEgb2JqZWN0cyByYXRoZXIgdGhhbiBmdW5jdGlvbnMuIFRoaW5raW5nIGFib3V0IGEgcHJvZ3JhbSBtb3JlIGFzIGEgY29sbGVjdGlvbiBvZiB0eXBlcyB0aGFuIGFzIGEgY29sbGVjdGlvbiBvZiBmdW5jdGlvbnMgbGVhZHMgdG8gYSBwcm9mb3VuZGx5IGRpZmZlcmVudCBvcmdhbml6aW5nIHByaW5jaXBsZS4gQW1vbmcgb3RoZXIgdGhpbmdzLCBpdCBlbmNvdXJhZ2VzIG9uZSB0byB0aGluayBhYm91dCBwcm9ncmFtbWluZyBhcyBhIHByb2Nlc3Mgb2YgY29tYmluaW5nIHJlbGF0aXZlbHkgbGFyZ2UgY2h1bmtzLCBzaW5jZSBkYXRhIGFic3RyYWN0aW9ucyB0eXBpY2FsbHkgZW5jb21wYXNzW15lbmNvbXBhc3NdIG1vcmUgZnVuY3Rpb25hbGl0eSB0aGFuIGRvIGluZGl2aWR1YWwgZnVuY3Rpb25zLiBUaGlzLCBpbiB0dXJuLCBsZWFkcyB1cyB0byB0aGluayBvZiB0aGUgZXNzZW5jZSBvZiBwcm9ncmFtbWluZyBhcyBhIHByb2Nlc3Mgbm90IG9mIHdyaXRpbmcgaW5kaXZpZHVhbCBsaW5lcyBvZiBjb2RlLCBidXQgb2YgY29tcG9zaW5nW15jb21wb3NlXSBhYnN0cmFjdGlvbnMuCgojIyMjIFJldXNlIGFic3RyYWN0aW9ucyB0byByZWR1Y2UgZGV2ZWxvcG1lbnQgdGltZSBhbmQgdG8geWllbGQgbW9yZSByZWxpYWJsZSBwcm9ncmFtcwoKVGhlIGF2YWlsYWJpbGl0eSBvZiByZXVzYWJsZSBhYnN0cmFjdGlvbnMgbm90IG9ubHkgcmVkdWNlcyBkZXZlbG9wbWVudCB0aW1lLCBidXQgYWxzbyB1c3VhbGx5IGxlYWRzIHRvIG1vcmUgcmVsaWFibGUgcHJvZ3JhbXMsIGJlY2F1c2UgbWF0dXJlIHNvZnR3YXJlIGlzIHVzdWFsbHkgbW9yZSByZWxpYWJsZSB0aGFuIG5ldyBzb2Z0d2FyZS4gRm9yIG1hbnkgeWVhcnMsIHRoZSBvbmx5IHByb2dyYW0gbGlicmFyaWVzIGluIGNvbW1vbiB1c2Ugd2VyZSBzdGF0aXN0aWNhbCBvciBzY2llbnRpZmljLiBUb2RheSwgaG93ZXZlciwgdGhlcmUgaXMgYSBncmVhdCByYW5nZSBvZiBhdmFpbGFibGUgcHJvZ3JhbSBsaWJyYXJpZXMgKGVzcGVjaWFsbHkgZm9yIFB5dGhvbiksIG9mdGVuIGJhc2VkIG9uIGEgcmljaCBzZXQgb2YgZGF0YSBhYnN0cmFjdGlvbnMuCgpbXmEgYmlnIGRlYWxdOiAqKmEgYmlnIGRlYWwqKjogKmluZm9ybWFsKiAqW3VzdWFsbHkgd2l0aCBuZWdhdGl2ZV0qIGEgdGhpbmcgY29uc2lkZXJlZCBpbXBvcnRhbnQ6ICp0aGV5IGRvbid0IG1ha2UgYSBiaWcgZGVhbCBvdXQgb2YgbWlub3IgaXJyaXRhdGlvbnMqLiDigKIgYW4gaW1wb3J0YW50IHBlcnNvbjogKlNhbSBLaW5pc29uIGJlY2FtZSBhIGJpZyBkZWFsKi4g4oCiIChiaWcgZGVhbCkgdXNlZCB0byBleHByZXNzIG9uZSdzIGNvbnRlbXB0IGZvciBzb21ldGhpbmcgcmVnYXJkZWQgYXMgaW1wcmVzc2l2ZSBvciBpbXBvcnRhbnQgYnkgYW5vdGhlciBwZXJzb246ICrigJxJJ2xsIGdpdmUgeW91IGFuIGFsbG93YW5jZSzigJ0gaGUgc2FpZC4g4oCcQmlnIGRlYWws4oCdIHNoZSB0aG91Z2h0Ki4KW15lbmNvbXBhc3NdOiAqKmVuY29tcGFzcyoqOiBUbyBjaXJjdW1zY3JpYmUgb3IgZ28gcm91bmQgc28gYXMgdG8gc3Vycm91bmQgY2xvc2VseTsgdG8gZW5jaXJjbGU7IHRvIGluY2xvc2U7IHRvIGVudmlyb247IGFzLCBhIHJpbmcgKmVuY29tcGFzc2VzKiB0aGUgZmluZ2VyOyBhbiBhcm15ICplbmNvbXBhc3NlcyogYSBjaXR5OyBhIHZveWFnZSAqZW5jb21wYXNzaW5nKiB0aGUgd29ybGQuIC0gU2hhay4gQSBxdWVzdGlvbiBtYXkgYmUgKmVuY29tcGFzc2VkKiB3aXRoIGRpZmZpY3VsdHkuIC0gQy4gSi4gU21pdGguClteY29tcG9zZV06ICoqY29tcG9zZSoqOiBUbyBjb25zdHJ1Y3QgYnkgbWVudGFsIGxhYm9yOyB0byBkZXNpZ24gYW5kIGV4ZWN1dGUsIG9yIHB1dCB0b2dldGhlciwgaW4gYSBtYW5uZXIgaW52b2x2aW5nIHRoZSBhZGFwdGF0aW9uIG9mIGZvcm1zIG9mIGV4cHJlc3Npb24gdG8gaWRlYXMsIG9yIHRvIHRoZSBsYXdzIG9mIGhhcm1vbnkgb3IgcHJvcG9ydGlvbjsgYXMsIHRvIGNvbXBvc2UgYSBzZW50ZW5jZSwgYSBzZXJtb24sIGEgc3ltcGhvbnksIG9yIGEgcGljdHVyZS4KCiMjIyBXaGF0IGFic3RyYWN0aW9uIG1pZ2h0IGJlIHVzZWZ1bCwgYmVmb3JlIHJ1c2hpbmcgaW4gdG8gZGVzaWduIGEgYnVuY2ggb2YgZGF0YSBzdHJ1Y3R1cmVzIHRvIGtlZXAgdHJhY2sgb2YgYWxsIHRoZSBzdHVkZW50cyBhbmQgZmFjdWx0eSwgPwoKSXMgdGhlcmUgYW4gYWJzdHJhY3Rpb24gdGhhdCBjb3ZlcnMgdGhlIGNvbW1vbiBhdHRyaWJ1dGVzIG9mIHN0dWRlbnRzLCBwcm9mZXNzb3JzLCBhbmQgc3RhZmY/IFNvbWUgd291bGQgYXJndWUgdGhhdCB0aGV5IGFyZSBhbGwgaHVtYW4uIFRoZSBmb2xsb3dpbmcgY29kZSBjb250YWlucyBhIGNsYXNzIHRoYXQgaW5jb3Jwb3JhdGVzIHNvbWUgb2YgdGhlIGNvbW1vbiBhdHRyaWJ1dGVzIChuYW1lIGFuZCBiaXJ0aGRheSkgb2YgaHVtYW5zLgoKYGBge3B5dGhvbn0KaW1wb3J0IGRhdGV0aW1lCgpjbGFzcyBQZXJzb24ob2JqZWN0KToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBuYW1lKToKICAgICAgICAiIiJDcmVhdGUgYSBwZXJzb24iIiIKICAgICAgICBzZWxmLm5hbWUgPSBuYW1lCiAgICAgICAgdHJ5OgogICAgICAgICAgICBsYXN0QmxhbmsgPSBuYW1lLnJpbmRleCgnICcpCiAgICAgICAgICAgIHNlbGYubGFzdE5hbWUgPSBuYW1lW2xhc3RCbGFuaysxOl0KICAgICAgICBleGNlcHQ6CiAgICAgICAgICAgIHNlbGYubGFzdE5hbWUgPSBuYW1lCiAgICAgICAgc2VsZi5iaXJ0aGRheSA9IE5vbmUKCiAgICBkZWYgZ2V0TmFtZShzZWxmKToKICAgICAgICAiIiJSZXR1cm5zIHNlbGYncyBmdWxsIG5hbWUiIiIKICAgICAgICByZXR1cm4gc2VsZi5uYW1lCgogICAgZGVmIGdldExhc3ROYW1lKHNlbGYpOgogICAgICAgICIiIlJldHVybnMgc2VsZidzIGxhc3QgbmFtZSIiIgogICAgICAgIHJldHVybiBzZWxmLmxhc3ROYW1lCgogICAgZGVmIHNldEJpcnRoZGF5KHNlbGYsIGJpcnRoZGF0ZSk6CiAgICAgICAgIiIiIEFzc3VtZXMgYmlydGhkYXRlIGlzIG9mIHR5cGUgZGF0ZXRpbWUuZGF0ZQogICAgICAgICAgICBTZXRzIHNlbGYncyBiaXJ0aGRheSB0byBiaXJ0aGRhdGUiIiIKICAgICAgICBzZWxmLmJpcnRoZGF5ID0gYmlydGhkYXRlCgogICAgZGVmIGdldEFnZShzZWxmKToKICAgICAgICAiIiJSZXR1cm5zIHNlbGYncyBjdXJyZW50IGFnZSBpbiBkYXlzIiIiCiAgICAgICAgaWYgc2VsZi5iaXJ0aGRheSA9PSBOb25lOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yCiAgICAgICAgcmV0dXJuIChkYXRldGltZS5kYXRlLnRvZGF5KCkgLSBzZWxmLmJpcnRoZGF5KS5kYXlzCgogICAgZGVmIF9fbHRfXyhzZWxmLCBvdGhlcik6CiAgICAgICAgIiIiUmV0dXJucyBUcnVlIGlmIHNlbGYgcHJlY2VkZXMgb3RoZXIgaW4gYWxwaGFiZXRpY2FsCiAgICAgICAgICAgIG9yZGVyLCBhbmQgRmFsc2Ugb3RoZXJ3aXNlLiBDb21wYXJpc29uIGlzIGJhc2VkIG9uIGxhc3QKICAgICAgICAgICAgbmFtZXMsIGJ1dCBpZiB0aGVzZSBhcmUgdGhlIHNhbWUgZnVsbCBuYW1lcyBhcmUKICAgICAgICAgICAgY29tcGFyZWQuIiIiCiAgICAgICAgaWYgc2VsZi5sYXN0TmFtZSA9PSBvdGhlci5sYXN0TmFtZToKICAgICAgICAgICAgcmV0dXJuIHNlbGYubmFtZSA8IG90aGVyLm5hbWUKICAgICAgICByZXR1cm4gc2VsZi5sYXN0TmFtZSA8IG90aGVyLmxhc3ROYW1lCgogICAgZGVmIF9fc3RyX18oc2VsZik6CiAgICAgICAgIiIiUmV0dXJucyBzZWxmJ3MgbmFtZSIiIgogICAgICAgIHJldHVybiBzZWxmLm5hbWUKYGBgCgpUaGUgZm9sbG93aW5nIGNvZGUgbWFrZXMgdXNlIG9mIFBlcnNvbi4KCmBgYHtweXRob259Cm1lID0gUGVyc29uKCdNaWNoYWVsIEd1dHRhZycpCmhpbSA9IFBlcnNvbignQmFyYWNrIEh1c3NlaW4gT2JhbWEnKQpoZXIgPSBQZXJzb24oJ01hZG9ubmEnKQpwcmludChoaW0uZ2V0TGFzdE5hbWUoKSkgCmhpbS5zZXRCaXJ0aGRheShkYXRldGltZS5kYXRlKDE5NjEsIDgsIDQpKSAKaGVyLnNldEJpcnRoZGF5KGRhdGV0aW1lLmRhdGUoMTk1OCwgOCwgMTYpKSAKcHJpbnQoaGltLmdldE5hbWUoKSwgJ2lzJywgaGltLmdldEFnZSgpLCAnZGF5cyBvbGQnKQpgYGAKCgoK