What is the key to object-oriented programming?

Think about objects as collections of both data and the meth- ods that operate on that data.

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 are the comments below the docstring of class and function?

In contrast, the comments below the docstring contain information about the implementation. That information is aimed at programmers who might want to modify the implementation or build subclasses of the class, not at programmers who might want to use the abstraction.

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
  • Conventions1 about how the implementations of the methods are to use the data structures. A key convention is captured by the representation2 invariant3.

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

  1. convention: General agreement or concurrence; arbitrary custom; usage; conventionality.

  2. representation: That which represents. Specifically: A description or statement; as, the representation of an historian, of a witness, or an advocate.

  3. invariant: n. (Math.) An invariable quantity; specifically, a function of the coefficients of one or more forms, which remains unaltered, when these undergo suitable linear transformations. - J. J. Sylvester.

LS0tCnRpdGxlOiAwOCBDTEFTU0VTIEFORCBPQkpFQ1QtT1JJRU5URUQgUFJPR1JBTU1JTkcKc3VidGl0bGU6IAphdXRob3I6IOabsuaUvwpkYXRlOiAyMDIwLTA1LTI5CnNsdWc6IGNsYXNzZXMgYW5kIG9iamVjdC1vcmllbnRlZCBwcm9ncmFtbWluZwp0YWdzOgotIApjYXRlZ29yaWVzOgotIG1pdDYwMDAKLSBJQ1BQIGJvb2tub3Rlcwp0eXBvcmEtcm9vdC11cmw6IC4uLy4uL3N0YXRpYwpzaG93X3RvYzogeWVzCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyBXaGF0IGlzIHRoZSBrZXkgdG8gb2JqZWN0LW9yaWVudGVkIHByb2dyYW1taW5nPwoKVGhpbmsgYWJvdXQgb2JqZWN0cyBhcyBjb2xsZWN0aW9ucyBvZiBib3RoIGRhdGEgYW5kIHRoZSBtZXRoLSBvZHMgdGhhdCBvcGVyYXRlIG9uIHRoYXQgZGF0YS4KCiMjIDguMSBBYnN0cmFjdCBEYXRhIFR5cGVzIGFuZCBDbGFzc2VzCgojIyMgV2h5IGJvdW5kIGEgc2V0IG9mIG9iamVjdHMgYW5kIHRoZSBvcGVyYXRpb25zIG9uIHRob3NlIG9iamVjdHMgdG9nZXRoZXIgd2l0aCBhbiBhYnN0cmFjdCBkYXRhIHR5cGU/CgpPbmUgY2FuIHBhc3MgYW4gb2JqZWN0IGZyb20gb25lIHBhcnQgb2YgYSBwcm9ncmFtIHRvIGFub3RoZXIsIGFuZCBpbiBkb2luZyBzbyBwcm92aWRlIGFjY2VzcyBub3Qgb25seSB0byB0aGUgZGF0YSBhdHRyaWJ1dGVzIG9mIHRoZSBvYmplY3QgYnV0IGFsc28gdG8gb3BlcmF0aW9ucyB0aGF0IG1ha2UgaXQgZWFzeSB0byBtYW5pcHVsYXRlIHRoYXQgZGF0YS4KCiMjIyBXaGF0IGRvZXMgYSBzcGVjaWZpY2F0aW9uIG9mIGEgY2xhc3MncyBvcGVyYXRpb25zIGRvPwoKVGhlIHNwZWNpZmljYXRpb25zIG9mIHRob3NlIG9wZXJhdGlvbnMgZGVmaW5lIGFuICoqaW50ZXJmYWNlKiogYmV0d2VlbiB0aGUgYWJzdHJhY3QgZGF0YSB0eXBlIGFuZCB0aGUgcmVzdCBvZiB0aGUgcHJvZ3JhbS4gVGhlIGludGVyZmFjZSBkZWZpbmVzIHRoZSBiZWhhdmlvciBvZiB0aGUgb3BlcmF0aW9uc+KAlHdoYXQgdGhleSBkbywgYnV0IG5vdCBob3cgdGhleSBkbyBpdC4gVGhlIGludGVyZmFjZSB0aHVzIHByb3ZpZGVzIGFuICoqYWJzdHJhY3Rpb24gYmFycmllcioqIHRoYXQgaXNvbGF0ZXMgdGhlIHJlc3Qgb2YgdGhlIHByb2dyYW0gZnJvbSB0aGUgZGF0YSBzdHJ1Y3R1cmVzLCBhbGdvcml0aG1zLCBhbmQgY29kZSBpbnZvbHZlZCBpbiBwcm92aWRpbmcgYSByZWFsaXphdGlvbiBvZiB0aGUgdHlwZSBhYnN0cmFjdGlvbi4KCiMjIyBXaGF0IG1lY2hhbmlzbXMgYXJlIGF2YWlsYWJsZSBmb3IgYWNjb21wbGlzaGluZyB0aGUgZ29hbCBvZiBtYW5hZ2luZyBjb21wbGV4aXR5IGluIGEgd2F5IHRoYXQgZmFjaWxpdGF0ZXMgY2hhbmdlPwoKRGVjb21wb3NpdGlvbiBjcmVhdGVzIHN0cnVjdHVyZSBpbiBhIHByb2dyYW0sIGFuZCBhYnN0cmFjdGlvbiBzdXBwcmVzc2VzIGRldGFpbC4KCiMjIyBXaHkgc29tZW9uZSBoYXMgYSBncmVhdCBsZWcgdXAgaW4gbWFpbnRhaW5pbmcgYSBzb2Z0d2FyZSBmb3IgeWVhcnM/CgpUaGUga2V5IGlzIHRvIHN1cHByZXNzIHRoZSBhcHByb3ByaWF0ZSBkZXRhaWxzLiBUaGlzIGlzIHdoZXJlIGRhdGEgYWJzdHJhY3Rpb24gaGl0cyB0aGUgbWFyay4gCgpPbmUgY2FuIGNyZWF0ZSBkb21haW4tc3BlY2lmaWMgdHlwZXMgdGhhdCBwcm92aWRlIGEgY29udmVuaWVudCBhYnN0cmFjdGlvbi4gSWRlYWxseSwgdGhlc2UgdHlwZXMgY2FwdHVyZSBjb25jZXB0cyB0aGF0IHdpbGwgYmUgcmVsZXZhbnQgb3ZlciB0aGUgbGlmZXRpbWUgb2YgYSBwcm9ncmFtLiBJZiBvbmUgc3RhcnRzIHRoZSBwcm9ncmFtbWluZyBwcm9jZXNzIGJ5IGRldmlzaW5nIHR5cGVzIHRoYXQgd2lsbCBiZSByZWxldmFudCBtb250aHMgYW5kIGV2ZW4gZGVjYWRlcyBsYXRlciwgb25lIGhhcyBhIGdyZWF0IGxlZyB1cCBpbiBtYWludGFpbmluZyB0aGF0IHNvZnR3YXJlLgoKIyMjIFdoYXQgYXJlIHRoZSBjb21tZW50cyBiZWxvdyB0aGUgZG9jc3RyaW5nIG9mIGNsYXNzIGFuZCBmdW5jdGlvbj8KCkluIGNvbnRyYXN0LCB0aGUgY29tbWVudHMgYmVsb3cgdGhlIGRvY3N0cmluZyBjb250YWluIGluZm9ybWF0aW9uIGFib3V0IHRoZSBpbXBsZW1lbnRhdGlvbi4gVGhhdCBpbmZvcm1hdGlvbiBpcyBhaW1lZCBhdCBwcm9ncmFtbWVycyB3aG8gbWlnaHQgd2FudCB0byBtb2RpZnkgdGhlIGltcGxlbWVudGF0aW9uIG9yIGJ1aWxkIHN1YmNsYXNzZXMgb2YgdGhlIGNsYXNzLCBub3QgYXQgcHJvZ3JhbW1lcnMgd2hvIG1pZ2h0IHdhbnQgdG8gdXNlIHRoZSBhYnN0cmFjdGlvbi4KCiMjIyBXaGF0IGlzIHRoZSBjb2RlIG9mIGltcGxlbWVudGF0aW9uIGFuICJpbnRzZXQiPwoKYGBge3B5dGhvbn0KY2xhc3MgSW50U2V0KG9iamVjdCk6CiAgICAiIiJBbiBpbnRTZXQgaXMgYSBzZXQgb2YgaW50ZWdlcnMiIiIKICAgICNJbmZvcm1hdGlvbiBhYm91dCB0aGUgaW1wbGVtZW50YXRpb24gKG5vdCB0aGUgYWJzdHJhY3Rpb24pCiAgICAjVmFsdWUgb2YgdGhlIHNldCBpcyByZXByZXNlbnRlZCBieSBhIGxpc3Qgb2YgaW50cywgc2VsZi52YWxzLgogICAgI0VhY2ggaW50IGluIHRoZSBzZXQgb2NjdXJzIGluIHNlbGYudmFscyBleGFjdGx5IG9uY2UuCiAgICBkZWYgX19pbml0X18oc2VsZik6CiAgICAgICAgIiIiQ3JlYXRlIGFuIGVtcHR5IHNldCBvZiBpbnRlZ2VycyIiIiAKICAgICAgICBzZWxmLnZhbHMgPSBbXQoKICAgIGRlZiBpbnNlcnQoc2VsZiwgZSk6CiAgICAgICAgIiIiQXNzdW1lcyBlIGlzIGFuIGludGVnZXIgYW5kIGluc2VydHMgZSBpbnRvIHNlbGYiIiIKICAgICAgICBpZiBlIG5vdCBpbiBzZWxmLnZhbHM6CiAgICAgICAgICAgIHNlbGYudmFscy5hcHBlbmQoZSkKCiAgICBkZWYgbWVtYmVyKHNlbGYsIGUpOgogICAgICAgICIiIkFzc3VtZXMgZSBpcyBhbiBpbnRlZ2VyCiAgICAgICAgICAgUmV0dXJucyBUcnVlIGlmIGUgaXMgaW4gc2VsZiwgYW5kIEZhbHNlIG90aGVyd2lzZSIiIgogICAgICAgIHJldHVybiBlIGluIHNlbGYudmFscwoKICAgIGRlZiByZW1vdmUoc2VsZiwgZSk6CiAgICAgICAgIiIiQXNzdW1lcyBlIGlzIGFuIGludGVnZXIgYW5kIHJlbW92ZXMgZSBmcm9tIHNlbGYKICAgICAgICAgICBSYWlzZXMgVmFsdWVFcnJvciBpZiBlIGlzIG5vdCBpbiBzZWxmIiIiCiAgICAgICAgdHJ5OgogICAgICAgICAgICBzZWxmLnZhbHMucmVtb3ZlKGUpCiAgICAgICAgZXhjZXB0OgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKHN0cihlKSArICcgbm90IGZvdW5kJykKCiAgICBkZWYgZ2V0TWVtYmVycyhzZWxmKToKICAgICAgICAiIiJSZXR1cm5zIGEgbGlzdCBjb250YWluaW5nIHRoZSBlbGVtZW50cyBvZiBzZWxmLgogICAgICAgICAgIE5vdGhpbmcgY2FuIGJlIGFzc3VtZWQgYWJvdXQgdGhlIG9yZGVyIG9mIHRoZSBlbGVtZW50cyIiIgogICAgICAgIHJldHVybiBzZWxmLnZhbHNbOl0KCiAgICBkZWYgX19zdHJfXyhzZWxmKToKICAgICAgICAiIiJSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHNlbGYiIiIKICAgICAgICBzZWxmLnZhbHMuc29ydCgpCiAgICAgICAgcmVzdWx0ID0gJycKICAgICAgICBmb3IgZSBpbiBzZWxmLnZhbHM6CiAgICAgICAgICAgIHJlc3VsdCA9IHJlc3VsdCArIHN0cihlKSArICcsJwogICAgICAgIHJldHVybiAneycgKyByZXN1bHRbOi0xXSArICd9JyAjLTEgb21pdHMgdHJhaWxpbmcgY29tbWEKYGBgCgojIyMgV2hhdCBpcyBhIGZ1bmN0aW9uIGluc2lkZSBhIGNsYXNzIGNhbGxlZD8KCmEgbWV0aG9kIHRoYXQgYXNzb2NpYXRlZCB3aXRoIHRoZSBjbGFzcwoKbWV0aG9kIGF0dHJpYnV0ZXMgb2YgdGhlIGNsYXNzCgojIyMgV2hhdCBpcyB0aGUgcmVsYXRpb25zaGlwIG9mIHR5cGUsIGNsYXNzLCBtZXRob2QgYW5kIGZ1bmN0aW9uPwoKQSBjbGFzcyBzaG91bGQgbm90IGJlIGNvbmZ1c2VkIHdpdGggaW5zdGFuY2VzIG9mIHRoYXQgY2xhc3MsIGp1c3QgYXMgYW4gb2JqZWN0IG9mIHR5cGUgbGlzdCBzaG91bGQgbm90IGJlIGNvbmZ1c2VkIHdpdGggdGhlIGxpc3QgdHlwZS4KCmBgYHtweXRob259CnMgPSBJbnRTZXQoKSAKcy5pbnNlcnQoMykgCnByaW50KCJXaGV0aGVyICczJyBleGlzdHMgaW4gJ3MnOiIsIHMubWVtYmVyKDMpKQpwcmludCAoIlR5cGUgb2YgJ0ludFNldCcgaXMgIiArIHN0cih0eXBlIChJbnRTZXQpKSArICIuXG4iICsgCiAgICAgICAiVHlwZSBvZiAnSW50U2V0Lmluc2VydCcgaXMgIiArIHN0cih0eXBlIChJbnRTZXQuaW5zZXJ0KSkgKyAiLiIpCnByaW50ICgiVHlwZSBvZiAncycgaXMgIiArIHN0cih0eXBlIChzKSkgKyAiLlxuIiArIAogICAgICAgIlR5cGUgb2YgJ3MuaW5zZXJ0JyBpcyAiICsgc3RyKHR5cGUocy5pbnNlcnQpKSArICIuIikKYGBgCgojIyMgV2hhdCBhcmUgbWV0aG9kIGF0dHJpYnV0ZXMgYW5kIGRhdGEgYXR0cmlidXRlcz8KCk1ldGhvZCBhdHRyaWJ1dGVzIGFyZSBkZWZpbmVkIGluIGEgY2xhc3MgZGVmaW5pdGlvbiwgZm9yIGV4YW1wbGUgYEludFNldC5tZW1iZXJgIGlzIGFuIGF0dHJpYnV0ZSBvZiB0aGUgY2xhc3MgYEludFNldGAuIFdoZW4gdGhlIGNsYXNzIGlzIGluc3RhbnRpYXRlZCwgZS5nLiwgYnkgdGhlIHN0YXRlbWVudCBgcyA9IEludFNldCgpYCwgaW5zdGFuY2UgYXR0cmlidXRlcywgZS5nLiwgYHMubWVtYmVyYCwgYXJlIGNyZWF0ZWQuCgpXaGVuIGRhdGEgYXR0cmlidXRlcyBhcmUgYXNzb2NpYXRlZCB3aXRoIGEgY2xhc3Mgd2UgY2FsbCB0aGVtIGNsYXNzIHZhcmlhYmxlcy4gV2hlbiB0aGV5IGFyZSBhc3NvY2lhdGVkIHdpdGggYW4gaW5zdGFuY2Ugd2UgY2FsbCB0aGVtIGluc3RhbmNlIHZhcmlhYmxlcy4KCiMjIyBXaGF0IGlzIHJlcHJlc2VudGF0aW9uLWluZGVwZW5kZW5jZT8KCkRhdGEgYWJzdHJhY3Rpb24gYWNoaWV2ZXMgcmVwcmVzZW50YXRpb24taW5kZXBlbmRlbmNlLiBUaGluayBvZiB0aGUgaW0tIHBsZW1lbnRhdGlvbiBvZiBhbiBhYnN0cmFjdCB0eXBlIGFzIGhhdmluZyBzZXZlcmFsIGNvbXBvbmVudHM6CgotIEltcGxlbWVudGF0aW9ucyBvZiB0aGUgbWV0aG9kcyBvZiB0aGUgdHlwZSwKLSBEYXRhIHN0cnVjdHVyZXMgdGhhdCB0b2dldGhlciBlbmNvZGUgdmFsdWVzIG9mIHRoZSB0eXBlLCBhbmQKLSBDb252ZW50aW9uc1teY29udmVudGlvbl0gYWJvdXQgaG93IHRoZSBpbXBsZW1lbnRhdGlvbnMgb2YgdGhlIG1ldGhvZHMgYXJlIHRvIHVzZSB0aGUgZGF0YSBzdHJ1Y3R1cmVzLiBBIGtleSBjb252ZW50aW9uIGlzIGNhcHR1cmVkIGJ5IHRoZSByZXByZXNlbnRhdGlvbltecmVwcmVzZW50YXRpb25dIGludmFyaWFudFteaW52YXJpYW50XS4KCiMjIyBXaGF0IGlzIHJlcHJlc2VudGF0aW9uIGludmFyaWFudD8KClRoZSAqKnJlcHJlc2VudGF0aW9uIGludmFyaWFudCoqIGRlZmluZXMgd2hpY2ggdmFsdWVzIG9mIHRoZSBkYXRhIGF0dHJpYnV0ZXMgY29ycmVzcG9uZCB0byB2YWxpZCByZXByZXNlbnRhdGlvbnMgb2YgY2xhc3MgaW5zdGFuY2VzLiBUaGUgcmVwcmVzZW50YXRpb24gaW52YXJpYW50IGZvciBgSW50U2V0YCBpcyB0aGF0IGB2YWxzYCBjb250YWlucyBubyBkdXBsaWNhdGVzLiBUaGUgaW1wbGVtZW50YXRpb24gb2YgYF9faW5pdF9fYCBpcyByZXNwb25zaWJsZSBmb3IgZXN0YWJsaXNoaW5nIHRoZSBpbnZhcmlhbnQgKHdoaWNoIGhvbGRzIG9uIHRoZSBlbXB0eSBsaXN0KSwgYW5kIHRoZSBvdGhlciBtZXRob2RzIGFyZSByZXNwb25zaWJsZSBmb3IgbWFpbnRhaW5pbmcgdGhhdCBpbnZhcmlhbnQuIFRoYXQgaXMgd2h5IGBpbnNlcnRgIGFwcGVuZHMgZSBvbmx5IGlmIGl0IGlzIG5vdCBhbHJlYWR5IGluIGBzZWxmLnZhbHNgLiBUaGUgaW1wbGVtZW50YXRpb24gb2YgYHJlbW92ZWAgZXhwbG9pdHMgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgcmVwcmVzZW50YXRpb24gaW52YXJpYW50IGlzIHNhdGlzZmllZCB3aGVuIGByZW1vdmVgIGlzIGVudGVyZWQuIEl0IGNhbGxzIGBsaXN0LnJlbW92ZWAgb25seSBvbmNlLCBzaW5jZSB0aGUgcmVwcmVzZW50YXRpb24gaW52YXJpYW50IGd1YXJhbnRlZXMgdGhhdCB0aGVyZSBpcyBhdCBtb3N0IG9uZSBvY2N1cnJlbmNlIG9mIGBlYCBpbiBgc2VsZi52YWxzYC4KClteY29udmVudGlvbl06ICoqY29udmVudGlvbioqOiBHZW5lcmFsIGFncmVlbWVudCBvciBjb25jdXJyZW5jZTsgYXJiaXRyYXJ5IGN1c3RvbTsgdXNhZ2U7IGNvbnZlbnRpb25hbGl0eS4KW15yZXByZXNlbnRhdGlvbl06ICoqcmVwcmVzZW50YXRpb24qKjogVGhhdCB3aGljaCByZXByZXNlbnRzLiBTcGVjaWZpY2FsbHk6IEEgZGVzY3JpcHRpb24gb3Igc3RhdGVtZW50OyBhcywgdGhlIHJlcHJlc2VudGF0aW9uIG9mIGFuIGhpc3Rvcmlhbiwgb2YgYSB3aXRuZXNzLCBvciBhbiBhZHZvY2F0ZS4KW15pbnZhcmlhbnRdOiAqKmludmFyaWFudCoqOiBuLiAoTWF0aC4pIEFuIGludmFyaWFibGUgcXVhbnRpdHk7IHNwZWNpZmljYWxseSwgYSBmdW5jdGlvbiBvZiB0aGUgY29lZmZpY2llbnRzIG9mIG9uZSBvciBtb3JlIGZvcm1zLCB3aGljaCByZW1haW5zIHVuYWx0ZXJlZCwgd2hlbiB0aGVzZSB1bmRlcmdvIHN1aXRhYmxlIGxpbmVhciB0cmFuc2Zvcm1hdGlvbnMuICAtIEouIEouIFN5bHZlc3Rlci4KCiMjIyBJcyBhIHVzZXItZGVmaW5lZCBjbGFzcyBpbnN0YW5jZSBoYXNoYWJsZT8KCiMjIyMgQW55IGluc3RhbmNlIG9mIGEgdXNlci1kZWZpbmVkIGNsYXNzIGlzIGhhc2hhYmxlCgpBbGwgaW5zdGFuY2VzIG9mIHVzZXItZGVmaW5lZCBjbGFzc2VzIGFyZSBoYXNoYWJsZSwgYW5kIHRoZXJlZm9yZSBjYW4gYmUgdXNlZCBhcyBkaWN0aW9uYXJ5IGtleXMuIElmIG5vIGBfX2hhc2hfX2AgbWV0aG9kIGlzIHByb3ZpZGVkLCB0aGUgaGFzaCB2YWx1ZSBvZiB0aGUgb2JqZWN0IGlzIGRlcml2ZWQgZnJvbSB0aGUgZnVuY3Rpb24gYGlkYC4KCiMjIyBXaHkgYWJzdHJhY3QgZGF0YSB0eXBlcyBhcmUgYSBiaWcgZGVhbFteYSBiaWcgZGVhbF0/CgpUaGV5IGxlYWQgdG8gYSBkaWZmZXJlbnQgd2F5IG9mIHRoaW5raW5nIGFib3V0IG9yZ2FuaXppbmcgbGFyZ2UgcHJvZ3JhbXMuIAoKIyMjIyBSZWx5IG9uIGFic3RyYWN0aW9uIHdoZW4gdHJ5aW5nIHRvIHVuZGVyc3RhbmQgY29uY2VwdHMgYWJvdXQgdGhlIHdvcmxkCgpXaGVuIHdlIHRoaW5rIGFib3V0IHRoZSB3b3JsZCwgd2UgcmVseSBvbiBhYnN0cmFjdGlvbnMuIEluIHRoZSB3b3JsZCBvZiBmaW5hbmNlIHBlb3BsZSB0YWxrIGFib3V0IHN0b2NrcyBhbmQgYm9uZHMuIEluIHRoZSB3b3JsZCBvZiBiaW9sb2d5IHBlb3BsZSB0YWxrIGFib3V0IHByb3RlaW5zIGFuZCByZXNpZHVlcy4gV2hlbiB0cnlpbmcgdG8gdW5kZXJzdGFuZCBjb25jZXB0cyBzdWNoIGFzIHRoZXNlLCB3ZSBtZW50YWxseSBnYXRoZXIgdG9nZXRoZXIgc29tZSBvZiB0aGUgcmVsZXZhbnQgKipkYXRhIGFuZCBmZWF0dXJlcyoqIG9mIHRoZXNlIGtpbmRzIG9mIG9iamVjdHMgaW50byBvbmUgKippbnRlbGxlY3R1YWwgcGFja2FnZSoqLiBGb3IgZXhhbXBsZSwgd2UgdGhpbmsgb2YgYm9uZHMgYXMgaGF2aW5nIGFuIGludGVyZXN0IHJhdGUgYW5kIGEgbWF0dXJpdHkgZGF0ZSBhcyBkYXRhIGF0dHJpYnV0ZXMuIFdlIGFsc28gdGhpbmsgb2YgYm9uZHMgYXMgaGF2aW5nIG9wZXJhdGlvbnMgc3VjaCBhcyDigJxzZXQgcHJpY2XigJ0gYW5kIOKAnGNhbGN1bGF0ZSB5aWVsZCB0byBtYXR1cml0eS7igJ0gQWJzdHJhY3QgZGF0YSB0eXBlcyBhbGxvdyB1cyB0byBpbmNvcnBvcmF0ZSB0aGlzIGtpbmQgb2Ygb3JnYW5pemF0aW9uIGludG8gdGhlIGRlc2lnbiBvZiBwcm9ncmFtcy4KCiMjIyMgRm9jdXMgb24gdGhlIGNlbnRyYWxpdHkgb2YgZGF0YSBvYmplY3QgcmF0aGVyIHRoYW4gZnVuY3Rpb25zIHdoZW4gZGVzaWduaW5nIHByb2dyYW1zIAoKRGF0YSBhYnN0cmFjdGlvbiBlbmNvdXJhZ2VzIHByb2dyYW0gZGVzaWduZXJzIHRvIGZvY3VzIG9uIHRoZSBjZW50cmFsaXR5IG9mIGRhdGEgb2JqZWN0cyByYXRoZXIgdGhhbiBmdW5jdGlvbnMuIFRoaW5raW5nIGFib3V0IGEgcHJvZ3JhbSBtb3JlIGFzIGEgY29sbGVjdGlvbiBvZiB0eXBlcyB0aGFuIGFzIGEgY29sbGVjdGlvbiBvZiBmdW5jdGlvbnMgbGVhZHMgdG8gYSBwcm9mb3VuZGx5IGRpZmZlcmVudCBvcmdhbml6aW5nIHByaW5jaXBsZS4gQW1vbmcgb3RoZXIgdGhpbmdzLCBpdCBlbmNvdXJhZ2VzIG9uZSB0byB0aGluayBhYm91dCBwcm9ncmFtbWluZyBhcyBhIHByb2Nlc3Mgb2YgY29tYmluaW5nIHJlbGF0aXZlbHkgbGFyZ2UgY2h1bmtzLCBzaW5jZSBkYXRhIGFic3RyYWN0aW9ucyB0eXBpY2FsbHkgZW5jb21wYXNzW15lbmNvbXBhc3NdIG1vcmUgZnVuY3Rpb25hbGl0eSB0aGFuIGRvIGluZGl2aWR1YWwgZnVuY3Rpb25zLiBUaGlzLCBpbiB0dXJuLCBsZWFkcyB1cyB0byB0aGluayBvZiB0aGUgZXNzZW5jZSBvZiBwcm9ncmFtbWluZyBhcyBhIHByb2Nlc3Mgbm90IG9mIHdyaXRpbmcgaW5kaXZpZHVhbCBsaW5lcyBvZiBjb2RlLCBidXQgb2YgY29tcG9zaW5nW15jb21wb3NlXSBhYnN0cmFjdGlvbnMuCgojIyMjIFJldXNlIGFic3RyYWN0aW9ucyB0byByZWR1Y2UgZGV2ZWxvcG1lbnQgdGltZSBhbmQgdG8geWllbGQgbW9yZSByZWxpYWJsZSBwcm9ncmFtcwoKVGhlIGF2YWlsYWJpbGl0eSBvZiByZXVzYWJsZSBhYnN0cmFjdGlvbnMgbm90IG9ubHkgcmVkdWNlcyBkZXZlbG9wbWVudCB0aW1lLCBidXQgYWxzbyB1c3VhbGx5IGxlYWRzIHRvIG1vcmUgcmVsaWFibGUgcHJvZ3JhbXMsIGJlY2F1c2UgbWF0dXJlIHNvZnR3YXJlIGlzIHVzdWFsbHkgbW9yZSByZWxpYWJsZSB0aGFuIG5ldyBzb2Z0d2FyZS4gRm9yIG1hbnkgeWVhcnMsIHRoZSBvbmx5IHByb2dyYW0gbGlicmFyaWVzIGluIGNvbW1vbiB1c2Ugd2VyZSBzdGF0aXN0aWNhbCBvciBzY2llbnRpZmljLiBUb2RheSwgaG93ZXZlciwgdGhlcmUgaXMgYSBncmVhdCByYW5nZSBvZiBhdmFpbGFibGUgcHJvZ3JhbSBsaWJyYXJpZXMgKGVzcGVjaWFsbHkgZm9yIFB5dGhvbiksIG9mdGVuIGJhc2VkIG9uIGEgcmljaCBzZXQgb2YgZGF0YSBhYnN0cmFjdGlvbnMuCgpbXmEgYmlnIGRlYWxdOiAqKmEgYmlnIGRlYWwqKjogKmluZm9ybWFsKiAqW3VzdWFsbHkgd2l0aCBuZWdhdGl2ZV0qIGEgdGhpbmcgY29uc2lkZXJlZCBpbXBvcnRhbnQ6ICp0aGV5IGRvbid0IG1ha2UgYSBiaWcgZGVhbCBvdXQgb2YgbWlub3IgaXJyaXRhdGlvbnMqLiDigKIgYW4gaW1wb3J0YW50IHBlcnNvbjogKlNhbSBLaW5pc29uIGJlY2FtZSBhIGJpZyBkZWFsKi4g4oCiIChiaWcgZGVhbCkgdXNlZCB0byBleHByZXNzIG9uZSdzIGNvbnRlbXB0IGZvciBzb21ldGhpbmcgcmVnYXJkZWQgYXMgaW1wcmVzc2l2ZSBvciBpbXBvcnRhbnQgYnkgYW5vdGhlciBwZXJzb246ICrigJxJJ2xsIGdpdmUgeW91IGFuIGFsbG93YW5jZSzigJ0gaGUgc2FpZC4g4oCcQmlnIGRlYWws4oCdIHNoZSB0aG91Z2h0Ki4KW15lbmNvbXBhc3NdOiAqKmVuY29tcGFzcyoqOiBUbyBjaXJjdW1zY3JpYmUgb3IgZ28gcm91bmQgc28gYXMgdG8gc3Vycm91bmQgY2xvc2VseTsgdG8gZW5jaXJjbGU7IHRvIGluY2xvc2U7IHRvIGVudmlyb247IGFzLCBhIHJpbmcgKmVuY29tcGFzc2VzKiB0aGUgZmluZ2VyOyBhbiBhcm15ICplbmNvbXBhc3NlcyogYSBjaXR5OyBhIHZveWFnZSAqZW5jb21wYXNzaW5nKiB0aGUgd29ybGQuIC0gU2hhay4gQSBxdWVzdGlvbiBtYXkgYmUgKmVuY29tcGFzc2VkKiB3aXRoIGRpZmZpY3VsdHkuIC0gQy4gSi4gU21pdGguClteY29tcG9zZV06ICoqY29tcG9zZSoqOiBUbyBjb25zdHJ1Y3QgYnkgbWVudGFsIGxhYm9yOyB0byBkZXNpZ24gYW5kIGV4ZWN1dGUsIG9yIHB1dCB0b2dldGhlciwgaW4gYSBtYW5uZXIgaW52b2x2aW5nIHRoZSBhZGFwdGF0aW9uIG9mIGZvcm1zIG9mIGV4cHJlc3Npb24gdG8gaWRlYXMsIG9yIHRvIHRoZSBsYXdzIG9mIGhhcm1vbnkgb3IgcHJvcG9ydGlvbjsgYXMsIHRvIGNvbXBvc2UgYSBzZW50ZW5jZSwgYSBzZXJtb24sIGEgc3ltcGhvbnksIG9yIGEgcGljdHVyZS4KCiMjIyBXaGF0IGFic3RyYWN0aW9uIG1pZ2h0IGJlIHVzZWZ1bCwgYmVmb3JlIHJ1c2hpbmcgaW4gdG8gZGVzaWduIGEgYnVuY2ggb2YgZGF0YSBzdHJ1Y3R1cmVzIHRvIGtlZXAgdHJhY2sgb2YgYWxsIHRoZSBzdHVkZW50cyBhbmQgZmFjdWx0eSwgPwoKSXMgdGhlcmUgYW4gYWJzdHJhY3Rpb24gdGhhdCBjb3ZlcnMgdGhlIGNvbW1vbiBhdHRyaWJ1dGVzIG9mIHN0dWRlbnRzLCBwcm9mZXNzb3JzLCBhbmQgc3RhZmY/IFNvbWUgd291bGQgYXJndWUgdGhhdCB0aGV5IGFyZSBhbGwgaHVtYW4uIFRoZSBmb2xsb3dpbmcgY29kZSBjb250YWlucyBhIGNsYXNzIHRoYXQgaW5jb3Jwb3JhdGVzIHNvbWUgb2YgdGhlIGNvbW1vbiBhdHRyaWJ1dGVzIChuYW1lIGFuZCBiaXJ0aGRheSkgb2YgaHVtYW5zLgoKYGBge3B5dGhvbn0KaW1wb3J0IGRhdGV0aW1lCgpjbGFzcyBQZXJzb24ob2JqZWN0KToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBuYW1lKToKICAgICAgICAiIiJDcmVhdGUgYSBwZXJzb24iIiIKICAgICAgICBzZWxmLm5hbWUgPSBuYW1lCiAgICAgICAgdHJ5OgogICAgICAgICAgICBsYXN0QmxhbmsgPSBuYW1lLnJpbmRleCgnICcpCiAgICAgICAgICAgIHNlbGYubGFzdE5hbWUgPSBuYW1lW2xhc3RCbGFuaysxOl0KICAgICAgICBleGNlcHQ6CiAgICAgICAgICAgIHNlbGYubGFzdE5hbWUgPSBuYW1lCiAgICAgICAgc2VsZi5iaXJ0aGRheSA9IE5vbmUKCiAgICBkZWYgZ2V0TmFtZShzZWxmKToKICAgICAgICAiIiJSZXR1cm5zIHNlbGYncyBmdWxsIG5hbWUiIiIKICAgICAgICByZXR1cm4gc2VsZi5uYW1lCgogICAgZGVmIGdldExhc3ROYW1lKHNlbGYpOgogICAgICAgICIiIlJldHVybnMgc2VsZidzIGxhc3QgbmFtZSIiIgogICAgICAgIHJldHVybiBzZWxmLmxhc3ROYW1lCgogICAgZGVmIHNldEJpcnRoZGF5KHNlbGYsIGJpcnRoZGF0ZSk6CiAgICAgICAgIiIiIEFzc3VtZXMgYmlydGhkYXRlIGlzIG9mIHR5cGUgZGF0ZXRpbWUuZGF0ZQogICAgICAgICAgICBTZXRzIHNlbGYncyBiaXJ0aGRheSB0byBiaXJ0aGRhdGUiIiIKICAgICAgICBzZWxmLmJpcnRoZGF5ID0gYmlydGhkYXRlCgogICAgZGVmIGdldEFnZShzZWxmKToKICAgICAgICAiIiJSZXR1cm5zIHNlbGYncyBjdXJyZW50IGFnZSBpbiBkYXlzIiIiCiAgICAgICAgaWYgc2VsZi5iaXJ0aGRheSA9PSBOb25lOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yCiAgICAgICAgcmV0dXJuIChkYXRldGltZS5kYXRlLnRvZGF5KCkgLSBzZWxmLmJpcnRoZGF5KS5kYXlzCgogICAgZGVmIF9fbHRfXyhzZWxmLCBvdGhlcik6CiAgICAgICAgIiIiUmV0dXJucyBUcnVlIGlmIHNlbGYgcHJlY2VkZXMgb3RoZXIgaW4gYWxwaGFiZXRpY2FsCiAgICAgICAgICAgIG9yZGVyLCBhbmQgRmFsc2Ugb3RoZXJ3aXNlLiBDb21wYXJpc29uIGlzIGJhc2VkIG9uIGxhc3QKICAgICAgICAgICAgbmFtZXMsIGJ1dCBpZiB0aGVzZSBhcmUgdGhlIHNhbWUgZnVsbCBuYW1lcyBhcmUKICAgICAgICAgICAgY29tcGFyZWQuIiIiCiAgICAgICAgaWYgc2VsZi5sYXN0TmFtZSA9PSBvdGhlci5sYXN0TmFtZToKICAgICAgICAgICAgcmV0dXJuIHNlbGYubmFtZSA8IG90aGVyLm5hbWUKICAgICAgICByZXR1cm4gc2VsZi5sYXN0TmFtZSA8IG90aGVyLmxhc3ROYW1lCgogICAgZGVmIF9fc3RyX18oc2VsZik6CiAgICAgICAgIiIiUmV0dXJucyBzZWxmJ3MgbmFtZSIiIgogICAgICAgIHJldHVybiBzZWxmLm5hbWUKYGBgCgpUaGUgZm9sbG93aW5nIGNvZGUgbWFrZXMgdXNlIG9mIFBlcnNvbi4KCmBgYHtweXRob259Cm1lID0gUGVyc29uKCdNaWNoYWVsIEd1dHRhZycpCmhpbSA9IFBlcnNvbignQmFyYWNrIEh1c3NlaW4gT2JhbWEnKQpoZXIgPSBQZXJzb24oJ01hZG9ubmEnKQpwcmludChoaW0uZ2V0TGFzdE5hbWUoKSkgCmhpbS5zZXRCaXJ0aGRheShkYXRldGltZS5kYXRlKDE5NjEsIDgsIDQpKSAKaGVyLnNldEJpcnRoZGF5KGRhdGV0aW1lLmRhdGUoMTk1OCwgOCwgMTYpKSAKcHJpbnQoaGltLmdldE5hbWUoKSwgJ2lzJywgaGltLmdldEFnZSgpLCAnZGF5cyBvbGQnKQpgYGAKCgoK