diff --git a/rbxmlexport/RB_XMLExport.egg-info/PKG-INFO b/rbxmlexport/RB_XMLExport.egg-info/PKG-INFO
new file mode 100644
index 0000000000000000000000000000000000000000..04d4645e1a273d54be1233a79dc3f18d604bd82e
--- /dev/null
+++ b/rbxmlexport/RB_XMLExport.egg-info/PKG-INFO
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: RB-XMLExport
+Version: 0.1
+Summary: XML Export of Review Files
+Home-page: UNKNOWN
+Author: Kahlil Amlani
+Author-email: UNKNOWN
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
diff --git a/rbxmlexport/RB_XMLExport.egg-info/SOURCES.txt b/rbxmlexport/RB_XMLExport.egg-info/SOURCES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e698f66de238a2f814016a884a5604cca4d506b8
--- /dev/null
+++ b/rbxmlexport/RB_XMLExport.egg-info/SOURCES.txt
@@ -0,0 +1,12 @@
+setup.py
+RB_XMLExport.egg-info/PKG-INFO
+RB_XMLExport.egg-info/SOURCES.txt
+RB_XMLExport.egg-info/dependency_links.txt
+RB_XMLExport.egg-info/entry_points.txt
+RB_XMLExport.egg-info/top_level.txt
+rbxmlexport/__init__.py
+rbxmlexport/admin_urls.py
+rbxmlexport/extension.py
+rbxmlexport/tests.py
+rbxmlexport/urls.py
+rbxmlexport/views.py
\ No newline at end of file
diff --git a/rbxmlexport/RB_XMLExport.egg-info/dependency_links.txt b/rbxmlexport/RB_XMLExport.egg-info/dependency_links.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/rbxmlexport/RB_XMLExport.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/rbxmlexport/RB_XMLExport.egg-info/entry_points.txt b/rbxmlexport/RB_XMLExport.egg-info/entry_points.txt
new file mode 100644
index 0000000000000000000000000000000000000000..84b8333ff162004a7475e2004b2d7abd40a6d0ff
--- /dev/null
+++ b/rbxmlexport/RB_XMLExport.egg-info/entry_points.txt
@@ -0,0 +1,3 @@
+[reviewboard.extensions]
+RB-XMLExport = rbxmlexport.extension:RBXMLExport
+
diff --git a/rbxmlexport/RB_XMLExport.egg-info/top_level.txt b/rbxmlexport/RB_XMLExport.egg-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..34acd6feb8140bf9ee8e0a9a08522658bf443598
--- /dev/null
+++ b/rbxmlexport/RB_XMLExport.egg-info/top_level.txt
@@ -0,0 +1 @@
+rbxmlexport
diff --git a/rbxmlexport/rbxmlexport/__init__.pyc b/rbxmlexport/rbxmlexport/__init__.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1ec940f93cb83b10f1ab3dbd0516e5acae711d76
diff --git a/rbxmlexport/rbxmlexport/admin_urls.py b/rbxmlexport/rbxmlexport/admin_urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..4606b13426b19fa60a1a319cc37cc47d205d7762
--- /dev/null
+++ b/rbxmlexport/rbxmlexport/admin_urls.py
@@ -0,0 +1,6 @@
+from django.conf.urls.defaults import patterns, include
+
+
+urlpatterns = patterns('',
+    (r'^$', 'rbreports.views.configure')
+)
diff --git a/rbxmlexport/rbxmlexport/admin_urls.pyc b/rbxmlexport/rbxmlexport/admin_urls.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ea4956a63ca128c59dfbd1b214ad0151e11c35cc
diff --git a/rbxmlexport/rbxmlexport/extension.py b/rbxmlexport/rbxmlexport/extension.py
new file mode 100644
index 0000000000000000000000000000000000000000..d167ec01d8ad48b9379aa80175127bf9341055d9
--- /dev/null
+++ b/rbxmlexport/rbxmlexport/extension.py
@@ -0,0 +1,17 @@
+# Reports extension for Review Board.
+from reviewboard.extensions.base import Extension
+from reviewboard.extensions.hooks import ReviewRequestActionHook
+from rbxmlexport.resources import reviewing_session_resource
+
+
+class RBXMLExportActionHook(ReviewRequestActionHook):
+    def get_action_info(self, context):
+       return {'label':'XML Export', 'uri':'templates/rbxmlexport/test.txt'}
+
+class RBXMLExport(Extension):
+    is_configurable = True
+    resources = [reviewing_session_resource]
+    def __init__(self):
+        Extension.__init__(self)
+        self.rr_action_hook = RBXMLExportActionHook(self)
+
diff --git a/rbxmlexport/rbxmlexport/extension.pyc b/rbxmlexport/rbxmlexport/extension.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..685e4a1e3726723126406d6408950aca2d76803f
diff --git a/rbxmlexport/rbxmlexport/resources.py b/rbxmlexport/rbxmlexport/resources.py
new file mode 100644
index 0000000000000000000000000000000000000000..ebeb3bdd0f66cfad298e00b681f69370b48638fc
--- /dev/null
+++ b/rbxmlexport/rbxmlexport/resources.py
@@ -0,0 +1,330 @@
+from reviewboard.reviews.views import get_file_chunks_in_range
+from djblets.webapi.core import NameArray
+from django.template.context import RequestContext
+from reviewboard.reviews.models import ReviewRequest
+from reviewboard.webapi.resources import review_request_resource
+from django.conf import settings
+from django.contrib.sites.models import Site
+from reviewboard.webapi.resources import WebAPIResource
+
+class ReviewRequestResource(WebAPIResource):
+    model = ReviewRequest
+    name = 'review-request'
+    plural_name = 'review-requests'
+    allowed_methods = ('GET')
+    uri_object_key = 'id'
+    fields = ('id')
+
+    def get(self, request, *args, **kwargs):
+        my_review_request = self.get_object(request, *args, **kwargs)
+
+        review_request_xml = [] #Review-Request xml info
+        if my_review_request.submitter.username:
+            review_request_xml.append(NameArray(
+                "user",
+                None,
+                [my_review_request.submitter.username]))
+        if my_review_request.summary:
+            review_request_xml.append(NameArray(
+                "summary",
+                None,
+                [my_review_request.summary]))
+        if my_review_request.description:
+            review_request_xml.append(NameArray(
+                "description",
+                None,
+                [my_review_request.description]))
+        if my_review_request.testing_done:
+            review_request_xml.append(NameArray(
+                "testing",
+                None,
+                [my_review_request.testing_done]))
+        if my_review_request.changenum:
+            review_request_xml.append(NameArray(
+                "changenum",
+                None,
+                [my_review_request.changenum]))
+        if my_review_request.bugs_closed:
+            review_request_xml.append(NameArray(
+                "bugs",
+                None,
+                [my_review_request.bugs_closed]))
+        if my_review_request.branch:
+            review_request_xml.append(NameArray(
+                "branch",
+                None,
+                [my_review_request.branch]))
+
+        people_array = []
+        for person in my_review_request.target_people.all():
+            people_array.append(NameArray(
+                "user",
+                None,
+                [person.username]))
+        if len(people_array):
+            review_request_xml.append(NameArray(
+                "people",
+                None,
+                people_array))
+
+        group_array = []
+        for group in my_review_request.target_groups.all():
+            people_array.append(NameArray(
+                "user",
+                None,
+                [group.display_name]))
+
+        if len(group_array):
+            review_request_xml.append(NameArray(
+                "group",
+                None,
+                group_array))
+
+        review_xml = []
+        for review in my_review_request.get_public_reviews():
+            current_review = self.build_review(request,review)
+            if current_review: review_xml.append(current_review)
+
+        return 200, {
+            self.item_result_key: {
+                            'request': NameArray(None,None,review_request_xml),
+                            'reviews ': NameArray(None,"review",review_xml),
+                            }
+                    }
+
+    def get_object(self, request, local_site_name=None, *args, **kwargs):
+        review_request_id = kwargs.get('id')
+        return review_request_resource.get_object(
+                request,
+                review_request_id,
+                local_site_name,
+                *args,
+                **kwargs)
+
+    # Builds the entire review, calls build_bodytop(self, review)
+    # build_body_top_screenshot(self, review) and
+    # build_body_top_diffs(self, request, review)
+    def build_review(self, request, review):
+        review_array = []
+
+        review_array.append(NameArray(
+            "user",
+            None,
+            [review.user.username]))
+
+        # Handle body_top reviews
+        body_top = self.build_body_top(review) # adds body_top text review part
+        if body_top is not None:
+            review_array.append(body_top)
+
+        # Handle screenshots and diffs
+        body_code_screenshot = []
+        body_code = self.build_diffs(request, review)
+        body_screenshot = self.build_screenshots(review)
+
+        if body_code is not None:
+            body_code_screenshot.extend(body_code)
+        if body_screenshot is not None:
+            body_code_screenshot.extend(body_screenshot)
+
+        if len(body_code_screenshot):
+            review_array.append(NameArray(
+                "comments",
+                None,
+                body_code_screenshot))
+
+        # Return review in a NameArray
+        if len(review_array):
+            return NameArray(
+                None,
+                None,
+                review_array)
+
+        return None
+
+    # Adds part of a review that contain just the body_top text
+    # along with the associated replies
+    def build_body_top(self, review):
+
+        text_review_array = []
+        if review.body_top is not u'':
+            if review.body_top == "Ship It!":
+                return(NameArray(
+                    "ship-it",
+                    None,
+                    ["1"]))
+            else:
+                text_review_array.append(NameArray(
+                    None,
+                    "text",
+                    [review.body_top]))
+
+        review_replies = []
+        for reply in review.public_replies():
+            single_reply = []
+            if reply.body_top is not u'':
+                single_reply.append(NameArray(
+                    None,
+                    "user",
+                    [reply.user.username]))
+                single_reply.append(NameArray(
+                    None,
+                    "comment",
+                    [reply.body_top]))
+                review_replies.append(NameArray(
+                    None,
+                    None,
+                    single_reply))
+
+        if len(review_replies):
+            text_review_array.append(NameArray(
+                "replies",
+                "reply",
+                review_replies))
+
+        if len(text_review_array):
+            return NameArray(
+                "body-top",
+                None,
+                text_review_array)
+
+        return None
+
+    # Adds part of a review that contains a screenshot review
+    # along with the associated replies
+    def build_screenshots(self, review):
+        screenshot_review_array = []
+
+        for screenshot in review.screenshot_comments.all():
+
+            screenshot_node = [] # Write SS Info
+            screenshot_node.append(NameArray(
+                "type",
+                None,
+                ["screenshot"]))
+            screenshot_node.append(NameArray(
+                "url",
+                None,
+                ["http://" +
+                    Site.objects.get_current().domain +
+                    screenshot.get_image_url()]))
+            screenshot_node.append(NameArray(
+                "text",
+                None,
+                [screenshot.text]))
+
+            screenshot_replies = self.get_reply_comment(
+                    screenshot.public_replies())
+
+            if len(screenshot_replies):
+                screenshot_node.append(NameArray(
+                    "replies",
+                    "reply",
+                    screenshot_replies))
+
+            screenshot_review_array.append(NameArray(
+                "comment",
+                None,
+                screenshot_node))
+
+        if len(screenshot_review_array):
+            return screenshot_review_array
+
+        return None
+
+    # Adds part of a review that contains a code/diff review
+    # along with the associated replies
+    def build_diffs(self, request,review):
+        diff_review_array = []
+
+        context = RequestContext(request, {
+                    'review_request': request,
+                    'review': review,
+                    })
+
+        diff_comments = review.comments.all()
+        for diff_comment in diff_comments:
+
+            content = list(get_file_chunks_in_range(context,
+                            diff_comment.filediff,
+                            diff_comment.interfilediff,
+                            diff_comment.first_line,
+                            diff_comment.num_lines,
+                            False))
+
+            diff_node = [] #write code-review info
+            diff_node.append(NameArray(
+                    "type",
+                    None,
+                    ["diff"]))
+            diff_node.append(NameArray(
+                "text",
+                    None,
+                    [diff_comment.text]))
+            diff_node.append(NameArray(
+                    "file",
+                    None,
+                    [diff_comment.filediff.source_file]))
+
+            chunks = []
+            for single_line in content[0]['lines']:
+                chunk = []
+                chunk.append(NameArray(
+                    "linenum",
+                    None,
+                    [single_line[0]]))
+                chunk.append(NameArray(
+                    "before",
+                    None,
+                    [single_line[2]]))
+                chunk.append(NameArray(
+                    "after",
+                    None,
+                    [single_line[5]]))
+                chunks.append(NameArray(
+                    "line",
+                    None,
+                    chunk))
+
+            diff_node.append(NameArray("chunk",
+                    None,
+                    chunks))
+            diff_replies = self.get_reply_comment(
+                    diff_comment.public_replies())
+
+            if len(diff_replies):
+                diff_node.append(NameArray(
+                    "replies",
+                    "reply",
+                    diff_replies))
+
+            diff_review_array.append(NameArray(
+                    "comment",
+                    None,
+                    diff_node))
+
+        if  len(diff_review_array):
+            return diff_review_array
+
+        return None
+
+    # Helper function that gets the replies of a review
+    def get_reply_comment(self, public_replies):
+        replies = []
+        for reply in public_replies:
+            reply_array = []
+            reply_array.append(NameArray(
+                None,
+                "user",
+                [reply.review.get().user.username]))
+            reply_array.append(NameArray(
+                None,
+                "comment",
+                [reply.text]))
+            replies.append(NameArray(
+                None,
+                None,
+                reply_array))
+        return replies
+
+reviewing_session_resource = ReviewRequestResource()
diff --git a/rbxmlexport/rbxmlexport/tests.py b/rbxmlexport/rbxmlexport/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..d1961e572d6d53c0fd35b7324e9181be8e1af011
--- /dev/null
+++ b/rbxmlexport/rbxmlexport/tests.py
@@ -0,0 +1,50 @@
+from django.test import TestCase
+
+from djblets.siteconfig.models import SiteConfiguration
+
+
+class ViewTests(TestCase):
+    """Tests for views in reviewboard.reports.views"""
+    fixtures = ['test_users', 'test_reviewrequests', 'test_scmtools']
+
+    def setUp(self):
+        siteconfig = SiteConfiguration.objects.get_current()
+        siteconfig.set("auth_require_sitewide_login", False)
+
+    def testReviewRequestReport(self):
+        """Testing review_request report"""
+        response = self.client.get("/reports/admin/review_request/moinmoin/")
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.get("/reports/admin/review_request/text/")
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.get("/reports/admin/review_request/abc/")
+        self.assertEqual(response.status_code, 404)
+
+    def testReviewReport(self):
+        """Testing review report"""
+        response = self.client.get("/reports/admin/review/moinmoin/")
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.get("/reports/admin/review/text/")
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.get("/reports/admin/review/abc/")
+        self.assertEqual(response.status_code, 404)
+
+    def testStatusReport(self):
+        """Testing status_report"""
+        response = self.client.get("/reports/admin/status_report/moinmoin/")
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.get("/reports/admin/status_report/text/")
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.get("/reports/admin/status_report/abc/")
+        self.assertEqual(response.status_code, 404)
+
+    def testReportList(self):
+        """Testing report_list"""
+        response = self.client.get("/reports/")
+        self.assertEqual(response.status_code, 200)
diff --git a/rbxmlexport/rbxmlexport/urls.py b/rbxmlexport/rbxmlexport/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..ed7151ad146abdd556e11b39650b1e612f630439
--- /dev/null
+++ b/rbxmlexport/rbxmlexport/urls.py
@@ -0,0 +1,11 @@
+from django.conf.urls.defaults import patterns
+
+
+urlpatterns = patterns('rbreports.views',
+    (r'^$', 'report_list'),
+    (r'^(?P<username>[A-Za-z0-9_-]+)/review_request/(?P<format>[a-z]+)/$',
+      'review_request'),
+    (r'^(?P<username>[A-Za-z0-9_-]+)/review/(?P<format>[a-z]+)/$', 'review'),
+    (r'^(?P<username>[A-Za-z0-9_-]+)/status_report/(?P<format>[a-z]+)/$',
+      'status_report'),
+)
diff --git a/rbxmlexport/rbxmlexport/urls.pyc b/rbxmlexport/rbxmlexport/urls.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e80dabd78c69bc0d5c58e8ffc33ca3b759539003
diff --git a/rbxmlexport/rbxmlexport/views.py b/rbxmlexport/rbxmlexport/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..91c4424b48594e84301ccf1459f830c746f75e7e
--- /dev/null
+++ b/rbxmlexport/rbxmlexport/views.py
@@ -0,0 +1,133 @@
+from datetime import datetime, timedelta
+
+from django.contrib.auth.models import User
+from django.contrib.sites.models import Site
+from django.http import Http404
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template.context import RequestContext
+
+from reviewboard.reviews.models import ReviewRequest, Review
+
+
+reports = {
+    'review_request': {
+        'name': 'Review Requests',
+        'templates': {
+            'text': {
+                'name': 'Plain Text',
+                'template': 'rbreports/review_request-text.txt',
+                'content-type': 'text/plain',
+            },
+            'moinmoin': {
+                'name': 'Wiki (MoinMoin)',
+                'template': 'rbreports/review_request-moinmoin.txt',
+                'content-type': 'text/plain',
+            },
+        },
+    },
+    'review': {
+        'name': 'Reviews Given',
+        'templates': {
+            'text': {
+                'name': 'Plain Text',
+                'template': 'rbreports/review-text.txt',
+                'content-type': 'text/plain',
+            },
+            'moinmoin': {
+                'name': 'Wiki (MoinMoin)',
+                'template': 'rbreports/review-moinmoin.txt',
+                'content-type': 'text/plain',
+            }
+        },
+    },
+    'status_report': {
+        'name': 'Combined Status Report',
+        'templates': {
+            'text': {
+                'name': 'Plain Text',
+                'template': 'rbreports/status_report-text.txt',
+                'content-type': 'text/plain',
+            },
+            'moinmoin': {
+                'name': 'Wiki (MoinMoin)',
+                'template': 'rbreports/status_report-moinmoin.txt',
+                'content-type': 'text/plain',
+            },
+        },
+    }
+}
+
+
+def report(request, username, format, report, get_context):
+    # FIXME - error checking?
+    period = int(request.GET.get('period', 7))
+
+    user = get_object_or_404(User, username=username)
+
+    try:
+        template = report['templates'][format]
+    except KeyError:
+        raise Http404
+
+    since = datetime.now() - timedelta(days=period)
+
+    site = Site.objects.get_current()
+    siteconfig = site.config.get()
+
+    context = get_context(user, since)
+    context.update({
+        'domain': site,
+        'domain_method': siteconfig.get("site_domain_method"),
+    })
+
+    return render_to_response(template['template'], context,
+                              RequestContext(request),
+                              mimetype="%s;charset=UTF-8" %
+                                       template['content-type'])
+
+
+def review_request(request, username, format):
+    return report(request, username, format,
+                  reports['review_request'],
+                  lambda user, since: {
+                      'review_requests' : ReviewRequest.objects.filter(
+                          submitter=user,
+                          time_added__gt=since)
+                  })
+
+
+def review(request, username, format):
+    return report(request, username, format,
+                  reports['review'],
+                  lambda user, since: {
+                      'reviews' : Review.objects.filter(
+                          user=user,
+                          timestamp__gt=since)
+                  })
+
+
+def status_report(request, username, format):
+    return report(request, username, format,
+                  reports['status_report'],
+                  lambda user, since: {
+                      'review_requests' : ReviewRequest.objects.filter(
+                          submitter=user,
+                          time_added__gt=since),
+                      'reviews' : Review.objects.filter(
+                          user=user,
+                          timestamp__gt=since)
+                  })
+
+
+def report_list(request,
+                template_name='rbreports/report_list.html'):
+
+    return render_to_response(template_name, RequestContext(request, {
+        'reports': reports,
+    }))
+
+
+def configure(request,
+              template_name='rbreports/configure.html'):
+    return render_to_response(template_name, RequestContext(request, {
+    }))
diff --git a/rbxmlexport/rbxmlexport/views.pyc b/rbxmlexport/rbxmlexport/views.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4f89127f6a7b95baccd30b8f1597368c3c215da1
diff --git a/rbxmlexport/setup.py b/rbxmlexport/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..7781fa3be9877481e17e59d412f381035700a1c7
--- /dev/null
+++ b/rbxmlexport/setup.py
@@ -0,0 +1,24 @@
+from setuptools import setup, find_packages
+
+PACKAGE="RB-XMLExport"
+VERSION="0.1"
+
+setup(
+    name=PACKAGE,
+    version=VERSION,
+    description="""XML Export of Review Files""",
+    author="Kahlil Amlani",
+    packages=["rbxmlexport"],
+    entry_points={
+        'reviewboard.extensions':
+        '%s = rbxmlexport.extension:RBXMLExport' % PACKAGE,
+    },
+    package_data={
+        'rbxmlexport': [
+            'htdocs/css/*.css',
+            'htdocs/js/*.js',
+            'templates/rbxmlexport/*.html',
+            'templates/rbxmlexport/*.txt',
+        ],
+    }
+)
