<commit_before>/*
 * $Id: PackageResource.java 4898 2006-03-13 13:44:52 -0800 (Mon, 13 Mar 2006)
 * joco01 $ $Revision$ $Date: 2006-03-13 13:44:52 -0800 (Mon, 13 Mar
 * 2006) $
 * 
 * ==============================================================================
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package wicket.markup.html;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import wicket.Application;
import wicket.SharedResources;
import wicket.WicketRuntimeException;
import wicket.util.lang.PackageName;
import wicket.util.lang.Packages;
import wicket.util.resource.IResourceStream;
import wicket.util.string.Strings;

/**
 * Represents a localizable static resource.
 * <p>
 * Use like eg:
 * 
 * <pre>
 * private static final PackageResource IMG_UNKNOWN = PackageResource.get(EditPage.class,
 * 		&quot;questionmark.gif&quot;);
 * </pre>
 * 
 * where the static resource references image 'questionmark.gif' from the the
 * package that EditPage is in to get a package resource. Register package
 * resources with one of the 'bind' methods to make them available as shared/
 * bookmarkable resources.
 * </p>
 * 
 * @author <NAME>
 * @author <NAME>
 */
public class PackageResource extends WebResource
{
	private static final long serialVersionUID = 1L;

	/** log. */
	private static final Log log = LogFactory.getLog(PackageResource.class);

	/**
	 * common extension pattern for javascript files; matches all files with
	 * extension 'js'.
	 */
	public static final Pattern EXTENSION_JS = Pattern.compile(".*\\.js");

	/**
	 * common extension pattern for css files; matches all files with extension
	 * 'css'.
	 */
	public static final Pattern EXTENSION_CSS = Pattern.compile(".*\\.css");

	/** The path to the resource */
	private final String absolutePath;

	/** The resource's locale */
	private Locale locale;

	/** The resource's style */
	private final String style;

	/** The scoping class, used for class loading and to determine the package. */
	private final Class scope;

	/** The path this resource was created with. */
	private final String path;

	/**
	 * Binds a resource to the given application object. Will create the
	 * resource if not already in the shared resources of the application
	 * object.
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param name
	 *            The name of the resource (like &quot;myfile.js&quot;)
	 * @throw IllegalArgumentException when the requested package resource was
	 *        not found
	 */
	public static void bind(Application application, Class scope, String name)
	{
		bind(application, scope, name, null, null);
	}

	/**
	 * Binds a resource to the given application object. Will create the
	 * resource if not already in the shared resources of the application
	 * object.
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param name
	 *            The name of the resource (like &quot;myfile.js&quot;)
	 * @param locale
	 *            The locale of the resource.
	 * @throw IllegalArgumentException when the requested package resource was
	 *        not found
	 */
	public static void bind(Application application, Class scope, String name, Locale locale)
	{
		bind(application, scope, name, locale, null);
	}

	/**
	 * Binds a resource to the given application object. Will create the
	 * resource if not already in the shared resources of the application
	 * object.
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param name
	 *            The name of the resource (like &quot;myfile.js&quot;)
	 * @param locale
	 *            The locale of the resource.
	 * @param style
	 *            The style of the resource.
	 * @throw IllegalArgumentException when the requested package resource was
	 *        not found
	 */
	public static void bind(Application application, Class scope, String name, Locale locale,
			String style)
	{
		if (name == null)
		{
			throw new IllegalArgumentException("argument name may not be null");
		}

		// first check on a direct hit for efficiency
		if (exists(scope, name, locale, style))
		{
			// we have got a hit, so we may safely assume the name
			// argument is not a regular expression, and can thus
			// just add the resource and return
			get(scope, name, locale, style);
		}
		else
		{
			throw new IllegalArgumentException("no package resource was found for scope " + scope
					+ ", name " + name + ", locale " + locale + ", style " + style);
		}
	}

	/**
	 * Binds the resources that match the provided pattern to the given
	 * application object. Will create any resources if not already in the
	 * shared resources of the application object.
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param pattern
	 *            A regular expression to match against the contents of the
	 *            package of the provided scope class (eg &quot;.*\\.js&quot;
	 *            will add all the files with extension &quot;js&quot; from that
	 *            package).
	 * @param recurse
	 *            Whether this method should recurse into sub packages
	 */
	public static void bind(Application application, Class scope, Pattern pattern)
	{
		// bind using the pattern without recursing
		bind(application, scope, pattern, false);
	}

