Example #1
0
 def test_vip(self):
     body = {"vip": {"ip_address": "10.0.0.1",
                     "net_port_id": uuidutils.generate_uuid(),
                     "subnet_id": uuidutils.generate_uuid(),
                     "floating_ip_id": uuidutils.generate_uuid(),
                     "floating_ip_network_id": uuidutils.generate_uuid()}}
     wsme_json.fromjson(self._type, body)
Example #2
0
    def valid_composite_rule(rules):
        if isinstance(rules, dict) and len(rules) == 1:
            and_or_key = list(rules)[0]
            if and_or_key not in ('and', 'or'):
                raise base.ClientSideError(
                    _('Threshold rules should be combined with "and" or "or"'))
            if isinstance(rules[and_or_key], list):
                for sub_rule in rules[and_or_key]:
                    CompositeRule.valid_composite_rule(sub_rule)
            else:
                raise InvalidCompositeRule(rules)
        elif isinstance(rules, dict):
            rule_type = rules.pop('type', None)
            if not rule_type:
                raise base.ClientSideError(_('type must be set in every rule'))

            if rule_type not in CompositeRule.threshold_plugins:
                plugins = sorted(CompositeRule.threshold_plugins.names())
                err = _('Unsupported sub-rule type :%(rule)s in composite '
                        'rule, should be one of: %(plugins)s') % {
                            'rule': rule_type,
                            'plugins': plugins}
                raise base.ClientSideError(err)
            plugin = CompositeRule.threshold_plugins[rule_type].plugin
            wjson.fromjson(plugin, rules)
            rule_dict = plugin(**rules).as_dict()
            rules.update(rule_dict)
            rules.update(type=rule_type)
        else:
            raise InvalidCompositeRule(rules)
Example #3
0
    def valid_composite_rule(rules):
        if isinstance(rules, dict) and len(rules) == 1:
            and_or_key = list(rules)[0]
            if and_or_key not in ('and', 'or'):
                raise base.ClientSideError(
                    _('Threshold rules should be combined with "and" or "or"'))
            if isinstance(rules[and_or_key], list):
                for sub_rule in rules[and_or_key]:
                    CompositeRule.valid_composite_rule(sub_rule)
            else:
                raise InvalidCompositeRule(rules)
        elif isinstance(rules, dict):
            rule_type = rules.pop('type', None)
            if not rule_type:
                raise base.ClientSideError(_('type must be set in every rule'))

            if rule_type not in CompositeRule.threshold_plugins:
                plugins = sorted(CompositeRule.threshold_plugins.names())
                err = _('Unsupported sub-rule type :%(rule)s in composite '
                        'rule, should be one of: %(plugins)s') % {
                            'rule': rule_type,
                            'plugins': plugins
                        }
                raise base.ClientSideError(err)
            plugin = CompositeRule.threshold_plugins[rule_type].plugin
            wjson.fromjson(plugin, rules)
            rule_dict = plugin(**rules).as_dict()
            rules.update(rule_dict)
            rules.update(type=rule_type)
        else:
            raise InvalidCompositeRule(rules)
Example #4
0
 def test_vip(self):
     body = {
         "vip_subnet_id": uuidutils.generate_uuid(),
         "vip_port_id": uuidutils.generate_uuid(),
         "vip_qos_policy_id": uuidutils.generate_uuid()
     }
     wsme_json.fromjson(self._type, body)
def test_jsonObject():
    # dictionaries work fine
    obj = AType()
    obj.data = {"a": 1}
    eq_(obj.data, {"a": 1})
    # other types don't
    assert_raises(wsme.exc.InvalidInput, lambda: setattr(obj, "data", ["a"]))
    # and un-JSONable Python data doesn't
    assert_raises(wsme.exc.InvalidInput, lambda: setattr(obj, "data", {"a": lambda: 1}))

    # valid JSON objects work fine
    obj = fromjson(AType, {"data": {"b": 2}})
    # other types don't
    assert_raises(wsme.exc.InvalidInput, lambda: fromjson(AType, {"data": ["b", 2]}))
