public DirProject(File dir, ProjectConf conf, final CompilationReport report, CompilationProcess compilProc) {
		if (!dir.isDirectory())
			throw new BugError("Parameter must be a directory here: " + dir.getAbsolutePath());
		this.dir = dir;
		this.conf = conf;
		this.report = report;
		this.compilProc = compilProc;
		this.fIgnore = new File(dir, ".lessnow_ignore");
		// - Start files watcher
		filesWatcher = new FilesWatcher(conf.getScanDelayFilesS());
		filesWatcher.addFilesListener(new FilesWatcherListener() {
			@Override
			public void fileModified(FilesWatcherEvent e) {
				List<LessFileStatus> lst = new ArrayList<LessFileStatus>();
				synchronized (WATCH_LOCK) {
					for (File file : e.getFiles()) {
						String lfsKey = getPathAndBaseName(file);
						LessFileStatus lfs = mapLessFileStatusByBaseName.get(lfsKey);
						if (lfs != null) {
							lst.add(lfs);
							if (lfs.isDeleted())
								mapLessFileStatusByBaseName.remove(lfsKey);
						}
					}
				}
				// - Not synchronized in order to avoid dead locks
				boolean refreshGui = false;
				for (LessFileStatus lfs : lst) {
					if (lfs.isDeleted()) {
						report.remove(lfs);
						filesWatcher.removeFile(lfs.getFrom());
						filesWatcher.removeFile(lfs.getTo());
					} else if (!lfs.isUpToDate()) {
						refreshGui = true;
						compile(lfs);
					}
				}
				if (refreshGui)
					report.refreshAll();
			}
		});
		// - Scan files
		initIgnored();
		scanProjectLessFiles();
		// - Directory watcher
		scanDirTimer = new Timer();
		scanDirTimer.schedule(new TimerTask() {
			@Override
			public void run() {
				scanProjectLessFiles();
			}
		}, 10000, conf.getScanDelayDirS() * 1000);
	}