コード例 #1
0
    def test_rotate_subscription_key(self, textanalytics_test_endpoint,
                                     textanalytics_test_api_key):
        credential = AzureKeyCredential(textanalytics_test_api_key)
        client = TextAnalyticsClient(textanalytics_test_endpoint, credential)

        docs = [{
            "id": "1",
            "text": "I will go to the park."
        }, {
            "id": "2",
            "text": "I did not like the hotel we stayed at."
        }, {
            "id": "3",
            "text": "The restaurant had really good food."
        }]

        response = client.analyze_sentiment(docs)
        assert response is not None

        credential.update("xxx")  # Make authentication fail
        with pytest.raises(ClientAuthenticationError):
            response = client.analyze_sentiment(docs)

        credential.update(
            textanalytics_test_api_key)  # Authenticate successfully again
        response = client.analyze_sentiment(docs)
        assert response is not None
    def test_rotate_subscription_key(self, resource_group, location,
                                     text_analytics_account,
                                     text_analytics_account_key):
        credential = AzureKeyCredential(text_analytics_account_key)
        client = TextAnalyticsClient(text_analytics_account, credential)

        docs = [{
            "id": "1",
            "text": "I will go to the park."
        }, {
            "id": "2",
            "text": "I did not like the hotel we stayed at."
        }, {
            "id": "3",
            "text": "The restaurant had really good food."
        }]

        response = client.analyze_sentiment(docs)
        self.assertIsNotNone(response)

        credential.update("xxx")  # Make authentication fail
        with self.assertRaises(ClientAuthenticationError):
            response = client.analyze_sentiment(docs)

        credential.update(
            text_analytics_account_key)  # Authenticate successfully again
        response = client.analyze_sentiment(docs)
        self.assertIsNotNone(response)
コード例 #3
0
    def test_some_errors_analyze_sentiment(self, resource_group, location,
                                           text_analytics_account,
                                           text_analytics_account_key):
        text_analytics = TextAnalyticsClient(text_analytics_account,
                                             text_analytics_account_key)

        docs = [{
            "id": "1",
            "language": "en",
            "text": ""
        }, {
            "id":
            "2",
            "language":
            "english",
            "text":
            "I did not like the hotel we stayed it. It was too expensive."
        }, {
            "id":
            "3",
            "language":
            "en",
            "text":
            "The restaurant had really good food. I recommend you try it."
        }]

        response = text_analytics.analyze_sentiment(docs)
        self.assertTrue(response[0].is_error)
        self.assertTrue(response[1].is_error)
コード例 #4
0
    def analyze_sentiment(self):
        # [START batch_analyze_sentiment]
        from azure.ai.textanalytics import TextAnalyticsClient, TextAnalyticsAPIKeyCredential
        text_analytics_client = TextAnalyticsClient(endpoint=self.endpoint, credential=TextAnalyticsAPIKeyCredential(self.key))
        documents = [
            "I had the best day of my life.",
            "This was a waste of my time. The speaker put me to sleep.",
            "No tengo dinero ni nada que dar...",
            "L'hôtel n'était pas très confortable. L'éclairage était trop sombre."
        ]

        result = text_analytics_client.analyze_sentiment(documents)
        docs = [doc for doc in result if not doc.is_error]

        for idx, doc in enumerate(docs):
            print("Document text: {}".format(documents[idx]))
            print("Overall sentiment: {}".format(doc.sentiment))
        # [END batch_analyze_sentiment]
            print("Overall scores: positive={0:.3f}; neutral={1:.3f}; negative={2:.3f} \n".format(
                doc.document_scores.positive,
                doc.document_scores.neutral,
                doc.document_scores.negative,
            ))
            for idx, sentence in enumerate(doc.sentences):
                print("Sentence {} sentiment: {}".format(idx+1, sentence.sentiment))
                print("Sentence score: positive={0:.3f}; neutral={1:.3f}; negative={2:.3f}".format(
                    sentence.sentence_scores.positive,
                    sentence.sentence_scores.neutral,
                    sentence.sentence_scores.negative,
                ))
                print("Offset: {}".format(sentence.offset))
                print("Length: {}\n".format(sentence.length))
            print("------------------------------------")