def test_jsonObject():
    # dictionaries work fine
    obj = AType()
    obj.data = {'a': 1}
    eq_(obj.data, {'a': 1})
    # other types don't
    assert_raises(wsme.exc.InvalidInput, lambda: setattr(obj, 'data', ['a']))
    # and un-JSONable Python data doesn't
    assert_raises(wsme.exc.InvalidInput,
                  lambda: setattr(obj, 'data', {'a': lambda: 1}))

    # valid JSON objects work fine
    obj = fromjson(AType, {'data': {'b': 2}})
    # other types don't
    assert_raises(wsme.exc.InvalidInput,
                  lambda: fromjson(AType, {'data': ['b', 2]}))
Example #7
0
 def test_l7policy_max_position(self):
     body = {"position": constants.MAX_POLICY_POSITION + 1}
     self.assertRaises(
         exc.InvalidInput, wsme_json.fromjson, self._type, body)
     body = {"position": constants.MAX_POLICY_POSITION}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(constants.MAX_POLICY_POSITION, l7policy.position)
Example #8
0
 def test_l7policy(self):
     body = {"action": constants.L7POLICY_ACTION_REJECT}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(sys.maxsize, l7policy.position)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_url)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
     self.assertTrue(l7policy.enabled)
Example #9
0
 def test_l7rule(self):
     body = {"type": constants.L7RULE_TYPE_PATH,
             "compare_type": constants.L7RULE_COMPARE_TYPE_STARTS_WITH,
             "value": "/api"}
     l7rule = wsme_json.fromjson(self._type, body)
     self.assertEqual(wsme_types.Unset, l7rule.key)
     self.assertFalse(l7rule.invert)
Example #10
0
 def test_l7policy(self):
     body = {"action": constants.L7POLICY_ACTION_REJECT,
             "position": 0}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(0, l7policy.position)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_url)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
Example #11
0
 def test_non_uuid_project_id(self):
     body = {"loadbalancer_id": uuidutils.generate_uuid(),
             "protocol": constants.PROTOCOL_HTTP,
             "lb_algorithm": constants.LB_ALGORITHM_ROUND_ROBIN,
             "project_id": "non-uuid"}
     pool = wsme_json.fromjson(self._type, body)
     self.assertEqual(pool.project_id, body['project_id'])
Example #12
0
 def test_member(self):
     body = {"name": "member1", "address": "10.0.0.1",
             "protocol_port": 80, "tags": ['test_tag']}
     member = wsme_json.fromjson(self._type, body)
     self.assertTrue(member.admin_state_up)
     self.assertEqual(1, member.weight)
     self.assertEqual(wsme_types.Unset, member.subnet_id)
Example #13
0
 def test_max_weight(self):
     body = {"weight": constants.MAX_WEIGHT + 1}
     self.assertRaises(
         exc.InvalidInput, wsme_json.fromjson, self._type, body)
     body = {"weight": constants.MAX_WEIGHT}
     member = wsme_json.fromjson(self._type, body)
     self.assertEqual(constants.MAX_WEIGHT, member.weight)
Example #14
0
 def test_l7policy_max_position(self):
     body = {"position": constants.MAX_POLICY_POSITION + 1}
     self.assertRaises(exc.InvalidInput, wsme_json.fromjson, self._type,
                       body)
     body = {"position": constants.MAX_POLICY_POSITION}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(constants.MAX_POLICY_POSITION, l7policy.position)
Example #15
0
 def test_l7policy(self):
     body = {"action": constants.L7POLICY_ACTION_REJECT}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(sys.maxsize, l7policy.position)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_url)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
     self.assertTrue(l7policy.enabled)
Example #16
0
 def test_l7rule(self):
     body = {"type": constants.L7RULE_TYPE_PATH,
             "compare_type": constants.L7RULE_COMPARE_TYPE_STARTS_WITH,
             "value": "/api", "tags": ['test_tag']}
     l7rule = wsme_json.fromjson(self._type, body)
     self.assertEqual(wsme_types.Unset, l7rule.key)
     self.assertFalse(l7rule.invert)
