/* 
    动态规划
 */
package main

import (
	"fmt"
	"strings"
)

// 判断字符是否为数字或字母
func isNumOrChar(b byte) bool {
	return (b >= '0' && b <= '9') ||
		(b >= 'a' && b <= 'z') ||
		(b >= 'A' && b <= 'Z')
}

// 不区分大小写的字符比较
func equalIgnoreCase(a, b byte) bool {
	return strings.ToLower(string(a)) == strings.ToLower(string(b))
}

// 检查通配符 s 是否匹配目标字符串 p
func check(s, p string) bool {
	m, n := len(s), len(p)
	
	// dp[i][j] 表示 s[:i] 是否匹配 p[:j]
	dp := make([][]bool, m+1)
	for i := range dp {
		dp[i] = make([]bool, n+1)
	}
	
	// 空模式匹配空字符串
	dp[0][0] = true
	
	// 处理 s 开头的 '*' 可以匹配空字符串
	for i := 1; i <= m; i++ {
		if s[i-1] == '*' {
			dp[i][0] = dp[i-1][0]
		} else {
			break // '*' 连续才有意义
		}
	}
	
	// 填充 DP 表
	for i := 1; i <= m; i++ {
		for j := 0; j <= n; j++ {
			if s[i-1] == '*' {
				// '*' 匹配 0 个:dp[i-1][j]
				// '*' 匹配多个:dp[i][j-1](如果 j>0)
				dp[i][j] = dp[i-1][j]
				if j > 0 {
					dp[i][j] = dp[i][j] || dp[i][j-1]
				}
			} else if s[i-1] == '?' {
				// '?' 必须匹配一个数字或字母
				if j > 0 && isNumOrChar(p[j-1]) {
					dp[i][j] = dp[i-1][j-1]
				}
			} else {
				// 普通字符
				if j > 0 {
					if isNumOrChar(s[i-1]) {
						// 字母:不区分大小写匹配
						dp[i][j] = dp[i-1][j-1] && equalIgnoreCase(s[i-1], p[j-1])
					} else {
						// 其他字符:精确匹配
						dp[i][j] = dp[i-1][j-1] && (s[i-1] == p[j-1])
					}
				}
			}
		}
	}
	
	return dp[m][n]
}

func main() {
	var s, p string
	fmt.Scanf("%s", &s)
	fmt.Scanf("%s", &p)
	
	// 注意:我们不提前转小写,因为在 equalIgnoreCase 中处理
	result := check(s, p)
	if result {
		fmt.Println("true")
	} else {
		fmt.Println("false")
	}
}