Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of ../../square/luhnybin

  • Loading branch information...
commit a1798dd6dcfb3c44174c7dc1548c6704f25d0a7a 2 parents af9c467 + 1176818
@crazybob authored
View
44 README.md
@@ -3,7 +3,7 @@ Coding Challenge: The Luhny Bin
> "To err is human; to forgive, divine." -Alexander Pope
-Computers break. Mistakes happen. At Square, we accept that human error is inevitable. We anticipate potential slip-ups and implement safety measures to mitigate—and oftentimes completely eliminate—any repercussions.
+Mistakes happen. At Square, we accept that human error is inevitable. We anticipate potential slip-ups and implement safety measures to mitigate—and oftentimes completely eliminate—any repercussions.
For example, Square's Luhn filter monitors logs and masks anything that looks like a credit card number. If a number like "4111 1111 1111 1111" were accidentally logged as part of an error message, our filter would replace it with "XXXX XXXX XXXX XXXX" and page an on call engineer.
@@ -11,36 +11,34 @@ The Luhn filter looks for sequences of digits that pass <a href="http://en.wikip
The Luhn check works like this:
-1. Start from the *rightmost* digit and work left.
-2. Double every second digit.
-3. If a product has two digits, treat the digits independently.
-4. Sum each individual digit, including the non-doubled digits.
-5. Divide the result by 10.
-6. If the remainder is 0, the number passed the Luhn check.
+1. Starting from the *rightmost* digit and working left, double every second digit.
+1. If a product has two digits, treat the digits independently.
+1. Sum each individual digit, including the non-doubled digits.
+1. Divide the result by 10.
+1. If the remainder is 0, the number passed the Luhn check.
For example, "5678" passes the Luhn check:
1. Double every other digit: 10, 6, 14, 8
-2. Sum the individual digits: (1 + 0) + 6 + (1 + 4) + 8 = 20
-3. Divide the result by 10: 20 mod 10 = 0 **(Pass)**
+1. Sum the individual digits: (1 + 0) + 6 + (1 + 4) + 8 = 20
+1. Divide the result by 10: 20 mod 10 = 0 <b><font color="green">Pass</font></b>
"6789" does not:
1. Double every other digit: 12, 7, 16, 9
-2. Sum the individual digits: (1 + 2) + 7 + (1 + 6) + 9 = 26
-3. Divide the result by 10: 26 mod 10 != 0 **(Fail)**
+1. Sum the individual digits: (1 + 2) + 7 + (1 + 6) + 9 = 26
+1. Divide the result by 10: 26 mod 10 != 0 <b><font color="red">Fail</font></b>
-*Now for the challenge.*
+Now for the challenge...
+------------------------
-Write a program that reads data from standard input, masks sequences of digits that look like credit card numbers, and writes the filtered data to standard output. For the purposes of this challenge, a credit card number:
+Write a command line program that reads ASCII text from standard input, masks sequences of digits that look like credit card numbers, and writes the filtered text to standard output. For the purposes of this challenge, a credit card number:
-- Is between 14 and 16 characters long, inclusive.
+- Consists of digits, spaces (`' '`) and hyphens (`'-'`).
+- Has between 14 and 16 digits, inclusive.
- Passes the Luhn check.
-- Can contain any combination of `' '` or `'-'` characters.
-If a sequence of digits looks like a credit card number, replace each digit with an `'X'`. Any characters, including digits, may flank a credit card number. *Beware:* A valid 16-digit number can contain a valid 14 or 15-digit number. Your program must mask every digit.
-
-This isn't a contest, but an innovative solution could score you interviews at Square. I'm primarily interested to see how different programming languages stack up with regard to readability and performance.
+If a sequence of digits looks like a credit card number, replace each digit with an `'X'`. Any characters, including digits, may flank a credit card number. *Beware.* Potential credit card numbers can overlap. A valid 16-digit number can even contain a valid 14 or 15-digit number. Your program must mask every digit.
I already wrote a test suite, so you can jump straight to the fun part: writing the algorithm. To participate:
@@ -49,7 +47,7 @@ I already wrote a test suite, so you can jump straight to the fun part: writing
3. Test your program by executing `run.sh`.
4. Once `run.sh` passes, post a link to your solution in the comments on [our blog](http://corner.squareup.com/2011/11/luhny-bin.html).
-Windows users should use [Cygwin](http://www.cygwin.com/) to run the tests. Please make it easy for someone else to check out and run your solution.
+Windows users should use [Cygwin](http://www.cygwin.com/) to run the tests. Please make it easy for others to check out and run your solution.
The first time you execute `run.sh`, you'll see a test failure:
@@ -64,6 +62,10 @@ The first time you execute `run.sh`, you'll see a test failure:
Expected result: XXXXXXXXXXXXXX\n
Actual result: 56613959932537\n
-Modify `mask.sh` and make the tests pass. The test suite outputs ASCII-encoded data. It expects the same for input. [Line feeds](http://en.wikipedia.org/wiki/Newline) delineate the test cases. If you pass a number on the command line, `run.sh` will repeat the test suite the specified number of times; this is useful for performance comparisons. The tests aren't set in stone&mdash;if you have an idea for improving the test suite, please submit a pull request.
+Modify `mask.sh` and make the tests pass. [Line feeds](http://en.wikipedia.org/wiki/Newline) delineate the test cases. If you pass a number on the command line, `run.sh` will repeat the test suite the specified number of times; this is useful for performance comparisons. The tests aren't set in stone&mdash;if you have an idea for improving the test suite, please submit a pull request.
+
+This isn't a contest, but an innovative solution could score you interviews at Square. I'm primarily interested to see how different programming languages stack up with regard to readability and performance.
+
+Once we have enough interesting submissions, I'll summarize the results in a followup [blog](http://corner.squareup.com/) post and open source our own Java-based implementation. In the mean time, if you enjoy working with talented people on challenging problems like this, email your résumé to <a href="mailto:luhnybin@squareup.com">luhnybin@squareup.com</a>.
-Once we have enough interesting submissions, I'll post a followup to [our blog](http://corner.squareup.com/) summarizing the results. I'll open source our own Java-based solution after everyone has had time to give the problem a shot. Good luck!
+Good luck!
View
18 tests/src/main/java/com/squareup/luhnybin/LuhnyBinTests.java
@@ -60,6 +60,24 @@
.send(nestedNumber())
.expect(mask(16));
+ // 1111111111111abc
+
+ // 15:
+ // 111111111111abc
+ // 121212121212aBc
+ // (18 + a + B + c) % 10 = 0
+
+ // 16:
+ // 1111111111111abc
+ // 2121212121212aBc
+ // (20 + a + B + c) % 10 = 0
+
+ // (18 + a + B + c) % 10 = (20 + a + B + c) % 10
+
+ // a: 0-9
+ // B: 0-9
+ // c: 0-9
+
test("16-digit # flanked by non-matching digits")
.send("9875610591081018250321")
.expect("987XXXXXXXXXXXXXXXX321");
View
5 tests/src/main/java/com/squareup/luhnybin/Main.java
@@ -93,6 +93,8 @@ public void run() {
long[] times = new long[iterations];
for (int i = 0; i < iterations; i++) {
+ final boolean lastIteration = i == iterations - 1;
+
long iterationStart = System.nanoTime();
// Write in the background. Writing can block if the buffer fills up.
@@ -101,6 +103,7 @@ public void run() {
try {
bout.writeTo(out);
out.flush();
+ if (lastIteration) out.close();
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
@@ -130,8 +133,6 @@ public void testFailed(TestCase test, String actualInput) {
times[i] = (System.nanoTime() - iterationStart) / 1000;
}
- out.close();
-
long elapsed = (System.nanoTime() - start) / 1000000;
System.out.println();
View
BIN  tests/target/luhnybin-1.0-SNAPSHOT.jar
Binary file not shown
Please sign in to comment.
Something went wrong with that request. Please try again.