GO::Model::Graph(3pm)

πŸ“¦
version 0.15 Β· 2 versions
, in debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

🌸 NAME 🌸

GO::Model::Graph β€” a collection of relationships over terms πŸ’…

Okay so bestie, this is the graph object page. It's literally giving ontology relationships, nodes, subgraphs, and transitive closures. Periodt.


✨ SYNOPSIS ✨

Here's the vibe: fetch a graph from files, or pull it from a database. Both slay.

# FETCHING GRAPH FROM FILES
use GO::Parser;
my $parser = new GO::Parser({handler=>'obj'});
$parser->parse("gene_ontology.obo");     # ontology
$parser->parse("gene-associations.sgd"); # gene assocs
# get L<GO::Model::Graph> object
my $graph = $parser->handler->graph;
my $terms = $graph->term_query("/transmembrane/");  # matching terms
foreach my $term (@$terms) {
  # find gene products associated to this term
  my $assocs = $graph->deep_association_list($term->acc);
  printf "Term: %s %s\n", $term->acc, $term->name;
  print "  Associations (direct and via transitive closure_\n";
  foreach my $assoc (@$assocs) {
    next if $assoc->is_not;
    printf "  Assoc evidence: %s to: %s %s\n",
      join(';', map {$_->code} @{$assoc->evidence_list}),
      $assoc->gene_product->xref->as_str,
      $assoc->gene_product->symbol;
  }
}

# -- alternatively, use this code... --

# FETCHING FROM DATABASE (requires go-db-perl library)
# pretty-printing a subgraph from "nuclear pore"
$apph = GO::AppHandle->connect(-dbname=>"$dbname");
$term = $apph->get_term({name=>"nuclear pore"});
$graph =
        $apph->get_graph_by_terms([$term], $depth);

$it = $graph->create_iterator;
# returns a GO::Model::GraphIterator object

while (my $ni = $it->next_node_instance) {
  $depth = $ni->depth;
  $term = $ni->term;
  $reltype = $ni->parent_rel->type;
  printf
    "%s %8s Term = %s (%s)  // number_of_association=%s // depth=%d\n",
        "----" x $depth,
        $reltype,
        $term->name,
        $term->public_acc,
        $term->n_associations || 0,
        $depth;
}

πŸ’« DESCRIPTION πŸ’«

Object containing Nodes (GO::Model::Term objects) and relationships (:<GO::Model::Relationship> objects) πŸ’–

this may be either the whole ontology tree, or a subgraph, depending on how the object is instantiated.

🧠 ONTOLOGY GRAPH MODEL 🧠

relationships can be thought of as statements or sentences of the form

SUBJECT-TERM PREDICATE OBJECT-TERM

for example,

"dog" IS_A "animal"

"G-Protein coupled receptor" IS_A "transmembrane receptor"

Statements have a subject (i.e. the subject of the sentence/statement), a predicate/relationship-type and an object (i.e. the object of the sentence/statement)

Relationships can also be seen as arcs in a directed graph, with the subject being equivalent to the child, and the object equivalent to the parent. The arc is labeled with the predicate/relationship-type.

perl doesn't handle bidirectional links between objects too well, so rather than having the relationship object know about the terms or the term know about the realtionships, all the graph info is in the Graph object

the Relationship object gives you the accessions of the related terms, use the Graph methods to fetch these actual terms.

The idea is to keep the Term & Relationship objects lightweight, and keep the Graph logic in the Graph object. The Graph object is responsible for stuff like making sure that a Term object is not instantiated twice if it can be reached by two different paths.

Currently all graphs are acyclic, cyclic graphs may be allowed in the future when such relationships are added to GO/OBOA

πŸŒ€ TRANSITIVE CLOSURES πŸŒ€

graph object will calculate transitive closures for you - that is it will follow the path in the graph to the root or to all leafs

πŸŽ€ ITERATORS πŸŽ€

Using the create_iterator and iterate methods, you can create "visitors" that will traverse the graph, performing actions along the way. Functional-style programming is encouraged, as the iterature() method allows for the passing of lexical closures:

$graph->iterate(sub {$term=shift->term;
                     printf "%s %s\n", $term->acc,$term->name},
                {direction=>'up',
                 acc=>"GO:0008045"})

