private static function _decodeCrockford($to, $encodedStr, $hasCheckSymbol = false) {
        // Check input string.
        if ($hasCheckSymbol) {
            $pattern = '/[0-9A-TV-Z-]*[0-9A-Z*~$=]-*/i';
        } else {
            $pattern = '/[0-9A-TV-Z-]*/i';
        }
        self::_checkEncodedString($encodedStr, $pattern);

        // Remove hyphens from encoded string.
        $encodedStr = str_replace('-', '', $encodedStr);

        // Get length (byte count) of encoded string.
        $encodedStrLen = self::_byteCount($encodedStr);

        // If the last character is a valid Crockford check symbol, remove it from
        // the encoded string.
        if ($hasCheckSymbol) {
            $checkSymbol = $encodedStr[$encodedStrLen - 1];
            $encodedStr = self::_extractBytes($encodedStr, 0, $encodedStrLen - 1);
            $encodedStrLen--;
        }

        // Compose Crockford decoding mapping.
        $mapping = self::$_crockfordFlippedAlphabet + self::$_crockfordAdditionalCharMapping + array('_' => 0);

        // Get decoded content.
        if ($to == 'byteStr') {
            $decoded = self::_decodeToByteStr($encodedStr, $encodedStrLen, $mapping, '_', true);
        } elseif ($to == 'intStr') {
            $decoded = self::_crockfordDecodeToIntStr($encodedStr, $encodedStrLen, $mapping);
        }

        // If check symbol is present, check if decoded string is correct.
        if ($hasCheckSymbol) {
            if ($to == 'byteStr') {
                $intStr = self::_byteStrToIntStr($decoded);
            } elseif ($to == 'intStr') {
                $intStr = $decoded;
            }
            $modulus = (int) self::_intStrModulus($intStr, 37);
            if ($modulus != $mapping[$checkSymbol]) {
                throw new UnexpectedValueException('Check symbol does not match data.', self::E_CHECKSYMBOL_DOES_NOT_MATCH_DATA);
            }
        }

        // Return byte-string.
        return $decoded;
    }