public static function writeDelimFile($filepath = null, $rows = array(), $opts = array())
	{
		$debug = \bdk\Debug::getInstance();
		$debug->groupCollapsed(__CLASS__.'->'.__FUNCTION__, $filepath);
		$return	= false;
		if (!is_array($rows)) {
			$rows = array();
		}
		// determine est size
		$est_size = 0;
		$sample_size = ceil(count($rows)/10);
		if ($sample_size > 1) {
			if ($sample_size > 100) {
				$sample_size = 100;
			}
			$rand_keys = array_rand($rows, $sample_size);
			foreach ($rand_keys as $k) {
				$est_size += strlen(implode(',', $rows[$k]));
			}
			$est_size = $est_size * count($rows)/$sample_size;
		}
		$opts = array_merge(array(
			'est_size'	=> $est_size,
			'char'		=> ',',
			'header'	=> true,
		), $opts);
		$fh = self::safeFopen($filepath, $opts);
		if ($fh) {
			$return = true;
			$keys = ArrayUtil::columnKeys($rows);
			if ($opts['header']) {
				$string = implode($opts['char'], $keys)."\n";
				$return = fwrite($fh, $string) !== false;
			}
			foreach ($rows as $row) {
				$values = array();
				foreach ($keys as $key) {
					$values[] = isset($row[$key])
						? $row[$key]
						: '';
				}
				$string = ArrayUtil::implodeDelim($values, $opts['char'])."\n";
				$return = fwrite($fh, $string) !== false;
				if (!$return) {
					break;
				}
			}
			if (!$return) {
				trigger_error('Error writing to '.$filepath, E_USER_ERROR);
			}
			self::safeFclose($fh);
		}
		$debug->groupEnd();
		return $return;
	}