// Path: core/src/main/java/it/nerdammer/spash/shell/common/SerializableFunction.java
// public abstract class SerializableFunction<T, R> implements Function<T, R>, Converter<T, R>, Serializable {
// 
//     @Override
//     public R call(T t) throws Exception {
//         return apply(t);
//     }
// 
//     @Override
//     public R convert(T t) {
//         return apply(t);
//     }
// 
//     public abstract R apply(T v1);
// 
// }
// 
// Path: core/src/main/java/it/nerdammer/spash/shell/common/SpashCollection.java
// public interface SpashCollection<T> extends Serializable {
// 
//     /**
//      * Prints the whole collection to the given writer.
//      *
//      * @param writer the writer on which the collection will be printed on.
//      */
//     void mkString(PrintWriter writer);
// 
//     /**
//      * Tranforms every element of the collection into another element.
//      *
//      * @param f the transformation function
//      * @param <R> the new type
//      * @return the transformed collection
//      */
//     <R> SpashCollection<R> map(SerializableFunction<T, R> f);
// 
//     /**
//      * Merges this collection to the one provided as input.
//      *
//      * @param coll the collection to merge
//      * @return the union of the two collections
//      */
//     SpashCollection<T> union(SpashCollection<T> coll);
// 
//     /**
//      * Filters a collection retaining only elements respecting the given condition.
//      *
//      * @param condition the condition that must evaluate to true for retained elements
//      * @return te resulting collection
//      */
//     SpashCollection<T> filter(SerializableFunction<T, Boolean> condition);
// 
//     /**
//      * Converts this collection to a Spark {@code JavaRDD}.
//      *
//      * @param sc the current Spark context
//      * @return a RDD corresponding to this collection
//      */
//     JavaRDD<T> toRDD(JavaSparkContext sc);
// 
//     /**
//      * Collects the whole collection into a {@code List}.
//      *
//      * @return the elements of the collection
//      */
//     List<T> collect();
// 
// }
// 
// Path: core/src/main/java/it/nerdammer/spash/shell/common/SpashCollectionEmptyAdapter.java
// public class SpashCollectionEmptyAdapter<T> implements SpashCollection<T> {
// 
//     public SpashCollectionEmptyAdapter() {
//     }
// 
//     @Override
//     public void mkString(PrintWriter writer) {
//     }
// 
//     @Override
//     public <R> SpashCollection<R> map(SerializableFunction<T, R> f) {
//         return new SpashCollectionEmptyAdapter<>();
//     }
// 
//     @Override
//     public SpashCollection<T> union(SpashCollection<T> coll) {
//         return coll;
//     }
// 
//     @Override
//     public SpashCollection<T> filter(SerializableFunction<T, Boolean> condition) {
//         return this;
//     }
// 
//     @Override
//     public JavaRDD<T> toRDD(JavaSparkContext sc) {
//         return sc.emptyRDD();
//     }
// 
//     @Override
//     public List<T> collect() {
//         return Collections.emptyList();
//     }
// }