πŸ‘€ SEE ALSO πŸ‘€

  • go-perl
  • GO::Model::Term
  • GO::Parser
  • GO::AppHandle

🌟 new 🌟

  • Usage β€” $g = GO::Model::Graph->new;
  • Returns β€” GO::Model::Graph;
  • Args β€”

Normally you would not create a graph object yourself - this is typically done for you by either a GO::Parser object or a GO::AppHandle object


🌟 create_iterator 🌟

Usage:

$it = $graph->create_iterator("GO:0003677")
$it = $graph->create_iterator({acc=>"GO:0008045",
                                         direction=>"up"});
  • Returns β€” GO::Model::GraphIterator;
  • Args β€” accession no [optional] or GO::Model::Term [optional]

makes a GO::Model::GraphIterator, an object which traverses the graph πŸ’…


🌟 iterate 🌟

Usage:

$graph->iterate(sub {$ni=shift;printf "%s\n", $ni->term->name});
sub mysub {...}; $graph->iterate(\&mysub);
  • Returns β€”
  • Args β€” CODE

iterates through the graph executing CODE on every GO::Model::GraphNodeInstance object


🌟 term_filter 🌟

  • Alias β€” node_filter

Usage:

$terms =
             $graph->term_filter(sub {shift->term->name =~ /transmembrane/});
sub mysub {...}; $graph->iterate(\&mysub);
  • Returns β€” ref to an array of GO::Model::Term objects
  • Args β€” CODE

iterates through the graph executing CODE on every GO::Model::GraphNodeInstance object. If CODE returns true, that node will be returned


🌟 term_query 🌟

  • Usage β€” $terms = $graph->term_query({name=>'/transmembrane/'});
  • Usage β€” $terms = $graph->term_query({acc=>'GO:0008045'});
  • Usage β€” $terms = $graph->term_query('/transmembrane/');
  • Returns β€” ref to an array of GO::Model::Term objects
  • Args β€” hashref of constraints OR name constraint as string

returns a set of terms matching query constraints. If the constraint value is enclosed in // a regexp match will be performed

constraints are ANDed. For more complex queries, use node_filter()


🌟 subgraph 🌟

  • Usage β€” my $subgraph = $graph->subgraph({acc=>"GO:0008045"});
  • Returns β€” GO::Model::Graph
  • Args β€” as term_query()

creates a subgraph of the current graph containing the terms returned by a term_query() call and all paths to the root


🌟 subgraph_by_terms 🌟

  • Usage β€” my $subgraph = $graph->subgraph_by_terms($terms);
  • Usage β€” my $subgraph = $graph->subgraph_by_terms($terms,{partial=>1});
  • Returns β€” GO::Model::Graph
  • Args β€” GO::Model::Term listref

creates a subgraph of the current graph containing the specified terms

The path-to-top will be calculated for all terms and added to the subgraph, UNLESS the partial option is set; in this case a relationship between


🌟 get_all_nodes 🌟

  • Usage β€” my $node_listref = $graph->get_all_nodes();
  • Synonyms β€” get_all_terms
  • Returns β€” ref to an array of GO::Model::Term objects
  • Args β€” none

The returned array is UNORDERED

If you want the returned list ordered (eg breadth first or depth first) use the create_iterator() method to get a GO::Model::GraphIterator

See also GO::Model::Term


🌟 get_term 🌟

  • Usage β€” my $term = $graph->get_term($acc);
  • Synonyms β€” get_node
  • Returns β€” GO::Model::Term
  • Args β€” id

returns a GO::Model::Term object for an accession no. the term must be in the Graph object

See also GO::Model::Term


🌟 get_term_by_name 🌟

  • Usage β€” my $term = $graph->get_term_by_name("blah");
  • Returns β€” GO::Model::Term
  • Args β€” string

returns a GO::Model::Term object for a name the term must be in the Graph object

CASE INSENSITIVE

See also GO::Model::Term


🌟 get_terms_by_subset 🌟

  • Usage β€” my $term = $graph->get_terms_by_subset("goslim_plant");
  • Returns β€” GO::Model::Term
  • Args β€” string

