GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add definitions for WeakRef and FinalizationRegistry by ikokostya · Pull Request #38232 · microsoft/TypeScript

Conversation

@ikokostya

@ikokostya ikokostya commented Apr 28, 2020

Copy link
Copy Markdown
Contributor

Fixes #32393

Link to proposal https://github.com/tc39/proposal-weakrefs/blob/master/reference.md

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@ikokostya
Add definitions for WeakRef and FinalizationRegistry
0ae7ab6
Fixes #32393
@msftclas

Microsoft Contribution License Agreements (msftclas) commented Apr 28, 2020 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ikokostya
Mark callback parameter in FinalizationRegistry#cleanupSome() as opti…
a5ce6c2
…onal
@sandersn
Nathan Shively-Sanders (sandersn) requested review from Orta Therox (orta) and Nathan Shively-Sanders (sandersn) May 12, 2020 14:36
@sandersn Nathan Shively-Sanders (sandersn) assigned Orta Therox (orta) May 12, 2020
@orta Orta Therox (orta) mentioned this pull request May 12, 2020
Feature/initial reference docs tc39/proposal-weakrefs#196
Merged
@orta

Orta Therox (orta) commented May 12, 2020

Copy link
Copy Markdown
Contributor

Great, this looks good to me:

  • the proposal is at stage 3, so it's good to be merged
  • the JSDoc annotations match the reference (nice work there)
  • It doesn't look like anything is missing

The file naming fits too, thanks 👍

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

orta
Orta Therox (orta) approved these changes May 12, 2020
View reviewed changes
@orta

Orta Therox (orta) commented May 12, 2020

Copy link
Copy Markdown
Contributor

I'll give Nathan a chance to look over it, but I'm good to merge

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

sandersn
Nathan Shively-Sanders (sandersn) requested changes May 12, 2020
View reviewed changes

@sandersn Nathan Shively-Sanders (sandersn) left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Questions about the type of target and unregisterToken:

  1. Maybe they should be unknown or {} instead.
  2. The proposal uses 'value' and 'object' fairly consistently, but doesn't define them. Does the ecmascript spec do so?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/lib/esnext.weakref.d.ts Outdated
* @param callback If given, the registry uses the given callback instead of the one it was
* created with.
*/
cleanupSome(callback?: (heldValue: any) => void): void;

@sandersn Nathan Shively-Sanders (sandersn) May 12, 2020

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's weird that heldValue: any but target: object and unregisterToken: object. I know the proposal uses the terms 'value' and 'object' but I don't think they exactly match the type system's definitions. In particular, object means "non-primitive". Can you provide null, undefined, "foo", false or 3 for target or unregisterToken?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ikokostya ikokostya May 12, 2020 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. target must be an object, i.e. non-primitive type.
    Specification: https://tc39.es/proposal-weakrefs/#sec-weak-ref-target

    1. If Type(target) is not Object, throw a TypeError exception.

    V8 implementation behavior:

    $ node --harmony-weak-refs
    Welcome to Node.js v14.0.0.
    Type ".help" for more information.
    > new WeakRef(null)
    Uncaught TypeError: WeakRef: target must be an object
        at new WeakRef (<anonymous>)
    > new WeakRef(undefined)
    Uncaught TypeError: WeakRef: target must be an object
        at new WeakRef (<anonymous>)
    > new WeakRef(1)
    Uncaught TypeError: WeakRef: target must be an object
        at new WeakRef (<anonymous>)
    > new WeakRef("str")
    Uncaught TypeError: WeakRef: target must be an object
        at new WeakRef (<anonymous>)
    
  2. unregisterToken must be an object (non-primitive type), or undefined.

    Specification: https://tc39.es/proposal-weakrefs/#sec-finalization-registry.prototype.register

    1. If Type(unregisterToken) is not Object,
      a. If unregisterToken is not undefined, throw a TypeError exception.
      b. Set unregisterToken to empty.

    V8 implementation behavior (please note that v8 in Node.js still uses old specification name FinalizationGroup instead of FinalizationRegistry):

    $ node --harmony-weak-refs
    > var fg = new FinalizationGroup(() => {})
    undefined
    > fg.register({}, null, null)
    Uncaught TypeError: unregisterToken ('null') must be an object
        at FinalizationGroup.register (<anonymous>)
    > fg.register({}, null, undefined)
    undefined
    > fg.register({}, null, 1)
    Uncaught TypeError: unregisterToken ('1') must be an object
        at FinalizationGroup.register (<anonymous>)
    > fg.register({}, null, 'a')
    Uncaught TypeError: unregisterToken ('a') must be an object
        at FinalizationGroup.register (<anonymous>)
    > fg.register({}, null, false)
    Uncaught TypeError: unregisterToken ('false') must be an object
        at FinalizationGroup.register (<anonymous>)
    
  3. heldValue can have any type.

    Specification: https://tc39.es/proposal-weakrefs/#sec-finalization-registry.prototype.register
    V8 implementation behavior:

    $ node --harmony-weak-refs
    > var fg = new FinalizationGroup(() => {})
    undefined
    > fg.register({}, null)
    undefined
    > fg.register({}, false)
    undefined
    > fg.register({}, 1)
    undefined
    > fg.register({}, {})
    undefined
    

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@littledan Daniel Ehrenberg (littledan) May 13, 2020

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest omitting cleanupSome from .d.ts, or otherwise somehow mark it as dispreferred/not tab-complete it. It's "normative optional" in the specification, it's currently under some debate, and it's not going to be part of what V8/Chrome ships initially. See whatwg/html#5446 for context.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ikokostya ikokostya May 13, 2020 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's "normative optional" in the specification, it can be marked as optional in .d.ts. Anyway this declaration is available only under --lib esnext compiler flag, which means that it isn't stable. If in final stage of the proposal this method will be removed, corresponding TypeScript declaration should reflect this change before move to stable es2020 lib.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@sandersn Nathan Shively-Sanders (sandersn) May 20, 2020

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Chrome's not going to ship with it initially, let's make this optional to start so that people have to prove that it's available before using it. (Only when strict: true of course.)

