text:
"""
Elffile is a library which reads and writes `ELF format object files
<http://en.wikipedia.org/wiki/Executable_and_Linkable_Format>`_.
Elffile is pure `python <http://python.org>`_ so installation is easy.

.. note:: while this library uses some classes as abstract base
    classes, it does not use :py:mod:`abc`.

.. todo:: need a "copy" method

.. todo:: need a reverse write method, (for testing)

"""

from __future__ import unicode_literals, print_function

__docformat__ = 'restructuredtext en'

#__all__ = []

import functools
import io
import mmap
import operator
import os
import struct

import coding

def open(name=None, fileobj=None, map=None, block=None):
    """

    The open function takes some form of file identifier and creates
    an :py:class:`ElfFile` instance from it.

    :param :py:class:`str` name: a file name
    :param :py:class:`file` fileobj: if given, this overrides *name*
    :param :py:class:`mmap.mmap` map: if given, this overrides *fileobj*
    :param :py:class:`bytes` block: file contents in a block of memory, (if given, this overrides *map*)

    The file to be used can be specified in any of four different
    forms, (in reverse precedence):

    #. a file name
    #. :py:class:`file` object
    #. :py:mod:`mmap.mmap`, or
    #. a block of memory
    """

    if block:
        if not name:
            name = '<unknown>'

        efi = ElfFileIdent()
        efi.unpack_from(block)

        ef = ElfFile.encodedClass(efi)(name, efi)
        ef.unpack_from(block)

        if fileobj:
            fileobj.close()

        return ef

    if map:
        block = map

    elif fileobj:
        map = mmap.mmap(fileobj.fileno(), 0, access=mmap.ACCESS_READ)

    elif name:
        fileobj = io.open(os.path.normpath(os.path.expanduser(name)), 'rb')

    else:
        assert False

    return open(name=name,
                fileobj=fileobj,
                map=map,
                block=block)

class StructBase(object):
    """
    An abstract base class representing objects which are inherently
    based on a struct.
    """

    coder = None
    """
    The :py:class:`struct.Struct` used to encode/decode this object
    into a block of memory.  This is expected to be overridden by
    subclasses.
    """

    class _Size(object):
        def __get__(self, obj, t):
            return t.coder.size

    size = _Size()
    """
    Exact size in bytes of a block of memory into which is suitable
    for packing this instance.
    """

    def unpack(self, block):
        return self.unpack_from(block)

    def unpack_from(self, block, offset=0):
        """
        Set the values of this instance from an in-memory
        representation of the struct.

        :param string block: block of memory from which to unpack
        :param int offset: optional offset into the memory block from
            which to start unpacking
        """
        raise NotImplementedError

    def pack(self):
        x = bytearray(self.size)
        self.pack_into(x)
        return x

    def pack_into(self, block, offset=0):
        """
        Store the values of this instance into an in-memory
        representation of the file.

        :param string block: block of memory into which to pack
        :param int offset: optional offset into the memory block into
            which to start packing
        """
        raise NotImplementedError

    __hash__ = None

    def __eq__(self, other):
        raise NotImplementedError

    def __ne__(self, other):
        return not self.__eq__(other)

    def close_enough(self, other):
        """
        This is a comparison similar to __eq__ except that here the
        goal is to determine whether two objects are "close enough"
        despite perhaps having been produced at different times in
        different locations in the file system.
        """
        return self == other

EI_NIDENT = 16
"""
Length of the byte-endian-independent, word size independent initial
portion of the ELF header file.  This is the portion represented by
:py:class:`ElfFileIdent`.
"""

class ElfFileIdent(StructBase):
    """
    This class corresponds to the first, byte-endian-independent,
    values in an elf file.  These tell us about the encodings for the
    rest of the file.  This is the *e_ident* field of the `elf file
    header
    <http://www.sco.com/developers/gabi/latest/ch4.eheader.html#elfid>`_.

    Most attributes are :py:class:`int`'s.  Some have encoded meanings
    which can be decoded with the accompanying
    :py:class:`coding.Coding` subclasses.
    """

    magic = None
    """
    The magic 'number' which should be '\x7fELF' for all ELF format files.
    """

    elfClass = None
    """
    The 'class', (sic), of the file which represents whether the file
    is 32-bit or 64-bit.  Encoded using :py:class:`ElfClass`.
    """

    elfData = None
    """
    The 'data', (sic), of the file which represents the endian-ness
    used to encode this file.  Encoded using :py:class:`ElfData`.
    """

    fileVersion = None
    """
    The version of the ELF format used to encode this file.  Must be
    :py:const:`EV_CURRENT`.  Encoded using :py:class:`EV`.
    """

    osabi = None
    """
    Represents the operating system for which this ELF file is
    intended.  Encoded using :py:class:`ElfOsabi`.
    """

    abiversion = None
    """
    Represents the version of the operating system ABI format used by
    this ELF file.
    """

    coder = struct.Struct(b'=4sBBBBBxxxxxxx')
    """
    A :py:class:`struct.Struct` (de)coder involving six fields:

    * '\x7fELF', (Elf file magic number)
    * ElfClass (32 vs 64-bit)
    * ElfData (endianness)
    * EV (file version)
    * ElfOsabi (operating system)
    * abiversion
    """

    # size is EI_IDENT
    assert (coder.size == EI_NIDENT), 'coder.size = {0}({0}), EI_NIDENT = {0}({0})'.format(coder.size, type(coder.size),
                                                                                EI_NIDENT, type(EI_NIDENT))

    def unpack_from(self, block, offset=0):
        (self.magic, self.elfClass, self.elfData, self.fileVersion, self.osabi,
         self.abiversion) = self.coder.unpack_from(block, offset)
        return self

    def pack_into(self, block, offset=0):
        self.coder.pack_into(block, offset, self.magic, self.elfClass,
                             self.elfData, self.fileVersion,
                             self.osabi, self.abiversion)

        return self

    def __repr__(self):
        return ('<{0}@{1}: coder={2}, magic=\'{3}\', elfClass={4}, elfData={5}, fileVersion={6}, osabi={7}, abiversion={8}>'
                .format(self.__class__.__name__, hex(id(self)), self.coder, self.magic,
                        ElfClass.bycode[self.elfClass] if self.elfClass in ElfClass.bycode else self.elfClass,
                        ElfData.bycode[self.elfData] if self.elfData in ElfData.bycode else self.elfData,
                        self.fileVersion, self.osabi, self.abiversion))

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
                and self.coder == other.coder
                and self.magic == other.magic
                and self.elfClass == other.elfClass
                and self.elfData == other.elfData
                and self.fileVersion == other.fileVersion
                and self.osabi == other.osabi
                and self.abiversion == other.abiversion)

    close_enough = __eq__

    def _list_encode(self):
        return (self.__class__.__name__,
                hex(id(self)),
                {
                    'coder': self.coder,
                    'magic': self.magic,
                    'elfClass': ElfClass.bycode[self.elfClass].name,
                    'elfData': ElfData.bycode[self.elfData].name,
                    'fileVersion': self.fileVersion,
                    'osabi': self.osabi,
                    'abiversion': self.abiversion,
                })

class ElfClass(coding.Coding):
    """
    Encodes the word size of the elf file as from the `ident portion
    of the ELF file header
    <http://www.sco.com/developers/gabi/latest/ch4.eheader.html#elfid>`_.
    This is a subclass of :py:class:`coding.Coding` and encodes
    :py:attr:`ElfFileIdent.elfClass`.
    """
    bycode = byname = {}

ElfClass('ELFCLASSNONE', 0, 'Invalid class')
ElfClass('ELFCLASS32', 1, '32-bit objects')
ElfClass('ELFCLASS64', 2, '64-bit objects')
ElfClass('ELFCLASSNUM', 3, '')          # from libelf

class ElfData(coding.Coding):
    """
    Encodes the byte-wise endianness of the elf file as from the
    `ident portion of the elf file header
    <http://www.sco.com/developers/gabi/latest/ch4.eheader.html#elfid>`_.
    This is a subclass of :py:class:`coding.Coding` and encodes
    :py:attr:`ElfFileIdent.elfData`.
    """
    bycode = byname = {}

ElfData('ELFDATANONE', 0, 'Invalid data encoding')
ElfData('ELFDATA2LSB', 1, 'least significant byte first')
ElfData('ELFDATA2MSB', 2, 'most significant byte first')
ElfData('ELFDATANUM', 3, '')

class EV(coding.Coding):
    """
    Encodes the elf file format version of this elf file as from the `ident portion of the elf file
    header
    <http://www.sco.com/developers/gabi/latest/ch4.eheader.html#elfid>`_.  This is a subclass of :py:class:`coding.Coding`.
    """
    bycode = byname = {}

EV('EV_NONE', 0, 'Invalid version')
EV('EV_CURRENT', 1, 'Current version')
EV('EV_NUM', 2, '')

class ElfOsabi(coding.Coding):
    """
    Encodes OSABI values which represent operating system ELF format
    extensions as from the `'ident' portion of the elf file header
    <http://www.sco.com/developers/gabi/latest/ch4.eheader.html#elfid>`_.

    This is a subclass of :py:class:`coding.Coding` which codes :py:attr:`ElfFileIdent.osabi`.
    """
    bycode = byname = {}
    overload_codes = True

ElfOsabi('ELFOSABI_NONE', 0, 'No extensions or unspecified')
ElfOsabi('ELFOSABI_SYSV', 0, 'No extensions or unspecified')
ElfOsabi('ELFOSABI_HPUX', 1, 'Hewlett-Packard HP-UX')
ElfOsabi('ELFOSABI_NETBSD', 2, 'NetBSD')
ElfOsabi('ELFOSABI_LINUX', 3, 'Linux')
ElfOsabi('ELFOSABI_SOLARIS', 6, 'Sun Solaris')
ElfOsabi('ELFOSABI_AIX', 7, 'AIX')
ElfOsabi('ELFOSABI_IRIX', 8, 'IRIX')
ElfOsabi('ELFOSABI_FREEBSD', 9, 'FreeBSD')
ElfOsabi('ELFOSABI_TRU64', 10, 'Compaq TRU64 UNIX')
ElfOsabi('ELFOSABI_MODESTO', 11, 'Novell Modesto')
ElfOsabi('ELFOSABI_OPENBSD', 12, 'Open BSD')
ElfOsabi('ELFOSABI_OPENVMS', 13, 'Open VMS')
ElfOsabi('ELFOSABI_NSK', 14, 'Hewlett-Packard Non-Stop Kernel')
ElfOsabi('ELFOSABI_AROS', 15, 'Amiga Research OS')
ElfOsabi('ELFOSABI_FENIXOS', 16, 'The FenixOS highly scalable multi-core OS')
ElfOsabi('ELFOSABI_ARM_EABI', 64, 'ARM EABI')
ElfOsabi('ELFOSABI_ARM', 97, 'ARM')
ElfOsabi('ELFOSABI_STANDALONE', 255, 'Standalone (embedded) application')