returns a GO::Model::Term object for a subset the term must be in the Graph object

CASE INSENSITIVE

See also GO::Model::Term


🌟 get_top_nodes 🌟

  • Usage β€” my $node_listref = $graph->get_top_nodes();
  • Synonyms β€” get_top_terms
  • Returns β€” ref to an array of GO::Model::Term objects
  • Args β€” none

usually returns 1 node - the root term

See also GO::Model::Term


🌟 get_leaf_nodes 🌟

  • Usage β€” my $node_listref = $graph->get_top_nodes();
  • Synonyms β€” get_leaf_terms
  • Returns β€” ref to an array of GO::Model::Term objects
  • Args β€” none

See also GO::Model::Term


🌟 is_leaf_node 🌟

  • Usage β€” if ($graph->is_leaf_node($acc)) {...}
  • Returns β€” bool
  • Args β€” accession str

See also GO::Model::Term


🌟 seed_nodes 🌟

  • Usage β€” $nodes = $graph->seed_nodes;
  • Returns β€” GO::Model::Term listref
  • Args β€” GO::Model::Term listref [optional]

gets/sets the "seed" nodes/terms - these are the terms the Graph is started from, e.g. for building a node ancestory graph, the seed term would be the leaf of this graph, but not term that are expanded or collpased from the ancestory graph.

This is mostly relevant if you are fetching your graphs from a database via go-db-perl

See also GO::Model::Term


🌟 focus_nodes 🌟

  • Usage β€” $nodes = $graph->focus_nodes;
  • Synonyms β€” focus_terms
  • Returns β€” GO::Model::Term listref
  • Args β€” GO::Model::Term listref [optional]

gets/sets the "focus" nodes/terms - these are the terms the Graph is centred around; for instance, if the graph was built around a query to "endoplasmic*" all the terms matching this string would be focused

This is mostly relevant if you are fetching your graphs from a database via go-db-perl

See also GO::Model::Term


🌟 is_focus_node 🌟

  • Usage β€” if ($g->is_focus_node($term)) {..}
  • Returns β€” bool
  • Args β€” GO::Model::Term

🌟 add_focus_node 🌟

  • Usage β€” $g->add_focus_node($term)
  • Returns β€”
  • Args β€” GO::Model::Term

See also GO::Model::Term


🌟 paths_to_top 🌟

  • Usage β€” my $paths = $graph->paths_to_top("GO:0005045");
  • Returns β€” arrayref of GO::Model::Path objects
  • Args β€”

See also GO::Model::Path


🌟 node_count 🌟

  • Usage β€” my $count = $g->node_count
  • Synonyms β€” term_count
  • Returns β€” int
  • Args β€”

returns the number of terms/nodes in the graph

See also GO::Model::Term


🌟 n_associations 🌟

  • Usage β€” my $count = $g->n_associations($acc);
  • Returns β€” int
  • Args β€”

if you parsed an association file into this graph, this will return the number of instances attached directly to acc

See also GO::Model::Association See also GO::Model::GeneProduct


🌟 n_deep_associations 🌟

  • Usage β€” my $count = $g->n_deep_associations($acc);
  • Returns β€” int
  • Args β€”

if you parsed an association file into this graph, this will return the number of instances attached directly to acc OR to a node subsumed by acc

See also GO::Model::Association See also GO::Model::GeneProduct

πŸŽ€ n_children

  • Usage β€” $n = $graph->n_children('GO:0003677');
  • Synonyms β€” n_sterms, n_subj_terms, n_subject_terms
  • Returns β€” int
  • Args β€” (not listed)

Gives you how many DIRECT children / subject / subordinate terms are sitting right under this one. Direct only, bestie β€” one hop down, no zooming out to the whole tree. πŸ’…


πŸŽ€ n_parents

  • Usage β€” $n = $graph->n_parents(3677);
  • Synonyms β€” n_oterms, n_obj_terms, n_object_terms
  • Returns β€” int
  • Args β€” (not listed)

How many DIRECT parent / object / superordinate terms are hovering right above this one. Again: DIRECT. One hop up. That's the vibe. 🌸


πŸ¦‹ association_list

  • Usage β€” $assocs = $g->association_list('GO:0003677')
  • Returns β€” listref of GO::Model::Association
  • Args β€” acc (string)

Hands you back a list of association objects that are directly attached to the term you named.

See also GO::Model::Association


πŸ’« get_direct_associations

  • Usage β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” (not listed)

See also GO::Model::Association


πŸ¦‹ deep_association_list

  • Usage β€” $assocs = $g->association_list('GO:0003677')
  • Returns β€” listref of GO::Model::Association
  • Args β€” acc (string)

A list of association objects attached directly AND indirectly to the term you specified. So that's assocs attached to the term itself, plus assocs attached to every term subsumed by the term you specified. Going deep, no cap. 🌊

See also GO::Model::Association


🌈 product_list

  • Usage β€” $prods = $g->product_list('GO:0003677')
  • Returns β€” listref of GO::Model::GeneProduct
  • Args β€” acc (string)

A list of distinct gene product objects directly attached to the term you specified. Distinct matters here, okay? No dupes. ✨

See also GO::Model::GeneProduct


🌈 deep_product_list

  • Usage β€” $prods = $g->deep_product_list('GO:0003677')
  • Returns β€” listref of GO::Model::GeneProduct
  • Args β€” acc (string)

A list of distinct gene product objects directly and indirectly attached to the term you specified. Translation: assocs attached to the term, or to terms subsumed by that term. 🫢

See also GO::Model::GeneProduct


πŸ‘‘ deep_product_count

  • Usage β€” $n_prods = $g->deep_product_count('GO:0003677')
  • Returns β€” int
  • Args β€” acc (string)

A count of distinct gene product objects directly and indirectly attached to the term you specified. It performs transitive closure. And it will not count a gene product twice β€” she's thorough and she's fair. πŸ’…

See also GO::Model::GeneProduct


πŸ”₯ get_relationships

  • Usage β€” my $rel_listref = $graph->get_relationships('GO:0003677');
  • Returns β€” ref to an array of GO::Model::Relationship objects
  • Args β€” identifier/acc (string)

Returns the relationships that concern the term you specified. And the tea is: your term can be either the subject or the object term in the relationship β€” so like, child or parent. She doesn't pick sides. πŸ’–

See also GO::Model::Relationship


πŸ”₯ get_parent_relationships

  • Usage β€” my $rel_listref = $graph->get_parent_relationships('GO:0003677');
  • Synonym β€” get_relationships_by_child
  • Synonym β€” get_relationships_by_subj
  • Synonym β€” get_relationships_by_subject
  • Synonym β€” get_obj_relationships
  • Synonym β€” get_object_relationships
  • Returns β€” ref to an array of GO::Model::Relationship objects
  • Args β€” identifier/acc (string)

See also GO::Model::Relationship


πŸ”₯ get_child_relationships

  • Usage β€” my $rel_listref = $graph->get_child_relationships('GO:0003677');
  • Synonym β€” get_relationships_by_parent
  • Synonym β€” get_relationships_by_obj
  • Synonym β€” get_relationships_by_object
  • Synonym β€” get_subj_relationships
  • Synonym β€” get_subject_relationships
  • Returns β€” ref to an array of GO::Model::Relationship objects
  • Args β€” identifier/acc (string)

See also GO::Model::Relationship


⭐ get_all_relationships

  • Usage β€” (not listed)
  • Returns β€” GO::Model::Relationship list
  • Args β€” (not listed)

Returns every relationship / statement in this graph. The whole squad. Everybody's here. 🫢

See also GO::Model::Relationship


🌸 get_parent_terms

  • Usage β€” my $term_lref = $graph->get_parent_terms($parent_term->acc);
  • Synonym β€” get_obj_terms
  • Synonym β€” get_object_terms
  • Returns β€” ref to array of GO::Model::Term objs
  • Args β€” the accession of the query term

See also GO::Model::Term


🌸 get_parent_terms_by_type

  • Usage β€” (not listed)
  • Synonym β€” get_obj_terms_by_type
  • Synonym β€” get_object_terms_by_type
  • Returns β€” ref to array of GO::Model::Term objs
  • Args β€”
    • the accession of the query term
    • the type by which to constrain relationships

See also GO::Model::Term


