Added support for VCD Database
This commit is contained in:
@ -1,54 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012 IT Just working.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IT Just working - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.minres.scviewer.database.text;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.minres.scviewer.database.ITrHierNode;
|
||||
|
||||
class HierNode implements ITrHierNode {
|
||||
|
||||
String name
|
||||
def childs = []
|
||||
|
||||
public HierNode(){
|
||||
}
|
||||
|
||||
public HierNode(String name){
|
||||
this.name=name
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ITrHierNode> getChildNodes() {
|
||||
return childs.sort{it.name}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullName() {
|
||||
// TODO Auto-generated method stub
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPropertyChangeListener(PropertyChangeListener l) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePropertyChangeListener(PropertyChangeListener l) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -19,17 +19,18 @@ import java.util.TreeMap;
|
||||
|
||||
import com.minres.scviewer.database.AssociationType;
|
||||
import com.minres.scviewer.database.DataType;
|
||||
import com.minres.scviewer.database.ITrAttrType;
|
||||
import com.minres.scviewer.database.ITrAttribute;
|
||||
import com.minres.scviewer.database.ITrDb;
|
||||
import com.minres.scviewer.database.ITrGenerator;
|
||||
import com.minres.scviewer.database.ITrHierNode;
|
||||
import com.minres.scviewer.database.ITrStream;
|
||||
import com.minres.scviewer.database.HierNode;
|
||||
import com.minres.scviewer.database.ITxAttributeType;
|
||||
import com.minres.scviewer.database.ITxAttribute;
|
||||
import com.minres.scviewer.database.IWaveformDb;
|
||||
import com.minres.scviewer.database.ITxGenerator;
|
||||
import com.minres.scviewer.database.IHierNode;
|
||||
import com.minres.scviewer.database.ITxStream;
|
||||
import com.minres.scviewer.database.InputFormatException;
|
||||
import com.minres.scviewer.database.EventTime
|
||||
import com.minres.scviewer.database.RelationType
|
||||
|
||||
public class TextDb extends HierNode implements ITrDb{
|
||||
public class TextDb extends HierNode implements IWaveformDb{
|
||||
|
||||
private EventTime maxTime;
|
||||
|
||||
@ -37,6 +38,10 @@ public class TextDb extends HierNode implements ITrDb{
|
||||
|
||||
def relationTypes=[:]
|
||||
|
||||
public TextDb() {
|
||||
super("TextDb");
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return getName();
|
||||
}
|
||||
@ -46,21 +51,21 @@ public class TextDb extends HierNode implements ITrDb{
|
||||
return maxTime;
|
||||
}
|
||||
|
||||
public ITrStream getStreamByName(String name){
|
||||
streams.find{ITrStream stream-> stream.fullName == name }
|
||||
public ITxStream getStreamByName(String name){
|
||||
streams.find{ITxStream stream-> stream.fullName == name }
|
||||
}
|
||||
|
||||
public List<ITrStream> getAllStreams() {
|
||||
return new LinkedList<ITrStream>(streams);
|
||||
public List<ITxStream> getAllWaves() {
|
||||
return new LinkedList<ITxStream>(streams);
|
||||
}
|
||||
|
||||
public List<ITrHierNode> getChildNodes() {
|
||||
public List<IHierNode> getChildNodes() {
|
||||
return childs.sort{it.name};
|
||||
}
|
||||
|
||||
public Map<Long, ITrGenerator> getGeneratorsById() {
|
||||
TreeMap<Long, ITrGenerator> res = new TreeMap<Long, ITrGenerator>();
|
||||
streams.each{Stream stream -> stream.generators.each{res.put(it.id, id)} }
|
||||
public Map<Long, ITxGenerator> getGeneratorsById() {
|
||||
TreeMap<Long, ITxGenerator> res = new TreeMap<Long, ITxGenerator>();
|
||||
streams.each{TxStream stream -> stream.generators.each{res.put(it.id, id)} }
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -78,8 +83,8 @@ public class TextDb extends HierNode implements ITrDb{
|
||||
def streamsById = [:]
|
||||
def generatorsById = [:]
|
||||
def transactionsById = [:]
|
||||
Generator generator
|
||||
Transaction transaction
|
||||
TxGenerator generator
|
||||
Tx transaction
|
||||
boolean endTransaction=false
|
||||
def matcher
|
||||
input.eachLine { line ->
|
||||
@ -91,19 +96,19 @@ public class TextDb extends HierNode implements ITrDb{
|
||||
case "end_attribute":
|
||||
if ((matcher = line =~ /^scv_tr_stream\s+\(ID (\d+),\s+name\s+"([^"]+)",\s+kind\s+"([^"]+)"\)$/)) {
|
||||
def id = Integer.parseInt(matcher[0][1])
|
||||
def stream = new Stream(id, this, matcher[0][2], matcher[0][3])
|
||||
def stream = new TxStream(id, this, matcher[0][2], matcher[0][3])
|
||||
streams<<stream
|
||||
streamsById[id]=stream
|
||||
} else if ((matcher = line =~ /^scv_tr_generator\s+\(ID\s+(\d+),\s+name\s+"([^"]+)",\s+scv_tr_stream\s+(\d+),$/)) {
|
||||
def id = Integer.parseInt(matcher[0][1])
|
||||
ITrStream stream=streamsById[Integer.parseInt(matcher[0][3])]
|
||||
generator=new Generator(id, stream, matcher[0][2])
|
||||
ITxStream stream=streamsById[Integer.parseInt(matcher[0][3])]
|
||||
generator=new TxGenerator(id, stream, matcher[0][2])
|
||||
stream.generators<<generator
|
||||
generatorsById[id]=generator
|
||||
} else if ((matcher = line =~ /^begin_attribute \(ID (\d+), name "([^"]+)", type "([^"]+)"\)$/)) {
|
||||
generator.begin_attrs << AttrType.getAttrType(matcher[0][2], DataType.valueOf(matcher[0][3]), AssociationType.BEGIN)
|
||||
generator.begin_attrs << TxAttributeType.getAttrType(matcher[0][2], DataType.valueOf(matcher[0][3]), AssociationType.BEGIN)
|
||||
} else if ((matcher = line =~ /^end_attribute \(ID (\d+), name "([^"]+)", type "([^"]+)"\)$/)) {
|
||||
generator.end_attrs << AttrType.getAttrType(matcher[0][2], DataType.valueOf(matcher[0][3]), AssociationType.END)
|
||||
generator.end_attrs << TxAttributeType.getAttrType(matcher[0][2], DataType.valueOf(matcher[0][3]), AssociationType.END)
|
||||
}
|
||||
break;
|
||||
case ")":
|
||||
@ -111,8 +116,8 @@ public class TextDb extends HierNode implements ITrDb{
|
||||
break
|
||||
case "tx_begin"://matcher = line =~ /^tx_begin\s+(\d+)\s+(\d+)\s+(\d+)\s+([munpf]?s)/
|
||||
def id = Integer.parseInt(tokens[1])
|
||||
Generator gen=generatorsById[Integer.parseInt(tokens[2])]
|
||||
transaction = new Transaction(id, gen.stream, gen, new EventTime(Integer.parseInt(tokens[3]), tokens[4]))
|
||||
TxGenerator gen=generatorsById[Integer.parseInt(tokens[2])]
|
||||
transaction = new Tx(id, gen.stream, gen, new EventTime(Integer.parseInt(tokens[3]), tokens[4]))
|
||||
gen.transactions << transaction
|
||||
transactionsById[id]= transaction
|
||||
gen.begin_attrs_idx=0;
|
||||
@ -130,21 +135,21 @@ public class TextDb extends HierNode implements ITrDb{
|
||||
break
|
||||
case "tx_record_attribute"://matcher = line =~ /^tx_record_attribute\s+(\d+)\s+"([^"]+)"\s+(\S+)\s*=\s*(.+)$/
|
||||
def id = Integer.parseInt(tokens[1])
|
||||
transactionsById[id].attributes<<new Attribute(tokens[2][1..-2], DataType.valueOf(tokens[3]), AssociationType.RECORD, tokens[5..-1].join(' '))
|
||||
transactionsById[id].attributes<<new TxAttribute(tokens[2][1..-2], DataType.valueOf(tokens[3]), AssociationType.RECORD, tokens[5..-1].join(' '))
|
||||
break
|
||||
case "a"://matcher = line =~ /^a\s+(.+)$/
|
||||
if(endTransaction){
|
||||
transaction.attributes << new Attribute(transaction.generator.end_attrs[0], tokens[1])
|
||||
transaction.attributes << new TxAttribute(transaction.generator.end_attrs[0], tokens[1])
|
||||
} else {
|
||||
transaction.attributes << new Attribute(transaction.generator.begin_attrs[0], tokens[1])
|
||||
transaction.attributes << new TxAttribute(transaction.generator.begin_attrs[0], tokens[1])
|
||||
}
|
||||
break
|
||||
case "tx_relation"://matcher = line =~ /^tx_relation\s+\"(\S+)\"\s+(\d+)\s+(\d+)$/
|
||||
Transaction tr1= transactionsById[Integer.parseInt(tokens[2])]
|
||||
Transaction tr2= transactionsById[Integer.parseInt(tokens[3])]
|
||||
Tx tr1= transactionsById[Integer.parseInt(tokens[2])]
|
||||
Tx tr2= transactionsById[Integer.parseInt(tokens[3])]
|
||||
def relType=tokens[1][1..-2]
|
||||
if(!relationTypes.containsKey(relType)) relationTypes[relType]=new RelationType(relType)
|
||||
def rel = new Relation(relationTypes[relType], tr1, tr2)
|
||||
def rel = new TxRelation(relationTypes[relType], tr1, tr2)
|
||||
tr1.outgoingRelations<<rel
|
||||
tr2.incomingRelations<<rel
|
||||
break
|
||||
@ -157,9 +162,9 @@ public class TextDb extends HierNode implements ITrDb{
|
||||
}
|
||||
|
||||
def addHierarchyNodes(){
|
||||
streams.each{ Stream stream->
|
||||
streams.each{ TxStream stream->
|
||||
def hier = stream.fullName.split(/\./)
|
||||
ITrHierNode node = this
|
||||
IHierNode node = this
|
||||
hier.each { name ->
|
||||
def n1 = node.childNodes.find{it.name == name}
|
||||
if(name == hier[-1]){ //leaf
|
||||
|
@ -2,15 +2,15 @@ package com.minres.scviewer.database.text
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import com.minres.scviewer.database.ITrDb
|
||||
import com.minres.scviewer.database.ITransactionDbFactory;
|
||||
import com.minres.scviewer.database.IWaveformDb
|
||||
import com.minres.scviewer.database.IWaveformDbFactory;
|
||||
|
||||
class TextDbFactory implements ITransactionDbFactory {
|
||||
class TextDbFactory implements IWaveformDbFactory {
|
||||
|
||||
byte[] x = "scv_tr_stream".bytes
|
||||
|
||||
@Override
|
||||
public ITrDb createDatabase(File file) {
|
||||
public IWaveformDb createDatabase(File file) {
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
byte[] buffer = new byte[x.size()];
|
||||
|
@ -15,37 +15,37 @@ import java.util.Set
|
||||
|
||||
import com.minres.scviewer.database.*
|
||||
|
||||
class Transaction implements ITransaction {
|
||||
class Tx implements ITx {
|
||||
|
||||
Long id
|
||||
|
||||
Generator generator
|
||||
TxGenerator generator
|
||||
|
||||
Stream stream
|
||||
TxStream stream
|
||||
|
||||
EventTime beginTime
|
||||
|
||||
EventTime endTime
|
||||
|
||||
ArrayList<ITrAttribute> attributes = new ArrayList<ITrAttribute>()
|
||||
ArrayList<ITxAttribute> attributes = new ArrayList<ITxAttribute>()
|
||||
|
||||
def incomingRelations =[]
|
||||
|
||||
def outgoingRelations =[]
|
||||
|
||||
Transaction(int id, Stream stream, Generator generator, EventTime begin){
|
||||
Tx(int id, TxStream stream, TxGenerator generator, EventTime begin){
|
||||
this.id=id
|
||||
this.generator=generator
|
||||
this.beginTime=begin
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ITrRelation> getIncomingRelations() {
|
||||
public Collection<ITxRelation> getIncomingRelations() {
|
||||
return incomingRelations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ITrRelation> getOutgoingRelations() {
|
||||
public Collection<ITxRelation> getOutgoingRelations() {
|
||||
return outgoingRelations;
|
||||
}
|
||||
|
@ -12,17 +12,17 @@ package com.minres.scviewer.database.text
|
||||
|
||||
import com.minres.scviewer.database.AssociationType;
|
||||
import com.minres.scviewer.database.DataType;
|
||||
import com.minres.scviewer.database.ITrAttrType;
|
||||
import com.minres.scviewer.database.ITrAttribute
|
||||
import com.minres.scviewer.database.ITxAttributeType;
|
||||
import com.minres.scviewer.database.ITxAttribute
|
||||
|
||||
class Attribute implements ITrAttribute{
|
||||
class TxAttribute implements ITxAttribute{
|
||||
|
||||
AttrType attributeType
|
||||
TxAttributeType attributeType
|
||||
|
||||
def value
|
||||
|
||||
Attribute(String name, DataType dataType, AssociationType type, value){
|
||||
attributeType = AttrTypeFactory.instance.getAttrType(name, dataType, type)
|
||||
TxAttribute(String name, DataType dataType, AssociationType type, value){
|
||||
attributeType = TxAttributeTypeFactory.instance.getAttrType(name, dataType, type)
|
||||
switch(dataType){
|
||||
case DataType.STRING:
|
||||
case DataType.ENUMERATION:
|
||||
@ -33,11 +33,11 @@ class Attribute implements ITrAttribute{
|
||||
}
|
||||
}
|
||||
|
||||
Attribute(AttrType other){
|
||||
TxAttribute(TxAttributeType other){
|
||||
attributeType=other
|
||||
}
|
||||
|
||||
Attribute(AttrType other, value){
|
||||
TxAttribute(TxAttributeType other, value){
|
||||
this(other.name, other.dataType, other.type, value)
|
||||
}
|
||||
|
@ -12,18 +12,18 @@ package com.minres.scviewer.database.text
|
||||
|
||||
import com.minres.scviewer.database.AssociationType;
|
||||
import com.minres.scviewer.database.DataType;
|
||||
import com.minres.scviewer.database.ITrAttrType;
|
||||
import com.minres.scviewer.database.ITxAttributeType;
|
||||
|
||||
class AttrType implements ITrAttrType {
|
||||
class TxAttributeType implements ITxAttributeType {
|
||||
String name
|
||||
DataType dataType
|
||||
AssociationType type
|
||||
|
||||
static AttrType getAttrType(String name, DataType dataType, AssociationType type){
|
||||
AttrTypeFactory.instance.getAttrType(name, dataType, type)
|
||||
static TxAttributeType getAttrType(String name, DataType dataType, AssociationType type){
|
||||
TxAttributeTypeFactory.instance.getAttrType(name, dataType, type)
|
||||
}
|
||||
|
||||
AttrType(String name, DataType dataType, AssociationType type){
|
||||
TxAttributeType(String name, DataType dataType, AssociationType type){
|
||||
this.name=name
|
||||
this.dataType=dataType
|
||||
this.type=type
|
@ -12,25 +12,25 @@ package com.minres.scviewer.database.text
|
||||
|
||||
import com.minres.scviewer.database.AssociationType;
|
||||
import com.minres.scviewer.database.DataType
|
||||
import com.minres.scviewer.database.ITrAttrType
|
||||
import com.minres.scviewer.database.ITrAttribute
|
||||
import com.minres.scviewer.database.ITxAttributeType
|
||||
import com.minres.scviewer.database.ITxAttribute
|
||||
|
||||
class AttrTypeFactory {
|
||||
private static final instance = new AttrTypeFactory()
|
||||
class TxAttributeTypeFactory {
|
||||
private static final instance = new TxAttributeTypeFactory()
|
||||
|
||||
def attributes = [:]
|
||||
|
||||
private AttrTypeFactory() {
|
||||
AttrTypeFactory.metaClass.constructor = {-> instance }
|
||||
private TxAttributeTypeFactory() {
|
||||
TxAttributeTypeFactory.metaClass.constructor = {-> instance }
|
||||
}
|
||||
|
||||
ITrAttrType getAttrType(String name, DataType dataType, AssociationType type){
|
||||
ITxAttributeType getAttrType(String name, DataType dataType, AssociationType type){
|
||||
def key = name+":"+dataType.toString()
|
||||
ITrAttrType res
|
||||
ITxAttributeType res
|
||||
if(attributes.containsKey(key)){
|
||||
res=attributes[key]
|
||||
} else {
|
||||
res=new AttrType(name, dataType, type)
|
||||
res=new TxAttributeType(name, dataType, type)
|
||||
attributes[key]=res
|
||||
}
|
||||
return res
|
@ -13,35 +13,35 @@ package com.minres.scviewer.database.text
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.minres.scviewer.database.ITrAttrType
|
||||
import com.minres.scviewer.database.ITrAttribute;
|
||||
import com.minres.scviewer.database.ITrGenerator;
|
||||
import com.minres.scviewer.database.ITrStream;
|
||||
import com.minres.scviewer.database.ITransaction;
|
||||
import com.minres.scviewer.database.ITxAttributeType
|
||||
import com.minres.scviewer.database.ITxAttribute;
|
||||
import com.minres.scviewer.database.ITxGenerator;
|
||||
import com.minres.scviewer.database.ITxStream;
|
||||
import com.minres.scviewer.database.ITx;
|
||||
|
||||
class Generator implements ITrGenerator{
|
||||
class TxGenerator implements ITxGenerator{
|
||||
Long id
|
||||
Stream stream
|
||||
TxStream stream
|
||||
String name
|
||||
Boolean active = false
|
||||
ArrayList<ITransaction> transactions=[]
|
||||
ArrayList<ITx> transactions=[]
|
||||
|
||||
ArrayList<ITrAttrType> begin_attrs = []
|
||||
ArrayList<ITxAttributeType> begin_attrs = []
|
||||
int begin_attrs_idx = 0
|
||||
ArrayList<ITrAttrType> end_attrs= []
|
||||
ArrayList<ITxAttributeType> end_attrs= []
|
||||
int end_attrs_idx = 0
|
||||
|
||||
Generator(int id, Stream stream, name){
|
||||
TxGenerator(int id, TxStream stream, name){
|
||||
this.id=id
|
||||
this.stream=stream
|
||||
this.name=name
|
||||
}
|
||||
|
||||
ITrStream getStream(){
|
||||
ITxStream getStream(){
|
||||
return stream;
|
||||
}
|
||||
|
||||
List<ITransaction> getTransactions(){
|
||||
List<ITx> getTransactions(){
|
||||
return transactions
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
package com.minres.scviewer.database.text
|
||||
|
||||
import com.minres.scviewer.database.ITrRelation
|
||||
import com.minres.scviewer.database.ITransaction;
|
||||
import com.minres.scviewer.database.ITxRelation
|
||||
import com.minres.scviewer.database.ITx;
|
||||
import com.minres.scviewer.database.RelationType;
|
||||
|
||||
class Relation implements ITrRelation {
|
||||
Transaction source
|
||||
class TxRelation implements ITxRelation {
|
||||
Tx source
|
||||
|
||||
Transaction target
|
||||
Tx target
|
||||
|
||||
RelationType relationType
|
||||
|
||||
|
||||
public Relation(RelationType relationType, Transaction source, Transaction target) {
|
||||
public TxRelation(RelationType relationType, Tx source, Tx target) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.relationType = relationType;
|
||||
@ -24,12 +24,12 @@ class Relation implements ITrRelation {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITransaction getSource() {
|
||||
public ITx getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITransaction getTarget() {
|
||||
public ITx getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
@ -14,13 +14,14 @@ import java.beans.PropertyChangeListener;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.minres.scviewer.database.ITrDb
|
||||
import com.minres.scviewer.database.ITrGenerator
|
||||
import com.minres.scviewer.database.ITrHierNode
|
||||
import com.minres.scviewer.database.ITrStream
|
||||
import com.minres.scviewer.database.ITransaction
|
||||
import com.minres.scviewer.database.HierNode;
|
||||
import com.minres.scviewer.database.IWaveformDb
|
||||
import com.minres.scviewer.database.ITxGenerator
|
||||
import com.minres.scviewer.database.IHierNode
|
||||
import com.minres.scviewer.database.ITxStream
|
||||
import com.minres.scviewer.database.ITx
|
||||
|
||||
class Stream extends HierNode implements ITrStream {
|
||||
class TxStream extends HierNode implements ITxStream {
|
||||
|
||||
Long id;
|
||||
|
||||
@ -34,31 +35,27 @@ class Stream extends HierNode implements ITrStream {
|
||||
|
||||
private allTransactions;
|
||||
|
||||
public TrHierNode(String name){
|
||||
this.name=name
|
||||
}
|
||||
|
||||
Stream(int id, TextDb db, String name, String kind){
|
||||
TxStream(int id, TextDb db, String name, String kind){
|
||||
super(name)
|
||||
this.id=id
|
||||
this.database=db
|
||||
this.name=name
|
||||
this.fullName=name
|
||||
this.kind=kind
|
||||
}
|
||||
|
||||
List<ITrGenerator> getGenerators(){
|
||||
return generators as List<ITrGenerator>
|
||||
List<ITxGenerator> getGenerators(){
|
||||
return generators as List<ITxGenerator>
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITrDb getDb() {
|
||||
public IWaveformDb getDb() {
|
||||
return database;
|
||||
}
|
||||
|
||||
// FIXME: maybe need to be somewhere else
|
||||
public int getMaxConcurrrentTx() {
|
||||
def rowendtime = [0]
|
||||
getTransactions().each{Transaction tx ->
|
||||
getTransactions().each{Tx tx ->
|
||||
def rowIdx = 0
|
||||
for(rowIdx=0; rowendtime.size()<rowIdx || rowendtime[rowIdx]>tx.beginTime.value; rowIdx++);
|
||||
if(rowendtime.size<=rowIdx){
|
||||
@ -71,14 +68,14 @@ class Stream extends HierNode implements ITrStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ITransaction> getTransactions() {
|
||||
public List<ITx> getTransactions() {
|
||||
if(!allTransactions)
|
||||
allTransactions=generators.transactions.flatten().sort{it.beginTime.value}
|
||||
return allTransactions
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITransaction getTransactionById(long id) {
|
||||
public ITx getTransactionById(long id) {
|
||||
if(!allTransactions)
|
||||
allTransactions=generators.transactions.flatten().sort{it.beginTime.value}
|
||||
allTransactions.find{it.id==id}
|
Reference in New Issue
Block a user