コード例 #5
0
    def alternative_scenario_analyze_sentiment(self):
        """This sample demonstrates how to retrieve batch statistics, the
        model version used, and the raw response returned from the service.

        It additionally shows an alternative way to pass in the input documents
        using a list[TextDocumentInput] and supplying your own IDs and language hints along
        with the text.
        """
        from azure.ai.textanalytics import TextAnalyticsClient, TextAnalyticsAPIKeyCredential
        text_analytics_client = TextAnalyticsClient(endpoint=self.endpoint, credential=TextAnalyticsAPIKeyCredential(self.key))

        documents = [
            {"id": "0", "language": "en", "text": "I had the best day of my life."},
            {"id": "1", "language": "en",
             "text": "This was a waste of my time. The speaker put me to sleep."},
            {"id": "2", "language": "es", "text": "No tengo dinero ni nada que dar..."},
            {"id": "3", "language": "fr",
             "text": "L'hôtel n'était pas très confortable. L'éclairage était trop sombre."}
        ]

        extras = []

        def callback(resp):
            extras.append(resp.statistics)
            extras.append(resp.model_version)
            extras.append(resp.raw_response)

        result = text_analytics_client.analyze_sentiment(
            documents,
            show_stats=True,
            model_version="latest",
            response_hook=callback
        )
コード例 #6
0
    def test_input_with_all_errors(self, resource_group, location,
                                   text_analytics_account,
                                   text_analytics_account_key):
        text_analytics = TextAnalyticsClient(
            text_analytics_account,
            TextAnalyticsApiKeyCredential(text_analytics_account_key))

        docs = [{
            "id": "1",
            "language": "en",
            "text": ""
        }, {
            "id":
            "2",
            "language":
            "english",
            "text":
            "I did not like the hotel we stayed at. It was too expensive."
        }, {
            "id": "3",
            "language": "en",
            "text": ""
        }]

        response = text_analytics.analyze_sentiment(docs)
        self.assertTrue(response[0].is_error)
        self.assertTrue(response[1].is_error)
        self.assertTrue(response[2].is_error)
コード例 #7
0
    def test_successful_analyze_sentiment(self, resource_group, location,
                                          cognitiveservices_account,
                                          cognitiveservices_account_key):
        text_analytics = TextAnalyticsClient(cognitiveservices_account,
                                             cognitiveservices_account_key)

        docs = [{
            "id": "1",
            "language": "en",
            "text": "Microsoft was founded by Bill Gates and Paul Allen."
        }, {
            "id":
            "2",
            "language":
            "en",
            "text":
            "I did not like the hotel we stayed it. It was too expensive."
        }, {
            "id":
            "3",
            "language":
            "en",
            "text":
            "The restaurant had really good food. I recommend you try it."
        }]

        response = text_analytics.analyze_sentiment(docs, show_stats=True)
        self.assertEqual(response[0].sentiment, "neutral")
        self.assertEqual(response[1].sentiment, "negative")
        self.assertEqual(response[2].sentiment, "positive")
        for doc in response:
            self.assertIsNotNone(doc.id)
            self.assertIsNotNone(doc.statistics)
            self.assertIsNotNone(doc.document_scores)
            self.assertIsNotNone(doc.sentences)
コード例 #8
0
    def test_all_errors_analyze_sentiment(self, resource_group, location,
                                          cognitiveservices_account,
                                          cognitiveservices_account_key):
        text_analytics = TextAnalyticsClient(cognitiveservices_account,
                                             cognitiveservices_account_key)

        docs = [{
            "id": "1",
            "language": "en",
            "text": ""
        }, {
            "id":
            "2",
            "language":
            "english",
            "text":
            "I did not like the hotel we stayed it. It was too expensive."
        }, {
            "id": "3",
            "language": "en",
            "text": ""
        }]

        response = text_analytics.analyze_sentiment(docs)
        self.assertTrue(response[0].is_error)
        self.assertTrue(response[1].is_error)
        self.assertTrue(response[2].is_error)