Example #17
0
 def test_non_uuid_project_id(self):
     body = {"loadbalancer_id": uuidutils.generate_uuid(),
             "protocol": constants.PROTOCOL_HTTP,
             "lb_algorithm": constants.LB_ALGORITHM_ROUND_ROBIN,
             "project_id": "non-uuid"}
     pool = wsme_json.fromjson(self._type, body)
     self.assertEqual(pool.project_id, body['project_id'])
Example #18
0
 def test_health_monitor(self):
     body = {"type": constants.HEALTH_MONITOR_HTTP, "delay": 1,
             "timeout": 1, "max_retries_down": 1, "max_retries": 1,
             "pool_id": uuidutils.generate_uuid(),
             "tags": ['test_tag']}
     hm = wsme_json.fromjson(self._type, body)
     self.assertTrue(hm.admin_state_up)
Example #19
0
 def test_max_weight(self):
     body = {"weight": constants.MAX_WEIGHT + 1}
     self.assertRaises(exc.InvalidInput, wsme_json.fromjson, self._type,
                       body)
     body = {"weight": constants.MAX_WEIGHT}
     member = wsme_json.fromjson(self._type, body)
     self.assertEqual(constants.MAX_WEIGHT, member.weight)
 def test_non_uuid_project_id(self):
     body = {"type": constants.HEALTH_MONITOR_HTTP, "delay": 1,
             "timeout": 1, "max_retries_down": 1, "max_retries": 1,
             "project_id": "non-uuid",
             "pool_id": uuidutils.generate_uuid()}
     hm = wsme_json.fromjson(self._type, body)
     self.assertEqual(hm.project_id, body['project_id'])
Example #21
0
 def test_pool(self):
     body = {
         "protocol": constants.PROTOCOL_HTTP,
         "lb_algorithm": constants.LB_ALGORITHM_ROUND_ROBIN
     }
     pool = wsme_json.fromjson(self._type, body)
     self.assertTrue(pool.enabled)
Example #22
0
 def test_l7policy(self):
     body = {"action": constants.L7POLICY_ACTION_REJECT,
             "position": 0}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(0, l7policy.position)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_url)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
Example #23
0
 def test_with_redirect_url(self):
     url = "http://www.example.com/"
     body = {"action": constants.L7POLICY_ACTION_REDIRECT_TO_URL,
             "redirect_url": url}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(constants.MAX_POLICY_POSITION, l7policy.position)
     self.assertEqual(url, l7policy.redirect_url)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
Example #24
0
 def test_listener(self):
     body = {"name": "test", "description": "test", "connection_limit": 10,
             "protocol": constants.PROTOCOL_HTTP, "protocol_port": 80,
             "default_pool_id": uuidutils.generate_uuid(),
             "loadbalancer_id": uuidutils.generate_uuid(),
             "tags": ['test_tag']}
     listener = wsme_json.fromjson(self._type, body)
     self.assertTrue(listener.admin_state_up)
Example #25
0
 def test_non_uuid_project_id(self):
     body = {"name": "test", "description": "test", "connection_limit": 10,
             "protocol": constants.PROTOCOL_HTTP, "protocol_port": 80,
             "default_pool_id": uuidutils.generate_uuid(),
             "loadbalancer_id": uuidutils.generate_uuid(),
             "project_id": "non-uuid"}
     listener = wsme_json.fromjson(self._type, body)
     self.assertEqual(listener.project_id, body['project_id'])
Example #26
0
 def test_load_balancer(self):
     body = {
         "name": "test_name",
         "description": "test_description",
         "vip": {}
     }
     lb = wsme_json.fromjson(self._type, body)
     self.assertTrue(lb.enabled)
Example #27
0
 def test_load_balancer(self):
     body = {
         "name": "test_name",
         "description": "test_description",
         "tags": ['test_tag']
     }
     lb = wsme_json.fromjson(self._type, body)
     self.assertEqual(wsme_types.Unset, lb.admin_state_up)