import ch.lambdaj.Lambda;
import com.google.common.collect.ImmutableMap;
import it.nerdammer.spash.shell.command.*;
import it.nerdammer.spash.shell.common.SerializableFunction;
import it.nerdammer.spash.shell.common.SpashCollection;
import it.nerdammer.spash.shell.common.SpashCollectionEmptyAdapter;
import java.util.List;
        if(args.size()==0) {
            return CommandResult.error(this, "Missing argument");
        } else if(args.size()==1) {
            // pipe mode
            SpashCollection<String> prev = ctx.getPreviousCommandResult() != null ? ctx.getPreviousCommandResult().getContent() : null;
            if(prev==null) {
                prev = new SpashCollectionEmptyAdapter<>();
            }
            return execute(ctx, prev);
        } else {
            // cat mode

            String catCmdString = "cat " + Lambda.join(args.subList(1, args.size()), " ");
            Command cat = CommandFactory.getInstance().getCommand(catCmdString);
            CommandResult res = cat.execute(ctx);
            if(!res.isSuccess()) {
                return CommandResult.error(this, res.getErrorMessage());
            }

            return execute(ctx, res.getContent());
        }

    }

    protected CommandResult execute(ExecutionContext ctx, SpashCollection<String> source) {

        String filter = this.getArguments().get(0);
        boolean reverse = this.getOptions().containsKey("v");
        boolean insensitive = this.getOptions().containsKey("i");

// Path: core/src/main/java/it/nerdammer/spash/shell/common/SerializableFunction.java
// public abstract class SerializableFunction<T, R> implements Function<T, R>, Converter<T, R>, Serializable {
// 
//     @Override
//     public R call(T t) throws Exception {
//         return apply(t);
//     }
// 
//     @Override
//     public R convert(T t) {
//         return apply(t);
//     }
// 
//     public abstract R apply(T v1);
// 
// }
// 
// Path: core/src/main/java/it/nerdammer/spash/shell/common/SpashCollection.java
// public interface SpashCollection<T> extends Serializable {
// 
//     /**
//      * Prints the whole collection to the given writer.
//      *
//      * @param writer the writer on which the collection will be printed on.
//      */
//     void mkString(PrintWriter writer);
// 
//     /**
//      * Tranforms every element of the collection into another element.
//      *
//      * @param f the transformation function
//      * @param <R> the new type
//      * @return the transformed collection
//      */
//     <R> SpashCollection<R> map(SerializableFunction<T, R> f);
// 
//     /**
//      * Merges this collection to the one provided as input.
//      *
//      * @param coll the collection to merge
//      * @return the union of the two collections
//      */
//     SpashCollection<T> union(SpashCollection<T> coll);
// 
//     /**
//      * Filters a collection retaining only elements respecting the given condition.
//      *
//      * @param condition the condition that must evaluate to true for retained elements
//      * @return te resulting collection
//      */
//     SpashCollection<T> filter(SerializableFunction<T, Boolean> condition);
// 
//     /**
//      * Converts this collection to a Spark {@code JavaRDD}.
//      *
//      * @param sc the current Spark context
//      * @return a RDD corresponding to this collection
//      */
//     JavaRDD<T> toRDD(JavaSparkContext sc);
// 
//     /**
//      * Collects the whole collection into a {@code List}.
//      *
//      * @return the elements of the collection
//      */
//     List<T> collect();
// 
// }
// 
// Path: core/src/main/java/it/nerdammer/spash/shell/common/SpashCollectionEmptyAdapter.java
// public class SpashCollectionEmptyAdapter<T> implements SpashCollection<T> {
// 
//     public SpashCollectionEmptyAdapter() {
//     }
// 
//     @Override
//     public void mkString(PrintWriter writer) {
//     }
// 
//     @Override
//     public <R> SpashCollection<R> map(SerializableFunction<T, R> f) {
//         return new SpashCollectionEmptyAdapter<>();
//     }
// 
//     @Override
//     public SpashCollection<T> union(SpashCollection<T> coll) {
//         return coll;
//     }
// 
//     @Override
//     public SpashCollection<T> filter(SerializableFunction<T, Boolean> condition) {
//         return this;
//     }
// 
//     @Override
//     public JavaRDD<T> toRDD(JavaSparkContext sc) {
//         return sc.emptyRDD();
//     }
// 
//     @Override
//     public List<T> collect() {
//         return Collections.emptyList();
//     }
// }


// Path: core/src/main/java/it/nerdammer/spash/shell/command/spi/GrepCommand.java
import ch.lambdaj.Lambda;
import com.google.common.collect.ImmutableMap;
import it.nerdammer.spash.shell.command.*;
import it.nerdammer.spash.shell.common.SerializableFunction;
import it.nerdammer.spash.shell.common.SpashCollection;
import it.nerdammer.spash.shell.common.SpashCollectionEmptyAdapter;
import java.util.List;

        if(args.size()==0) {
            return CommandResult.error(this, "Missing argument");
        } else if(args.size()==1) {
            // pipe mode
            SpashCollection<String> prev = ctx.getPreviousCommandResult() != null ? ctx.getPreviousCommandResult().getContent() : null;
            if(prev==null) {
                prev = new SpashCollectionEmptyAdapter<>();
            }
            return execute(ctx, prev);
        } else {
            // cat mode

            String catCmdString = "cat " + Lambda.join(args.subList(1, args.size()), " ");
            Command cat = CommandFactory.getInstance().getCommand(catCmdString);
            CommandResult res = cat.execute(ctx);
            if(!res.isSuccess()) {
                return CommandResult.error(this, res.getErrorMessage());
            }

            return execute(ctx, res.getContent());
        }

    }

    protected CommandResult execute(ExecutionContext ctx, SpashCollection<String> source) {

        String filter = this.getArguments().get(0);
        boolean reverse = this.getOptions().containsKey("v");
        boolean insensitive = this.getOptions().containsKey("i");

        SpashCollection<String> content = source.filter(new FilterFunction(filter, reverse, insensitive));