class ElfFile(StructBase):
    """
    This class corresponds to an entire ELF format file.  It is an
    abstract base class which is not intended to be instantiated but
    rather subclassed.

    This abstract base class works in tight concert with it's
    subclasses: :py:class:`ElfFile32b`, :py:class:`ElfFile32l`,
    :py:class:`ElfFile64b`, and :py:class:`ElfFile64l`.  This abstract
    base class sets useless defaults and includes byte order and word
    size independent methods while the subclasses define byte order
    and word size dependent methods.
    """

    name = None
    """
    A :py:class:`str` containing the file name for this ELF format
    object file.
    """

    fileIdent = None
    """
    A :py:class:`ElfFileIdent` representing the :c:data:`e_ident`
    portion of the ELF format file header.
    """

    fileHeader = None
    """
    A :py:class:`ElfFileHeader` representing the byte order and word
    size dependent portion of the ELF format file header.
    """

    sectionHeaders = []
    """
    A :py:class:`list` of section headers.  This corresponds to the
    section header table.
    """

    programHeaders = []
    """
    A :py:class:`list` of the program headers.  This corresponds to
    the program header table.
    """

    fileHeaderClass = None
    """
    Intended to be set by the subclasses.  Points to the byte order
    and word size sensitive class to be used for the ELF file header.
    """

    class NO_CLASS(Exception):
        """
        Raised when attempting to decode an unrecognized value for
        :py:class:`ElfClass`, (that is, word size).
        """
        pass

    class NO_ENCODING(Exception):
        """
        Raised when attempting to decode an unrecognized value for
        :py:class:`ElfData`, (that is, byte order).
        """

    @staticmethod
    def encodedClass(ident):
        """
        :param :py:class:`ElfFileIdent`:  This is
        :rtype :py:class:`ElfFile`: broken
        .. todo:: file sphinx bug on this once code is released so that they can see it.

        Given an *ident*, return a suitable :py:class:`ElfFile` subclass to represent that file.

        Raises :py:exc:`NO_CLASS` if the :py:class:`ElfClass`, (word size), cannot be represented.

        Raises :py:exc:`NO_ENCODING` if the :py:class:`ElfData`, (byte order), cannot be represented.
        """
        classcode = ident.elfClass
        if classcode in _fileEncodingDict:
            elfclass = _fileEncodingDict[classcode]
        else:
            raise ElfFile.NO_CLASS

        endiancode = ident.elfData
        if endiancode in elfclass:
            return elfclass[endiancode]
        else:
            raise ElfFile.NO_ENCODING

    def __new__(cls, name, fileIdent):
        assert fileIdent

        if cls != ElfFile:
            return object.__new__(cls)

        retval = ElfFile.__new__(ElfFile.encodedClass(fileIdent), name, fileIdent)
        retval.__init__(name, fileIdent)
        return retval

    def __init__(self, name, fileIdent):
        """
        :param :py:class:`str` name
        :param :py:class:`ElfFileIdent`
        """

        self.name = name

        self.fileIdent = fileIdent
        self.fileHeader = None
        self.sectionHeaders = []
        self.programHeaders = []

    def unpack_from(self, block, offset=0):
        """
        Unpack an entire file.

        .. todo:: I don't understand whether segments overlap sections
            or not.
        """

        self._unpack_fileIdent(block, offset)
        self._unpack_file_header(block, offset)
        self._unpack_section_headers(block, offset)
        self._unpack_sections(block, offset)
        self._unpack_section_names()
        self._unpack_program_headers(block, offset)
        self._unpack_segments(block, offset)

        return self

    def _unpack_fileIdent(self, block, offset):
        if not self.fileIdent:
            self.fileIdent = ElfFileIdent()

        self.fileIdent.unpack_from(block, offset)

    def _unpack_file_header(self, block, offset):
        if not self.fileHeader:
            self.fileHeader = self.fileHeaderClass()

        self.fileHeader.unpack_from(block, offset + self.fileIdent.size)

    def _unpack_section_headers(self, block, offset):
        # section headers
        if self.fileHeader.shoff != 0:
            sectionCount = self.fileHeader.shnum

            self.sectionHeaders.append(self.sectionHeaderClass().unpack_from(block, offset + self.fileHeader.shoff))

            if sectionCount == 0:
                sectionCount = self.sectionHeaders[0].section_size

            for i in range(1, sectionCount):
                self.sectionHeaders.append(self.sectionHeaderClass().unpack_from(block,
                                                                            offset + self.fileHeader.shoff
                                                                            + (i * self.fileHeader.shentsize)))

    def _unpack_sections(self, block, offset):
        for sh in self.sectionHeaders:
            sh.content = block[offset + sh.offset:offset + sh.offset + sh.section_size] # section contents are copied

    def _unpack_section_names(self):
        # little tricky here - can't read section names until after
        # that section has been read.  So effectively this is two pass.

        for section in self.sectionHeaders:
            section.name = self.sectionName(section)

    def _unpack_program_headers(self, block, offset):
        if self.fileHeader.phoff != 0:
            segmentCount = self.fileHeader.phnum

            self.programHeaders.append(self.programHeaderClass().unpack_from(block, offset + self.fileHeader.phoff))

            if segmentCount == ElfProgramHeader.PN_XNUM:
                segmentCount = self.sectionHeaders[0].info

            for i in range(1, segmentCount):
                self.programHeaders.append(self.programHeaderClass().unpack_from(block,
                                                                                offset + self.fileHeader.phoff
                                                                                + (i * self.fileHeader.phentsize)))

    def _unpack_segments(self, block, offset):
        for ph in self.programHeaders:
            ph.content = block[offset + ph.offset:offset + ph.offset + ph.filesz] # segment contents are copied

    def pack_into(self, block, offset=0):
        """
        Pack the entire file.  Rewrite offsets as necessary.
        """

        total, scoff, shoff, pcoff, phoff = self._offsets(offset)

        self._regen_section_name_table()
        self._pack_file_header(block, offset, shoff, phoff)
        self._pack_sections(block, scoff)
        self._pack_section_headers(block, shoff)

    def _offsets(self, offset=0):
        """
        Current packing layout is:

        * fileIdent + fileHeader
        * section contents
        * sectionHeaders
        """
        x = offset
        x += self.fileHeader.ehsize

        scoff = x
        for i in self.sectionHeaders:
            x += i.section_size

        shoff = x
        x += (len(self.sectionHeaders) * self.fileHeader.shentsize)

        pcoff = x
        for i in self.programHeaders:
            x += 0

        phoff = x
        x += (len(self.programHeaders) * self.fileHeader.phentsize)

        total = x

        return (total, scoff, shoff, pcoff, phoff)

    def _regen_section_name_table(self):
        """
        (Re)build the section name table section.
        """

        # rewrite existing section.  If none exists, we're in trouble.
        # (Will need to deal with that case when it arises.)
        assert self.fileHeader.shstrndx

        section = self.sectionHeaders[self.fileHeader.shstrndx]

        # sum of the sizes of all of the names plus initial null plus
        # all terminating nulls

        # FIXME: could merge pointers to same strings and/or common suffixes.

        section.section_size = (functools.reduce(operator.__add__, [len(sh.name) for sh in self.sectionHeaders])
                                + len(self.sectionHeaders) + 1)

        section.contents = bytearray(section.section_size)

        p = 0
        section.contents[p] = b'\0'
        p += 1

        for sh in self.sectionHeaders:
            l = len(sh.name)
            section.contents[p:l] = sh.name
            section.nameoffset = p
            p += l
            section.contents[l] = b'\0'
            p += 1

    def _pack_file_header(self, block, offset, shoff, phoff):
        """
        Determine and set current offsets then pack the file header.
        """
        self.fileIdent.pack_into(block, offset)

        self.fileHeader.shoff = shoff if len(self.sectionHeaders) > 0 else 0
        self.fileHeader.phoff = phoff if len(self.programHeaders) > 0 else 0
        self.fileHeader.pack_into(block, offset + self.fileIdent.size)

    def _pack_sections(self, block, offset=0):
        """
        Pack the section contents.  As a side effect, set the offsets
        in the section headers telling where we put them and the
        section_sizes telling how much we put.
        """
        p = offset
        for section in self.sectionHeaders:
            section.offset = p
            section.section_size = len(section.content)
            block[p:p + section.section_size] = section.content
            p += section.section_size

    def _pack_section_headers(self, block, offset):
        """
        Pack the section header table.

        .. todo:: first section header is reserved and should be all
            zeros.  Need to verify this and/or force one.
        """
        shiter = zip(range(0, len(self.sectionHeaders)), self.sectionHeaders)
        for i, sh in shiter:
            sh.pack_into(block, offset + (i * self.fileHeader.shentsize))

    @property
    def size(self):
        return self._offsets()[0]

    def sectionName(self, section):
        """
        Given a section, return it's name.

        :param :py:class:`ElfSectionHeader` section:
        """
        x = self.sectionHeaders[self.fileHeader.shstrndx].content
        return x[section.nameoffset:x.find(b'\0', section.nameoffset)]

    def __eq__(self, other):
        """
        .. todo:: it would not be difficult to break up the string
            table, sort, and compare the results.  But then we'll also
            need a way to stub out the embedded path names.
        """

        if not isinstance(other, self.__class__):
            return False

        if (self.fileIdent != other.fileIdent
            or self.fileHeader != other.fileHeader):
            return False

        # FIXME: need to handle order independence
        for this, that in zip(self.sectionHeaders, other.sectionHeaders):
            if this != that:
                import sys
                print('{0} differs from {1}'.format(this, that), file=sys.stderr)
                return False

        return True

    def close_enough(self, other):
        """
        .. todo:: it would not be difficult to break up the string
            table, sort, and compare the results.  But then we'll also
            need a way to stub out the embedded path names.
        """

        if not isinstance(other, self.__class__):
            return False

        if ((not self.fileIdent.close_enough(other.fileIdent))
            or (not self.fileHeader.close_enough(other.fileHeader))):
            return False

        # FIXME: need to handle order independence
        for this, that in zip(self.sectionHeaders, other.sectionHeaders):
            if (this.name in [
                '.ARM.attributes',
                '.ARM.exidx',
                '.ARM.extab',
                '.comment',
                '.debug_aranges',
                '.debug_frame',
                '.debug_info',    # x86_64 linux dyn
                '.debug_line',    # arm debug lines contain file names
                '.debug_loc',
                '.debug_pubnames',
                '.debug_ranges',
                '.debug_str',           # x86_64 linux rela
                '.gnu_debuglink',       # arm: maybe time stamps?
                '.note.GNU-stack',
                '.note.gnu.build-id',   # x86_64 linux dyn
                '.rel.ARM.exidx',
                '.rel.debug_aranges',
                '.rel.debug_frame',
                '.rel.debug_info',      # x86_64 linux rela
                '.rel.debug_line',
                '.rel.debug_pubnames',
                '.rel.text',
                '.rodata',
                '.rodata.str1.4',
                '.shstrtab',
                '.strtab',
                '.symtab',
                ]
                or this.type == SHT.byname['SHT_NOBITS'].code # Not sure what this is or why it differs
                ):
                continue

            if not this.close_enough(that):
                import sys
                print('section({0}) not close enough to section({1})'.format(this.name, that.name), file=sys.stdout)
                return False

        return True

    def __repr__(self):
        return ('<{0}@{1}: name=\'{2}\', fileIdent={3}, fileHeader={4}>'
                .format(self.__class__.__name__, hex(id(self)), self.name, self.fileIdent, self.fileHeader))

    def _list_encode(self):
        return (self.__class__.__name__,
                hex(id(self)),
                {
                    'name': self.name,
                    'fileIdent': self.fileIdent._list_encode(),
                    'fileHeader': self.fileHeader._list_encode(),
                    'sectionHeaders': [sh._list_encode() for sh in self.sectionHeaders],
                    'programHeaders': [ph._list_encode() for ph in self.programHeaders],
                })

