Weak/Soft references?

H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Tegiri Nenashi schreef:
|> No. The graph looks like this:
|>
|> Window <-> Widget <- Data Manager
|
| Fair enough. Let's return to Mike's original claim then:
|
|> 1. G can be careful to unsubscribing when its parent window exits.
|> 2. G can subscribe via a WeakReference to itself.
|
|> 2 involves less bookkeeping, and so is more robust.
|
| The bookkeeping can be hidden in the widget cleanup procedure, can't
| it? Just make widget to be aware of the objects it lisens to. Joshua
| diagramm becomes
|
| Window <-> Widget <-> Data Manager
|
| So one needs to enhance two methods:
| 1. The one that registers the widget as a listener.
| 2. The widget cleanup.
|
| Both are the GUI library methods, so whatever happens onside them is
| transparent to the end user! This can be done high enough in widget
| class hierarchy, of course, to avoid repeating it for every widget
| type.

Well, you’re completely ignoring Joshua’s argument:

|> 2 involves less bookkeeping, and so is more robust.

Your solution involves a lot of bookkeeping.

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iEYEARECAAYFAkh3HWcACgkQe+7xMGD3itRbBACbBjdIF+x9eokUbxTTRTSOp+sM
iMwAnR0uq3NhGWRKuER4DdOmL35T35Ol
=rdWp
-----END PGP SIGNATURE-----
 
H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Andreas Leitgeb schreef:
| For WeakReferences, the #1-example of use is "canonicalizing HashMaps".

I didn’t find a useful thing for this on Google, can you elaborate?

| In other words, it is typically used for HashMaps on Objects whose
| equal() is not overridden from Object (thus reflecting identity),
| and that (the HashMap) is intended to be *never iterated*.
|
| By using a WeakHashMap
| <http://java.sun.com/javase/6/docs/api/java/util/WeakHashMap.html>
| you effectively tell the jvm, that you're never going to iterate
| the map, and that nothing else than the originally added key-objects
| will ever be able to successfully retrieve a value through get().

I don’t read these promises from the Javadoc. Specifically, it mentions
nothing about not being able to use iterators over any of the Collection
views. Where do you get this idea from?

It does warn about using keys which are recreatable, or override
equals(), indeed.

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iEYEARECAAYFAkh3IqsACgkQe+7xMGD3itRGvQCaAqqlvOYAlmgIB4ElX674xXiY
I7QAn1T+15FMfcQBzOjDQKhHj5Au/F8U
=drcd
-----END PGP SIGNATURE-----
 
T

Tom Anderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Andreas Leitgeb schreef:
| For WeakReferences, the #1-example of use is "canonicalizing HashMaps".

I didnt find a useful thing for this on Google, can you elaborate?

Okay, there is actually a minor bit of confusion here. WeakRefrerences are
useful for canonicalisation mappings; a WeakHashMap isn't. To do a
canonicalisation mapping, you need weak values, not weak keys.

Here's what a canonicalisation mapping is. You have some class like
Customer, which is identified by a string ID, and has lots of data that's
pulled from a database or something. For some reason, it's really
important that there is only one instance of Customer representing any
actual customer at a time - if you had two Customer instances representing
Mr Smith, you'd be in trouble. A naive approach would be to do something
like this:

private Map<String, Customer> customers ;

public Customer getCustomer(String id) {
Customer c = customers.get(id) ;
if (c == null) {
c = loadCustomerFromDatabase(id) ;
customers.put(id, c) ;
}
return c ;
}

This is great, but introduces a memory leak: there's no way to remove
Customers from the map, and so it will grow indefinitely, and nobble your
app.

You might think you could deal with this explicitly, by having a
releaseCustomer method which removes the customer from the map. But this
allows bugs: double-frees aren't a problem, because the release isn't
deleting the object or anything, but it means that if client A releases a
customer while client B still has a reference to it, then client C comes
along and loads it again, then B and C have different objects for the same
customer, which is bad. You could do explicit refcounting, but this could
be a huge headache for the client code.

The solution is to store the objects using weak refs:

private Map<String, Reference<Customer>) customers ;

public Customer getCustomer(String id) {
Customer c = customers.get(id).get() ;
if (c == null) {
c = loadCustomerFromDatabase(id) ;
customers.put(id, new WeakReference<c>) ;
}
return c ;
}

Now, they're automatically released when there are no more client
references to them. Problem solved.

In practice, you'd want to use a ReferenceQueue to detect and clean up
dead references, so the map isn't full of thum. But that's a detail.

Note that if we used SoftReferences instead of WeakReferences, we'd have a
more aggressive cache, which would hold on to objects even after they were
unreferenced, but would still release them if memory was tight.

