Added support for comments. Added benchmark
diff --git a/lex.go b/lex.go
index aad9c00..67205dd 100644
--- a/lex.go
+++ b/lex.go
@@ -127,6 +127,13 @@
 	l.backup()
 }
 
+// acceptRunUntil consumes a run of runes up to a terminator.
+func (l *lexer) acceptRunUntil(term rune) {
+	for term != l.next() {
+	}
+	l.backup()
+}
+
 // hasText returns true if the current parsed text is not empty.
 func (l *lexer) isNotEmpty() bool {
 	return l.pos > l.start
@@ -166,22 +173,39 @@
 
 // run runs the state machine for the lexer.
 func (l *lexer) run() {
-	for l.state = lexKey(l); l.state != nil; {
+	for l.state = lexBeforeKey(l); l.state != nil; {
 		l.state = l.state(l)
 	}
 }
 
 // state functions
 // TODO: handle comments
-// TODO: handle multi-line values
+
+// lexBeforeKey scans until a key begins.
+func lexBeforeKey(l *lexer) stateFn {
+	switch r := l.next(); {
+	case isEOF(r):
+		l.emit(itemEOF)
+		return nil
+
+	case isEOL(r):
+		l.ignore()
+		return lexBeforeKey
+
+	case isComment(r):
+		l.acceptRunUntil('\n')
+		l.ignore()
+		return lexBeforeKey
+
+	default:
+		l.backup()
+		return lexKey
+	}
+
+}
 
 // lexKey scans the key up to a delimiter
 func lexKey(l *lexer) stateFn {
-	if l.peek() == eof {
-		l.emit(itemEOF)
-		return nil
-	}
-
 Loop:
 	for {
 		switch r := l.next(); {
@@ -250,7 +274,7 @@
 
 			// ignore the new line
 			l.ignore()
-			return lexKey
+			return lexBeforeKey
 
 		case isEOF(r):
 			l.emit(itemValue)
@@ -321,6 +345,11 @@
 	}
 }
 
+// isComment reports whether we are at the start of a comment.
+func isComment(r rune) bool {
+	return r == '#' || r == '!'
+}
+
 // isEOF reports whether we are at EOF.
 func isEOF(r rune) bool {
 	return r == eof
diff --git a/properties_test.go b/properties_test.go
index b8e034a..2420da5 100644
--- a/properties_test.go
+++ b/properties_test.go
@@ -24,6 +24,27 @@
 	testAllDelimiterCombinations(c, "key", "value")
 }
 
+func (l *LoadSuite) TestTwoKeysAndValues(c *C) {
+	testKeyValue(c, "key1=value1\nkey2=value2", "key1", "value1", "key2", "value2")
+}
+
+func (l *LoadSuite) TestWithBlankLines(c *C) {
+	testKeyValue(c, "\n\nkey=value\n\n", "key", "value")
+}
+
+func (l *LoadSuite) TestWithComments(c *C) {
+	input := `
+# this is a comment
+! and so is this
+key1=value1
+key#2=value#2
+key!3=value!3
+# and another one
+! and the final one
+`
+	testKeyValue(c, input, "key1", "value1", "key#2", "value#2", "key!3", "value!3")
+}
+
 func (l *LoadSuite) TestValueWithTrailingSpaces(c *C) {
 	testAllDelimiterCombinations(c, "key", "value   ")
 }
@@ -42,26 +63,30 @@
 }
 
 func (l *LoadSuite) TestMultilineValue(c *C) {
-	input := "key = valueA,\\\n    valueB"
-	testKeyValue(c, input, "key", "valueA,valueB")
+	testKeyValue(c, "key = valueA,\\\n    valueB", "key", "valueA,valueB")
 }
 
 func (l *LoadSuite) TestFailWithPrematureEOF(c *C) {
-	_, err := NewPropertiesFromString("key")
-	c.Assert(err, NotNil)
-	c.Assert(strings.Contains(err.Error(), "premature EOF"), Equals, true)
+	testError(c, "key", "premature EOF")
 }
 
 func (l *LoadSuite) TestFailWithNonISO8859_1Input(c *C) {
-	_, err := NewPropertiesFromString("key₡")
-	c.Assert(err, NotNil)
-	c.Assert(strings.Contains(err.Error(), "invalid ISO-8859-1 input"), Equals, true)
+	testError(c, "key₡", "invalid ISO-8859-1 input")
 }
 
 func (l *LoadSuite) TestFailWithInvalidUnicodeLiteralInKey(c *C) {
-	_, err := NewPropertiesFromString("key\\ugh32 = value")
-	c.Assert(err, NotNil)
-	c.Assert(strings.Contains(err.Error(), "invalid unicode literal"), Equals, true)
+	testError(c, "key\\ugh32 = value", "invalid unicode literal")
+}
+
+func BenchmarkNewPropertiesFromString(b *testing.B) {
+	input := ""
+	for i := 0; i < 1000; i++ {
+		input += fmt.Sprintf("key%d=value%d\n", i, i)
+	}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		NewPropertiesFromString(input)
+	}
 }
 
 // tests all combinations of delimiters plus leading and/or trailing spaces.
@@ -73,14 +98,22 @@
 	}
 }
 
-// tests a single key/value combination for a given input.
-func testKeyValue(c *C, input, key, value string) {
-	// fmt.Printf("Testing '%s'\n", input)
+// tests key/value pairs for a given input.
+func testKeyValue(c *C, input string, keyvalues ...string) {
 	p, err := NewPropertiesFromString(input)
 	c.Assert(err, IsNil)
 	c.Assert(p, NotNil)
-	c.Assert(p.Len(), Equals, 1)
-	assertKeyValue(c, p, key, value)
+	c.Assert(p.Len(), Equals, len(keyvalues)/2)
+	for i := 0; i < len(keyvalues)/2; i += 2 {
+		assertKeyValue(c, p, keyvalues[i], keyvalues[i+1])
+	}
+}
+
+// tests whether a given input produces a given error message.
+func testError(c *C, input, msg string) {
+	_, err := NewPropertiesFromString(input)
+	c.Assert(err, NotNil)
+	c.Assert(strings.Contains(err.Error(), msg), Equals, true)
 }
 
 func assertKeyValue(c *C, p *Properties, key, value string) {