class ElfFileHeader(StructBase):
    """
    This abstract base class corresponds to the portion of the `ELF
    file header
    <http://www.sco.com/developers/gabi/latest/ch4.eheader.html>`_
    which follows :c:data:`e_ident`, that is, the word size and byte
    order dependent portion.  This includes thirteen fields.

    Most attributes are :py:class:`int`'s.  Some have encoded meanings
    which can be decoded with the accompanying
    :py:class:`coding.Coding` subclasses.

    This abstract base class works in tight concert with it's
    subclasses: :py:class:`ElfFileHeader32b`,
    :py:class:`ElfFileHeader32l`, :py:class:`ElfFileHeader64b`, and
    :py:class:`ElfFileHeader64l`.  This base class sets useless
    defaults and includes any byte order and word size independent
    methods while the subclasses define byte order and word size
    dependent methods.
    """

    type = None
    """
    The 'type', (sic), of the file which represents whether this file
    is an executable, relocatable object, shared library, etc.
    Encoded using :py:class:`ET`.
    """

    machine = None
    """
    Specifies the processor architecture of the file.  Encoded using :py:class:`EM`.
    """

    version = None
    """
    Specifies the version of the ELF format used for this file.
    Should be 1 in most cases.  Extensions are expected to increment
    the number.
    """

    entry = None
    """
    Virtual start address when this file is converted into a process.
    Zero if not used.
    """

    phoff = None
    """
    Offset in bytes into this file at which the program header table,
    (:py:class:`ElfProgramHeader`), starts.
    """

    shoff = None
    """
    Offset in bytes into this file at which the section header table,
    (:py:class:`ElfSectionHeader`), starts.
    """

    flags = None
    """
    Any processor specific flags for this file.
    """

    ehsize = None
    """
    Size in bytes of the ELF file header, (:py:class:`ElfFileHeader`),
    as represented in this file.
    """

    phentsize = None
    """
    Size in bytes of a program header table entry,
    (:py:class:`ElfProgramHeader`), as represented in this file.  All
    entries are the same size.
    """

    phnum = None
    """
    A count of the number of program header table entries,
    (:py:class:`ElfProgramHeader`), in this file.
    """

    shentsize = None
    """
    Size in bytes of a section table entry,
    (:py:class:`ElfSectionHeader`), as represented in this file.  All
    entries aer the same size.
    """

    shnum = None
    """
    A count of the number of section header table entries,
    (:py:class:`ElfSectionHeader`), in this file.
    """

    shstrndx = None
    """
    The section header table index of the section name string table.
    (SHN_UNDEF if there is none).
    """

    def unpack_from(self, block, offset=0):
        (self.type, self.machine, self.version, self.entry,
         self.phoff, self.shoff, self.flags, self.ehsize,
         self.phentsize, self.phnum, self.shentsize, self.shnum,
         self.shstrndx) = self.coder.unpack_from(block, offset)

        return self

    def pack_into(self, block, offset=0):
        assert(self.type in ET.bycode)
        assert(self.machine in EM.bycode)

        self.coder.pack_into(block, offset, self.type, self.machine,
                             self.version if self.version != None else 1,
                             self.entry if self.entry != None else 0,
                             self.phoff if self.phoff != None else 0,
                             self.shoff if self.shoff != None else 0,
                             self.flags if self.flags != None else 0,
                             self.ehsize if self.ehsize != None else self.size,
                             self.phentsize if self.phentsize != None else self.programHeaderClass.size,
                             self.phnum if self.phnum != None else 0,
                             self.shentsize if self.shentsize != None else self.sectionHeaderClass.size,
                             self.shnum if self.shnum != None else 0,
                             self.shstrndx if self.shstrndx != None else 0)

        return self

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
                and self.type == other.type
                and self.machine == other.machine
                and self.version == other.version
                and self.entry == other.entry
                and self.phoff == other.phoff
                # and self.shoff == other.shoff
                and self.flags == other.flags
                and self.ehsize == other.ehsize
                and self.phentsize == other.phentsize
                and self.phnum == other.phnum
                and self.shentsize == other.shentsize
                and self.shnum == other.shnum
                and self.shstrndx == other.shstrndx)

    def close_enough(self, other):
        return (isinstance(other, self.__class__)
                and self.type == other.type
                and self.machine == other.machine
                and self.version == other.version
                and self.entry == other.entry
                and self.phoff == other.phoff
                and self.flags == other.flags
                and self.ehsize == other.ehsize
                and self.phentsize == other.phentsize
                and self.phnum == other.phnum
                and self.shentsize == other.shentsize
                and self.shnum == other.shnum
                and self.shstrndx == other.shstrndx)

    def __repr__(self):
        return ('<{0}@{1}: type={2}, machine={3}, version={4},'
                ' entry={5}, phoff={6}, shoff={7}, flags={8},'
                ' ehsize={9}, phnum={10}, shentsize={11}, shnum={12},'
                ' shstrndx={13}>'
                .format(self.__class__.__name__, hex(id(self)), ET.bycode[self.type], EM.bycode[self.machine],
                        self.version, hex(self.entry), self.phoff, self.shoff,
                        hex(self.flags), self.ehsize, self.phnum, self.shentsize,
                        self.shnum, self.shstrndx))

    def _list_encode(self):
        return (self.__class__.__name__,
                hex(id(self)),
                {
                    'type': ET.bycode[self.type].name,
                    'machine': EM.bycode[self.machine].name,
                    'version': self.version,
                    'entry': hex(self.entry),
                    'phoff': self.phoff,
                    'shoff': self.shoff,
                    'flags': hex(self.flags),
                    'ehsize': self.ehsize,
                    'phnum': self.phnum,
                    'shentsize': self.shentsize,
                    'shnum': self.shnum,
                    'shstrndx': self.shstrndx,
                })

class ElfFileHeader32b(ElfFileHeader):
    """
    A subclass of :py:class:`ElfFileHeader`.  This one represents
    32-bit, big-endian headers.
    """
    coder = struct.Struct(b'>HHIIIIIHHHHHH')

class ElfFileHeader32l(ElfFileHeader):
    """
    A subclass of :py:class:`ElfFileHeader`.  This one represents
    32-bit, little-endian headers.
    """
    coder = struct.Struct(b'<HHIIIIIHHHHHH')

class ElfFileHeader64b(ElfFileHeader):
    """
    A subclass of :py:class:`ElfFileHeader`.  This one represents
    64-bit, big-endian headers.
    """
    coder = struct.Struct(b'>HHIQQQIHHHHHH')

class ElfFileHeader64l(ElfFileHeader):
    """
    A subclass of :py:class:`ElfFileHeader`.  This one represents
    64-bit, little-endian headers.
    """
    coder = struct.Struct(b'<HHIQQQIHHHHHH')

class ET(coding.Coding):
    """
    Encodes the type of this elf file, (relocatable, executable,
    shared library, etc.), as represented in the `ELF file header
    <http://www.sco.com/developers/gabi/latest/ch4.eheader.html>`_.
    This is a subclass of :py:class:`coding.Coding` and encodes
    :py:attr:`ElfFileHeader.type`.
    """
    bycode = byname = {}

ET('ET_NONE', 0, 'No file type')
ET('ET_REL', 1, 'Relocatable file')
ET('ET_EXEC', 2, 'Executable file')
ET('ET_DYN', 3, 'Shared object file')
ET('ET_CORE', 4, 'Core file')
ET('ET_NUM', 5, '')
ET('ET_LOOS', 0xfe00, 'Operating system-specific')
ET('ET_HIOS', 0xfeff, 'Operating system-specific')
ET('ET_LOPROC', 0xff00, 'Processor-specific')
ET('ET_HIPROC', 0xffff, 'Processor-specific')

class EM(coding.Coding):
    """
    Encodes the processor type represented in this elf file as
    recorded in the `ELF file header <http://www.sco.com/developers/gabi/latest/ch4.eheader.html>`_.

    This is a subclass of :py:class:`coding.Coding` and encodes
    :py:attr:`ElfFileHeader.machine`.
    """
    bycode = byname = {}
    overload_codes = True

