Glide ModelLoader that loads either from local or remoteStrange out of memory issue while loading an image to a Bitmap objectLazy load of images in ListViewStop EditText from gaining focus at Activity startupHow to pick an image from gallery (SD Card) for my app?Is there a way to get the source code from an APK file?How to round an image with Glide library?Picasso v/s Imageloader v/s Fresco vs GlideGlide load local image by Uri.Using Glide for Android, what's a good way to use (local) alternative sources for urls?storing and loading images to be displayed in recycler view items
How was the quadratic formula created?
Set collection doesn't always enforce uniqueness with the Date datatype? Does the following example seem correct?
Can hackers enable the camera after the user disabled it?
Send iMessage from Firefox
Why wasn't the Night King naked in S08E03?
Why is "Vayechulu" said 3 times on Leil Shabbat?
Does a card have a keyword if it has the same effect as said keyword?
Why do money exchangers give different rates to different bills?
What was the first instance of a "planet eater" in sci-fi?
Have I damaged my car by attempting to reverse with hand/park brake up?
How can I support myself financially as a 17 year old with a loan?
What are the advantages of luxury car brands like Acura/Lexus over their sibling non-luxury brands Honda/Toyota?
Make some Prime Squares!
What is the name of this hexagon/pentagon polyhedron?
I drew a randomly colored grid of points with tikz, how do I force it to remember the first grid from then on?
Would Hubble Space Telescope improve black hole image observed by EHT if it joined array of telesopes?
Can Infinity Stones be retrieved more than once?
Why was the battle set up *outside* Winterfell?
Will 700 more planes a day fly because of the Heathrow expansion?
Purpose of のは in this sentence?
How does this change to the opportunity attack rule impact combat?
How important is people skills in academic career and applications?
Building a list of products from the elements in another list
As matter approaches a black hole, does it speed up?
Glide ModelLoader that loads either from local or remote
Strange out of memory issue while loading an image to a Bitmap objectLazy load of images in ListViewStop EditText from gaining focus at Activity startupHow to pick an image from gallery (SD Card) for my app?Is there a way to get the source code from an APK file?How to round an image with Glide library?Picasso v/s Imageloader v/s Fresco vs GlideGlide load local image by Uri.Using Glide for Android, what's a good way to use (local) alternative sources for urls?storing and loading images to be displayed in recycler view items
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I have a custom Glide model to calculate the center crop for image. The same model is used for getting images from server and also from local storage.
Here's the model interface:
interface CenterCropImageInformation
fun getCenterCropUri(context: Context, @Px width: Int, @Px height: Int): Uri
And here is its ModelLoader that extends from BaseGlideUrlLoader
:
class CenterCropImageInformationLoader private constructor(
context: Context,
concreteLoader: ModelLoader<GlideUrl, InputStream>,
modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
) : BaseGlideUrlLoader<CenterCropImageInformation>(concreteLoader, modelCache)
private val applicationContext: Context = context.applicationContext
override fun getUrl(
model: CenterCropImageInformation, width: Int,
height: Int, options: Options
): String
return model.getCenterCropUri(applicationContext, width, height).toString()
override fun handles(centerCropImageInformation: CenterCropImageInformation): Boolean
return true
/**
* The default factory for [CenterCropImageInformation]s.
*/
class Factory(
private val applicationContext: Context,
private val modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
) : ModelLoaderFactory<CenterCropImageInformation, InputStream>
override fun build(
multiFactory: MultiModelLoaderFactory
): ModelLoader<CenterCropImageInformation, InputStream>
val modelLoader = multiFactory.build(GlideUrl::class.java, InputStream::class.java)
return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
override fun teardown()
This works fine for images with http/https
scheme, but it doesn't work for file
scheme - the one used for loading images from local device storage.
I had a look into Glide's source code and the closest ModelLoader that sounds like an option is UriLoader
, but the issue that that one doesn't support custom models. It only supports Uri
.
The optimal solution would be to use a pre-existing ModelLoader that is bundled with Glide, but unless I missed it, I couldn't find any that suits my needs. If that's really the case, how do I implement such ModelLoader?
android android-image android-glide
add a comment |
I have a custom Glide model to calculate the center crop for image. The same model is used for getting images from server and also from local storage.
Here's the model interface:
interface CenterCropImageInformation
fun getCenterCropUri(context: Context, @Px width: Int, @Px height: Int): Uri
And here is its ModelLoader that extends from BaseGlideUrlLoader
:
class CenterCropImageInformationLoader private constructor(
context: Context,
concreteLoader: ModelLoader<GlideUrl, InputStream>,
modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
) : BaseGlideUrlLoader<CenterCropImageInformation>(concreteLoader, modelCache)
private val applicationContext: Context = context.applicationContext
override fun getUrl(
model: CenterCropImageInformation, width: Int,
height: Int, options: Options
): String
return model.getCenterCropUri(applicationContext, width, height).toString()
override fun handles(centerCropImageInformation: CenterCropImageInformation): Boolean
return true
/**
* The default factory for [CenterCropImageInformation]s.
*/
class Factory(
private val applicationContext: Context,
private val modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
) : ModelLoaderFactory<CenterCropImageInformation, InputStream>
override fun build(
multiFactory: MultiModelLoaderFactory
): ModelLoader<CenterCropImageInformation, InputStream>
val modelLoader = multiFactory.build(GlideUrl::class.java, InputStream::class.java)
return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
override fun teardown()
This works fine for images with http/https
scheme, but it doesn't work for file
scheme - the one used for loading images from local device storage.
I had a look into Glide's source code and the closest ModelLoader that sounds like an option is UriLoader
, but the issue that that one doesn't support custom models. It only supports Uri
.
The optimal solution would be to use a pre-existing ModelLoader that is bundled with Glide, but unless I missed it, I couldn't find any that suits my needs. If that's really the case, how do I implement such ModelLoader?
android android-image android-glide
add a comment |
I have a custom Glide model to calculate the center crop for image. The same model is used for getting images from server and also from local storage.
Here's the model interface:
interface CenterCropImageInformation
fun getCenterCropUri(context: Context, @Px width: Int, @Px height: Int): Uri
And here is its ModelLoader that extends from BaseGlideUrlLoader
:
class CenterCropImageInformationLoader private constructor(
context: Context,
concreteLoader: ModelLoader<GlideUrl, InputStream>,
modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
) : BaseGlideUrlLoader<CenterCropImageInformation>(concreteLoader, modelCache)
private val applicationContext: Context = context.applicationContext
override fun getUrl(
model: CenterCropImageInformation, width: Int,
height: Int, options: Options
): String
return model.getCenterCropUri(applicationContext, width, height).toString()
override fun handles(centerCropImageInformation: CenterCropImageInformation): Boolean
return true
/**
* The default factory for [CenterCropImageInformation]s.
*/
class Factory(
private val applicationContext: Context,
private val modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
) : ModelLoaderFactory<CenterCropImageInformation, InputStream>
override fun build(
multiFactory: MultiModelLoaderFactory
): ModelLoader<CenterCropImageInformation, InputStream>
val modelLoader = multiFactory.build(GlideUrl::class.java, InputStream::class.java)
return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
override fun teardown()
This works fine for images with http/https
scheme, but it doesn't work for file
scheme - the one used for loading images from local device storage.
I had a look into Glide's source code and the closest ModelLoader that sounds like an option is UriLoader
, but the issue that that one doesn't support custom models. It only supports Uri
.
The optimal solution would be to use a pre-existing ModelLoader that is bundled with Glide, but unless I missed it, I couldn't find any that suits my needs. If that's really the case, how do I implement such ModelLoader?
android android-image android-glide
I have a custom Glide model to calculate the center crop for image. The same model is used for getting images from server and also from local storage.
Here's the model interface:
interface CenterCropImageInformation
fun getCenterCropUri(context: Context, @Px width: Int, @Px height: Int): Uri
And here is its ModelLoader that extends from BaseGlideUrlLoader
:
class CenterCropImageInformationLoader private constructor(
context: Context,
concreteLoader: ModelLoader<GlideUrl, InputStream>,
modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
) : BaseGlideUrlLoader<CenterCropImageInformation>(concreteLoader, modelCache)
private val applicationContext: Context = context.applicationContext
override fun getUrl(
model: CenterCropImageInformation, width: Int,
height: Int, options: Options
): String
return model.getCenterCropUri(applicationContext, width, height).toString()
override fun handles(centerCropImageInformation: CenterCropImageInformation): Boolean
return true
/**
* The default factory for [CenterCropImageInformation]s.
*/
class Factory(
private val applicationContext: Context,
private val modelCache: ModelCache<CenterCropImageInformation, GlideUrl>?
) : ModelLoaderFactory<CenterCropImageInformation, InputStream>
override fun build(
multiFactory: MultiModelLoaderFactory
): ModelLoader<CenterCropImageInformation, InputStream>
val modelLoader = multiFactory.build(GlideUrl::class.java, InputStream::class.java)
return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
override fun teardown()
This works fine for images with http/https
scheme, but it doesn't work for file
scheme - the one used for loading images from local device storage.
I had a look into Glide's source code and the closest ModelLoader that sounds like an option is UriLoader
, but the issue that that one doesn't support custom models. It only supports Uri
.
The optimal solution would be to use a pre-existing ModelLoader that is bundled with Glide, but unless I missed it, I couldn't find any that suits my needs. If that's really the case, how do I implement such ModelLoader?
android android-image android-glide
android android-image android-glide
asked Mar 22 at 22:16
Nimrod DayanNimrod Dayan
1,99842334
1,99842334
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
I figured it out after reading Glide's ModelLoaders tutorial. The key is by delegating the loading to a ModelLoader that knows how to handle file
and http/https
scheme.
What I had to do is to implement ModelLoader
interface directly instead of extending BaseGlideUrlLoader
. We already know that Glide's built-in UriLoader
can handle both file
and http/https
scheme so we delegate to it. Now to get an instance of UriLoader
we use the MultiModelLoaderFactory
that is passed to our factory's build
method. The default Glide configuration registers UriLoader
for Uri
+ InputStream
pair.
class CenterCropImageInformationLoader(
private val modelLoader: ModelLoader<Uri, InputStream>,
private val modelCache: ModelCache< CenterCropImageInformation, Uri>
) : ModelLoader<CenterCropImageInformation, InputStream>
override fun buildLoadData(
model: CenterCropImageInformation,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<InputStream>?
val uri: Uri = modelCache.get(model, width, height) ?: model.getUri(model, width, height)
modelCache.put(model, width, height, uri)
return modelLoader.buildLoadData(uri, width, height, options)
override fun handles(model: CenterCropImageInformation): Boolean = true
class Factory(
private val applicationContext: Context,
private val modelCache: ModelCache<CenterCropImageInformation, Uri>
) : ModelLoaderFactory<CenterCropImageInformation, InputStream>
override fun build(
multiFactory: MultiModelLoaderFactory
): ModelLoader<CenterCropImageInformation, InputStream>
val modelLoader = multiFactory.build(Uri::class.java, InputStream::class.java)
return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
override fun teardown()
As we can see we no longer extend BaseGlideUrlLoader
. Instead we implement ModelLoader
interface and in buildLoadData()
implementation we try to get the URI from cache (this is similar to what BaseGlideUrlLoader
is doing) and then we call buildLoadData()
on the ModelLoader
that we passed to the constructor, which happens to be an instance of UriLoader
as I mentioned earlier thanks to MultiModelLoaderFactory
.
It's really surprising that this type of ModelLoader is not part of Glide built-in model loaders.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55308477%2fglide-modelloader-that-loads-either-from-local-or-remote%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I figured it out after reading Glide's ModelLoaders tutorial. The key is by delegating the loading to a ModelLoader that knows how to handle file
and http/https
scheme.
What I had to do is to implement ModelLoader
interface directly instead of extending BaseGlideUrlLoader
. We already know that Glide's built-in UriLoader
can handle both file
and http/https
scheme so we delegate to it. Now to get an instance of UriLoader
we use the MultiModelLoaderFactory
that is passed to our factory's build
method. The default Glide configuration registers UriLoader
for Uri
+ InputStream
pair.
class CenterCropImageInformationLoader(
private val modelLoader: ModelLoader<Uri, InputStream>,
private val modelCache: ModelCache< CenterCropImageInformation, Uri>
) : ModelLoader<CenterCropImageInformation, InputStream>
override fun buildLoadData(
model: CenterCropImageInformation,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<InputStream>?
val uri: Uri = modelCache.get(model, width, height) ?: model.getUri(model, width, height)
modelCache.put(model, width, height, uri)
return modelLoader.buildLoadData(uri, width, height, options)
override fun handles(model: CenterCropImageInformation): Boolean = true
class Factory(
private val applicationContext: Context,
private val modelCache: ModelCache<CenterCropImageInformation, Uri>
) : ModelLoaderFactory<CenterCropImageInformation, InputStream>
override fun build(
multiFactory: MultiModelLoaderFactory
): ModelLoader<CenterCropImageInformation, InputStream>
val modelLoader = multiFactory.build(Uri::class.java, InputStream::class.java)
return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
override fun teardown()
As we can see we no longer extend BaseGlideUrlLoader
. Instead we implement ModelLoader
interface and in buildLoadData()
implementation we try to get the URI from cache (this is similar to what BaseGlideUrlLoader
is doing) and then we call buildLoadData()
on the ModelLoader
that we passed to the constructor, which happens to be an instance of UriLoader
as I mentioned earlier thanks to MultiModelLoaderFactory
.
It's really surprising that this type of ModelLoader is not part of Glide built-in model loaders.
add a comment |
I figured it out after reading Glide's ModelLoaders tutorial. The key is by delegating the loading to a ModelLoader that knows how to handle file
and http/https
scheme.
What I had to do is to implement ModelLoader
interface directly instead of extending BaseGlideUrlLoader
. We already know that Glide's built-in UriLoader
can handle both file
and http/https
scheme so we delegate to it. Now to get an instance of UriLoader
we use the MultiModelLoaderFactory
that is passed to our factory's build
method. The default Glide configuration registers UriLoader
for Uri
+ InputStream
pair.
class CenterCropImageInformationLoader(
private val modelLoader: ModelLoader<Uri, InputStream>,
private val modelCache: ModelCache< CenterCropImageInformation, Uri>
) : ModelLoader<CenterCropImageInformation, InputStream>
override fun buildLoadData(
model: CenterCropImageInformation,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<InputStream>?
val uri: Uri = modelCache.get(model, width, height) ?: model.getUri(model, width, height)
modelCache.put(model, width, height, uri)
return modelLoader.buildLoadData(uri, width, height, options)
override fun handles(model: CenterCropImageInformation): Boolean = true
class Factory(
private val applicationContext: Context,
private val modelCache: ModelCache<CenterCropImageInformation, Uri>
) : ModelLoaderFactory<CenterCropImageInformation, InputStream>
override fun build(
multiFactory: MultiModelLoaderFactory
): ModelLoader<CenterCropImageInformation, InputStream>
val modelLoader = multiFactory.build(Uri::class.java, InputStream::class.java)
return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
override fun teardown()
As we can see we no longer extend BaseGlideUrlLoader
. Instead we implement ModelLoader
interface and in buildLoadData()
implementation we try to get the URI from cache (this is similar to what BaseGlideUrlLoader
is doing) and then we call buildLoadData()
on the ModelLoader
that we passed to the constructor, which happens to be an instance of UriLoader
as I mentioned earlier thanks to MultiModelLoaderFactory
.
It's really surprising that this type of ModelLoader is not part of Glide built-in model loaders.
add a comment |
I figured it out after reading Glide's ModelLoaders tutorial. The key is by delegating the loading to a ModelLoader that knows how to handle file
and http/https
scheme.
What I had to do is to implement ModelLoader
interface directly instead of extending BaseGlideUrlLoader
. We already know that Glide's built-in UriLoader
can handle both file
and http/https
scheme so we delegate to it. Now to get an instance of UriLoader
we use the MultiModelLoaderFactory
that is passed to our factory's build
method. The default Glide configuration registers UriLoader
for Uri
+ InputStream
pair.
class CenterCropImageInformationLoader(
private val modelLoader: ModelLoader<Uri, InputStream>,
private val modelCache: ModelCache< CenterCropImageInformation, Uri>
) : ModelLoader<CenterCropImageInformation, InputStream>
override fun buildLoadData(
model: CenterCropImageInformation,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<InputStream>?
val uri: Uri = modelCache.get(model, width, height) ?: model.getUri(model, width, height)
modelCache.put(model, width, height, uri)
return modelLoader.buildLoadData(uri, width, height, options)
override fun handles(model: CenterCropImageInformation): Boolean = true
class Factory(
private val applicationContext: Context,
private val modelCache: ModelCache<CenterCropImageInformation, Uri>
) : ModelLoaderFactory<CenterCropImageInformation, InputStream>
override fun build(
multiFactory: MultiModelLoaderFactory
): ModelLoader<CenterCropImageInformation, InputStream>
val modelLoader = multiFactory.build(Uri::class.java, InputStream::class.java)
return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
override fun teardown()
As we can see we no longer extend BaseGlideUrlLoader
. Instead we implement ModelLoader
interface and in buildLoadData()
implementation we try to get the URI from cache (this is similar to what BaseGlideUrlLoader
is doing) and then we call buildLoadData()
on the ModelLoader
that we passed to the constructor, which happens to be an instance of UriLoader
as I mentioned earlier thanks to MultiModelLoaderFactory
.
It's really surprising that this type of ModelLoader is not part of Glide built-in model loaders.
I figured it out after reading Glide's ModelLoaders tutorial. The key is by delegating the loading to a ModelLoader that knows how to handle file
and http/https
scheme.
What I had to do is to implement ModelLoader
interface directly instead of extending BaseGlideUrlLoader
. We already know that Glide's built-in UriLoader
can handle both file
and http/https
scheme so we delegate to it. Now to get an instance of UriLoader
we use the MultiModelLoaderFactory
that is passed to our factory's build
method. The default Glide configuration registers UriLoader
for Uri
+ InputStream
pair.
class CenterCropImageInformationLoader(
private val modelLoader: ModelLoader<Uri, InputStream>,
private val modelCache: ModelCache< CenterCropImageInformation, Uri>
) : ModelLoader<CenterCropImageInformation, InputStream>
override fun buildLoadData(
model: CenterCropImageInformation,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<InputStream>?
val uri: Uri = modelCache.get(model, width, height) ?: model.getUri(model, width, height)
modelCache.put(model, width, height, uri)
return modelLoader.buildLoadData(uri, width, height, options)
override fun handles(model: CenterCropImageInformation): Boolean = true
class Factory(
private val applicationContext: Context,
private val modelCache: ModelCache<CenterCropImageInformation, Uri>
) : ModelLoaderFactory<CenterCropImageInformation, InputStream>
override fun build(
multiFactory: MultiModelLoaderFactory
): ModelLoader<CenterCropImageInformation, InputStream>
val modelLoader = multiFactory.build(Uri::class.java, InputStream::class.java)
return CenterCropImageInformationLoader(applicationContext, modelLoader, modelCache)
override fun teardown()
As we can see we no longer extend BaseGlideUrlLoader
. Instead we implement ModelLoader
interface and in buildLoadData()
implementation we try to get the URI from cache (this is similar to what BaseGlideUrlLoader
is doing) and then we call buildLoadData()
on the ModelLoader
that we passed to the constructor, which happens to be an instance of UriLoader
as I mentioned earlier thanks to MultiModelLoaderFactory
.
It's really surprising that this type of ModelLoader is not part of Glide built-in model loaders.
edited Mar 26 at 20:48
answered Mar 25 at 15:00
Nimrod DayanNimrod Dayan
1,99842334
1,99842334
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55308477%2fglide-modelloader-that-loads-either-from-local-or-remote%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown