Make sure family name does not begin with a digit.

     Font family names which start with a numeral are often not
     discoverable in Windows applications.
6568
def com_google_fonts_check_name_familyname_first_char(ttFont):
  
  from fontbakery.utils import get_name_entry_strings
  failed = False
  for familyname in get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME):
    digits = map(str, range(0, 10))
    if familyname[0] in digits:
      yield FAIL, ("Font family name '{}'"
                   " begins with a digit!").format(familyname)
      failed = True
  if failed is False:
    yield PASS, "Font family name first character is not a digit."
1339227
@Override
	public boolean validate(final Problems problems, final String compName, final String model) {
		if (model.length() > 0) {
			final char c = model.charAt(0);
			if (Character.isDigit(c)) {
				problems.add(ValidationBundle.getMessage(MayNotStartWithDigit.class, "MAY_NOT_START_WITH_DIGIT", compName)); // NOI18N
			}
		}
		return true;
	}
1228262
private void processBaseFonts(byte[] data)
   {
      int offset = 0;

      int blockCount = MPPUtility.getShort(data, 0);
      offset += 2;

      int size;
      String name;

      for (int loop = 0; loop < blockCount; loop++)
      {
         /*unknownAttribute = MPPUtility.getShort(data, offset);*/
         offset += 2;

         size = MPPUtility.getShort(data, offset);
         offset += 2;

         name = MPPUtility.getUnicodeString(data, offset);
         offset += 64;

         if (name.length() != 0)
         {
            FontBase fontBase = new FontBase(Integer.valueOf(loop), name, size);
            m_fontBases.put(fontBase.getIndex(), fontBase);
         }
      }
   }
1202351
public static FontData getPlain(String familyName) {
		FontData data = (FontData) plain.get(familyName);
		
		return data;
	}
351942
Rule XcomNumber() {
		return Sequence(OneOrMore(DIGIT()),
						Optional(Sequence('.', OneOrMore(DIGIT())))
		).label(XcomNumber).suppressSubnodes();
	}