EM('EM_NONE', 0, 'No machine')
EM('EM_M32', 1, 'AT&T WE 32100')
EM('EM_SPARC', 2, 'SPARC')
EM('EM_386', 3, 'Intel 80386')
EM('EM_68K', 4, 'Motorola 68000')
EM('EM_88K', 5, 'Motorola 88000')
EM('EM_486', 6, 'Reserved for future use (was EM_486)')
EM('EM_860', 7, 'Intel 80860')
EM('EM_MIPS', 8, 'MIPS I Architecture')
EM('EM_S370', 9, 'IBM System/370 Processor')
EM('EM_MIPS_RS3_LE', 10, 'MIPS RS3000 Little-endian')
# 11 - 14 reserved
EM('EM_PARISC', 15, 'Hewlett-Packard PA-RISC')
# 16 reserved
EM('EM_VPP500', 17, 'Fujitsu VPP500')
EM('EM_SPARC32PLUS', 18, 'Enhanced instruction set SPARC')
EM('EM_960', 19, 'Intel 80960')
EM('EM_PPC', 20, 'PowerPC')
EM('EM_PPC64', 21, '64-bit PowerPC')
EM('EM_S390', 22, 'IBM System/390 Processor')
EM('EM_SPU', 23, 'IBM SPU/SPC')
# 24 - 35 reserved
EM('EM_V800', 36, 'NEC V800')
EM('EM_FR20', 37, 'Fujitsu FR20')
EM('EM_RH32', 38, 'TRW RH-32')
EM('EM_RCE', 39, 'Motorola RCE')
EM('EM_ARM', 40, 'Advanced RISC Machines ARM')
EM('EM_ALPHA', 41, 'Digital Alpha')
EM('EM_SH', 42, 'Hitachi SH')
EM('EM_SPARCV9', 43, 'SPARC Version 9')
EM('EM_TRICORE', 44, 'Siemens TriCore embedded processor')
EM('EM_ARC', 45, 'Argonaut RISC Core, Argonaut Technologies Inc.')
EM('EM_H8_300', 46, 'Hitachi H8/300')
EM('EM_H8_300H', 47, 'Hitachi H8/300H')
EM('EM_H8S', 48, 'Hitachi H8S')
EM('EM_H8_500', 49, 'Hitachi H8/500')
EM('EM_IA_64', 50, 'Intel IA-64 processor architecture')
EM('EM_MIPS_X', 51, 'Stanford MIPS-X')
EM('EM_COLDFIRE', 52, 'Motorola ColdFire')
EM('EM_68HC12', 53, 'Motorola M68HC12')
EM('EM_MMA', 54, 'Fujitsu MMA Multimedia Accelerator')
EM('EM_PCP', 55, 'Siemens PCP')
EM('EM_NCPU', 56, 'Sony nCPU embedded RISC processor')
EM('EM_NDR1', 57, 'Denso NDR1 microprocessor')
EM('EM_STARCORE', 58, 'Motorola Star*Core processor')
EM('EM_ME16', 59, 'Toyota ME16 processor')
EM('EM_ST100', 60, 'STMicroelectronics ST100 processor')
EM('EM_TINYJ', 61, 'Advanced Logic Corp. TinyJ embedded processor family')
EM('EM_X86_64', 62, 'AMD x86-64 architecture')
EM('EM_PDSP', 63, 'Sony DSP Processor')
EM('EM_PDP10', 64, 'Digital Equipment Corp. PDP-10')
EM('EM_PDP11', 65, 'Digital Equipment Corp. PDP-11')
EM('EM_FX66', 66, 'Siemens FX66 microcontroller')
EM('EM_ST9PLUS', 67, 'STMicroelectronics ST9+ 8/16 bit microcontroller')
EM('EM_ST7', 68, 'STMicroelectronics ST7 8-bit microcontroller')
EM('EM_68HC16', 69, 'Motorola MC68HC16 Microcontroller')
EM('EM_68HC11', 70, 'Motorola MC68HC11 Microcontroller')
EM('EM_68HC08', 71, 'Motorola MC68HC08 Microcontroller')
EM('EM_68HC05', 72, 'Motorola MC68HC05 Microcontroller')
EM('EM_SVX', 73, 'Silicon Graphics SVx')
EM('EM_ST19', 74, 'STMicroelectronics ST19 8-bit microcontroller')
EM('EM_VAX', 75, 'Digital VAX')
EM('EM_CRIS', 76, 'Axis Communications 32-bit embedded processor')
EM('EM_JAVELIN', 77, 'Infineon Technologies 32-bit embedded processor')
EM('EM_FIREPATH', 78, 'Element 14 64-bit DSP Processor')
EM('EM_ZSP', 79, 'LSI Logic 16-bit DSP Processor')
EM('EM_MMIX', 80, 'Donald Knuth\'s educational 64-bit processor')
EM('EM_HUANY', 81, 'Harvard University machine-independent object files')
EM('EM_PRISM', 82, 'SiTera Prism')
EM('EM_AVR', 83, 'Atmel AVR 8-bit microcontroller')
EM('EM_FR30', 84, 'Fujitsu FR30')
EM('EM_D10V', 85, 'Mitsubishi D10V')
EM('EM_D30V', 86, 'Mitsubishi D30V')
EM('EM_V850', 87, 'NEC v850')
EM('EM_M32R', 88, 'Mitsubishi M32R')
EM('EM_MN10300', 89, 'Matsushita MN10300')
EM('EM_MN10200', 90, 'Matsushita MN10200')
EM('EM_PJ', 91, 'picoJava')
EM('EM_OPENRISC', 92, 'OpenRISC 32-bit embedded processor')
EM('EM_ARC_COMPACT', 93, 'ARC International ARCompact processor (old spelling/synonym: EM_ARC_A5)')
EM('EM_XTENSA', 94, 'Tensilica Xtensa Architecture')
EM('EM_VIDEOCORE', 95, 'Alphamosaic VideoCore processor')
EM('EM_TMM_GPP', 96, 'Thompson Multimedia General Purpose Processor')
EM('EM_NS32K', 97, 'National Semiconductor 32000 series')
EM('EM_TPC', 98, 'Tenor Network TPC processor')
EM('EM_SNP1K', 99, 'Trebia SNP 1000 processor')
EM('EM_ST200', 100, 'STMicroelectronics (www.st.com) ST200 microcontroller')
EM('EM_IP2K', 101, 'Ubicom IP2xxx microcontroller family')
EM('EM_MAX', 102, 'MAX Processor')
EM('EM_CR', 103, 'National Semiconductor CompactRISC microprocessor')
EM('EM_F2MC16', 104, 'Fujitsu F2MC16')
EM('EM_MSP430', 105, 'Texas Instruments embedded microcontroller msp430')
EM('EM_BLACKFIN', 106, 'Analog Devices Blackfin (DSP) processor')
EM('EM_SE_C33', 107, 'S1C33 Family of Seiko Epson processors')
EM('EM_SEP', 108, 'Sharp embedded microprocessor')
EM('EM_ARCA', 109, 'Arca RISC Microprocessor')
EM('EM_UNICORE', 110, 'Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University')
EM('EM_EXCESS', 111, 'eXcess: 16/32/64-bit configurable embedded CPU')
EM('EM_DXP', 112, 'Icera Semiconductor Inc. Deep Execution Processor')
EM('EM_ALTERA_NIOS2', 113, 'Altera Nios II soft-core processor')
EM('EM_CRX', 114, 'National Semiconductor CompactRISC CRX microprocessor')
EM('EM_XGATE', 115, 'Motorola XGATE embedded processor')
EM('EM_C166', 116, 'Infineon C16x/XC16x processor')
EM('EM_M16C', 117, 'Renesas M16C series microprocessors')
EM('EM_DSPIC30F', 118, 'Microchip Technology dsPIC30F Digital Signal Controller')
EM('EM_CE', 119, 'Freescale Communication Engine RISC core')
EM('EM_M32C', 120, 'Renesas M32C series microprocessors')
# 121 - 130 reserved
EM('EM_TSK3000', 131, 'Altium TSK3000 core')
EM('EM_RS08', 132, 'Freescale RS08 embedded processor')
# 133 reserved
EM('EM_ECOG2', 134, 'Cyan Technology eCOG2 microprocessor')
EM('EM_SCORE7', 135, 'Sunplus S+core7 RISC processor')
EM('EM_DSP24', 136, 'New Japan Radio (NJR) 24-bit DSP Processor')
EM('EM_VIDEOCORE3', 137, 'Broadcom VideoCore III processor')
EM('EM_LATTICEMICO32', 138, 'RISC processor for Lattice FPGA architecture')
EM('EM_SE_C17', 139, 'Seiko Epson C17 family')
EM('EM_TI_C6000', 140, 'The Texas Instruments TMS320C6000 DSP family')
EM('EM_TI_C2000', 141, 'The Texas Instruments TMS320C2000 DSP family')
EM('EM_TI_C5500', 142, 'The Texas Instruments TMS320C55x DSP family')
# 143 - 159 reserved
EM('EM_MMDSP_PLUS', 160, 'STMicroelectronics 64bit VLIW Data Signal Processor')
EM('EM_CYPRESS_M8C', 161, 'Cypress M8C microprocessor')
EM('EM_R32C', 162, 'Renesas R32C series microprocessors')
EM('EM_TRIMEDIA', 163, 'NXP Semiconductors TriMedia architecture family')
EM('EM_QDSP6', 164, 'QUALCOMM DSP6 Processor')
EM('EM_8051', 165, 'Intel 8051 and variants')
EM('EM_STXP7X', 166, 'STMicroelectronics STxP7x family of configurable and extensible RISC processors')
EM('EM_NDS32', 167, 'Andes Technology compact code size embedded RISC processor family')
EM('EM_ECOG1', 168, 'Cyan Technology eCOG1X family')
EM('EM_ECOG1X', 168, 'Cyan Technology eCOG1X family')
EM('EM_MAXQ30', 169, 'Dallas Semiconductor MAXQ30 Core Micro-controllers')
EM('EM_XIMO16', 170, 'New Japan Radio (NJR) 16-bit DSP Processor')
EM('EM_MANIK', 171, 'M2000 Reconfigurable RISC Microprocessor')
EM('EM_CRAYNV2', 172, 'Cray Inc. NV2 vector architecture')
EM('EM_RX', 173, 'Renesas RX family')
EM('EM_METAG', 174, 'Imagination Technologies META processor architecture')
EM('EM_MCST_ELBRUS', 175, 'MCST Elbrus general purpose hardware architecture')
EM('EM_ECOG16', 176, 'Cyan Technology eCOG16 family')
EM('EM_CR16', 177, 'National Semiconductor CompactRISC CR16 16-bit microprocessor')
EM('EM_ETPU', 178, 'Freescale Extended Time Processing Unit')
EM('EM_SLE9X', 179, 'Infineon Technologies SLE9X core')
# 180-182 Reserved for future Intel use
# 183-184 Reserved for future ARM use
EM('EM_AVR32', 185, 'Atmel Corporation 32-bit microprocessor family')
EM('EM_STM8', 186, 'STMicroeletronics STM8 8-bit microcontroller')
EM('EM_TILE64', 187, 'Tilera TILE64 multicore architecture family')
EM('EM_TILEPRO', 188, 'Tilera TILEPro multicore architecture family')
EM('EM_MICROBLAZE', 189, 'Xilinx MicroBlaze 32-bit RISC soft processor core')
EM('EM_CUDA', 190, 'NVIDIA CUDA architecture')
EM('EM_TILEGX', 191, 'Tilera TILE-Gx multicore architecture family')
EM('EM_CLOUDSHIELD', 192, 'CloudShield architecture family')
EM('EM_COREA_1ST', 193, 'KIPO-KAIST Core-A 1st generation processor family')
EM('EM_COREA_2ND', 194, 'KIPO-KAIST Core-A 2nd generation processor family')

class ElfSectionHeader(StructBase):
    """
    This abstract base class corresponds to an entry in `the section
    header table
    <http://www.sco.com/developers/gabi/latest/ch4.sheader.html#section_header>`_.
    This includes ten fields.

    Most attributes are :py:class:`int`'s.  Some have encoded meanings
    which can be decoded with the accompanying
    :py:class:`coding.Coding` subclasses.

    This abstract base class works in tight concert with it's
    subclasses: :py:class:`ElfSectionHeader32b`,
    :py:class:`ElfSectionHeader32l`, :py:class:`ElfSectionHeader64b`,
    and :py:class:`ElfSectionHeader64l`.  This base class sets useless
    defaults and includes any byte order and word size independent
    methods while the subclasses define byte order and word size
    dependent methods.
    """

    nameoffset = None
    """
    Offset into the `section header string table section
    <http://www.sco.com/developers/gabi/latest/ch4.strtab.html>`_ of
    the name of this section.
    """

    name = None
    """
    The name of this section.
    """

    type = None
    """
    Section type encoded with :py:class:`SHT`.
    """

    flags = None
    """
    Flags which define miscellaneous attributes.  These are bit flags
    which are or'd together.  The individual bit-flags are encoded
    using :py:class:`SHF`.
    """

    addr = None
    """
    The load address of this section if it will appear in memory during a running process.
    """

    offset = None
    """
    Byte offset from the start of the file to the beginning of the content of this section.
    """

    section_size = None
    """
    Size in bytes of the content of this section.
    """

    link = None
    """
    A section header table index.  It's meaning varies by context.
    """

    info = None
    """
    Extra information.  It's meaning varies by context.
    """

    addralign = None
    """
    Section alignment constraints.
    """

    entsize = None
    """
    If the section holds fixed sized entries then this is the size of each entry.
    """

    content = None
    """
    A memory block representing the contents of this section.
    """

    def unpack_from(self, block, offset=0):
        (self.nameoffset, self.type, self.flags, self.addr,
         self.offset, self.section_size, self.link, self.info,
         self.addralign, self.entsize) = self.coder.unpack_from(block, offset)

        return self

    def pack_into(self, block, offset=0):
        """
        .. note:: this is a special case.  *block* here must be the
            entire file or we won't know how to place our content.
        """
        self.coder.pack_into(block, offset,
                             self.nameoffset, self.type, self.flags, self.addr,
                             self.offset, self.section_size, self.link, self.info,
                             self.addralign, self.entsize)

        block[self.offset:self.offset + self.section_size] = self.content

        return self

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
                and self.nameoffset == other.nameoffset
                and self.type == other.type
                and self.flags == other.flags
                and self.addr == other.addr
                and self.offset == other.offset
                and self.section_size == other.section_size
                and self.link == other.link
                and self.info == other.info
                and self.addralign == other.addralign
                and self.entsize == other.entsize
                and self.content == other.content)

    def close_enough(self, other):
        return (isinstance(other, self.__class__)
                and self.nameoffset == other.nameoffset
                and self.type == other.type
                and self.flags == other.flags
                and self.addr == other.addr
                and self.section_size == other.section_size
                and self.link == other.link
                and self.info == other.info
                and self.addralign == other.addralign
                and self.entsize == other.entsize
                and self.content == other.content)

    def __repr__(self):
        # FIXME: I wish I could include the first few bytes of the content as well.
        return ('<{0}@{1}: name=\'{2}\', type={3},'
                ' flags={4}, addr={5}, offset={6}, section_size={7},'
                ' link={8}, info={9}, addralign={10}, entsize={11}>'
                .format(self.__class__.__name__, hex(id(self)), self.name,
                        SHT.bycode[self.type] if self.type in SHT.bycode else hex(self.type),
                        hex(self.flags), hex(self.addr), self.offset, self.section_size,
                        self.link, self.info, self.addralign, self.entsize))

    def _list_encode(self):
        return (self.__class__.__name__,
                hex(id(self)),
                {
                    'name': self.name,
                    'type': SHT.bycode[self.type].name if self.type in SHT.bycode else self.type,
                    'flags': hex(self.flags),
                    'offset': self.offset,
                    'section_size': self.section_size,
                    'link': self.link,
                    'info': self.info,
                    'addralign': self.addralign,
                    'entsize': self.entsize,
                })

class ElfSectionHeader32b(ElfSectionHeader):
    """
    A subclass of :py:class:`ElfSectionHeader`.  This one represents
    32-bit, big-endian structs.
    """
    coder = struct.Struct(b'>IIIIIIIIII')

class ElfSectionHeader32l(ElfSectionHeader):
    """
    A subclass of :py:class:`ElfSectionHeader`.  This one represents
    32-bit, little-endian structs.
    """
    coder = struct.Struct(b'<IIIIIIIIII')

class ElfSectionHeader64b(ElfSectionHeader):
    """
    A subclass of :py:class:`ElfSectionHeader`.  This one represents
    64-bit, big-endian structs.
    """
    coder = struct.Struct(b'>IIQQQQIIQQ')

