public static function join(array $paths, $above = true, $join = true) {
        $clean = array();
        $parts = array();
        $ds = static::SEPARATOR;
        $up = 0;

        // First pass expands sub-paths
        foreach ($paths as $path) {
            if (!is_string($path)) {
                throw new InvalidTypeException('Path parts must be strings');
            }

            $path = trim(static::ds($path), $ds);

            if (strpos($path, $ds) !== false) {
                $clean = array_merge($clean, explode($ds, $path));
            } else {
                $clean[] = $path;
            }
        }

        // Second pass flattens dot paths
        foreach (array_reverse($clean) as $path) {
            if ($path === '.' || !$path) {
                continue;

            } else if ($path === '..') {
                $up++;

            } else if ($up) {
                $up--;

            } else {
                $parts[] = $path;
            }
        }

        // Append double dots above root
        if ($above) {
            while ($up) {
                $parts[] = '..';
                $up--;
            }
        }

        $parts = array_reverse($parts);

        if ($join) {
            return implode($parts, $ds);
        }

        return $parts;
    }