Suggested change
cleanupSome(callback?: (heldValue: any) => void): void;
cleanupSome?(callback?: (heldValue: any) => void): void;

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

littledan and willstott101 reacted with thumbs up emoji
All reactions
  • 👍 2 reactions
@ikokostya
ikokostya requested a review from Nathan Shively-Sanders (sandersn) May 12, 2020 16:12
@ikokostya

ikokostya commented May 12, 2020

Copy link
Copy Markdown
Contributor Author

Actually this behavior is the same as in WeakMap, where key must be an object:

TypeScript/lib/lib.es2015.collection.d.ts

Line 45 in 0326534

interface WeakMap<K extends object, V> {

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@sandersn Nathan Shively-Sanders (sandersn) added the For Backlog Bug PRs that fix a backlog bug label May 20, 2020
sandersn
Nathan Shively-Sanders (sandersn) requested changes May 20, 2020
View reviewed changes
Comment thread src/lib/esnext.weakref.d.ts Outdated
* @param callback If given, the registry uses the given callback instead of the one it was
* created with.
*/
cleanupSome(callback?: (heldValue: any) => void): void;

@sandersn Nathan Shively-Sanders (sandersn) May 20, 2020

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Chrome's not going to ship with it initially, let's make this optional to start so that people have to prove that it's available before using it. (Only when strict: true of course.)

Suggested change
cleanupSome(callback?: (heldValue: any) => void): void;
cleanupSome?(callback?: (heldValue: any) => void): void;

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

littledan and willstott101 reacted with thumbs up emoji
All reactions
  • 👍 2 reactions
@ikokostya
Make FinalizationRegistry.prototype.cleanupSome optional
6548776
@ikokostya
ikokostya requested a review from Nathan Shively-Sanders (sandersn) May 20, 2020 23:07
@miniak Milan Burda (miniak) mentioned this pull request Jun 8, 2020
refactor: replace v8Util.createIDWeakMap() with native WeakRef in tests electron/electron#24017
Closed
7 tasks
@Jamesernator

James Browning (Jamesernator) commented Jul 22, 2020 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Is there any reason FinalizationRegistry isn't generic? I've used it a bit on the older version in Node (with --harmony-weakrefs) and I generally found the typechecking was helpful when I defined the types.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@littledan

Daniel Ehrenberg (littledan) commented Jul 22, 2020

Copy link
Copy Markdown

cleanupSome has been moved into a separate Stage 2 proposal, so I recommend omitting it from the typings here.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ikokostya
Remove FinalizationRegistry.prototype.cleanupSome()
b6c29c7
@willstott101

Will Stott (willstott101) commented Aug 18, 2020

Copy link
Copy Markdown

Is there any reason FinalizationRegistry isn't generic? I've used it a bit on the older version in Node (with --harmony-weakrefs) and I generally found the typechecking was helpful when I defined the types.

What would you include in the Generic? target, heldValue, unregisterToken or multiple?