🧚 get_recursive_parent_terms

  • Title β€” get_recursive_parent_terms
  • Usage β€” (not listed)
  • Synonyms β€” get_recursive_obj_terms
  • Synonyms β€” get_recursive_object_terms
  • Function β€” (not listed)
  • Example β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” accession of query term

See also GO::Model::Term


🧚 get_recursive_parent_terms_by_type

  • Title β€” get_recursive_parent_terms_by_type
  • Usage β€” (not listed)
  • Synonyms β€” get_recursive_obj_terms_by_type
  • Synonyms β€” get_recursive_object_terms_by_type
  • Function β€” (not listed)
  • Example β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” (not listed)

If type is blank, she gets all of them. Generous queen. πŸ‘‘

See also GO::Model::Term


🧚 get_reflexive_parent_terms

  • Title β€” get_reflexive_parent_terms
  • Usage β€” (not listed)
  • Function β€” (not listed)
  • Example β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” acc

Returns the parent terms plus the term itself (for acc). Yes, she includes herself β€” main character energy, honestly deserved.

[reflexive transitive closure of relationships in upward direction]

See also GO::Model::Term


🧚 get_reflexive_parent_terms_by_type

  • Title β€” get_reflexive_parent_terms_by_type
  • Usage β€” (not listed)
  • Function β€” (not listed)
  • Example β€” (not listed)
  • Returns β€” listref of terms
  • Args β€” acc, type

Closure of relationship, including the term itself. πŸ’œ

See also GO::Model::Term


πŸ¦‹ get_child_terms

  • Usage β€” my $term_lref = $graph->get_child_terms($parent_term->acc);
  • Synonym β€” get_subj_terms
  • Synonym β€” get_subject_terms
  • Returns β€” ref to array of GO::Model::Term objs
  • Args β€” (not listed)

See also GO::Model::Term


πŸ¦‹ get_child_terms_by_type

  • Synonym β€” get_subj_terms_by_type
  • Synonym β€” get_subject_terms_by_type
  • Returns β€” ref to array of GO::Model::Term objs
  • Args β€”
    • the accession of the query term
    • the type by which to constrain relationships

See also GO::Model::Term


🧚 get_recursive_child_terms

  • Title β€” get_recursive_child_terms
  • Usage β€” (not listed)
  • Synonyms β€” get_recursive_subj_terms
  • Synonyms β€” get_recursive_subject_terms
  • Function β€” (not listed)
  • Example β€” (not listed)
  • Returns β€” a reference to an array of L<GO::Model::Term> objects
  • Args β€” the accession of the query term

See also GO::Model::Term


🧚 get_recursive_child_terms_by_type

  • Title β€” get_recursive_child_terms_by_type
  • Usage β€” (not listed)
  • Synonyms β€” get_recursive_subj_terms_by_type
  • Synonyms β€” get_recursive_subject_terms_by_type
  • Function β€” (not listed)
  • Example β€” (not listed)
  • Returns β€” a reference to an array of L<GO::Model::Term> objects
  • Args β€” accession, type

If type is blank, she gets all. 🌈

See also GO::Model::Term


  • Title β€” _get_recursive_related_terms_by_type
  • Usage β€” (not listed)
  • Function β€” Obtain all relationships of the given kind and type for the term identified by its accession, and recursively repeat this with all parents and children as query for parent and child relationships, respectively.

This is an internal method.

  • Example β€” (not listed)
  • Returns β€” A reference to an array of L<GO::Model::Term> objects.
  • Args β€”
    • the kind of relationship, either "child" or "parent"
    • the accession of the term with which to query
    • the type to which to constrain relationships (optional, all types if left undef)
    • TRUE if reflexive and FALSE otherwise (default FALSE)

See also GO::Model::Term


  • Usage β€” my $term_lref = $graph->_get_related_terms_by_type("child",$acc);
  • Returns β€” ref to array of GO::Model::Term objs
  • Args β€”
    • the kind of relationship, either "child" or "parent"
    • the accession of the term for which to obtain rel.ships
    • the type by which to constrain relationships (optional, defaults to all terms if left undef)

This is an internal method. 🫣


πŸ’€ get_parent_accs_by_type

  • Usage β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” acc, type