def test_jsonObject():
    # dictionaries work fine
    obj = AType()
    obj.data = {'a': 1}
    eq_(obj.data, {'a': 1})
    # other types don't
    assert_raises(wsme.exc.InvalidInput, lambda:
                  setattr(obj, 'data', ['a']))
    # and un-JSONable Python data doesn't
    assert_raises(wsme.exc.InvalidInput, lambda:
                  setattr(obj, 'data', {'a': lambda: 1}))

    # valid JSON objects work fine
    obj = fromjson(AType, {'data': {'b': 2}})
    # other types don't
    assert_raises(wsme.exc.InvalidInput, lambda:
                  fromjson(AType, {'data': ['b', 2]}))
Example #29
0
 def test_non_uuid_project_id(self):
     body = {
         "name": "test_name",
         "description": "test_description",
         "flavor_profile_id": uuidutils.generate_uuid()
     }
     lb = wsme_json.fromjson(self._type, body)
     self.assertEqual(lb.flavor_profile_id, body['flavor_profile_id'])
Example #30
0
 def test_load_balancer(self):
     body = {
         "name": "test_name",
         "description": "test_description",
         "vip_subnet_id": uuidutils.generate_uuid()
     }
     lb = wsme_json.fromjson(self._type, body)
     self.assertTrue(lb.admin_state_up)
def test_date_formatting():
    """ISO 8601 formatted dates with timezones are correctly translated to
    datetime instances and back"""
    d = TypeWithDate()
    d.when = datetime(2015, 2, 28, 1, 2, 3, tzinfo=UTC)
    j = {'when': '2015-02-28T01:02:03+00:00'}
    eq_(tojson(TypeWithDate, d), j)
    eq_(fromjson(TypeWithDate, j).when, d.when)
Example #32
0
 def test_with_redirect_url(self):
     url = "http://www.example.com/"
     body = {"action": constants.L7POLICY_ACTION_REDIRECT_TO_URL,
             "redirect_url": url}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(sys.maxsize, l7policy.position)
     self.assertEqual(url, l7policy.redirect_url)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
def test_date_formatting():
    """ISO 8601 formatted dates with timezones are correctly translated to
    datetime instances and back"""
    d = TypeWithDate()
    d.when = datetime(2015, 2, 28, 1, 2, 3, tzinfo=UTC)
    j = {'when': '2015-02-28T01:02:03+00:00'}
    eq_(tojson(TypeWithDate, d), j)
    eq_(fromjson(TypeWithDate, j).when, d.when)
Example #34
0
 def test_pool(self):
     body = {
         "loadbalancer_id": uuidutils.generate_uuid(),
         "protocol": constants.PROTOCOL_HTTP,
         "lb_algorithm": constants.LB_ALGORITHM_ROUND_ROBIN
     }
     pool = wsme_json.fromjson(self._type, body)
     self.assertTrue(pool.admin_state_up)
Example #35
0
 def test_non_uuid_project_id(self):
     body = {
         "address": "10.0.0.1",
         "protocol_port": 80,
         "project_id": "non-uuid"
     }
     member = wsme_json.fromjson(self._type, body)
     self.assertEqual(member.project_id, body['project_id'])
Example #36
0
 def test_flavor(self):
     body = {
         "name": "test_name",
         "description": "test_description",
         "flavor_profile_id": uuidutils.generate_uuid()
     }
     flavor = wsme_json.fromjson(self._type, body)
     self.assertTrue(flavor.enabled)
Example #37
0
 def test_availability_zone(self):
     body = {
         "name": "test_name",
         "description": "test_description",
         "availability_zone_profile_id": uuidutils.generate_uuid()
     }
     availability_zone = wsme_json.fromjson(self._type, body)
     self.assertTrue(availability_zone.enabled)
Example #38
0
    def to_model_properties(db_property_types):
        property_types = {}
        for db_property_type in db_property_types:
            # Convert the persisted json schema to a dict of PropertyTypes
            property_type = json.fromjson(PropertyType, db_property_type.schema)
            property_type_name = db_property_type.name
            property_types[property_type_name] = property_type

        return property_types
