)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"9804bf8a2223021da1476e88f828fd1b110666ff","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Simple subnetpool allocation quotas"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Enables enforcement of allocation quotas on subnet pools. The quota"},{"line_number":10,"context_line":"is pool-wide, with the value of allocation_quota applied to every"},{"line_number":11,"context_line":"tenant who uses the pool. allocation_quota must be non-negative,"},{"line_number":12,"context_line":"and is an optional attribute. If not supplied, no quotas are"},{"line_number":13,"context_line":"enforced. Quotas are measured in prefix space allocated. For IPv4"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"9a80dd14_07d7cdbf","line":10,"updated":"2015-03-20 21:14:50.000000000","message":"We may need to follow this up with tenant specific quota capability.  This would be considered the default tenant quota.  A pool owner may want to treat some tenants as special and give them a bigger quota in the same pool.  But, I\u0027m happy to accept this patch as you\u0027ve outlined assuming everything else is good.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":14,"context_line":"subnet pools, the quota is measured in units of /32 ie each tenant"},{"line_number":15,"context_line":"can allocate up to X /32\u0027s from the pool. For IPv6 subnet pools, the"},{"line_number":16,"context_line":"quota is measured in units of /64 ie each tenant can allocate up to"},{"line_number":17,"context_line":"X /64\u0027s from the pool. For backward-compatibility, allocation quotas"},{"line_number":18,"context_line":"are not applied to the implicit (AKA null) pool. Standard subnet"},{"line_number":19,"context_line":"quotas will continue to be applied to all requests."},{"line_number":20,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"1a6ced46_9405177c","line":17,"updated":"2015-03-25 11:03:09.000000000","message":"are /32s and /64s arbitrary choices? What if a tenant starts allocating /66 subnets from a IPv6 pool? Would those count as 0.25 allocation units? Is that accounted for in your patch?","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"350b9c13639a5326ceb3a197cc31db7635f17d3c","unresolved":false,"context_lines":[{"line_number":14,"context_line":"subnet pools, the quota is measured in units of /32 ie each tenant"},{"line_number":15,"context_line":"can allocate up to X /32\u0027s from the pool. For IPv6 subnet pools, the"},{"line_number":16,"context_line":"quota is measured in units of /64 ie each tenant can allocate up to"},{"line_number":17,"context_line":"X /64\u0027s from the pool. For backward-compatibility, allocation quotas"},{"line_number":18,"context_line":"are not applied to the implicit (AKA null) pool. Standard subnet"},{"line_number":19,"context_line":"quotas will continue to be applied to all requests."},{"line_number":20,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"fa963961_5cc4353f","line":17,"in_reply_to":"1a6ced46_9405177c","updated":"2015-03-26 15:59:27.000000000","message":"It wasn\u0027t arbitrary.  I discussed this at length with Sean Collins.  Neutron doesn\u0027t allow anything less than /64.  He signed off on this with an update to the spec [1] which he requested I make to address his concerns.  You might recall that update.\n\n[1] https://review.openstack.org/#/c/142231/","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":15,"context_line":"can allocate up to X /32\u0027s from the pool. For IPv6 subnet pools, the"},{"line_number":16,"context_line":"quota is measured in units of /64 ie each tenant can allocate up to"},{"line_number":17,"context_line":"X /64\u0027s from the pool. For backward-compatibility, allocation quotas"},{"line_number":18,"context_line":"are not applied to the implicit (AKA null) pool. Standard subnet"},{"line_number":19,"context_line":"quotas will continue to be applied to all requests."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"ApiImpact"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"1a6ced46_74a97b7a","line":18,"updated":"2015-03-25 11:03:09.000000000","message":"well, did we agree that this implicit pool does not exist after all? It\u0027s null for a reason!\n\nIf yes, please change the commit message.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"9804bf8a2223021da1476e88f828fd1b110666ff","unresolved":false,"context_lines":[{"line_number":18,"context_line":"are not applied to the implicit (AKA null) pool. Standard subnet"},{"line_number":19,"context_line":"quotas will continue to be applied to all requests."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"ApiImpact"},{"line_number":22,"context_line":"Partially-Implements: blueprint subnet-allocation"},{"line_number":23,"context_line":"Change-Id: I7e4641f47790414c693c7cc9b7a44b1889087801"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"9a80dd14_847d7be9","line":21,"updated":"2015-03-20 21:14:50.000000000","message":"We probably will need a DocImpact here to draw attention to your explanation of how these quotas will work and get that in the docs.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":4187,"name":"Ryan Tidwell","email":"rtidwell@suse.com","username":"ryan-tidwell"},"change_message_id":"69040caa1e2e94da8d8539d643f8cea31477cbdc","unresolved":false,"context_lines":[{"line_number":18,"context_line":"are not applied to the implicit (AKA null) pool. Standard subnet"},{"line_number":19,"context_line":"quotas will continue to be applied to all requests."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"ApiImpact"},{"line_number":22,"context_line":"Partially-Implements: blueprint subnet-allocation"},{"line_number":23,"context_line":"Change-Id: I7e4641f47790414c693c7cc9b7a44b1889087801"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"9a80dd14_baab7486","line":21,"in_reply_to":"9a80dd14_847d7be9","updated":"2015-03-20 21:35:35.000000000","message":"Done","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"7a316427df414eea51dcc319d24582ff43e9ab83","unresolved":false,"context_lines":[{"line_number":13,"context_line":"enforced. Quotas are measured in prefix space allocated. For IPv4"},{"line_number":14,"context_line":"subnet pools, the quota is measured in units of /32 ie each tenant"},{"line_number":15,"context_line":"can allocate up to X /32\u0027s from the pool. For IPv6 subnet pools, the"},{"line_number":16,"context_line":"quota is measured in units of /64 ie each tenant can allocate up to"},{"line_number":17,"context_line":"X /64\u0027s from the pool. For backward-compatibility, allocation quotas"},{"line_number":18,"context_line":"are not applied to the implicit (AKA null) pool. Standard subnet"},{"line_number":19,"context_line":"quotas will continue to be applied to all requests."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"da9b358b_3214da42","line":16,"updated":"2015-03-30 13:53:12.000000000","message":"I did not know Neutron did not support anything smaller than a /64. Anyway, we just have to accept it then.","commit_id":"4a93b75a7e5e2fd43cbc501f1c940bf1b6e2245b"}],"neutron/api/v2/attributes.py":[{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":855,"context_line":"                         \u0027validate\u0027: {\u0027type:non_negative\u0027: None},"},{"line_number":856,"context_line":"                         \u0027convert_to\u0027: convert_to_int,"},{"line_number":857,"context_line":"                         \u0027default\u0027: ATTR_NOT_SPECIFIED,"},{"line_number":858,"context_line":"                         \u0027is_visible\u0027: True},"},{"line_number":859,"context_line":"        \u0027ip_version\u0027: {\u0027allow_post\u0027: False,"},{"line_number":860,"context_line":"                       \u0027allow_put\u0027: False,"},{"line_number":861,"context_line":"                       \u0027is_visible\u0027: True},"}],"source_content_type":"text/x-python","patch_set":5,"id":"1a6ced46_8f27c2b5","line":858,"updated":"2015-03-25 11:03:09.000000000","message":"I reckon this attribute only makes sense for shared pools. If shared\u003dFalse then it should no be specified, unless there is a use case to limit how much of a pool its owner can use!\nIn the shared case however, allocation quota should be set on a tenant basis. You would expect admin users or the pool owner to have different allocation quotas. However, since I understand this is a default, this point probably does not apply here. Still I\u0027m not sure how you plan to implement per-tenant and per-pool quotas using the current quota API. I don\u0027t think that having specific APIs for managing pool quotas is a good solution from a usability perspective.\nI would prefer quotas to be managed within the quota APIs. This will not allow you, within the current framework, to have per-pool quotas. But this will be consistent with the rest of neutron. For instance you cannot have per-network port quotas.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"7a316427df414eea51dcc319d24582ff43e9ab83","unresolved":false,"context_lines":[{"line_number":855,"context_line":"                          \u0027validate\u0027: {\u0027type:non_negative\u0027: None},"},{"line_number":856,"context_line":"                          \u0027convert_to\u0027: convert_to_int,"},{"line_number":857,"context_line":"                          \u0027default\u0027: ATTR_NOT_SPECIFIED,"},{"line_number":858,"context_line":"                          \u0027is_visible\u0027: True},"},{"line_number":859,"context_line":"        \u0027ip_version\u0027: {\u0027allow_post\u0027: False,"},{"line_number":860,"context_line":"                       \u0027allow_put\u0027: False,"},{"line_number":861,"context_line":"                       \u0027is_visible\u0027: True},"}],"source_content_type":"text/x-python","patch_set":8,"id":"da9b358b_92872661","line":858,"updated":"2015-03-30 13:53:12.000000000","message":"any answer to my comment in pset 5?\nwhat does a default quota mean if the pool is not shared?","commit_id":"4a93b75a7e5e2fd43cbc501f1c940bf1b6e2245b"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"34e7d6f1cff895f15a386236dcbc3dfb215ea655","unresolved":false,"context_lines":[{"line_number":855,"context_line":"                          \u0027validate\u0027: {\u0027type:non_negative\u0027: None},"},{"line_number":856,"context_line":"                          \u0027convert_to\u0027: convert_to_int,"},{"line_number":857,"context_line":"                          \u0027default\u0027: ATTR_NOT_SPECIFIED,"},{"line_number":858,"context_line":"                          \u0027is_visible\u0027: True},"},{"line_number":859,"context_line":"        \u0027ip_version\u0027: {\u0027allow_post\u0027: False,"},{"line_number":860,"context_line":"                       \u0027allow_put\u0027: False,"},{"line_number":861,"context_line":"                       \u0027is_visible\u0027: True},"}],"source_content_type":"text/x-python","patch_set":8,"id":"da9b358b_3f0a5527","line":858,"in_reply_to":"da9b358b_92872661","updated":"2015-03-30 18:28:52.000000000","message":"@Salvatore.  I have to ask myself:  why would a user fill in this field for one that isn\u0027t shared.  He is only putting a limit on himself.  Is it so bad?  If he hits the limit he put on himself, he has the power to increase it.\n\nWould you be happy if we documented that default_quota is only useful for shared pools?  Do you think we should enforce that quotas only be set for shared pools?  Would you accept a bug filed to address this?","commit_id":"4a93b75a7e5e2fd43cbc501f1c940bf1b6e2245b"}],"neutron/db/models_v2.py":[{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"9804bf8a2223021da1476e88f828fd1b110666ff","unresolved":false,"context_lines":[{"line_number":247,"context_line":"    max_prefixlen \u003d sa.Column(sa.Integer, nullable\u003dFalse)"},{"line_number":248,"context_line":"    shared \u003d sa.Column(sa.Boolean, nullable\u003dFalse)"},{"line_number":249,"context_line":"    allow_overlap \u003d sa.Column(sa.Boolean, nullable\u003dFalse)"},{"line_number":250,"context_line":"    allocation_quota \u003d sa.Column(sa.Integer, nullable\u003dTrue)"},{"line_number":251,"context_line":"    prefixes \u003d orm.relationship(SubnetPoolPrefix,"},{"line_number":252,"context_line":"                                backref\u003d\u0027subnetpools\u0027,"},{"line_number":253,"context_line":"                                cascade\u003d\u0027all, delete, delete-orphan\u0027,"}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_e489d7ca","line":250,"updated":"2015-03-20 21:14:50.000000000","message":"I wonder if we should do either:\n\n1) call this default_quota instead of allocation_quota.  Worry about tenant-specific quotas later.\n\n2) create a new table with (tenant_id, quota).  The default quota for the pool could be entered with tenant_id\u003dnull.\n\nI think we\u0027ll need a separate table when we support tenant-specific quotas.  However, I think I lean toward option #1 for now and leave the new table out of it.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"350b9c13639a5326ceb3a197cc31db7635f17d3c","unresolved":false,"context_lines":[{"line_number":247,"context_line":"    max_prefixlen \u003d sa.Column(sa.Integer, nullable\u003dFalse)"},{"line_number":248,"context_line":"    shared \u003d sa.Column(sa.Boolean, nullable\u003dFalse)"},{"line_number":249,"context_line":"    allow_overlap \u003d sa.Column(sa.Boolean, nullable\u003dFalse)"},{"line_number":250,"context_line":"    allocation_quota \u003d sa.Column(sa.Integer, nullable\u003dTrue)"},{"line_number":251,"context_line":"    prefixes \u003d orm.relationship(SubnetPoolPrefix,"},{"line_number":252,"context_line":"                                backref\u003d\u0027subnetpools\u0027,"},{"line_number":253,"context_line":"                                cascade\u003d\u0027all, delete, delete-orphan\u0027,"}],"source_content_type":"text/x-python","patch_set":5,"id":"fa963961_1c122db5","line":250,"in_reply_to":"9a80dd14_9a0cf0ed","updated":"2015-03-26 15:59:27.000000000","message":"+1.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":4187,"name":"Ryan Tidwell","email":"rtidwell@suse.com","username":"ryan-tidwell"},"change_message_id":"69040caa1e2e94da8d8539d643f8cea31477cbdc","unresolved":false,"context_lines":[{"line_number":247,"context_line":"    max_prefixlen \u003d sa.Column(sa.Integer, nullable\u003dFalse)"},{"line_number":248,"context_line":"    shared \u003d sa.Column(sa.Boolean, nullable\u003dFalse)"},{"line_number":249,"context_line":"    allow_overlap \u003d sa.Column(sa.Boolean, nullable\u003dFalse)"},{"line_number":250,"context_line":"    allocation_quota \u003d sa.Column(sa.Integer, nullable\u003dTrue)"},{"line_number":251,"context_line":"    prefixes \u003d orm.relationship(SubnetPoolPrefix,"},{"line_number":252,"context_line":"                                backref\u003d\u0027subnetpools\u0027,"},{"line_number":253,"context_line":"                                cascade\u003d\u0027all, delete, delete-orphan\u0027,"}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_9a0cf0ed","line":250,"in_reply_to":"9a80dd14_e489d7ca","updated":"2015-03-20 21:35:35.000000000","message":"The spirit of option 1 is what I had in mind. I\u0027ll rename this so it\u0027s clearer.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"}],"neutron/ipam/subnet_alloc.py":[{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"9804bf8a2223021da1476e88f828fd1b110666ff","unresolved":false,"context_lines":[{"line_number":65,"context_line":"            qry \u003d session.query("},{"line_number":66,"context_line":"                 models_v2.SubnetAllocation).with_lockmode(\u0027update\u0027)"},{"line_number":67,"context_line":"            allocations \u003d qry.filter_by(subnetpool_id\u003dsubnetpool_id,"},{"line_number":68,"context_line":"                                        tenant_id\u003dtenant_id).all()"},{"line_number":69,"context_line":"            value \u003d 0"},{"line_number":70,"context_line":"            for allocation in allocations:"},{"line_number":71,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_841c9b78","line":68,"updated":"2015-03-20 21:14:50.000000000","message":"nit:  .all() not needed (I don\u0027t think).","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":4187,"name":"Ryan Tidwell","email":"rtidwell@suse.com","username":"ryan-tidwell"},"change_message_id":"69040caa1e2e94da8d8539d643f8cea31477cbdc","unresolved":false,"context_lines":[{"line_number":65,"context_line":"            qry \u003d session.query("},{"line_number":66,"context_line":"                 models_v2.SubnetAllocation).with_lockmode(\u0027update\u0027)"},{"line_number":67,"context_line":"            allocations \u003d qry.filter_by(subnetpool_id\u003dsubnetpool_id,"},{"line_number":68,"context_line":"                                        tenant_id\u003dtenant_id).all()"},{"line_number":69,"context_line":"            value \u003d 0"},{"line_number":70,"context_line":"            for allocation in allocations:"},{"line_number":71,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_badd3443","line":68,"in_reply_to":"9a80dd14_841c9b78","updated":"2015-03-20 21:35:35.000000000","message":"I think I had it as you suggest and I think I remember having to tack on.all(). I\u0027ll give this another look.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":65,"context_line":"            qry \u003d session.query("},{"line_number":66,"context_line":"                 models_v2.SubnetAllocation).with_lockmode(\u0027update\u0027)"},{"line_number":67,"context_line":"            allocations \u003d qry.filter_by(subnetpool_id\u003dsubnetpool_id,"},{"line_number":68,"context_line":"                                        tenant_id\u003dtenant_id).all()"},{"line_number":69,"context_line":"            value \u003d 0"},{"line_number":70,"context_line":"            for allocation in allocations:"},{"line_number":71,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"}],"source_content_type":"text/x-python","patch_set":5,"id":"1a6ced46_9301ac07","line":68,"in_reply_to":"9a80dd14_badd3443","updated":"2015-03-25 11:03:09.000000000","message":"all() will give you a list, but the sqlalchemy query is an iterator as well, so you should not need it for any reason","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"9804bf8a2223021da1476e88f828fd1b110666ff","unresolved":false,"context_lines":[{"line_number":68,"context_line":"                                        tenant_id\u003dtenant_id).all()"},{"line_number":69,"context_line":"            value \u003d 0"},{"line_number":70,"context_line":"            for allocation in allocations:"},{"line_number":71,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"},{"line_number":72,"context_line":"                value +\u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":73,"context_line":"            return value"},{"line_number":74,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_8709fdde","line":71,"updated":"2015-03-20 21:14:50.000000000","message":"This is a non-obvious piece of computation (L72).  It might be a good place for an example or two.  Maybe an ipv4 example and an ipv6 one.\n\nThe computation is correct, I just think readers might appreciate a little help.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":4187,"name":"Ryan Tidwell","email":"rtidwell@suse.com","username":"ryan-tidwell"},"change_message_id":"69040caa1e2e94da8d8539d643f8cea31477cbdc","unresolved":false,"context_lines":[{"line_number":68,"context_line":"                                        tenant_id\u003dtenant_id).all()"},{"line_number":69,"context_line":"            value \u003d 0"},{"line_number":70,"context_line":"            for allocation in allocations:"},{"line_number":71,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"},{"line_number":72,"context_line":"                value +\u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":73,"context_line":"            return value"},{"line_number":74,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_3ae944e3","line":71,"in_reply_to":"9a80dd14_8709fdde","updated":"2015-03-20 21:35:35.000000000","message":"Done","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"9804bf8a2223021da1476e88f828fd1b110666ff","unresolved":false,"context_lines":[{"line_number":69,"context_line":"            value \u003d 0"},{"line_number":70,"context_line":"            for allocation in allocations:"},{"line_number":71,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"},{"line_number":72,"context_line":"                value +\u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":73,"context_line":"            return value"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    def _check_subnetpool_tenant_quota(self, session, tenant_id, prefixlen):"}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_a75521c3","line":72,"updated":"2015-03-20 21:14:50.000000000","message":"Since math.pow returns a floating point number, you might consider wrapping it with int(...)\n\n  value +\u003d int(math.pow(2, quota_unit - prefixlen))","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":4187,"name":"Ryan Tidwell","email":"rtidwell@suse.com","username":"ryan-tidwell"},"change_message_id":"69040caa1e2e94da8d8539d643f8cea31477cbdc","unresolved":false,"context_lines":[{"line_number":69,"context_line":"            value \u003d 0"},{"line_number":70,"context_line":"            for allocation in allocations:"},{"line_number":71,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"},{"line_number":72,"context_line":"                value +\u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":73,"context_line":"            return value"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    def _check_subnetpool_tenant_quota(self, session, tenant_id, prefixlen):"}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_dae74810","line":72,"in_reply_to":"9a80dd14_a75521c3","updated":"2015-03-20 21:35:35.000000000","message":"Done","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":69,"context_line":"            value \u003d 0"},{"line_number":70,"context_line":"            for allocation in allocations:"},{"line_number":71,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"},{"line_number":72,"context_line":"                value +\u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":73,"context_line":"            return value"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    def _check_subnetpool_tenant_quota(self, session, tenant_id, prefixlen):"}],"source_content_type":"text/x-python","patch_set":5,"id":"1a6ced46_7318b075","line":72,"in_reply_to":"9a80dd14_dae74810","updated":"2015-03-25 11:03:09.000000000","message":"Idk... perhaps we want a decimal number... since  prefixlen can be greater than quota_unit","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    def _check_subnetpool_tenant_quota(self, session, tenant_id, prefixlen):"},{"line_number":76,"context_line":"        quota_unit \u003d self._sp_helper.ip_version_subnetpool_quota_unit("},{"line_number":77,"context_line":"                                               self._subnetpool[\u0027ip_version\u0027])"},{"line_number":78,"context_line":"        quota \u003d self._subnetpool.get(\u0027allocation_quota\u0027,"},{"line_number":79,"context_line":"                                     attributes.ATTR_NOT_SPECIFIED)"},{"line_number":80,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"1a6ced46_b3a8688e","line":77,"updated":"2015-03-25 11:03:09.000000000","message":"It seems this patch assumes that allocating v6 subnets with a prefix greater than /64 is something that should not be done.\nI know quite little about ipv6, what\u0027s the reason for that?","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":76,"context_line":"        quota_unit \u003d self._sp_helper.ip_version_subnetpool_quota_unit("},{"line_number":77,"context_line":"                                               self._subnetpool[\u0027ip_version\u0027])"},{"line_number":78,"context_line":"        quota \u003d self._subnetpool.get(\u0027allocation_quota\u0027,"},{"line_number":79,"context_line":"                                     attributes.ATTR_NOT_SPECIFIED)"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if quota:"},{"line_number":82,"context_line":"            used \u003d self._allocations_used_by_tenant(session, quota_unit)"}],"source_content_type":"text/x-python","patch_set":5,"id":"1a6ced46_53ef34e9","line":79,"updated":"2015-03-25 11:03:09.000000000","message":"I don\u0027t see any good reason for defaulting to attribues.ATTR_NOT_SPECIFIED. That value is only used at the API layer to distinguish an explicit null value for an unspecified one.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"9804bf8a2223021da1476e88f828fd1b110666ff","unresolved":false,"context_lines":[{"line_number":78,"context_line":"        quota \u003d self._subnetpool.get(\u0027allocation_quota\u0027,"},{"line_number":79,"context_line":"                                     attributes.ATTR_NOT_SPECIFIED)"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if quota:"},{"line_number":82,"context_line":"            used \u003d self._allocations_used_by_tenant(session, quota_unit)"},{"line_number":83,"context_line":"            requested_units \u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":84,"context_line":"            if used + requested_units \u003e quota:"}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_c77cd573","line":81,"updated":"2015-03-20 21:14:50.000000000","message":"style nit:  I always prefer this:\n\n  if not quota:\n      return\n\n  ...\n\nIt reduces indentation and I always like a quick return if we\u0027ve decided we don\u0027t have anything else to do in the method.  As a code reader, it means I don\u0027t have to scroll down a potentially long method to see if there is an \"else\" hanging out down there.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"350b9c13639a5326ceb3a197cc31db7635f17d3c","unresolved":false,"context_lines":[{"line_number":78,"context_line":"        quota \u003d self._subnetpool.get(\u0027allocation_quota\u0027,"},{"line_number":79,"context_line":"                                     attributes.ATTR_NOT_SPECIFIED)"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if quota:"},{"line_number":82,"context_line":"            used \u003d self._allocations_used_by_tenant(session, quota_unit)"},{"line_number":83,"context_line":"            requested_units \u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":84,"context_line":"            if used + requested_units \u003e quota:"}],"source_content_type":"text/x-python","patch_set":5,"id":"fa963961_498d927a","line":81,"in_reply_to":"1a6ced46_3339d8d7","updated":"2015-03-26 15:59:27.000000000","message":"Feel free to ignore all of my nits.  ;)  I don\u0027t vote negatively for them.  I just add them in case you\u0027re interested.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":78,"context_line":"        quota \u003d self._subnetpool.get(\u0027allocation_quota\u0027,"},{"line_number":79,"context_line":"                                     attributes.ATTR_NOT_SPECIFIED)"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if quota:"},{"line_number":82,"context_line":"            used \u003d self._allocations_used_by_tenant(session, quota_unit)"},{"line_number":83,"context_line":"            requested_units \u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":84,"context_line":"            if used + requested_units \u003e quota:"}],"source_content_type":"text/x-python","patch_set":5,"id":"1a6ced46_3339d8d7","line":81,"in_reply_to":"9a80dd14_c77cd573","updated":"2015-03-25 11:03:09.000000000","message":"I\u0027m ok either way.\nI know of another cult that don\u0027t like negative conditions though ;)","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"9804bf8a2223021da1476e88f828fd1b110666ff","unresolved":false,"context_lines":[{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if quota:"},{"line_number":82,"context_line":"            used \u003d self._allocations_used_by_tenant(session, quota_unit)"},{"line_number":83,"context_line":"            requested_units \u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":84,"context_line":"            if used + requested_units \u003e quota:"},{"line_number":85,"context_line":"                raise n_exc.SubnetPoolQuotaExceeded()"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_a7e441e0","line":83,"updated":"2015-03-20 21:14:50.000000000","message":"Actually, now that this non-obvious computation is done twice, let\u0027s wrap it in a method that helps readability.  Something along these lines:\n\n  def num_units_in_subnet(cidr, quota_unit):\n      \"\"\" Nice docstring here\"\"\"\n      prefixlen \u003d netaddr.IPNetwork(cidr).prefixlen\n      return math.pow(2, quota_unit - prefixlen","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"350b9c13639a5326ceb3a197cc31db7635f17d3c","unresolved":false,"context_lines":[{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if quota:"},{"line_number":82,"context_line":"            used \u003d self._allocations_used_by_tenant(session, quota_unit)"},{"line_number":83,"context_line":"            requested_units \u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":84,"context_line":"            if used + requested_units \u003e quota:"},{"line_number":85,"context_line":"                raise n_exc.SubnetPoolQuotaExceeded()"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"fa963961_4969128b","line":83,"in_reply_to":"1a6ced46_f37f4064","updated":"2015-03-26 15:59:27.000000000","message":"The goal wasn\u0027t to save computation.  The goal was clarity.  Since the computation was less than obvious to me, it helps me to give it a descriptive name by wrapping it in a method.  That\u0027s all.  It is a minor point so I\u0027ll be fine with whatever.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if quota:"},{"line_number":82,"context_line":"            used \u003d self._allocations_used_by_tenant(session, quota_unit)"},{"line_number":83,"context_line":"            requested_units \u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":84,"context_line":"            if used + requested_units \u003e quota:"},{"line_number":85,"context_line":"                raise n_exc.SubnetPoolQuotaExceeded()"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"1a6ced46_f37f4064","line":83,"in_reply_to":"9a80dd14_5aa278ae","updated":"2015-03-25 11:03:09.000000000","message":"prefixlen here is the length of the prefix being requested. In the other method it\u0027s the length of all allocated prefixes.\n\nif you want to have a wrapper method that\u0027s ok but how that saves computation?","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":4187,"name":"Ryan Tidwell","email":"rtidwell@suse.com","username":"ryan-tidwell"},"change_message_id":"69040caa1e2e94da8d8539d643f8cea31477cbdc","unresolved":false,"context_lines":[{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if quota:"},{"line_number":82,"context_line":"            used \u003d self._allocations_used_by_tenant(session, quota_unit)"},{"line_number":83,"context_line":"            requested_units \u003d math.pow(2, quota_unit - prefixlen)"},{"line_number":84,"context_line":"            if used + requested_units \u003e quota:"},{"line_number":85,"context_line":"                raise n_exc.SubnetPoolQuotaExceeded()"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"9a80dd14_5aa278ae","line":83,"in_reply_to":"9a80dd14_a7e441e0","updated":"2015-03-20 21:35:35.000000000","message":"Done","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":316,"context_line":""},{"line_number":317,"context_line":"class SubnetPoolHelper(object):"},{"line_number":318,"context_line":""},{"line_number":319,"context_line":"    PREFIX_VERSION_INFO \u003d {4: {\u0027max_prefixlen\u0027: constants.IPv4_BITS,"},{"line_number":320,"context_line":"                               \u0027wildcard\u0027: \u00270.0.0.0\u0027,"},{"line_number":321,"context_line":"                               \u0027default_min_prefixlen\u0027: 8,"},{"line_number":322,"context_line":"                               # IPv4 quota measured in units of /32"}],"source_content_type":"text/x-python","patch_set":5,"id":"1a6ced46_539d7465","line":319,"updated":"2015-03-25 11:03:09.000000000","message":"it sound like you intend this an internal constant, since you\u0027ve provided accessors.\n\nIn this case please prepend it with an underscore.","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"61ae58ab4f5fa76e23ec1de5e5b42f39df47e8c7","unresolved":false,"context_lines":[{"line_number":325,"context_line":"                               \u0027wildcard\u0027: \u0027::\u0027,"},{"line_number":326,"context_line":"                               \u0027default_min_prefixlen\u0027: 64,"},{"line_number":327,"context_line":"                               # IPv6 quota measured in units of /64"},{"line_number":328,"context_line":"                               \u0027quota_units\u0027: 64}}"},{"line_number":329,"context_line":""},{"line_number":330,"context_line":"    def validate_min_prefixlen(self, min_prefixlen, max_prefixlen):"},{"line_number":331,"context_line":"        if min_prefixlen \u003c 0:"}],"source_content_type":"text/x-python","patch_set":5,"id":"1a6ced46_53bc9406","line":328,"updated":"2015-03-25 11:03:09.000000000","message":"I will never get why we needed a class for this, but that\u0027s ok.\nThis makes the code more readable for developers whose background are languages where everybody must be contained in a class.\n\nbtw... python modules are classes too!","commit_id":"89a4ec1b46a65fa907c6ead1ad03ae5823be5ce4"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"7a316427df414eea51dcc319d24582ff43e9ab83","unresolved":false,"context_lines":[{"line_number":64,"context_line":"            qry \u003d session.query("},{"line_number":65,"context_line":"                 models_v2.Subnet).with_lockmode(\u0027update\u0027)"},{"line_number":66,"context_line":"            allocations \u003d qry.filter_by(subnetpool_id\u003dsubnetpool_id,"},{"line_number":67,"context_line":"                                        tenant_id\u003dtenant_id).all()"},{"line_number":68,"context_line":"            value \u003d 0"},{"line_number":69,"context_line":"            for allocation in allocations:"},{"line_number":70,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"}],"source_content_type":"text/x-python","patch_set":8,"id":"da9b358b_b29b4ac9","line":67,"updated":"2015-03-30 13:53:12.000000000","message":"did I already comment in a previous patchset that there was no point in calling all() here, since the query is an iterator as well?","commit_id":"4a93b75a7e5e2fd43cbc501f1c940bf1b6e2245b"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"34e7d6f1cff895f15a386236dcbc3dfb215ea655","unresolved":false,"context_lines":[{"line_number":64,"context_line":"            qry \u003d session.query("},{"line_number":65,"context_line":"                 models_v2.Subnet).with_lockmode(\u0027update\u0027)"},{"line_number":66,"context_line":"            allocations \u003d qry.filter_by(subnetpool_id\u003dsubnetpool_id,"},{"line_number":67,"context_line":"                                        tenant_id\u003dtenant_id).all()"},{"line_number":68,"context_line":"            value \u003d 0"},{"line_number":69,"context_line":"            for allocation in allocations:"},{"line_number":70,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"}],"source_content_type":"text/x-python","patch_set":8,"id":"da9b358b_fa319bed","line":67,"in_reply_to":"da9b358b_b29b4ac9","updated":"2015-03-30 18:28:52.000000000","message":"+1  I think this has been mentioned several times by both of us.  Ryan might be trying to keep too many balls in the air.  :)  It is a minor performance thing.  The cost to create the list in memory will be small compared to the cost of hitting the database and retrieving the results.\n\nThis will need at least one more patch set to bring it up to date with the version of allocations that finally merges.  Hopefully, you can remove this before then.","commit_id":"4a93b75a7e5e2fd43cbc501f1c940bf1b6e2245b"},{"author":{"_account_id":4187,"name":"Ryan Tidwell","email":"rtidwell@suse.com","username":"ryan-tidwell"},"change_message_id":"df9a3f13b2c45ce3dee4534cdcdb0321a7b94031","unresolved":false,"context_lines":[{"line_number":64,"context_line":"            qry \u003d session.query("},{"line_number":65,"context_line":"                 models_v2.Subnet).with_lockmode(\u0027update\u0027)"},{"line_number":66,"context_line":"            allocations \u003d qry.filter_by(subnetpool_id\u003dsubnetpool_id,"},{"line_number":67,"context_line":"                                        tenant_id\u003dtenant_id).all()"},{"line_number":68,"context_line":"            value \u003d 0"},{"line_number":69,"context_line":"            for allocation in allocations:"},{"line_number":70,"context_line":"                prefixlen \u003d netaddr.IPNetwork(allocation.cidr).prefixlen"}],"source_content_type":"text/x-python","patch_set":8,"id":"da9b358b_65cbac54","line":67,"in_reply_to":"da9b358b_fa319bed","updated":"2015-03-30 19:00:47.000000000","message":"Done. This patch requires a rebase at this point anyway, so I\u0027ll make that change.","commit_id":"4a93b75a7e5e2fd43cbc501f1c940bf1b6e2245b"},{"author":{"_account_id":261,"name":"Salvatore Orlando","email":"salv.orlando@gmail.com","username":"salvatore-orlando"},"change_message_id":"7a316427df414eea51dcc319d24582ff43e9ab83","unresolved":false,"context_lines":[{"line_number":82,"context_line":"            requested_units \u003d self._num_quota_units_in_prefixlen(prefixlen,"},{"line_number":83,"context_line":"                                                                 quota_unit)"},{"line_number":84,"context_line":"            if used + requested_units \u003e quota:"},{"line_number":85,"context_line":"                raise n_exc.SubnetPoolQuotaExceeded()"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    def _allocate_any_subnet(self, session, request):"},{"line_number":88,"context_line":"        with session.begin(subtransactions\u003dTrue):"}],"source_content_type":"text/x-python","patch_set":8,"id":"da9b358b_b2746a9c","line":85,"updated":"2015-03-30 13:53:12.000000000","message":"this algorithm like all quota enforcement in neutron suffers from a problem that when isolation mode is repeatable read or serializable, concurrent allocations might lead to exceed the quota. \n\nthere is a deferred blueprint to address this: https://blueprints.launchpad.net/neutron/+spec/better-quotas\n\nYou do not need to do anything... perhaps just put a #TODO note if you have a chance","commit_id":"4a93b75a7e5e2fd43cbc501f1c940bf1b6e2245b"},{"author":{"_account_id":4187,"name":"Ryan Tidwell","email":"rtidwell@suse.com","username":"ryan-tidwell"},"change_message_id":"df9a3f13b2c45ce3dee4534cdcdb0321a7b94031","unresolved":false,"context_lines":[{"line_number":82,"context_line":"            requested_units \u003d self._num_quota_units_in_prefixlen(prefixlen,"},{"line_number":83,"context_line":"                                                                 quota_unit)"},{"line_number":84,"context_line":"            if used + requested_units \u003e quota:"},{"line_number":85,"context_line":"                raise n_exc.SubnetPoolQuotaExceeded()"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    def _allocate_any_subnet(self, session, request):"},{"line_number":88,"context_line":"        with session.begin(subtransactions\u003dTrue):"}],"source_content_type":"text/x-python","patch_set":8,"id":"da9b358b_657dec1b","line":85,"in_reply_to":"da9b358b_b2746a9c","updated":"2015-03-30 19:00:47.000000000","message":"Done","commit_id":"4a93b75a7e5e2fd43cbc501f1c940bf1b6e2245b"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"eac71cdb5d36456388cad6c923b70ed9defe64bd","unresolved":false,"context_lines":[{"line_number":73,"context_line":"            return value"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    def _check_subnetpool_tenant_quota(self, session, tenant_id, prefixlen):"},{"line_number":76,"context_line":"        quota_unit \u003d self._sp_helper.ip_version_subnetpool_quota_unit("},{"line_number":77,"context_line":"                                               self._subnetpool[\u0027ip_version\u0027])"},{"line_number":78,"context_line":"        quota \u003d self._subnetpool.get(\u0027default_quota\u0027)"},{"line_number":79,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"da9b358b_7d3b059d","line":76,"updated":"2015-04-01 04:13:07.000000000","message":"nit:  Would be preferable to move this under the \"if quota:\" on L80.","commit_id":"2fa1fc4bb1a324e3878c68a74ca7bdb4bd545db1"}]}
