"""
An ipython 2.x notebook manager that uses s3 for storage.

# Configuration file for ipython-notebook.
c = get_config()

c.NotebookApp.notebook_manager_class = 's3nb.S3NotebookManager'
c.NotebookApp.log_level = 'DEBUG'
c.S3NotebookManager.s3_base_uri = 's3://bucket/notebook/prefix/'
"""
import boto
from tornado import web

from IPython.html.services.notebooks.nbmanager import NotebookManager
from IPython.utils.traitlets import Unicode


class S3NotebookManager(NotebookManager):
    s3_bucket = Unicode(u"", config=True)
    s3_prefix = Unicode(u"", config=True)

    @staticmethod
    def _parse_s3_uri(uri, delimiter='/'):
        if not uri.startswith("s3://"):
            raise Exception("Unexpected s3 uri scheme in '{}', expected s3://".format(uri))
        return uri[5:].split(delimiter, 1)

    def __init__(self, **kwargs):
        super(S3NotebookManager, self).__init__(**kwargs)
        config = kwargs['parent'].config[self.__class__.__name__]  # this can't be right
        self.s3_base_uri = config['s3_base_uri']
        self.s3_key_delimiter = config.get('s3_key_delimiter', '/')
        self.s3_bucket, self.s3_prefix = self._parse_s3_uri(self.s3_base_uri, self.s3_key_delimiter)
        self.s3_connection = boto.connect_s3()
        self.bucket = self.s3_connection.get_bucket(self.s3_bucket)

    def info_string(self):
        return "Serving notebooks from {}".format(self.s3_base_uri)

@@ -562,16 +562,73 @@
 ig=True)
+%0A    notebook_dir = Unicode(u%22%22, config=True)  # not used
 %0A%0A    @s
@@ -858,16 +858,499 @@
 er, 1)%0A%0A
+    def _s3_key_dir_to_model(self, key):%0A        self.log.debug(%22_s3_key_dir_to_model: %7B%7D: %7B%7D%22.format(key, key.name))%0A        model = %7B%0A            'name': key.name.rsplit(self.s3_key_delimiter, 2)%5B-2%5D,%0A            'path': key.name,%0A            'last_modified': None, # key.last_modified,%0A            'created': None, # key.last_modified,%0A            'type': 'directory',%0A        %7D%0A        self.log.debug(%22_s3_key_dir_to_model: %7B%7D: %7B%7D%22.format(key.name, model))%0A        return model%0A%0A
     def 
@@ -1740,16 +1740,174 @@
 imiter)%0A
+        # ensure prefix ends with the delimiter%0A        if not self.s3_prefix.endswith(self.s3_key_delimiter):%0A            self.s3_prefix += s3_key_delimiter%0A
         
@@ -2109,8 +2109,973 @@
 se_uri)%0A
+%0A    def path_exists(self, path):%0A        self.log.debug('path_exists: %7B%7D'.format(locals()))%0A        return True%0A%0A    def is_hidden(self, path):%0A        self.log.debug('is_hidden: %7B%7D'.format(locals()))%0A        return False%0A%0A    def list_dirs(self, path):%0A        self.log.debug('list_dirs: %7B%7D'.format(locals()))%0A        key = self.s3_prefix + path.strip(self.s3_key_delimiter)%0A        # append delimiter if path is non-empty to avoid s3://bucket//%0A        if path != '':%0A            key += self.s3_key_delimiter%0A        self.log.debug('list_dirs: looking in bucket:%7B%7D under:%7B%7D'.format(self.bucket.name, key))%0A        notebooks = %5B%5D%0A        for k in self.bucket.list(key, self.s3_key_delimiter):%0A            if k.name.endswith(self.s3_key_delimiter):%0A                notebooks.append(self._s3_key_dir_to_model(k))%0A                self.log.debug('list_dirs: found %7B%7D'.format(k.name))%0A        return notebooks%0A%0A    def list_notebooks(self, path=''):%0A        return %5B%5D%0A

implement list_dirs() and deps