Example #39
0
 def test_member_full(self):
     name = "new_name"
     weight = 1
     admin_state = True
     body = {"name": name, "weight": weight, "admin_state_up": admin_state}
     member = wsme_json.fromjson(self._type, body)
     self.assertEqual(name, member.name)
     self.assertEqual(weight, member.weight)
     self.assertEqual(admin_state, member.admin_state_up)
Example #40
0
 def create_tags(self, request):
     body = self._get_request_body(request)
     self._check_allowed(body)
     try:
         self.schema_for_list.validate(body)
     except exception.InvalidObject as e:
         raise webob.exc.HTTPBadRequest(explanation=e.msg)
     metadata_tags = json.fromjson(MetadefTags, body)
     return dict(metadata_tags=metadata_tags)
Example #41
0
 def update(self, request):
     body = self._get_request_body(request)
     self._check_allowed(body)
     try:
         self.schema.validate(body)
     except exception.InvalidObject as e:
         raise webob.exc.HTTPBadRequest(explanation=e.msg)
     namespace = json.fromjson(Namespace, body)
     return dict(user_ns=namespace)
Example #42
0
 def create(self, request):
     body = self._get_request_body(request)
     self._check_allowed(body)
     try:
         self.schema.validate(body)
     except exception.InvalidObject as e:
         raise webob.exc.HTTPBadRequest(explanation=e.msg)
     resource_type = json.fromjson(ResourceTypeAssociation, body)
     return dict(resource_type=resource_type)
Example #43
0
 def update(self, request):
     body = self._get_request_body(request)
     self._check_allowed(body)
     try:
         self.schema.validate(body)
     except exception.InvalidObject as e:
         raise webob.exc.HTTPBadRequest(explanation=e.msg)
     namespace = json.fromjson(Namespace, body)
     return dict(user_ns=namespace)
Example #44
0
 def test_max_weight(self):
     body = {"address": "10.0.0.1", "protocol_port": 443,
             "weight": constants.MAX_WEIGHT + 1}
     self.assertRaises(
         exc.InvalidInput, wsme_json.fromjson, self._type, body)
     body = {"address": "10.0.0.1", "protocol_port": 443,
             "weight": constants.MAX_WEIGHT}
     member = wsme_json.fromjson(self._type, body)
     self.assertEqual(constants.MAX_WEIGHT, member.weight)
Example #45
0
 def update(self, request):
     body = self._get_request_body(request)
     self._check_allowed(body)
     try:
         self.schema.validate(body)
     except exception.InvalidObject as e:
         raise webob.exc.HTTPBadRequest(explanation=e.msg)
     property_type = json.fromjson(PropertyType, body)
     return dict(property_type=property_type)
Example #46
0
 def test_pool(self):
     body = {
         "loadbalancer_id": uuidutils.generate_uuid(),
         "listener_id": uuidutils.generate_uuid(),
         "protocol": constants.PROTOCOL_HTTP,
         "lb_algorithm": constants.LB_ALGORITHM_ROUND_ROBIN,
         "tags": ['test_tag']}
     pool = wsme_json.fromjson(self._type, body)
     self.assertTrue(pool.admin_state_up)
 def create(self, request):
     body = self._get_request_body(request)
     self._check_allowed(body)
     try:
         self.schema.validate(body)
     except exception.InvalidObject as e:
         raise webob.exc.HTTPBadRequest(explanation=e.msg)
     resource_type = json.fromjson(ResourceTypeAssociation, body)
     return dict(resource_type=resource_type)
Example #48
0
 def test_non_uuid_project_id(self):
     body = {
         "name": "test_name",
         "description": "test_description",
         "vip_subnet_id": uuidutils.generate_uuid(),
         "project_id": "non-uuid"
     }
     lb = wsme_json.fromjson(self._type, body)
     self.assertEqual(lb.project_id, body['project_id'])