コード例 #9
0
    def test_whole_batch_language_hint_and_obj_per_item_hints(
            self, resource_group, location, cognitiveservices_account,
            cognitiveservices_account_key):
        text_analytics = TextAnalyticsClient(cognitiveservices_account,
                                             cognitiveservices_account_key)

        def callback(resp):
            language_str = "\"language\": \"es\""
            language = resp.http_request.body.count(language_str)
            self.assertEqual(language, 2)
            language_str = "\"language\": \"en\""
            language = resp.http_request.body.count(language_str)
            self.assertEqual(language, 1)

        docs = [
            TextDocumentInput(id="1",
                              text="I should take my cat to the veterinarian.",
                              language="es"),
            TextDocumentInput(id="2",
                              text="Este es un document escrito en Español.",
                              language="es"),
            TextDocumentInput(id="3", text="猫は幸せ"),
        ]

        response = text_analytics.analyze_sentiment(docs,
                                                    language="en",
                                                    response_hook=callback)
コード例 #10
0
    def test_bad_document_input(self, resource_group, location, cognitiveservices_account, cognitiveservices_account_key):
        text_analytics = TextAnalyticsClient(cognitiveservices_account, cognitiveservices_account_key)

        docs = "This is the wrong type"

        with self.assertRaises(TypeError):
            response = text_analytics.analyze_sentiment(docs)
コード例 #11
0
    def test_document_errors(self, resource_group, location,
                             text_analytics_account,
                             text_analytics_account_key):
        text_analytics = TextAnalyticsClient(
            text_analytics_account,
            TextAnalyticsApiKeyCredential(text_analytics_account_key))
        text = ""
        for _ in range(5121):
            text += "x"

        docs = [{
            "id": "1",
            "text": ""
        }, {
            "id": "2",
            "language": "english",
            "text": "I did not like the hotel we stayed at."
        }, {
            "id": "3",
            "text": text
        }]

        doc_errors = text_analytics.analyze_sentiment(docs)
        self.assertEqual(doc_errors[0].error.code, "invalidDocument")
        self.assertIsNotNone(doc_errors[0].error.message)
        self.assertEqual(doc_errors[1].error.code, "unsupportedLanguageCode")
        self.assertIsNotNone(doc_errors[1].error.message)
        self.assertEqual(doc_errors[2].error.code, "invalidDocument")
        self.assertIsNotNone(doc_errors[2].error.message)
コード例 #12
0
def TextAnalytics(url, key, text_chunks):
    #perform analytics on the input text
    client = TextAnalyticsClient(url, AzureKeyCredential(key))

    keyphrase_message = []
    entity_message = []
    sentiment_message = []

    positive_score = 0
    neutral_score  = 0
    negative_score = 0

    for text in text_chunks:
        text = [text]
        #grab the sentiment response
        sentiment_response = client.analyze_sentiment(documents = text)[0]

        positive_score    += sentiment_response.confidence_scores.positive
        neutral_score     += sentiment_response.confidence_scores.neutral
        negative_score    += sentiment_response.confidence_scores.negative

        keyphrase_response = client.extract_key_phrases(documents = text)[0]
        for phrase in keyphrase_response.key_phrases:
            keyphrase_message.append("* {0} \n".format(phrase))

        #grab the keyphrases
        entities_response = client.recognize_entities(documents = text)[0]
        for entity in entities_response.entities:
            entity_message.append("* {0} [{1}]\n".format(entity.text, entity.category))

    sentiment_message = [str(positive_score*100)+"%", str(neutral_score*100)+"%", str(negative_score*100)+"%"]
    
    return sentiment_message, entity_message, keyphrase_message
コード例 #13
0
    def test_all_successful_passing_text_document_input(
            self, resource_group, location, text_analytics_account,
            text_analytics_account_key):
        text_analytics = TextAnalyticsClient(
            text_analytics_account,
            TextAnalyticsApiKeyCredential(text_analytics_account_key))

        docs = [
            TextDocumentInput(
                id="1",
                text="Microsoft was founded by Bill Gates and Paul Allen."),
            TextDocumentInput(
                id="2",
                text=
                "I did not like the hotel we stayed at. It was too expensive."
            ),
            TextDocumentInput(
                id="3",
                text=
                "The restaurant had really good food. I recommend you try it."
            ),
        ]

        response = text_analytics.analyze_sentiment(docs)
        self.assertEqual(response[0].sentiment, "neutral")
        self.assertEqual(response[1].sentiment, "negative")
        self.assertEqual(response[2].sentiment, "positive")

        for doc in response:
            self.assertIsNotNone(doc.confidence_scores)
            self.assertIsNotNone(doc.sentences)
