We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Old-style profile with JS/CSS imported but not reliably used within rendered pages after a while
Situation: Plone 5.0a3 buildout with 

git@bitbucket.org:onkopedia/zopyx.existdb.git 

('dexterity' branch).

I created a new Plone site and added 'zopyx.existdb' as add-on.

As expected the JS/CSS resources show up in the resource registry control panels.

For debugging purposes I added an alert() to the local.js file of the package.

After the some operations in the control panel and some content management work in Plone UI the 
zopyx.existdb resources are no longer loaded - they do not longer show up in the HTML markup and of course the alert() is no longer trigger for each page load.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `Products/CMFPlone/resources/viewlets/__init__.py`
Content:
```
1 
2 from Products.ResourceRegistries.interfaces.registries import IResourceRegistry
3 from Products.ResourceRegistries.interfaces.registries import ICSSRegistry
4 from Products.ResourceRegistries.interfaces.registries import IKSSRegistry
5 from Products.ResourceRegistries.interfaces.registries import IJSRegistry
6 from Products.ResourceRegistries.interfaces.registries import ICookedFile
7 from Products.ResourceRegistries.interfaces.registries import IResourceProvider
8 from Products.ResourceRegistries.interfaces.viewletmanagers import IHtmlHeadScripts
9 from Products.ResourceRegistries.interfaces.viewletmanagers import IHtmlHeadStyles
10 from Products.ResourceRegistries.interfaces.settings import IResourceRegistriesSettings
11
```

