// check that this is a valid property to change for this wizard
    if (!isset($account_data['wizard'])) {
        throw new Exception("No wizard data found");
    }
    $wizard_type = get_wizard_account_type($account_data['wizard']);
    if (!isset($wizard_type['display_editable'][$key])) {
        throw new Exception("Key '" . htmlspecialchars($key) . "' is not a valid editable key");
    }
    // check that this is a valid input for this key
    $config = get_accounts_wizard_config($exchange);
    if (!isset($config['inputs'][$key])) {
        throw new Exception("A '" . htmlspecialchars($exchange) . "' does not have an input '" . htmlspecialchars($key) . "'");
    }
    if (isset($config['inputs'][$key]['number']) && $config['inputs'][$key]['number']) {
        // remove any commas
        $value = number_unformat($value);
    }
    $callback = $config['inputs'][$key]['callback'];
    if (!$callback($value)) {
        $errors[] = t("':value' is not a valid :title :label.", array(':value' => htmlspecialchars($value), ':title' => htmlspecialchars($account_data['title']), ':label' => htmlspecialchars($config['inputs'][$key]['title'])));
    } else {
        $q = db()->prepare("UPDATE " . $account_data['table'] . " SET " . $config['inputs'][$key]['key'] . "=? WHERE user_id=? AND id=?");
        $q->execute(array($value, user_id(), $id));
        $messages[] = t("Updated :title :label.", array(':title' => htmlspecialchars($account_data['title']), ':label' => htmlspecialchars($config['inputs'][$key]['inline_title'])));
        // redirect to GET
        set_temporary_messages($messages);
        redirect(url_for(require_post("callback")));
    }
}
// process add
if (require_post("add", false)) {
            $q->execute(array('summary_type' => $summary_type));
            $type_id = db()->lastInsertId();
        } else {
            $q = db()->prepare("UPDATE notifications_summary_instances SET summary_type=:summary_type WHERE id=:id");
            $q->execute(array('summary_type' => $summary_type, 'id' => $type_id));
        }
        break;
    default:
        throw new Exception("Unknown new notification type '" . htmlspecialchars($notification_type) . "'");
}
$permitted_notification_periods = get_permitted_notification_periods();
if (!isset($permitted_notification_periods[require_post("period")])) {
    throw new Exception("Invalid notification period '" . htmlspecialchars(require_post("period")) . "'");
}
// remove any commas
$value = number_unformat(require_post("value"));
if (!is_numeric($value)) {
    throw new Exception("'" . htmlspecialchars($value) . "' is not numeric");
}
$args = array("user_id" => user_id(), "type_id" => $type_id, "trigger_condition" => require_post("condition"), "trigger_value" => $value, "is_percent" => require_post("percent", 0) ? 1 : 0, "period" => require_post("period"), "notification_type" => $notification_type);
if (require_post("id", false)) {
    // update existing
    // need to also reset last_value and is_notified so that we don't accidentally send notifications for an old currency
    $q = db()->prepare("UPDATE notifications SET notification_type=:notification_type, trigger_condition=:trigger_condition, trigger_value=:trigger_value, is_percent=:is_percent, period=:period, type_id=:type_id, is_notified=0, last_value=NULL, last_notification=NULL WHERE id=:id AND user_id=:user_id");
    $args += array('id' => $instance['id']);
    $q->execute($args);
    $messages[] = t("Updated existing notification.");
} else {
    // create new
    $q = db()->prepare("INSERT INTO notifications SET notification_type=:notification_type, trigger_condition=:trigger_condition, trigger_value=:trigger_value, is_percent=:is_percent, period=:period, type_id=:type_id, is_notified=0, user_id=:user_id");
    $q->execute($args);