// Path: app/utils/CollectionUtils.java
// public class CollectionUtils
// {
//     private CollectionUtils()
//     {
//         // no-op
//     }
// 
//     /**
//      * Gets the first element of the list.
//      *
//      * @param list the list
//      * @param <T> the list's generic type
//      * @return the first element of the list, or null if the list is null or empty.  The returned value will also be null
//      * if the first element of the list is null.
//      */
//     public static <T> T first(List<T> list)
//     {
//         return isEmpty(list) ? null : list.get(0);
//     }
// 
//     /**
//      * Gets the last element of the list.
//      *
//      * @param list the list
//      * @param <T> the list's generic type
//      * @return the last element of the list, or null if the list is null or empty.  The returned value will also be null
//      * if the last element of the list is null.
//      */
//     public static <T> T last(List<T> list)
//     {
//         return isEmpty(list) ? null : list.get(list.size() - 1);
//     }
// 
//     /**
//      * Checks if a collection is null or empty.
//      *
//      * @param c the collection
//      * @return true if the collection is null or has a length of 0. A collection containing null entries is considered
//      * to be non-empty.
//      */
//     public static boolean isEmpty(Collection c)
//     {
//         return c == null || c.isEmpty();
//     }
// 
//     /**
//      * Gets the first matching element of collection, using the filter.
//      *
//      * @param collection the collection to filter
//      * @param filter filters the elements
//      * @param <T> the generic type
//      * @return the first element that is accepted by the filter, or null if the collection is null, empty or contains
//      * no acceptable elements
//      */
//     public static <T> T filterFirst(Collection<T> collection,
//                                     Filter<T> filter)
//     {
//         T t = null;
// 
//         if (!isEmpty(collection))
//         {
//             for (Iterator<T> iterator = collection.iterator(); t == null && iterator.hasNext(); )
//             {
//                 T element = iterator.next();
//                 t = filter.isAcceptable(element) ? element :  null;
//             }
//         }
// 
//         return t;
//     }
// 
//     /**
//      * Transforms a collection of objects of one type into a list of another type.
//      *
//      * @param input the collection to transform
//      * @param transformer transforms individual objects
//      * @param <I> the input type to tranform
//      * @param <O> the output type that is the result of the transformation
//      * @return a list of transformed objects
//      */
//     public static <I, O> List<O> transform(Collection<I> input,
//                                            Transformer<I, O> transformer)
//     {
//         List<O> output = new ArrayList<O>();
//         if (input != null)
//         {
//             for (I i : input)
//             {
//                 if (i != null)
//                 {
//                     output.add(transformer.transform(i));
//                 }
//             }
//         }
//         return output;
//     }
// 
//     /**
//      * Convenience method for type erasure when casting lists.
//      *
//      * @param list the list to cast
//      * @param t the class type
//      * @param <T> the generic type
//      * @return a list of type T
//      */
//     public static <T> List<T> castTo(List list,
//                                     Class<T> t)
//     {
//         return (List<T>)list;
//     }
// }