Path: `Products/CMFPlone/controlpanel/browser/resourceregistry.py`
Content:
```
1 from datetime import datetime
2 from Products.CMFPlone.interfaces import IBundleRegistry
3 from Products.CMFPlone.interfaces import IResourceRegistry
4 from Products.CMFPlone.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME  # noqa
5 from Products.CMFPlone.resources.browser.configjs import RequireJsView
6 from StringIO import StringIO
7 from plone.memoize.view import memoize
8 from plone.registry.interfaces import IRegistry
9 from plone.resource.interfaces import IResourceDirectory
10 from urlparse import urlparse
11 from zExceptions import NotFound
12 from zope.component import getUtility
13 import json
14 
15 
16 class JSONEncoder(json.JSONEncoder):
17     def default(self, obj):
18         if hasattr(obj, 'isoformat'):
19             return obj.isoformat()
20         else:
21             return json.JSONEncoder.default(self, obj)
22 
23 
24 def recordsToDict(record):
25     data = {}
26     for name in record.__schema__.names():
27         data[name] = getattr(record, name)
28     return data
29 
30 
31 def updateRecordFromDict(record, data):
32     for name in record.__schema__.names():
33         if name in ['last_compilation']:
34             continue
35         if name in data:
36             # almost all string data needs to be str, not unicode
37             val = data[name]
38             if isinstance(val, unicode):
39                 val = val.encode('utf-8')
40             if isinstance(val, list):
41                 newval = []
42                 for item in val:
43                     if isinstance(item, unicode):
44                         item = item.encode('utf-8')
45                     newval.append(item)
46                 val = newval
47             setattr(record, name, val)
48 
49 
50 class OverrideFolderManager(object):
51 
52     def __init__(self, context):
53         self.context = context
54         persistent_directory = getUtility(IResourceDirectory, name="persistent")  # noqa
55         if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:
56             persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)  # noqa
57         self.container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]
58 
59     def save_file(self, filepath, data):
60         resource_name, resource_filepath = filepath.split('/', 1)
61         if resource_name not in self.container:
62             self.container.makeDirectory(resource_name)
63         folder = self.container[resource_name]
64         fi = StringIO(data)
65         folder.writeFile(resource_filepath, fi)
66         return folder[resource_filepath]
67 
68     def delete_file(self, filepath):
69         resource_name, resource_filepath = filepath.split('/', 1)
70 
71         if resource_name not in self.container:
72             return
73         folder = self.container[resource_name]
74         try:
75             fi = folder[resource_filepath]
76         except NotFound:
77             return
78         parent = self.get_parent(fi)
79         del parent[fi.getId()]
80         if filepath not in self.container:
81             return
82         folder = self.container[resource_name]
83         try:
84             fi = folder[resource_filepath]
85         except NotFound:
86             return
87         parent = self.get_parent(fi)
88         del parent[fi.getId()]
89 
90     def get_parent(self, item):
91         path = '/'.join(item.getPhysicalPath()[:-1])
92         return self.context.restrictedTraverse(path)
93 
94     def list_dir(self, container):
95         if hasattr(container, 'listDirectory'):
96             return container.listDirectory()
97         else:
98             return container.objectIds()
99 
100 
101 class ResourceRegistryControlPanelView(RequireJsView):
102 
103     def __call__(self):
104         req = self.request
105         if req.REQUEST_METHOD == 'POST':
106             action = req.get('action', '')
107             method = action.replace('-', '_')
108             if hasattr(self, method):
109                 return getattr(self, method)()
110             else:
111                 return json.dumps({
112                     'success': False,
113                     'msg': 'Invalid action: ' + action
114                 })
115         else:
116             return self.index()
117 
118     @property
119     @memoize
120     def registry(self):
121         return getUtility(IRegistry)
122 
123     def update_registry_collection(self, itype, prefix, newdata):
124         rdata = self.registry.collectionOfInterface(itype, prefix=prefix)
125         for key, data in newdata.items():
126             if key not in rdata:
127                 record = rdata.add(key)
128             else:
129                 record = rdata[key]
130             updateRecordFromDict(record, data)
131         # remove missing ones
132         for key in set(rdata.keys()) - set(newdata.keys()):
133             del rdata[key]
134 
135     def save_development_mode(self):
136         if self.request.form.get('value', '').lower() == 'true':
137             self.registry['plone.resources.development'] = True
138         else:
139             self.registry['plone.resources.development'] = False
140         return json.dumps({
141             'success': True
142         })
143 
144     def save_registry(self):
145         req = self.request
146 
147         self.update_registry_collection(
148             IResourceRegistry, "plone.resources",
149             json.loads(req.get('resources')))
150         self.update_registry_collection(
151             IBundleRegistry, "plone.bundles",
152             json.loads(req.get('bundles')))
153 
154         return json.dumps({
155             'success': True
156         })
157 
158     def save_file(self):
159         req = self.request
160         resource_path = req.form.get('filepath').split('++plone++')[-1]
161         overrides = OverrideFolderManager(self.context)
162         overrides.save_file(resource_path, req.form['data'])
163         return json.dumps({
164             'success': True
165         })
166 
167     def delete_file(self):
168         req = self.request
169         resource_path = req.form.get('filepath').split('++plone++')[-1]
170         overrides = OverrideFolderManager(self.context)
171         overrides.delete_file(resource_path)
172 
173         return json.dumps({
174             'success': True
175         })
176 
177     def get_bundles(self):
178         return self.registry.collectionOfInterface(
179             IBundleRegistry, prefix="plone.bundles")
180 
181     def get_resources(self):
182         return self.registry.collectionOfInterface(
183             IResourceRegistry, prefix="plone.resources")
184 
185     def less_build_config(self):
186         site_url = self.context.portal_url()
187         bundles = self.get_bundles()
188         bundle = self.request.get('bundle', None)
189         resources = self.get_resources()
190         less_files = []
191         if bundle and bundle in bundles:
192             bundle_obj = bundles[bundle]
193             for resource in bundle_obj.resources:
194                 if resource in resources:
195                     for css in resources[resource].css:
196                         url = urlparse(css)
197                         if url.netloc == '':
198                             # Local
199                             src = "%s/%s" % (site_url, css)
200                         else:
201                             src = "%s" % (css)
202 
203                         extension = url.path.split('.')[-1]
204                         if extension == 'less':
205                             less_files.append(src)
206         return json.dumps({
207             'less': less_files,
208         })
209 
210     def js_build_config(self):
211         (baseUrl, paths, shims) = self.get_requirejs_config()
212         bundles = self.get_bundles()
213         resources = self.get_resources()
214 
215         bundle = self.request.get('bundle', None)
216         includes = []
217         if bundle and bundle in bundles:
218             bundle_obj = bundles[bundle]
219             for resource_name in bundle_obj.resources:
220                 # need to check if this resource has a js file
221                 # it could just be a css resource
222                 try:
223                     resource = resources[resource_name]
224                     if resource.js:
225                         includes.append(resource_name)
226                 except KeyError:
227                     # skip if missing
228                     pass
229         return json.dumps({
230             'include': includes,
231             'shims': shims,
232             'paths': paths
233         })
234 
235     def save_js_build(self):
236         overrides = OverrideFolderManager(self.context)
237         req = self.request
238         filepath = 'static/%s-compiled.js' % req.form['bundle']
239         overrides.save_file(filepath, req.form['data'])
240         bundle = self.get_bundles().get(req.form['bundle'])
241         if bundle:
242             bundle.last_compilation = datetime.now()
243         return json.dumps({
244             'success': True,
245             'filepath': '++plone++' + filepath
246         })
247 
248     def save_less_build(self):
249         overrides = OverrideFolderManager(self.context)
250         req = self.request
251         filepath = 'static/%s-compiled.css' % req.form['bundle']
252         data = '\n'.join([req.form[k] for k in req.form.keys()
253                           if k.startswith('data-')])
254         overrides.save_file(filepath, data)
255         bundle = self.get_bundles().get(req.form['bundle'])
256         if bundle:
257             bundle.last_compilation = datetime.now()
258         return json.dumps({
259             'success': True,
260             'filepath': '++plone++' + filepath
261         })
262 
263     def save_less_variables(self):
264         data = {}
265         for key, val in json.loads(self.request.form.get('data')).items():
266             # need to convert to str: unicode
267             data[key.encode('utf8')] = val
268         self.registry['plone.lessvariables'] = data
269         return json.dumps({
270             'success': True
271         })
272 
273     def save_pattern_options(self):
274         data = {}
275         for key, val in json.loads(self.request.form.get('data')).items():
276             # need to convert to str: unicode
277             data[key.encode('utf8')] = val
278         self.registry['plone.patternoptions'] = data
279         return json.dumps({
280             'success': True
281         })
282 
283     def get_overrides(self):
284         overrides = OverrideFolderManager(self.context)
285 
286         def _read_folder(folder):
287             files = []
288             for filename in folder.listDirectory():
289                 item = folder[filename]
290                 if folder.isDirectory(filename):
291                     files.extend(_read_folder(item))
292                 else:
293                     files.append(item)
294             return files
295         files = _read_folder(overrides.container)
296         results = []
297         site_path = self.context.getPhysicalPath()
298         for fi in files:
299             path = fi.getPhysicalPath()
300             rel_path = path[len(site_path) + 2:]
301             results.append('++plone++%s/%s' % (
302                 rel_path[0], '/'.join(rel_path[1:])))
303         return results
304 
305     def config(self):
306         base_url = self.context.absolute_url()
307         resources = self.get_resources()
308 
309         try:
310             less_url = self.registry['plone.resources.lessc']
311         except KeyError:
312             less_url = '++plone++static/components/less/dist/less-1.7.4.min.js'
313         try:
314             rjs_url = resources['rjs'].js
315         except KeyError:
316             rjs_url = '++plone++static/components/r.js/dist/r.js'
317 
318         data = {
319             'development': self.registry['plone.resources.development'],
320             'lessvariables': self.registry['plone.lessvariables'],
321             'resources': {},
322             'bundles': {},
323             'javascripts': {},
324             'css': {},
325             'baseUrl': base_url,
326             'manageUrl': '%s/@@resourceregistry-controlpanel' % base_url,
327             'lessUrl': '%s/%s' % (base_url, less_url),
328             'lessConfigUrl': '%s/less-variables.js' % base_url,
329             'rjsUrl': rjs_url,
330             'patternoptions': self.registry['plone.patternoptions']
331         }
332         bundles = self.get_bundles()
333         for key, resource in resources.items():
334             data['resources'][key] = recordsToDict(resource)
335         for key, bundle in bundles.items():
336             data['bundles'][key] = recordsToDict(bundle)
337         data['overrides'] = self.get_overrides()
338         return json.dumps(data, cls=JSONEncoder)
339
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py
--- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py
+++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py
@@ -240,6 +240,7 @@
         bundle = self.get_bundles().get(req.form['bundle'])
         if bundle:
             bundle.last_compilation = datetime.now()
+            bundle.jscompilation = '++plone++{}'.format(filepath)
         return json.dumps({
             'success': True,
             'filepath': '++plone++' + filepath
@@ -255,6 +256,7 @@
         bundle = self.get_bundles().get(req.form['bundle'])
         if bundle:
             bundle.last_compilation = datetime.now()
+            bundle.csscompilation = '++plone++{}'.format(filepath)
         return json.dumps({
             'success': True,
             'filepath': '++plone++' + filepath
diff --git a/Products/CMFPlone/resources/viewlets/__init__.py b/Products/CMFPlone/resources/viewlets/__init__.py
--- a/Products/CMFPlone/resources/viewlets/__init__.py
+++ b/Products/CMFPlone/resources/viewlets/__init__.py
@@ -1,4 +1,3 @@
-
 from Products.ResourceRegistries.interfaces.registries import IResourceRegistry
 from Products.ResourceRegistries.interfaces.registries import ICSSRegistry
 from Products.ResourceRegistries.interfaces.registries import IKSSRegistry

{"golden_diff": "diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n--- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n+++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n@@ -240,6 +240,7 @@\n         bundle = self.get_bundles().get(req.form['bundle'])\n         if bundle:\n             bundle.last_compilation = datetime.now()\n+            bundle.jscompilation = '++plone++{}'.format(filepath)\n         return json.dumps({\n             'success': True,\n             'filepath': '++plone++' + filepath\n@@ -255,6 +256,7 @@\n         bundle = self.get_bundles().get(req.form['bundle'])\n         if bundle:\n             bundle.last_compilation = datetime.now()\n+            bundle.csscompilation = '++plone++{}'.format(filepath)\n         return json.dumps({\n             'success': True,\n             'filepath': '++plone++' + filepath\ndiff --git a/Products/CMFPlone/resources/viewlets/__init__.py b/Products/CMFPlone/resources/viewlets/__init__.py\n--- a/Products/CMFPlone/resources/viewlets/__init__.py\n+++ b/Products/CMFPlone/resources/viewlets/__init__.py\n@@ -1,4 +1,3 @@\n-\n from Products.ResourceRegistries.interfaces.registries import IResourceRegistry\n from Products.ResourceRegistries.interfaces.registries import ICSSRegistry\n from Products.ResourceRegistries.interfaces.registries import IKSSRegistry\n", "issue": "Old-style profile with JS/CSS imported but not reliably used within rendered pages after a while\nSituation: Plone 5.0a3 buildout with \n\ngit@bitbucket.org:onkopedia/zopyx.existdb.git \n\n('dexterity' branch).\n\nI created a new Plone site and added 'zopyx.existdb' as add-on.\n\nAs expected the JS/CSS resources show up in the resource registry control panels.\n\nFor debugging purposes I added an alert() to the local.js file of the package.\n\nAfter the some operations in the control panel and some content management work in Plone UI the \nzopyx.existdb resources are no longer loaded - they do not longer show up in the HTML markup and of course the alert() is no longer trigger for each page load.\n\n", "before_files": [{"content": "\nfrom Products.ResourceRegistries.interfaces.registries import IResourceRegistry\nfrom Products.ResourceRegistries.interfaces.registries import ICSSRegistry\nfrom Products.ResourceRegistries.interfaces.registries import IKSSRegistry\nfrom Products.ResourceRegistries.interfaces.registries import IJSRegistry\nfrom Products.ResourceRegistries.interfaces.registries import ICookedFile\nfrom Products.ResourceRegistries.interfaces.registries import IResourceProvider\nfrom Products.ResourceRegistries.interfaces.viewletmanagers import IHtmlHeadScripts\nfrom Products.ResourceRegistries.interfaces.viewletmanagers import IHtmlHeadStyles\nfrom Products.ResourceRegistries.interfaces.settings import IResourceRegistriesSettings\n", "path": "Products/CMFPlone/resources/viewlets/__init__.py"}, {"content": "from datetime import datetime\nfrom Products.CMFPlone.interfaces import IBundleRegistry\nfrom Products.CMFPlone.interfaces import IResourceRegistry\nfrom Products.CMFPlone.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME  # noqa\nfrom Products.CMFPlone.resources.browser.configjs import RequireJsView\nfrom StringIO import StringIO\nfrom plone.memoize.view import memoize\nfrom plone.registry.interfaces import IRegistry\nfrom plone.resource.interfaces import IResourceDirectory\nfrom urlparse import urlparse\nfrom zExceptions import NotFound\nfrom zope.component import getUtility\nimport json\n\n\nclass JSONEncoder(json.JSONEncoder):\n    def default(self, obj):\n        if hasattr(obj, 'isoformat'):\n            return obj.isoformat()\n        else:\n            return json.JSONEncoder.default(self, obj)\n\n\ndef recordsToDict(record):\n    data = {}\n    for name in record.__schema__.names():\n        data[name] = getattr(record, name)\n    return data\n\n\ndef updateRecordFromDict(record, data):\n    for name in record.__schema__.names():\n        if name in ['last_compilation']:\n            continue\n        if name in data:\n            # almost all string data needs to be str, not unicode\n            val = data[name]\n            if isinstance(val, unicode):\n                val = val.encode('utf-8')\n            if isinstance(val, list):\n                newval = []\n                for item in val:\n                    if isinstance(item, unicode):\n                        item = item.encode('utf-8')\n                    newval.append(item)\n                val = newval\n            setattr(record, name, val)\n\n\nclass OverrideFolderManager(object):\n\n    def __init__(self, context):\n        self.context = context\n        persistent_directory = getUtility(IResourceDirectory, name=\"persistent\")  # noqa\n        if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:\n            persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)  # noqa\n        self.container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n\n    def save_file(self, filepath, data):\n        resource_name, resource_filepath = filepath.split('/', 1)\n        if resource_name not in self.container:\n            self.container.makeDirectory(resource_name)\n        folder = self.container[resource_name]\n        fi = StringIO(data)\n        folder.writeFile(resource_filepath, fi)\n        return folder[resource_filepath]\n\n    def delete_file(self, filepath):\n        resource_name, resource_filepath = filepath.split('/', 1)\n\n        if resource_name not in self.container:\n            return\n        folder = self.container[resource_name]\n        try:\n            fi = folder[resource_filepath]\n        except NotFound:\n            return\n        parent = self.get_parent(fi)\n        del parent[fi.getId()]\n        if filepath not in self.container:\n            return\n        folder = self.container[resource_name]\n        try:\n            fi = folder[resource_filepath]\n        except NotFound:\n            return\n        parent = self.get_parent(fi)\n        del parent[fi.getId()]\n\n    def get_parent(self, item):\n        path = '/'.join(item.getPhysicalPath()[:-1])\n        return self.context.restrictedTraverse(path)\n\n    def list_dir(self, container):\n        if hasattr(container, 'listDirectory'):\n            return container.listDirectory()\n        else:\n            return container.objectIds()\n\n\nclass ResourceRegistryControlPanelView(RequireJsView):\n\n    def __call__(self):\n        req = self.request\n        if req.REQUEST_METHOD == 'POST':\n            action = req.get('action', '')\n            method = action.replace('-', '_')\n            if hasattr(self, method):\n                return getattr(self, method)()\n            else:\n                return json.dumps({\n                    'success': False,\n                    'msg': 'Invalid action: ' + action\n                })\n        else:\n            return self.index()\n\n    @property\n    @memoize\n    def registry(self):\n        return getUtility(IRegistry)\n\n    def update_registry_collection(self, itype, prefix, newdata):\n        rdata = self.registry.collectionOfInterface(itype, prefix=prefix)\n        for key, data in newdata.items():\n            if key not in rdata:\n                record = rdata.add(key)\n            else:\n                record = rdata[key]\n            updateRecordFromDict(record, data)\n        # remove missing ones\n        for key in set(rdata.keys()) - set(newdata.keys()):\n            del rdata[key]\n\n    def save_development_mode(self):\n        if self.request.form.get('value', '').lower() == 'true':\n            self.registry['plone.resources.development'] = True\n        else:\n            self.registry['plone.resources.development'] = False\n        return json.dumps({\n            'success': True\n        })\n\n    def save_registry(self):\n        req = self.request\n\n        self.update_registry_collection(\n            IResourceRegistry, \"plone.resources\",\n            json.loads(req.get('resources')))\n        self.update_registry_collection(\n            IBundleRegistry, \"plone.bundles\",\n            json.loads(req.get('bundles')))\n\n        return json.dumps({\n            'success': True\n        })\n\n    def save_file(self):\n        req = self.request\n        resource_path = req.form.get('filepath').split('++plone++')[-1]\n        overrides = OverrideFolderManager(self.context)\n        overrides.save_file(resource_path, req.form['data'])\n        return json.dumps({\n            'success': True\n        })\n\n    def delete_file(self):\n        req = self.request\n        resource_path = req.form.get('filepath').split('++plone++')[-1]\n        overrides = OverrideFolderManager(self.context)\n        overrides.delete_file(resource_path)\n\n        return json.dumps({\n            'success': True\n        })\n\n    def get_bundles(self):\n        return self.registry.collectionOfInterface(\n            IBundleRegistry, prefix=\"plone.bundles\")\n\n    def get_resources(self):\n        return self.registry.collectionOfInterface(\n            IResourceRegistry, prefix=\"plone.resources\")\n\n    def less_build_config(self):\n        site_url = self.context.portal_url()\n        bundles = self.get_bundles()\n        bundle = self.request.get('bundle', None)\n        resources = self.get_resources()\n        less_files = []\n        if bundle and bundle in bundles:\n            bundle_obj = bundles[bundle]\n            for resource in bundle_obj.resources:\n                if resource in resources:\n                    for css in resources[resource].css:\n                        url = urlparse(css)\n                        if url.netloc == '':\n                            # Local\n                            src = \"%s/%s\" % (site_url, css)\n                        else:\n                            src = \"%s\" % (css)\n\n                        extension = url.path.split('.')[-1]\n                        if extension == 'less':\n                            less_files.append(src)\n        return json.dumps({\n            'less': less_files,\n        })\n\n    def js_build_config(self):\n        (baseUrl, paths, shims) = self.get_requirejs_config()\n        bundles = self.get_bundles()\n        resources = self.get_resources()\n\n        bundle = self.request.get('bundle', None)\n        includes = []\n        if bundle and bundle in bundles:\n            bundle_obj = bundles[bundle]\n            for resource_name in bundle_obj.resources:\n                # need to check if this resource has a js file\n                # it could just be a css resource\n                try:\n                    resource = resources[resource_name]\n                    if resource.js:\n                        includes.append(resource_name)\n                except KeyError:\n                    # skip if missing\n                    pass\n        return json.dumps({\n            'include': includes,\n            'shims': shims,\n            'paths': paths\n        })\n\n    def save_js_build(self):\n        overrides = OverrideFolderManager(self.context)\n        req = self.request\n        filepath = 'static/%s-compiled.js' % req.form['bundle']\n        overrides.save_file(filepath, req.form['data'])\n        bundle = self.get_bundles().get(req.form['bundle'])\n        if bundle:\n            bundle.last_compilation = datetime.now()\n        return json.dumps({\n            'success': True,\n            'filepath': '++plone++' + filepath\n        })\n\n    def save_less_build(self):\n        overrides = OverrideFolderManager(self.context)\n        req = self.request\n        filepath = 'static/%s-compiled.css' % req.form['bundle']\n        data = '\\n'.join([req.form[k] for k in req.form.keys()\n                          if k.startswith('data-')])\n        overrides.save_file(filepath, data)\n        bundle = self.get_bundles().get(req.form['bundle'])\n        if bundle:\n            bundle.last_compilation = datetime.now()\n        return json.dumps({\n            'success': True,\n            'filepath': '++plone++' + filepath\n        })\n\n    def save_less_variables(self):\n        data = {}\n        for key, val in json.loads(self.request.form.get('data')).items():\n            # need to convert to str: unicode\n            data[key.encode('utf8')] = val\n        self.registry['plone.lessvariables'] = data\n        return json.dumps({\n            'success': True\n        })\n\n    def save_pattern_options(self):\n        data = {}\n        for key, val in json.loads(self.request.form.get('data')).items():\n            # need to convert to str: unicode\n            data[key.encode('utf8')] = val\n        self.registry['plone.patternoptions'] = data\n        return json.dumps({\n            'success': True\n        })\n\n    def get_overrides(self):\n        overrides = OverrideFolderManager(self.context)\n\n        def _read_folder(folder):\n            files = []\n            for filename in folder.listDirectory():\n                item = folder[filename]\n                if folder.isDirectory(filename):\n                    files.extend(_read_folder(item))\n                else:\n                    files.append(item)\n            return files\n        files = _read_folder(overrides.container)\n        results = []\n        site_path = self.context.getPhysicalPath()\n        for fi in files:\n            path = fi.getPhysicalPath()\n            rel_path = path[len(site_path) + 2:]\n            results.append('++plone++%s/%s' % (\n                rel_path[0], '/'.join(rel_path[1:])))\n        return results\n\n    def config(self):\n        base_url = self.context.absolute_url()\n        resources = self.get_resources()\n\n        try:\n            less_url = self.registry['plone.resources.lessc']\n        except KeyError:\n            less_url = '++plone++static/components/less/dist/less-1.7.4.min.js'\n        try:\n            rjs_url = resources['rjs'].js\n        except KeyError:\n            rjs_url = '++plone++static/components/r.js/dist/r.js'\n\n        data = {\n            'development': self.registry['plone.resources.development'],\n            'lessvariables': self.registry['plone.lessvariables'],\n            'resources': {},\n            'bundles': {},\n            'javascripts': {},\n            'css': {},\n            'baseUrl': base_url,\n            'manageUrl': '%s/@@resourceregistry-controlpanel' % base_url,\n            'lessUrl': '%s/%s' % (base_url, less_url),\n            'lessConfigUrl': '%s/less-variables.js' % base_url,\n            'rjsUrl': rjs_url,\n            'patternoptions': self.registry['plone.patternoptions']\n        }\n        bundles = self.get_bundles()\n        for key, resource in resources.items():\n            data['resources'][key] = recordsToDict(resource)\n        for key, bundle in bundles.items():\n            data['bundles'][key] = recordsToDict(bundle)\n        data['overrides'] = self.get_overrides()\n        return json.dumps(data, cls=JSONEncoder)\n", "path": "Products/CMFPlone/controlpanel/browser/resourceregistry.py"}], "after_files": [{"content": "from Products.ResourceRegistries.interfaces.registries import IResourceRegistry\nfrom Products.ResourceRegistries.interfaces.registries import ICSSRegistry\nfrom Products.ResourceRegistries.interfaces.registries import IKSSRegistry\nfrom Products.ResourceRegistries.interfaces.registries import IJSRegistry\nfrom Products.ResourceRegistries.interfaces.registries import ICookedFile\nfrom Products.ResourceRegistries.interfaces.registries import IResourceProvider\nfrom Products.ResourceRegistries.interfaces.viewletmanagers import IHtmlHeadScripts\nfrom Products.ResourceRegistries.interfaces.viewletmanagers import IHtmlHeadStyles\nfrom Products.ResourceRegistries.interfaces.settings import IResourceRegistriesSettings\n", "path": "Products/CMFPlone/resources/viewlets/__init__.py"}, {"content": "from datetime import datetime\nfrom Products.CMFPlone.interfaces import IBundleRegistry\nfrom Products.CMFPlone.interfaces import IResourceRegistry\nfrom Products.CMFPlone.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME  # noqa\nfrom Products.CMFPlone.resources.browser.configjs import RequireJsView\nfrom StringIO import StringIO\nfrom plone.memoize.view import memoize\nfrom plone.registry.interfaces import IRegistry\nfrom plone.resource.interfaces import IResourceDirectory\nfrom urlparse import urlparse\nfrom zExceptions import NotFound\nfrom zope.component import getUtility\nimport json\n\n\nclass JSONEncoder(json.JSONEncoder):\n    def default(self, obj):\n        if hasattr(obj, 'isoformat'):\n            return obj.isoformat()\n        else:\n            return json.JSONEncoder.default(self, obj)\n\n\ndef recordsToDict(record):\n    data = {}\n    for name in record.__schema__.names():\n        data[name] = getattr(record, name)\n    return data\n\n\ndef updateRecordFromDict(record, data):\n    for name in record.__schema__.names():\n        if name in ['last_compilation']:\n            continue\n        if name in data:\n            # almost all string data needs to be str, not unicode\n            val = data[name]\n            if isinstance(val, unicode):\n                val = val.encode('utf-8')\n            if isinstance(val, list):\n                newval = []\n                for item in val:\n                    if isinstance(item, unicode):\n                        item = item.encode('utf-8')\n                    newval.append(item)\n                val = newval\n            setattr(record, name, val)\n\n\nclass OverrideFolderManager(object):\n\n    def __init__(self, context):\n        self.context = context\n        persistent_directory = getUtility(IResourceDirectory, name=\"persistent\")  # noqa\n        if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:\n            persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)  # noqa\n        self.container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n\n    def save_file(self, filepath, data):\n        resource_name, resource_filepath = filepath.split('/', 1)\n        if resource_name not in self.container:\n            self.container.makeDirectory(resource_name)\n        folder = self.container[resource_name]\n        fi = StringIO(data)\n        folder.writeFile(resource_filepath, fi)\n        return folder[resource_filepath]\n\n    def delete_file(self, filepath):\n        resource_name, resource_filepath = filepath.split('/', 1)\n\n        if resource_name not in self.container:\n            return\n        folder = self.container[resource_name]\n        try:\n            fi = folder[resource_filepath]\n        except NotFound:\n            return\n        parent = self.get_parent(fi)\n        del parent[fi.getId()]\n        if filepath not in self.container:\n            return\n        folder = self.container[resource_name]\n        try:\n            fi = folder[resource_filepath]\n        except NotFound:\n            return\n        parent = self.get_parent(fi)\n        del parent[fi.getId()]\n\n    def get_parent(self, item):\n        path = '/'.join(item.getPhysicalPath()[:-1])\n        return self.context.restrictedTraverse(path)\n\n    def list_dir(self, container):\n        if hasattr(container, 'listDirectory'):\n            return container.listDirectory()\n        else:\n            return container.objectIds()\n\n\nclass ResourceRegistryControlPanelView(RequireJsView):\n\n    def __call__(self):\n        req = self.request\n        if req.REQUEST_METHOD == 'POST':\n            action = req.get('action', '')\n            method = action.replace('-', '_')\n            if hasattr(self, method):\n                return getattr(self, method)()\n            else:\n                return json.dumps({\n                    'success': False,\n                    'msg': 'Invalid action: ' + action\n                })\n        else:\n            return self.index()\n\n    @property\n    @memoize\n    def registry(self):\n        return getUtility(IRegistry)\n\n    def update_registry_collection(self, itype, prefix, newdata):\n        rdata = self.registry.collectionOfInterface(itype, prefix=prefix)\n        for key, data in newdata.items():\n            if key not in rdata:\n                record = rdata.add(key)\n            else:\n                record = rdata[key]\n            updateRecordFromDict(record, data)\n        # remove missing ones\n        for key in set(rdata.keys()) - set(newdata.keys()):\n            del rdata[key]\n\n    def save_development_mode(self):\n        if self.request.form.get('value', '').lower() == 'true':\n            self.registry['plone.resources.development'] = True\n        else:\n            self.registry['plone.resources.development'] = False\n        return json.dumps({\n            'success': True\n        })\n\n    def save_registry(self):\n        req = self.request\n\n        self.update_registry_collection(\n            IResourceRegistry, \"plone.resources\",\n            json.loads(req.get('resources')))\n        self.update_registry_collection(\n            IBundleRegistry, \"plone.bundles\",\n            json.loads(req.get('bundles')))\n\n        return json.dumps({\n            'success': True\n        })\n\n    def save_file(self):\n        req = self.request\n        resource_path = req.form.get('filepath').split('++plone++')[-1]\n        overrides = OverrideFolderManager(self.context)\n        overrides.save_file(resource_path, req.form['data'])\n        return json.dumps({\n            'success': True\n        })\n\n    def delete_file(self):\n        req = self.request\n        resource_path = req.form.get('filepath').split('++plone++')[-1]\n        overrides = OverrideFolderManager(self.context)\n        overrides.delete_file(resource_path)\n\n        return json.dumps({\n            'success': True\n        })\n\n    def get_bundles(self):\n        return self.registry.collectionOfInterface(\n            IBundleRegistry, prefix=\"plone.bundles\")\n\n    def get_resources(self):\n        return self.registry.collectionOfInterface(\n            IResourceRegistry, prefix=\"plone.resources\")\n\n    def less_build_config(self):\n        site_url = self.context.portal_url()\n        bundles = self.get_bundles()\n        bundle = self.request.get('bundle', None)\n        resources = self.get_resources()\n        less_files = []\n        if bundle and bundle in bundles:\n            bundle_obj = bundles[bundle]\n            for resource in bundle_obj.resources:\n                if resource in resources:\n                    for css in resources[resource].css:\n                        url = urlparse(css)\n                        if url.netloc == '':\n                            # Local\n                            src = \"%s/%s\" % (site_url, css)\n                        else:\n                            src = \"%s\" % (css)\n\n                        extension = url.path.split('.')[-1]\n                        if extension == 'less':\n                            less_files.append(src)\n        return json.dumps({\n            'less': less_files,\n        })\n\n    def js_build_config(self):\n        (baseUrl, paths, shims) = self.get_requirejs_config()\n        bundles = self.get_bundles()\n        resources = self.get_resources()\n\n        bundle = self.request.get('bundle', None)\n        includes = []\n        if bundle and bundle in bundles:\n            bundle_obj = bundles[bundle]\n            for resource_name in bundle_obj.resources:\n                # need to check if this resource has a js file\n                # it could just be a css resource\n                try:\n                    resource = resources[resource_name]\n                    if resource.js:\n                        includes.append(resource_name)\n                except KeyError:\n                    # skip if missing\n                    pass\n        return json.dumps({\n            'include': includes,\n            'shims': shims,\n            'paths': paths\n        })\n\n    def save_js_build(self):\n        overrides = OverrideFolderManager(self.context)\n        req = self.request\n        filepath = 'static/%s-compiled.js' % req.form['bundle']\n        overrides.save_file(filepath, req.form['data'])\n        bundle = self.get_bundles().get(req.form['bundle'])\n        if bundle:\n            bundle.last_compilation = datetime.now()\n            bundle.jscompilation = '++plone++{}'.format(filepath)\n        return json.dumps({\n            'success': True,\n            'filepath': '++plone++' + filepath\n        })\n\n    def save_less_build(self):\n        overrides = OverrideFolderManager(self.context)\n        req = self.request\n        filepath = 'static/%s-compiled.css' % req.form['bundle']\n        data = '\\n'.join([req.form[k] for k in req.form.keys()\n                          if k.startswith('data-')])\n        overrides.save_file(filepath, data)\n        bundle = self.get_bundles().get(req.form['bundle'])\n        if bundle:\n            bundle.last_compilation = datetime.now()\n            bundle.csscompilation = '++plone++{}'.format(filepath)\n        return json.dumps({\n            'success': True,\n            'filepath': '++plone++' + filepath\n        })\n\n    def save_less_variables(self):\n        data = {}\n        for key, val in json.loads(self.request.form.get('data')).items():\n            # need to convert to str: unicode\n            data[key.encode('utf8')] = val\n        self.registry['plone.lessvariables'] = data\n        return json.dumps({\n            'success': True\n        })\n\n    def save_pattern_options(self):\n        data = {}\n        for key, val in json.loads(self.request.form.get('data')).items():\n            # need to convert to str: unicode\n            data[key.encode('utf8')] = val\n        self.registry['plone.patternoptions'] = data\n        return json.dumps({\n            'success': True\n        })\n\n    def get_overrides(self):\n        overrides = OverrideFolderManager(self.context)\n\n        def _read_folder(folder):\n            files = []\n            for filename in folder.listDirectory():\n                item = folder[filename]\n                if folder.isDirectory(filename):\n                    files.extend(_read_folder(item))\n                else:\n                    files.append(item)\n            return files\n        files = _read_folder(overrides.container)\n        results = []\n        site_path = self.context.getPhysicalPath()\n        for fi in files:\n            path = fi.getPhysicalPath()\n            rel_path = path[len(site_path) + 2:]\n            results.append('++plone++%s/%s' % (\n                rel_path[0], '/'.join(rel_path[1:])))\n        return results\n\n    def config(self):\n        base_url = self.context.absolute_url()\n        resources = self.get_resources()\n\n        try:\n            less_url = self.registry['plone.resources.lessc']\n        except KeyError:\n            less_url = '++plone++static/components/less/dist/less-1.7.4.min.js'\n        try:\n            rjs_url = resources['rjs'].js\n        except KeyError:\n            rjs_url = '++plone++static/components/r.js/dist/r.js'\n\n        data = {\n            'development': self.registry['plone.resources.development'],\n            'lessvariables': self.registry['plone.lessvariables'],\n            'resources': {},\n            'bundles': {},\n            'javascripts': {},\n            'css': {},\n            'baseUrl': base_url,\n            'manageUrl': '%s/@@resourceregistry-controlpanel' % base_url,\n            'lessUrl': '%s/%s' % (base_url, less_url),\n            'lessConfigUrl': '%s/less-variables.js' % base_url,\n            'rjsUrl': rjs_url,\n            'patternoptions': self.registry['plone.patternoptions']\n        }\n        bundles = self.get_bundles()\n        for key, resource in resources.items():\n            data['resources'][key] = recordsToDict(resource)\n        for key, bundle in bundles.items():\n            data['bundles'][key] = recordsToDict(bundle)\n        data['overrides'] = self.get_overrides()\n        return json.dumps(data, cls=JSONEncoder)\n", "path": "Products/CMFPlone/controlpanel/browser/resourceregistry.py"}]}