コード例 #14
0
    def test_user_agent(self, resource_group, location, text_analytics_account,
                        text_analytics_account_key):
        text_analytics = TextAnalyticsClient(
            text_analytics_account,
            TextAnalyticsApiKeyCredential(text_analytics_account_key))

        def callback(resp):
            self.assertIn(
                "azsdk-python-azure-ai-textanalytics/{} Python/{} ({})".format(
                    VERSION, platform.python_version(), platform.platform()),
                resp.http_request.headers["User-Agent"])

        docs = [{
            "id": "1",
            "text": "I will go to the park."
        }, {
            "id": "2",
            "text": "I did not like the hotel we stayed at."
        }, {
            "id": "3",
            "text": "The restaurant had really good food."
        }]

        response = text_analytics.analyze_sentiment(docs,
                                                    raw_response_hook=callback)
コード例 #15
0
    def test_whole_batch_language_hint_and_dict_per_item_hints(
            self, resource_group, location, text_analytics_account,
            text_analytics_account_key):
        text_analytics = TextAnalyticsClient(
            text_analytics_account,
            TextAnalyticsApiKeyCredential(text_analytics_account_key))

        def callback(resp):
            language_str = "\"language\": \"es\""
            language = resp.http_request.body.count(language_str)
            self.assertEqual(language, 2)
            language_str = "\"language\": \"en\""
            language = resp.http_request.body.count(language_str)
            self.assertEqual(language, 1)

        docs = [{
            "id": "1",
            "language": "es",
            "text": "I will go to the park."
        }, {
            "id": "2",
            "language": "es",
            "text": "I did not like the hotel we stayed at."
        }, {
            "id": "3",
            "text": "The restaurant had really good food."
        }]

        response = text_analytics.analyze_sentiment(docs,
                                                    language="en",
                                                    raw_response_hook=callback)
コード例 #16
0
    def test_validate_multilanguage_input(self, resource_group, location,
                                          cognitiveservices_account,
                                          cognitiveservices_account_key):
        text_analytics = TextAnalyticsClient(cognitiveservices_account,
                                             cognitiveservices_account_key)

        docs = [
            TextDocumentInput(
                id="1",
                text="Microsoft was founded by Bill Gates and Paul Allen."),
            TextDocumentInput(
                id="2",
                text=
                "I did not like the hotel we stayed it. It was too expensive."
            ),
            TextDocumentInput(
                id="3",
                text=
                "The restaurant had really good food. I recommend you try it."
            ),
        ]

        response = text_analytics.analyze_sentiment(docs)
        self.assertEqual(response[0].sentiment, "neutral")
        self.assertEqual(response[1].sentiment, "negative")
        self.assertEqual(response[2].sentiment, "positive")
    def get_detailed_diagnostics_information(self):
        from azure.ai.textanalytics import TextAnalyticsClient, TextAnalyticsApiKeyCredential
        text_analytics_client = TextAnalyticsClient(
            endpoint=self.endpoint,
            credential=TextAnalyticsApiKeyCredential(self.key))

        documents = [
            "I had the best day of my life.",
            "This was a waste of my time. The speaker put me to sleep.",
            "No tengo dinero ni nada que dar...",
            "L'hôtel n'était pas très confortable. L'éclairage était trop sombre."
        ]

        def callback(resp):
            _LOGGER.info("document_count: {}".format(
                resp.statistics["document_count"]))
            _LOGGER.info("valid_document_count: {}".format(
                resp.statistics["valid_document_count"]))
            _LOGGER.info("erroneous_document_count: {}".format(
                resp.statistics["erroneous_document_count"]))
            _LOGGER.info("transaction_count: {}".format(
                resp.statistics["transaction_count"]))
            _LOGGER.info("model_version: {}".format(resp.model_version))
            _LOGGER.info("raw_response: {}".format(resp.raw_response))

        result = text_analytics_client.analyze_sentiment(
            documents,
            show_stats=True,
            model_version="latest",
            raw_response_hook=callback)