Given that this is a popular (even canonical!) use, i'm surprised that
there isn't a class for it in the standard library.
| In other words, it is typically used for HashMaps on Objects whose
| equal() is not overridden from Object (thus reflecting identity),
| and that (the HashMap) is intended to be *never iterated*.
|
| By using a WeakHashMap
| <http://java.sun.com/javase/6/docs/api/java/util/WeakHashMap.html>
| you effectively tell the jvm, that you're never going to iterate
| the map, and that nothing else than the originally added key-objects
| will ever be able to successfully retrieve a value through get().

I dont read these promises from the Javadoc. Specifically, it mentions
nothing about not being able to use iterators over any of the Collection
views. Where do you get this idea from?

I think Andreas's point is that if you use identity-equals objects and
never iterate, then a WeakHashMap is actually *indistinguishable* from a
normal HashMap, because the only entries which get thrown away are ones
you would never be able to look up anyway.

It's an unusual way of looking at WeakHashMap, but interesting.

tom
 
A

Andreas Leitgeb

Hendrik Maryns said:
Andreas Leitgeb schreef:
| For WeakReferences, the #1-example of use is "canonicalizing HashMaps".
I didn’t find a useful thing for this on Google, can you elaborate?

I read this "canonicalizing HashMap" from WeakReference's javadoc.
I was considerably puzzled by that phrase, myself. Since it didn't
make even the slightest sense to me, I tried to go backwards and
deduce the meaning of that HashMap from WeakReference's behaviour :)
| In other words, it is typically used for HashMaps on Objects whose
| equal() is not overridden from Object (thus reflecting identity),
| and that (the HashMap) is intended to be *never iterated*.

Let's take another, more real-world example:
Suppose you've got some perfect biometric-based security-system
and you keep records for all registered individuals.

At some time, you (as administrator) are informed, that one of
the registered individuals has deceised (hit by a falling
16tons weight), so you can purge the record for that person,
since he won't be asking for entrance ever again.

The WeakHashMap does this purging automatically.
Specifically, it mentions
nothing about not being able to use iterators over any of the Collection
views. Where do you get this idea from?
It does warn about using keys which are recreatable, or override
equals(), indeed.

The whole point of WeakHashMap is, that I want it to clean up for me
all those Entries, whose Key I've lost. This implies, that I do not
some day come back and demand: Hey, HashMap, I know I once gave you
some Key-Object... I don't know what it was, but I'd recognize it
when I see it, so show me all your keys ... (one iteration later)
.... Hey it isn't among those! You lost it, you $§§$&$"&! ...

You can of course iterate a WeakHashMap, but you must not rely on
finding any particular Object that you once added to it, even if you
didn't explictily remove it. If you wanted to rely on iteration
bringing back all Keys, then use a normal HashMap.
 
H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Andreas Leitgeb schreef:
|> Andreas Leitgeb schreef:
|> | For WeakReferences, the #1-example of use is "canonicalizing HashMaps".
|> I didn’t find a useful thing for this on Google, can you elaborate?
|
| I read this "canonicalizing HashMap" from WeakReference's javadoc.
| I was considerably puzzled by that phrase, myself. Since it didn't
| make even the slightest sense to me, I tried to go backwards and
| deduce the meaning of that HashMap from WeakReference's behaviour :)
|
|> | In other words, it is typically used for HashMaps on Objects whose
|> | equal() is not overridden from Object (thus reflecting identity),
|> | and that (the HashMap) is intended to be *never iterated*.
|
| Let's take another, more real-world example:
| Suppose you've got some perfect biometric-based security-system
| and you keep records for all registered individuals.
|
| At some time, you (as administrator) are informed, that one of
| the registered individuals has deceised (hit by a falling
| 16tons weight), so you can purge the record for that person,
| since he won't be asking for entrance ever again.
|
| The WeakHashMap does this purging automatically.
|
|> Specifically, it mentions
|> nothing about not being able to use iterators over any of the Collection
|> views. Where do you get this idea from?
|
|> It does warn about using keys which are recreatable, or override
|> equals(), indeed.
|
| The whole point of WeakHashMap is, that I want it to clean up for me
| all those Entries, whose Key I've lost. This implies, that I do not
| some day come back and demand: Hey, HashMap, I know I once gave you
| some Key-Object... I don't know what it was, but I'd recognize it
| when I see it, so show me all your keys ... (one iteration later)
| ... Hey it isn't among those! You lost it, you $§§$&$"&! ...
|
| You can of course iterate a WeakHashMap, but you must not rely on
| finding any particular Object that you once added to it, even if you
| didn't explictily remove it. If you wanted to rely on iteration
| bringing back all Keys, then use a normal HashMap.

