diff --git a/controllers/toolbox.py b/controllers/toolbox.py
deleted file mode 100644
index 90d6d410d5823409e3258bbfddcaa4326e808c72..0000000000000000000000000000000000000000
--- a/controllers/toolbox.py
+++ /dev/null
@@ -1,17 +0,0 @@
-""" Collection of tools to help debugging, .... 
-
-"""
-
-def fill_categories():
-    """Fill the categories table with a large number of data.
-    Usefull to test the buffered render.
-    
-    """
-    data = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', \
-            'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y']
-    
-    for i in range(1, (1000/len(data))+1):
-        for el in data:
-            s = el*i
-            print s
-            db.categories[0] = dict(code=s, definition=s.lower())
diff --git a/scripts/export-to-csv.py b/scripts/export-to-csv.py
new file mode 100644
index 0000000000000000000000000000000000000000..803e6f05e3cf4edb49e8ad72b9539b5719118edc
--- /dev/null
+++ b/scripts/export-to-csv.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+""" NAME
+        export-to-csv -- export table content as CSV file 
+        
+    SYNOPSIS
+        export-to-csv [options] table file
+        
+    DESCRIPTION
+        Write the full content of the table to a CSV file.
+        
+    OPTIONS
+    
+        -h, --help
+            Display the help and exit.
+            
+    EXAMPLE
+    
+        > cd ...track_lhcbfrance/scripts
+        > ./run export-to-csv.py history ~/mywap/track_lhcbfrance/scripts/history.csv
+        
+    AUTHOR
+        R. Le Gac
+        
+"""
+JSON_TYPES = ('json', 'list:integer', 'list:string')
+
+if __name__ == "__main__":
+    
+    import csv
+    import json
+    import os
+    import sys
+    
+    from argparse import ArgumentParser, FileType
+
+    # command line options
+    parser = ArgumentParser()
+    parser.add_argument('table',
+                        help='the name of the table.')
+
+    parser.add_argument('file',
+                        type=FileType('w'),
+                        help='the absolute path of the CSV file.')
+    
+    args = parser.parse_args()
+    
+    # the CSV writer
+    writer = csv.DictWriter(args.file, 
+                            db[args.table].fields, 
+                            quoting=csv.QUOTE_MINIMAL)
+    
+    # write the header
+    headers = {}
+    for el in db[args.table].fields:
+        headers[el] = el
+    writer.writerow(headers)
+    
+    # write table content dumping properly json field
+    for row in db(db[args.table]).select():
+        di = {}
+        for el in headers:
+            if db[args.table][el].type in JSON_TYPES:
+                di[el] = json.dumps(row[el])
+            else:
+                di[el] = row[el]
+        writer.writerow(di)
+
+    # close
+    print 'Table "%s" exported to "%s"' % (args.table, args.file.name)
+    args.file.close()
+    sys.exit(0)
diff --git a/scripts/fill-categories.py b/scripts/fill-categories.py
new file mode 100644
index 0000000000000000000000000000000000000000..526c0d2a7f43069117716d8929caf3a9f12bce21
--- /dev/null
+++ b/scripts/fill-categories.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+""" NAME
+        fill-categories --
+        
+    SYNOPSIS
+        fill-categories
+        
+    DESCRIPTION
+        Fill the categories table with a lot of dummy data.
+        It is useful to test grid paging and buffered store.
+        
+    OPTIONS
+    
+        -h, --help
+            Display the help and exit.
+            
+    EXAMPLE
+    
+        > cd ..plugin_dbui/scripts
+        > ./run fill-categories.py
+        
+    AUTHOR
+        R. Le Gac
+        
+"""
+
+if __name__ == "__main__":
+
+    import sys
+        
+    data = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', \
+            'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y']
+    
+    for i in range(1, (1000/len(data))+1):
+        for el in data:
+            s = el*i
+            print s
+            db.categories.insert(code=s, definition=s.lower())
+
+    db.commit()
+    sys.exit(0)
\ No newline at end of file
diff --git a/scripts/import-from-csv.py b/scripts/import-from-csv.py
new file mode 100644
index 0000000000000000000000000000000000000000..8030705ec1e92ec3843dc319d5196b5931aa1053
--- /dev/null
+++ b/scripts/import-from-csv.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+""" NAME
+        import-from-csv -- import table content from CSV file 
+        
+    SYNOPSIS
+        import-from-csv [options] file table
+        
+    DESCRIPTION
+        Load the full content of the table from a CSV file.
+        
+    OPTIONS
+    
+        -h, --help
+            Display the help and exit.
+            
+    EXAMPLE
+    
+        > cd ...track_lhcbfrance/scripts
+        > ./run import-from-csv.py ~/mywap/track_lhcbfrance/scripts/history.csv history
+        
+    AUTHOR
+        R. Le Gac
+        
+"""
+JSON_TYPES = ('json', 'list:integer', 'list:string')
+
+
+if __name__ == "__main__":
+    
+    import csv
+    import json
+    import os
+    import sys
+    
+    from argparse import ArgumentParser, FileType
+
+    # command line options
+    parser = ArgumentParser()
+
+    parser.add_argument('file',
+                        type=FileType('r'),
+                        help='the absolute path of the CSV file.')
+    
+    parser.add_argument('table',
+                    help='the name of the table.')
+
+    args = parser.parse_args()
+    
+    # json fields
+    json_fields = []
+    for field in db[args.table]:
+        if field.type in JSON_TYPES:
+            json_fields.append(field.name)
+
+    # load table content loading properly json fields
+    reader = csv.DictReader(args.file)
+    for di in reader:
+        
+        for el in json_fields:
+            di[el] = json.loads(di[el])
+            
+        db[args.table].insert(**di)
+ 
+    db.commit()
+    
+    # close
+    print 'File "%s" import in "%s"' % (args.file.name, args.table)
+    args.file.close()
+    sys.exit(0)
diff --git a/scripts/run b/scripts/run
new file mode 100755
index 0000000000000000000000000000000000000000..ae9dcfc51277b943cb31b1cce92db49e7446edac
--- /dev/null
+++ b/scripts/run
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+""" NAME
+        run -- run a script using the application model 
+        
+    SYNOPSIS
+        run [options] script.py
+        
+    DESCRIPTION
+        run the script in the web2py context when the 
+        application model is instantiated.
+        
+    OPTIONS
+        -h, --help
+            Display the help and exit.
+        
+    EXAMPLE
+    
+        > cd ... myapp/scripts
+        > ./run myscript.py
+        
+    AUTHOR
+        R. Le Gac
+        
+"""
+if __name__ == "__main__":
+    
+    import os
+    import subprocess
+    import sys
+    
+    from argparse import ArgumentParser
+
+    APP = os.getcwd().split(os.sep)[-2]
+    WEB2PY_DIR = '../../web2py'
+    WEB2PY = os.path.join(WEB2PY_DIR, 'web2py.py')
+    
+    # command line options
+    parser = ArgumentParser()
+    parser.add_argument('script',
+                        help='the name of the script to be run.')
+
+    parser.add_argument('args',
+                        nargs='*',
+                        help='the arguments for the script.')
+    
+    args = parser.parse_args()
+    
+    # run the script in the track_publication context
+    script_path = os.path.join(os.getcwd(), args.script)
+    
+    cmd = [WEB2PY,
+           '--no-banner',
+           '--shell', APP,
+           '--import_models',
+           '--run', script_path]
+    
+    if args.args:
+        cmd.append('--args')
+        cmd.extend(args.args)
+    
+    return_code = subprocess.call(cmd)
+    
+    # exit
+    sys.exit(return_code)