class ElfSectionHeader64l(ElfSectionHeader):
    """
    A subclass of :py:class:`ElfSectionHeader`.  This one represents
    64-bit, little-endian structs.
    """
    coder = struct.Struct(b'<IIQQQQIIQQ')

class SHN(coding.Coding):
    """
    Encodes special section indices into the section header table.

    This is a subclass of :py:class:`coding.Coding`.
    """
    bycode = byname = {}
    overload_codes = True

SHN('SHN_UNDEF', 0, 'marks an undefined, missing, irrelevant, or'
    ' otherwise meaningless section reference')
SHN('SHN_LORESERVE', 0xff00, 'specifies the lower bound of the range'
    ' of reserved indexes')
SHN('SHN_BEFORE', 0xff00, 'Order section before all others (Solaris).')
SHN('SHN_LOPROC', 0xff00, '')
SHN('SHN_AFTER', 0xff01, 'Order section after all others (Solaris).')
SHN('SHN_HIPROC', 0xff1f, '')
SHN('SHN_LOOS', 0xff20, '')
SHN('SHN_HIOS', 0xff3f, '')
SHN('SHN_ABS', 0xfff1, 'specifies absolute values for the corresponding'
    ' reference')
SHN('SHN_COMMON', 0xfff2, 'symbols defined relative to this section are'
    ' common symbols, such as FORTRAN COMMON or unallocated C external variables.')
SHN('SHN_XINDEX', 0xffff, 'This value is an escape value. It indicates'
    ' that the actual section header index is too large to fit in the'
    ' containing field and is to be found in another location (specific'
    ' to the structure where it appears). ')
SHN('SHN_HIRESERVE', 0xffff, 'specifies the upper bound of the range of'
    ' reserved indexes')

class SHT(coding.Coding):
    """
    Encodes the type of a section as represented in the section header
    entry of `the section header table
    <http://www.sco.com/developers/gabi/latest/ch4.sheader.html#section_header>`_.

    This is a subclass of :py:class:`coding.Coding` and encodes
    :py:attr:`ElfSectionHeader.type`.
    """
    bycode = byname = {}
    overload_codes = True

SHT('SHT_NULL', 0, 'marks the section header as inactive; it does not have an'
    ' associated section. Other members of the section header have undefined values.')
SHT('SHT_PROGBITS', 1, 'The section holds information defined by the program,'
    ' whose format and meaning are determined solely by the program.')
SHT('SHT_SYMTAB', 2, 'provides symbols for link editing, though it may also'
    ' be used for dynamic linking.')
SHT('SHT_STRTAB', 3, 'section holds a string table. An object file may have'
    ' multiple string table sections.')
SHT('SHT_RELA', 4, 'section holds relocation entries with explicit addends,'
    ' such as type Elf32_Rela for the 32-bit class of object files or type'
    ' Elf64_Rela for the 64-bit class of object files.')
SHT('SHT_HASH', 5, 'section holds a symbol hash table')
SHT('SHT_DYNAMIC', 6, 'section holds information for dynamic linking')
SHT('SHT_NOTE', 7, 'section holds information that marks the file in some way')
SHT('SHT_NOBITS', 8, 'A section of this type occupies no space in the file'
    ' but otherwise resembles SHT_PROGBITS')
SHT('SHT_REL', 9, 'section holds relocation entries without explicit addends')
SHT('SHT_SHLIB', 10, 'section type is reserved but has unspecified semantics')
SHT('SHT_DYNSYM', 11, 'holds a minimal set of dynamic linking symbols,')
SHT('SHT_INIT_ARRAY', 14, 'section contains an array of pointers to initialization functions')
SHT('SHT_FINI_ARRAY', 15, 'section contains an array of pointers to termination functions')
SHT('SHT_PREINIT_ARRAY', 16, 'section contains an array of pointers to functions'
    ' that are invoked before all other initialization functions')
SHT('SHT_GROUP', 17, 'section defines a section group')
SHT('SHT_SYMTAB_SHNDX', 18, 'section is associated with a section of type'
    ' SHT_SYMTAB and is required if any of the section header indexes referenced'
    ' by that symbol table contain the escape value SHN_XINDEX')
SHT('SHT_LOOS', 0x60000000, '')
SHT('SHT_GNU_ATTRIBUTES', 0x6ffffff5, 'Object attributes.')
SHT('SHT_GNU_HASH', 0x6ffffff6, 'GNU-style hash table.')
SHT('SHT_GNU_LIBLIST', 0x6ffffff7, 'Prelink library lis')
SHT('SHT_CHECKSUM', 0x6ffffff8, 'Checksum for DSO content.')
SHT('SHT_LOSUNW', 0x6ffffffa, 'Sun-specific low bound.')
SHT('SHT_SUNW_move', 0x6ffffffa, 'efine SHT_SUNW_COMDAT')
SHT('SHT_SUNW_COMDAT', 0x6ffffffb, '')
SHT('SHT_SUNW_syminfo', 0x6ffffffc, '')
SHT('SHT_GNU_verdef', 0x6ffffffd, 'Version definition section.')
SHT('SHT_GNU_verneed', 0x6ffffffe, 'Version needs section.')
SHT('SHT_GNU_versym', 0x6fffffff, 'Version symbol table.')
SHT('SHT_HISUNW', 0x6fffffff, 'Sun-specific high bound.')
SHT('SHT_HIOS', 0x6fffffff, '')
SHT('SHT_LOPROC', 0x70000000, '')
SHT('SHT_HIPROC', 0x7fffffff, '')
SHT('SHT_LOUSER', 0x80000000, '')
SHT('SHT_HIUSER', 0xffffffff, '')

class SHF(coding.Coding):
    """
    Encodes the section flags as represented in the section header
    entry of `the section header table
    <http://www.sco.com/developers/gabi/latest/ch4.sheader.html#section_header>`_.

    This is a subclass of :py:class:`coding.Coding` and encodes
    :py:attr:`ElfSectionHeader.flags`.  These are bit flags which are
    or'd together.
    """
    bycode = byname = {}

SHF('SHF_WRITE', 0x1, 'section contains data that should be writable'
    ' during process execution')
SHF('SHF_ALLOC', 0x2, 'section occupies memory during process execution')
SHF('SHF_EXECINSTR', 0x4, 'section contains executable machine instructions')
SHF('SHF_MERGE', 0x10, 'data in the section may be merged to eliminate'
    ' duplication')
SHF('SHF_STRINGS', 0x20, 'data elements in the section consist of'
    ' null-terminated character strings')
SHF('SHF_INFO_LINK', 0x40, 'The sh_info field of this section header'
    ' holds a section header table index')
SHF('SHF_LINK_ORDER', 0x80, 'adds special ordering requirements for link editors')
SHF('SHF_OS_NONCONFORMING', 0x100, 'section requires special OS-specific processing')
SHF('SHF_GROUP', 0x200, 'section is a member of a section group')
SHF('SHF_TLS', 0x400, 'section holds Thread-Local Storage')
SHF('SHF_MASKOS', 0x0ff00000, 'All bits included in this mask are reserved'
    ' for operating system-specific semantics')
SHF('SHF_MASKPROC', 0xf0000000, 'All bits included in this mask are reserved'
    ' for processor-specific semantics')
SHF('SHF_ORDERED', (1 << 30), 'Special ordering requirement (Solaris).')
SHF('SHF_EXCLUDE', (1 << 31), 'Section is excluded unless referenced or allocated (Solaris).')

class ElfProgramHeader(StructBase):
    """
    This abstract base class corresponds to a `program header
    <http://www.sco.com/developers/gabi/latest/ch5.pheader.html>`_.

    Most attributes are :py:class:`int`'s.  Some have encoded meanings
    which can be decoded with the accompanying
    :py:class:`coding.Coding` subclasses.

    This abstract base class works in tight concert with it's
    subclasses: :py:class:`ElfProgramHeader32b`,
    :py:class:`ElfProgramHeader32l`, :py:class:`ElfProgramHeader64b`,
    and :py:class:`ElfProgramHeader64l`.  This base class sets useless
    defaults and includes any byte order and word size independent
    methods while the subclasses define byte order and word size
    dependent methods.
    """

    PN_XNUM = 0xffff
    """
    Program header overflow number.
    """

    type = None
    """
    Segment type encoded with :py:class:`PT`.
    """

    offset = None
    """
    Offset in bytes from the beginning of the file to the start of this segment.
    """

    vaddr = None
    """
    Virtual address at which this segment will reside in memory when loaded to run.
    """

    paddr = None
    """
    Physical address in memory, when physical addresses are used.
    """

    filesz = None
    """
    Segment size in bytes in file.
    """

    memsz = None
    """
    Segment size in bytes when loaded into memory.  Must be at least
    :py:attr:`ElfProgramHeader.filesz` or greater.  Extra space is
    zero'd out.
    """

    flags = None
    """
    Flags for the segment.  Encoded using :py:class:`PF`.
    """

    content = None
    """
    A memory block representing the contents of this section.
    """

    align = None
    """
    Alignment of both segments in memory as well as in file.
    """

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
                and self.type == other.type
                and self.offset == other.offset
                and self.vaddr == other.vaddr
                and self.paddr == other.paddr
                and self.filesz == other.filesz
                and self.memsz == other.memsz
                and self.flags == other.flags
                and self.align == other.align)

    def __repr__(self):
        return ('<{0}@{1}: type={2},'
                ' offset={3}, vaddr={4}, paddr={5},'
                ' filesz={6}, memsz={7}, flags={8}, align={9}>'
                .format(self.__class__.__name__, hex(id(self)),
                        PT.bycode[self.type].name if self.type in PT.bycode else self.type,
                        self.offset, hex(self.vaddr), hex(self.paddr),
                        self.filesz, self.memsz, hex(self.flags), self.align))

    def _list_encode(self):
        return (self.__class__.__name__,
                hex(id(self)),
                {
                    'type': PT.bycode[self.type].name if self.type in PT.bycode else self.type,
                    'offset': self.offset,
                    'vaddr': hex(self.vaddr),
                    'paddr': hex(self.paddr),
                    'filesz': self.filesz,
                    'memsz': self.memsz,
                    'flags': hex(self.flags),
                    'align': self.align,
                })

class PT(coding.Coding):
    """
    Encodes the segment type as recorded in the `program header
    <http://www.sco.com/developers/gabi/latest/ch5.pheader.html>`_.

    This is a subclass of :py:class:`coding.Coding` and encodes
    :py:attr:`ElfProgramHeader.type`.
    """
    bycode = byname = {}
    overload_codes = True

PT('PT_NULL', 0, 'array element is unused')
PT('PT_LOAD', 1, 'array element specifies a loadable segment')
PT('PT_DYNAMIC', 2, 'array element specifies dynamic linking information')
PT('PT_INTERP', 3, 'array element specifies the location and size'
   ' of a null-terminated path name to invoke as an interpreter')
PT('PT_NOTE', 4, 'array element specifies the location and size of'
   ' auxiliary information')
PT('PT_SHLIB', 5, 'segment type is reserved')
PT('PT_PHDR', 6, 'specifies the location and size of the program'
   ' header table itself')
PT('PT_TLS', 7, 'array element specifies the Thread-Local Storage template')
PT('PT_LOOS', 0x60000000, '')
PT('PT_GNU_EH_FRAME', 0x6474e550, 'GCC .eh_frame_hdr segment')
PT('PT_GNU_STACK', 0x6474e551, 'Indicates stack executability')
PT('PT_GNU_RELRO', 0x6474e552, 'Read only after relocation')
PT('PT_LOSUNW', 0x6ffffffa, '')
PT('PT_SUNWBSS', 0x6ffffffa, 'Sun Specific segment')
PT('PT_SUNWSTACK', 0x6ffffffb, 'Stack segment')
PT('PT_HISUNW', 0x6fffffff, '')
PT('PT_HIOS', 0x6fffffff, '')
PT('PT_LOPROC', 0x70000000, '')
PT('PT_HIPROC', 0x7fffffff, '')