Right. Your original comment sounded like one couldn’t use iteration at
all, though, which isn’t right. It is fine to do, but one shouldn’t
expect to retrieve lost keys with it.

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iEYEARECAAYFAkh3ZGEACgkQe+7xMGD3itQc6wCdEFw0rN6VlJXn4JjbGiq11S/l
hKoAnA1HHucYGIEXoTXe7Th9qHMTr/yv
=+F48
-----END PGP SIGNATURE-----
 
A

Andreas Leitgeb

Tom Anderson said:
Here's what a canonicalisation mapping is. You have some class like
Customer, which is identified by a string ID, and has lots of data that's
pulled from a database or something. For some reason, it's really
important that there is only one instance of Customer representing any
actual customer at a time - if you had two Customer instances representing
Mr Smith, you'd be in trouble.

Thanks for clarifying that!
I think Andreas's point is that if you use identity-equals objects and
never iterate, then a WeakHashMap is actually *indistinguishable* from a
normal HashMap, because the only entries which get thrown away are ones
you would never be able to look up anyway.

Thanks also for putting my thoughts to proper english!
I meant exactly this, but approached it from the opposite side, where
you *would not* do this'n'that, because otherwise you *would* notice
the difference :)

If you don't mind seeing the difference in the first place, then doing
"this'n'that" is of course perfectly ok.
It's an unusual way of looking at WeakHashMap, but interesting.

I'm used to this kind of feedback :) Sometimes it's an
advantage to look at things differently, but more often
it impedes proper conversation, unfortunately.
 
T

Tegiri Nenashi

The point is, you want to have a hash
map (note no capitals here, speaking generically), which you keep as
long as you want, without worrying about memory.  The problem is, the
stuff that is inside the hash map is referenced by it so can’t be
collected, even if it is no longer used anywhere else in the program.

Once again what is so special about "map" let alone "hash"? Wouldn't
argument be verbatim for TreeMap? List, LinkedList? Sure if I put
something in the globally referenced List it would be kept there
indefinitely even if there is no other references to a list element.
If you use WeakHashMap, the stuff *inside* the map can get collected,
once nothing else points at it; the reference the map has to it doesn’t
hinder collection.
Use case: You have some pool of objects which are used in some part of
your program.

"A bunch of stuff used somewhere" -- very precise descrption, but go
on.
 Another part of your program uses them, but needs to do
some effort to get references to them.  At the same time it wants to
have them within reach.  It puts them in a WeakHashMap, so they are
there whenever it needs them.  When OTOH, the first part of the program
stops using the object, it will be removed from the hash map as well, so
the latter part cannot get it any more, which is exactly what is needed,
since it would be invalid to use it any longer.

Hm, maybe not an ideal use case, but something like it.

The culprit is to identify usages where global Map is useful. Map is
essentially a bastardized version of a database, so no wonder that
caching surfaced as the obvious case. I struggle to see anything else.
 
T

Tegiri Nenashi

Let's take another, more real-world example:
Suppose you've got some perfect biometric-based security-system
and you keep records for all registered individuals.

At some time, you (as administrator) are informed, that one of
the registered individuals has deceised (hit by a falling
16tons weight), so you can purge the record for that person,
since he won't be asking for entrance ever again.

The WeakHashMap does this purging automatically.

Look, the application like you describe is database application, and
here you start to sound like one of these "roll your own persistence
layer" morons. If you need to update some records, you'd better do it
properly in the database, rather than rejoicing to the fact that some
cache implemention artifact may help you a little.
 
J

Joshua Cranmer

Tegiri said:
Look, the application like you describe is database application, and
here you start to sound like one of these "roll your own persistence
layer" morons. If you need to update some records, you'd better do it
properly in the database, rather than rejoicing to the fact that some
cache implemention artifact may help you a little.

No, it's not. Here is a correlating example in actual code:

Suppose I'm writing a program wrapping around a scripting API, say some
JavaScript. A JavaScript object, when represented in the engine, is
obviously unique in that there is no way to generate it except get the
object. Since I'm wrapping around the API, I have to use my own metadata
structure, a hash map. Once the object disappears in use from the
script, it can no longer be retrieved from the hash map because the only
reference is IN the hash map. Therefore, the hash map would hold a weak
reference to the object so that it can be cleaned up when it goes out of
scope.

And it's not helping us a little. In many cases, in the most useful
examples, the weak reference may well be the only way to do what needs
to be done without tearing up APIs across the board.
 
M

Mike Schilling

Steven Simpson said:
I think I'm getting it...