	/**
	 * Binds the resources that match the provided pattern to the given
	 * application object. Will create any resources if not already in the
	 * shared resources of the application object and does that recursively when
	 * the recurse parameter is true, or just for the scoped package if that
	 * parameter is false
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param pattern
	 *            A regular expression to match against the contents of the
	 *            package of the provided scope class (eg &quot;.*\\.js&quot;
	 *            will add all the files with extension &quot;js&quot; from that
	 *            package).
	 * @param recurse
	 *            Whether this method should recurse into sub packages
	 */
	public static void bind(Application application, Class scope, Pattern pattern, boolean recurse)
	{
		// bind using the pattern
		get(scope, pattern, recurse);
	}

	/**
	 * Gets a non-localized resource for a given set of criteria. Only one
	 * resource will be loaded for the same criteria.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the calling class/ the class in which you
	 *            call this method
	 * @param path
	 *            The path to the resource
	 * @return The resource
	 */
	public static PackageResource get(final Class scope, final String path)
	{
		return get(scope, path, null, null);
	}

	/**
	 * Gets the resource for a given set of criteria. Only one resource will be
	 * loaded for the same criteria.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the class in which you call this method
	 * @param path
	 *            The path to the resource
	 * @param locale
	 *            The locale of the resource
	 * @param style
	 *            The style of the resource (see {@link wicket.Session})
	 * @return The resource
	 */
	public static PackageResource get(final Class scope, final String path, final Locale locale,
			final String style)
	{
		final SharedResources sharedResources = Application.get().getSharedResources();
		PackageResource resource = (PackageResource)sharedResources.get(scope, path, locale, style,
				true);
		if (resource == null)
		{
			resource = new PackageResource(scope, path, locale, style);
			sharedResources.add(scope, path, locale, style, resource);
		}
		return resource;
	}

	/**
	 * Gets non-localized resources for a given set of criteria. Multiple
	 * resource can be loaded for the same criteria if they match the pattern.
	 * If no resources were found, this method returns null.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the calling class/ the class in which you
	 *            call this method
	 * @param pattern
	 *            Regexp pattern to match resources
	 * @return The resources, never null but may be empty
	 */
	public static PackageResource[] get(Class scope, Pattern pattern)
	{
		return get(scope, pattern, false);
	}

	/**
	 * Gets non-localized resources for a given set of criteria. Multiple
	 * resource can be loaded for the same criteria if they match the pattern.
	 * If no resources were found, this method returns null.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the calling class/ the class in which you
	 *            call this method
	 * @param pattern
	 *            Regexp pattern to match resources
	 * @param recurse
	 *            Whether this method should recurse into sub packages
	 * @return The resources, never null but may be empty
	 */
	public static PackageResource[] get(Class scope, Pattern pattern, boolean recurse)
	{
		final List resources = new ArrayList();
		String packageRef = Strings.replaceAll(PackageName.forClass(scope).getName(), ".", "/");
		ClassLoader loader = scope.getClassLoader();
		try
		{
			// loop through the resources of the package
			Enumeration packageResources = loader.getResources(packageRef);
			while (packageResources.hasMoreElements())
			{
				URL resource = (URL)packageResources.nextElement();
				URLConnection connection = resource.openConnection();
				if (connection instanceof JarURLConnection)
				{
					JarFile jf = ((JarURLConnection)connection).getJarFile();
					Enumeration enumeration = jf.entries();
					while (enumeration.hasMoreElements())
					{
						JarEntry je = (JarEntry)enumeration.nextElement();
						String name = je.getName();
						if (name.startsWith(packageRef))
						{
							name = name.substring(packageRef.length() + 1);
							if (pattern.matcher(name).matches()
									&& (recurse || (name.indexOf('/') == -1)))
							{
								// we add the entry as a package resource
								resources.add(get(scope, name, null, null));
							}
						}
					}
				}
				else
				{
					String absolutePath = scope.getResource("").getPath();
					File basedir = new File(absolutePath);
					if (!basedir.isDirectory())
					{
						throw new IllegalStateException("unable to read resources from directory "
								+ basedir);
					}
					addResources(scope, pattern, resources, new StringBuffer(""), basedir, recurse);
				}
			}
		}
		catch (IOException e)
		{
			throw new WicketRuntimeException(e);
		}

		return (resources != null) ? (PackageResource[])resources
				.toArray(new PackageResource[resources.size()]) : null;
	}