import com.petebevin.markdown.MarkdownProcessor;
import play.data.validation.Constraints;
import utils.CollectionUtils;
import javax.persistence.*;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static javax.persistence.CascadeType.*;
import static javax.persistence.FetchType.LAZY;
import static play.data.validation.Constraints.MaxLength;
import static play.data.validation.Constraints.Required;

    public Date createdOn = new Date();

    @Column(nullable = false)
    public Date updatedOn = new Date();

    @OneToOne(optional = true, cascade = ALL)
    public Rating rating;

    @OneToMany(fetch = LAZY, cascade = ALL, orphanRemoval = true)
    public List<Comment> comments;

    @ManyToMany(cascade = {DETACH, PERSIST, REFRESH})
    public List<Tag> tags;

    @Override
    public int compareTo(Module module) {
        return name == null ? -1 : name.compareTo(module.name);
    }

    public String getDescriptionHtml() {
        return new MarkdownProcessor().markdown(description);
    }

    public static final Finder<Long, Module> FIND = new Finder<Long, Module>(Long.class, Module.class);

    public List<ModuleVersion> getVersions() {
        return ModuleVersion.findByModule(this);
    }

    public ModuleVersion getMostRecentVersion() {

// Path: app/utils/CollectionUtils.java
// public class CollectionUtils
// {
//     private CollectionUtils()
//     {
//         // no-op
//     }
// 
//     /**
//      * Gets the first element of the list.
//      *
//      * @param list the list
//      * @param <T> the list's generic type
//      * @return the first element of the list, or null if the list is null or empty.  The returned value will also be null
//      * if the first element of the list is null.
//      */
//     public static <T> T first(List<T> list)
//     {
//         return isEmpty(list) ? null : list.get(0);
//     }
// 
//     /**
//      * Gets the last element of the list.
//      *
//      * @param list the list
//      * @param <T> the list's generic type
//      * @return the last element of the list, or null if the list is null or empty.  The returned value will also be null
//      * if the last element of the list is null.
//      */
//     public static <T> T last(List<T> list)
//     {
//         return isEmpty(list) ? null : list.get(list.size() - 1);
//     }
// 
//     /**
//      * Checks if a collection is null or empty.
//      *
//      * @param c the collection
//      * @return true if the collection is null or has a length of 0. A collection containing null entries is considered
//      * to be non-empty.
//      */
//     public static boolean isEmpty(Collection c)
//     {
//         return c == null || c.isEmpty();
//     }
// 
//     /**
//      * Gets the first matching element of collection, using the filter.
//      *
//      * @param collection the collection to filter
//      * @param filter filters the elements
//      * @param <T> the generic type
//      * @return the first element that is accepted by the filter, or null if the collection is null, empty or contains
//      * no acceptable elements
//      */
//     public static <T> T filterFirst(Collection<T> collection,
//                                     Filter<T> filter)
//     {
//         T t = null;
// 
//         if (!isEmpty(collection))
//         {
//             for (Iterator<T> iterator = collection.iterator(); t == null && iterator.hasNext(); )
//             {
//                 T element = iterator.next();
//                 t = filter.isAcceptable(element) ? element :  null;
//             }
//         }
// 
//         return t;
//     }
// 
//     /**
//      * Transforms a collection of objects of one type into a list of another type.
//      *
//      * @param input the collection to transform
//      * @param transformer transforms individual objects
//      * @param <I> the input type to tranform
//      * @param <O> the output type that is the result of the transformation
//      * @return a list of transformed objects
//      */
//     public static <I, O> List<O> transform(Collection<I> input,
//                                            Transformer<I, O> transformer)
//     {
//         List<O> output = new ArrayList<O>();
//         if (input != null)
//         {
//             for (I i : input)
//             {
//                 if (i != null)
//                 {
//                     output.add(transformer.transform(i));
//                 }
//             }
//         }
//         return output;
//     }
// 
//     /**
//      * Convenience method for type erasure when casting lists.
//      *
//      * @param list the list to cast
//      * @param t the class type
//      * @param <T> the generic type
//      * @return a list of type T
//      */
//     public static <T> List<T> castTo(List list,
//                                     Class<T> t)
//     {
//         return (List<T>)list;
//     }
// }


// Path: app/models/Module.java
import com.petebevin.markdown.MarkdownProcessor;
import play.data.validation.Constraints;
import utils.CollectionUtils;
import javax.persistence.*;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static javax.persistence.CascadeType.*;
import static javax.persistence.FetchType.LAZY;
import static play.data.validation.Constraints.MaxLength;
import static play.data.validation.Constraints.Required;

    public Date createdOn = new Date();

    @Column(nullable = false)
    public Date updatedOn = new Date();

    @OneToOne(optional = true, cascade = ALL)
    public Rating rating;

    @OneToMany(fetch = LAZY, cascade = ALL, orphanRemoval = true)
    public List<Comment> comments;

    @ManyToMany(cascade = {DETACH, PERSIST, REFRESH})
    public List<Tag> tags;

    @Override
    public int compareTo(Module module) {
        return name == null ? -1 : name.compareTo(module.name);
    }

    public String getDescriptionHtml() {
        return new MarkdownProcessor().markdown(description);
    }

    public static final Finder<Long, Module> FIND = new Finder<Long, Module>(Long.class, Module.class);

    public List<ModuleVersion> getVersions() {
        return ModuleVersion.findByModule(this);
    }

    public ModuleVersion getMostRecentVersion() {

        return CollectionUtils.last(getVersions());