Suppose that the ThreadLocal class has not yet been conceived, but Thread
is built in as standard. You're not the author of the standard library,
so you can't rewrite Thread, but you want to implement ThreadLocal. You
need to associate additional state with each thread, so a
basic implementation might be:

// (Not quite the same as java.lang.ThreadLocal!)
public class ThreadLocal<T> {
private Map<Thread,T> extra = new HashMap<Thread,T>();

public T get() {
return extra.get(Thread.currentThread());
}

public void set(T value) {
extra.put(Thread.currentThread(), value);
}

public void remove() {
extra.remove(Thread.currentThread());
}
}

But this now holds strong references to any Thread that uses it, and those
Threads won't be collectable as long as the ThreadLocal object exists
(which is likely to be static), unless a Thread remembers to remove() all
its thread-locals before it terminates.

Change to a WeakHashMap, and that problem goes away.

Apply this to any situation where you want to associate extra data with
objects you don't have any control over, without imposing any extra
lifetime on those objects.

Have I got that right?


Good example; in fact ThreadLocal was originally implemented with a
WeakHashMap.
 
T

Tegiri Nenashi

You may mean that the GC would get the ref-count cheaply as a
byproduct of the normal gc'ing-pass, but I strongly doubt that.

While an unreachable object can not become reachable
concurrently to the GC's mark-phase (that's before
finalizers are run), a refcount of 1 can easly grow
anytime. So even if the gc identified a ref-count
of 1 for some object: by the time the OutOfMemory-
notification is processed by the first Listener, this
ref-count may already be 42 and higher.

That leads to the point which the Java-devs have
reached back at 1.2, namely to leave the task of
on-demand breaking of certain (non-hard) references
to the GC directly. :)

Let me address your concerns in the reverse order. May I suggest that
JVM/GC implementers were too bored with simplicity of standard mark-
and-sweep algorithm and were excited to spice things a little. Seen it
all the time. The question is if their invention of obscure references
has a merit.

In general yes, nothing prevents the count not to go up. But we are
talking a very specific usage here. If a notifier sees an element in
its collection of listeners to be not referenced from outside, it can
safely assume it is not referenced from anywhere else, even though the
information at hand is dated. So far we didn't identify too many cases
to worry that the approach of going after the application reference
usages may not scale up.
 
T

Tegiri Nenashi

Well, you’re completely ignoring Joshua’s argument:

|> 2 involves less bookkeeping, and so is more robust.

Your solution involves a lot of bookkeeping.

Let see. In fancy reference scenario you have a reference that can
become invalid at any given time. Your application have to check it
for null and delete it from collection. Whereas I suggest to have a
dedicated library collection class(es) so that end user don't write
any cleanup code at all. On an low memory event (or why not at will?)
the collection checks the validity of references itself and purges
them if needed.
 
J

Joshua Cranmer

Tegiri said:
In general yes, nothing prevents the count not to go up. But we are
talking a very specific usage here. If a notifier sees an element in
its collection of listeners to be not referenced from outside, it can

And how do you propose to do that? That makes sense in ref-counted
systems, but Java isn't ref-counted...
 
T

Tom Anderson

Apply this to any situation where you want to associate extra data with
objects you don't have any control over, without imposing any extra
lifetime on those objects.

Have I got that right?

Yes. Right on the nose - that's an excellent statement of the point of
WHMs.

tom
 
T

Tegiri Nenashi

Suppose that the ThreadLocal class has not yet been conceived...

Let's establish that ThreadLocal is not yet another worthless goofy
pointer invention, first.

Consider two cases. Threads sharing the global object

String x;
new Thread() {
public void run() {
x = "1";
}
}.start();
new Thread() {
public void run() {
x = "2";
}
}.start();

versus two threads working with different copies of it

new Thread() {
String x;
public void run() {
x = "1";
}
}.start();
new Thread() {
String x;
public void run() {
x = "2";
}
}.start();

Why it is not as simple as this, and what benefit an extra layer of
indirection would possibly buy us? Is Java programming about creating
dynamic variables as this ThreadLocal idea suggests?