  • I suppose target for typedocs so you know what it's intended to be holding references to, though I don't think this would help much with correctness.
  • heldValue to be type-safe between your callback and register calls.
  • unregisterToken to be type-safe for all register and unregister calls.

I see a lot more value in the latter two, but in many cases you might only use one or the other. It doesn't seem obvious to me what the Generic implementation would be.

littledan reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Jamesernator

James Browning (Jamesernator) commented Aug 19, 2020

Copy link
Copy Markdown

What would you include in the Generic? target, heldValue, unregisterToken or multiple?

I've generally defined it with all 3 as:

declare global {
     class FinalizationRegistry<
         TValue extends object=object,
         THeldValue=any, 
         TUnregisterToken extends object=never
     > {
        constructor(
           finalizationCallback: (heldValue: THeldValue) => void,
        );
        register(
            object: TValue,
            heldValue: THeldValue,
            unregisterToken?: TUnregisterToken,
        ): void;
        unregister(unregisterToken: TUnregisterToken): void;
    }
}

I do agree you'd often only use some, it's a bit of a shame there aren't named generics. There are hacky ways around it (like this) but this isn't an existing convention in the TS standard lib.

type FinalizationOptions = {
    Value: object,
    HeldValue: any,
    UnregisterToken: object,
}

type Get<T extends object, K, Else> = K extends keyof T ? T[K] : Else;

declare class FinalizationRegistry<T extends Partial<FinalizationOptions>> {
    constructor(
        finalizationCallback: (heldValue: Get<T, 'HeldValue', any>) => void,
    );
    register(
        value: Get<T, 'Value', object>,
        heldValue: Get<T, 'HeldValue', any>,
        unregisterToken?: Get<T, 'UnregisterToken', never>,
    ): void;
    unregister(
        unregisterToken: Get<T, 'UnregisterToken', never>,
    ): void;
}

const f = new FinalizationRegistry<{ HeldValue: number }>((i /* number */) => {
    console.log(i);
});

f.register({} /* object */, 3 /* number */);
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

ykahlon
Yossi Kahlon (ykahlon) reviewed Oct 5, 2020
View reviewed changes
Comment thread src/lib/esnext.weakref.d.ts
deref(): T | undefined;
}

