<commit_before>using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using IO.Interfaces.Extensions;
using IO.Interfaces.Implementations;

namespace IO.Interfaces {

	/// <summary>Represents a directory.  Any class that has a public string Path property can be an IDirectory</summary>
	/// <remarks>Why?  So you can use the IDirectoryExtensions with your IDirectory class to Copy(), Move(), Delete(), etc the Directory.</remarks>
	public interface IDirectory {
		string Path { get; set; }
	}

	/// <summary>The actual methods for an IDirectory</summary>
	public static class IDirectoryExtensions {

		/// <summary>returns the IDirectory.Path, if it exists, else null</summary>
		public static string Path(this IDirectory dir) {
			return (dir == null) ? null : dir.Path;
		}

		public static bool   Exists(this IDirectory dir)       { return Directory.Exists(dir.Path); }
		public static bool   DoesNotExist(this IDirectory dir) { return ! dir.Exists(); }
		public static string Name(this IDirectory dir)         { return System.IO.Path.GetFileName(dir.Path); }
		public static void   Delete(this IDirectory dir)       { Directory.Delete(dir.Path, true); }
		public static string FullPath(this IDirectory dir)     { return System.IO.Path.GetFullPath(dir.Path); }

		/// <summary>Creates this directory (if it doesn't exist)</summary>
		public static IDirectory Create(this IDirectory dir) {
			if (! dir.Exists())
				Directory.CreateDirectory(dir.Path);
			return dir;
		}

		/// <summary>
		/// Returns an IFile with the specified path relative to this IDirectory's Path. 
		/// It might not exist, but we don't return null!
		/// </summary>
		public static IFile GetFile(this IDirectory dir, string path) {
			return new RealFile(System.IO.Path.Combine(dir.Path, path));
		}

		/// <summary>
		/// Returns an IDirectory with the specified path relative to this IDirectory's Path. 
		/// It might not exist, but we don't return null!
		/// </summary>
		public static IDirectory GetDirectory(this IDirectory dir, string path) {
			return new RealDirectory(System.IO.Path.Combine(dir.Path, path));
		}

		/// <summary>Shortcut to GetDirectory</summary>
		public static IDirectory GetDir(this IDirectory dir, string path){ return dir.GetDirectory(path); }

		public static IDirectory Copy(this IDirectory dir, params string[] destinationParts) {
			var destination = destinationParts.Combine();
			if (Directory.Exists(destination))
				dir.CopyToExactPath(System.IO.Path.Combine(destination, dir.Name()));
			else
				dir.CopyToExactPath(destination);
			return dir;
		}

		public static string Relative(this IDirectory dir, string path) {
			var fullPath    = path.AsFile().FullPath();
			var fullDirPath = dir.FullPath();

			var index = fullPath.IndexOf(fullDirPath);
			if (index < 0)
				return null; // this path is NOT relative to this directory.
			else
				return fullPath.Substring(index + fullDirPath.Length);
		}

		public static string Relative(this IDirectory dir, IFile file) {
			return dir.Relative(file.Path);
		}

		public static IDirectory CopyToExactPath(this IDirectory dir, string exactPath) {
			Directory.CreateDirectory(exactPath);
			dir.Dirs().ForEach(fullDir => Directory.CreateDirectory(System.IO.Path.Combine(exactPath, dir.Relative(fullDir.Path).TrimStart('/'))));<commit_msg>Updated Relative() to support generating paths like ..\..\foo<commit_after>using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using IO.Interfaces.Extensions;
using IO.Interfaces.Implementations;

namespace IO.Interfaces {

	/// <summary>Represents a directory.  Any class that has a public string Path property can be an IDirectory</summary>
	/// <remarks>Why?  So you can use the IDirectoryExtensions with your IDirectory class to Copy(), Move(), Delete(), etc the Directory.</remarks>
	public interface IDirectory {
		string Path { get; set; }
	}

	/// <summary>The actual methods for an IDirectory</summary>
	public static class IDirectoryExtensions {

		/// <summary>returns the IDirectory.Path, if it exists, else null</summary>
		public static string Path(this IDirectory dir) {
			return (dir == null) ? null : dir.Path;
		}

		public static bool   Exists(this IDirectory dir)       { return Directory.Exists(dir.Path); }
		public static bool   DoesNotExist(this IDirectory dir) { return ! dir.Exists(); }
		public static string Name(this IDirectory dir)         { return System.IO.Path.GetFileName(dir.Path); }
		public static void   Delete(this IDirectory dir)       { Directory.Delete(dir.Path, true); }
		public static string FullPath(this IDirectory dir)     { return System.IO.Path.GetFullPath(dir.Path); }

		/// <summary>Creates this directory (if it doesn't exist)</summary>
		public static IDirectory Create(this IDirectory dir) {
			if (! dir.Exists())
				Directory.CreateDirectory(dir.Path);
			return dir;
		}

		/// <summary>
		/// Returns an IFile with the specified path relative to this IDirectory's Path. 
		/// It might not exist, but we don't return null!
		/// </summary>
		public static IFile GetFile(this IDirectory dir, string path) {
			return new RealFile(System.IO.Path.Combine(dir.Path, path));
		}

		/// <summary>
		/// Returns an IDirectory with the specified path relative to this IDirectory's Path. 
		/// It might not exist, but we don't return null!
		/// </summary>
		public static IDirectory GetDirectory(this IDirectory dir, string path) {
			return new RealDirectory(System.IO.Path.Combine(dir.Path, path));
		}

		/// <summary>Shortcut to GetDirectory</summary>
		public static IDirectory GetDir(this IDirectory dir, string path){ return dir.GetDirectory(path); }

		public static IDirectory Copy(this IDirectory dir, params string[] destinationParts) {
			var destination = destinationParts.Combine();
			if (Directory.Exists(destination))
				dir.CopyToExactPath(System.IO.Path.Combine(destination, dir.Name()));
			else
				dir.CopyToExactPath(destination);
			return dir;
		}

		public static string Relative(this IDirectory dir, string path) {
			var fullPath    = path.AsFile().FullPath();
			var fullDirPath = dir.FullPath();

			var index = fullPath.IndexOf(fullDirPath);
			if (index >= 0) 
				return fullPath.Substring(index + fullDirPath.Length);

			// This is ugly!  :(
			var dirsUp  = 1;
			var baseDir = System.IO.Path.GetDirectoryName(dir.Path);
			while (baseDir != null) {
				if (path.Contains(baseDir)) {
					var dots = "";
					for (int i = 0; i < dirsUp; i++)
						dots = ".." + System.IO.Path.DirectorySeparatorChar.ToString() + dots;
					return dots + baseDir.AsDir().Relative(path).TrimStart(System.IO.Path.DirectorySeparatorChar);
				}
				dirsUp++;
				baseDir = System.IO.Path.GetDirectoryName(baseDir);
			}

			// Didn't find a common path ... not relative?
			return null;
		}

		public static string Relative(this IDirectory dir, IFile file) {
			return dir.Relative(file.Path);
		}

		public static IDirectory CopyToExactPath(this IDirectory dir, string exactPath) {
			Directory.CreateDirectory(exactPath);
			dir.Dirs().ForEach(fullDir => Directory.CreateDirectory(System.IO.Path.Combine(exactPath, dir.Relative(fullDir.Path).TrimStart('/'))));
{'fraction_non_alphanumeric': 0.11497252747252747, 'fraction_numerical': 0.0005494505494505495, 'mean_word_length': 3.8604806408544725, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '2049697', 'n_tokens_mistral': 2400, 'n_tokens_neox': 2072, 'n_words': 642}