```go
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var n int
fmt.Fscan(reader, &n)
reader.ReadString('\n')
type CatchInfo struct {
exType string
message string
line int
}
// We need to parse the program and figure out try-catch block structure
// and the throw operator.
// Strategy:
// 1. First pass: parse all lines, identify try, catch, throw operators
// 2. Match try-catch blocks using a stack
// 3. Find which try-catch blocks contain the throw (try before throw, catch after throw)
// 4. Among those with matching exception type, pick the one with earliest catch
type Op struct {
kind string // "try", "catch", "throw"
line int
exType string
message string
}
ops := make([]Op, 0)
for i := 0; i < n; i++ {
line, _ := reader.ReadString('\n')
line = strings.TrimRight(line, "\r\n")
trimmed := strings.TrimSpace(line)
if trimmed == "" {
continue
}
if trimmed == "try" {
ops = append(ops, Op{kind: "try", line: i})
} else if strings.HasPrefix(trimmed, "catch") {
// parse catch(<exception_type>, <message>)
// Remove "catch" prefix
rest := strings.TrimSpace(trimmed[5:])
// rest starts with '('
// Find the content between ( and )
// There might be spaces around parens
rest = strings.TrimSpace(rest)
if rest[0] == '(' {
rest = rest[1:]
}
// remove trailing ')'
if rest[len(rest)-1] == ')' {
rest = rest[:len(rest)-1]
}
// Now split by comma - but message is in quotes and could contain commas?
// Actually message consists of letters, digits and spaces. No commas.
// So split by first comma
commaIdx := strings.Index(rest, ",")
exType := strings.TrimSpace(rest[:commaIdx])
msgPart := strings.TrimSpace(rest[commaIdx+1:])
// msgPart is surrounded by quote marks (with possible spaces)
msgPart = strings.TrimSpace(msgPart)
// Remove surrounding quotes
if msgPart[0] == '"' {
msgPart = msgPart[1:]
}
if msgPart[len(msgPart)-1] == '"' {
msgPart = msgPart[:len(msgPart)-1]
}
ops = append(ops, Op{kind: "catch", line: i, exType: exType, message: msgPart})
} else if strings.HasPrefix(trimmed, "throw") {
rest := strings.TrimSpace(trimmed[5:])
rest = strings.TrimSpace(rest)
if rest[0] == '(' {
rest = rest[1:]
}
if rest[len(rest)-1] == ')' {
rest = rest[:len(rest)-1]
}
exType := strings.TrimSpace(rest)
ops = append(ops, Op{kind: "throw", line: i, exType: exType})
}
}
// Match try-catch blocks
type Block struct {
tryLine int
catchLine int
exType string
message string
}
var blocks []Block
var stack []int // stack of try line numbers
for _, op := range ops {
if op.kind == "try" {
stack = append(stack, op.line)
} else if op.kind == "catch" {
tryLine := stack[len(stack)-1]
stack = stack[:len(stack)-1]
blocks = append(blocks, Block{tryLine: tryLine, catchLine: op.line, exType: op.exType, message: op.message})
}
}
// Find throw
var throwLine int
var throwType string
for _, op := range ops {
if op.kind == "throw" {
throwLine = op.line
throwType = op.exType
break
}
}
// Find candidate blocks: tryLine < throwLine, catchLine > throwLine, exType == throwType
// Among those, pick the one with smallest catchLine
bestCatch := -1
bestMessage := ""
for _, b := range blocks {
if b.tryLine < throwLine && b.catchLine > throwLine && b.exType == throwType {
if bestCatch == -1 || b.catchLine < bestCatch {
bestCatch = b.catchLine
bestMessage = b.message
}
}
}
if bestCatch == -1 {
fmt.Println("Unhandled Exception")
} else {
fmt.Println(bestMessage)
}
}
```