	/**
	 * Gets whether a resource for a given set of criteria exists.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the class in which you call this method
	 * @param path
	 *            The path to the resource
	 * @param locale
	 *            The locale of the resource
	 * @param style
	 *            The style of the resource (see {@link wicket.Session})
	 * @return true if a resource could be loaded, false otherwise
	 */
	public static boolean exists(final Class scope, final String path, final Locale locale,
			final String style)
	{
		String absolutePath = Packages.absolutePath(scope, path);
		return Application.get().getResourceSettings().getResourceStreamLocator().locate(scope,
				absolutePath, style, locale, null) != null;
	}

	/**
	 * Adds resources recursively.
	 * 
	 * @param scope
	 *            the original scope used to get the base directory
	 * @param pattern
	 *            Regexp pattern to match resources
	 * @param resources
	 *            the current list of resources
	 * @param relativePath
	 *            The relative path that is to be prepended to the resource's
	 *            name
	 * @param dir
	 *            the current directory
	 * @param recurse
	 *            Whether this method should recurse into sub packages
	 */
	private static final void addResources(final Class scope, final Pattern pattern,
			final List resources, final StringBuffer relativePath, final File dir, boolean recurse)
	{
		File[] files = dir.listFiles();
		for (int i = 0; i < files.length; i++)
		{
			File file = files[i];
			if (file.isDirectory())
			{
				if (recurse)
				{
					addResources(scope, pattern, resources, relativePath.append(file.getName())
							.append('/'), file, recurse);
				}
			}
			else
			{
				String fileName = file.getName();
				if (pattern.matcher(fileName).matches())
				{
					// we add the entry as a package resource
					resources.add(get(scope, relativePath + fileName, null, null));
				}
			}
		}
	}

	/**
	 * Hidden constructor.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in
	 * @param path
	 *            The path to the resource
	 * @param locale<commit_msg>thanks for noticing Joshua :)<commit_after>/*
 * $Id: PackageResource.java 4898 2006-03-13 13:44:52 -0800 (Mon, 13 Mar 2006)
 * joco01 $ $Revision$ $Date: 2006-03-13 13:44:52 -0800 (Mon, 13 Mar
 * 2006) $
 * 
 * ==============================================================================
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package wicket.markup.html;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import wicket.Application;
import wicket.SharedResources;
import wicket.WicketRuntimeException;
import wicket.util.lang.PackageName;
import wicket.util.lang.Packages;
import wicket.util.resource.IResourceStream;
import wicket.util.string.Strings;

/**
 * Represents a localizable static resource.
 * <p>
 * Use like eg:
 * 
 * <pre>
 * private static final PackageResource IMG_UNKNOWN = PackageResource.get(EditPage.class,
 * 		&quot;questionmark.gif&quot;);
 * </pre>
 * 
 * where the static resource references image 'questionmark.gif' from the the
 * package that EditPage is in to get a package resource. Register package
 * resources with one of the 'bind' methods to make them available as shared/
 * bookmarkable resources.
 * </p>
 * 
 * @author <NAME>
 * @author <NAME>
 */
public class PackageResource extends WebResource
{
	private static final long serialVersionUID = 1L;

	/** log. */
	private static final Log log = LogFactory.getLog(PackageResource.class);

	/**
	 * common extension pattern for javascript files; matches all files with
	 * extension 'js'.
	 */
	public static final Pattern EXTENSION_JS = Pattern.compile(".*\\.js");

	/**
	 * common extension pattern for css files; matches all files with extension
	 * 'css'.
	 */
	public static final Pattern EXTENSION_CSS = Pattern.compile(".*\\.css");

	/** The path to the resource */
	private final String absolutePath;

	/** The resource's locale */
	private Locale locale;

	/** The resource's style */
	private final String style;

	/** The scoping class, used for class loading and to determine the package. */
	private final Class scope;

	/** The path this resource was created with. */
	private final String path;

	/**
	 * Binds a resource to the given application object. Will create the
	 * resource if not already in the shared resources of the application
	 * object.
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param name
	 *            The name of the resource (like &quot;myfile.js&quot;)
	 * @throw IllegalArgumentException when the requested package resource was
	 *        not found
	 */
	public static void bind(Application application, Class scope, String name)
	{
		bind(application, scope, name, null, null);
	}

