text: # The contents of this file are subject to the Python Software Foundation
  # License Version 2.3 (the License).  You may not copy or use this file, in
  # either source code or executable form, except in compliance with the License.
  # You may obtain a copy of the License at http://www.python.org/license.
  #
  # Software distributed under the License is distributed on an AS IS basis,
  # WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
  # for the specific language governing rights and limitations under the
  # License.
  
  ctypes = None
  try:
      import ctypes
  except ImportError:
      pass
  
  
  from cStringIO import StringIO
  
  class cStringIO_Buffer(object):
  
      def __init__(self):
          self.buffer = StringIO()
          for attr in dir(self.buffer):
              self.__dict__[attr] = getattr(self.buffer, attr)
  
      def __getattr__(self, attr):
          return getattr(self.buffer, attr)
  
      def _slice_to_a_b(self, i):
          if not isinstance(i, slice):
              if i >= len(self):
                  raise IndexError("buffer index out of range")
              i = slice(i, i+1)
          o = self.tell()
          if i.start is None:
              a = 0
          else:
              a = i.start
          if i.stop is None:
              b = o
          else:
              b = i.stop
          if b < 0:
              b = o + b
          b = max(a, b - a)
          return o, a, b            
  
      def __setitem__(self, i, d):
          o, a, b = self._slice_to_a_b(i)
          self.seek(a)
          self.write(d)
          self.seek(o)
          
      def __getitem__(self, i):
          o, a, b = self._slice_to_a_b(i)
          self.seek(a)
          d = self.read(b)
          self.seek(o)
          return d
  
      def drop(self, size):
          v = self.getvalue()
          self.truncate(0)
          self.write(buffer(v, size))
  
      def __len__(self):
          o = self.tell()
          self.seek(0, 2)
          x = self.tell()
          self.seek(o)
          return x
  
      def __str__(self):
          return self.getvalue()
  
  Buffer = cStringIO_Buffer
  
  # slow, has dependencies
  if False: # ctypes:
      
      class ctypes_Buffer(object):
  
          def __init__(self):
              self.length = 32
              self.data = ctypes.create_string_buffer(self.length)
              self.written = 0
              self.offset = 0
  
          def __setitem__(self, i, y):
              if isinstance(i, slice):
                  return self.data.__setslice__(i.start, i.stop, y)
              else:
                  return self.data.__setitem__(i, y)
  
          # TODO: call PyBuffer_FromMemory!
          def __getitem__(self, i):
              if isinstance(i, slice):
                  if i.stop < 0:
                      i = slice(i.start, self.written + i.stop)
                  return self.data.__getslice__(i.start or 0, i.stop or self.written)
              else:
                  return self.data.__getitem__(i)
              
          def __getattr__(self, attr):
              return getattr(self.data, attr)
  
          def __str__(self):
              return self.data[:self.written]
  
          def __len__(self):
              return self.written
  
          def _oversize(self, l):
              o = self.length
              while l > self.length:
                  self.length *= 2
              if self.length > o:
                  d = self.data
                  self.data = ctypes.create_string_buffer(self.length)
                  # which is faster?
                  #self.data[0:self.written] = d[:self.written]
                  self.data[0:o] = d
  
          def write(self, s):
              l = len(s)
              self._oversize(self.offset + l)
              self.data[self.offset:self.offset + l] = s
              self.offset += l
              self.written = max(self.written, self.offset)
              return l
          
          def seek(self, offset):
              self.offset = min(self.written - 1, max(0, offset))
  
          def truncate(self, size=None):
              if size is None:
                  size = self.offset
              self.written = size
              self.offset = min(size, self.offset)
  
          def drop(self, size):
              if size < 0:
                  raise ValueError("cannot discard negative bytes")
              size = min(size, self.written)
              new_written = self.written - size
              # ow
              try:
                  self.data[:new_written] = self.data[size:self.written]
              except ValueError:
                  print new_written, size, self.written
              self.written = new_written
              self.offset = min(self.written, self.offset)
  
      Buffer = ctypes_Buffer
      
  
      
  b = Buffer()
  b.write("ghello")
  b.seek(0)
  b.write(buffer("ghell"))
  b.drop(1)
  b[2:3] = 'b'
  assert str(b) == "heblo"
  assert b[0] == "h"
  #print repr(b[:-1])
  assert b[:-1] == "hebl"
  #assert len(b) <= b.length
  assert len(b) == len(str(b))
  b.drop(1)
  b.seek(0)
  b.write('foo')
  assert b[0] == 'f'
  try:
      b[100]
  except IndexError:
      pass
  else:
      assert False