protected function _parseIncludes($includes, $blacklist, $whitelist, Table $repository = null, $path = [])
    {
        $wildcard = implode('.', array_merge($path, ['*']));
        $wildcardWhitelist = Hash::get((array)$whitelist, $wildcard);
        $wildcardBlacklist = Hash::get((array)$blacklist, $wildcard);
        $contains = [];

        foreach ($includes as $include => $nestedIncludes) {
            $nestedContains = [];
            $includePath = array_merge($path, [$include]);
            $includeDotPath = implode('.', $includePath);

            if ($blacklist === true || ($blacklist !== false && ($wildcardBlacklist === true || Hash::get($blacklist, $includeDotPath) === true))) {
                continue;
            }

            if ($whitelist === false || (
                $whitelist !== true &&
                !$wildcardWhitelist &&
                Hash::get($whitelist, $includeDotPath) === null
            )) {
                continue;
            }

            $association = null;

            if ($repository !== null) {
                $association = $this->_getAssociation($repository, $include);
                if ($association === null) {
                    throw new BadRequestException("Invalid relationship path '{$includeDotPath}' supplied in include parameter");
                }
            }

            if (!empty($nestedIncludes)) {
                $nestedContains = $this->_parseIncludes($nestedIncludes, $blacklist, $whitelist, $association ? $association->getTarget() : null, $includePath);
            }

            if (!empty($nestedContains)) {
                if (!empty($association)) {
                    $contains[$association->getAlias()] = $nestedContains;
                }
            } else {
                if (!empty($association)) {
                    $contains[] = $association->getAlias();
                }
            }
        }

        return $contains;
    }