=== added directory 'lava'
=== added file 'lava/__init__.py'
--- lava/__init__.py	1970-01-01 00:00:00 +0000
+++ lava/__init__.py	2012-01-17 01:15:02 +0000
@@ -0,0 +1,3 @@
+__import__('pkg_resources').declare_namespace(__name__)
+# DO NOT ADD ANYTHING TO THIS FILE!
+# IT MUST STAY AS IS (empty apart from the two lines above)

=== added directory 'lava/utils'
=== added file 'lava/utils/__init__.py'
--- lava/utils/__init__.py	1970-01-01 00:00:00 +0000
+++ lava/utils/__init__.py	2012-01-17 01:16:42 +0000
@@ -0,0 +1,3 @@
+__import__('pkg_resources').declare_namespace(__name__)
+# DO NOT ADD ANYTHING TO THIS FILE!
+# IT MUST STAY AS IS (empty apart from the two lines above)

=== added directory 'lava/utils/data_tables'
=== added file 'lava/utils/data_tables/__init__.py'
=== added file 'lava/utils/data_tables/backends.py'
--- lava/utils/data_tables/backends.py	1970-01-01 00:00:00 +0000
+++ lava/utils/data_tables/backends.py	2012-01-18 21:15:42 +0000
@@ -0,0 +1,72 @@
+# Copyright (C) 2012 Linaro Limited
+#
+# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
+#
+# This file is part of LAVA Server.
+#
+# LAVA Server is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# as published by the Free Software Foundation
+#
+# LAVA Server is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with LAVA Server.  If not, see <http://www.gnu.org/licenses/>.
+
+from django.core.exceptions import ImproperlyConfigured
+
+from lava.utils.data_tables.interface import IBackend
+
+
+class _BackendBase(IBackend):
+    """
+    Common code for data backends to data tables
+    """
+
+    def process(self, query):
+        return {
+            'sEcho': query.sEcho,
+            'sColumns': query.sColumns
+        }
+
+
+class ArrayBackend(_BackendBase):
+    """
+    Array backend to data tables
+
+    Stores all data in a plain python list. All filtering is handled in the
+    running process. It is suitable for very small data sets only but has the
+    advantage of being unrelated to any databases.
+    """
+
+    def __init__(self, data):
+        self.data = data
+
+    def process(self, query):
+        # Get the basic response structure
+        response = super(ArrayBackend, self).process(query)
+        # 0) Copy original data
+        # TODO: add support for lazy copy (only if really needed)
+        data = list(self.data)
+        response['iTotalRecords'] = len(data)
+        # 1) Apply search/filtering
+        if query.sSearch:
+            if query.bRegex:
+                raise NotImplementedError("Searching with regular expresions is not implemented")
+            else:
+                data = [row for row in data if any((query.sSearch in unicode(cell) for cell in row))]
+        # Remember how many records matched filtering
+        response['iTotalDisplayRecords'] = len(data)
+        # TODO: Support regex search
+        # TODO: Support per-column search
+        # 2) Apply sorting
+        for column_index, order in reversed(euery.sorting_columns):
+            data.sort(key=lambda row: row[column_index], reverse=order == 'desc')
+        # 3) Apply offset/limit
+        data = data[query.iDisplayStart:query.iDisplayStart + query.iDisplayLength]
+        # Remember the subset of the displayed data
+        response['aaData'] = data
+        return response

=== added file 'lava/utils/data_tables/interface.py'
--- lava/utils/data_tables/interface.py	1970-01-01 00:00:00 +0000
+++ lava/utils/data_tables/interface.py	2012-01-17 01:26:01 +0000
@@ -0,0 +1,34 @@
+# Copyright (C) 2012 Linaro Limited
+#
+# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
+#
+# This file is part of LAVA Server.
+#
+# LAVA Server is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# as published by the Free Software Foundation
+#
+# LAVA Server is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with LAVA Server.  If not, see <http://www.gnu.org/licenses/>.
+
+from lava.utils.interface import Interface, abstractmethod
+
+
+class IBackend(Interface):
+    """
+    Interface for data-store-and-compute backends to data-tables.
+    """
+
+    @abstractmethod
+    def process(self, query):
+        """
+        Process data query.
+
+        Process the query and return a JSON response object compatible with
+        data tables.
+        """