1227213
function getFirstFont(fonts, skipSystemFonts) {
  let regularFont = undefined;
  let systemFont = undefined;

  fonts.split(',').forEach(font => {
    font = font.trim().replace(/^["']+|["']+$/g, '');
    if (font === '') {
      return;
    }

    // See above for a note on OS-specific fonts
    if (!regularFont && (!skipSystemFonts || SYSTEM_FONTS.indexOf(font) < 0)) {
      regularFont = font;
    }
    if (!systemFont) {
      systemFont = font;
    }
  });

  if (regularFont) {
    return regularFont;
  }

  if (systemFont) {
    return systemFont;
  }

  return '-apple-system';
}
1317597
def find(cls, family_name, is_bold, is_italic):
        
        if cls._font_files is None:
            cls._font_files = cls._installed_fonts()
        return cls._font_files[(family_name, is_bold, is_italic)]
137033
def validateMemberName(n):
    
    try:
        if len(n) < 1:
            raise Exception('Name must be at least one byte in length')
        if len(n) > 255:
            raise Exception('Name exceeds maximum length of 255')
        if n[0].isdigit():
            raise Exception('Names may not begin with a digit')
        if mbr_re.search(n):
            raise Exception(
                'Names contains a character outside the set [A-Za-z0-9_]')
    except Exception as e:
        raise MarshallingError('Invalid member name "%s": %s' % (n, str(e)))
70346
public static FontData getBold(String familyName) {
		FontData data = (FontData) bold.get(familyName);
		
		return data;
	}
1295955
def com_adobe_fonts_check_family_bold_italic_unique_for_nameid1(ttFonts):
  """"""
  from collections import Counter
  from fontbakery.utils import get_name_entry_strings
  from fontbakery.constants import NameID, FsSelection

  failed = False
  family_name_and_bold_italic = list()
  for ttFont in ttFonts:
    names_list = get_name_entry_strings(ttFont, NameID.FONT_FAMILY_NAME)
    # names_list will likely contain multiple entries, e.g. multiple copies
    # of the same name in the same language for different platforms, but
    # also different names in different languages, we use set() below
    # to remove the duplicates and only store the unique family name(s)
    # used for a given font
    names_set = set(names_list)

    bold = (ttFont['OS/2'].fsSelection & FsSelection.BOLD) != 0
    italic = (ttFont['OS/2'].fsSelection & FsSelection.ITALIC) != 0
    bold_italic = 'Bold=%r, Italic=%r' % (bold, italic)

    for name in names_set:
      family_name_and_bold_italic.append((name, bold_italic,))

  counter = Counter(family_name_and_bold_italic)

  for (family_name, bold_italic), count in counter.items():
    if count > 1:
      failed = True
      yield FAIL, ("Family '{}' has {} fonts (should be no more than 1) with "
                   "the same OS/2.fsSelection bold & italic settings: {}"
                   ).format(family_name, count, bold_italic)
  if not failed:
    yield PASS, ("The OS/2.fsSelection bold & italic settings were unique "
                 "within each compatible family group.")
550105
def family_directory(fonts):
  """"""
  if fonts:
    dirname = os.path.dirname(fonts[0])
    if dirname == '':
      dirname = '.'
    return dirname
101325
def com_google_fonts_check_name_typographicfamilyname(ttFont, style, familyname_with_spaces):
  
  from fontbakery.utils import name_entry_id

  failed = False
  if style in ['Regular',
               'Italic',
               'Bold',
               'BoldItalic']:
    for name in ttFont['name'].names:
      if name.nameID == NameID.TYPOGRAPHIC_FAMILY_NAME:
        failed = True
        yield FAIL, Message("ribbi",
                            ("Font style is '{}' and, for that reason,"
                             " it is not expected to have a "
                             "{} entry!").format(style,
                                                 name_entry_id(name)))
  else:
    expected_value = familyname_with_spaces
    has_entry = False
    for name in ttFont['name'].names:
      if name.nameID == NameID.TYPOGRAPHIC_FAMILY_NAME:
        string = name.string.decode(name.getEncoding()).strip()
        if string == expected_value:
          has_entry = True
        else:
          failed = True
          yield FAIL, Message("non-ribbi-bad-value",
                              ("Entry {} on the 'name' table: "
                               "Expected '{}' "
                               "but got '{}'.").format(name_entry_id(name),
                                                       expected_value,
                                                       string))
    if not failed and not has_entry:
      failed = True
      yield FAIL, Message("non-ribbi-lacks-entry",
                          ("non-RIBBI fonts must have a"
                           " TYPOGRAPHIC_FAMILY_NAME entry"
                           " on the name table."))
  if not failed:
    yield PASS, "TYPOGRAPHIC_FAMILY_NAME entries are all good."
790083
def com_google_fonts_check_name_family_and_style_max_length(ttFont):
  """"""
  from fontbakery.utils import (get_name_entries,
                                get_name_entry_strings)
  failed = False
  for familyname in get_name_entries(ttFont,
                                     NameID.FONT_FAMILY_NAME):
    # we'll only match family/style name entries with the same platform ID:
    plat = familyname.platformID
    familyname_str = familyname.string.decode(familyname.getEncoding())
    for stylename_str in get_name_entry_strings(ttFont,
                                                NameID.FONT_SUBFAMILY_NAME,
                                                platformID=plat):
      if len(familyname_str + stylename_str) > 27:
        failed = True
        yield WARN, ("The combined length of family and style"
                     " exceeds 27 chars in the following '{}' entries:"
                     " FONT_FAMILY_NAME = '{}' / SUBFAMILY_NAME = '{}'"
                     "").format(PlatformID(plat).name,
                                familyname_str,
                                stylename_str)
        yield WARN, ("Please take a look at the conversation at"
                     " https://github.com/googlefonts/fontbakery/issues/2179"
                     " in order to understand the reasoning behing these"
                     " name table records max-length criteria.")
  if not failed:
    yield PASS, "All name entries are good."
820360
public static FontData getItalic(String familyName) {
		FontData data = (FontData) italic.get(familyName);
		
		return data;
	}
1134369
private String digit(Data data) {
	String rtn = "";
	while (data.srcCode.isValidIndex()) {
	    if (!data.srcCode.isCurrentBetween('0', '9')) break;
	    rtn += data.srcCode.getCurrentLower();
	    data.srcCode.next();
	}
	return rtn;
    }
1356149
def com_google_fonts_check_metadata_valid_filename_values(font,
                                                          family_metadata):
  """"""
  expected = os.path.basename(font)
  failed = True
  for font_metadata in family_metadata.fonts:
    if font_metadata.filename == expected:
      failed = False
      yield PASS, ("METADATA.pb filename field contains"
                   " font name in right format.")
      break
  if failed:
    yield FAIL, ("None of the METADATA.pb filename fields match"
                f" correct font name format (\"{expected}\").")
1338478
private function isNanpaNumberWithNationalPrefix()
    {
        // For NANPA numbers beginning with 1[2-9], treat the 1 as the national prefix. The reason is
        // that national significant numbers in NANPA always start with [2-9] after the national prefix.
        // Numbers beginning with 1[01] can only be short/emergency numbers, which don't need the
        // national prefix.
        return ($this->currentMetadata->getCountryCode() == 1) && (mb_substr($this->nationalNumber, 0, 1) == '1')
            && (mb_substr($this->nationalNumber, 1, 1) != '0') && (mb_substr($this->nationalNumber, 1, 1) != '1');
    }