コード例 #18
0
    def test_out_of_order_ids(self, resource_group, location,
                              cognitiveservices_account,
                              cognitiveservices_account_key):
        text_analytics = TextAnalyticsClient(cognitiveservices_account,
                                             cognitiveservices_account_key)

        docs = [{
            "id": "56",
            "text": ":)"
        }, {
            "id": "0",
            "text": ":("
        }, {
            "id": "22",
            "text": ""
        }, {
            "id": "19",
            "text": ":P"
        }, {
            "id": "1",
            "text": ":D"
        }]

        response = text_analytics.analyze_sentiment(docs)
        in_order = ["56", "0", "22", "19", "1"]
        for idx, resp in enumerate(response):
            self.assertEqual(resp.id, in_order[idx])
コード例 #19
0
    def test_bad_document_input(self, resource_group, location, text_analytics_account, text_analytics_account_key):
        text_analytics = TextAnalyticsClient(text_analytics_account, TextAnalyticsApiKeyCredential(text_analytics_account_key))

        docs = "This is the wrong type"

        with self.assertRaises(TypeError):
            response = text_analytics.analyze_sentiment(docs)
コード例 #20
0
 def test_bad_model_version(self, resource_group, location, text_analytics_account, text_analytics_account_key):
     text_analytics = TextAnalyticsClient(text_analytics_account, TextAnalyticsApiKeyCredential(text_analytics_account_key))
     with self.assertRaises(HttpResponseError):
         response = text_analytics.analyze_sentiment(
             inputs=["Microsoft was founded by Bill Gates."],
             model_version="old"
         )
コード例 #21
0
    def test_per_item_dont_use_language_hint(self, resource_group, location,
                                             cognitiveservices_account,
                                             cognitiveservices_account_key):
        text_analytics = TextAnalyticsClient(cognitiveservices_account,
                                             cognitiveservices_account_key)

        def callback(resp):
            language_str = "\"language\": \"\""
            language = resp.http_request.body.count(language_str)
            self.assertEqual(language, 2)
            language_str = "\"language\": \"en\""
            language = resp.http_request.body.count(language_str)
            self.assertEqual(language, 1)

        docs = [{
            "id": "1",
            "language": "",
            "text": "I will go to the park."
        }, {
            "id": "2",
            "language": "",
            "text": "I did not like the hotel we stayed it."
        }, {
            "id": "3",
            "text": "The restaurant had really good food."
        }]

        response = text_analytics.analyze_sentiment(docs,
                                                    response_hook=callback)
コード例 #22
0
    def test_show_stats_and_model_version(self, resource_group, location,
                                          cognitiveservices_account,
                                          cognitiveservices_account_key):
        text_analytics = TextAnalyticsClient(cognitiveservices_account,
                                             cognitiveservices_account_key)

        def callback(response):
            self.assertIsNotNone(response.model_version)
            self.assertIsNotNone(response.raw_response)
            self.assertEqual(response.statistics.document_count, 5)
            self.assertEqual(response.statistics.transaction_count, 4)
            self.assertEqual(response.statistics.valid_document_count, 4)
            self.assertEqual(response.statistics.erroneous_document_count, 1)

        docs = [{
            "id": "56",
            "text": ":)"
        }, {
            "id": "0",
            "text": ":("
        }, {
            "id": "22",
            "text": ""
        }, {
            "id": "19",
            "text": ":P"
        }, {
            "id": "1",
            "text": ":D"
        }]

        response = text_analytics.analyze_sentiment(docs,
                                                    show_stats=True,
                                                    model_version="latest",
                                                    response_hook=callback)
コード例 #23
0
 def test_missing_input_records_error(self, resource_group, location, text_analytics_account, text_analytics_account_key):
     text_analytics = TextAnalyticsClient(text_analytics_account, TextAnalyticsApiKeyCredential(text_analytics_account_key))
     docs = []
     try:
         result = text_analytics.analyze_sentiment(docs)
     except HttpResponseError as err:
         self.assertEqual(err.error_code, "MissingInputRecords")
         self.assertIsNotNone(err.message)
コード例 #24
0
 def test_empty_credential_class(self, resource_group, location,
                                 text_analytics_account,
                                 text_analytics_account_key):
     text_analytics = TextAnalyticsClient(text_analytics_account,
                                          TextAnalyticsApiKeyCredential(""))
     with self.assertRaises(ClientAuthenticationError):
         response = text_analytics.analyze_sentiment(
             ["This is written in English."])