=== added file 'lava/utils/data_tables/query.py'
--- lava/utils/data_tables/query.py	1970-01-01 00:00:00 +0000
+++ lava/utils/data_tables/query.py	2012-01-17 01:24:32 +0000
@@ -0,0 +1,67 @@
+# Copyright (C) 2012 Linaro Limited
+#
+# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
+#
+# This file is part of LAVA Server.
+#
+# LAVA Server is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# as published by the Free Software Foundation
+#
+# LAVA Server is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with LAVA Server.  If not, see <http://www.gnu.org/licenses/>.
+
+
+class DataTableQuery(object):
+    """
+    Query to data table server backend
+    """
+
+    DEFAULT_DISPLAY_LENGTH = 10
+
+    def __init__(self, request):
+        # Store the request object
+        self.request = request
+
+        # Number of columns
+        self.iColumns = int(request.GET.get('iColumns', 0))
+        self.sColumns = request.GET.get('sColumns', '')
+
+        # Echo data (seems to be cache poison, needs follow up checks)
+        self.sEcho = request.GET.get('sEcho', 0)
+
+        # Some unspecified value
+        # XXX: What is this for?
+        self._ = request.GET.get('_', '')
+
+        # Data window parameters
+        self.iDisplayStart = int(request.GET.get('iDisplayStart', 0))
+        self.iDisplayLength = int(request.GET.get('iDisplayLength', self.DEFAULT_DISPLAY_LENGTH))
+
+        # Sorting/ordering parameters
+        self.sorting_columns = []
+        self.iSortingCols = int(request.GET.get('iSortingCols', 0))
+        for i in range(self.iSortingCols):
+            column_index = int(request.GET.get('iSortCol_{0}'.format(i), 0))
+            sortable = request.GET.get('bSortable_{0}'.format(i), 'false') == 'true'
+            if sortable:
+                sorting_direction = request.GET.get('sSortDir_{0}'.format(i), 'asc')
+                self.sorting_columns.append((column_index, sorting_direction))
+
+        # Global search parameters
+        self.sSearch = request.GET.get('sSearch', '')
+        self.bRegex = request.GET.get('bRegex', 'false') == 'true'
+
+        # Per-column search parameters
+        self.search_columns = []
+        for i in range(self.iColumns):
+            searchable = request.GET.get('bSearchable_{0}'.format(i), 'false') == 'true'
+            if searchable:
+                regex = request.GET.get('bRegex_{0}'.format(i), 'false') == 'true'
+                term = request.GET.get('sSearch_{0}'.format(i), '')
+                self.search_columns.append((i, regex, term))

=== added file 'lava/utils/data_tables/views.py'
--- lava/utils/data_tables/views.py	1970-01-01 00:00:00 +0000
+++ lava/utils/data_tables/views.py	2012-01-17 01:43:59 +0000
@@ -0,0 +1,42 @@
+# Copyright (C) 2012 Linaro Limited
+#
+# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
+#
+# This file is part of LAVA Server.
+#
+# LAVA Server is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# as published by the Free Software Foundation
+#
+# LAVA Server is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with LAVA Server.  If not, see <http://www.gnu.org/licenses/>.
+
+from django.core.exceptions import ImproperlyConfigured
+from django.http import HttpResponse
+from django.utils import simplejson
+from django.views.generic import View
+
+from lava.utils.data_tables.query import DataTableQuery
+
+
+class DataTableView(View):
+    """
+    View for processing data table requests
+    """
+
+    backend = None
+
+    def get(self, request, *args, **kwargs):
+        if self.backend is None:
+            raise ImproperlyConfigured(
+                "DataTableView requires a definition of a backend")
+        query = DataTableQuery(request)
+        result = self.backend.process(query)
+        return HttpResponse(
+            simplejson.dumps(result),
+            mimetype='application/json')

=== added directory 'lava/utils/interface'
=== added file 'lava/utils/interface/__init__.py'
--- lava/utils/interface/__init__.py	1970-01-01 00:00:00 +0000
+++ lava/utils/interface/__init__.py	2012-01-17 01:18:34 +0000
@@ -0,0 +1,27 @@
+# Copyright (C) 2012 Linaro Limited
+#
+# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
+#
+# This file is part of LAVA Server.
+#
+# LAVA Server is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# as published by the Free Software Foundation
+#
+# LAVA Server is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with LAVA Server.  If not, see <http://www.gnu.org/licenses/>.
+
+from abc import ABCMeta, abstractmethod
+
+
+class Interface(object):
+    """
+    Interface class
+    """
+
+    __metaclass__ = ABCMeta

=== modified file 'setup.py'
--- setup.py	2011-11-29 19:59:48 +0000
+++ setup.py	2012-01-17 01:29:55 +0000
@@ -26,6 +26,7 @@
     version=":versiontools:lava_server:__version__",
     author="Zygmunt Krynicki",
     author_email="zygmunt.krynicki@linaro.org",
+    namespace_packages=['lava', 'lava.utils'],
     packages=find_packages(),
     entry_points="""
         [console_scripts]
@@ -57,7 +58,7 @@
         "Topic :: Software Development :: Testing",
     ],
     install_requires=[
-        'django >= 1.2',
+        'django >= 1.3',
         'django-debian >= 0.10',
         'django-openid-auth >= 0.2',
         'django-restricted-resource >= 0.2.6',