class PF(coding.Coding):
    """
    Encodes the segment flags as recorded in the `program header
    <http://www.sco.com/developers/gabi/latest/ch5.pheader.html>`_.

    This is a subclass of :py:class:`coding.Coding` and encodes
    :py:attr:`ElfProgramHeader.flags`.
    """

    bycode = byname = {}

PF('PF_X', 0x1, 'Execute')
PF('PF_W', 0x2, 'Write')
PF('PF_R', 0x4, 'Read')
PF('PF_MASKOS', 0x0ff00000, 'Unspecified')
PF('PF_MASKPROC', 0xf0000000, 'Unspecified')

class ElfProgramHeader32(ElfProgramHeader):
    """
    32 vs 64 bit files have differing element orders.  This class
    represents the 32 bit element order.  A subclass of
    :py:class:`ElfProgramHeader`.
    """

    def unpack_from(self, block, offset=0):
        (self.type, self.offset, self.vaddr, self.paddr,
         self.filesz, self.memsz, self.flags, self.align) = self.coder.unpack_from(block, offset)

        return self

    def pack_into(self, block, offset=0):
        self.coder.pack_into(block, offset,
                             self.type, self.offset, self.vaddr, self.paddr,
                             self.filesz, self.memsz, self.flags, self.align)

        return self

class ElfProgramHeader64(ElfProgramHeader):
    """
    32 vs 64 bit files have differing element orders.  This class
    represents the 64 bit element order.  A subclass of
    :py:class:`ElfProgramHeader`.
    """

    def unpack_from(self, block, offset=0):
        (self.type, self.flags, self.offset, self.vaddr,
         self.paddr, self.filesz, self.memsz, self.align) = self.coder.unpack_from(block, offset)

        return self

    def pack_into(self, block, offset=0):
        self.coder.pack_into(block, offset,
                             self.type, self.flags, self.offset, self.vaddr,
                             self.paddr, self.filesz, self.memsz, self.align)

        return self

class ElfProgramHeader32b(ElfProgramHeader32):
    """
    A subclass of :py:class:`ElfProgramHeader32`.  Represents big
    endian byte order.
    """
    coder = struct.Struct(b'>IIIIIIII')

class ElfProgramHeader32l(ElfProgramHeader32):
    """
    A subclass of :py:class:`ElfProgramHeader32`.  Represents little
    endian byte order.
    """
    coder = struct.Struct(b'<IIIIIIII')

class ElfProgramHeader64b(ElfProgramHeader64):
    """
    A subclass of :py:class:`ElfProgramHeader64`.  Represents big
    endian byte order.
    """
    coder = struct.Struct(b'>IIQQQQQQ')

class ElfProgramHeader64l(ElfProgramHeader64):
    """
    A subclass of :py:class:`ElfProgramHeader64`.  Represents little
    endian byte order.
    """
    coder = struct.Struct(b'<IIQQQQQQ')

class ElfFile32b(ElfFile):
    """
    A subclass of :py:class:`ElfFile`.  Represents 32-bit, big-endian
    files.
    """
    fileHeaderClass = ElfFileHeader32b
    sectionHeaderClass = ElfSectionHeader32b
    programHeaderClass = ElfProgramHeader32b

class ElfFile32l(ElfFile):
    """
    A subclass of :py:class:`ElfFile`.  Represents 32-bit,
    little-endian files.
    """
    fileHeaderClass = ElfFileHeader32l
    sectionHeaderClass = ElfSectionHeader32l
    programHeaderClass = ElfProgramHeader32l

class ElfFile64b(ElfFile):
    """
    A subclass of :py:class:`ElfFile`.  Represents 64-bit, big-endian
    files.
    """
    fileHeaderClass = ElfFileHeader64b
    sectionHeaderClass = ElfSectionHeader64b
    programHeaderClass = ElfProgramHeader64b

class ElfFile64l(ElfFile):
    """
    A subclass of :py:class:`ElfFile`.  Represents 64-bit,
    little-endian files.
    """
    fileHeaderClass = ElfFileHeader64l
    sectionHeaderClass = ElfSectionHeader64l
    programHeaderClass = ElfProgramHeader64l

_fileEncodingDict = {
    1: {
        1: ElfFile32l,
        2: ElfFile32b,
        },
    2: {
        1: ElfFile64l,
        2: ElfFile32b,
        },
    }
"""
This is a dict of dicts.  The first level keys correspond to
:py:class:`ElfClass` codes and the values are second level dicts.  The
second level dict keys correspond to :py:class:`ElfData` codes and the
second level values are the four :py:class:`ElfFile` subclasses.  It
is used by :py:meth:`ElfClass.encodedClass` to determine an
appropriate subclass to represent a file based on a
:py:class:`ElfFileIdent`.
"""

class GRP(coding.Coding):
    bycode = byname = {}

GRP('GRP_COMDAT', 0x1, 'This is a COMDAT group')
GRP('GRP_MASKOS', 0x0ff00000, 'All bits included in this mask are'
    ' reserved for operating system-specific semantics')
GRP('GRP_MASKPROC', 0xf0000000, 'All bits included in this mask'
    ' are reserved for processor-specific semantics')


text:
Alternatives

Think about whether you really need the Singleton. The example below shows a project where a singleton, BulletManager was used, but it wasn’t really necessary.

class Bullet
    {
    public:
    int getX() const { return x_; }
    int getY() const { return y_; }

    void setX(int x) { x_ = x; }
    void setY(int y) { y_ = y; }

    private:
    int x_, y_;
    };

    class BulletManager
    {
    public:
    Bullet* create(int x, int y)
    {
    Bullet* bullet = new Bullet();
    bullet->setX(x);
    bullet->setY(y);

    return bullet;
    }

    bool isOnScreen(Bullet& bullet)
    {
    return bullet.getX() >= 0 &&
    bullet.getX() < SCREEN_WIDTH &&
    bullet.getY() >= 0 &&
    bullet.getY() < SCREEN_HEIGHT;
    }

    void move(Bullet& bullet)
    {
    bullet.setX(bullet.getX() + 5);
    }
    };

In the example above, someone was using a Bullet class to hold data about a bullet, like its x and y location. They were then using a BulletManager class to move the bullet. This is an extreme example, but nevertheless worth exploring.

An obvious solution below:

class Bullet
    {
    public:
    Bullet(int x, int y) : x_(x), y_(y) {}

    bool isOnScreen()
    {
    return x_ >= 0 && x_ < SCREEN_WIDTH &&
    y_ >= 0 && y_ < SCREEN_HEIGHT;
    }

    void move() { x_ += 5; }

    private:
    int x_, y_;
    };

There was no need for BulletManager in the first place!

Use something already global

Usually, games will have an unavoidable singleton, like Game, or World. Often it is better to have these singletons contain things like FileSystem, AudioEngine, Log, or others.

Pass it as a parameter!

It can be cumbersome, but it can also be a good solution. Android passes a Context class nearly everywhere. Are our games going to be that large and complex that passing a couple parameters here and there is too difficult?

In order to pass it as a parameter everywhere, the Google Testing Blog7 recommends using an ApplicationFactory class, which will instantiate the necessary classes. You will only create one instance of an ApplicationFactory class in the main() method.

    The Unity Alternative

    As addressed on the Unity3D wiki, Singletons are generally abused by being misused a lot, so they encourage that you use ToolBox instead.

    Toolbox

    The Toolbox is a Singleton but improves on the concept by improving unit testing and coupling. What makes the Toolbox different from the Singleton is that a Singleton is a class where as the Toolbox is the application which contains the components required. You can learn more about the Toolbox in this paper www.ibm.com/developerworks/webservices/library/co-single/co-single-pdf.pdf.

Tool boxes make it easier for unit testing.

<kuizu datasource="alternatives.json" spark-scroll-animate="quizAnimation"></kuizu>

redpajama_set_name: RedPajamaGithub


text:
'''Tools for image recognition and classification projects.

Author: Karl J. Obermeyer
'''

# Scientific Computing and Visualization
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import cv2  # Image processing.

# ----- Image Processing -----

def rgb2gray(image, add_degenerate_dimension=False):
    '''Convert RGB image to grayscale.

    Args:
        image: numpy array, RGB image.
        add_degenerate_dimension: bool, whether to make grayscale output image
          have and extra degenerate dimension of size 1.

    Returns:
        numpy array, grayscale image.
    '''
    if add_degenerate_dimension:
        return cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)[:, :, None]
    else:
        return cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

def histogram_equalize_brightness(image):
    '''Improve contrast of RGB or grayscale image via histogram equalization of
    brightness. Preserves degenerate dimension of grayscale image, if any.

    Args:
        image: numpy array, RGB or grayscale image.

    Returns:
        image_out: numpy array, RGB image with improved contrast.
    '''

    if len(image.shape) == 3:
        if image.shape[2] == 3:
            image_yuv = cv2.cvtColor(image, cv2.COLOR_RGB2YUV)
            image_yuv[:, :, 0] = cv2.equalizeHist(image_yuv[:, :, 0])
            image_out = cv2.cvtColor(image_yuv, cv2.COLOR_YUV2RGB)
        else:  # image.shape[2] == 1  # gray with degenerate dimension
            image_out = cv2.equalizeHist(image[:, :, 0])[:, :, None]
    else:  # grayscale
        image_out = cv2.equalizeHist(image)

    return image_out

def test_histogram_equalize_brightness(image):
    '''Test histogram brightness equalization on an RGB or grayscale image.

    Args:
        image: numpy array, RGB or grayscale image. Grayscale images are
          allowed to have degenerate dimension.

    Returns:
        None, just plots images.
    '''

    if len(image.shape) == 2 or image.shape[2] == 1:  # grayscale
        fig, axes = plt.subplots(
            1, 2, figsize=(6, 5),
            subplot_kw={'xticks': [], 'yticks': []})
        fig.subplots_adjust(hspace=0.7, wspace=0.8)
        axf = axes.flat # Iterator over axes.
        ax = next(axf); ax.imshow(image.squeeze(), cmap='gray')
        ax = next(axf); ax.imshow(
            histogram_equalize_brightness(image.squeeze()), cmap='gray')
    else:  # RGB
        image_gray = rgb2gray(image)
        fig, axes = plt.subplots(
            2, 2, figsize=(6, 5),
            subplot_kw={'xticks': [], 'yticks': []})
        fig.subplots_adjust(hspace=0.7, wspace=0.8)
        axf = axes.flat # Iterator over axes.
        ax = next(axf); ax.imshow(image)
        ax = next(axf); ax.imshow(histogram_equalize_brightness(image))
        ax = next(axf); ax.imshow(image_gray, cmap='gray')
        ax = next(axf); ax.imshow(
            histogram_equalize_brightness(image_gray), cmap='gray')

def scale_brightness(image, scale_factor=1.0):
    '''Scale brightness of an image, with clamp from above.

    Args:
        image: numpy array, RGB or grayscale image. Grayscale images are
          allowed to have a degenerate dimension, and that dimension is
          preserved when present in input.
        scale_factor: float.

    Returns:
        numpy array, image with brightness scaled.
    '''

    if len(image.shape) == 3 and image.shape[2] == 3:  # RGB
        image_out = cv2.cvtColor(
            image, cv2.COLOR_RGB2HSV).astype(dtype=np.float32)
        image_out[:, :, 2] = scale_factor*image_out[:, :, 2]
        image_out[:, :, 2][image_out[:, :, 2] > 255] = 255  # Upper clamp.
        image_out = image_out.astype(dtype=np.uint8)
        image_out = cv2.cvtColor(image_out, cv2.COLOR_HSV2RGB)
    else:  # grayscale
        image_out = scale_factor*image.astype(dtype=np.float32)
        np.clip(image_out, a_min=0.0, a_max=255.0, out=image_out)
        image_out = image_out.astype(dtype=np.uint8)

    return image_out