	/**
	 * Binds a resource to the given application object. Will create the
	 * resource if not already in the shared resources of the application
	 * object.
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param name
	 *            The name of the resource (like &quot;myfile.js&quot;)
	 * @param locale
	 *            The locale of the resource.
	 * @throw IllegalArgumentException when the requested package resource was
	 *        not found
	 */
	public static void bind(Application application, Class scope, String name, Locale locale)
	{
		bind(application, scope, name, locale, null);
	}

	/**
	 * Binds a resource to the given application object. Will create the
	 * resource if not already in the shared resources of the application
	 * object.
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param name
	 *            The name of the resource (like &quot;myfile.js&quot;)
	 * @param locale
	 *            The locale of the resource.
	 * @param style
	 *            The style of the resource.
	 * @throw IllegalArgumentException when the requested package resource was
	 *        not found
	 */
	public static void bind(Application application, Class scope, String name, Locale locale,
			String style)
	{
		if (name == null)
		{
			throw new IllegalArgumentException("argument name may not be null");
		}

		// first check on a direct hit for efficiency
		if (exists(scope, name, locale, style))
		{
			// we have got a hit, so we may safely assume the name
			// argument is not a regular expression, and can thus
			// just add the resource and return
			get(scope, name, locale, style);
		}
		else
		{
			throw new IllegalArgumentException("no package resource was found for scope " + scope
					+ ", name " + name + ", locale " + locale + ", style " + style);
		}
	}

	/**
	 * Binds the resources that match the provided pattern to the given
	 * application object. Will create any resources if not already in the
	 * shared resources of the application object.
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param pattern
	 *            A regular expression to match against the contents of the
	 *            package of the provided scope class (eg &quot;.*\\.js&quot;
	 *            will add all the files with extension &quot;js&quot; from that
	 *            package).
	 * @param recurse
	 *            Whether this method should recurse into sub packages
	 */
	public static void bind(Application application, Class scope, Pattern pattern)
	{
		// bind using the pattern without recursing
		bind(application, scope, pattern, false);
	}

	/**
	 * Binds the resources that match the provided pattern to the given
	 * application object. Will create any resources if not already in the
	 * shared resources of the application object and does that recursively when
	 * the recurse parameter is true, or just for the scoped package if that
	 * parameter is false
	 * 
	 * @param application
	 *            The application to bind to.
	 * @param scope
	 *            The scope of the resource.
	 * @param pattern
	 *            A regular expression to match against the contents of the
	 *            package of the provided scope class (eg &quot;.*\\.js&quot;
	 *            will add all the files with extension &quot;js&quot; from that
	 *            package).
	 * @param recurse
	 *            Whether this method should recurse into sub packages
	 */
	public static void bind(Application application, Class scope, Pattern pattern, boolean recurse)
	{
		// bind using the pattern
		get(scope, pattern, recurse);
	}

	/**
	 * Gets a non-localized resource for a given set of criteria. Only one
	 * resource will be loaded for the same criteria.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the calling class/ the class in which you
	 *            call this method
	 * @param path
	 *            The path to the resource
	 * @return The resource
	 */
	public static PackageResource get(final Class scope, final String path)
	{
		return get(scope, path, null, null);
	}

	/**
	 * Gets the resource for a given set of criteria. Only one resource will be
	 * loaded for the same criteria.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the class in which you call this method
	 * @param path
	 *            The path to the resource
	 * @param locale
	 *            The locale of the resource
	 * @param style
	 *            The style of the resource (see {@link wicket.Session})
	 * @return The resource
	 */
	public static PackageResource get(final Class scope, final String path, final Locale locale,
			final String style)
	{
		final SharedResources sharedResources = Application.get().getSharedResources();
		PackageResource resource = (PackageResource)sharedResources.get(scope, path, locale, style,
				true);
		if (resource == null)
		{
			resource = new PackageResource(scope, path, locale, style);
			sharedResources.add(scope, path, locale, style, resource);
		}
		return resource;
	}

	/**
	 * Gets non-localized resources for a given set of criteria. Multiple
	 * resource can be loaded for the same criteria if they match the pattern.
	 * If no resources were found, this method returns null.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the calling class/ the class in which you
	 *            call this method
	 * @param pattern
	 *            Regexp pattern to match resources
	 * @return The resources, never null but may be empty
	 */
	public static PackageResource[] get(Class scope, Pattern pattern)
	{
		return get(scope, pattern, false);
	}

