text: """
  2D rendering framework
  """
  from __future__ import division
  import os
  import six
  import sys
  
  if "Apple" in sys.version:
      if 'DYLD_FALLBACK_LIBRARY_PATH' in os.environ:
          os.environ['DYLD_FALLBACK_LIBRARY_PATH'] += ':/usr/lib'
          # (JDS 2016/04/15): avoid bug on Anaconda 2.3.0 / Yosemite
  
  from evo_gym import error
  
  try:
      import pyglet
  except ImportError as e:
      raise ImportError('''
      Cannot import pyglet.
      HINT: you can install pyglet directly via 'pip install pyglet'.
      But if you really just want to install all Gym dependencies and not have to think about it,
      'pip install -e .[all]' or 'pip install gym[all]' will do it.
      ''')
  
  try:
      from pyglet.gl import *
  except ImportError as e:
      raise ImportError('''
      Error occurred while running `from pyglet.gl import *`
      HINT: make sure you have OpenGL install. On Ubuntu, you can run 'apt-get install python-opengl'.
      If you're running on a server, you may need a virtual frame buffer; something like this should work:
      'xvfb-run -s \"-screen 0 1400x900x24\" python <your_script.py>'
      ''')
  
  import math
  import numpy as np
  
  RAD2DEG = 57.29577951308232
  
  def get_display(spec):
      """Convert a display specification (such as :0) into an actual Display
      object.
  
      Pyglet only supports multiple Displays on Linux.
      """
      if spec is None:
          return None
      elif isinstance(spec, six.string_types):
          return pyglet.canvas.Display(spec)
      else:
          raise error.Error('Invalid display specification: {}. (Must be a string like :0 or None.)'.format(spec))
  
  class Viewer(object):
      def __init__(self, width, height, display=None):
          display = get_display(display)
  
          self.width = width
          self.height = height
          self.window = pyglet.window.Window(width=width, height=height, display=display)
          self.window.on_close = self.window_closed_by_user
          self.isopen = True
          self.geoms = []
          self.onetime_geoms = []
          self.transform = Transform()
  
          glEnable(GL_BLEND)
          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  
      def close(self):
          self.window.close()
  
      def window_closed_by_user(self):
          self.isopen = False
  
      def set_bounds(self, left, right, bottom, top):
          assert right > left and top > bottom
          scalex = self.width/(right-left)
          scaley = self.height/(top-bottom)
          self.transform = Transform(
              translation=(-left*scalex, -bottom*scaley),
              scale=(scalex, scaley))
  
      def add_geom(self, geom):
          self.geoms.append(geom)
  
      def add_onetime(self, geom):
          self.onetime_geoms.append(geom)
  
      def render(self, return_rgb_array=False):
          glClearColor(1,1,1,1)
          self.window.clear()
          self.window.switch_to()
          self.window.dispatch_events()
          self.transform.enable()
          for geom in self.geoms:
              geom.render()
          for geom in self.onetime_geoms:
              geom.render()
          self.transform.disable()
          arr = None
          if return_rgb_array:
              buffer = pyglet.image.get_buffer_manager().get_color_buffer()
              image_data = buffer.get_image_data()
              arr = np.frombuffer(image_data.get_data(), dtype=np.uint8)
              # In https://github.com/openai/gym-http-api/issues/2, we
              # discovered that someone using Xmonad on Arch was having
              # a window of size 598 x 398, though a 600 x 400 window
              # was requested. (Guess Xmonad was preserving a pixel for
              # the boundary.) So we use the buffer height/width rather
              # than the requested one.
              arr = arr.reshape(buffer.height, buffer.width, 4)
              arr = arr[::-1,:,0:3]
          self.window.flip()
          self.onetime_geoms = []
          return arr if return_rgb_array else self.isopen
  
      # Convenience
      def draw_circle(self, radius=10, res=30, filled=True, **attrs):
          geom = make_circle(radius=radius, res=res, filled=filled)
          _add_attrs(geom, attrs)
          self.add_onetime(geom)
          return geom
  
      def draw_polygon(self, v, filled=True, **attrs):
          geom = make_polygon(v=v, filled=filled)
          _add_attrs(geom, attrs)
          self.add_onetime(geom)
          return geom
  
      def draw_polyline(self, v, **attrs):
          geom = make_polyline(v=v)
          _add_attrs(geom, attrs)
          self.add_onetime(geom)
          return geom
  
      def draw_line(self, start, end, **attrs):
          geom = Line(start, end)
          _add_attrs(geom, attrs)
          self.add_onetime(geom)
          return geom
  
      def get_array(self):
          self.window.flip()
          image_data = pyglet.image.get_buffer_manager().get_color_buffer().get_image_data()
          self.window.flip()
          arr = np.fromstring(image_data.get_data(), dtype=np.uint8, sep='')
          arr = arr.reshape(self.height, self.width, 4)
          return arr[::-1,:,0:3]
  
      def __del__(self):
          self.close()
  
  def _add_attrs(geom, attrs):
      if "color" in attrs:
          geom.set_color(*attrs["color"])
      if "linewidth" in attrs:
          geom.set_linewidth(attrs["linewidth"])
  
  class Geom(object):
      def __init__(self):
          self._color=Color((0, 0, 0, 1.0))
          self.attrs = [self._color]
      def render(self):
          for attr in reversed(self.attrs):
              attr.enable()
          self.render1()
          for attr in self.attrs:
              attr.disable()
      def render1(self):
          raise NotImplementedError
      def add_attr(self, attr):
          self.attrs.append(attr)
      def set_color(self, r, g, b):
          self._color.vec4 = (r, g, b, 1)
  
  class Attr(object):
      def enable(self):
          raise NotImplementedError
      def disable(self):
          pass
  
  class Transform(Attr):
      def __init__(self, translation=(0.0, 0.0), rotation=0.0, scale=(1,1)):
          self.set_translation(*translation)
          self.set_rotation(rotation)
          self.set_scale(*scale)
      def enable(self):
          glPushMatrix()
          glTranslatef(self.translation[0], self.translation[1], 0) # translate to GL loc ppint
          glRotatef(RAD2DEG * self.rotation, 0, 0, 1.0)
          glScalef(self.scale[0], self.scale[1], 1)
      def disable(self):
          glPopMatrix()
      def set_translation(self, newx, newy):
          self.translation = (float(newx), float(newy))
      def set_rotation(self, new):
          self.rotation = float(new)
      def set_scale(self, newx, newy):
          self.scale = (float(newx), float(newy))
  
  class Color(Attr):
      def __init__(self, vec4):
          self.vec4 = vec4
      def enable(self):
          glColor4f(*self.vec4)
  
  class LineStyle(Attr):
      def __init__(self, style):
          self.style = style
      def enable(self):
          glEnable(GL_LINE_STIPPLE)
          glLineStipple(1, self.style)
      def disable(self):
          glDisable(GL_LINE_STIPPLE)
  
  class LineWidth(Attr):
      def __init__(self, stroke):
          self.stroke = stroke
      def enable(self):
          glLineWidth(self.stroke)
  
  class Point(Geom):
      def __init__(self):
          Geom.__init__(self)
      def render1(self):
          glBegin(GL_POINTS) # draw point
          glVertex3f(0.0, 0.0, 0.0)
          glEnd()
  
  class FilledPolygon(Geom):
      def __init__(self, v):
          Geom.__init__(self)
          self.v = v
      def render1(self):
          if   len(self.v) == 4 : glBegin(GL_QUADS)
          elif len(self.v)  > 4 : glBegin(GL_POLYGON)
          else: glBegin(GL_TRIANGLES)
          for p in self.v:
              glVertex3f(p[0], p[1],0)  # draw each vertex
          glEnd()
  
  def make_circle(radius=10, res=30, filled=True):
      points = []
      for i in range(res):
          ang = 2*math.pi*i / res
          points.append((math.cos(ang)*radius, math.sin(ang)*radius))
      if filled:
          return FilledPolygon(points)
      else:
          return PolyLine(points, True)
  
  def make_polygon(v, filled=True):
      if filled: return FilledPolygon(v)
      else: return PolyLine(v, True)
  
  def make_polyline(v):
      return PolyLine(v, False)
  
  def make_capsule(length, width):
      l, r, t, b = 0, length, width/2, -width/2
      box = make_polygon([(l,b), (l,t), (r,t), (r,b)])
      circ0 = make_circle(width/2)
      circ1 = make_circle(width/2)
      circ1.add_attr(Transform(translation=(length, 0)))
      geom = Compound([box, circ0, circ1])
      return geom
  
  class Compound(Geom):
      def __init__(self, gs):
          Geom.__init__(self)
          self.gs = gs
          for g in self.gs:
              g.attrs = [a for a in g.attrs if not isinstance(a, Color)]
      def render1(self):
          for g in self.gs:
              g.render()
  
  class PolyLine(Geom):
      def __init__(self, v, close):
          Geom.__init__(self)
          self.v = v
          self.close = close
          self.linewidth = LineWidth(1)
          self.add_attr(self.linewidth)
      def render1(self):
          glBegin(GL_LINE_LOOP if self.close else GL_LINE_STRIP)
          for p in self.v:
              glVertex3f(p[0], p[1],0)  # draw each vertex
          glEnd()
      def set_linewidth(self, x):
          self.linewidth.stroke = x
  
  class Line(Geom):
      def __init__(self, start=(0.0, 0.0), end=(0.0, 0.0)):
          Geom.__init__(self)
          self.start = start
          self.end = end
          self.linewidth = LineWidth(1)
          self.add_attr(self.linewidth)
  
      def render1(self):
          glBegin(GL_LINES)
          glVertex2f(*self.start)
          glVertex2f(*self.end)
          glEnd()
  
  class Image(Geom):
      def __init__(self, fname, width, height):
          Geom.__init__(self)
          self.width = width
          self.height = height
          img = pyglet.image.load(fname)
          self.img = img
          self.flip = False
      def render1(self):
          self.img.blit(-self.width/2, -self.height/2, width=self.width, height=self.height)
  
  # ================================================================
  
  class SimpleImageViewer(object):
      def __init__(self, display=None, maxwidth=500):
          self.window = None
          self.isopen = False
          self.display = display
          self.maxwidth = maxwidth
      def imshow(self, arr):
          if self.window is None:
              height, width, _channels = arr.shape
              if width > self.maxwidth:
                  scale = self.maxwidth / width
                  width = int(scale * width)
                  height = int(scale * height)
              self.window = pyglet.window.Window(width=width, height=height, 
                  display=self.display, vsync=False, resizable=True)            
              self.width = width
              self.height = height
              self.isopen = True
  
              @self.window.event
              def on_resize(width, height):
                  self.width = width
                  self.height = height
  
              @self.window.event
              def on_close():
                  self.isopen = False
  
          assert len(arr.shape) == 3, "You passed in an image with the wrong number shape"
          image = pyglet.image.ImageData(arr.shape[1], arr.shape[0], 
              'RGB', arr.tobytes(), pitch=arr.shape[1]*-3)
          gl.glTexParameteri(gl.GL_TEXTURE_2D, 
              gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST)
          texture = image.get_texture()
          texture.width = self.width
          texture.height = self.height
          self.window.clear()
          self.window.switch_to()
          self.window.dispatch_events()
          texture.blit(0, 0) # draw
          self.window.flip()
      def close(self):
          if self.isopen and sys.meta_path:
              # ^^^ check sys.meta_path to avoid 'ImportError: sys.meta_path is None, Python is likely shutting down'
              self.window.close()
              self.isopen = False
  
      def __del__(self):
          self.close()
  