public Ticket unmarshal(String input) throws InvalidTicketException {
        List<String> parts = split(input, separator);
        if (parts.isEmpty()) {
            throw new InvalidTicketException("Ticket string does not end with MAC (looks empty)");
        }
        String macPart = parts.get(parts.size() - 1);
        if (!macPart.startsWith("x")) {
            throw new InvalidTicketException("Ticket string does not end with MAC");
        }
        String theirMac = macPart.substring(1);
        String ourMac;
        if (parts.size() == 1) {
            ourMac = macGenerator.generateMAC("");
        } else {
            String payload = input.substring(0, input.length() - macPart.length() - 1);
            ourMac = macGenerator.generateMAC(payload);
        }
        if (!ourMac.equals(theirMac)) {
            throw new TicketMacMismatchException(ourMac, theirMac);
        }
        Ticket ticket = new Ticket();
        for (String part : parts) {
            if (part.isEmpty()) {
                continue;
            }
            char key = part.charAt(0);
            if (key == 'x') {
                continue;
            }
            String value = decodeValue(part.substring(1));
            ticket.add(key, value);
        }
        return ticket;
    }