Example #49
0
 def update(self, request):
     body = self._get_request_body(request)
     self._check_allowed(body)
     try:
         self.schema.validate(body)
     except exception.InvalidObject as e:
         raise webob.exc.HTTPBadRequest(explanation=e.msg)
     property_type = json.fromjson(PropertyType, body)
     return dict(property_type=property_type)
Example #50
0
 def update(self, request):
     body = self._get_request_body(request)
     self._check_allowed(body)
     try:
         self.schema.validate(body)
     except exception.InvalidObject as e:
         raise webob.exc.HTTPBadRequest(explanation=e.msg)
     metadata_object = json.fromjson(MetadefObject, body)
     return dict(metadata_object=metadata_object)
Example #51
0
 def test_l7policy(self):
     body = {"listener_id": self.listener_id,
             "action": constants.L7POLICY_ACTION_REJECT,
             "tags": ['test_tag']}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(self.listener_id, l7policy.listener_id)
     self.assertEqual(constants.MAX_POLICY_POSITION, l7policy.position)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_url)
     self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
     self.assertTrue(l7policy.admin_state_up)
Example #52
0
 def test_listener(self):
     body = {
         "name": "test",
         "description": "test",
         "connection_limit": 10,
         "protocol": constants.PROTOCOL_HTTP,
         "protocol_port": 80,
     }
     listener = wsme_json.fromjson(self._type, body)
     self.assertEqual(wsme_types.Unset, listener.enabled)
Example #53
0
 def test_listener(self):
     body = {"name": "test", "description": "test",
             "connection_limit": 10,
             "default_tls_container_ref": uuidutils.generate_uuid(),
             "sni_container_refs": [uuidutils.generate_uuid(),
                                    uuidutils.generate_uuid()],
             "default_pool_id": uuidutils.generate_uuid(),
             "insert_headers": {"a": "1", "b": "2"},
             "tags": ['test_tag']}
     listener = wsme_json.fromjson(self._type, body)
     self.assertEqual(wsme_types.Unset, listener.admin_state_up)
Example #54
0
 def test_l7policy_min_position(self):
     body = {"listener_id": self.listener_id,
             "action": constants.L7POLICY_ACTION_REJECT,
             "position": constants.MIN_POLICY_POSITION - 1}
     self.assertRaises(
         exc.InvalidInput, wsme_json.fromjson, self._type, body)
     body = {"listener_id": self.listener_id,
             "action": constants.L7POLICY_ACTION_REJECT,
             "position": constants.MIN_POLICY_POSITION}
     l7policy = wsme_json.fromjson(self._type, body)
     self.assertEqual(constants.MIN_POLICY_POSITION, l7policy.position)
Example #55
0
    def _format_metadef_object_from_db(self, metadata_object, namespace_entity):
        required_str = metadata_object["required"]
        required_list = required_str.split(",") if required_str else []

        # Convert the persisted json schema to a dict of PropertyTypes
        property_types = {}
        json_props = metadata_object["json_schema"]
        for id in json_props:
            property_types[id] = json.fromjson(PropertyType, json_props[id])

        return glance.domain.MetadefObject(
            namespace=namespace_entity,
            object_id=metadata_object["id"],
            name=metadata_object["name"],
            required=required_list,
            description=metadata_object["description"],
            properties=property_types,
            created_at=metadata_object["created_at"],
            updated_at=metadata_object["updated_at"],
        )
Example #56
0
    def _format_metadef_object_from_db(self, metadata_object,
                                       namespace_entity):
        required_str = metadata_object['required']
        required_list = required_str.split(",") if required_str else []

        # Convert the persisted json schema to a dict of PropertyTypes
        property_types = {}
        json_props = json.loads(metadata_object['schema'])
        for id in json_props:
            property_types[id] = fromjson(PropertyType, json_props[id])

        return glance.domain.MetadefObject(
            namespace=namespace_entity,
            object_id=metadata_object['id'],
            name=metadata_object['name'],
            required=required_list,
            description=metadata_object['description'],
            properties=property_types,
            created_at=metadata_object['created_at'],
            updated_at=metadata_object['updated_at']
        )