You may imply that somewhere within the thread's run call we can call
another method on some object y and have no way to pass a reference to
x? May I ask why object y has to know implementation details of a
thread that is running it? Isn't it a good programming practice to
pass information via rigorously defined interfaces, rather than access
global variables? (I cringe every time I see the "Context" object in
the "framework" code of the project I'm currently working on).
 
A

Andreas Leitgeb

In general yes, nothing prevents the count not to go up. But we are
talking a very specific usage here. If a notifier sees an element in
its collection of listeners to be not referenced from outside, it can
safely assume it is not referenced from anywhere else, even though the
information at hand is dated. So far we didn't identify too many cases
to worry that the approach of going after the application reference
usages may not scale up.

What you said is not wrong, but it is still far too narrow:
Some Object may have cyclic references to itself, so while it is
reachable only through the Collection, it still has a ref-count>1
Collection -> A -> B -> A
As long as A is reachable, so is B, and thus A appears doubly-reachable.

I wish you much fun designing your own ref-counting engine for java,
and when I'm back from vacation in about 3 weeks, you surely can tell me
yourself how it didn't work out...
 
D

Daniel Pitts

Andreas said:
What you said is not wrong, but it is still far too narrow:
Some Object may have cyclic references to itself, so while it is
reachable only through the Collection, it still has a ref-count>1
Collection -> A -> B -> A
As long as A is reachable, so is B, and thus A appears doubly-reachable.

I wish you much fun designing your own ref-counting engine for java,
and when I'm back from vacation in about 3 weeks, you surely can tell me
yourself how it didn't work out...
The thing is that Java doesn't use reference counting (at least, not
just).

The number of strong references to an object doesn't matter. What
matters is the existence of a path of strong references that start from
either a static context or on an active threads stack.

So, Collection -> A -> B -> A doesn't matter if there is nothing else
pointing to A, B, or Collection.

also, WeakReference -> A -> B -> A doesn't prevent B from being garbage
collected, assuming no other strong reference to A or B.
 
H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Tegiri Nenashi schreef:
|> The point is, you want to have a hash
|> map (note no capitals here, speaking generically), which you keep as
|> long as you want, without worrying about memory. The problem is, the
|> stuff that is inside the hash map is referenced by it so can’t be
|> collected, even if it is no longer used anywhere else in the program.
|
| Once again what is so special about "map" let alone "hash"? Wouldn't
| argument be verbatim for TreeMap? List, LinkedList? Sure if I put
| something in the globally referenced List it would be kept there
| indefinitely even if there is no other references to a list element.

You’re totally drifting off here. There is nothing special about hash
map and I never claimed that. Feel free to implement a WeakArrayList,
but note that it will be much more difficult (and I see no use for it).

Note that I have not claimed anything of what you said is wrong, it’s
just completely beside the point.

|> If you use WeakHashMap, the stuff *inside* the map can get collected,
|> once nothing else points at it; the reference the map has to it doesn’t
|> hinder collection.
|> Use case: You have some pool of objects which are used in some part of
|> your program.
|
| "A bunch of stuff used somewhere" -- very precise descrption, but go
| on.

Well, if you don’t want to listen to reason, you could as well stop reading.

|> Another part of your program uses them, but needs to do
|> some effort to get references to them. At the same time it wants to
|> have them within reach. It puts them in a WeakHashMap, so they are
|> there whenever it needs them. When OTOH, the first part of the program
|> stops using the object, it will be removed from the hash map as well, so
|> the latter part cannot get it any more, which is exactly what is needed,
|> since it would be invalid to use it any longer.

| The culprit is to identify usages where global Map is useful. Map is
| essentially a bastardized version of a database, so no wonder that
| caching surfaced as the obvious case. I struggle to see anything else.

ACK. Global variables are seldomly good things. But again: what does
this have to do with the argument about Weak/SoftReferences?

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iEYEARECAAYFAkh7AEAACgkQBGFP0CTku6O/5gCfdzfLfVfNAO2nG+6zwMDMK1Gv
/JQAnRDHsygpO4orP6lhYBSrdoIh24Sa
=o4W+
-----END PGP SIGNATURE-----
 
H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Tegiri Nenashi schreef:
|> Well, you’re completely ignoring Joshua’s argument:
|>
|> |> 2 involves less bookkeeping, and so is more robust.
|>
|> Your solution involves a lot of bookkeeping.
|
| Let see. In fancy reference scenario you have a reference that can
| become invalid at any given time. Your application have to check it
| for null and delete it from collection.

No it does not. It disappears automagically.

| Whereas I suggest to have a
| dedicated library collection class(es) so that end user don't write
| any cleanup code at all. On an low memory event (or why not at will?)
| the collection checks the validity of references itself and purges
| them if needed.

Moot, due to above, but anyway: this is exactly what WeakReference does:
library class, no need for any cleanup code, just create it appropriately.

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iEYEARECAAYFAkh7ASsACgkQBGFP0CTku6PXegCfRVSbsCIZ1tdOlbCQE/q9kD1U
lhIAn1LxnJ1RRujNmpCYvWgls4zpSOHu
=HLL9
-----END PGP SIGNATURE-----
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top