import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
import jalview.datamodel.Mapping;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
findXrefSourcesForSequence(seq, dna, sources);
}
}
+ sources.remove(DBRefSource.EMBL); // hack to prevent EMBL xrefs resulting in
+ // redundant datasets
+ if (dna)
+ {
+ sources.remove(DBRefSource.ENSEMBL); // hack to prevent Ensembl and
+ // EnsemblGenomes xref option shown
+ // from cdna panel
+ sources.remove(DBRefSource.ENSEMBLGENOMES);
+ }
+ // redundant datasets
return sources;
}
*/
for (SequenceI rs : foundSeqs)
{
- DBRefEntry[] xrs = DBRefUtils
- .selectDbRefs(!fromDna, rs.getDBRefs());
+ DBRefEntry[] xrs = DBRefUtils.selectDbRefs(!fromDna,
+ rs.getDBRefs());
addXrefsToSources(xrs, sources);
}
}
rseqs = new ArrayList<SequenceI>();
AlignedCodonFrame cf = new AlignedCodonFrame();
- matcher = new SequenceIdMatcher(
- dataset.getSequences());
+ matcher = new SequenceIdMatcher(dataset.getSequences());
for (SequenceI seq : fromSeqs)
{
dss = dss.getDatasetSequence();
}
boolean found = false;
- DBRefEntry[] xrfs = DBRefUtils
- .selectDbRefs(!fromDna, dss.getDBRefs());
+ DBRefEntry[] xrfs = DBRefUtils.selectDbRefs(!fromDna,
+ dss.getDBRefs());
+ // ENST & ENSP comes in to both Protein and nucleotide, so we need to
+ // filter them
+ // out later.
if ((xrfs == null || xrfs.length == 0) && dataset != null)
{
/*
List<DBRefEntry> sourceRefs = DBRefUtils.searchRefsForSource(xrfs,
source);
Iterator<DBRefEntry> refIterator = sourceRefs.iterator();
+ // At this point, if we are retrieving Ensembl, we still don't filter out
+ // ENST when looking for protein crossrefs.
while (refIterator.hasNext())
{
DBRefEntry xref = refIterator.next();
found = false;
- if (xref.hasMap())
+ // we're only interested in coding cross-references, not
+ // locus->transcript
+ if (xref.hasMap() && xref.getMap().getMap().isTripletMap())
{
SequenceI mappedTo = xref.getMap().getTo();
if (mappedTo != null)
* but findInDataset() matches ENSP when looking for Uniprot...
*/
SequenceI matchInDataset = findInDataset(xref);
+ if (matchInDataset != null && xref.getMap().getTo() != null
+ && matchInDataset != xref.getMap().getTo())
+ {
+ System.err.println(
+ "Implementation problem (reopen JAL-2154): CrossRef.findInDataset seems to have recovered a different sequence than the one explicitly mapped for xref."
+ + "Found:" + matchInDataset + "\nExpected:"
+ + xref.getMap().getTo() + "\nFor xref:"
+ + xref);
+ }
/*matcher.findIdMatch(mappedTo);*/
if (matchInDataset != null)
{
{
rseqs.add(matchInDataset);
}
+ // even if rseqs contained matchInDataset - check mappings between
+ // these seqs are added
+ // need to try harder to only add unique mappings
+ if (xref.getMap().getMap().isTripletMap()
+ && dataset.getMapping(seq, matchInDataset) == null
+ && cf.getMappingBetween(seq, matchInDataset) == null)
+ {
+ // materialise a mapping for highlighting between these
+ // sequences
+ if (fromDna)
+ {
+ cf.addMap(dss, matchInDataset, xref.getMap().getMap(),
+ xref.getMap().getMappedFromId());
+ }
+ else
+ {
+ cf.addMap(matchInDataset, dss,
+ xref.getMap().getMap().getInverse(),
+ xref.getMap().getMappedFromId());
+ }
+ }
+
refIterator.remove();
continue;
}
if (fromDna)
{
// map is from dna seq to a protein product
- cf.addMap(dss, rsq, xref.getMap().getMap(), xref.getMap()
- .getMappedFromId());
+ cf.addMap(dss, rsq, xref.getMap().getMap(),
+ xref.getMap().getMappedFromId());
}
else
{
if (!found)
{
- SequenceI matchedSeq = matcher.findIdMatch(xref.getSource() + "|"
- + xref.getAccessionId());
- if (matchedSeq != null)
+ SequenceI matchedSeq = matcher.findIdMatch(
+ xref.getSource() + "|" + xref.getAccessionId());
+ // if there was a match, check it's at least the right type of
+ // molecule!
+ if (matchedSeq != null && matchedSeq.isProtein() == fromDna)
{
if (constructMapping(seq, matchedSeq, xref, cf, fromDna))
{
{
ASequenceFetcher sftch = SequenceFetcherFactory.getSequenceFetcher();
SequenceI[] retrieved = null;
- SequenceI dss = seq.getDatasetSequence() == null ? seq : seq
- .getDatasetSequence();
+ SequenceI dss = seq.getDatasetSequence() == null ? seq
+ : seq.getDatasetSequence();
+ // first filter in case we are retrieving crossrefs that have already been
+ // retrieved. this happens for cases where a database record doesn't yield
+ // protein products for CDS
+ removeAlreadyRetrievedSeqs(sourceRefs, fromDna);
+ if (sourceRefs.size() == 0)
+ {
+ // no more work to do! We already had all requested sequence records in
+ // the dataset.
+ return;
+ }
try
{
retrieved = sftch.getSequences(sourceRefs, !fromDna);
} catch (Exception e)
{
- System.err
- .println("Problem whilst retrieving cross references for Sequence : "
+ System.err.println(
+ "Problem whilst retrieving cross references for Sequence : "
+ seq.getName());
e.printStackTrace();
}
if (retrieved != null)
{
- updateDbrefMappings(seq, xrfs, retrieved, cf, fromDna);
+ boolean addedXref = false;
+ List<SequenceI> newDsSeqs = new ArrayList<SequenceI>(),
+ doNotAdd = new ArrayList<SequenceI>();
+
for (SequenceI retrievedSequence : retrieved)
{
// dataset gets contaminated ccwith non-ds sequences. why ??!
// try: Ensembl -> Nuc->Ensembl, Nuc->Uniprot-->Protein->EMBL->
- SequenceI retrievedDss = retrievedSequence.getDatasetSequence() == null ? retrievedSequence
- : retrievedSequence.getDatasetSequence();
- DBRefEntry[] dbr = retrievedSequence.getDBRefs();
- if (dbr != null)
+ SequenceI retrievedDss = retrievedSequence
+ .getDatasetSequence() == null ? retrievedSequence
+ : retrievedSequence.getDatasetSequence();
+ addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
+ retrievedDss);
+ }
+ if (!addedXref)
+ {
+ // try again, after looking for matching IDs
+ // shouldn't need to do this unless the dbref mechanism has broken.
+ updateDbrefMappings(seq, xrfs, retrieved, cf, fromDna);
+ for (SequenceI retrievedSequence : retrieved)
+ {
+ // dataset gets contaminated ccwith non-ds sequences. why ??!
+ // try: Ensembl -> Nuc->Ensembl, Nuc->Uniprot-->Protein->EMBL->
+ SequenceI retrievedDss = retrievedSequence
+ .getDatasetSequence() == null ? retrievedSequence
+ : retrievedSequence.getDatasetSequence();
+ addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
+ retrievedDss);
+ }
+ }
+ for (SequenceI newToSeq : newDsSeqs)
+ {
+ if (!doNotAdd.contains(newToSeq)
+ && dataset.findIndex(newToSeq) == -1)
+ {
+ dataset.addSequence(newToSeq);
+ matcher.add(newToSeq);
+ }
+ }
+ }
+ }
+
+ /**
+ * Search dataset for sequences with a primary reference contained in
+ * sourceRefs.
+ *
+ * @param sourceRefs
+ * - list of references to filter.
+ * @param fromDna
+ * - type of sequence to search for matching primary reference.
+ */
+ private void removeAlreadyRetrievedSeqs(List<DBRefEntry> sourceRefs,
+ boolean fromDna)
+ {
+ DBRefEntry[] dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]);
+ for (SequenceI sq : dataset.getSequences())
+ {
+ boolean dupeFound = false;
+ // !fromDna means we are looking only for nucleotide sequences, not
+ // protein
+ if (sq.isProtein() == fromDna)
+ {
+ for (DBRefEntry dbr : sq.getPrimaryDBRefs())
+ {
+ for (DBRefEntry found : DBRefUtils.searchRefs(dbrSourceSet, dbr))
+ {
+ sourceRefs.remove(found);
+ dupeFound = true;
+ }
+ }
+ }
+ if (dupeFound)
+ {
+ // rebuild the search array from the filtered sourceRefs list
+ dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]);
+ }
+ }
+ }
+
+ /**
+ * process sequence retrieved via a dbref on source sequence to resolve and
+ * transfer data
+ *
+ * @param cf
+ * @param sourceSequence
+ * @param retrievedSequence
+ * @return true if retrieveSequence was imported
+ */
+ private boolean importCrossRefSeq(AlignedCodonFrame cf,
+ List<SequenceI> newDsSeqs, List<SequenceI> doNotAdd,
+ SequenceI sourceSequence, SequenceI retrievedSequence)
+ {
+ /**
+ * set when retrievedSequence has been verified as a crossreference for
+ * sourceSequence
+ */
+ boolean imported = false;
+ DBRefEntry[] dbr = retrievedSequence.getDBRefs();
+ if (dbr != null)
+ {
+ for (DBRefEntry dbref : dbr)
+ {
+ SequenceI matched = findInDataset(dbref);
+ if (matched == sourceSequence)
{
- for (DBRefEntry dbref : dbr)
+ // verified retrieved and source sequence cross-reference each other
+ imported = true;
+ }
+ // find any entry where we should put in the sequence being
+ // cross-referenced into the map
+ Mapping map = dbref.getMap();
+ if (map != null)
+ {
+ if (map.getTo() != null && map.getMap() != null)
{
- // find any entry where we should put in the sequence being
- // cross-referenced into the map
- Mapping map = dbref.getMap();
- if (map != null)
+ if (map.getTo() == sourceSequence)
{
- if (map.getTo() != null && map.getMap() != null)
+ // already called to import once, and most likely this sequence
+ // already imported !
+ continue;
+ }
+ if (matched == null)
+ {
+ /*
+ * sequence is new to dataset, so save a reference so it can be added.
+ */
+ newDsSeqs.add(map.getTo());
+ continue;
+ }
+
+ /*
+ * there was a matching sequence in dataset, so now, check to see if we can update the map.getTo() sequence to the existing one.
+ */
+
+ try
+ {
+ // compare ms with dss and replace with dss in mapping
+ // if map is congruent
+ SequenceI ms = map.getTo();
+ // TODO findInDataset requires exact sequence match but
+ // 'congruent' test is only for the mapped part
+ // maybe not a problem in practice since only ENA provide a
+ // mapping and it is to the full protein translation of CDS
+ // matcher.findIdMatch(map.getTo());
+ // TODO addendum: if matched is shorter than getTo, this will fail
+ // - when it should really succeed.
+ int sf = map.getMap().getToLowest();
+ int st = map.getMap().getToHighest();
+ SequenceI mappedrg = ms.getSubSequence(sf, st);
+ if (mappedrg.getLength() > 0 && ms.getSequenceAsString()
+ .equals(matched.getSequenceAsString()))
{
- // TODO findInDataset requires exact sequence match but
- // 'congruent' test is only for the mapped part
- // maybe not a problem in practice since only ENA provide a
- // mapping and it is to the full protein translation of CDS
- SequenceI matched = findInDataset(dbref);
- // matcher.findIdMatch(map.getTo());
- if (matched != null)
+ /*
+ * sequences were a match,
+ */
+ String msg = "Mapping updated from " + ms.getName()
+ + " to retrieved crossreference "
+ + matched.getName();
+ System.out.println(msg);
+
+ DBRefEntry[] toRefs = map.getTo().getDBRefs();
+ if (toRefs != null)
{
/*
- * already got an xref to this sequence; update this
- * map to point to the same sequence, and add
- * any new dbrefs to it
+ * transfer database refs
*/
- DBRefEntry[] toRefs = map.getTo().getDBRefs();
- if (toRefs != null)
+ for (DBRefEntry ref : toRefs)
{
- for (DBRefEntry ref : toRefs)
+ if (dbref.getSrcAccString()
+ .equals(ref.getSrcAccString()))
{
- matched.addDBRef(ref); // add or update mapping
+ continue; // avoid overwriting the ref on source sequence
}
+ matched.addDBRef(ref); // add or update mapping
}
- map.setTo(matched);
- }
- else
- {
- matcher.add(map.getTo());
}
- try
- {
- // compare ms with dss and replace with dss in mapping
- // if map is congruent
- SequenceI ms = map.getTo();
- int sf = map.getMap().getToLowest();
- int st = map.getMap().getToHighest();
- SequenceI mappedrg = ms.getSubSequence(sf, st);
- // SequenceI loc = dss.getSubSequence(sf, st);
- if (mappedrg.getLength() > 0
- && ms.getSequenceAsString().equals(
- dss.getSequenceAsString()))
- // && mappedrg.getSequenceAsString().equals(
- // loc.getSequenceAsString()))
- {
- String msg = "Mapping updated from " + ms.getName()
- + " to retrieved crossreference "
- + dss.getName();
- System.out.println(msg);
- map.setTo(dss);
+ doNotAdd.add(map.getTo());
+ map.setTo(matched);
- /*
- * give the reverse reference the inverse mapping
- * (if it doesn't have one already)
- */
- setReverseMapping(dss, dbref, cf);
+ /*
+ * give the reverse reference the inverse mapping
+ * (if it doesn't have one already)
+ */
+ setReverseMapping(matched, dbref, cf);
- /*
- * copy sequence features as well, avoiding
- * duplication (e.g. same variation from two
- * transcripts)
- */
- SequenceFeature[] sfs = ms.getSequenceFeatures();
- if (sfs != null)
+ /*
+ * copy sequence features as well, avoiding
+ * duplication (e.g. same variation from two
+ * transcripts)
+ */
+ List<SequenceFeature> sfs = ms.getFeatures()
+ .getAllFeatures();
+ for (SequenceFeature feat : sfs)
+ {
+ /*
+ * make a flyweight feature object which ignores Parent
+ * attribute in equality test; this avoids creating many
+ * otherwise duplicate exon features on genomic sequence
+ */
+ SequenceFeature newFeature = new SequenceFeature(feat)
+ {
+ @Override
+ public boolean equals(Object o)
{
- for (SequenceFeature feat : sfs)
- {
- /*
- * make a flyweight feature object which ignores Parent
- * attribute in equality test; this avoids creating many
- * otherwise duplicate exon features on genomic sequence
- */
- SequenceFeature newFeature = new SequenceFeature(
- feat)
- {
- @Override
- public boolean equals(Object o)
- {
- return super.equals(o, true);
- }
- };
- dss.addSequenceFeature(newFeature);
- }
+ return super.equals(o, true);
}
- }
- cf.addMap(retrievedDss, map.getTo(), map.getMap());
- } catch (Exception e)
- {
- System.err
- .println("Exception when consolidating Mapped sequence set...");
- e.printStackTrace(System.err);
+ };
+ matched.addSequenceFeature(newFeature);
}
}
+ cf.addMap(retrievedSequence, map.getTo(), map.getMap());
+ } catch (Exception e)
+ {
+ System.err.println(
+ "Exception when consolidating Mapped sequence set...");
+ e.printStackTrace(System.err);
}
}
}
- retrievedSequence.updatePDBIds();
- rseqs.add(retrievedDss);
- dataset.addSequence(retrievedDss);
- matcher.add(retrievedDss);
}
}
+ if (imported)
+ {
+ retrievedSequence.updatePDBIds();
+ rseqs.add(retrievedSequence);
+ if (dataset.findIndex(retrievedSequence) == -1)
+ {
+ dataset.addSequence(retrievedSequence);
+ matcher.add(retrievedSequence);
+ }
+ }
+ return imported;
}
+
/**
* Sets the inverse sequence mapping in the corresponding dbref of the mapped
* to sequence (if any). This is used after fetching a cross-referenced
}
/**
- * Returns the first identical sequence in the dataset if any, else null
+ * Returns null or the first sequence in the dataset which is identical to
+ * xref.mapTo, and has a) a primary dbref matching xref, or if none found, the
+ * first one with an ID source|xrefacc
*
* @param xref
+ * with map and mapped-to sequence
* @return
*/
SequenceI findInDataset(DBRefEntry xref)
SequenceI mapsTo = xref.getMap().getTo();
String name = xref.getAccessionId();
String name2 = xref.getSource() + "|" + name;
- SequenceI dss = mapsTo.getDatasetSequence() == null ? mapsTo : mapsTo
- .getDatasetSequence();
+ SequenceI dss = mapsTo.getDatasetSequence() == null ? mapsTo
+ : mapsTo.getDatasetSequence();
+ // first check ds if ds is directly referenced
+ if (dataset.findIndex(dss) > -1)
+ {
+ return dss;
+ }
+ DBRefEntry template = new DBRefEntry(xref.getSource(), null,
+ xref.getAccessionId());
+ /**
+ * remember the first ID match - in case we don't find a match to template
+ */
+ SequenceI firstIdMatch = null;
for (SequenceI seq : dataset.getSequences())
{
+ // first check primary refs.
+ List<DBRefEntry> match = DBRefUtils.searchRefs(
+ seq.getPrimaryDBRefs().toArray(new DBRefEntry[0]), template);
+ if (match != null && match.size() == 1 && sameSequence(seq, dss))
+ {
+ return seq;
+ }
/*
* clumsy alternative to using SequenceIdMatcher which currently
* returns sequences with a dbref to the matched accession id
* which we don't want
*/
- if (name.equals(seq.getName()) || seq.getName().startsWith(name2))
+ if (firstIdMatch == null && (name.equals(seq.getName())
+ || seq.getName().startsWith(name2)))
{
if (sameSequence(seq, dss))
{
- return seq;
+ firstIdMatch = seq;
}
}
}
- return null;
+ return firstIdMatch;
}
/**
{
return false;
}
- char[] c1 = seq1.getSequence();
- char[] c2 = seq2.getSequence();
- if (c1.length != c2.length)
+
+ if (seq1.getLength() != seq2.getLength())
{
return false;
}
- for (int i = 0; i < c1.length; i++)
+ int length = seq1.getLength();
+ for (int i = 0; i < length; i++)
{
- int diff = c1[i] - c2[i];
+ int diff = seq1.getCharAt(i) - seq2.getCharAt(i);
/*
* same char or differ in case only ('a'-'A' == 32)
*/
DBRefEntry xref, AlignedCodonFrame mappings, boolean fromDna)
{
MapList mapping = null;
-
+ SequenceI dsmapFrom = mapFrom.getDatasetSequence() == null ? mapFrom
+ : mapFrom.getDatasetSequence();
+ SequenceI dsmapTo = mapTo.getDatasetSequence() == null ? mapTo
+ : mapTo.getDatasetSequence();
/*
- * look for a reverse mapping, if found make its inverse
+ * look for a reverse mapping, if found make its inverse.
+ * Note - we do this on dataset sequences only.
*/
- if (mapTo.getDBRefs() != null)
+ if (dsmapTo.getDBRefs() != null)
{
- for (DBRefEntry dbref : mapTo.getDBRefs())
+ for (DBRefEntry dbref : dsmapTo.getDBRefs())
{
String name = dbref.getSource() + "|" + dbref.getAccessionId();
- if (dbref.hasMap() && mapFrom.getName().startsWith(name))
+ if (dbref.hasMap() && dsmapFrom.getName().startsWith(name))
{
/*
* looks like we've found a map from 'mapTo' to 'mapFrom'
* - invert it to make the mapping the other way
*/
MapList reverse = dbref.getMap().getMap().getInverse();
- xref.setMap(new Mapping(mapTo, reverse));
- mappings.addMap(mapFrom, mapTo, reverse);
+ xref.setMap(new Mapping(dsmapTo, reverse));
+ mappings.addMap(mapFrom, dsmapTo, reverse);
return true;
}
}
/*
* and add a reverse DbRef with the inverse mapping
*/
- if (mapFrom.getDatasetSequence() != null
- && mapFrom.getDatasetSequence().getSourceDBRef() != null)
+ if (mapFrom.getDatasetSequence() != null && false)
+ // && mapFrom.getDatasetSequence().getSourceDBRef() != null)
{
- DBRefEntry dbref = new DBRefEntry(mapFrom.getDatasetSequence()
- .getSourceDBRef());
- dbref.setMap(new Mapping(mapFrom.getDatasetSequence(), mapping
- .getInverse()));
- mapTo.addDBRef(dbref);
+ // possible need to search primary references... except, why doesn't xref
+ // == getSourceDBRef ??
+ // DBRefEntry dbref = new DBRefEntry(mapFrom.getDatasetSequence()
+ // .getSourceDBRef());
+ // dbref.setMap(new Mapping(mapFrom.getDatasetSequence(), mapping
+ // .getInverse()));
+ // mapTo.addDBRef(dbref);
}
if (fromDna)
* @return true if matches were found.
*/
private boolean searchDatasetXrefs(boolean fromDna, SequenceI sequenceI,
- DBRefEntry[] lrfs, List<SequenceI> foundSeqs, AlignedCodonFrame cf)
+ DBRefEntry[] lrfs, List<SequenceI> foundSeqs,
+ AlignedCodonFrame cf)
{
boolean found = false;
if (lrfs == null)
// add in wildcards
xref.setVersion(null);
xref.setMap(null);
- found |= searchDataset(fromDna, sequenceI, xref, foundSeqs, cf, false);
+ found |= searchDataset(fromDna, sequenceI, xref, foundSeqs, cf,
+ false);
}
return found;
}
* </ul>
* @return true if relationship found and sequence added.
*/
- boolean searchDataset(boolean fromDna, SequenceI fromSeq,
- DBRefEntry xrf, List<SequenceI> foundSeqs, AlignedCodonFrame mappings,
+ boolean searchDataset(boolean fromDna, SequenceI fromSeq, DBRefEntry xrf,
+ List<SequenceI> foundSeqs, AlignedCodonFrame mappings,
boolean direct)
{
boolean found = false;
{
if (nxt.getDatasetSequence() != null)
{
- System.err
- .println("Implementation warning: CrossRef initialised with a dataset alignment with non-dataset sequences in it! ("
- + nxt.getDisplayId(true)
- + " has ds reference "
+ System.err.println(
+ "Implementation warning: CrossRef initialised with a dataset alignment with non-dataset sequences in it! ("
+ + nxt.getDisplayId(true) + " has ds reference "
+ nxt.getDatasetSequence().getDisplayId(true)
+ ")");
}
// }
if (!cands.isEmpty())
{
- if (!foundSeqs.contains(nxt))
+ if (foundSeqs.contains(nxt))
{
- found = true;
- foundSeqs.add(nxt);
- if (mappings != null && !direct)
+ continue;
+ }
+ found = true;
+ foundSeqs.add(nxt);
+ if (mappings != null && !direct)
+ {
+ /*
+ * if the matched sequence has mapped dbrefs to
+ * protein product / cdna, add equivalent mappings to
+ * our source sequence
+ */
+ for (DBRefEntry candidate : cands)
{
- /*
- * if the matched sequence has mapped dbrefs to
- * protein product / cdna, add equivalent mappings to
- * our source sequence
- */
- for (DBRefEntry candidate : cands)
+ Mapping mapping = candidate.getMap();
+ if (mapping != null)
{
- Mapping mapping = candidate.getMap();
- if (mapping != null)
+ MapList map = mapping.getMap();
+ if (mapping.getTo() != null
+ && map.getFromRatio() != map.getToRatio())
{
- MapList map = mapping.getMap();
- if (mapping.getTo() != null
- && map.getFromRatio() != map.getToRatio())
+ /*
+ * add a mapping, as from dna to peptide sequence
+ */
+ if (map.getFromRatio() == 3)
+ {
+ mappings.addMap(nxt, fromSeq, map);
+ }
+ else
{
- /*
- * add a mapping, as from dna to peptide sequence
- */
- if (map.getFromRatio() == 3)
- {
- mappings.addMap(nxt, fromSeq, map);
- }
- else
- {
- mappings.addMap(nxt, fromSeq, map.getInverse());
- }
+ mappings.addMap(nxt, fromSeq, map.getInverse());
}
}
}