No results found

Try a different or more specific query
Developer Console
Amazon Developer Blogs

Amazon Developer Blogs

Showing posts tagged with AWS

January 26, 2012

Yosuke Matsuda

Amazon DynamoDB is a fast, highly scalable, highly available, cost-effective, non-relational database service. Amazon DynamoDB removes traditional scalability limitations on data storage while maintaining low latency and predictable performance. The sample mobile application described here demonstrates how to store user preferences in Amazon DynamoDB. Because more and more people are using multiple mobile devices, connecting these devices to the cloud, and storing user preferences in the cloud, enables developers to provide a more uniform cross-device experience for their users.

This article shows sample code for the Android platform. The complete sample code and project files are included in the AWS SDK for Android. Links to the SDK are available at the end of this article.

To use the sample app, you'll need to deploy a token vending machine (TVM). A TVM is a cloud-based application that manages AWS credentials for users of mobile applications. To deploy the TVM, you'll first need to obtain your own AWS credentials: an Access Key ID and Secret Key.

If you haven't already signed up for Amazon Web Services (AWS), you will need to do that first to get your AWS credentials. You can sign up for AWS here. After you sign up, you can retrieve your credentials at this page. The credentials will be used to set up the TVM to authenticate users of AWS mobile applications. Sample Java web applications are available here: Anonymous TVM and Identity TVM (this sample uses Anonymous TVM).

Overview

In Amazon DynamoDB, a database is a collection of tables. A table is a collection of items, and each item is a collection of attributes. For our app, we create a single table to store our list of users and their preferences. Each item in the table represents an individual user. Each item has multiple attributes, which include the user's name and their preferences. Each item also has a hash key—in this case, userNo—which is the primary key for the table.

The app demonstrates how to add and remove users, and modify and retrieve their preference data. The app also demonstrates how to create and delete Amazon DynamoDB tables.

Registering the Device with Token Vending Machine

In order to create an Amazon DynamoDB client, we must first register the mobile device with the token vending machine (TVM). For this sample, we use the Anonymous TVM to register the device. Then we store the UID and key returned by the TVM on the device.

RegisterDeviceRequest registerDeviceRequest = 
                                        new RegisterDeviceRequest(this.endpoint, this.useSSL, uid, key);ResponseHandler handler = new ResponseHandler();response = this.processRequest(registerDeviceRequest, handler);if (response.requestWasSuccessful()) {	AmazonSharedPreferencesWrapper.registerDeviceId(this.sharedPreferences, uid, key);}

Retrieving the Temporary Credentials from Token Vending Machine

The following code demonstrates how to request that the TVM generate temporary credentials, and how to store the returned credentials on the device.

Request getTokenRequest = new GetTokenRequest(this.endpoint, this.useSSL, uid, key);ResponseHandler handler = new GetTokenResponseHandler(key);GetTokenResponse getTokenResponse = 
                                (GetTokenResponse) this.processRequest(getTokenRequest, handler);if (getTokenResponse.requestWasSuccessful()) {	AmazonSharedPreferencesWrapper.storeCredentialsInSharedPreferences(			this.sharedPreferences, getTokenResponse.getAccessKey(),			getTokenResponse.getSecretKey(),			getTokenResponse.getSecurityToken(),			getTokenResponse.getExpirationDate());}

Creating an Amazon DynamoDB Client

To make service requests to Amazon DynamoDB, you need to instantiate an Amazon DynamoDB client. The code below shows how to create an Amazon DynamoDB client for Android using the stored temporary credentials from the TVM.

AWSCredentials credentials = AmazonSharedPreferencesWrapper		.getCredentialsFromSharedPreferences(this.sharedPreferences);AmazonDynamoDBClient ddb = new AmazonDynamoDBClient(credentials);

Creating a User List (Table Creation)

Each user's preferences are stored as items in an Amazon DynamoDB table. The following code creates that table using the client we created above. Every Amazon DynamoDB table require a hash key. In this sample, we use userNo as the hash key for the table.

AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();KeySchemaElement kse = new KeySchemaElement()
                                                    .withAttributeName("userNo")
                                                    .withAttributeType(ScalarAttributeType.N);KeySchema ks = new KeySchema().withHashKeyElement(kse);ProvisionedThroughput pt = 
                new ProvisionedThroughput().withReadCapacityUnits(10l).withWriteCapacityUnits(5l);CreateTableRequest request = new CreateTableRequest()		                               .withTableName(PropertyLoader.getInstance().getTestTableName())                                               .withKeySchema(ks)
                                               .withProvisionedThroughput(pt);ddb.createTable(request);

Checking the Status of the Table (Table Description)

Before we can move to the next step (creating users), we must wait until the status of the tables is ACTIVE. To retrieve the status of the table, we use a describe table request. This request returns information about the table such as the name of the table, item count, creation date and time, and its status.

AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();DescribeTableRequest request = new DescribeTableRequest()		.withTableName(PropertyLoader.getInstance().getTestTableName());DescribeTableResult result = ddb.describeTable(request);String status = result.getTable().getTableStatus();

Creating Users (Item Creation)

For each user, we'll create an item in the table. An item is a collection of attribute/value pairs. For each item, we'll have three attributes: userNo, firstName, and lastName. These are added to a put item request in order to create the item.

HashMap<String, AttributeValue> item = new HashMap<String, AttributeValue>();AttributeValue userNo = new AttributeValue().withN(String.valueOf(i));item.put("userNo", userNo);AttributeValue firstName = new AttributeValue().withS(Constants.getRandomName());item.put("firstName", firstName);AttributeValue lastName = new AttributeValue().withS(Constants.getRandomName());item.put("lastName", lastName);PutItemRequest request = new PutItemRequest().withTableName(		PropertyLoader.getInstance().getTestTableName()).withItem(item);ddb.putItem(request);

Deleting Users (Item Deletion)

To remove a user from the list simply means deleting the corresponding item from the table. We specify the item we wish to delete using the hash key for the item.

AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();Key primaryKey = new Key().withHashKeyElement(targetValue);DeleteItemRequest request = new DeleteItemRequest().withTableName(		PropertyLoader.getInstance().getTestTableName()).withKey(primaryKey);ddb.deleteItem(request);

Listing Users (Table Scan)

We can retrieve a collection of users with a scan request. A scan request simply scans the table and returns the results in an undetermined order. Scan is an expensive operation and should be used with care to avoid disrupting your higher priority production traffic on the table. See the Amazon DynamoDB developer guide for more recommendations for safely using the Scan operation.

AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();ScanRequest request = new ScanRequest();request.setTableName(PropertyLoader.getInstance().getTestTableName());ScanResult result = ddb.scan(request);ArrayList<HashMap<String, AttributeValue>> users = 
                      (ArrayList<HashMap<String, AttributeValue>>) result.getItems();

Retrieving a User's Preferences (Item Retrieval)

Knowing a user's userNo, the hash key of the table, it is easy to find the item for the user. This next snippet shows how to get all the attributes for an item using the hash key.

AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();AttributeValue userNoAttr = new AttributeValue().withN(String.valueOf(userNo));Key primaryKey = new Key().withHashKeyElement(userNoAttr);GetItemRequest request = new GetItemRequest().withTableName(		PropertyLoader.getInstance().getTestTableName()).withKey(primaryKey);GetItemResult result = ddb.getItem(request);HashMap<String, AttributeValue> userPreferences = 
                                        (HashMap<String, AttributeValue>) result.getItem();

Modifying User Preferences (Item Update)

The hash key also makes it easy to update an attribute for an item.

AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();AttributeValue av = new AttributeValue().withS(value);AttributeValueUpdate avu = new AttributeValueUpdate().withValue(av).withAction(AttributeAction.PUT);Key primaryKey = new Key().withHashKeyElement(targetValue);HashMap<String, AttributeValueUpdate> updates = new HashMap<String, AttributeValueUpdate>();updates.put(key, avu);UpdateItemRequest request = new UpdateItemRequest()		.withTableName(PropertyLoader.getInstance().getTestTableName())		.withKey(primaryKey).withAttributeUpdates(updates);ddb.updateItem(request);

List Deletion (Table Deletion)

The easiest way to remove all the user preference data is to delete the Amazon DynamoDB table. The following code shows how:

AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();DeleteTableRequest request = new DeleteTableRequest()		.withTableName(PropertyLoader.getInstance().getTestTableName());ddb.deleteTable(request);

Conclusion and Additional Resources

The code in this article demonstrates how to use Amazon DynamoDB as a storage device for your mobile application. You can find more information about Amazon DynamoDB here.

Sample apps that include the code from this article are provided with the AWS SDK for Android. You can download the SDK using the following link:

AWS SDK for Android

For more information about using AWS credentials with mobile applications see the following article:

Authenticating Users of AWS Mobile Applications with a Token Vending Machine

Questions?

Please feel free to ask questions or provide comments in the Mobile Development Forum.

December 16, 2011

gdierkes

Overview

This article discusses how mobile apps can use Amazon Web Services to communicate with users via e-mail, short message service (SMS), and other communication channels. The sample code presented here uses Amazon Simple Notification Service and Amazon Simple Queue Service. Amazon Simple Notification Service (Amazon SNS) makes it easy to set up, manage, and send notifications from mobile apps and have these notifications delivered immediately to any users who have chosen to subscribe to them. Amazon SNS provides a highly scalable, flexible, and cost-effective method to implement such notification systems.

Amazon Simple Queue Service (Amazon SQS), also discussed here, offers a reliable, highly scalable, hosted queue for storing messages. The types of messages supported by Amazon SQS include—but aren't limited to—the notification messages sent from Amazon SNS.

Together, Amazon SNS and Amazon SQS enable developers to create apps that can message large numbers of users in multiple formats quickly and easily.

The sample app described here demostrates how mobile apps can message their users through Amazon SNS and Amazon SQS. The sample demonstrates how to use Amazon SNS to create a topic, subscribe users to that topic, and publish notifications to the topic. Subscribers to the topic can receive their notifications via e-mail, SMS, or an Amazon SQS queue. Amazon SQS and Amazon SNS can also be used to create other types of communication systems not shown here.

This article shows sample code but the complete sample code and project files are included in the AWS SDK for Android. A link to the SDK is available at the end of this article.

To use the AWS SDK for Android, you will need AWS credentials, that is, an Access Key ID and Secret Access Key. If you haven't already signed up for Amazon Web Services (AWS), you will need to do that first to get your credentials. You can sign up for AWS here. After you sign up, you can retrieve your credentials at this page.

Creating Amazon SQS and Amazon SNS Clients

Making requests to Amazon SNS and Amazon SQS requires creating a client for each service. The code below shows how to create a client:

AWSCredentials credentials =      new BasicAWSCredentials( Constants.ACCESS_KEY_ID, Constants.SECRET_KEY );		AmazonSNSClient snsClient = new AmazonSNSClient( credentials );AmazonSQSClient sqsClient = new AmazonSQSClient( credentials );

Topic Creation

Amazon SNS uses topics to route notifications from publishers to subscribers. The term publisher refers to an app that sends notifications; the term subscriber refers to an entity, such as a user, that receives notifications. Topics provide a junction point for publishers and subscribers to communicate with each other. Once a topic is created, subscribers can be added to the topic and receive notifications/messages. The DisplayName attribute is added to a topic to allow notifications to be sent via SMS.

CreateTopicRequest ctr = new CreateTopicRequest( Constants.TOPIC_NAME );CreateTopicResult result = snsClient.createTopic( ctr );	        SetTopicAttributesRequest tar      = new SetTopicAttributesRequest( result.getTopicArn(), "DisplayName", "MessageBoard" );this.snsClient.setTopicAttributes( tar );  

Subscribing to Topics

In order for notifications sent to a topic to be received, you have to subscribe an endpoint to that topic. The endpoint corresponds to a recipient. An endpoint is an e-mail address, SMS number, web server, or Amazon SQS queue. If you are using an Amazon SQS queue, it needs to be configured to receive notification messages from Amazon SNS. Once you subscribe an endpoint to a topic and the subscription is confirmed, the endpoint will receive all messages published to that topic.

SubscribeRequest sr = new SubscribeRequest( this.topicARN, "email", email );this.snsClient.subscribe( sr );

Listing a Topic's Subscribers

