// Path: lib/src/main/java/tk/zielony/randomdata/DataContext.java
// public class DataContext {
// 
//     private static final String LOCALE = "locale";
//     public static final String NAME = "name";
// 
//     protected final List<Map<String, Object>> stack = new ArrayList<>();
// 
//     void save() {
//         HashMap<String, Object> contextData = (HashMap<String, Object>) stack.get(stack.size() - 1);
//         HashMap<String, Object> clone = (HashMap<String, Object>) contextData.clone();
//         stack.add(clone);
//     }
// 
//     public DataContext() {
//         stack.add(new HashMap<>());
//     }
// 
//     void restore() {
//         stack.remove(stack.size() - 1);
//     }
// 
//     public <Type> Type get(String key) {
//         return (Type) stack.get(stack.size() - 1).get(key);
//     }
// 
//     public <Type> void set(String key, Type value) {
//         stack.get(stack.size() - 1).put(key, value);
//     }
// }
// 
// Path: lib/src/main/java/tk/zielony/randomdata/Generator.java
// public abstract class Generator<Type> implements SimpleGenerator<Type> {
//     private Matcher matcher;
// 
//     protected Matcher getDefaultMatcher() {
//         return f -> true;
//     }
// 
//     public Generator<Type> withMatcher(Matcher matcher) {
//         this.matcher = matcher;
//         return this;
//     }
// 
//     public <OutType> GeneratorWithTransformer<Type, OutType> withTransformer(Transformer<Type, OutType> transformer) {
//         return new GeneratorWithTransformer<>(this, transformer);
//     }
// 
//     protected boolean match(Target target) {
//         if (matcher == null)
//             matcher = getDefaultMatcher();
//         return matcher.matches(target);
//     }
// 
//     public Type next() {
//         return next(null);
//     }
// 
//     public abstract Type next(@Nullable DataContext context);
// 
//     public void reset() {
//     }
// }
// 
// Path: lib/src/main/java/tk/zielony/randomdata/Matcher.java
// public interface Matcher {
//     boolean matches(Target target);
// }


import java.util.Random;
import tk.zielony.randomdata.DataContext;
import tk.zielony.randomdata.Generator;
import tk.zielony.randomdata.Matcher;
package tk.zielony.randomdata.finance;



public class StringCardNumberGenerator extends Generator<String> {
    private static class BIN {
        String name;
        int number;
        int length;

        BIN(String name, int number, int length) {
            this.name = name;
            this.number = number;
            this.length = length;
        }
    }

    private static BIN[] bins = {
            new BIN("MasterCard", 51, 16),
            new BIN("MasterCard", 52, 16),
            new BIN("MasterCard", 53, 16),
            new BIN("MasterCard", 54, 16),
            new BIN("MasterCard", 55, 16),
            new BIN("VISA", 4, 16),
            new BIN("American Express", 34, 15),
            new BIN("American Express", 37, 15)
    };

    private Random random = new Random();

    @Override
// Path: lib/src/main/java/tk/zielony/randomdata/DataContext.java
// public class DataContext {
// 
//     private static final String LOCALE = "locale";
//     public static final String NAME = "name";
// 
//     protected final List<Map<String, Object>> stack = new ArrayList<>();
// 
//     void save() {
//         HashMap<String, Object> contextData = (HashMap<String, Object>) stack.get(stack.size() - 1);
//         HashMap<String, Object> clone = (HashMap<String, Object>) contextData.clone();
//         stack.add(clone);
//     }
// 
//     public DataContext() {
//         stack.add(new HashMap<>());
//     }
// 
//     void restore() {
//         stack.remove(stack.size() - 1);
//     }
// 
//     public <Type> Type get(String key) {
//         return (Type) stack.get(stack.size() - 1).get(key);
//     }
// 
//     public <Type> void set(String key, Type value) {
//         stack.get(stack.size() - 1).put(key, value);
//     }
// }
// 
// Path: lib/src/main/java/tk/zielony/randomdata/Generator.java
// public abstract class Generator<Type> implements SimpleGenerator<Type> {
//     private Matcher matcher;
// 
//     protected Matcher getDefaultMatcher() {
//         return f -> true;
//     }
// 
//     public Generator<Type> withMatcher(Matcher matcher) {
//         this.matcher = matcher;
//         return this;
//     }
// 
//     public <OutType> GeneratorWithTransformer<Type, OutType> withTransformer(Transformer<Type, OutType> transformer) {
//         return new GeneratorWithTransformer<>(this, transformer);
//     }
// 
//     protected boolean match(Target target) {
//         if (matcher == null)
//             matcher = getDefaultMatcher();
//         return matcher.matches(target);
//     }
// 
//     public Type next() {
//         return next(null);
//     }
// 
//     public abstract Type next(@Nullable DataContext context);
// 
//     public void reset() {
//     }
// }
// 
// Path: lib/src/main/java/tk/zielony/randomdata/Matcher.java
// public interface Matcher {
//     boolean matches(Target target);
// }


// Path: finance/src/main/java/tk/zielony/randomdata/finance/StringCardNumberGenerator.java
import java.util.Random;
import tk.zielony.randomdata.DataContext;
import tk.zielony.randomdata.Generator;
import tk.zielony.randomdata.Matcher;

package tk.zielony.randomdata.finance;



public class StringCardNumberGenerator extends Generator<String> {
    private static class BIN {
        String name;
        int number;
        int length;

        BIN(String name, int number, int length) {
            this.name = name;
            this.number = number;
            this.length = length;
        }
    }

    private static BIN[] bins = {
            new BIN("MasterCard", 51, 16),
            new BIN("MasterCard", 52, 16),
            new BIN("MasterCard", 53, 16),
            new BIN("MasterCard", 54, 16),
            new BIN("MasterCard", 55, 16),
            new BIN("VISA", 4, 16),
            new BIN("American Express", 34, 15),
            new BIN("American Express", 37, 15)
    };

    private Random random = new Random();

    @Override
    protected Matcher getDefaultMatcher() {