docs: def makeInstance(self, instanceDescriptor,
              doRules=False,
              glyphNames=None,
              pairs=None,
              bend=False):
          """ Generate a font object for this instance """
          font = self._instantiateFont(None)
          # make fonty things here
          loc = Location(instanceDescriptor.location)
          anisotropic = False
          locHorizontal = locVertical = loc
          if self.isAnisotropic(loc):
              anisotropic = True
              locHorizontal, locVertical = self.splitAnisotropic(loc)
          # groups
          renameMap = getattr(self.fonts[self.default.name], "kerningGroupConversionRenameMaps", None)
          font.kerningGroupConversionRenameMaps = renameMap if renameMap is not None else {'side1': {}, 'side2': {}}
          # make the kerning
          # this kerning is always horizontal. We can take the horizontal location
          # filter the available pairs?
          if instanceDescriptor.kerning:
              if pairs:
                  try:
                      kerningMutator = self.getKerningMutator(pairs=pairs)
                      kerningObject = kerningMutator.makeInstance(locHorizontal, bend=bend)
                      kerningObject.extractKerning(font)
                  except:
                      self.problems.append("Could not make kerning for %s. %s" % (loc, traceback.format_exc()))
              else:
                  kerningMutator = self.getKerningMutator()
                  kerningObject = kerningMutator.makeInstance(locHorizontal, bend=bend)
                  kerningObject.extractKerning(font)
          # make the info
          try:
              infoMutator = self.getInfoMutator()
              if not anisotropic:
                  infoInstanceObject = infoMutator.makeInstance(loc, bend=bend)
              else:
                  horizontalInfoInstanceObject = infoMutator.makeInstance(locHorizontal, bend=bend)
                  verticalInfoInstanceObject = infoMutator.makeInstance(locVertical, bend=bend)
                  # merge them again
                  infoInstanceObject = (1,0)*horizontalInfoInstanceObject + (0,1)*verticalInfoInstanceObject
              if self.roundGeometry:
                  try:
                      infoInstanceObject = infoInstanceObject.round()
                  except AttributeError:
                      pass
              infoInstanceObject.extractInfo(font.info)
              font.info.familyName = instanceDescriptor.familyName
              font.info.styleName = instanceDescriptor.styleName
              font.info.postscriptFontName = instanceDescriptor.postScriptFontName # yikes, note the differences in capitalisation..
              font.info.styleMapFamilyName = instanceDescriptor.styleMapFamilyName
              font.info.styleMapStyleName = instanceDescriptor.styleMapStyleName
              # NEED SOME HELP WITH THIS
              # localised names need to go to the right openTypeNameRecords
              # records = []
              # nameID = 1
              # platformID =
              # for languageCode, name in instanceDescriptor.localisedStyleMapFamilyName.items():
              #    # Name ID 1 (font family name) is found at the generic styleMapFamily attribute.
              #    records.append((nameID, ))
          except:
              self.problems.append("Could not make fontinfo for %s. %s" % (loc, traceback.format_exc()))
          for sourceDescriptor in self.sources:
              if sourceDescriptor.copyInfo:
                  # this is the source
                  if self.fonts[sourceDescriptor.name] is not None:
                      self._copyFontInfo(self.fonts[sourceDescriptor.name].info, font.info)
              if sourceDescriptor.copyLib:
                  # excplicitly copy the font.lib items
                  if self.fonts[sourceDescriptor.name] is not None:
                      for key, value in self.fonts[sourceDescriptor.name].lib.items():
                          font.lib[key] = value
              if sourceDescriptor.copyGroups:
                  if self.fonts[sourceDescriptor.name] is not None:
                      sides = font.kerningGroupConversionRenameMaps.get('side1', {})
                      sides.update(font.kerningGroupConversionRenameMaps.get('side2', {}))
                      for key, value in self.fonts[sourceDescriptor.name].groups.items():
                          if key not in sides:
                              font.groups[key] = value
              if sourceDescriptor.copyFeatures:
                  if self.fonts[sourceDescriptor.name] is not None:
                      featuresText = self.fonts[sourceDescriptor.name].features.text
                      font.features.text = featuresText
          # glyphs
          if glyphNames:
              selectedGlyphNames = glyphNames
          else:
              selectedGlyphNames = self.glyphNames
          # add the glyphnames to the font.lib['public.glyphOrder']
          if not 'public.glyphOrder' in font.lib.keys():
              font.lib['public.glyphOrder'] = selectedGlyphNames
          for glyphName in selectedGlyphNames:
              try:
                  glyphMutator = self.getGlyphMutator(glyphName)
                  if glyphMutator is None:
                      continue
              except:
                  self.problems.append("Could not make mutator for glyph %s %s" % (glyphName, traceback.format_exc()))
                  continue
              if glyphName in instanceDescriptor.glyphs.keys():
                  # XXX this should be able to go now that we have full rule support.
                  # reminder: this is what the glyphData can look like
                  # {'instanceLocation': {'custom': 0.0, 'weight': 824.0},
                  #  'masters': [{'font': 'master.Adobe VF Prototype.Master_0.0',
                  #               'glyphName': 'dollar.nostroke',
                  #               'location': {'custom': 0.0, 'weight': 0.0}},
                  #              {'font': 'master.Adobe VF Prototype.Master_1.1',
                  #               'glyphName': 'dollar.nostroke',
                  #               'location': {'custom': 0.0, 'weight': 368.0}},
                  #              {'font': 'master.Adobe VF Prototype.Master_2.2',
                  #               'glyphName': 'dollar.nostroke',
                  #               'location': {'custom': 0.0, 'weight': 1000.0}},
                  #              {'font': 'master.Adobe VF Prototype.Master_3.3',
                  #               'glyphName': 'dollar.nostroke',
                  #               'location': {'custom': 100.0, 'weight': 1000.0}},
                  #              {'font': 'master.Adobe VF Prototype.Master_0.4',
                  #               'glyphName': 'dollar.nostroke',
                  #               'location': {'custom': 100.0, 'weight': 0.0}},
                  #              {'font': 'master.Adobe VF Prototype.Master_4.5',
                  #               'glyphName': 'dollar.nostroke',
                  #               'location': {'custom': 100.0, 'weight': 368.0}}],
                  #  'unicodes': [36]}
                  glyphData = instanceDescriptor.glyphs[glyphName]
              else:
                  glyphData = {}
              font.newGlyph(glyphName)
              font[glyphName].clear()
              if glyphData.get('mute', False):
                  # mute this glyph, skip
                  continue
              glyphInstanceLocation = glyphData.get("instanceLocation", instanceDescriptor.location)
              glyphInstanceLocation = Location(glyphInstanceLocation)
              uniValues = []
              neutral = glyphMutator.get(())
              if neutral is not None:
                  uniValues = neutral[0].unicodes
              else:
                  neutralFont = self.getNeutralFont()
                  if glyphName in neutralFont:
                      uniValues = neutralFont[glyphName].unicodes
              glyphInstanceUnicodes = glyphData.get("unicodes", uniValues)
              note = glyphData.get("note")
              if note:
                  font[glyphName] = note
              # XXXX phase out support for instance-specific masters
              # this should be handled by the rules system.
              masters = glyphData.get("masters", None)
              if masters is not None:
                  items = []
                  for glyphMaster in masters:
                      sourceGlyphFont = glyphMaster.get("font")
                      sourceGlyphName = glyphMaster.get("glyphName", glyphName)
                      m = self.fonts.get(sourceGlyphFont)
                      if not sourceGlyphName in m:
                          continue
                      if hasattr(m[sourceGlyphName], "toMathGlyph"):
                          sourceGlyph = m[sourceGlyphName].toMathGlyph()
                      else:
                          sourceGlyph = MathGlyph(m[sourceGlyphName])
                      sourceGlyphLocation = glyphMaster.get("location")
                      items.append((Location(sourceGlyphLocation), sourceGlyph))
                  bias, glyphMutator = self.getVariationModel(items, axes=self.serializedAxes, bias=self.newDefaultLocation())
              try:
                  if not self.isAnisotropic(glyphInstanceLocation):
                      glyphInstanceObject = glyphMutator.makeInstance(glyphInstanceLocation, bend=bend)
                  else:
                      # split anisotropic location into horizontal and vertical components
                      horizontal, vertical = self.splitAnisotropic(glyphInstanceLocation)
                      horizontalGlyphInstanceObject = glyphMutator.makeInstance(horizontal, bend=bend)
                      verticalGlyphInstanceObject = glyphMutator.makeInstance(vertical, bend=bend)
                      # merge them again
                      glyphInstanceObject = (1,0)*horizontalGlyphInstanceObject + (0,1)*verticalGlyphInstanceObject
              except IndexError:
                  # alignment problem with the data?
                  continue
              font.newGlyph(glyphName)
              font[glyphName].clear()
              if self.roundGeometry:
                  try:
                      glyphInstanceObject = glyphInstanceObject.round()
                  except AttributeError:
                      pass
              try:
                  # File "/Users/erik/code/ufoProcessor/Lib/ufoProcessor/__init__.py", line 649, in makeInstance
                  #   glyphInstanceObject.extractGlyph(font[glyphName], onlyGeometry=True)
                  # File "/Applications/RoboFont.app/Contents/Resources/lib/python3.6/fontMath/mathGlyph.py", line 315, in extractGlyph
                  #   glyph.anchors = [dict(anchor) for anchor in self.anchors]
                  # File "/Applications/RoboFont.app/Contents/Resources/lib/python3.6/fontParts/base/base.py", line 103, in __set__
                  #   raise FontPartsError("no setter for %r" % self.name)
                  #   fontParts.base.errors.FontPartsError: no setter for 'anchors'
                  if hasattr(font[glyphName], "fromMathGlyph"):
                      font[glyphName].fromMathGlyph(glyphInstanceObject)
                  else:
                      glyphInstanceObject.extractGlyph(font[glyphName], onlyGeometry=True)
              except TypeError:
                  # this causes ruled glyphs to end up in the wrong glyphname
                  # but defcon2 objects don't support it
                  pPen = font[glyphName].getPointPen()
                  font[glyphName].clear()
                  glyphInstanceObject.drawPoints(pPen)
              font[glyphName].width = glyphInstanceObject.width
              font[glyphName].unicodes = glyphInstanceUnicodes
          if doRules:
              resultNames = processRules(self.rules, loc, self.glyphNames)
              for oldName, newName in zip(self.glyphNames, resultNames):
                  if oldName != newName:
                      swapGlyphNames(font, oldName, newName)
          # copy the glyph lib?
          #for sourceDescriptor in self.sources:
          #    if sourceDescriptor.copyLib:
          #        pass
          #    pass
          # store designspace location in the font.lib
          font.lib['designspace.location'] = list(instanceDescriptor.location.items())
          return font