def fromFileName(klass, fileName):
		# stars seems to have switched to utf-8 at some time. more or less a guess
		# that it used to be iso-8859-1 before.
		data = None
		fp = codecs.open(fileName, encoding='utf-8')
		try:
			data = fp.read()
		except UnicodeDecodeError: pass
		else:
			#NOTE: remove BOM(s) if present. seen unicode BOM_BE trailing game headers
			# even within HHs (no idea why), so for now we remove all BOMs unconditionally
			data = data.replace(unicode(codecs.BOM_UTF8, 'utf-8'), '')
			#NOTE: found that some files start with \x10 (TourneySumaries)
			if data.startswith('\x10'):
				data = data[1:]
		finally:
			fp.close()
		if data is None:
			fp = codecs.open(fileName, encoding='iso-8859-1')
			try:
				data = fp.read()
			finally:
				fp.close()
		lines = HcConfig.linesFromString(data)
		return klass(lines, fileName=fileName)
	def parseGameHeader(self, lines, eventHandler, events, state):
		if len(lines) < 2:
			return False
				
		m = self.PatternGameHeader.match(lines[0][1])
		if m is None:
			return False
		d = m.groupdict()
		m = self.PatternTableHeader.match(lines[1][1])
		if m is None:
			lines.pop(0)
			return False
		d.update(m.groupdict())
		
		d['seatNoButton'] = int(d['seatNoButton'])
		d['site'] = self.ID['site']
		d['gameScope'] = self.ID['gameScope']
		d['gameContext'] = self.ID['gameContext']
		d['game'] = GameMapping[d['game']]
		d['gameLimit'] = GameLimitMapping[d['gameLimit'].lower()]
		#NOTE: stars added currency to header at some point, but this is pretty useless
		# for parsing old hand histories, so we parse currency symbols directly
		line = lines[0][1]
		currency = CurrencyMapping['']
		for symbol in CurrencySymbols:
			if symbol in line:
				currency = CurrencyMapping[symbol]
				break
		d['currency'] = currency
		d['bigBlind'] = self.stringToFloat(d['bigBlind'])
		d['smallBlind'] = self.stringToFloat(d['smallBlind'])
		d['maxPlayers'] = int(d['maxPlayers'])
		d['time'] = HcConfig.timeToUTC(
								(int(d.pop('year')), 
								int(d.pop('month')), 
								int(d.pop('day')), 
								int(d.pop('hour')), 
								int(d.pop('minute')), 
								int(d.pop('second'))),
								timeZone=HcConfig.TimeZoneET, 
								)
		
		lines.pop(0)
		lines.pop(0)
		
		#NOTE: we have to parse ante here because PS does not report it in header
		# we can either guess here (highest amount posted) or look it up somewhere
		# if we are positive that ante is charged.
		maxAnte = self.parsePlayerPostAnte(lines, eventHandler, events, state)
		d['ante'] = maxAnte
				
		events[0] = (eventHandler.handleHandStart, d)
		return True
	def fromString(klass, string):
		lines = HcConfig.linesFromString(string)
		return klass(lines, fileName='')