create or replace function dump_signon_response
return clob
as
    k varchar2(32767);
    v apex_json.t_value;
    t apex_json.t_kind;
    res clob := '';
begin
    k := apex_json.g_values.first;
    while k is not null loop
        v := apex_json.get_value(k);
        res := res || k || ' = ';
        case v.kind
        when apex_json.c_null then
            res := res || '(NULL)';
        when apex_json.c_true then
            res := res || '(TRUE)';
        when apex_json.c_false then
            res := res || '(FALSE)';
        when apex_json.c_number then
            res := res || to_char(v.number_value);
        when apex_json.c_varchar2 then
            res := res || v.varchar2_value;
        when apex_json.c_object then
            res := res || '(OBJECT[' || apex_string.join(v.object_members, ':') || '])';
        when apex_json.c_array then
            res := res || '(ARRAY[' || to_number(v.number_value) || '])';
        when apex_json.c_clob then
            res := res || v.clob_value;
        else
            res := res || '(OTHER)';
        end case;
        res := res || apex_application.LF;
        k := apex_json.g_values.next(k);
    end loop;
    return res;
end dump_signon_response;