public void Compile(CompilerOptions opt)
        {
            if (!File.Exists(opt.Path) && !Directory.Exists(opt.Path))
            {
                throw new SourceNotFoundException(opt.Path);
            }

            if(! opt.OutputDir.IsNullOrWhiteSpace() && !opt.OutputDir.AsDirectory().Exists)
            {
                throw new TargetNotFoundException(opt.OutputDir);
            }

            IEnumerable<string> toCompile;
            if (!Directory.Exists(opt.Path) && File.Exists(opt.Path))
                toCompile = new[] { opt.Path };
            else
                toCompile = Glob(opt.Path, "*.coffee");

            if (opt.Compile)
            {
                CompileMany(toCompile, opt);
            }

            if (opt.Watch)
            {
                StartWatching(opt);
            }

            return;
        }
        private static void CompileMany(IEnumerable<string> toCompile, CompilerOptions opt)
        {
            foreach (var sourcePath in toCompile)
            {
                string result = Compile(sourcePath, opt);

                if (opt.Print)
                    Console.WriteLine(result);
                else
                {
                    string dest;
                    dest = opt.OutputDir.IsNullOrWhiteSpace() ?
                                        sourcePath
                                        : sourcePath.Replace(opt.Path, opt.OutputDir);

                    dest = Path.ChangeExtension(dest, ".js");
                    var destDir = new FileInfo(dest).Directory;
                    if(!destDir.Exists)
                    {
                        destDir.Create();
                    }

                    File.WriteAllText(dest, result, Encoding.UTF8);
                }
            }
        }
        private static string Compile(string sourcePath, CompilerOptions opt)
        {
            //ugly hack. When triggered by the filesystemwatcher (--watch mode), the file may be transiently locked
            //by another process, and the call to Read would throw. Trying to monitor this in procmon I found at least
            //three background processes happily opening the file. We should poll and check locking beforehand, but this
            //will do for now. Wow, that's a big comment/code ratio.
            Thread.Sleep(100);

            var source = File.ReadAllText(sourcePath, Encoding.UTF8);
            string result = "";
            try
            {
                result = CoffeeScriptProcessor.Process(source, opt.Bare);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error while compiling " + sourcePath + " :");
                Console.WriteLine(ex.Message);
            }
            return result;
        }
        static void Main(string[] args)
        {
            var opt = new CompilerOptions();

            var p = new OptionSet()
                .Add("c|compile", "compile to JavaScript and save as .js files", _ => opt.Compile = true)
                .Add("o=|output=","set the directory for compiled JavaScript", d => opt.OutputDir = d )
                .Add("w|watch","watch scripts for changes, and recompile", d => opt.Watch = true )
                .Add("p|print", "print the compiled JavaScript to stdout", _ => opt.Print = true)
                .Add("b|bare", "compile without the top-level function wrapper", _ => opt.Bare = true)
                .Add("v|version", "display coffeescript version", _ => DisplayVersion())
                .Add("h|help", "display this help message", _ => opt.Help = true);

            if (args.Length == 0)
            {
                DisplayHelp(p);
            }

               if (opt.Help)
              DisplayHelp(p);

            try
            {
                opt.Path = p.Parse(args).First();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error parsing arguments: " + ex.Message);
                DisplayHelp(p);
            }

            new Compiler().Compile(opt);

            if(opt.Watch)
            {
                Console.WriteLine("Press enter to quit");
                Console.ReadLine();
                Environment.Exit(0);
            }
        }
        public ChangeWatcher(string path, CompilerOptions options, Action<string,CompilerOptions> action)
        {
            //Filesystemwatcher watches..directories. So if the path is a file we watch the file dir
            var isDirectory = (File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory;
            var subDirs = isDirectory;

            string toWatch = path;
            string filter = "*.coffee";

            if (!isDirectory)
            {
                var info = new FileInfo(path);
                toWatch = info.DirectoryName;
                filter = info.Name;
            }

            watcher = new FileSystemWatcher(toWatch, filter) { IncludeSubdirectories = subDirs };
            this.action = action;
            this.options = options;
            watcher.NotifyFilter = NotifyFilters.LastWrite;
            watcher.Changed += OnChanged;
        }
        private static void StartWatching(CompilerOptions opt)
        {
            Console.WriteLine("watching:" + opt.Path);
            var watcher = new ChangeWatcher(opt.Path, opt,
                                (path, options) =>
                                {
                                    Console.WriteLine(DateTime.Now + ":" + path + " has changed.");
                                    CompileMany(new[] { path }, options);
                                    Console.WriteLine(DateTime.Now + ":" + path + " recompiled");
                                });

            watcher.Start();
        }