コード例 #25
0
 def chackSentiment(data, title):
     key = os.getenv("TEXT_KEY")
     endpoint = "https://hackjaipur.cognitiveservices.azure.com/"
     credential_ta = AzureKeyCredential(key)
     text_analytics_client = TextAnalyticsClient(
         endpoint=endpoint, credential=credential_ta)
     response = text_analytics_client.analyze_sentiment(documents=[data, title])
     return response
コード例 #26
0
 def test_no_single_input(self, resource_group, location,
                          text_analytics_account,
                          text_analytics_account_key):
     text_analytics = TextAnalyticsClient(
         text_analytics_account,
         TextAnalyticsApiKeyCredential(text_analytics_account_key))
     with self.assertRaises(TypeError):
         response = text_analytics.analyze_sentiment("hello world")
コード例 #27
0
def main():
    try:
        # Get Configuration Settings
        load_dotenv()
        cog_endpoint = os.getenv('COG_SERVICE_ENDPOINT')
        cog_key = os.getenv('COG_SERVICE_KEY')

        # Create client using endpoint and key
        credential = AzureKeyCredential(cog_key)
        cog_client = TextAnalyticsClient(endpoint=cog_endpoint,
                                         credential=credential)

        # Analyze each text file in the reviews folder
        reviews_folder = 'reviews'
        for file_name in os.listdir(reviews_folder):
            # Read the file contents
            print('\n-------------\n' + file_name)
            text = open(os.path.join(reviews_folder, file_name),
                        encoding='utf8').read()
            print('\n' + text)

            # Get language
            detectedLanguage = cog_client.detect_language(documents=[text])[0]
            print('\nLanguage: {}'.format(
                detectedLanguage.primary_language.name))

            # Get sentiment
            sentimentAnalysis = cog_client.analyze_sentiment(
                documents=[text])[0]
            print("\nSentiment: {}".format(sentimentAnalysis.sentiment))

            # Get key phrases
            phrases = cog_client.extract_key_phrases(
                documents=[text])[0].key_phrases
            if len(phrases) > 0:
                print("\nKey Phrases:")
                for phrase in phrases:
                    print('\t{}'.format(phrase))

            # Get entities
            entities = cog_client.recognize_entities(
                documents=[text])[0].entities
            if len(entities) > 0:
                print("\nEntities")
                for entity in entities:
                    print('\t{} ({})'.format(entity.text, entity.category))

            # Get linked entities
            entities = cog_client.recognize_linked_entities(
                documents=[text])[0].entities
            if len(entities) > 0:
                print("\nLinks")
                for linked_entity in entities:
                    print('\t{} ({})'.format(linked_entity.name,
                                             linked_entity.url))

    except Exception as ex:
        print(ex)
コード例 #28
0
 def test_mixing_inputs(self, resource_group, location, cognitiveservices_account, cognitiveservices_account_key):
     text_analytics = TextAnalyticsClient(cognitiveservices_account, cognitiveservices_account_key)
     docs = [
         {"id": "1", "text": "Microsoft was founded by Bill Gates and Paul Allen."},
         TextDocumentInput(id="2", text="I did not like the hotel we stayed it. It was too expensive."),
         u"You cannot mix string input with the above inputs"
     ]
     with self.assertRaises(TypeError):
         response = text_analytics.analyze_sentiment(docs)
コード例 #29
0
 def test_duplicate_ids_error(self, resource_group, location, text_analytics_account, text_analytics_account_key):
     text_analytics = TextAnalyticsClient(text_analytics_account, TextAnalyticsApiKeyCredential(text_analytics_account_key))
     # Duplicate Ids
     docs = [{"id": "1", "text": "hello world"},
             {"id": "1", "text": "I did not like the hotel we stayed at."}]
     try:
         result = text_analytics.analyze_sentiment(docs)
     except HttpResponseError as err:
         self.assertEqual(err.error_code, "InvalidDocument")
         self.assertIsNotNone(err.message)
コード例 #30
0
    def test_batch_size_over_limit_error(self, resource_group, location, text_analytics_account, text_analytics_account_key):
        text_analytics = TextAnalyticsClient(text_analytics_account, TextAnalyticsApiKeyCredential(text_analytics_account_key))

        # Batch size over limit
        docs = [u"hello world"] * 1001
        try:
            response = text_analytics.analyze_sentiment(docs)
        except HttpResponseError as err:
            self.assertEqual(err.error_code, "InvalidDocumentBatch")
            self.assertIsNotNone(err.message)