Listing the subscribers for a topic provides the endpoint and corresponding protocol for each subscriber who receives notification via that topic. The protocol for an endpoint depends on the type of endpoint. For example, endpoints that are e-mail addresses have a protocol of SMTP.

ListSubscriptionsByTopicRequest ls = new ListSubscriptionsByTopicRequest( this.topicARN );ListSubscriptionsByTopicResult response = this.snsClient.listSubscriptionsByTopic( ls );return response.getSubscriptions();

Publishing Notifications

Publishers send notifications to topics. Once a new notification is published, Amazon SNS attempts to deliver that notification to every endpoint that is subscribed to the topic.

PublishRequest pr = new PublishRequest( this.topicARN, message );this.snsClient.publish( pr );	

Unsubscribing from Topics

Unsubscribing removes the endpoint from the topic and stops notifications from being received.

UnsubscribeRequest unsubscribeRequest = new UnsubscribeRequest( subscriptionArn );this.snsClient.unsubscribe( unsubscribeRequest );

Creating a Queue

The first task in using Amazon SQS is to create a queue. Once a queue is created it can be subscribed as an endpoint to an Amazon SNS topic.

CreateQueueRequest cqr = new CreateQueueRequest( Constants.QUEUE_NAME );CreateQueueResult result = this.sqsClient.createQueue( cqr );return result.getQueueUrl();

Subscribing a Queue to a Topic

Here's how to subscribe a queue to a topic. However, for the queue to receive messages, you must also add a policy to the queue. See below.

String queueArn = this.createMessageQueue();		SubscribeRequest request = new SubscribeRequest();request.withEndpoint( queueArn ).withProtocol( "sqs" ).withTopicArn( this.topicARN );		this.snsClient.subscribe( request );

Adding a policy to a Queue

In order for a queue to receive messages from a topic, the queue must have a policy object that specifies that the topic has sqs:SendMessage permission for the queue. For further details see the Amazon SNS FAQ. For more information about queue policies see the Amazon SQS documentation. Once the policy object is created it can be attached to the queue as follows:

HashMap attributes = new HashMap();attributes.put("Policy", generateSqsPolicyForTopic( queueArn, this.topicARN ) );this.sqsClient.setQueueAttributes(new SetQueueAttributesRequest( queueUrl, attributes ) );

Receiving Messages from a Queue

Now that a message is in the queue, you can receive it, which requires getting it from the queue. When requesting to get a message from the queue, you can't specify which message to get. Instead, you simply specify the maximum number of messages you want to get (up to 10), and Amazon SQS returns up to that maximum number. Because Amazon SQS is a distributed system and the particular queue we're working with here has very few messages in it, the response to the receive request might be empty. Therefore, you should rerun the sample until you get the message. You should design your own app so that it continues to poll the queue until it gets one or more messages.

ReceiveMessageRequest rmr = new ReceiveMessageRequest( this.queueUrl );rmr.setMaxNumberOfMessages( 10 );rmr.setVisibilityTimeout( 30 );ReceiveMessageResult result = this.sqsClient.receiveMessage( rmr );

Delete Messages from a Queue

Amazon SQS doesn't automatically delete a message after returning it to the app. By default, it keeps the message to protect against the case where the receiving app fails or loses its connection. In these cases, a different app—or perhaps a new instance of the same app— might attempt to get the message.

To delete the message, you must send a separate request. You specify which message to delete by providing the receipt handle that Amazon SQS returned when you received the message. You can delete only one message per call. Deleting the message acknowledges that you've successfully received and processed it.

DeleteMessageRequest request      = new DeleteMessageRequest( this.queueUrl, message.getReceiptHandle() );this.sqsClient.deleteMessage( request );

References

A sample app that includes this code is provided with the SDK. The download link can be found on the following page:

For more information about using AWS credentials with mobile apps see the following article:

Questions?

Please feel free to ask questions or provide comments in the Mobile Development Forum.

November 10, 2011

gdierkes

This article demonstrates how to use the AWS SDK for Android to uploadan image to Amazon Simple StorageService (S3) from your mobile device and how to make that imageavailable on the web. Amazon S3 is storage for the Internet. It's a simplestorage service that offers software developers a highly-scalable,reliable, secure, fast, and inexpensive data storage. The complete samplecode and project files are included in the AWS SDK for Android which canbe found here.