interface WeakRefConstructor {

@ykahlon Yossi Kahlon (ykahlon) Oct 5, 2020

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, any chance to expedite this change?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@sandersn Nathan Shively-Sanders (sandersn) Oct 5, 2020

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it got lost in my email, but I think it's good to go after I re-run the github CI.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@sandersn
Merge branch 'master' into weakrefs-dts
3c0ed5f
sandersn
Nathan Shively-Sanders (sandersn) approved these changes Oct 5, 2020
View reviewed changes
@sandersn
Nathan Shively-Sanders (sandersn) merged commit bd1d8e5 into microsoft:master Oct 6, 2020
Nathan Shively-Sanders (sandersn) added a commit that referenced this pull request Oct 7, 2020
@sandersn
Fix missed tasks to add esnext.weakref
9befc78
Follow up to #38232, based on #33844
@sandersn Nathan Shively-Sanders (sandersn) mentioned this pull request Oct 7, 2020
Fix missed tasks to add esnext.weakref #40981
Merged
Nathan Shively-Sanders (sandersn) added a commit that referenced this pull request Oct 7, 2020
@sandersn
Fix missed tasks to add esnext.weakref (#40981)
fc783a9
Follow up to #38232, based on #33844
@KilianKilmister

Slick Kilmister (KilianKilmister) commented Oct 8, 2020 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Funny coincidence, i just started using weak refs/Finalisation registry in a project yesterday and was little annoyed that it wasn't typed (the typescript nightly i had installed was a few days old). Perfect timing.

Two notes on FinalisationRegistry:
In FinalizationRegistry.prototype.register it looks like heldValue is optional (tested in node-v14.13.0). While i didn't find a anything specific calling it optional in the proposal, on MDN at least it is stated that undefined is an acceptable value for heldValue

As for Generics, this is what i used:

  • T extends object => so it can be integrated nicely with a collection
  • V = void => this way a type can be declared in the constructor argument and TypeScript knows that the second
    parameter of FinalizationRegistry.prototype.register is only needed if it has a non-default type (if V defaults to
    undefined, TypeScript will still want that second argument as a literal and throw a compiler error otherwise:
    finalisationRegistry.register(someObject, undefined) )
  • Token extends object = object => defaulting to object since it is optional and needs a default since it's following a
    another defaulting generic
declare class FinalizationRegistry<T extends object, V = void, Token extends object = object> {
  constructor (callback: (heldValue: V) => void)
  register (target: T, heldValue: V, token?: Token): void
  unregister (token: Token): void
}

usage:

const registry = new FinalizationRegistry<Record<string, string>>(() => console.log('some cleanup optimisation'))
// => `FinalizationRegistry<Record<string, string>, void, object>`
const registry = new FinalizationRegistry<readonly string[], number, readonly string[]>((heldItem: number) => console.log(`Array of ${heldItem} hasn't been unregistered`'))
const arr = [1,2,3,4] as const
registry.register(arr, arr.length, arr)
class Collection<T extends object, Held = void> {
  #registry: FinalizationRegistry<T, Held, this>
  constructor (callback: (heldValue: Held) => void, iterable?: Iterable<[T, Held]>) {
    this.#registry = new (FinalizationRegistry)(callback)
    for (const [item, held] of iterable ?? []) this.#registry.register(item, held, this)
  }

  register (item: T, heldValue: Held) { this.#registry.register(item, heldValue, this) }
  reset () { this.#registry.unregister(this) }
}

How James Browning (@Jamesernator) did the Token extends object = never is interesting, tho. migth me a good choice too, but for the other two i think this way is the best.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

ExE-Boss
ExE Boss (ExE-Boss) reviewed Jan 10, 2021
View reviewed changes
Comment thread src/lib/esnext.weakref.d.ts
* Creates a WeakRef instance for the given target object.
* @param target The target object for the WeakRef instance.
*/
new<T extends object>(target?: T): WeakRef<T>;

@ExE-Boss ExE Boss (ExE-Boss) Jan 10, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s invalid to call WeakRef with undefined:

Suggested change
new<T extends object>(target?: T): WeakRef<T>;
new<T extends object>(target: T): WeakRef<T>;

I’m fixing this in #42274.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
ExE-Boss
ExE Boss (ExE-Boss) reviewed Jan 10, 2021
View reviewed changes

@ExE-Boss ExE Boss (ExE-Boss) left a comment •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FinalizationRegistry should be generic.


I’m fixing this in #42274.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/lib/esnext.weakref.d.ts

declare var WeakRef: WeakRefConstructor;

interface FinalizationRegistry {

@ExE-Boss ExE Boss (ExE-Boss) Jan 10, 2021

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
interface FinalizationRegistry {
interface FinalizationRegistry<T> {

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/lib/esnext.weakref.d.ts
* object. If provided (and not undefined), this must be an object. If not provided, the target
* cannot be unregistered.
*/
register(target: object, heldValue: any, unregisterToken?: object): void;

@ExE-Boss ExE Boss (ExE-Boss) Jan 10, 2021

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
register(target: object, heldValue: any, unregisterToken?: object): void;
register(target: object, heldValue: T, unregisterToken?: object): void;

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/lib/esnext.weakref.d.ts
}

interface FinalizationRegistryConstructor {
readonly prototype: FinalizationRegistry;

@ExE-Boss ExE Boss (ExE-Boss) Jan 10, 2021

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
readonly prototype: FinalizationRegistry;
readonly prototype: FinalizationRegistry<any>;

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/lib/esnext.weakref.d.ts
* Creates a finalization registry with an associated cleanup callback
* @param cleanupCallback The callback to call after an object in the registry has been reclaimed.
*/
new(cleanupCallback: (heldValue: any) => void): FinalizationRegistry;

@ExE-Boss ExE Boss (ExE-Boss) Jan 10, 2021

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
new(cleanupCallback: (heldValue: any) => void): FinalizationRegistry;
new<T>(cleanupCallback: (heldValue: T) => void): FinalizationRegistry<T>;

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@ExE-Boss ExE Boss (ExE-Boss) mentioned this pull request Jan 10, 2021
feat(lib/es2021): Add type parameter to FinalizationRegistry #42274
Merged
@microsoft Microsoft (microsoft) locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

@sandersn Nathan Shively-Sanders (sandersn) sandersn approved these changes
+4 more reviewers
@littledan Daniel Ehrenberg (littledan) littledan left review comments
@ExE-Boss ExE Boss (ExE-Boss) ExE-Boss left review comments
@ykahlon Yossi Kahlon (ykahlon) ykahlon left review comments
@orta Orta Therox (orta) orta approved these changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@orta Orta Therox (orta)

Labels

For Backlog Bug PRs that fix a backlog bug

Projects

PR Backlog
Archived in project

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Suport for WeakRef / FinalizationGroup

Uh oh!

There was an error while loading. Please reload this page.

10 participants

@ikokostya @msftclas @orta @Jamesernator @littledan @willstott101 @KilianKilmister @sandersn @ExE-Boss @ykahlon
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.