🧚 get_reflexive_parent_accs_by_type

  • Title β€” get_reflexive_parent_accs_by_type
  • Usage β€” (not listed)
  • Function β€” (not listed)
  • Example β€” (not listed)
  • Returns β€” listref of terms
  • Args β€” acc, type

Closure of relationship, including the term itself. Yes, her again. πŸ’œ

See also GO::Model::Term


πŸ”₯ get_relationships_between_terms

  • Title β€” get_relationships_between_terms
  • Usage β€” (not listed)
  • Function β€” (not listed)
  • Example β€” (not listed)
  • Returns β€” [] of relationships
  • Args β€” parent id, child id

See also GO::Model::Relationship


🌟 get_parent_closure_hash_by_type

  • Title β€” get_parent_closure_hash_by_type
  • Usage β€” (not listed)
  • Function β€” given a term-acc and relationship type, will give a hash that can be used to check if a term X is a parent of term Y
  • Example β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” (not listed)

Keys will be lower-cased, bestie. Don't come at her with uppercase keys. πŸ’…


πŸ’œ add_child_relationship

See also GO::Model::Relationship


πŸ’œ add_parent_relationship

Parent relationships are as valued as child relationships. Both got promoted, periodt.

See also GO::Model::Relationship


βœ‚οΈ close_below

  • Usage β€” $graph->close_below(3677);
  • Returns β€” (not listed)
  • Args β€” term (as acc or GO::Model::Term object)

Gets rid of everything below a node. Like, gone gone.

Used by AmiGO for when a user closes a term in the graph. 🫢


🌱 find_roots

  • Usage β€” my $terms = $graph->find_roots;
  • Returns β€” arrayref of GO::Model::Term objects
  • Args β€” (not listed)

All terms withOUT a parent. Yes the OUT is shouting in the original. She's dramatic and correct. πŸ‘‘

See also GO::Model::Term


🌈 get_all_products

  • Usage β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” (not listed)

See also GO::Model::GeneProduct


🫢 merge

  • Usage β€” $g->merge($g2);
  • Returns β€” (not listed)
  • Args β€” GO::Model::Graph

Merges two graphs into one. Friendship bracelet behavior. πŸ’–


✨ export

  • Usage β€” $graph->export({format=>$format});
  • Returns β€” (not listed)
  • Args β€” opt hash

Writes out the graph in any export format β€” including obo, go_ont, owl, png (graphviz) etc. Versatile icon. 🌈


πŸ¦‹ to_xml

  • Usage β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” (not listed)

πŸŽ€ add_term

  • Usage β€” $g->add_term($term)
  • Returns β€” (not listed)
  • Args β€” GO::Model::Term

πŸŽ€ add_node

  • Usage β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” (not listed)

A synonym for add_term. Same girl, different name tag.


πŸ’œ add_relationship

  • Usage β€” $graph->add_relationship({acc1=>from_id, acc2=>to_id});
  • Usage β€” $graph->add_relationship($from_id, $to_id, $type});
  • Usage β€” $graph->add_relationship($obj, $subj, $type});
  • Returns β€” (not listed)
  • Args β€” (not listed)

Only one relationship between id1 and id2 is allowed. She said what she said. Don't try it. πŸ’…

See also GO::Model::Relationship


πŸͺ£ add_buckets

  • Usage β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” (not listed)

Adds bucket terms to non-leaf nodes.

This is useful for making GO slims. πŸŽ€


πŸ“ to_text_output

  • Usage β€” (not listed)
  • Returns β€” (not listed)
  • Args β€” fmt, assocs [bool]

Hacky text output. Her own words, not mine. 😭

This method should probably move out of the model code into output adapters.


and that's a wrap, bestie πŸŽ€βœ¨

This page dropped as part of perl v5.36.0, dated 2023-12-18 β€” so if you're staring at a different version number or date down at the bottom of your own terminal, that's just your install's little timestamp flex, no cap. GO::Model::Graph(3pm) said everything it came to say, and you read the whole thing, which is lowkey iconic of you πŸ’…

go be the main character of your own object graph now πŸ‘‘πŸ¦‹

πŸ“¦ where this page comes from