def normalize(image):
    '''Normalize image, RGB or grayscale.  Puts each pixel into the
    range [-1.0, 1.0].

    Args:
        image: numpy array, image with pixels values in the range [0, 255].
          RGB, grayscale, and grayscale with a degenerate dimension are all
          allowed. Degenerate dimension is preserved when present in input.

    Returns:
        numpy array like input image, but normalized, so
        dtype is float32 instead of a uint8.
    '''
    return ((image - 128.0) / 128.0).astype(np.float32)

def randomly_perturb(
    image,
    brightness_radius=0.3,
    rotation_radius=30.0,
    translation_radius=3,
    shear_radius=3):
    '''Perturb image in brightness, rotation, translation, and shear. The
    *_radius inputs, w.r.t. the infinity norm, are the radii of intervals on
    which perturbation parameters are uniform randomly sampled.

    Inspired in part by
    https://github.com/vxy10/ImageAugmentation

    OpenCV functions
    http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html

    Args:
        image: numpy array, RGB or grayscale image. Grayscale images are
          allowed to have a degenerate dimension, and that dimension is
          preserved when present in input.
        brightness_radius: float, unitless.
        rotation_radius: float, degrees.
        translation_radius: float, pixels.
        shear_radius: float, pixels.

    Returns:
        image_out: numpy array, perturbed version of the image.
    '''
    row_cnt = image.shape[0]
    column_cnt = image.shape[1]

    # Brightness.
    brightness_factor = np.random.uniform(
        low=1.0 - brightness_radius,
        high=1.0 + brightness_radius)
    image_out = scale_brightness(image, scale_factor=brightness_factor)

    # Rotation.
    rotation_angle = np.random.uniform(
        low=-0.5*rotation_radius, high=0.5*rotation_radius)
    M_rotation = cv2.getRotationMatrix2D(
        (column_cnt/2, row_cnt/2), rotation_angle, 1.0)

    # Translation.
    dx = np.random.uniform(
      low=-0.5*translation_radius, high=0.5*translation_radius)
    dy = np.random.uniform(
      low=-0.5*translation_radius, high=0.5*translation_radius)
    M_translation = np.float32([[1.0, 0.0, dx], [0.0, 1.0, dy]])

    # Shear.
    points0 = np.float32([[5.0, 5.0], [20.0, 5.0], [5.0, 20.0]])
    point0 = 5.0 + shear_radius*np.random.uniform(low=-0.5, high=0.5)
    point1 = 20 + shear_radius*np.random.uniform(low=-0.5, high=0.5)
    points1 = np.float32([[point0, 5.0], [point1, point0], [5.0, point1]])
    M_shear = cv2.getAffineTransform(points0, points1)

    if len(image_out.shape) == 3 and image_out.shape[2] == 1:
        # Grayscale with degenerate dimension.
        image_out = cv2.warpAffine(
            image_out[:, :, 0], M_rotation, (column_cnt, row_cnt))
        image_out = cv2.warpAffine(
            image_out, M_translation, (column_cnt, row_cnt))
        image_out = cv2.warpAffine(
            image_out, M_shear, (column_cnt, row_cnt))[:, :, None]
    else:  # RGB and grayscale without degenerate dimension.
        image_out = cv2.warpAffine(
            image_out, M_rotation, (column_cnt, row_cnt))
        image_out = cv2.warpAffine(
            image_out, M_translation, (column_cnt, row_cnt))
        image_out = cv2.warpAffine(
            image_out, M_shear, (column_cnt, row_cnt))

    return image_out

def test_randomly_perturb(
    image,
    brightness_radius=0.3,
    rotation_radius=30.0,
    translation_radius=3,
    shear_radius=3):
    '''Test random perturbation on an RGB image.

    Args:
        image: numpy array, RGB or grayscale image. Grayscale images are
            allowed to have degenerate dimension.
        brightness_radius: float.
        rotation_radius: float.
        translation_radius: float.
        shear_radius: float.

    Returns:
        None, just plots images.
    '''
    row_cnt = 6
    column_cnt = 4
    width = 17
    height = 15
    gs = gridspec.GridSpec(row_cnt, column_cnt)
    gs.update(wspace=0.01, hspace=0.02) # set the spacing between axes.
    plt.figure(figsize=(width, height))
    for i in range(row_cnt*column_cnt):
        perturbation = randomly_perturb(
            image,
            brightness_radius,
            rotation_radius,
            translation_radius,
            shear_radius)
        ax1 = plt.subplot(gs[i])
        ax1.set_xticklabels([])
        ax1.set_yticklabels([])
        ax1.set_aspect('equal')
        plt.subplot(row_cnt, column_cnt, i+1)

        if len(image.shape) == 3 and image.shape[2] == 3:  # RGB
            plt.imshow(perturbation)
        else:  # grayscale
            plt.imshow(perturbation.squeeze(), cmap='gray')

        plt.axis('off')

# ----- Dataset Manipulation -----

def shuffle(X, y):
    '''Generate and return randomly shuffled versions of X and y.
    Similar to sklearn.utils.shuffle, but uses numpy.random seed
    for consistency.

    Args:
        X: numpy array, e.g., as X_train, X_validate, or X_test.
        y: numpy array, e.g., as y_train, y_validate, or y_test.

    Returns:œ
        X_shuffled: numpy array of images, e.g., as X_train,
          X_validate, or X_test.
        y_shuffled: numpy array of int labels, e.g., as y_train,
          y_validate, or y_test.
    '''
    ixs_shuffled = np.arange(len(y))
    np.random.shuffle(ixs_shuffled)
    return X[ixs_shuffled, :], y[ixs_shuffled]

def combine(*args):
    '''Combine image classification datasets.

    Args:
        args: a sequence of data pairs, e.g., X0, y0, X1, y1, X2, y2,
          where each X is a numpy array of images and each y is a
          numpy array of class labels.

    Returns:
        X_combined: numpy array of images.
        y_combined: numpy array of class labels.
    '''
    assert len(args) % 2 == 0, 'Must be even number of arguments!'
    input_pair_cnt = int(len(args)/2)
    image_shape = args[0][0, :].shape

    X_dtype = args[0].dtype  # Usu. np.uint8 or np.float32.
    y_dtype = args[1].dtype  # Usu. np.uint8 or str.

    # Count total number of datapoints.
    datapoint_cnt = 0
    for i in range(input_pair_cnt):
        datapoint_cnt += len(args[2*i + 1])

    # Initialize output.
    X_combined = np.zeros((datapoint_cnt, *image_shape), dtype=X_dtype)
    y_combined = np.zeros(datapoint_cnt, dtype=y_dtype)

    # Populate output.
    ix_next = 0
    for i in range(input_pair_cnt):
        ix_next_next = ix_next + len(args[2*i + 1])
        X_combined[ix_next:ix_next_next, :] = args[2*i]
        y_combined[ix_next:ix_next_next] = args[2*i + 1]
        ix_next = ix_next_next

    return X_combined, y_combined

def count_by_label(y):
    '''Count the number of occurrences of each label.
    Args:
        y: numpy array of int labels, e.g., as y_train, y_validate,
          or y_test.

    Returns:
        datapoint_cnt_by_label: dict, where keys are class labels and
          values are the number of respective label occurrences as
          unsigned ints.
    '''
    datapoint_cnt_by_label = {}
    for y_ in y:
        if y_ in datapoint_cnt_by_label:
            datapoint_cnt_by_label[y_] += 1
        else:
            datapoint_cnt_by_label[y_] = 1

    return datapoint_cnt_by_label

def sort_by_class(X, y, class_list, datapoint_cnt_by_label=None):
    '''Sort images by class.

    Args:
        X: numpy array of images, e.g., as X_train, X_validate, or
          X_test.
        y: numpy array of int labels, e.g., as y_train, y_validate,
          or y_test.
        class_list: list of class labels.
        datapoint_cnt_by_label: None or dict, where keys are class
          labels and values are the number of respective label
          occurrences as unsigned ints.  None => computed
          internally, else precompute using
          count_by_label(...).

    Returns:
        images_by_label: dict, where keys are class labels and
          values are numpy arrays of images.
    '''
    image_shape = X[0].shape

    images_by_label = {}  # All images by label.
    if datapoint_cnt_by_label is None:
        datapoint_cnt_by_label = count_by_label(y)

    # Initialize numpy array for each label.
    for label, cnt in datapoint_cnt_by_label.items():
        images_by_label[label] = \
          np.zeros((cnt, *image_shape), dtype=X.dtype)

    # Finish populating output.
    next_image_ixs = { label: 0 for label in class_list }
    for i, label in enumerate(y):
        images_by_label[label][next_image_ixs[label], :] = X[i, :]
        next_image_ixs[label] += 1

    return images_by_label

def balance(
        X, y, class_list, datapoint_cnt_per_class=None, perturb=False):
    '''Create a new dataset with datapoints either pruned or replicated
    such that every class has exactly datapoint_cnt_per_class datapoints.

    Args:
        X: numpy array of images, e.g., as X_train, X_validate, or
          X_test.  Assumed shuffled.
        y: numpy array of int labels, e.g., as y_train, y_validate,
          or y_test.  Assumed shuffled.
        class_list: list of class labels.
        datapoint_cnt_per_class: None or unsigned, optional number
          of data points to use per label. Default is the number of
          datapoints in the most represented class.
        perturb: bool, whether to perturb (modulate brightness, translate,
          rotate, shear) replicated images.

    Returns:
        X_balanced: numpy array of images, where each class has
          exactly datapoint_cnt_per_class datapoints.
        y_balanced: numpy array of unsigned labels, where each
            class has exactly datapoint_cnt_per_class datapoints.
    '''

    class_cnt = len(class_list)
    image_shape = X[0, :].shape
    datapoint_cnt_by_label = count_by_label(y)
    if datapoint_cnt_per_class is None:
        datapoint_cnt_per_class = max(datapoint_cnt_by_label.values())
    images_by_label = sort_by_class(
        X, y, class_list, datapoint_cnt_by_label=datapoint_cnt_by_label)

    # Initialize output.
    datapoint_cnt = datapoint_cnt_per_class*class_cnt
    X_balanced = np.zeros((datapoint_cnt, *image_shape), dtype=np.uint8)
    y_balanced = np.zeros(datapoint_cnt, dtype=np.uint8)

    # Populate output.
    running_datapoint_cnts = { label: 0 for label in class_list }
    for i in range(datapoint_cnt):
        label = class_list[i % class_cnt]
        image = images_by_label[label][i % datapoint_cnt_by_label[label], :]
        if not perturb or \
           running_datapoint_cnts[label] < datapoint_cnt_by_label[label]:
            X_balanced[i, :] = image
        else:
            X_balanced[i, :] = randomly_perturb(image)
        y_balanced[i] = label
        running_datapoint_cnts[label] += 1

    return shuffle(X_balanced, y_balanced)

# ----- Dataset Visualization -----

def truncate_string(s, ubnd, add_ellipses=True):
    '''Return a version of the string that is clamped at the end to
    length `ubnd`.

    Args:
        s: string, string to clamp.
        ubnd: unsigned int, max length of output string.
        add_ellipses: bool, whether to replace the last 3 chars of truncated
          strings with an ellipsis.

    Returns:
      string, clamped version of `s`.
    '''
    s_length = len(s)
    if s_length <= ubnd:
        return s
    else:
        return s[:ubnd-3] + '...'