To use the AWS SDK for Android, you will need your AWS credentials,that is, your Access Key ID and Secret Access Key. If you haven'talready signed up for Amazon WebServices (AWS), you will need to do that first to get your AWScredentials. You can sign up for AWS here.

Here's what the sample app looks like at start up on Android:

Android-Uploader

Photo Upload

The app uses each platform's "image picker" utility to have theend-user select an image for upload. The app then creates an Amazon S3client, uses the client to create an Amazon S3 bucket in which to storethe image, and finally uploads the image into the bucket. A bucket is acontainer for objects stored in Amazon S3. Every object--such as animage--is contained within a bucket.      

Get the image

The first step is to retrieve the content, in this case an image, tobe uploaded to Amazon S3. For this sample app, selecting an image from thedevice itself is an easy choice.

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType("image/*");startActivityForResult(intent, PHOTO_SELECTED);

Android-Image-Picker

Once an image is selected, a callback method is invoked with theselected image's information. The app uses this information to completethe upload.

Upload the image

Once we have the image, we can attempt to upload it to Amazon S3.

First, create an Amazon S3 client to communicate withthe service.

AmazonS3Client s3Client =   new AmazonS3Client( new BasicAWSCredentials( MY_ACCESS_KEY_ID, MY_SECRET_KEY ) );

Second, create an Amazon S3 bucket to store thepicture.

s3Client.createBucket( MY_PICTURE_BUCKET );

Finally, put the image object into the Amazon S3bucket.

PutObjectRequest por =    new PutObjectRequest( Constants.getPictureBucket(),                          Constants.PICTURE_NAME,                          new java.io.File( filePath) );s3Client.putObject( por );

Browser Display

The app makes the image available for viewing in a browser bygenerating a pre-signed URL. A pre-signed URL is a URL for an Amazon S3resource that is signed with current AWS security credentials. Thepre-signed URL can then be shared with other users, allowing them toaccess resources without providing an account's AWS securitycredentials.

First, create an override content type to ensure thatthe "content" will be treated as an image by the browser.

ResponseHeaderOverrides override = new ResponseHeaderOverrides();override.setContentType( "image/jpeg" );

Second, create the pre-signed URL request. Pre-signedURLs can be created with an expiration date, that is, a date andtime after which the resource will no longer be available. In the sample,the pre-signed URLs are valid for only one hour.

GeneratePresignedUrlRequest urlRequest =    new GeneratePresignedUrlRequest( Constants.getPictureBucket(),                                     Constants.PICTURE_NAME );// Added an hour's worth of milliseconds to the current time.urlRequest.setExpiration(    new Date( System.currentTimeMillis() + 3600000 ) );urlRequest.setResponseHeaders( override );

Third, generate the pre-signed URL. 

URL url = s3Client.generatePresignedUrl( urlRequest );

Finally, launch the browser to view the pre-signed URLwhich will display the image. 

startActivity(    new Intent( Intent.ACTION_VIEW, Uri.parse( url.toURI().toString() ) ));

Android-ShowPic

Next Steps

These few lines of code demonstrate how Amazon S3 could become alimitless storage device for your mobile photos. A photo sharing app thatallows users to view photos from other users would not be a difficultextension to the above code. Also, the content that is uploaded and sharedis not limited to images. The content could be audio files, video files,text, or other content that users want to store and share. 

References

A sample app that includes this code is provided with both mobile SDKs.The download links can be found here: AWS SDK for Android.

For more information about using AWS credentials with mobileapplications see the following article: Authenticating Users of AWS Mobile Applications with a Token VendingMachine

Questions?

Please feel free to ask questions or make comments in the MobileDevelopment Forum.

Portions of this page are reproduced from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.

October 28, 2011

amberta

Last month we announced a promotion with Amazon Web Services (AWS) where qualifying developers who submit an Android app or app update to the Amazon Appstore for Android are eligible to receive a $50 AWS credit to use toward the following services:

