function scoper_object_roles_list($viewing_user, $args = array())
{
    $html = '';
    if (!USER_ROLES_RS && !GROUP_ROLES_RS) {
        wp_die(__awp('Cheatin’ uh?'));
    }
    $defaults = array('enforce_duration_limits' => true, 'is_user_profile' => false, 'echo' => true);
    $args = array_merge($defaults, (array) $args);
    extract($args);
    global $scoper, $wpdb, $current_user;
    if ($viewing_user) {
        if (!is_object($viewing_user)) {
            global $current_rs_user;
            if ($viewing_user == $current_rs_user->ID) {
                $viewing_user = $current_rs_user;
            } else {
                $viewing_user = new WP_Scoped_User($viewing_user);
            }
        }
    }
    $all_roles = array();
    $role_display = array();
    foreach ($scoper->role_defs->get_all_keys() as $role_handle) {
        if ($viewing_user) {
            $role_display[$role_handle] = $scoper->role_defs->get_display_name($role_handle, OBJECT_UI_RS);
        } else {
            $role_display[$role_handle] = $scoper->role_defs->get_abbrev($role_handle, OBJECT_UI_RS);
        }
    }
    if (!$is_user_profile) {
        $require_blogwide_editor = scoper_get_option('role_admin_blogwide_editor_only');
        if ('admin' === $require_blogwide_editor && !is_user_administrator_rs()) {
            return false;
        }
        if ('admin_content' === $require_blogwide_editor && !is_content_administrator_rs()) {
            return false;
        }
    } else {
        $require_blogwide_editor = false;
    }
    foreach ($scoper->data_sources->get_all() as $src_name => $src) {
        $otype_count = 0;
        if (!empty($src->taxonomy_only) || $src_name == 'group' && !$viewing_user) {
            continue;
        }
        $strict_objects = $scoper->get_restrictions(OBJECT_SCOPE_RS, $src_name);
        foreach ($src->object_types as $object_type => $otype) {
            $otype_count++;
            $disable_role_admin = false;
            if ($require_blogwide_editor) {
                if (!$scoper->user_can_edit_blogwide('post', $object_type, array('require_others_cap' => true))) {
                    $disable_role_admin = true;
                }
            }
            if (!empty($src->cols->type) && !empty($otype->name)) {
                $col_type = $src->cols->type;
                $otype_clause = "AND {$src->table}.{$col_type} = '{$otype->name}'";
            } elseif ($otype_count < 2) {
                $otype_clause = '';
            } else {
                continue;
            }
            $col_id = $src->cols->id;
            $col_name = $src->cols->name;
            $ug_clause_for_user_being_viewed = $viewing_user ? $viewing_user->get_user_clause('uro') : '';
            // TODO: replace join with uro subselect
            $qry = "SELECT DISTINCT {$src->table}.{$col_name}, {$src->table}.{$col_id}, uro.role_name, uro.date_limited, uro.start_date_gmt, uro.end_date_gmt" . " FROM {$src->table} ";
            $join = " INNER JOIN {$wpdb->user2role2object_rs} AS uro" . " ON uro.obj_or_term_id = {$src->table}.{$col_id}" . " AND uro.src_or_tx_name = '{$src_name}'" . " AND uro.scope = 'object' AND uro.role_type = 'rs'";
            $duration_clause = $enforce_duration_limits ? scoper_get_duration_clause("{$src->table}.{$src->cols->date}") : '';
            $status_clause = 'post' == $src_name ? "AND post_status != 'auto-draft'" : '';
            // TODO: version update script to delete post roles on auto-drafts (stored via default roles)
            $where = " WHERE 1=1 {$status_clause} {$otype_clause} {$duration_clause} {$ug_clause_for_user_being_viewed}";
            $orderby = " ORDER BY {$src->table}.{$col_name} ASC, uro.role_name ASC";
            $qry .= $join . $where . $orderby;
            $results = scoper_get_results($qry);
            if (!is_user_administrator_rs()) {
                // no need to filter admins - just query the assignments
                // only list role assignments which the logged-in user can administer
                $args['required_operation'] = OP_EDIT_RS;
                // Possible TODO: re-implement OP_ADMIN distinction with admin-specific capabilities
                /*
                if ( cr_get_reqd_caps( $src_name, OP_ADMIN_RS, $object_type ) {
                	$args['required_operation'] = OP_ADMIN_RS;
                } else {
                	$reqd_caps = array();
                	foreach (array_keys($src->statuses) as $status_name) {
                		$admin_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_ADMIN_RS, $status_name);
                		$delete_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_DELETE_RS, $status_name);
                		$reqd_caps[$object_type][$status_name] = array_merge(array_keys($admin_caps), array_keys($delete_caps));
                	}
                	$args['force_reqd_caps'] = $reqd_caps;
                }
                */
                $qry = "SELECT {$src->table}.{$col_id} FROM {$src->table} WHERE 1=1";
                $args['require_full_object_role'] = true;
                $qry_flt = apply_filters('objects_request_rs', $qry, $src_name, $object_type, $args);
                $cu_admin_results = scoper_get_col($qry_flt);
                if (empty($viewing_user) || $current_user->ID != $viewing_user->ID) {
                    foreach ($results as $key => $row) {
                        if (!in_array($row->{$col_id}, $cu_admin_results)) {
                            unset($results[$key]);
                        }
                    }
                } else {
                    // for current user's view of their own user profile, just de-link unadminable objects
                    $link_roles = array();
                    $link_objects = array();
                    if (!$disable_role_admin) {
                        foreach ($results as $key => $row) {
                            if (in_array($row->{$col_id}, $cu_admin_results)) {
                                $link_roles[$row->{$col_id}] = true;
                            }
                        }
                        $args['required_operation'] = OP_EDIT_RS;
                        $args['require_full_object_role'] = false;
                        if (isset($args['force_reqd_caps'])) {
                            unset($args['force_reqd_caps']);
                        }
                        $qry_flt = apply_filters('objects_request_rs', $qry, $src_name, $object_type, $args);
                        $cu_edit_results = scoper_get_col($qry_flt);
                        foreach ($results as $key => $row) {
                            if (in_array($row->{$col_id}, $cu_edit_results)) {
                                $link_objects[$row->{$col_id}] = true;
                            }
                        }
                    }
                }
            }
            $object_roles = array();
            $objnames = array();
            if ($results) {
                $got_object_roles = true;
                foreach ($results as $row) {
                    if (!isset($objnames[$row->{$col_id}])) {
                        if ('post' == $src->name) {
                            $objnames[$row->{$col_id}] = apply_filters('the_title', $row->{$col_name}, $row->{$col_id});
                        } else {
                            $objnames[$row->{$col_id}] = $row->{$col_name};
                        }
                    }
                    $role_handle = 'rs_' . $row->role_name;
                    if ($row->date_limited) {
                        $duration_key = serialize(array('start_date_gmt' => $row->start_date_gmt, 'end_date_gmt' => $row->end_date_gmt));
                    } else {
                        $duration_key = '';
                    }
                    $object_roles[$duration_key][$row->{$col_id}][$role_handle] = true;
                }
            } else {
                continue;
            }
            ?>

		
		<?php 
            $title_roles = __('edit roles', 'scoper');
            foreach (array_keys($object_roles) as $duration_key) {
                $date_caption = '';
                $limit_class = '';
                $limit_style = '';
                $link_class = '';
                if ($duration_key) {
                    $html .= "<h3 style='margin-bottom:0'>{$date_caption}</h3>";
                    $duration_limits = unserialize($duration_key);
                    $duration_limits['date_limited'] = true;
                    ScoperAdminUI::set_agent_formatting($duration_limits, $date_caption, $limit_class, $link_class, $limit_style);
                    $title = "title='{$date_caption}'";
                    $date_caption = '<span class="rs-gray"> ' . trim($date_caption) . '</span>';
                } else {
                    $title = "title='{$title_roles}'";
                }
                if (!$disable_role_admin && (is_user_administrator_rs() || $cu_admin_results)) {
                    //if ( ( $src_name != $object_type ) && ( 'post' != $object_type ) ) {  // menu links currently assume unique object type names
                    //	$roles_page = "rs-roles-{$object_type}_{$src_name}";
                    //} else {
                    $roles_page = "rs-{$object_type}-roles";
                    //}
                    $url = "admin.php?page={$roles_page}";
                    $html .= "<h4><a name='{$object_type}' href='{$url}'><strong>" . sprintf(__('%1$s Roles%2$s:', 'scoper'), $otype->labels->singular_name, '</strong></a><span style="font-weight:normal">' . $date_caption) . "</span></h4>";
                } else {
                    $html .= "<h4><strong>" . sprintf(__('%1$s Roles%2$s:', 'scoper'), $otype->labels->singular_name, $date_caption) . "</strong></h4>";
                }
                $html .= "<ul class='rs-termlist'><li>" . "<table class='widefat'>" . "<thead>" . "<tr class='thead'>" . "\t<th class='rs-tightcol'>" . __('ID') . "</th>" . "\t<th>" . __awp('Name') . "</th>" . "\t<th>" . __('Role Assignments', 'scoper') . "</th>" . "</tr>" . "</thead>";
                $id_clause = isset($role_codes[$role_handle]) ? "id='roles-{$role_codes[$role_handle]}'" : '';
                $html .= "<tbody {$id_clause}>";
                $style = ' class="rs-backwhite"';
                $title_item = sprintf(__('edit %s', 'scoper'), agp_strtolower($otype->labels->singular_name));
                foreach ($object_roles[$duration_key] as $obj_id => $roles) {
                    $object_name = esc_attr($objnames[$obj_id]);
                    $html .= "\n\t<tr{$style}>";
                    $link_this_object = !isset($link_objects) || isset($link_objects[$obj_id]);
                    // link from object ID to the object type's default editor, if defined
                    if ($link_this_object && !empty($src->edit_url)) {
                        $src_edit_url = sprintf($src->edit_url, $obj_id);
                        $html .= "<td><a href='{$src_edit_url}' class='edit' title='{$title_item}'>{$obj_id}</a></td>";
                    } else {
                        $html .= "<td>{$obj_id}</td>";
                    }
                    $name = !empty($objnames[$obj_id]) ? $objnames[$obj_id] : __('(untitled)', 'scoper');
                    // link from object name to our "Edit Object Role Assignment" interface
                    $link_this_role = !isset($link_roles) || isset($link_roles[$obj_id]);
                    if ($link_this_role) {
                        if ('group' == $object_type) {
                            $rs_edit_url = sprintf($src->edit_url, $obj_id);
                        } else {
                            $rs_edit_url = "admin.php?page=rs-object_role_edit&amp;src_name={$src_name}&amp;object_type={$object_type}&amp;object_id={$obj_id}&amp;object_name={$object_name}";
                        }
                        $html .= "\n\t<td><a {$title}{$limit_style}class='{$link_class}{$limit_class}' href='{$rs_edit_url}'>{$name}</a></td>";
                    } else {
                        $html .= "\n\t<td>{$name}</td>";
                    }
                    $html .= "<td>";
                    $role_list = array();
                    foreach (array_keys($roles) as $role_handle) {
                        // roles which require object assignment are asterisked (bolding would contradict the notation of term roles list, where propogating roles are bolded)
                        if (isset($strict_objects['restrictions'][$role_handle][$obj_id]) || isset($strict_objects['unrestrictions'][$role_handle]) && is_array($strict_objects['unrestrictions'][$role_handle]) && !isset($strict_objects['unrestrictions'][$role_handle][$obj_id])) {
                            $role_list[] = "<span class='rs-backylw'>" . $role_display[$role_handle] . '</span>';
                        } else {
                            $role_list[] = $role_display[$role_handle];
                        }
                    }
                    $html .= implode(', ', $role_list);
                    $html .= '</td></tr>';
                    $style = ' class="alternate"' == $style ? ' class="rs-backwhite"' : ' class="alternate"';
                }
                // end foreach object_roles
                $html .= '</tbody></table>';
                $html .= '</li></ul><br />';
            }
            // end foreach role date range
        }
        // end foreach object_types
    }
    // end foreach data source
    if ($echo) {
        echo $html;
    } else {
        return $html;
    }
}