prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Add a configuration of collections that the history plugin needs to keep track on
  Today the history plugin applies to all the collection but most of them don't need it.
  For instance with the kinto-signer plugin we don't want to track history of changes in the preview and signed collection.
  The same goes with the kinto-changes plugin when we don't want to track monitor changes modifications.
  
  The same way we can configure the kinto-signer resources we want to track, we should be able to configure the list of collections we want the history plugin to track.
  Add a configuration of collections that the history plugin needs to keep track on
  Today the history plugin applies to all the collection but most of them don't need it.
  For instance with the kinto-signer plugin we don't want to track history of changes in the preview and signed collection.
  The same goes with the kinto-changes plugin when we don't want to track monitor changes modifications.
  
  The same way we can configure the kinto-signer resources we want to track, we should be able to configure the list of collections we want the history plugin to track.
  
  </issue>
  <code>
  [start of kinto/plugins/history/listener.py]
  1 from kinto.core.utils import instance_uri
  2 from datetime import datetime
  3 
  4 
  5 def on_resource_changed(event):
  6     """
  7     Everytime an object is created/changed/deleted, we create an entry in the
  8     ``history`` resource. The entries are served as read-only in the
  9     :mod:`kinto.plugins.history.views` module.
  10     """
  11     payload = event.payload
  12     resource_name = payload['resource_name']
  13     event_uri = payload['uri']
  14 
  15     bucket_id = None
  16     bucket_uri = None
  17     collection_uri = None
  18 
  19     storage = event.request.registry.storage
  20     permission = event.request.registry.permission
  21 
  22     targets = []
  23     for impacted in event.impacted_records:
  24         target = impacted['new']
  25         obj_id = target['id']
  26 
  27         try:
  28             bucket_id = payload['bucket_id']
  29         except KeyError:
  30             # e.g. DELETE /buckets
  31             bucket_id = obj_id
  32         bucket_uri = instance_uri(event.request, 'bucket', id=bucket_id)
  33 
  34         if 'collection_id' in payload:
  35             collection_id = payload['collection_id']
  36             collection_uri = instance_uri(event.request,
  37                                           'collection',
  38                                           bucket_id=bucket_id,
  39                                           id=collection_id)
  40 
  41         # On POST .../records, the URI does not contain the newly created
  42         # record id.
  43         parts = event_uri.split('/')
  44         if resource_name in parts[-1]:
  45             parts.append(obj_id)
  46         else:
  47             # Make sure the id is correct on grouped events.
  48             parts[-1] = obj_id
  49         uri = '/'.join(parts)
  50         targets.append((uri, target))
  51 
  52     # Prepare a list of object ids to be fetched from permission backend,
  53     # and fetch them all at once. Use a mapping for later convenience.
  54     all_perms_objects_ids = [oid for (oid, _) in targets]
  55     all_perms_objects_ids.append(bucket_uri)
  56     if collection_uri is not None:
  57         all_perms_objects_ids.append(collection_uri)
  58     all_perms_objects_ids = list(set(all_perms_objects_ids))
  59     all_permissions = permission.get_objects_permissions(all_perms_objects_ids)
  60     perms_by_object_id = dict(zip(all_perms_objects_ids, all_permissions))
  61 
  62     bucket_perms = perms_by_object_id[bucket_uri]
  63     collection_perms = {}
  64     if collection_uri is not None:
  65         collection_perms = perms_by_object_id[collection_uri]
  66 
  67     # The principals allowed to read the bucket and collection.
  68     # (Note: ``write`` means ``read``)
  69     read_principals = set(bucket_perms.get('read', []))
  70     read_principals.update(bucket_perms.get('write', []))
  71     read_principals.update(collection_perms.get('read', []))
  72     read_principals.update(collection_perms.get('write', []))
  73 
  74     # Create a history entry for each impacted record.
  75     for (uri, target) in targets:
  76         obj_id = target['id']
  77         # Prepare the history entry attributes.
  78         perms = {k: list(v) for k, v in perms_by_object_id[uri].items()}
  79         eventattrs = dict(**payload)
  80         eventattrs.pop('timestamp', None)  # Already in target `last_modified`.
  81         eventattrs.pop('bucket_id', None)
  82         eventattrs['%s_id' % resource_name] = obj_id
  83         eventattrs['uri'] = uri
  84         attrs = dict(date=datetime.now().isoformat(),
  85                      target={'data': target, 'permissions': perms},
  86                      **eventattrs)
  87 
  88         # Create a record for the 'history' resource, whose parent_id is
  89         # the bucket URI (c.f. views.py).
  90         # Note: this will be rolledback if the transaction is rolledback.
  91         entry = storage.create(parent_id=bucket_uri,
  92                                collection_id='history',
  93                                record=attrs)
  94 
  95         # The read permission on the newly created history entry is the union
  96         # of the record permissions with the one from bucket and collection.
  97         entry_principals = set(read_principals)
  98         entry_principals.update(perms.get('read', []))
  99         entry_principals.update(perms.get('write', []))
  100         entry_perms = {'read': list(entry_principals)}
  101         # /buckets/{id}/history is the URI for the list of history entries.
  102         entry_perm_id = '/buckets/%s/history/%s' % (bucket_id, entry['id'])
  103         permission.replace_object_permissions(entry_perm_id, entry_perms)
  104
  [end of kinto/plugins/history/listener.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/kinto/plugins/history/listener.py b/kinto/plugins/history/listener.py
  --- a/kinto/plugins/history/listener.py
  +++ b/kinto/plugins/history/listener.py
  @@ -1,3 +1,5 @@
  +from pyramid.settings import aslist
  +
   from kinto.core.utils import instance_uri
   from datetime import datetime
   
  @@ -18,6 +20,9 @@
   
       storage = event.request.registry.storage
       permission = event.request.registry.permission
  +    settings = event.request.registry.settings
  +
  +    excluded_resources = aslist(settings.get('history.exclude_resources', ''))
   
       targets = []
       for impacted in event.impacted_records:
  @@ -31,12 +36,17 @@
               bucket_id = obj_id
           bucket_uri = instance_uri(event.request, 'bucket', id=bucket_id)
   
  +        if bucket_uri in excluded_resources:
  +            continue
  +
           if 'collection_id' in payload:
               collection_id = payload['collection_id']
               collection_uri = instance_uri(event.request,
                                             'collection',
                                             bucket_id=bucket_id,
                                             id=collection_id)
  +            if collection_uri in excluded_resources:
  +                continue
   
           # On POST .../records, the URI does not contain the newly created
           # record id.
  @@ -47,8 +57,15 @@
               # Make sure the id is correct on grouped events.
               parts[-1] = obj_id
           uri = '/'.join(parts)
  +
  +        if uri in excluded_resources:
  +            continue
  +
           targets.append((uri, target))
   
  +    if not targets:
  +        return  # Nothing to do.
  +
       # Prepare a list of object ids to be fetched from permission backend,
       # and fetch them all at once. Use a mapping for later convenience.
       all_perms_objects_ids = [oid for (oid, _) in targets]
  
verification_info: {"golden_diff": "diff --git a/kinto/plugins/history/listener.py b/kinto/plugins/history/listener.py\n--- a/kinto/plugins/history/listener.py\n+++ b/kinto/plugins/history/listener.py\n@@ -1,3 +1,5 @@\n+from pyramid.settings import aslist\n+\n from kinto.core.utils import instance_uri\n from datetime import datetime\n \n@@ -18,6 +20,9 @@\n \n     storage = event.request.registry.storage\n     permission = event.request.registry.permission\n+    settings = event.request.registry.settings\n+\n+    excluded_resources = aslist(settings.get('history.exclude_resources', ''))\n \n     targets = []\n     for impacted in event.impacted_records:\n@@ -31,12 +36,17 @@\n             bucket_id = obj_id\n         bucket_uri = instance_uri(event.request, 'bucket', id=bucket_id)\n \n+        if bucket_uri in excluded_resources:\n+            continue\n+\n         if 'collection_id' in payload:\n             collection_id = payload['collection_id']\n             collection_uri = instance_uri(event.request,\n                                           'collection',\n                                           bucket_id=bucket_id,\n                                           id=collection_id)\n+            if collection_uri in excluded_resources:\n+                continue\n \n         # On POST .../records, the URI does not contain the newly created\n         # record id.\n@@ -47,8 +57,15 @@\n             # Make sure the id is correct on grouped events.\n             parts[-1] = obj_id\n         uri = '/'.join(parts)\n+\n+        if uri in excluded_resources:\n+            continue\n+\n         targets.append((uri, target))\n \n+    if not targets:\n+        return  # Nothing to do.\n+\n     # Prepare a list of object ids to be fetched from permission backend,\n     # and fetch them all at once. Use a mapping for later convenience.\n     all_perms_objects_ids = [oid for (oid, _) in targets]\n", "issue": "Add a configuration of collections that the history plugin needs to keep track on\nToday the history plugin applies to all the collection but most of them don't need it.\r\nFor instance with the kinto-signer plugin we don't want to track history of changes in the preview and signed collection.\r\nThe same goes with the kinto-changes plugin when we don't want to track monitor changes modifications.\r\n\r\nThe same way we can configure the kinto-signer resources we want to track, we should be able to configure the list of collections we want the history plugin to track.\nAdd a configuration of collections that the history plugin needs to keep track on\nToday the history plugin applies to all the collection but most of them don't need it.\r\nFor instance with the kinto-signer plugin we don't want to track history of changes in the preview and signed collection.\r\nThe same goes with the kinto-changes plugin when we don't want to track monitor changes modifications.\r\n\r\nThe same way we can configure the kinto-signer resources we want to track, we should be able to configure the list of collections we want the history plugin to track.\n", "before_files": [{"content": "from kinto.core.utils import instance_uri\nfrom datetime import datetime\n\n\ndef on_resource_changed(event):\n    \"\"\"\n    Everytime an object is created/changed/deleted, we create an entry in the\n    ``history`` resource. The entries are served as read-only in the\n    :mod:`kinto.plugins.history.views` module.\n    \"\"\"\n    payload = event.payload\n    resource_name = payload['resource_name']\n    event_uri = payload['uri']\n\n    bucket_id = None\n    bucket_uri = None\n    collection_uri = None\n\n    storage = event.request.registry.storage\n    permission = event.request.registry.permission\n\n    targets = []\n    for impacted in event.impacted_records:\n        target = impacted['new']\n        obj_id = target['id']\n\n        try:\n            bucket_id = payload['bucket_id']\n        except KeyError:\n            # e.g. DELETE /buckets\n            bucket_id = obj_id\n        bucket_uri = instance_uri(event.request, 'bucket', id=bucket_id)\n\n        if 'collection_id' in payload:\n            collection_id = payload['collection_id']\n            collection_uri = instance_uri(event.request,\n                                          'collection',\n                                          bucket_id=bucket_id,\n                                          id=collection_id)\n\n        # On POST .../records, the URI does not contain the newly created\n        # record id.\n        parts = event_uri.split('/')\n        if resource_name in parts[-1]:\n            parts.append(obj_id)\n        else:\n            # Make sure the id is correct on grouped events.\n            parts[-1] = obj_id\n        uri = '/'.join(parts)\n        targets.append((uri, target))\n\n    # Prepare a list of object ids to be fetched from permission backend,\n    # and fetch them all at once. Use a mapping for later convenience.\n    all_perms_objects_ids = [oid for (oid, _) in targets]\n    all_perms_objects_ids.append(bucket_uri)\n    if collection_uri is not None:\n        all_perms_objects_ids.append(collection_uri)\n    all_perms_objects_ids = list(set(all_perms_objects_ids))\n    all_permissions = permission.get_objects_permissions(all_perms_objects_ids)\n    perms_by_object_id = dict(zip(all_perms_objects_ids, all_permissions))\n\n    bucket_perms = perms_by_object_id[bucket_uri]\n    collection_perms = {}\n    if collection_uri is not None:\n        collection_perms = perms_by_object_id[collection_uri]\n\n    # The principals allowed to read the bucket and collection.\n    # (Note: ``write`` means ``read``)\n    read_principals = set(bucket_perms.get('read', []))\n    read_principals.update(bucket_perms.get('write', []))\n    read_principals.update(collection_perms.get('read', []))\n    read_principals.update(collection_perms.get('write', []))\n\n    # Create a history entry for each impacted record.\n    for (uri, target) in targets:\n        obj_id = target['id']\n        # Prepare the history entry attributes.\n        perms = {k: list(v) for k, v in perms_by_object_id[uri].items()}\n        eventattrs = dict(**payload)\n        eventattrs.pop('timestamp', None)  # Already in target `last_modified`.\n        eventattrs.pop('bucket_id', None)\n        eventattrs['%s_id' % resource_name] = obj_id\n        eventattrs['uri'] = uri\n        attrs = dict(date=datetime.now().isoformat(),\n                     target={'data': target, 'permissions': perms},\n                     **eventattrs)\n\n        # Create a record for the 'history' resource, whose parent_id is\n        # the bucket URI (c.f. views.py).\n        # Note: this will be rolledback if the transaction is rolledback.\n        entry = storage.create(parent_id=bucket_uri,\n                               collection_id='history',\n                               record=attrs)\n\n        # The read permission on the newly created history entry is the union\n        # of the record permissions with the one from bucket and collection.\n        entry_principals = set(read_principals)\n        entry_principals.update(perms.get('read', []))\n        entry_principals.update(perms.get('write', []))\n        entry_perms = {'read': list(entry_principals)}\n        # /buckets/{id}/history is the URI for the list of history entries.\n        entry_perm_id = '/buckets/%s/history/%s' % (bucket_id, entry['id'])\n        permission.replace_object_permissions(entry_perm_id, entry_perms)\n", "path": "kinto/plugins/history/listener.py"}]}