Remember, there’s still time to submit. The promotion runs through November 15, 2011, and we encourage you to get your apps in soon. We encourage you to ensure you’ve submitted the current versions of all your apps to the Amazon Appstore. Now is also a good time to verify that each app’s meta-data (including list price) is up-to-date. You can update your existing apps and submit new apps using the Amazon Appstore Developer Portal.

For developers new to AWS, here’s a great video on how to get started:

Many developers have already qualified for and received their promotion code for AWS. AWS combined with the Amazon Appstore provide a solid suite of solutions to build apps and a great place to get exposure. MightyMeeting, an app that enables users to run online meetings on the go from tablets, smartphones, or any web-enabled device is one great example. “We needed a cost-efficient robust infrastructure that could be used to manage presentations and online meetings in the cloud and scale up or down dynamically depending on the workload. We found that AWS addresses all our needs, even real-time media streaming during a meeting,” says Dmitri Tcherevik, CEO of MightyMeeting Inc.

Learn more about the AWS SDK and this promotion online here. To apply your code, sign up for an AWS account and apply your promotion code by visiting: http://aws.amazon.com/awscredits/

Submit your app online here.
 

September 12, 2011

merydith

The Amazon Web Services (AWS) Mobile SDK for Android is now generally available (GA).  The SDK features APIs designed specifically for mobile apps, and has sample code showing you how to connect to AWS using the AWS Security Token Service.

Made by mobile developers for mobile developers, the AWS Mobile SDK for Android provides support for connecting your application to the cloud. These “connected” apps leverage AWS to manage and scale new and compelling features.  The SDK makes it easy for you to build connected mobile applications by providing APIs that hide much of the lower-level networking code, including authentication, request retries, and error handling.

What types of connected features can you implement with the AWS Mobile SDK for Android?

  • Build a camera-to-cloud media application that uploads photos or videos to Amazon S3 for world-wide distribution through Amazon CloudFront. Amazon S3 provides the storage and Amazon CloudFront provides low-latency delivery of static or streaming content.
  • Make your mobile game "social" by adding the ability to share moves, high scores, or player stats between devices using Amazon SimpleDB.  Use the SDK to store and query data items via a simple interface, and Amazon SimpleDB does the rest.
  • Add the ability to broadcast messages (“It’s your turn, Dave”) between devices with Amazon Simple Notification Service and Amazon Simple Queue Service―without writing any server code.
  • And remember that camera-to-cloud application? Well, when your users ask you to update the application so they can email those photos and videos to friends, it’s going to be a snap, because you can use Amazon Simple Email Service to send emails from your application.

Get started by visiting the AWS SDK for Android page where you can download the SDK and read the Getting Started Guide.

If you submit your app to the Amazon Appstore for Android by November 15, you'll receive a $50 credit.  Learn more about this promotion at:  http://aws.amazon.com/Android-development-with-AWS

September 07, 2011

amberta

The Amazon Appstore for Android is the place where developers can get exposure for their Android applications through automated merchandising and other marketing.  Amazon also offers great solutions for developers to build apps with the Amazon Web Services (AWS) Mobile SDK.

From September 7, 2011 through November 15, 2011, developers who submit an Android app to the Amazon Appstore are eligible to receive a one-time $50 promotion code for use on certain AWS services (subject to terms and conditions).  Promotion codes will be emailed directly to developers during the first week of October and the last week of November.


AWS delivers a set of simple building block services that together form a reliable, scalable, and inexpensive computing platform “in the cloud”. With AWS, developers can easily access a scalable and cost-effective cloud computing resources through simple API calls or with the use of the AWS Mobile SDK for Android (and iOS).  As noted in this blog post , some highlights of the AWS SDK for Android include:

  • Storage – developers can store and retrieve any amount of data using Amazon S3
  • Database – developers can add a highly available, scalable, and flexible non-relational data store using Amazon SimpleDB with little or no administrative burden
  • Messaging – developers can integrate reliable, highly scalable mobile-to-mobile communication into applications using Amazon SQS and Amazon SNS

The SDK includes a library, full documentation, and some sample code.  You can get the library on GitHub.  Also, in true open source fashion, AWS is open to and encourages external contributions.

Learn more about the AWS SDK and this promotion online here.

Submit your app online here.