def class_histograms(
    y_train, y_validate, y_test,
    class_cnt, suptitle_prefix=''):
    '''Plot histograms of class representation in each dataset.

    Args:
        y_train: numpy array, training labels.
        y_validate: numpy array, validation labels.
        y_test: numpy array, testing labels.
        class_cnt: unsigned, precomputed number of classes.
        suptitle_prefix: string, to describe datasets modified, e.g.,
          by over- or undersampling.

    Returns:
        None
    '''

    bin_cnt = class_cnt

    #fig = plt.figure()
    fig = plt.figure(
        figsize=(13, 10), dpi=80, facecolor='w', edgecolor='k')
    fig.subplots_adjust(hspace=0.4, wspace=0.7, top=0.9)
    fig.suptitle(r'$\ \ \ $ ' + suptitle_prefix +
        ' Class Counts', fontsize=16, fontweight='bold')

    # Bar chart showing distribution of classes in training set.
    ax = fig.add_subplot(3, 1, 1)  # [rows|columns|plot]
    plt.hist(y_train, bins=bin_cnt, normed=False)
    #plt.xlabel('', fontsize=14, fontweight='bold')
    #plt.ylabel('Number of Classes', fontsize=14, fontweight='bold')
    plt.title('Training Set', fontsize=14, fontweight='bold')
    ax.grid(True)

    # Bar chart showing distribution of classes in validation set.
    ax = fig.add_subplot(3, 1, 2)  # [rows|columns|plot]
    plt.hist(y_validate, bins=bin_cnt, normed=False)
    #plt.xlabel('', fontsize=14, fontweight='bold')
    plt.ylabel('Number of Datapoints in Class', fontsize=14, fontweight='bold')
    plt.title('Validation Set', fontsize=14, fontweight='bold')
    ax.grid(True)

    # Bar chart showing distribution of classes in test set.
    ax = fig.add_subplot(3, 1, 3)  # [rows|columns|plot]
    plt.hist(y_test, bins=bin_cnt, normed=False)
    plt.xlabel('Class Label', fontsize=14, fontweight='bold')
    #plt.ylabel('Number of Classes', fontsize=14, fontweight='bold')
    plt.title('Test Set', fontsize=14, fontweight='bold')
    ax.grid(True)

def plot_images(X, y=None, english_labels=None):
    '''Plot all images in a dataset.

    Args:
        X: numpy array of images, e.g., as X_train, X_validate, or
          X_test.
        y: None or indexable of labels, e.g., as y_train,
          y_validate, or y_test.
        english_labels: None or list of strings, the English names
          for labels in y.

    Returns:
        None
    '''
    # ::CAUTION:: RGB images should have type np.uint8. Images cast
    # as a float type will not display correctly with matplotlib.

    image_cnt = X.shape[0]
    column_cnt = 3
    row_cnt = int(np.ceil(image_cnt/column_cnt))
    height = 2.5*row_cnt
    fig, axes = plt.subplots(
        row_cnt, column_cnt, figsize=(15, height),
        subplot_kw={'xticks': [], 'yticks': []})
    fig.subplots_adjust(hspace=0.7, wspace=0.8)
    axf = axes.flat  # Iterator over axes.
    for i in range(X.shape[0]):
        ax = next(axf)
        if X.shape[3] == 3:
            ax.imshow(X[i, :].squeeze())
        else:
            ax.imshow(X[i, :].squeeze(), cmap='gray')
        if y is not None:
            label = y[i]
            if english_labels is not None:
                full_label = str(label) + ': ' + english_labels[label]
            else:
                full_label = str(label)
            ax.set_title(truncate_string(full_label, ubnd=25))
    for i in range(row_cnt*column_cnt - image_cnt):
        ax = next(axf)
        ax.set_visible(False)  # Hide blank subplot.

def plot_representative_images(
    images_by_label, class_cnt, english_labels=None,
    method='first', image_cnt=None):
    '''Plot one summary image for each class in a dataset.

    Args:
        images_by_label: dict of numpy arrays, e.g., as output by
            sort_by_class(...).
        class_cnt: unsigned, number of image classes.
        english_labels: None or list of strings, the English names
          for labels in y.
        method: string, use as representative
          'first' => first encountered example,
          'mean' => pixelwise mean of first image_cnt images encoutnered,
          'median' => pixelwise median of first image_cnt images encoutnered.
        image_cnt: None or uint, number of images to use for mean or median, if
          applicable. None will use all when 'mean' or 'median are used.

    Returns:
        None
    '''
    # ::CAUTION:: RGB images should have type np.uint8. Images cast
    # as a float type will not display correctly with matplotlib.

    image_shape = next(iter(images_by_label.values()))[0].shape
    if len(image_shape) < 3 or image_shape[2] == 1:
        cmap = 'gray'
    else:
        cmap = 'jet'

    image_cnt = class_cnt
    column_cnt = 3
    row_cnt = int(np.ceil(image_cnt/column_cnt))
    height = 2.5*row_cnt
    fig, axes = plt.subplots(
        row_cnt, column_cnt, figsize=(15, height),
        subplot_kw={'xticks': [], 'yticks': []})
    fig.subplots_adjust(hspace=0.7, wspace=0.8)
    axf = axes.flat  # Iterator over axes.

    #for label, images in images_by_label.items():
    for label in sorted(images_by_label):
        images = images_by_label[label]
        if image_cnt is None:
            image_cnt = len(images)
        if method == 'mean':
            summary_image = np.mean(
                images[0:image_cnt], axis=0).astype(images.dtype)
        elif method == 'median':
            summary_image = np.median(
                images[0:image_cnt], axis=0).astype(images.dtype)
        else:  # 'first'
            summary_image = images[0, :]
        ax = next(axf)
        ax.imshow(summary_image.squeeze(), cmap=cmap)
        if english_labels:
            full_label = str(label) + ': ' + english_labels[label]
        else:
            full_label = str(label)
        ax.set_title(truncate_string(full_label, ubnd=25))
    for i in range(row_cnt*column_cnt - image_cnt):
        ax = next(axf)
        ax.set_visible(False)  # Hide blank subplot.


text:
package cn.felord.wepay.ali.sdk.api.response;

import cn.felord.wepay.ali.sdk.api.AlipayResponse;

/**
 * ALIPAY API: alipay.commerce.cityfacilitator.voucher.cancel response.
 *
 * @author auto create
 * @version $Id: $Id
 */
public class AlipayCommerceCityfacilitatorVoucherCancelResponse extends AlipayResponse {

	private static final long serialVersionUID = 6759827366352166345L;

}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WebMatrix.WebData;
using Yackimo.Infrastructure;

namespace Yackimo.Controllers
{
    public class BagController : Controller
    {
        private YackimoDb db = new YackimoDb();

        //
        // GET: /Bag/

        public ActionResult Index()
        {
            var userId = WebSecurity.GetUserId(User.Identity.Name);

            var bag = db.Bags.Where(b => b.UserId == userId).Single();

            return View(bag);
        }

        //
        // POST: /Bag/Add

        [HttpGet]
        public ActionResult Add(int id)
        {
            var product = db.Products.Find(id);

            var userId = WebSecurity.GetUserId(User.Identity.Name);

            var bag = db.Bags.Where(b => b.UserId == userId).Single();

            bag.Products.Add(product);

            db.SaveChanges();

            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (db != null)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}


text:
/*
Mocha test
This test was created for PR #159
*/

var Chai            = require('chai'),
    Hapi            = require('hapi'),
    Joi             = require('joi'),
    Inert           = require('inert'),
    Vision          = require('vision'),
	  H2o2            = require('h2o2'),
    Wreck           = require('wreck'),
    HapiSwagger     = require('../lib/index.js');
    assert          = Chai.assert;

var defaultHandler = function(request, response) {
  reply('ok');
};

var replyWithJSON = function( err, res, request, reply, settings, ttl ){
    Wreck.read(res, { json: true }, function (err, payload) {
        reply(payload);
    });
}

describe('proxy test', function() {

    var server;

    var routes = [{
      method: 'POST',
      path: '/tools/microformats',
      config: {
        description:'parse microformats',
        tags: ['api'],
        plugins: {
          'hapi-swagger': {
            payloadType: 'form',
            validate: {
              payload: {
                url: Joi.string().uri().required(),
                callback: Joi.string(),
                collapsewhitespace: Joi.boolean(),
                dateformat: Joi.any().allow(['auto', 'w3c', 'rfc3339', 'html5'])
              }
            }
          },
        },
        handler: {
          proxy: {
            host: 'glennjones.net',
            protocol: 'http',
            onResponse: replyWithJSON
          }
        }
      }
    },{
      method: 'POST',
      path: '/tools/microformats/',
      config: {
        description:'parse microformats',
        tags: ['api'],
        plugins: {
          'hapi-swagger': {
            nickname: 'microformatsapi',
            validate: {
              payload: {
                url: Joi.string().uri().required(),
                callback: Joi.string(),
                collapsewhitespace: Joi.boolean(),
                dateformat: Joi.any().allow(['auto', 'w3c', 'rfc3339', 'html5'])
              }
            }
          },
        },
        handler: {
          proxy: {
            host: 'glennjones.net',
            protocol: 'http',
            onResponse: replyWithJSON
          }
        }
      }
    }];

  beforeEach(function(done) {
    server = new Hapi.Server();
    server.connection();
    server.register([Inert, Vision, H2o2, HapiSwagger], function(err){
      server.start(function(err){
        server.route(routes);
        assert.ifError(err);
        done();
      });
    });
  });

  afterEach(function(done) {
    server.stop(function() {
      server = null;
      done();
    });
  });

    it('returned user built parameters', function(done) {
      server.inject({ method: 'GET', url: '/docs?path=tools '}, function (response) {
        //console.log(JSON.stringify(response.result.apis[0].operations[0].parameters));

        var optionClassModel = JSON.parse(JSON.stringify(response.result.apis[0].operations[0].parameters));
        assert.deepEqual(optionClassModel, [
            {
                "type": "string",
                "required": true,
                "name": "url",
                "paramType": "form"
            },
            {
                "type": "string",
                "defaultValue": null,
                "name": "callback",
                "paramType": "form"
            },
            {
                "type": "boolean",
                "defaultValue": null,
                "name": "collapsewhitespace",
                "paramType": "form"
            },
            {
                "type": "any",
                "defaultValue": null,
                "enum": [
                    "auto",
                    "w3c",
                    "rfc3339",
                    "html5"
                ],
                "name": "dateformat",
                "paramType": "form"
            }
        ]);
        done();
      });
    });

    it('returned user built model', function(done) {
      server.inject({ method: 'GET', url: '/docs?path=tools '}, function (response) {
        //console.log(JSON.stringify(response.result));

        var optionClassModel = JSON.parse(JSON.stringify(response.result.models));
        assert.deepEqual(optionClassModel, {
          "microformatsapi": {
              "id": "microformatsapi",
              "type": "object",
              "properties": {
                  "url": {
                      "type": "string",
                      "required": true
                  },
                  "callback": {
                      "type": "string",
                      "defaultValue": null
                  },
                  "collapsewhitespace": {
                      "type": "boolean",
                      "defaultValue": null
                  },
                  "dateformat": {
                      "type": "any",
                      "defaultValue": null,
                      "enum": [
                          "auto",
                          "w3c",
                          "rfc3339",
                          "html5"
                      ]
                  }
              }
          }
        });
        done();
      });
    });

/*

    it('return a classname based on path_method', function(done) {
      server.inject({ method: 'GET', url: '/docs?path=tools '}, function (response) {

        var pathMethodModel = JSON.parse(JSON.stringify(response.result.models.testmethodid_GET_response));
        //console.log(JSON.stringify(pathMethodModel));

        assert.deepEqual(pathMethodModel, {
            "id": "testmethodid_GET_response",
            "type": "object",
            "properties": {
                "methodGet": {
                    "type": "string",
                    "required": true
                }
            }
        });
        done();
      });
    });

    it('return a shortid based classname', function(done) {
      server.inject({ method: 'GET', url: '/docs?path=test '}, function (response) {

        var name = response.result.apis[4].operations[0].type;
        //console.log(name)

        var shortidModel = JSON.parse(JSON.stringify(response.result.models[name]));
        //console.log(JSON.stringify(shortidModel));

        assert.deepEqual(shortidModel, {
            "id": name,
            "type": "object",
            "properties": {
                "_id": {
                    "type": "any",
                    "required": true
                },
                "name": {
                    "type": "string",
                    "required": false
                }
            }
        });
        done();
      });
    });

    */

});


text:
{% include Resent_Posts.html %}
{% include Categories.html %}
{% include Blogroll.html %}
{% include Copyright_Notice.html %}