	/**
	 * Gets non-localized resources for a given set of criteria. Multiple
	 * resource can be loaded for the same criteria if they match the pattern.
	 * If no resources were found, this method returns null.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the calling class/ the class in which you
	 *            call this method
	 * @param pattern
	 *            Regexp pattern to match resources
	 * @param recurse
	 *            Whether this method should recurse into sub packages
	 * @return The resources, never null but may be empty
	 */
	public static PackageResource[] get(Class scope, Pattern pattern, boolean recurse)
	{
		final List resources = new ArrayList();
		String packageRef = Strings.replaceAll(PackageName.forClass(scope).getName(), ".", "/");
		ClassLoader loader = scope.getClassLoader();
		try
		{
			// loop through the resources of the package
			Enumeration packageResources = loader.getResources(packageRef);
			while (packageResources.hasMoreElements())
			{
				URL resource = (URL)packageResources.nextElement();
				URLConnection connection = resource.openConnection();
				if (connection instanceof JarURLConnection)
				{
					JarFile jf = ((JarURLConnection)connection).getJarFile();
					Enumeration enumeration = jf.entries();
					while (enumeration.hasMoreElements())
					{
						JarEntry je = (JarEntry)enumeration.nextElement();
						String name = je.getName();
						if (name.startsWith(packageRef))
						{
							name = name.substring(packageRef.length() + 1);
							if (pattern.matcher(name).matches()
									&& (recurse || (name.indexOf('/') == -1)))
							{
								// we add the entry as a package resource
								resources.add(get(scope, name, null, null));
							}
						}
					}
				}
				else
				{
					String absolutePath = scope.getResource("").getPath();
					File basedir = new File(absolutePath);
					if (!basedir.isDirectory())
					{
						throw new IllegalStateException("unable to read resources from directory "
								+ basedir);
					}
					addResources(scope, pattern, resources, new StringBuffer(""), basedir, recurse);
				}
			}
		}
		catch (IOException e)
		{
			throw new WicketRuntimeException(e);
		}

		return (resources != null) ? (PackageResource[])resources
				.toArray(new PackageResource[resources.size()]) : null;
	}

	/**
	 * Gets whether a resource for a given set of criteria exists.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in.
	 *            Typically this is the class in which you call this method
	 * @param path
	 *            The path to the resource
	 * @param locale
	 *            The locale of the resource
	 * @param style
	 *            The style of the resource (see {@link wicket.Session})
	 * @return true if a resource could be loaded, false otherwise
	 */
	public static boolean exists(final Class scope, final String path, final Locale locale,
			final String style)
	{
		String absolutePath = Packages.absolutePath(scope, path);
		return Application.get().getResourceSettings().getResourceStreamLocator().locate(scope,
				absolutePath, style, locale, null) != null;
	}

	/**
	 * Adds resources recursively.
	 * 
	 * @param scope
	 *            the original scope used to get the base directory
	 * @param pattern
	 *            Regexp pattern to match resources
	 * @param resources
	 *            the current list of resources
	 * @param relativePath
	 *            The relative path that is to be prepended to the resource's
	 *            name
	 * @param dir
	 *            the current directory
	 * @param recurse
	 *            Whether this method should recurse into sub packages
	 */
	private static final void addResources(final Class scope, final Pattern pattern,
			final List resources, final StringBuffer relativePath, final File dir, boolean recurse)
	{
		File[] files = dir.listFiles();
		for (int i = 0; i < files.length; i++)
		{
			File file = files[i];
			if (file.isDirectory())
			{
				if (recurse)
				{
					addResources(scope, pattern, resources, new StringBuffer(relativePath).append(file.getName())
							.append('/'), file, recurse);
				}
			}
			else
			{
				String fileName = file.getName();
				if (pattern.matcher(fileName).matches())
				{
					// we add the entry as a package resource
					resources.add(get(scope, relativePath + fileName, null, null));
				}
			}
		}
	}

	/**
	 * Hidden constructor.
	 * 
	 * @param scope
	 *            This argument will be used to get the class loader for loading
	 *            the package resource, and to determine what package it is in
	 * @param path
	 *            The path to the resource
	 * @param locale
{'fraction_non_alphanumeric': 0.0894690325650962, 'fraction_numerical': 0.004215106397443742, 'mean_word_length': 2.785254760679362, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1885923', 'n_tokens_mistral': 8601, 'n_tokens_neox': 7454, 'n_words': 3240}